@vzn/vx 0.0.645 → 0.0.648
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 +39 -50
- package/launcher.cjs +9 -2
- package/launcher.sh +2 -2
- package/package.json +5 -5
- package/schemas/cache.json +5 -5
- package/schemas/error.json +1 -1
- package/schemas/info.json +16 -2
- package/schemas/last.json +127 -5
- package/schemas/plan.json +28 -2
- package/schemas/show.json +10 -1
- package/skills/vx/SKILL.md +19 -3
- package/src/bin.ts +54 -13
- package/src/cache/archive.ts +324 -23
- package/src/cache/cache.ts +330 -65
- package/src/cache/git-inputs.ts +274 -97
- package/src/cache/index.ts +7 -2
- package/src/cache/inputs.ts +515 -83
- package/src/cache/key-fold.ts +15 -6
- package/src/cache/layer.ts +74 -11
- package/src/cache/layered-cache.ts +154 -59
- package/src/cache/linked-inputs.ts +1 -1
- package/src/cache/output-index.ts +44 -14
- package/src/cache/plugin-cache.ts +49 -23
- package/src/cache/remote-hits.ts +72 -0
- package/src/cache/remote-lane.ts +100 -15
- package/src/cache/run-history.ts +77 -23
- package/src/cache/run-store.ts +11 -10
- package/src/cache/schema.ts +42 -6
- package/src/cache/tar-stream.ts +5 -0
- package/src/cache/umask.ts +1 -2
- package/src/cli/cache.ts +58 -27
- package/src/cli/completions.ts +12 -5
- package/src/cli/core-alias.ts +5 -2
- package/src/cli/docs.ts +42 -16
- package/src/cli/help.ts +62 -25
- package/src/cli/index.ts +79 -45
- package/src/cli/info.ts +12 -6
- package/src/cli/init.ts +222 -34
- package/src/cli/last.ts +443 -47
- package/src/cli/lock.ts +197 -52
- package/src/cli/plan-format.ts +91 -49
- package/src/cli/plugin-commands.ts +160 -11
- package/src/cli/plugin-templates.ts +13 -13
- package/src/cli/registry.ts +209 -0
- package/src/cli/run.ts +111 -41
- package/src/cli/select.ts +148 -49
- package/src/cli/show.ts +59 -16
- package/src/cli/task-verb.ts +16 -6
- package/src/cli/upgrade.ts +155 -54
- package/src/cli/watch-cycle.ts +10 -5
- package/src/cli/watch-filter.ts +71 -3
- package/src/cli/watch-fs.ts +22 -6
- package/src/cli/watch-judge.ts +48 -6
- package/src/cli/watch.ts +163 -42
- package/src/cli/why.ts +211 -73
- package/src/cli/workspace-config.ts +54 -15
- package/src/config.ts +13 -1
- package/src/exec/env.ts +7 -2
- package/src/exec/executor.ts +262 -15
- package/src/exec/index.ts +8 -2
- package/src/exec/kill-tree.ts +15 -0
- package/src/exec/local-executor.ts +1 -1
- package/src/exec/proc-sample.ts +70 -6
- package/src/exec/runner.ts +256 -53
- package/src/exec/sandbox-binds.ts +7 -3
- package/src/exec/sandbox-paths.ts +1 -1
- package/src/exec/sandbox-runtime.ts +222 -28
- package/src/exec/sandbox-violations.ts +52 -20
- package/src/graph/critical-path.ts +79 -0
- package/src/graph/default-build.ts +19 -0
- package/src/graph/definition.ts +38 -0
- package/src/graph/folds.ts +38 -5
- package/src/graph/index.ts +4 -1
- package/src/graph/priorities.ts +74 -8
- package/src/graph/scheduler.ts +326 -65
- package/src/graph/task-graph.ts +228 -35
- package/src/handoff.ts +97 -9
- package/src/history/failure-mode.ts +6 -3
- package/src/history/history.ts +268 -50
- package/src/history/index.ts +2 -0
- package/src/history/metrics.ts +142 -45
- package/src/index.ts +42 -10
- package/src/orchestrator/admission.ts +10 -6
- package/src/orchestrator/affected-tasks.ts +11 -6
- package/src/orchestrator/deferred-outputs.ts +2 -0
- package/src/orchestrator/doctor.ts +134 -42
- package/src/orchestrator/execute-args.ts +6 -0
- package/src/orchestrator/execute-task.ts +155 -42
- package/src/orchestrator/fingerprint-watch.ts +1 -1
- package/src/orchestrator/graph-memo.ts +140 -0
- package/src/orchestrator/graph-stage.ts +18 -1
- package/src/orchestrator/held-servers.ts +86 -0
- package/src/orchestrator/hit-restore.ts +227 -122
- package/src/orchestrator/index.ts +20 -3
- package/src/orchestrator/local-floor.ts +198 -0
- package/src/orchestrator/local-shortcircuit.ts +51 -8
- package/src/orchestrator/lockfile-claim.ts +96 -16
- package/src/orchestrator/miss-save.ts +52 -12
- package/src/orchestrator/options.ts +8 -6
- package/src/orchestrator/output-host.ts +43 -14
- package/src/orchestrator/output-log.ts +90 -10
- package/src/orchestrator/persistent-task.ts +97 -28
- package/src/orchestrator/persistent.ts +16 -4
- package/src/orchestrator/placement.ts +257 -14
- package/src/orchestrator/plan.ts +64 -7
- package/src/orchestrator/plugin-host.ts +230 -40
- package/src/orchestrator/plugin.ts +150 -37
- package/src/orchestrator/prepare.ts +178 -32
- package/src/orchestrator/projects.ts +65 -40
- package/src/orchestrator/remote-prefetch.ts +119 -25
- package/src/orchestrator/run-artifacts.ts +95 -32
- package/src/orchestrator/run-context.ts +39 -41
- package/src/orchestrator/run-failures.ts +65 -23
- package/src/orchestrator/run-id.ts +6 -3
- package/src/orchestrator/run-keys.ts +300 -0
- package/src/orchestrator/run-live.ts +294 -0
- package/src/orchestrator/run-lock.ts +13 -7
- package/src/orchestrator/run-records.ts +35 -23
- package/src/orchestrator/run-report.ts +3 -3
- package/src/orchestrator/run-steps.ts +58 -22
- package/src/orchestrator/run-stop.ts +22 -5
- package/src/orchestrator/run.ts +409 -79
- package/src/orchestrator/sandbox-fix.ts +7 -5
- package/src/orchestrator/sandbox-request.ts +78 -22
- package/src/orchestrator/shell-verdict.ts +5 -5
- package/src/orchestrator/signals.ts +26 -1
- package/src/orchestrator/stable-keys.ts +92 -8
- package/src/orchestrator/steps.ts +2 -2
- package/src/orchestrator/task-artifacts.ts +206 -0
- package/src/orchestrator/task-hash.ts +89 -14
- package/src/orchestrator/task-log-buffer.ts +72 -36
- package/src/orchestrator/task-process.ts +22 -0
- package/src/orchestrator/telemetry-host.ts +24 -3
- package/src/orchestrator/telemetry.ts +113 -38
- package/src/orchestrator/upstream.ts +15 -0
- package/src/report/events.ts +32 -13
- package/src/report/forecast.ts +36 -35
- package/src/report/framed-output.ts +173 -46
- package/src/report/index.ts +1 -0
- package/src/report/logger.ts +217 -186
- package/src/report/path-links.ts +12 -4
- package/src/report/plain-output.ts +13 -5
- package/src/report/status-line.ts +94 -46
- package/src/report/summary.ts +174 -38
- package/src/report/terminal-signals.ts +13 -2
- package/src/settings.ts +14 -6
- package/src/util/bun-version.ts +4 -1
- package/src/util/colors.ts +20 -3
- package/src/util/config-frame.ts +41 -4
- package/src/{graph → util}/dependency-spec.ts +22 -13
- package/src/util/edit-distance.ts +13 -1
- package/src/util/env-flag.ts +9 -0
- package/src/util/errors.ts +59 -3
- package/src/util/essential-env.ts +57 -0
- package/src/util/git-ignored.ts +1 -1
- package/src/util/hash.ts +35 -0
- package/src/util/hide-env.ts +45 -5
- package/src/util/index.ts +22 -5
- package/src/util/num.ts +8 -0
- package/src/util/paths.ts +121 -21
- package/src/util/report.ts +6 -1
- package/src/util/secret-mask.ts +62 -1
- package/src/util/secrets.ts +7 -2
- package/src/util/size.ts +11 -3
- package/src/util/tail.ts +6 -1
- package/src/util/timing.ts +13 -1
- package/src/util/ui.ts +65 -4
- package/src/util/which.ts +1 -1
- package/src/util/write-file.ts +67 -0
- package/src/workspace/affected.ts +710 -107
- package/src/workspace/bracket-literal.ts +84 -0
- package/src/workspace/canonical-dir.ts +37 -0
- package/src/workspace/config-bytecode.ts +282 -0
- package/src/workspace/config-eval.ts +29 -8
- package/src/workspace/config-imports.ts +199 -58
- package/src/workspace/config-schema.ts +242 -39
- package/src/workspace/filter.ts +37 -8
- package/src/workspace/index.ts +11 -2
- package/src/workspace/json-data.ts +3 -4
- package/src/workspace/lockfile.ts +57 -8
- package/src/workspace/migration.ts +72 -49
- package/src/workspace/package-graph.ts +5 -4
- package/src/workspace/project-loader.ts +314 -47
- package/src/workspace/repo-id.ts +1 -1
- package/src/workspace/workspace.ts +176 -33
- package/src/cli/foreign-flags.ts +0 -727
package/src/cli/run.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { statSync } from 'node:fs'
|
|
2
|
+
import path from 'node:path'
|
|
1
3
|
import { isatty } from 'node:tty'
|
|
2
4
|
import { findWorkspaceRoot } from '../workspace/index.js'
|
|
3
|
-
import {
|
|
4
|
-
import { flagHint, refuse, seeHelp } from './help.js'
|
|
5
|
+
import { anchoredSpecError, flagHint, refuse, seeHelp } from './help.js'
|
|
5
6
|
import {
|
|
6
7
|
planRun,
|
|
7
8
|
run as runOrchestrator,
|
|
@@ -19,7 +20,14 @@ import {
|
|
|
19
20
|
} from '../cache/index.js'
|
|
20
21
|
import { affectedFilterFor, findCwdSelection, pickTask, resolveFilters } from './select.js'
|
|
21
22
|
import { nxTargetHint, taskNamesHere } from './task-verb.js'
|
|
22
|
-
import {
|
|
23
|
+
import {
|
|
24
|
+
detectColors,
|
|
25
|
+
envFlagOn,
|
|
26
|
+
hasControl,
|
|
27
|
+
parseDecimalInt,
|
|
28
|
+
sayNotice,
|
|
29
|
+
sayLine,
|
|
30
|
+
} from '../util/index.js'
|
|
23
31
|
import { kindHint, parseSettingValue, type Setting, SETTINGS, settingRefusal } from '../settings.js'
|
|
24
32
|
import { formatPlanJson, formatPlanText } from './plan-format.js'
|
|
25
33
|
|
|
@@ -56,15 +64,15 @@ export interface RunArgs {
|
|
|
56
64
|
* workspace's `cache.policy` and applies these on top.
|
|
57
65
|
*/
|
|
58
66
|
cacheFlags?: CacheFlags
|
|
59
|
-
/**
|
|
60
|
-
remoteRequested?:
|
|
67
|
+
/** Which setting named a remote axis (`remote:r`, `:w`, `:rw`): the run says so when no plugin serves one. */
|
|
68
|
+
remoteRequested?: '--cache-policy' | 'VX_CACHE_POLICY'
|
|
61
69
|
/** `--cache-dir <path>`: override the cache directory (cwd-relative). */
|
|
62
70
|
cacheDir: string | undefined
|
|
63
71
|
/** `vx watch --poll` (`watch.poll`). */
|
|
64
72
|
poll?: true
|
|
65
73
|
forwardArgs: string[]
|
|
66
74
|
verbosity: number
|
|
67
|
-
dry: '
|
|
75
|
+
dry: 'pretty' | 'json' | undefined
|
|
68
76
|
profile: string | undefined
|
|
69
77
|
/**
|
|
70
78
|
* `--affected[=<base>]`. When undefined the flag wasn't passed.
|
|
@@ -116,7 +124,7 @@ const SETTING_OPTIONS = [
|
|
|
116
124
|
|
|
117
125
|
/** `verb` is the one being parsed for: `vx watch` reads `vx run`'s flags, and
|
|
118
126
|
* its flag hints named `vx run` (M-58). The caller appends the help pointer. */
|
|
119
|
-
export function parseRunArgs(
|
|
127
|
+
export function parseRunArgs(args: readonly string[], verb: 'run' | 'watch' = 'run'): RunArgs {
|
|
120
128
|
const out: RunArgs = {
|
|
121
129
|
tasks: [],
|
|
122
130
|
filters: [],
|
|
@@ -132,10 +140,6 @@ export function parseRunArgs(rawArgs: readonly string[], verb: 'run' | 'watch' =
|
|
|
132
140
|
affected: undefined,
|
|
133
141
|
}
|
|
134
142
|
|
|
135
|
-
// A Turbo or Nx spelling becomes vx's, or a refusal naming vx's.
|
|
136
|
-
const translated = translateForeign(rawArgs)
|
|
137
|
-
if ('error' in translated) return { ...out, error: translated.error }
|
|
138
|
-
const args = translated
|
|
139
143
|
const sepIdx = args.indexOf('--')
|
|
140
144
|
const before = sepIdx === -1 ? args : args.slice(0, sepIdx)
|
|
141
145
|
out.forwardArgs = sepIdx === -1 ? [] : args.slice(sepIdx + 1)
|
|
@@ -158,7 +162,7 @@ export function parseRunArgs(rawArgs: readonly string[], verb: 'run' | 'watch' =
|
|
|
158
162
|
if (v === undefined || v === '' || (a === '--filter' && v.startsWith('--')))
|
|
159
163
|
return {
|
|
160
164
|
...out,
|
|
161
|
-
error: `--filter requires a value
|
|
165
|
+
error: `--filter requires a value: a project name, glob or path, e.g. --filter app`,
|
|
162
166
|
}
|
|
163
167
|
out.filters.push(v)
|
|
164
168
|
} else if (a === '--all') {
|
|
@@ -178,19 +182,26 @@ export function parseRunArgs(rawArgs: readonly string[], verb: 'run' | 'watch' =
|
|
|
178
182
|
// half the callers mean. Reject and name both explicit forms; the
|
|
179
183
|
// sibling value flags (--retries=, --timeout=, --cache-dir=)
|
|
180
184
|
// reject an empty `=` value the same way.
|
|
181
|
-
|
|
185
|
+
const names = raw
|
|
186
|
+
.split(',')
|
|
187
|
+
.map((s) => s.trim())
|
|
188
|
+
.filter((s) => s.length > 0)
|
|
189
|
+
// `=,` named nothing and ran every edge, as `=` would have.
|
|
190
|
+
if (names.length === 0) {
|
|
182
191
|
return {
|
|
183
192
|
...out,
|
|
184
193
|
error: `--exclude-dependencies= needs a value — pass bare --exclude-dependencies to drop every dependsOn edge, or omit the flag to keep them`,
|
|
185
194
|
}
|
|
186
195
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
.
|
|
196
|
+
// Repeated, the last list replaced the earlier ones, so their
|
|
197
|
+
// edges ran; `--filter` adds up the same way.
|
|
198
|
+
if (out.excludeDependencies !== 'all')
|
|
199
|
+
out.excludeDependencies = [...new Set([...out.excludeDependencies, ...names])]
|
|
191
200
|
} else if (a === '--cache-dir' || a?.startsWith('--cache-dir=')) {
|
|
192
201
|
const v = a === '--cache-dir' ? before[++i] : a.slice('--cache-dir='.length)
|
|
193
|
-
|
|
202
|
+
// Whitespace named a directory in spaces; `VX_CACHE_DIR` and `cache.dir` refuse it.
|
|
203
|
+
if (v === undefined || v.trim() === '')
|
|
204
|
+
return { ...out, error: `--cache-dir requires a path` }
|
|
194
205
|
// Unlike every other value flag, a cache dir is an arbitrary
|
|
195
206
|
// string — nothing about its shape rejects a swallowed flag. An
|
|
196
207
|
// unquoted empty shell var (`--cache-dir $EMPTY --force`) would
|
|
@@ -210,7 +221,7 @@ export function parseRunArgs(rawArgs: readonly string[], verb: 'run' | 'watch' =
|
|
|
210
221
|
if (v === undefined)
|
|
211
222
|
return {
|
|
212
223
|
...out,
|
|
213
|
-
error: `${name} requires a value
|
|
224
|
+
error: `${name} requires a value: a spec like local:r, local:rw, remote:, or local:,remote:rw`,
|
|
214
225
|
}
|
|
215
226
|
// A spec with no segment at all applies NOTHING, so `--cache-policy=`
|
|
216
227
|
// (an empty shell var, or someone reaching for "no cache") left
|
|
@@ -225,7 +236,7 @@ export function parseRunArgs(rawArgs: readonly string[], verb: 'run' | 'watch' =
|
|
|
225
236
|
}
|
|
226
237
|
try {
|
|
227
238
|
cachePolicy = parseCachePolicy(v, cachePolicy)
|
|
228
|
-
if (/remote:[rw]/.test(v)) out.remoteRequested =
|
|
239
|
+
if (/remote:[rw]/.test(v)) out.remoteRequested = '--cache-policy'
|
|
229
240
|
} catch (err) {
|
|
230
241
|
cacheSpecError = `--cache-policy: ${err instanceof Error ? err.message : String(err)}`
|
|
231
242
|
}
|
|
@@ -246,7 +257,7 @@ export function parseRunArgs(rawArgs: readonly string[], verb: 'run' | 'watch' =
|
|
|
246
257
|
} else if (a?.startsWith('--continue=')) {
|
|
247
258
|
const v = a.slice('--continue='.length)
|
|
248
259
|
if (v === '') {
|
|
249
|
-
return { ...out, error: `--continue= requires a mode
|
|
260
|
+
return { ...out, error: `--continue= requires a mode: never, deps-ok, or always` }
|
|
250
261
|
}
|
|
251
262
|
if (v !== 'never' && v !== 'deps-ok' && v !== 'always') {
|
|
252
263
|
return { ...out, error: `--continue must be never, deps-ok, or always (got ${v})` }
|
|
@@ -254,18 +265,31 @@ export function parseRunArgs(rawArgs: readonly string[], verb: 'run' | 'watch' =
|
|
|
254
265
|
out.continueMode = v
|
|
255
266
|
} else if (a === '--verbosity' || a?.startsWith('--verbosity=')) {
|
|
256
267
|
const v = a === '--verbosity' ? before[++i] : a.slice('--verbosity='.length)
|
|
257
|
-
if (v === undefined)
|
|
258
|
-
return { ...out, error: `--verbosity requires a value
|
|
268
|
+
if (v === undefined || v === '')
|
|
269
|
+
return { ...out, error: `--verbosity requires a value: a non-negative integer` }
|
|
259
270
|
const n = parseDecimalInt(v)
|
|
260
271
|
if (n === null)
|
|
261
272
|
return { ...out, error: `--verbosity must be a non-negative integer (got ${v})` }
|
|
262
273
|
out.verbosity = n
|
|
263
274
|
} else if (a === '--dry') {
|
|
264
|
-
|
|
275
|
+
// As `--continue`'s mode: `--dry json` read `json` as a task, and the
|
|
276
|
+
// run said no project declares it.
|
|
277
|
+
const next = before[i + 1]
|
|
278
|
+
if (next === 'pretty' || next === 'json') {
|
|
279
|
+
return { ...out, error: `--dry takes its format with '=': --dry=${next}` }
|
|
280
|
+
}
|
|
281
|
+
out.dry = 'pretty'
|
|
265
282
|
} else if (a?.startsWith('--dry=')) {
|
|
266
283
|
const fmt = a.slice('--dry='.length)
|
|
267
|
-
if (fmt
|
|
268
|
-
return {
|
|
284
|
+
if (fmt === '') {
|
|
285
|
+
return {
|
|
286
|
+
...out,
|
|
287
|
+
error: `--dry= requires a format: pretty or json; bare --dry prints pretty`,
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
// The values every --format takes.
|
|
291
|
+
if (fmt !== 'pretty' && fmt !== 'json') {
|
|
292
|
+
return { ...out, error: `--dry must be pretty or json (got ${fmt})` }
|
|
269
293
|
}
|
|
270
294
|
out.dry = fmt
|
|
271
295
|
} else if (a === '--profile') {
|
|
@@ -280,19 +304,36 @@ export function parseRunArgs(rawArgs: readonly string[], verb: 'run' | 'watch' =
|
|
|
280
304
|
out.affected = ''
|
|
281
305
|
} else if (a?.startsWith('--affected=')) {
|
|
282
306
|
out.affected = a.slice('--affected='.length)
|
|
283
|
-
} else if (
|
|
307
|
+
} else if (a === '--poll') {
|
|
308
|
+
// The edit-distance hint offered vx run `--all`, a different flag.
|
|
309
|
+
if (verb === 'run')
|
|
310
|
+
return { ...out, error: `unknown flag: --poll (a vx watch flag: vx watch --poll <task>)` }
|
|
284
311
|
out.poll = true
|
|
285
312
|
} else if (a !== undefined && settingFlagOf(a) !== undefined) {
|
|
286
313
|
const { s: set, name } = settingFlagOf(a)!
|
|
287
314
|
const v = a === name ? before[++i] : a.slice(name.length + 1)
|
|
288
315
|
if (v === undefined || v === '')
|
|
289
|
-
return { ...out, error: `${name} requires a value
|
|
316
|
+
return { ...out, error: `${name} requires a value: ${kindHint(set.kind)}` }
|
|
317
|
+
// A string's shape rejects nothing, so the space form would swallow
|
|
318
|
+
// the next flag as the value, as `--cache-dir` would above.
|
|
319
|
+
if (set.kind.type === 'string' && a === name && v.startsWith('-'))
|
|
320
|
+
return {
|
|
321
|
+
...out,
|
|
322
|
+
error: `${name} requires a value (got flag ${v}; a value that starts with - needs ${name}=${v})`,
|
|
323
|
+
}
|
|
290
324
|
const value = parseSettingValue(set.kind, v)
|
|
291
325
|
if (value === null) return { ...out, error: settingRefusal(set.path, name, v) }
|
|
292
326
|
out.settings[set.path] = value
|
|
293
327
|
} else if (a !== undefined && a.startsWith('-')) {
|
|
294
328
|
return { ...out, error: `unknown flag: ${a}${flagHint(verb, a)}` }
|
|
295
329
|
} else if (a !== undefined) {
|
|
330
|
+
// A config may not declare such a name (`taskNameProblem`); a pasted
|
|
331
|
+
// newline was refused as an unknown task, printed raw.
|
|
332
|
+
if (hasControl(a))
|
|
333
|
+
return {
|
|
334
|
+
...out,
|
|
335
|
+
error: `task ${JSON.stringify(a)} holds a control character, which no task name may hold — retype it`,
|
|
336
|
+
}
|
|
296
337
|
out.tasks.push(a)
|
|
297
338
|
}
|
|
298
339
|
}
|
|
@@ -316,7 +357,7 @@ export function parseRunArgs(rawArgs: readonly string[], verb: 'run' | 'watch' =
|
|
|
316
357
|
error: `VX_CACHE_POLICY: ${err instanceof Error ? err.message : String(err)}`,
|
|
317
358
|
}
|
|
318
359
|
}
|
|
319
|
-
if (/remote:[rw]/.test(envSpec)) out.remoteRequested =
|
|
360
|
+
if (/remote:[rw]/.test(envSpec)) out.remoteRequested = 'VX_CACHE_POLICY'
|
|
320
361
|
}
|
|
321
362
|
// --no-cache (all off) beats --force (reads off, writes kept), both
|
|
322
363
|
// layered on top of the spec; with none named, on the workspace's.
|
|
@@ -405,12 +446,22 @@ export async function resolveRunOptions(
|
|
|
405
446
|
scopeOut?: { affectedBase?: string },
|
|
406
447
|
): Promise<RunOptions | { error: string; code?: string } | { nothingSelected: string }> {
|
|
407
448
|
for (const t of tasks) {
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
449
|
+
// A blank name (`vx run --all ''`) otherwise reached the orchestrator,
|
|
450
|
+
// which refuses it in the embedder API's words.
|
|
451
|
+
if (t.trim() === '')
|
|
452
|
+
return { error: `empty task name ${JSON.stringify(t)} (vx show lists the tasks)` }
|
|
453
|
+
// A bare name runs in the cwd project: `--all` is every project.
|
|
454
|
+
const error = anchoredSpecError(
|
|
455
|
+
t,
|
|
456
|
+
(task) => `vx ${verb} ${task} --all runs it in every project`,
|
|
457
|
+
)
|
|
458
|
+
if (error !== undefined) return { error }
|
|
459
|
+
// No config can declare a padded name (taskNameProblem): `'build '` was
|
|
460
|
+
// reported as "no projects declare task(s): build", its space unseen.
|
|
461
|
+
const task = t.slice(t.indexOf('#') + 1)
|
|
462
|
+
if (task.trim() !== task) {
|
|
463
|
+
return {
|
|
464
|
+
error: `task name ${JSON.stringify(task)} has surrounding whitespace (vx show lists the tasks)`,
|
|
414
465
|
}
|
|
415
466
|
}
|
|
416
467
|
}
|
|
@@ -441,6 +492,7 @@ export async function resolveRunOptions(
|
|
|
441
492
|
filterStrings,
|
|
442
493
|
parsed.cacheDir !== undefined ? { cacheDir: parsed.cacheDir } : {},
|
|
443
494
|
affectedFilter,
|
|
495
|
+
verb,
|
|
444
496
|
)
|
|
445
497
|
: undefined
|
|
446
498
|
if (resolved !== undefined && 'error' in resolved) return resolved
|
|
@@ -469,7 +521,10 @@ export async function resolveRunOptions(
|
|
|
469
521
|
} else if (parsed.all) {
|
|
470
522
|
projects = undefined
|
|
471
523
|
} else {
|
|
472
|
-
const cwdProject = await findCwdSelection(
|
|
524
|
+
const cwdProject = await findCwdSelection(
|
|
525
|
+
cwd,
|
|
526
|
+
parsed.cacheDir !== undefined ? { cacheDir: parsed.cacheDir } : {},
|
|
527
|
+
)
|
|
473
528
|
if (!cwdProject) {
|
|
474
529
|
const nx = await nxTargetHint(tasks, cwd)
|
|
475
530
|
if (nx !== null) return { error: nx }
|
|
@@ -487,7 +542,7 @@ export async function resolveRunOptions(
|
|
|
487
542
|
...(parsed.cacheFlags !== undefined
|
|
488
543
|
? { cacheFlags: parsed.cacheFlags }
|
|
489
544
|
: { cache: parsed.cache }),
|
|
490
|
-
...(parsed.remoteRequested ? { remoteRequested:
|
|
545
|
+
...(parsed.remoteRequested ? { remoteRequested: parsed.remoteRequested } : {}),
|
|
491
546
|
// A laptop reads the shared cache and never writes it (owner,
|
|
492
547
|
// 2026-10-03); naming the remote in `--cache-policy` is asking to.
|
|
493
548
|
...(!parsed.remoteRequested && !onCI(process.env['CI'])
|
|
@@ -532,6 +587,10 @@ export async function runCmd(args: readonly string[]): Promise<number> {
|
|
|
532
587
|
}
|
|
533
588
|
|
|
534
589
|
const cwd = process.cwd()
|
|
590
|
+
if (parsed.profile !== undefined) {
|
|
591
|
+
const problem = profileProblem(cwd, parsed.profile)
|
|
592
|
+
if (problem !== undefined) return refuse('run', args, problem, 'VX_E_USAGE')
|
|
593
|
+
}
|
|
535
594
|
let tasks = [...parsed.tasks]
|
|
536
595
|
let picked: string | undefined
|
|
537
596
|
|
|
@@ -645,7 +704,7 @@ export async function runCmd(args: readonly string[]): Promise<number> {
|
|
|
645
704
|
if (parsed.dry === 'json') {
|
|
646
705
|
process.stdout.write(formatPlanJson(plan, scopeOut.affectedBase))
|
|
647
706
|
} else {
|
|
648
|
-
process.stdout.write(formatPlanText(plan))
|
|
707
|
+
process.stdout.write(formatPlanText(plan, detectColors(process.stdout)))
|
|
649
708
|
}
|
|
650
709
|
return 0
|
|
651
710
|
}
|
|
@@ -662,7 +721,18 @@ export async function runCmd(args: readonly string[]): Promise<number> {
|
|
|
662
721
|
return summary.ok ? 0 : 1
|
|
663
722
|
}
|
|
664
723
|
|
|
665
|
-
/**
|
|
666
|
-
|
|
667
|
-
|
|
724
|
+
/**
|
|
725
|
+
* Why `--profile` cannot write `target`, or undefined. Asked before the
|
|
726
|
+
* run: a directory named as the file died with EISDIR only after it. A
|
|
727
|
+
* missing parent is no fault: the write makes it (item 993).
|
|
728
|
+
*/
|
|
729
|
+
function profileProblem(cwd: string, target: string): string | undefined {
|
|
730
|
+
if (statSync(path.resolve(cwd, target), { throwIfNoEntry: false })?.isDirectory() === true)
|
|
731
|
+
return `--profile: ${target} is a directory — name a file, e.g. --profile=${path.join(target, 'profile.json')}`
|
|
732
|
+
return undefined
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
/** Whether `CI` names a CI run, as detectCi reads it. */
|
|
736
|
+
export function onCI(v: string | undefined): boolean {
|
|
737
|
+
return envFlagOn(v)
|
|
668
738
|
}
|