@depup/nx 23.1.2-depup.1 → 23.2.0-depup.0

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 (296) hide show
  1. package/README.md +7 -6
  2. package/changes.json +12 -8
  3. package/dist/bin/init-local.js +3 -5
  4. package/dist/bin/nx.js +1 -0
  5. package/dist/src/adapter/ngcli-adapter.js +60 -1
  6. package/dist/src/ai/constants.d.ts +15 -0
  7. package/dist/src/ai/constants.js +17 -1
  8. package/dist/src/ai/set-up-ai-agents/set-up-ai-agents.js +57 -9
  9. package/dist/src/ai/utils.d.ts +13 -0
  10. package/dist/src/ai/utils.js +29 -0
  11. package/dist/src/analytics/analytics.js +2 -4
  12. package/dist/src/command-line/completion/command-object.js +7 -12
  13. package/dist/src/command-line/configure-ai-agents/configure-ai-agents.js +42 -31
  14. package/dist/src/command-line/format/format.js +84 -101
  15. package/dist/src/command-line/generate/generate.js +35 -35
  16. package/dist/src/command-line/import/import.js +29 -38
  17. package/dist/src/command-line/init/ai-agent-prompts.js +5 -11
  18. package/dist/src/command-line/init/command-object.js +4 -2
  19. package/dist/src/command-line/init/configure-plugins.js +4 -1
  20. package/dist/src/command-line/init/implementation/add-nx-to-monorepo.js +12 -32
  21. package/dist/src/command-line/init/implementation/add-nx-to-nest.js +17 -21
  22. package/dist/src/command-line/init/implementation/add-nx-to-npm-repo.js +8 -21
  23. package/dist/src/command-line/init/implementation/add-nx-to-turborepo.js +3 -17
  24. package/dist/src/command-line/init/implementation/angular/index.js +10 -15
  25. package/dist/src/command-line/init/implementation/angular/legacy-angular-versions.js +2 -0
  26. package/dist/src/command-line/init/implementation/angular/standalone-workspace.js +8 -2
  27. package/dist/src/command-line/init/implementation/check-compatible-with-plugins.js +2 -0
  28. package/dist/src/command-line/init/implementation/dot-nx/add-nx-scripts.js +5 -0
  29. package/dist/src/command-line/init/implementation/format.d.ts +18 -0
  30. package/dist/src/command-line/init/implementation/format.js +114 -0
  31. package/dist/src/command-line/init/implementation/utils.js +8 -8
  32. package/dist/src/command-line/init/init-v1.js +15 -18
  33. package/dist/src/command-line/init/init-v2.js +77 -66
  34. package/dist/src/command-line/migrate/agentic/definitions.js +36 -9
  35. package/dist/src/command-line/migrate/agentic/handoff-gitignore.d.ts +37 -22
  36. package/dist/src/command-line/migrate/agentic/handoff-gitignore.js +30 -39
  37. package/dist/src/command-line/migrate/agentic/handoff.d.ts +7 -7
  38. package/dist/src/command-line/migrate/agentic/handoff.js +13 -10
  39. package/dist/src/command-line/migrate/agentic/print-dropped-agent-context.d.ts +7 -12
  40. package/dist/src/command-line/migrate/agentic/print-dropped-agent-context.js +7 -0
  41. package/dist/src/command-line/migrate/agentic/run-step.d.ts +10 -0
  42. package/dist/src/command-line/migrate/agentic/run-step.js +1 -0
  43. package/dist/src/command-line/migrate/agentic/runner.js +24 -24
  44. package/dist/src/command-line/migrate/agentic/select.d.ts +10 -2
  45. package/dist/src/command-line/migrate/agentic/select.js +30 -32
  46. package/dist/src/command-line/migrate/agentic/types.d.ts +33 -3
  47. package/dist/src/command-line/migrate/agentic/types.js +35 -0
  48. package/dist/src/command-line/migrate/command-object.d.ts +6 -0
  49. package/dist/src/command-line/migrate/command-object.js +19 -1
  50. package/dist/src/command-line/migrate/execute-migration.d.ts +28 -9
  51. package/dist/src/command-line/migrate/execute-migration.js +112 -27
  52. package/dist/src/command-line/migrate/migrate-analytics.d.ts +35 -0
  53. package/dist/src/command-line/migrate/migrate-analytics.js +64 -0
  54. package/dist/src/command-line/migrate/migrate-commits.d.ts +38 -8
  55. package/dist/src/command-line/migrate/migrate-commits.js +130 -15
  56. package/dist/src/command-line/migrate/migrate-config.d.ts +13 -12
  57. package/dist/src/command-line/migrate/migrate-config.js +22 -14
  58. package/dist/src/command-line/migrate/migrate-output.d.ts +45 -7
  59. package/dist/src/command-line/migrate/migrate-output.js +52 -8
  60. package/dist/src/command-line/migrate/migrate-ui-api.d.ts +2 -1
  61. package/dist/src/command-line/migrate/migrate-ui-api.js +16 -7
  62. package/dist/src/command-line/migrate/migrate.d.ts +24 -55
  63. package/dist/src/command-line/migrate/migrate.js +553 -226
  64. package/dist/src/command-line/migrate/migration-shape.d.ts +8 -0
  65. package/dist/src/command-line/migrate/multi-major.js +7 -10
  66. package/dist/src/command-line/migrate/resolve-package-version.js +4 -8
  67. package/dist/src/command-line/migrate/run/agent-output.d.ts +20 -0
  68. package/dist/src/command-line/migrate/run/agent-output.js +65 -0
  69. package/dist/src/command-line/migrate/run/index.d.ts +9 -0
  70. package/dist/src/command-line/migrate/run/index.js +23 -0
  71. package/dist/src/command-line/migrate/run/orchestrator.d.ts +20 -0
  72. package/dist/src/command-line/migrate/run/orchestrator.js +1200 -0
  73. package/dist/src/command-line/migrate/run/run-id.d.ts +16 -0
  74. package/dist/src/command-line/migrate/run/run-id.js +56 -0
  75. package/dist/src/command-line/migrate/run/run-state.d.ts +157 -0
  76. package/dist/src/command-line/migrate/run/run-state.js +438 -0
  77. package/dist/src/command-line/migrate/run/state-lock.d.ts +25 -0
  78. package/dist/src/command-line/migrate/run/state-lock.js +76 -0
  79. package/dist/src/command-line/migrate/run/state-machine.d.ts +84 -0
  80. package/dist/src/command-line/migrate/run/state-machine.js +315 -0
  81. package/dist/src/command-line/migrate/run/util.d.ts +59 -0
  82. package/dist/src/command-line/migrate/run/util.js +148 -0
  83. package/dist/src/command-line/migrate/run/worker.d.ts +16 -0
  84. package/dist/src/command-line/migrate/run/worker.js +682 -0
  85. package/dist/src/command-line/migrate/run-migration-process.js +6 -5
  86. package/dist/src/command-line/migrate/safe-prompt.d.ts +14 -26
  87. package/dist/src/command-line/migrate/safe-prompt.js +32 -43
  88. package/dist/src/command-line/migrate/sort-migrations.d.ts +16 -0
  89. package/dist/src/command-line/migrate/sort-migrations.js +32 -0
  90. package/dist/src/command-line/migrate/step-actions.d.ts +5 -0
  91. package/dist/src/command-line/migrate/step-actions.js +12 -0
  92. package/dist/src/command-line/migrate/text.d.ts +18 -0
  93. package/dist/src/command-line/migrate/text.js +26 -0
  94. package/dist/src/command-line/migrate/version-skew-guard.d.ts +60 -0
  95. package/dist/src/command-line/migrate/version-skew-guard.js +175 -0
  96. package/dist/src/command-line/nx-cloud/connect/connect-to-nx-cloud.js +16 -20
  97. package/dist/src/command-line/nx-cloud/start-nx-agents/command-object.d.ts +2 -0
  98. package/dist/src/command-line/nx-cloud/start-nx-agents/command-object.js +16 -0
  99. package/dist/src/command-line/nx-cloud/start-nx-agents/start-nx-agents.d.ts +4 -0
  100. package/dist/src/command-line/nx-cloud/start-nx-agents/start-nx-agents.js +13 -0
  101. package/dist/src/command-line/nx-commands.js +26 -24
  102. package/dist/src/command-line/release/changelog.js +6 -17
  103. package/dist/src/command-line/release/plan.js +15 -28
  104. package/dist/src/command-line/release/publish.js +5 -0
  105. package/dist/src/command-line/release/release.js +6 -17
  106. package/dist/src/command-line/release/utils/release-graph.d.ts +1 -0
  107. package/dist/src/command-line/release/utils/release-graph.js +10 -2
  108. package/dist/src/command-line/release/utils/remote-release-clients/github.js +10 -22
  109. package/dist/src/command-line/release/utils/remote-release-clients/gitlab.js +13 -22
  110. package/dist/src/command-line/release/utils/resolve-semver-specifier.js +19 -41
  111. package/dist/src/command-line/release/version/resolve-current-version.js +7 -10
  112. package/dist/src/command-line/release/version.js +2 -2
  113. package/dist/src/command-line/reset/reset.js +17 -15
  114. package/dist/src/command-line/yargs-utils/shared-options.d.ts +1 -1
  115. package/dist/src/command-line/yargs-utils/shared-options.js +3 -1
  116. package/dist/src/config/misc-interfaces.d.ts +19 -7
  117. package/dist/src/core/graph/main.js +1 -1
  118. package/dist/src/core/graph/styles.js +1 -1
  119. package/dist/src/daemon/client/client.d.ts +2 -7
  120. package/dist/src/daemon/client/client.js +113 -28
  121. package/dist/src/daemon/client/daemon-environment.d.ts +35 -0
  122. package/dist/src/daemon/client/daemon-environment.js +106 -6
  123. package/dist/src/daemon/client/daemon-socket-messenger.d.ts +1 -1
  124. package/dist/src/daemon/client/daemon-socket-messenger.js +8 -3
  125. package/dist/src/daemon/is-v8-serializer-enabled.d.ts +2 -2
  126. package/dist/src/daemon/is-v8-serializer-enabled.js +2 -2
  127. package/dist/src/daemon/message-types/daemon-message.d.ts +2 -1
  128. package/dist/src/daemon/message-types/daemon-message.js +25 -2
  129. package/dist/src/daemon/sandbox-socket-hint.d.ts +27 -0
  130. package/dist/src/daemon/sandbox-socket-hint.js +136 -0
  131. package/dist/src/daemon/server/client-socket-context.d.ts +1 -1
  132. package/dist/src/daemon/server/client-socket-context.js +2 -3
  133. package/dist/src/daemon/server/dotenv-graph-changes.d.ts +97 -0
  134. package/dist/src/daemon/server/dotenv-graph-changes.js +284 -0
  135. package/dist/src/daemon/server/handle-client-env.d.ts +8 -0
  136. package/dist/src/daemon/server/handle-client-env.js +92 -0
  137. package/dist/src/daemon/server/handle-outputs-changes.d.ts +10 -0
  138. package/dist/src/daemon/server/handle-outputs-changes.js +86 -0
  139. package/dist/src/daemon/server/project-graph-incremental-recomputation.d.ts +21 -0
  140. package/dist/src/daemon/server/project-graph-incremental-recomputation.js +159 -6
  141. package/dist/src/daemon/server/server.js +36 -72
  142. package/dist/src/daemon/server/shutdown-utils.d.ts +1 -1
  143. package/dist/src/daemon/server/shutdown-utils.js +2 -2
  144. package/dist/src/daemon/socket-utils.d.ts +26 -7
  145. package/dist/src/daemon/socket-utils.js +45 -31
  146. package/dist/src/daemon/tmp-dir.d.ts +10 -0
  147. package/dist/src/daemon/tmp-dir.js +21 -37
  148. package/dist/src/devkit-internals.d.ts +20 -9
  149. package/dist/src/devkit-internals.js +49 -6
  150. package/dist/src/executors/run-commands/running-tasks.js +46 -29
  151. package/dist/src/generators/internal-utils/{format-changed-files-with-prettier-if-available.d.ts → format-changed-files.d.ts} +6 -6
  152. package/dist/src/generators/internal-utils/format-changed-files.js +163 -0
  153. package/dist/src/generators/testing-utils/create-tree-with-empty-workspace.d.ts +15 -0
  154. package/dist/src/generators/testing-utils/create-tree-with-empty-workspace.js +21 -3
  155. package/dist/src/migrations/update-15-0-0/prefix-outputs.js +2 -2
  156. package/dist/src/migrations/update-16-0-0/remove-nrwl-cli.js +2 -2
  157. package/dist/src/migrations/update-16-0-0/update-depends-on-to-tokens.js +2 -2
  158. package/dist/src/migrations/update-16-0-0/update-nx-cloud-runner.js +2 -2
  159. package/dist/src/migrations/update-16-2-0/remove-run-commands-output-path.js +2 -2
  160. package/dist/src/migrations/update-17-0-0/rm-default-collection-npm-scope.js +2 -2
  161. package/dist/src/migrations/update-17-0-0/use-minimal-config-for-tasks-runner-options.js +2 -2
  162. package/dist/src/migrations/update-17-2-0/move-default-base.js +2 -2
  163. package/dist/src/migrations/update-18-0-0/disable-crystal-for-existing-workspaces.js +2 -2
  164. package/dist/src/migrations/update-19-2-4/set-project-name.js +2 -2
  165. package/dist/src/migrations/update-20-0-0/move-use-daemon-process.js +2 -2
  166. package/dist/src/migrations/update-20-0-1/use-legacy-cache.js +2 -2
  167. package/dist/src/migrations/update-21-0-0/release-changelog-config-changes.js +2 -2
  168. package/dist/src/migrations/update-21-0-0/release-version-config-changes.js +2 -2
  169. package/dist/src/migrations/update-21-0-0/remove-custom-tasks-runner.js +2 -2
  170. package/dist/src/migrations/update-21-0-0/remove-legacy-cache.js +2 -2
  171. package/dist/src/migrations/update-22-0-0/consolidate-release-tag-config.js +2 -2
  172. package/dist/src/migrations/update-22-0-0/release-version-config-changes.js +2 -2
  173. package/dist/src/migrations/update-22-2-0/add-self-healing-to-gitignore.js +2 -2
  174. package/dist/src/migrations/update-22-6-0/add-claude-settings-local-to-git-ignore.js +2 -2
  175. package/dist/src/migrations/update-22-6-0/add-claude-worktrees-to-git-ignore.js +2 -2
  176. package/dist/src/migrations/update-22-7-0/add-polygraph-to-git-ignore.js +2 -2
  177. package/dist/src/migrations/update-23-0-0/add-migrate-runs-to-git-ignore.js +2 -2
  178. package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.js +2 -2
  179. package/dist/src/native/index.d.ts +7 -3
  180. package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
  181. package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
  182. package/dist/src/nx-cloud/generators/connect-to-nx-cloud/connect-to-nx-cloud.js +3 -3
  183. package/dist/src/nx-cloud/utilities/url-shorten.d.ts +1 -4
  184. package/dist/src/nx-cloud/utilities/url-shorten.js +9 -8
  185. package/dist/src/plugins/js/lock-file/lock-file.d.ts +46 -4
  186. package/dist/src/plugins/js/lock-file/lock-file.js +192 -15
  187. package/dist/src/plugins/js/lock-file/npm-parser.js +10 -3
  188. package/dist/src/plugins/js/lock-file/pnpm-parser.js +356 -62
  189. package/dist/src/plugins/js/lock-file/project-graph-pruning.d.ts +25 -1
  190. package/dist/src/plugins/js/lock-file/project-graph-pruning.js +78 -4
  191. package/dist/src/plugins/js/lock-file/pruned-output.d.ts +330 -0
  192. package/dist/src/plugins/js/lock-file/pruned-output.js +1441 -0
  193. package/dist/src/plugins/js/lock-file/utils/pnpm-normalizer.d.ts +1 -0
  194. package/dist/src/plugins/js/lock-file/utils/pnpm-normalizer.js +6 -5
  195. package/dist/src/plugins/js/utils/register.d.ts +11 -0
  196. package/dist/src/plugins/js/utils/register.js +40 -6
  197. package/dist/src/project-graph/plugins/get-plugins.d.ts +27 -1
  198. package/dist/src/project-graph/plugins/get-plugins.js +110 -5
  199. package/dist/src/project-graph/plugins/isolation/enabled.js +1 -4
  200. package/dist/src/project-graph/plugins/isolation/isolated-plugin.d.ts +16 -0
  201. package/dist/src/project-graph/plugins/isolation/isolated-plugin.js +69 -11
  202. package/dist/src/project-graph/plugins/isolation/messaging.js +1 -3
  203. package/dist/src/project-graph/plugins/isolation/plugin-worker.js +23 -2
  204. package/dist/src/project-graph/project-graph.js +27 -2
  205. package/dist/src/project-graph/utils/project-configuration/project-nodes-manager.d.ts +7 -0
  206. package/dist/src/project-graph/utils/project-configuration/project-nodes-manager.js +14 -6
  207. package/dist/src/project-graph/utils/project-configuration/target-defaults.js +47 -21
  208. package/dist/src/tasks-runner/is-tui-enabled.js +3 -1
  209. package/dist/src/tasks-runner/life-cycle.d.ts +2 -2
  210. package/dist/src/tasks-runner/life-cycle.js +2 -2
  211. package/dist/src/tasks-runner/life-cycles/performance-report.d.ts +12 -0
  212. package/dist/src/tasks-runner/life-cycles/performance-report.js +62 -3
  213. package/dist/src/tasks-runner/life-cycles/static-run-many-terminal-output-life-cycle.d.ts +26 -1
  214. package/dist/src/tasks-runner/life-cycles/static-run-many-terminal-output-life-cycle.js +99 -5
  215. package/dist/src/tasks-runner/life-cycles/static-run-one-terminal-output-life-cycle.d.ts +26 -0
  216. package/dist/src/tasks-runner/life-cycles/static-run-one-terminal-output-life-cycle.js +113 -17
  217. package/dist/src/tasks-runner/pseudo-ipc.js +14 -13
  218. package/dist/src/tasks-runner/pseudo-terminal.d.ts +17 -3
  219. package/dist/src/tasks-runner/pseudo-terminal.js +22 -10
  220. package/dist/src/tasks-runner/run-command.js +32 -39
  221. package/dist/src/tasks-runner/running-tasks/batch-process.d.ts +55 -0
  222. package/dist/src/tasks-runner/running-tasks/batch-process.js +161 -8
  223. package/dist/src/tasks-runner/task-env.d.ts +25 -0
  224. package/dist/src/tasks-runner/task-env.js +39 -0
  225. package/dist/src/tasks-runner/task-orchestrator.d.ts +68 -0
  226. package/dist/src/tasks-runner/task-orchestrator.js +159 -8
  227. package/dist/src/utils/analytics-enabled.d.ts +7 -0
  228. package/dist/src/utils/analytics-enabled.js +11 -0
  229. package/dist/src/utils/analytics-prompt.js +4 -7
  230. package/dist/src/utils/cache-directory.d.ts +62 -3
  231. package/dist/src/utils/cache-directory.js +276 -25
  232. package/dist/src/utils/catalog/bun-manager-utils.d.ts +8 -0
  233. package/dist/src/utils/catalog/bun-manager-utils.js +174 -0
  234. package/dist/src/utils/catalog/bun-manager.d.ts +28 -0
  235. package/dist/src/utils/catalog/bun-manager.js +130 -0
  236. package/dist/src/utils/catalog/index.d.ts +1 -1
  237. package/dist/src/utils/catalog/index.js +1 -1
  238. package/dist/src/utils/catalog/manager-factory.js +3 -0
  239. package/dist/src/utils/catalog/manager-utils.d.ts +8 -1
  240. package/dist/src/utils/catalog/manager-utils.js +9 -4
  241. package/dist/src/utils/catalog/manager.d.ts +13 -1
  242. package/dist/src/utils/catalog/manager.js +30 -0
  243. package/dist/src/utils/catalog/pnpm-manager.d.ts +2 -1
  244. package/dist/src/utils/catalog/pnpm-manager.js +3 -0
  245. package/dist/src/utils/catalog/types.d.ts +4 -0
  246. package/dist/src/utils/catalog/yarn-manager.d.ts +6 -2
  247. package/dist/src/utils/catalog/yarn-manager.js +23 -32
  248. package/dist/src/utils/child-process.d.ts +31 -1
  249. package/dist/src/utils/child-process.js +103 -0
  250. package/dist/src/utils/chunkify.d.ts +7 -1
  251. package/dist/src/utils/chunkify.js +10 -3
  252. package/dist/src/utils/consume-messages-from-socket.d.ts +42 -7
  253. package/dist/src/utils/consume-messages-from-socket.js +273 -38
  254. package/dist/src/utils/db-connection.js +8 -16
  255. package/dist/src/utils/exit-codes.d.ts +9 -0
  256. package/dist/src/utils/exit-codes.js +19 -0
  257. package/dist/src/utils/formatters/index.d.ts +13 -0
  258. package/dist/src/utils/formatters/index.js +74 -0
  259. package/dist/src/utils/formatters/oxfmt.d.ts +32 -0
  260. package/dist/src/utils/formatters/oxfmt.js +764 -0
  261. package/dist/src/utils/formatters/prettier.d.ts +26 -0
  262. package/dist/src/utils/formatters/prettier.js +201 -0
  263. package/dist/src/utils/formatters/shared.d.ts +5 -0
  264. package/dist/src/utils/formatters/shared.js +8 -0
  265. package/dist/src/utils/git-utils.d.ts +38 -2
  266. package/dist/src/utils/git-utils.js +422 -19
  267. package/dist/src/utils/has-nx-js-plugin.d.ts +1 -1
  268. package/dist/src/utils/has-nx-js-plugin.js +1 -1
  269. package/dist/src/utils/ignore.d.ts +47 -5
  270. package/dist/src/utils/ignore.js +93 -11
  271. package/dist/src/utils/kill-child-on-host-exit.d.ts +7 -0
  272. package/dist/src/utils/kill-child-on-host-exit.js +42 -0
  273. package/dist/src/utils/nx-console-prompt.js +3 -6
  274. package/dist/src/utils/nx-tmp-dir.d.ts +5 -0
  275. package/dist/src/utils/nx-tmp-dir.js +7 -2
  276. package/dist/src/utils/output.d.ts +153 -0
  277. package/dist/src/utils/output.js +289 -5
  278. package/dist/src/utils/owned-private-dir.d.ts +13 -0
  279. package/dist/src/utils/owned-private-dir.js +39 -0
  280. package/dist/src/utils/package-json.d.ts +2 -0
  281. package/dist/src/utils/package-manager.js +17 -7
  282. package/dist/src/utils/params.d.ts +7 -1
  283. package/dist/src/utils/params.js +64 -6
  284. package/dist/src/utils/permission-errors.d.ts +11 -0
  285. package/dist/src/utils/permission-errors.js +17 -0
  286. package/dist/src/utils/plugins/core-plugins.js +4 -0
  287. package/dist/src/utils/prompt-helpers.d.ts +53 -0
  288. package/dist/src/utils/prompt-helpers.js +111 -0
  289. package/dist/src/utils/socket-refused-exit-code.d.ts +15 -0
  290. package/dist/src/utils/socket-refused-exit-code.js +18 -0
  291. package/dist/src/utils/write-formatted-json-file.d.ts +3 -2
  292. package/dist/src/utils/write-formatted-json-file.js +5 -4
  293. package/package.json +33 -24
  294. package/dist/src/generators/internal-utils/format-changed-files-with-prettier-if-available.js +0 -88
  295. package/dist/src/utils/is-using-prettier.d.ts +0 -3
  296. package/dist/src/utils/is-using-prettier.js +0 -62
@@ -7,15 +7,13 @@ exports.resolveInclude = resolveInclude;
7
7
  exports.parseMigrationsOptions = parseMigrationsOptions;
8
8
  exports.createFetcher = createFetcher;
9
9
  exports.generateMigrationsJsonAndUpdatePackageJson = generateMigrationsJsonAndUpdatePackageJson;
10
- exports.resolveAgenticRunId = resolveAgenticRunId;
11
10
  exports.formatSkippedPromptsNextStep = formatSkippedPromptsNextStep;
12
- exports.resolveCreateCommits = resolveCreateCommits;
13
- exports.resolveShouldRunValidation = resolveShouldRunValidation;
14
11
  exports.executeMigrations = executeMigrations;
12
+ exports.isRunPhaseInvocation = isRunPhaseInvocation;
15
13
  exports.migrate = migrate;
14
+ exports.readLocalNxVersion = readLocalNxVersion;
16
15
  exports.runMigration = runMigration;
17
16
  exports.resolveMigrationForRun = resolveMigrationForRun;
18
- exports.resolveDocumentationFileToWorkspacePath = resolveDocumentationFileToWorkspacePath;
19
17
  exports.nxCliPath = nxCliPath;
20
18
  const tslib_1 = require("tslib");
21
19
  const pc = tslib_1.__importStar(require("picocolors"));
@@ -30,6 +28,7 @@ const util_1 = require("util");
30
28
  const fileutils_1 = require("../../utils/fileutils");
31
29
  const tar_1 = require("../../utils/tar");
32
30
  const write_formatted_json_file_1 = require("../../utils/write-formatted-json-file");
31
+ const shell_quoting_1 = require("../../utils/shell-quoting");
33
32
  const logger_1 = require("../../utils/logger");
34
33
  const git_utils_1 = require("../../utils/git-utils");
35
34
  const package_json_1 = require("../../utils/package-json");
@@ -48,7 +47,7 @@ const configuration_1 = require("../../config/configuration");
48
47
  const child_process_2 = require("../../utils/child-process");
49
48
  const client_1 = require("../../daemon/client/client");
50
49
  const nx_cloud_utils_1 = require("../../utils/nx-cloud-utils");
51
- const format_changed_files_with_prettier_if_available_1 = require("../../generators/internal-utils/format-changed-files-with-prettier-if-available");
50
+ const format_changed_files_1 = require("../../generators/internal-utils/format-changed-files");
52
51
  const provenance_1 = require("../../utils/provenance");
53
52
  const catalog_1 = require("../../utils/catalog");
54
53
  const migrate_analytics_1 = require("./migrate-analytics");
@@ -56,7 +55,6 @@ const multi_major_1 = require("./multi-major");
56
55
  const prompt_files_1 = require("./prompt-files");
57
56
  const command_object_1 = require("./command-object");
58
57
  const migrate_config_1 = require("./migrate-config");
59
- const handoff_gitignore_1 = require("./agentic/handoff-gitignore");
60
58
  const migrate_commits_1 = require("./migrate-commits");
61
59
  const migrate_output_1 = require("./migrate-output");
62
60
  const migration_shape_1 = require("./migration-shape");
@@ -67,6 +65,11 @@ Object.defineProperty(exports, "filterDowngradedUpdates", { enumerable: true, ge
67
65
  const version_utils_1 = require("./version-utils");
68
66
  Object.defineProperty(exports, "normalizeVersion", { enumerable: true, get: function () { return version_utils_1.normalizeVersion; } });
69
67
  const execute_migration_1 = require("./execute-migration");
68
+ const step_actions_1 = require("./step-actions");
69
+ const sort_migrations_1 = require("./sort-migrations");
70
+ const inception_1 = require("./agentic/inception");
71
+ const version_skew_guard_1 = require("./version-skew-guard");
72
+ const versions_1 = require("../../utils/versions");
70
73
  tslib_1.__exportStar(require("./execute-migration"), exports);
71
74
  const execAsync = (0, util_1.promisify)(child_process_1.exec);
72
75
  function formatCommandFailure(command, error) {
@@ -514,17 +517,14 @@ class Migrator {
514
517
  // a same prompt was already answered, skip
515
518
  return Promise.resolve(false);
516
519
  }
517
- const promptConfig = {
518
- name: 'shouldApply',
519
- type: 'confirm',
520
- message: packageUpdate['x-prompt'],
520
+ // No footer slot, so the docs link is appended to the message.
521
+ const detailsLink = packageName.startsWith('@nx/')
522
+ ? pc.dim(`\n View migration details at https://nx.dev/nx-api/${packageName.replace('@nx/', '')}#${packageUpdateKey.replace(/[-\.]/g, '')}packageupdates`)
523
+ : '';
524
+ return await (0, safe_prompt_1.migrateConfirm)({
525
+ message: `${packageUpdate['x-prompt']}${detailsLink}`,
521
526
  initial: true,
522
- };
523
- if (packageName.startsWith('@nx/')) {
524
- // @ts-expect-error -- enquirer types aren't correct, footer does exist
525
- promptConfig.footer = () => pc.dim(` View migration details at https://nx.dev/nx-api/${packageName.replace('@nx/', '')}#${packageUpdateKey.replace(/[-\.]/g, '')}packageupdates`);
526
- }
527
- return await (0, safe_prompt_1.migratePrompt)([promptConfig]).then(({ shouldApply }) => {
527
+ }).then((shouldApply) => {
528
528
  this.promptAnswers[promptKey] = shouldApply;
529
529
  if (!shouldApply &&
530
530
  (!this.minVersionWithSkippedUpdates ||
@@ -625,8 +625,8 @@ async function resolveInclude(include, context, configuredInclude) {
625
625
  }
626
626
  const choices = [
627
627
  {
628
- name: 'required',
629
- message: 'Required only (the target package and the packages it ships with)',
628
+ value: 'required',
629
+ label: 'Required only (the target package and the packages it ships with)',
630
630
  },
631
631
  ];
632
632
  // `--interactive` keeps the legacy x-prompt flow, which the `optional` value
@@ -635,8 +635,8 @@ async function resolveInclude(include, context, configuredInclude) {
635
635
  !context.hasExcludeAppliedMigrations &&
636
636
  context.interactive !== true) {
637
637
  choices.push({
638
- name: 'optional',
639
- message: 'Optional only (the dependency updates those packages recommend)',
638
+ value: 'optional',
639
+ label: 'Optional only (the dependency updates those packages recommend)',
640
640
  });
641
641
  }
642
642
  if (!(0, safe_prompt_1.canPrompt)(context.interactive)) {
@@ -644,12 +644,10 @@ async function resolveInclude(include, context, configuredInclude) {
644
644
  return 'all';
645
645
  }
646
646
  choices.push({
647
- name: 'all',
648
- message: 'All (required and optional)',
647
+ value: 'all',
648
+ label: 'All (required and optional)',
649
649
  });
650
- const { include: selected } = await (0, safe_prompt_1.migratePrompt)({
651
- type: 'select',
652
- name: 'include',
650
+ const selected = await (0, safe_prompt_1.migrateChoice)({
653
651
  message: 'Which packages would you like to migrate?',
654
652
  choices,
655
653
  });
@@ -709,6 +707,75 @@ async function parseTargetPackageAndVersion(args) {
709
707
  return { targetPackage: args, targetVersion: 'latest' };
710
708
  }
711
709
  async function parseMigrationsOptions(options, fetch) {
710
+ // A run recorded or reconciled via `--run-id` is driven by the outer agent;
711
+ // spawning another agent from it would double-drive the run. Only the
712
+ // explicit "on" values conflict; the nx.json default is ignored for
713
+ // `--run-id` invocations instead.
714
+ if (options.runId !== undefined &&
715
+ options.agentic !== undefined &&
716
+ options.agentic !== false) {
717
+ throw new Error(`Error: '--agentic' cannot be combined with '--run-id'.`);
718
+ }
719
+ if (options.runMigration !== undefined) {
720
+ if (options.runMigration === '') {
721
+ throw new Error(`Error: '--run-migration' requires a migration id, e.g. '--run-migration=@nx/js:my-migration'.`);
722
+ }
723
+ if (options.runId === '') {
724
+ throw new Error(`Error: '--run-id' requires the id of the migrate run to record into.`);
725
+ }
726
+ if (options.stepAction !== undefined) {
727
+ throw new Error(`Error: '--step-action' cannot be combined with '--run-migration'. It applies to an orchestrated reconcile ('--run-id' without '--run-migration').`);
728
+ }
729
+ if (options.runMigrations !== undefined) {
730
+ throw new Error(`Error: '--run-migration' (run a single migration) cannot be combined with '--run-migrations' (run the whole migrations file).`);
731
+ }
732
+ if (options.include) {
733
+ throw new Error(`Error: '--run-migration' cannot be combined with '--include'.`);
734
+ }
735
+ if (options.multiMajorMode) {
736
+ throw new Error(`Error: '--run-migration' cannot be combined with '--multi-major-mode'.`);
737
+ }
738
+ // `--if-exists` only applies to a whole-file run, so an explicit "on"
739
+ // conflicts. Its yargs default (false) is always present and is tolerated.
740
+ if (options.ifExists === true) {
741
+ throw new Error(`Error: '--run-migration' cannot be combined with '--if-exists'.`);
742
+ }
743
+ return {
744
+ type: 'runSingleMigration',
745
+ runMigration: options.runMigration,
746
+ runId: options.runId,
747
+ agentic: options.agentic,
748
+ validate: options.validate,
749
+ interactive: options.interactive,
750
+ };
751
+ }
752
+ if (options.runId !== undefined) {
753
+ // Empty '--run-id' is an error on every path.
754
+ if (options.runId === '') {
755
+ throw new Error(`Error: '--run-id' requires the id of the migrate run to record into.`);
756
+ }
757
+ if (options.runMigrations !== undefined) {
758
+ throw new Error(`Error: '--run-id' (reconcile an orchestrated run) cannot be combined with '--run-migrations' (run the whole migrations file).`);
759
+ }
760
+ // A bare '--run-id' reconciles the run it names. Ungated, unlike init:
761
+ // the id has to name a run directory that exists, and only a gated init
762
+ // ever creates one.
763
+ // yargs' choices already reject bad CLI values; this guards programmatic
764
+ // callers, where silently dropping the action would reconcile without it.
765
+ if (options.stepAction !== undefined && !(0, step_actions_1.isStepAction)(options.stepAction)) {
766
+ throw new Error(`Error: '--step-action' must be one of ${step_actions_1.STEP_ACTIONS.join(', ')}.`);
767
+ }
768
+ return {
769
+ type: 'orchestratorReconcile',
770
+ runId: options.runId,
771
+ ...(options.stepAction !== undefined
772
+ ? { stepAction: options.stepAction }
773
+ : {}),
774
+ };
775
+ }
776
+ if (options.stepAction !== undefined) {
777
+ throw new Error(`Error: '--step-action' requires '--run-id'.`);
778
+ }
712
779
  if (options.runMigrations === '') {
713
780
  options.runMigrations = 'migrations.json';
714
781
  }
@@ -1360,7 +1427,7 @@ async function formatCatalogDefinitionFiles(manager, root) {
1360
1427
  content: (0, fs_1.readFileSync)(absolutePath, 'utf-8'),
1361
1428
  };
1362
1429
  });
1363
- const results = await (0, format_changed_files_with_prettier_if_available_1.formatFilesWithPrettierIfAvailable)(catalogDefinitionFiles.map(({ path, content }) => ({ path, content })), root, { silent: true });
1430
+ const results = await (0, format_changed_files_1.formatFileContents)(catalogDefinitionFiles.map(({ path, content }) => ({ path, content })), root, { silent: true });
1364
1431
  for (const { path, absolutePath, content } of catalogDefinitionFiles) {
1365
1432
  (0, fs_1.writeFileSync)(absolutePath, results.has(path) ? results.get(path) : content, { encoding: 'utf-8' });
1366
1433
  }
@@ -1654,112 +1721,22 @@ function showConnectToCloudMessage() {
1654
1721
  return false;
1655
1722
  }
1656
1723
  }
1657
- function resolveAgenticRunId(migrations) {
1658
- return (0, semver_1.rsort)(migrations.map((m) => (0, version_utils_1.normalizeVersion)(m.version)))[0];
1659
- }
1660
1724
  function formatSkippedPromptsNextStep(skipped) {
1661
1725
  return [
1662
1726
  'Some prompt migrations were skipped. Review and apply each of the following prompt files to the workspace, in the listed order:',
1663
1727
  ...skipped.map((m) => ` - ${m.prompt}`),
1664
1728
  ].join('\n');
1665
1729
  }
1666
- /**
1667
- * Resolves the effective `--create-commits` state once the agentic flow has
1668
- * been resolved. The agent's outer prompt only embeds the impl-phase file list
1669
- * when per-migration commits isolate each migration's diff, so the diff-context
1670
- * flag returned here gates that section.
1671
- */
1672
- function resolveCreateCommits(args) {
1673
- const { createCommits, agenticKind, isGitRepo, commitPrefixIsCustom } = args;
1674
- // Explicit `--create-commits` without git is a hard error — the user asked
1675
- // for something we cannot deliver.
1676
- if (createCommits === true && !isGitRepo) {
1677
- return {
1678
- effective: false,
1679
- agenticHasDiffContext: false,
1680
- error: '`--create-commits` requires a git repository. Run `git init` first, or omit the flag.',
1681
- };
1682
- }
1683
- if (agenticKind === 'enabled') {
1684
- if (createCommits === false) {
1685
- return {
1686
- effective: false,
1687
- agenticHasDiffContext: false,
1688
- warning: "--no-create-commits was passed alongside --agentic. Without per-migration commits, the agent can't isolate the current migration's changes from earlier migrations in this run. Drop --no-create-commits for accurate per-migration review." +
1689
- (commitPrefixIsCustom
1690
- ? ' Note: the custom --commit-prefix value will have no effect because commits are disabled.'
1691
- : ''),
1692
- };
1693
- }
1694
- // Without git we cannot soft-force commits the user didn't explicitly
1695
- // opt into. Degrade rather than error: continue the agentic run, but
1696
- // without per-file diff context (which depends on per-migration commits).
1697
- if (!isGitRepo) {
1698
- return {
1699
- effective: false,
1700
- agenticHasDiffContext: false,
1701
- warning: '`--agentic` enables per-migration commits by default, but the workspace is not a git repository. Continuing without commits — the agent will not receive per-file diff context. Run `git init` to enable.' +
1702
- (commitPrefixIsCustom
1703
- ? ' The custom --commit-prefix value will have no effect.'
1704
- : ''),
1705
- };
1706
- }
1707
- return { effective: true, agenticHasDiffContext: true };
1708
- }
1709
- // Commits aren't enabled here. A custom prefix only reaches this path via
1710
- // nx.json (e.g. `migrate.commitPrefix` + `migrate.agentic` when the agentic
1711
- // flow resolves to disabled); surface that it has no effect rather than
1712
- // dropping it silently.
1713
- return {
1714
- effective: createCommits === true,
1715
- agenticHasDiffContext: false,
1716
- warning: commitPrefixIsCustom && createCommits !== true
1717
- ? 'A custom migrate commit prefix is configured, but commits are not enabled for this run, so it has no effect. Set `migrate.createCommits` to `true` (or pass `--create-commits`) to create a commit per migration.'
1718
- : undefined,
1719
- };
1720
- }
1721
- /**
1722
- * Resolves whether the framework-owned generic-validation agent step should run
1723
- * after generator-only migrations.
1724
- *
1725
- * Default-on when the agentic flow resolved to `enabled`; silently ignored
1726
- * otherwise (no warning emitted) — `--validate` requires an active agent
1727
- * session by definition. An explicit `--no-validate` (`validate === false`)
1728
- * opts out even when agentic is enabled.
1729
- */
1730
- function resolveShouldRunValidation(args) {
1731
- return args.validate !== false && args.agenticKind === 'enabled';
1732
- }
1733
1730
  async function executeMigrations(root, migrations, isVerbose, shouldCreateCommits, commitPrefix, shouldSkipInstall = false, agentic, agenticHasDiffContext = false, shouldRunValidation = false) {
1734
1731
  const changedDepInstaller = new execute_migration_1.ChangedDepInstaller(root, shouldSkipInstall);
1735
1732
  const migrationsWithNoChanges = [];
1736
- const sortedMigrations = migrations.sort((a, b) => {
1737
- // Under `--agentic`, hoist the v23 migration that ignores
1738
- // `.nx/migrate-runs` to position 0 so its .gitignore update lands
1739
- // before any per-migration commit absorbs the run's handoff scratch.
1740
- // See `agentic/handoff-gitignore.ts` for the full rationale and the
1741
- // inline-fallback path that covers intra-pre-v23 agentic runs.
1742
- if (agentic?.kind === 'enabled') {
1743
- if ((0, handoff_gitignore_1.isHandoffGitignoreMigration)(a))
1744
- return -1;
1745
- if ((0, handoff_gitignore_1.isHandoffGitignoreMigration)(b))
1746
- return 1;
1747
- }
1748
- // special case for the split configuration migration to run first
1749
- if (a.name === '15-7-0-split-configuration-into-project-json-files') {
1750
- return -1;
1751
- }
1752
- if (b.name === '15-7-0-split-configuration-into-project-json-files') {
1753
- return 1;
1754
- }
1755
- return (0, semver_1.lt)((0, version_utils_1.normalizeVersion)(a.version), (0, version_utils_1.normalizeVersion)(b.version))
1756
- ? -1
1757
- : 1;
1733
+ const sortedMigrations = (0, sort_migrations_1.sortMigrations)(migrations, {
1734
+ hoistHandoffGitignore: agentic?.kind === 'enabled',
1758
1735
  });
1759
1736
  // Lazy-load the agentic chain so non-agentic runs don't pay its startup cost.
1760
1737
  let agenticRun;
1761
1738
  if (agentic?.kind === 'enabled' && sortedMigrations.length > 0) {
1762
- const { initRunDir } = require('./agentic/handoff');
1739
+ const { initRunDir, resolveAgenticRunId } = require('./agentic/handoff');
1763
1740
  const { runAgenticPromptStep } = require('./agentic/run-step');
1764
1741
  agenticRun = {
1765
1742
  agentic,
@@ -1847,6 +1824,23 @@ async function executeMigrations(root, migrations, isVerbose, shouldCreateCommit
1847
1824
  // as a commit failure.
1848
1825
  return { kind: 'none' };
1849
1826
  }
1827
+ // Records what a migration's deterministic phase produced. A migration that
1828
+ // changed nothing must not attempt a commit: the absorbing `git add -A`
1829
+ // would build a commit subject naming this no-op migration even though its
1830
+ // content is entirely prior pending diffs, confusing `git log` / `git blame`
1831
+ // attribution. Pending stays pending and the next change-producing migration
1832
+ // absorbs it.
1833
+ async function commitOrRecordNoChanges(m, madeChanges) {
1834
+ if (!madeChanges) {
1835
+ migrationsWithNoChanges.push(m);
1836
+ return { kind: 'none' };
1837
+ }
1838
+ const commit = await attemptMigrationCommit(m);
1839
+ if (commit.kind === 'landed' && commit.sha) {
1840
+ logger_1.logger.info(pc.dim(`Committed as ${commit.sha}`));
1841
+ }
1842
+ return commit;
1843
+ }
1850
1844
  const totalMigrations = sortedMigrations.length;
1851
1845
  let migrationIndex = 0;
1852
1846
  for (const m of sortedMigrations) {
@@ -1867,6 +1861,11 @@ async function executeMigrations(root, migrations, isVerbose, shouldCreateCommit
1867
1861
  const { resolvedCollection, documentationPath } = resolveMigrationForRun(root, m, !!agenticRun);
1868
1862
  let outcome;
1869
1863
  let commit = { kind: 'none' };
1864
+ // Set when the migration returned `skipAgentic: true` and something was
1865
+ // actually waived, so the end-of-run recaps can report it. A hybrid's
1866
+ // prompt is owed in every agentic mode, so waiving it always counts; a
1867
+ // generator-only migration only counts when validation would have run.
1868
+ let waivedAgenticStep = false;
1870
1869
  if ((0, migration_shape_1.isPromptOnlyMigration)(m)) {
1871
1870
  if (agenticRun) {
1872
1871
  inAgenticStep = true;
@@ -1891,10 +1890,19 @@ async function executeMigrations(root, migrations, isVerbose, shouldCreateCommit
1891
1890
  }
1892
1891
  }
1893
1892
  else if ((0, migration_shape_1.isHybridMigration)(m)) {
1894
- const { changes, nextSteps, agentContext, logs, madeChanges } = await (0, execute_migration_1.runNxOrAngularMigration)(root, m, isVerbose,
1893
+ const { changes, nextSteps, agentContext, skipAgentic, logs, madeChanges, } = await (0, execute_migration_1.runNxOrAngularMigration)(root, m, isVerbose,
1895
1894
  /* captureGeneratorOutput: */ !!agenticRun, resolvedCollection);
1896
1895
  migrationEmittedNextSteps.push(...nextSteps);
1897
- if (agenticRun) {
1896
+ if (skipAgentic) {
1897
+ // The generator reported the prompt half unnecessary, so nothing is
1898
+ // owed: no agent run, and no next-steps entry telling the user to
1899
+ // run the prompt themselves. Runs in all three agentic modes.
1900
+ (0, migrate_output_1.logWaivedAgenticStep)(m, agentContext);
1901
+ waivedAgenticStep = true;
1902
+ commit = await commitOrRecordNoChanges(m, madeChanges);
1903
+ outcome = madeChanges ? 'applied' : 'no-changes';
1904
+ }
1905
+ else if (agenticRun) {
1898
1906
  // Install any deps the deterministic phase added/bumped before the
1899
1907
  // agent runs — the prompt half may depend on them being present in
1900
1908
  // node_modules.
@@ -1933,21 +1941,7 @@ async function executeMigrations(root, migrations, isVerbose, shouldCreateCommit
1933
1941
  printDroppedAgentContext({ migration: m, agentContext });
1934
1942
  }
1935
1943
  skippedPrompts.push(m);
1936
- if (!madeChanges) {
1937
- migrationsWithNoChanges.push(m);
1938
- }
1939
- // Only attempt a commit when this migration's deterministic
1940
- // phase actually produced changes. Otherwise the absorbing
1941
- // `git add -A` would build a commit subject naming this no-op
1942
- // migration even though its content is entirely prior pending
1943
- // diffs — confusing `git log` / `git blame` attribution. Pending
1944
- // stays pending and the next change-producing migration absorbs.
1945
- if (madeChanges) {
1946
- commit = await attemptMigrationCommit(m);
1947
- }
1948
- if (commit.kind === 'landed' && commit.sha) {
1949
- logger_1.logger.info(pc.dim(`Committed as ${commit.sha}`));
1950
- }
1944
+ commit = await commitOrRecordNoChanges(m, madeChanges);
1951
1945
  outcome = 'deferred';
1952
1946
  }
1953
1947
  }
@@ -1955,10 +1949,14 @@ async function executeMigrations(root, migrations, isVerbose, shouldCreateCommit
1955
1949
  // Defer commit until validation succeeds; failed validation leaves
1956
1950
  // changes uncommitted in the working tree for the user to review.
1957
1951
  const validationRun = agenticRun && shouldRunValidation ? agenticRun : undefined;
1958
- const { changes, nextSteps, agentContext, logs, madeChanges } = await (0, execute_migration_1.runNxOrAngularMigration)(root, m, isVerbose,
1952
+ const { changes, nextSteps, agentContext, skipAgentic, logs, madeChanges, } = await (0, execute_migration_1.runNxOrAngularMigration)(root, m, isVerbose,
1959
1953
  /* captureGeneratorOutput: */ !!validationRun, resolvedCollection);
1960
1954
  migrationEmittedNextSteps.push(...nextSteps);
1961
- const canRunValidation = !!validationRun && changes.length > 0;
1955
+ // Whether a validation step was on the table at all. `skipAgentic`
1956
+ // waives nothing when it wasn't, so the whole waived path hangs off
1957
+ // this, not just the log line.
1958
+ const validationApplies = !!validationRun && changes.length > 0;
1959
+ const canRunValidation = validationApplies && !skipAgentic;
1962
1960
  if (canRunValidation) {
1963
1961
  // Install any deps the deterministic phase added/bumped before the
1964
1962
  // validation agent runs — the agent may run tasks that need them.
@@ -1989,22 +1987,17 @@ async function executeMigrations(root, migrations, isVerbose, shouldCreateCommit
1989
1987
  outcome = 'applied';
1990
1988
  }
1991
1989
  else {
1992
- // Inner validation step didn't run. Surface `agentContext` under
1993
- // `inside-agent` so the outer driving agent can ingest it.
1994
- if (printDroppedAgentContext && agentContext.length > 0) {
1995
- printDroppedAgentContext({ migration: m, agentContext });
1996
- }
1997
- if (!madeChanges) {
1998
- migrationsWithNoChanges.push(m);
1999
- outcome = 'no-changes';
1990
+ if (skipAgentic && validationApplies) {
1991
+ (0, migrate_output_1.logWaivedAgenticStep)(m, agentContext);
1992
+ waivedAgenticStep = true;
2000
1993
  }
2001
- else {
2002
- commit = await attemptMigrationCommit(m);
2003
- if (commit.kind === 'landed' && commit.sha) {
2004
- logger_1.logger.info(pc.dim(`Committed as ${commit.sha}`));
2005
- }
2006
- outcome = 'applied';
1994
+ else if (printDroppedAgentContext && agentContext.length > 0) {
1995
+ // Inner validation step didn't run. Surface `agentContext` under
1996
+ // `inside-agent` so the outer driving agent can ingest it.
1997
+ printDroppedAgentContext({ migration: m, agentContext });
2007
1998
  }
1999
+ commit = await commitOrRecordNoChanges(m, madeChanges);
2000
+ outcome = madeChanges ? 'applied' : 'no-changes';
2008
2001
  }
2009
2002
  }
2010
2003
  outcomes.push({
@@ -2012,6 +2005,7 @@ async function executeMigrations(root, migrations, isVerbose, shouldCreateCommit
2012
2005
  status: 'completed',
2013
2006
  kind: outcome,
2014
2007
  commit,
2008
+ waivedAgenticStep,
2015
2009
  });
2016
2010
  logger_1.logger.info('');
2017
2011
  }
@@ -2074,7 +2068,7 @@ async function executeMigrations(root, migrations, isVerbose, shouldCreateCommit
2074
2068
  await installDepsIfChanged();
2075
2069
  }
2076
2070
  if (changedDepInstaller.skippedInstall) {
2077
- logSkippedPostMigrationInstall(root);
2071
+ (0, execute_migration_1.logSkippedPostMigrationInstall)(root);
2078
2072
  }
2079
2073
  // Combined-view next-steps array kept for back-compat with repair.ts, which
2080
2074
  // consumes the single `nextSteps` field.
@@ -2090,6 +2084,7 @@ async function executeMigrations(root, migrations, isVerbose, shouldCreateCommit
2090
2084
  skippedPrompts,
2091
2085
  migrationEmittedNextSteps,
2092
2086
  committedShasCount: (0, migrate_output_1.countLandedCommits)(outcomes),
2087
+ waivedAgenticStepsCount: (0, migrate_output_1.countWaivedAgenticSteps)(outcomes),
2093
2088
  // Migrations whose commits failed and never got absorbed by a later
2094
2089
  // commit. The caller surfaces them so a successful run doesn't claim
2095
2090
  // "up to date" while leaving uncommitted diffs in the working tree.
@@ -2097,13 +2092,18 @@ async function executeMigrations(root, migrations, isVerbose, shouldCreateCommit
2097
2092
  retainedAtSuccess: (0, migrate_output_1.retainedMigrations)(outcomes).map((p) => `${p.package}: ${p.name}`),
2098
2093
  };
2099
2094
  }
2100
- function logSkippedPostMigrationInstall(root) {
2101
- const packageManager = (0, package_manager_1.detectPackageManager)(root);
2102
- const installCommand = (0, package_manager_1.getPackageManagerCommand)(packageManager, root).install;
2103
- output_1.output.warn({
2104
- title: 'Migrations updated your dependencies, but the install was skipped',
2105
- bodyLines: [`Run "${installCommand}" to install the updated dependencies.`],
2106
- });
2095
+ // nx is located at spawn time, after the gated pre-install, so the child runs
2096
+ // the bytes that install put in place.
2097
+ function handOffToLocalNx(args) {
2098
+ const exitCode = runOrReturnExitCode(() => (0, child_process_2.runNxArgvSync)(['migrate', ...args], {
2099
+ stdio: ['inherit', 'inherit', 'inherit'],
2100
+ env: {
2101
+ ...process.env,
2102
+ NX_MIGRATE_SKIP_INSTALL: 'true',
2103
+ NX_MIGRATE_USE_LOCAL: 'true',
2104
+ },
2105
+ }));
2106
+ return exitCode !== 0 ? exitCode : undefined;
2107
2107
  }
2108
2108
  async function runMigrations(root, opts, args, isVerbose, shouldCreateCommits, commitPrefix, shouldSkipInstall = false) {
2109
2109
  if (!shouldSkipInstall && !process.env.NX_MIGRATE_SKIP_INSTALL) {
@@ -2112,18 +2112,7 @@ async function runMigrations(root, opts, args, isVerbose, shouldCreateCommits, c
2112
2112
  if (!__dirname.startsWith(workspace_root_1.workspaceRoot)) {
2113
2113
  // we are running from a temp installation with nx latest, switch to running
2114
2114
  // from local installation
2115
- const exitCode = runOrReturnExitCode(() => (0, child_process_2.runNxSync)(`migrate ${args.join(' ')}`, {
2116
- stdio: ['inherit', 'inherit', 'inherit'],
2117
- env: {
2118
- ...process.env,
2119
- NX_MIGRATE_SKIP_INSTALL: 'true',
2120
- NX_MIGRATE_USE_LOCAL: 'true',
2121
- },
2122
- }));
2123
- if (exitCode !== 0) {
2124
- return exitCode;
2125
- }
2126
- return;
2115
+ return handOffToLocalNx(args);
2127
2116
  }
2128
2117
  const migrationsExists = (0, fileutils_1.fileExists)(opts.runMigrations);
2129
2118
  if (opts.ifExists && !migrationsExists) {
@@ -2135,12 +2124,53 @@ async function runMigrations(root, opts, args, isVerbose, shouldCreateCommits, c
2135
2124
  else if (!opts.ifExists && !migrationsExists) {
2136
2125
  throw new Error(`File '${opts.runMigrations}' doesn't exist, can't run migrations. Use flag --if-exists to run migrations only if the file exists`);
2137
2126
  }
2138
- const migrations = (0, fileutils_1.readJsonFile)((0, path_1.join)(root, opts.runMigrations)).migrations;
2127
+ const migrationsJson = (0, fileutils_1.readJsonFile)((0, path_1.join)(root, opts.runMigrations));
2128
+ const migrations = migrationsJson.migrations;
2129
+ // An outer agent drives the loop, so hand off to the orchestrator instead of
2130
+ // the classic loop: init either starts a fresh run or resumes an already-
2131
+ // active one. `--run-id` reconciles are dispatched separately and never
2132
+ // reach here.
2133
+ if (process.env.NX_MIGRATE_ORCHESTRATOR === 'true' && (0, inception_1.isInsideAgent)()) {
2134
+ // Orchestrated runs are agent-driven, so commits default on exactly as they
2135
+ // do under `--agentic=enabled`; the orchestrator replaces `resolveAgentic`.
2136
+ const { effective: effectiveCreateCommits, warning: createCommitsWarning, error: createCommitsError, } = (0, migrate_commits_1.resolveCreateCommits)({
2137
+ createCommits: shouldCreateCommits,
2138
+ mode: 'orchestrated',
2139
+ isGitRepo: (0, git_utils_1.isGitRepository)(root),
2140
+ commitPrefixIsCustom: commitPrefix !== command_object_1.DEFAULT_MIGRATION_COMMIT_PREFIX,
2141
+ });
2142
+ if (createCommitsError) {
2143
+ throw new Error(createCommitsError);
2144
+ }
2145
+ if (createCommitsWarning) {
2146
+ output_1.output.warn({ title: createCommitsWarning });
2147
+ }
2148
+ // The run commits on the user's behalf across many invocations, so the
2149
+ // default-branch confirmation belongs here, once, before any of them.
2150
+ if (effectiveCreateCommits &&
2151
+ (0, safe_prompt_1.canPrompt)(opts.interactive) &&
2152
+ !(await (0, migrate_commits_1.confirmMigrationCommitsOnDefaultBranch)(root, 'running migrations'))) {
2153
+ return;
2154
+ }
2155
+ const { packageJson: orchestratorNxPackageJson } = (0, package_json_1.readModulePackageJson)('nx', (0, installation_directory_1.getNxRequirePaths)(root));
2156
+ const { runOrchestratorInit } = require('./run');
2157
+ return await runOrchestratorInit({
2158
+ root,
2159
+ migrationsJson,
2160
+ createCommits: effectiveCreateCommits,
2161
+ commitPrefix,
2162
+ // The flag only, never NX_MIGRATE_SKIP_INSTALL: the wrapper's local
2163
+ // re-exec sets that env var for its own hop, and it says nothing about
2164
+ // what the user asked for.
2165
+ skipInstall: shouldSkipInstall,
2166
+ installedNxVersion: orchestratorNxPackageJson.version,
2167
+ });
2168
+ }
2139
2169
  (0, migrate_analytics_1.reportMigrateRunStart)({
2140
2170
  createCommits: shouldCreateCommits ?? false,
2141
2171
  migrationCount: migrations.length,
2142
2172
  });
2143
- const { resolveAgentic } = require('./agentic/select');
2173
+ const { resolveAgentic, resolveShouldRunValidation } = require('./agentic/select');
2144
2174
  let agentic;
2145
2175
  try {
2146
2176
  agentic = await resolveAgentic({
@@ -2153,9 +2183,9 @@ async function runMigrations(root, opts, args, isVerbose, shouldCreateCommits, c
2153
2183
  (0, migrate_analytics_1.reportMigrateRunError)({ code: 'agentic', error: e });
2154
2184
  throw e;
2155
2185
  }
2156
- const { effective: effectiveCreateCommits, agenticHasDiffContext, warning: createCommitsWarning, error: createCommitsError, } = resolveCreateCommits({
2186
+ const { effective: effectiveCreateCommits, agenticHasDiffContext, warning: createCommitsWarning, error: createCommitsError, } = (0, migrate_commits_1.resolveCreateCommits)({
2157
2187
  createCommits: shouldCreateCommits,
2158
- agenticKind: agentic.kind,
2188
+ mode: agentic.kind,
2159
2189
  isGitRepo: (0, git_utils_1.isGitRepository)(root),
2160
2190
  commitPrefixIsCustom: commitPrefix !== command_object_1.DEFAULT_MIGRATION_COMMIT_PREFIX,
2161
2191
  });
@@ -2165,6 +2195,11 @@ async function runMigrations(root, opts, args, isVerbose, shouldCreateCommits, c
2165
2195
  if (createCommitsWarning) {
2166
2196
  output_1.output.warn({ title: createCommitsWarning });
2167
2197
  }
2198
+ if (effectiveCreateCommits &&
2199
+ (0, safe_prompt_1.canPrompt)(opts.interactive) &&
2200
+ !(await (0, migrate_commits_1.confirmMigrationCommitsOnDefaultBranch)(root, 'running migrations'))) {
2201
+ return;
2202
+ }
2168
2203
  const shouldRunValidation = resolveShouldRunValidation({
2169
2204
  validate: opts.validate,
2170
2205
  agenticKind: agentic.kind,
@@ -2179,8 +2214,9 @@ async function runMigrations(root, opts, args, isVerbose, shouldCreateCommits, c
2179
2214
  (0, migrate_commits_1.commitCheckpointBeforeMigrations)(root, commitPrefix);
2180
2215
  }
2181
2216
  if (agentic.kind === 'enabled') {
2217
+ const { applyAgenticHandoffGitignoreFallback } = require('./agentic/handoff-gitignore');
2182
2218
  const { packageJson: nxPackageJson } = (0, package_json_1.readModulePackageJson)('nx', (0, installation_directory_1.getNxRequirePaths)(root));
2183
- await (0, handoff_gitignore_1.applyAgenticHandoffGitignoreFallback)({
2219
+ await applyAgenticHandoffGitignoreFallback({
2184
2220
  migrations,
2185
2221
  installedNxVersion: nxPackageJson.version,
2186
2222
  effectiveCreateCommits,
@@ -2188,7 +2224,7 @@ async function runMigrations(root, opts, args, isVerbose, shouldCreateCommits, c
2188
2224
  root,
2189
2225
  });
2190
2226
  }
2191
- const { migrationsWithNoChanges, skippedPromptsCount, notRunMigrationsCount, skippedPrompts, migrationEmittedNextSteps, committedShasCount, retainedAtSuccess, } = await executeMigrations(root, migrations, isVerbose, effectiveCreateCommits, commitPrefix, shouldSkipInstall, agentic, agenticHasDiffContext, shouldRunValidation);
2227
+ const { migrationsWithNoChanges, skippedPromptsCount, notRunMigrationsCount, skippedPrompts, migrationEmittedNextSteps, committedShasCount, waivedAgenticStepsCount, retainedAtSuccess, } = await executeMigrations(root, migrations, isVerbose, effectiveCreateCommits, commitPrefix, shouldSkipInstall, agentic, agenticHasDiffContext, shouldRunValidation);
2192
2228
  const ranWithChangesCount = migrations.length - notRunMigrationsCount - migrationsWithNoChanges.length;
2193
2229
  // The "applied" tally counts fully-completed migrations — those that
2194
2230
  // left no deferred work behind. Hybrid migrations whose prompt half was
@@ -2199,6 +2235,7 @@ async function runMigrations(root, opts, args, isVerbose, shouldCreateCommits, c
2199
2235
  appliedCount,
2200
2236
  committedShasCount,
2201
2237
  skippedPromptsCount,
2238
+ waivedAgenticStepsCount,
2202
2239
  insideAgent,
2203
2240
  });
2204
2241
  const tallyBody = tallyLine ? [tallyLine] : undefined;
@@ -2280,18 +2317,30 @@ async function runMigrations(root, opts, args, isVerbose, shouldCreateCommits, c
2280
2317
  appliedCount,
2281
2318
  });
2282
2319
  }
2320
+ function isRunPhaseInvocation(args) {
2321
+ return (args.runMigration !== undefined ||
2322
+ args.runId !== undefined ||
2323
+ args.stepAction !== undefined);
2324
+ }
2283
2325
  async function migrate(root, args, rawArgs) {
2284
2326
  await client_1.daemonClient.stop();
2285
2327
  return (0, handle_errors_1.handleErrors)(process.env.NX_VERBOSE_LOGGING === 'true', async () => {
2286
2328
  const mergedArgs = (0, migrate_config_1.applyNxJsonMigrateDefaults)(args, (0, configuration_1.readNxJson)().migrate);
2287
- (0, migrate_config_1.assertCommitPrefixHasCommits)(mergedArgs);
2329
+ // Run-phase invocations resolve their commit config downstream (run.json
2330
+ // for recorded runs, resolveCreateCommits for standalone), so this assert
2331
+ // must not fire for them; otherwise an nx.json prefix the whole-file run
2332
+ // legitimately uses would wedge every dispensed command.
2333
+ const runPhase = isRunPhaseInvocation(mergedArgs);
2334
+ if (!runPhase) {
2335
+ (0, migrate_config_1.assertCommitPrefixHasCommits)(mergedArgs);
2336
+ }
2288
2337
  // One fetcher (registry-first, install fallback) shared by the `--include`
2289
2338
  // eligibility gate and the migration cascade so package metadata is fetched
2290
2339
  // at most once per package/version.
2291
2340
  const fetch = createFetcher((0, package_manager_1.getPackageManagerCommand)());
2292
- // `--run-migrations` without a value parses as '' - undefined means the
2293
- // generate phase.
2294
- const isGenerateInvocation = mergedArgs['runMigrations'] === undefined;
2341
+ // `--run-migrations` without a value parses as '', so only undefined (and
2342
+ // no run-phase flag) means the generate phase.
2343
+ const isGenerateInvocation = mergedArgs['runMigrations'] === undefined && !runPhase;
2295
2344
  let opts;
2296
2345
  try {
2297
2346
  opts = await parseMigrationsOptions(mergedArgs, fetch);
@@ -2300,36 +2349,320 @@ async function migrate(root, args, rawArgs) {
2300
2349
  if (isGenerateInvocation) {
2301
2350
  (0, migrate_analytics_1.reportMigrateGenerateError)('resolve_version', e);
2302
2351
  }
2352
+ else if (runPhase) {
2353
+ (0, migrate_analytics_1.reportMigrateRunError)({ code: 'other', error: e });
2354
+ }
2303
2355
  throw e;
2304
2356
  }
2305
- if (opts.type === 'generateMigrations') {
2306
- await generateMigrationsJsonAndUpdatePackageJson(root, opts, fetch);
2357
+ switch (opts.type) {
2358
+ case 'generateMigrations':
2359
+ await generateMigrationsJsonAndUpdatePackageJson(root, opts, fetch);
2360
+ return;
2361
+ case 'runSingleMigration':
2362
+ try {
2363
+ return await runSingleMigrationFromCli(root, opts, rawArgs, mergedArgs);
2364
+ }
2365
+ catch (e) {
2366
+ // `runInstall` already logged the remediation; returning instead of
2367
+ // rethrowing keeps `handleErrors` from printing a stack over it.
2368
+ if (e instanceof execute_migration_1.NpmPeerDepsInstallError) {
2369
+ (0, migrate_analytics_1.reportMigrateRunError)({ code: 'npm_install', error: e });
2370
+ return 1;
2371
+ }
2372
+ (0, migrate_analytics_1.reportMigrateRunError)({ code: 'other', error: e });
2373
+ throw e;
2374
+ }
2375
+ case 'orchestratorReconcile':
2376
+ return await runOrchestratorReconcileFromCli(root, opts, rawArgs);
2377
+ case 'runMigrations':
2378
+ try {
2379
+ return await runMigrations(root, opts, rawArgs, mergedArgs['verbose'], mergedArgs['createCommits'], mergedArgs['commitPrefix'] ?? command_object_1.DEFAULT_MIGRATION_COMMIT_PREFIX, mergedArgs['skipInstall']);
2380
+ }
2381
+ catch (e) {
2382
+ if (e instanceof execute_migration_1.NpmPeerDepsInstallError) {
2383
+ (0, migrate_analytics_1.reportMigrateRunError)({ code: 'npm_install', error: e });
2384
+ return 1;
2385
+ }
2386
+ (0, migrate_analytics_1.reportMigrateRunError)({ code: 'other', error: e });
2387
+ throw e;
2388
+ }
2389
+ default: {
2390
+ // `unhandled: never` makes a new invocation type a compile error here
2391
+ // rather than a silent fall-through.
2392
+ const unhandled = opts;
2393
+ throw new Error(`Unhandled migrate invocation type: ${JSON.stringify(unhandled)}`);
2394
+ }
2307
2395
  }
2308
- else {
2309
- try {
2310
- return await runMigrations(root, opts, rawArgs, mergedArgs['verbose'], mergedArgs['createCommits'], mergedArgs['commitPrefix'] ?? command_object_1.DEFAULT_MIGRATION_COMMIT_PREFIX, mergedArgs['skipInstall']);
2396
+ });
2397
+ }
2398
+ // Evaluated manifest code can throw any value: a null-prototype object defeats
2399
+ // String() (the Object.prototype.toString rung catches it), and a revoked
2400
+ // proxy defeats that too. Interpolating either in a catch would throw again
2401
+ // and escape the catch.
2402
+ function stringifyCaught(e) {
2403
+ try {
2404
+ return String(e);
2405
+ }
2406
+ catch {
2407
+ try {
2408
+ return Object.prototype.toString.call(e);
2409
+ }
2410
+ catch {
2411
+ return '<unprintable value>';
2412
+ }
2413
+ }
2414
+ }
2415
+ // A resolver-based lookup (including `resolvePackageJsonWithoutCachePollution`,
2416
+ // which does defeat Node's package self-reference) is the wrong tool here:
2417
+ // resolvers fall back to NODE_PATH after the explicit paths, and NODE_PATH
2418
+ // names the temp installation when this runs there. The scan below reads its
2419
+ // candidate directories itself, so neither NODE_PATH nor self-reference can
2420
+ // reach it; `getNxBin` (utils/child-process.ts), which locates the nx the
2421
+ // hand-off spawns, avoids resolvers for the same reason, over a narrower set
2422
+ // of directories: it skips `.nx/installation`, declines a root without a
2423
+ // package.json, and stops at the nearest install rather than reading past an
2424
+ // unusable one. The PnP branch below stays bespoke either way: a resolver
2425
+ // cannot see into the zip cache without the PnP runtime.
2426
+ function readLocalNxVersion(root) {
2427
+ // A PnP manifest is consulted only when yarn drives the hand-off:
2428
+ // `getRunNxBaseCommand` builds the hand-off command through this same
2429
+ // detectPackageManager call (which answers from nx.json's
2430
+ // cli.packageManager first, before any lockfile), and yarn is the one
2431
+ // package manager that executes the manifest's nx. That mirror alone
2432
+ // cannot see a switch off yarn, because yarn.lock survives one and
2433
+ // outranks all but bun's lockfiles in the detection order, while .pnp.cjs
2434
+ // lingers only on a switch to another package manager (yarn removes it
2435
+ // when moving to node_modules linking). A rival lockfile beside the
2436
+ // manifest is therefore read as evidence of such a switch, though not
2437
+ // proof, since `pnpm install --lockfile-only` writes one without
2438
+ // installing: on a scan miss the manifest still answers rather than
2439
+ // failing the guards, and a rival install over a still-live PnP
2440
+ // workspace is read over the PnP nx the yarn spawn executes, because
2441
+ // preferring the manifest would judge the dead install that a completed
2442
+ // switch leaves behind and refuse persistently. The known misread left
2443
+ // is yarn classic driving a workspace with a leftover Berry manifest
2444
+ // and no other lockfile; telling the two yarns apart from disk is not
2445
+ // worth the fragility, and a `yarn node` runtime probe was rejected
2446
+ // because its stdout is forgeable through an inherited NODE_OPTIONS
2447
+ // preload and a hung descendant holding the output pipe outlives a
2448
+ // subprocess timeout on this synchronous path.
2449
+ const pnpManifest = ['.pnp.cjs', '.pnp.js']
2450
+ .map((f) => (0, path_1.join)(root, f))
2451
+ .find((f) => (0, fs_1.existsSync)(f));
2452
+ if (pnpManifest) {
2453
+ const competingLockfile = [
2454
+ 'package-lock.json',
2455
+ 'npm-shrinkwrap.json',
2456
+ 'pnpm-lock.yaml',
2457
+ 'bun.lockb',
2458
+ 'bun.lock',
2459
+ ].some((f) => (0, fs_1.existsSync)((0, path_1.join)(root, f)));
2460
+ if (competingLockfile) {
2461
+ const version = scanNodeModulesForNxVersion(root);
2462
+ if (version) {
2463
+ return version;
2311
2464
  }
2312
- catch (e) {
2313
- // The remediation guidance is already logged by `runInstall`; swallow
2314
- // the error here so `handleErrors` doesn't print a noisy stack after
2315
- // the friendly output.
2316
- if (e instanceof execute_migration_1.NpmPeerDepsInstallError) {
2317
- (0, migrate_analytics_1.reportMigrateRunError)({ code: 'npm_install', error: e });
2318
- return 1;
2465
+ }
2466
+ try {
2467
+ if ((0, package_manager_1.detectPackageManager)(root) === 'yarn') {
2468
+ // Compiled manually rather than required: a require would serve the
2469
+ // stale cached copy the runtime loaded at startup. new Function does
2470
+ // not strip a leading shebang like the CJS loader, so drop it here.
2471
+ const manifestModule = {
2472
+ exports: {},
2473
+ };
2474
+ new Function('module', 'exports', 'require', '__dirname', '__filename', (0, fs_1.readFileSync)(pnpManifest, 'utf-8').replace(/^#!.*/, ''))(manifestModule, manifestModule.exports, require, root, pnpManifest);
2475
+ const packageJsonPath = manifestModule.exports.resolveRequest('nx/package.json', (0, path_1.join)(root, 'package.json'));
2476
+ if (packageJsonPath) {
2477
+ // A resolving manifest names the install the yarn spawn runs, so
2478
+ // every branch below returns rather than falling through to the
2479
+ // ancestor scan.
2480
+ try {
2481
+ const { version } = (0, fileutils_1.readJsonFile)(packageJsonPath);
2482
+ if (typeof version === 'string') {
2483
+ logger_1.logger.verbose(`Read the workspace's nx version ${version} from '${packageJsonPath}'.`);
2484
+ return version;
2485
+ }
2486
+ logger_1.logger.verbose(`'${packageJsonPath}' does not declare a usable version.`);
2487
+ return undefined;
2488
+ }
2489
+ catch (readError) {
2490
+ // A zip-served path (installs with scripts disabled keep nx
2491
+ // zipped) cannot be read without the PnP runtime's zip fs, but
2492
+ // the manifest's own locator still names the version (e.g.
2493
+ // 'virtual:<hash>#npm:23.1.0').
2494
+ let version;
2495
+ try {
2496
+ const reference = manifestModule.exports.findPackageLocator?.(packageJsonPath)?.reference;
2497
+ version =
2498
+ typeof reference === 'string'
2499
+ ? reference.match(/npm:([^#:]+)/)?.[1]
2500
+ : undefined;
2501
+ }
2502
+ catch (locatorError) {
2503
+ logger_1.logger.verbose(`Could not read the nx locator from the PnP manifest '${pnpManifest}': ${stringifyCaught(locatorError)}`);
2504
+ }
2505
+ if (version && (0, semver_1.valid)(version)) {
2506
+ logger_1.logger.verbose(`Read the workspace's nx version ${version} from the locator in the PnP manifest '${pnpManifest}'.`);
2507
+ return version;
2508
+ }
2509
+ logger_1.logger.verbose(`Could not read the workspace's nx version through the PnP manifest '${pnpManifest}': ${stringifyCaught(readError)}`);
2510
+ return undefined;
2511
+ }
2319
2512
  }
2320
- (0, migrate_analytics_1.reportMigrateRunError)({ code: 'other', error: e });
2321
- throw e;
2322
2513
  }
2323
2514
  }
2515
+ catch (e) {
2516
+ // Degrade to the full scan: neither a failed detection nor an
2517
+ // unevaluable manifest can name the spawn's nx.
2518
+ logger_1.logger.verbose(`Could not read the workspace's nx version through the PnP manifest '${pnpManifest}': ${stringifyCaught(e)}`);
2519
+ }
2520
+ }
2521
+ return scanNodeModulesForNxVersion(root);
2522
+ }
2523
+ // The workspace's own install locations first (.nx/installation, root), then
2524
+ // ancestor directories: package-manager executable lookup ascends (npx and
2525
+ // bun always, pnpm and yarn inside an outer workspace) and hoisted layouts
2526
+ // install nx above the workspace root. `getNxBin` ascends too, so an ancestor
2527
+ // read here is usually the one the hand-off spawns. They diverge for a
2528
+ // `.nx/installation` workspace, which `getNxBin` declines, and where the only
2529
+ // nx found sits past the package manager's own lookup boundary and the spawn
2530
+ // has fallen back to that manager: yarn then reports "command not found"
2531
+ // while pnpm exec lands on an nx on PATH. The version read here is therefore
2532
+ // the readable answer, not necessarily the executed one.
2533
+ function scanNodeModulesForNxVersion(root) {
2534
+ const searchPaths = [...(0, installation_directory_1.getNxRequirePaths)(root)];
2535
+ for (let dir = (0, path_1.dirname)(root);; dir = (0, path_1.dirname)(dir)) {
2536
+ searchPaths.push(dir);
2537
+ if (dir === (0, path_1.dirname)(dir)) {
2538
+ break;
2539
+ }
2540
+ }
2541
+ return readNxVersionFromNodeModules(searchPaths);
2542
+ }
2543
+ function readNxVersionFromNodeModules(searchPaths) {
2544
+ for (const searchPath of searchPaths) {
2545
+ const packageJsonPath = (0, path_1.join)(searchPath, 'node_modules', 'nx', 'package.json');
2546
+ try {
2547
+ if ((0, fs_1.existsSync)(packageJsonPath)) {
2548
+ const { version } = (0, fileutils_1.readJsonFile)(packageJsonPath);
2549
+ if (typeof version === 'string') {
2550
+ logger_1.logger.verbose(`Resolved nx version ${version} from '${packageJsonPath}'.`);
2551
+ return version;
2552
+ }
2553
+ logger_1.logger.verbose(`'${packageJsonPath}' does not declare a usable version; continuing the search.`);
2554
+ }
2555
+ }
2556
+ catch (e) {
2557
+ logger_1.logger.verbose(`Could not read the workspace's installed nx version from '${packageJsonPath}': ${e}`);
2558
+ }
2559
+ }
2560
+ return undefined;
2561
+ }
2562
+ // Mirrors the local-nx hand-off of the other run paths so a reconcile always
2563
+ // executes against the workspace-local nx that owns the run state, never the
2564
+ // temp installation. Reconciles only read state and commit, so no install.
2565
+ async function runOrchestratorReconcileFromCli(root, opts, args) {
2566
+ if (!__dirname.startsWith(workspace_root_1.workspaceRoot)) {
2567
+ // The workspace-local nx we are about to hand off to must be new enough to
2568
+ // understand the new flags we forward to it.
2569
+ (0, version_skew_guard_1.assertWorkspaceNxSupportsNewMigrateFlags)({
2570
+ argv: args,
2571
+ readLocalNxVersion: () => readLocalNxVersion(root),
2572
+ });
2573
+ return handOffToLocalNx(args);
2574
+ }
2575
+ const { runOrchestratorReconcile } = require('./run');
2576
+ return runOrchestratorReconcile({
2577
+ root,
2578
+ runId: opts.runId,
2579
+ stepAction: opts.stepAction,
2580
+ });
2581
+ }
2582
+ // Keeps `--run-migration` behaving like `--run-migrations` when invoked from
2583
+ // a temp `nx@latest` install: same pre-install, same local-nx hand-off.
2584
+ async function runSingleMigrationFromCli(root, opts, args, mergedArgs) {
2585
+ const shouldSkipInstall = mergedArgs['skipInstall'] ?? false;
2586
+ // A recorded execution skips the pre-install: the run carries its own
2587
+ // install policy and its worker installs what the migration changed, so
2588
+ // paying for a full install ahead of every dispensed command would be
2589
+ // redundant.
2590
+ if (opts.runId === undefined &&
2591
+ !shouldSkipInstall &&
2592
+ !process.env.NX_MIGRATE_SKIP_INSTALL) {
2593
+ await (0, execute_migration_1.runInstall)(undefined, 'pre-migration', (0, execute_migration_1.formatSingleMigrationRerunCommand)(opts.runMigration));
2594
+ }
2595
+ if (!__dirname.startsWith(workspace_root_1.workspaceRoot)) {
2596
+ // Must stay after the pre-install: it reads the version that install may
2597
+ // have just updated, so checking earlier would falsely refuse a workspace
2598
+ // whose package.json bump was not installed yet.
2599
+ (0, version_skew_guard_1.assertWorkspaceNxSupportsNewMigrateFlags)({
2600
+ argv: args,
2601
+ // `workspaceRoot`, not `root`: the migrate flow's `root` is the
2602
+ // invocation directory, which may sit below the workspace the hand-off
2603
+ // resolves nx in.
2604
+ readLocalNxVersion: () => readLocalNxVersion(workspace_root_1.workspaceRoot),
2605
+ });
2606
+ return handOffToLocalNx(args);
2607
+ }
2608
+ // The worker resolves the agentic flow, the effective commit config, and
2609
+ // the default-branch confirmation itself; hand it the raw flags. Recorded
2610
+ // runs (--run-id) take their commit config from run.json instead.
2611
+ // Lazy-load run/ so plain migrate and repair runs don't pay for the agentic
2612
+ // selection chain its barrel pulls in eagerly.
2613
+ const { runSingleMigrationWorker } = require('./run');
2614
+ await runSingleMigrationWorker({
2615
+ root,
2616
+ runMigration: opts.runMigration,
2617
+ runId: opts.runId,
2618
+ agentic: opts.agentic,
2619
+ validate: opts.validate,
2620
+ createCommits: mergedArgs['createCommits'],
2621
+ commitPrefix: mergedArgs['commitPrefix'] ??
2622
+ command_object_1.DEFAULT_MIGRATION_COMMIT_PREFIX,
2623
+ interactive: opts.interactive,
2624
+ skipInstall: shouldSkipInstall,
2625
+ isVerbose: mergedArgs['verbose'] ?? false,
2324
2626
  });
2325
2627
  }
2326
2628
  async function runMigration() {
2327
2629
  return (0, handle_errors_1.handleErrors)(process.env.NX_VERBOSE_LOGGING === 'true', async () => {
2328
- const runLocalMigrate = () => runOrReturnExitCode(() => (0, child_process_2.runNxSync)(`_migrate ${process.argv.slice(3).join(' ')}`, {
2630
+ // Spawning `nx _migrate` re-resolves the workspace's nx, normally the
2631
+ // very installation running this code: bin/nx.ts delegated the outer
2632
+ // `migrate` command to it, while `_migrate` skips that delegation. A
2633
+ // new-flag invocation reaching this fallback therefore lands on an nx
2634
+ // that parsed the flags, so it needs no capability check. Two lookups
2635
+ // can still diverge from the running install, both properties of the
2636
+ // spawn machinery rather than of this fallback: a `.nx/installation`
2637
+ // beside a root package.json, and, once the spawn falls back to the
2638
+ // package manager, a lookup that misses the workspace install and lands
2639
+ // on an nx on PATH (pnpm exec).
2640
+ const forwardedArgv = process.argv.slice(3);
2641
+ const runLocalMigrate = () => runOrReturnExitCode(() => (0, child_process_2.runNxArgvSync)(['_migrate', ...forwardedArgv], {
2329
2642
  stdio: ['inherit', 'inherit', 'inherit'],
2330
2643
  }));
2331
- if (process.env.NX_USE_LOCAL !== 'true' &&
2644
+ if (!(0, version_skew_guard_1.targetsExistingRun)(process.argv.slice(3)) &&
2645
+ process.env.NX_USE_LOCAL !== 'true' &&
2332
2646
  process.env.NX_MIGRATE_USE_LOCAL === undefined) {
2647
+ // The version spec mirrors nxCliPath's; keep the two in sync.
2648
+ const cliVersionSpec = process.env.NX_MIGRATE_CLI_VERSION || 'latest';
2649
+ const target = await (0, version_skew_guard_1.resolveNewMigrateFlagsRunTarget)({
2650
+ argv: process.argv.slice(3),
2651
+ cliVersionSpec,
2652
+ fromEnvOverride: !!process.env.NX_MIGRATE_CLI_VERSION,
2653
+ ownNxVersion: versions_1.nxVersion,
2654
+ resolveVersion: (spec) =>
2655
+ // A probe must not prompt, write pnpm excludes, or install; a
2656
+ // minimum-release-age violation surfaces as a rejection and
2657
+ // routes local.
2658
+ (0, resolve_package_version_1.resolvePackageVersionRespectingMinReleaseAge)('nx', spec, {
2659
+ applySideEffects: false,
2660
+ }),
2661
+ readLocalNxVersion: () => readLocalNxVersion(workspace_root_1.workspaceRoot),
2662
+ });
2663
+ if (target === 'local-nx') {
2664
+ return runLocalMigrate();
2665
+ }
2333
2666
  const p = await nxCliPath();
2334
2667
  if (p === null) {
2335
2668
  return runLocalMigrate();
@@ -2340,14 +2673,26 @@ async function runMigration() {
2340
2673
  process.env.npm_config_registry.match(/^https:\/\/registry\.(npmjs\.org|yarnpkg\.com)/)) {
2341
2674
  delete process.env.npm_config_registry;
2342
2675
  }
2343
- // Intentionally not runNxSync: `p` is an nx CLI freshly installed into a
2344
- // temp dir by nxCliPath() (latest, or NX_MIGRATE_CLI_VERSION), so
2345
- // migrations run with an up-to-date migrate implementation instead of
2346
- // the workspace's current nx.
2347
- return runOrReturnExitCode(() => (0, child_process_1.execSync)(`${p} _migrate ${process.argv.slice(3).join(' ')}`, {
2348
- stdio: ['inherit', 'inherit', 'inherit'],
2349
- windowsHide: true,
2350
- }));
2676
+ // Intentionally not the workspace's nx: `p` is an nx CLI freshly
2677
+ // installed into a temp dir by nxCliPath() (latest, or
2678
+ // NX_MIGRATE_CLI_VERSION), so migrations run with an up-to-date migrate
2679
+ // implementation. `p` is <tmpDir>/node_modules/.bin/nx, a shell shim;
2680
+ // spawning the entry point that install's own manifest names instead
2681
+ // keeps the forwarded argv out of a shell. That install declares nx
2682
+ // itself, so it is read without ascending: an nx above the temp dir is
2683
+ // one nothing asked for, and the shim below is the answer instead.
2684
+ const tempNxEntry = (0, child_process_2.readInstalledNxBin)((0, path_1.dirname)((0, path_1.dirname)((0, path_1.dirname)(p))));
2685
+ return runOrReturnExitCode(() => tempNxEntry
2686
+ ? (0, child_process_2.runNxArgvSync)(['_migrate', ...forwardedArgv], {
2687
+ stdio: ['inherit', 'inherit', 'inherit'],
2688
+ nxBin: tempNxEntry,
2689
+ })
2690
+ : (0, child_process_1.execSync)(`${(0, shell_quoting_1.quoteShellArg)(p)} _migrate ${forwardedArgv
2691
+ .map(shell_quoting_1.quoteShellArg)
2692
+ .join(' ')}`, {
2693
+ stdio: ['inherit', 'inherit', 'inherit'],
2694
+ windowsHide: true,
2695
+ }));
2351
2696
  }
2352
2697
  return runLocalMigrate();
2353
2698
  });
@@ -2383,7 +2728,7 @@ function resolveMigrationForRun(root, migration, resolveDocumentation) {
2383
2728
  let documentationPath;
2384
2729
  if (resolveDocumentation && migration.documentation) {
2385
2730
  documentationPath = resolvedCollection
2386
- ? resolveDocumentationFileToWorkspacePath(root, (0, path_1.dirname)(resolvedCollection.collectionPath), migration.documentation)
2731
+ ? (0, execute_migration_1.resolveDocumentationFileToWorkspacePath)(root, (0, path_1.dirname)(resolvedCollection.collectionPath), migration.documentation)
2387
2732
  : undefined;
2388
2733
  if (!documentationPath) {
2389
2734
  logger_1.logger.warn(`Could not resolve the "documentation" file "${migration.documentation}" declared for migration "${migration.package}: ${migration.name}". It will be skipped as additional context for the AI agent.`);
@@ -2391,24 +2736,6 @@ function resolveMigrationForRun(root, migration, resolveDocumentation) {
2391
2736
  }
2392
2737
  return { resolvedCollection, documentationPath };
2393
2738
  }
2394
- // Resolves a `documentation` path (relative to the package's migrations dir) to
2395
- // a workspace-relative path - or the absolute path when it resolves outside the
2396
- // workspace (unusual hoisted/symlinked layouts). The agent runs with cwd =
2397
- // workspace root, so the workspace-relative form is preferred. Returns
2398
- // undefined when the file can't be resolved.
2399
- function resolveDocumentationFileToWorkspacePath(root, migrationsDir, documentation) {
2400
- let documentationFile;
2401
- try {
2402
- documentationFile = require.resolve(documentation, {
2403
- paths: [migrationsDir],
2404
- });
2405
- }
2406
- catch {
2407
- return undefined;
2408
- }
2409
- const relativePath = (0, path_1.relative)(root, documentationFile);
2410
- return relativePath.startsWith('..') ? documentationFile : relativePath;
2411
- }
2412
2739
  async function nxCliPath(nxWorkspaceRoot) {
2413
2740
  const version = process.env.NX_MIGRATE_CLI_VERSION || 'latest';
2414
2741
  const isVerbose = process.env.NX_VERBOSE_LOGGING === 'true';
@@ -2459,7 +2786,7 @@ async function nxCliPath(nxWorkspaceRoot) {
2459
2786
  return (0, path_1.join)(tmpDir, `node_modules`, '.bin', 'nx');
2460
2787
  }
2461
2788
  catch (e) {
2462
- console.error(`Failed to install the ${version} version of the migration script. Using the current version.`);
2789
+ console.error(`Failed to install the ${version} version of the migration script. Falling back to the workspace's installed nx.`);
2463
2790
  if (isVerbose) {
2464
2791
  console.error(e);
2465
2792
  }