@vzn/vx 0.0.637 → 0.0.638
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 +41 -14
- package/docs/cli.md +115 -73
- package/docs/execution.md +1 -1
- package/docs/features.md +6 -5
- package/docs/schema.md +24 -15
- package/package.json +5 -5
- package/schemas/plan.json +2 -2
- package/skills/vx/SKILL.md +13 -2
- package/src/bin.ts +13 -7
- package/src/cache/cache.ts +21 -2
- package/src/cache/chained-cache.ts +4 -0
- package/src/cache/index.ts +9 -1
- package/src/cache/inputs.ts +0 -24
- package/src/cache/layer.ts +7 -1
- package/src/cache/layered-cache.ts +4 -0
- package/src/cache/plugin-cache.ts +248 -0
- package/src/cache/policy.ts +9 -0
- package/src/cache/run-history.ts +68 -0
- package/src/cache/run-store.ts +77 -0
- package/src/cache/schema.ts +38 -9
- package/src/cache/scoped-cache.ts +15 -2
- package/src/cli/cache.ts +33 -16
- package/src/cli/completions.ts +9 -5
- package/src/cli/help.ts +16 -7
- package/src/cli/index.ts +25 -11
- package/src/cli/info.ts +6 -5
- package/src/cli/init.ts +14 -15
- package/src/cli/last.ts +14 -7
- package/src/cli/lock.ts +39 -27
- package/src/cli/plan-format.ts +5 -3
- package/src/cli/plugin-commands.ts +77 -6
- package/src/cli/plugin-templates.ts +1 -1
- package/src/cli/run.ts +14 -12
- package/src/cli/select.ts +18 -9
- package/src/cli/show.ts +66 -40
- package/src/cli/task-verb.ts +4 -4
- package/src/cli/upgrade.ts +20 -11
- package/src/cli/watch-filter.ts +7 -2
- package/src/cli/watch-judge.ts +6 -1
- package/src/cli/watch.ts +44 -20
- package/src/cli/why.ts +10 -1
- package/src/cli/workspace-config.ts +2 -2
- package/src/graph/scheduler.ts +8 -0
- package/src/graph/task-graph.ts +32 -4
- package/src/index.ts +11 -1
- package/src/orchestrator/affected-tasks.ts +8 -3
- package/src/orchestrator/doctor.ts +1 -1
- package/src/orchestrator/execute-task.ts +26 -43
- package/src/orchestrator/failure-mode.ts +19 -10
- package/src/orchestrator/framed-output.ts +1 -2
- package/src/orchestrator/history.ts +60 -4
- package/src/orchestrator/index.ts +2 -1
- package/src/orchestrator/logger.ts +9 -2
- package/src/orchestrator/metrics.ts +7 -3
- package/src/orchestrator/plugin-host.ts +14 -4
- package/src/orchestrator/plugin.ts +80 -8
- package/src/orchestrator/prepare.ts +51 -7
- package/src/orchestrator/projects.ts +3 -0
- package/src/orchestrator/remote-prefetch.ts +9 -5
- package/src/orchestrator/run-records.ts +1 -1
- package/src/orchestrator/run.ts +126 -27
- package/src/orchestrator/status-line.ts +1 -1
- package/src/orchestrator/summary.ts +69 -44
- package/src/orchestrator/telemetry.ts +1 -1
- package/src/settings.ts +12 -1
- package/src/{orchestrator → util}/colors.ts +5 -0
- package/src/util/config-frame.ts +31 -2
- package/src/util/errors.ts +32 -0
- package/src/util/index.ts +8 -1
- package/src/util/refusal-notice.ts +111 -0
- package/src/util/report.ts +31 -0
- package/src/util/ui.ts +186 -0
- package/src/workspace/affected.ts +20 -23
- package/src/workspace/dependency-rules.ts +12 -4
- package/src/workspace/migration.ts +87 -91
- package/src/workspace/workspace.ts +5 -4
package/docs/caching.md
CHANGED
|
@@ -839,10 +839,10 @@ Skipped when:
|
|
|
839
839
|
on, so it DOES clean (the saved snapshot must be clean).
|
|
840
840
|
- `cache.outputs.clean` is `false` (on the task, else the workspace's
|
|
841
841
|
`cache.outputs.clean`): the command sees last run's outputs (tsc's
|
|
842
|
-
`.tsbuildinfo`).
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
cleans before its restore.
|
|
842
|
+
`.tsbuildinfo`). You opt out of the clean-tree guarantee: the save
|
|
843
|
+
stores every file the outputs match after the run, so a leftover from
|
|
844
|
+
an older build is cached and restored everywhere. A retry cleans as
|
|
845
|
+
usual; a hit still cleans before its restore.
|
|
846
846
|
|
|
847
847
|
A declared output the process cannot remove (a `dist/` another user
|
|
848
848
|
wrote, a read-only checkout) fails the task with `cannot remove declared
|
|
@@ -1192,7 +1192,8 @@ in `~/.vx/<id>/cache`, and each workspace keeps only its own index in
|
|
|
1192
1192
|
its `.vx/cache`: every checkout of the repository hits what another
|
|
1193
1193
|
saved (a second clone, a worktree), and none reads another's history.
|
|
1194
1194
|
Task timings are shared too: `task_durations`, what a duration forecast
|
|
1195
|
-
reads, so a new worktree has one on its first run.
|
|
1195
|
+
reads, so a new worktree has one on its first run. So are plugins' own
|
|
1196
|
+
entries (`plugin_blobs`, a plugin's `ctx.cache`).
|
|
1196
1197
|
The id is Nx 23's: 16 hex of a sha256 of the remote (`origin`, then
|
|
1197
1198
|
`upstream`, `base`, the first; `host/owner/repo` in lower case, so ssh
|
|
1198
1199
|
and https agree) and the workspace's path in the repository; with no
|
|
@@ -1204,7 +1205,7 @@ owner-only; vx closes one of yours that others can read (chmod 700), and one oth
|
|
|
1204
1205
|
~/.vx/<id>/cache/ the shared store
|
|
1205
1206
|
├── store.db entries, entry_stdout, output_files,
|
|
1206
1207
|
│ entry_inputs, task_durations,
|
|
1207
|
-
│ store_meta; artifacts
|
|
1208
|
+
│ plugin_blobs, store_meta; artifacts
|
|
1208
1209
|
│ of at most 32 KiB compressed (v33)
|
|
1209
1210
|
└── <hash>.tar.zst the larger artifacts (below)
|
|
1210
1211
|
|
|
@@ -1469,9 +1470,9 @@ keep). The artifacts stay: each is indexed again from its own bytes
|
|
|
1469
1470
|
when its task next asks for its key (below).
|
|
1470
1471
|
|
|
1471
1472
|
```sql
|
|
1472
|
-
-- src/cache/schema.ts (SCHEMA_VERSION = '
|
|
1473
|
+
-- src/cache/schema.ts (SCHEMA_VERSION = 'v38', in cache.ts)
|
|
1473
1474
|
-- With a shared store, entries, entry_stdout, output_files, entry_inputs,
|
|
1474
|
-
-- store_meta and
|
|
1475
|
+
-- store_meta, task_durations, task_outcomes, blob_sizes and plugin_blobs live in its store.db, attached as `store`; the rest is
|
|
1475
1476
|
-- the workspace's cache.db. A named cache dir holds all of them.
|
|
1476
1477
|
|
|
1477
1478
|
CREATE TABLE schema_meta (
|
|
@@ -1537,10 +1538,6 @@ CREATE TABLE runs (
|
|
|
1537
1538
|
-- the history reader bounds its scan by rowid instead (see history.md).
|
|
1538
1539
|
CREATE INDEX runs_started_at ON runs(started_at);
|
|
1539
1540
|
CREATE INDEX runs_run_id ON runs(run_id);
|
|
1540
|
-
-- The one keyed index, PARTIAL over failed rows: a green run's inserts only
|
|
1541
|
-
-- evaluate its predicate, and the flakiness probe after a miss
|
|
1542
|
-
-- (failure-mode.ts, "did this key ever fail?") reads a few leaves.
|
|
1543
|
-
CREATE INDEX runs_failed ON runs(hash) WHERE status = 'failed';
|
|
1544
1541
|
|
|
1545
1542
|
-- Every non-group, non-aborted outcome of a run gets a row, so
|
|
1546
1543
|
-- `invocations.task_count` always equals `COUNT(*)` here for that run_id
|
|
@@ -1575,7 +1572,8 @@ CREATE TABLE file_hashes (
|
|
|
1575
1572
|
-- The size of each index blob the enumeration checked against the
|
|
1576
1573
|
-- worktree size git recorded (§ Cache key derivation, A-60): fixed for
|
|
1577
1574
|
-- its OID, so a warm run asks git for none. Swept with file_hashes by
|
|
1578
|
-
-- seen_at, the time the row was written.
|
|
1575
|
+
-- seen_at, the time the row was written. v38: in the store, so a worktree
|
|
1576
|
+
-- reads what another learned.
|
|
1579
1577
|
CREATE TABLE blob_sizes (
|
|
1580
1578
|
oid TEXT PRIMARY KEY,
|
|
1581
1579
|
size INTEGER NOT NULL,
|
|
@@ -1636,7 +1634,7 @@ CREATE TABLE invocations (
|
|
|
1636
1634
|
run_id TEXT PRIMARY KEY, -- UUIDv7, == runs.run_id
|
|
1637
1635
|
command TEXT NOT NULL, -- full argv, e.g. "vx run build --all"
|
|
1638
1636
|
requested_tasks TEXT NOT NULL, -- JSON string[] of options.tasks
|
|
1639
|
-
cache_policy TEXT NOT NULL, --
|
|
1637
|
+
cache_policy TEXT NOT NULL, -- the --cache-policy spec, e.g. "local:rw,remote:r"
|
|
1640
1638
|
concurrency INTEGER NOT NULL,
|
|
1641
1639
|
flow TEXT, -- 'focused' | 'broad' | NULL (programmatic)
|
|
1642
1640
|
started_at INTEGER NOT NULL, -- ms-epoch
|
|
@@ -1696,6 +1694,8 @@ CREATE TABLE store_meta (
|
|
|
1696
1694
|
-- v36: each executed success's duration, appended in the run's history
|
|
1697
1695
|
-- transaction, in the store so every worktree forecasts from it.
|
|
1698
1696
|
-- source: 'branch:<name>'; the forecast reads the newest five per task.
|
|
1697
|
+
-- v37: 'remote' rows are a default-branch commit's timings a plugin
|
|
1698
|
+
-- imported, one per (sha, task).
|
|
1699
1699
|
CREATE TABLE task_durations (
|
|
1700
1700
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
1701
1701
|
project TEXT NOT NULL,
|
|
@@ -1706,6 +1706,33 @@ CREATE TABLE task_durations (
|
|
|
1706
1706
|
recorded_at INTEGER NOT NULL
|
|
1707
1707
|
);
|
|
1708
1708
|
CREATE INDEX task_durations_task ON task_durations(project, task, source, id);
|
|
1709
|
+
CREATE UNIQUE INDEX task_durations_remote
|
|
1710
|
+
ON task_durations(sha, project, task) WHERE source = 'remote';
|
|
1711
|
+
|
|
1712
|
+
-- v38: the flaky record (failure-mode.ts), in the store so a key that
|
|
1713
|
+
-- passed in one worktree and failed in another is flaky in both. Every
|
|
1714
|
+
-- executed success or failure that names its key (keyed, cached, not run
|
|
1715
|
+
-- behind a failure), and a key's first hit: a later hit replays a pass on
|
|
1716
|
+
-- record, so a warm run on passed keys writes no row (one index probe,
|
|
1717
|
+
-- ~1 ms per 1,000 hits). Pruned by age with the run history.
|
|
1718
|
+
CREATE TABLE task_outcomes (
|
|
1719
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
1720
|
+
project TEXT NOT NULL,
|
|
1721
|
+
task TEXT NOT NULL,
|
|
1722
|
+
hash TEXT NOT NULL,
|
|
1723
|
+
status TEXT NOT NULL,
|
|
1724
|
+
attempts INTEGER,
|
|
1725
|
+
recorded_at INTEGER NOT NULL
|
|
1726
|
+
);
|
|
1727
|
+
CREATE INDEX task_outcomes_hash ON task_outcomes(hash, status);
|
|
1728
|
+
|
|
1729
|
+
-- v37: a plugin's own entries (`ctx.cache`), by core's key for its
|
|
1730
|
+
-- name; written once, pruned by age with the run history.
|
|
1731
|
+
CREATE TABLE plugin_blobs (
|
|
1732
|
+
key TEXT PRIMARY KEY,
|
|
1733
|
+
bytes BLOB NOT NULL,
|
|
1734
|
+
at INTEGER NOT NULL
|
|
1735
|
+
);
|
|
1709
1736
|
|
|
1710
1737
|
-- v33: an artifact of at most 32 KiB compressed, its exact <hash>.tar.zst
|
|
1711
1738
|
-- bytes, written in the transaction that writes its entry rows. In the
|
package/docs/cli.md
CHANGED
|
@@ -69,7 +69,8 @@ declare task(s): <name>.` on stderr, a run and `--dry` / `--graph` alike
|
|
|
69
69
|
declared task (or, for `pkg#task`, a runnable spec) is within two edits,
|
|
70
70
|
and with no name that near, what exists: `Tasks: build, test.`, `No
|
|
71
71
|
project is named zzz; projects: a, b.`, or `a's tasks: build, test.`
|
|
72
|
-
(M-56),
|
|
72
|
+
(M-56), each followed by ``A run reads the lock: after editing a
|
|
73
|
+
vx.config, run `vx lock`.`` (a task just added is not in the lock yet),
|
|
73
74
|
and with `Only projects outside the selection declare <name> — pass
|
|
74
75
|
--all, or --filter to pick them.` when the run was scoped (the cwd's
|
|
75
76
|
project, a `--filter`) and a project outside the scope declares it
|
|
@@ -999,7 +1000,9 @@ $ vx run build lint --affected=main --dry
|
|
|
999
1000
|
`kind` is `input` (a changed `file` is a declared input), `project` (its
|
|
1000
1001
|
project changed and the task reads it whole: an uncached task, or a changed
|
|
1001
1002
|
`file` no cached task of the project declares, often an output git does not
|
|
1002
|
-
ignore; no `file` for a
|
|
1003
|
+
ignore; no `file` for a config import), `workspace` (a workspace-wide
|
|
1004
|
+
`file` changed: the workspace config, or a root file a plugin claims such
|
|
1005
|
+
as a lockfile, reached every task of the project),
|
|
1003
1006
|
`package` (a `^` edge passes a changed `project` with no such task),
|
|
1004
1007
|
`named` (`pkg#task` beside a bare task) or `selected` (another filter
|
|
1005
1008
|
selected its project). `via` is the `dependsOn` chain, nearest first, to
|
|
@@ -1392,7 +1395,10 @@ run...` precedes it.
|
|
|
1392
1395
|
heard from its nearest directory that exists and each one above it,
|
|
1393
1396
|
and a watch whose
|
|
1394
1397
|
directory was replaced is armed again (an OS watch holds the deleted
|
|
1395
|
-
one; `watch-recreated-dirs.test.ts`).
|
|
1398
|
+
one; `watch-recreated-dirs.test.ts`). There, a project directory
|
|
1399
|
+
that is still the same one starts no cycle: a task writing at its
|
|
1400
|
+
top level moved its mtime, which macOS reports to the parent
|
|
1401
|
+
(`watch-project-dir-write.test.ts`). Under `--filter` or
|
|
1396
1402
|
`--affected` the scope is the one resolved at start, and a new
|
|
1397
1403
|
project joins it only as a dependency of it. A task's own declared outputs (`cache.outputs.files`,
|
|
1398
1404
|
`outputs.workspaceFiles`; a plugin's `project` stage counts, as in
|
|
@@ -1432,7 +1438,10 @@ run...` precedes it.
|
|
|
1432
1438
|
starts a cycle, since no cache key can see it (a user's edit to one
|
|
1433
1439
|
still does in a project with a task that has a command and no cache,
|
|
1434
1440
|
which reads what it likes, item 947, outside any project nested
|
|
1435
|
-
in it
|
|
1441
|
+
in it; a write the last cycle made is not, read off the later of
|
|
1442
|
+
its mtime and ctime, so an output a cache hit restores with its
|
|
1443
|
+
saved mtime is the run's, and so is the restore's own `.vx-tmp-*`
|
|
1444
|
+
file, `watch-restored-output.test.ts`) — or declared an
|
|
1436
1445
|
output, or the loop re-runs on it; after three such cycles in a row
|
|
1437
1446
|
watch names the path and the remedy, once, and keeps going. A dev
|
|
1438
1447
|
server the last cycle left running counts as that cycle for as long
|
|
@@ -1467,9 +1476,11 @@ watch events within 2000 ms; polling every 250 ms instead`.
|
|
|
1467
1476
|
changed, then its task rows as `vx run` prints them, with no footer.
|
|
1468
1477
|
The named path is the first changed one that still exists, so an
|
|
1469
1478
|
editor's temporary file renamed away names nothing; a deletion names
|
|
1470
|
-
the cycle when nothing else changed.
|
|
1471
|
-
|
|
1472
|
-
|
|
1479
|
+
the cycle when nothing else changed. The `watching` line is said
|
|
1480
|
+
once: a cycle that re-reads the watched set (a member came or went,
|
|
1481
|
+
the lock or a plugin changed) says nothing more; `VX_DEBUG_WATCH=1`
|
|
1482
|
+
says each arm on stderr as `vx watch: armed N projects`. Errors and
|
|
1483
|
+
refusals go to stderr. The
|
|
1473
1484
|
orchestrator is invoked again with the same options, save one: the
|
|
1474
1485
|
`--affected` diff is read once, for the initial run. A later cycle
|
|
1475
1486
|
runs the requested task in every project of the scope fixed at start,
|
|
@@ -1490,7 +1501,8 @@ Always ignored (no re-trigger):
|
|
|
1490
1501
|
tracked + untracked-not-ignored — so a cycle it started could change
|
|
1491
1502
|
nothing. A tracked file that matches a pattern is not ignored, by
|
|
1492
1503
|
git's own rule; outside a repository nothing is.
|
|
1493
|
-
- Files ending in
|
|
1504
|
+
- Files ending in `~` (editor swap files), and a restore's own
|
|
1505
|
+
`.vx-tmp-*` file.
|
|
1494
1506
|
- The run's **resolved cache directory**, wherever it is. `.vx/cache/` covers the
|
|
1495
1507
|
default, but `defineWorkspace({ cache: { dir } })` and `--cache-dir` can put it
|
|
1496
1508
|
anywhere; watching it would let vx's own cache writes trigger the next
|
|
@@ -1661,16 +1673,19 @@ bound clears the whole cache when that is really what you want.
|
|
|
1661
1673
|
|
|
1662
1674
|
```
|
|
1663
1675
|
$ vx cache clean --older-than 30d
|
|
1664
|
-
|
|
1676
|
+
✓ vx cache clean freed 1.3 GB
|
|
1665
1677
|
|
|
1666
|
-
|
|
1667
|
-
Pruned 18 entries (320 MB freed)
|
|
1678
|
+
42 entries
|
|
1668
1679
|
|
|
1669
1680
|
$ vx cache clean --older-than 30d # after a SCHEMA_VERSION bump
|
|
1670
|
-
|
|
1681
|
+
✓ vx cache clean freed 1.3 GB
|
|
1682
|
+
|
|
1683
|
+
42 orphaned artifacts
|
|
1671
1684
|
|
|
1672
1685
|
$ vx cache clean --older-than 30d --dry-run
|
|
1673
|
-
|
|
1686
|
+
› vx cache clean would free 1.3 GB (dry run)
|
|
1687
|
+
|
|
1688
|
+
42 entries · 3 orphaned artifacts
|
|
1674
1689
|
```
|
|
1675
1690
|
|
|
1676
1691
|
`--dry-run` picks the victims under the same policy and counts the
|
|
@@ -1694,8 +1709,8 @@ artifact that vanishes before its restore is a miss, and the task runs
|
|
|
1694
1709
|
Exit codes:
|
|
1695
1710
|
|
|
1696
1711
|
- `0` — pruning completed (zero or more entries evicted). A workspace
|
|
1697
|
-
that never ran has no cache:
|
|
1698
|
-
nothing is created.
|
|
1712
|
+
that never ran has no cache: `› vx cache clean nothing to free`,
|
|
1713
|
+
and nothing is created.
|
|
1699
1714
|
- `1` — parse error, missing policy, or workspace-discovery error.
|
|
1700
1715
|
|
|
1701
1716
|
`vx cache clean` resolves the workspace root from cwd and honors a
|
|
@@ -1723,17 +1738,19 @@ and the directory goes only if that empties it. A directory with no
|
|
|
1723
1738
|
names goes only if it is one (`.vx/<id>/cache` holding a `store.db`): the
|
|
1724
1739
|
index is a file in the checkout, which a commit or a restored CI cache
|
|
1725
1740
|
could point at any directory. A workspace that never ran says
|
|
1726
|
-
|
|
1741
|
+
`› vx cache clean nothing to free`. The next run misses every task once
|
|
1727
1742
|
and saves again.
|
|
1728
1743
|
|
|
1729
1744
|
```
|
|
1730
1745
|
$ vx cache clean
|
|
1731
|
-
|
|
1746
|
+
✓ vx cache clean freed 1.4 GB
|
|
1747
|
+
|
|
1732
1748
|
.vx/cache
|
|
1733
1749
|
/home/me/.vx/3f2a9c01b4d5e6f7/cache
|
|
1734
1750
|
|
|
1735
1751
|
$ vx cache clean --global --dry-run
|
|
1736
|
-
|
|
1752
|
+
› vx cache clean would free 3.1 GB (dry run)
|
|
1753
|
+
|
|
1737
1754
|
.vx/cache
|
|
1738
1755
|
/home/me/.vx/3f2a9c01b4d5e6f7/cache
|
|
1739
1756
|
/home/me/.vx/9b8e7d6c5a4f3e2d/cache
|
|
@@ -1775,8 +1792,8 @@ add directories (X-143). Before writing, it
|
|
|
1775
1792
|
builds the graph of every task the workspace declares, `graph` stage
|
|
1776
1793
|
included, and checks the graph rules (`run.rules`), which no run
|
|
1777
1794
|
checks, `dependencies` (which projects a project may depend on,
|
|
1778
|
-
`VX_E_DEPENDENCY_RULE`) among them: a broken one prints
|
|
1779
|
-
|
|
1795
|
+
`VX_E_DEPENDENCY_RULE`) among them: a broken one prints `✗ vx lock lock not written`
|
|
1796
|
+
with the rule's refusal under it and writes nothing.
|
|
1780
1797
|
|
|
1781
1798
|
```
|
|
1782
1799
|
vx lock # Evaluate all vx.config.* now; write .vx/projects.lock.json.
|
|
@@ -1830,7 +1847,7 @@ A project with no `vx.config.*` — its tasks from a plugin's `project`
|
|
|
1830
1847
|
stage (`turbo()` from `@vzn/vx-migrate`), or none at all — has nothing
|
|
1831
1848
|
to freeze: the lock records nothing for it, `--check` does not audit
|
|
1832
1849
|
it, and a run still loads its tasks live. Both verbs name such
|
|
1833
|
-
projects that have tasks (`
|
|
1850
|
+
projects that have tasks (`0 project configs → .vx/projects.lock.json (no
|
|
1834
1851
|
vx.config, so not locked: app, lib)`, five names then `and N more`),
|
|
1835
1852
|
so an empty lock on a plugin-only workspace never reads like an audit.
|
|
1836
1853
|
One with no task (core's default `build` aside) is not named.
|
|
@@ -2035,8 +2052,9 @@ binary keeps the old one's mode (and, as root, its owner), and must
|
|
|
2035
2052
|
answer `--version` before the upgrade reports it installed: one that
|
|
2036
2053
|
does not start on this machine, or does not answer within 10 s, is
|
|
2037
2054
|
swapped back for the previous vx, and the command exits 1 saying so
|
|
2038
|
-
(item 1097). On the version it
|
|
2039
|
-
<version>` and downloads
|
|
2055
|
+
(item 1097): `✓ vx upgrade installed 0.0.2`. On the version it
|
|
2056
|
+
already is it says `› vx upgrade already at <version>` and downloads
|
|
2057
|
+
nothing.
|
|
2040
2058
|
|
|
2041
2059
|
**A vx a package manager installed** (the npm package's launcher runs
|
|
2042
2060
|
`…/node_modules/@vzn/vx-<os>-<arch>/vx`) is upgraded by that package
|
|
@@ -2060,10 +2078,16 @@ root adds `--workspace-root`. The lockfile is updated by that manager.
|
|
|
2060
2078
|
Run inside a project that installs `@vzn/vx`, a global vx hands
|
|
2061
2079
|
`vx upgrade` to the project's own (§ Which vx runs), so the project's
|
|
2062
2080
|
dependency is what moves.
|
|
2063
|
-
vx prints what it runs
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2081
|
+
vx prints what it runs, runs it there, and exits with an error if it
|
|
2082
|
+
fails:
|
|
2083
|
+
|
|
2084
|
+
```
|
|
2085
|
+
› vx upgrade 0.0.1 → 0.0.2
|
|
2086
|
+
|
|
2087
|
+
bun add @vzn/vx@0.0.2 in /repo
|
|
2088
|
+
```
|
|
2089
|
+
|
|
2090
|
+
vx never installs Node or a package manager: one not on `PATH` is refused with the command to run. A vx run from an npx or
|
|
2067
2091
|
bunx cache has nothing installed to upgrade, and says to ask for
|
|
2068
2092
|
`@vzn/vx@latest` instead.
|
|
2069
2093
|
|
|
@@ -2321,12 +2345,15 @@ lists core's verbs. A plugin's verb exists once its plugin is in
|
|
|
2321
2345
|
No project in scope declares a requested task. The message lists the
|
|
2322
2346
|
tasks it found; `vx show --format json` lists each project's. Check the
|
|
2323
2347
|
spelling, and the scope: `--filter`, `--all`, or the project the working
|
|
2324
|
-
directory is in.
|
|
2348
|
+
directory is in. A run reads its configs from the lock, so a task
|
|
2349
|
+
added to a `vx.config` since the last `vx lock` is not there yet: run
|
|
2350
|
+
`vx lock`.
|
|
2325
2351
|
|
|
2326
2352
|
#### `VX_E_UNKNOWN_PROJECT`
|
|
2327
2353
|
|
|
2328
2354
|
`vx show` names a project the workspace does not have. A project is named
|
|
2329
|
-
by its
|
|
2355
|
+
by its config's `name`, else by a plugin (a lockfile plugin names it from
|
|
2356
|
+
its `package.json`), else by its directory; `vx show --format json` lists them.
|
|
2330
2357
|
|
|
2331
2358
|
#### `VX_E_NO_HISTORY`
|
|
2332
2359
|
|
|
@@ -2487,23 +2514,25 @@ Nx's spellings name these: `vx show projects` (when no project or task
|
|
|
2487
2514
|
has that name) and `vx show project <name>` say `vx show` and
|
|
2488
2515
|
`vx show <name>`.
|
|
2489
2516
|
|
|
2490
|
-
No target: one
|
|
2491
|
-
and
|
|
2492
|
-
tasks all come from plugins reads `N tasks (no vx
|
|
2493
|
-
|
|
2494
|
-
vx config
|
|
2495
|
-
`^build` (X-48). A
|
|
2517
|
+
No target: a table, one row per project — name, root-relative dir,
|
|
2518
|
+
task count, and `no vx config` for config-less packages; one whose
|
|
2519
|
+
tasks all come from plugins reads `N tasks from plugins (no vx
|
|
2520
|
+
config)`, and one a configured project depends on reads `1 task,
|
|
2521
|
+
default build (no vx config)`: a run loads it for that dependant's
|
|
2522
|
+
`^build` (X-48). A `tags` column appears when any project has tags. With `--format json`
|
|
2496
2523
|
it's an array of `{ name, dir, tags: string[], tasks: string[] }`.
|
|
2497
2524
|
|
|
2498
2525
|
```
|
|
2499
2526
|
$ vx show
|
|
2500
|
-
|
|
2501
|
-
|
|
2527
|
+
project dir tasks tags
|
|
2528
|
+
app packages/app 3 tasks scope:web
|
|
2529
|
+
bare packages/bare no vx config
|
|
2502
2530
|
```
|
|
2503
2531
|
|
|
2504
|
-
|
|
2505
|
-
`
|
|
2506
|
-
|
|
2532
|
+
A report naming the project opens it: its `dir`, its `tags`, and
|
|
2533
|
+
`config none` for a package with no config file. Then
|
|
2534
|
+
`vx show <project>` prints a block per task, headed by its
|
|
2535
|
+
`project#task`, with every field the run reads: description, command (`(group)` for group tasks), `dependsOn`,
|
|
2507
2536
|
`timeout`, `retries`, `env.passThrough` / `env.define` / `env.secret`,
|
|
2508
2537
|
`remote`, `sandbox`, `persistent`, `interactive` (`yes` / `no`), and the
|
|
2509
2538
|
cache block
|
|
@@ -2521,15 +2550,15 @@ list and `vx show <project>`, but `vx show build`, like
|
|
|
2521
2550
|
|
|
2522
2551
|
```
|
|
2523
2552
|
$ vx show app#build
|
|
2524
|
-
app — packages/app
|
|
2525
2553
|
|
|
2526
|
-
build
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
inputs.
|
|
2532
|
-
|
|
2554
|
+
─ app#build ──────────────────────────────────────────────────
|
|
2555
|
+
dir packages/app
|
|
2556
|
+
description compile the app
|
|
2557
|
+
command tsc -b
|
|
2558
|
+
dependsOn ^build
|
|
2559
|
+
inputs.files src/**
|
|
2560
|
+
inputs.env NODE_ENV
|
|
2561
|
+
outputs.files dist/**
|
|
2533
2562
|
```
|
|
2534
2563
|
|
|
2535
2564
|
Unknown project / task names exit `1` with the same near-miss hint
|
|
@@ -2572,24 +2601,26 @@ counts are zero and `projects lock` says `no` — a broken config is
|
|
|
2572
2601
|
|
|
2573
2602
|
```
|
|
2574
2603
|
$ vx info
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
cache
|
|
2587
|
-
cache
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2604
|
+
|
|
2605
|
+
─ vx info ────────────────────────────────────────────────────
|
|
2606
|
+
vx 0.0.0
|
|
2607
|
+
bun 1.4.2
|
|
2608
|
+
git 2.53.0
|
|
2609
|
+
git status cache core.fsmonitor, core.untrackedCache off
|
|
2610
|
+
workspace root /work/repo
|
|
2611
|
+
projects 12 (34 tasks)
|
|
2612
|
+
plugins 2 — @vzn/vx-reapi (executor, cache); @vzn/vx-otel (telemetry)
|
|
2613
|
+
workers 2 — cgroup CPU quota 2 of 8 cores
|
|
2614
|
+
memory 13 GB usable — cgroup limit; the machine has 16 GB
|
|
2615
|
+
cache dir /work/repo/.vx/cache (8.2 MB, this workspace's run history)
|
|
2616
|
+
cache store /home/me/.vx/3f2a9c1e7b4d5a60/cache (1.3 GB, shared by this repo's checkouts)
|
|
2617
|
+
cache versions keys vx-cache-v43 · index schema v38
|
|
2618
|
+
cache entries 42 (1.3 GB)
|
|
2619
|
+
orphans 3 artifacts (12 MB) the index does not know — `vx cache clean` reaps them
|
|
2620
|
+
task runs (24h) 7 (5 cache hits)
|
|
2621
|
+
flaky tasks 1 — web#test (3 of 11 runs failed on unchanged inputs)
|
|
2622
|
+
sandbox available (9 tasks declare exec.sandbox)
|
|
2623
|
+
projects lock yes
|
|
2593
2624
|
```
|
|
2594
2625
|
|
|
2595
2626
|
- `git` shows `(not found)` when the binary is missing.
|
|
@@ -2905,9 +2936,9 @@ measured. `--stats` does not combine with `--list`, `--failed` or
|
|
|
2905
2936
|
`--log`; `--branch` combines only with `--stats`. `--list --format json`
|
|
2906
2937
|
an array of the same `invocation` objects, newest first. An unknown run id fails
|
|
2907
2938
|
loud and points at `--list`. Before any run, every form says so
|
|
2908
|
-
(
|
|
2909
|
-
|
|
2910
|
-
`--list --failed` prints
|
|
2939
|
+
(`› vx last no runs yet` with `fix vx run`, exit 1; `--list` prints
|
|
2940
|
+
`› vx last no runs yet`, exit 0), and past green runs only,
|
|
2941
|
+
`--list --failed` prints `› vx last no failed runs`. A run id may be typed as a unique prefix; a
|
|
2911
2942
|
prefix several runs share fails and lists them. A replayed run with
|
|
2912
2943
|
failures ends with the command that re-runs them (`re-run what failed:
|
|
2913
2944
|
vx run app#test -- …`, with the arguments the run forwarded to the
|
|
@@ -2994,7 +3025,7 @@ export function mcp(): VxPlugin {
|
|
|
2994
3025
|
mcp: {
|
|
2995
3026
|
description: 'serve the run history to an AI agent over stdio',
|
|
2996
3027
|
async run(argv, ctx) {
|
|
2997
|
-
// ctx.workspaceRoot, ctx.cacheDir, ctx.concurrency, ctx.warn(...)
|
|
3028
|
+
// ctx.workspaceRoot, ctx.cacheDir, ctx.concurrency, ctx.cache, ctx.warn(...)
|
|
2998
3029
|
return 0 // the process exit code
|
|
2999
3030
|
},
|
|
3000
3031
|
},
|
|
@@ -3005,6 +3036,9 @@ export function mcp(): VxPlugin {
|
|
|
3005
3036
|
|
|
3006
3037
|
The plugin's name is its package name, which `definePlugin` reads from
|
|
3007
3038
|
`import.meta`; a plain object is refused when the workspace loads.
|
|
3039
|
+
`ctx.cache` reads the plugin's own entries as `setup` writes them (the
|
|
3040
|
+
local store, then each remote the workspace's cache plugins supply,
|
|
3041
|
+
under the run's scope), read-only, opened on first use.
|
|
3008
3042
|
|
|
3009
3043
|
(`@vzn/vx-schedule-history` ships exactly this: `vx history`, what it
|
|
3010
3044
|
learned per task and the reservation its `admit` hook packs.) The dispatcher tries core's verbs
|
|
@@ -3066,11 +3100,11 @@ what a TASK sees is `exec.env` in `docs/schema.md`.
|
|
|
3066
3100
|
| `VX_CACHE_DOWNLOAD` | [`cache.download`](schema.md#settings) | Which remote hits land on disk: every one, only the requested tasks, or none. |
|
|
3067
3101
|
| `VX_CACHE_INPUT_STABILITY_STRATEGY` | [`cache.inputStability.strategy`](schema.md#settings) | What a write to an input during the command means for the save, for tasks without their own. |
|
|
3068
3102
|
| `VX_CACHE_INPUT_STABILITY_SEVERITY` | [`cache.inputStability.severity`](schema.md#settings) | Whether a skipped save warns or fails the task, for tasks without their own. |
|
|
3069
|
-
| `VX_CACHE_OUTPUTS_CLEAN` | [`cache.outputs.clean`](schema.md#settings) | Remove a task's declared outputs before it runs on a miss, for tasks without their own. |
|
|
3070
3103
|
| `VX_LOCK_REVIEW_FILES` | [`lock.reviewFiles`](schema.md#settings) | `vx lock` writes each project's resolved config, pretty, to `vx.lock.json` beside its `vx.config`, for review; vx never reads it. |
|
|
3071
3104
|
| `VX_WATCH_POLL` | [`watch.poll`](schema.md#settings) | Poll for changes from the start instead of the OS watcher. |
|
|
3072
3105
|
| `VX_CONFIG_WORKER_TIMEOUT` | [`config.workerTimeout`](schema.md#settings) | How long one config evaluation may take. |
|
|
3073
3106
|
| `VX_DEBUG_TIMING` | [`debug.timing`](schema.md#settings) | Print the run's stage timings to stderr. |
|
|
3107
|
+
| `VX_DEBUG_WATCH` | [`debug.watch`](schema.md#settings) | `vx watch`: say on stderr each time the loop arms, with the projects it watches. |
|
|
3074
3108
|
| `VX_DEBUG_DUMPABLE` | [`debug.dumpable`](schema.md#settings) | Linux: keep vx dumpable, so strace or a debugger can read its memory and `/proc/<pid>/fd`, and an unsandboxed task its env. |
|
|
3075
3109
|
| `VX_HANDED_OFF` | — | Set by a global vx that hands the call to the project's own (§ Which vx runs): the path of the vx that handed off, so the receiver does not hand off again. |
|
|
3076
3110
|
| `VX_RUN_WORKSPACE`, `VX_RUN_TASK` | — | Set by vx on every task (below); a `vx run` a task starts reads them back. |
|
|
@@ -3165,7 +3199,7 @@ A broad run looks like:
|
|
|
3165
3199
|
tasks ▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰
|
|
3166
3200
|
2 success · 2 total
|
|
3167
3201
|
cache ▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰
|
|
3168
|
-
1
|
|
3202
|
+
local 1↓ 1↑
|
|
3169
3203
|
|
|
3170
3204
|
info 8 workers · local cache
|
|
3171
3205
|
time 5.34s · 900ms saved
|
|
@@ -3174,7 +3208,15 @@ A broad run looks like:
|
|
|
3174
3208
|
The three bars are meters: `projects` is what the run covered against
|
|
3175
3209
|
the workspace, `tasks` is failed / success / skipped, `cache` is miss /
|
|
3176
3210
|
no-cache / up-to-date / local / remote (a skipped task rides it too, so
|
|
3177
|
-
the two bars fill alike; its count is on the tasks legend only).
|
|
3211
|
+
the two bars fill alike; its count is on the tasks legend only). Its
|
|
3212
|
+
legend reads per layer: `local 1● 1○ 2↓ 4↑ · remote 3↓ 4↑`.
|
|
3213
|
+
`●` is a fresh hit (outputs already on disk, whichever layer answered,
|
|
3214
|
+
so it counts under local), `○` a task with no cache, `↓` is restored
|
|
3215
|
+
from that layer and `↑` saved to it (local `↑` counts only tasks that ran here; remote `↑` counts
|
|
3216
|
+
uploads that landed). A layer shows only when the run's
|
|
3217
|
+
`--cache-policy` uses it. `N not saved` (ran, succeeded, saved nothing),
|
|
3218
|
+
`N not downloaded` (outputs left in the remote store) and `N ↑ failed`
|
|
3219
|
+
show only when non-zero. The
|
|
3178
3220
|
`time` row is the wall time, then what the cache saved (the hits' stored
|
|
3179
3221
|
exec times, never the restore), then the spread over executed tasks
|
|
3180
3222
|
only — a hit's restore time never enters it. The footer never says a
|
package/docs/execution.md
CHANGED
|
@@ -548,7 +548,7 @@ Status and Cache columns.
|
|
|
548
548
|
|
|
549
549
|
The colors / framing modules:
|
|
550
550
|
|
|
551
|
-
- `
|
|
551
|
+
- `util/colors.ts` — ANSI truecolor (`ansi-16m`), gated by
|
|
552
552
|
`NO_COLOR` / `FORCE_COLOR` / `isTTY`. Programmatic-logger callers
|
|
553
553
|
always see plain text.
|
|
554
554
|
- `orchestrator/framed-output.ts` — the `┌─` frames, the glyph grid
|
package/docs/features.md
CHANGED
|
@@ -75,7 +75,7 @@ config key or an environment variable is missing here.
|
|
|
75
75
|
- **Docs for agents** (`llms.txt`, `llms-full.txt`) — the whole site as markdown for coding agents. [page](https://vznjs.github.io/vx/features/llms-txt/) · post: [Built for the agent at the keyboard](https://vznjs.github.io/vx/blog/built-for-agents/)
|
|
76
76
|
- **vx docs** (`vx docs`, `--limit`) — search the CLI, config and cache reference offline; it ships inside vx. [page](https://vznjs.github.io/vx/features/vx-docs/) · post: [The reference, offline](https://vznjs.github.io/vx/blog/vx-docs-offline/)
|
|
77
77
|
- **Affected reasons** (`--affected --dry`) — each kept task says the changed file or the dependency chain that reached it, text or JSON. [page](https://vznjs.github.io/vx/features/affected-reasons/) · post: [See inside a run](https://vznjs.github.io/vx/blog/see-inside-a-run/)
|
|
78
|
-
- **Agent skill** (`skills/vx/SKILL.md`, `npx skills add vznjs/vx
|
|
78
|
+
- **Agent skill** (`skills/vx/SKILL.md`, `npx skills add vznjs/vx`) — an installable skill that teaches a coding agent to run, debug and query vx through the CLI's `--format json`; copy it from `node_modules/@vzn/vx/skills/vx/` to match the installed version. [page](https://vznjs.github.io/vx/features/agent-skill/) · post: [Built for the agent at the keyboard](https://vznjs.github.io/vx/blog/built-for-agents/)
|
|
79
79
|
|
|
80
80
|
## Cache
|
|
81
81
|
|
|
@@ -83,7 +83,7 @@ config key or an environment variable is missing here.
|
|
|
83
83
|
- **Inputs** (`cache.inputs.env`, `cache.inputs.runtime`, `cache.inputs.tasks`, `cache.inputs.workspaceFiles`, `cache.inputs.workspaceRuntime`) — env vars, tool versions, upstream tasks and workspace files in the key. [page](https://vznjs.github.io/vx/features/key-inputs/) · post: [What goes into a key, and what comes back](https://vznjs.github.io/vx/blog/inside-a-cache-hit/)
|
|
84
84
|
- **Outputs** (`cache.outputs.files`, `cache.outputs.workspaceFiles`) — what a hit restores. [page](https://vznjs.github.io/vx/features/cache-outputs/) · post: [What goes into a key, and what comes back](https://vznjs.github.io/vx/blog/inside-a-cache-hit/)
|
|
85
85
|
- **Input stability** (`cache.inputStability`, workspace `cache.inputStability`, `VX_CACHE_INPUT_STABILITY_STRATEGY`, `VX_CACHE_INPUT_STABILITY_SEVERITY`) — an input written while the command runs withholds the save, on CI too, and the saves of every task that ran over its outputs; `strategy: 'mutable'` accepts a task's identical rewrite of its own input, `'unchecked'` skips the check; `severity: 'error'` fails the run instead of warning. no post
|
|
86
|
-
- **Keep outputs on a miss** (`cache.outputs.clean`, workspace `cache.outputs.clean
|
|
86
|
+
- **Keep outputs on a miss** (`cache.outputs.clean`, workspace `cache.outputs.clean`) — `false` leaves a task's outputs in place for a tool that reads its last output (tsc's `.tsbuildinfo`) and caches everything the outputs then hold, leftovers included (an opt-out of the clean-tree guarantee). no post
|
|
87
87
|
- **Outputs are exactly the snapshot** (`run.rules.exclusiveOutputs`, `VX_RUN_RULES_EXCLUSIVE_OUTPUTS`) — a hit leaves the tree as the run did; two tasks may not own one output without an edge. [page](https://vznjs.github.io/vx/features/strict-outputs/) · post: [The tree is exactly the snapshot](https://vznjs.github.io/vx/blog/strict-output-ownership/)
|
|
88
88
|
- **Keys from git's index** — tracked clean files hash by their blob id, no read. [page](https://vznjs.github.io/vx/features/keys-from-git/) · post: [Your cache key is already in git's index](https://vznjs.github.io/vx/blog/keys-from-git/)
|
|
89
89
|
- **Config keyed as evaluated** — the key sees the resolved config object. [page](https://vznjs.github.io/vx/features/typescript-config/) · post: [Configs are programs](https://vznjs.github.io/vx/blog/resolved-config-hashing/)
|
|
@@ -109,7 +109,7 @@ config key or an environment variable is missing here.
|
|
|
109
109
|
- **Sandboxed tasks** (`exec.sandbox`: `allow`, `deny`, `ignore`, `weakerNetworkIsolation`, `weakerWhenNested`) — a task reads and writes only what it declares; `allow` names `read`, `write`, `network`, `unixSockets`, `localBinding`, `pty`, `systemInfo`, `gitConfig`, `machLookup`. [page](https://vznjs.github.io/vx/features/sandbox/) · post: [The sandbox](https://vznjs.github.io/vx/blog/the-sandbox/)
|
|
110
110
|
- **Env isolation** (`exec.env`: `define`, `passThrough`, `secret`, `VX_DEBUG_DUMPABLE`) — a task sees only the env it names; secrets are masked; vx hides its own env from tasks (Linux and macOS). [page](https://vznjs.github.io/vx/features/env-isolation/) · post: [A task sees only the env it names](https://vznjs.github.io/vx/blog/env-isolation/)
|
|
111
111
|
- **vx lock** (`vx lock`, `--check`, `--format json`, `lock.reviewFiles`, `VX_LOCK_REVIEW_FILES`) — find the projects (every directory holding a `vx.config`), freeze what their configs evaluate to and check the graph rules once; only `vx lock` evaluates configs: runs, `vx show` and `vx info` read the lock and never write it; a pretty `vx.lock.json` beside each config shows reviewers what it resolves to. [page](https://vznjs.github.io/vx/features/vx-lock/) · post: [vx lock: freezing what the key sees](https://vznjs.github.io/vx/blog/lock-and-frozen/)
|
|
112
|
-
- **Flaky detection** — a task
|
|
112
|
+
- **Flaky detection** — a task whose key fails after it passed is reported flaky, judged on every worktree's record of the repo. [page](https://vznjs.github.io/vx/features/flaky-detection/) · post: [Flaky is a claim](https://vznjs.github.io/vx/blog/flaky-tasks/)
|
|
113
113
|
- **Project boundaries** — globs never cross into another project. [page](https://vznjs.github.io/vx/features/project-boundaries/) · post: [What goes into a key, and what comes back](https://vznjs.github.io/vx/blog/inside-a-cache-hit/)
|
|
114
114
|
- **Artifact integrity checks** — a CRC-32, a key match and an outputs-only check on every artifact; damage is a miss. [page](https://vznjs.github.io/vx/features/artifact-integrity/) · post: [What goes into a key, and what comes back](https://vznjs.github.io/vx/blog/inside-a-cache-hit/)
|
|
115
115
|
- **Sandbox names what to grant** — a refused write is named beside the failed task with the path to allow. [page](https://vznjs.github.io/vx/features/sandbox-grants/) · post: [Guard rails that tell you the fix](https://vznjs.github.io/vx/blog/guard-rails/)
|
|
@@ -118,7 +118,7 @@ config key or an environment variable is missing here.
|
|
|
118
118
|
|
|
119
119
|
## Daily work
|
|
120
120
|
|
|
121
|
-
- **Watch mode** (`vx watch`, `--poll`, `watch.poll`, `VX_WATCH_POLL`) — re-run what a change affects, on content, not events. [page](https://vznjs.github.io/vx/features/watch/) · post: [Watch: a content gate](https://vznjs.github.io/vx/blog/watch-mode/)
|
|
121
|
+
- **Watch mode** (`vx watch`, `--poll`, `watch.poll`, `VX_WATCH_POLL`, `VX_DEBUG_WATCH`) — re-run what a change affects, on content, not events. [page](https://vznjs.github.io/vx/features/watch/) · post: [Watch: a content gate](https://vznjs.github.io/vx/blog/watch-mode/)
|
|
122
122
|
- **Dev servers in the graph** (`exec.persistent`, `readyWhen`, `--ready-notice`, `run.readyNotice`, `VX_RUN_READY_NOTICE`) — a server is a node; dependents start when it is ready. [page](https://vznjs.github.io/vx/features/dev-servers/) · post: [Dev servers as graph nodes](https://vznjs.github.io/vx/blog/dev-servers-in-the-graph/)
|
|
123
123
|
- **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/)
|
|
124
124
|
- **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/)
|
|
@@ -169,7 +169,7 @@ config key or an environment variable is missing here.
|
|
|
169
169
|
- **Remote cache and execution** (`@vzn/vx-reapi`, `exec.remote`) — Bazel REAPI cache and workers; the scheduler stays here. [page](https://vznjs.github.io/vx/features/remote-execution/) · post: [Remote execution without moving the scheduler](https://vznjs.github.io/vx/blog/remote-execution/)
|
|
170
170
|
- **OpenTelemetry** (`@vzn/vx-otel`) — each run exported to your OpenTelemetry backend, never breaking it. [page](https://vznjs.github.io/vx/features/opentelemetry/) · post: [Observability that cannot break a run](https://vznjs.github.io/vx/blog/telemetry-never-breaks-a-run/)
|
|
171
171
|
- **vx history** (`@vzn/vx-schedule-history`, `vx history`) — what the scheduler learned per task. [page](https://vznjs.github.io/vx/features/vx-history/) · post: [A scheduler that learns from your runs](https://vznjs.github.io/vx/blog/a-scheduler-that-learns/)
|
|
172
|
-
- **Setup and teardown hooks** (`setup`, `teardown`) — plugin code around the run, bounded by a timeout. [page](https://vznjs.github.io/vx/features/setup-teardown/) · post: [Extend vx in an afternoon](https://vznjs.github.io/vx/blog/extend-vx/)
|
|
172
|
+
- **Setup and teardown hooks** (`setup`, `teardown`, `RunReport`, `ctx.cache.getRun`) — plugin code around the run, bounded by a timeout; on a run that writes a remote, vx keeps failed tasks' logs and outputs and uncached tasks' logs there, and `teardown` gets the run, its CI job and every task with the names to read them by, which a plugin verb reads back through its read-only `ctx.cache`. [page](https://vznjs.github.io/vx/features/setup-teardown/) · post: [Extend vx in an afternoon](https://vznjs.github.io/vx/blog/extend-vx/)
|
|
173
173
|
- **REAPI TLS, mTLS and headers** — connect to hosted servers such as BuildBuddy the way Bazel does. [page](https://vznjs.github.io/vx/features/reapi-tls/) · post: [A remote server you can trust in production](https://vznjs.github.io/vx/blog/reapi-in-production/)
|
|
174
174
|
- **REAPI execution records** — a repeat remote execution skips the worker and replays outputs and stdout. [page](https://vznjs.github.io/vx/features/reapi-action-cache/) · post: [A remote server you can trust in production](https://vznjs.github.io/vx/blog/reapi-in-production/)
|
|
175
175
|
- **REAPI verified downloads and deadlines** — a corrupt blob or a wedged server degrades to a miss, never a hang. [page](https://vznjs.github.io/vx/features/reapi-safety/) · post: [A remote server you can trust in production](https://vznjs.github.io/vx/blog/reapi-in-production/)
|
|
@@ -177,3 +177,4 @@ config key or an environment variable is missing here.
|
|
|
177
177
|
- **OTel live export** (`otel({ live })`) — spans and metrics stream as tasks end, so a dashboard follows a CI run live. [page](https://vznjs.github.io/vx/features/otel-live/) · post: [Watch a CI run while it runs](https://vznjs.github.io/vx/blog/otel-live/)
|
|
178
178
|
- **Memory-aware admission** (`@vzn/vx-schedule-history`) — tasks are packed by the peak memory learned from past runs. [page](https://vznjs.github.io/vx/features/memory-admission/) · post: [A scheduler that learns from your runs](https://vznjs.github.io/vx/blog/a-scheduler-that-learns/)
|
|
179
179
|
- **CI timings file** (`@vzn/vx-schedule-history`, `file`) — one JSON file of learned task times a CI cache carries between runners, so a fresh runner orders by real times. [page](https://vznjs.github.io/vx/features/critical-path/) · post: [Carry the scheduler's memory between CI runners](https://vznjs.github.io/vx/blog/ci-timings-file/)
|
|
180
|
+
- **Shared timings** (`@vzn/vx-schedule-history`, `defaultBranch`) — CI on the default branch writes task timings to the remote cache; a branch with none imports its merge-base's. Plugins keep their own entries there through `ctx.cache`. [page](https://vznjs.github.io/vx/features/critical-path/)
|