nx 23.2.0-beta.6 → 23.2.0-beta.8
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/init-local.js +3 -5
- package/dist/release/changelog-renderer/index.js +4 -5
- package/dist/src/adapter/ngcli-adapter.js +60 -1
- package/dist/src/command-line/completion/command-object.js +7 -12
- package/dist/src/command-line/configure-ai-agents/configure-ai-agents.js +17 -23
- package/dist/src/command-line/generate/generate.js +35 -35
- package/dist/src/command-line/import/import.js +18 -40
- package/dist/src/command-line/init/ai-agent-prompts.js +5 -11
- package/dist/src/command-line/init/command-object.js +4 -2
- package/dist/src/command-line/init/implementation/add-nx-to-monorepo.js +12 -32
- package/dist/src/command-line/init/implementation/add-nx-to-nest.js +8 -21
- package/dist/src/command-line/init/implementation/add-nx-to-npm-repo.js +8 -21
- package/dist/src/command-line/init/implementation/angular/index.js +6 -15
- package/dist/src/command-line/init/init-v1.js +8 -18
- package/dist/src/command-line/init/init-v2.js +28 -56
- package/dist/src/command-line/migrate/agentic/definitions.js +35 -8
- package/dist/src/command-line/migrate/agentic/handoff-gitignore.d.ts +22 -3
- package/dist/src/command-line/migrate/agentic/handoff-gitignore.js +13 -10
- package/dist/src/command-line/migrate/agentic/handoff.d.ts +3 -1
- package/dist/src/command-line/migrate/agentic/handoff.js +4 -2
- package/dist/src/command-line/migrate/agentic/run-step.js +1 -0
- package/dist/src/command-line/migrate/agentic/runner.js +24 -24
- package/dist/src/command-line/migrate/agentic/select.js +20 -30
- package/dist/src/command-line/migrate/agentic/types.d.ts +19 -3
- package/dist/src/command-line/migrate/agentic/types.js +13 -4
- package/dist/src/command-line/migrate/command-object.d.ts +3 -0
- package/dist/src/command-line/migrate/command-object.js +13 -0
- package/dist/src/command-line/migrate/execute-migration.d.ts +14 -0
- package/dist/src/command-line/migrate/execute-migration.js +30 -9
- package/dist/src/command-line/migrate/migrate-analytics.d.ts +28 -0
- package/dist/src/command-line/migrate/migrate-analytics.js +51 -1
- package/dist/src/command-line/migrate/migrate-commits.d.ts +8 -2
- package/dist/src/command-line/migrate/migrate-commits.js +66 -19
- package/dist/src/command-line/migrate/migrate-config.d.ts +4 -2
- package/dist/src/command-line/migrate/migrate-config.js +12 -4
- package/dist/src/command-line/migrate/migrate.d.ts +9 -2
- package/dist/src/command-line/migrate/migrate.js +179 -56
- package/dist/src/command-line/migrate/multi-major.js +7 -10
- package/dist/src/command-line/migrate/resolve-package-version.js +4 -8
- package/dist/src/command-line/migrate/run/agent-output.d.ts +20 -0
- package/dist/src/command-line/migrate/run/agent-output.js +65 -0
- package/dist/src/command-line/migrate/run/index.d.ts +7 -0
- package/dist/src/command-line/migrate/run/index.js +19 -1
- package/dist/src/command-line/migrate/run/orchestrator.d.ts +20 -0
- package/dist/src/command-line/migrate/run/orchestrator.js +1200 -0
- package/dist/src/command-line/migrate/run/run-id.d.ts +16 -0
- package/dist/src/command-line/migrate/run/run-id.js +56 -0
- package/dist/src/command-line/migrate/run/run-state.d.ts +157 -0
- package/dist/src/command-line/migrate/run/run-state.js +438 -0
- package/dist/src/command-line/migrate/run/state-lock.d.ts +25 -0
- package/dist/src/command-line/migrate/run/state-lock.js +76 -0
- package/dist/src/command-line/migrate/run/state-machine.d.ts +84 -0
- package/dist/src/command-line/migrate/run/state-machine.js +315 -0
- package/dist/src/command-line/migrate/run/util.d.ts +58 -0
- package/dist/src/command-line/migrate/run/util.js +139 -7
- package/dist/src/command-line/migrate/run/worker.d.ts +1 -0
- package/dist/src/command-line/migrate/run/worker.js +308 -45
- package/dist/src/command-line/migrate/safe-prompt.d.ts +14 -26
- package/dist/src/command-line/migrate/safe-prompt.js +32 -43
- package/dist/src/command-line/migrate/step-actions.d.ts +5 -0
- package/dist/src/command-line/migrate/step-actions.js +12 -0
- package/dist/src/command-line/migrate/text.d.ts +18 -0
- package/dist/src/command-line/migrate/text.js +26 -0
- package/dist/src/command-line/migrate/version-skew-guard.d.ts +6 -4
- package/dist/src/command-line/migrate/version-skew-guard.js +34 -14
- package/dist/src/command-line/nx-cloud/connect/connect-to-nx-cloud.js +16 -20
- package/dist/src/command-line/release/changelog.js +6 -17
- package/dist/src/command-line/release/plan.js +15 -28
- package/dist/src/command-line/release/release.js +6 -17
- package/dist/src/command-line/release/utils/remote-release-clients/github.js +16 -22
- package/dist/src/command-line/release/utils/remote-release-clients/gitlab.js +13 -22
- package/dist/src/command-line/release/utils/resolve-semver-specifier.js +19 -41
- package/dist/src/command-line/release/version/resolve-current-version.js +7 -10
- package/dist/src/core/graph/main.js +1 -1
- package/dist/src/devkit-internals.d.ts +3 -0
- package/dist/src/devkit-internals.js +15 -4
- package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.d.ts +12 -0
- package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.js +250 -0
- package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.md +50 -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/plugins/js/lock-file/bun-parser.js +43 -10
- package/dist/src/project-graph/utils/project-configuration/target-normalization.js +128 -2
- package/dist/src/tasks-runner/run-command.js +17 -32
- package/dist/src/tasks-runner/task-env.js +5 -2
- package/dist/src/tasks-runner/utils.js +2 -6
- package/dist/src/utils/analytics-prompt.js +4 -7
- package/dist/src/utils/exit-codes.d.ts +9 -0
- package/dist/src/utils/exit-codes.js +19 -0
- package/dist/src/utils/fileutils.d.ts +5 -0
- package/dist/src/utils/fileutils.js +7 -2
- package/dist/src/utils/git-utils.d.ts +33 -2
- package/dist/src/utils/git-utils.js +156 -8
- package/dist/src/utils/long-running-target.d.ts +10 -0
- package/dist/src/utils/long-running-target.js +19 -0
- package/dist/src/utils/min-release-age/behavior/bun.js +7 -11
- package/dist/src/utils/min-release-age/behavior/npm.js +5 -2
- package/dist/src/utils/min-release-age/packument.js +1 -1
- package/dist/src/utils/nx-console-prompt.js +3 -6
- package/dist/src/utils/package-manager-config/bunfig.d.ts +14 -0
- package/dist/src/utils/package-manager-config/bunfig.js +49 -0
- package/dist/src/utils/package-manager-config/npmrc.d.ts +23 -0
- package/dist/src/utils/package-manager-config/npmrc.js +124 -0
- package/dist/src/utils/package-manager-config/pnpm-config.d.ts +17 -0
- package/dist/src/utils/package-manager-config/pnpm-config.js +60 -0
- package/dist/src/utils/package-manager.d.ts +21 -2
- package/dist/src/utils/package-manager.js +244 -47
- package/dist/src/utils/params.d.ts +7 -1
- package/dist/src/utils/params.js +64 -6
- package/dist/src/utils/plugins/core-plugins.js +4 -0
- package/dist/src/utils/prompt-helpers.d.ts +53 -0
- package/dist/src/utils/prompt-helpers.js +111 -0
- package/dist/src/utils/provenance.js +6 -14
- package/dist/src/utils/registry-config/bun.d.ts +2 -0
- package/dist/src/utils/registry-config/bun.js +257 -0
- package/dist/src/utils/registry-config/index.d.ts +13 -0
- package/dist/src/utils/registry-config/index.js +102 -0
- package/dist/src/utils/registry-config/pnpm.d.ts +2 -0
- package/dist/src/utils/registry-config/pnpm.js +1551 -0
- package/dist/src/utils/registry-config/utils.d.ts +195 -0
- package/dist/src/utils/registry-config/utils.js +496 -0
- package/dist/src/utils/registry-config/yarn-berry.d.ts +2 -0
- package/dist/src/utils/registry-config/yarn-berry.js +612 -0
- package/dist/src/utils/registry-config/yarn-classic.d.ts +2 -0
- package/dist/src/utils/registry-config/yarn-classic.js +1001 -0
- package/dist/src/utils/safe-spawn.d.ts +24 -0
- package/dist/src/utils/safe-spawn.js +104 -0
- package/migrations.json +6 -0
- package/package.json +18 -13
- package/dist/src/utils/min-release-age/npmrc.d.ts +0 -15
- package/dist/src/utils/min-release-age/npmrc.js +0 -45
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.addNxToAngularCliRepo = addNxToAngularCliRepo;
|
|
4
|
-
const
|
|
4
|
+
const prompt_helpers_1 = require("../../../../utils/prompt-helpers");
|
|
5
5
|
const path_1 = require("path");
|
|
6
6
|
const fileutils_1 = require("../../../../utils/fileutils");
|
|
7
7
|
const versions_1 = require("../../../../utils/versions");
|
|
@@ -65,20 +65,11 @@ async function collectCacheableOperations(options) {
|
|
|
65
65
|
output_1.output.log({
|
|
66
66
|
title: '🧑🔧 Please answer the following questions about the targets found in your angular.json in order to generate task runner configuration',
|
|
67
67
|
});
|
|
68
|
-
cacheableOperations =
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
message: 'Which of the following targets are cacheable? (Produce the same output given the same input, e.g. build, test and lint usually are, serve and start are not)',
|
|
74
|
-
// enquirer mutates the array below, create a new one to avoid it
|
|
75
|
-
choices: [...workspaceTargets],
|
|
76
|
-
/**
|
|
77
|
-
* limit is missing from the interface but it limits the amount of options shown
|
|
78
|
-
*/
|
|
79
|
-
limit: process.stdout.rows - 4, // 4 leaves room for the header above, the prompt and some whitespace
|
|
80
|
-
},
|
|
81
|
-
])).cacheableOperations;
|
|
68
|
+
cacheableOperations = await (0, prompt_helpers_1.multiselectPrompt)({
|
|
69
|
+
message: 'Which of the following targets are cacheable? (Produce the same output given the same input, e.g. build, test and lint usually are, serve and start are not)',
|
|
70
|
+
choices: workspaceTargets,
|
|
71
|
+
initialValues: defaultCacheableTargetsInWorkspace,
|
|
72
|
+
});
|
|
82
73
|
}
|
|
83
74
|
else {
|
|
84
75
|
cacheableOperations =
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.initHandler = initHandler;
|
|
4
4
|
const child_process_1 = require("child_process");
|
|
5
|
-
const
|
|
5
|
+
const prompt_helpers_1 = require("../../utils/prompt-helpers");
|
|
6
6
|
const fs_1 = require("fs");
|
|
7
7
|
const semver_1 = require("semver");
|
|
8
8
|
const add_nx_to_monorepo_1 = require("./implementation/add-nx-to-monorepo");
|
|
@@ -54,23 +54,13 @@ async function initHandler(options) {
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
else {
|
|
57
|
-
const useDotNxFolder = await (0,
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
name: 'In a new folder under this directory',
|
|
65
|
-
value: 'false',
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
name: 'In this directory',
|
|
69
|
-
value: 'true',
|
|
70
|
-
},
|
|
71
|
-
],
|
|
72
|
-
},
|
|
73
|
-
]).then((r) => r.useDotNxFolder === 'true');
|
|
57
|
+
const useDotNxFolder = (await (0, prompt_helpers_1.selectPrompt)({
|
|
58
|
+
message: 'Where should your workspace be created?',
|
|
59
|
+
choices: [
|
|
60
|
+
{ value: 'false', label: 'In a new folder under this directory' },
|
|
61
|
+
{ value: 'true', label: 'In this directory' },
|
|
62
|
+
],
|
|
63
|
+
})) === 'true';
|
|
74
64
|
if (useDotNxFolder) {
|
|
75
65
|
setupDotNxInstallation(version);
|
|
76
66
|
}
|
|
@@ -5,7 +5,7 @@ exports.getPluginReason = getPluginReason;
|
|
|
5
5
|
exports.detectPlugins = detectPlugins;
|
|
6
6
|
const fs_1 = require("fs");
|
|
7
7
|
const path_1 = require("path");
|
|
8
|
-
const
|
|
8
|
+
const prompt_helpers_1 = require("../../utils/prompt-helpers");
|
|
9
9
|
const semver_1 = require("semver");
|
|
10
10
|
const nx_json_1 = require("../../config/nx-json");
|
|
11
11
|
const fileutils_1 = require("../../utils/fileutils");
|
|
@@ -33,7 +33,6 @@ const detect_ai_agent_1 = require("../../ai/detect-ai-agent");
|
|
|
33
33
|
const ab_testing_1 = require("../../utils/ab-testing");
|
|
34
34
|
const analytics_prompt_1 = require("../../utils/analytics-prompt");
|
|
35
35
|
const is_ci_1 = require("../../utils/is-ci");
|
|
36
|
-
const package_manager_2 = require("../../utils/package-manager");
|
|
37
36
|
const ai_output_1 = require("./utils/ai-output");
|
|
38
37
|
async function initHandler(options, inner = false) {
|
|
39
38
|
// Use environment variable to force local execution
|
|
@@ -43,7 +42,7 @@ async function initHandler(options, inner = false) {
|
|
|
43
42
|
let cleanup;
|
|
44
43
|
try {
|
|
45
44
|
await (0, provenance_1.ensurePackageHasProvenance)('nx', 'latest');
|
|
46
|
-
const packageInstallResults = (0, package_json_1.installPackageToTmp)('nx', 'latest', (0,
|
|
45
|
+
const packageInstallResults = (0, package_json_1.installPackageToTmp)('nx', 'latest', (0, package_manager_1.detectPackageManager)(process.cwd()));
|
|
47
46
|
cleanup = packageInstallResults.cleanup;
|
|
48
47
|
let modulePath = require.resolve('nx/src/command-line/init/init-v2.js', {
|
|
49
48
|
paths: [packageInstallResults.tempDir],
|
|
@@ -95,7 +94,7 @@ async function initHandlerImpl(options) {
|
|
|
95
94
|
const baseMeta = {
|
|
96
95
|
nodeVersion: process.versions.node,
|
|
97
96
|
os: process.platform,
|
|
98
|
-
packageManager: (0,
|
|
97
|
+
packageManager: (0, package_manager_1.detectPackageManager)(),
|
|
99
98
|
aiAgent: (0, native_1.isAiAgent)(),
|
|
100
99
|
isCI: (0, is_ci_1.isCI)(),
|
|
101
100
|
};
|
|
@@ -162,21 +161,17 @@ async function runInit(options, baseMeta) {
|
|
|
162
161
|
options.interactive &&
|
|
163
162
|
!aiMode &&
|
|
164
163
|
process.stdin.isTTY) {
|
|
165
|
-
const setupMode = await (0,
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
},
|
|
177
|
-
],
|
|
178
|
-
},
|
|
179
|
-
]).then((r) => r.setupMode);
|
|
164
|
+
const setupMode = await (0, prompt_helpers_1.selectPrompt)({
|
|
165
|
+
message: 'How would you like to set up Nx in this directory?',
|
|
166
|
+
choices: [
|
|
167
|
+
{
|
|
168
|
+
value: '.nx installation (recommended for non-JavaScript projects)',
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
value: 'package.json installation (recommended for JavaScript/TypeScript projects)',
|
|
172
|
+
},
|
|
173
|
+
],
|
|
174
|
+
});
|
|
180
175
|
if (setupMode.startsWith('package.json')) {
|
|
181
176
|
// Create a minimal package.json so the JS/TS workflow takes over
|
|
182
177
|
const workspaceName = (0, path_1.basename)(process.cwd());
|
|
@@ -199,14 +194,10 @@ async function runInit(options, baseMeta) {
|
|
|
199
194
|
// AI mode defaults to minimum setup, humans can choose
|
|
200
195
|
let guided = !aiMode; // Default to minimum (false) for AI, guided (true) for humans
|
|
201
196
|
if (options.interactive && !(_isTurborepo || _isNonJs)) {
|
|
202
|
-
const setupType = await (0,
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
message: 'Would you like a minimum or guided setup?',
|
|
207
|
-
choices: [{ name: 'Minimum' }, { name: 'Guided' }],
|
|
208
|
-
},
|
|
209
|
-
]).then((r) => r.setupPreference);
|
|
197
|
+
const setupType = await (0, prompt_helpers_1.selectPrompt)({
|
|
198
|
+
message: 'Would you like a minimum or guided setup?',
|
|
199
|
+
choices: [{ value: 'Minimum' }, { value: 'Guided' }],
|
|
200
|
+
});
|
|
210
201
|
guided = setupType === 'Guided';
|
|
211
202
|
}
|
|
212
203
|
/**
|
|
@@ -368,7 +359,7 @@ async function runInit(options, baseMeta) {
|
|
|
368
359
|
analyticsPrompt,
|
|
369
360
|
nodeVersion: process.versions.node,
|
|
370
361
|
os: process.platform,
|
|
371
|
-
packageManager: (0,
|
|
362
|
+
packageManager: (0, package_manager_1.detectPackageManager)(),
|
|
372
363
|
aiAgent: aiMode,
|
|
373
364
|
isCI: (0, is_ci_1.isCI)(),
|
|
374
365
|
pluginsInstalled: pluginsToInstall.join(','),
|
|
@@ -401,6 +392,7 @@ async function runInit(options, baseMeta) {
|
|
|
401
392
|
function getPluginReason(plugin) {
|
|
402
393
|
const reasonMap = {
|
|
403
394
|
'@nx/eslint': 'eslint detected in dependencies',
|
|
395
|
+
'@nx/oxlint': 'oxlint detected in dependencies',
|
|
404
396
|
'@nx/storybook': 'storybook detected in dependencies',
|
|
405
397
|
'@nx/vite': 'vite detected in dependencies',
|
|
406
398
|
'@nx/vitest': 'vitest detected in dependencies',
|
|
@@ -448,6 +440,7 @@ function parsePluginsFlag(value) {
|
|
|
448
440
|
const npmPackageToPluginMap = {
|
|
449
441
|
// Generic JS tools
|
|
450
442
|
eslint: '@nx/eslint',
|
|
443
|
+
oxlint: '@nx/oxlint',
|
|
451
444
|
storybook: '@nx/storybook',
|
|
452
445
|
// Bundlers
|
|
453
446
|
vite: '@nx/vite',
|
|
@@ -574,39 +567,18 @@ async function detectPlugins(nxJson, packageJson, interactive, includeAngularCli
|
|
|
574
567
|
`Add these Nx plugins to integrate with the tools used in your workspace.`,
|
|
575
568
|
],
|
|
576
569
|
});
|
|
577
|
-
const pluginsToInstall = await (0,
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
message: `Which plugins would you like to add? Press <Space> to select and <Enter> to submit.`,
|
|
582
|
-
choices: plugins.map((p) => ({ name: p, value: p })),
|
|
583
|
-
/**
|
|
584
|
-
* limit is missing from the interface but it limits the amount of options shown
|
|
585
|
-
*/
|
|
586
|
-
limit: process.stdout.rows - 4, // 4 leaves room for the header above, the prompt and some whitespace
|
|
587
|
-
},
|
|
588
|
-
]).then((r) => r.plugins);
|
|
570
|
+
const pluginsToInstall = await (0, prompt_helpers_1.multiselectPrompt)({
|
|
571
|
+
message: `Which plugins would you like to add? Press <Space> to select and <Enter> to submit.`,
|
|
572
|
+
choices: plugins,
|
|
573
|
+
});
|
|
589
574
|
if (pluginsToInstall?.length === 0)
|
|
590
575
|
return {
|
|
591
576
|
plugins: [],
|
|
592
577
|
updatePackageScripts: false,
|
|
593
578
|
};
|
|
594
579
|
const updatePackageScripts = (0, fs_1.existsSync)('package.json') &&
|
|
595
|
-
(await (0,
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
type: 'autocomplete',
|
|
599
|
-
message: `Do you want to start using Nx in your package.json scripts?`,
|
|
600
|
-
choices: [
|
|
601
|
-
{
|
|
602
|
-
name: 'Yes',
|
|
603
|
-
},
|
|
604
|
-
{
|
|
605
|
-
name: 'No',
|
|
606
|
-
},
|
|
607
|
-
],
|
|
608
|
-
initial: 0,
|
|
609
|
-
},
|
|
610
|
-
]).then((r) => r.updatePackageScripts === 'Yes'));
|
|
580
|
+
(await (0, prompt_helpers_1.confirmationPrompt)({
|
|
581
|
+
message: `Do you want to start using Nx in your package.json scripts?`,
|
|
582
|
+
}));
|
|
611
583
|
return { plugins: pluginsToInstall, updatePackageScripts };
|
|
612
584
|
}
|
|
@@ -13,21 +13,48 @@ function claudeCodeWellKnownPaths() {
|
|
|
13
13
|
}
|
|
14
14
|
return [(0, path_1.join)((0, os_1.homedir)(), '.claude', 'local', 'claude')];
|
|
15
15
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
/**
|
|
17
|
+
* The run directory names Nx will interpolate into a permission rule. A rule
|
|
18
|
+
* is a gitignore pattern, which reads `*?[]\` as syntax, and `--allowedTools`
|
|
19
|
+
* splits its value on commas and spaces, so a name carrying any of those
|
|
20
|
+
* would change what the rule authorizes rather than what it names. Run
|
|
21
|
+
* directory names derive from a migration's own version string, which nothing
|
|
22
|
+
* upstream constrains to this alphabet. The leading character rejects `.`
|
|
23
|
+
* and `..`.
|
|
24
|
+
*/
|
|
25
|
+
const RULE_SAFE_RUN_DIR_NAME = /^[A-Za-z0-9][A-Za-z0-9._+-]*$/;
|
|
26
|
+
/**
|
|
27
|
+
* Pre-authorizes the handoff write. Claude Code's default permission mode
|
|
28
|
+
* asks before a file write it has no allow rule for, so without this every
|
|
29
|
+
* step ends on an approval prompt for Nx's own handoff scratch.
|
|
30
|
+
*
|
|
31
|
+
* The rule reaches one run's handoffs and nothing else. Its own run
|
|
32
|
+
* directory also holds state Nx wrote and reads back, and the sibling
|
|
33
|
+
* directories belong to other runs, including an orchestrated run whose
|
|
34
|
+
* handoffs decide how its steps settle. `Edit` is the only tool name file
|
|
35
|
+
* rules are matched against, and it covers creating the file as well as
|
|
36
|
+
* correcting one already written. Prefix-less patterns resolve against the
|
|
37
|
+
* session cwd, pinned to the workspace root below.
|
|
38
|
+
*
|
|
39
|
+
* Returns null for a name it cannot express, which costs the approval prompt
|
|
40
|
+
* this exists to avoid. That beats widening the rule, and nothing narrower is
|
|
41
|
+
* available: Claude Code has no escape for a literal path.
|
|
42
|
+
*/
|
|
43
|
+
function claudeCodeHandoffAllowedTools(runDirName) {
|
|
44
|
+
if (!RULE_SAFE_RUN_DIR_NAME.test(runDirName)) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
return `Edit(${types_1.MIGRATE_RUNS_RELATIVE_DIR}/${runDirName}/${types_1.HANDOFFS_DIR_NAME}/**)`;
|
|
48
|
+
}
|
|
22
49
|
function claudeCodeBuildInteractive(ctx) {
|
|
50
|
+
const allowedTools = claudeCodeHandoffAllowedTools(ctx.runDirName);
|
|
23
51
|
return {
|
|
24
52
|
// `--allowedTools` is variadic (space/comma separated): a positional
|
|
25
53
|
// placed right after its value gets swallowed as another rule. The rules
|
|
26
54
|
// must stay in one comma-joined element with a non-variadic flag
|
|
27
55
|
// (`--system-prompt`) between them and the user prompt.
|
|
28
56
|
args: [
|
|
29
|
-
'--allowedTools',
|
|
30
|
-
CLAUDE_CODE_HANDOFF_ALLOWED_TOOLS,
|
|
57
|
+
...(allowedTools ? ['--allowedTools', allowedTools] : []),
|
|
31
58
|
'--system-prompt',
|
|
32
59
|
ctx.systemContext,
|
|
33
60
|
ctx.userPrompt,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* `.nx/migrate-runs/<run-id
|
|
2
|
+
* Both the agentic runner and the orchestrator write per-run scratch under
|
|
3
|
+
* `.nx/migrate-runs/<run-id>/`: handoff files in both cases, plus the durable
|
|
4
|
+
* run state and its plan snapshots for the orchestrator. The v23 migration
|
|
4
5
|
* `23-0-0-add-migrate-runs-to-git-ignore` adds `.nx/migrate-runs` to
|
|
5
6
|
* `.gitignore`; in its declared slot (typically late) earlier per-migration
|
|
6
7
|
* commits would absorb the scratch into the user-visible diff.
|
|
@@ -23,7 +24,7 @@
|
|
|
23
24
|
* had the entry historically; if it is gone, that is a conscious removal we
|
|
24
25
|
* respect.
|
|
25
26
|
*/
|
|
26
|
-
export declare function applyAgenticHandoffGitignoreFallback({ migrations, installedNxVersion, effectiveCreateCommits, commitPrefix, root, }: {
|
|
27
|
+
export declare function applyAgenticHandoffGitignoreFallback({ migrations, installedNxVersion, effectiveCreateCommits, commitPrefix, root, applyWhenPlanned, commitStandalone, }: {
|
|
27
28
|
migrations: ReadonlyArray<{
|
|
28
29
|
package: string;
|
|
29
30
|
name: string;
|
|
@@ -39,4 +40,22 @@ export declare function applyAgenticHandoffGitignoreFallback({ migrations, insta
|
|
|
39
40
|
effectiveCreateCommits: boolean;
|
|
40
41
|
commitPrefix: string;
|
|
41
42
|
root: string;
|
|
43
|
+
/**
|
|
44
|
+
* Apply the entry even when the hoisted migration is in the plan. The
|
|
45
|
+
* classic loop can defer to that migration because its run scratch appears
|
|
46
|
+
* only after migration 1 has run; the orchestrator creates its run dir at
|
|
47
|
+
* init, before any migration, so it needs the entry immediately. A planned
|
|
48
|
+
* migration also means the missing entry is not a conscious removal, so the
|
|
49
|
+
* v23 cutoff does not apply.
|
|
50
|
+
*/
|
|
51
|
+
applyWhenPlanned?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Commit the applied entry as its own preflight commit (the default). The
|
|
54
|
+
* orchestrator suppresses this: it applies the fallback before its init
|
|
55
|
+
* checkpoint so the checkpoint's `git add -A` cannot sweep in older
|
|
56
|
+
* scratch, and in that ordering a standalone commit here would carry the
|
|
57
|
+
* user's pre-existing changes along with the entry. The checkpoint that
|
|
58
|
+
* follows captures both instead.
|
|
59
|
+
*/
|
|
60
|
+
commitStandalone?: boolean;
|
|
42
61
|
}): Promise<void>;
|
|
@@ -10,8 +10,9 @@ const git_utils_1 = require("../../../utils/git-utils");
|
|
|
10
10
|
const logger_1 = require("../../../utils/logger");
|
|
11
11
|
const types_1 = require("./types");
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
14
|
-
* `.nx/migrate-runs/<run-id
|
|
13
|
+
* Both the agentic runner and the orchestrator write per-run scratch under
|
|
14
|
+
* `.nx/migrate-runs/<run-id>/`: handoff files in both cases, plus the durable
|
|
15
|
+
* run state and its plan snapshots for the orchestrator. The v23 migration
|
|
15
16
|
* `23-0-0-add-migrate-runs-to-git-ignore` adds `.nx/migrate-runs` to
|
|
16
17
|
* `.gitignore`; in its declared slot (typically late) earlier per-migration
|
|
17
18
|
* commits would absorb the scratch into the user-visible diff.
|
|
@@ -34,13 +35,15 @@ const types_1 = require("./types");
|
|
|
34
35
|
* had the entry historically; if it is gone, that is a conscious removal we
|
|
35
36
|
* respect.
|
|
36
37
|
*/
|
|
37
|
-
async function applyAgenticHandoffGitignoreFallback({ migrations, installedNxVersion, effectiveCreateCommits, commitPrefix, root, }) {
|
|
38
|
+
async function applyAgenticHandoffGitignoreFallback({ migrations, installedNxVersion, effectiveCreateCommits, commitPrefix, root, applyWhenPlanned = false, commitStandalone = true, }) {
|
|
38
39
|
if (migrations.some(types_1.isHandoffGitignoreMigration)) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
if (!applyWhenPlanned) {
|
|
41
|
+
// The queue runs it itself: hoisted to the front by the sort comparator
|
|
42
|
+
// in a full run, or as the single requested migration in a worker run.
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
42
45
|
}
|
|
43
|
-
if ((0, semver_1.major)(installedNxVersion) >= 23) {
|
|
46
|
+
else if ((0, semver_1.major)(installedNxVersion) >= 23) {
|
|
44
47
|
// User is past v23. Respect their `.gitignore` state — if the entry
|
|
45
48
|
// is missing, that's a conscious removal.
|
|
46
49
|
return;
|
|
@@ -54,13 +57,13 @@ async function applyAgenticHandoffGitignoreFallback({ migrations, installedNxVer
|
|
|
54
57
|
return;
|
|
55
58
|
}
|
|
56
59
|
(0, tree_1.flushChanges)(root, changes);
|
|
57
|
-
logger_1.logger.info(pc.dim(`- Added .
|
|
58
|
-
if (!effectiveCreateCommits)
|
|
60
|
+
logger_1.logger.info(pc.dim(`- Added ${types_1.MIGRATE_RUNS_RELATIVE_DIR} to .gitignore so this run's scratch state is ignored.`));
|
|
61
|
+
if (!effectiveCreateCommits || !commitStandalone)
|
|
59
62
|
return;
|
|
60
63
|
if (!(0, git_utils_1.hasUncommittedChanges)(root))
|
|
61
64
|
return;
|
|
62
65
|
try {
|
|
63
|
-
const sha = (0, git_utils_1.tryCommitChanges)(`${commitPrefix}add .
|
|
66
|
+
const sha = (0, git_utils_1.tryCommitChanges)(`${commitPrefix}add ${types_1.MIGRATE_RUNS_RELATIVE_DIR} to .gitignore`, root, [types_1.MIGRATE_RUNS_RELATIVE_DIR]);
|
|
64
67
|
if (sha) {
|
|
65
68
|
logger_1.logger.info(pc.dim(` Commit: ${sha}`));
|
|
66
69
|
}
|
|
@@ -20,7 +20,9 @@ export declare function mkdirSafely(dir: string, purpose: string): void;
|
|
|
20
20
|
*/
|
|
21
21
|
export declare function initRunDir(workspaceRoot: string, runId: string): string;
|
|
22
22
|
/**
|
|
23
|
-
* Absolute path of the handoff file for a migration step within a run
|
|
23
|
+
* Absolute path of the handoff file for a migration step within a run, under
|
|
24
|
+
* the run directory's `handoffs/` subtree: the pre-authorized write scope
|
|
25
|
+
* stops there, so a handoff placed anywhere else costs an approval prompt.
|
|
24
26
|
* The package's scope (if any) becomes a real subdirectory so the package name
|
|
25
27
|
* stays readable; two packages can ship a migration with the same name without
|
|
26
28
|
* colliding because they land in different package subdirectories. Each
|
|
@@ -72,14 +72,16 @@ function sanitizeSegment(value) {
|
|
|
72
72
|
return sanitized || '_';
|
|
73
73
|
}
|
|
74
74
|
/**
|
|
75
|
-
* Absolute path of the handoff file for a migration step within a run
|
|
75
|
+
* Absolute path of the handoff file for a migration step within a run, under
|
|
76
|
+
* the run directory's `handoffs/` subtree: the pre-authorized write scope
|
|
77
|
+
* stops there, so a handoff placed anywhere else costs an approval prompt.
|
|
76
78
|
* The package's scope (if any) becomes a real subdirectory so the package name
|
|
77
79
|
* stays readable; two packages can ship a migration with the same name without
|
|
78
80
|
* colliding because they land in different package subdirectories. Each
|
|
79
81
|
* segment is sanitized so the path is always writable on every platform.
|
|
80
82
|
*/
|
|
81
83
|
function stepHandoffPath(runDir, migration) {
|
|
82
|
-
return (0, path_1.join)(runDir, ...migration.package.split('/').map(sanitizeSegment), `${sanitizeSegment(migration.name)}.json`);
|
|
84
|
+
return (0, path_1.join)(runDir, types_1.HANDOFFS_DIR_NAME, ...migration.package.split('/').map(sanitizeSegment), `${sanitizeSegment(migration.name)}.json`);
|
|
83
85
|
}
|
|
84
86
|
/**
|
|
85
87
|
* Reads and validates a handoff file written by an agent. Returns a tagged
|
|
@@ -41,10 +41,11 @@ async function runAgentic(args) {
|
|
|
41
41
|
});
|
|
42
42
|
}
|
|
43
43
|
// Counts SIGINTs while the agent runs. Non-zero after exit means the
|
|
44
|
-
// user pressed Ctrl+C → skip the ambiguous abort/continue prompt
|
|
45
|
-
//
|
|
46
|
-
// (ERR_USE_AFTER_CLOSE, setRawMode EIO)
|
|
47
|
-
//
|
|
44
|
+
// user pressed Ctrl+C → skip the ambiguous abort/continue prompt. Prompting
|
|
45
|
+
// in the TTY state left by a SIGINT-killed child misbehaved under enquirer
|
|
46
|
+
// (ERR_USE_AFTER_CLOSE, setRawMode EIO) from async chains `await` could not
|
|
47
|
+
// catch. Whether @clack/prompts shares that fault is unverified, so the skip
|
|
48
|
+
// stays; reproducing it needs a real terminal.
|
|
48
49
|
let userInterruptCount = 0;
|
|
49
50
|
const swallowSigint = () => {
|
|
50
51
|
userInterruptCount++;
|
|
@@ -279,9 +280,10 @@ async function resolveFromHandoffOrPrompt(handoffFilePath, userInterrupted = fal
|
|
|
279
280
|
};
|
|
280
281
|
if (userInterrupted) {
|
|
281
282
|
// User pressed Ctrl+C. Don't show the abort/continue prompt — they
|
|
282
|
-
// already told us what they want
|
|
283
|
-
// SIGINT-killed child
|
|
284
|
-
// ERR_USE_AFTER_CLOSE bugs
|
|
283
|
+
// already told us what they want. Prompting in the TTY state left by a
|
|
284
|
+
// SIGINT-killed child also tripped enquirer's setRawMode-EIO and
|
|
285
|
+
// ERR_USE_AFTER_CLOSE bugs; whether @clack/prompts shares that fault is
|
|
286
|
+
// unverified, so the skip stays. The orchestrator's standard failure
|
|
285
287
|
// cascade surfaces the abort outcome.
|
|
286
288
|
//
|
|
287
289
|
// Forward the underlying cause as pre-rendered summary lines so the
|
|
@@ -357,13 +359,14 @@ function escapeCmdCommand(arg) {
|
|
|
357
359
|
}
|
|
358
360
|
async function promptAmbiguous(cause) {
|
|
359
361
|
// stderr blank line so the spacer lands in the same stream as output.warn
|
|
360
|
-
// and the
|
|
361
|
-
//
|
|
362
|
+
// and the prompt — buffered stdout could otherwise reorder it and glue the
|
|
363
|
+
// prompt to the agent's trailing exit message.
|
|
362
364
|
process.stderr.write('\n');
|
|
363
|
-
// Cause rendered ABOVE the prompt rather than inlined into
|
|
364
|
-
// enquirer's select redraw
|
|
365
|
-
// restore (raw \n-split count), so a multi-line message
|
|
366
|
-
// cells on arrow-key re-renders.
|
|
365
|
+
// Cause rendered ABOVE the prompt rather than inlined into its message:
|
|
366
|
+
// enquirer's select redraw used different math for clear (wrap-aware) vs
|
|
367
|
+
// restore (raw \n-split count), so a multi-line message could leave orphaned
|
|
368
|
+
// cells on arrow-key re-renders. Kept single-line because that constraint is
|
|
369
|
+
// unverified under @clack/prompts, not because the cause still applies.
|
|
367
370
|
const causeLines = describeAmbiguousCause(cause);
|
|
368
371
|
if (causeLines.length > 0) {
|
|
369
372
|
output_1.output.warn({
|
|
@@ -371,24 +374,21 @@ async function promptAmbiguous(cause) {
|
|
|
371
374
|
bodyLines: causeLines,
|
|
372
375
|
});
|
|
373
376
|
}
|
|
374
|
-
//
|
|
375
|
-
//
|
|
376
|
-
// Any other rejection we treat as abort.
|
|
377
|
+
// Cancelling exits 130 from inside the prompt; any other rejection is an
|
|
378
|
+
// abort.
|
|
377
379
|
try {
|
|
378
|
-
const
|
|
379
|
-
name: 'choice',
|
|
380
|
-
type: 'select',
|
|
380
|
+
const choice = await (0, safe_prompt_1.migrateChoice)({
|
|
381
381
|
message: 'How should nx migrate proceed?',
|
|
382
382
|
choices: [
|
|
383
|
-
{
|
|
383
|
+
{ value: 'abort', label: 'Treat as failed — abort the run' },
|
|
384
384
|
{
|
|
385
|
-
|
|
386
|
-
|
|
385
|
+
value: 'continue',
|
|
386
|
+
label: 'Treat as completed — mark done and continue',
|
|
387
387
|
},
|
|
388
388
|
],
|
|
389
389
|
});
|
|
390
|
-
(0, migrate_analytics_1.reportMigratePrompt)('ambiguous_agent_outcome',
|
|
391
|
-
return
|
|
390
|
+
(0, migrate_analytics_1.reportMigratePrompt)('ambiguous_agent_outcome', choice);
|
|
391
|
+
return choice === 'continue'
|
|
392
392
|
? { kind: 'ambiguous-continue' }
|
|
393
393
|
: { kind: 'ambiguous-abort' };
|
|
394
394
|
}
|
|
@@ -2,11 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.resolveAgentic = resolveAgentic;
|
|
4
4
|
exports.resolveShouldRunValidation = resolveShouldRunValidation;
|
|
5
|
-
const tslib_1 = require("tslib");
|
|
6
5
|
const fs_1 = require("fs");
|
|
7
6
|
const jsonc_parser_1 = require("jsonc-parser");
|
|
8
7
|
const path_1 = require("path");
|
|
9
|
-
const pc = tslib_1.__importStar(require("picocolors"));
|
|
10
8
|
const output_1 = require("../../../utils/output");
|
|
11
9
|
const workspace_root_1 = require("../../../utils/workspace-root");
|
|
12
10
|
const migrate_analytics_1 = require("../migrate-analytics");
|
|
@@ -129,46 +127,40 @@ async function firePromptForAgentic(migrations, detected) {
|
|
|
129
127
|
const pinChoice = multipleAgents
|
|
130
128
|
? [
|
|
131
129
|
{
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
130
|
+
value: 'yes-pin',
|
|
131
|
+
label: 'Yes, always with the same agent',
|
|
132
|
+
hint: rememberHint,
|
|
135
133
|
},
|
|
136
134
|
]
|
|
137
135
|
: [];
|
|
138
136
|
const choices = [
|
|
139
137
|
{
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
138
|
+
value: 'yes-once',
|
|
139
|
+
label: 'Yes, just this time',
|
|
140
|
+
hint: applyHint,
|
|
143
141
|
},
|
|
144
142
|
{
|
|
145
|
-
|
|
146
|
-
|
|
143
|
+
value: 'yes-flex',
|
|
144
|
+
label: multipleAgents
|
|
147
145
|
? "Yes, always (I'll pick the agent each run)"
|
|
148
146
|
: 'Yes, always',
|
|
149
|
-
|
|
147
|
+
hint: rememberHint,
|
|
150
148
|
},
|
|
151
149
|
...pinChoice,
|
|
152
|
-
{
|
|
153
|
-
{
|
|
150
|
+
{ value: 'no-once', label: 'No, just this time', hint: skipHint },
|
|
151
|
+
{ value: 'no-never', label: 'No, never', hint: rememberHint },
|
|
154
152
|
];
|
|
155
153
|
// Blank line keeps the prompt from gluing to the previous `npm install`
|
|
156
154
|
// output or any earlier orchestrator line.
|
|
157
155
|
console.log();
|
|
158
|
-
//
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
type: 'select',
|
|
156
|
+
// Each choice's hint renders beside it, so the description no longer needs a
|
|
157
|
+
// footer that tracks the cursor.
|
|
158
|
+
const choice = await (0, safe_prompt_1.migrateChoice)({
|
|
162
159
|
message: 'Enable the agentic flow?',
|
|
163
160
|
choices,
|
|
164
|
-
initial: 0,
|
|
165
|
-
footer: function () {
|
|
166
|
-
const focused = this.focused;
|
|
167
|
-
return focused?.description ? pc.dim(` ${focused.description}`) : '';
|
|
168
|
-
},
|
|
169
161
|
});
|
|
170
|
-
(0, migrate_analytics_1.reportMigratePrompt)('agentic',
|
|
171
|
-
switch (
|
|
162
|
+
(0, migrate_analytics_1.reportMigratePrompt)('agentic', choice);
|
|
163
|
+
switch (choice) {
|
|
172
164
|
case 'yes-once':
|
|
173
165
|
return { enabled: true };
|
|
174
166
|
case 'yes-flex':
|
|
@@ -250,12 +242,10 @@ async function selectAgent(detected, explicitId, isInteractive) {
|
|
|
250
242
|
requireInteractiveOrAbort(isInteractive);
|
|
251
243
|
// Blank line keeps the prompt from gluing to the preceding output.
|
|
252
244
|
console.log();
|
|
253
|
-
const
|
|
254
|
-
name: 'id',
|
|
255
|
-
type: 'select',
|
|
245
|
+
const id = await (0, safe_prompt_1.migrateChoice)({
|
|
256
246
|
message: 'Multiple AI agents detected. Which one should Nx use?',
|
|
257
|
-
choices: detected.map((d) => ({
|
|
247
|
+
choices: detected.map((d) => ({ value: d.id, label: d.displayName })),
|
|
258
248
|
});
|
|
259
|
-
(0, migrate_analytics_1.reportMigratePrompt)('agent_select',
|
|
260
|
-
return detected.find((d) => d.id ===
|
|
249
|
+
(0, migrate_analytics_1.reportMigratePrompt)('agent_select', id);
|
|
250
|
+
return detected.find((d) => d.id === id);
|
|
261
251
|
}
|