@vzn/vx 0.0.651 → 0.0.653

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.
Files changed (177) hide show
  1. package/README.md +3 -4
  2. package/launcher.sh +2 -1
  3. package/package.json +5 -5
  4. package/schemas/error.json +1 -1
  5. package/schemas/show.json +15 -20
  6. package/skills/vx/SKILL.md +3 -3
  7. package/src/bin.ts +37 -3
  8. package/src/cache/archive.ts +197 -32
  9. package/src/cache/cache.ts +882 -230
  10. package/src/cache/checkpointer.ts +102 -0
  11. package/src/cache/file-hashes.ts +2 -1
  12. package/src/cache/fold-memo.ts +24 -4
  13. package/src/cache/fs-clock.ts +26 -0
  14. package/src/cache/git-inputs.ts +188 -22
  15. package/src/cache/history-stream.ts +151 -0
  16. package/src/cache/history-writer.ts +76 -0
  17. package/src/cache/index.ts +12 -1
  18. package/src/cache/inputs.ts +616 -135
  19. package/src/cache/key-fold.ts +1 -1
  20. package/src/cache/layer.ts +29 -16
  21. package/src/cache/layered-cache.ts +28 -7
  22. package/src/cache/lockfile-memo.ts +2 -1
  23. package/src/cache/output-index.ts +106 -44
  24. package/src/cache/plugin-cache.ts +2 -2
  25. package/src/cache/policy.ts +6 -2
  26. package/src/cache/remote-lane.ts +3 -1
  27. package/src/cache/run-history.ts +94 -25
  28. package/src/cache/schema.ts +46 -10
  29. package/src/cli/cache.ts +149 -36
  30. package/src/cli/completions.ts +2 -2
  31. package/src/cli/core-alias.ts +9 -2
  32. package/src/cli/docs.ts +4 -2
  33. package/src/cli/help.ts +27 -4
  34. package/src/cli/index.ts +62 -7
  35. package/src/cli/info.ts +5 -4
  36. package/src/cli/init.ts +55 -20
  37. package/src/cli/last.ts +218 -43
  38. package/src/cli/lock.ts +187 -24
  39. package/src/cli/plan-format.ts +24 -21
  40. package/src/cli/plugin-commands.ts +6 -1
  41. package/src/cli/plugin-templates.ts +36 -45
  42. package/src/cli/run.ts +68 -34
  43. package/src/cli/select.ts +160 -64
  44. package/src/cli/show.ts +70 -28
  45. package/src/cli/task-verb.ts +12 -7
  46. package/src/cli/upgrade.ts +210 -76
  47. package/src/cli/watch-filter.ts +88 -15
  48. package/src/cli/watch-fs.ts +34 -47
  49. package/src/cli/watch-judge.ts +73 -9
  50. package/src/cli/watch-set.ts +10 -8
  51. package/src/cli/watch.ts +190 -33
  52. package/src/cli/why.ts +107 -33
  53. package/src/cli/workspace-config.ts +11 -1
  54. package/src/config.ts +56 -30
  55. package/src/exec/env.ts +3 -1
  56. package/src/exec/executor.ts +116 -16
  57. package/src/exec/index.ts +1 -0
  58. package/src/exec/kill-tree.ts +7 -7
  59. package/src/exec/runner.ts +270 -108
  60. package/src/exec/sandbox-binds.ts +109 -18
  61. package/src/exec/sandbox-paths.ts +3 -1
  62. package/src/exec/sandbox-runtime.ts +446 -64
  63. package/src/exec/sandbox-violations.ts +250 -46
  64. package/src/exec/spawn-off.ts +10 -5
  65. package/src/exec/task-proxy.ts +93 -0
  66. package/src/exec/warm-shell.ts +29 -7
  67. package/src/graph/definition.ts +16 -3
  68. package/src/graph/folds.ts +89 -16
  69. package/src/graph/index.ts +8 -0
  70. package/src/graph/priorities.ts +8 -5
  71. package/src/graph/scheduler.ts +176 -39
  72. package/src/graph/stand-ins.ts +36 -0
  73. package/src/graph/task-graph.ts +347 -160
  74. package/src/graph/task-status.ts +5 -1
  75. package/src/handoff.ts +45 -10
  76. package/src/history/failure-mode.ts +39 -6
  77. package/src/history/history.ts +103 -30
  78. package/src/history/index.ts +2 -0
  79. package/src/history/metrics.ts +193 -73
  80. package/src/index.ts +6 -3
  81. package/src/orchestrator/admission.ts +14 -10
  82. package/src/orchestrator/affected-tasks.ts +35 -13
  83. package/src/orchestrator/command-windows.ts +8 -5
  84. package/src/orchestrator/deferred-outputs.ts +42 -13
  85. package/src/orchestrator/doctor.ts +21 -9
  86. package/src/orchestrator/download-policy.ts +8 -10
  87. package/src/orchestrator/excluded-keys.ts +15 -3
  88. package/src/orchestrator/execute-args.ts +9 -2
  89. package/src/orchestrator/execute-task.ts +612 -138
  90. package/src/orchestrator/graph-memo.ts +26 -4
  91. package/src/orchestrator/graph-stage.ts +27 -4
  92. package/src/orchestrator/held-servers.ts +36 -14
  93. package/src/orchestrator/hit-restore.ts +141 -93
  94. package/src/orchestrator/index.ts +4 -1
  95. package/src/orchestrator/keyed-projects.ts +53 -0
  96. package/src/orchestrator/local-floor.ts +21 -3
  97. package/src/orchestrator/local-shortcircuit.ts +2 -2
  98. package/src/orchestrator/lockfile-claim.ts +30 -4
  99. package/src/orchestrator/miss-save.ts +60 -61
  100. package/src/orchestrator/options.ts +13 -0
  101. package/src/orchestrator/output-host.ts +16 -4
  102. package/src/orchestrator/output-log.ts +1 -54
  103. package/src/orchestrator/persistent-task.ts +32 -16
  104. package/src/orchestrator/persistent.ts +152 -15
  105. package/src/orchestrator/placement.ts +82 -16
  106. package/src/orchestrator/plan.ts +39 -17
  107. package/src/orchestrator/plugin-host.ts +238 -110
  108. package/src/orchestrator/plugin.ts +59 -27
  109. package/src/orchestrator/prepare.ts +194 -38
  110. package/src/orchestrator/projects.ts +89 -10
  111. package/src/orchestrator/read-only.ts +115 -0
  112. package/src/orchestrator/remote-prefetch.ts +1 -1
  113. package/src/orchestrator/run-context.ts +6 -2
  114. package/src/orchestrator/run-failures.ts +101 -23
  115. package/src/orchestrator/run-id.ts +13 -2
  116. package/src/orchestrator/run-keys.ts +87 -28
  117. package/src/orchestrator/run-live.ts +16 -13
  118. package/src/orchestrator/run-lock.ts +27 -4
  119. package/src/orchestrator/run-records.ts +95 -74
  120. package/src/orchestrator/run-report.ts +3 -2
  121. package/src/orchestrator/run-stop.ts +17 -9
  122. package/src/orchestrator/run.ts +531 -122
  123. package/src/orchestrator/sandbox-fix.ts +40 -12
  124. package/src/orchestrator/sandbox-request.ts +314 -44
  125. package/src/orchestrator/save-lane.ts +24 -13
  126. package/src/orchestrator/shell-verdict.ts +29 -1
  127. package/src/orchestrator/signals.ts +103 -8
  128. package/src/orchestrator/stable-keys.ts +34 -27
  129. package/src/orchestrator/task-artifacts.ts +16 -3
  130. package/src/orchestrator/task-hash.ts +191 -34
  131. package/src/orchestrator/telemetry-host.ts +25 -6
  132. package/src/orchestrator/telemetry.ts +85 -13
  133. package/src/orchestrator/upstream.ts +3 -1
  134. package/src/report/events.ts +23 -6
  135. package/src/report/forecast.ts +103 -37
  136. package/src/report/framed-output.ts +179 -162
  137. package/src/report/index.ts +2 -1
  138. package/src/report/logger.ts +108 -31
  139. package/src/report/plain-output.ts +15 -9
  140. package/src/report/status-line.ts +28 -55
  141. package/src/report/summary.ts +61 -18
  142. package/src/settings.ts +50 -14
  143. package/src/ui/components.ts +36 -42
  144. package/src/ui/index.ts +3 -1
  145. package/src/ui/live-region.ts +67 -8
  146. package/src/ui/terminal.ts +12 -0
  147. package/src/ui/theme.ts +16 -1
  148. package/src/util/config-frame.ts +142 -6
  149. package/src/util/edit-distance.ts +17 -1
  150. package/src/util/errors.ts +23 -7
  151. package/src/util/foreign-cache-dir.ts +60 -0
  152. package/src/util/git-ignored.ts +59 -5
  153. package/src/util/index.ts +15 -1
  154. package/src/util/paths.ts +51 -7
  155. package/src/util/plain-text.ts +19 -0
  156. package/src/util/secret-mask.ts +57 -1
  157. package/src/util/settle.ts +18 -1
  158. package/src/util/size.ts +12 -2
  159. package/src/util/tail.ts +4 -1
  160. package/src/util/write-file.ts +86 -9
  161. package/src/workspace/affected.ts +225 -27
  162. package/src/workspace/bracket-literal.ts +2 -2
  163. package/src/workspace/config-bytecode.ts +23 -4
  164. package/src/workspace/config-eval.ts +90 -16
  165. package/src/workspace/config-imports.ts +96 -41
  166. package/src/workspace/config-schema.ts +192 -86
  167. package/src/workspace/dependencies-lock.ts +7 -14
  168. package/src/workspace/filter.ts +18 -2
  169. package/src/workspace/index.ts +3 -1
  170. package/src/workspace/json-data.ts +34 -8
  171. package/src/workspace/lockfile.ts +86 -37
  172. package/src/workspace/migration.ts +58 -31
  173. package/src/workspace/module-state.ts +62 -0
  174. package/src/workspace/nested-dirs.ts +8 -0
  175. package/src/workspace/project-loader.ts +276 -32
  176. package/src/workspace/repo-id.ts +29 -6
  177. package/src/workspace/workspace.ts +190 -30
@@ -0,0 +1,151 @@
1
+ // A run's hits written to the history while the graph still runs, on a
2
+ // thread of their own (history-writer.ts). A warm run's rows were the
3
+ // main thread's last ~65 ms at 8,002 hits, after the graph; here they land
4
+ // while it runs. What does not land (no thread, a refused batch) is
5
+ // handed back and goes in the run's own bundle, as before.
6
+
7
+ import type { RunRecord } from './layer.js'
8
+ import type { HistoryWriterIn, HistoryWriterOut } from './history-writer.js'
9
+
10
+ /** Rows per batch: one transaction on the thread. */
11
+ const BATCH = 512
12
+
13
+ /**
14
+ * The hits a run writes before a thread pays for its start: a run with
15
+ * fewer writes them all in its bundle. A warm 1,000-project run took
16
+ * median 170 ms with a thread, 150 without; at 2,500 and 3,000 the two
17
+ * tie or the thread wins by ~10 ms (2026-11-07, compiled binary).
18
+ */
19
+ const THREAD_FROM = 2048
20
+
21
+ /** A record of `T` whose row the stream holds. */
22
+ export interface Streamed<T> {
23
+ item: T
24
+ record: RunRecord
25
+ }
26
+
27
+ export class HistoryStream<T> {
28
+ private worker: Worker | undefined
29
+ private buffer: Streamed<T>[] = []
30
+ private readonly sent = new Map<number, Streamed<T>[]>()
31
+ private readonly landed: Streamed<T>[] = []
32
+ private seq = 0
33
+ /** A batch was refused or the thread died: nothing more is sent. */
34
+ private dead = false
35
+ /** The thread died: no batch answers any more. */
36
+ private gone = false
37
+ private readonly refused = new Set<number>()
38
+ private settle: (() => void) | undefined
39
+ private ended: (() => void) | undefined
40
+ private added = 0
41
+
42
+ /**
43
+ * `expected` is the hits the run knows of before its graph runs (its
44
+ * confirmed local hits): from {@link THREAD_FROM} the first batch starts
45
+ * the thread; under it, only the hit that reaches it does.
46
+ */
47
+ constructor(
48
+ private readonly files: { index: string; store?: string },
49
+ private readonly expected: number,
50
+ ) {}
51
+
52
+ add(item: T, record: RunRecord): void {
53
+ this.buffer.push({ item, record })
54
+ this.added++
55
+ if (this.buffer.length < BATCH || this.dead) return
56
+ if (this.worker === undefined && this.expected < THREAD_FROM && this.added < THREAD_FROM) return
57
+ this.send()
58
+ }
59
+
60
+ /**
61
+ * Waits for every batch sent, closes the thread, and returns what landed
62
+ * and what did not (the run's bundle writes those).
63
+ */
64
+ async finish(): Promise<{ landed: Streamed<T>[]; unlanded: Streamed<T>[] }> {
65
+ const w = this.worker
66
+ if (w !== undefined && !this.gone) {
67
+ // Unreferenced, its answers alone left the loop with nothing to
68
+ // wait on: the run ended "awaited can never settle".
69
+ w.ref()
70
+ await new Promise<void>((resolve) => {
71
+ this.settle = resolve
72
+ this.settled()
73
+ })
74
+ if (!this.gone) {
75
+ await new Promise<void>((resolve) => {
76
+ this.ended = resolve
77
+ w.postMessage({ end: true } satisfies HistoryWriterIn)
78
+ })
79
+ }
80
+ }
81
+ w?.terminate()
82
+ const unlanded = [...this.sent.values()].flat().concat(this.buffer)
83
+ this.sent.clear()
84
+ this.buffer = []
85
+ return { landed: this.landed, unlanded }
86
+ }
87
+
88
+ private send(): void {
89
+ const w = (this.worker ??= this.start())
90
+ const batch = this.buffer
91
+ this.buffer = []
92
+ const seq = this.seq++
93
+ this.sent.set(seq, batch)
94
+ // A record's spans are bigint, which JSON cannot carry: as numbers, exact
95
+ // below 2^53 ns (104 days into a run). A replacer function cost 20 ms
96
+ // of 8,002 rows, the copies 4.
97
+ const hits = JSON.stringify(
98
+ batch.map(({ record: r }) => ({
99
+ ...r,
100
+ wallclockStartNs: r.wallclockStartNs === undefined ? undefined : Number(r.wallclockStartNs),
101
+ wallclockEndNs: r.wallclockEndNs === undefined ? undefined : Number(r.wallclockEndNs),
102
+ })),
103
+ )
104
+ w.postMessage({ seq, hits } satisfies HistoryWriterIn)
105
+ }
106
+
107
+ private start(): Worker {
108
+ const w = new Worker(new URL('./history-writer.ts', import.meta.url).href)
109
+ // A run that throws before `finish` must still exit; a batch cut off
110
+ // mid-write rolls back whole.
111
+ w.unref()
112
+ w.onmessage = (e: MessageEvent<HistoryWriterOut>) => {
113
+ const m = e.data
114
+ if ('ended' in m) {
115
+ this.ended?.()
116
+ return
117
+ }
118
+ const batch = this.sent.get(m.seq)
119
+ if (batch === undefined) return
120
+ if (m.error === undefined) {
121
+ this.sent.delete(m.seq)
122
+ for (const b of batch) this.landed.push(b)
123
+ } else {
124
+ // Kept in `sent`, so the bundle writes it; no later batch is sent.
125
+ this.refused.add(m.seq)
126
+ this.dead = true
127
+ }
128
+ this.settled()
129
+ }
130
+ // A thread that cannot start or dies: what it did not answer for is
131
+ // the bundle's.
132
+ w.onerror = (e) => {
133
+ e.preventDefault()
134
+ this.dead = true
135
+ this.gone = true
136
+ this.settled()
137
+ this.ended?.()
138
+ }
139
+ w.postMessage({ open: this.files } satisfies HistoryWriterIn)
140
+ return w
141
+ }
142
+
143
+ /** Resolves `finish`'s wait once every batch sent has answered, or the thread is gone. */
144
+ private settled(): void {
145
+ if (this.settle === undefined) return
146
+ if (!this.gone && [...this.sent.keys()].some((seq) => !this.refused.has(seq))) return
147
+ const s = this.settle
148
+ this.settle = undefined
149
+ s()
150
+ }
151
+ }
@@ -0,0 +1,76 @@
1
+ // The thread that writes a run's hits to the history while the run goes on
2
+ // (history-stream.ts). A connection of its own on the run's cache files,
3
+ // opened as `Cache` opens them; each batch is one IMMEDIATE transaction,
4
+ // answered by its sequence number so the run knows which landed.
5
+ // A separate entry point: `bun build --compile` embeds it beside bin.ts.
6
+
7
+ import { Database } from 'bun:sqlite'
8
+ import type { RunRecord } from './layer.js'
9
+ import { RunHistory } from './run-history.js'
10
+ import { SQLITE_FCNTL_PERSIST_WAL } from './schema.js'
11
+
12
+ export type HistoryWriterIn =
13
+ | { open: { index: string; store?: string } }
14
+ | { seq: number; hits: string }
15
+ | { end: true }
16
+
17
+ export type HistoryWriterOut = { seq: number; error?: string } | { ended: true }
18
+
19
+ declare const self: Worker
20
+
21
+ let db: Database | undefined
22
+ let history: RunHistory | undefined
23
+ let refused: string | undefined
24
+
25
+ function open(files: { index: string; store?: string }): void {
26
+ // The timeout first, as `Cache` sets it: every later pragma waits under it.
27
+ db = new Database(files.index)
28
+ db.exec('PRAGMA busy_timeout = 5000')
29
+ db.fileControl(SQLITE_FCNTL_PERSIST_WAL, 1)
30
+ db.exec('PRAGMA journal_size_limit = 67108864')
31
+ db.exec('PRAGMA synchronous = NORMAL')
32
+ if (files.store !== undefined) {
33
+ db.prepare('ATTACH DATABASE ? AS store').run(files.store)
34
+ db.fileControl('store', SQLITE_FCNTL_PERSIST_WAL, 1)
35
+ db.exec('PRAGMA store.journal_size_limit = 67108864')
36
+ db.exec('PRAGMA store.synchronous = NORMAL')
37
+ }
38
+ // A streamed hit carries no forward args (history-stream.ts): nothing digests.
39
+ history = new RunHistory(db, () => {
40
+ throw new Error('a streamed hit has no value to digest')
41
+ })
42
+ }
43
+
44
+ self.onmessage = (e: MessageEvent<HistoryWriterIn>) => {
45
+ const m = e.data
46
+ if ('open' in m) {
47
+ try {
48
+ open(m.open)
49
+ } catch (err) {
50
+ refused = err instanceof Error ? err.message : String(err)
51
+ }
52
+ return
53
+ }
54
+ if ('end' in m) {
55
+ try {
56
+ db?.close()
57
+ } catch {
58
+ // The rows are in; a close that fails leaves the WAL to the next opener.
59
+ }
60
+ postMessage({ ended: true } satisfies HistoryWriterOut)
61
+ return
62
+ }
63
+ if (history === undefined) {
64
+ postMessage({ seq: m.seq, error: refused ?? 'not open' } satisfies HistoryWriterOut)
65
+ return
66
+ }
67
+ try {
68
+ history.recordHits(JSON.parse(m.hits) as RunRecord[])
69
+ postMessage({ seq: m.seq } satisfies HistoryWriterOut)
70
+ } catch (err) {
71
+ postMessage({
72
+ seq: m.seq,
73
+ error: err instanceof Error ? err.message : String(err),
74
+ } satisfies HistoryWriterOut)
75
+ }
76
+ }
@@ -8,6 +8,7 @@ export {
8
8
  applyCacheFlags,
9
9
  ArtifactVanishedError,
10
10
  Cache,
11
+ CorruptArtifactError,
11
12
  DEFAULT_STORE,
12
13
  type StoreOptions,
13
14
  type CacheFlags,
@@ -18,6 +19,9 @@ export {
18
19
  type CachePolicy,
19
20
  cachesNothing,
20
21
  EXECUTED_RUNS_SQL,
22
+ historyFiles,
23
+ holdCacheDir,
24
+ holdStore,
21
25
  indexDb,
22
26
  formatCachePolicy,
23
27
  FULL_CACHE_POLICY,
@@ -34,13 +38,15 @@ export {
34
38
  FILE_HASH_RACY_MS,
35
39
  OUTPUT_DIRS_RACY_MS,
36
40
  racyWindowMs,
41
+ hashFileSeen,
37
42
  type SchemaReset,
38
43
  SCHEMA_VERSION,
44
+ storedLog,
39
45
  vxCacheEntries,
40
46
  } from './cache.js'
41
47
  export { ABSENT_INPUT, absentOr, CACHE_VERSION, foldHead } from './key-fold.js'
42
48
  export type { FoldMemo } from './fold-memo.js'
43
- export { measureFsClockLag, setFsClockLag } from './fs-clock.js'
49
+ export { fsClockNow, measureFsClockLag, setFsClockLag, stampGrainMs } from './fs-clock.js'
44
50
  export { behindLink, filesBehind } from './linked-inputs.js'
45
51
  export {
46
52
  addedInput,
@@ -49,6 +55,7 @@ export {
49
55
  committedFiles,
50
56
  cleanWorkspaceOutputs,
51
57
  declaresInput,
58
+ namedIgnoredReach,
52
59
  namedOutright,
53
60
  workspaceFilesReachInto,
54
61
  filesToken,
@@ -68,6 +75,8 @@ export {
68
75
  ownOutputsSince,
69
76
  ownWorkspaceOutputsSince,
70
77
  stampOutputs,
78
+ stampCommitted,
79
+ committedMoved,
71
80
  stampWorkspaceOutputs,
72
81
  stopRuntimeProbes,
73
82
  answerRuntime,
@@ -76,6 +85,7 @@ export {
76
85
  export {
77
86
  GitFilesCache,
78
87
  gitRefusal,
88
+ repoFacts,
79
89
  applyGitEnumeration,
80
90
  gitPathspecs,
81
91
  MAX_SCOPED_PATHSPECS,
@@ -104,6 +114,7 @@ export {
104
114
  } from './plugin-cache.js'
105
115
  export { packRunOutputs, putRunEntry, runEntryName, writesRunStore } from './run-store.js'
106
116
  export { branchSource } from './run-history.js'
117
+ export { HistoryStream } from './history-stream.js'
107
118
  export {
108
119
  type KeptFailure,
109
120
  keepRunNotes,