@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.
- package/README.md +21 -18
- package/docs/caching.md +2247 -0
- package/docs/cli.md +3214 -0
- package/docs/execution.md +708 -0
- package/docs/features.md +172 -0
- package/docs/patterns.md +219 -0
- package/docs/schema.md +2137 -0
- package/docs/security.md +209 -0
- package/package.json +14 -5
- package/schemas/cache.json +24 -0
- package/schemas/docs.json +28 -0
- package/schemas/error.json +23 -0
- package/schemas/info.json +147 -0
- package/schemas/init.json +57 -0
- package/schemas/last.json +188 -0
- package/schemas/lock.json +21 -0
- package/schemas/plan.json +88 -0
- package/schemas/show.json +124 -0
- package/schemas/summary.json +133 -0
- package/schemas/why.json +168 -0
- package/skills/vx/SKILL.md +89 -0
- package/src/bin.ts +9 -0
- package/src/cache/archive.ts +153 -51
- package/src/cache/cache.ts +542 -137
- package/src/cache/chained-cache.ts +9 -0
- package/src/cache/inputs.ts +5 -0
- package/src/cache/layer.ts +10 -5
- package/src/cache/layered-cache.ts +4 -0
- package/src/cache/schema.ts +44 -17
- package/src/cache/tar-stream.ts +204 -66
- package/src/cache/zstd.ts +1 -1
- package/src/cli/cache.ts +14 -14
- package/src/cli/docs-corpus.ts +21 -0
- package/src/cli/docs-text.d.ts +5 -0
- package/src/cli/docs.ts +167 -0
- package/src/cli/foreign-flags.ts +1 -1
- package/src/cli/help.ts +42 -7
- package/src/cli/index.ts +25 -11
- package/src/cli/info.ts +38 -9
- package/src/cli/init.ts +131 -24
- package/src/cli/last.ts +54 -3
- package/src/cli/lock.ts +43 -15
- package/src/cli/plan-format.ts +23 -1
- package/src/cli/plugin-commands.ts +3 -0
- package/src/cli/plugin-templates.ts +1 -1
- package/src/cli/run.ts +40 -21
- package/src/cli/show.ts +10 -7
- package/src/cli/upgrade.ts +19 -7
- package/src/cli/watch.ts +7 -2
- package/src/cli/why.ts +14 -40
- package/src/exec/runner.ts +27 -10
- package/src/graph/scheduler.ts +36 -0
- package/src/graph/task-graph.ts +4 -4
- package/src/index.ts +22 -5
- package/src/orchestrator/admission.ts +29 -1
- package/src/orchestrator/affected-tasks.ts +87 -18
- package/src/orchestrator/doctor.ts +14 -1
- package/src/orchestrator/execute-task.ts +149 -64
- package/src/orchestrator/failure-mode.ts +5 -3
- package/src/orchestrator/framed-output.ts +17 -3
- package/src/orchestrator/index.ts +11 -0
- package/src/orchestrator/logger.ts +57 -6
- package/src/orchestrator/metrics.ts +76 -4
- package/src/orchestrator/miss-reason.ts +3 -5
- package/src/orchestrator/miss-save.ts +6 -5
- package/src/orchestrator/options.ts +12 -0
- package/src/orchestrator/output-log.ts +14 -1
- package/src/orchestrator/path-links.ts +79 -0
- package/src/orchestrator/plan.ts +20 -3
- package/src/orchestrator/plugin.ts +7 -0
- package/src/orchestrator/prepare.ts +14 -4
- package/src/orchestrator/projects.ts +2 -2
- package/src/orchestrator/run-artifacts.ts +18 -2
- package/src/orchestrator/run-failures.ts +192 -0
- package/src/orchestrator/run-records.ts +10 -8
- package/src/orchestrator/run.ts +87 -22
- package/src/orchestrator/task-hash.ts +4 -4
- package/src/orchestrator/terminal-signals.ts +16 -0
- package/src/orchestrator/upstream.ts +65 -10
- package/src/util/errors.ts +55 -1
- package/src/util/index.ts +3 -0
- package/src/util/secret-mask.ts +13 -1
- package/src/util/verbs.ts +1 -0
- package/src/workspace/config-schema.ts +10 -8
- package/src/workspace/migration.ts +30 -3
- package/src/workspace/workspace.ts +1 -0
package/src/util/secret-mask.ts
CHANGED
|
@@ -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)
|
|
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
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|