@vzn/vx 0.0.555 → 0.0.556

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.555",
3
+ "version": "0.0.556",
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.555",
25
- "@vzn/vx-linux-arm64": "0.0.555",
26
- "@vzn/vx-darwin-x64": "0.0.555",
27
- "@vzn/vx-darwin-arm64": "0.0.555"
24
+ "@vzn/vx-linux-x64": "0.0.556",
25
+ "@vzn/vx-linux-arm64": "0.0.556",
26
+ "@vzn/vx-darwin-x64": "0.0.556",
27
+ "@vzn/vx-darwin-arm64": "0.0.556"
28
28
  },
29
29
  "dependencies": {
30
30
  "@anthropic-ai/sandbox-runtime": "^0.0.76"
@@ -739,11 +739,15 @@ function stampFiles(files: readonly string[]): Map<string, OutputStamp> {
739
739
  * a current tree, so no new trust is introduced. A file the run rewrote
740
740
  * with identical bytes counts as its own (the mtime moved), which is the
741
741
  * rewrite-in-place cost the design note records.
742
+ *
743
+ * Undefined when the run REMOVED a file it found: an artifact holds what a
744
+ * run wrote, never what it took away, and the upstream's restore puts the
745
+ * file back, so no entry reproduces that run and none is saved.
742
746
  */
743
747
  export async function ownOutputsSince(
744
748
  args: { projectDir: string; outputs: string[]; nestedProjectDirs: string[] },
745
749
  before: ReadonlyMap<string, OutputStamp>,
746
- ): Promise<string[]> {
750
+ ): Promise<string[] | undefined> {
747
751
  return changedSince(await resolveOutputs(args), before)
748
752
  }
749
753
 
@@ -751,15 +755,16 @@ export async function ownOutputsSince(
751
755
  export async function ownWorkspaceOutputsSince(
752
756
  args: { workspaceRoot: string; outputs: string[] },
753
757
  before: ReadonlyMap<string, OutputStamp>,
754
- ): Promise<string[]> {
758
+ ): Promise<string[] | undefined> {
755
759
  return changedSince(await resolveWorkspaceOutputs(args), before)
756
760
  }
757
761
 
758
762
  function changedSince(
759
763
  after: readonly string[],
760
764
  before: ReadonlyMap<string, OutputStamp>,
761
- ): string[] {
765
+ ): string[] | undefined {
762
766
  const own: string[] = []
767
+ let kept = 0
763
768
  for (const f of after) {
764
769
  const was = before.get(f)
765
770
  if (was === undefined) {
@@ -768,12 +773,13 @@ function changedSince(
768
773
  }
769
774
  try {
770
775
  const st = lstatSync(f)
776
+ kept++
771
777
  if (st.size !== was.size || st.mtimeMs !== was.mtimeMs) own.push(f)
772
778
  } catch {
773
- // Vanished since the walk: not an output.
779
+ // Vanished since the walk: removed, as one the walk missed is.
774
780
  }
775
781
  }
776
- return own
782
+ return kept < before.size ? undefined : own
777
783
  }
778
784
 
779
785
  /**
@@ -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 (effectiveExitCode === 0 && willSave && (await keyStillTrue())) {
1238
- const ownOutputFiles =
1239
- additive && stampedBefore !== undefined
1240
- ? await ownOutputsSince(cleanArgs, stampedBefore)
1241
- : undefined
1242
- const ownWsOutputFiles =
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
- ...(ownOutputFiles !== undefined ? { ownOutputFiles } : {}),
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