@vzn/vx 0.0.16 → 0.0.21
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/LICENSE +1 -1
- package/README.md +135 -124
- package/index.ts +10 -0
- package/launcher.mjs +10 -11
- package/package.json +11 -7
- package/src/bin.ts +14 -4
- package/src/cache/archive.ts +659 -0
- package/src/cache/cache.ts +769 -1101
- package/src/cache/chained-cache.ts +194 -0
- package/src/cache/config-evals.ts +89 -0
- package/src/cache/file-hashes.ts +262 -0
- package/src/cache/git-inputs.ts +637 -0
- package/src/cache/index.ts +24 -5
- package/src/cache/inputs.ts +373 -456
- package/src/cache/layer.ts +604 -0
- package/src/cache/layered-cache.ts +96 -43
- package/src/cache/output-index.ts +224 -0
- package/src/cache/policy.ts +84 -0
- package/src/cache/run-history.ts +147 -0
- package/src/cache/tar-stream.ts +358 -0
- package/src/cache/zstd.ts +160 -0
- package/src/cli/cache.ts +75 -21
- package/src/cli/completions.ts +104 -0
- package/src/cli/core-alias.ts +25 -0
- package/src/cli/help.ts +195 -128
- package/src/cli/index.ts +116 -46
- package/src/cli/info.ts +122 -63
- package/src/cli/init.ts +75 -0
- package/src/cli/last.ts +172 -0
- package/src/cli/lock.ts +2 -1
- package/src/cli/plan-format.ts +72 -6
- package/src/cli/plugin-commands.ts +103 -0
- package/src/cli/run.ts +245 -271
- package/src/cli/select.ts +332 -0
- package/src/cli/show.ts +144 -69
- package/src/cli/upgrade.ts +9 -7
- package/src/cli/watch.ts +858 -110
- package/src/cli/why.ts +223 -0
- package/src/cli/workspace-config.ts +126 -0
- package/src/config.ts +187 -150
- package/src/exec/env.ts +18 -1
- package/src/exec/executor.ts +224 -0
- package/src/exec/index.ts +24 -2
- package/src/exec/local-executor.ts +41 -0
- package/src/exec/runner.ts +166 -40
- package/src/exec/sandbox-binds.ts +182 -0
- package/src/exec/sandbox-paths.ts +50 -0
- package/src/exec/sandbox-runtime.ts +642 -260
- package/src/exec/sandbox-violations.ts +280 -0
- package/src/graph/index.ts +4 -10
- package/src/graph/scheduler.ts +232 -203
- package/src/graph/task-graph.ts +222 -8
- package/src/index.ts +146 -153
- package/src/orchestrator/admission.ts +137 -0
- package/src/orchestrator/deferred-outputs.ts +147 -0
- package/src/orchestrator/doctor.ts +255 -0
- package/src/orchestrator/download-policy.ts +171 -0
- package/src/orchestrator/events.ts +72 -8
- package/src/orchestrator/execute-task.ts +374 -549
- package/src/orchestrator/failure-mode.ts +202 -0
- package/src/orchestrator/framed-output.ts +126 -69
- package/src/orchestrator/history.ts +126 -59
- package/src/orchestrator/hit-restore.ts +221 -0
- package/src/orchestrator/index.ts +77 -93
- package/src/orchestrator/local-shortcircuit.ts +22 -0
- package/src/orchestrator/lockfile-claim.ts +281 -0
- package/src/orchestrator/logger.ts +208 -35
- package/src/orchestrator/metrics.ts +102 -1388
- package/src/orchestrator/miss-save.ts +169 -0
- package/src/orchestrator/options.ts +55 -34
- package/src/orchestrator/persistent.ts +79 -0
- package/src/orchestrator/placement.ts +182 -0
- package/src/orchestrator/plan.ts +144 -1
- package/src/orchestrator/plugin-host.ts +357 -120
- package/src/orchestrator/plugin.ts +298 -58
- package/src/orchestrator/prepare.ts +202 -106
- package/src/orchestrator/projects.ts +259 -0
- package/src/orchestrator/remote-prefetch.ts +12 -8
- package/src/orchestrator/run-artifacts.ts +63 -16
- package/src/orchestrator/run-context.ts +167 -29
- package/src/orchestrator/run-records.ts +149 -0
- package/src/orchestrator/run-report.ts +74 -47
- package/src/orchestrator/run.ts +534 -417
- package/src/orchestrator/sandbox-request.ts +243 -0
- package/src/orchestrator/save-lane.ts +47 -0
- package/src/orchestrator/signals.ts +111 -0
- package/src/orchestrator/stable-keys.ts +129 -31
- package/src/orchestrator/status-line.ts +49 -9
- package/src/orchestrator/summary.ts +90 -26
- package/src/orchestrator/tally.ts +78 -35
- package/src/orchestrator/task-hash.ts +111 -15
- package/src/orchestrator/task-log-buffer.ts +288 -0
- package/src/orchestrator/telemetry-host.ts +34 -6
- package/src/orchestrator/telemetry.ts +182 -36
- package/src/orchestrator/upstream.ts +72 -31
- package/src/util/cgroup.ts +160 -0
- package/src/util/edit-distance.ts +70 -0
- package/src/util/errors.ts +15 -1
- package/src/util/index.ts +15 -2
- package/src/util/num.ts +37 -0
- package/src/util/paths.ts +64 -0
- package/src/util/settle.ts +67 -0
- package/src/util/size.ts +5 -1
- package/src/util/tail.ts +66 -0
- package/src/util/timing.ts +63 -0
- package/src/util/verbs.ts +39 -0
- package/src/workspace/affected.ts +250 -23
- package/src/workspace/config-cache.ts +313 -0
- package/src/workspace/config-eval.ts +217 -0
- package/src/workspace/config-imports.ts +162 -0
- package/src/workspace/config-schema.ts +837 -0
- package/src/workspace/filter.ts +65 -10
- package/src/workspace/fingerprint.ts +53 -4
- package/src/workspace/index.ts +42 -3
- package/src/workspace/lockfile.ts +25 -9
- package/src/workspace/migrate-scripts.ts +134 -0
- package/src/workspace/migration.ts +314 -0
- package/src/workspace/nested-dirs.ts +21 -7
- package/src/workspace/package-graph.ts +114 -41
- package/src/workspace/project-loader.ts +224 -450
- package/src/workspace/workspace.ts +298 -72
- package/src/cache/cas-backend.ts +0 -97
- package/src/cache/digest.ts +0 -47
- package/src/cache/tar.ts +0 -343
- package/src/cli/backend.ts +0 -23
- package/src/cli/mcp-rpc.ts +0 -292
- package/src/cli/mcp.ts +0 -92
- package/src/cli/migrate-nx.ts +0 -450
- package/src/cli/migrate-turbo.ts +0 -364
- package/src/cli/migrate.ts +0 -219
- package/src/orchestrator/devframe-surface.ts +0 -74
- package/src/orchestrator/predict.ts +0 -106
- package/src/orchestrator/protocol.ts +0 -156
- package/src/orchestrator/resources.ts +0 -59
- package/src/orchestrator/run-state.ts +0 -145
- package/src/orchestrator/verify.ts +0 -164
- package/src/orchestrator/wire-render.ts +0 -92
- package/src/orchestrator/wire.ts +0 -212
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -3,11 +3,33 @@
|
|
|
3
3
|
**The fastest way to build a monorepo.**
|
|
4
4
|
|
|
5
5
|
vx runs your task graph, remembers every result, and never does the
|
|
6
|
-
same work twice.
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
same work twice.
|
|
7
|
+
|
|
8
|
+
<!-- bench:start — generated by packages/vx-bench/update-site.ts from results.json; do not hand-edit -->
|
|
9
|
+
|
|
10
|
+
The runner adds seconds to a cold build where others add minutes. On a
|
|
11
|
+
1,090-package graph of 3,270 tasks whose ideal schedule is 3m 38s,
|
|
12
|
+
vx finishes in 3m 46s (+0:08), Turborepo in 5m 13s (+1:35) and Nx in
|
|
13
|
+
34m 44s (+31:06) — 8 ms of overhead per package against 88 ms and
|
|
14
|
+
1,712 ms, so the graph can grow and the runner stays in seconds. The cold build
|
|
15
|
+
burns 35 s of CPU in vx, 73 s in Turborepo and 114 minutes in Nx; a
|
|
16
|
+
fully cached run replays the graph in 510 ms.
|
|
17
|
+
<!-- bench:end -->
|
|
18
|
+
|
|
19
|
+
On a real Turbo monorepo (`solidjs/solid`, its own `turbo.json`, no
|
|
20
|
+
config rewritten) vx replays a cached build in 51 ms where Turbo takes
|
|
21
|
+
95, restores every output in 66 ms against 127, and builds cold in
|
|
22
|
+
40.6 s against 45.5 s. Measured, reproducible, on hardware you own
|
|
23
|
+
([benchmarks](packages/vx/docs/benchmarks.md)).
|
|
24
|
+
|
|
25
|
+
One binary. No daemon, no cloud, no account, no paywall. Sandboxed
|
|
26
|
+
tasks, a plugin at every stage, seconds of overhead at a thousand
|
|
27
|
+
packages.
|
|
28
|
+
|
|
29
|
+
vx does one thing — run and cache a task graph, correctly — and stops
|
|
30
|
+
there. Remote caches, remote execution, telemetry, AI agents, learned
|
|
31
|
+
scheduling and your own verbs are plugins on documented seams, not
|
|
32
|
+
features inside: what Nx would be if it weren't a product.
|
|
11
33
|
|
|
12
34
|
📖 **[Documentation site →](https://vznjs.github.io/vx/)** — guides,
|
|
13
35
|
architecture, caching, and the full CLI / config reference.
|
|
@@ -42,6 +64,7 @@ export default defineProject({
|
|
|
42
64
|
```
|
|
43
65
|
|
|
44
66
|
```sh
|
|
67
|
+
vx init # scaffold vx.workspace.ts + a vx.config.ts per package from scripts
|
|
45
68
|
vx run build # cwd project + its workspace deps
|
|
46
69
|
vx run test --all # every project that declares `test`
|
|
47
70
|
vx run ci --affected # only what changed since origin/HEAD
|
|
@@ -73,16 +96,11 @@ skip extraction entirely when the tree already matches. In-process
|
|
|
73
96
|
tar (no subprocess on the hot path). Atomic artifact publishes.
|
|
74
97
|
Single-transaction metadata writes. Every optimization is recorded
|
|
75
98
|
with the invariant that keeps it valid —
|
|
76
|
-
[`docs/optimizations.md`](docs/optimizations.md) is the ledger, and
|
|
77
|
-
[`bench/`](bench/) reproduces the numbers.
|
|
99
|
+
[`packages/vx/docs/optimizations.md`](packages/vx/docs/optimizations.md) is the ledger, and
|
|
100
|
+
[`packages/vx-bench/`](packages/vx-bench/) reproduces the numbers.
|
|
78
101
|
|
|
79
102
|
## Built for trust
|
|
80
103
|
|
|
81
|
-
- **Provable cache correctness.** `vx run --verify` re-runs each
|
|
82
|
-
cacheable task and byte-compares outputs (determinism);
|
|
83
|
-
`--verify=inputs` sandboxes it against the declared inputs and fails
|
|
84
|
-
loud naming any undeclared read (completeness). No other runner can
|
|
85
|
-
prove a cache entry safe.
|
|
86
104
|
- **Corruption can't go live.** A remote artifact is verified against
|
|
87
105
|
its content digest and validated before it enters the store
|
|
88
106
|
(zstd-bomb and oversize downloads refused); bad bytes degrade to a
|
|
@@ -92,7 +110,11 @@ with the invariant that keeps it valid —
|
|
|
92
110
|
- **Readiness you can bound.** Persistent tasks gate downstream work
|
|
93
111
|
on a `readyWhen` signal; `exec.timeout` bounds any task (with
|
|
94
112
|
`--timeout` / workspace defaults), `exec.retries` + `--retry` absorb
|
|
95
|
-
flakes
|
|
113
|
+
flakes.
|
|
114
|
+
- **Flaky tasks are found, not guessed.** The same inputs both passing
|
|
115
|
+
and failing is the definition, and vx holds every hash and outcome
|
|
116
|
+
locally: a run names them under its footer, `--summarize` types them
|
|
117
|
+
per task, `vx info` lists them. No service.
|
|
96
118
|
- **Kernel-level sandboxing**, opt-in per task, that fails the build
|
|
97
119
|
on violation instead of hiding it.
|
|
98
120
|
|
|
@@ -125,46 +147,75 @@ resolution that bridges packages without the task · multi-task runs
|
|
|
125
147
|
with one shared graph · pnpm-style filters and `--affected` ·
|
|
126
148
|
watch mode · `--dry` / `--graph` plans · persistent dev servers ·
|
|
127
149
|
retries, timeouts, `--continue` modes · per-layer cache control
|
|
128
|
-
(`--cache=local:r,remote:`) · `vx
|
|
129
|
-
|
|
130
|
-
`vx
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
150
|
+
(`--cache=local:r,remote:`) · `vx why` explains a re-run from the
|
|
151
|
+
persisted input fingerprints · `vx last` replays a recorded run ·
|
|
152
|
+
`vx info`,
|
|
153
|
+
`--summarize`, `--profile` Chrome traces, `--report` · `vx cache prune`
|
|
154
|
+
with TTL and size caps · `bunx @vzn/vx-migrate` from turbo.json or an Nx graph.
|
|
155
|
+
|
|
156
|
+
## A pipeline with seams — plugins decide what happens
|
|
157
|
+
|
|
158
|
+
Core is the pipeline: discover projects, evaluate configs, build the
|
|
159
|
+
task graph, derive keys, schedule, execute, cache, observe. Plugins
|
|
160
|
+
declared in `vx.workspace.ts` hook each stage, Vite-style, on one
|
|
161
|
+
`VxPlugin` object:
|
|
162
|
+
|
|
163
|
+
| Stage | Hook | A plugin can… |
|
|
164
|
+
| --------- | -------------------------- | ----------------------------------------------------------- |
|
|
165
|
+
| workspace | `config(ws, ctx)` | edit the workspace config before it is used |
|
|
166
|
+
| project | `project(config, ctx)` | add, remove or rewrite a project's tasks (keyed like yours) |
|
|
167
|
+
| graph | `graph(nodes, ctx)` | add or drop edges, mark tasks requested |
|
|
168
|
+
| key | `key(task, ctx)` | fold extra material into the cache key (named in `vx why`) |
|
|
169
|
+
| schedule | `schedule(nodes, ctx)` | decide which ready task runs first |
|
|
170
|
+
| execute | `executor(ctx)` | decide WHERE a task's command runs (local, a REAPI worker) |
|
|
171
|
+
| store | `cache(ctx)` | decide where artifacts live (local, a shared remote) |
|
|
172
|
+
| observe | `telemetry(ctx)` / `setup` | receive every run record, or the raw event bus |
|
|
173
|
+
| cli | `commands` | add verbs to `vx` |
|
|
174
|
+
|
|
175
|
+
Core applies **no plugin by default** and names none. Running here and
|
|
176
|
+
caching here are its floor — the tail of every executor list and cache
|
|
177
|
+
chain — so a workspace with no `vx.workspace.ts` runs and caches, and a
|
|
178
|
+
plugin that declines a task hands it back to this machine. First-party
|
|
179
|
+
plugins:
|
|
180
|
+
[`@vzn/vx-reapi`](packages/vx-reapi) (Bazel Remote Execution API —
|
|
181
|
+
remote cache and remote execution against NativeLink, BuildBuddy,
|
|
182
|
+
Buildbarn or bazel-remote), [`@vzn/vx-otel`](packages/vx-otel)
|
|
183
|
+
(OpenTelemetry traces + metrics + logs, zero SDK deps),
|
|
184
|
+
[`@vzn/vx-github`](packages/vx-github) (Actions job summary + Checks
|
|
185
|
+
API), [`@vzn/vx-mcp`](packages/vx-mcp) (`vx mcp` — a read-only Model
|
|
186
|
+
Context Protocol server for AI coding agents, no SDK),
|
|
187
|
+
[`@vzn/vx-migrate`](packages/vx-migrate) (adoption in one package:
|
|
188
|
+
`turbo()` runs a Turbo repo under vx with nothing written, `bunx
|
|
189
|
+
@vzn/vx-migrate` writes configs from `turbo.json` or an Nx graph, and
|
|
190
|
+
`turboCache()` / `nxCache()` keep a remote cache speaking Turbo's
|
|
191
|
+
`/v8/artifacts` API or Nx's self-hosted spec — the wire is theirs, the
|
|
192
|
+
artifacts are vx's),
|
|
193
|
+
[`@vzn/vx-lockfile`](packages/vx-lockfile) (`pnpm()`, `bun()`, `npm()`,
|
|
194
|
+
`yarn()`: the lockfile keyed per project, so one install re-keys only the
|
|
195
|
+
projects it reaches, and `--affected` follows), and [`@vzn/vx-schedule-history`](packages/vx-schedule-history)
|
|
196
|
+
(order by learned critical path) and [`@vzn/vx-migrate`](packages/vx-migrate)
|
|
197
|
+
(`bunx @vzn/vx-migrate`: turbo.json or an Nx graph → vx.config.ts, through
|
|
198
|
+
core's migration seam). Core ships no plugin and reads no other runner's
|
|
199
|
+
format; nothing
|
|
200
|
+
distributed ships in this repo; the seams are how you build it.
|
|
145
201
|
|
|
146
202
|
## How it compares
|
|
147
203
|
|
|
148
|
-
| | vx
|
|
149
|
-
| ------------------------- |
|
|
150
|
-
| Fully cached, 100 pkgs¹ | **144 ms**
|
|
151
|
-
| Config | TypeScript, evaluated into the cache key
|
|
152
|
-
| Output ownership | **Strict** — wiped before exec AND restore
|
|
153
|
-
| Clean-tree hashing | **Zero reads** (git index OIDs)
|
|
154
|
-
| Daemon required for speed | **No**
|
|
155
|
-
| Per-task sandbox | **Yes** — kernel-level, opt-in
|
|
156
|
-
|
|
|
157
|
-
|
|
|
158
|
-
|
|
|
159
|
-
| Predictive scheduling | **Yes** (opt-in: `predictive: true`) | No | No |
|
|
160
|
-
| OTel CI/CD spans | **Yes** — `otel()` plugin, zero OTel-SDK deps | No | Paid |
|
|
161
|
-
| Self-hosted platform² | **Yes** — dashboard, distributed CI, remote cache; Docker compose | Vercel-only cache | Paid (Nx Cloud) |
|
|
162
|
-
| Install | **Single binary** — npm or 1 curl line, no Node/Bun needed | npm + Node | npm + Node |
|
|
204
|
+
| | vx | Turborepo | Nx |
|
|
205
|
+
| ------------------------- | ---------------------------------------------------------- | ------------------------------ | ---------------- |
|
|
206
|
+
| Fully cached, 100 pkgs¹ | **144 ms** | 279 ms | 583+ ms |
|
|
207
|
+
| Config | TypeScript, evaluated into the cache key | JSON (static) | JSON (static) |
|
|
208
|
+
| Output ownership | **Strict** — wiped before exec AND restore | Additive (stale files survive) | Additive |
|
|
209
|
+
| Clean-tree hashing | **Zero reads** (git index OIDs) | git OIDs | re-hash / daemon |
|
|
210
|
+
| Daemon required for speed | **No** | Optional | Yes |
|
|
211
|
+
| Per-task sandbox | **Yes** — kernel-level, opt-in | No | No |
|
|
212
|
+
| Plugin API | **Yes** — executor / cache / telemetry seams | No | Yes (TS-tied) |
|
|
213
|
+
| OTel CI/CD spans | **Yes** — `otel()` plugin, zero OTel-SDK deps | No | Paid |
|
|
214
|
+
| Install | **Single binary** — npm or 1 curl line, no Node/Bun needed | npm + Node | npm + Node |
|
|
163
215
|
|
|
164
216
|
¹ Wall-clock, direct binaries, same machine and workspace — full
|
|
165
217
|
methodology and more scenarios in
|
|
166
|
-
[`docs/benchmarks.md`](docs/benchmarks.md).
|
|
167
|
-
OSS — see [vx Cloud](#vx-cloud).
|
|
218
|
+
[`packages/vx/docs/benchmarks.md`](packages/vx/docs/benchmarks.md).
|
|
168
219
|
|
|
169
220
|
## Switching from another runner
|
|
170
221
|
|
|
@@ -212,51 +263,9 @@ Differences to know:
|
|
|
212
263
|
- Persistent tasks: `persistent: { readyWhen: 'regex' }` (Turbo uses just `persistent: true`).
|
|
213
264
|
- Remote caching is a plugin, not a built-in — connect one and every `vx run` reads through it.
|
|
214
265
|
|
|
215
|
-
Side-by-side feature matrix + every known gap: [`docs/comparison.md`](
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
An **optional, self-hosted CI platform** — the first-party service you
|
|
220
|
-
run yourself. It is a fully independent app (accounts, roles,
|
|
221
|
-
organizations, teams, multiple workspaces), with **Postgres** as the
|
|
222
|
-
system of record and an **S3-compatible bucket** for artifacts; the
|
|
223
|
-
controller keeps zero artifact bytes at rest. Core `vx` never depends
|
|
224
|
-
on it — it connects to a deployment through the plugin seams above.
|
|
225
|
-
|
|
226
|
-
What a connected platform adds:
|
|
227
|
-
|
|
228
|
-
- **Dashboard.** Runs, flamegraphs, a live run cockpit with the task
|
|
229
|
-
DAG, per-task logs + artifacts, cache-key diffs ("why did this
|
|
230
|
-
re-run?"), and flaky-task detection with the concrete fix.
|
|
231
|
-
- **Remote cache.** The vx-native `/v1/cache` wire, tenant-partitioned
|
|
232
|
-
per org/workspace, with **trusted / untrusted tiers derived from the
|
|
233
|
-
token** — a fork-PR artifact can never feed a trusted build — and an
|
|
234
|
-
always-on integrity digest the client verifies.
|
|
235
|
-
- **Distributed CI (DTE).** Agents form a session-keyed pool; a
|
|
236
|
-
`vx run` fans tasks out across same-commit agents, outputs propagate
|
|
237
|
-
through the shared artifact store, and a standing pool multiplexes
|
|
238
|
-
concurrent runs with fair scheduling.
|
|
239
|
-
- **MCP over the platform.** `POST /mcp` (Postgres-backed, behind the
|
|
240
|
-
token) exposes the analytics as typed tools for AI agents — alongside
|
|
241
|
-
the core `vx mcp` stdio server that reads your local cache.
|
|
242
|
-
|
|
243
|
-
Deploy the stack (app + Postgres + object storage) with Docker
|
|
244
|
-
Compose, then connect any workspace with one URL and a minted token:
|
|
245
|
-
|
|
246
|
-
```sh
|
|
247
|
-
# Deploy — open the URL, register the first admin, mint a CI token under Admin → Tokens:
|
|
248
|
-
VX_CLOUD_SECRET=$(openssl rand -hex 32) \
|
|
249
|
-
docker compose -f packages/cloud/deploy/docker-compose.yml up
|
|
250
|
-
|
|
251
|
-
# Connect a workspace (remote cache + analytics + distribution):
|
|
252
|
-
vx-cloud connect https://ci.acme.dev --token vxc_…
|
|
253
|
-
# …or set VX_CLOUD_URL + VX_CLOUD_TOKEN in the environment.
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
Install the platform CLI with `npm i -g @vzn/vx-cloud` (a standalone
|
|
257
|
-
binary, or the `ghcr.io/vznjs/vx-cloud` image). Full setup, RBAC,
|
|
258
|
-
distributed CI, and the wire protocol live in the **vx Cloud** section
|
|
259
|
-
of the [documentation site](https://vznjs.github.io/vx/).
|
|
266
|
+
Side-by-side feature matrix + every known gap: [`packages/vx/docs/comparison.md`](packages/vx/docs/comparison.md).
|
|
267
|
+
What a Turbo or Nx user relies on, spelled in vx and pinned by a test:
|
|
268
|
+
[`packages/vx/docs/parity.md`](packages/vx/docs/parity.md).
|
|
260
269
|
|
|
261
270
|
## Architecture (one paragraph)
|
|
262
271
|
|
|
@@ -275,58 +284,60 @@ versioned telemetry contract (`TelemetryRecord` / `RunSummaryRecord`)
|
|
|
275
284
|
them. Core never imports a plugin; the arrow only points plugin → core.
|
|
276
285
|
Every module has a docs page; every interface is a swappable seam.
|
|
277
286
|
|
|
278
|
-
Read [`docs/architecture.md`](
|
|
279
|
-
map; the design record lives under [`docs/design/`](
|
|
287
|
+
Read [`packages/vx/docs/architecture.md`](packages/vx/docs/architecture.md) for the module
|
|
288
|
+
map; the design record lives under [`packages/vx/docs/design/`](packages/vx/docs/design/).
|
|
280
289
|
|
|
281
290
|
## Documentation
|
|
282
291
|
|
|
283
|
-
Full technical docs live under [`docs/`](
|
|
292
|
+
Full technical docs live under [`packages/vx/docs/`](packages/vx/docs/) and on the
|
|
284
293
|
[documentation site](https://vznjs.github.io/vx/):
|
|
285
294
|
|
|
286
|
-
- [`docs/architecture.md`](
|
|
287
|
-
- [`docs/schema.md`](
|
|
288
|
-
- [`docs/caching.md`](
|
|
289
|
-
- [`docs/execution.md`](
|
|
290
|
-
- [`docs/cli.md`](
|
|
291
|
-
- [`docs/comparison.md`](
|
|
292
|
-
- [`docs/modules/`](
|
|
293
|
-
- The **vx Cloud** section of the [docs site](https://vznjs.github.io/vx/) — deploy, RBAC, dashboard, distributed CI, wire protocol
|
|
295
|
+
- [`packages/vx/docs/architecture.md`](packages/vx/docs/architecture.md) — module map + data flow
|
|
296
|
+
- [`packages/vx/docs/schema.md`](packages/vx/docs/schema.md) — every config field
|
|
297
|
+
- [`packages/vx/docs/caching.md`](packages/vx/docs/caching.md) — cache-key derivation + invalidation table
|
|
298
|
+
- [`packages/vx/docs/execution.md`](packages/vx/docs/execution.md) — `vx run` lifecycle
|
|
299
|
+
- [`packages/vx/docs/cli.md`](packages/vx/docs/cli.md) — every flag
|
|
300
|
+
- [`packages/vx/docs/comparison.md`](packages/vx/docs/comparison.md) — Turbo / Nx / vite-task feature matrix
|
|
301
|
+
- [`packages/vx/docs/modules/`](packages/vx/docs/modules/) — one reference page per source module
|
|
294
302
|
|
|
295
|
-
The
|
|
296
|
-
|
|
303
|
+
The design record lives under [`packages/vx/docs/design/`](packages/vx/docs/design/); the
|
|
304
|
+
maintainers' handoff is [`packages/vx/docs/STATUS.md`](packages/vx/docs/STATUS.md).
|
|
297
305
|
|
|
298
306
|
## Status
|
|
299
307
|
|
|
300
308
|
**Pre-alpha.** The schema is settling; we bump `CACHE_VERSION` rather
|
|
301
|
-
than maintain back-compat.
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
309
|
+
than maintain back-compat. **~2,500 core tests plus the package suites; CI green on every commit**;
|
|
310
|
+
the project dogfoods itself (`vx run ci`). Published on npm:
|
|
311
|
+
[`@vzn/vx`](https://www.npmjs.com/package/@vzn/vx) (a prebuilt standalone
|
|
312
|
+
binary).
|
|
305
313
|
|
|
306
314
|
Production readiness for the **core task runner**: the semantics are
|
|
307
|
-
solid; it is dogfooded continuously.
|
|
308
|
-
is
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
|
312
|
-
|
|
|
313
|
-
|
|
|
314
|
-
| `
|
|
315
|
-
|
|
|
316
|
-
|
|
|
317
|
-
| OTel export (`@vzn/vx-otel`)
|
|
318
|
-
|
|
|
315
|
+
solid; it is dogfooded continuously. Linux and macOS, x64 and arm64;
|
|
316
|
+
Windows runs vx under WSL (POSIX shell is the API), with no native
|
|
317
|
+
build.
|
|
318
|
+
|
|
319
|
+
| Surface | Maturity | Notes |
|
|
320
|
+
| -------------------------------------------------- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
321
|
+
| Core task runner + caching | **production-ready** | dogfooded continuously; ~2,500 core tests + the package suites, green |
|
|
322
|
+
| Plugin pipeline (9 hooks, `commands` included) | **shippable** | crash-isolated, re-validated; the local executor + cache are the floor under every plugin |
|
|
323
|
+
| `vx init` / `@vzn/vx-migrate` (scripts; Turbo, Nx) | **shippable** | one config per package, TODOs where a source cannot say |
|
|
324
|
+
| REAPI remote cache + execution (`@vzn/vx-reapi`) | **shippable** | Bazel AC + CAS + Execute; NativeLink / BuildBuddy / Buildbarn / bazel-remote |
|
|
325
|
+
| OTel export (`@vzn/vx-otel`) | **shippable** | OTLP traces + metrics + logs, zero SDK deps |
|
|
326
|
+
| GitHub Actions (`@vzn/vx-github`) | **shippable** | job summary + Checks API run |
|
|
327
|
+
| MCP server (`@vzn/vx-mcp`) | **shippable** | `vx mcp` — read-only tools for AI agents, no SDK |
|
|
328
|
+
| Adoption (`@vzn/vx-migrate`) | **shippable** | `turbo()`: a `turbo.json` workspace runs with no `vx.config` written; `turboCache()` / `nxCache()`: any `/v8/artifacts` or Nx `/v1/cache` server; the migrate CLI |
|
|
329
|
+
| Lockfile keys (`@vzn/vx-lockfile`) | **shippable** | `pnpm()` `bun()` `npm()` `yarn()`: per-project dependency-closure keys; `--affected` follows |
|
|
319
330
|
|
|
320
331
|
## Development
|
|
321
332
|
|
|
322
333
|
```sh
|
|
323
334
|
git clone https://github.com/vznjs/vx && cd vx
|
|
324
335
|
bun install
|
|
325
|
-
bun src/bin.ts run ci
|
|
326
|
-
bun src/bin.ts run build
|
|
336
|
+
bun packages/vx/src/bin.ts run ci --all # lint + test + docs build, every package
|
|
337
|
+
bun packages/vx/src/bin.ts run build --filter @vzn/vx # cross-target binaries → packages/vx/dist/
|
|
327
338
|
```
|
|
328
339
|
|
|
329
|
-
vx is self-hosted: every dev task routes through `bun src/bin.ts run <task>` per
|
|
340
|
+
vx is self-hosted: every dev task routes through `bun packages/vx/src/bin.ts run <task>` per each package's own `vx.config.ts`. No `package.json` scripts; CI invokes vx directly. Start with [`packages/vx/docs/STATUS.md`](packages/vx/docs/STATUS.md) — the living handoff — and `CLAUDE.md`.
|
|
330
341
|
|
|
331
342
|
## License
|
|
332
343
|
|
package/index.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Root entry shim. Bun 1.4.0's `--compile` binaries resolve an on-disk
|
|
2
|
+
// package by directory convention (`<pkg>/index.ts`, `<pkg>/<subpath>/index.ts`)
|
|
3
|
+
// and ignore package.json `exports` / `main` (measured 2026-09-03: an
|
|
4
|
+
// entry of `./src/index.ts` resolved to the root `index.ts` regardless of the
|
|
5
|
+
// manifest, and a package with no root file was "not found"). Without this
|
|
6
|
+
// file every `import … from '@vzn/vx'` in a workspace config fails under the
|
|
7
|
+
// standalone binary. The exports map still wins everywhere else and points
|
|
8
|
+
// at the same module, so this is one extra hop for the binary and nothing
|
|
9
|
+
// for anyone else.
|
|
10
|
+
export * from './src/index.js'
|
package/launcher.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// npm launcher for a vx command — the entry a published package's `bin` points
|
|
3
3
|
// at. It execs the prebuilt standalone binary shipped as a per-platform
|
|
4
|
-
// optionalDependency, so end users get the command WITHOUT installing Bun.
|
|
5
|
-
//
|
|
6
|
-
//
|
|
4
|
+
// optionalDependency, so end users get the command WITHOUT installing Bun.
|
|
5
|
+
// Everything is derived from this package's OWN name, read from the
|
|
6
|
+
// package.json sitting beside this file, so any package built by
|
|
7
|
+
// scripts/build-npm.ts can carry it:
|
|
7
8
|
//
|
|
8
|
-
// @vzn/vx
|
|
9
|
-
// @vzn/vx-cloud → platform pkg @vzn/vx-cloud-<key>, binary `vx-cloud`
|
|
9
|
+
// @vzn/vx → platform pkg @vzn/vx-<key>, binary `vx`
|
|
10
10
|
//
|
|
11
11
|
// Resolution order:
|
|
12
12
|
// 1. the matching <name>-<platform> optionalDependency's binary (the normal
|
|
@@ -26,11 +26,10 @@ const require = createRequire(import.meta.url)
|
|
|
26
26
|
const here = dirname(fileURLToPath(import.meta.url))
|
|
27
27
|
const pkg = require('./package.json')
|
|
28
28
|
|
|
29
|
-
// Derive the platform-package prefix + binary basename from this package's
|
|
30
|
-
//
|
|
31
|
-
//
|
|
32
|
-
//
|
|
33
|
-
// entry: `src/bin.ts` for vx, `src/cli/bin.ts` for vx-cloud.
|
|
29
|
+
// Derive the platform-package prefix + binary basename from this package's
|
|
30
|
+
// name. `base` is the unscoped name — the command AND the binary filename
|
|
31
|
+
// inside the platform package. `vxSourceEntry` (a package.json field) is the
|
|
32
|
+
// source-mode entry, `src/bin.ts` by default.
|
|
34
33
|
const name = pkg.name
|
|
35
34
|
const base = name.replace(/^@[^/]+\//, '')
|
|
36
35
|
const sourceEntry = pkg.vxSourceEntry ?? 'src/bin.ts'
|
|
@@ -86,7 +85,7 @@ process.stderr.write(
|
|
|
86
85
|
`${base}: no prebuilt binary for ${key}.\n` +
|
|
87
86
|
` Supported platforms: ${supported}.\n` +
|
|
88
87
|
` If your platform should be supported, reinstall so npm fetches the\n` +
|
|
89
|
-
` matching ${name}-${key} optionalDependency, or install Bun (>=1.
|
|
88
|
+
` matching ${name}-${key} optionalDependency, or install Bun (>=1.4) to\n` +
|
|
90
89
|
` run ${base} from source.\n`,
|
|
91
90
|
)
|
|
92
91
|
process.exit(1)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vzn/vx",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.21",
|
|
4
4
|
"description": "An open, extensible monorepo task runner.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -17,21 +17,25 @@
|
|
|
17
17
|
"node": ">=18"
|
|
18
18
|
},
|
|
19
19
|
"optionalDependencies": {
|
|
20
|
-
"@vzn/vx-linux-x64": "0.0.
|
|
21
|
-
"@vzn/vx-linux-arm64": "0.0.
|
|
22
|
-
"@vzn/vx-darwin-x64": "0.0.
|
|
23
|
-
"@vzn/vx-darwin-arm64": "0.0.
|
|
20
|
+
"@vzn/vx-linux-x64": "0.0.21",
|
|
21
|
+
"@vzn/vx-linux-arm64": "0.0.21",
|
|
22
|
+
"@vzn/vx-darwin-x64": "0.0.21",
|
|
23
|
+
"@vzn/vx-darwin-arm64": "0.0.21"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@anthropic-ai/sandbox-runtime": "^0.0.
|
|
26
|
+
"@anthropic-ai/sandbox-runtime": "^0.0.75"
|
|
27
27
|
},
|
|
28
28
|
"files": [
|
|
29
|
+
"index.ts",
|
|
29
30
|
"src",
|
|
30
31
|
"launcher.mjs",
|
|
31
32
|
"README.md",
|
|
32
33
|
"LICENSE"
|
|
33
34
|
],
|
|
34
|
-
"repository":
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "git+https://github.com/vznjs/vx.git"
|
|
38
|
+
},
|
|
35
39
|
"homepage": "https://github.com/vznjs/vx#readme",
|
|
36
40
|
"bugs": "https://github.com/vznjs/vx/issues",
|
|
37
41
|
"license": "MIT",
|
package/src/bin.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
import { run } from './cli/index.js'
|
|
3
|
-
import {
|
|
2
|
+
import { registerCoreAlias, run } from './cli/index.js'
|
|
3
|
+
import { isUserError } from './util/index.js'
|
|
4
|
+
|
|
5
|
+
// Every `import … from '@vzn/vx'` this process evaluates — a plugin
|
|
6
|
+
// package, a workspace or project config — resolves to THIS core, not to
|
|
7
|
+
// a second copy from node_modules (core-alias.ts says why and what it
|
|
8
|
+
// costs). Registered before any verb runs; the façade loads on first use.
|
|
9
|
+
registerCoreAlias(() => import('./index.js') as Promise<Record<string, unknown>>)
|
|
4
10
|
|
|
5
11
|
// Wrapped in an explicit async main so `bun build --compile` accepts
|
|
6
12
|
// the file. The compile target doesn't allow top-level await.
|
|
@@ -12,8 +18,12 @@ async function main(): Promise<void> {
|
|
|
12
18
|
// print the message only; the stack is noise the user can't act
|
|
13
19
|
// on. Everything else gets the full stack so internal bugs are
|
|
14
20
|
// debuggable.
|
|
15
|
-
if (err
|
|
16
|
-
|
|
21
|
+
if (isUserError(err)) {
|
|
22
|
+
// A message that already names the tool (`vx why: …`, thrown by a verb
|
|
23
|
+
// that wants its own name in the line) is printed as it is; prefixing
|
|
24
|
+
// it produced `vx: vx why: …` (walkthrough, 2026-09-04).
|
|
25
|
+
const m = err.message
|
|
26
|
+
process.stderr.write(m.startsWith('vx ') ? `${m}\n` : `vx: ${m}\n`)
|
|
17
27
|
} else {
|
|
18
28
|
const message = err instanceof Error ? (err.stack ?? err.message) : String(err)
|
|
19
29
|
process.stderr.write(`vx: ${message}\n`)
|