Skip to content

Upgrade to TypeScript 7 (native compiler)#1149

Open
RhysSullivan wants to merge 1 commit into
mainfrom
ts7-upgrade
Open

Upgrade to TypeScript 7 (native compiler)#1149
RhysSullivan wants to merge 1 commit into
mainfrom
ts7-upgrade

Conversation

@RhysSullivan

Copy link
Copy Markdown
Owner

Moves the workspace to typescript@7.0.1-rc, the native (Go) compiler, across the bun catalog and every package that pins typescript directly.

Why it is not a one-line bump

TS7 removes the classic require("typescript") JS compiler API (the package no longer exposes a main; it exports only ./package.json and ./unstable/*). A few consumers depended on that API:

  • tsup loads typescript at module init even with dts: false, so it now throws ERR_PACKAGE_PATH_NOT_EXPORTED. Added a patch that makes its typescript require tolerant.
  • sdk tool-output-contract test helper used the in-process virtual-host compiler API. Rewritten to type-check synthesized snippets by shelling out to the native tsgo binary.
  • desktop-settings declaration emit moved off rollup-plugin-dts (classic API) to native tsc --emitDeclarationOnly.

The effect-language-service patch is dropped from the prepare hook (it patches the classic compiler and is incompatible with TS7); it stays as an inert tsconfig plugin entry.

rootDir change

The native compiler enforces rootDir against cross-package React source imports that the previous toolchain tolerated (TS6059). Widened rootDir in the app, cloud, and local tsconfigs. These are all --noEmit typecheck targets that build via Vite, so the change only affects the diagnostic, not emit.

Verification

  • bun install (lockfile consistent, prepare hook runs)
  • bun run typecheck (41/41)
  • bun run build:packages
  • bun run format:check
  • bun run lint (0/0)
  • Affected contract consumer tests (sdk, execution, mcp, openapi)

Move the workspace to typescript@7.0.1-rc (the native Go compiler) across the
bun catalog and all packages that pin typescript directly.

TS7 removes the classic require("typescript") JS compiler API, which required
working around two consumers:
- Patch tsup so its eager typescript require tolerates the missing module (it
  loads typescript at module init even when dts is disabled).
- Rewrite the sdk tool-output-contract test helper to type-check synthesized
  snippets by invoking the native tsgo binary instead of the in-process
  compiler API.
- Move desktop-settings declaration emit from rollup-plugin-dts (classic API)
  to native tsc --emitDeclarationOnly.

Drop the effect-language-service patch from the prepare hook (it patches the
classic compiler and is incompatible with TS7); it remains an inert tsconfig
plugin entry.

The native compiler enforces rootDir against cross-package react source imports
that the previous toolchain tolerated, so widen rootDir in the app, cloud, and
local tsconfigs (all noEmit typecheck targets that build via Vite).

Verified: install, typecheck (41/41), build:packages, format, lint, and the
affected contract consumer tests all pass.
@github-actions

Copy link
Copy Markdown
Contributor

Cloudflare preview

Console https://executor-preview-pr-1149.executor-e2e.workers.dev
MCP https://executor-preview-pr-1149.executor-e2e.workers.dev/mcp
Deployed commit 212632b

Sign-in is Cloudflare Access (one-time PIN to an allowed email). The preview has its own database and encryption key; it is destroyed when this PR closes.

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
executor-cloud 212632b Jun 26 2026, 04:12 PM

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
executor-marketing 212632b Commit Preview URL

Branch Preview URL
Jun 26 2026, 04:12 PM

@pkg-pr-new

pkg-pr-new Bot commented Jun 26, 2026

Copy link
Copy Markdown

Open in StackBlitz

@executor-js/cli

npm i https://pkg.pr.new/@executor-js/cli@1149

@executor-js/config

npm i https://pkg.pr.new/@executor-js/config@1149

@executor-js/execution

npm i https://pkg.pr.new/@executor-js/execution@1149

@executor-js/sdk

npm i https://pkg.pr.new/@executor-js/sdk@1149

@executor-js/codemode-core

npm i https://pkg.pr.new/@executor-js/codemode-core@1149

@executor-js/runtime-quickjs

npm i https://pkg.pr.new/@executor-js/runtime-quickjs@1149

@executor-js/plugin-file-secrets

npm i https://pkg.pr.new/@executor-js/plugin-file-secrets@1149

@executor-js/plugin-graphql

npm i https://pkg.pr.new/@executor-js/plugin-graphql@1149

@executor-js/plugin-keychain

npm i https://pkg.pr.new/@executor-js/plugin-keychain@1149

@executor-js/plugin-mcp

npm i https://pkg.pr.new/@executor-js/plugin-mcp@1149

@executor-js/plugin-onepassword

npm i https://pkg.pr.new/@executor-js/plugin-onepassword@1149

@executor-js/plugin-openapi

npm i https://pkg.pr.new/@executor-js/plugin-openapi@1149

executor

npm i https://pkg.pr.new/executor@1149

commit: 212632b

@greptile-apps

greptile-apps Bot commented Jun 26, 2026

Copy link
Copy Markdown

Greptile Summary

This PR upgrades the entire workspace from TypeScript 5.x to 7.0.1-rc (the native Go compiler), which no longer exposes the classic require("typescript") JS API. Several consumers had to be adapted to work without that API.

  • tool-output-contract.ts: The in-process virtual-host compiler is replaced with a spawnSync call to the tsgo binary; spawnSync errors (result.error) are not checked, so a missing or crashing binary silently produces an empty error list and causes type-check tests to falsely pass.
  • desktop-settings build: Declaration emit moves from rollup-plugin-dts to tsc --emitDeclarationOnly, but || true suppresses all tsc exit codes, hiding any future type errors in declarations.
  • tsup patch + dts: false: A patch wraps require('typescript') in tsup's compiled output in a try/catch so the tool loads without TS7's missing JS API; dts: false prevents tsup from exercising the now-empty API object.

Confidence Score: 3/5

The tsconfig, lockfile, and patch changes are straightforward and well-motivated; the tool-output-contract rewrite introduces a spawn-error blind spot that can mask type-check failures entirely.

The spawnSync call in tool-output-contract.ts doesn't check result.error or a null result.status (set when the process never started). If the tsgo binary is absent — e.g., on a CI image that installs only production dependencies, or after an install that skips optional platform packages — every call returns [] with no exceptions raised, making every contract test pass without performing any type-checking. That's a correctness hole in the test infrastructure that can silently hide regressions.

packages/core/sdk/src/testing/tool-output-contract.ts and packages/plugins/desktop-settings/package.json deserve a second look before merging.

Important Files Changed

Filename Overview
packages/core/sdk/src/testing/tool-output-contract.ts Rewrites in-process TS compiler API to shell out to tsgo binary; spawn errors are not checked, which can cause tests to silently pass with no type-checking performed.
packages/plugins/desktop-settings/package.json Moves declaration emit from tsup/rollup-plugin-dts to tsc CLI, but suppresses all tsc exit codes with `
patches/tsup@8.5.1.patch Wraps both require('typescript') calls in tsup's compiled output in a try/catch that defaults to {}, allowing tsup to load without the classic TS JS API present.
apps/cloud/tsconfig.json Widens rootDir from . to ../.. to satisfy TS7's stricter cross-package import enforcement; safe for a --noEmit typecheck target built via Vite.
apps/local/tsconfig.json Same rootDir widening as apps/cloud/tsconfig.json; no emit impact.
packages/app/tsconfig.json Widens rootDir from . to .. to accommodate cross-package React source imports flagged by TS7's stricter TS6059 check.
packages/plugins/desktop-settings/tsup.config.ts Sets dts: false to avoid tsup invoking the missing classic TS API for declaration emit; declarations are now handled by the tsc CLI invocation in the build script.
package.json Bumps typescript to 7.0.1-rc, upgrades @effect/language-service and @effect/tsgo, drops effect-language-service patch from the prepare hook, and registers the new tsup patch.
bun.lock Lockfile reflecting all dependency changes: typescript 5→7.0.1-rc, @effect/tsgo, @typescript/native-preview bumps, and removal of per-package typescript@6 overrides.
examples/all-plugins/package.json Pins typescript from latest to 7.0.1-rc to align with the workspace catalog.
examples/promise-sdk/package.json Same latest7.0.1-rc pin as examples/all-plugins.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Test as Test Suite
    participant Helper as tool-output-contract.ts
    participant FS as tmp filesystem
    participant tsgo as tsgo (native binary)

    Test->>Helper: typeCheckOutputTypeScript(contract, output, opts)
    Helper->>Helper: resolveTsgoShim() → path to tsgo.js
    Helper->>FS: mkdtempSync() → create temp dir
    Helper->>FS: writeFileSync(fileName, synthesized source)
    Helper->>tsgo: spawnSync(node, [tsgo.js, --noEmit, ...flags, fileName])
    alt spawn succeeds
        tsgo-->>Helper: stdout/stderr with TS diagnostics
        Helper->>Helper: filter lines matching /: error TS\d+:/
        Helper-->>Test: "string[] of error lines (empty = pass)"
    else spawn fails (ENOENT / signal / OOM)
        tsgo-->>Helper: "result.error set, stdout=null, stderr=null"
        Helper->>Helper: ?? "" guards produce empty strings
        Helper-->>Test: [] ← falsely indicates clean type-check
    end
    Helper->>FS: rmSync(dir, recursive+force)
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Test as Test Suite
    participant Helper as tool-output-contract.ts
    participant FS as tmp filesystem
    participant tsgo as tsgo (native binary)

    Test->>Helper: typeCheckOutputTypeScript(contract, output, opts)
    Helper->>Helper: resolveTsgoShim() → path to tsgo.js
    Helper->>FS: mkdtempSync() → create temp dir
    Helper->>FS: writeFileSync(fileName, synthesized source)
    Helper->>tsgo: spawnSync(node, [tsgo.js, --noEmit, ...flags, fileName])
    alt spawn succeeds
        tsgo-->>Helper: stdout/stderr with TS diagnostics
        Helper->>Helper: filter lines matching /: error TS\d+:/
        Helper-->>Test: "string[] of error lines (empty = pass)"
    else spawn fails (ENOENT / signal / OOM)
        tsgo-->>Helper: "result.error set, stdout=null, stderr=null"
        Helper->>Helper: ?? "" guards produce empty strings
        Helper-->>Test: [] ← falsely indicates clean type-check
    end
    Helper->>FS: rmSync(dir, recursive+force)
Loading

Reviews (1): Last reviewed commit: "Upgrade to TypeScript 7 (native compiler..." | Re-trigger Greptile

Comment on lines +56 to +76
const result = spawnSync(
process.execPath,
[
resolveTsgoShim(),
"--noEmit",
"--strict",
"--skipLibCheck",
"--target",
"es2022",
"--module",
"esnext",
"--pretty",
"false",
fileName,
],
{ cwd: dir, encoding: "utf8" },
);
return `${result.stdout ?? ""}\n${result.stderr ?? ""}`
.split("\n")
.map((line) => line.trim())
.filter((line) => ERROR_LINE.test(line));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Silent pass on spawn failure

spawnSync sets result.error when the process cannot be started (e.g., ENOENT from a missing tsgo binary, an OOM kill, or a signal termination) and leaves result.stdout / result.stderr as null. The ?? "" guards produce empty strings, the ERROR_LINE filter matches nothing, and the function returns [] — indistinguishable from a clean type-check. Any test relying on this helper will silently pass without the compiler ever running. A result.error (or a null result.status) check is needed to surface the failure.

},
"scripts": {
"build": "tsup",
"build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 || true silences all tsc declaration-emit errors

The || true makes the build script always succeed regardless of why tsc exits non-zero. If tsc encounters real type errors (not just the rootDir/TS6059 issue mentioned in the PR), the build completes silently with potentially incomplete or incorrect .d.ts files. A targeted exit-code filter would let the intended TS6059 class through while still propagating other failures.

Suggested change
"build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)",
"build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src 2>&1 | grep -v 'error TS6059' || true)",

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant