@vzn/vx 0.0.640 → 0.0.641
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/caching.md +47 -23
- package/docs/cli.md +10 -5
- package/docs/execution.md +7 -6
- package/docs/features.md +1 -1
- package/docs/schema.md +19 -12
- package/docs/security.md +4 -3
- package/launcher.sh +9 -2
- package/package.json +5 -5
- package/src/bin.ts +8 -6
- package/src/cache/archive.ts +248 -41
- package/src/cache/cache.ts +42 -18
- package/src/cache/index.ts +3 -0
- package/src/cache/inputs.ts +81 -35
- package/src/cache/layer.ts +7 -1
- package/src/cache/layered-cache.ts +8 -7
- package/src/cache/scoped-cache.ts +8 -2
- package/src/cli/help.ts +7 -1
- package/src/cli/upgrade.ts +37 -2
- package/src/cli/watch-filter.ts +1 -6
- package/src/cli/watch-fs.ts +2 -1
- package/src/handoff.ts +5 -0
- package/src/index.ts +1 -1
- package/src/orchestrator/hit-restore.ts +101 -27
- package/src/orchestrator/local-shortcircuit.ts +8 -0
- package/src/orchestrator/plugin-host.ts +4 -5
- package/src/orchestrator/run-report.ts +30 -9
- package/src/orchestrator/run.ts +25 -23
- package/src/report/logger.ts +5 -2
- package/src/report/summary.ts +6 -4
- package/src/util/index.ts +3 -0
- package/src/util/paths.ts +38 -4
- package/src/workspace/config-eval.ts +2 -2
- package/src/workspace/project-loader.ts +5 -4
package/docs/caching.md
CHANGED
|
@@ -399,12 +399,26 @@ On a hit:
|
|
|
399
399
|
clock (4 ms at HZ=250), so a same-size rewrite inside the tick of
|
|
400
400
|
vx's own write, in place or as a new file that took the same inode,
|
|
401
401
|
with its mtime forged back, still matches.
|
|
402
|
-
3. Otherwise the
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
`
|
|
406
|
-
|
|
407
|
-
|
|
402
|
+
3. Otherwise the `outputs/<rel>` (+ `workspace-outputs/<rel>`) entries
|
|
403
|
+
are extracted from the artifact (its bytes inline in the index, read
|
|
404
|
+
in one read transaction with the entry's rows, or
|
|
405
|
+
`<cacheDir>/<hash>.tar.zst`) **in place**: every entry is staged in
|
|
406
|
+
the workspace's `.vx/tmp/` (never an output folder), and only once the
|
|
407
|
+
whole archive has staged is each renamed over the file it replaces. A
|
|
408
|
+
file that already holds the entry's bytes (compared byte for byte, up
|
|
409
|
+
to 4 MiB) is left in place, only its mode and mtime set. A
|
|
410
|
+
target on another filesystem goes through a temp beside it; a file
|
|
411
|
+
takes the group its directory gives new files (setgid on Linux, any
|
|
412
|
+
directory on macOS), ACLs are not copied. The next run removes
|
|
413
|
+
the staging a killed run left. A process reading the output tree during the
|
|
414
|
+
restore never finds a declared output missing or half-written, and a
|
|
415
|
+
restore that fails first (a full disk, a damaged entry) leaves the
|
|
416
|
+
outputs as they were. Then the declared outputs the entry does not
|
|
417
|
+
hold are removed — see
|
|
418
|
+
[§ Strict output ownership](#strict-output-ownership). Only a found
|
|
419
|
+
output that blocks a rename (a file where the entry needs a directory,
|
|
420
|
+
or the reverse) goes before. Turbo also restores in place; Nx deletes
|
|
421
|
+
and copies each file, and a reader meets a missing or short file.
|
|
408
422
|
4. Captured stdout is replayed to the live terminal via the logger —
|
|
409
423
|
the framed block looks like a fresh run. (stderr is not cached —
|
|
410
424
|
only successful runs are cached and their stderr is near-always
|
|
@@ -483,10 +497,11 @@ the glob matches (a tracked output, a directory a `!` rule takes back);
|
|
|
483
497
|
anything git cannot answer keeps the key late. Undeclared writes, an
|
|
484
498
|
`outputs.workspaceFiles` producer upstream, a rewriter the key does not
|
|
485
499
|
fold, and runtime probes after a writer still leave a key preliminary.
|
|
486
|
-
|
|
487
|
-
short-circuit
|
|
488
|
-
|
|
489
|
-
|
|
500
|
+
With a
|
|
501
|
+
remote declared the short-circuit probes the local store alone, so a
|
|
502
|
+
local hit still restores ahead of its dependencies and no remote GET
|
|
503
|
+
sits on the critical path (remote prefetch asks the remote for the
|
|
504
|
+
rest). It never fires with local reads off or on a local cache
|
|
490
505
|
that holds no artifact (`Cache.holdsNothing`: every probe would miss,
|
|
491
506
|
and a cold 1,090-package run started its first task ~90 ms sooner
|
|
492
507
|
without it), and never throws —
|
|
@@ -822,7 +837,7 @@ the run (`tests/runner.test.ts`) — and the save resolves the output
|
|
|
822
837
|
globs at once. A descendant the command detached (`setsid … &`, a
|
|
823
838
|
daemon) that writes after that is not in the artifact: the entry saves
|
|
824
839
|
what was there, often nothing (with the `cache.outputs matched no
|
|
825
|
-
files` line), and the next hit's
|
|
840
|
+
files` line), and the next hit's restore removes what the
|
|
826
841
|
descendant wrote and restores the saved entry in its place (upstream
|
|
827
842
|
survey, turborepo#12786). vx does not wait for it and cannot see it: a
|
|
828
843
|
process that left the task's session is outside the process group vx
|
|
@@ -849,14 +864,15 @@ Declared `cache.outputs.files` are wiped in two distinct places:
|
|
|
849
864
|
- **Before exec on a cache miss.** A leftover `dist/old.js` from a
|
|
850
865
|
prior build can't survive into a fresh build that doesn't rewrite
|
|
851
866
|
it.
|
|
852
|
-
- **
|
|
853
|
-
cached snapshot byte-for-byte
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
867
|
+
- **After restore on a cache hit.** The post-restore tree is the
|
|
868
|
+
cached snapshot byte-for-byte: the restore renames the entry's files
|
|
869
|
+
over the ones it finds, then removes what the entry does not hold.
|
|
870
|
+
Hand-edits to output files don't persist through a cache replay. When
|
|
871
|
+
the hit's own check walked the output globs to find the tree stale,
|
|
872
|
+
the removal uses that walk's list instead of walking again (X-161).
|
|
873
|
+
|
|
874
|
+
Both use the same helpers (`cleanOutputs`, `cleanOutputPaths` in
|
|
875
|
+
`src/cache/inputs.ts`) with the same boundary rules, and vx's own paths stay off the wipe
|
|
860
876
|
whatever the glob: `.git`, `.vx` and each `vx.lock.json` (`OUTPUT_NEVER`;
|
|
861
877
|
`.vx` holds the workspace config and the lock, which a clean deleted and a
|
|
862
878
|
hit restored stale while `.vx/cache` alone was listed). `node_modules` is
|
|
@@ -889,7 +905,7 @@ Skipped when:
|
|
|
889
905
|
`.tsbuildinfo`). You opt out of the clean-tree guarantee: the save
|
|
890
906
|
stores every file the outputs match after the run, so a leftover from
|
|
891
907
|
an older build is cached and restored everywhere. A retry cleans as
|
|
892
|
-
usual; a hit still
|
|
908
|
+
usual; a hit's restore still removes what its entry does not hold.
|
|
893
909
|
|
|
894
910
|
A declared output the process cannot remove (a `dist/` another user
|
|
895
911
|
wrote, a read-only checkout) fails the task with `cannot remove declared
|
|
@@ -1333,8 +1349,9 @@ pax `path`/`size`, GNU long names, header checksums, truncation; an
|
|
|
1333
1349
|
extended header (read whole) past 1 MiB or a pax `size` that is not a
|
|
1334
1350
|
whole number is refused as corrupt, since a 1 GiB pax header costs 2 GiB
|
|
1335
1351
|
of memory from a ~32 KB artifact — and
|
|
1336
|
-
every regular entry is written
|
|
1337
|
-
|
|
1352
|
+
every regular entry is written to the workspace's `.vx/tmp/<pid>-0/`
|
|
1353
|
+
(vx's own, ignored by git, never an output folder) and renamed over its
|
|
1354
|
+
target only after the whole archive has ended cleanly and
|
|
1338
1355
|
the index's recorded outputs are all present. vx itself holds one
|
|
1339
1356
|
chunk of the tar at a time (measured 2026-09-03, incompressible
|
|
1340
1357
|
artifacts, fresh process: 150 MiB peaked at +644 MiB through
|
|
@@ -1413,7 +1430,14 @@ them, `CacheGetContext.outputs`), and never when it holds one path as a
|
|
|
1413
1430
|
file and a directory at once. Either used to reach the tree, an input
|
|
1414
1431
|
overwritten or a `.git/hooks` file planted under a green
|
|
1415
1432
|
`cache-hit-remote`, or a restore that failed every later run from the
|
|
1416
|
-
local copy (item 942); now the read is a miss and the task runs.
|
|
1433
|
+
local copy (item 942); now the read is a miss and the task runs. Every
|
|
1434
|
+
restore asks the same of the local copy, whatever route it reached the
|
|
1435
|
+
store by: an entry outside the declared outputs, one a `!` entry takes
|
|
1436
|
+
back, one under `.git`, `.vx` or a `vx.lock.json`, or one under a
|
|
1437
|
+
`node_modules` no output glob names fails the whole restore before
|
|
1438
|
+
anything is written; the entry is dropped and the task runs. Remote
|
|
1439
|
+
execution (`@vzn/vx-reapi`) writes a remote action's outputs through the
|
|
1440
|
+
same gate (`restorableOutput`). On the save side a
|
|
1417
1441
|
**symlinked output** is captured as its target's bytes and comes back
|
|
1418
1442
|
as a regular file (a hit that finds the task's own link still current
|
|
1419
1443
|
leaves it); a link to a directory, or a dangling one, has no bytes to
|
package/docs/cli.md
CHANGED
|
@@ -37,7 +37,7 @@ vx show [PROJECT[#TASK] | TASK] [--filter <pattern>] [--affected[=<ref>]] [--for
|
|
|
37
37
|
vx info [--format pretty|json] [--cache-dir <path>]
|
|
38
38
|
vx why (TASK | PKG#TASK) [--run RUNID] [--format pretty|json] [--cache-dir <path>]
|
|
39
39
|
vx last [RUNID] [--list[=N]] [--failed] [--log <task>] [--stats [<task>] [--branch <name>]] [--format pretty|json] [--cache-dir <path>]
|
|
40
|
-
vx upgrade [TAG]
|
|
40
|
+
vx upgrade [TAG] [-g|--global]
|
|
41
41
|
vx docs <query> [--limit N] [--format pretty|json]
|
|
42
42
|
vx completions bash|zsh|fish
|
|
43
43
|
|
|
@@ -1243,8 +1243,7 @@ run...` precedes it.
|
|
|
1243
1243
|
which reads what it likes, item 947, outside any project nested
|
|
1244
1244
|
in it; a write the last cycle made is not, read off the later of
|
|
1245
1245
|
its mtime and ctime, so an output a cache hit restores with its
|
|
1246
|
-
saved mtime is the run's,
|
|
1247
|
-
file, `watch-restored-output.test.ts`) — or declared an
|
|
1246
|
+
saved mtime is the run's, `watch-restored-output.test.ts`) — or declared an
|
|
1248
1247
|
output, or the loop re-runs on it; after three such cycles in a row
|
|
1249
1248
|
watch names the path and the remedy, once, and keeps going. A dev
|
|
1250
1249
|
server the last cycle left running counts as that cycle for as long
|
|
@@ -1305,8 +1304,8 @@ Always ignored (no re-trigger):
|
|
|
1305
1304
|
tracked + untracked-not-ignored — so a cycle it started could change
|
|
1306
1305
|
nothing. A tracked file that matches a pattern is not ignored, by
|
|
1307
1306
|
git's own rule; outside a repository nothing is.
|
|
1308
|
-
- Files ending in `~` (editor swap files), and
|
|
1309
|
-
|
|
1307
|
+
- Files ending in `~` (editor swap files), and `.vx/tmp/`, where
|
|
1308
|
+
restores stage.
|
|
1310
1309
|
- The run's **resolved cache directory**, wherever it is. `.vx/cache/` covers the
|
|
1311
1310
|
default, but `defineWorkspace({ cache: { dir } })` and `--cache-dir` can put it
|
|
1312
1311
|
anywhere; watching it would let vx's own cache writes trigger the next
|
|
@@ -1906,6 +1905,12 @@ project that fails leaves the global as it was. The project's vx run
|
|
|
1906
1905
|
directly (a package script, `node_modules/.bin/vx`) has no global behind it, so only
|
|
1907
1906
|
the project moves.
|
|
1908
1907
|
|
|
1908
|
+
**`vx upgrade -g`** (`--global`) moves only the global vx, wherever it
|
|
1909
|
+
runs: it never hands the call to a project's vx, and it never touches a
|
|
1910
|
+
`package.json` or a plugin. Run as the project's own vx, it refuses:
|
|
1911
|
+
`vx upgrade -g: no global vx ran — <path> is the project's own. Install
|
|
1912
|
+
one (npm install -g @vzn/vx), or run \`vx upgrade\` to move the project's`.
|
|
1913
|
+
|
|
1909
1914
|
```
|
|
1910
1915
|
› vx upgrade project 0.0.1 → 0.0.2
|
|
1911
1916
|
|
package/docs/execution.md
CHANGED
|
@@ -174,12 +174,13 @@ terminal and a task succeeding or failing. Read it alongside
|
|
|
174
174
|
│ overlap is the point); drained before cache.close(). At most
|
|
175
175
|
│ one remote GET per key (shared in-flight map with the lazy
|
|
176
176
|
│ read-through).
|
|
177
|
-
│ • LOCAL SHORT-CIRCUIT (
|
|
178
|
-
│
|
|
179
|
-
│
|
|
180
|
-
│
|
|
181
|
-
│
|
|
182
|
-
│ set (confirmed hits). Awaited
|
|
177
|
+
│ • LOCAL SHORT-CIRCUIT (local reads on, ≥1 task) — derive the
|
|
178
|
+
│ same stable keys and probe the LOCAL store in ONE batched
|
|
179
|
+
│ getMany (a layer without getMany: get once per task under a
|
|
180
|
+
│ bounded pool) → a `preProbed` map (hits AND stable misses;
|
|
181
|
+
│ with a remote declared, hits only: a local miss may be a
|
|
182
|
+
│ remote hit) + a `restoreTier` set (confirmed hits). Awaited
|
|
183
|
+
│ before scheduling; never asks a remote; never throws
|
|
183
184
|
│ (degrades to the normal schedule).
|
|
184
185
|
│
|
|
185
186
|
├─ Scheduling (src/graph/scheduler.ts:runGraph — two-tier)
|
package/docs/features.md
CHANGED
|
@@ -121,7 +121,7 @@ config key or an environment variable is missing here.
|
|
|
121
121
|
- **Interactive tasks** (`exec.interactive`) — a task that owns the terminal. [page](https://vznjs.github.io/vx/features/interactive-tasks/) · post: [When a task misbehaves](https://vznjs.github.io/vx/blog/tasks-that-misbehave/)
|
|
122
122
|
- **Shell completions** (`vx completions`) — bash, zsh, fish. [page](https://vznjs.github.io/vx/features/completions/) · post: [The small things](https://vznjs.github.io/vx/blog/the-small-things/)
|
|
123
123
|
- **Project-local vx** (`VX_HANDED_OFF`) — a global vx hands every call to the project's own `@vzn/vx`. [page](https://vznjs.github.io/vx/cli/#which-vx-runs)
|
|
124
|
-
- **vx upgrade** (`vx upgrade`) — upgrade vx the way it was installed: a verified binary, or its package manager. Inside a project, the project's vx, its `@vzn/vx-*` plugins (one install, one release) and the global vx that ran it move together. [page](https://vznjs.github.io/vx/features/upgrade/) · post: [An upgrade you can trust](https://vznjs.github.io/vx/blog/upgrade-you-can-trust/)
|
|
124
|
+
- **vx upgrade** (`vx upgrade`) — upgrade vx the way it was installed: a verified binary, or its package manager. Inside a project, the project's vx, its `@vzn/vx-*` plugins (one install, one release) and the global vx that ran it move together; `vx upgrade -g` moves only the global. [page](https://vznjs.github.io/vx/features/upgrade/) · post: [An upgrade you can trust](https://vznjs.github.io/vx/blog/upgrade-you-can-trust/)
|
|
125
125
|
- **Help and version** (`vx help`, `vx version`) — every verb's reference. [page](https://vznjs.github.io/vx/features/help-and-version/) · post: [An upgrade you can trust](https://vznjs.github.io/vx/blog/upgrade-you-can-trust/)
|
|
126
126
|
- **Did-you-mean** — a mistyped flag or verb gets the nearest valid spelling. [page](https://vznjs.github.io/vx/features/did-you-mean/) · post: [The small things](https://vznjs.github.io/vx/blog/the-small-things/)
|
|
127
127
|
- **Task typed as a verb** — `vx build app` answers with the exact `vx run` command that does it. [page](https://vznjs.github.io/vx/features/task-as-verb/) · post: [The small things](https://vznjs.github.io/vx/blog/the-small-things/)
|
package/docs/schema.md
CHANGED
|
@@ -822,19 +822,25 @@ Always applied to every glob pass (regardless of what you wrote):
|
|
|
822
822
|
`.cache/gen/**`), which is then walked on disk under that prefix only.
|
|
823
823
|
Such a file is hashed from disk and never stored or restored; a
|
|
824
824
|
missing one is not an input until it exists. A broad glob (`**`,
|
|
825
|
-
`src/**` over a listed `src`) still skips ignored files, so
|
|
826
|
-
`node_modules
|
|
825
|
+
`src/**` over a listed `src`) still skips ignored files, so it never
|
|
826
|
+
walks `node_modules`.
|
|
827
827
|
Its bytes differ per machine, so machines with different files miss
|
|
828
828
|
each other's shared entries. An ignored file never selects a task
|
|
829
829
|
under `--affected` on its own, as in Nx (only what git sees does); `vx
|
|
830
830
|
watch` re-runs it on an edit there.
|
|
831
831
|
- **Always-ignored** — `.git/**`, `.vx/cache/**`,
|
|
832
|
-
`.vx/projects.lock.json`, `vx.lock.json`,
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
832
|
+
`.vx/projects.lock.json`, `vx.lock.json`, and `.vx/tmp/**`, where vx's
|
|
833
|
+
restores stage, at any depth. Nothing else: a tool's temp files are the
|
|
834
|
+
task's to exclude. A broad glob on a `bun build --compile` task, or on
|
|
835
|
+
one that runs beside it, excludes Bun's intermediate and its
|
|
836
|
+
cross-compile extraction directory itself:
|
|
837
|
+
`['**/*', '!**/*.bun-build', '!**/.????????????????-????????.tmp/**']`.
|
|
838
|
+
- **Installs** — an untracked file under any `node_modules/` that git
|
|
839
|
+
does not ignore. An ignored one follows the gitignore filter above
|
|
840
|
+
like any other ignored path: named outright, it is an input
|
|
841
|
+
(`node_modules/.prisma/client/**`, a generated client); a broad glob
|
|
842
|
+
skips it because it is ignored. A file git TRACKS there, such as a committed test fixture, is an input
|
|
843
|
+
like any other.
|
|
838
844
|
- **Declared `outputs.files`** are excluded — a task never invalidates
|
|
839
845
|
itself via its own output. A path an output `!` entry takes back is
|
|
840
846
|
no output, so it stays an input (A-44). Another task's outputs are
|
|
@@ -887,7 +893,7 @@ backslash separator (`src\**`, `src\*.ts`) or a drive (`C:\src\**`,
|
|
|
887
893
|
backslash stays an escape.
|
|
888
894
|
|
|
889
895
|
Still applied: the always-ignored set (`.git/**`, `.vx/cache/**`,
|
|
890
|
-
`.vx/projects.lock.json`, `vx.lock.json`,
|
|
896
|
+
`.vx/projects.lock.json`, `vx.lock.json`, `.vx/tmp/**`),
|
|
891
897
|
untracked files under `node_modules/`, and the task's own declared
|
|
892
898
|
outputs, `outputs.workspaceFiles` and the `outputs.files` its globs reach
|
|
893
899
|
in its own project (a task never invalidates itself).
|
|
@@ -1666,8 +1672,9 @@ The loader rejects:
|
|
|
1666
1672
|
|
|
1667
1673
|
Loaded from `.vx/workspace.{ts,mts,js,mjs,cts,cjs}`: the directory holding
|
|
1668
1674
|
`.vx` is the workspace root. `.vx` also holds the lock (`.vx/projects.lock.json`)
|
|
1669
|
-
|
|
1670
|
-
|
|
1675
|
+
`.vx/cache`, the machine-local state (the cache, the workspace id), and
|
|
1676
|
+
`.vx/tmp`, where a restore stages files; git ignores only those two:
|
|
1677
|
+
`.vx/.gitignore` says `/cache` and `/tmp`. Every field falls back to its
|
|
1671
1678
|
built-in default.
|
|
1672
1679
|
|
|
1673
1680
|
```ts
|
|
@@ -1827,7 +1834,7 @@ interface CacheSettings {
|
|
|
1827
1834
|
workspace (`'..'`, `'/'`) is refused before anything is written, since its `*`
|
|
1828
1835
|
`.gitignore` would hide the sources from git and the cache keys. A
|
|
1829
1836
|
directory other than the default `.vx/cache` gets that `*` `.gitignore`;
|
|
1830
|
-
the default is ignored by `.vx/.gitignore` (`/cache`) instead, written
|
|
1837
|
+
the default is ignored by `.vx/.gitignore` (`/cache`, `/tmp`) instead, written
|
|
1831
1838
|
when missing and never edited.
|
|
1832
1839
|
- **`cache.retention`** — the `vx cache clean` policy, applied at the
|
|
1833
1840
|
end of every run: entries unused for
|
package/docs/security.md
CHANGED
|
@@ -45,9 +45,10 @@ vulnerability), never in a public issue.
|
|
|
45
45
|
choosing is trusted as a writer, as it is in every action cache. Use a
|
|
46
46
|
store only your builds write to, or `turboCache()`'s signature key,
|
|
47
47
|
which refuses an artifact a keyholder did not sign. A job you do not
|
|
48
|
-
trust (a fork's pull request) reads at most: `--cache-policy=local:rw,remote:r
|
|
49
|
-
or
|
|
50
|
-
|
|
48
|
+
trust (a fork's pull request) reads at most: `--cache-policy=local:rw,remote:r`
|
|
49
|
+
or `cache.policy`. Core's policy alone decides; a cache plugin reads no
|
|
50
|
+
tool's own switch (`TURBO_CACHE`, `NX_SKIP_REMOTE_CACHE`) and cannot
|
|
51
|
+
narrow it.
|
|
51
52
|
|
|
52
53
|
## Cache poisoning
|
|
53
54
|
|
package/launcher.sh
CHANGED
|
@@ -35,8 +35,15 @@ scope=${scope##*/}
|
|
|
35
35
|
# directory up to the git top-level (handoff.ts workspaceFile, the same
|
|
36
36
|
# rule). One hop (VX_HANDED_OFF, which also names this launcher), never to
|
|
37
37
|
# this package itself (`-ef`: same inode, so a pnpm symlink counts as
|
|
38
|
-
# itself). Shell tests and builtins only, no fork per level.
|
|
39
|
-
|
|
38
|
+
# itself). Shell tests and builtins only, no fork per level. `vx upgrade -g`
|
|
39
|
+
# moves only this global vx, so it never hands off (owner, 2026-10-16).
|
|
40
|
+
stay=
|
|
41
|
+
if [ "${1-}" = upgrade ]; then
|
|
42
|
+
for a in "$@"; do
|
|
43
|
+
case $a in -g | --global) stay=1 ;; esac
|
|
44
|
+
done
|
|
45
|
+
fi
|
|
46
|
+
if [ -z "${VX_HANDED_OFF-}" ] && [ -z "$stay" ]; then
|
|
40
47
|
d=$PWD
|
|
41
48
|
while :; do
|
|
42
49
|
root=
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vzn/vx",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.641",
|
|
4
4
|
"description": "Task orchestration you own: correct, sandboxed, extensible, with a content-addressed build cache.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -21,10 +21,10 @@
|
|
|
21
21
|
"node": ">=18"
|
|
22
22
|
},
|
|
23
23
|
"optionalDependencies": {
|
|
24
|
-
"@vzn/vx-linux-x64": "0.0.
|
|
25
|
-
"@vzn/vx-linux-arm64": "0.0.
|
|
26
|
-
"@vzn/vx-darwin-x64": "0.0.
|
|
27
|
-
"@vzn/vx-darwin-arm64": "0.0.
|
|
24
|
+
"@vzn/vx-linux-x64": "0.0.641",
|
|
25
|
+
"@vzn/vx-linux-arm64": "0.0.641",
|
|
26
|
+
"@vzn/vx-darwin-x64": "0.0.641",
|
|
27
|
+
"@vzn/vx-darwin-arm64": "0.0.641"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@anthropic-ai/sandbox-runtime": "^0.0.76"
|
package/src/bin.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env -S bun --no-env-file --no-install
|
|
2
2
|
// Wrapped in an explicit async main so `bun build --compile` accepts
|
|
3
3
|
// the file. The compile target doesn't allow top-level await.
|
|
4
|
-
import { handOff, localVx, vxPath } from './handoff.js'
|
|
4
|
+
import { handOff, localVx, upgradesOnlyItself, vxPath } from './handoff.js'
|
|
5
5
|
|
|
6
6
|
let settled = false
|
|
7
7
|
|
|
@@ -10,11 +10,13 @@ async function main(): Promise<void> {
|
|
|
10
10
|
try {
|
|
11
11
|
// Inside the try: `process.cwd()` throws EMFILE when out of descriptors,
|
|
12
12
|
// and that is a one-line UserError below, not a stack.
|
|
13
|
-
const local =
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
const local = upgradesOnlyItself(argv)
|
|
14
|
+
? null
|
|
15
|
+
: await localVx(
|
|
16
|
+
process.cwd(),
|
|
17
|
+
process.execPath,
|
|
18
|
+
Bun.main.startsWith('/$bunfs') || (process.argv[1] ?? '').startsWith('/$bunfs'),
|
|
19
|
+
)
|
|
18
20
|
if (local !== null) await handOff(local, argv)
|
|
19
21
|
// `vx --version` needs one leaf module; the dispatcher and the util
|
|
20
22
|
// barrel it pulled in were 20 ms of its 28 (2026-10-01).
|