@vzn/vx 0.0.607 → 0.0.609
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/run.ts +6 -1
- package/src/orchestrator/plan.ts +2 -0
- package/src/orchestrator/projects.ts +16 -0
- package/src/orchestrator/run.ts +19 -14
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vzn/vx",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.609",
|
|
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.609",
|
|
25
|
+
"@vzn/vx-linux-arm64": "0.0.609",
|
|
26
|
+
"@vzn/vx-darwin-x64": "0.0.609",
|
|
27
|
+
"@vzn/vx-darwin-arm64": "0.0.609"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@anthropic-ai/sandbox-runtime": "^0.0.76"
|
package/src/cli/run.ts
CHANGED
|
@@ -11,7 +11,6 @@ import {
|
|
|
11
11
|
run as runOrchestrator,
|
|
12
12
|
shellQuote,
|
|
13
13
|
type RunOptions,
|
|
14
|
-
type RunResult,
|
|
15
14
|
} from '../orchestrator/index.js'
|
|
16
15
|
import type { ContinueMode, TaskOutcome } from '../graph/index.js'
|
|
17
16
|
import {
|
|
@@ -721,6 +720,12 @@ export async function runCmd(args: readonly string[]): Promise<number> {
|
|
|
721
720
|
return 1
|
|
722
721
|
}
|
|
723
722
|
if (plan.tasks.length === 0) {
|
|
723
|
+
// The run's own line: a dry run that guessed from the scope alone
|
|
724
|
+
// said no affected project declared a task one did (X-141).
|
|
725
|
+
if (plan.noneAffected !== undefined) {
|
|
726
|
+
process.stderr.write(`${plan.noneAffected}\n`)
|
|
727
|
+
return 0
|
|
728
|
+
}
|
|
724
729
|
if (opts.selectedByDiff === true) {
|
|
725
730
|
process.stderr.write(`vx run: no affected project declares task(s): ${tasks.join(', ')}.\n`)
|
|
726
731
|
return 0
|
package/src/orchestrator/plan.ts
CHANGED
|
@@ -82,6 +82,8 @@ export interface RunPlan {
|
|
|
82
82
|
unresolvedTasks?: readonly string[]
|
|
83
83
|
/** What `vx run` appends to that refusal: the nearest declared names, or how to declare one. */
|
|
84
84
|
unresolvedHint?: string
|
|
85
|
+
/** Set when `--affected` left nothing to run: the line the run would print, and why. */
|
|
86
|
+
noneAffected?: string
|
|
85
87
|
/**
|
|
86
88
|
* Producers `--download` WANTED to defer but could not, mapped to why.
|
|
87
89
|
* Without this the gate is invisible: a user asks for `--download=none`,
|
|
@@ -9,6 +9,7 @@ import type { ProjectConfig, TaskConfig } from '../config.js'
|
|
|
9
9
|
import {
|
|
10
10
|
frozenProjectConfigs,
|
|
11
11
|
loadProjectConfigs,
|
|
12
|
+
LOCKFILE_NAME,
|
|
12
13
|
validateProjectConfig,
|
|
13
14
|
type LoadProjectConfigOptions,
|
|
14
15
|
type LoadReads,
|
|
@@ -243,6 +244,21 @@ export async function loadProjects(args: LoadProjectsArgs): Promise<LoadedProjec
|
|
|
243
244
|
// alike. With no root project it stays, and the graph's refusal says so.
|
|
244
245
|
const root = path.resolve(workspaceRoot)
|
|
245
246
|
const rootName = args.projectMetas.find((m) => path.resolve(m.dir) === root)?.name
|
|
247
|
+
// A project the lock holds whose config file is gone ran nothing under
|
|
248
|
+
// --frozen, green, though the lock promises what runs is what was
|
|
249
|
+
// locked (X-144); a run never even asks such a project for a task.
|
|
250
|
+
// Refused as a moved config is (D-88). With no lock at all, nothing was
|
|
251
|
+
// locked: a repo of config-less projects needs none.
|
|
252
|
+
if (lock) {
|
|
253
|
+
const bare = args.projectMetas.filter((m) => m.configPath === null)
|
|
254
|
+
const held = bare.length === 0 ? null : await lock().catch(() => null)
|
|
255
|
+
const gone = held === null ? undefined : bare.find((m) => Object.hasOwn(held.projects, m.name))
|
|
256
|
+
if (gone !== undefined && held !== null)
|
|
257
|
+
throw new UserError(
|
|
258
|
+
`${LOCKFILE_NAME} locks "${gone.name}" at ${held.projects[gone.name]!.configPath}, but it has no config now — ` +
|
|
259
|
+
`run \`vx lock\` to refresh, or delete ${LOCKFILE_NAME}`,
|
|
260
|
+
)
|
|
261
|
+
}
|
|
246
262
|
const projects = new Map<string, ProjectEntry>()
|
|
247
263
|
while (pending.length > 0) {
|
|
248
264
|
const round = pending.splice(0, pending.length)
|
package/src/orchestrator/run.ts
CHANGED
|
@@ -404,20 +404,7 @@ async function runOnBus(
|
|
|
404
404
|
return { ok: false, outcomes: [], refused }
|
|
405
405
|
}
|
|
406
406
|
if (prepared.empty === 'none-affected') {
|
|
407
|
-
|
|
408
|
-
// what left nothing (affected-tasks.ts), not the scope.
|
|
409
|
-
const inScope = new Set(options.projects ?? [])
|
|
410
|
-
const reachedNone =
|
|
411
|
-
options.affected !== undefined &&
|
|
412
|
-
[...prepared.projects.values()].some(
|
|
413
|
-
(p) =>
|
|
414
|
-
inScope.has(p.name) && options.tasks.some((t) => declaredTask(p.config, t) !== undefined),
|
|
415
|
-
)
|
|
416
|
-
log.status(
|
|
417
|
-
reachedNone
|
|
418
|
-
? `Nothing affected: the change reaches no ${options.tasks.join(', ')} task.`
|
|
419
|
-
: `No affected project declares task(s): ${options.tasks.join(', ')}.`,
|
|
420
|
-
)
|
|
407
|
+
log.status(noneAffected(prepared, options))
|
|
421
408
|
await teardown()
|
|
422
409
|
prepared.cache.close()
|
|
423
410
|
return { ok: true, outcomes: [] }
|
|
@@ -1516,6 +1503,22 @@ async function applyCacheRetention(prepared: PreparedRun): Promise<void> {
|
|
|
1516
1503
|
}
|
|
1517
1504
|
}
|
|
1518
1505
|
|
|
1506
|
+
/** Why an `--affected` run has nothing to run, said alike by the run and its `--dry` plan. */
|
|
1507
|
+
function noneAffected(prepared: PreparedRun, options: RunOptions): string {
|
|
1508
|
+
// A changed project declares the task, so `--affected`'s task walk is
|
|
1509
|
+
// what left nothing (affected-tasks.ts), not the scope.
|
|
1510
|
+
const inScope = new Set(options.projects ?? [])
|
|
1511
|
+
const reachedNone =
|
|
1512
|
+
options.affected !== undefined &&
|
|
1513
|
+
[...prepared.projects.values()].some(
|
|
1514
|
+
(p) =>
|
|
1515
|
+
inScope.has(p.name) && options.tasks.some((t) => declaredTask(p.config, t) !== undefined),
|
|
1516
|
+
)
|
|
1517
|
+
return reachedNone
|
|
1518
|
+
? `Nothing affected: the change reaches no ${options.tasks.join(', ')} task.`
|
|
1519
|
+
: `No affected project declares task(s): ${options.tasks.join(', ')}.`
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1519
1522
|
/**
|
|
1520
1523
|
* Planning mode. Same setup as `run()` — workspace discovery, config
|
|
1521
1524
|
* load, package graph, task graph — but stops short of execution.
|
|
@@ -1548,6 +1551,8 @@ export async function planRun(options: RunOptions): Promise<RunPlan> {
|
|
|
1548
1551
|
unresolvedHint: elsewhereHint(prepared.declaredElsewhere),
|
|
1549
1552
|
}
|
|
1550
1553
|
}
|
|
1554
|
+
if (prepared.empty === 'none-affected')
|
|
1555
|
+
return { tasks: [], noneAffected: noneAffected(prepared, options) }
|
|
1551
1556
|
if (prepared.empty !== null) return { tasks: [] }
|
|
1552
1557
|
// Its own mark: a dry run's plan (every task's hash, the cache lookups,
|
|
1553
1558
|
// the history p50s) was booked under `close`, the next mark, and read
|