@vzn/vx 0.0.565 → 0.0.566
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/cli/watch-filter.ts +23 -1
- package/src/cli/watch.ts +28 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vzn/vx",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.566",
|
|
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.566",
|
|
25
|
+
"@vzn/vx-linux-arm64": "0.0.566",
|
|
26
|
+
"@vzn/vx-darwin-x64": "0.0.566",
|
|
27
|
+
"@vzn/vx-darwin-arm64": "0.0.566"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@anthropic-ai/sandbox-runtime": "^0.0.76"
|
package/src/cli/watch-filter.ts
CHANGED
|
@@ -229,6 +229,7 @@ export function makeRootEventFilter(
|
|
|
229
229
|
projectDirs: readonly string[],
|
|
230
230
|
workspaceInputs: readonly string[],
|
|
231
231
|
claimedRootFiles: ReadonlySet<string> = new Set(),
|
|
232
|
+
fenced: (ownDir: string, abs: string) => boolean = () => false,
|
|
232
233
|
): (filename: string) => boolean {
|
|
233
234
|
const dirs = projectDirs.map((d) => path.resolve(d))
|
|
234
235
|
const globs = workspaceInputs
|
|
@@ -257,12 +258,33 @@ export function makeRootEventFilter(
|
|
|
257
258
|
return true
|
|
258
259
|
}
|
|
259
260
|
const abs = path.resolve(workspaceRoot, filename)
|
|
260
|
-
for (const d of dirs)
|
|
261
|
+
for (const d of dirs)
|
|
262
|
+
if (abs === d || (abs.startsWith(d + path.sep) && !fenced(d, abs))) return true
|
|
261
263
|
for (const g of globs) if (g.match(rel)) return true
|
|
262
264
|
return false
|
|
263
265
|
}
|
|
264
266
|
}
|
|
265
267
|
|
|
268
|
+
/**
|
|
269
|
+
* Whether `abs`, under the project at `ownDir`, lies inside another
|
|
270
|
+
* project nested there: the key's boundary (`computeNestedProjectDirs`)
|
|
271
|
+
* leaves such a file out, so it is no edit of `ownDir`'s. A root project
|
|
272
|
+
* watched its whole tree and ran a cycle for every edit in a nested one
|
|
273
|
+
* (X-42). The fences are the projects with a config, which fence a key
|
|
274
|
+
* whatever the plugins; a config-less one may not, and an edit there
|
|
275
|
+
* still counts. The fence's own config is let through: it coming or going
|
|
276
|
+
* moves the boundary, and the cycle it starts re-reads the set.
|
|
277
|
+
*/
|
|
278
|
+
export function makeFence(fenceDirs: readonly string[]): (ownDir: string, abs: string) => boolean {
|
|
279
|
+
const fences = fenceDirs.map((d) => path.resolve(d))
|
|
280
|
+
return (ownDir, abs) => {
|
|
281
|
+
const config = PROJECT_CONFIGS.has(path.basename(abs)) ? path.dirname(abs) : undefined
|
|
282
|
+
return fences.some(
|
|
283
|
+
(f) => f !== config && f.startsWith(ownDir + path.sep) && abs.startsWith(f + path.sep),
|
|
284
|
+
)
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
266
288
|
/**
|
|
267
289
|
* A file whose edit can change what the loop watches: a `package.json`
|
|
268
290
|
* (a dependency added under `--filter` widens the closure), a project
|
package/src/cli/watch.ts
CHANGED
|
@@ -37,6 +37,7 @@ import {
|
|
|
37
37
|
isWorkspaceConfigFile,
|
|
38
38
|
gitFiles,
|
|
39
39
|
isWorkspaceFingerprintFile,
|
|
40
|
+
makeFence,
|
|
40
41
|
makeRootEventFilter,
|
|
41
42
|
makeWatchIgnore,
|
|
42
43
|
shapesWatchedSet,
|
|
@@ -242,6 +243,7 @@ export async function watchCmd(args: readonly string[]): Promise<number> {
|
|
|
242
243
|
workspaceConfigImports: swept.workspaceConfigImports,
|
|
243
244
|
memberBases: memberBaseDirs(workspace),
|
|
244
245
|
packageDirs: new Set(allProjects.map((p) => p.dir)),
|
|
246
|
+
fenceDirs: fenceDirs(allProjects),
|
|
245
247
|
// The workspace as the cycle that just ran saw it: a package added or
|
|
246
248
|
// removed since the loop armed joins or leaves the watched set. The
|
|
247
249
|
// scope is the one resolved at start; a new package joins it only as a
|
|
@@ -266,6 +268,7 @@ export async function watchCmd(args: readonly string[]): Promise<number> {
|
|
|
266
268
|
configImports: sweep.configImports,
|
|
267
269
|
workspaceConfigImports: sweep.workspaceConfigImports,
|
|
268
270
|
packageDirs: new Set(all.map((p) => p.dir)),
|
|
271
|
+
fenceDirs: fenceDirs(all),
|
|
269
272
|
}
|
|
270
273
|
},
|
|
271
274
|
// Under --frozen every cycle's configs are the lock's, so a re-lock is
|
|
@@ -312,10 +315,15 @@ interface WatchLoopArgs {
|
|
|
312
315
|
memberBases: readonly string[]
|
|
313
316
|
/** Every package's directory, in scope or not: a member base's other entries are packages still to come. */
|
|
314
317
|
packageDirs: ReadonlySet<string>
|
|
318
|
+
/** Every project with a config, in scope or not: a project's key leaves out what lies in one nested under it. */
|
|
319
|
+
fenceDirs: readonly string[]
|
|
315
320
|
/** The watched set again, after a cycle that followed an event which can change it. */
|
|
316
321
|
rediscover: () => Promise<Rediscovered>
|
|
317
322
|
}
|
|
318
323
|
|
|
324
|
+
const fenceDirs = (all: readonly ProjectMeta[]): string[] =>
|
|
325
|
+
all.filter((p) => p.configPath !== null).map((p) => p.dir)
|
|
326
|
+
|
|
319
327
|
interface Rediscovered {
|
|
320
328
|
projects: readonly ProjectMeta[]
|
|
321
329
|
claimedRootFiles: ReadonlySet<string>
|
|
@@ -328,6 +336,7 @@ interface Rediscovered {
|
|
|
328
336
|
configImports: readonly string[]
|
|
329
337
|
workspaceConfigImports: readonly string[]
|
|
330
338
|
packageDirs: ReadonlySet<string>
|
|
339
|
+
fenceDirs: readonly string[]
|
|
331
340
|
}
|
|
332
341
|
|
|
333
342
|
async function runWatchLoop(args: WatchLoopArgs): Promise<number> {
|
|
@@ -424,7 +433,14 @@ async function runWatchLoop(args: WatchLoopArgs): Promise<number> {
|
|
|
424
433
|
// project would otherwise trigger every save during `bun install` —
|
|
425
434
|
// and vx's own cache writes would trigger a cycle that writes again.
|
|
426
435
|
let isIgnoredPath = makeWatchIgnore(cacheDir, outputs, inputs)
|
|
427
|
-
let
|
|
436
|
+
let fenced = makeFence(args.fenceDirs)
|
|
437
|
+
let matters = makeRootEventFilter(
|
|
438
|
+
workspaceRoot,
|
|
439
|
+
projectDirs,
|
|
440
|
+
workspaceInputs,
|
|
441
|
+
claimedRootFiles,
|
|
442
|
+
fenced,
|
|
443
|
+
)
|
|
428
444
|
/** Since the last cycle, a member came or went, or a file that shapes the watched set changed (`shapesWatchedSet`). */
|
|
429
445
|
let reread = false
|
|
430
446
|
|
|
@@ -472,9 +488,10 @@ async function runWatchLoop(args: WatchLoopArgs): Promise<number> {
|
|
|
472
488
|
const armProject = (proj: ProjectMeta): void => {
|
|
473
489
|
try {
|
|
474
490
|
const handle = arm(proj.dir, true, (filename) => {
|
|
475
|
-
|
|
491
|
+
const abs = path.join(proj.dir, filename)
|
|
492
|
+
if (isIgnoredPath(proj.dir, filename) || fenced(proj.dir, abs)) return
|
|
476
493
|
if (shapesWatchedSet(filename)) reread = true
|
|
477
|
-
trigger(`${proj.name} ${filename}`,
|
|
494
|
+
trigger(`${proj.name} ${filename}`, abs)
|
|
478
495
|
})
|
|
479
496
|
perProject.set(proj.dir, handle)
|
|
480
497
|
armedAs.set(proj.dir, inodeOf(proj.dir) ?? '')
|
|
@@ -659,7 +676,14 @@ async function runWatchLoop(args: WatchLoopArgs): Promise<number> {
|
|
|
659
676
|
memberBases = next.memberBases
|
|
660
677
|
armBases()
|
|
661
678
|
isIgnoredPath = makeWatchIgnore(cacheDir, outputs, inputs)
|
|
662
|
-
|
|
679
|
+
fenced = makeFence(next.fenceDirs)
|
|
680
|
+
matters = makeRootEventFilter(
|
|
681
|
+
workspaceRoot,
|
|
682
|
+
projectDirs,
|
|
683
|
+
workspaceInputs,
|
|
684
|
+
claimedRootFiles,
|
|
685
|
+
fenced,
|
|
686
|
+
)
|
|
663
687
|
if (next.workspaceWide !== workspaceWide) {
|
|
664
688
|
// A task started or stopped declaring `workspaceFiles`: the other
|
|
665
689
|
// arm's shape. Until item 891 the choice was made once, at start, and
|