@vzn/vx 0.0.77 → 0.0.78

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.77",
3
+ "version": "0.0.78",
4
4
  "description": "An open, extensible monorepo task runner.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -17,10 +17,10 @@
17
17
  "node": ">=18"
18
18
  },
19
19
  "optionalDependencies": {
20
- "@vzn/vx-linux-x64": "0.0.77",
21
- "@vzn/vx-linux-arm64": "0.0.77",
22
- "@vzn/vx-darwin-x64": "0.0.77",
23
- "@vzn/vx-darwin-arm64": "0.0.77"
20
+ "@vzn/vx-linux-x64": "0.0.78",
21
+ "@vzn/vx-linux-arm64": "0.0.78",
22
+ "@vzn/vx-darwin-x64": "0.0.78",
23
+ "@vzn/vx-darwin-arm64": "0.0.78"
24
24
  },
25
25
  "dependencies": {
26
26
  "@anthropic-ai/sandbox-runtime": "^0.0.76"
@@ -54,8 +54,6 @@ export async function keyExcludedDependencies(args: KeyExcludedArgs): Promise<vo
54
54
  const derive = async (node: TaskNode): Promise<string | undefined> => {
55
55
  const upstream = await outcomes(fullDeps(node))
56
56
  if (isGroupTask(node)) return computeGroupHash(upstream)
57
- // A persistent task has no key on the live path, so none here either.
58
- if (node.config.exec?.persistent !== undefined) return undefined
59
57
  return computeTaskHash({
60
58
  node,
61
59
  upstream,
@@ -260,6 +260,23 @@ async function executePersistentTask(args: ExecuteArgs): Promise<TaskOutcome> {
260
260
  const effectiveForwardArgs = node.requested ? (args.forwardArgs ?? []) : []
261
261
  const env = taskEnv(node, step, args.workspaceRoot)
262
262
  const wallclockStartNs = process.hrtime.bigint() - args.runStartHrTimeNs
263
+ // Keyed like an uncached task (its whole project), so a cached dependant
264
+ // behind a dev server re-runs when the server's sources change; with no
265
+ // key the dependant folded nothing of it and replayed a stale e2e (A-17).
266
+ const hash =
267
+ args.noDependants === true
268
+ ? undefined
269
+ : await computeTaskHash({
270
+ node,
271
+ upstream: args.upstream,
272
+ workspaceRoot: args.workspaceRoot,
273
+ workspaceFingerprint: args.workspaceFingerprint,
274
+ cache: args.cache,
275
+ forwardArgs: args.forwardArgs,
276
+ nestedProjectDirs: args.nestedProjectDirs,
277
+ ...(args.gitFilesCache !== undefined ? { gitFilesCache: args.gitFilesCache } : {}),
278
+ ...(args.hashCache !== undefined ? { hashCache: args.hashCache } : {}),
279
+ })
263
280
 
264
281
  // The args after `--` reach a server as they reach any task. A readyWhen
265
282
  // server once got none — "so the matcher sees the unmodified output",
@@ -383,6 +400,7 @@ async function executePersistentTask(args: ExecuteArgs): Promise<TaskOutcome> {
383
400
  status: 'success',
384
401
  exitCode: 0,
385
402
  durationMs: spawn.readyMs(),
403
+ ...(hash !== undefined ? { hash } : {}),
386
404
  wallclockStartNs,
387
405
  wallclockEndNs: process.hrtime.bigint() - args.runStartHrTimeNs,
388
406
  }
@@ -18,10 +18,7 @@ import { selectFoldedDeps, type FoldCandidate } from './upstream.js'
18
18
  * selects them (absent, or no `cache` at all, means all);
19
19
  * - a group folds every dependency (`computeGroupHash`) and folds no
20
20
  * files of its own;
21
- * - a persistent task has no hash on the live path, so it is folded by
22
- * no one and its own dependencies reach no key through it. (The local
23
- * classify pass does give it one — stable-keys.ts — so a key there can
24
- * move with more than this set names; never with less.)
21
+ * - a persistent task is keyed as a task with no `cache` (A-17).
25
22
  *
26
23
  * Every exec task reached contributes its project, cached or not: a key
27
24
  * folds the task's own project files, and a task with no `cache` declares
@@ -71,7 +68,6 @@ function folded(node: TaskNode, nodes: ReadonlyMap<string, TaskNode>): FoldCandi
71
68
  const candidates: FoldCandidate[] = []
72
69
  for (const id of node.deps) {
73
70
  const dep = nodes.get(id)!
74
- if (dep.config.exec?.persistent !== undefined) continue
75
71
  candidates.push({ node: dep, unit: foldUnit(dep) })
76
72
  }
77
73
  if (isGroupTask(node)) return candidates
@@ -131,14 +131,6 @@ export async function plan(args: PlanArgs): Promise<RunPlan> {
131
131
  cacheStatusById.set(node.id, 'group')
132
132
  return planOutcome(node, computeGroupHash(upstream))
133
133
  }
134
- // A persistent task has no key on the live path (its outcome carries
135
- // none, `stable-keys.ts`), so a dependant folds nothing for it. The
136
- // plan keyed it and folded that, and `--dry` then called a dependant
137
- // a miss under a key the run never looks up (item 766).
138
- if (node.config.exec?.persistent !== undefined) {
139
- cacheStatusById.set(node.id, 'no-cache')
140
- return planOutcome(node, undefined)
141
- }
142
134
 
143
135
  const hash = await computeTaskHash({
144
136
  node,
@@ -87,13 +87,12 @@ export async function deriveStableKeys(args: DeriveStableKeysArgs): Promise<Stab
87
87
  const unfoldedById = new Map<string, ProjectSet>()
88
88
  const wsRewriters = new Set<string>()
89
89
  // A cached rewriter matters only to a key that leaves a dependency's key
90
- // out: a `cache.inputs.tasks` filter, or a persistent dependency, which
91
- // has no key. With neither in the graph every edge folds and the sets
92
- // above stay empty, so they are not built (about 2 ms, median, of a 27 ms
93
- // memoised walk over the 3,000-task bench; item 750).
90
+ // out: a `cache.inputs.tasks` filter. With none in the graph every edge
91
+ // folds and the sets above stay empty, so they are not built (about 2 ms,
92
+ // median, of a 27 ms memoised walk over the 3,000-task bench; item 750).
94
93
  let anyUnfolded = false
95
94
  for (const n of args.nodes.values()) {
96
- if (n.config.cache?.inputs?.tasks !== undefined || n.config.exec?.persistent !== undefined) {
95
+ if (n.config.cache?.inputs?.tasks !== undefined) {
97
96
  anyUnfolded = true
98
97
  break
99
98
  }
@@ -188,12 +187,6 @@ export async function deriveStableKeys(args: DeriveStableKeysArgs): Promise<Stab
188
187
  continue
189
188
  }
190
189
 
191
- // A persistent task has no key on the live path (its outcome carries no
192
- // hash, so a dependent folds nothing of it); recording one here gave
193
- // its dependents a second key, which a `--force` or remote run never
194
- // saved under.
195
- if (node.config.exec?.persistent !== undefined) continue
196
-
197
190
  const hash = await computeTaskHash({
198
191
  node,
199
192
  upstream,
@@ -226,8 +219,7 @@ export async function deriveStableKeys(args: DeriveStableKeysArgs): Promise<Stab
226
219
  /**
227
220
  * Does this task's key fold the dependency's? What `computeTaskHash` folds
228
221
  * (`filterUpstreamHashes` over the same synthetic outcomes); a group folds
229
- * every keyed member. A dependency with no key (persistent) is folded by
230
- * none.
222
+ * every keyed member.
231
223
  */
232
224
  function foldedBy(
233
225
  node: TaskNode,
@@ -47,7 +47,7 @@ export function keyedDeps(node: TaskNode): readonly string[] {
47
47
  * folded into the cache key (the fold sorts by hash, so ordering here
48
48
  * doesn't affect derivation); the task id rides along so Tier-3's
49
49
  * `entry_inputs` rows can NAME which upstream a hash came from. An
50
- * upstream with no hash (a persistent task) folds nothing.
50
+ * upstream with no hash folds nothing.
51
51
  */
52
52
  export function filterUpstreamHashes(
53
53
  upstream: TaskOutcome[],