@vzn/vx 0.0.546 → 0.0.548
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vzn/vx",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.548",
|
|
4
4
|
"description": "The fastest task runner and build cache for JavaScript monorepos.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -21,10 +21,10 @@
|
|
|
21
21
|
"node": ">=18"
|
|
22
22
|
},
|
|
23
23
|
"optionalDependencies": {
|
|
24
|
-
"@vzn/vx-linux-x64": "0.0.
|
|
25
|
-
"@vzn/vx-linux-arm64": "0.0.
|
|
26
|
-
"@vzn/vx-darwin-x64": "0.0.
|
|
27
|
-
"@vzn/vx-darwin-arm64": "0.0.
|
|
24
|
+
"@vzn/vx-linux-x64": "0.0.548",
|
|
25
|
+
"@vzn/vx-linux-arm64": "0.0.548",
|
|
26
|
+
"@vzn/vx-darwin-x64": "0.0.548",
|
|
27
|
+
"@vzn/vx-darwin-arm64": "0.0.548"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@anthropic-ai/sandbox-runtime": "^0.0.76"
|
|
@@ -507,11 +507,13 @@ async function executePersistentTask(args: ExecuteArgs): Promise<TaskOutcome> {
|
|
|
507
507
|
}
|
|
508
508
|
// The reason rides the outcome (every label reads it), and a child that
|
|
509
509
|
// exited before ready keeps its own exit code rather than a made-up 1.
|
|
510
|
+
// One the readiness timeout is killing reports the signal's, as an
|
|
511
|
+
// ordinary timeout does (X-24).
|
|
510
512
|
const ready = err instanceof PersistentReadyError ? err : undefined
|
|
511
513
|
return {
|
|
512
514
|
node,
|
|
513
515
|
status: 'failed',
|
|
514
|
-
exitCode: ready?.exitCode ?? 1,
|
|
516
|
+
exitCode: ready?.reason === 'timeout' ? await spawn.child.exited : (ready?.exitCode ?? 1),
|
|
515
517
|
durationMs: spawn.readyMs(),
|
|
516
518
|
...(ready !== undefined ? { notReady: ready.reason } : {}),
|
|
517
519
|
wallclockStartNs,
|
package/src/orchestrator/run.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import type { ProjectEntry } from '../workspace/index.js'
|
|
6
6
|
import { loadWorkspace, unreachedHint, unreachedPackages } from '../workspace/index.js'
|
|
7
7
|
import path from 'node:path'
|
|
8
|
-
import { type CacheLayer, type CachePolicy, stopRuntimeProbes } from '../cache/index.js'
|
|
8
|
+
import { Cache, type CacheLayer, type CachePolicy, stopRuntimeProbes } from '../cache/index.js'
|
|
9
9
|
import { VERSION } from '../version.js'
|
|
10
10
|
import {
|
|
11
11
|
resetSandbox,
|
|
@@ -1177,38 +1177,48 @@ async function runOnBus(
|
|
|
1177
1177
|
// entry's save transaction (miss path only), so a warm all-cache-hit
|
|
1178
1178
|
// run does no extra recording work. The telemetry mirror is built in
|
|
1179
1179
|
// the same pass, only when a sink is active.
|
|
1180
|
-
const
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1180
|
+
const recordsOf = (final: TaskOutcome[], runOk: boolean) =>
|
|
1181
|
+
assembleRunRecords({
|
|
1182
|
+
outcomes: final,
|
|
1183
|
+
runId,
|
|
1184
|
+
startedAtMs: endedAtMsAtStart,
|
|
1185
|
+
endedAtMs,
|
|
1186
|
+
totalMs,
|
|
1187
|
+
ok: runOk,
|
|
1188
|
+
// The invocation is stored and `vx last` prints it: a secret passed
|
|
1189
|
+
// after `--` (`-- --token=$NPM_TOKEN`) is masked here as the task's
|
|
1190
|
+
// own output masks it, so cache.db holds no plaintext value.
|
|
1191
|
+
command: maskInvocation(options.command ?? process.argv.slice(1).join(' ')),
|
|
1192
|
+
requestedTasks: options.tasks,
|
|
1193
|
+
cachePolicy: compactCachePolicy(policy),
|
|
1194
|
+
concurrency,
|
|
1195
|
+
flow: options.flow ?? null,
|
|
1196
|
+
forwardArgs: options.forwardArgs,
|
|
1197
|
+
tags: maskTags(options.tags ?? {}),
|
|
1198
|
+
git: gitContext,
|
|
1199
|
+
ci: ciContext,
|
|
1200
|
+
host: hostContext,
|
|
1201
|
+
withTelemetry: telemetry !== undefined,
|
|
1202
|
+
})
|
|
1203
|
+
const records = recordsOf(list, ok)
|
|
1204
|
+
const recordHistory = (write: () => void): void => {
|
|
1205
|
+
try {
|
|
1206
|
+
write()
|
|
1207
|
+
} catch (err) {
|
|
1208
|
+
// History is observability: a full cache disk at the very end must
|
|
1209
|
+
// not turn a finished run's verdict into a stack and exit 1 (seen as
|
|
1210
|
+
// an unprivileged user on a 2 MiB disk, 2026-09-16). The run said
|
|
1211
|
+
// what happened; `vx last` and the flaky list will not know this one.
|
|
1212
|
+
const message = err instanceof Error ? err.message : String(err)
|
|
1213
|
+
log.status(`[vx] run history not recorded: ${message} — the verdict above stands`)
|
|
1214
|
+
}
|
|
1211
1215
|
}
|
|
1216
|
+
// A server kept in the foreground can still fail the run after the
|
|
1217
|
+
// cache closes: its history is written once the wait has decided, or it
|
|
1218
|
+
// read `ok` over the exit 1 and fed the flaky list a pass (X-23).
|
|
1219
|
+
const historyAfterWait = keepAlive.children.length > 0 && !hold && stoppedBy === undefined
|
|
1220
|
+
if (stoppedBy === undefined && !historyAfterWait)
|
|
1221
|
+
recordHistory(() => cache.recordRunBundle(records))
|
|
1212
1222
|
mark('record history')
|
|
1213
1223
|
// Drain any still-in-flight background prefetches before closing the
|
|
1214
1224
|
// cache handle — a prefetch ingesting into a closed SQLite DB would
|
|
@@ -1317,7 +1327,7 @@ async function runOnBus(
|
|
|
1317
1327
|
|
|
1318
1328
|
// Edge case the summary already reported: the user requested a
|
|
1319
1329
|
// persistent task (dev server / watcher). The run is "done" in every
|
|
1320
|
-
// bookkeeping sense — summary printed,
|
|
1330
|
+
// bookkeeping sense — summary printed, the cache closed — but the
|
|
1321
1331
|
// server is still up and that's the point. Stay in the foreground
|
|
1322
1332
|
// until ONE of them exits: Ctrl-C hits the whole process group (the
|
|
1323
1333
|
// server dies; our SIGINT handler also exits 130), and a crash ends
|
|
@@ -1378,6 +1388,16 @@ async function runOnBus(
|
|
|
1378
1388
|
if (!stopRun.signal.aborted && first.code !== 0) failServer(node.id, first.code)
|
|
1379
1389
|
const final = [...outcomes.values()]
|
|
1380
1390
|
await summarize(ok && first.code === 0, final)
|
|
1391
|
+
if (historyAfterWait) {
|
|
1392
|
+
recordHistory(() => {
|
|
1393
|
+
const local = Cache.inspect(prepared.cacheDir)
|
|
1394
|
+
try {
|
|
1395
|
+
local.recordRunBundle(recordsOf(final, ok && first.code === 0))
|
|
1396
|
+
} finally {
|
|
1397
|
+
local.close()
|
|
1398
|
+
}
|
|
1399
|
+
})
|
|
1400
|
+
}
|
|
1381
1401
|
return { ok: ok && first.code === 0, outcomes: final }
|
|
1382
1402
|
}
|
|
1383
1403
|
|
|
@@ -110,6 +110,15 @@ export function validateWorkspace(config: WorkspaceConfig, configPath: string):
|
|
|
110
110
|
if (config.cacheDir !== undefined && typeof config.cacheDir !== 'string') {
|
|
111
111
|
throw new UserError(`${configPath}: \`cacheDir\` must be a string`)
|
|
112
112
|
}
|
|
113
|
+
// `' '` made a directory named three spaces at the root, hidden by the
|
|
114
|
+
// cache's own `.gitignore` (X-22).
|
|
115
|
+
if (
|
|
116
|
+
typeof config.cacheDir === 'string' &&
|
|
117
|
+
config.cacheDir !== '' &&
|
|
118
|
+
config.cacheDir.trim() === ''
|
|
119
|
+
) {
|
|
120
|
+
throw new UserError(`${configPath}: \`cacheDir\` is only whitespace — name a directory`)
|
|
121
|
+
}
|
|
113
122
|
if (config.timeout !== undefined) {
|
|
114
123
|
if (
|
|
115
124
|
typeof config.timeout !== 'number' ||
|
|
@@ -728,7 +737,9 @@ export function validateProjectConfig(config: ProjectConfig, configPath: string)
|
|
|
728
737
|
if (list !== undefined) {
|
|
729
738
|
if (
|
|
730
739
|
!Array.isArray(list) ||
|
|
731
|
-
|
|
740
|
+
// Whitespace alone ran as a no-op probe that folds nothing, as
|
|
741
|
+
// a blank `exec.command` did before item 1099 (X-22).
|
|
742
|
+
list.some((s) => typeof s !== 'string' || s.trim() === '' || s.includes('\0'))
|
|
732
743
|
) {
|
|
733
744
|
throw new UserError(
|
|
734
745
|
`${where}.cache.inputs.${field} must be an array of non-empty shell command strings with no NUL`,
|