@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.
Files changed (138) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +135 -124
  3. package/index.ts +10 -0
  4. package/launcher.mjs +10 -11
  5. package/package.json +11 -7
  6. package/src/bin.ts +14 -4
  7. package/src/cache/archive.ts +659 -0
  8. package/src/cache/cache.ts +769 -1101
  9. package/src/cache/chained-cache.ts +194 -0
  10. package/src/cache/config-evals.ts +89 -0
  11. package/src/cache/file-hashes.ts +262 -0
  12. package/src/cache/git-inputs.ts +637 -0
  13. package/src/cache/index.ts +24 -5
  14. package/src/cache/inputs.ts +373 -456
  15. package/src/cache/layer.ts +604 -0
  16. package/src/cache/layered-cache.ts +96 -43
  17. package/src/cache/output-index.ts +224 -0
  18. package/src/cache/policy.ts +84 -0
  19. package/src/cache/run-history.ts +147 -0
  20. package/src/cache/tar-stream.ts +358 -0
  21. package/src/cache/zstd.ts +160 -0
  22. package/src/cli/cache.ts +75 -21
  23. package/src/cli/completions.ts +104 -0
  24. package/src/cli/core-alias.ts +25 -0
  25. package/src/cli/help.ts +195 -128
  26. package/src/cli/index.ts +116 -46
  27. package/src/cli/info.ts +122 -63
  28. package/src/cli/init.ts +75 -0
  29. package/src/cli/last.ts +172 -0
  30. package/src/cli/lock.ts +2 -1
  31. package/src/cli/plan-format.ts +72 -6
  32. package/src/cli/plugin-commands.ts +103 -0
  33. package/src/cli/run.ts +245 -271
  34. package/src/cli/select.ts +332 -0
  35. package/src/cli/show.ts +144 -69
  36. package/src/cli/upgrade.ts +9 -7
  37. package/src/cli/watch.ts +858 -110
  38. package/src/cli/why.ts +223 -0
  39. package/src/cli/workspace-config.ts +126 -0
  40. package/src/config.ts +187 -150
  41. package/src/exec/env.ts +18 -1
  42. package/src/exec/executor.ts +224 -0
  43. package/src/exec/index.ts +24 -2
  44. package/src/exec/local-executor.ts +41 -0
  45. package/src/exec/runner.ts +166 -40
  46. package/src/exec/sandbox-binds.ts +182 -0
  47. package/src/exec/sandbox-paths.ts +50 -0
  48. package/src/exec/sandbox-runtime.ts +642 -260
  49. package/src/exec/sandbox-violations.ts +280 -0
  50. package/src/graph/index.ts +4 -10
  51. package/src/graph/scheduler.ts +232 -203
  52. package/src/graph/task-graph.ts +222 -8
  53. package/src/index.ts +146 -153
  54. package/src/orchestrator/admission.ts +137 -0
  55. package/src/orchestrator/deferred-outputs.ts +147 -0
  56. package/src/orchestrator/doctor.ts +255 -0
  57. package/src/orchestrator/download-policy.ts +171 -0
  58. package/src/orchestrator/events.ts +72 -8
  59. package/src/orchestrator/execute-task.ts +374 -549
  60. package/src/orchestrator/failure-mode.ts +202 -0
  61. package/src/orchestrator/framed-output.ts +126 -69
  62. package/src/orchestrator/history.ts +126 -59
  63. package/src/orchestrator/hit-restore.ts +221 -0
  64. package/src/orchestrator/index.ts +77 -93
  65. package/src/orchestrator/local-shortcircuit.ts +22 -0
  66. package/src/orchestrator/lockfile-claim.ts +281 -0
  67. package/src/orchestrator/logger.ts +208 -35
  68. package/src/orchestrator/metrics.ts +102 -1388
  69. package/src/orchestrator/miss-save.ts +169 -0
  70. package/src/orchestrator/options.ts +55 -34
  71. package/src/orchestrator/persistent.ts +79 -0
  72. package/src/orchestrator/placement.ts +182 -0
  73. package/src/orchestrator/plan.ts +144 -1
  74. package/src/orchestrator/plugin-host.ts +357 -120
  75. package/src/orchestrator/plugin.ts +298 -58
  76. package/src/orchestrator/prepare.ts +202 -106
  77. package/src/orchestrator/projects.ts +259 -0
  78. package/src/orchestrator/remote-prefetch.ts +12 -8
  79. package/src/orchestrator/run-artifacts.ts +63 -16
  80. package/src/orchestrator/run-context.ts +167 -29
  81. package/src/orchestrator/run-records.ts +149 -0
  82. package/src/orchestrator/run-report.ts +74 -47
  83. package/src/orchestrator/run.ts +534 -417
  84. package/src/orchestrator/sandbox-request.ts +243 -0
  85. package/src/orchestrator/save-lane.ts +47 -0
  86. package/src/orchestrator/signals.ts +111 -0
  87. package/src/orchestrator/stable-keys.ts +129 -31
  88. package/src/orchestrator/status-line.ts +49 -9
  89. package/src/orchestrator/summary.ts +90 -26
  90. package/src/orchestrator/tally.ts +78 -35
  91. package/src/orchestrator/task-hash.ts +111 -15
  92. package/src/orchestrator/task-log-buffer.ts +288 -0
  93. package/src/orchestrator/telemetry-host.ts +34 -6
  94. package/src/orchestrator/telemetry.ts +182 -36
  95. package/src/orchestrator/upstream.ts +72 -31
  96. package/src/util/cgroup.ts +160 -0
  97. package/src/util/edit-distance.ts +70 -0
  98. package/src/util/errors.ts +15 -1
  99. package/src/util/index.ts +15 -2
  100. package/src/util/num.ts +37 -0
  101. package/src/util/paths.ts +64 -0
  102. package/src/util/settle.ts +67 -0
  103. package/src/util/size.ts +5 -1
  104. package/src/util/tail.ts +66 -0
  105. package/src/util/timing.ts +63 -0
  106. package/src/util/verbs.ts +39 -0
  107. package/src/workspace/affected.ts +250 -23
  108. package/src/workspace/config-cache.ts +313 -0
  109. package/src/workspace/config-eval.ts +217 -0
  110. package/src/workspace/config-imports.ts +162 -0
  111. package/src/workspace/config-schema.ts +837 -0
  112. package/src/workspace/filter.ts +65 -10
  113. package/src/workspace/fingerprint.ts +53 -4
  114. package/src/workspace/index.ts +42 -3
  115. package/src/workspace/lockfile.ts +25 -9
  116. package/src/workspace/migrate-scripts.ts +134 -0
  117. package/src/workspace/migration.ts +314 -0
  118. package/src/workspace/nested-dirs.ts +21 -7
  119. package/src/workspace/package-graph.ts +114 -41
  120. package/src/workspace/project-loader.ts +224 -450
  121. package/src/workspace/workspace.ts +298 -72
  122. package/src/cache/cas-backend.ts +0 -97
  123. package/src/cache/digest.ts +0 -47
  124. package/src/cache/tar.ts +0 -343
  125. package/src/cli/backend.ts +0 -23
  126. package/src/cli/mcp-rpc.ts +0 -292
  127. package/src/cli/mcp.ts +0 -92
  128. package/src/cli/migrate-nx.ts +0 -450
  129. package/src/cli/migrate-turbo.ts +0 -364
  130. package/src/cli/migrate.ts +0 -219
  131. package/src/orchestrator/devframe-surface.ts +0 -74
  132. package/src/orchestrator/predict.ts +0 -106
  133. package/src/orchestrator/protocol.ts +0 -156
  134. package/src/orchestrator/resources.ts +0 -59
  135. package/src/orchestrator/run-state.ts +0 -145
  136. package/src/orchestrator/verify.ts +0 -164
  137. package/src/orchestrator/wire-render.ts +0 -92
  138. package/src/orchestrator/wire.ts +0 -212
@@ -1,92 +0,0 @@
1
- // The inverse of `wireForwarder`: turn a stream of `WireEvent`s back into
2
- // `Logger` calls on a concrete renderer. A `vx serve` client feeds the
3
- // service's event stream through this into a normal `defaultLogger`, so a
4
- // DELEGATED run renders identically to a local one — the terminal
5
- // renderer stays completely untouched (it just receives reconstructed
6
- // node-shaped objects instead of live graph nodes). This file is the
7
- // whole adapter; it can be rewritten or removed without touching the
8
- // renderer or the producer side.
9
-
10
- import type { TaskNode, TaskOutcome } from '../graph/index.js'
11
- import type { Logger } from './logger.js'
12
- import type { OutcomeView, TaskView, WireEvent } from './events.js'
13
-
14
- /**
15
- * Rebuild a node-shaped object from a `TaskView`. The formatters only ever
16
- * read `id` / `projectName` / `taskName` / `requested` / `surfaced` and
17
- * `config.exec` (presence ⇒ not a group; `.command`; `.persistent`), so a
18
- * structural stand-in is indistinguishable from a real `TaskNode` to them.
19
- */
20
- function reconstructNode(view: TaskView): TaskNode {
21
- const exec = view.isGroup
22
- ? undefined
23
- : {
24
- command: view.command ?? '',
25
- ...(view.persistent ? { persistent: { readyWhen: '' } } : {}),
26
- }
27
- return {
28
- id: view.id,
29
- projectName: view.project,
30
- taskName: view.task,
31
- requested: view.requested,
32
- surfaced: view.surfaced,
33
- config: exec === undefined ? {} : { exec },
34
- } as unknown as TaskNode
35
- }
36
-
37
- function reconstructOutcome(view: OutcomeView, node: TaskNode): TaskOutcome {
38
- return {
39
- node,
40
- status: view.status,
41
- exitCode: view.exitCode,
42
- durationMs: view.durationMs,
43
- ...(view.restored !== undefined ? { restored: view.restored } : {}),
44
- ...(view.sandboxViolations !== undefined ? { sandboxViolations: view.sandboxViolations } : {}),
45
- ...(view.sandboxViolationLines !== undefined
46
- ? { sandboxViolationLines: view.sandboxViolationLines }
47
- : {}),
48
- } as TaskOutcome
49
- }
50
-
51
- /**
52
- * Build a `WireEvent` consumer that drives `sink` (typically a
53
- * `defaultLogger`). Stateful: it accumulates the reconstructed nodes from
54
- * `task:start` so later `task:*` events can resolve their node by id.
55
- */
56
- export function createWireRenderer(sink: Logger): (event: WireEvent) => void {
57
- const nodes = new Map<string, TaskNode>()
58
- return (event) => {
59
- switch (event.kind) {
60
- case 'run:start':
61
- sink.runStart?.(event.info)
62
- return
63
- case 'task:start': {
64
- const node = reconstructNode(event.task)
65
- nodes.set(node.id, node)
66
- sink.taskStart?.(node)
67
- return
68
- }
69
- case 'task:stdout': {
70
- const node = nodes.get(event.taskId)
71
- if (node) sink.taskStdout(node, event.chunk)
72
- return
73
- }
74
- case 'task:stderr': {
75
- const node = nodes.get(event.taskId)
76
- if (node) sink.taskStderr(node, event.chunk)
77
- return
78
- }
79
- case 'task:complete': {
80
- const node = nodes.get(event.outcome.taskId)
81
- if (node) sink.taskComplete(node, reconstructOutcome(event.outcome, node))
82
- return
83
- }
84
- case 'run:status':
85
- sink.status(event.line)
86
- return
87
- case 'run:end':
88
- sink.runEnd?.()
89
- return
90
- }
91
- }
92
- }
@@ -1,212 +0,0 @@
1
- // JSON-RPC 2.0 envelope + OTel-LogRecord payload — the wire spec
2
- // committed by docs/design/wire-protocol-2026-06.md. Lives alongside
3
- // the existing protocol.ts (t-discriminated ServerMessage/ClientMessage)
4
- // so vx serve can speak both formats during the transition.
5
- //
6
- // One envelope, three transports (WS / SSE / NDJSON), four channels
7
- // (vx:events / vx:state / vx:rpc / vx:submit). Every external consumer
8
- // that already speaks JSON-RPC works against vx out of the box.
9
- //
10
- // Pure types + a small adapter pair. No transport here; the Hono
11
- // router in src/cli/serve.ts wires the byte frames.
12
-
13
- import type { RunRequest, RunResult, ServerMessage, ClientMessage } from './protocol.js'
14
- import type { WireEvent as InternalWireEvent } from './events.js'
15
-
16
- /** Protocol version returned by GET /version. */
17
- export const WIRE_PROTOCOL_VERSION = '1.0'
18
-
19
- /** The four channels we expose; clients pick the subset they care about. */
20
- export const WIRE_CHANNELS = ['vx:events', 'vx:state', 'vx:rpc', 'vx:submit'] as const
21
- export type WireChannel = (typeof WIRE_CHANNELS)[number]
22
-
23
- /** JSON-RPC 2.0 method names emitted by the server (notifications). */
24
- export type ServerNotificationMethod = 'events.append' | 'state.patch'
25
-
26
- /** JSON-RPC 2.0 method names dispatched from the client (request/response). */
27
- export type ClientRequestMethod = 'state.snapshot' | 'submit.run' | `rpc.${string}`
28
-
29
- /**
30
- * The JSON-RPC 2.0 envelope. One of four shapes per the spec.
31
- *
32
- * - request: { jsonrpc, id, method, params? }
33
- * - response: { jsonrpc, id, result }
34
- * - error: { jsonrpc, id, error: { code, message, data? } }
35
- * - notification: { jsonrpc, method, params? }
36
- */
37
- export type Envelope = Request | Response | ErrorResponse | Notification
38
-
39
- export interface Request {
40
- jsonrpc: '2.0'
41
- id: number | string
42
- method: string
43
- params?: unknown
44
- }
45
-
46
- export interface Response {
47
- jsonrpc: '2.0'
48
- id: number | string
49
- result: unknown
50
- }
51
-
52
- export interface ErrorResponse {
53
- jsonrpc: '2.0'
54
- id: number | string
55
- error: { code: number; message: string; data?: unknown }
56
- }
57
-
58
- export interface Notification {
59
- jsonrpc: '2.0'
60
- method: string
61
- params?: unknown
62
- }
63
-
64
- /** JSON-RPC 2.0 error codes used by vx. The spec reserves -32000..-32099 for impl-defined. */
65
- export const ENVELOPE_ERRORS = {
66
- PARSE_ERROR: -32700,
67
- INVALID_REQUEST: -32600,
68
- METHOD_NOT_FOUND: -32601,
69
- INVALID_PARAMS: -32602,
70
- INTERNAL_ERROR: -32603,
71
- USER_ERROR: -32000, // a vx UserError — clean message, no stack
72
- TASK_HASH_UNKNOWN: -32001,
73
- RUN_NOT_FOUND: -32002,
74
- UNAUTHORIZED: -32003,
75
- RATE_LIMITED: -32004,
76
- } as const
77
-
78
- /** Build a request envelope. */
79
- export function makeRequest(id: number | string, method: string, params?: unknown): Request {
80
- const req: Request = { jsonrpc: '2.0', id, method }
81
- if (params !== undefined) req.params = params
82
- return req
83
- }
84
-
85
- /** Build a notification envelope. */
86
- export function makeNotification(method: string, params?: unknown): Notification {
87
- const note: Notification = { jsonrpc: '2.0', method }
88
- if (params !== undefined) note.params = params
89
- return note
90
- }
91
-
92
- /** Build a success response envelope. */
93
- export function makeResponse(id: number | string, result: unknown): Response {
94
- return { jsonrpc: '2.0', id, result }
95
- }
96
-
97
- /** Build an error response envelope. */
98
- export function makeError(
99
- id: number | string,
100
- code: number,
101
- message: string,
102
- data?: unknown,
103
- ): ErrorResponse {
104
- const err: ErrorResponse = { jsonrpc: '2.0', id, error: { code, message } }
105
- if (data !== undefined) err.error.data = data
106
- return err
107
- }
108
-
109
- /** Type-guard: does a parsed object look like an Envelope? */
110
- export function isEnvelope(value: unknown): value is Envelope {
111
- if (value === null || typeof value !== 'object') return false
112
- const v = value as { jsonrpc?: unknown }
113
- return v.jsonrpc === '2.0'
114
- }
115
-
116
- /** Type-guard for a request envelope. */
117
- export function isRequest(env: Envelope): env is Request {
118
- return 'method' in env && 'id' in env
119
- }
120
-
121
- /** Type-guard for a notification envelope (request without id). */
122
- export function isNotification(env: Envelope): env is Notification {
123
- return 'method' in env && !('id' in env)
124
- }
125
-
126
- // ---------------------------------------------------------------------------
127
- // Bidirectional adapters between the legacy t-discriminated wire and the
128
- // JSON-RPC envelope. Lets vx serve accept both formats on the same WS
129
- // endpoint during the transition: parse one, fall back to the other.
130
- // ---------------------------------------------------------------------------
131
-
132
- /**
133
- * Project a ServerMessage to an envelope. Events become `events.append`
134
- * notifications; results become `submit.run` responses; errors become
135
- * error responses. The distributed coordinator messages map to the
136
- * `coord.*` namespace in a distribution plugin's own adapters.
137
- */
138
- export function serverMessageToEnvelope(msg: ServerMessage, id?: number | string): Envelope {
139
- switch (msg.t) {
140
- case 'event':
141
- return makeNotification('events.append', msg.event)
142
- case 'result':
143
- // submit.run's response. id required from the caller.
144
- return makeResponse(id ?? 0, msg.result)
145
- case 'error':
146
- return makeError(id ?? 0, ENVELOPE_ERRORS.USER_ERROR, msg.message)
147
- }
148
- }
149
-
150
- /**
151
- * Project an envelope back to a ServerMessage where one exists. Returns
152
- * null for envelopes that don't have a mapping (e.g. state.snapshot
153
- * responses — pure JSON-RPC, no submitter form).
154
- */
155
- export function envelopeToServerMessage(env: Envelope): ServerMessage | null {
156
- if (isNotification(env) && env.method === 'events.append') {
157
- return { t: 'event', event: env.params as InternalWireEvent }
158
- }
159
- if ('result' in env) {
160
- return { t: 'result', result: env.result as RunResult }
161
- }
162
- if ('error' in env) {
163
- return { t: 'error', message: env.error.message }
164
- }
165
- return null
166
- }
167
-
168
- /** Project a ClientMessage to an envelope. `run` becomes a `submit.run` request. */
169
- export function clientMessageToEnvelope(msg: ClientMessage, id?: number | string): Envelope {
170
- return makeRequest(id ?? 1, 'submit.run', msg.request)
171
- }
172
-
173
- /** Project an envelope back to a ClientMessage. */
174
- export function envelopeToClientMessage(env: Envelope): ClientMessage | null {
175
- if (isRequest(env) && env.method === 'submit.run') {
176
- return { t: 'run', request: env.params as RunRequest }
177
- }
178
- return null
179
- }
180
-
181
- // ---------------------------------------------------------------------------
182
- // Transport encoders — single bus, one envelope, three byte framings.
183
- // Helpers exposed for the Hono mounts in src/cli/serve.ts.
184
- // ---------------------------------------------------------------------------
185
-
186
- /** Encode an envelope for a WebSocket frame (one JSON object per frame). */
187
- export function encodeForWS(env: Envelope): string {
188
- return JSON.stringify(env)
189
- }
190
-
191
- /**
192
- * Encode an envelope as an SSE event block. Each block is one
193
- * `data: <json>\n\n` chunk so a `curl` or browser EventSource gets it
194
- * cleanly.
195
- */
196
- export function encodeForSSE(env: Envelope): string {
197
- return `data: ${JSON.stringify(env)}\n\n`
198
- }
199
-
200
- /** Encode an envelope as a NDJSON line. One envelope per line. */
201
- export function encodeForNDJSON(env: Envelope): string {
202
- return JSON.stringify(env) + '\n'
203
- }
204
-
205
- /** Parse a UTF-8 string back to an envelope (and validate the shape). */
206
- export function decodeEnvelope(raw: string): Envelope {
207
- const value = JSON.parse(raw) as unknown
208
- if (!isEnvelope(value)) {
209
- throw new Error(`not a JSON-RPC 2.0 envelope: ${raw.slice(0, 100)}`)
210
- }
211
- return value
212
- }