fix(vtz): vtz ci self-hosts config loading — drop bun/tsx requirement#2742
Merged
Conversation
edb4113 to
a718221
Compare
vtz ci's config loader used to spawn an external JS runtime to evaluate ci.config.ts — bun (preferred) or node + tsx (fallback). That made bun or tsx a hard requirement for `vtz ci` despite vtz itself being a TypeScript runtime. Surfaced in #2739 while migrating CI from bun install to vtz install: without bun on PATH, the fallback failed because @vertz/ci's package.json exports don't satisfy strict-Node ESM. Three changes make vtz self-hosting for this path: 1. New hidden subcommand `vtz __exec <file> [args...]`: runs a single JS/TS file through the vtz runtime with process.argv populated as [vtz_bin, abs_file, ...extra_args]. Not intended for end-user use. 2. find_runtime() in ci/config.rs now prefers std::env::current_exe() with the __exec subcommand. bun and node+tsx remain as fallbacks for the rare case current_exe() is unavailable. 3. process.exit(code) is now implemented (new op_process_exit op). It previously threw. The existing .pipe/_loader.mjs calls process.exit(0) at the end of its run, so this is needed for the loader to terminate cleanly under vtz. Verified end-to-end locally: vtz ci test --scope @vertz/errors loads ci.config.ts without setup-bun on PATH and without tsx as a devDep. The loader writes config JSON, receives callback eval requests, and exits cleanly via process.exit. Unblocks migrating CI from `bun install` to `vtz install --frozen` (follow-up PR; tracked separately from #2739). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
a718221 to
b7deb83
Compare
This was referenced Apr 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Resolves #2739.
vtz ci's config loader used to spawn an external JS runtime to evaluateci.config.ts— bun preferred,node --import tsxas fallback. That meant bun (or tsx as a devDep) was a hard requirement forvtz cidespite vtz itself being a TypeScript runtime.Surfaced during the bun→vtz CI migration attempt (closed PR #2733): without bun on PATH, the node+tsx fallback also failed because
@vertz/ci's package.json exports don't satisfy strict-Node ESM resolution, which tsx uses. Piling workarounds would have masked the real architectural problem.This PR makes vtz self-hosting for this path — with no fallback. If the running vtz binary path can't be determined,
vtz cifails fast with a clear error rather than silently picking up bun or tsx (which would mask real bugs in the vtz install / execution path).Changes
1.
vtz __exec <file> [args...]— new hidden subcommandRuns a single JS/TS file through the vtz runtime with
process.argvpopulated as[vtz_bin, abs_file, ...extra_args]. Not for end-user use — it exists to support internal tooling likevtz ci.2.
find_runtime()inci/config.rsAlways uses
std::env::current_exe()+ the__execsubcommand. No bun, no tsx, no fallbacks. Ifcurrent_exe()fails (extremely rare — platform-specific sandbox edge cases),vtz cisurfaces the error instead of silently switching interpreters.3.
process.exit(code)is now implementedVia new
op_process_exitop. It previously threw. The existing.pipe/_loader.mjs(unchanged in this PR) callsprocess.exit(0)at the end of its run, so this is necessary for the loader to terminate cleanly under vtz. Flushes stdout/stderr before exit.Verified end-to-end locally
$ vtz ci test --scope @vertz/errors --concurrency 1 [pipe] Loading ci.config.ts... ← loaded via vtz, not bun/tsx [pipe] Workspace: 47 packages, 3 native crates [pipe] Running with concurrency=1 ...No bun on PATH, no tsx devDependency — and
vtz ciworks.Rust quality gates
cargo test -p vtz --lib— 3441 pass, 0 failcargo clippy -p vtz --all-targets -- -D warningscleancargo fmt --all -- --checkcleanUnblocks
After this lands + 0.2.69 publishes, the bun→vtz CI migration (formerly PR #2733) becomes a trivial workflow-only change.
Related tracking issues
vtz installextracts tarballs #2735 — tarball extraction exec mode (fixed + shipped in 0.2.68)^0.27.3incorrectly resolves to 0.25.12 #2738 — vtz install semver resolver bug (open)🤖 Generated with Claude Code