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.
- package/dist/bin/nx.js +1 -0
- package/dist/src/command-line/affected/affected.js +1 -0
- package/dist/src/command-line/configure-ai-agents/configure-ai-agents.js +2 -2
- package/dist/src/command-line/init/init-v2.js +2 -2
- package/dist/src/command-line/migrate/agentic/definitions.js +2 -2
- package/dist/src/command-line/migrate/agentic/handoff-gitignore.d.ts +15 -19
- package/dist/src/command-line/migrate/agentic/handoff-gitignore.js +19 -31
- package/dist/src/command-line/migrate/agentic/handoff.d.ts +4 -6
- package/dist/src/command-line/migrate/agentic/handoff.js +9 -8
- package/dist/src/command-line/migrate/agentic/print-dropped-agent-context.d.ts +7 -12
- package/dist/src/command-line/migrate/agentic/print-dropped-agent-context.js +7 -0
- package/dist/src/command-line/migrate/agentic/run-step.d.ts +10 -0
- package/dist/src/command-line/migrate/agentic/select.d.ts +10 -2
- package/dist/src/command-line/migrate/agentic/select.js +10 -2
- package/dist/src/command-line/migrate/agentic/types.d.ts +17 -3
- package/dist/src/command-line/migrate/agentic/types.js +26 -0
- package/dist/src/command-line/migrate/command-object.d.ts +3 -0
- package/dist/src/command-line/migrate/command-object.js +6 -1
- package/dist/src/command-line/migrate/execute-migration.d.ts +14 -9
- package/dist/src/command-line/migrate/execute-migration.js +82 -18
- package/dist/src/command-line/migrate/migrate-analytics.d.ts +7 -0
- package/dist/src/command-line/migrate/migrate-analytics.js +14 -0
- package/dist/src/command-line/migrate/migrate-commits.d.ts +32 -8
- package/dist/src/command-line/migrate/migrate-commits.js +77 -9
- package/dist/src/command-line/migrate/migrate-config.d.ts +11 -12
- package/dist/src/command-line/migrate/migrate-config.js +14 -14
- package/dist/src/command-line/migrate/migrate-output.d.ts +45 -7
- package/dist/src/command-line/migrate/migrate-output.js +52 -8
- package/dist/src/command-line/migrate/migrate-ui-api.d.ts +2 -1
- package/dist/src/command-line/migrate/migrate-ui-api.js +16 -7
- package/dist/src/command-line/migrate/migrate.d.ts +17 -68
- package/dist/src/command-line/migrate/migrate.js +411 -229
- package/dist/src/command-line/migrate/migration-shape.d.ts +8 -0
- package/dist/src/command-line/migrate/run/index.d.ts +2 -0
- package/dist/src/command-line/migrate/run/index.js +5 -0
- package/dist/src/command-line/migrate/run/util.d.ts +1 -0
- package/dist/src/command-line/migrate/run/util.js +16 -0
- package/dist/src/command-line/migrate/run/worker.d.ts +15 -0
- package/dist/src/command-line/migrate/run/worker.js +419 -0
- package/dist/src/command-line/migrate/run-migration-process.js +6 -5
- package/dist/src/command-line/migrate/sort-migrations.d.ts +16 -0
- package/dist/src/command-line/migrate/sort-migrations.js +32 -0
- package/dist/src/command-line/migrate/version-skew-guard.d.ts +58 -0
- package/dist/src/command-line/migrate/version-skew-guard.js +155 -0
- package/dist/src/command-line/nx-cloud/start-nx-agents/command-object.d.ts +2 -0
- package/dist/src/command-line/nx-cloud/start-nx-agents/command-object.js +16 -0
- package/dist/src/command-line/nx-cloud/start-nx-agents/start-nx-agents.d.ts +4 -0
- package/dist/src/command-line/nx-cloud/start-nx-agents/start-nx-agents.js +13 -0
- package/dist/src/command-line/nx-commands.js +26 -24
- package/dist/src/command-line/release/changelog.js +5 -0
- package/dist/src/command-line/release/utils/git.js +1 -1
- package/dist/src/command-line/release/utils/release-graph.d.ts +1 -0
- package/dist/src/command-line/release/utils/release-graph.js +15 -3
- package/dist/src/command-line/release/version/version-actions.d.ts +8 -0
- package/dist/src/command-line/release/version/version-actions.js +8 -0
- package/dist/src/command-line/release/version.js +9 -5
- package/dist/src/command-line/reset/reset.js +6 -1
- package/dist/src/command-line/run/run-one.js +1 -0
- package/dist/src/command-line/run-many/run-many.js +1 -0
- package/dist/src/config/misc-interfaces.d.ts +19 -7
- package/dist/src/core/graph/main.js +1 -1
- package/dist/src/core/graph/styles.js +1 -1
- package/dist/src/daemon/client/client.d.ts +45 -1
- package/dist/src/daemon/client/client.js +128 -32
- package/dist/src/daemon/client/daemon-socket-messenger.js +4 -0
- package/dist/src/daemon/message-types/daemon-message.d.ts +32 -0
- package/dist/src/daemon/message-types/daemon-message.js +25 -0
- package/dist/src/daemon/server/latest-nx.js +5 -2
- package/dist/src/daemon/server/server.js +22 -0
- package/dist/src/daemon/server/shutdown-utils.d.ts +5 -0
- package/dist/src/daemon/server/shutdown-utils.js +11 -4
- package/dist/src/daemon/socket-utils.d.ts +1 -0
- package/dist/src/daemon/socket-utils.js +24 -3
- package/dist/src/daemon/tmp-dir.d.ts +43 -3
- package/dist/src/daemon/tmp-dir.js +437 -15
- package/dist/src/devkit-internals.d.ts +92 -3
- package/dist/src/devkit-internals.js +189 -5
- package/dist/src/generators/internal-utils/format-changed-files-with-prettier-if-available.d.ts +5 -0
- package/dist/src/generators/internal-utils/format-changed-files-with-prettier-if-available.js +9 -2
- package/dist/src/generators/tree.d.ts +4 -2
- package/dist/src/native/index.d.ts +10 -0
- package/dist/src/native/index.js +71 -28
- package/dist/src/native/native-bindings.js +1 -0
- package/dist/src/native/native-file-cache-location.d.ts +17 -1
- package/dist/src/native/native-file-cache-location.js +86 -12
- package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
- package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
- package/dist/src/nx-cloud/utilities/get-cloud-options.js +5 -2
- package/dist/src/nx-cloud/utilities/onboarding.js +5 -2
- package/dist/src/nx-cloud/utilities/url-shorten.d.ts +1 -4
- package/dist/src/nx-cloud/utilities/url-shorten.js +9 -8
- package/dist/src/plugins/js/lock-file/project-graph-pruning.js +14 -8
- package/dist/src/plugins/js/project-graph/build-dependencies/target-project-locator.js +2 -0
- package/dist/src/project-graph/affected/affected-project-graph-models.d.ts +1 -1
- package/dist/src/project-graph/affected/affected-project-graph.d.ts +1 -1
- package/dist/src/project-graph/affected/affected-project-graph.js +2 -2
- package/dist/src/project-graph/affected/locators/project-glob-changes.js +5 -2
- package/dist/src/project-graph/plugins/isolation/isolated-plugin.d.ts +1 -0
- package/dist/src/project-graph/plugins/isolation/isolated-plugin.js +18 -1
- package/dist/src/project-graph/plugins/isolation/messaging.d.ts +16 -3
- package/dist/src/project-graph/plugins/isolation/messaging.js +3 -0
- package/dist/src/project-graph/plugins/isolation/plugin-worker.js +58 -8
- package/dist/src/project-graph/project-graph.js +20 -0
- package/dist/src/tasks-runner/life-cycles/performance-report.d.ts +12 -0
- package/dist/src/tasks-runner/life-cycles/performance-report.js +62 -3
- package/dist/src/tasks-runner/run-command.js +4 -0
- package/dist/src/utils/assert-workspace-validity.js +7 -2
- package/dist/src/utils/child-process.d.ts +31 -1
- package/dist/src/utils/child-process.js +103 -0
- package/dist/src/utils/ignore.d.ts +128 -1
- package/dist/src/utils/ignore.js +182 -12
- package/dist/src/utils/nx-tmp-dir.d.ts +18 -0
- package/dist/src/utils/nx-tmp-dir.js +40 -0
- package/dist/src/utils/owned-private-dir.d.ts +132 -0
- package/dist/src/utils/owned-private-dir.js +323 -0
- package/dist/src/utils/shell-quoting.d.ts +15 -0
- package/dist/src/utils/shell-quoting.js +35 -0
- package/dist/src/utils/wait-for-socket-connection.d.ts +11 -0
- package/dist/src/utils/wait-for-socket-connection.js +14 -8
- 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,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 {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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;
|