Skip to content

Carry the TypeScript toolchain as a CLI dependency#123

Merged
ctate merged 8 commits into
mainfrom
fix/ts-transpiler-bootstrap
Jul 13, 2026
Merged

Carry the TypeScript toolchain as a CLI dependency#123
ctate merged 8 commits into
mainfrom
fix/ts-transpiler-bootstrap

Conversation

@ctate

@ctate ctate commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

Fixes the one gap the 0.5.0 npm-channel funnel test found: a fresh npm i @native-sdk/cli could not run any TypeScript verb — the published CLI carries the packages/core transpiler mirror, but npm never installs a nested package's devDependencies, so the toolchain was absent. native check stopped at a manual-npm ci teaching; the build-graph verbs delivered it via std.debug.panic (stack trace, signal ABRT, mangled path).

The fix: npm owns the install. The CLI declares its TypeScript toolchain as regular, exactly-pinned dependencies:

  • @typescript/typescript6@6.0.2 — Microsoft's TS6-API continuity package (a one-line re-export), and @typescript/old pinned to npm:typescript@6.0.3 — the real compiler behind the wrapper's caret alias, so consumer installs can never drift onto an untested compiler. check-version-sync asserts both pins string-equal across manifests and shape-exact (no ranges).
  • TypeScript verbs gate on toolchain resolution — an fs ancestor walk matching node's require semantics (wrapper manifest + entrypoint + the aliased compiler resolving from the wrapper's directory; nested, hoisted, and pnpm layouts all verified). Direct zig build gets a clean configure-time teaching with a resolved path and exit 1 — no panic.
  • Per-layout teachings, no automation: a repo checkout missing its dev install is taught the one command (cd packages/core && npm ci --include=dev); an npm install missing its declared dependency is taught to reinstall the CLI. By design ruling, contributor paths get a teaching, not machinery — the CLI never runs npm at verb time on any layout.

End-to-end proofs on the real npm pack artifact: fresh install → init/check/test/build zero-touch; the same funnel fully offline; a chmod -R a-w install byte-identical before/after (SHA-256 over every file); NODE_ENV=production no effect; the checkout teaching fires without spawning anything; the panic path gone.

Suites: full battery, validate, test-tooling (153/153, 4× flake check), test-ts-core-e2e, the new test-ts-toolchain-twins pin step, packages/core npm suite 204/204, version:check in sync.

@vercel

vercel Bot commented Jul 13, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
native-sdk Ready Ready Preview, Comment Jul 13, 2026 6:52pm

ctate added 3 commits July 13, 2026 11:39
…endencies

- @native-sdk/cli gains @typescript/typescript6 6.0.2 and @typescript/old npm:typescript@6.0.3 as regular dependencies, so npm installs the whole toolchain (the wrapper AND the real compiler it re-exports) in the same transaction as the CLI
- packages/core pins the same two exact versions as devDependencies (replacing the ^6.0.2 range) and its lockfile follows
- check-version-sync asserts both pins string-equal across the two manifests and shape-exact: X.Y.Z for the wrapper, npm:typescript@X.Y.Z for the alias
… layout

- transpilerResolves walks node's ancestor node_modules from packages/core and requires the wrapper's manifest + entrypoint AND the aliased real compiler resolving from the wrapper's own directory (nested, hoisted, and global layouts alike); partial extractions read as unresolved
- the gate runs before any zig spawn (check, dev --core, build-graph verbs) and never runs npm: checkouts (the packages/core/test signal) are taught the one npm ci --include=dev against a resolved absolute path, npm layouts are taught the reinstall (BrokenToolchainInstall)
- build/app.zig carries the twin predicate for direct zig build and fails configure with a clean teaching instead of a panic; test-ts-toolchain-twins pins the twins' alias probes and teachings in lockstep
- first TS-verb use needs no network, no install step, and never runs npm
- repo checkouts are taught the one npm ci command; direct zig build teaches instead of panicking
- BrokenToolchainInstall already prints its reinstall guidance; list it in failVerb's expected-error switch so the CLI exits without a Zig error-return trace.
- Ejected apps pin their own SDK in build.zig.zon, so gating the CLI's
  resolved SDK false-failed healthy apps whose direct zig build works;
  they now flow to the spawn, where build/app.zig's tsCoreStage teaching
  names the app's actual dependency SDK.
- Name the one generated-vs-ejected decision (isEjectedAt) so the
  preflight and the argv assembly share a single predicate, and keep
  check/dev --core gated: they always transpile against the CLI's SDK.
- Cover both paths in a verbs test: an ejected-shaped TS layout skips
  the gate against a toolchain-less SDK; the generated layout still
  teaches, and passes once the toolchain resolves.
- ts_run.mjs now teaches "upgrade to Node.js 22.15+" and exits before importing a node_modules-resident target when module.registerHooks is missing, instead of dying inside node with the raw ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING; repo-checkout targets keep running natively on any Node 22.
- Every "Node.js 22+" surface (nodeMissing teaching, build/app.zig panic, scaffold README, quick-start docs, changelog fragment) now names 22.15.
- packages/core/test/ts_run.test.ts pins both tiers by spawning the runner with a --import preload that deletes module.registerHooks, plus the real hook-stripping path against the package's own toolchain install.
…mpiler

- build/ts_run.mjs now strips ALL .ts modules (node's default stripping is 22.18+, so the 22.15-22.17 checkout fall-through died raw); hooks-absent teaches for any .ts target, and the hook requires @typescript/old directly with a sane direct-run teaching when the dev install is missing
- typed_ast.ts imports @typescript/old instead of the wrapper, so a consumer tree's conflicting hoisted copy can never shadow the SDK's exact pin (the wrapper stays the declared dependency)
- both resolution twins (ts_core.zig transpilerResolution, build/app.zig tsToolchainResolution) read the resolved @typescript/old version and hold it against the npm:typescript@X.Y.Z pin parsed from packages/core/package.json, teaching resolved-vs-pinned on mismatch; fixtures gain version/pin manifests and mismatch tests cover both layouts
Comment thread src/tooling/ts_core.zig Outdated
…from

- Both resolution twins now walk @typescript/old from packages/core — the origin typed_ast.ts and ts_run.mjs actually load from — instead of holding the wrapper's origin against the pin, which false-rejected npm's own conflict shape (consumer's hoisted compiler + our exact pin nested under the CLI); the unused @typescript/typescript6 wrapper is no longer probed at all, though it stays a declared dependency.
- Make the node requirement branch-aware everywhere it is taught (22.15+ admits 23.0-23.4 numerically, but registerHooks only landed in 22.15 and 23.5): one phrasing across ts_run.mjs, both gate teachings, the templates README, the quick-start docs, and the changelog fragment.
- Correct the changelog fragment's claim that repo checkouts run on any Node 22: every .ts module rides the same registerHooks stripping, so the floor is uniform across layouts.
@ctate ctate merged commit 4b9d40b into main Jul 13, 2026
21 checks passed
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