@vzn/vx 0.0.587 → 0.0.589
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.589",
|
|
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.589",
|
|
25
|
+
"@vzn/vx-linux-arm64": "0.0.589",
|
|
26
|
+
"@vzn/vx-darwin-x64": "0.0.589",
|
|
27
|
+
"@vzn/vx-darwin-arm64": "0.0.589"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@anthropic-ai/sandbox-runtime": "^0.0.76"
|
package/src/cache/archive.ts
CHANGED
|
@@ -952,14 +952,9 @@ function assertSafeName(name: string): void {
|
|
|
952
952
|
if (name.includes('//')) {
|
|
953
953
|
throw new ArchiveSecurityError(`archive entry name has empty path component (unsafe): ${name}`)
|
|
954
954
|
}
|
|
955
|
-
//
|
|
956
|
-
//
|
|
957
|
-
//
|
|
958
|
-
if (name.includes('\\')) {
|
|
959
|
-
throw new ArchiveSecurityError(
|
|
960
|
-
`archive entry uses backslash separators (windows-unsafe): ${name}`,
|
|
961
|
-
)
|
|
962
|
-
}
|
|
955
|
+
// No backslash refusal: vx runs on Linux and macOS (Windows through WSL),
|
|
956
|
+
// where it is a name character, and the save scans its own artifact with
|
|
957
|
+
// these checks, so refusing one made `dist/back\slash` uncacheable.
|
|
963
958
|
if (/^[A-Za-z]:[\\/]/.test(name)) {
|
|
964
959
|
throw new ArchiveSecurityError(`archive entry has windows drive prefix (unsafe): ${name}`)
|
|
965
960
|
}
|
package/src/cli/run.ts
CHANGED
|
@@ -7,11 +7,9 @@ import { defaultAffectedBase, findWorkspaceRoot } from '../workspace/index.js'
|
|
|
7
7
|
import {
|
|
8
8
|
planRun,
|
|
9
9
|
formatRunReportMarkdown,
|
|
10
|
-
outcomeLabel,
|
|
11
10
|
projectOutcome,
|
|
12
11
|
run as runOrchestrator,
|
|
13
12
|
shellQuote,
|
|
14
|
-
type OutcomeView,
|
|
15
13
|
type RunOptions,
|
|
16
14
|
type RunResult,
|
|
17
15
|
} from '../orchestrator/index.js'
|
|
@@ -567,6 +565,7 @@ export async function resolveRunOptions(
|
|
|
567
565
|
flow: detectFlow(parsed),
|
|
568
566
|
...(parsed.frozen ? { frozen: true } : {}),
|
|
569
567
|
...(parsed.outputLogs !== undefined ? { outputLogs: parsed.outputLogs } : {}),
|
|
568
|
+
...(parsed.verbosity > 0 ? { summaryTable: true } : {}),
|
|
570
569
|
...(parsed.download !== undefined ? { download: parsed.download } : {}),
|
|
571
570
|
...(parsed.continueMode !== undefined ? { continueMode: parsed.continueMode } : {}),
|
|
572
571
|
forwardArgs: parsed.forwardArgs,
|
|
@@ -707,7 +706,6 @@ export async function runCmd(args: readonly string[]): Promise<number> {
|
|
|
707
706
|
return 1
|
|
708
707
|
}
|
|
709
708
|
const result: RunResult = { ok: summary.ok, outcomes: summary.outcomes.map(projectOutcome) }
|
|
710
|
-
if (parsed.verbosity > 0) printSummary(result)
|
|
711
709
|
// Report generation is post-run, gated on the flags — zero cost when
|
|
712
710
|
// both are absent. Rendered once, however many sinks asked for it.
|
|
713
711
|
if (parsed.report === 'markdown' || parsed.reportFile !== undefined) {
|
|
@@ -742,35 +740,3 @@ export async function runCmd(args: readonly string[]): Promise<number> {
|
|
|
742
740
|
}
|
|
743
741
|
return result.ok ? 0 : 1
|
|
744
742
|
}
|
|
745
|
-
|
|
746
|
-
function printSummary(summary: RunResult): void {
|
|
747
|
-
const rows = summary.outcomes.map((o) => formatRow(o))
|
|
748
|
-
if (rows.length === 0) return
|
|
749
|
-
const widths = {
|
|
750
|
-
task: Math.max(4, ...rows.map((r) => r.task.length)),
|
|
751
|
-
status: Math.max(6, ...rows.map((r) => r.status.length)),
|
|
752
|
-
duration: Math.max(8, ...rows.map((r) => r.duration.length)),
|
|
753
|
-
}
|
|
754
|
-
const header =
|
|
755
|
-
'TASK'.padEnd(widths.task) +
|
|
756
|
-
' ' +
|
|
757
|
-
'STATUS'.padEnd(widths.status) +
|
|
758
|
-
' ' +
|
|
759
|
-
'DURATION'.padStart(widths.duration)
|
|
760
|
-
process.stdout.write(`\n${header}\n`)
|
|
761
|
-
process.stdout.write('-'.repeat(header.length) + '\n')
|
|
762
|
-
for (const r of rows) {
|
|
763
|
-
process.stdout.write(
|
|
764
|
-
r.task.padEnd(widths.task) +
|
|
765
|
-
' ' +
|
|
766
|
-
r.status.padEnd(widths.status) +
|
|
767
|
-
' ' +
|
|
768
|
-
r.duration.padStart(widths.duration) +
|
|
769
|
-
'\n',
|
|
770
|
-
)
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
function formatRow(o: OutcomeView): { task: string; status: string; duration: string } {
|
|
775
|
-
return { task: o.taskId, status: outcomeLabel(o), duration: `${o.durationMs}ms` }
|
|
776
|
-
}
|
|
@@ -207,6 +207,11 @@ export interface RunOptions {
|
|
|
207
207
|
* is replaced only when the next cycle starts.
|
|
208
208
|
*/
|
|
209
209
|
holdPersistent?: boolean
|
|
210
|
+
/**
|
|
211
|
+
* Print the per-task table (`--verbosity 1`) just above the footer: the
|
|
212
|
+
* footer is the run's last word, so the caller cannot print it after.
|
|
213
|
+
*/
|
|
214
|
+
summaryTable?: boolean
|
|
210
215
|
/**
|
|
211
216
|
* vx's stdin is a terminal: each `exec.interactive` task is handed it,
|
|
212
217
|
* alone (placement.ts `terminalHolders`). The CLI sets it from
|
package/src/orchestrator/run.ts
CHANGED
|
@@ -92,7 +92,7 @@ import { assembleRunRecords } from './run-records.js'
|
|
|
92
92
|
import { hasEnded, selectKeepAlive, shutdownPersistent } from './persistent.js'
|
|
93
93
|
import { writeRunProfile, writeRunSummary } from './run-artifacts.js'
|
|
94
94
|
import { createSaveLane } from './save-lane.js'
|
|
95
|
-
import { formatRunSummary } from './summary.js'
|
|
95
|
+
import { formatOutcomeTable, formatRunSummary } from './summary.js'
|
|
96
96
|
import { detectFlaky, type FlakyCandidate, type FlakyFinding } from './failure-mode.js'
|
|
97
97
|
import { createMissExplainer } from './miss-reason.js'
|
|
98
98
|
import type { RunOptions, RunSummary } from './options.js'
|
|
@@ -1328,6 +1328,7 @@ async function runOnBus(
|
|
|
1328
1328
|
// sandbox reset included, so any warning they raise lands above it. A
|
|
1329
1329
|
// task's own facts (flaky, blocked) ride its row. Only a kept server's
|
|
1330
1330
|
// own output follows.
|
|
1331
|
+
if (options.summaryTable === true) for (const line of formatOutcomeTable(list)) log.status(line)
|
|
1331
1332
|
for (const line of formatRunSummary(list, totalMs, colors, runContext)) log.status(line)
|
|
1332
1333
|
|
|
1333
1334
|
// Edge case the summary already reported: the user requested a
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import type { TaskOutcome } from '../graph/index.js'
|
|
7
7
|
import { paint, type ColorSupport } from './colors.js'
|
|
8
8
|
import { tallyOutcomes } from './tally.js'
|
|
9
|
+
import { outcomeLabel, projectOutcome } from './events.js'
|
|
9
10
|
import { isGroupTask } from '../graph/index.js'
|
|
10
11
|
import { formatElapsed } from '../util/index.js'
|
|
11
12
|
|
|
@@ -314,6 +315,34 @@ function resultLine(
|
|
|
314
315
|
return parts.join(` ${paint('', '\u00b7', colors, { dim: true })} `)
|
|
315
316
|
}
|
|
316
317
|
|
|
318
|
+
/**
|
|
319
|
+
* The `--verbosity 1` per-task table (`RunOptions.summaryTable`). Groups are
|
|
320
|
+
* left out as the footer and `--report` leave them: a group ran no command.
|
|
321
|
+
*/
|
|
322
|
+
export function formatOutcomeTable(outcomes: readonly TaskOutcome[]): string[] {
|
|
323
|
+
const rows = outcomes
|
|
324
|
+
.filter((o) => !isGroupTask(o.node))
|
|
325
|
+
.map((o) => {
|
|
326
|
+
const v = projectOutcome(o)
|
|
327
|
+
return { task: v.taskId, status: outcomeLabel(v), duration: `${v.durationMs}ms` }
|
|
328
|
+
})
|
|
329
|
+
if (rows.length === 0) return []
|
|
330
|
+
const widths = {
|
|
331
|
+
task: Math.max(4, ...rows.map((r) => r.task.length)),
|
|
332
|
+
status: Math.max(6, ...rows.map((r) => r.status.length)),
|
|
333
|
+
duration: Math.max(8, ...rows.map((r) => r.duration.length)),
|
|
334
|
+
}
|
|
335
|
+
const line = (task: string, status: string, duration: string) =>
|
|
336
|
+
`${task.padEnd(widths.task)} ${status.padEnd(widths.status)} ${duration.padStart(widths.duration)}`
|
|
337
|
+
const header = line('TASK', 'STATUS', 'DURATION')
|
|
338
|
+
return [
|
|
339
|
+
'',
|
|
340
|
+
header,
|
|
341
|
+
'-'.repeat(header.length),
|
|
342
|
+
...rows.map((r) => line(r.task, r.status, r.duration)),
|
|
343
|
+
]
|
|
344
|
+
}
|
|
345
|
+
|
|
317
346
|
// Local byte formatter — the orchestrator can't import cli/format.ts
|
|
318
347
|
// (module boundary), and the footer only needs one compact form.
|
|
319
348
|
export function formatRunSummary(
|