@vzn/vx 0.0.636 → 0.0.637
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/README.md +39 -11
- package/docs/caching.md +213 -207
- package/docs/cli.md +699 -655
- package/docs/execution.md +67 -75
- package/docs/features.md +44 -40
- package/docs/patterns.md +26 -25
- package/docs/schema.md +376 -198
- package/docs/security.md +76 -39
- package/launcher.sh +43 -0
- package/package.json +5 -5
- package/schemas/cache.json +41 -19
- package/schemas/info.json +23 -11
- package/schemas/last.json +48 -2
- package/schemas/lock.json +1 -1
- package/schemas/plan.json +2 -2
- package/schemas/show.json +5 -3
- package/schemas/why.json +15 -1
- package/skills/vx/SKILL.md +16 -12
- package/src/bin.ts +17 -2
- package/src/cache/archive.ts +11 -0
- package/src/cache/cache.ts +105 -53
- package/src/cache/git-inputs.ts +277 -63
- package/src/cache/index.ts +7 -1
- package/src/cache/inputs.ts +125 -35
- package/src/cache/key-fold.ts +8 -7
- package/src/cache/layer.ts +8 -17
- package/src/cache/layered-cache.ts +16 -102
- package/src/cache/policy.ts +25 -29
- package/src/cache/run-history.ts +36 -14
- package/src/cache/schema.ts +21 -23
- package/src/cache/scoped-cache.ts +224 -0
- package/src/cli/cache.ts +150 -28
- package/src/cli/completions.ts +2 -2
- package/src/cli/core-alias.ts +1 -1
- package/src/cli/foreign-flags.ts +13 -12
- package/src/cli/help.ts +94 -63
- package/src/cli/index.ts +42 -13
- package/src/cli/info.ts +38 -23
- package/src/cli/init.ts +115 -406
- package/src/cli/last.ts +145 -4
- package/src/cli/lock.ts +333 -111
- package/src/cli/plan-format.ts +2 -2
- package/src/cli/plugin-commands.ts +5 -9
- package/src/cli/plugin-templates.ts +10 -10
- package/src/cli/run.ts +103 -149
- package/src/cli/select.ts +33 -39
- package/src/cli/show.ts +17 -19
- package/src/cli/task-verb.ts +2 -9
- package/src/cli/upgrade.ts +402 -145
- package/src/cli/watch-cycle.ts +9 -2
- package/src/cli/watch-filter.ts +33 -60
- package/src/cli/watch-fs.ts +29 -16
- package/src/cli/watch-judge.ts +12 -3
- package/src/cli/watch-set.ts +16 -42
- package/src/cli/watch.ts +188 -215
- package/src/cli/why.ts +28 -17
- package/src/cli/workspace-config.ts +31 -68
- package/src/config.ts +169 -70
- package/src/exec/env.ts +1 -31
- package/src/exec/executor.ts +1 -5
- package/src/exec/kill-tree.ts +2 -1
- package/src/exec/sandbox-runtime.ts +12 -1
- package/src/exec/sandbox-violations.ts +9 -1
- package/src/graph/dependency-spec.ts +1 -1
- package/src/graph/index.ts +1 -0
- package/src/graph/priorities.ts +1 -1
- package/src/graph/scheduler.ts +19 -7
- package/src/graph/task-graph.ts +44 -20
- package/src/handoff.ts +169 -0
- package/src/index.ts +24 -57
- package/src/orchestrator/affected-tasks.ts +7 -5
- package/src/orchestrator/command-windows.ts +44 -0
- package/src/orchestrator/deferred-outputs.ts +12 -10
- package/src/orchestrator/doctor.ts +98 -110
- package/src/orchestrator/download-policy.ts +3 -3
- package/src/orchestrator/events.ts +19 -3
- package/src/orchestrator/excluded-keys.ts +0 -2
- package/src/orchestrator/execute-task.ts +158 -63
- package/src/orchestrator/fingerprint-watch.ts +18 -15
- package/src/orchestrator/forecast.ts +10 -2
- package/src/orchestrator/framed-output.ts +8 -3
- package/src/orchestrator/graph-stage.ts +5 -5
- package/src/orchestrator/history.ts +70 -30
- package/src/orchestrator/hit-restore.ts +15 -3
- package/src/orchestrator/index.ts +18 -4
- package/src/orchestrator/local-shortcircuit.ts +2 -1
- package/src/orchestrator/lockfile-claim.ts +79 -20
- package/src/orchestrator/logger.ts +71 -39
- package/src/orchestrator/metrics.ts +71 -6
- package/src/orchestrator/miss-save.ts +3 -0
- package/src/orchestrator/options.ts +42 -29
- package/src/orchestrator/output-host.ts +72 -0
- package/src/orchestrator/plan.ts +6 -8
- package/src/orchestrator/plugin-host.ts +87 -63
- package/src/orchestrator/plugin.ts +94 -60
- package/src/orchestrator/prepare.ts +113 -72
- package/src/orchestrator/projects.ts +102 -99
- package/src/orchestrator/remote-prefetch.ts +2 -1
- package/src/orchestrator/run-context.ts +25 -6
- package/src/orchestrator/run-failures.ts +17 -8
- package/src/orchestrator/run-lock.ts +1 -1
- package/src/orchestrator/run-report.ts +9 -9
- package/src/orchestrator/run-settings.ts +48 -0
- package/src/orchestrator/run.ts +121 -95
- package/src/orchestrator/sandbox-fix.ts +39 -20
- package/src/orchestrator/sandbox-request.ts +84 -13
- package/src/orchestrator/signals.ts +1 -1
- package/src/orchestrator/stable-keys.ts +13 -11
- package/src/orchestrator/status-line.ts +48 -6
- package/src/orchestrator/summary.ts +46 -62
- package/src/orchestrator/task-hash.ts +12 -83
- package/src/orchestrator/telemetry.ts +3 -3
- package/src/settings.ts +417 -0
- package/src/util/errors.ts +1 -1
- package/src/util/essential-env.ts +31 -0
- package/src/util/hide-env.ts +107 -0
- package/src/util/index.ts +8 -2
- package/src/util/paths.ts +10 -0
- package/src/util/settle.ts +49 -30
- package/src/util/size.ts +23 -4
- package/src/util/timing.ts +3 -2
- package/src/util/ulid.ts +1 -1
- package/src/util/verbs.ts +0 -15
- package/src/workspace/affected.ts +77 -222
- package/src/workspace/config-eval.ts +15 -20
- package/src/workspace/config-imports.ts +78 -3
- package/src/workspace/config-schema.ts +209 -268
- package/src/workspace/dependency-rules.ts +57 -0
- package/src/workspace/filter.ts +2 -2
- package/src/workspace/fingerprint.ts +11 -121
- package/src/workspace/index.ts +20 -27
- package/src/workspace/load-reads.ts +4 -4
- package/src/workspace/lockfile.ts +96 -140
- package/src/workspace/migration.ts +242 -146
- package/src/workspace/package-graph.ts +30 -216
- package/src/workspace/project-loader.ts +80 -285
- package/src/workspace/repo-id.ts +2 -1
- package/src/workspace/workspace.ts +362 -831
- package/src/cache/config-evals.ts +0 -130
- package/src/workspace/config-cache.ts +0 -661
- package/src/workspace/migrate-scripts.ts +0 -1121
package/docs/security.md
CHANGED
|
@@ -8,12 +8,31 @@ vulnerability), never in a public issue.
|
|
|
8
8
|
|
|
9
9
|
## What vx trusts
|
|
10
10
|
|
|
11
|
-
- **Your configs.** `vx.config.ts` and
|
|
11
|
+
- **Your configs.** `vx.config.ts` and `.vx/workspace.ts` are programs vx
|
|
12
12
|
runs in its own process. A config can do anything you can: vx
|
|
13
|
-
validates what it returns, not what it does.
|
|
13
|
+
validates what it returns, not what it does. The workspace root is
|
|
14
|
+
the nearest `.vx/workspace.*`, and vx never looks for it above the git
|
|
15
|
+
top-level, so a file planted in a shared directory such as `/tmp`
|
|
16
|
+
cannot claim your checkout and run as you. Outside git, one another
|
|
17
|
+
user owns is refused, root aside, judged by the file itself (a link,
|
|
18
|
+
not what it names) and its `.vx` (`tests/workspace-root-file.test.ts`).
|
|
19
|
+
No task output reaches `.vx` or a `vx.lock.json`: a clean never deletes
|
|
20
|
+
them and a hit never restores them (`tests/output-never-dotvx.test.ts`).
|
|
21
|
+
What a config imports
|
|
14
22
|
must already be installed: vx runs Bun with `--no-install`, so an
|
|
15
23
|
import no `node_modules` provides is refused, never fetched from the
|
|
16
24
|
registry (L-22).
|
|
25
|
+
- **Your projects lock.** A run executes `.vx/projects.lock.json` as
|
|
26
|
+
written and never re-evaluates or re-validates it, so the lock is code
|
|
27
|
+
too. It is minified and marked generated, which collapses it in a
|
|
28
|
+
pull request's diff: a change to it alone changes what runs while every
|
|
29
|
+
config and `vx.lock.json` reads the same. Run `vx lock --check` in CI
|
|
30
|
+
before anything else; it fails on any entry that differs from what its
|
|
31
|
+
config evaluates to and on one with no config (`tests/lock.test.ts`).
|
|
32
|
+
- **Your project's own vx.** A global vx hands every call to the
|
|
33
|
+
workspace root's `node_modules/.bin/vx` (cli.md § Which vx runs), so even
|
|
34
|
+
`vx --version` in a repo you do not trust runs that repo's code. One
|
|
35
|
+
another user owns is never run.
|
|
17
36
|
- **Your plugins.** A plugin is code you imported. It runs in vx's
|
|
18
37
|
process with a config's reach; vx checks the shape of what it hands
|
|
19
38
|
back and isolates a telemetry plugin's failures, nothing more.
|
|
@@ -26,7 +45,7 @@ vulnerability), never in a public issue.
|
|
|
26
45
|
choosing is trusted as a writer, as it is in every action cache. Use a
|
|
27
46
|
store only your builds write to, or `turboCache()`'s signature key,
|
|
28
47
|
which refuses an artifact a keyholder did not sign. A job you do not
|
|
29
|
-
trust (a fork's pull request) reads at most: `--cache=local:rw,remote:r`,
|
|
48
|
+
trust (a fork's pull request) reads at most: `--cache-policy=local:rw,remote:r`,
|
|
30
49
|
or the tools' own `TURBO_REMOTE_CACHE_READ_ONLY`, `TURBO_CACHE` and
|
|
31
50
|
`NX_SKIP_REMOTE_CACHE`, which the cache plugins honour (L-34).
|
|
32
51
|
|
|
@@ -35,14 +54,20 @@ vulnerability), never in a public issue.
|
|
|
35
54
|
A pull request that can write the cache the default branch reads can
|
|
36
55
|
plant bytes main later replays (CREEP, CVE-2025-36852). The boundary is
|
|
37
56
|
the credential, enforced by the cache server: the default branch's job
|
|
38
|
-
holds a token that writes the
|
|
57
|
+
holds a token that writes the default keys, and a pull request's job
|
|
39
58
|
holds one that cannot (read-only, or confined by the server to its own
|
|
40
59
|
namespace), or none.
|
|
41
60
|
|
|
42
|
-
`
|
|
43
|
-
then
|
|
44
|
-
Actions (`pr-<n>`, `ref-<name>`; the default branch
|
|
45
|
-
and `VX_CACHE_SCOPE` or `--cache-scope` sets on any CI.
|
|
61
|
+
`cache.scope` is the client half. `'pr-123'` reads the default keys,
|
|
62
|
+
then its own, and writes only its own, which `github()` sets on
|
|
63
|
+
Actions (`pr-<n>`, `ref-<name>`; the default branch sets none)
|
|
64
|
+
and `VX_CACHE_SCOPE` or `--cache-scope` sets on any CI. Whether a run
|
|
65
|
+
writes is `cache.policy`'s call: off CI the default reads the remote and
|
|
66
|
+
writes nothing, since a key holds only declared inputs and a laptop's
|
|
67
|
+
undeclared tool or file would replay on CI. A laptop that should never
|
|
68
|
+
write gets a read-only token too. The local cache follows the same
|
|
69
|
+
key rule, so on one disk a PR's entries sit under its scope's keys and
|
|
70
|
+
a persistent runner never serves them to main.
|
|
46
71
|
It keeps honest runs apart and stops a non-hermetic PR build from
|
|
47
72
|
landing where main reads; it is not a boundary, since the PR's own
|
|
48
73
|
config decides it and any run holding a write credential can write any
|
|
@@ -58,7 +83,7 @@ bazel-remote --dir /data --max_size 50 --grpc_address 0.0.0.0:9092 \
|
|
|
58
83
|
```
|
|
59
84
|
|
|
60
85
|
```ts
|
|
61
|
-
// vx
|
|
86
|
+
// .vx/workspace.ts: the header only where the secret is set
|
|
62
87
|
reapi({
|
|
63
88
|
endpoint: 'grpcs://cache.example.com:9092',
|
|
64
89
|
headers: process.env.CACHE_AUTH ? { authorization: `Basic ${process.env.CACHE_AUTH}` } : {},
|
|
@@ -114,7 +139,8 @@ the local store:
|
|
|
114
139
|
|
|
115
140
|
Remote execution (`@vzn/vx-reapi`) holds each blob to its digest, and
|
|
116
141
|
writes only the server's outputs a declared glob names, inside the
|
|
117
|
-
workspace, through no link that leads out of it
|
|
142
|
+
workspace, through no link that leads out of it, and through no link
|
|
143
|
+
into a place no declared glob names.
|
|
118
144
|
|
|
119
145
|
## What the sandbox stops
|
|
120
146
|
|
|
@@ -130,22 +156,45 @@ A task with `exec.sandbox` runs where only what it declares exists:
|
|
|
130
156
|
- its temp directory, port-bridge socket and trace log are its own
|
|
131
157
|
(mode 0700), unreachable from another task and another local user;
|
|
132
158
|
- the host's credential stores (`~/.ssh`, `~/.gnupg`, `~/.aws`,
|
|
133
|
-
`~/.npmrc`, `~/.netrc
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
159
|
+
`~/.npmrc`, `~/.netrc`, the token files of deploy and agent CLIs such
|
|
160
|
+
as Vercel, Wrangler, Fly or Claude, and the like; the list is in the
|
|
161
|
+
schema's sandbox section) are unreadable unless `allow.read` names one
|
|
162
|
+
(L-41), cannot be hard-linked into an output for vx to pack, and a denied read's `fix:` hint never suggests granting one
|
|
163
|
+
(`tests/sandbox-credential-stores.unsafe.test.ts`, `tests/sandbox-fix.test.ts`);
|
|
164
|
+
- vx's own cache directory, wherever `cache.dir` puts it in the
|
|
165
|
+
workspace, is a wall like `.vx/cache`: a broad grant stops at it, and a write
|
|
137
166
|
grant that would bind it is refused (L-24);
|
|
138
167
|
- a symlinked output must resolve inside its project: vx packs outputs
|
|
139
168
|
outside the sandbox, and a link to another project's file would have
|
|
140
169
|
carried that file into the cache (L-23). An output directory linked out
|
|
141
|
-
of the project refuses the task by name (X-88).
|
|
170
|
+
of the project refuses the task by name (X-88). Inside the project, a
|
|
171
|
+
link must name a file the task could read (a read or write grant, its
|
|
172
|
+
`node_modules`) or one of its own outputs, so `dist/x -> ../.env` under
|
|
173
|
+
`read: ['src/']` is refused, and Linux judges making the link by the
|
|
174
|
+
link, never its target (`tests/sandbox-output-link.unsafe.test.ts`).
|
|
175
|
+
- vx's own environment, which holds the variables a task is not given
|
|
176
|
+
(a token, a key), is unreadable: the task cannot see vx's
|
|
177
|
+
`/proc/<pid>/environ` on Linux or read it through `ps eww` on macOS
|
|
178
|
+
(`tests/sandbox-parent-env.unsafe.test.ts`).
|
|
142
179
|
|
|
143
180
|
An undeclared touch of the task's own files fails the task, and a failed
|
|
144
181
|
task is never cached. See [Sandboxing tasks](https://vznjs.github.io/vx/guides/sandboxing/).
|
|
145
182
|
|
|
183
|
+
The sandbox costs each task it runs; a cache hit runs nothing and costs
|
|
184
|
+
nothing. `tests/sandbox-parent-env.unsafe.test.ts` prints the cost of one
|
|
185
|
+
`true` task, min of 20, on every CI run. On GitHub-hosted runners on
|
|
186
|
+
2026-10-13 it printed +269 ms on Linux and +97 ms on macOS.
|
|
187
|
+
|
|
146
188
|
## What it does not stop
|
|
147
189
|
|
|
148
|
-
- **A task with no `exec.sandbox`.** It runs with your permissions
|
|
190
|
+
- **A task with no `exec.sandbox`.** It runs with your permissions:
|
|
191
|
+
it reads anything you can. vx hides its own environment from it on
|
|
192
|
+
every command: on Linux vx makes itself non-dumpable (about 0.8 ms), on
|
|
193
|
+
macOS it zeroes the values `ps eww` reads, every variable but the
|
|
194
|
+
essentials every task gets (about 0.7 ms). It starts its helpers with `PATH`
|
|
195
|
+
alone and each `git` with only what git reads
|
|
196
|
+
(`tests/hide-env.unsafe.test.ts`, `tests/git-env.test.ts`). That hides
|
|
197
|
+
the environment only, not files.
|
|
149
198
|
- **Reads outside the workspace root.** `~/.cache`, `/etc` and the like
|
|
150
199
|
stay readable (tools need them) and fold into no key. The credential
|
|
151
200
|
stores under home (`~/.ssh`, `~/.aws`, `~/.npmrc` and the like) are
|
|
@@ -156,24 +205,6 @@ task is never cached. See [Sandboxing tasks](https://vznjs.github.io/vx/guides/s
|
|
|
156
205
|
`weakerWhenNested` in a container, a task that itself sandboxes on
|
|
157
206
|
macOS. `vx info` says what the host supports.
|
|
158
207
|
|
|
159
|
-
## Agents (`vx mcp`)
|
|
160
|
-
|
|
161
|
-
An agent connected to `vx mcp` can do what `vx run` can do, nothing more.
|
|
162
|
-
Every tool but `runTasks` only reads. `runTasks` runs `vx run --format json`
|
|
163
|
-
as a child process: the agent names tasks and sets `all`, `force`,
|
|
164
|
-
`filter` and `affected`, and nothing else. A task name that starts with
|
|
165
|
-
`-` is refused, a filter goes as one `--filter=` value, and a ref reaches
|
|
166
|
-
git after `--end-of-options`, so no argument becomes a flag. The commands
|
|
167
|
-
that run are the ones your configs declare, from the workspace root, with
|
|
168
|
-
the environment `vx mcp` started with, filtered by each task's `exec.env`
|
|
169
|
-
and held by its `exec.sandbox`. `force` costs a rerun, not a wrong entry:
|
|
170
|
-
the key stays the same. What reaches the agent (summaries, refusals,
|
|
171
|
-
`getFailures` output) is masked as described under Secrets.
|
|
172
|
-
`mcp({ run: false })` takes `runTasks` away, and `mcp({ run: ['test'] })`
|
|
173
|
-
limits it to those task names. An agent that
|
|
174
|
-
can edit `vx.config.ts` can run anything, as you can, because configs are
|
|
175
|
-
code vx trusts.
|
|
176
|
-
|
|
177
208
|
## Secrets
|
|
178
209
|
|
|
179
210
|
The value, of 6 characters or more, of a variable whose name holds
|
|
@@ -183,7 +214,7 @@ task lists in `exec.env.secret`, and the password of a URL
|
|
|
183
214
|
(`scheme://user:<password>@`) in any variable's value, is printed as `***` wherever vx shows, stores or
|
|
184
215
|
exports it: task output, the stdout a hit replays, commands, an
|
|
185
216
|
executor's error, telemetry,
|
|
186
|
-
`vx show`
|
|
217
|
+
`vx show` (L-26). Values in the run history are digests under a per-store
|
|
187
218
|
salt, and what follows `--` on the command line reaches telemetry as a
|
|
188
219
|
count, not a quote, a secret before it masked (L-44). A remote executor (`@vzn/vx-reapi`) receives a
|
|
189
220
|
task's `exec.env.define` values and the `cache.inputs.env` values its
|
|
@@ -204,10 +235,16 @@ secret values: a name-based match would refuse public `*_KEY` values too.
|
|
|
204
235
|
|
|
205
236
|
Release binaries carry a build-provenance attestation
|
|
206
237
|
(`gh attestation verify vx-<target> --repo vznjs/vx`); `vx upgrade`
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
238
|
+
installs a binary only after npm's registry signature over the platform
|
|
239
|
+
package's `name@version:integrity` verifies against npm's key, pinned
|
|
240
|
+
in vx, and the tarball matches that integrity: the host that serves the
|
|
241
|
+
bytes cannot make the signature, so a swapped tarball is refused before
|
|
242
|
+
anything is written, and a key id vx does not pin is refused with a hint
|
|
243
|
+
that the installer needs updating (owner, 2026-10-13; pnpm's installer
|
|
244
|
+
checks the same). The new binary is staged in a fresh directory, never a
|
|
245
|
+
name another user could plant a link at. A vx a package manager
|
|
246
|
+
installed is upgraded by that manager, which checks its own integrity.
|
|
247
|
+
npm packages
|
|
211
248
|
publish with provenance; every third-party action in CI runs from a
|
|
212
249
|
full commit SHA; and a workflow hands an event's or a dispatcher's value
|
|
213
250
|
to a script through `env`, never pasted in (a release tag is checked as a
|
package/launcher.sh
CHANGED
|
@@ -29,6 +29,49 @@ base=${here##*/}
|
|
|
29
29
|
scope=${here%/*}
|
|
30
30
|
scope=${scope##*/}
|
|
31
31
|
|
|
32
|
+
# A global vx hands off to the project's own (owner, 2026-10-13): the
|
|
33
|
+
# workspace root's node_modules/<scope>/<name>, through its .bin entry. The
|
|
34
|
+
# root is the first directory holding a .vx/workspace.* from the working
|
|
35
|
+
# directory up to the git top-level (handoff.ts workspaceFile, the same
|
|
36
|
+
# rule). One hop (VX_HANDED_OFF, which also names this launcher), never to
|
|
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
|
+
if [ -z "${VX_HANDED_OFF-}" ]; then
|
|
40
|
+
d=$PWD
|
|
41
|
+
while :; do
|
|
42
|
+
root=
|
|
43
|
+
for ext in ts mts js mjs cts cjs; do
|
|
44
|
+
if [ -f "$d/.vx/workspace.$ext" ]; then
|
|
45
|
+
root=${d:-/}
|
|
46
|
+
break
|
|
47
|
+
fi
|
|
48
|
+
done
|
|
49
|
+
if [ -n "$root" ]; then
|
|
50
|
+
bin=$d/node_modules/.bin/$base
|
|
51
|
+
# -O: a vx another user planted would run as you.
|
|
52
|
+
if [ -d "$d/node_modules/$scope/$base" ] && [ ! "$d/node_modules/$scope/$base" -ef "$here" ] && [ -x "$bin" ] && [ -O "$bin" ]; then
|
|
53
|
+
VX_HANDED_OFF=$self
|
|
54
|
+
export VX_HANDED_OFF
|
|
55
|
+
exec "$bin" "$@"
|
|
56
|
+
fi
|
|
57
|
+
break
|
|
58
|
+
fi
|
|
59
|
+
[ -z "$d" ] && break
|
|
60
|
+
# A submodule's .git file points into its superproject's .git/modules:
|
|
61
|
+
# the walk goes on to the superproject.
|
|
62
|
+
if [ -d "$d/.git" ]; then
|
|
63
|
+
break
|
|
64
|
+
elif [ -f "$d/.git" ]; then
|
|
65
|
+
read -r gitdir <"$d/.git" || :
|
|
66
|
+
case $gitdir in
|
|
67
|
+
*.git/modules/*) ;;
|
|
68
|
+
*) break ;;
|
|
69
|
+
esac
|
|
70
|
+
fi
|
|
71
|
+
d=${d%/*}
|
|
72
|
+
done
|
|
73
|
+
fi
|
|
74
|
+
|
|
32
75
|
key=
|
|
33
76
|
loader=
|
|
34
77
|
case $(uname -sm) in
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vzn/vx",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.637",
|
|
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.637",
|
|
25
|
+
"@vzn/vx-linux-arm64": "0.0.637",
|
|
26
|
+
"@vzn/vx-darwin-x64": "0.0.637",
|
|
27
|
+
"@vzn/vx-darwin-arm64": "0.0.637"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@anthropic-ai/sandbox-runtime": "^0.0.76"
|
package/schemas/cache.json
CHANGED
|
@@ -1,24 +1,46 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"title": "vx cache
|
|
4
|
-
"description": "
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
"
|
|
12
|
-
|
|
3
|
+
"title": "vx cache clean --format json",
|
|
4
|
+
"description": "With a bound (prune): what the policy evicted and the orphan sweep reaped. With no bound (clear): the directories it deleted. With dryRun, what they would.",
|
|
5
|
+
"oneOf": [{ "$ref": "#/$defs/prune" }, { "$ref": "#/$defs/clear" }],
|
|
6
|
+
"$defs": {
|
|
7
|
+
"prune": {
|
|
8
|
+
"type": "object",
|
|
9
|
+
"additionalProperties": false,
|
|
10
|
+
"required": ["dryRun", "evicted", "bytesFreed", "orphans", "orphanBytes"],
|
|
11
|
+
"properties": {
|
|
12
|
+
"dryRun": { "type": "boolean" },
|
|
13
|
+
"evicted": {
|
|
14
|
+
"type": "integer",
|
|
15
|
+
"description": "index entries evicted by the age / size policy"
|
|
16
|
+
},
|
|
17
|
+
"bytesFreed": {
|
|
18
|
+
"type": "integer",
|
|
19
|
+
"description": "bytes those entries occupied, per the index"
|
|
20
|
+
},
|
|
21
|
+
"orphans": {
|
|
22
|
+
"type": "integer",
|
|
23
|
+
"description": "artifacts and temp files with no index row, reaped"
|
|
24
|
+
},
|
|
25
|
+
"orphanBytes": { "type": "integer" }
|
|
26
|
+
}
|
|
13
27
|
},
|
|
14
|
-
"
|
|
15
|
-
"type": "
|
|
16
|
-
"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
28
|
+
"clear": {
|
|
29
|
+
"type": "object",
|
|
30
|
+
"additionalProperties": false,
|
|
31
|
+
"required": ["dryRun", "cleared", "bytesFreed"],
|
|
32
|
+
"properties": {
|
|
33
|
+
"dryRun": { "type": "boolean" },
|
|
34
|
+
"cleared": {
|
|
35
|
+
"type": "array",
|
|
36
|
+
"items": { "type": "string" },
|
|
37
|
+
"description": "the cache directory and the store deleted: workspace-relative inside it, else absolute"
|
|
38
|
+
},
|
|
39
|
+
"bytesFreed": {
|
|
40
|
+
"type": "integer",
|
|
41
|
+
"description": "bytes under those directories"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
23
45
|
}
|
|
24
46
|
}
|
package/schemas/info.json
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
"additionalProperties": false,
|
|
6
6
|
"required": [
|
|
7
7
|
"vx",
|
|
8
|
+
"vxPath",
|
|
9
|
+
"handedOffFrom",
|
|
8
10
|
"bun",
|
|
9
11
|
"bunSupported",
|
|
10
12
|
"git",
|
|
@@ -12,16 +14,18 @@
|
|
|
12
14
|
"workspaceRoot",
|
|
13
15
|
"projects",
|
|
14
16
|
"tasks",
|
|
15
|
-
"configErrors",
|
|
16
17
|
"plugins",
|
|
17
18
|
"workers",
|
|
18
19
|
"memory",
|
|
19
20
|
"cacheDir",
|
|
21
|
+
"cacheDirBytes",
|
|
20
22
|
"cacheStore",
|
|
23
|
+
"cacheStoreBytes",
|
|
21
24
|
"cacheVersion",
|
|
22
25
|
"schemaVersion",
|
|
23
26
|
"cacheEntries",
|
|
24
27
|
"cacheBytes",
|
|
28
|
+
"settings",
|
|
25
29
|
"cacheRetention",
|
|
26
30
|
"orphans",
|
|
27
31
|
"runs24h",
|
|
@@ -33,6 +37,8 @@
|
|
|
33
37
|
],
|
|
34
38
|
"properties": {
|
|
35
39
|
"vx": { "type": "string" },
|
|
40
|
+
"vxPath": { "type": "string" },
|
|
41
|
+
"handedOffFrom": { "type": ["string", "null"] },
|
|
36
42
|
"bun": { "type": "string" },
|
|
37
43
|
"bunSupported": { "type": "boolean" },
|
|
38
44
|
"git": { "type": ["string", "null"] },
|
|
@@ -45,15 +51,6 @@
|
|
|
45
51
|
"workspaceRoot": { "type": "string" },
|
|
46
52
|
"projects": { "type": "integer" },
|
|
47
53
|
"tasks": { "type": "integer" },
|
|
48
|
-
"configErrors": {
|
|
49
|
-
"type": "array",
|
|
50
|
-
"items": {
|
|
51
|
-
"type": "object",
|
|
52
|
-
"additionalProperties": false,
|
|
53
|
-
"required": ["path", "message"],
|
|
54
|
-
"properties": { "path": { "type": "string" }, "message": { "type": "string" } }
|
|
55
|
-
}
|
|
56
|
-
},
|
|
57
54
|
"plugins": {
|
|
58
55
|
"type": "array",
|
|
59
56
|
"items": {
|
|
@@ -88,14 +85,29 @@
|
|
|
88
85
|
}
|
|
89
86
|
},
|
|
90
87
|
"cacheDir": { "type": "string" },
|
|
88
|
+
"cacheDirBytes": { "type": "integer" },
|
|
91
89
|
"cacheStore": { "type": ["string", "null"] },
|
|
90
|
+
"cacheStoreBytes": { "type": ["integer", "null"] },
|
|
92
91
|
"cacheVersion": { "type": "string" },
|
|
93
92
|
"schemaVersion": { "type": "string" },
|
|
94
93
|
"cacheEntries": { "type": "integer" },
|
|
95
94
|
"cacheBytes": { "type": "integer" },
|
|
95
|
+
"settings": {
|
|
96
|
+
"type": "object",
|
|
97
|
+
"description": "every setting (docs/schema.md § Settings) by path, as a run with no flags takes it: its variable as written, else .vx/workspace's value, else null with source default",
|
|
98
|
+
"additionalProperties": {
|
|
99
|
+
"type": "object",
|
|
100
|
+
"additionalProperties": false,
|
|
101
|
+
"required": ["value", "source"],
|
|
102
|
+
"properties": {
|
|
103
|
+
"value": { "type": ["string", "number", "boolean", "null"] },
|
|
104
|
+
"source": { "enum": ["env", "workspace", "default"] }
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
},
|
|
96
108
|
"cacheRetention": {
|
|
97
109
|
"type": ["object", "null"],
|
|
98
|
-
"description": "the workspace
|
|
110
|
+
"description": "cache.retention from its variables, else the workspace, maxSize also in bytes; null when none is declared",
|
|
99
111
|
"additionalProperties": false,
|
|
100
112
|
"properties": {
|
|
101
113
|
"olderThan": { "type": "string" },
|
package/schemas/last.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"title": "vx last --format json",
|
|
4
|
-
"description": "`vx last [RUNID] [--failed]` prints a run; `--list` prints an array of invocations, newest first; `--log <task>` prints that task's output.",
|
|
4
|
+
"description": "`vx last [RUNID] [--failed]` prints a run; `--list` prints an array of invocations, newest first; `--log <task>` prints that task's output; `--stats` prints per-task history numbers.",
|
|
5
5
|
"oneOf": [
|
|
6
6
|
{
|
|
7
7
|
"type": "object",
|
|
@@ -13,9 +13,55 @@
|
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
{ "type": "array", "items": { "$ref": "#/$defs/invocation" } },
|
|
16
|
-
{ "$ref": "#/$defs/log" }
|
|
16
|
+
{ "$ref": "#/$defs/log" },
|
|
17
|
+
{ "$ref": "#/$defs/stats" }
|
|
17
18
|
],
|
|
18
19
|
"$defs": {
|
|
20
|
+
"stats": {
|
|
21
|
+
"type": "object",
|
|
22
|
+
"additionalProperties": false,
|
|
23
|
+
"required": ["window", "branch", "stats"],
|
|
24
|
+
"properties": {
|
|
25
|
+
"window": { "type": "integer", "description": "the newest runs the numbers cover" },
|
|
26
|
+
"branch": {
|
|
27
|
+
"type": ["string", "null"],
|
|
28
|
+
"description": "the branch p50 forecasts from: --branch, VX_RUN_BRANCH, git's, then CI's"
|
|
29
|
+
},
|
|
30
|
+
"stats": { "type": "array", "items": { "$ref": "#/$defs/taskStats" } }
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"taskStats": {
|
|
34
|
+
"type": "object",
|
|
35
|
+
"additionalProperties": false,
|
|
36
|
+
"required": [
|
|
37
|
+
"taskId",
|
|
38
|
+
"runs",
|
|
39
|
+
"p50DurationMs",
|
|
40
|
+
"p99DurationMs",
|
|
41
|
+
"successRate",
|
|
42
|
+
"hitRate",
|
|
43
|
+
"failureMode",
|
|
44
|
+
"maxPeakRssBytes",
|
|
45
|
+
"maxCpuParallelism"
|
|
46
|
+
],
|
|
47
|
+
"properties": {
|
|
48
|
+
"taskId": { "type": "string" },
|
|
49
|
+
"runs": { "type": "integer", "description": "executed runs in the window, skips aside" },
|
|
50
|
+
"p50DurationMs": {
|
|
51
|
+
"type": ["number", "null"],
|
|
52
|
+
"description": "the forecast a run shows: median of the last 5 timings on branch, else on any branch; null when none"
|
|
53
|
+
},
|
|
54
|
+
"p99DurationMs": { "type": ["number", "null"] },
|
|
55
|
+
"successRate": { "type": "number", "description": "0 to 1" },
|
|
56
|
+
"hitRate": { "type": "number", "description": "0 to 1" },
|
|
57
|
+
"failureMode": { "enum": ["stable", "flaky-recoverable", "flaky-fatal"] },
|
|
58
|
+
"maxPeakRssBytes": { "type": ["integer", "null"] },
|
|
59
|
+
"maxCpuParallelism": {
|
|
60
|
+
"type": ["number", "null"],
|
|
61
|
+
"description": "cpu time over wall time; 2.0 is two cores busy"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
},
|
|
19
65
|
"log": {
|
|
20
66
|
"type": "object",
|
|
21
67
|
"additionalProperties": false,
|
package/schemas/lock.json
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"audited": { "type": "integer", "description": "projects with a vx.config, each audited" },
|
|
11
11
|
"notAudited": {
|
|
12
12
|
"type": "integer",
|
|
13
|
-
"description": "projects
|
|
13
|
+
"description": "projects with tasks and no vx.config: nothing to freeze, never audited"
|
|
14
14
|
},
|
|
15
15
|
"problems": {
|
|
16
16
|
"type": "array",
|
package/schemas/plan.json
CHANGED
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
"download": {
|
|
37
37
|
"const": "deferred",
|
|
38
|
-
"description": "outputs would stay remote (--download)"
|
|
38
|
+
"description": "outputs would stay remote (--cache-download)"
|
|
39
39
|
},
|
|
40
40
|
"description": { "type": "string" },
|
|
41
41
|
"affected": {
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
},
|
|
81
81
|
"downloadDowngrades": {
|
|
82
82
|
"type": "array",
|
|
83
|
-
"description": "producers --download wanted to defer but could not, and why",
|
|
83
|
+
"description": "producers --cache-download wanted to defer but could not, and why",
|
|
84
84
|
"items": {
|
|
85
85
|
"type": "object",
|
|
86
86
|
"additionalProperties": false,
|
package/schemas/show.json
CHANGED
|
@@ -32,9 +32,10 @@
|
|
|
32
32
|
"dir": { "type": "string" },
|
|
33
33
|
"config": {
|
|
34
34
|
"type": ["object", "null"],
|
|
35
|
-
"description": "null when the
|
|
35
|
+
"description": "null when the project has no vx config and no plugin gave it one",
|
|
36
36
|
"additionalProperties": false,
|
|
37
37
|
"properties": {
|
|
38
|
+
"name": { "type": "string" },
|
|
38
39
|
"tags": { "$ref": "#/$defs/stringList" },
|
|
39
40
|
"tasks": { "type": "object", "additionalProperties": { "$ref": "#/$defs/taskConfig" } }
|
|
40
41
|
}
|
|
@@ -66,7 +67,7 @@
|
|
|
66
67
|
"properties": {
|
|
67
68
|
"command": { "type": "string" },
|
|
68
69
|
"remote": { "enum": [true, false, "only"] },
|
|
69
|
-
"timeout": { "type": "
|
|
70
|
+
"timeout": { "type": "string", "description": "a duration as written, like '30s'" },
|
|
70
71
|
"retries": { "type": "integer" },
|
|
71
72
|
"env": {
|
|
72
73
|
"type": "object",
|
|
@@ -113,7 +114,8 @@
|
|
|
113
114
|
"required": ["files"],
|
|
114
115
|
"properties": {
|
|
115
116
|
"files": { "$ref": "#/$defs/stringList" },
|
|
116
|
-
"workspaceFiles": { "$ref": "#/$defs/stringList" }
|
|
117
|
+
"workspaceFiles": { "$ref": "#/$defs/stringList" },
|
|
118
|
+
"clean": { "type": "boolean" }
|
|
117
119
|
}
|
|
118
120
|
},
|
|
119
121
|
"inputStability": {
|
package/schemas/why.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
{
|
|
7
7
|
"type": "object",
|
|
8
8
|
"additionalProperties": false,
|
|
9
|
-
"required": ["taskId", "runId", "why", "diff", "roots"],
|
|
9
|
+
"required": ["taskId", "runId", "why", "diff", "roots", "writers"],
|
|
10
10
|
"properties": {
|
|
11
11
|
"taskId": { "type": "string" },
|
|
12
12
|
"runId": { "type": "string" },
|
|
@@ -38,6 +38,20 @@
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
|
+
},
|
|
42
|
+
"writers": {
|
|
43
|
+
"type": "array",
|
|
44
|
+
"description": "For each moved input file of the task or a root cause, the recorded tasks running when the file last changed: a task writing a file another key reads re-keys it every run.",
|
|
45
|
+
"items": {
|
|
46
|
+
"type": "object",
|
|
47
|
+
"additionalProperties": false,
|
|
48
|
+
"required": ["taskId", "file", "writers"],
|
|
49
|
+
"properties": {
|
|
50
|
+
"taskId": { "type": "string" },
|
|
51
|
+
"file": { "type": "string" },
|
|
52
|
+
"writers": { "type": "array", "items": { "type": "string" } }
|
|
53
|
+
}
|
|
54
|
+
}
|
|
41
55
|
}
|
|
42
56
|
}
|
|
43
57
|
},
|
package/skills/vx/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: vx
|
|
3
|
-
description: Run, inspect and debug tasks in a vx monorepo (vx.config.ts, vx
|
|
3
|
+
description: Run, inspect and debug tasks in a vx monorepo (vx.config.ts, .vx/workspace.ts). Use to build or test projects, find what a change affects, read why a task failed or re-ran, and query the cache as JSON.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# vx
|
|
@@ -59,22 +59,20 @@ files, fix, and re-run the same command: cached tasks that passed replay from th
|
|
|
59
59
|
vx why app#build --format json # which input changed, down to the root cause
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
-
##
|
|
62
|
+
## Run history
|
|
63
63
|
|
|
64
64
|
```sh
|
|
65
|
-
vx
|
|
65
|
+
vx last --stats --format json # per task: p50 (the live estimate's), p99, pass and hit rate, failure mode, peak RSS
|
|
66
|
+
vx last --stats --branch main --format json # p50 from main's timings
|
|
67
|
+
vx last --stats app#build --format json # one task; a task name covers every project
|
|
68
|
+
vx last --list --format json # recent runs, newest first
|
|
66
69
|
```
|
|
67
70
|
|
|
68
|
-
##
|
|
71
|
+
## Workspace health
|
|
69
72
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
`getRunHistory`, `explainCacheKey`, `whyDidThisRerun`, `getFailures`, `getTaskLog`, `getConfig`, `checkLock`, `pruneCache`, `planInit`, `searchDocs`,
|
|
74
|
-
`getWorkspaceInfo`, `runTasks`, `planTasks`. `runTasks` answers what
|
|
75
|
-
`vx run <tasks> --format json` prints, `planTasks` what
|
|
76
|
-
`vx run <tasks> --dry=json` prints, `pruneCache` evicts only with
|
|
77
|
-
`dryRun: false`; the others only read.
|
|
73
|
+
```sh
|
|
74
|
+
vx info --format json # vx and Bun versions, projects, config errors, plugins, cache
|
|
75
|
+
```
|
|
78
76
|
|
|
79
77
|
## Rules
|
|
80
78
|
|
|
@@ -93,3 +91,9 @@ same facts and runs tasks. Adoption does not add it: install
|
|
|
93
91
|
`https://raw.githubusercontent.com/vznjs/vx/main/packages/vx-docs/src/content/docs/<page>.md`:
|
|
94
92
|
`quickstart`, `guides/migrate`, `guides/configure`, `guides/agents`,
|
|
95
93
|
`guides/troubleshooting`, `guides/ci`, `guides/plugins`.
|
|
94
|
+
|
|
95
|
+
## Install
|
|
96
|
+
|
|
97
|
+
`npx skills add vznjs/vx/packages/vx/skills/vx` installs this skill. To match the vx a workspace
|
|
98
|
+
has installed, copy it from there instead:
|
|
99
|
+
`cp node_modules/@vzn/vx/skills/vx/SKILL.md .claude/skills/vx/`.
|