@vzn/vx 0.0.547 → 0.0.549

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.547",
3
+ "version": "0.0.549",
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.547",
25
- "@vzn/vx-linux-arm64": "0.0.547",
26
- "@vzn/vx-darwin-x64": "0.0.547",
27
- "@vzn/vx-darwin-arm64": "0.0.547"
24
+ "@vzn/vx-linux-x64": "0.0.549",
25
+ "@vzn/vx-linux-arm64": "0.0.549",
26
+ "@vzn/vx-darwin-x64": "0.0.549",
27
+ "@vzn/vx-darwin-arm64": "0.0.549"
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,
@@ -10,6 +10,7 @@
10
10
  // too. `--report-file` is the sink that carries the property end to end.
11
11
 
12
12
  import { failedLabel, skippedLabel, type OutcomeView } from './events.js'
13
+ import { neverStarted } from './summary.js'
13
14
 
14
15
  /**
15
16
  * One finished run, reduced to what a report needs. Used to live in
@@ -35,8 +36,10 @@ import { tallyViews, type Tally } from './tally.js'
35
36
  * a row claiming `success | miss | 0ms`.
36
37
  */
37
38
  interface ReportTally extends Tally {
38
- /** Wall-clock ms summed over tasks that actually executed (misses). */
39
+ /** Wall-clock ms summed over tasks that ran a command, an aborted one's time so far included. */
39
40
  executedMs: number
41
+ /** The aborted tasks the stop reached before they ran, as the terminal splits them. */
42
+ notRun: number
40
43
  /**
41
44
  * Ms of work the cache SKIPPED — the sum of the hits' STORED exec times.
42
45
  * Deliberately not `durationMs`, which for a hit is the restore this run
@@ -46,7 +49,7 @@ interface ReportTally extends Tally {
46
49
  }
47
50
 
48
51
  function tally(outcomes: readonly OutcomeView[]): ReportTally {
49
- const t: ReportTally = { ...tallyViews(outcomes), executedMs: 0, savedMs: 0 }
52
+ const t: ReportTally = { ...tallyViews(outcomes), executedMs: 0, savedMs: 0, notRun: 0 }
50
53
  for (const o of outcomes) {
51
54
  if (o.isGroup === true) continue
52
55
  switch (o.status) {
@@ -54,6 +57,10 @@ function tally(outcomes: readonly OutcomeView[]): ReportTally {
54
57
  case 'failed':
55
58
  t.executedMs += o.durationMs
56
59
  break
60
+ case 'aborted':
61
+ if (neverStarted(o)) t.notRun++
62
+ else t.executedMs += o.durationMs
63
+ break
57
64
  case 'cache-hit':
58
65
  case 'cache-hit-remote':
59
66
  // An outcome that doesn't know what it skipped contributes nothing:
@@ -78,6 +85,8 @@ function statusWord(o: OutcomeView): string {
78
85
  return failedLabel(o.exitCode, o.timedOut, o.sandboxViolations, o.notReady)
79
86
  case 'skipped':
80
87
  return skippedLabel(o.blockedBy)
88
+ case 'aborted':
89
+ return neverStarted(o) ? 'not run' : 'aborted'
81
90
  default:
82
91
  return o.status
83
92
  }
@@ -145,12 +154,21 @@ export function formatRunReportMarkdown(result: RunResult): string {
145
154
  : '0 cached',
146
155
  ]
147
156
  if (t.skipped > 0) parts.push(`${t.skipped} skipped`)
148
- if (t.aborted > 0) parts.push(`${t.aborted} aborted`)
149
157
  parts.push(`${fmtDuration(t.executedMs)} total`)
150
158
  if (t.savedMs > 0) parts.push(`${fmtDuration(t.savedMs)} saved`)
159
+ // The terminal summary's words: neither is in `total`, and a task the stop
160
+ // reached before it ran was never aborted.
161
+ const aborted = t.aborted - t.notRun
162
+ const uncounted: string[] = []
163
+ if (aborted > 0) uncounted.push(`${aborted} aborted`)
164
+ if (t.notRun > 0) uncounted.push(`${t.notRun} not run`)
165
+ if (uncounted.length > 0) parts.push(`not counted: ${uncounted.join(', ')}`)
151
166
 
167
+ // Only a stop (a signal, `RunOptions.signal`) makes an `aborted` outcome,
168
+ // so one is how an interrupted run tells itself from a failed one.
169
+ const heading = t.aborted > 0 ? 'interrupted' : result.ok ? 'passed' : 'failed'
152
170
  const lines: string[] = []
153
- lines.push(`## vx run — ${result.ok ? 'passed' : 'failed'}`)
171
+ lines.push(`## vx run — ${heading}`)
154
172
  lines.push('')
155
173
  lines.push(parts.join(' · '))
156
174
  lines.push('')
@@ -163,7 +181,7 @@ export function formatRunReportMarkdown(result: RunResult): string {
163
181
  if (o.isGroup === true) continue
164
182
  lines.push(
165
183
  `| ${cell(o.taskId)} | ${cell(statusWord(o))} | ${cell(cacheWord(o))} | ${cell(
166
- fmtDuration(o.durationMs),
184
+ neverStarted(o) ? '—' : fmtDuration(o.durationMs),
167
185
  )} |`,
168
186
  )
169
187
  }
@@ -381,7 +381,9 @@ export function formatRunSummary(
381
381
  * it an invented exit 1; only a started task carries a wall-clock start, so
382
382
  * that is what tells "never ran" from "killed" (item 1062).
383
383
  */
384
- export function neverStarted(o: TaskOutcome): boolean {
384
+ export function neverStarted(
385
+ o: Pick<TaskOutcome, 'status'> & { wallclockStartNs?: unknown },
386
+ ): boolean {
385
387
  return o.status === 'aborted' && o.wallclockStartNs === undefined
386
388
  }
387
389