nx 23.2.0-beta.7 → 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.
Files changed (130) hide show
  1. package/dist/bin/init-local.js +3 -5
  2. package/dist/release/changelog-renderer/index.js +4 -5
  3. package/dist/src/adapter/ngcli-adapter.js +60 -1
  4. package/dist/src/command-line/completion/command-object.js +7 -12
  5. package/dist/src/command-line/configure-ai-agents/configure-ai-agents.js +17 -23
  6. package/dist/src/command-line/generate/generate.js +35 -35
  7. package/dist/src/command-line/import/import.js +18 -40
  8. package/dist/src/command-line/init/ai-agent-prompts.js +5 -11
  9. package/dist/src/command-line/init/command-object.js +4 -2
  10. package/dist/src/command-line/init/implementation/add-nx-to-monorepo.js +12 -32
  11. package/dist/src/command-line/init/implementation/add-nx-to-nest.js +8 -21
  12. package/dist/src/command-line/init/implementation/add-nx-to-npm-repo.js +8 -21
  13. package/dist/src/command-line/init/implementation/angular/index.js +6 -15
  14. package/dist/src/command-line/init/init-v1.js +8 -18
  15. package/dist/src/command-line/init/init-v2.js +26 -56
  16. package/dist/src/command-line/migrate/agentic/definitions.js +35 -8
  17. package/dist/src/command-line/migrate/agentic/handoff-gitignore.d.ts +22 -3
  18. package/dist/src/command-line/migrate/agentic/handoff-gitignore.js +13 -10
  19. package/dist/src/command-line/migrate/agentic/handoff.d.ts +3 -1
  20. package/dist/src/command-line/migrate/agentic/handoff.js +4 -2
  21. package/dist/src/command-line/migrate/agentic/run-step.js +1 -0
  22. package/dist/src/command-line/migrate/agentic/runner.js +24 -24
  23. package/dist/src/command-line/migrate/agentic/select.js +20 -30
  24. package/dist/src/command-line/migrate/agentic/types.d.ts +19 -3
  25. package/dist/src/command-line/migrate/agentic/types.js +13 -4
  26. package/dist/src/command-line/migrate/command-object.d.ts +3 -0
  27. package/dist/src/command-line/migrate/command-object.js +13 -0
  28. package/dist/src/command-line/migrate/execute-migration.d.ts +14 -0
  29. package/dist/src/command-line/migrate/execute-migration.js +30 -9
  30. package/dist/src/command-line/migrate/migrate-analytics.d.ts +28 -0
  31. package/dist/src/command-line/migrate/migrate-analytics.js +51 -1
  32. package/dist/src/command-line/migrate/migrate-commits.d.ts +8 -2
  33. package/dist/src/command-line/migrate/migrate-commits.js +66 -19
  34. package/dist/src/command-line/migrate/migrate-config.d.ts +4 -2
  35. package/dist/src/command-line/migrate/migrate-config.js +12 -4
  36. package/dist/src/command-line/migrate/migrate.d.ts +9 -2
  37. package/dist/src/command-line/migrate/migrate.js +179 -56
  38. package/dist/src/command-line/migrate/multi-major.js +7 -10
  39. package/dist/src/command-line/migrate/resolve-package-version.js +4 -8
  40. package/dist/src/command-line/migrate/run/agent-output.d.ts +20 -0
  41. package/dist/src/command-line/migrate/run/agent-output.js +65 -0
  42. package/dist/src/command-line/migrate/run/index.d.ts +7 -0
  43. package/dist/src/command-line/migrate/run/index.js +19 -1
  44. package/dist/src/command-line/migrate/run/orchestrator.d.ts +20 -0
  45. package/dist/src/command-line/migrate/run/orchestrator.js +1200 -0
  46. package/dist/src/command-line/migrate/run/run-id.d.ts +16 -0
  47. package/dist/src/command-line/migrate/run/run-id.js +56 -0
  48. package/dist/src/command-line/migrate/run/run-state.d.ts +157 -0
  49. package/dist/src/command-line/migrate/run/run-state.js +438 -0
  50. package/dist/src/command-line/migrate/run/state-lock.d.ts +25 -0
  51. package/dist/src/command-line/migrate/run/state-lock.js +76 -0
  52. package/dist/src/command-line/migrate/run/state-machine.d.ts +84 -0
  53. package/dist/src/command-line/migrate/run/state-machine.js +315 -0
  54. package/dist/src/command-line/migrate/run/util.d.ts +58 -0
  55. package/dist/src/command-line/migrate/run/util.js +139 -7
  56. package/dist/src/command-line/migrate/run/worker.d.ts +1 -0
  57. package/dist/src/command-line/migrate/run/worker.js +308 -45
  58. package/dist/src/command-line/migrate/safe-prompt.d.ts +14 -26
  59. package/dist/src/command-line/migrate/safe-prompt.js +32 -43
  60. package/dist/src/command-line/migrate/step-actions.d.ts +5 -0
  61. package/dist/src/command-line/migrate/step-actions.js +12 -0
  62. package/dist/src/command-line/migrate/text.d.ts +18 -0
  63. package/dist/src/command-line/migrate/text.js +26 -0
  64. package/dist/src/command-line/migrate/version-skew-guard.d.ts +6 -4
  65. package/dist/src/command-line/migrate/version-skew-guard.js +34 -14
  66. package/dist/src/command-line/nx-cloud/connect/connect-to-nx-cloud.js +16 -20
  67. package/dist/src/command-line/release/changelog.js +6 -17
  68. package/dist/src/command-line/release/plan.js +15 -28
  69. package/dist/src/command-line/release/release.js +6 -17
  70. package/dist/src/command-line/release/utils/remote-release-clients/github.js +16 -22
  71. package/dist/src/command-line/release/utils/remote-release-clients/gitlab.js +13 -22
  72. package/dist/src/command-line/release/utils/resolve-semver-specifier.js +19 -41
  73. package/dist/src/command-line/release/version/resolve-current-version.js +7 -10
  74. package/dist/src/core/graph/main.js +1 -1
  75. package/dist/src/devkit-internals.d.ts +2 -0
  76. package/dist/src/devkit-internals.js +12 -4
  77. package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.d.ts +12 -0
  78. package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.js +250 -0
  79. package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.md +50 -0
  80. package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
  81. package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
  82. package/dist/src/plugins/js/lock-file/bun-parser.js +43 -10
  83. package/dist/src/project-graph/utils/project-configuration/target-normalization.js +128 -2
  84. package/dist/src/tasks-runner/run-command.js +17 -32
  85. package/dist/src/tasks-runner/task-env.js +5 -2
  86. package/dist/src/tasks-runner/utils.js +2 -6
  87. package/dist/src/utils/analytics-prompt.js +4 -7
  88. package/dist/src/utils/exit-codes.d.ts +9 -0
  89. package/dist/src/utils/exit-codes.js +19 -0
  90. package/dist/src/utils/fileutils.d.ts +5 -0
  91. package/dist/src/utils/fileutils.js +7 -2
  92. package/dist/src/utils/git-utils.d.ts +33 -2
  93. package/dist/src/utils/git-utils.js +156 -8
  94. package/dist/src/utils/long-running-target.d.ts +10 -0
  95. package/dist/src/utils/long-running-target.js +19 -0
  96. package/dist/src/utils/min-release-age/behavior/bun.js +7 -11
  97. package/dist/src/utils/min-release-age/behavior/npm.js +5 -2
  98. package/dist/src/utils/min-release-age/packument.js +1 -1
  99. package/dist/src/utils/nx-console-prompt.js +3 -6
  100. package/dist/src/utils/package-manager-config/bunfig.d.ts +14 -0
  101. package/dist/src/utils/package-manager-config/bunfig.js +49 -0
  102. package/dist/src/utils/package-manager-config/npmrc.d.ts +23 -0
  103. package/dist/src/utils/package-manager-config/npmrc.js +124 -0
  104. package/dist/src/utils/package-manager-config/pnpm-config.d.ts +17 -0
  105. package/dist/src/utils/package-manager-config/pnpm-config.js +60 -0
  106. package/dist/src/utils/package-manager.d.ts +21 -2
  107. package/dist/src/utils/package-manager.js +244 -47
  108. package/dist/src/utils/params.d.ts +7 -1
  109. package/dist/src/utils/params.js +64 -6
  110. package/dist/src/utils/prompt-helpers.d.ts +53 -0
  111. package/dist/src/utils/prompt-helpers.js +111 -0
  112. package/dist/src/utils/provenance.js +6 -14
  113. package/dist/src/utils/registry-config/bun.d.ts +2 -0
  114. package/dist/src/utils/registry-config/bun.js +257 -0
  115. package/dist/src/utils/registry-config/index.d.ts +13 -0
  116. package/dist/src/utils/registry-config/index.js +102 -0
  117. package/dist/src/utils/registry-config/pnpm.d.ts +2 -0
  118. package/dist/src/utils/registry-config/pnpm.js +1551 -0
  119. package/dist/src/utils/registry-config/utils.d.ts +195 -0
  120. package/dist/src/utils/registry-config/utils.js +496 -0
  121. package/dist/src/utils/registry-config/yarn-berry.d.ts +2 -0
  122. package/dist/src/utils/registry-config/yarn-berry.js +612 -0
  123. package/dist/src/utils/registry-config/yarn-classic.d.ts +2 -0
  124. package/dist/src/utils/registry-config/yarn-classic.js +1001 -0
  125. package/dist/src/utils/safe-spawn.d.ts +24 -0
  126. package/dist/src/utils/safe-spawn.js +104 -0
  127. package/migrations.json +6 -0
  128. package/package.json +17 -13
  129. package/dist/src/utils/min-release-age/npmrc.d.ts +0 -15
  130. package/dist/src/utils/min-release-age/npmrc.js +0 -45
@@ -9,7 +9,7 @@ exports.createFetcher = createFetcher;
9
9
  exports.generateMigrationsJsonAndUpdatePackageJson = generateMigrationsJsonAndUpdatePackageJson;
10
10
  exports.formatSkippedPromptsNextStep = formatSkippedPromptsNextStep;
11
11
  exports.executeMigrations = executeMigrations;
12
- exports.isSingleMigrationInvocation = isSingleMigrationInvocation;
12
+ exports.isRunPhaseInvocation = isRunPhaseInvocation;
13
13
  exports.migrate = migrate;
14
14
  exports.readLocalNxVersion = readLocalNxVersion;
15
15
  exports.runMigration = runMigration;
@@ -31,7 +31,6 @@ const write_formatted_json_file_1 = require("../../utils/write-formatted-json-fi
31
31
  const shell_quoting_1 = require("../../utils/shell-quoting");
32
32
  const logger_1 = require("../../utils/logger");
33
33
  const git_utils_1 = require("../../utils/git-utils");
34
- const command_line_utils_1 = require("../../utils/command-line-utils");
35
34
  const package_json_1 = require("../../utils/package-json");
36
35
  const package_manager_1 = require("../../utils/package-manager");
37
36
  const errors_1 = require("../../utils/min-release-age/errors");
@@ -66,7 +65,9 @@ Object.defineProperty(exports, "filterDowngradedUpdates", { enumerable: true, ge
66
65
  const version_utils_1 = require("./version-utils");
67
66
  Object.defineProperty(exports, "normalizeVersion", { enumerable: true, get: function () { return version_utils_1.normalizeVersion; } });
68
67
  const execute_migration_1 = require("./execute-migration");
68
+ const step_actions_1 = require("./step-actions");
69
69
  const sort_migrations_1 = require("./sort-migrations");
70
+ const inception_1 = require("./agentic/inception");
70
71
  const version_skew_guard_1 = require("./version-skew-guard");
71
72
  const versions_1 = require("../../utils/versions");
72
73
  tslib_1.__exportStar(require("./execute-migration"), exports);
@@ -476,17 +477,14 @@ class Migrator {
476
477
  // a same prompt was already answered, skip
477
478
  return Promise.resolve(false);
478
479
  }
479
- const promptConfig = {
480
- name: 'shouldApply',
481
- type: 'confirm',
482
- message: packageUpdate['x-prompt'],
480
+ // No footer slot, so the docs link is appended to the message.
481
+ const detailsLink = packageName.startsWith('@nx/')
482
+ ? pc.dim(`\n View migration details at https://nx.dev/nx-api/${packageName.replace('@nx/', '')}#${packageUpdateKey.replace(/[-\.]/g, '')}packageupdates`)
483
+ : '';
484
+ return await (0, safe_prompt_1.migrateConfirm)({
485
+ message: `${packageUpdate['x-prompt']}${detailsLink}`,
483
486
  initial: true,
484
- };
485
- if (packageName.startsWith('@nx/')) {
486
- // @ts-expect-error -- enquirer types aren't correct, footer does exist
487
- promptConfig.footer = () => pc.dim(` View migration details at https://nx.dev/nx-api/${packageName.replace('@nx/', '')}#${packageUpdateKey.replace(/[-\.]/g, '')}packageupdates`);
488
- }
489
- return await (0, safe_prompt_1.migratePrompt)([promptConfig]).then(({ shouldApply }) => {
487
+ }).then((shouldApply) => {
490
488
  this.promptAnswers[promptKey] = shouldApply;
491
489
  if (!shouldApply &&
492
490
  (!this.minVersionWithSkippedUpdates ||
@@ -587,8 +585,8 @@ async function resolveInclude(include, context, configuredInclude) {
587
585
  }
588
586
  const choices = [
589
587
  {
590
- name: 'required',
591
- message: 'Required only (the target package and the packages it ships with)',
588
+ value: 'required',
589
+ label: 'Required only (the target package and the packages it ships with)',
592
590
  },
593
591
  ];
594
592
  // `--interactive` keeps the legacy x-prompt flow, which the `optional` value
@@ -597,8 +595,8 @@ async function resolveInclude(include, context, configuredInclude) {
597
595
  !context.hasExcludeAppliedMigrations &&
598
596
  context.interactive !== true) {
599
597
  choices.push({
600
- name: 'optional',
601
- message: 'Optional only (the dependency updates those packages recommend)',
598
+ value: 'optional',
599
+ label: 'Optional only (the dependency updates those packages recommend)',
602
600
  });
603
601
  }
604
602
  if (!(0, safe_prompt_1.canPrompt)(context.interactive)) {
@@ -606,12 +604,10 @@ async function resolveInclude(include, context, configuredInclude) {
606
604
  return 'all';
607
605
  }
608
606
  choices.push({
609
- name: 'all',
610
- message: 'All (required and optional)',
607
+ value: 'all',
608
+ label: 'All (required and optional)',
611
609
  });
612
- const { include: selected } = await (0, safe_prompt_1.migratePrompt)({
613
- type: 'select',
614
- name: 'include',
610
+ const selected = await (0, safe_prompt_1.migrateChoice)({
615
611
  message: 'Which packages would you like to migrate?',
616
612
  choices,
617
613
  });
@@ -671,10 +667,25 @@ async function parseTargetPackageAndVersion(args) {
671
667
  return { targetPackage: args, targetVersion: 'latest' };
672
668
  }
673
669
  async function parseMigrationsOptions(options, fetch) {
670
+ // A run recorded or reconciled via `--run-id` is driven by the outer agent;
671
+ // spawning another agent from it would double-drive the run. Only the
672
+ // explicit "on" values conflict; the nx.json default is ignored for
673
+ // `--run-id` invocations instead.
674
+ if (options.runId !== undefined &&
675
+ options.agentic !== undefined &&
676
+ options.agentic !== false) {
677
+ throw new Error(`Error: '--agentic' cannot be combined with '--run-id'.`);
678
+ }
674
679
  if (options.runMigration !== undefined) {
675
680
  if (options.runMigration === '') {
676
681
  throw new Error(`Error: '--run-migration' requires a migration id, e.g. '--run-migration=@nx/js:my-migration'.`);
677
682
  }
683
+ if (options.runId === '') {
684
+ throw new Error(`Error: '--run-id' requires the id of the migrate run to record into.`);
685
+ }
686
+ if (options.stepAction !== undefined) {
687
+ throw new Error(`Error: '--step-action' cannot be combined with '--run-migration'. It applies to an orchestrated reconcile ('--run-id' without '--run-migration').`);
688
+ }
678
689
  if (options.runMigrations !== undefined) {
679
690
  throw new Error(`Error: '--run-migration' (run a single migration) cannot be combined with '--run-migrations' (run the whole migrations file).`);
680
691
  }
@@ -692,11 +703,39 @@ async function parseMigrationsOptions(options, fetch) {
692
703
  return {
693
704
  type: 'runSingleMigration',
694
705
  runMigration: options.runMigration,
706
+ runId: options.runId,
695
707
  agentic: options.agentic,
696
708
  validate: options.validate,
697
709
  interactive: options.interactive,
698
710
  };
699
711
  }
712
+ if (options.runId !== undefined) {
713
+ // Empty '--run-id' is an error on every path.
714
+ if (options.runId === '') {
715
+ throw new Error(`Error: '--run-id' requires the id of the migrate run to record into.`);
716
+ }
717
+ if (options.runMigrations !== undefined) {
718
+ throw new Error(`Error: '--run-id' (reconcile an orchestrated run) cannot be combined with '--run-migrations' (run the whole migrations file).`);
719
+ }
720
+ // A bare '--run-id' reconciles the run it names. Ungated, unlike init:
721
+ // the id has to name a run directory that exists, and only a gated init
722
+ // ever creates one.
723
+ // yargs' choices already reject bad CLI values; this guards programmatic
724
+ // callers, where silently dropping the action would reconcile without it.
725
+ if (options.stepAction !== undefined && !(0, step_actions_1.isStepAction)(options.stepAction)) {
726
+ throw new Error(`Error: '--step-action' must be one of ${step_actions_1.STEP_ACTIONS.join(', ')}.`);
727
+ }
728
+ return {
729
+ type: 'orchestratorReconcile',
730
+ runId: options.runId,
731
+ ...(options.stepAction !== undefined
732
+ ? { stepAction: options.stepAction }
733
+ : {}),
734
+ };
735
+ }
736
+ if (options.stepAction !== undefined) {
737
+ throw new Error(`Error: '--step-action' requires '--run-id'.`);
738
+ }
700
739
  if (options.runMigrations === '') {
701
740
  options.runMigrations = 'migrations.json';
702
741
  }
@@ -1121,8 +1160,30 @@ async function getPackageMigrationsUsingRegistry(packageName, packageVersion) {
1121
1160
  // try to obtain the migrations from the registry directly
1122
1161
  return await downloadPackageMigrationsFromRegistry(packageName, packageVersion, migrationsConfig);
1123
1162
  }
1163
+ // Matched exactly: a hostname that merely contains one of these is a different
1164
+ // registry. registry.yarnpkg.com is npmjs' CNAME, so it serves the same
1165
+ // metadata; the two loopback literals are the spellings of a local registry
1166
+ // that the substring below cannot reach, since neither contains "localhost".
1167
+ const FULL_METADATA_REGISTRIES = [
1168
+ 'registry.npmjs.org',
1169
+ 'registry.yarnpkg.com',
1170
+ '127.0.0.1',
1171
+ '[::1]',
1172
+ ];
1173
+ // Matched as substrings, since neither names a single host: a local registry
1174
+ // can sit on a subdomain of localhost, and an Artifactory instance is
1175
+ // identified only by that word appearing somewhere in its hostname.
1176
+ const FULL_METADATA_REGISTRY_MARKERS = [
1177
+ 'localhost',
1178
+ 'artifactory',
1179
+ ];
1124
1180
  async function getPackageMigrationsConfigFromRegistry(packageName, packageVersion) {
1125
- const result = await (0, package_manager_1.packageRegistryView)(packageName, packageVersion, 'nx-migrations ng-update dist --json');
1181
+ const result = await (0, package_manager_1.packageRegistryView)(packageName, packageVersion, [
1182
+ 'nx-migrations',
1183
+ 'ng-update',
1184
+ 'dist',
1185
+ '--json',
1186
+ ]);
1126
1187
  if (!result) {
1127
1188
  return null;
1128
1189
  }
@@ -1130,9 +1191,10 @@ async function getPackageMigrationsConfigFromRegistry(packageName, packageVersio
1130
1191
  if (!json['nx-migrations'] && !json['ng-update']) {
1131
1192
  const registry = new node_url_1.URL('dist' in json ? json.dist.tarball : json.tarball)
1132
1193
  .hostname;
1133
- // Registries other than npmjs and the local registry may not support full metadata via npm view
1134
- // so throw error so that fetcher falls back to getting config via install
1135
- if (!['registry.npmjs.org', 'localhost', 'artifactory'].some((v) => registry.includes(v))) {
1194
+ // Other registries may not support full metadata via npm view; throw to
1195
+ // trigger the install fallback.
1196
+ if (!FULL_METADATA_REGISTRIES.includes(registry) &&
1197
+ !FULL_METADATA_REGISTRY_MARKERS.some((v) => registry.includes(v))) {
1136
1198
  throw new Error(`Getting migration config from registry is not supported from ${registry}`);
1137
1199
  }
1138
1200
  }
@@ -2024,6 +2086,46 @@ async function runMigrations(root, opts, args, isVerbose, shouldCreateCommits, c
2024
2086
  }
2025
2087
  const migrationsJson = (0, fileutils_1.readJsonFile)((0, path_1.join)(root, opts.runMigrations));
2026
2088
  const migrations = migrationsJson.migrations;
2089
+ // An outer agent drives the loop, so hand off to the orchestrator instead of
2090
+ // the classic loop: init either starts a fresh run or resumes an already-
2091
+ // active one. `--run-id` reconciles are dispatched separately and never
2092
+ // reach here.
2093
+ if (process.env.NX_MIGRATE_ORCHESTRATOR === 'true' && (0, inception_1.isInsideAgent)()) {
2094
+ // Orchestrated runs are agent-driven, so commits default on exactly as they
2095
+ // do under `--agentic=enabled`; the orchestrator replaces `resolveAgentic`.
2096
+ const { effective: effectiveCreateCommits, warning: createCommitsWarning, error: createCommitsError, } = (0, migrate_commits_1.resolveCreateCommits)({
2097
+ createCommits: shouldCreateCommits,
2098
+ mode: 'orchestrated',
2099
+ isGitRepo: (0, git_utils_1.isGitRepository)(root),
2100
+ commitPrefixIsCustom: commitPrefix !== command_object_1.DEFAULT_MIGRATION_COMMIT_PREFIX,
2101
+ });
2102
+ if (createCommitsError) {
2103
+ throw new Error(createCommitsError);
2104
+ }
2105
+ if (createCommitsWarning) {
2106
+ output_1.output.warn({ title: createCommitsWarning });
2107
+ }
2108
+ // The run commits on the user's behalf across many invocations, so the
2109
+ // default-branch confirmation belongs here, once, before any of them.
2110
+ if (effectiveCreateCommits &&
2111
+ (0, safe_prompt_1.canPrompt)(opts.interactive) &&
2112
+ !(await (0, migrate_commits_1.confirmMigrationCommitsOnDefaultBranch)(root, 'running migrations'))) {
2113
+ return;
2114
+ }
2115
+ const { packageJson: orchestratorNxPackageJson } = (0, package_json_1.readModulePackageJson)('nx', (0, installation_directory_1.getNxRequirePaths)(root));
2116
+ const { runOrchestratorInit } = require('./run');
2117
+ return await runOrchestratorInit({
2118
+ root,
2119
+ migrationsJson,
2120
+ createCommits: effectiveCreateCommits,
2121
+ commitPrefix,
2122
+ // The flag only, never NX_MIGRATE_SKIP_INSTALL: the wrapper's local
2123
+ // re-exec sets that env var for its own hop, and it says nothing about
2124
+ // what the user asked for.
2125
+ skipInstall: shouldSkipInstall,
2126
+ installedNxVersion: orchestratorNxPackageJson.version,
2127
+ });
2128
+ }
2027
2129
  (0, migrate_analytics_1.reportMigrateRunStart)({
2028
2130
  createCommits: shouldCreateCommits ?? false,
2029
2131
  migrationCount: migrations.length,
@@ -2043,7 +2145,7 @@ async function runMigrations(root, opts, args, isVerbose, shouldCreateCommits, c
2043
2145
  }
2044
2146
  const { effective: effectiveCreateCommits, agenticHasDiffContext, warning: createCommitsWarning, error: createCommitsError, } = (0, migrate_commits_1.resolveCreateCommits)({
2045
2147
  createCommits: shouldCreateCommits,
2046
- agenticKind: agentic.kind,
2148
+ mode: agentic.kind,
2047
2149
  isGitRepo: (0, git_utils_1.isGitRepository)(root),
2048
2150
  commitPrefixIsCustom: commitPrefix !== command_object_1.DEFAULT_MIGRATION_COMMIT_PREFIX,
2049
2151
  });
@@ -2053,24 +2155,10 @@ async function runMigrations(root, opts, args, isVerbose, shouldCreateCommits, c
2053
2155
  if (createCommitsWarning) {
2054
2156
  output_1.output.warn({ title: createCommitsWarning });
2055
2157
  }
2056
- if (effectiveCreateCommits && (0, safe_prompt_1.canPrompt)(opts.interactive)) {
2057
- const currentBranch = (0, git_utils_1.getGitCurrentBranch)(root);
2058
- // `getBaseRef` may carry an `origin/` prefix (set by the CI-workflow
2059
- // generator); compare against the local branch name.
2060
- const defaultBranch = (0, command_line_utils_1.getBaseRef)((0, configuration_1.readNxJson)(root)).replace(/^origin\//, '');
2061
- const proceed = await (0, migrate_commits_1.confirmCommitsOnDefaultBranch)({
2062
- currentBranch,
2063
- defaultBranch,
2064
- });
2065
- if (!proceed) {
2066
- output_1.output.log({
2067
- title: `Skipped running migrations to avoid committing to the default branch '${currentBranch}'.`,
2068
- bodyLines: [
2069
- 'Switch to a different branch and re-run, or re-run and confirm to proceed.',
2070
- ],
2071
- });
2072
- return;
2073
- }
2158
+ if (effectiveCreateCommits &&
2159
+ (0, safe_prompt_1.canPrompt)(opts.interactive) &&
2160
+ !(await (0, migrate_commits_1.confirmMigrationCommitsOnDefaultBranch)(root, 'running migrations'))) {
2161
+ return;
2074
2162
  }
2075
2163
  const shouldRunValidation = resolveShouldRunValidation({
2076
2164
  validate: opts.validate,
@@ -2189,17 +2277,21 @@ async function runMigrations(root, opts, args, isVerbose, shouldCreateCommits, c
2189
2277
  appliedCount,
2190
2278
  });
2191
2279
  }
2192
- function isSingleMigrationInvocation(args) {
2193
- return args.runMigration !== undefined;
2280
+ function isRunPhaseInvocation(args) {
2281
+ return (args.runMigration !== undefined ||
2282
+ args.runId !== undefined ||
2283
+ args.stepAction !== undefined);
2194
2284
  }
2195
2285
  async function migrate(root, args, rawArgs) {
2196
2286
  await client_1.daemonClient.stop();
2197
2287
  return (0, handle_errors_1.handleErrors)(process.env.NX_VERBOSE_LOGGING === 'true', async () => {
2198
2288
  const mergedArgs = (0, migrate_config_1.applyNxJsonMigrateDefaults)(args, (0, configuration_1.readNxJson)().migrate);
2199
- // A single-migration invocation resolves its commit config downstream via
2200
- // resolveCreateCommits, so this assert must not fire for it.
2201
- const singleMigration = isSingleMigrationInvocation(mergedArgs);
2202
- if (!singleMigration) {
2289
+ // Run-phase invocations resolve their commit config downstream (run.json
2290
+ // for recorded runs, resolveCreateCommits for standalone), so this assert
2291
+ // must not fire for them; otherwise an nx.json prefix the whole-file run
2292
+ // legitimately uses would wedge every dispensed command.
2293
+ const runPhase = isRunPhaseInvocation(mergedArgs);
2294
+ if (!runPhase) {
2203
2295
  (0, migrate_config_1.assertCommitPrefixHasCommits)(mergedArgs);
2204
2296
  }
2205
2297
  // One fetcher (registry-first, install fallback) shared by the `--include`
@@ -2207,8 +2299,8 @@ async function migrate(root, args, rawArgs) {
2207
2299
  // at most once per package/version.
2208
2300
  const fetch = createFetcher((0, package_manager_1.getPackageManagerCommand)());
2209
2301
  // `--run-migrations` without a value parses as '', so only undefined (and
2210
- // no single-migration flag) means the generate phase.
2211
- const isGenerateInvocation = mergedArgs['runMigrations'] === undefined && !singleMigration;
2302
+ // no run-phase flag) means the generate phase.
2303
+ const isGenerateInvocation = mergedArgs['runMigrations'] === undefined && !runPhase;
2212
2304
  let opts;
2213
2305
  try {
2214
2306
  opts = await parseMigrationsOptions(mergedArgs, fetch);
@@ -2217,7 +2309,7 @@ async function migrate(root, args, rawArgs) {
2217
2309
  if (isGenerateInvocation) {
2218
2310
  (0, migrate_analytics_1.reportMigrateGenerateError)('resolve_version', e);
2219
2311
  }
2220
- else if (singleMigration) {
2312
+ else if (runPhase) {
2221
2313
  (0, migrate_analytics_1.reportMigrateRunError)({ code: 'other', error: e });
2222
2314
  }
2223
2315
  throw e;
@@ -2240,6 +2332,8 @@ async function migrate(root, args, rawArgs) {
2240
2332
  (0, migrate_analytics_1.reportMigrateRunError)({ code: 'other', error: e });
2241
2333
  throw e;
2242
2334
  }
2335
+ case 'orchestratorReconcile':
2336
+ return await runOrchestratorReconcileFromCli(root, opts, rawArgs);
2243
2337
  case 'runMigrations':
2244
2338
  try {
2245
2339
  return await runMigrations(root, opts, rawArgs, mergedArgs['verbose'], mergedArgs['createCommits'], mergedArgs['commitPrefix'] ?? command_object_1.DEFAULT_MIGRATION_COMMIT_PREFIX, mergedArgs['skipInstall']);
@@ -2425,11 +2519,37 @@ function readNxVersionFromNodeModules(searchPaths) {
2425
2519
  }
2426
2520
  return undefined;
2427
2521
  }
2522
+ // Mirrors the local-nx hand-off of the other run paths so a reconcile always
2523
+ // executes against the workspace-local nx that owns the run state, never the
2524
+ // temp installation. Reconciles only read state and commit, so no install.
2525
+ async function runOrchestratorReconcileFromCli(root, opts, args) {
2526
+ if (!__dirname.startsWith(workspace_root_1.workspaceRoot)) {
2527
+ // The workspace-local nx we are about to hand off to must be new enough to
2528
+ // understand the new flags we forward to it.
2529
+ (0, version_skew_guard_1.assertWorkspaceNxSupportsNewMigrateFlags)({
2530
+ argv: args,
2531
+ readLocalNxVersion: () => readLocalNxVersion(root),
2532
+ });
2533
+ return handOffToLocalNx(args);
2534
+ }
2535
+ const { runOrchestratorReconcile } = require('./run');
2536
+ return runOrchestratorReconcile({
2537
+ root,
2538
+ runId: opts.runId,
2539
+ stepAction: opts.stepAction,
2540
+ });
2541
+ }
2428
2542
  // Keeps `--run-migration` behaving like `--run-migrations` when invoked from
2429
2543
  // a temp `nx@latest` install: same pre-install, same local-nx hand-off.
2430
2544
  async function runSingleMigrationFromCli(root, opts, args, mergedArgs) {
2431
2545
  const shouldSkipInstall = mergedArgs['skipInstall'] ?? false;
2432
- if (!shouldSkipInstall && !process.env.NX_MIGRATE_SKIP_INSTALL) {
2546
+ // A recorded execution skips the pre-install: the run carries its own
2547
+ // install policy and its worker installs what the migration changed, so
2548
+ // paying for a full install ahead of every dispensed command would be
2549
+ // redundant.
2550
+ if (opts.runId === undefined &&
2551
+ !shouldSkipInstall &&
2552
+ !process.env.NX_MIGRATE_SKIP_INSTALL) {
2433
2553
  await (0, execute_migration_1.runInstall)(undefined, 'pre-migration', (0, execute_migration_1.formatSingleMigrationRerunCommand)(opts.runMigration));
2434
2554
  }
2435
2555
  if (!__dirname.startsWith(workspace_root_1.workspaceRoot)) {
@@ -2446,13 +2566,15 @@ async function runSingleMigrationFromCli(root, opts, args, mergedArgs) {
2446
2566
  return handOffToLocalNx(args);
2447
2567
  }
2448
2568
  // The worker resolves the agentic flow, the effective commit config, and
2449
- // the default-branch confirmation itself; hand it the raw flags.
2569
+ // the default-branch confirmation itself; hand it the raw flags. Recorded
2570
+ // runs (--run-id) take their commit config from run.json instead.
2450
2571
  // Lazy-load run/ so plain migrate and repair runs don't pay for the agentic
2451
2572
  // selection chain its barrel pulls in eagerly.
2452
2573
  const { runSingleMigrationWorker } = require('./run');
2453
2574
  await runSingleMigrationWorker({
2454
2575
  root,
2455
2576
  runMigration: opts.runMigration,
2577
+ runId: opts.runId,
2456
2578
  agentic: opts.agentic,
2457
2579
  validate: opts.validate,
2458
2580
  createCommits: mergedArgs['createCommits'],
@@ -2479,7 +2601,8 @@ async function runMigration() {
2479
2601
  const runLocalMigrate = () => runOrReturnExitCode(() => (0, child_process_2.runNxArgvSync)(['_migrate', ...forwardedArgv], {
2480
2602
  stdio: ['inherit', 'inherit', 'inherit'],
2481
2603
  }));
2482
- if (process.env.NX_USE_LOCAL !== 'true' &&
2604
+ if (!(0, version_skew_guard_1.targetsExistingRun)(process.argv.slice(3)) &&
2605
+ process.env.NX_USE_LOCAL !== 'true' &&
2483
2606
  process.env.NX_MIGRATE_USE_LOCAL === undefined) {
2484
2607
  // The version spec mirrors nxCliPath's; keep the two in sync.
2485
2608
  const cliVersionSpec = process.env.NX_MIGRATE_CLI_VERSION || 'latest';
@@ -63,32 +63,29 @@ async function promptMultiMajorMigration(args) {
63
63
  let recommendedMarked = false;
64
64
  if (args.latestInCurrent) {
65
65
  choices.push({
66
- name: args.latestInCurrent,
67
- message: `Migrate to ${args.targetPackage}@${args.latestInCurrent} (latest in current major) [recommended]`,
66
+ value: args.latestInCurrent,
67
+ label: `Migrate to ${args.targetPackage}@${args.latestInCurrent} (latest in current major) [recommended]`,
68
68
  });
69
69
  recommendedMarked = true;
70
70
  }
71
71
  if (args.latestInNext) {
72
72
  choices.push({
73
- name: args.latestInNext,
74
- message: `Migrate to ${args.targetPackage}@${args.latestInNext} (next major)${recommendedMarked ? '' : ' [recommended]'}`,
73
+ value: args.latestInNext,
74
+ label: `Migrate to ${args.targetPackage}@${args.latestInNext} (next major)${recommendedMarked ? '' : ' [recommended]'}`,
75
75
  });
76
76
  }
77
77
  choices.push({
78
- name: args.target,
79
- message: `Migrate directly to ${args.targetPackage}@${args.target}`,
78
+ value: args.target,
79
+ label: `Migrate directly to ${args.targetPackage}@${args.target}`,
80
80
  });
81
81
  output_1.output.log({
82
82
  title: multiMajorHeader(args.targetPackage, args.installed, args.target),
83
83
  bodyLines: multiMajorBodyLines,
84
84
  });
85
- const { chosen } = await (0, safe_prompt_1.migratePrompt)({
86
- type: 'select',
87
- name: 'chosen',
85
+ return (0, safe_prompt_1.migrateChoice)({
88
86
  message: 'How would you like to proceed?',
89
87
  choices,
90
88
  });
91
- return chosen;
92
89
  }
93
90
  // Flag wins over env var; only the two literal values are honoured.
94
91
  function resolveMultiMajorMode(options) {
@@ -198,14 +198,10 @@ async function handleViolation(packageName, error, policy) {
198
198
  const blockedLine = ` ${packageName}@${resolved.version} (published ${formatPublishAge(resolved.publishedAt)})`;
199
199
  // pnpm prompts once for the whole run; remember an approval for later picks.
200
200
  if (!strictApprovalGranted) {
201
- const { approved } = await (0, safe_prompt_1.migratePrompt)([
202
- {
203
- name: 'approved',
204
- type: 'confirm',
205
- initial: false,
206
- message: `The following version does not meet the ${policy.sourceDescription} constraint:\n${blockedLine}\nInstall anyway and add it to minimumReleaseAgeExclude in pnpm-workspace.yaml?`,
207
- },
208
- ]);
201
+ const approved = await (0, safe_prompt_1.migrateConfirm)({
202
+ initial: false,
203
+ message: `The following version does not meet the ${policy.sourceDescription} constraint:\n${blockedLine}\nInstall anyway and add it to minimumReleaseAgeExclude in pnpm-workspace.yaml?`,
204
+ });
209
205
  if (!approved) {
210
206
  // Deny must surface as a violation: migrate.ts only rethrows
211
207
  // MinReleaseAgeViolationError, so a plain Error would silently fall back
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Lines are kept unjoined all the way here on purpose. Joining them and
3
+ * splitting them back turns an injected break into its own entry before this
4
+ * module sees it, indistinguishable from a line the caller meant to write, and
5
+ * nothing downstream can undo that.
6
+ */
7
+ export interface AgentMessage {
8
+ title: string;
9
+ bodyLines?: string[];
10
+ }
11
+ /**
12
+ * The safe form of a set of lines. Exported so a caller that needs the same
13
+ * text twice, once for a human and once inside a block payload, derives both
14
+ * from one array instead of sanitizing one copy and not the other.
15
+ */
16
+ export declare function safeLines(lines: readonly string[]): string[];
17
+ export declare function logToAgent(message: AgentMessage): void;
18
+ export declare function warnToAgent(message: AgentMessage): void;
19
+ export declare function emitStepBlock(runId: string, stepId: string, action: string, payload: object): void;
20
+ export declare function emitPromptBlock(migrationId: string, payload: object): void;
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ // Internal to run/: deliberately not re-exported from ./index.
3
+ //
4
+ // The single writer for everything an orchestrated run puts on stdout. Human
5
+ // lines and the `<nx_migrate_*>` blocks the driving agent parses share that one
6
+ // stream, so a value carrying its own line break could open a forged block.
7
+ //
8
+ // Two boundaries: a thrown error leaves through handleErrors, which prints it
9
+ // outside this guarantee; and migration code is not contained at all (nx
10
+ // `require`s and runs it in process), so the guarantee is that data cannot
11
+ // corrupt the framing, nothing more.
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.safeLines = safeLines;
14
+ exports.logToAgent = logToAgent;
15
+ exports.warnToAgent = warnToAgent;
16
+ exports.emitStepBlock = emitStepBlock;
17
+ exports.emitPromptBlock = emitPromptBlock;
18
+ const output_1 = require("../../../utils/output");
19
+ const print_dropped_agent_context_1 = require("../agentic/print-dropped-agent-context");
20
+ const text_1 = require("../text");
21
+ /**
22
+ * The safe form of a set of lines. Exported so a caller that needs the same
23
+ * text twice, once for a human and once inside a block payload, derives both
24
+ * from one array instead of sanitizing one copy and not the other.
25
+ */
26
+ function safeLines(lines) {
27
+ return lines.map(text_1.singleLine);
28
+ }
29
+ function safe(message) {
30
+ return {
31
+ title: (0, text_1.singleLine)(message.title),
32
+ bodyLines: safeLines(message.bodyLines ?? []),
33
+ };
34
+ }
35
+ function logToAgent(message) {
36
+ output_1.output.log(safe(message));
37
+ }
38
+ function warnToAgent(message) {
39
+ output_1.output.warn(safe(message));
40
+ }
41
+ /**
42
+ * Serializes a block payload. `<` becomes its JSON unicode escape so a raw one
43
+ * in a value cannot forge the closing tag, and the result stays valid JSON for
44
+ * the agent to parse.
45
+ */
46
+ function blockPayload(payload) {
47
+ return JSON.stringify(payload, null, 2).replace(/</g, '\\u003c');
48
+ }
49
+ // A bare newline pair frames the block so adjacent stdout cannot run into it.
50
+ function writeBlock(tag, attrs, json) {
51
+ const attrText = attrs
52
+ .map(([name, value]) => ` ${name}="${(0, print_dropped_agent_context_1.escapeXmlAttr)((0, text_1.singleLine)(value))}"`)
53
+ .join('');
54
+ process.stdout.write(`\n<${tag}${attrText}>\n${json}\n</${tag}>\n\n`);
55
+ }
56
+ function emitStepBlock(runId, stepId, action, payload) {
57
+ writeBlock('nx_migrate_step', [
58
+ ['run-id', runId],
59
+ ['step', stepId],
60
+ ['action', action],
61
+ ], blockPayload(payload));
62
+ }
63
+ function emitPromptBlock(migrationId, payload) {
64
+ writeBlock('nx_migrate_prompt', [['migration', migrationId]], blockPayload(payload));
65
+ }
@@ -1,2 +1,9 @@
1
+ export { CURRENT_RUN_STATE_FORMAT_VERSION, NewerRunStateFormatError, migrateRunsDir, runDir, readRunState, writeRunState, findActiveRun, createRun, } from './run-state';
2
+ export type { MigrateRunStatus, MigrateRunRound, MigrateStepStatus, PromptOutcomeStatus, MigrateStepOutcome, MigrateStepPromptOutcome, MigrateStep, MigrateCommitKind, MigrateCommitLedgerEntry, MigrateRunAnalytics, MigrateRunState, } from './run-state';
3
+ export { applyStepEvent, hasPendingCommitDebt } from './state-machine';
4
+ export type { StepAction, StepEvent, ApplyStepEventResult, } from './state-machine';
5
+ export { createRunId, computePlanHash } from './run-id';
1
6
  export { runSingleMigrationWorker } from './worker';
2
7
  export type { RunSingleMigrationWorkerInput } from './worker';
8
+ export { runOrchestratorInit, runOrchestratorReconcile } from './orchestrator';
9
+ export type { RunOrchestratorInitInput, RunOrchestratorReconcileInput, } from './orchestrator';
@@ -1,5 +1,23 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.runSingleMigrationWorker = void 0;
3
+ exports.runOrchestratorReconcile = exports.runOrchestratorInit = exports.runSingleMigrationWorker = exports.computePlanHash = exports.createRunId = exports.hasPendingCommitDebt = exports.applyStepEvent = exports.createRun = exports.findActiveRun = exports.writeRunState = exports.readRunState = exports.runDir = exports.migrateRunsDir = exports.NewerRunStateFormatError = exports.CURRENT_RUN_STATE_FORMAT_VERSION = void 0;
4
+ var run_state_1 = require("./run-state");
5
+ Object.defineProperty(exports, "CURRENT_RUN_STATE_FORMAT_VERSION", { enumerable: true, get: function () { return run_state_1.CURRENT_RUN_STATE_FORMAT_VERSION; } });
6
+ Object.defineProperty(exports, "NewerRunStateFormatError", { enumerable: true, get: function () { return run_state_1.NewerRunStateFormatError; } });
7
+ Object.defineProperty(exports, "migrateRunsDir", { enumerable: true, get: function () { return run_state_1.migrateRunsDir; } });
8
+ Object.defineProperty(exports, "runDir", { enumerable: true, get: function () { return run_state_1.runDir; } });
9
+ Object.defineProperty(exports, "readRunState", { enumerable: true, get: function () { return run_state_1.readRunState; } });
10
+ Object.defineProperty(exports, "writeRunState", { enumerable: true, get: function () { return run_state_1.writeRunState; } });
11
+ Object.defineProperty(exports, "findActiveRun", { enumerable: true, get: function () { return run_state_1.findActiveRun; } });
12
+ Object.defineProperty(exports, "createRun", { enumerable: true, get: function () { return run_state_1.createRun; } });
13
+ var state_machine_1 = require("./state-machine");
14
+ Object.defineProperty(exports, "applyStepEvent", { enumerable: true, get: function () { return state_machine_1.applyStepEvent; } });
15
+ Object.defineProperty(exports, "hasPendingCommitDebt", { enumerable: true, get: function () { return state_machine_1.hasPendingCommitDebt; } });
16
+ var run_id_1 = require("./run-id");
17
+ Object.defineProperty(exports, "createRunId", { enumerable: true, get: function () { return run_id_1.createRunId; } });
18
+ Object.defineProperty(exports, "computePlanHash", { enumerable: true, get: function () { return run_id_1.computePlanHash; } });
4
19
  var worker_1 = require("./worker");
5
20
  Object.defineProperty(exports, "runSingleMigrationWorker", { enumerable: true, get: function () { return worker_1.runSingleMigrationWorker; } });
21
+ var orchestrator_1 = require("./orchestrator");
22
+ Object.defineProperty(exports, "runOrchestratorInit", { enumerable: true, get: function () { return orchestrator_1.runOrchestratorInit; } });
23
+ Object.defineProperty(exports, "runOrchestratorReconcile", { enumerable: true, get: function () { return orchestrator_1.runOrchestratorReconcile; } });
@@ -0,0 +1,20 @@
1
+ import { type StepAction } from './state-machine';
2
+ import { type PlannedMigration } from '../migration-shape';
3
+ export interface RunOrchestratorInitInput {
4
+ root: string;
5
+ migrationsJson: {
6
+ migrations?: PlannedMigration[];
7
+ [k: string]: unknown;
8
+ };
9
+ createCommits: boolean;
10
+ commitPrefix: string;
11
+ skipInstall: boolean;
12
+ installedNxVersion: string;
13
+ }
14
+ export interface RunOrchestratorReconcileInput {
15
+ root: string;
16
+ runId: string;
17
+ stepAction?: StepAction;
18
+ }
19
+ export declare function runOrchestratorInit(input: RunOrchestratorInitInput): Promise<void>;
20
+ export declare function runOrchestratorReconcile(input: RunOrchestratorReconcileInput): Promise<void>;