@vzn/vx 0.0.366 → 0.0.368
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.368",
|
|
4
4
|
"description": "A fast, correct 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.368",
|
|
25
|
+
"@vzn/vx-linux-arm64": "0.0.368",
|
|
26
|
+
"@vzn/vx-darwin-x64": "0.0.368",
|
|
27
|
+
"@vzn/vx-darwin-arm64": "0.0.368"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@anthropic-ai/sandbox-runtime": "^0.0.76"
|
|
@@ -399,6 +399,22 @@ async function executePersistentTask(args: ExecuteArgs): Promise<TaskOutcome> {
|
|
|
399
399
|
try {
|
|
400
400
|
await spawn.ready
|
|
401
401
|
} catch (err) {
|
|
402
|
+
// A server the run's stop killed while it started is aborted, as any
|
|
403
|
+
// task the stop kills (item 962): it read `failed (never ready:
|
|
404
|
+
// exited, exit 130)` with a recap after every Ctrl-C (C-62). The stop
|
|
405
|
+
// aborts before it kills, so it is set by the time the child is gone.
|
|
406
|
+
// Read through a call: the early return above narrows `aborted` to
|
|
407
|
+
// false, but the stop can land during `spawn.ready`.
|
|
408
|
+
if (isAborted(args.stopSignal)) {
|
|
409
|
+
return {
|
|
410
|
+
node,
|
|
411
|
+
status: 'aborted',
|
|
412
|
+
exitCode: err instanceof PersistentReadyError ? (err.exitCode ?? 1) : 1,
|
|
413
|
+
durationMs: spawn.readyMs(),
|
|
414
|
+
wallclockStartNs,
|
|
415
|
+
wallclockEndNs: process.hrtime.bigint() - args.runStartHrTimeNs,
|
|
416
|
+
}
|
|
417
|
+
}
|
|
402
418
|
const message = err instanceof Error ? err.message : String(err)
|
|
403
419
|
// The task's OWN stream, not the process's: the frame is where a
|
|
404
420
|
// reader looks for why a task failed, and a run with a custom logger
|
|
@@ -1300,3 +1316,7 @@ function taskEnv(node: TaskNode, step: ExecConfig, workspaceRoot: string): NodeJ
|
|
|
1300
1316
|
env[VX_RUN_TASK_ENV] = node.id
|
|
1301
1317
|
return env
|
|
1302
1318
|
}
|
|
1319
|
+
|
|
1320
|
+
function isAborted(signal: AbortSignal | undefined): boolean {
|
|
1321
|
+
return signal?.aborted === true
|
|
1322
|
+
}
|
|
@@ -674,11 +674,27 @@ function revParse(workspaceRoot: string, ref: string): string | undefined {
|
|
|
674
674
|
'ignore',
|
|
675
675
|
)
|
|
676
676
|
const sha = new TextDecoder().decode(proc.stdout).trim()
|
|
677
|
-
|
|
677
|
+
if (proc.exitCode !== 0 || sha.length === 0) return undefined
|
|
678
|
+
resolvedRefs.set(`${workspaceRoot}\0${ref}`, sha)
|
|
679
|
+
return sha
|
|
678
680
|
}
|
|
679
681
|
|
|
682
|
+
/**
|
|
683
|
+
* Refs `revParse` resolved to a commit, by workspace: the default base is
|
|
684
|
+
* found that way, and `verifyRef` asked git about it again, a synchronous
|
|
685
|
+
* spawn (~3.5 ms) of every bare `--affected`. A ref is fixed for a run.
|
|
686
|
+
*/
|
|
687
|
+
const resolvedRefs = new Map<string, string>()
|
|
688
|
+
|
|
689
|
+
/** A ref that names an ancestor of HEAD by its own spelling (`HEAD~1`, `HEAD^`). */
|
|
690
|
+
const HEAD_ANCESTOR = /^HEAD(?:~\d*|\^\d*)+$/
|
|
691
|
+
|
|
680
692
|
/** `git merge-base <ref> HEAD`, or `ref` itself when the two share no ancestor. */
|
|
681
693
|
async function mergeBase(workspaceRoot: string, ref: string): Promise<string> {
|
|
694
|
+
// HEAD's own ancestor is its merge base with HEAD: the commit it names,
|
|
695
|
+
// which the default base's search already resolved (`HEAD~1`).
|
|
696
|
+
const known = HEAD_ANCESTOR.test(ref) ? resolvedRefs.get(`${workspaceRoot}\0${ref}`) : undefined
|
|
697
|
+
if (known !== undefined) return known
|
|
682
698
|
const proc = spawnGit(['merge-base', '--end-of-options', ref, 'HEAD'], workspaceRoot)
|
|
683
699
|
const [out, exit] = await Promise.all([new Response(proc.stdout).text(), proc.exited])
|
|
684
700
|
const sha = out.trim()
|
|
@@ -686,6 +702,7 @@ async function mergeBase(workspaceRoot: string, ref: string): Promise<string> {
|
|
|
686
702
|
}
|
|
687
703
|
|
|
688
704
|
async function verifyRef(workspaceRoot: string, ref: string): Promise<void> {
|
|
705
|
+
if (resolvedRefs.has(`${workspaceRoot}\0${ref}`)) return
|
|
689
706
|
const proc = spawnGitSync(
|
|
690
707
|
['rev-parse', '--verify', '--quiet', '--end-of-options', ref],
|
|
691
708
|
workspaceRoot,
|
|
@@ -676,23 +676,49 @@ export function migrateScripts(
|
|
|
676
676
|
.filter(([, v]) => typeof v === 'string' && v !== '')
|
|
677
677
|
.map(([n]) => n),
|
|
678
678
|
)
|
|
679
|
-
|
|
679
|
+
// The root scripts left out, by why: jest's root `build` (every package's)
|
|
680
|
+
// went unnamed beside the website's, and `vx run build --all` built the
|
|
681
|
+
// website alone (D-85). A left-out script's `pre` / `post` hook goes with
|
|
682
|
+
// it where the manager runs hooks: kept, it became a task of its own.
|
|
683
|
+
const leftOut = (meta: ProjectMeta): { runs: string[]; shared: string[]; out: Set<string> } => {
|
|
680
684
|
const scripts = scriptsOf(meta)
|
|
681
685
|
const runs = runningMembers(
|
|
682
686
|
scripts,
|
|
683
687
|
meta.dir,
|
|
684
688
|
metas.filter((m) => m !== root).map((m) => m.dir),
|
|
685
689
|
)
|
|
690
|
+
const hooks = runsScriptHooks(meta.dir, hookMemo) !== null
|
|
691
|
+
const hookOf = (n: string): string | undefined => {
|
|
692
|
+
const base = hooks ? /^(?:pre|post)(.+)$/.exec(n)?.[1] : undefined
|
|
693
|
+
return base !== undefined && typeof scripts[base] === 'string' ? base : undefined
|
|
694
|
+
}
|
|
695
|
+
// A hook rides in its script's command, so it is judged with it.
|
|
696
|
+
const named = Object.keys(scripts).filter(
|
|
697
|
+
(n) => typeof scripts[n] === 'string' && !LIFECYCLE.test(n) && hookOf(n) === undefined,
|
|
698
|
+
)
|
|
699
|
+
const left = {
|
|
700
|
+
runs: named.filter((n) => runs.has(n)),
|
|
701
|
+
shared: named.filter((n) => memberTasks.has(n) && !runs.has(n)),
|
|
702
|
+
}
|
|
703
|
+
const outNames = new Set([...left.runs, ...left.shared])
|
|
704
|
+
const out = new Set(
|
|
705
|
+
Object.keys(scripts).filter((n) => outNames.has(n) || outNames.has(hookOf(n) ?? '')),
|
|
706
|
+
)
|
|
707
|
+
return { ...left, out }
|
|
708
|
+
}
|
|
709
|
+
const rootScripts = (meta: ProjectMeta): Record<string, unknown> => {
|
|
710
|
+
const scripts = scriptsOf(meta)
|
|
711
|
+
const { out } = leftOut(meta)
|
|
686
712
|
return Object.fromEntries(
|
|
687
|
-
Object.entries(scripts).filter(
|
|
688
|
-
([n, v]) => typeof v === 'string' && !memberTasks.has(n) && !runs.has(n),
|
|
689
|
-
),
|
|
713
|
+
Object.entries(scripts).filter(([n, v]) => typeof v === 'string' && !out.has(n)),
|
|
690
714
|
)
|
|
691
715
|
}
|
|
692
716
|
const rootMapped =
|
|
693
717
|
rootMeta === undefined
|
|
694
718
|
? 0
|
|
695
719
|
: Object.keys(rootScripts(rootMeta)).filter((n) => !LIFECYCLE.test(n)).length
|
|
720
|
+
const listed = (names: readonly string[]): string =>
|
|
721
|
+
names.slice(0, 8).join(', ') + (names.length > 8 ? ` and ${names.length - 8} more` : '')
|
|
696
722
|
const outsideScripts = outside?.['scripts']
|
|
697
723
|
const outsideRuns =
|
|
698
724
|
typeof outsideScripts === 'object' &&
|
|
@@ -720,8 +746,15 @@ export function migrateScripts(
|
|
|
720
746
|
: 'package.json'
|
|
721
747
|
: undefined)
|
|
722
748
|
if (rootName !== undefined && rootMapped > 0) {
|
|
749
|
+
const { runs, shared } = leftOut(rootMeta!)
|
|
723
750
|
notes.push(
|
|
724
|
-
`${rootName} (the workspace root): its scripts that check the whole repo are its tasks
|
|
751
|
+
`${rootName} (the workspace root): its scripts that check the whole repo are its tasks` +
|
|
752
|
+
(runs.length > 0
|
|
753
|
+
? `; left out as running the members (${membersExample(rootMeta && rootManager(rootMeta.dir, hookMemo))}, a runner): ${listed(runs)}`
|
|
754
|
+
: '') +
|
|
755
|
+
(shared.length > 0
|
|
756
|
+
? `; left out as a member's task name, so \`--all\` never runs one twice: ${listed(shared)} — one that does other work maps by hand under a name of its own`
|
|
757
|
+
: ''),
|
|
725
758
|
)
|
|
726
759
|
} else if (rootName === 'package.json' && outsideDir !== undefined && unnamedMaps().length > 0) {
|
|
727
760
|
// react's nameless root: "its scripts run the workspace" was not why,
|