@vzn/vx 0.0.631 → 0.0.633

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.
Files changed (86) hide show
  1. package/README.md +21 -18
  2. package/docs/caching.md +2247 -0
  3. package/docs/cli.md +3214 -0
  4. package/docs/execution.md +708 -0
  5. package/docs/features.md +172 -0
  6. package/docs/patterns.md +219 -0
  7. package/docs/schema.md +2137 -0
  8. package/docs/security.md +209 -0
  9. package/package.json +14 -5
  10. package/schemas/cache.json +24 -0
  11. package/schemas/docs.json +28 -0
  12. package/schemas/error.json +23 -0
  13. package/schemas/info.json +147 -0
  14. package/schemas/init.json +57 -0
  15. package/schemas/last.json +188 -0
  16. package/schemas/lock.json +21 -0
  17. package/schemas/plan.json +88 -0
  18. package/schemas/show.json +124 -0
  19. package/schemas/summary.json +133 -0
  20. package/schemas/why.json +168 -0
  21. package/skills/vx/SKILL.md +89 -0
  22. package/src/bin.ts +9 -0
  23. package/src/cache/archive.ts +153 -51
  24. package/src/cache/cache.ts +542 -137
  25. package/src/cache/chained-cache.ts +9 -0
  26. package/src/cache/inputs.ts +5 -0
  27. package/src/cache/layer.ts +10 -5
  28. package/src/cache/layered-cache.ts +4 -0
  29. package/src/cache/schema.ts +44 -17
  30. package/src/cache/tar-stream.ts +204 -66
  31. package/src/cache/zstd.ts +1 -1
  32. package/src/cli/cache.ts +14 -14
  33. package/src/cli/docs-corpus.ts +21 -0
  34. package/src/cli/docs-text.d.ts +5 -0
  35. package/src/cli/docs.ts +167 -0
  36. package/src/cli/foreign-flags.ts +1 -1
  37. package/src/cli/help.ts +42 -7
  38. package/src/cli/index.ts +25 -11
  39. package/src/cli/info.ts +38 -9
  40. package/src/cli/init.ts +131 -24
  41. package/src/cli/last.ts +54 -3
  42. package/src/cli/lock.ts +43 -15
  43. package/src/cli/plan-format.ts +23 -1
  44. package/src/cli/plugin-commands.ts +3 -0
  45. package/src/cli/plugin-templates.ts +1 -1
  46. package/src/cli/run.ts +40 -21
  47. package/src/cli/show.ts +10 -7
  48. package/src/cli/upgrade.ts +19 -7
  49. package/src/cli/watch.ts +7 -2
  50. package/src/cli/why.ts +14 -40
  51. package/src/exec/runner.ts +27 -10
  52. package/src/graph/scheduler.ts +36 -0
  53. package/src/graph/task-graph.ts +4 -4
  54. package/src/index.ts +22 -5
  55. package/src/orchestrator/admission.ts +29 -1
  56. package/src/orchestrator/affected-tasks.ts +87 -18
  57. package/src/orchestrator/doctor.ts +14 -1
  58. package/src/orchestrator/execute-task.ts +149 -64
  59. package/src/orchestrator/failure-mode.ts +5 -3
  60. package/src/orchestrator/framed-output.ts +17 -3
  61. package/src/orchestrator/index.ts +11 -0
  62. package/src/orchestrator/logger.ts +57 -6
  63. package/src/orchestrator/metrics.ts +76 -4
  64. package/src/orchestrator/miss-reason.ts +3 -5
  65. package/src/orchestrator/miss-save.ts +6 -5
  66. package/src/orchestrator/options.ts +12 -0
  67. package/src/orchestrator/output-log.ts +14 -1
  68. package/src/orchestrator/path-links.ts +79 -0
  69. package/src/orchestrator/plan.ts +20 -3
  70. package/src/orchestrator/plugin.ts +7 -0
  71. package/src/orchestrator/prepare.ts +14 -4
  72. package/src/orchestrator/projects.ts +2 -2
  73. package/src/orchestrator/run-artifacts.ts +18 -2
  74. package/src/orchestrator/run-failures.ts +192 -0
  75. package/src/orchestrator/run-records.ts +10 -8
  76. package/src/orchestrator/run.ts +87 -22
  77. package/src/orchestrator/task-hash.ts +4 -4
  78. package/src/orchestrator/terminal-signals.ts +16 -0
  79. package/src/orchestrator/upstream.ts +65 -10
  80. package/src/util/errors.ts +55 -1
  81. package/src/util/index.ts +3 -0
  82. package/src/util/secret-mask.ts +13 -1
  83. package/src/util/verbs.ts +1 -0
  84. package/src/workspace/config-schema.ts +10 -8
  85. package/src/workspace/migration.ts +30 -3
  86. package/src/workspace/workspace.ts +1 -0
@@ -32,6 +32,12 @@ export function secretNamed(name: string): boolean {
32
32
  return secret
33
33
  }
34
34
 
35
+ /**
36
+ * A URL's password (`postgres://app:<pw>@db/app`): a credential whatever
37
+ * the variable is named, so `DATABASE_URL` and `REDIS_URL` printed it.
38
+ */
39
+ const URL_PASSWORD = /[a-z][a-z0-9+.-]*:\/\/[^\s:/@]*:([^\s/@]+)@/gi
40
+
35
41
  /**
36
42
  * Values shorter than this are not masked: `KEY=1` would mask every `1`
37
43
  * in every line, and a value that short is no secret worth the noise.
@@ -86,7 +92,13 @@ export function secretMask(
86
92
  }
87
93
  for (const source of sources) {
88
94
  if (source === undefined) continue
89
- for (const name in source) if (secretNamed(name)) add(source[name])
95
+ for (const name in source) {
96
+ const value = source[name]
97
+ if (secretNamed(name)) add(value)
98
+ if (value?.includes('://') === true && value.includes('@')) {
99
+ for (const m of value.matchAll(URL_PASSWORD)) add(m[1])
100
+ }
101
+ }
90
102
  for (const name of named) add(source[name])
91
103
  }
92
104
  if (values.size === 0) return null
package/src/util/verbs.ts CHANGED
@@ -14,6 +14,7 @@ export const CORE_VERBS = [
14
14
  'info',
15
15
  'why',
16
16
  'last',
17
+ 'docs',
17
18
  'completions',
18
19
  'help',
19
20
  'version',
@@ -616,15 +616,12 @@ export function validateProjectConfig(config: ProjectConfig, configPath: string)
616
616
  // so a dependant's `^build` finds it and waits on nothing
617
617
  // (the quickstart). The comment here used to call that case
618
618
  // "almost certainly a config mistake" while the docs taught it.
619
- if (dependsOn === undefined) {
619
+ // A keyed group (`cache` with no `exec`) is a declaration on its own:
620
+ // its inputs are a key that dependants fold, with no process.
621
+ if (dependsOn === undefined && cache === undefined) {
620
622
  throw new UserError(
621
- `${where}: a task with no \`exec\` must declare \`dependsOn\` ` +
622
- `(group tasks exist to chain dependencies)`,
623
- )
624
- }
625
- if (cache !== undefined) {
626
- throw new UserError(
627
- `${where}: \`cache\` requires \`exec\` — a group task has nothing to cache`,
623
+ `${where}: a task with no \`exec\` must declare \`dependsOn\` or \`cache.inputs\` ` +
624
+ `(group tasks exist to chain dependencies or carry a key)`,
628
625
  )
629
626
  }
630
627
  }
@@ -852,6 +849,11 @@ export function validateProjectConfig(config: ProjectConfig, configPath: string)
852
849
  if (wsOutputs !== undefined) {
853
850
  validateWorkspaceGlobs(wsOutputs, `${where}.cache.outputs.workspaceFiles`, false)
854
851
  }
852
+ if (exec === undefined && (outFiles.length > 0 || wsOutputs !== undefined)) {
853
+ throw new UserError(
854
+ `${where}.cache.outputs: a task with no \`exec\` writes nothing — \`outputs: { files: [] }\``,
855
+ )
856
+ }
855
857
  }
856
858
  }
857
859
  }
@@ -261,6 +261,11 @@ export interface ApplyMigrationArgs {
261
261
  * and compiled the config into its dist (TanStack/query, 2026-09-11).
262
262
  */
263
263
  format?: MigrationFormat
264
+ /**
265
+ * With `dry`: one JSON document on stdout (`schemas/init.json`) in place
266
+ * of the files and the report, so an agent reads the plan as data.
267
+ */
268
+ json?: boolean
264
269
  }
265
270
 
266
271
  export type MigrationFormat = 'ts' | 'mjs'
@@ -360,11 +365,11 @@ export async function applyMigration(args: ApplyMigrationArgs): Promise<number>
360
365
  const existing = metas.find((m) => m.dir === p.dir)?.configPath
361
366
  if (existing && existing !== path.join(p.dir, configName)) replaced.push(existing)
362
367
  }
363
- if (dry) {
368
+ if (dry && args.json !== true) {
364
369
  for (const f of files) {
365
370
  process.stdout.write(`── ${f.relPath} ──\n${f.contents}\n`)
366
371
  }
367
- } else {
372
+ } else if (!dry) {
368
373
  for (const f of files) await Bun.write(f.abs, f.contents)
369
374
  for (const f of replaced) await unlink(f)
370
375
  }
@@ -476,7 +481,29 @@ export async function applyMigration(args: ApplyMigrationArgs): Promise<number>
476
481
  ...(inGitWorkTree(root) ? [] : ['git init']),
477
482
  ...(empty ? [`declare a task as the example shows`] : []),
478
483
  ]
479
- report.push('', `next: ${steps.length === 0 ? run : `${steps.join(', ')}, then ${run}`}`)
484
+ const next = steps.length === 0 ? run : `${steps.join(', ')}, then ${run}`
485
+ if (args.json === true) {
486
+ process.stdout.write(
487
+ `${JSON.stringify({
488
+ dry,
489
+ source,
490
+ files: files.map((f) => ({ path: f.relPath, contents: f.contents })),
491
+ kept,
492
+ replaced: replaced.map((f) => relPosix(root, f)),
493
+ todos: [...todos].map(([reason, tasks]) => ({ reason, tasks })),
494
+ notes: [
495
+ ...(empty && unreached.length > 0 ? [unreachedHint(unreached, root)] : []),
496
+ ...(empty ? noMembers : []),
497
+ ...(args.notes ?? []),
498
+ ...plan.headerNotes,
499
+ ...plan.notes,
500
+ ],
501
+ next,
502
+ })}\n`,
503
+ )
504
+ return 0
505
+ }
506
+ report.push('', `next: ${next}`)
480
507
  process.stdout.write(`${report.join('\n')}\n`)
481
508
  return 0
482
509
  }
@@ -165,6 +165,7 @@ export async function findWorkspaceRoot(
165
165
  `Could not find a workspace root in any parent of ${start} ` +
166
166
  `(looked for pnpm-workspace.yaml or package.json): run vx inside a project, ` +
167
167
  `or create a package.json (\`bun init\` or \`npm init -y\`) and run \`vx init\``,
168
+ 'VX_E_NO_WORKSPACE',
168
169
  )
169
170
  }
170
171