nx 23.2.0-beta.4 → 23.2.0-beta.6

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 (120) hide show
  1. package/dist/bin/nx.js +1 -0
  2. package/dist/src/command-line/affected/affected.js +1 -0
  3. package/dist/src/command-line/configure-ai-agents/configure-ai-agents.js +2 -2
  4. package/dist/src/command-line/init/init-v2.js +2 -2
  5. package/dist/src/command-line/migrate/agentic/definitions.js +2 -2
  6. package/dist/src/command-line/migrate/agentic/handoff-gitignore.d.ts +15 -19
  7. package/dist/src/command-line/migrate/agentic/handoff-gitignore.js +19 -31
  8. package/dist/src/command-line/migrate/agentic/handoff.d.ts +4 -6
  9. package/dist/src/command-line/migrate/agentic/handoff.js +9 -8
  10. package/dist/src/command-line/migrate/agentic/print-dropped-agent-context.d.ts +7 -12
  11. package/dist/src/command-line/migrate/agentic/print-dropped-agent-context.js +7 -0
  12. package/dist/src/command-line/migrate/agentic/run-step.d.ts +10 -0
  13. package/dist/src/command-line/migrate/agentic/select.d.ts +10 -2
  14. package/dist/src/command-line/migrate/agentic/select.js +10 -2
  15. package/dist/src/command-line/migrate/agentic/types.d.ts +17 -3
  16. package/dist/src/command-line/migrate/agentic/types.js +26 -0
  17. package/dist/src/command-line/migrate/command-object.d.ts +3 -0
  18. package/dist/src/command-line/migrate/command-object.js +6 -1
  19. package/dist/src/command-line/migrate/execute-migration.d.ts +14 -9
  20. package/dist/src/command-line/migrate/execute-migration.js +82 -18
  21. package/dist/src/command-line/migrate/migrate-analytics.d.ts +7 -0
  22. package/dist/src/command-line/migrate/migrate-analytics.js +14 -0
  23. package/dist/src/command-line/migrate/migrate-commits.d.ts +32 -8
  24. package/dist/src/command-line/migrate/migrate-commits.js +77 -9
  25. package/dist/src/command-line/migrate/migrate-config.d.ts +11 -12
  26. package/dist/src/command-line/migrate/migrate-config.js +14 -14
  27. package/dist/src/command-line/migrate/migrate-output.d.ts +45 -7
  28. package/dist/src/command-line/migrate/migrate-output.js +52 -8
  29. package/dist/src/command-line/migrate/migrate-ui-api.d.ts +2 -1
  30. package/dist/src/command-line/migrate/migrate-ui-api.js +16 -7
  31. package/dist/src/command-line/migrate/migrate.d.ts +17 -68
  32. package/dist/src/command-line/migrate/migrate.js +411 -229
  33. package/dist/src/command-line/migrate/migration-shape.d.ts +8 -0
  34. package/dist/src/command-line/migrate/run/index.d.ts +2 -0
  35. package/dist/src/command-line/migrate/run/index.js +5 -0
  36. package/dist/src/command-line/migrate/run/util.d.ts +1 -0
  37. package/dist/src/command-line/migrate/run/util.js +16 -0
  38. package/dist/src/command-line/migrate/run/worker.d.ts +15 -0
  39. package/dist/src/command-line/migrate/run/worker.js +419 -0
  40. package/dist/src/command-line/migrate/run-migration-process.js +6 -5
  41. package/dist/src/command-line/migrate/sort-migrations.d.ts +16 -0
  42. package/dist/src/command-line/migrate/sort-migrations.js +32 -0
  43. package/dist/src/command-line/migrate/version-skew-guard.d.ts +58 -0
  44. package/dist/src/command-line/migrate/version-skew-guard.js +155 -0
  45. package/dist/src/command-line/nx-cloud/start-nx-agents/command-object.d.ts +2 -0
  46. package/dist/src/command-line/nx-cloud/start-nx-agents/command-object.js +16 -0
  47. package/dist/src/command-line/nx-cloud/start-nx-agents/start-nx-agents.d.ts +4 -0
  48. package/dist/src/command-line/nx-cloud/start-nx-agents/start-nx-agents.js +13 -0
  49. package/dist/src/command-line/nx-commands.js +26 -24
  50. package/dist/src/command-line/release/changelog.js +5 -0
  51. package/dist/src/command-line/release/utils/git.js +1 -1
  52. package/dist/src/command-line/release/utils/release-graph.d.ts +1 -0
  53. package/dist/src/command-line/release/utils/release-graph.js +15 -3
  54. package/dist/src/command-line/release/version/version-actions.d.ts +8 -0
  55. package/dist/src/command-line/release/version/version-actions.js +8 -0
  56. package/dist/src/command-line/release/version.js +9 -5
  57. package/dist/src/command-line/reset/reset.js +6 -1
  58. package/dist/src/command-line/run/run-one.js +1 -0
  59. package/dist/src/command-line/run-many/run-many.js +1 -0
  60. package/dist/src/config/misc-interfaces.d.ts +19 -7
  61. package/dist/src/core/graph/main.js +1 -1
  62. package/dist/src/core/graph/styles.js +1 -1
  63. package/dist/src/daemon/client/client.d.ts +45 -1
  64. package/dist/src/daemon/client/client.js +128 -32
  65. package/dist/src/daemon/client/daemon-socket-messenger.js +4 -0
  66. package/dist/src/daemon/message-types/daemon-message.d.ts +32 -0
  67. package/dist/src/daemon/message-types/daemon-message.js +25 -0
  68. package/dist/src/daemon/server/latest-nx.js +5 -2
  69. package/dist/src/daemon/server/server.js +22 -0
  70. package/dist/src/daemon/server/shutdown-utils.d.ts +5 -0
  71. package/dist/src/daemon/server/shutdown-utils.js +11 -4
  72. package/dist/src/daemon/socket-utils.d.ts +1 -0
  73. package/dist/src/daemon/socket-utils.js +24 -3
  74. package/dist/src/daemon/tmp-dir.d.ts +43 -3
  75. package/dist/src/daemon/tmp-dir.js +437 -15
  76. package/dist/src/devkit-internals.d.ts +92 -3
  77. package/dist/src/devkit-internals.js +189 -5
  78. package/dist/src/generators/internal-utils/format-changed-files-with-prettier-if-available.d.ts +5 -0
  79. package/dist/src/generators/internal-utils/format-changed-files-with-prettier-if-available.js +9 -2
  80. package/dist/src/generators/tree.d.ts +4 -2
  81. package/dist/src/native/index.d.ts +10 -0
  82. package/dist/src/native/index.js +71 -28
  83. package/dist/src/native/native-bindings.js +1 -0
  84. package/dist/src/native/native-file-cache-location.d.ts +17 -1
  85. package/dist/src/native/native-file-cache-location.js +86 -12
  86. package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
  87. package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
  88. package/dist/src/nx-cloud/utilities/get-cloud-options.js +5 -2
  89. package/dist/src/nx-cloud/utilities/onboarding.js +5 -2
  90. package/dist/src/nx-cloud/utilities/url-shorten.d.ts +1 -4
  91. package/dist/src/nx-cloud/utilities/url-shorten.js +9 -8
  92. package/dist/src/plugins/js/lock-file/project-graph-pruning.js +14 -8
  93. package/dist/src/plugins/js/project-graph/build-dependencies/target-project-locator.js +2 -0
  94. package/dist/src/project-graph/affected/affected-project-graph-models.d.ts +1 -1
  95. package/dist/src/project-graph/affected/affected-project-graph.d.ts +1 -1
  96. package/dist/src/project-graph/affected/affected-project-graph.js +2 -2
  97. package/dist/src/project-graph/affected/locators/project-glob-changes.js +5 -2
  98. package/dist/src/project-graph/plugins/isolation/isolated-plugin.d.ts +1 -0
  99. package/dist/src/project-graph/plugins/isolation/isolated-plugin.js +18 -1
  100. package/dist/src/project-graph/plugins/isolation/messaging.d.ts +16 -3
  101. package/dist/src/project-graph/plugins/isolation/messaging.js +3 -0
  102. package/dist/src/project-graph/plugins/isolation/plugin-worker.js +58 -8
  103. package/dist/src/project-graph/project-graph.js +20 -0
  104. package/dist/src/tasks-runner/life-cycles/performance-report.d.ts +12 -0
  105. package/dist/src/tasks-runner/life-cycles/performance-report.js +62 -3
  106. package/dist/src/tasks-runner/run-command.js +4 -0
  107. package/dist/src/utils/assert-workspace-validity.js +7 -2
  108. package/dist/src/utils/child-process.d.ts +31 -1
  109. package/dist/src/utils/child-process.js +103 -0
  110. package/dist/src/utils/ignore.d.ts +128 -1
  111. package/dist/src/utils/ignore.js +182 -12
  112. package/dist/src/utils/nx-tmp-dir.d.ts +18 -0
  113. package/dist/src/utils/nx-tmp-dir.js +40 -0
  114. package/dist/src/utils/owned-private-dir.d.ts +132 -0
  115. package/dist/src/utils/owned-private-dir.js +323 -0
  116. package/dist/src/utils/shell-quoting.d.ts +15 -0
  117. package/dist/src/utils/shell-quoting.js +35 -0
  118. package/dist/src/utils/wait-for-socket-connection.d.ts +11 -0
  119. package/dist/src/utils/wait-for-socket-connection.js +14 -8
  120. package/package.json +12 -12
@@ -3,6 +3,14 @@ interface MigrationShape {
3
3
  implementation?: string;
4
4
  factory?: string;
5
5
  }
6
+ /** A migration entry as written into the plan (migrations.json). */
7
+ export interface PlannedMigration extends MigrationShape {
8
+ package: string;
9
+ name: string;
10
+ version: string;
11
+ description?: string;
12
+ documentation?: string;
13
+ }
6
14
  export declare function isPromptOnlyMigration(m: MigrationShape): boolean;
7
15
  export declare function isHybridMigration(m: MigrationShape): boolean;
8
16
  export {};
@@ -0,0 +1,2 @@
1
+ export { runSingleMigrationWorker } from './worker';
2
+ export type { RunSingleMigrationWorkerInput } from './worker';
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runSingleMigrationWorker = void 0;
4
+ var worker_1 = require("./worker");
5
+ Object.defineProperty(exports, "runSingleMigrationWorker", { enumerable: true, get: function () { return worker_1.runSingleMigrationWorker; } });
@@ -0,0 +1 @@
1
+ export declare function pmExecPrefix(root: string): string;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ // Internal to run/: deliberately not re-exported from ./index.
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.pmExecPrefix = pmExecPrefix;
5
+ const package_manager_1 = require("../../../utils/package-manager");
6
+ const cachedPmExecPrefix = new Map();
7
+ // getPackageManagerCommand can shell out to detect a version, so cache the
8
+ // result per root.
9
+ function pmExecPrefix(root) {
10
+ let prefix = cachedPmExecPrefix.get(root);
11
+ if (prefix === undefined) {
12
+ prefix = (0, package_manager_1.getPackageManagerCommand)((0, package_manager_1.detectPackageManager)(root), root).exec;
13
+ cachedPmExecPrefix.set(root, prefix);
14
+ }
15
+ return prefix;
16
+ }
@@ -0,0 +1,15 @@
1
+ import { type AgenticArg } from '../agentic/select';
2
+ export interface RunSingleMigrationWorkerInput {
3
+ root: string;
4
+ runMigration: string;
5
+ /** The raw `--agentic` value; resolved here against the environment. */
6
+ agentic: AgenticArg;
7
+ validate: boolean | undefined;
8
+ /** The requested value; the effective value is resolved here against the agentic kind. */
9
+ createCommits: boolean | undefined;
10
+ commitPrefix: string;
11
+ interactive: boolean | undefined;
12
+ skipInstall: boolean;
13
+ isVerbose: boolean;
14
+ }
15
+ export declare function runSingleMigrationWorker(input: RunSingleMigrationWorkerInput): Promise<void>;
@@ -0,0 +1,419 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runSingleMigrationWorker = runSingleMigrationWorker;
4
+ const fs_1 = require("fs");
5
+ const path_1 = require("path");
6
+ const configuration_1 = require("../../../config/configuration");
7
+ const git_utils_1 = require("../../../utils/git-utils");
8
+ const command_line_utils_1 = require("../../../utils/command-line-utils");
9
+ const fileutils_1 = require("../../../utils/fileutils");
10
+ const installation_directory_1 = require("../../../utils/installation-directory");
11
+ const logger_1 = require("../../../utils/logger");
12
+ const output_1 = require("../../../utils/output");
13
+ const package_json_1 = require("../../../utils/package-json");
14
+ const print_dropped_agent_context_1 = require("../agentic/print-dropped-agent-context");
15
+ const select_1 = require("../agentic/select");
16
+ const command_object_1 = require("../command-object");
17
+ const execute_migration_1 = require("../execute-migration");
18
+ const migrate_analytics_1 = require("../migrate-analytics");
19
+ const migrate_commits_1 = require("../migrate-commits");
20
+ const migrate_output_1 = require("../migrate-output");
21
+ const migration_shape_1 = require("../migration-shape");
22
+ const safe_prompt_1 = require("../safe-prompt");
23
+ const util_1 = require("./util");
24
+ async function runSingleMigrationWorker(input) {
25
+ const { root, runMigration, commitPrefix, interactive, skipInstall, isVerbose, } = input;
26
+ const { migrations, source } = readMigrationsSource(root);
27
+ const migration = resolveMigration(migrations, runMigration, source);
28
+ (0, migrate_analytics_1.reportMigrateSingleMigrationInvocation)({
29
+ migrationType: (0, migration_shape_1.isPromptOnlyMigration)(migration)
30
+ ? 'prompt'
31
+ : (0, migration_shape_1.isHybridMigration)(migration)
32
+ ? 'hybrid'
33
+ : 'generator',
34
+ });
35
+ let agentic;
36
+ try {
37
+ agentic = await (0, select_1.resolveAgentic)({
38
+ agentic: input.agentic,
39
+ migrations: [migration],
40
+ interactive,
41
+ });
42
+ }
43
+ catch (e) {
44
+ (0, migrate_analytics_1.reportMigrateRunError)({ code: 'agentic', error: e });
45
+ throw e;
46
+ }
47
+ const resolved = (0, migrate_commits_1.resolveCreateCommits)({
48
+ createCommits: input.createCommits,
49
+ agenticKind: agentic.kind,
50
+ isGitRepo: (0, git_utils_1.isGitRepository)(root),
51
+ commitPrefixIsCustom: commitPrefix !== command_object_1.DEFAULT_MIGRATION_COMMIT_PREFIX,
52
+ });
53
+ if (resolved.error) {
54
+ throw new Error(resolved.error);
55
+ }
56
+ if (resolved.warning) {
57
+ output_1.output.warn({ title: resolved.warning });
58
+ }
59
+ const createCommits = resolved.effective;
60
+ if (createCommits && (0, safe_prompt_1.canPrompt)(interactive)) {
61
+ const currentBranch = (0, git_utils_1.getGitCurrentBranch)(root);
62
+ // `getBaseRef` may carry an `origin/` prefix (set by the CI-workflow
63
+ // generator); compare against the local branch name.
64
+ const defaultBranch = (0, command_line_utils_1.getBaseRef)((0, configuration_1.readNxJson)(root)).replace(/^origin\//, '');
65
+ const proceed = await (0, migrate_commits_1.confirmCommitsOnDefaultBranch)({
66
+ currentBranch,
67
+ defaultBranch,
68
+ });
69
+ if (!proceed) {
70
+ output_1.output.log({
71
+ title: `Skipped running the migration to avoid committing to the default branch '${currentBranch}'.`,
72
+ bodyLines: [
73
+ 'Switch to a different branch and re-run, or re-run and confirm to proceed.',
74
+ ],
75
+ });
76
+ return;
77
+ }
78
+ }
79
+ await runStandalone(root, migration, {
80
+ agentic,
81
+ createCommits,
82
+ agenticHasDiffContext: resolved.agenticHasDiffContext,
83
+ shouldRunValidation: (0, select_1.resolveShouldRunValidation)({
84
+ validate: input.validate,
85
+ agenticKind: agentic.kind,
86
+ }),
87
+ commitPrefix,
88
+ skipInstall,
89
+ isVerbose,
90
+ });
91
+ }
92
+ function readMigrationsSource(root) {
93
+ const migrationsPath = (0, path_1.join)(root, 'migrations.json');
94
+ if (!(0, fs_1.existsSync)(migrationsPath)) {
95
+ throw new Error(`File 'migrations.json' doesn't exist, can't run the migration. Run \`${(0, util_1.pmExecPrefix)(root)} nx migrate\` to generate it first.`);
96
+ }
97
+ return {
98
+ migrations: readPlanMigrations(migrationsPath),
99
+ source: 'migrations.json',
100
+ };
101
+ }
102
+ function readPlanMigrations(path) {
103
+ return ((0, fileutils_1.readJsonFile)(path).migrations ?? []);
104
+ }
105
+ function resolveMigration(migrations, id, source) {
106
+ // Split on the first ':' only, so a name that itself contains one survives.
107
+ const colon = id.indexOf(':');
108
+ const matches = colon === -1
109
+ ? migrations.filter((m) => m.name === id)
110
+ : migrations.filter((m) => m.package === id.slice(0, colon) && m.name === id.slice(colon + 1));
111
+ if (matches.length === 0) {
112
+ throw new Error(`No migration matching '${id}' was found in ${source}.`);
113
+ }
114
+ if (matches.length > 1) {
115
+ throw new Error([
116
+ `More than one migration matches '${id}' in ${source}. Re-run with the full '<package>:<name>' id:`,
117
+ ...matches.map((m) => ` - ${m.package}:${m.name}`),
118
+ ].join('\n'));
119
+ }
120
+ return matches[0];
121
+ }
122
+ async function runStandalone(root, migration, opts) {
123
+ const { agentic, createCommits, commitPrefix, skipInstall, isVerbose } = opts;
124
+ if ((0, migration_shape_1.isPromptOnlyMigration)(migration)) {
125
+ if (agentic.kind !== 'enabled') {
126
+ // No agent to apply the prompt, so nothing runs: no checkpoint, no
127
+ // commit.
128
+ emitOrPrintPrompt(root, migration, agentic.kind);
129
+ return;
130
+ }
131
+ // Checkpoint pre-existing working-tree state first, or the migration
132
+ // commit's `git add -A` folds it in.
133
+ if (createCommits) {
134
+ (0, migrate_commits_1.commitCheckpointBeforeMigrations)(root, commitPrefix);
135
+ }
136
+ const agenticRun = await prepareAgenticRun(root, migration, agentic, createCommits, commitPrefix);
137
+ const installer = new execute_migration_1.ChangedDepInstaller(root, skipInstall, (0, execute_migration_1.formatSingleMigrationRerunCommand)(`${migration.package}:${migration.name}`));
138
+ const installDepsIfChanged = () => installer.installDepsIfChanged();
139
+ const stepResult = await runAgenticStep(agenticRun, {
140
+ root,
141
+ migration,
142
+ installDepsIfChanged,
143
+ documentationPath: resolveDocumentationPath(root, migration),
144
+ });
145
+ await commitAndLogAgenticOutcome({
146
+ root,
147
+ migration,
148
+ createCommits,
149
+ commitPrefix,
150
+ installDepsIfChanged,
151
+ successLabel: 'Applied',
152
+ stepResult,
153
+ });
154
+ if (installer.skippedInstall) {
155
+ (0, execute_migration_1.logSkippedPostMigrationInstall)(root);
156
+ }
157
+ return;
158
+ }
159
+ if (createCommits) {
160
+ (0, migrate_commits_1.commitCheckpointBeforeMigrations)(root, commitPrefix);
161
+ }
162
+ const agenticRun = agentic.kind === 'enabled'
163
+ ? await prepareAgenticRun(root, migration, agentic, createCommits, commitPrefix)
164
+ : undefined;
165
+ const installer = new execute_migration_1.ChangedDepInstaller(root, skipInstall, (0, execute_migration_1.formatSingleMigrationRerunCommand)(`${migration.package}:${migration.name}`));
166
+ const installDepsIfChanged = () => installer.installDepsIfChanged();
167
+ const validationRun = agenticRun && opts.shouldRunValidation ? agenticRun : undefined;
168
+ const resolvedCollection = (0, execute_migration_1.readMigrationCollection)(migration.package, root);
169
+ const { changes, nextSteps, agentContext, skipAgentic, logs, madeChanges } = await (0, execute_migration_1.runNxOrAngularMigration)(root, migration, isVerbose, (0, migration_shape_1.isHybridMigration)(migration) || !!validationRun, resolvedCollection);
170
+ // Whether an AI step was on the table for `skipAgentic` to waive. A hybrid
171
+ // owes its prompt in every agentic mode; a generator-only migration owes
172
+ // only the validation pass, and only where one would have run.
173
+ const validationApplies = !!validationRun && changes.length > 0;
174
+ const waivedAgenticStep = skipAgentic && ((0, migration_shape_1.isHybridMigration)(migration) || validationApplies);
175
+ if ((0, migration_shape_1.isHybridMigration)(migration) && agenticRun && !skipAgentic) {
176
+ // The prompt half may need the deps the generator half added, so install
177
+ // before the agent runs.
178
+ await installDepsIfChanged();
179
+ const stepResult = await runAgenticStep(agenticRun, {
180
+ root,
181
+ migration,
182
+ installDepsIfChanged,
183
+ documentationPath: resolveDocumentationPath(root, migration, resolvedCollection),
184
+ implContext: {
185
+ logs,
186
+ changes,
187
+ agentContext,
188
+ // No prior migrations run here, so unlike the classic loop there is no
189
+ // pending-commit debt to suppress the git-inspect context for.
190
+ hasDiffContext: opts.agenticHasDiffContext,
191
+ },
192
+ });
193
+ await commitAndLogAgenticOutcome({
194
+ root,
195
+ migration,
196
+ createCommits,
197
+ commitPrefix,
198
+ installDepsIfChanged,
199
+ successLabel: 'Applied',
200
+ stepResult,
201
+ });
202
+ if (installer.skippedInstall) {
203
+ (0, execute_migration_1.logSkippedPostMigrationInstall)(root);
204
+ }
205
+ printNextSteps(migration, nextSteps);
206
+ return;
207
+ }
208
+ if (validationApplies && !skipAgentic) {
209
+ // Commit after validation: a failed validation throws, leaving the changes
210
+ // in the working tree for review.
211
+ await installDepsIfChanged();
212
+ const stepResult = await runAgenticStep(validationRun, {
213
+ root,
214
+ migration,
215
+ installDepsIfChanged,
216
+ documentationPath: resolveDocumentationPath(root, migration, resolvedCollection),
217
+ implContext: {
218
+ logs,
219
+ changes,
220
+ agentContext,
221
+ hasDiffContext: opts.agenticHasDiffContext,
222
+ },
223
+ mode: 'generic-validation',
224
+ });
225
+ await commitAndLogAgenticOutcome({
226
+ root,
227
+ migration,
228
+ createCommits,
229
+ commitPrefix,
230
+ installDepsIfChanged,
231
+ successLabel: 'Validation passed',
232
+ stepResult,
233
+ });
234
+ if (installer.skippedInstall) {
235
+ (0, execute_migration_1.logSkippedPostMigrationInstall)(root);
236
+ }
237
+ printNextSteps(migration, nextSteps);
238
+ return;
239
+ }
240
+ if (waivedAgenticStep) {
241
+ (0, migrate_output_1.logWaivedAgenticStep)(migration, agentContext);
242
+ }
243
+ else if (!(0, migration_shape_1.isHybridMigration)(migration)) {
244
+ forwardDroppedAgentContext(migration, agentContext, agentic.kind);
245
+ }
246
+ // A no-op migration must not build a commit whose `git add -A` absorbs
247
+ // unrelated pending diffs under its name. The commit path installs deps
248
+ // itself, so the else branch does it here instead.
249
+ if (createCommits && madeChanges) {
250
+ await attemptStandaloneCommit(root, migration, createCommits, commitPrefix, installDepsIfChanged);
251
+ }
252
+ else {
253
+ await installer.installDepsIfChanged();
254
+ }
255
+ if (installer.skippedInstall) {
256
+ (0, execute_migration_1.logSkippedPostMigrationInstall)(root);
257
+ }
258
+ printNextSteps(migration, nextSteps);
259
+ // A waived prompt is not deferred, so it gets no hand-off to an outer agent
260
+ // and no "apply this manually" block for the user either.
261
+ if ((0, migration_shape_1.isHybridMigration)(migration) && !skipAgentic) {
262
+ emitOrPrintPrompt(root, migration, agentic.kind, {
263
+ logs,
264
+ changes,
265
+ agentContext,
266
+ }, resolvedCollection);
267
+ }
268
+ }
269
+ // The handoff and run-step machinery is `require`d here so this module pulls
270
+ // it in only when agentic is enabled.
271
+ async function prepareAgenticRun(root, migration, agentic, effectiveCreateCommits, commitPrefix) {
272
+ const { applyAgenticHandoffGitignoreFallback } = require('../agentic/handoff-gitignore');
273
+ const { packageJson: nxPackageJson } = (0, package_json_1.readModulePackageJson)('nx', (0, installation_directory_1.getNxRequirePaths)(root));
274
+ await applyAgenticHandoffGitignoreFallback({
275
+ migrations: [migration],
276
+ installedNxVersion: nxPackageJson.version,
277
+ effectiveCreateCommits,
278
+ commitPrefix,
279
+ root,
280
+ });
281
+ const { initRunDir, resolveAgenticRunId } = require('../agentic/handoff');
282
+ const { runAgenticPromptStep } = require('../agentic/run-step');
283
+ return {
284
+ agentic,
285
+ runDir: initRunDir(root, resolveAgenticRunId([migration])),
286
+ runStep: runAgenticPromptStep,
287
+ };
288
+ }
289
+ async function runAgenticStep(agenticRun, input) {
290
+ try {
291
+ return await agenticRun.runStep({
292
+ ...input,
293
+ agentic: agenticRun.agentic,
294
+ runDir: agenticRun.runDir,
295
+ });
296
+ }
297
+ catch (e) {
298
+ (0, migrate_analytics_1.reportMigrateRunError)({
299
+ code: 'agentic',
300
+ migrationPackage: input.migration.package,
301
+ migrationName: input.migration.name,
302
+ error: e,
303
+ });
304
+ throw e;
305
+ }
306
+ }
307
+ // A standalone run has no later commit or end-of-run recap to absorb a failed
308
+ // commit's diff, so it passes its own guidance instead of the default.
309
+ // `commitMigrationIfRequested` logs a failed commit itself with that guidance.
310
+ function attemptStandaloneCommit(root, migration, createCommits, commitPrefix, installDepsIfChanged) {
311
+ return (0, migrate_commits_1.commitMigrationIfRequested)(root, migration, createCommits, commitPrefix, installDepsIfChanged, [], 'Commit or revert the changes manually.');
312
+ }
313
+ async function commitAndLogAgenticOutcome(args) {
314
+ const commit = await attemptStandaloneCommit(args.root, args.migration, args.createCommits, args.commitPrefix, args.installDepsIfChanged);
315
+ (0, migrate_output_1.logAgenticSuccessOutcome)(args.stepResult.ambiguous ? 'Marked complete by user' : args.successLabel, commit.status === 'committed' ? commit.sha : null, args.stepResult.summary);
316
+ }
317
+ // Hybrids are excluded by the caller: their `agentContext` rides in the
318
+ // prompt payload instead.
319
+ function forwardDroppedAgentContext(migration, agentContext, agenticKind) {
320
+ if (agentContext.length > 0 && agenticKind === 'inside-agent') {
321
+ (0, print_dropped_agent_context_1.printDroppedAgentContextForOuterAgent)({ migration, agentContext });
322
+ }
323
+ }
324
+ function printNextSteps(migration, nextSteps) {
325
+ if (nextSteps.length === 0)
326
+ return;
327
+ output_1.output.log({
328
+ title: `Next steps for ${migration.package}: ${migration.name}`,
329
+ bodyLines: nextSteps.map((line) => `- ${line}`),
330
+ });
331
+ }
332
+ function emitOrPrintPrompt(root, migration, agenticKind, impl, resolvedCollection) {
333
+ const migrationId = `${migration.package}:${migration.name}`;
334
+ const promptPath = migration.prompt;
335
+ const documentationPath = resolveDocumentationPath(root, migration, resolvedCollection);
336
+ if (agenticKind === 'inside-agent') {
337
+ emitPromptForOuterAgent(migrationId, promptPath, documentationPath, impl);
338
+ }
339
+ else {
340
+ printPromptForUser(root, migration, promptPath, documentationPath);
341
+ }
342
+ }
343
+ function emitPromptForOuterAgent(migrationId, promptPath, documentationPath, impl) {
344
+ const payload = { migrationId, prompt: promptPath };
345
+ if (documentationPath)
346
+ payload.documentationPath = documentationPath;
347
+ if (impl) {
348
+ payload.impl = {
349
+ logs: impl.logs,
350
+ changes: impl.changes.map((c) => ({ type: c.type, path: c.path })),
351
+ ...(impl.agentContext.length > 0
352
+ ? { agentContext: impl.agentContext }
353
+ : {}),
354
+ };
355
+ }
356
+ // A raw `<` in a migration-authored string could forge the closing tag; the
357
+ // JSON unicode escape removes every one and keeps the payload valid JSON.
358
+ const json = JSON.stringify(payload, null, 2).replace(/</g, '\\u003c');
359
+ const block = [
360
+ `The following prompt-based migration was not applied automatically. Apply it to this workspace, then continue.`,
361
+ ``,
362
+ `<nx_migrate_prompt migration="${(0, print_dropped_agent_context_1.escapeXmlAttr)(migrationId)}">`,
363
+ json,
364
+ `</nx_migrate_prompt>`,
365
+ ].join('\n');
366
+ // Bare newline pair frames the block so adjacent stdout doesn't run into it.
367
+ process.stdout.write(`\n${block}\n\n`);
368
+ }
369
+ function printPromptForUser(root, migration, promptPath, documentationPath) {
370
+ const bodyLines = [];
371
+ if (promptPath)
372
+ bodyLines.push(`Instructions file: ${promptPath}`);
373
+ if (documentationPath)
374
+ bodyLines.push(`Documentation: ${documentationPath}`);
375
+ let content = '';
376
+ let readErrorCode;
377
+ if (promptPath) {
378
+ try {
379
+ content = (0, fs_1.readFileSync)((0, path_1.join)(root, promptPath), 'utf-8');
380
+ }
381
+ catch (e) {
382
+ const err = e;
383
+ readErrorCode = err.code ?? err.message;
384
+ }
385
+ }
386
+ if (readErrorCode) {
387
+ // Point at the file and error code: the generic "review the instructions
388
+ // above" copy would sit under an empty body.
389
+ bodyLines.push('', `The instructions file '${promptPath}' could not be read (${readErrorCode}). Open it manually and apply the instructions.`);
390
+ }
391
+ else {
392
+ if (content) {
393
+ bodyLines.push('', ...content.split('\n'));
394
+ }
395
+ bodyLines.push('', 'Review the instructions above and apply them manually.');
396
+ }
397
+ output_1.output.log({
398
+ title: `Prompt-based migration ${migration.package}: ${migration.name} must be applied manually`,
399
+ bodyLines,
400
+ });
401
+ }
402
+ // Non-fatal: documentation is supplementary, so a failure warns and the
403
+ // prompt still runs without it.
404
+ function resolveDocumentationPath(root, migration, resolvedCollection) {
405
+ if (!migration.documentation)
406
+ return undefined;
407
+ let documentationPath;
408
+ try {
409
+ const { collectionPath } = resolvedCollection ?? (0, execute_migration_1.readMigrationCollection)(migration.package, root);
410
+ documentationPath = (0, execute_migration_1.resolveDocumentationFileToWorkspacePath)(root, (0, path_1.dirname)(collectionPath), migration.documentation);
411
+ }
412
+ catch {
413
+ // An unreadable collection is reported through the warning below.
414
+ }
415
+ if (!documentationPath) {
416
+ logger_1.logger.warn(`Could not resolve the "documentation" file "${migration.documentation}" declared for migration "${migration.package}: ${migration.name}". It will be skipped.`);
417
+ }
418
+ return documentationPath;
419
+ }
@@ -39,11 +39,11 @@ async function runMigrationProcess() {
39
39
  const installer = new ChangedDepInstaller(workspacePath);
40
40
  const installDepsIfChanged = () => installer.installDepsIfChanged();
41
41
 
42
- const { changes: fileChanges, nextSteps } = await runNxOrAngularMigration(
43
- workspacePath,
44
- migration,
45
- false
46
- );
42
+ const {
43
+ changes: fileChanges,
44
+ nextSteps,
45
+ skipAgentic,
46
+ } = await runNxOrAngularMigration(workspacePath, migration, false);
47
47
 
48
48
  if (configuration.createCommits) {
49
49
  const commitResult = await commitMigrationIfRequested(
@@ -81,6 +81,7 @@ async function runMigrationProcess() {
81
81
  })),
82
82
  gitRefAfter,
83
83
  nextSteps,
84
+ skipAgentic,
84
85
  })
85
86
  );
86
87
 
@@ -0,0 +1,16 @@
1
+ interface SortableMigration {
2
+ package: string;
3
+ name: string;
4
+ version: string;
5
+ }
6
+ /**
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
+ */
13
+ export declare function sortMigrations<T extends SortableMigration>(migrations: T[], opts: {
14
+ hoistHandoffGitignore: boolean;
15
+ }): T[];
16
+ export {};
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sortMigrations = sortMigrations;
4
+ const semver_1 = require("semver");
5
+ const types_1 = require("./agentic/types");
6
+ const version_utils_1 = require("./version-utils");
7
+ /**
8
+ * 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
+ */
14
+ function sortMigrations(migrations, opts) {
15
+ 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
+ if (a.name === '15-7-0-split-configuration-into-project-json-files') {
23
+ return -1;
24
+ }
25
+ if (b.name === '15-7-0-split-configuration-into-project-json-files') {
26
+ return 1;
27
+ }
28
+ return (0, semver_1.lt)((0, version_utils_1.normalizeVersion)(a.version), (0, version_utils_1.normalizeVersion)(b.version))
29
+ ? -1
30
+ : 1;
31
+ });
32
+ }
@@ -0,0 +1,58 @@
1
+ export declare const NEW_MIGRATE_FLAGS_FLOOR = "23.2.0";
2
+ export declare const NEW_MIGRATE_FLAGS: readonly ['--run-migration', '--runMigration'];
3
+ /**
4
+ * Matches an exact token or `<flag>=<value>`. The `=` matters: a bare
5
+ * `startsWith` would also match `--run-migrations` (trailing s).
6
+ */
7
+ export declare function findNewMigrateFlag(argv: string[]): string | undefined;
8
+ /**
9
+ * Guard A (local side, before hop A). The current nx knows the new flags, but
10
+ * the temp CLI 'nx migrate' is about to install may be older and would
11
+ * silently drop them. Decides where a new-flag invocation runs:
12
+ *
13
+ * - No new flag in `argv`, or the temp CLI version resolves at or above the
14
+ * feature floor: 'temp-cli', the normal temp-installation path.
15
+ * - The temp CLI resolves below the floor, or resolution fails (a registry
16
+ * error, or a minimum-release-age violation that a temp install must not
17
+ * bypass): 'local-nx', provided the workspace-local nx can take the flags.
18
+ * The local nx qualifies when it is the exact version running this code
19
+ * (it parsed the flag, so it supports it regardless of the floor) or is at
20
+ * or above the floor. An unreadable local version throws: the hand-off's
21
+ * spawn normally lands on the very install this read verifies, and a
22
+ * layout where the version cannot be read gives no such assurance, so
23
+ * handing off blind could run a below-floor nx that silently drops the
24
+ * flag.
25
+ * - Neither side is capable: throw with remediation.
26
+ *
27
+ * An explicit NX_MIGRATE_CLI_VERSION pinned below the floor throws instead of
28
+ * silently overriding the user's pin with the local fallback.
29
+ *
30
+ * `cliVersionSpec` is NX_MIGRATE_CLI_VERSION when set, else 'latest'.
31
+ */
32
+ export declare function resolveNewMigrateFlagsRunTarget(options: {
33
+ argv: string[];
34
+ cliVersionSpec: string;
35
+ fromEnvOverride: boolean;
36
+ ownNxVersion: string;
37
+ resolveVersion: (spec: string) => Promise<string>;
38
+ readLocalNxVersion: () => string | undefined;
39
+ }): Promise<'temp-cli' | 'local-nx'>;
40
+ /**
41
+ * Guard B (temp side, before hop B). The temp CLI knows the new flags, but the
42
+ * workspace-local nx it is about to hand off to may be older and would silently
43
+ * drop them.
44
+ *
45
+ * A workspace pinned to a feature-carrying 23.2.0 prerelease is refused here
46
+ * too: published prereleases that predate the feature cannot be told apart by
47
+ * version alone. Guard A's same-version bypass does not apply on this side
48
+ * because the invoking nx's version is not forwarded across hop A; the
49
+ * refusal names the workspace update that resolves it.
50
+ *
51
+ * `readLocalNxVersion` returning undefined does not block: the hand-off then
52
+ * resolves nx as it always does, which may fail visibly or land on another nx
53
+ * the package manager locates.
54
+ */
55
+ export declare function assertWorkspaceNxSupportsNewMigrateFlags(options: {
56
+ argv: string[];
57
+ readLocalNxVersion: () => string | undefined;
58
+ }): void;