@vzn/vx 0.0.586 → 0.0.588
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.588",
|
|
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.588",
|
|
25
|
+
"@vzn/vx-linux-arm64": "0.0.588",
|
|
26
|
+
"@vzn/vx-darwin-x64": "0.0.588",
|
|
27
|
+
"@vzn/vx-darwin-arm64": "0.0.588"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@anthropic-ai/sandbox-runtime": "^0.0.76"
|
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
|
-
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import { statSync } from 'node:fs'
|
|
8
8
|
import path from 'node:path'
|
|
9
9
|
import { absolutize, atOrUnder, isUnderAny, localBindingOn, toRealPath } from './sandbox-paths.js'
|
|
10
|
-
import { bindableReads } from './sandbox-binds.js'
|
|
10
|
+
import { bindableReads, bindableWrites } from './sandbox-binds.js'
|
|
11
11
|
import type {
|
|
12
12
|
ResolvedSandboxConfig,
|
|
13
13
|
SandboxedRunArgs,
|
|
@@ -321,17 +321,22 @@ export async function parseStraceViolations(
|
|
|
321
321
|
const text = await Bun.file(logPath).text()
|
|
322
322
|
if (text.length === 0) return []
|
|
323
323
|
|
|
324
|
-
// Treat every baseAllow + sandbox.allowRead path as "this
|
|
325
|
-
// explicitly permitted; any -ENOENT here is the user's own missing
|
|
326
|
-
// file, not a sandbox-induced denial".
|
|
327
|
-
//
|
|
328
|
-
//
|
|
329
|
-
//
|
|
324
|
+
// Treat every baseAllow + sandbox.allowRead + allowWrite path as "this
|
|
325
|
+
// was explicitly permitted; any -ENOENT here is the user's own missing
|
|
326
|
+
// file, not a sandbox-induced denial". A write grant counts: GNU cp
|
|
327
|
+
// opens its destination before creating it, and tsc probes its
|
|
328
|
+
// buildinfo. Same for absolute denyRead checks below. Canonical on BOTH
|
|
329
|
+
// sides — the policy is expressed in real paths (see
|
|
330
|
+
// `canonicalBaselines`), so comparing a link-path here would report an
|
|
331
|
+
// explicitly-allowed read as a violation.
|
|
330
332
|
const allowAbs = new Set<string>(
|
|
331
|
-
// A grant SRT could not mount (`bindableReads`)
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
333
|
+
// A grant SRT could not mount (`bindableReads`, `bindableWrites`)
|
|
334
|
+
// permits nothing.
|
|
335
|
+
[
|
|
336
|
+
...baselines.allowRead,
|
|
337
|
+
...bindableReads(args.config.allowRead),
|
|
338
|
+
...args.config.allowWrite.filter((w) => bindableWrites([w]).length > 0),
|
|
339
|
+
].map((p) => toRealPath(absolutize(p))),
|
|
335
340
|
)
|
|
336
341
|
const denyAnchors = baselines.denyRead.map((p) => toRealPath(absolutize(p)))
|
|
337
342
|
// A read under a widened write grant's directory is never refused, so it
|
|
@@ -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(
|