@vzn/vx 0.0.466 → 0.0.467
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 +5 -5
- package/src/cli/last.ts +14 -6
- package/src/orchestrator/doctor.ts +40 -16
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vzn/vx",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.467",
|
|
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.467",
|
|
25
|
+
"@vzn/vx-linux-arm64": "0.0.467",
|
|
26
|
+
"@vzn/vx-darwin-x64": "0.0.467",
|
|
27
|
+
"@vzn/vx-darwin-arm64": "0.0.467"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@anthropic-ai/sandbox-runtime": "^0.0.76"
|
package/src/cli/last.ts
CHANGED
|
@@ -208,6 +208,10 @@ export async function lastCmd(args: readonly string[]): Promise<number> {
|
|
|
208
208
|
noteSchemaReset(cache, warnToStderr)
|
|
209
209
|
try {
|
|
210
210
|
const db = cache.dbHandle()
|
|
211
|
+
// Nothing recorded at all is its own answer: `--failed` said "no
|
|
212
|
+
// recorded run failed" and a run id pointed at a `--list` that lists
|
|
213
|
+
// nothing, while `--list --failed` past green runs said there were none.
|
|
214
|
+
const noRuns = (): boolean => listInvocations(db, { limit: 1 }).length === 0
|
|
211
215
|
|
|
212
216
|
if (parsed.list !== undefined) {
|
|
213
217
|
const invocations =
|
|
@@ -219,7 +223,9 @@ export async function lastCmd(args: readonly string[]): Promise<number> {
|
|
|
219
223
|
return 0
|
|
220
224
|
}
|
|
221
225
|
if (invocations.length === 0) {
|
|
222
|
-
process.stdout.write(
|
|
226
|
+
process.stdout.write(
|
|
227
|
+
parsed.failed === true && !noRuns() ? 'no recorded run failed\n' : 'no recorded runs\n',
|
|
228
|
+
)
|
|
223
229
|
return 0
|
|
224
230
|
}
|
|
225
231
|
for (const inv of invocations) {
|
|
@@ -241,11 +247,13 @@ export async function lastCmd(args: readonly string[]): Promise<number> {
|
|
|
241
247
|
: (listInvocations(db, { limit: 1 })[0] ?? null)
|
|
242
248
|
if (inv === null || inv === undefined) {
|
|
243
249
|
throw new UserError(
|
|
244
|
-
|
|
245
|
-
?
|
|
246
|
-
: parsed.
|
|
247
|
-
?
|
|
248
|
-
:
|
|
250
|
+
noRuns()
|
|
251
|
+
? 'vx last: no recorded runs yet — run something first'
|
|
252
|
+
: parsed.runId !== undefined
|
|
253
|
+
? `vx last: no recorded run ${parsed.runId} (vx last --list shows recent runs)`
|
|
254
|
+
: parsed.failed === true
|
|
255
|
+
? 'vx last: no recorded run failed'
|
|
256
|
+
: 'vx last: no recorded runs yet — run something first',
|
|
249
257
|
)
|
|
250
258
|
}
|
|
251
259
|
const detail = getRun(db, inv.runId)
|
|
@@ -114,8 +114,34 @@ export interface CollectInfoOptions {
|
|
|
114
114
|
export async function collectInfo(cwd: string, opts: CollectInfoOptions = {}): Promise<InfoFacts> {
|
|
115
115
|
const warn = opts.warn ?? warnToStderr
|
|
116
116
|
const reads: LoadReads = new Map()
|
|
117
|
+
// Both first: outside a workspace, or under a workspace config that does
|
|
118
|
+
// not load, the doctor refuses at once, with no probe (~180 ms) ahead.
|
|
117
119
|
const root = await findWorkspaceRoot(cwd, reads)
|
|
118
|
-
const
|
|
120
|
+
const workspace = await loadWorkspacePlugins(root, warn)
|
|
121
|
+
// The sandbox probe asks nothing of the workspace, so it runs under the
|
|
122
|
+
// loads below instead of after them. Awaited on every path: it resets
|
|
123
|
+
// the runtime it brought up, whose sockets would hold the process open.
|
|
124
|
+
const probing = sandboxProbe()
|
|
125
|
+
// Rejects only if the reset does; awaited below, never unhandled.
|
|
126
|
+
probing.catch(() => {})
|
|
127
|
+
try {
|
|
128
|
+
return await collectWorkspaceInfo(cwd, root, reads, workspace, opts, probing)
|
|
129
|
+
} catch (err) {
|
|
130
|
+
// The workspace's refusal is the error worth reporting.
|
|
131
|
+
await probing.catch(() => {})
|
|
132
|
+
throw err
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async function collectWorkspaceInfo(
|
|
137
|
+
cwd: string,
|
|
138
|
+
root: string,
|
|
139
|
+
reads: LoadReads,
|
|
140
|
+
{ workspaceConfig, plugins }: Awaited<ReturnType<typeof loadWorkspacePlugins>>,
|
|
141
|
+
opts: CollectInfoOptions,
|
|
142
|
+
probing: Promise<Omit<InfoFacts['sandbox'], 'declared'>>,
|
|
143
|
+
): Promise<InfoFacts> {
|
|
144
|
+
const warn = opts.warn ?? warnToStderr
|
|
119
145
|
const cacheDir =
|
|
120
146
|
opts.cacheDir === undefined
|
|
121
147
|
? resolveCacheDir(root, workspaceConfig)
|
|
@@ -173,7 +199,10 @@ export async function collectInfo(cwd: string, opts: CollectInfoOptions = {}): P
|
|
|
173
199
|
}
|
|
174
200
|
|
|
175
201
|
const lockPresent = await Bun.file(lockfilePath(root)).exists()
|
|
176
|
-
|
|
202
|
+
// Asked while the probe runs: each is a synchronous spawn.
|
|
203
|
+
const git = gitVersion()
|
|
204
|
+
const statusCache = gitStatusCache(root)
|
|
205
|
+
const sandbox = { ...(await probing), declared: sandboxed }
|
|
177
206
|
return {
|
|
178
207
|
vx: VERSION,
|
|
179
208
|
// An unsupported Bun does not stop a run, it makes the run's ANSWERS
|
|
@@ -183,12 +212,12 @@ export async function collectInfo(cwd: string, opts: CollectInfoOptions = {}): P
|
|
|
183
212
|
// have, which is a property 19 tests hold on purpose.
|
|
184
213
|
bun: Bun.version,
|
|
185
214
|
bunSupported: !isUnsupportedBun(Bun.version),
|
|
186
|
-
git
|
|
215
|
+
git,
|
|
187
216
|
// The one `git status` walk per run is the warm path's critical path on
|
|
188
217
|
// a large tree (~55 ms at 1000 projects, measured 2026-09-02). git's
|
|
189
218
|
// own caches make it near-free after the first run, and they are OFF by
|
|
190
219
|
// default — say so, since nothing else in a run would.
|
|
191
|
-
gitStatusCache:
|
|
220
|
+
gitStatusCache: statusCache,
|
|
192
221
|
workspaceRoot: root,
|
|
193
222
|
projects: metas.length,
|
|
194
223
|
tasks: taskCount,
|
|
@@ -224,24 +253,19 @@ export async function collectInfo(cwd: string, opts: CollectInfoOptions = {}): P
|
|
|
224
253
|
}
|
|
225
254
|
|
|
226
255
|
/**
|
|
227
|
-
* The runtime probe's verdict — one sandboxed `true` (memoized)
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
*
|
|
256
|
+
* The runtime probe's verdict — one sandboxed `true` (memoized). The probe
|
|
257
|
+
* initializes the Linux runtime, whose proxy sockets would keep a
|
|
258
|
+
* standalone process alive; reset after asking, since the doctor runs
|
|
259
|
+
* nothing.
|
|
231
260
|
*/
|
|
232
|
-
async function
|
|
261
|
+
async function sandboxProbe(): Promise<Omit<InfoFacts['sandbox'], 'declared'>> {
|
|
233
262
|
try {
|
|
234
263
|
const verdict = await probeSandbox()
|
|
235
264
|
const untraced = verdict.available ? await untracedReason() : null
|
|
236
|
-
return {
|
|
237
|
-
available: verdict.available,
|
|
238
|
-
reason: stableSandboxReason(verdict.reason),
|
|
239
|
-
declared,
|
|
240
|
-
untraced,
|
|
241
|
-
}
|
|
265
|
+
return { available: verdict.available, reason: stableSandboxReason(verdict.reason), untraced }
|
|
242
266
|
} catch (err) {
|
|
243
267
|
const message = err instanceof Error ? err.message : String(err)
|
|
244
|
-
return { available: false, reason: stableSandboxReason(message),
|
|
268
|
+
return { available: false, reason: stableSandboxReason(message), untraced: null }
|
|
245
269
|
} finally {
|
|
246
270
|
await resetSandbox()
|
|
247
271
|
}
|