@vzn/vx 0.0.555 → 0.0.557
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/cache/inputs.ts +31 -12
- package/src/orchestrator/execute-task.ts +30 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vzn/vx",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.557",
|
|
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.557",
|
|
25
|
+
"@vzn/vx-linux-arm64": "0.0.557",
|
|
26
|
+
"@vzn/vx-darwin-x64": "0.0.557",
|
|
27
|
+
"@vzn/vx-darwin-arm64": "0.0.557"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@anthropic-ai/sandbox-runtime": "^0.0.76"
|
package/src/cache/inputs.ts
CHANGED
|
@@ -692,10 +692,17 @@ export async function cleanOutputPaths(args: {
|
|
|
692
692
|
await pruneEmptiedDirs(args.projectDir, await removeAll(files, args.projectDir))
|
|
693
693
|
}
|
|
694
694
|
|
|
695
|
-
/**
|
|
695
|
+
/**
|
|
696
|
+
* A file's identity for the additive diff: what the hit path's
|
|
697
|
+
* `isOutputsCurrent` trusts too. Size and mtime alone missed a rewrite to
|
|
698
|
+
* bytes of the same length with the mtime stamped back; the inode and
|
|
699
|
+
* ctime are what no task sets (item 886).
|
|
700
|
+
*/
|
|
696
701
|
export interface OutputStamp {
|
|
697
702
|
size: number
|
|
698
703
|
mtimeMs: number
|
|
704
|
+
ino: number
|
|
705
|
+
ctimeMs: number
|
|
699
706
|
}
|
|
700
707
|
|
|
701
708
|
/**
|
|
@@ -724,7 +731,7 @@ function stampFiles(files: readonly string[]): Map<string, OutputStamp> {
|
|
|
724
731
|
for (const f of files) {
|
|
725
732
|
try {
|
|
726
733
|
const st = lstatSync(f)
|
|
727
|
-
out.set(f, { size: st.size, mtimeMs: st.mtimeMs })
|
|
734
|
+
out.set(f, { size: st.size, mtimeMs: st.mtimeMs, ino: st.ino, ctimeMs: st.ctimeMs })
|
|
728
735
|
} catch {
|
|
729
736
|
// Gone between the walk and the stat: not a file the task found.
|
|
730
737
|
}
|
|
@@ -734,16 +741,20 @@ function stampFiles(files: readonly string[]): Map<string, OutputStamp> {
|
|
|
734
741
|
|
|
735
742
|
/**
|
|
736
743
|
* The files an additive task's run ADDED or CHANGED under its declared
|
|
737
|
-
* outputs: every selected file that was not in `before`, or whose
|
|
738
|
-
*
|
|
739
|
-
*
|
|
740
|
-
*
|
|
744
|
+
* outputs: every selected file that was not in `before`, or whose stamp
|
|
745
|
+
* (`OutputStamp`) moved — the proof the hit path trusts for a current
|
|
746
|
+
* tree, so no new trust is introduced. A file the run rewrote, even with
|
|
747
|
+
* identical bytes, counts as its own (its ctime moved), which is the
|
|
741
748
|
* rewrite-in-place cost the design note records.
|
|
749
|
+
*
|
|
750
|
+
* Undefined when the run REMOVED a file it found: an artifact holds what a
|
|
751
|
+
* run wrote, never what it took away, and the upstream's restore puts the
|
|
752
|
+
* file back, so no entry reproduces that run and none is saved.
|
|
742
753
|
*/
|
|
743
754
|
export async function ownOutputsSince(
|
|
744
755
|
args: { projectDir: string; outputs: string[]; nestedProjectDirs: string[] },
|
|
745
756
|
before: ReadonlyMap<string, OutputStamp>,
|
|
746
|
-
): Promise<string[]> {
|
|
757
|
+
): Promise<string[] | undefined> {
|
|
747
758
|
return changedSince(await resolveOutputs(args), before)
|
|
748
759
|
}
|
|
749
760
|
|
|
@@ -751,15 +762,16 @@ export async function ownOutputsSince(
|
|
|
751
762
|
export async function ownWorkspaceOutputsSince(
|
|
752
763
|
args: { workspaceRoot: string; outputs: string[] },
|
|
753
764
|
before: ReadonlyMap<string, OutputStamp>,
|
|
754
|
-
): Promise<string[]> {
|
|
765
|
+
): Promise<string[] | undefined> {
|
|
755
766
|
return changedSince(await resolveWorkspaceOutputs(args), before)
|
|
756
767
|
}
|
|
757
768
|
|
|
758
769
|
function changedSince(
|
|
759
770
|
after: readonly string[],
|
|
760
771
|
before: ReadonlyMap<string, OutputStamp>,
|
|
761
|
-
): string[] {
|
|
772
|
+
): string[] | undefined {
|
|
762
773
|
const own: string[] = []
|
|
774
|
+
let kept = 0
|
|
763
775
|
for (const f of after) {
|
|
764
776
|
const was = before.get(f)
|
|
765
777
|
if (was === undefined) {
|
|
@@ -768,12 +780,19 @@ function changedSince(
|
|
|
768
780
|
}
|
|
769
781
|
try {
|
|
770
782
|
const st = lstatSync(f)
|
|
771
|
-
|
|
783
|
+
kept++
|
|
784
|
+
if (
|
|
785
|
+
st.size !== was.size ||
|
|
786
|
+
st.mtimeMs !== was.mtimeMs ||
|
|
787
|
+
st.ino !== was.ino ||
|
|
788
|
+
st.ctimeMs !== was.ctimeMs
|
|
789
|
+
)
|
|
790
|
+
own.push(f)
|
|
772
791
|
} catch {
|
|
773
|
-
// Vanished since the walk:
|
|
792
|
+
// Vanished since the walk: removed, as one the walk missed is.
|
|
774
793
|
}
|
|
775
794
|
}
|
|
776
|
-
return own
|
|
795
|
+
return kept < before.size ? undefined : own
|
|
777
796
|
}
|
|
778
797
|
|
|
779
798
|
/**
|
|
@@ -1213,6 +1213,7 @@ async function executeCachedTask(args: ExecuteArgs): Promise<TaskOutcome> {
|
|
|
1213
1213
|
|
|
1214
1214
|
const wallclockEndNs = process.hrtime.bigint() - args.runStartHrTimeNs
|
|
1215
1215
|
|
|
1216
|
+
let own: Awaited<ReturnType<typeof ownOutputs>>
|
|
1216
1217
|
if (effectiveExitCode === 0 && willSave && deferralRequested) {
|
|
1217
1218
|
// The outputs never landed here: no artifact, no rows. A partial local
|
|
1218
1219
|
// record (a row with no artifact) is exactly the corrupt-entry shape
|
|
@@ -1234,18 +1235,14 @@ async function executeCachedTask(args: ExecuteArgs): Promise<TaskOutcome> {
|
|
|
1234
1235
|
},
|
|
1235
1236
|
})
|
|
1236
1237
|
}
|
|
1237
|
-
} else if (
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
additive && wsStampedBefore !== undefined
|
|
1244
|
-
? await ownWorkspaceOutputsSince(wsCleanArgs, wsStampedBefore)
|
|
1245
|
-
: undefined
|
|
1238
|
+
} else if (
|
|
1239
|
+
effectiveExitCode === 0 &&
|
|
1240
|
+
willSave &&
|
|
1241
|
+
(await keyStillTrue()) &&
|
|
1242
|
+
(own = await ownOutputs()) !== undefined
|
|
1243
|
+
) {
|
|
1246
1244
|
const { landed } = await saveMiss({
|
|
1247
|
-
...
|
|
1248
|
-
...(ownWsOutputFiles !== undefined ? { ownWsOutputFiles } : {}),
|
|
1245
|
+
...own,
|
|
1249
1246
|
node,
|
|
1250
1247
|
hash,
|
|
1251
1248
|
cache,
|
|
@@ -1302,6 +1299,28 @@ async function executeCachedTask(args: ExecuteArgs): Promise<TaskOutcome> {
|
|
|
1302
1299
|
return true
|
|
1303
1300
|
}
|
|
1304
1301
|
|
|
1302
|
+
/**
|
|
1303
|
+
* What an additive run saves as its own, or undefined when it removed a
|
|
1304
|
+
* file it found: no entry replays a removal (`ownOutputsSince`), so the
|
|
1305
|
+
* task saves nothing and runs again.
|
|
1306
|
+
*/
|
|
1307
|
+
async function ownOutputs(): Promise<
|
|
1308
|
+
{ ownOutputFiles?: string[]; ownWsOutputFiles?: string[] } | undefined
|
|
1309
|
+
> {
|
|
1310
|
+
const mine: { ownOutputFiles?: string[]; ownWsOutputFiles?: string[] } = {}
|
|
1311
|
+
if (stampedBefore !== undefined) {
|
|
1312
|
+
const files = await ownOutputsSince(cleanArgs, stampedBefore)
|
|
1313
|
+
if (files === undefined) return undefined
|
|
1314
|
+
mine.ownOutputFiles = files
|
|
1315
|
+
}
|
|
1316
|
+
if (wsStampedBefore !== undefined) {
|
|
1317
|
+
const files = await ownWorkspaceOutputsSince(wsCleanArgs, wsStampedBefore)
|
|
1318
|
+
if (files === undefined) return undefined
|
|
1319
|
+
mine.ownWsOutputFiles = files
|
|
1320
|
+
}
|
|
1321
|
+
return mine
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1305
1324
|
/**
|
|
1306
1325
|
* The input that no longer holds what the key folded: `null` when the
|
|
1307
1326
|
* key re-derived just before the command already differed (the file
|