@vzn/vx 0.0.155 → 0.0.158

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.155",
3
+ "version": "0.0.158",
4
4
  "description": "A fast, correct task runner and build cache for JavaScript monorepos.",
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.155",
21
- "@vzn/vx-linux-arm64": "0.0.155",
22
- "@vzn/vx-darwin-x64": "0.0.155",
23
- "@vzn/vx-darwin-arm64": "0.0.155"
20
+ "@vzn/vx-linux-x64": "0.0.158",
21
+ "@vzn/vx-linux-arm64": "0.0.158",
22
+ "@vzn/vx-darwin-x64": "0.0.158",
23
+ "@vzn/vx-darwin-arm64": "0.0.158"
24
24
  },
25
25
  "dependencies": {
26
26
  "@anthropic-ai/sandbox-runtime": "^0.0.76"
@@ -28,11 +28,14 @@ export function formatPlanText(plan: RunPlan): string {
28
28
  let remote = 0
29
29
  let miss = 0
30
30
  let nocache = 0
31
+ let noop = 0
31
32
  for (const t of real) {
32
- const sym = symbolFor(t.cacheStatus)
33
- const desc = describe(t.cacheStatus)
33
+ // `@noop`: the run succeeds it without running, whatever its key says.
34
+ const skipped = t.executor === 'noop'
35
+ const sym = skipped ? '∅' : symbolFor(t.cacheStatus)
36
+ const desc = skipped ? 'noop — would not run' : describe(t.cacheStatus)
34
37
  const shortHash = t.hash ? t.hash.slice(0, 8) : ''
35
- const executes = t.cacheStatus === 'miss' || t.cacheStatus === 'no-cache'
38
+ const executes = !skipped && (t.cacheStatus === 'miss' || t.cacheStatus === 'no-cache')
36
39
  const eta = executes && t.p50Ms !== undefined ? ` ~${formatDuration(t.p50Ms)}` : ''
37
40
  // Placement, by EXECUTOR NAME rather than a local/remote word: the
38
41
  // summary line below already spends "local" and "remote" on the cache
@@ -48,7 +51,8 @@ export function formatPlanText(plan: RunPlan): string {
48
51
  if (taskDesc) {
49
52
  lines.push(` ${' '.repeat(idWidth)} ${taskDesc}`)
50
53
  }
51
- if (t.cacheStatus === 'hit-local') local++
54
+ if (skipped) noop++
55
+ else if (t.cacheStatus === 'hit-local') local++
52
56
  else if (t.cacheStatus === 'hit-remote') remote++
53
57
  else if (t.cacheStatus === 'miss') miss++
54
58
  else if (t.cacheStatus === 'no-cache') nocache++
@@ -62,6 +66,7 @@ export function formatPlanText(plan: RunPlan): string {
62
66
  if (hits > 0) summary.push(`${hits} cache hit${hits === 1 ? '' : 's'} (${hitParts.join(', ')})`)
63
67
  if (miss > 0) summary.push(`${miss} would run`)
64
68
  if (nocache > 0) summary.push(`${nocache} no-cache`)
69
+ if (noop > 0) summary.push(`${noop} noop`)
65
70
  lines.push('')
66
71
  lines.push(summary.join(', ') + '.')
67
72
 
@@ -1,9 +1,10 @@
1
1
  // What a finished run leaves behind: the `runs` rows, the `invocations`
2
2
  // header row, and — only when a telemetry sink is active — the per-task
3
3
  // telemetry mirror. One pass over the outcome list builds all three, so
4
- // `invocations.task_count`, the terminal's "N total" and the number of
5
- // telemetry tasks are the same count by construction (`tallyOutcomes`
6
- // applies the same group/aborted filter).
4
+ // `invocations.task_count` and the number of telemetry tasks agree by
5
+ // construction; the terminal's "N total" agrees because `tallyOutcomes`
6
+ // applies the same group/aborted filter, a second copy of the rule that
7
+ // tests/run-records.test.ts holds to this one.
7
8
 
8
9
  import type { InvocationRecord, RunRecord } from '../cache/index.js'
9
10
  import { isGroupTask, type TaskOutcome } from '../graph/index.js'
@@ -113,7 +113,14 @@ export function validateWorkspace(config: WorkspaceConfig, configPath: string):
113
113
  const fileClaimants = new Map<string, string>()
114
114
  for (const [i, p] of config.plugins.entries()) {
115
115
  if (p === null || typeof p !== 'object') {
116
- throw new UserError(`${configPath}: \`plugins[${i}]\` must be an object`)
116
+ // Nx's nx.json lists plugins by module name (`'@nx/vite/plugin'`);
117
+ // a vx plugin is the value its package's function returns.
118
+ throw new UserError(
119
+ `${configPath}: \`plugins[${i}]\` must be an object` +
120
+ (typeof p === 'string'
121
+ ? ` — a plugin is what its package's function returns (\`nx()\` from \`@vzn/vx-migrate\`), not a module name`
122
+ : ''),
123
+ )
117
124
  }
118
125
  // The loose schema's shape (unknown-typed hooks) plus the one retired
119
126
  // key this loader still refuses by name.
@@ -716,6 +723,12 @@ const FOREIGN_FIELDS: ReadonlyMap<ReadonlySet<string>, Readonly<Record<string, s
716
723
  cmd: '`exec.command`',
717
724
  script: '`exec.command`',
718
725
  persistent: '`exec.persistent: {}`',
726
+ // Nx's target keys (project.json) and Turbo's `outputLogs`.
727
+ continuous: '`exec.persistent: {}`',
728
+ executor:
729
+ '`exec.command`: vx runs one shell command (`nx()` from `@vzn/vx-migrate` runs an Nx executor as one)',
730
+ options: '`exec.command` (a run-commands `options.command`) and `exec.env`',
731
+ outputLogs: 'the `--output-logs` flag of `vx run`',
719
732
  },
720
733
  ],
721
734
  [EXEC_FIELDS, { cmd: '`command`', script: '`command`' }],
@@ -737,6 +750,9 @@ const FOREIGN_FIELDS: ReadonlyMap<ReadonlySet<string>, Readonly<Record<string, s
737
750
  'a cache plugin in `plugins` (`turboCache()` or `nxCache()` from `@vzn/vx-migrate`)',
738
751
  parallel: '`concurrency`',
739
752
  cacheDirectory: '`cacheDir`',
753
+ defaultBase: 'the base in `--affected=<base>` (default `origin/HEAD`)',
754
+ tasksRunnerOptions: 'a cache plugin in `plugins` (`nxCache()` from `@vzn/vx-migrate`)',
755
+ globalPassThroughEnv: '`exec.env.passThrough` on the tasks it passes to',
740
756
  },
741
757
  ],
742
758
  ])