@vzn/vx 0.0.533 → 0.0.535

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.533",
3
+ "version": "0.0.535",
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.533",
25
- "@vzn/vx-linux-arm64": "0.0.533",
26
- "@vzn/vx-darwin-x64": "0.0.533",
27
- "@vzn/vx-darwin-arm64": "0.0.533"
24
+ "@vzn/vx-linux-x64": "0.0.535",
25
+ "@vzn/vx-linux-arm64": "0.0.535",
26
+ "@vzn/vx-darwin-x64": "0.0.535",
27
+ "@vzn/vx-darwin-arm64": "0.0.535"
28
28
  },
29
29
  "dependencies": {
30
30
  "@anthropic-ai/sandbox-runtime": "^0.0.76"
package/src/cli/run.ts CHANGED
@@ -498,6 +498,7 @@ export async function resolveRunOptions(
498
498
  let discovered: RunOptions['discovered']
499
499
  let selectedByDiff = false
500
500
  let affected: RunOptions['affected']
501
+ let outright: string[] | undefined
501
502
  if (bareTasks.length === 0) {
502
503
  projects = undefined
503
504
  } else if (filterStrings.length > 0) {
@@ -528,6 +529,7 @@ export async function resolveRunOptions(
528
529
  staged = resolved.staged
529
530
  discovered = resolved.discovered
530
531
  affected = resolved.affected
532
+ outright = resolved.outright
531
533
  }
532
534
  } else if (parsed.all) {
533
535
  projects = undefined
@@ -573,6 +575,7 @@ export async function resolveRunOptions(
573
575
  if (projects !== undefined) opts.projects = projects
574
576
  if (selectedByDiff) opts.selectedByDiff = true
575
577
  if (affected !== undefined) opts.affected = affected
578
+ if (outright !== undefined) opts.selectedOutright = outright
576
579
  if (staged !== undefined) opts.staged = staged
577
580
  if (discovered !== undefined) opts.discovered = discovered
578
581
  if (parsed.retries !== undefined) opts.retries = parsed.retries
package/src/cli/select.ts CHANGED
@@ -182,6 +182,8 @@ export type FilterResolution =
182
182
  discovered: { root: string; projects: ProjectMeta[] }
183
183
  /** The `affected` filter's diff, for the run to seed its tasks from (`RunOptions.affected`). */
184
184
  affected?: AffectedChanges
185
+ /** What the other includes selected (`RunOptions.selectedOutright`). */
186
+ outright?: string[]
185
187
  }
186
188
  | { error: string }
187
189
  | { empty: string }
@@ -367,6 +369,22 @@ export async function resolveFilters(
367
369
  process.stderr.write(
368
370
  `vx: filter "${f}" matched no projects${didYouMean([f], projects, tags)}\n`,
369
371
  )
372
+ // Each include is a union: what `--filter other` selected runs its tasks
373
+ // whether or not the `--affected` diff reaches them, and an exclude
374
+ // still removes it (X-10).
375
+ const others = parsed.filter((f) => f.negate || f.raw !== affected)
376
+ const outright =
377
+ changes !== undefined && others.some((f) => !f.negate)
378
+ ? [
379
+ ...applyFilters({
380
+ filters: others,
381
+ projects,
382
+ graph,
383
+ affectedByFilter,
384
+ ...(tags !== undefined ? { tags } : {}),
385
+ }),
386
+ ].filter((n) => selected.has(n))
387
+ : []
370
388
  let staged: Map<string, ProjectEntry> | undefined
371
389
  if (stagedPromise !== undefined) {
372
390
  try {
@@ -382,6 +400,7 @@ export async function resolveFilters(
382
400
  ...(staged !== undefined ? { staged } : {}),
383
401
  discovered: { root, projects },
384
402
  ...(changes !== undefined ? { affected: changes } : {}),
403
+ ...(outright.length > 0 ? { outright: outright.sort() } : {}),
385
404
  }
386
405
  }
387
406
 
package/src/cli/show.ts CHANGED
@@ -266,8 +266,11 @@ function renderProject(
266
266
  return `${JSON.stringify(JSON.parse(JSON.stringify({ name, dir, config: shown })), null, 2)}\n`
267
267
  }
268
268
  const tags = config?.tags ?? []
269
- const head = `${name} — ${dir}${tags.length > 0 ? `\n tags: ${tags.join(', ')}` : ''}`
270
269
  const tasks = Object.entries(config?.tasks ?? {})
270
+ const head = `${name} — ${dir}${tags.length > 0 ? `\n tags: ${tags.join(', ')}` : ''}${
271
+ // A config-less package a dependant reaches has the default `build` (X-9).
272
+ hasConfigFile || tasks.length === 0 ? '' : '\n (no vx config)'
273
+ }`
271
274
  if (tasks.length === 0)
272
275
  return `${head}\n ${hasConfigFile ? '(no tasks declared)' : '(no vx config)'}\n`
273
276
  const blocks = tasks.map(([taskName, task]) => taskBlock(taskName, task))
@@ -35,6 +35,12 @@ export interface RunOptions {
35
35
  * 2026-10-04). `projects` is the candidate set it narrows.
36
36
  */
37
37
  affected?: AffectedChanges
38
+ /**
39
+ * The projects an include other than `--affected` selected (`--filter
40
+ * other`): every include is a union, so their requested tasks run
41
+ * whether or not `affected` reaches them (X-10).
42
+ */
43
+ selectedOutright?: readonly string[]
38
44
  /**
39
45
  * Configs a selection pass in this same process already loaded and
40
46
  * staged with the same `cacheDir` and `frozen` (the CLI walks every
@@ -521,9 +521,12 @@ export async function prepareRun(options: RunOptions, log: Logger): Promise<Prep
521
521
  // closure; a `pkg#task` the user named runs as it always does.
522
522
  if (options.affected !== undefined) {
523
523
  const named = new Set(tasks.filter((t) => t.includes('#')))
524
+ const outright = new Set(options.selectedOutright)
524
525
  const ids = requested.map((r) => `${r.project}#${r.task}`)
525
526
  const reached = new Set(affectedRoots(nodes, ids, options.affected, projects, packageGraph))
526
- const kept = requested.filter((_r, i) => named.has(ids[i]!) || reached.has(ids[i]!))
527
+ const kept = requested.filter(
528
+ (r, i) => named.has(ids[i]!) || outright.has(r.project) || reached.has(ids[i]!),
529
+ )
527
530
  if (kept.length === 0) return emptyRun('none-affected')
528
531
  if (kept.length < requested.length) {
529
532
  unproven.length = 0
@@ -179,13 +179,16 @@ export async function loadProjects(args: LoadProjectsArgs): Promise<LoadedProjec
179
179
  // scripts mapped onto packages that never wrote a `vx.config.ts`). It
180
180
  // then loads as `{ tasks: {} }` — nothing to evaluate, nothing to freeze
181
181
  // — and the stage runs on that like on any loaded config. With no
182
- // `project` plugin a plain run never visits (or fences, or seeds) a
183
- // config-less package.
182
+ // `project` plugin a plain run never seeds (or fences) a config-less
183
+ // package, but loads one a loaded project's closure reaches: it gets the
184
+ // default `build`, so a dependant bundling its source is keyed on it
185
+ // behind `^build`. Left out, its edit replayed the dependant's stale
186
+ // output as a hit (X-9).
184
187
  const projectStage = hasHook(plugins, 'project')
185
188
  const configured = args.projectMetas.filter(
186
189
  (m) => projectStage || (typeof m.configPath === 'string' && m.configPath.length > 0),
187
190
  )
188
- const metaByName = new Map<string, ProjectMeta>(configured.map((m) => [m.name, m]))
191
+ const metaByName = new Map<string, ProjectMeta>(args.projectMetas.map((m) => [m.name, m]))
189
192
  const needed = new Set<string>()
190
193
  const pending: ProjectMeta[] = []
191
194
  // Counted, not read off `pending`: a round empties `pending`, and a guard
@@ -212,10 +215,11 @@ export async function loadProjects(args: LoadProjectsArgs): Promise<LoadedProjec
212
215
  walked.add(name)
213
216
  for (const dep of packageGraph.transitiveDeps(name)) consider(dep)
214
217
  }
215
- const seeds = args.seeds === 'all' ? metaByName.keys() : [...args.seeds]
218
+ const seedAll = (): Iterable<string> => configured.map((m) => m.name)
219
+ const seeds = args.seeds === 'all' ? seedAll() : [...args.seeds]
216
220
  for (const seed of seeds) consider(seed)
217
221
  if (graph !== null && pending.length < metaByName.size) {
218
- for (const seed of args.seeds === 'all' ? metaByName.keys() : seeds) {
222
+ for (const seed of args.seeds === 'all' ? seedAll() : seeds) {
219
223
  considerWithDeps(graph, seed)
220
224
  }
221
225
  }