nx 24.0.0-beta.0 → 24.0.0-beta.2
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/dist/nx-cloud-internals.d.ts +1 -0
- package/dist/nx-cloud-internals.js +7 -1
- package/dist/src/command-line/graph/graph.js +2 -1
- package/dist/src/command-line/migrate/agentic/close-agent-session.d.ts +1 -1
- package/dist/src/command-line/migrate/agentic/close-agent-session.js +4 -3
- package/dist/src/command-line/migrate/agentic/handoff-gitignore.d.ts +19 -23
- package/dist/src/command-line/migrate/agentic/handoff-gitignore.js +16 -19
- package/dist/src/command-line/migrate/agentic/master/run-master-session.js +25 -13
- package/dist/src/command-line/migrate/agentic/master/spawn-master.js +82 -22
- package/dist/src/command-line/migrate/agentic/select.js +3 -3
- package/dist/src/command-line/migrate/agentic/types.js +1 -3
- package/dist/src/command-line/migrate/command-object.js +5 -9
- package/dist/src/command-line/migrate/execute-migration.d.ts +2 -2
- package/dist/src/command-line/migrate/execute-migration.js +18 -10
- package/dist/src/command-line/migrate/migrate-analytics.d.ts +6 -0
- package/dist/src/command-line/migrate/migrate-analytics.js +12 -0
- package/dist/src/command-line/migrate/migrate-commits.d.ts +4 -1
- package/dist/src/command-line/migrate/migrate-commits.js +10 -3
- package/dist/src/command-line/migrate/migrate-config.d.ts +6 -6
- package/dist/src/command-line/migrate/migrate-config.js +12 -6
- package/dist/src/command-line/migrate/migrate.d.ts +3 -30
- package/dist/src/command-line/migrate/migrate.js +206 -237
- package/dist/src/command-line/migrate/run/agent-output.d.ts +1 -0
- package/dist/src/command-line/migrate/run/agent-output.js +5 -0
- package/dist/src/command-line/migrate/run/broker.d.ts +14 -5
- package/dist/src/command-line/migrate/run/broker.js +68 -20
- package/dist/src/command-line/migrate/run/existing-run-report.d.ts +1 -1
- package/dist/src/command-line/migrate/run/existing-run-report.js +7 -5
- package/dist/src/command-line/migrate/run/index.d.ts +6 -5
- package/dist/src/command-line/migrate/run/index.js +12 -1
- package/dist/src/command-line/migrate/run/orchestrator.d.ts +21 -0
- package/dist/src/command-line/migrate/run/orchestrator.js +149 -32
- package/dist/src/command-line/migrate/run/run-state.d.ts +13 -0
- package/dist/src/command-line/migrate/run/run-state.js +21 -0
- package/dist/src/command-line/migrate/run/runbook.js +19 -0
- package/dist/src/command-line/migrate/run/state-machine.js +4 -1
- package/dist/src/command-line/migrate/run/util.d.ts +3 -0
- package/dist/src/command-line/migrate/run/util.js +7 -1
- package/dist/src/command-line/migrate/sort-migrations.d.ts +1 -7
- package/dist/src/command-line/migrate/sort-migrations.js +1 -12
- package/dist/src/command-line/show/show-target/info.js +1 -1
- package/dist/src/config/nx-json.d.ts +13 -4
- package/dist/src/config/task-graph.d.ts +1 -1
- package/dist/src/config/workspace-json-project-json.d.ts +72 -0
- package/dist/src/core/graph/main.js +1 -1
- package/dist/src/devkit-exports.d.ts +1 -1
- package/dist/src/hasher/check-task-files.js +4 -4
- package/dist/src/hasher/native-task-hasher-impl.js +3 -1
- package/dist/src/hasher/task-hasher.d.ts +2 -0
- package/dist/src/hasher/task-hasher.js +4 -1
- package/dist/src/native/index.d.ts +92 -14
- package/dist/src/native/native-bindings.js +3 -0
- package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
- package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
- package/dist/src/project-graph/utils/project-configuration/target-normalization.js +6 -1
- package/dist/src/project-graph/utils/retrieve-workspace-files.js +27 -6
- package/dist/src/tasks-runner/create-task-graph.d.ts +7 -16
- package/dist/src/tasks-runner/create-task-graph.js +43 -57
- package/dist/src/tasks-runner/default-tasks-runner.js +1 -1
- package/dist/src/tasks-runner/init-tasks-runner.js +13 -0
- package/dist/src/tasks-runner/life-cycle.d.ts +4 -1
- package/dist/src/tasks-runner/life-cycle.js +7 -0
- package/dist/src/tasks-runner/life-cycles/performance-analysis.d.ts +5 -2
- package/dist/src/tasks-runner/life-cycles/performance-analysis.js +13 -7
- package/dist/src/tasks-runner/life-cycles/performance-life-cycle.d.ts +4 -3
- package/dist/src/tasks-runner/life-cycles/performance-life-cycle.js +9 -2
- package/dist/src/tasks-runner/readiness/probes.d.ts +9 -0
- package/dist/src/tasks-runner/readiness/probes.js +62 -0
- package/dist/src/tasks-runner/readiness/ready-when.d.ts +38 -0
- package/dist/src/tasks-runner/readiness/ready-when.js +190 -0
- package/dist/src/tasks-runner/run-command.js +7 -6
- package/dist/src/tasks-runner/running-tasks/batch-process.js +6 -0
- package/dist/src/tasks-runner/running-tasks/node-child-process.js +5 -4
- package/dist/src/tasks-runner/task-graph-utils.d.ts +9 -6
- package/dist/src/tasks-runner/task-graph-utils.js +17 -12
- package/dist/src/tasks-runner/task-orchestrator.d.ts +37 -10
- package/dist/src/tasks-runner/task-orchestrator.js +459 -79
- package/dist/src/tasks-runner/tasks-runner.d.ts +1 -1
- package/dist/src/tasks-runner/tasks-schedule.d.ts +18 -1
- package/dist/src/tasks-runner/tasks-schedule.js +64 -6
- package/dist/src/tasks-runner/utils.js +6 -22
- package/dist/src/utils/child-process.js +1 -0
- package/dist/src/utils/git-utils.d.ts +6 -1
- package/dist/src/utils/git-utils.js +26 -5
- package/dist/src/utils/plugins/core-plugins.js +4 -0
- package/dist/src/utils/spawn-without-terminal.d.ts +27 -0
- package/dist/src/utils/spawn-without-terminal.js +110 -0
- package/package.json +12 -11
- package/schemas/nx-schema.json +93 -4
- package/schemas/project-schema.json +84 -2
|
@@ -5,6 +5,9 @@ exports.runOrchestratorResume = runOrchestratorResume;
|
|
|
5
5
|
exports.holdRunToContinue = holdRunToContinue;
|
|
6
6
|
exports.activeRunToReplace = activeRunToReplace;
|
|
7
7
|
exports.releaseRunToHandOff = releaseRunToHandOff;
|
|
8
|
+
exports.activeRunForClassic = activeRunForClassic;
|
|
9
|
+
exports.checkRunForStartFresh = checkRunForStartFresh;
|
|
10
|
+
exports.deleteRunForStartFresh = deleteRunForStartFresh;
|
|
8
11
|
exports.runOrchestratorReconcile = runOrchestratorReconcile;
|
|
9
12
|
exports.completionWarnings = completionWarnings;
|
|
10
13
|
const child_process_1 = require("child_process");
|
|
@@ -42,7 +45,7 @@ const issues_1 = require("./issues");
|
|
|
42
45
|
const runbook_1 = require("./runbook");
|
|
43
46
|
const existing_run_report_1 = require("./existing-run-report");
|
|
44
47
|
const package_manager_1 = require("../../../utils/package-manager");
|
|
45
|
-
// The
|
|
48
|
+
// The migrate orchestrator: drives a durable run one dispense at a time.
|
|
46
49
|
// An outer AI agent runs each dispensed command and re-invokes `nx migrate
|
|
47
50
|
// --run-id=<id>` to reconcile; there is no long-lived process.
|
|
48
51
|
const PLAN_SNAPSHOT_0 = 'plan-0.json';
|
|
@@ -55,7 +58,11 @@ const HANG_THRESHOLD_MS = 15 * 60 * 1000;
|
|
|
55
58
|
const NO_PROGRESS_THRESHOLD = 3;
|
|
56
59
|
// Two rearms per step: one for the diagnosed fix and one for its correction.
|
|
57
60
|
const REARM_ESCALATION_CAP = 2;
|
|
58
|
-
const INIT_CONTINUE_HINT = 're-run the command, or
|
|
61
|
+
const INIT_CONTINUE_HINT = 're-run the command, or re-run it with --agentic=false to use the standard migrate flow.';
|
|
62
|
+
const ID_PROBLEM_REFUSALS = {
|
|
63
|
+
'not-shell-safe': 'contains characters that are not shell-safe. Orchestrated runs require shell-safe migration ids.',
|
|
64
|
+
duplicate: 'is listed more than once in the plan. Orchestrated runs require each migration id once.',
|
|
65
|
+
};
|
|
59
66
|
function continueRunHint(runId) {
|
|
60
67
|
return `re-run the command to continue run '${runId}'.`;
|
|
61
68
|
}
|
|
@@ -92,9 +99,7 @@ function refuseUnsafeScratchExposure(exposure, thenWhat) {
|
|
|
92
99
|
async function runOrchestratorInit(input) {
|
|
93
100
|
const { root, migrationsJson, migrationsPath, createCommits, commitPrefix, skipInstall, installedNxVersion, validate, finalValidation, emitAgentInstructions = true, onExistingRun = 'report', replaceRunId, confirmStart, } = input;
|
|
94
101
|
const migrations = (migrationsJson.migrations ?? []);
|
|
95
|
-
const sorted = (0, sort_migrations_1.sortMigrations)(migrations.slice()
|
|
96
|
-
hoistHandoffGitignore: true,
|
|
97
|
-
});
|
|
102
|
+
const sorted = (0, sort_migrations_1.sortMigrations)(migrations.slice());
|
|
98
103
|
const plannedIds = sorted.map((m) => `${m.package}:${m.name}`);
|
|
99
104
|
// An active run means a prior init already happened (e.g. it crashed before
|
|
100
105
|
// the agent's first reconcile); starting a second run would compete with it,
|
|
@@ -124,13 +129,13 @@ async function runOrchestratorInit(input) {
|
|
|
124
129
|
}
|
|
125
130
|
});
|
|
126
131
|
}
|
|
127
|
-
// Dispensed commands interpolate migration ids verbatim
|
|
128
|
-
// validates the incoming plan's ids. Before
|
|
129
|
-
// not be thrown away for a plan that cannot
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}
|
|
132
|
+
// Dispensed commands interpolate migration ids verbatim and a worker finds
|
|
133
|
+
// its step by id, so every init validates the incoming plan's ids. Before
|
|
134
|
+
// the delete below: a run must not be thrown away for a plan that cannot
|
|
135
|
+
// start.
|
|
136
|
+
const [idProblem] = (0, run_state_1.migrationIdProblems)(sorted);
|
|
137
|
+
if (idProblem !== undefined) {
|
|
138
|
+
throw new Error(`The migration id '${idProblem.id}' ${ID_PROBLEM_REFUSALS[idProblem.problem]} To run the plan without orchestration, re-run with --agentic=false.`);
|
|
134
139
|
}
|
|
135
140
|
if (confirmStart && !(await confirmStart())) {
|
|
136
141
|
return { kind: 'refused' };
|
|
@@ -152,9 +157,8 @@ async function runOrchestratorInit(input) {
|
|
|
152
157
|
// Applied before the checkpoint so the entry (when it can be added) already
|
|
153
158
|
// covers older scratch by the time the checkpoint's `git add -A` runs; the
|
|
154
159
|
// fallback's standalone commit is suppressed because that checkpoint
|
|
155
|
-
// carries the edit.
|
|
156
|
-
//
|
|
157
|
-
// migration runs.
|
|
160
|
+
// carries the edit. A planned ignore migration can't be deferred to: the
|
|
161
|
+
// run dir is created below, before that migration runs.
|
|
158
162
|
await (0, handoff_gitignore_1.applyAgenticHandoffGitignoreFallback)({
|
|
159
163
|
migrations: sorted,
|
|
160
164
|
installedNxVersion,
|
|
@@ -314,11 +318,65 @@ function activeRunToReplace(root, runId) {
|
|
|
314
318
|
function releaseRunToHandOff(root, runId) {
|
|
315
319
|
(0, state_lock_1.releaseRunActivity)((0, run_state_1.runDir)(root, runId));
|
|
316
320
|
}
|
|
321
|
+
/**
|
|
322
|
+
* The active run a classic `--run-migrations` must not run over, held while
|
|
323
|
+
* the caller reports it or asks what to do; null when no run is active. Run
|
|
324
|
+
* directories that cannot be read refuse as they do for init.
|
|
325
|
+
*/
|
|
326
|
+
function activeRunForClassic(root, plannedIds) {
|
|
327
|
+
const active = findActiveRunForInit(root);
|
|
328
|
+
if (!active)
|
|
329
|
+
return null;
|
|
330
|
+
// Held before the facts are read, as init's report does.
|
|
331
|
+
(0, state_lock_1.holdRunActivity)(root, active.runId);
|
|
332
|
+
return {
|
|
333
|
+
runId: active.runId,
|
|
334
|
+
facts: (0, existing_run_report_1.collectExistingRunFacts)(root, active.runId, active.state, plannedIds),
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Throws when a classic start fresh could not delete the active run `runId`.
|
|
339
|
+
* Run before the commit prompt, as init does, so the user is not asked for a
|
|
340
|
+
* run that is then refused; deleteRunForStartFresh repeats the checks.
|
|
341
|
+
*/
|
|
342
|
+
function checkRunForStartFresh(root, runId) {
|
|
343
|
+
(0, state_lock_1.withRunCreationLock)(root, () => {
|
|
344
|
+
const active = activeRunToDelete(root, runId);
|
|
345
|
+
refuseUndeletableRun(root, runId, active.state);
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Deletes the record of the active run `runId` for a classic start fresh,
|
|
350
|
+
* under the refusals init applies before it replaces a run. The classic loop
|
|
351
|
+
* records no run of its own afterwards.
|
|
352
|
+
*/
|
|
353
|
+
function deleteRunForStartFresh(root, runId) {
|
|
354
|
+
const deleted = (0, state_lock_1.withRunCreationLock)(root, () => {
|
|
355
|
+
activeRunToDelete(root, runId);
|
|
356
|
+
return deleteRunRecord(root, runId);
|
|
357
|
+
});
|
|
358
|
+
if (deleted) {
|
|
359
|
+
removeDeletedRunDir(root, runId);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
// Call under the creation lock. A run that became active since the user chose
|
|
363
|
+
// is refused, never deleted in place of the one they saw.
|
|
364
|
+
function activeRunToDelete(root, runId) {
|
|
365
|
+
refuseLiveReservation(root);
|
|
366
|
+
const active = findActiveRunForInit(root, true);
|
|
367
|
+
if (!active) {
|
|
368
|
+
throw new Error(noActiveRunToReplace(runId));
|
|
369
|
+
}
|
|
370
|
+
if (active.runId !== runId) {
|
|
371
|
+
throw new Error(`Not starting fresh: migrate run '${active.runId}' became active while this command was starting. Re-run the command to see it.`);
|
|
372
|
+
}
|
|
373
|
+
return active;
|
|
374
|
+
}
|
|
317
375
|
// Reads the newest active run; null when no run is active. Uninterpretable
|
|
318
376
|
// run dirs refuse a fresh start (one of them could be an active run this
|
|
319
|
-
//
|
|
320
|
-
// unless `refuseUninterpretable`: a start-fresh would delete that run
|
|
321
|
-
// then find only the unreadable ones. NewerRunStateFormatError propagates
|
|
377
|
+
// invocation would compete with) but only warn when a healthy active run is
|
|
378
|
+
// found, unless `refuseUninterpretable`: a start-fresh would delete that run
|
|
379
|
+
// and then find only the unreadable ones. NewerRunStateFormatError propagates
|
|
322
380
|
// from the read.
|
|
323
381
|
function findActiveRunForInit(root, refuseUninterpretable = false) {
|
|
324
382
|
const { active, uninterpretable } = (0, run_state_1.findActiveRun)(root);
|
|
@@ -331,7 +389,7 @@ function findActiveRunForInit(root, refuseUninterpretable = false) {
|
|
|
331
389
|
const details = uninterpretable.map((u) => `${types_1.MIGRATE_RUNS_RELATIVE_DIR}/${(0, text_1.singleLine)(u.dirName)}: ${(0, text_1.singleLine)(u.reason)}`);
|
|
332
390
|
if (!active || refuseUninterpretable) {
|
|
333
391
|
throw new Error([
|
|
334
|
-
`Whether a migrate run is still active could not be determined;
|
|
392
|
+
`Whether a migrate run is still active could not be determined; running the plan could re-apply migrations an unfinished run already applied.`,
|
|
335
393
|
...details,
|
|
336
394
|
`Fix or remove the listed ${noun}, then re-run the command.`,
|
|
337
395
|
].join('\n'));
|
|
@@ -776,6 +834,8 @@ async function runOrchestratorReconcile(input) {
|
|
|
776
834
|
return;
|
|
777
835
|
}
|
|
778
836
|
(0, give_up_1.warnAboutGiveUp)(target, outcome);
|
|
837
|
+
if (target.installFailed === true)
|
|
838
|
+
warnInstallLeftToUser(root, target);
|
|
779
839
|
// Settled already; the dispense refuses a tree still held.
|
|
780
840
|
scope.lease?.release();
|
|
781
841
|
scope.lease = undefined;
|
|
@@ -786,8 +846,9 @@ async function runOrchestratorReconcile(input) {
|
|
|
786
846
|
// sections stay synchronous); the transition and any unrecorded entry then
|
|
787
847
|
// land in one write. Adopt and skip keep the tree, so the install they owe
|
|
788
848
|
// runs here: the next dispense would take the changed deps as its baseline.
|
|
789
|
-
// Giving up keeps it the same way when the run does not commit.
|
|
790
|
-
//
|
|
849
|
+
// Giving up keeps it the same way when the run does not commit. An install
|
|
850
|
+
// that already failed is left to the step's mark instead. Retries owe
|
|
851
|
+
// nothing: the rearmed attempt reconciles itself.
|
|
791
852
|
const { entry, installFailed, recorded } = await stepActionSideEffects(root, dir, state, target, stepAction, result.resetTree, scope);
|
|
792
853
|
// A rearm starts a fresh attempt; drop the stale handoff before the rearm
|
|
793
854
|
// is persisted so a crash in between can't refold the old outcome into the
|
|
@@ -863,6 +924,11 @@ async function runOrchestratorReconcile(input) {
|
|
|
863
924
|
if (unresolvedArchiveError !== undefined) {
|
|
864
925
|
(0, give_up_1.warnUnresolvedNotArchived)((0, state_machine_1.stepLabel)(target), unresolvedArchiveError);
|
|
865
926
|
}
|
|
927
|
+
// A retry's rearm drops the mark: its next attempt installs.
|
|
928
|
+
if (target.installFailed === true &&
|
|
929
|
+
written.steps.find((s) => s.id === target.id)?.installFailed === true) {
|
|
930
|
+
warnInstallLeftToUser(root, target);
|
|
931
|
+
}
|
|
866
932
|
state = written;
|
|
867
933
|
}
|
|
868
934
|
finally {
|
|
@@ -1131,6 +1197,14 @@ async function installFailedForStep(root, dir, state, step, seam, scope) {
|
|
|
1131
1197
|
return true;
|
|
1132
1198
|
}
|
|
1133
1199
|
}
|
|
1200
|
+
function warnInstallLeftToUser(root, step) {
|
|
1201
|
+
(0, agent_output_1.warnToAgent)({
|
|
1202
|
+
title: `The dependency changes made by ${(0, state_machine_1.stepLabel)(step)} are not installed.`,
|
|
1203
|
+
bodyLines: [
|
|
1204
|
+
`Run \`${(0, util_1.pmInstallCommand)(root)}\` once the cause of the failed install is fixed. The run's final report repeats this unless a later install covers them.`,
|
|
1205
|
+
],
|
|
1206
|
+
});
|
|
1207
|
+
}
|
|
1134
1208
|
// A failed handoff fails the prompt; a success handoff completes it, unless it
|
|
1135
1209
|
// marks the prompt not applicable via `extras.outcome === 'skipped'`.
|
|
1136
1210
|
function handoffToPromptOutcome(handoff) {
|
|
@@ -1316,11 +1390,13 @@ function unresolvedResetsTree(state, step, cleanRetry) {
|
|
|
1316
1390
|
async function stepActionSideEffects(root, dir, state, step, action, resetTree, scope) {
|
|
1317
1391
|
switch (action) {
|
|
1318
1392
|
case 'adopt':
|
|
1319
|
-
// A died worker's
|
|
1320
|
-
//
|
|
1321
|
-
// would be replayed.
|
|
1393
|
+
// A died worker's commit request is reused while nothing records its
|
|
1394
|
+
// outcome, since the session may still answer it. Otherwise the adopt
|
|
1395
|
+
// asks under its own request, or the old answer would be replayed.
|
|
1322
1396
|
return state.createCommits
|
|
1323
1397
|
? commitForStep(root, dir, state, step, scope, step.status === 'failed' ||
|
|
1398
|
+
step.commitLedgerIndex !== undefined ||
|
|
1399
|
+
step.installFailed === true ||
|
|
1324
1400
|
(0, state_machine_1.coveringLandedEntries)(state, step.id).length > 0
|
|
1325
1401
|
? 'adopt'
|
|
1326
1402
|
: undefined)
|
|
@@ -1631,6 +1707,7 @@ function emitRetryFailed(root, runId, state, step, noProgress) {
|
|
|
1631
1707
|
` current HEAD: ${head ?? '(unknown)'}`,
|
|
1632
1708
|
` working tree: ${tree === null ? '(unknown)' : tree ? `\n${tree}` : '(clean)'}`,
|
|
1633
1709
|
``,
|
|
1710
|
+
...unfinishedOperationLines(root, state, step),
|
|
1634
1711
|
retryBudgetLine(step, committed),
|
|
1635
1712
|
``,
|
|
1636
1713
|
`Decide how to proceed and re-run reconcile with one of:`,
|
|
@@ -1641,11 +1718,15 @@ function emitRetryFailed(root, runId, state, step, noProgress) {
|
|
|
1641
1718
|
if (cleanRetry && !capReached) {
|
|
1642
1719
|
lines.push(` retry-clean: reset the tree to ${step.gitRefBefore ?? 'the pre-migration ref'} (discarding its uncommitted tracked changes and the untracked files git does not ignore, ${types_1.MIGRATE_RUNS_RELATIVE_DIR} kept) and retry from that clean state by running: ${reconcileCommand(root, runId, 'retry-clean')}`);
|
|
1643
1720
|
}
|
|
1721
|
+
// A failed commit is already named above the choices.
|
|
1722
|
+
const adoptWhen = recordedCommitFailed(state, step)
|
|
1723
|
+
? ''
|
|
1724
|
+
: committed
|
|
1725
|
+
? `a commit of this ${(0, state_machine_1.stepNoun)(step)}'s changes was started and never recorded; `
|
|
1726
|
+
: `the ${(0, state_machine_1.stepNoun)(step)} was ${step.kind === 'migration' ? 'applied' : 'done'} by hand; `;
|
|
1644
1727
|
lines.push(landed
|
|
1645
1728
|
? ` adopt: keep the landed commit${landed.sha ? ` ${landed.sha}` : ''} and the current working-tree state as the ${(0, state_machine_1.stepNoun)(step)}'s result, then run: ${reconcileCommand(root, runId, 'adopt')}`
|
|
1646
|
-
: ` adopt: ${
|
|
1647
|
-
? `a commit of this ${(0, state_machine_1.stepNoun)(step)}'s changes was started and never recorded`
|
|
1648
|
-
: `the ${(0, state_machine_1.stepNoun)(step)} was ${step.kind === 'migration' ? 'applied' : 'done'} by hand`}; keep the current working-tree state as its result, then run: ${reconcileCommand(root, runId, 'adopt')}`);
|
|
1729
|
+
: ` adopt: ${adoptWhen}keep the current working-tree state as its result, then run: ${reconcileCommand(root, runId, 'adopt')}`);
|
|
1649
1730
|
// Refused by the state machine: the migration is, or may be, committed.
|
|
1650
1731
|
if (!committed) {
|
|
1651
1732
|
lines.push(` skip: ${reconcileCommand(root, runId, 'skip')}`, unresolvedOptionLine(root, runId, state, step, unresolvedResetsTree(state, step, cleanRetry)));
|
|
@@ -1677,6 +1758,26 @@ function retryBudgetLine(step, committed) {
|
|
|
1677
1758
|
? `adopt only once you have inspected the tree and finished the ${(0, state_machine_1.stepNoun)(step)}; otherwise stop and report`
|
|
1678
1759
|
: 'give the step up with unresolved and continue'}.`;
|
|
1679
1760
|
}
|
|
1761
|
+
// A recorded failed commit with the mark standing withdraws skip and
|
|
1762
|
+
// unresolved, so every choice left commits.
|
|
1763
|
+
function unfinishedOperationLines(root, state, step) {
|
|
1764
|
+
const lines = [];
|
|
1765
|
+
if (step.installFailed === true) {
|
|
1766
|
+
lines.push(`Its dependency install did not complete. A retry runs it again, so fix the cause first if it can be fixed. Any other choice settles the step without installing and leaves the install to you; the run's final report asks for \`${(0, util_1.pmInstallCommand)(root)}\`.`, ``);
|
|
1767
|
+
}
|
|
1768
|
+
if (recordedCommitFailed(state, step)) {
|
|
1769
|
+
lines.push(`Its commit did not complete. Every choice below commits again.`, ``);
|
|
1770
|
+
}
|
|
1771
|
+
return lines;
|
|
1772
|
+
}
|
|
1773
|
+
function recordedCommitFailed(state, step) {
|
|
1774
|
+
// Not commitReceipt, which throws on an index the ledger lacks: a dispense
|
|
1775
|
+
// has to render whatever run.json holds.
|
|
1776
|
+
const receipt = step.commitLedgerIndex === undefined
|
|
1777
|
+
? undefined
|
|
1778
|
+
: state.commits[step.commitLedgerIndex];
|
|
1779
|
+
return step.commitStarted === true && receipt?.kind === 'failed';
|
|
1780
|
+
}
|
|
1680
1781
|
// Opens a capped dispense and is the reason a retry past the cap is refused.
|
|
1681
1782
|
function rearmCapLine(step, committed) {
|
|
1682
1783
|
return `This ${(0, state_machine_1.stepNoun)(step)} has already been retried ${step.attempt - 1} times without completing, and no further retry is accepted. ${committed
|
|
@@ -1776,6 +1877,7 @@ function emitDied(root, runId, state, step, noProgress) {
|
|
|
1776
1877
|
` current HEAD: ${head ?? '(unknown)'}`,
|
|
1777
1878
|
` working tree: ${tree === null ? '(unknown)' : tree ? `\n${tree}` : '(clean)'}`,
|
|
1778
1879
|
``,
|
|
1880
|
+
...unfinishedOperationLines(root, state, step),
|
|
1779
1881
|
retryBudgetLine(step, committed),
|
|
1780
1882
|
``,
|
|
1781
1883
|
];
|
|
@@ -1810,9 +1912,19 @@ function emitDied(root, runId, state, step, noProgress) {
|
|
|
1810
1912
|
}, noProgress);
|
|
1811
1913
|
}
|
|
1812
1914
|
function emitHeld(root, runId, state, step, held, noProgress) {
|
|
1915
|
+
const heldStep = state.steps.find((s) => s.id === held.stepId);
|
|
1916
|
+
const heldStepName = heldStep && (0, state_machine_1.stepLabel)(heldStep);
|
|
1813
1917
|
emit(root, runId, state, step, 'held', {
|
|
1814
1918
|
next: reconcileCommand(root, runId),
|
|
1815
|
-
instructionLines: [
|
|
1919
|
+
instructionLines: [
|
|
1920
|
+
(0, broker_1.treeBusyMessage)(held, heldStepName),
|
|
1921
|
+
// Quitting this session frees the terminal only for its own parent.
|
|
1922
|
+
...(held.owner === process.env[broker_1.BROKER_ENV_VAR]
|
|
1923
|
+
? [
|
|
1924
|
+
`If it seems stuck, the user can ${(0, broker_1.sessionOperationWayOut)((0, broker_1.treeOperationLabel)(held, heldStepName))}.`,
|
|
1925
|
+
]
|
|
1926
|
+
: []),
|
|
1927
|
+
],
|
|
1816
1928
|
}, noProgress);
|
|
1817
1929
|
}
|
|
1818
1930
|
function emitStillRunning(root, runId, state, step, held, noProgress) {
|
|
@@ -1830,7 +1942,7 @@ function emitStillRunning(root, runId, state, step, held, noProgress) {
|
|
|
1830
1942
|
if (ageMs >= HANG_THRESHOLD_MS) {
|
|
1831
1943
|
const hung = `It has been running for ${Math.floor(ageMs / 60000)} minutes and may be hung.`;
|
|
1832
1944
|
lines.push(parentOperation
|
|
1833
|
-
? `${hung} Report this to the user: they can
|
|
1945
|
+
? `${hung} Report this to the user: they can ${(0, broker_1.sessionOperationWayOut)(parentOperation)}.`
|
|
1834
1946
|
: `${hung} Verify pid ${step.pid}; either keep waiting, or kill it so the next reconcile can classify it as died.`);
|
|
1835
1947
|
}
|
|
1836
1948
|
emit(root, runId, state, step, 'still-running', {
|
|
@@ -2074,14 +2186,19 @@ function completionWarnings(root, runId, state) {
|
|
|
2074
2186
|
// fact absorbed; suppress the warning only on a verified-clean tree. A dirty
|
|
2075
2187
|
// tree can still be unrelated edits, so the warning only claims the changes
|
|
2076
2188
|
// "may remain".
|
|
2077
|
-
const
|
|
2189
|
+
const debtStepIds = (0, state_machine_1.uncoveredFailedStepIds)(state);
|
|
2190
|
+
const uncommitted = debtStepIds.length > 0 && (0, git_utils_1.getWorkingTreeStatus)(root) !== 'clean'
|
|
2191
|
+
? state.steps.filter((s) => debtStepIds.includes(s.id))
|
|
2192
|
+
: [];
|
|
2078
2193
|
const uninstalled = state.steps.filter((s) => s.installFailed);
|
|
2079
2194
|
const issueLines = (0, issues_1.renderUnresolvedIssueLines)(state, runId);
|
|
2080
2195
|
return [
|
|
2081
|
-
...(
|
|
2196
|
+
...(uncommitted.length > 0
|
|
2082
2197
|
? [
|
|
2083
2198
|
[
|
|
2084
|
-
|
|
2199
|
+
`The changes made by ${uncommitted
|
|
2200
|
+
.map(state_machine_1.stepLabel)
|
|
2201
|
+
.join(', ')} could not be committed and may remain in the working tree; review and commit them manually.`,
|
|
2085
2202
|
],
|
|
2086
2203
|
]
|
|
2087
2204
|
: []),
|
|
@@ -9,6 +9,19 @@ export declare const RUN_STATE_FILE_NAME = "run.json";
|
|
|
9
9
|
* with fails closed as corrupt instead of being dispensed.
|
|
10
10
|
*/
|
|
11
11
|
export declare const SHELL_SAFE_VALUE: RegExp;
|
|
12
|
+
export type MigrationIdProblem = 'not-shell-safe' | 'duplicate';
|
|
13
|
+
/**
|
|
14
|
+
* The ids of `migrations` that no orchestrated run can take, each once, in the
|
|
15
|
+
* order found. A worker finds its step by migration id, so an id the plan
|
|
16
|
+
* lists twice can't name one step.
|
|
17
|
+
*/
|
|
18
|
+
export declare function migrationIdProblems(migrations: ReadonlyArray<{
|
|
19
|
+
package: string;
|
|
20
|
+
name: string;
|
|
21
|
+
}>): {
|
|
22
|
+
id: string;
|
|
23
|
+
problem: MigrationIdProblem;
|
|
24
|
+
}[];
|
|
12
25
|
export declare const ISSUE_ID: RegExp;
|
|
13
26
|
declare const MIGRATE_RUN_STATUSES: readonly ['active', 'completed'];
|
|
14
27
|
export type MigrateRunStatus = (typeof MIGRATE_RUN_STATUSES)[number];
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.NewerRunStateFormatError = exports.TREE_OPERATION_KINDS = exports.MIGRATE_ISSUE_DISPOSITIONS = exports.TERMINAL_STEP_STATUSES = exports.ISSUE_ID = exports.SHELL_SAFE_VALUE = exports.RUN_STATE_FILE_NAME = exports.CURRENT_RUN_STATE_FORMAT_VERSION = void 0;
|
|
4
|
+
exports.migrationIdProblems = migrationIdProblems;
|
|
4
5
|
exports.issueFingerprint = issueFingerprint;
|
|
5
6
|
exports.migrateRunsDir = migrateRunsDir;
|
|
6
7
|
exports.runDir = runDir;
|
|
@@ -32,6 +33,26 @@ exports.RUN_STATE_FILE_NAME = 'run.json';
|
|
|
32
33
|
* with fails closed as corrupt instead of being dispensed.
|
|
33
34
|
*/
|
|
34
35
|
exports.SHELL_SAFE_VALUE = /^[A-Za-z0-9@/:._-]+$/;
|
|
36
|
+
/**
|
|
37
|
+
* The ids of `migrations` that no orchestrated run can take, each once, in the
|
|
38
|
+
* order found. A worker finds its step by migration id, so an id the plan
|
|
39
|
+
* lists twice can't name one step.
|
|
40
|
+
*/
|
|
41
|
+
function migrationIdProblems(migrations) {
|
|
42
|
+
const seen = new Set();
|
|
43
|
+
const problems = new Map();
|
|
44
|
+
for (const m of migrations) {
|
|
45
|
+
const id = `${m.package}:${m.name}`;
|
|
46
|
+
if (!exports.SHELL_SAFE_VALUE.test(id)) {
|
|
47
|
+
problems.set(id, 'not-shell-safe');
|
|
48
|
+
}
|
|
49
|
+
else if (seen.has(id) && !problems.has(id)) {
|
|
50
|
+
problems.set(id, 'duplicate');
|
|
51
|
+
}
|
|
52
|
+
seen.add(id);
|
|
53
|
+
}
|
|
54
|
+
return [...problems].map(([id, problem]) => ({ id, problem }));
|
|
55
|
+
}
|
|
35
56
|
// `new Date().toISOString()`, the only shape Nx writes. Retention and active-run
|
|
36
57
|
// selection compare these lexicographically, and the value is rendered into the
|
|
37
58
|
// stdout the agent scans for blocks, so neither a different notation nor an
|
|
@@ -76,6 +76,25 @@ function renderRunbook(ctx) {
|
|
|
76
76
|
`already active. Show its report to the user and let them choose between`,
|
|
77
77
|
`the two commands it lists; do not choose for them.`,
|
|
78
78
|
``,
|
|
79
|
+
`## Long-running commands`,
|
|
80
|
+
``,
|
|
81
|
+
`A worker or \`next\` command can wait for minutes on a dependency install`,
|
|
82
|
+
`or a commit. When Nx started this session, the nx process that started it`,
|
|
83
|
+
`runs them, and the waiting command prints an \`[nx]\` line after 15`,
|
|
84
|
+
`seconds and then once a minute: what nx is running and for how long.`,
|
|
85
|
+
``,
|
|
86
|
+
`- If your shell tool can run a command in the background, start worker and`,
|
|
87
|
+
` \`next\` commands that way and check their output about once a minute.`,
|
|
88
|
+
` Each time, tell the user in one sentence what the latest \`[nx]\` line`,
|
|
89
|
+
` says.`,
|
|
90
|
+
`- Claude Code: start each worker and \`next\` command with`,
|
|
91
|
+
` \`run_in_background\`, then start a Monitor on its output that passes`,
|
|
92
|
+
` \`[nx]\` lines through. A \`next\` command can wait as long as a worker.`,
|
|
93
|
+
`- Stopping a worker or \`next\` command does not stop the install or the`,
|
|
94
|
+
` commit it waits on. If one seems stuck, tell the user they can quit this`,
|
|
95
|
+
` session, then press Ctrl+C in the terminal to end it, and resume the run`,
|
|
96
|
+
` afterwards.`,
|
|
97
|
+
``,
|
|
79
98
|
`## Agent work`,
|
|
80
99
|
``,
|
|
81
100
|
`Some steps hand work back to you:`,
|
|
@@ -231,7 +231,10 @@ function applyStepAction(state, index, step, action) {
|
|
|
231
231
|
};
|
|
232
232
|
}
|
|
233
233
|
function workerDiedSummary(step) {
|
|
234
|
-
|
|
234
|
+
const worker = `the worker process${step.pid === undefined ? '' : ` (pid ${step.pid})`}`;
|
|
235
|
+
return step.installFailed === true
|
|
236
|
+
? `its dependency install did not complete, and ${worker} died`
|
|
237
|
+
: `${worker} died before recording an outcome`;
|
|
235
238
|
}
|
|
236
239
|
// Re-arms for a retry that resets the tree first. The reset target predates
|
|
237
240
|
// the generator unless a commit of this step's own already carries it, so the
|
|
@@ -28,6 +28,9 @@ export declare function depsHash(root: string): string | null;
|
|
|
28
28
|
* dispense-time probe failed has no baseline, which says the dependencies it
|
|
29
29
|
* started from are unknown rather than unchanged, and skipping there would
|
|
30
30
|
* strand the change with nothing left to detect it.
|
|
31
|
+
*
|
|
32
|
+
* A failed or died step whose install already failed settles without it, so
|
|
33
|
+
* the settle cannot hang on that install again. A retry's rearm drops the mark.
|
|
31
34
|
*/
|
|
32
35
|
export declare function installDepsChangedSinceDispense(root: string, dir: string, step: MigrateStep, skipInstall: boolean, rerunCommand?: string, sink?: MigrateOutputSink): Promise<void>;
|
|
33
36
|
/**
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// Internal to run/: deliberately not re-exported from ./index.
|
|
3
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
3
|
exports.nowIso = nowIso;
|
|
5
4
|
exports.depsHash = depsHash;
|
|
@@ -51,8 +50,15 @@ function depsHash(root) {
|
|
|
51
50
|
* dispense-time probe failed has no baseline, which says the dependencies it
|
|
52
51
|
* started from are unknown rather than unchanged, and skipping there would
|
|
53
52
|
* strand the change with nothing left to detect it.
|
|
53
|
+
*
|
|
54
|
+
* A failed or died step whose install already failed settles without it, so
|
|
55
|
+
* the settle cannot hang on that install again. A retry's rearm drops the mark.
|
|
54
56
|
*/
|
|
55
57
|
async function installDepsChangedSinceDispense(root, dir, step, skipInstall, rerunCommand, sink) {
|
|
58
|
+
if (step.installFailed === true &&
|
|
59
|
+
(step.status === 'failed' || step.status === 'died')) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
56
62
|
const current = depsHash(root);
|
|
57
63
|
if (current !== null && current === step.depsHashAtDispense)
|
|
58
64
|
return;
|
|
@@ -5,12 +5,6 @@ interface SortableMigration {
|
|
|
5
5
|
}
|
|
6
6
|
/**
|
|
7
7
|
* Sorts in place (like `Array.prototype.sort`) and returns the same array.
|
|
8
|
-
*
|
|
9
|
-
* `hoistHandoffGitignore` is set for agentic runs, which write scratch under
|
|
10
|
-
* `.nx/migrate-runs`; see `agentic/handoff-gitignore.ts` for why the v23
|
|
11
|
-
* gitignore migration must run first there.
|
|
12
8
|
*/
|
|
13
|
-
export declare function sortMigrations<T extends SortableMigration>(migrations: T[]
|
|
14
|
-
hoistHandoffGitignore: boolean;
|
|
15
|
-
}): T[];
|
|
9
|
+
export declare function sortMigrations<T extends SortableMigration>(migrations: T[]): T[];
|
|
16
10
|
export {};
|
|
@@ -2,23 +2,12 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.sortMigrations = sortMigrations;
|
|
4
4
|
const semver_1 = require("semver");
|
|
5
|
-
const types_1 = require("./agentic/types");
|
|
6
5
|
const version_utils_1 = require("./version-utils");
|
|
7
6
|
/**
|
|
8
7
|
* Sorts in place (like `Array.prototype.sort`) and returns the same array.
|
|
9
|
-
*
|
|
10
|
-
* `hoistHandoffGitignore` is set for agentic runs, which write scratch under
|
|
11
|
-
* `.nx/migrate-runs`; see `agentic/handoff-gitignore.ts` for why the v23
|
|
12
|
-
* gitignore migration must run first there.
|
|
13
8
|
*/
|
|
14
|
-
function sortMigrations(migrations
|
|
9
|
+
function sortMigrations(migrations) {
|
|
15
10
|
return migrations.sort((a, b) => {
|
|
16
|
-
if (opts.hoistHandoffGitignore) {
|
|
17
|
-
if ((0, types_1.isHandoffGitignoreMigration)(a))
|
|
18
|
-
return -1;
|
|
19
|
-
if ((0, types_1.isHandoffGitignoreMigration)(b))
|
|
20
|
-
return 1;
|
|
21
|
-
}
|
|
22
11
|
if (a.name === '15-7-0-split-configuration-into-project-json-files') {
|
|
23
12
|
return -1;
|
|
24
13
|
}
|
|
@@ -126,7 +126,7 @@ function resolveTaskGraphDependencies(graph, extraTargetDeps, projectName, targe
|
|
|
126
126
|
const directDeps = [
|
|
127
127
|
...(taskGraph.dependencies[rootId] ?? []),
|
|
128
128
|
...(taskGraph.continuousDependencies[rootId] ?? []),
|
|
129
|
-
];
|
|
129
|
+
].map((edge) => edge.id);
|
|
130
130
|
const directDepSet = new Set(directDeps);
|
|
131
131
|
const depSourceIndices = directDeps.map((depTaskId) => {
|
|
132
132
|
const task = taskGraph.tasks[depTaskId];
|
|
@@ -711,7 +711,9 @@ export interface NxSyncConfiguration {
|
|
|
711
711
|
export interface NxMigrateConfiguration {
|
|
712
712
|
/**
|
|
713
713
|
* Whether to automatically create a git commit after each migration runs.
|
|
714
|
-
* Equivalent to the `--create-commits` flag. Defaults to `
|
|
714
|
+
* Equivalent to the `--create-commits` flag. Defaults to `true` when the
|
|
715
|
+
* agentic flow runs the migrations in a Git repository, and `false`
|
|
716
|
+
* otherwise.
|
|
715
717
|
*/
|
|
716
718
|
createCommits?: boolean;
|
|
717
719
|
/**
|
|
@@ -753,11 +755,18 @@ export interface NxMigrateConfiguration {
|
|
|
753
755
|
*/
|
|
754
756
|
agentic?: boolean | AgentId;
|
|
755
757
|
/**
|
|
756
|
-
* Whether
|
|
757
|
-
*
|
|
758
|
-
*
|
|
758
|
+
* Whether the AI agent driving a migrate run reviews the changes of
|
|
759
|
+
* generator-only migrations. Equivalent to the `--validate` flag. Defaults to
|
|
760
|
+
* `true`.
|
|
759
761
|
*/
|
|
760
762
|
validate?: boolean;
|
|
763
|
+
/**
|
|
764
|
+
* Whether a migrate run an AI agent drives ends with a final check, where the
|
|
765
|
+
* agent makes sure the projects the run touched still lint, build, and pass
|
|
766
|
+
* their unit tests. Equivalent to the `--final-validation` flag. Defaults to
|
|
767
|
+
* `true`.
|
|
768
|
+
*/
|
|
769
|
+
finalValidation?: boolean;
|
|
761
770
|
}
|
|
762
771
|
/**
|
|
763
772
|
* Nx.json configuration
|
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
* `packages/nx/src/native/tasks/types.rs` and exposed to TypeScript via NAPI.
|
|
4
4
|
* This file re-exports them so existing imports keep working.
|
|
5
5
|
*/
|
|
6
|
-
export type { Task, TaskGraph, TaskTarget, TaskHashDetails, TaskUltracacheSettings, } from '../native';
|
|
6
|
+
export type { Task, TaskGraph, TaskGraphEdge, TaskTarget, TaskHashDetails, TaskUltracacheSettings, } from '../native';
|
|
@@ -163,6 +163,54 @@ export type Spreadable<T> = T & {
|
|
|
163
163
|
* permits `'...'`, which target merging resolves away.
|
|
164
164
|
*/
|
|
165
165
|
export type TargetUltracacheSettings = Spreadable<TaskUltracacheSettings>;
|
|
166
|
+
export interface ReadyWhenOptions {
|
|
167
|
+
/**
|
|
168
|
+
* Milliseconds to wait for readiness before failing dependents that wait
|
|
169
|
+
* for it. Default is 60000.
|
|
170
|
+
*/
|
|
171
|
+
timeout?: number;
|
|
172
|
+
/**
|
|
173
|
+
* Milliseconds between probe attempts. By default attempts back off from
|
|
174
|
+
* 100 to 1000 milliseconds. Unused by `logMatches`.
|
|
175
|
+
*/
|
|
176
|
+
interval?: number;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Readiness probe of a continuous target. Exactly one of `url`, `port`,
|
|
180
|
+
* `command` or `logMatches` must be set. Strings may use the `{workspaceRoot}`,
|
|
181
|
+
* `{projectRoot}`, `{projectName}` and `{options.*}` placeholders, resolved
|
|
182
|
+
* against the options the task runs with.
|
|
183
|
+
*/
|
|
184
|
+
export type ReadyWhen = ({
|
|
185
|
+
/**
|
|
186
|
+
* Ready when an HTTP or HTTPS GET gets a status from 200 to 403. A
|
|
187
|
+
* redirect counts as ready and is not followed.
|
|
188
|
+
*/
|
|
189
|
+
url: string;
|
|
190
|
+
} & ReadyWhenOptions) | ({
|
|
191
|
+
/**
|
|
192
|
+
* Ready when a TCP connection to the port succeeds. A string must
|
|
193
|
+
* resolve to a port number through a placeholder such as
|
|
194
|
+
* `{options.port}`.
|
|
195
|
+
*/
|
|
196
|
+
port: number | string;
|
|
197
|
+
/**
|
|
198
|
+
* Host to connect to. By default 127.0.0.1 and ::1 are both tried.
|
|
199
|
+
*/
|
|
200
|
+
host?: string;
|
|
201
|
+
} & ReadyWhenOptions) | ({
|
|
202
|
+
/**
|
|
203
|
+
* Ready when the command, run through the shell at the workspace root,
|
|
204
|
+
* exits with code 0.
|
|
205
|
+
*/
|
|
206
|
+
command: string;
|
|
207
|
+
} & ReadyWhenOptions) | ({
|
|
208
|
+
/**
|
|
209
|
+
* Ready when every one of these substrings has appeared in the task's
|
|
210
|
+
* output.
|
|
211
|
+
*/
|
|
212
|
+
logMatches: string | string[];
|
|
213
|
+
} & ReadyWhenOptions);
|
|
166
214
|
export interface TargetDependencyConfig {
|
|
167
215
|
/**
|
|
168
216
|
* A list of projects that have `target`.
|
|
@@ -192,22 +240,40 @@ export interface TargetDependencyConfig {
|
|
|
192
240
|
* target's hash. It still runs first. Has no effect on other dependencies.
|
|
193
241
|
*/
|
|
194
242
|
inputs?: boolean;
|
|
243
|
+
/**
|
|
244
|
+
* When the dependency is a continuous task, whether this target waits for
|
|
245
|
+
* it to have started (default) or to be ready per its `readyWhen`.
|
|
246
|
+
* Ignored when the dependency is not continuous or declares no `readyWhen`.
|
|
247
|
+
*/
|
|
248
|
+
waitFor?: 'started' | 'ready';
|
|
195
249
|
}
|
|
250
|
+
/**
|
|
251
|
+
* `always`: the files the input resolves to stay in the hash even when the task
|
|
252
|
+
* is hashed from its ultracache recording.
|
|
253
|
+
* `dependencies` with `projects`: the selected projects' dependencies (as `^input`
|
|
254
|
+
* resolves for each), not the projects themselves.
|
|
255
|
+
*/
|
|
196
256
|
export type InputDefinition = {
|
|
197
257
|
input: string;
|
|
198
258
|
projects: string | string[];
|
|
259
|
+
dependencies?: boolean;
|
|
260
|
+
always?: boolean;
|
|
199
261
|
} | {
|
|
200
262
|
input: string;
|
|
201
263
|
dependencies: true;
|
|
264
|
+
always?: boolean;
|
|
202
265
|
} | {
|
|
203
266
|
input: string;
|
|
267
|
+
always?: boolean;
|
|
204
268
|
} | {
|
|
205
269
|
fileset: string;
|
|
206
270
|
includeIgnored?: boolean;
|
|
271
|
+
always?: boolean;
|
|
207
272
|
} | {
|
|
208
273
|
fileset: string;
|
|
209
274
|
dependencies: true;
|
|
210
275
|
includeIgnored?: boolean;
|
|
276
|
+
always?: boolean;
|
|
211
277
|
} | {
|
|
212
278
|
runtime: string;
|
|
213
279
|
} | {
|
|
@@ -282,6 +348,12 @@ export interface TargetConfiguration<T = any> {
|
|
|
282
348
|
* Whether this target runs continuously
|
|
283
349
|
*/
|
|
284
350
|
continuous?: boolean;
|
|
351
|
+
/**
|
|
352
|
+
* How Nx detects that this continuous target is ready. Only honored when
|
|
353
|
+
* `continuous` is true; dependents opt in with `waitFor: 'ready'` on their
|
|
354
|
+
* `dependsOn` entry.
|
|
355
|
+
*/
|
|
356
|
+
readyWhen?: ReadyWhen;
|
|
285
357
|
/**
|
|
286
358
|
* List of generators to run before the target to ensure the workspace
|
|
287
359
|
* is up to date.
|