nx 23.2.0-beta.0 → 23.2.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/init-local.js +3 -5
- package/dist/bin/nx.js +3 -1
- package/dist/release/changelog-renderer/index.js +4 -5
- package/dist/release/index.d.ts +1 -1
- package/dist/src/adapter/ngcli-adapter.js +60 -1
- package/dist/src/ai/set-up-ai-agents/set-up-ai-agents.js +35 -15
- package/dist/src/analytics/analytics.d.ts +6 -0
- package/dist/src/analytics/analytics.js +16 -10
- package/dist/src/analytics/index.d.ts +1 -1
- package/dist/src/analytics/index.js +2 -1
- package/dist/src/command-line/add/add.js +5 -0
- package/dist/src/command-line/affected/affected.js +1 -0
- package/dist/src/command-line/completion/command-object.js +7 -12
- package/dist/src/command-line/configure-ai-agents/configure-ai-agents.js +19 -25
- package/dist/src/command-line/format/format.js +84 -101
- package/dist/src/command-line/generate/generate.js +35 -35
- package/dist/src/command-line/graph/graph.d.ts +1 -0
- package/dist/src/command-line/graph/graph.js +15 -6
- package/dist/src/command-line/import/import.js +30 -40
- package/dist/src/command-line/init/ai-agent-prompts.d.ts +1 -1
- package/dist/src/command-line/init/ai-agent-prompts.js +12 -17
- package/dist/src/command-line/init/command-object.js +14 -4
- package/dist/src/command-line/init/configure-plugins.js +4 -1
- package/dist/src/command-line/init/implementation/add-nx-to-monorepo.js +12 -32
- package/dist/src/command-line/init/implementation/add-nx-to-nest.js +17 -21
- package/dist/src/command-line/init/implementation/add-nx-to-npm-repo.js +8 -21
- package/dist/src/command-line/init/implementation/add-nx-to-turborepo.js +3 -17
- package/dist/src/command-line/init/implementation/angular/index.js +10 -15
- package/dist/src/command-line/init/implementation/angular/integrated-workspace.js +2 -5
- package/dist/src/command-line/init/implementation/angular/legacy-angular-versions.js +5 -0
- package/dist/src/command-line/init/implementation/angular/standalone-workspace.js +8 -2
- package/dist/src/command-line/init/implementation/check-compatible-with-plugins.js +2 -0
- package/dist/src/command-line/init/implementation/dot-nx/add-nx-scripts.js +9 -1
- package/dist/src/command-line/init/implementation/format.d.ts +18 -0
- package/dist/src/command-line/init/implementation/format.js +114 -0
- package/dist/src/command-line/init/implementation/utils.js +8 -0
- package/dist/src/command-line/init/init-v1.js +15 -18
- package/dist/src/command-line/init/init-v2.js +40 -57
- package/dist/src/command-line/migrate/agentic/definitions.js +36 -9
- package/dist/src/command-line/migrate/agentic/handoff-gitignore.d.ts +37 -22
- package/dist/src/command-line/migrate/agentic/handoff-gitignore.js +30 -39
- package/dist/src/command-line/migrate/agentic/handoff.d.ts +7 -7
- package/dist/src/command-line/migrate/agentic/handoff.js +13 -10
- package/dist/src/command-line/migrate/agentic/print-dropped-agent-context.d.ts +7 -12
- package/dist/src/command-line/migrate/agentic/print-dropped-agent-context.js +7 -0
- package/dist/src/command-line/migrate/agentic/run-step.d.ts +10 -0
- package/dist/src/command-line/migrate/agentic/run-step.js +1 -0
- package/dist/src/command-line/migrate/agentic/runner.js +24 -24
- package/dist/src/command-line/migrate/agentic/select.d.ts +10 -2
- package/dist/src/command-line/migrate/agentic/select.js +30 -32
- package/dist/src/command-line/migrate/agentic/types.d.ts +33 -3
- package/dist/src/command-line/migrate/agentic/types.js +35 -0
- package/dist/src/command-line/migrate/command-object.d.ts +6 -0
- package/dist/src/command-line/migrate/command-object.js +19 -1
- package/dist/src/command-line/migrate/execute-migration.d.ts +91 -0
- package/dist/src/command-line/migrate/execute-migration.js +474 -0
- package/dist/src/command-line/migrate/migrate-analytics.d.ts +35 -0
- package/dist/src/command-line/migrate/migrate-analytics.js +64 -0
- package/dist/src/command-line/migrate/migrate-commits.d.ts +38 -8
- package/dist/src/command-line/migrate/migrate-commits.js +130 -15
- package/dist/src/command-line/migrate/migrate-config.d.ts +13 -12
- package/dist/src/command-line/migrate/migrate-config.js +22 -14
- package/dist/src/command-line/migrate/migrate-output.d.ts +45 -7
- package/dist/src/command-line/migrate/migrate-output.js +52 -8
- package/dist/src/command-line/migrate/migrate-ui-api.d.ts +2 -1
- package/dist/src/command-line/migrate/migrate-ui-api.js +33 -19
- package/dist/src/command-line/migrate/migrate.d.ts +29 -113
- package/dist/src/command-line/migrate/migrate.js +666 -664
- package/dist/src/command-line/migrate/migration-shape.d.ts +8 -0
- package/dist/src/command-line/migrate/multi-major.js +7 -10
- package/dist/src/command-line/migrate/resolve-package-version.js +4 -8
- package/dist/src/command-line/migrate/run/agent-output.d.ts +20 -0
- package/dist/src/command-line/migrate/run/agent-output.js +65 -0
- package/dist/src/command-line/migrate/run/index.d.ts +9 -0
- package/dist/src/command-line/migrate/run/index.js +23 -0
- package/dist/src/command-line/migrate/run/orchestrator.d.ts +20 -0
- package/dist/src/command-line/migrate/run/orchestrator.js +1200 -0
- package/dist/src/command-line/migrate/run/run-id.d.ts +16 -0
- package/dist/src/command-line/migrate/run/run-id.js +56 -0
- package/dist/src/command-line/migrate/run/run-state.d.ts +157 -0
- package/dist/src/command-line/migrate/run/run-state.js +438 -0
- package/dist/src/command-line/migrate/run/state-lock.d.ts +25 -0
- package/dist/src/command-line/migrate/run/state-lock.js +76 -0
- package/dist/src/command-line/migrate/run/state-machine.d.ts +84 -0
- package/dist/src/command-line/migrate/run/state-machine.js +315 -0
- package/dist/src/command-line/migrate/run/util.d.ts +59 -0
- package/dist/src/command-line/migrate/run/util.js +148 -0
- package/dist/src/command-line/migrate/run/worker.d.ts +16 -0
- package/dist/src/command-line/migrate/run/worker.js +682 -0
- package/dist/src/command-line/migrate/run-migration-process.js +6 -5
- package/dist/src/command-line/migrate/safe-prompt.d.ts +14 -26
- package/dist/src/command-line/migrate/safe-prompt.js +32 -43
- package/dist/src/command-line/migrate/sort-migrations.d.ts +16 -0
- package/dist/src/command-line/migrate/sort-migrations.js +32 -0
- package/dist/src/command-line/migrate/step-actions.d.ts +5 -0
- package/dist/src/command-line/migrate/step-actions.js +12 -0
- package/dist/src/command-line/migrate/text.d.ts +18 -0
- package/dist/src/command-line/migrate/text.js +26 -0
- package/dist/src/command-line/migrate/version-skew-guard.d.ts +60 -0
- package/dist/src/command-line/migrate/version-skew-guard.js +175 -0
- package/dist/src/command-line/nx-cloud/connect/connect-to-nx-cloud.js +17 -21
- package/dist/src/command-line/nx-cloud/connect/view-logs.js +2 -0
- package/dist/src/command-line/nx-cloud/start-nx-agents/command-object.d.ts +2 -0
- package/dist/src/command-line/nx-cloud/start-nx-agents/command-object.js +16 -0
- package/dist/src/command-line/nx-cloud/start-nx-agents/start-nx-agents.d.ts +4 -0
- package/dist/src/command-line/nx-cloud/start-nx-agents/start-nx-agents.js +13 -0
- package/dist/src/command-line/nx-commands.js +26 -24
- package/dist/src/command-line/release/changelog.js +11 -17
- package/dist/src/command-line/release/index.d.ts +1 -1
- package/dist/src/command-line/release/plan.js +15 -28
- package/dist/src/command-line/release/publish.js +5 -0
- package/dist/src/command-line/release/release.js +6 -17
- package/dist/src/command-line/release/utils/git.js +1 -1
- package/dist/src/command-line/release/utils/release-graph.d.ts +20 -2
- package/dist/src/command-line/release/utils/release-graph.js +81 -21
- package/dist/src/command-line/release/utils/remote-release-clients/github.js +17 -23
- package/dist/src/command-line/release/utils/remote-release-clients/gitlab.js +14 -23
- package/dist/src/command-line/release/utils/resolve-semver-specifier.js +19 -41
- package/dist/src/command-line/release/utils/shared.d.ts +2 -2
- package/dist/src/command-line/release/version/release-group-processor.d.ts +24 -0
- package/dist/src/command-line/release/version/release-group-processor.js +80 -6
- package/dist/src/command-line/release/version/resolve-current-version.js +7 -10
- package/dist/src/command-line/release/version/version-actions.d.ts +27 -2
- package/dist/src/command-line/release/version/version-actions.js +9 -1
- package/dist/src/command-line/release/version.js +10 -6
- package/dist/src/command-line/reset/reset.js +6 -1
- package/dist/src/command-line/run/run-one.js +1 -0
- package/dist/src/command-line/run-many/run-many.js +1 -0
- package/dist/src/command-line/show/show-target/inputs.js +50 -153
- package/dist/src/command-line/show/show-target/outputs.js +48 -173
- package/dist/src/command-line/show/show-target/utils.d.ts +28 -0
- package/dist/src/command-line/show/show-target/utils.js +83 -3
- package/dist/src/command-line/watch/watch.js +13 -0
- package/dist/src/command-line/yargs-utils/shared-options.d.ts +2 -2
- package/dist/src/command-line/yargs-utils/shared-options.js +3 -1
- package/dist/src/commands-runner/create-command-graph.js +5 -0
- package/dist/src/config/misc-interfaces.d.ts +19 -7
- package/dist/src/config/nx-json.d.ts +5 -3
- package/dist/src/core/graph/main.js +1 -1
- package/dist/src/core/graph/styles.js +1 -1
- package/dist/src/daemon/client/client.d.ts +52 -1
- package/dist/src/daemon/client/client.js +160 -36
- package/dist/src/daemon/client/daemon-environment.d.ts +17 -0
- package/dist/src/daemon/client/daemon-environment.js +110 -2
- package/dist/src/daemon/client/daemon-socket-messenger.js +4 -0
- package/dist/src/daemon/message-types/daemon-message.d.ts +32 -0
- package/dist/src/daemon/message-types/daemon-message.js +25 -0
- package/dist/src/daemon/server/file-watching/file-watcher-sockets.d.ts +5 -0
- package/dist/src/daemon/server/file-watching/file-watcher-sockets.js +16 -0
- package/dist/src/daemon/server/handle-tasks-execution-hooks.d.ts +1 -1
- package/dist/src/daemon/server/latest-nx.js +5 -2
- package/dist/src/daemon/server/server.js +31 -4
- package/dist/src/daemon/server/shutdown-utils.d.ts +5 -0
- package/dist/src/daemon/server/shutdown-utils.js +11 -4
- package/dist/src/daemon/socket-utils.d.ts +1 -0
- package/dist/src/daemon/socket-utils.js +24 -3
- package/dist/src/daemon/tmp-dir.d.ts +43 -3
- package/dist/src/daemon/tmp-dir.js +437 -15
- package/dist/src/devkit-internals.d.ts +105 -8
- package/dist/src/devkit-internals.js +223 -7
- package/dist/src/executors/run-commands/running-tasks.js +46 -29
- package/dist/src/generators/internal-utils/format-changed-files.d.ts +24 -0
- package/dist/src/generators/internal-utils/format-changed-files.js +163 -0
- package/dist/src/generators/testing-utils/create-tree-with-empty-workspace.d.ts +15 -0
- package/dist/src/generators/testing-utils/create-tree-with-empty-workspace.js +21 -3
- package/dist/src/generators/tree.d.ts +4 -2
- package/dist/src/generators/utils/nx-json.js +13 -3
- package/dist/src/hasher/check-task-files.d.ts +86 -0
- package/dist/src/hasher/check-task-files.js +378 -0
- package/dist/src/migrations/update-15-0-0/prefix-outputs.js +2 -2
- package/dist/src/migrations/update-16-0-0/remove-nrwl-cli.js +2 -2
- package/dist/src/migrations/update-16-0-0/update-depends-on-to-tokens.js +2 -2
- package/dist/src/migrations/update-16-0-0/update-nx-cloud-runner.js +2 -2
- package/dist/src/migrations/update-16-2-0/remove-run-commands-output-path.js +2 -2
- package/dist/src/migrations/update-17-0-0/rm-default-collection-npm-scope.js +2 -2
- package/dist/src/migrations/update-17-0-0/use-minimal-config-for-tasks-runner-options.js +2 -2
- package/dist/src/migrations/update-17-2-0/move-default-base.js +2 -2
- package/dist/src/migrations/update-18-0-0/disable-crystal-for-existing-workspaces.js +2 -2
- package/dist/src/migrations/update-19-2-4/set-project-name.js +2 -2
- package/dist/src/migrations/update-20-0-0/move-use-daemon-process.js +2 -2
- package/dist/src/migrations/update-20-0-1/use-legacy-cache.js +2 -2
- package/dist/src/migrations/update-21-0-0/release-changelog-config-changes.js +2 -2
- package/dist/src/migrations/update-21-0-0/release-version-config-changes.js +2 -2
- package/dist/src/migrations/update-21-0-0/remove-custom-tasks-runner.js +2 -2
- package/dist/src/migrations/update-21-0-0/remove-legacy-cache.js +2 -2
- package/dist/src/migrations/update-22-0-0/consolidate-release-tag-config.js +2 -2
- package/dist/src/migrations/update-22-0-0/release-version-config-changes.js +2 -2
- package/dist/src/migrations/update-22-2-0/add-self-healing-to-gitignore.js +2 -2
- package/dist/src/migrations/update-22-6-0/add-claude-settings-local-to-git-ignore.js +2 -2
- package/dist/src/migrations/update-22-6-0/add-claude-worktrees-to-git-ignore.js +2 -2
- package/dist/src/migrations/update-22-7-0/add-polygraph-to-git-ignore.js +2 -2
- package/dist/src/migrations/update-23-0-0/add-migrate-runs-to-git-ignore.js +2 -2
- package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.d.ts +12 -0
- package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.js +250 -0
- package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.md +50 -0
- package/dist/src/native/index.d.ts +37 -4
- package/dist/src/native/index.js +71 -28
- package/dist/src/native/native-bindings.js +3 -0
- package/dist/src/native/native-file-cache-location.d.ts +17 -1
- package/dist/src/native/native-file-cache-location.js +86 -12
- package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
- package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
- package/dist/src/nx-cloud/generators/connect-to-nx-cloud/connect-to-nx-cloud.js +3 -3
- package/dist/src/nx-cloud/utilities/get-cloud-options.js +5 -2
- package/dist/src/nx-cloud/utilities/onboarding.js +5 -2
- package/dist/src/nx-cloud/utilities/url-shorten.d.ts +1 -4
- package/dist/src/nx-cloud/utilities/url-shorten.js +9 -8
- package/dist/src/plugins/js/lock-file/bun-parser.js +43 -10
- package/dist/src/plugins/js/lock-file/lock-file.d.ts +46 -4
- package/dist/src/plugins/js/lock-file/lock-file.js +192 -15
- package/dist/src/plugins/js/lock-file/pnpm-parser.js +420 -64
- package/dist/src/plugins/js/lock-file/project-graph-pruning.d.ts +25 -1
- package/dist/src/plugins/js/lock-file/project-graph-pruning.js +92 -12
- package/dist/src/plugins/js/lock-file/pruned-output.d.ts +330 -0
- package/dist/src/plugins/js/lock-file/pruned-output.js +1441 -0
- package/dist/src/plugins/js/lock-file/utils/pnpm-normalizer.d.ts +1 -0
- package/dist/src/plugins/js/lock-file/utils/pnpm-normalizer.js +9 -5
- package/dist/src/plugins/js/project-graph/affected/npm-packages.js +51 -20
- package/dist/src/plugins/js/project-graph/build-dependencies/target-project-locator.js +14 -4
- package/dist/src/project-graph/affected/affected-project-graph-models.d.ts +1 -1
- package/dist/src/project-graph/affected/affected-project-graph.d.ts +1 -1
- package/dist/src/project-graph/affected/affected-project-graph.js +2 -2
- package/dist/src/project-graph/affected/locators/project-glob-changes.js +5 -2
- package/dist/src/project-graph/build-project-graph.js +7 -1
- package/dist/src/project-graph/error-types.d.ts +12 -1
- package/dist/src/project-graph/error-types.js +27 -2
- package/dist/src/project-graph/file-utils.js +6 -1
- package/dist/src/project-graph/plugins/isolation/isolated-plugin.d.ts +1 -0
- package/dist/src/project-graph/plugins/isolation/isolated-plugin.js +18 -1
- package/dist/src/project-graph/plugins/isolation/messaging.d.ts +16 -3
- package/dist/src/project-graph/plugins/isolation/messaging.js +3 -0
- package/dist/src/project-graph/plugins/isolation/plugin-worker.js +58 -8
- package/dist/src/project-graph/plugins/loaded-nx-plugin.js +1 -0
- package/dist/src/project-graph/project-graph.js +23 -0
- package/dist/src/project-graph/utils/project-configuration/name-substitution-manager.d.ts +1 -0
- package/dist/src/project-graph/utils/project-configuration/name-substitution-manager.js +16 -2
- package/dist/src/project-graph/utils/project-configuration/project-nodes-manager.d.ts +12 -8
- package/dist/src/project-graph/utils/project-configuration/project-nodes-manager.js +30 -21
- package/dist/src/project-graph/utils/project-configuration/source-maps.d.ts +12 -5
- package/dist/src/project-graph/utils/project-configuration/source-maps.js +21 -7
- package/dist/src/project-graph/utils/project-configuration/target-defaults.d.ts +1 -1
- package/dist/src/project-graph/utils/project-configuration/target-defaults.js +26 -27
- package/dist/src/project-graph/utils/project-configuration/target-merging.js +50 -8
- package/dist/src/project-graph/utils/project-configuration/target-normalization.js +149 -6
- package/dist/src/project-graph/utils/project-configuration/utils.d.ts +15 -0
- package/dist/src/project-graph/utils/project-configuration/utils.js +42 -6
- package/dist/src/project-graph/utils/project-configuration-utils.d.ts +15 -12
- package/dist/src/project-graph/utils/project-configuration-utils.js +79 -99
- package/dist/src/tasks-runner/is-tui-enabled.js +3 -1
- package/dist/src/tasks-runner/life-cycle.d.ts +2 -2
- package/dist/src/tasks-runner/life-cycle.js +2 -2
- package/dist/src/tasks-runner/life-cycles/performance-analysis.d.ts +9 -4
- package/dist/src/tasks-runner/life-cycles/performance-life-cycle.js +5 -4
- package/dist/src/tasks-runner/life-cycles/performance-report.d.ts +28 -8
- package/dist/src/tasks-runner/life-cycles/performance-report.js +117 -30
- package/dist/src/tasks-runner/life-cycles/static-run-many-terminal-output-life-cycle.d.ts +26 -1
- package/dist/src/tasks-runner/life-cycles/static-run-many-terminal-output-life-cycle.js +99 -5
- package/dist/src/tasks-runner/life-cycles/static-run-one-terminal-output-life-cycle.d.ts +26 -0
- package/dist/src/tasks-runner/life-cycles/static-run-one-terminal-output-life-cycle.js +113 -17
- package/dist/src/tasks-runner/pseudo-terminal.d.ts +17 -3
- package/dist/src/tasks-runner/pseudo-terminal.js +22 -10
- package/dist/src/tasks-runner/run-command.js +28 -35
- package/dist/src/tasks-runner/running-tasks/batch-process.d.ts +55 -0
- package/dist/src/tasks-runner/running-tasks/batch-process.js +161 -8
- package/dist/src/tasks-runner/task-env.d.ts +9 -0
- package/dist/src/tasks-runner/task-env.js +31 -4
- package/dist/src/tasks-runner/task-orchestrator.d.ts +72 -1
- package/dist/src/tasks-runner/task-orchestrator.js +182 -18
- package/dist/src/tasks-runner/utils.js +2 -6
- package/dist/src/utils/acknowledge-build-scripts.js +7 -5
- package/dist/src/utils/analytics-enabled.d.ts +7 -0
- package/dist/src/utils/analytics-enabled.js +11 -0
- package/dist/src/utils/analytics-prompt.d.ts +0 -6
- package/dist/src/utils/analytics-prompt.js +4 -58
- package/dist/src/utils/assert-workspace-validity.js +7 -2
- package/dist/src/utils/catalog/bun-manager-utils.d.ts +8 -0
- package/dist/src/utils/catalog/bun-manager-utils.js +174 -0
- package/dist/src/utils/catalog/bun-manager.d.ts +28 -0
- package/dist/src/utils/catalog/bun-manager.js +130 -0
- package/dist/src/utils/catalog/index.d.ts +1 -1
- package/dist/src/utils/catalog/index.js +1 -1
- package/dist/src/utils/catalog/manager-factory.js +3 -0
- package/dist/src/utils/catalog/manager-utils.d.ts +8 -1
- package/dist/src/utils/catalog/manager-utils.js +9 -4
- package/dist/src/utils/catalog/manager.d.ts +13 -1
- package/dist/src/utils/catalog/manager.js +30 -0
- package/dist/src/utils/catalog/pnpm-manager.d.ts +2 -1
- package/dist/src/utils/catalog/pnpm-manager.js +3 -0
- package/dist/src/utils/catalog/types.d.ts +4 -0
- package/dist/src/utils/catalog/yarn-manager.d.ts +6 -2
- package/dist/src/utils/catalog/yarn-manager.js +23 -32
- package/dist/src/utils/child-process.d.ts +31 -1
- package/dist/src/utils/child-process.js +103 -0
- package/dist/src/utils/chunkify.d.ts +7 -1
- package/dist/src/utils/chunkify.js +10 -3
- package/dist/src/utils/command-line-utils.js +30 -20
- package/dist/src/utils/exit-codes.d.ts +9 -0
- package/dist/src/utils/exit-codes.js +19 -0
- package/dist/src/utils/fileutils.d.ts +5 -0
- package/dist/src/utils/fileutils.js +7 -2
- package/dist/src/utils/formatters/index.d.ts +13 -0
- package/dist/src/utils/formatters/index.js +74 -0
- package/dist/src/utils/formatters/oxfmt.d.ts +32 -0
- package/dist/src/utils/formatters/oxfmt.js +764 -0
- package/dist/src/utils/formatters/prettier.d.ts +26 -0
- package/dist/src/utils/formatters/prettier.js +201 -0
- package/dist/src/utils/formatters/shared.d.ts +5 -0
- package/dist/src/utils/formatters/shared.js +8 -0
- package/dist/src/utils/git-revision.d.ts +12 -0
- package/dist/src/utils/git-revision.js +25 -0
- package/dist/src/utils/git-utils.d.ts +48 -2
- package/dist/src/utils/git-utils.js +220 -14
- package/dist/src/utils/git-worktrees.d.ts +30 -0
- package/dist/src/utils/git-worktrees.js +212 -0
- package/dist/src/utils/ignore.d.ts +170 -1
- package/dist/src/utils/ignore.js +263 -11
- package/dist/src/utils/long-running-target.d.ts +10 -0
- package/dist/src/utils/long-running-target.js +19 -0
- package/dist/src/utils/min-release-age/behavior/bun.js +7 -11
- package/dist/src/utils/min-release-age/behavior/npm.js +5 -2
- package/dist/src/utils/min-release-age/packument.js +1 -1
- package/dist/src/utils/nx-console-prompt.js +3 -6
- package/dist/src/utils/nx-tmp-dir.d.ts +18 -0
- package/dist/src/utils/nx-tmp-dir.js +40 -0
- package/dist/src/utils/output.d.ts +153 -0
- package/dist/src/utils/output.js +289 -5
- package/dist/src/utils/owned-private-dir.d.ts +132 -0
- package/dist/src/utils/owned-private-dir.js +323 -0
- package/dist/src/utils/package-json.d.ts +2 -0
- package/dist/src/utils/package-json.js +11 -7
- package/dist/src/utils/package-manager-config/bunfig.d.ts +14 -0
- package/dist/src/utils/package-manager-config/bunfig.js +49 -0
- package/dist/src/utils/package-manager-config/npmrc.d.ts +23 -0
- package/dist/src/utils/package-manager-config/npmrc.js +124 -0
- package/dist/src/utils/package-manager-config/pnpm-config.d.ts +17 -0
- package/dist/src/utils/package-manager-config/pnpm-config.js +60 -0
- package/dist/src/utils/package-manager.d.ts +23 -2
- package/dist/src/utils/package-manager.js +268 -44
- package/dist/src/utils/params.d.ts +7 -1
- package/dist/src/utils/params.js +64 -6
- package/dist/src/utils/plugins/core-plugins.js +4 -0
- package/dist/src/utils/prompt-helpers.d.ts +53 -0
- package/dist/src/utils/prompt-helpers.js +111 -0
- package/dist/src/utils/provenance.js +6 -14
- package/dist/src/utils/registry-config/bun.d.ts +2 -0
- package/dist/src/utils/registry-config/bun.js +257 -0
- package/dist/src/utils/registry-config/index.d.ts +13 -0
- package/dist/src/utils/registry-config/index.js +102 -0
- package/dist/src/utils/registry-config/pnpm.d.ts +2 -0
- package/dist/src/utils/registry-config/pnpm.js +1551 -0
- package/dist/src/utils/registry-config/utils.d.ts +195 -0
- package/dist/src/utils/registry-config/utils.js +496 -0
- package/dist/src/utils/registry-config/yarn-berry.d.ts +2 -0
- package/dist/src/utils/registry-config/yarn-berry.js +612 -0
- package/dist/src/utils/registry-config/yarn-classic.d.ts +2 -0
- package/dist/src/utils/registry-config/yarn-classic.js +1001 -0
- package/dist/src/utils/safe-spawn.d.ts +24 -0
- package/dist/src/utils/safe-spawn.js +104 -0
- package/dist/src/utils/shell-quoting.d.ts +15 -0
- package/dist/src/utils/shell-quoting.js +35 -0
- package/dist/src/utils/wait-for-socket-connection.d.ts +11 -0
- package/dist/src/utils/wait-for-socket-connection.js +14 -8
- package/dist/src/utils/workspace-id.d.ts +20 -0
- package/dist/src/utils/workspace-id.js +54 -0
- package/dist/src/utils/write-formatted-json-file.d.ts +3 -2
- package/dist/src/utils/write-formatted-json-file.js +5 -4
- package/migrations.json +6 -0
- package/package.json +29 -19
- package/dist/src/generators/internal-utils/format-changed-files-with-prettier-if-available.d.ts +0 -19
- package/dist/src/generators/internal-utils/format-changed-files-with-prettier-if-available.js +0 -81
- package/dist/src/utils/is-using-prettier.d.ts +0 -3
- package/dist/src/utils/is-using-prettier.js +0 -62
- package/dist/src/utils/min-release-age/npmrc.d.ts +0 -15
- package/dist/src/utils/min-release-age/npmrc.js +0 -45
|
@@ -1,46 +1,36 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.isHybridMigration = exports.isPromptOnlyMigration = exports.filterDowngradedUpdates = exports.Migrator = exports.normalizeVersion = void 0;
|
|
4
4
|
exports.formatCommandFailure = formatCommandFailure;
|
|
5
5
|
exports.resolveCanonicalNxPackage = resolveCanonicalNxPackage;
|
|
6
6
|
exports.resolveInclude = resolveInclude;
|
|
7
7
|
exports.parseMigrationsOptions = parseMigrationsOptions;
|
|
8
8
|
exports.createFetcher = createFetcher;
|
|
9
9
|
exports.generateMigrationsJsonAndUpdatePackageJson = generateMigrationsJsonAndUpdatePackageJson;
|
|
10
|
-
exports.isNpmPeerDepsError = isNpmPeerDepsError;
|
|
11
|
-
exports.resolveAgenticRunId = resolveAgenticRunId;
|
|
12
10
|
exports.formatSkippedPromptsNextStep = formatSkippedPromptsNextStep;
|
|
13
|
-
exports.resolveCreateCommits = resolveCreateCommits;
|
|
14
|
-
exports.confirmCommitsOnDefaultBranch = confirmCommitsOnDefaultBranch;
|
|
15
|
-
exports.resolveShouldRunValidation = resolveShouldRunValidation;
|
|
16
11
|
exports.executeMigrations = executeMigrations;
|
|
17
|
-
exports.
|
|
18
|
-
exports.parseMigrationReturn = parseMigrationReturn;
|
|
12
|
+
exports.isRunPhaseInvocation = isRunPhaseInvocation;
|
|
19
13
|
exports.migrate = migrate;
|
|
14
|
+
exports.readLocalNxVersion = readLocalNxVersion;
|
|
20
15
|
exports.runMigration = runMigration;
|
|
21
|
-
exports.readMigrationCollection = readMigrationCollection;
|
|
22
|
-
exports.getImplementationPath = getImplementationPath;
|
|
23
16
|
exports.resolveMigrationForRun = resolveMigrationForRun;
|
|
24
|
-
exports.resolveDocumentationFileToWorkspacePath = resolveDocumentationFileToWorkspacePath;
|
|
25
17
|
exports.nxCliPath = nxCliPath;
|
|
26
18
|
const tslib_1 = require("tslib");
|
|
27
19
|
const pc = tslib_1.__importStar(require("picocolors"));
|
|
28
20
|
const child_process_1 = require("child_process");
|
|
29
21
|
const safe_prompt_1 = require("./safe-prompt");
|
|
30
|
-
const handle_import_1 = require("../../utils/handle-import");
|
|
31
22
|
const path_1 = require("path");
|
|
32
23
|
const module_1 = require("module");
|
|
33
24
|
const path_2 = require("../../utils/path");
|
|
34
25
|
const semver_1 = require("semver");
|
|
35
26
|
const node_url_1 = require("node:url");
|
|
36
27
|
const util_1 = require("util");
|
|
37
|
-
const tree_1 = require("../../generators/tree");
|
|
38
28
|
const fileutils_1 = require("../../utils/fileutils");
|
|
39
29
|
const tar_1 = require("../../utils/tar");
|
|
40
30
|
const write_formatted_json_file_1 = require("../../utils/write-formatted-json-file");
|
|
31
|
+
const shell_quoting_1 = require("../../utils/shell-quoting");
|
|
41
32
|
const logger_1 = require("../../utils/logger");
|
|
42
33
|
const git_utils_1 = require("../../utils/git-utils");
|
|
43
|
-
const command_line_utils_1 = require("../../utils/command-line-utils");
|
|
44
34
|
const package_json_1 = require("../../utils/package-json");
|
|
45
35
|
const package_manager_1 = require("../../utils/package-manager");
|
|
46
36
|
const errors_1 = require("../../utils/min-release-age/errors");
|
|
@@ -57,8 +47,7 @@ const configuration_1 = require("../../config/configuration");
|
|
|
57
47
|
const child_process_2 = require("../../utils/child-process");
|
|
58
48
|
const client_1 = require("../../daemon/client/client");
|
|
59
49
|
const nx_cloud_utils_1 = require("../../utils/nx-cloud-utils");
|
|
60
|
-
const
|
|
61
|
-
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");
|
|
62
51
|
const provenance_1 = require("../../utils/provenance");
|
|
63
52
|
const catalog_1 = require("../../utils/catalog");
|
|
64
53
|
const migrate_analytics_1 = require("./migrate-analytics");
|
|
@@ -66,7 +55,6 @@ const multi_major_1 = require("./multi-major");
|
|
|
66
55
|
const prompt_files_1 = require("./prompt-files");
|
|
67
56
|
const command_object_1 = require("./command-object");
|
|
68
57
|
const migrate_config_1 = require("./migrate-config");
|
|
69
|
-
const handoff_gitignore_1 = require("./agentic/handoff-gitignore");
|
|
70
58
|
const migrate_commits_1 = require("./migrate-commits");
|
|
71
59
|
const migrate_output_1 = require("./migrate-output");
|
|
72
60
|
const migration_shape_1 = require("./migration-shape");
|
|
@@ -76,6 +64,13 @@ const update_filters_1 = require("./update-filters");
|
|
|
76
64
|
Object.defineProperty(exports, "filterDowngradedUpdates", { enumerable: true, get: function () { return update_filters_1.filterDowngradedUpdates; } });
|
|
77
65
|
const version_utils_1 = require("./version-utils");
|
|
78
66
|
Object.defineProperty(exports, "normalizeVersion", { enumerable: true, get: function () { return version_utils_1.normalizeVersion; } });
|
|
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");
|
|
73
|
+
tslib_1.__exportStar(require("./execute-migration"), exports);
|
|
79
74
|
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
80
75
|
function formatCommandFailure(command, error) {
|
|
81
76
|
const normalizeCommandOutput = (output) => {
|
|
@@ -118,6 +113,8 @@ class Migrator {
|
|
|
118
113
|
this.packageUpdates = {};
|
|
119
114
|
this.collectedVersions = {};
|
|
120
115
|
this.promptAnswers = {};
|
|
116
|
+
this.pendingPackageJsonUpdates = new Map();
|
|
117
|
+
this.appliedPackageJsonUpdates = new Set();
|
|
121
118
|
if ((opts.include === 'required' || opts.include === 'optional') &&
|
|
122
119
|
!opts.requiredPackages) {
|
|
123
120
|
throw new Error(`Error: 'requiredPackages' is required when 'include' is '${opts.include}'.`);
|
|
@@ -145,6 +142,7 @@ class Migrator {
|
|
|
145
142
|
version: targetVersion,
|
|
146
143
|
addToPackageJson: false,
|
|
147
144
|
});
|
|
145
|
+
await this.applyPendingPackageJsonUpdates();
|
|
148
146
|
this.applyIncludeFilter();
|
|
149
147
|
const { migrations, promptContents } = await this.createMigrateJson();
|
|
150
148
|
return {
|
|
@@ -190,29 +188,66 @@ class Migrator {
|
|
|
190
188
|
for (const packageToCheck of packagesToCheck) {
|
|
191
189
|
const filteredUpdates = {};
|
|
192
190
|
for (const [packageUpdateKey, packageUpdate] of Object.entries(packageToCheck.updates)) {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
191
|
+
Object.assign(filteredUpdates, await this.applyPackageJsonUpdate(packageToCheck.package, packageUpdateKey, packageUpdate));
|
|
192
|
+
}
|
|
193
|
+
await Promise.all(Object.entries(filteredUpdates).map(([name, update]) => this.buildPackageJsonUpdates(name, update)));
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
async applyPackageJsonUpdate(sourcePackage, packageUpdateKey, packageUpdate) {
|
|
197
|
+
const appliedKey = JSON.stringify([sourcePackage, packageUpdateKey]);
|
|
198
|
+
if (this.appliedPackageJsonUpdates.has(appliedKey)) {
|
|
199
|
+
this.pendingPackageJsonUpdates.delete(appliedKey);
|
|
200
|
+
return {};
|
|
201
|
+
}
|
|
202
|
+
if (!this.areRequirementsMet(packageUpdate.requires) ||
|
|
203
|
+
this.areIncompatiblePackagesPresent(packageUpdate.incompatibleWith)) {
|
|
204
|
+
this.pendingPackageJsonUpdates.set(appliedKey, {
|
|
205
|
+
package: sourcePackage,
|
|
206
|
+
key: packageUpdateKey,
|
|
207
|
+
update: packageUpdate,
|
|
208
|
+
});
|
|
209
|
+
return {};
|
|
210
|
+
}
|
|
211
|
+
this.pendingPackageJsonUpdates.delete(appliedKey);
|
|
212
|
+
if (this.interactive &&
|
|
213
|
+
!(await this.runPackageJsonUpdatesConfirmationPrompt(packageUpdate, packageUpdateKey, sourcePackage))) {
|
|
214
|
+
return {};
|
|
215
|
+
}
|
|
216
|
+
this.appliedPackageJsonUpdates.add(appliedKey);
|
|
217
|
+
const updateEntries = Object.entries(packageUpdate.packages);
|
|
218
|
+
// Validate all up front so invalid metadata fails fast, before any
|
|
219
|
+
// resolution does I/O.
|
|
220
|
+
for (const [name, update] of updateEntries) {
|
|
221
|
+
this.validatePackageUpdateVersion(sourcePackage, name, update);
|
|
222
|
+
}
|
|
223
|
+
const filteredUpdates = {};
|
|
224
|
+
// Resolve serially: resolution can prompt (pnpm strict cooldown) and append
|
|
225
|
+
// to minimumReleaseAgeExclude, so a serial loop avoids overlapping prompts
|
|
226
|
+
// and keeps packageUpdates ordering stable.
|
|
227
|
+
for (const [name, update] of updateEntries) {
|
|
228
|
+
const resolvedUpdate = {
|
|
229
|
+
...update,
|
|
230
|
+
version: await this.resolveVersionForCascade(name, update.version),
|
|
231
|
+
};
|
|
232
|
+
this.addPackageUpdate(name, resolvedUpdate);
|
|
233
|
+
filteredUpdates[name] = this.packageUpdates[name];
|
|
234
|
+
}
|
|
235
|
+
return filteredUpdates;
|
|
236
|
+
}
|
|
237
|
+
async applyPendingPackageJsonUpdates() {
|
|
238
|
+
while (this.pendingPackageJsonUpdates.size) {
|
|
239
|
+
let applied = false;
|
|
240
|
+
const filteredUpdates = {};
|
|
241
|
+
for (const pending of [...this.pendingPackageJsonUpdates.values()]) {
|
|
242
|
+
const updates = await this.applyPackageJsonUpdate(pending.package, pending.key, pending.update);
|
|
243
|
+
if (Object.keys(updates).length) {
|
|
244
|
+
applied = true;
|
|
245
|
+
Object.assign(filteredUpdates, updates);
|
|
214
246
|
}
|
|
215
247
|
}
|
|
248
|
+
if (!applied) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
216
251
|
await Promise.all(Object.entries(filteredUpdates).map(([name, update]) => this.buildPackageJsonUpdates(name, update)));
|
|
217
252
|
}
|
|
218
253
|
}
|
|
@@ -416,7 +451,7 @@ class Migrator {
|
|
|
416
451
|
}
|
|
417
452
|
addPackageUpdate(name, packageUpdate) {
|
|
418
453
|
if (!this.packageUpdates[name] ||
|
|
419
|
-
this.
|
|
454
|
+
!this.lt(packageUpdate.version, this.packageUpdates[name].version)) {
|
|
420
455
|
this.packageUpdates[name] = packageUpdate;
|
|
421
456
|
}
|
|
422
457
|
}
|
|
@@ -482,17 +517,14 @@ class Migrator {
|
|
|
482
517
|
// a same prompt was already answered, skip
|
|
483
518
|
return Promise.resolve(false);
|
|
484
519
|
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
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}`,
|
|
489
526
|
initial: true,
|
|
490
|
-
}
|
|
491
|
-
if (packageName.startsWith('@nx/')) {
|
|
492
|
-
// @ts-expect-error -- enquirer types aren't correct, footer does exist
|
|
493
|
-
promptConfig.footer = () => pc.dim(` View migration details at https://nx.dev/nx-api/${packageName.replace('@nx/', '')}#${packageUpdateKey.replace(/[-\.]/g, '')}packageupdates`);
|
|
494
|
-
}
|
|
495
|
-
return await (0, safe_prompt_1.migratePrompt)([promptConfig]).then(({ shouldApply }) => {
|
|
527
|
+
}).then((shouldApply) => {
|
|
496
528
|
this.promptAnswers[promptKey] = shouldApply;
|
|
497
529
|
if (!shouldApply &&
|
|
498
530
|
(!this.minVersionWithSkippedUpdates ||
|
|
@@ -593,8 +625,8 @@ async function resolveInclude(include, context, configuredInclude) {
|
|
|
593
625
|
}
|
|
594
626
|
const choices = [
|
|
595
627
|
{
|
|
596
|
-
|
|
597
|
-
|
|
628
|
+
value: 'required',
|
|
629
|
+
label: 'Required only (the target package and the packages it ships with)',
|
|
598
630
|
},
|
|
599
631
|
];
|
|
600
632
|
// `--interactive` keeps the legacy x-prompt flow, which the `optional` value
|
|
@@ -603,8 +635,8 @@ async function resolveInclude(include, context, configuredInclude) {
|
|
|
603
635
|
!context.hasExcludeAppliedMigrations &&
|
|
604
636
|
context.interactive !== true) {
|
|
605
637
|
choices.push({
|
|
606
|
-
|
|
607
|
-
|
|
638
|
+
value: 'optional',
|
|
639
|
+
label: 'Optional only (the dependency updates those packages recommend)',
|
|
608
640
|
});
|
|
609
641
|
}
|
|
610
642
|
if (!(0, safe_prompt_1.canPrompt)(context.interactive)) {
|
|
@@ -612,12 +644,10 @@ async function resolveInclude(include, context, configuredInclude) {
|
|
|
612
644
|
return 'all';
|
|
613
645
|
}
|
|
614
646
|
choices.push({
|
|
615
|
-
|
|
616
|
-
|
|
647
|
+
value: 'all',
|
|
648
|
+
label: 'All (required and optional)',
|
|
617
649
|
});
|
|
618
|
-
const
|
|
619
|
-
type: 'select',
|
|
620
|
-
name: 'include',
|
|
650
|
+
const selected = await (0, safe_prompt_1.migrateChoice)({
|
|
621
651
|
message: 'Which packages would you like to migrate?',
|
|
622
652
|
choices,
|
|
623
653
|
});
|
|
@@ -677,6 +707,75 @@ async function parseTargetPackageAndVersion(args) {
|
|
|
677
707
|
return { targetPackage: args, targetVersion: 'latest' };
|
|
678
708
|
}
|
|
679
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
|
+
}
|
|
680
779
|
if (options.runMigrations === '') {
|
|
681
780
|
options.runMigrations = 'migrations.json';
|
|
682
781
|
}
|
|
@@ -1053,6 +1152,15 @@ function createFetcher(pmc) {
|
|
|
1053
1152
|
migrationsCache[packageName + '-' + packageVersion] = migrations;
|
|
1054
1153
|
}
|
|
1055
1154
|
migrations = fetchMigrations(packageName, packageVersion, setCache).then((result) => {
|
|
1155
|
+
// An exact requested version must come back verbatim; a mismatch means
|
|
1156
|
+
// a config surface (registry proxy, override, cooldown gate) silently
|
|
1157
|
+
// substituted another version, which would corrupt the whole plan.
|
|
1158
|
+
if ((0, semver_1.valid)(packageVersion) &&
|
|
1159
|
+
result.version &&
|
|
1160
|
+
result.version !== packageVersion) {
|
|
1161
|
+
throw new Error(`Fetching ${packageName}@${packageVersion} resolved to version ${result.version}. ` +
|
|
1162
|
+
`Check for registry, override, or minimum-release-age configuration that hides the requested version.`);
|
|
1163
|
+
}
|
|
1056
1164
|
if (result.schematics) {
|
|
1057
1165
|
result.generators = { ...result.schematics, ...result.generators };
|
|
1058
1166
|
delete result.schematics;
|
|
@@ -1092,8 +1200,30 @@ async function getPackageMigrationsUsingRegistry(packageName, packageVersion) {
|
|
|
1092
1200
|
// try to obtain the migrations from the registry directly
|
|
1093
1201
|
return await downloadPackageMigrationsFromRegistry(packageName, packageVersion, migrationsConfig);
|
|
1094
1202
|
}
|
|
1203
|
+
// Matched exactly: a hostname that merely contains one of these is a different
|
|
1204
|
+
// registry. registry.yarnpkg.com is npmjs' CNAME, so it serves the same
|
|
1205
|
+
// metadata; the two loopback literals are the spellings of a local registry
|
|
1206
|
+
// that the substring below cannot reach, since neither contains "localhost".
|
|
1207
|
+
const FULL_METADATA_REGISTRIES = [
|
|
1208
|
+
'registry.npmjs.org',
|
|
1209
|
+
'registry.yarnpkg.com',
|
|
1210
|
+
'127.0.0.1',
|
|
1211
|
+
'[::1]',
|
|
1212
|
+
];
|
|
1213
|
+
// Matched as substrings, since neither names a single host: a local registry
|
|
1214
|
+
// can sit on a subdomain of localhost, and an Artifactory instance is
|
|
1215
|
+
// identified only by that word appearing somewhere in its hostname.
|
|
1216
|
+
const FULL_METADATA_REGISTRY_MARKERS = [
|
|
1217
|
+
'localhost',
|
|
1218
|
+
'artifactory',
|
|
1219
|
+
];
|
|
1095
1220
|
async function getPackageMigrationsConfigFromRegistry(packageName, packageVersion) {
|
|
1096
|
-
const result = await (0, package_manager_1.packageRegistryView)(packageName, packageVersion,
|
|
1221
|
+
const result = await (0, package_manager_1.packageRegistryView)(packageName, packageVersion, [
|
|
1222
|
+
'nx-migrations',
|
|
1223
|
+
'ng-update',
|
|
1224
|
+
'dist',
|
|
1225
|
+
'--json',
|
|
1226
|
+
]);
|
|
1097
1227
|
if (!result) {
|
|
1098
1228
|
return null;
|
|
1099
1229
|
}
|
|
@@ -1101,9 +1231,10 @@ async function getPackageMigrationsConfigFromRegistry(packageName, packageVersio
|
|
|
1101
1231
|
if (!json['nx-migrations'] && !json['ng-update']) {
|
|
1102
1232
|
const registry = new node_url_1.URL('dist' in json ? json.dist.tarball : json.tarball)
|
|
1103
1233
|
.hostname;
|
|
1104
|
-
//
|
|
1105
|
-
//
|
|
1106
|
-
if (!
|
|
1234
|
+
// Other registries may not support full metadata via npm view; throw to
|
|
1235
|
+
// trigger the install fallback.
|
|
1236
|
+
if (!FULL_METADATA_REGISTRIES.includes(registry) &&
|
|
1237
|
+
!FULL_METADATA_REGISTRY_MARKERS.some((v) => registry.includes(v))) {
|
|
1107
1238
|
throw new Error(`Getting migration config from registry is not supported from ${registry}`);
|
|
1108
1239
|
}
|
|
1109
1240
|
}
|
|
@@ -1113,7 +1244,13 @@ async function downloadPackageMigrationsFromRegistry(packageName, packageVersion
|
|
|
1113
1244
|
const { dir, cleanup } = (0, package_manager_1.createTempNpmDirectory)();
|
|
1114
1245
|
let result;
|
|
1115
1246
|
try {
|
|
1116
|
-
const { tarballPath } = await (0, package_manager_1.packageRegistryPack)(dir, packageName, packageVersion
|
|
1247
|
+
const { tarballPath } = await (0, package_manager_1.packageRegistryPack)(dir, packageName, packageVersion,
|
|
1248
|
+
// packageVersion is exact and already resolved through the workspace
|
|
1249
|
+
// package manager's min-release-age policy by the fetcher. In an npm
|
|
1250
|
+
// workspace the pack gate IS that policy, so leave it enforcing; for
|
|
1251
|
+
// other package managers npm's gate is foreign config with no
|
|
1252
|
+
// exclusions and would wrongly re-judge the vetted version.
|
|
1253
|
+
{ bypassMinReleaseAge: (0, package_manager_1.detectPackageManager)() !== 'npm' });
|
|
1117
1254
|
const fullTarballPath = (0, path_1.join)(dir, tarballPath);
|
|
1118
1255
|
let migrations;
|
|
1119
1256
|
try {
|
|
@@ -1191,7 +1328,7 @@ async function getPackageMigrationsUsingInstallImpl(packageName, packageVersion,
|
|
|
1191
1328
|
// as-is by the outer catch instead of being mislabeled as install failures.
|
|
1192
1329
|
throw new Error(formatCommandFailure(addCommand, e));
|
|
1193
1330
|
}
|
|
1194
|
-
const { migrations: migrationsFilePath, packageGroup, supportsOptionalMigrations, packageJson, } = readPackageMigrationConfig(packageName, dir);
|
|
1331
|
+
const { migrations: migrationsFilePath, packageGroup, supportsOptionalMigrations, packageJson, } = (0, execute_migration_1.readPackageMigrationConfig)(packageName, dir);
|
|
1195
1332
|
let migrations = undefined;
|
|
1196
1333
|
let resolvedPromptFiles;
|
|
1197
1334
|
if (migrationsFilePath) {
|
|
@@ -1218,32 +1355,6 @@ async function getPackageMigrationsUsingInstallImpl(packageName, packageVersion,
|
|
|
1218
1355
|
}
|
|
1219
1356
|
return result;
|
|
1220
1357
|
}
|
|
1221
|
-
function readPackageMigrationConfig(packageName, dir) {
|
|
1222
|
-
const { path: packageJsonPath, packageJson: json } = (0, package_json_1.readModulePackageJson)(packageName, (0, installation_directory_1.getNxRequirePaths)(dir));
|
|
1223
|
-
const config = (0, package_json_1.readNxMigrateConfig)(json);
|
|
1224
|
-
if (!config) {
|
|
1225
|
-
return { packageJson: json, migrations: null, packageGroup: [] };
|
|
1226
|
-
}
|
|
1227
|
-
try {
|
|
1228
|
-
const migrationFile = require.resolve(config.migrations, {
|
|
1229
|
-
paths: [(0, path_1.dirname)(packageJsonPath)],
|
|
1230
|
-
});
|
|
1231
|
-
return {
|
|
1232
|
-
packageJson: json,
|
|
1233
|
-
migrations: migrationFile,
|
|
1234
|
-
packageGroup: config.packageGroup,
|
|
1235
|
-
supportsOptionalMigrations: config.supportsOptionalMigrations,
|
|
1236
|
-
};
|
|
1237
|
-
}
|
|
1238
|
-
catch {
|
|
1239
|
-
return {
|
|
1240
|
-
packageJson: json,
|
|
1241
|
-
migrations: null,
|
|
1242
|
-
packageGroup: config.packageGroup,
|
|
1243
|
-
supportsOptionalMigrations: config.supportsOptionalMigrations,
|
|
1244
|
-
};
|
|
1245
|
-
}
|
|
1246
|
-
}
|
|
1247
1358
|
async function createMigrationsFile(root, migrations) {
|
|
1248
1359
|
await (0, write_formatted_json_file_1.writeFormattedJsonFile)((0, path_1.join)(root, 'migrations.json'), { migrations });
|
|
1249
1360
|
}
|
|
@@ -1316,7 +1427,7 @@ async function formatCatalogDefinitionFiles(manager, root) {
|
|
|
1316
1427
|
content: (0, fs_1.readFileSync)(absolutePath, 'utf-8'),
|
|
1317
1428
|
};
|
|
1318
1429
|
});
|
|
1319
|
-
const results = await (0,
|
|
1430
|
+
const results = await (0, format_changed_files_1.formatFileContents)(catalogDefinitionFiles.map(({ path, content }) => ({ path, content })), root, { silent: true });
|
|
1320
1431
|
for (const { path, absolutePath, content } of catalogDefinitionFiles) {
|
|
1321
1432
|
(0, fs_1.writeFileSync)(absolutePath, results.has(path) ? results.get(path) : content, { encoding: 'utf-8' });
|
|
1322
1433
|
}
|
|
@@ -1610,248 +1721,22 @@ function showConnectToCloudMessage() {
|
|
|
1610
1721
|
return false;
|
|
1611
1722
|
}
|
|
1612
1723
|
}
|
|
1613
|
-
function runInstall(nxWorkspaceRoot, phase = 'pre-migration') {
|
|
1614
|
-
const cwd = nxWorkspaceRoot ?? process.cwd();
|
|
1615
|
-
const packageManager = (0, package_manager_1.detectPackageManager)(cwd);
|
|
1616
|
-
const pmCommands = (0, package_manager_1.getPackageManagerCommand)(packageManager, cwd);
|
|
1617
|
-
const installCommand = `${pmCommands.install} ${pmCommands.ignoreScriptsFlag ?? ''}`;
|
|
1618
|
-
output_1.output.log({
|
|
1619
|
-
title: `Running '${installCommand}' to make sure necessary packages are installed`,
|
|
1620
|
-
});
|
|
1621
|
-
return new Promise((resolve, reject) => {
|
|
1622
|
-
// For npm, pipe stderr so we can detect peer dependency errors while still
|
|
1623
|
-
// mirroring it live to the user's terminal. Other package managers inherit
|
|
1624
|
-
// stderr directly since we don't need to inspect their output.
|
|
1625
|
-
const shouldCaptureStderr = packageManager === 'npm';
|
|
1626
|
-
const child = (0, child_process_1.spawn)(installCommand, {
|
|
1627
|
-
shell: true,
|
|
1628
|
-
stdio: ['inherit', 'inherit', shouldCaptureStderr ? 'pipe' : 'inherit'],
|
|
1629
|
-
windowsHide: true,
|
|
1630
|
-
cwd,
|
|
1631
|
-
});
|
|
1632
|
-
const stderrChunks = [];
|
|
1633
|
-
child.stderr?.on('data', (chunk) => {
|
|
1634
|
-
process.stderr.write(chunk);
|
|
1635
|
-
stderrChunks.push(chunk);
|
|
1636
|
-
});
|
|
1637
|
-
child.on('error', reject);
|
|
1638
|
-
child.on('close', (code) => {
|
|
1639
|
-
if (code === 0) {
|
|
1640
|
-
resolve();
|
|
1641
|
-
return;
|
|
1642
|
-
}
|
|
1643
|
-
if (shouldCaptureStderr) {
|
|
1644
|
-
const stderr = Buffer.concat(stderrChunks).toString().trim();
|
|
1645
|
-
if (isNpmPeerDepsError(stderr)) {
|
|
1646
|
-
// Log the remediation guidance here so every caller of `runInstall`
|
|
1647
|
-
// (CLI migrate, `nx repair`, single-migration runner, etc.) surfaces
|
|
1648
|
-
// it consistently. Top-level callers catch `NpmPeerDepsInstallError`
|
|
1649
|
-
// and return a non-zero exit code without re-logging.
|
|
1650
|
-
logNpmPeerDepsError(phase);
|
|
1651
|
-
reject(new NpmPeerDepsInstallError());
|
|
1652
|
-
return;
|
|
1653
|
-
}
|
|
1654
|
-
}
|
|
1655
|
-
reject(new Error(`Command failed: ${installCommand}`));
|
|
1656
|
-
});
|
|
1657
|
-
});
|
|
1658
|
-
}
|
|
1659
|
-
class NpmPeerDepsInstallError extends Error {
|
|
1660
|
-
constructor() {
|
|
1661
|
-
super('npm install failed due to peer dependency conflicts.');
|
|
1662
|
-
this.name = 'NpmPeerDepsInstallError';
|
|
1663
|
-
}
|
|
1664
|
-
}
|
|
1665
|
-
/**
|
|
1666
|
-
* Detects npm peer-dependency resolution failures. Keyed on the `ERESOLVE`
|
|
1667
|
-
* error code, which npm consistently emits for this class of failure across
|
|
1668
|
-
* v7+ (`npm ERR! code ERESOLVE` / `npm error code ERESOLVE`). Falls back to a
|
|
1669
|
-
* small set of stable phrases in case the code line is missing from the
|
|
1670
|
-
* captured output.
|
|
1671
|
-
*/
|
|
1672
|
-
function isNpmPeerDepsError(stderr) {
|
|
1673
|
-
if (/\bERESOLVE\b/.test(stderr)) {
|
|
1674
|
-
return true;
|
|
1675
|
-
}
|
|
1676
|
-
const lowerStderr = stderr.toLowerCase();
|
|
1677
|
-
return (lowerStderr.includes('unable to resolve dependency tree') ||
|
|
1678
|
-
lowerStderr.includes('could not resolve dependency') ||
|
|
1679
|
-
lowerStderr.includes('conflicting peer dependency'));
|
|
1680
|
-
}
|
|
1681
|
-
function logNpmPeerDepsError(phase) {
|
|
1682
|
-
const peerDepsResolutionSteps = [
|
|
1683
|
-
'Recommended approaches (in order of preference):',
|
|
1684
|
-
'',
|
|
1685
|
-
'1. Use "overrides" in package.json to force compatible versions across the dependency tree.',
|
|
1686
|
-
' See https://docs.npmjs.com/cli/configuring-npm/package-json#overrides',
|
|
1687
|
-
'2. Persist legacy peer deps resolution in the project ".npmrc":',
|
|
1688
|
-
' npm config set legacy-peer-deps=true --location=project',
|
|
1689
|
-
' (bypasses peer dependency resolution; use with caution)',
|
|
1690
|
-
'3. As a last resort, force the installation by running "npm install --force".',
|
|
1691
|
-
' (does not persist and may produce broken installs)',
|
|
1692
|
-
];
|
|
1693
|
-
const manualInstallHint = [
|
|
1694
|
-
'If you installed the dependencies manually, pass "--skip-install" to avoid re-installing them:',
|
|
1695
|
-
' nx migrate --run-migrations --skip-install',
|
|
1696
|
-
];
|
|
1697
|
-
if (phase === 'pre-migration') {
|
|
1698
|
-
output_1.output.error({
|
|
1699
|
-
title: 'You need to resolve the peer dependency conflicts before the migration can continue',
|
|
1700
|
-
bodyLines: [
|
|
1701
|
-
...peerDepsResolutionSteps,
|
|
1702
|
-
'',
|
|
1703
|
-
'Once the conflicts are resolved, re-run the migrations:',
|
|
1704
|
-
' nx migrate --run-migrations',
|
|
1705
|
-
'',
|
|
1706
|
-
...manualInstallHint,
|
|
1707
|
-
],
|
|
1708
|
-
});
|
|
1709
|
-
}
|
|
1710
|
-
else {
|
|
1711
|
-
output_1.output.error({
|
|
1712
|
-
title: 'Some migrations have been applied, but installing the updated dependencies failed',
|
|
1713
|
-
bodyLines: [
|
|
1714
|
-
...peerDepsResolutionSteps,
|
|
1715
|
-
'',
|
|
1716
|
-
'Once the conflicts are resolved, run "npm install" to install the updated dependencies.',
|
|
1717
|
-
'If the migration was interrupted before completing, re-run the remaining migrations:',
|
|
1718
|
-
' nx migrate --run-migrations',
|
|
1719
|
-
'',
|
|
1720
|
-
...manualInstallHint,
|
|
1721
|
-
],
|
|
1722
|
-
});
|
|
1723
|
-
}
|
|
1724
|
-
}
|
|
1725
|
-
function resolveAgenticRunId(migrations) {
|
|
1726
|
-
return (0, semver_1.rsort)(migrations.map((m) => (0, version_utils_1.normalizeVersion)(m.version)))[0];
|
|
1727
|
-
}
|
|
1728
1724
|
function formatSkippedPromptsNextStep(skipped) {
|
|
1729
1725
|
return [
|
|
1730
1726
|
'Some prompt migrations were skipped. Review and apply each of the following prompt files to the workspace, in the listed order:',
|
|
1731
1727
|
...skipped.map((m) => ` - ${m.prompt}`),
|
|
1732
1728
|
].join('\n');
|
|
1733
1729
|
}
|
|
1734
|
-
/**
|
|
1735
|
-
* Resolves the effective `--create-commits` state once the agentic flow has
|
|
1736
|
-
* been resolved. The agent's outer prompt only embeds the impl-phase file list
|
|
1737
|
-
* when per-migration commits isolate each migration's diff, so the diff-context
|
|
1738
|
-
* flag returned here gates that section.
|
|
1739
|
-
*/
|
|
1740
|
-
function resolveCreateCommits(args) {
|
|
1741
|
-
const { createCommits, agenticKind, isGitRepo, commitPrefixIsCustom } = args;
|
|
1742
|
-
// Explicit `--create-commits` without git is a hard error — the user asked
|
|
1743
|
-
// for something we cannot deliver.
|
|
1744
|
-
if (createCommits === true && !isGitRepo) {
|
|
1745
|
-
return {
|
|
1746
|
-
effective: false,
|
|
1747
|
-
agenticHasDiffContext: false,
|
|
1748
|
-
error: '`--create-commits` requires a git repository. Run `git init` first, or omit the flag.',
|
|
1749
|
-
};
|
|
1750
|
-
}
|
|
1751
|
-
if (agenticKind === 'enabled') {
|
|
1752
|
-
if (createCommits === false) {
|
|
1753
|
-
return {
|
|
1754
|
-
effective: false,
|
|
1755
|
-
agenticHasDiffContext: false,
|
|
1756
|
-
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." +
|
|
1757
|
-
(commitPrefixIsCustom
|
|
1758
|
-
? ' Note: the custom --commit-prefix value will have no effect because commits are disabled.'
|
|
1759
|
-
: ''),
|
|
1760
|
-
};
|
|
1761
|
-
}
|
|
1762
|
-
// Without git we cannot soft-force commits the user didn't explicitly
|
|
1763
|
-
// opt into. Degrade rather than error: continue the agentic run, but
|
|
1764
|
-
// without per-file diff context (which depends on per-migration commits).
|
|
1765
|
-
if (!isGitRepo) {
|
|
1766
|
-
return {
|
|
1767
|
-
effective: false,
|
|
1768
|
-
agenticHasDiffContext: false,
|
|
1769
|
-
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.' +
|
|
1770
|
-
(commitPrefixIsCustom
|
|
1771
|
-
? ' The custom --commit-prefix value will have no effect.'
|
|
1772
|
-
: ''),
|
|
1773
|
-
};
|
|
1774
|
-
}
|
|
1775
|
-
return { effective: true, agenticHasDiffContext: true };
|
|
1776
|
-
}
|
|
1777
|
-
// Commits aren't enabled here. A custom prefix only reaches this path via
|
|
1778
|
-
// nx.json (e.g. `migrate.commitPrefix` + `migrate.agentic` when the agentic
|
|
1779
|
-
// flow resolves to disabled); surface that it has no effect rather than
|
|
1780
|
-
// dropping it silently.
|
|
1781
|
-
return {
|
|
1782
|
-
effective: createCommits === true,
|
|
1783
|
-
agenticHasDiffContext: false,
|
|
1784
|
-
warning: commitPrefixIsCustom && createCommits !== true
|
|
1785
|
-
? '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.'
|
|
1786
|
-
: undefined,
|
|
1787
|
-
};
|
|
1788
|
-
}
|
|
1789
|
-
/**
|
|
1790
|
-
* Confirms before creating per-migration commits while the user sits on the
|
|
1791
|
-
* repository's default branch, so migrations don't silently commit there (most
|
|
1792
|
-
* relevant since `--agentic` enables commits by default). Only the default
|
|
1793
|
-
* branch triggers a prompt; a detached HEAD, a different branch, or an
|
|
1794
|
-
* unresolved default branch all proceed untouched. Callers gate this on
|
|
1795
|
-
* commits being effective and prompting being possible, so non-interactive
|
|
1796
|
-
* runs (CI, `--no-interactive`) never reach here.
|
|
1797
|
-
*/
|
|
1798
|
-
async function confirmCommitsOnDefaultBranch(args) {
|
|
1799
|
-
const { currentBranch, defaultBranch } = args;
|
|
1800
|
-
if (!currentBranch || !defaultBranch || currentBranch !== defaultBranch) {
|
|
1801
|
-
return true;
|
|
1802
|
-
}
|
|
1803
|
-
const { proceed } = await (0, safe_prompt_1.migratePrompt)([
|
|
1804
|
-
{
|
|
1805
|
-
name: 'proceed',
|
|
1806
|
-
type: 'confirm',
|
|
1807
|
-
message: `You're on the default branch '${currentBranch}'. nx migrate will create a commit for each migration on this branch. Continue?`,
|
|
1808
|
-
initial: false,
|
|
1809
|
-
},
|
|
1810
|
-
]);
|
|
1811
|
-
return proceed;
|
|
1812
|
-
}
|
|
1813
|
-
/**
|
|
1814
|
-
* Resolves whether the framework-owned generic-validation agent step should run
|
|
1815
|
-
* after generator-only migrations.
|
|
1816
|
-
*
|
|
1817
|
-
* Default-on when the agentic flow resolved to `enabled`; silently ignored
|
|
1818
|
-
* otherwise (no warning emitted) — `--validate` requires an active agent
|
|
1819
|
-
* session by definition. An explicit `--no-validate` (`validate === false`)
|
|
1820
|
-
* opts out even when agentic is enabled.
|
|
1821
|
-
*/
|
|
1822
|
-
function resolveShouldRunValidation(args) {
|
|
1823
|
-
return args.validate !== false && args.agenticKind === 'enabled';
|
|
1824
|
-
}
|
|
1825
1730
|
async function executeMigrations(root, migrations, isVerbose, shouldCreateCommits, commitPrefix, shouldSkipInstall = false, agentic, agenticHasDiffContext = false, shouldRunValidation = false) {
|
|
1826
|
-
const changedDepInstaller = new ChangedDepInstaller(root, shouldSkipInstall);
|
|
1731
|
+
const changedDepInstaller = new execute_migration_1.ChangedDepInstaller(root, shouldSkipInstall);
|
|
1827
1732
|
const migrationsWithNoChanges = [];
|
|
1828
|
-
const sortedMigrations =
|
|
1829
|
-
|
|
1830
|
-
// `.nx/migrate-runs` to position 0 so its .gitignore update lands
|
|
1831
|
-
// before any per-migration commit absorbs the run's handoff scratch.
|
|
1832
|
-
// See `agentic/handoff-gitignore.ts` for the full rationale and the
|
|
1833
|
-
// inline-fallback path that covers intra-pre-v23 agentic runs.
|
|
1834
|
-
if (agentic?.kind === 'enabled') {
|
|
1835
|
-
if ((0, handoff_gitignore_1.isHandoffGitignoreMigration)(a))
|
|
1836
|
-
return -1;
|
|
1837
|
-
if ((0, handoff_gitignore_1.isHandoffGitignoreMigration)(b))
|
|
1838
|
-
return 1;
|
|
1839
|
-
}
|
|
1840
|
-
// special case for the split configuration migration to run first
|
|
1841
|
-
if (a.name === '15-7-0-split-configuration-into-project-json-files') {
|
|
1842
|
-
return -1;
|
|
1843
|
-
}
|
|
1844
|
-
if (b.name === '15-7-0-split-configuration-into-project-json-files') {
|
|
1845
|
-
return 1;
|
|
1846
|
-
}
|
|
1847
|
-
return (0, semver_1.lt)((0, version_utils_1.normalizeVersion)(a.version), (0, version_utils_1.normalizeVersion)(b.version))
|
|
1848
|
-
? -1
|
|
1849
|
-
: 1;
|
|
1733
|
+
const sortedMigrations = (0, sort_migrations_1.sortMigrations)(migrations, {
|
|
1734
|
+
hoistHandoffGitignore: agentic?.kind === 'enabled',
|
|
1850
1735
|
});
|
|
1851
1736
|
// Lazy-load the agentic chain so non-agentic runs don't pay its startup cost.
|
|
1852
1737
|
let agenticRun;
|
|
1853
1738
|
if (agentic?.kind === 'enabled' && sortedMigrations.length > 0) {
|
|
1854
|
-
const { initRunDir } = require('./agentic/handoff');
|
|
1739
|
+
const { initRunDir, resolveAgenticRunId } = require('./agentic/handoff');
|
|
1855
1740
|
const { runAgenticPromptStep } = require('./agentic/run-step');
|
|
1856
1741
|
agenticRun = {
|
|
1857
1742
|
agentic,
|
|
@@ -1939,6 +1824,23 @@ async function executeMigrations(root, migrations, isVerbose, shouldCreateCommit
|
|
|
1939
1824
|
// as a commit failure.
|
|
1940
1825
|
return { kind: 'none' };
|
|
1941
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
|
+
}
|
|
1942
1844
|
const totalMigrations = sortedMigrations.length;
|
|
1943
1845
|
let migrationIndex = 0;
|
|
1944
1846
|
for (const m of sortedMigrations) {
|
|
@@ -1959,6 +1861,11 @@ async function executeMigrations(root, migrations, isVerbose, shouldCreateCommit
|
|
|
1959
1861
|
const { resolvedCollection, documentationPath } = resolveMigrationForRun(root, m, !!agenticRun);
|
|
1960
1862
|
let outcome;
|
|
1961
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;
|
|
1962
1869
|
if ((0, migration_shape_1.isPromptOnlyMigration)(m)) {
|
|
1963
1870
|
if (agenticRun) {
|
|
1964
1871
|
inAgenticStep = true;
|
|
@@ -1983,10 +1890,19 @@ async function executeMigrations(root, migrations, isVerbose, shouldCreateCommit
|
|
|
1983
1890
|
}
|
|
1984
1891
|
}
|
|
1985
1892
|
else if ((0, migration_shape_1.isHybridMigration)(m)) {
|
|
1986
|
-
const { changes, nextSteps, agentContext, logs, madeChanges } = await runNxOrAngularMigration(root, m, isVerbose,
|
|
1893
|
+
const { changes, nextSteps, agentContext, skipAgentic, logs, madeChanges, } = await (0, execute_migration_1.runNxOrAngularMigration)(root, m, isVerbose,
|
|
1987
1894
|
/* captureGeneratorOutput: */ !!agenticRun, resolvedCollection);
|
|
1988
1895
|
migrationEmittedNextSteps.push(...nextSteps);
|
|
1989
|
-
if (
|
|
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) {
|
|
1990
1906
|
// Install any deps the deterministic phase added/bumped before the
|
|
1991
1907
|
// agent runs — the prompt half may depend on them being present in
|
|
1992
1908
|
// node_modules.
|
|
@@ -2025,21 +1941,7 @@ async function executeMigrations(root, migrations, isVerbose, shouldCreateCommit
|
|
|
2025
1941
|
printDroppedAgentContext({ migration: m, agentContext });
|
|
2026
1942
|
}
|
|
2027
1943
|
skippedPrompts.push(m);
|
|
2028
|
-
|
|
2029
|
-
migrationsWithNoChanges.push(m);
|
|
2030
|
-
}
|
|
2031
|
-
// Only attempt a commit when this migration's deterministic
|
|
2032
|
-
// phase actually produced changes. Otherwise the absorbing
|
|
2033
|
-
// `git add -A` would build a commit subject naming this no-op
|
|
2034
|
-
// migration even though its content is entirely prior pending
|
|
2035
|
-
// diffs — confusing `git log` / `git blame` attribution. Pending
|
|
2036
|
-
// stays pending and the next change-producing migration absorbs.
|
|
2037
|
-
if (madeChanges) {
|
|
2038
|
-
commit = await attemptMigrationCommit(m);
|
|
2039
|
-
}
|
|
2040
|
-
if (commit.kind === 'landed' && commit.sha) {
|
|
2041
|
-
logger_1.logger.info(pc.dim(`Committed as ${commit.sha}`));
|
|
2042
|
-
}
|
|
1944
|
+
commit = await commitOrRecordNoChanges(m, madeChanges);
|
|
2043
1945
|
outcome = 'deferred';
|
|
2044
1946
|
}
|
|
2045
1947
|
}
|
|
@@ -2047,10 +1949,14 @@ async function executeMigrations(root, migrations, isVerbose, shouldCreateCommit
|
|
|
2047
1949
|
// Defer commit until validation succeeds; failed validation leaves
|
|
2048
1950
|
// changes uncommitted in the working tree for the user to review.
|
|
2049
1951
|
const validationRun = agenticRun && shouldRunValidation ? agenticRun : undefined;
|
|
2050
|
-
const { changes, nextSteps, agentContext, logs, madeChanges } = await runNxOrAngularMigration(root, m, isVerbose,
|
|
1952
|
+
const { changes, nextSteps, agentContext, skipAgentic, logs, madeChanges, } = await (0, execute_migration_1.runNxOrAngularMigration)(root, m, isVerbose,
|
|
2051
1953
|
/* captureGeneratorOutput: */ !!validationRun, resolvedCollection);
|
|
2052
1954
|
migrationEmittedNextSteps.push(...nextSteps);
|
|
2053
|
-
|
|
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;
|
|
2054
1960
|
if (canRunValidation) {
|
|
2055
1961
|
// Install any deps the deterministic phase added/bumped before the
|
|
2056
1962
|
// validation agent runs — the agent may run tasks that need them.
|
|
@@ -2081,22 +1987,17 @@ async function executeMigrations(root, migrations, isVerbose, shouldCreateCommit
|
|
|
2081
1987
|
outcome = 'applied';
|
|
2082
1988
|
}
|
|
2083
1989
|
else {
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
printDroppedAgentContext({ migration: m, agentContext });
|
|
1990
|
+
if (skipAgentic && validationApplies) {
|
|
1991
|
+
(0, migrate_output_1.logWaivedAgenticStep)(m, agentContext);
|
|
1992
|
+
waivedAgenticStep = true;
|
|
2088
1993
|
}
|
|
2089
|
-
if (
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
else {
|
|
2094
|
-
commit = await attemptMigrationCommit(m);
|
|
2095
|
-
if (commit.kind === 'landed' && commit.sha) {
|
|
2096
|
-
logger_1.logger.info(pc.dim(`Committed as ${commit.sha}`));
|
|
2097
|
-
}
|
|
2098
|
-
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 });
|
|
2099
1998
|
}
|
|
1999
|
+
commit = await commitOrRecordNoChanges(m, madeChanges);
|
|
2000
|
+
outcome = madeChanges ? 'applied' : 'no-changes';
|
|
2100
2001
|
}
|
|
2101
2002
|
}
|
|
2102
2003
|
outcomes.push({
|
|
@@ -2104,6 +2005,7 @@ async function executeMigrations(root, migrations, isVerbose, shouldCreateCommit
|
|
|
2104
2005
|
status: 'completed',
|
|
2105
2006
|
kind: outcome,
|
|
2106
2007
|
commit,
|
|
2008
|
+
waivedAgenticStep,
|
|
2107
2009
|
});
|
|
2108
2010
|
logger_1.logger.info('');
|
|
2109
2011
|
}
|
|
@@ -2124,7 +2026,7 @@ async function executeMigrations(root, migrations, isVerbose, shouldCreateCommit
|
|
|
2124
2026
|
// `nx repair` reuses executeMigrations; only record for migrate runs.
|
|
2125
2027
|
if ((0, migrate_analytics_1.hasMigrateRunStarted)()) {
|
|
2126
2028
|
(0, migrate_analytics_1.reportMigrateRunError)({
|
|
2127
|
-
code: e instanceof NpmPeerDepsInstallError
|
|
2029
|
+
code: e instanceof execute_migration_1.NpmPeerDepsInstallError
|
|
2128
2030
|
? 'npm_install'
|
|
2129
2031
|
: inAgenticStep
|
|
2130
2032
|
? 'agentic'
|
|
@@ -2135,7 +2037,7 @@ async function executeMigrations(root, migrations, isVerbose, shouldCreateCommit
|
|
|
2135
2037
|
error: e,
|
|
2136
2038
|
});
|
|
2137
2039
|
}
|
|
2138
|
-
if (!(e instanceof NpmPeerDepsInstallError)) {
|
|
2040
|
+
if (!(e instanceof execute_migration_1.NpmPeerDepsInstallError)) {
|
|
2139
2041
|
// `withGeneratorOutputCapture` attaches the generator's `console.*`
|
|
2140
2042
|
// output as `capturedLogs` (best-effort; may be absent). Surface it
|
|
2141
2043
|
// so the user sees what the generator printed before it crashed.
|
|
@@ -2166,7 +2068,7 @@ async function executeMigrations(root, migrations, isVerbose, shouldCreateCommit
|
|
|
2166
2068
|
await installDepsIfChanged();
|
|
2167
2069
|
}
|
|
2168
2070
|
if (changedDepInstaller.skippedInstall) {
|
|
2169
|
-
logSkippedPostMigrationInstall(root);
|
|
2071
|
+
(0, execute_migration_1.logSkippedPostMigrationInstall)(root);
|
|
2170
2072
|
}
|
|
2171
2073
|
// Combined-view next-steps array kept for back-compat with repair.ts, which
|
|
2172
2074
|
// consumes the single `nextSteps` field.
|
|
@@ -2182,6 +2084,7 @@ async function executeMigrations(root, migrations, isVerbose, shouldCreateCommit
|
|
|
2182
2084
|
skippedPrompts,
|
|
2183
2085
|
migrationEmittedNextSteps,
|
|
2184
2086
|
committedShasCount: (0, migrate_output_1.countLandedCommits)(outcomes),
|
|
2087
|
+
waivedAgenticStepsCount: (0, migrate_output_1.countWaivedAgenticSteps)(outcomes),
|
|
2185
2088
|
// Migrations whose commits failed and never got absorbed by a later
|
|
2186
2089
|
// commit. The caller surfaces them so a successful run doesn't claim
|
|
2187
2090
|
// "up to date" while leaving uncommitted diffs in the working tree.
|
|
@@ -2189,106 +2092,27 @@ async function executeMigrations(root, migrations, isVerbose, shouldCreateCommit
|
|
|
2189
2092
|
retainedAtSuccess: (0, migrate_output_1.retainedMigrations)(outcomes).map((p) => `${p.package}: ${p.name}`),
|
|
2190
2093
|
};
|
|
2191
2094
|
}
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
if (this.initialDeps !== currentDeps) {
|
|
2205
|
-
if (this.shouldSkipInstall) {
|
|
2206
|
-
this._skippedInstall = true;
|
|
2207
|
-
}
|
|
2208
|
-
else {
|
|
2209
|
-
await runInstall(this.root, 'post-migration');
|
|
2210
|
-
}
|
|
2211
|
-
}
|
|
2212
|
-
this.initialDeps = currentDeps;
|
|
2213
|
-
}
|
|
2214
|
-
}
|
|
2215
|
-
exports.ChangedDepInstaller = ChangedDepInstaller;
|
|
2216
|
-
function logSkippedPostMigrationInstall(root) {
|
|
2217
|
-
const packageManager = (0, package_manager_1.detectPackageManager)(root);
|
|
2218
|
-
const installCommand = (0, package_manager_1.getPackageManagerCommand)(packageManager, root).install;
|
|
2219
|
-
output_1.output.warn({
|
|
2220
|
-
title: 'Migrations updated your dependencies, but the install was skipped',
|
|
2221
|
-
bodyLines: [`Run "${installCommand}" to install the updated dependencies.`],
|
|
2222
|
-
});
|
|
2223
|
-
}
|
|
2224
|
-
async function runNxOrAngularMigration(root, migration, isVerbose, captureGeneratorOutput = false, resolvedCollection) {
|
|
2225
|
-
const { collection, collectionPath } = resolvedCollection ?? readMigrationCollection(migration.package, root);
|
|
2226
|
-
let changes = [];
|
|
2227
|
-
let nextSteps = [];
|
|
2228
|
-
let agentContext = [];
|
|
2229
|
-
let logs = '';
|
|
2230
|
-
// Angular's `ngResult.changes` is synthesized from the schematic's
|
|
2231
|
-
// DryRunEvent stream so Nx and Angular paths can share commit/validation
|
|
2232
|
-
// gating via `changes.length > 0`.
|
|
2233
|
-
let madeChanges = false;
|
|
2234
|
-
logger_1.logger.info(pc.dim('→ Running generator…'));
|
|
2235
|
-
if (!isAngularMigration(collection, migration.name)) {
|
|
2236
|
-
({ nextSteps, changes, agentContext, logs } = await runNxMigration(root, collectionPath, collection, migration.name, migration.version, captureGeneratorOutput));
|
|
2237
|
-
madeChanges = changes.length > 0;
|
|
2238
|
-
logger_1.logger.info(`Ran ${migration.name} from ${migration.package}`);
|
|
2239
|
-
if (migration.description) {
|
|
2240
|
-
logger_1.logger.info(` ${migration.description}`);
|
|
2241
|
-
}
|
|
2242
|
-
logger_1.logger.info('');
|
|
2243
|
-
if (!madeChanges) {
|
|
2244
|
-
logger_1.logger.info(`No changes were made\n`);
|
|
2245
|
-
return { changes, nextSteps, agentContext, logs, madeChanges };
|
|
2246
|
-
}
|
|
2247
|
-
logger_1.logger.info('Changes:');
|
|
2248
|
-
(0, tree_1.printChanges)(changes, ' ');
|
|
2249
|
-
logger_1.logger.info('');
|
|
2250
|
-
}
|
|
2251
|
-
else {
|
|
2252
|
-
const ngCliAdapter = await getNgCompatLayer();
|
|
2253
|
-
const migrationProjectGraph = await (0, project_graph_1.createProjectGraphAsync)();
|
|
2254
|
-
const ngResult = await ngCliAdapter.runMigration(root, migration.package, migration.name, (0, project_graph_1.readProjectsConfigurationFromProjectGraph)(migrationProjectGraph).projects, isVerbose, migrationProjectGraph);
|
|
2255
|
-
changes = ngResult.changes;
|
|
2256
|
-
madeChanges = ngResult.madeChanges;
|
|
2257
|
-
logs = ngResult.loggingQueue.join('\n');
|
|
2258
|
-
logger_1.logger.info(`Ran ${migration.name} from ${migration.package}`);
|
|
2259
|
-
if (migration.description) {
|
|
2260
|
-
logger_1.logger.info(` ${migration.description}`);
|
|
2261
|
-
}
|
|
2262
|
-
logger_1.logger.info('');
|
|
2263
|
-
if (!madeChanges) {
|
|
2264
|
-
logger_1.logger.info(`No changes were made\n`);
|
|
2265
|
-
return { changes, nextSteps, agentContext, logs, madeChanges };
|
|
2266
|
-
}
|
|
2267
|
-
logger_1.logger.info('Changes:');
|
|
2268
|
-
ngResult.loggingQueue.forEach((log) => logger_1.logger.info(' ' + log));
|
|
2269
|
-
logger_1.logger.info('');
|
|
2270
|
-
}
|
|
2271
|
-
return { changes, nextSteps, agentContext, logs, madeChanges };
|
|
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;
|
|
2272
2107
|
}
|
|
2273
2108
|
async function runMigrations(root, opts, args, isVerbose, shouldCreateCommits, commitPrefix, shouldSkipInstall = false) {
|
|
2274
2109
|
if (!shouldSkipInstall && !process.env.NX_MIGRATE_SKIP_INSTALL) {
|
|
2275
|
-
await runInstall();
|
|
2110
|
+
await (0, execute_migration_1.runInstall)();
|
|
2276
2111
|
}
|
|
2277
2112
|
if (!__dirname.startsWith(workspace_root_1.workspaceRoot)) {
|
|
2278
2113
|
// we are running from a temp installation with nx latest, switch to running
|
|
2279
2114
|
// from local installation
|
|
2280
|
-
|
|
2281
|
-
stdio: ['inherit', 'inherit', 'inherit'],
|
|
2282
|
-
env: {
|
|
2283
|
-
...process.env,
|
|
2284
|
-
NX_MIGRATE_SKIP_INSTALL: 'true',
|
|
2285
|
-
NX_MIGRATE_USE_LOCAL: 'true',
|
|
2286
|
-
},
|
|
2287
|
-
}));
|
|
2288
|
-
if (exitCode !== 0) {
|
|
2289
|
-
return exitCode;
|
|
2290
|
-
}
|
|
2291
|
-
return;
|
|
2115
|
+
return handOffToLocalNx(args);
|
|
2292
2116
|
}
|
|
2293
2117
|
const migrationsExists = (0, fileutils_1.fileExists)(opts.runMigrations);
|
|
2294
2118
|
if (opts.ifExists && !migrationsExists) {
|
|
@@ -2300,12 +2124,53 @@ async function runMigrations(root, opts, args, isVerbose, shouldCreateCommits, c
|
|
|
2300
2124
|
else if (!opts.ifExists && !migrationsExists) {
|
|
2301
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`);
|
|
2302
2126
|
}
|
|
2303
|
-
const
|
|
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
|
+
}
|
|
2304
2169
|
(0, migrate_analytics_1.reportMigrateRunStart)({
|
|
2305
2170
|
createCommits: shouldCreateCommits ?? false,
|
|
2306
2171
|
migrationCount: migrations.length,
|
|
2307
2172
|
});
|
|
2308
|
-
const { resolveAgentic } = require('./agentic/select');
|
|
2173
|
+
const { resolveAgentic, resolveShouldRunValidation } = require('./agentic/select');
|
|
2309
2174
|
let agentic;
|
|
2310
2175
|
try {
|
|
2311
2176
|
agentic = await resolveAgentic({
|
|
@@ -2318,9 +2183,9 @@ async function runMigrations(root, opts, args, isVerbose, shouldCreateCommits, c
|
|
|
2318
2183
|
(0, migrate_analytics_1.reportMigrateRunError)({ code: 'agentic', error: e });
|
|
2319
2184
|
throw e;
|
|
2320
2185
|
}
|
|
2321
|
-
const { effective: effectiveCreateCommits, agenticHasDiffContext, warning: createCommitsWarning, error: createCommitsError, } = resolveCreateCommits({
|
|
2186
|
+
const { effective: effectiveCreateCommits, agenticHasDiffContext, warning: createCommitsWarning, error: createCommitsError, } = (0, migrate_commits_1.resolveCreateCommits)({
|
|
2322
2187
|
createCommits: shouldCreateCommits,
|
|
2323
|
-
|
|
2188
|
+
mode: agentic.kind,
|
|
2324
2189
|
isGitRepo: (0, git_utils_1.isGitRepository)(root),
|
|
2325
2190
|
commitPrefixIsCustom: commitPrefix !== command_object_1.DEFAULT_MIGRATION_COMMIT_PREFIX,
|
|
2326
2191
|
});
|
|
@@ -2330,24 +2195,10 @@ async function runMigrations(root, opts, args, isVerbose, shouldCreateCommits, c
|
|
|
2330
2195
|
if (createCommitsWarning) {
|
|
2331
2196
|
output_1.output.warn({ title: createCommitsWarning });
|
|
2332
2197
|
}
|
|
2333
|
-
if (effectiveCreateCommits &&
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
const defaultBranch = (0, command_line_utils_1.getBaseRef)((0, configuration_1.readNxJson)(root)).replace(/^origin\//, '');
|
|
2338
|
-
const proceed = await confirmCommitsOnDefaultBranch({
|
|
2339
|
-
currentBranch,
|
|
2340
|
-
defaultBranch,
|
|
2341
|
-
});
|
|
2342
|
-
if (!proceed) {
|
|
2343
|
-
output_1.output.log({
|
|
2344
|
-
title: `Skipped running migrations to avoid committing to the default branch '${currentBranch}'.`,
|
|
2345
|
-
bodyLines: [
|
|
2346
|
-
'Switch to a different branch and re-run, or re-run and confirm to proceed.',
|
|
2347
|
-
],
|
|
2348
|
-
});
|
|
2349
|
-
return;
|
|
2350
|
-
}
|
|
2198
|
+
if (effectiveCreateCommits &&
|
|
2199
|
+
(0, safe_prompt_1.canPrompt)(opts.interactive) &&
|
|
2200
|
+
!(await (0, migrate_commits_1.confirmMigrationCommitsOnDefaultBranch)(root, 'running migrations'))) {
|
|
2201
|
+
return;
|
|
2351
2202
|
}
|
|
2352
2203
|
const shouldRunValidation = resolveShouldRunValidation({
|
|
2353
2204
|
validate: opts.validate,
|
|
@@ -2363,8 +2214,9 @@ async function runMigrations(root, opts, args, isVerbose, shouldCreateCommits, c
|
|
|
2363
2214
|
(0, migrate_commits_1.commitCheckpointBeforeMigrations)(root, commitPrefix);
|
|
2364
2215
|
}
|
|
2365
2216
|
if (agentic.kind === 'enabled') {
|
|
2217
|
+
const { applyAgenticHandoffGitignoreFallback } = require('./agentic/handoff-gitignore');
|
|
2366
2218
|
const { packageJson: nxPackageJson } = (0, package_json_1.readModulePackageJson)('nx', (0, installation_directory_1.getNxRequirePaths)(root));
|
|
2367
|
-
await
|
|
2219
|
+
await applyAgenticHandoffGitignoreFallback({
|
|
2368
2220
|
migrations,
|
|
2369
2221
|
installedNxVersion: nxPackageJson.version,
|
|
2370
2222
|
effectiveCreateCommits,
|
|
@@ -2372,7 +2224,7 @@ async function runMigrations(root, opts, args, isVerbose, shouldCreateCommits, c
|
|
|
2372
2224
|
root,
|
|
2373
2225
|
});
|
|
2374
2226
|
}
|
|
2375
|
-
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);
|
|
2376
2228
|
const ranWithChangesCount = migrations.length - notRunMigrationsCount - migrationsWithNoChanges.length;
|
|
2377
2229
|
// The "applied" tally counts fully-completed migrations — those that
|
|
2378
2230
|
// left no deferred work behind. Hybrid migrations whose prompt half was
|
|
@@ -2383,6 +2235,7 @@ async function runMigrations(root, opts, args, isVerbose, shouldCreateCommits, c
|
|
|
2383
2235
|
appliedCount,
|
|
2384
2236
|
committedShasCount,
|
|
2385
2237
|
skippedPromptsCount,
|
|
2238
|
+
waivedAgenticStepsCount,
|
|
2386
2239
|
insideAgent,
|
|
2387
2240
|
});
|
|
2388
2241
|
const tallyBody = tallyLine ? [tallyLine] : undefined;
|
|
@@ -2464,71 +2317,30 @@ async function runMigrations(root, opts, args, isVerbose, shouldCreateCommits, c
|
|
|
2464
2317
|
appliedCount,
|
|
2465
2318
|
});
|
|
2466
2319
|
}
|
|
2467
|
-
function
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
}
|
|
2472
|
-
catch {
|
|
2473
|
-
// We don't really care if the .nx/installation property changes,
|
|
2474
|
-
// whenever nxw is invoked it will handle the dep updates.
|
|
2475
|
-
return '';
|
|
2476
|
-
}
|
|
2477
|
-
}
|
|
2478
|
-
async function runNxMigration(root, collectionPath, collection, name, migrationVersion, captureGeneratorOutput) {
|
|
2479
|
-
const { path: implPath, fnSymbol } = getImplementationPath(collection, collectionPath, name, migrationVersion);
|
|
2480
|
-
const fn = require(implPath)[fnSymbol];
|
|
2481
|
-
const host = new tree_1.FsTree(root, process.env.NX_VERBOSE_LOGGING === 'true', `migration ${collection.name}:${name}`);
|
|
2482
|
-
let result;
|
|
2483
|
-
let logs = '';
|
|
2484
|
-
if (captureGeneratorOutput) {
|
|
2485
|
-
const { withGeneratorOutputCapture } = require('./agentic/capture-generator-output');
|
|
2486
|
-
({ result, logs } = await withGeneratorOutputCapture(() => fn(host, {})));
|
|
2487
|
-
}
|
|
2488
|
-
else {
|
|
2489
|
-
result = await fn(host, {});
|
|
2490
|
-
}
|
|
2491
|
-
const { nextSteps, agentContext } = parseMigrationReturn(result);
|
|
2492
|
-
host.lock();
|
|
2493
|
-
const changes = host.listChanges();
|
|
2494
|
-
(0, tree_1.flushChanges)(root, changes);
|
|
2495
|
-
return { changes, nextSteps, agentContext, logs };
|
|
2496
|
-
}
|
|
2497
|
-
function parseMigrationReturn(value) {
|
|
2498
|
-
if (Array.isArray(value)) {
|
|
2499
|
-
return { nextSteps: filterStrings(value), agentContext: [] };
|
|
2500
|
-
}
|
|
2501
|
-
if (value && typeof value === 'object') {
|
|
2502
|
-
const obj = value;
|
|
2503
|
-
return {
|
|
2504
|
-
nextSteps: filterStrings(obj.nextSteps),
|
|
2505
|
-
agentContext: filterStrings(obj.agentContext),
|
|
2506
|
-
};
|
|
2507
|
-
}
|
|
2508
|
-
// Catches `void`, mistakenly-returned generator callbacks, malformed values.
|
|
2509
|
-
return { nextSteps: [], agentContext: [] };
|
|
2510
|
-
}
|
|
2511
|
-
// Bucket-level tolerance: a single non-string entry shouldn't discard the
|
|
2512
|
-
// whole `nextSteps` / `agentContext` array. Migration authors occasionally
|
|
2513
|
-
// push `null` / `undefined` / a number into the array; we drop the bad entries
|
|
2514
|
-
// and keep the rest so end-of-run guidance isn't silently lost.
|
|
2515
|
-
function filterStrings(value) {
|
|
2516
|
-
if (!Array.isArray(value))
|
|
2517
|
-
return [];
|
|
2518
|
-
return value.filter((v) => typeof v === 'string');
|
|
2320
|
+
function isRunPhaseInvocation(args) {
|
|
2321
|
+
return (args.runMigration !== undefined ||
|
|
2322
|
+
args.runId !== undefined ||
|
|
2323
|
+
args.stepAction !== undefined);
|
|
2519
2324
|
}
|
|
2520
2325
|
async function migrate(root, args, rawArgs) {
|
|
2521
2326
|
await client_1.daemonClient.stop();
|
|
2522
2327
|
return (0, handle_errors_1.handleErrors)(process.env.NX_VERBOSE_LOGGING === 'true', async () => {
|
|
2523
2328
|
const mergedArgs = (0, migrate_config_1.applyNxJsonMigrateDefaults)(args, (0, configuration_1.readNxJson)().migrate);
|
|
2524
|
-
(
|
|
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
|
+
}
|
|
2525
2337
|
// One fetcher (registry-first, install fallback) shared by the `--include`
|
|
2526
2338
|
// eligibility gate and the migration cascade so package metadata is fetched
|
|
2527
2339
|
// at most once per package/version.
|
|
2528
2340
|
const fetch = createFetcher((0, package_manager_1.getPackageManagerCommand)());
|
|
2529
|
-
// `--run-migrations` without a value parses as ''
|
|
2530
|
-
// generate phase.
|
|
2531
|
-
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;
|
|
2532
2344
|
let opts;
|
|
2533
2345
|
try {
|
|
2534
2346
|
opts = await parseMigrationsOptions(mergedArgs, fetch);
|
|
@@ -2537,36 +2349,320 @@ async function migrate(root, args, rawArgs) {
|
|
|
2537
2349
|
if (isGenerateInvocation) {
|
|
2538
2350
|
(0, migrate_analytics_1.reportMigrateGenerateError)('resolve_version', e);
|
|
2539
2351
|
}
|
|
2352
|
+
else if (runPhase) {
|
|
2353
|
+
(0, migrate_analytics_1.reportMigrateRunError)({ code: 'other', error: e });
|
|
2354
|
+
}
|
|
2540
2355
|
throw e;
|
|
2541
2356
|
}
|
|
2542
|
-
|
|
2543
|
-
|
|
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
|
+
}
|
|
2544
2395
|
}
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
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;
|
|
2548
2464
|
}
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
//
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
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
|
+
}
|
|
2556
2512
|
}
|
|
2557
|
-
(0, migrate_analytics_1.reportMigrateRunError)({ code: 'other', error: e });
|
|
2558
|
-
throw e;
|
|
2559
2513
|
}
|
|
2560
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,
|
|
2561
2626
|
});
|
|
2562
2627
|
}
|
|
2563
2628
|
async function runMigration() {
|
|
2564
2629
|
return (0, handle_errors_1.handleErrors)(process.env.NX_VERBOSE_LOGGING === 'true', async () => {
|
|
2565
|
-
|
|
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], {
|
|
2566
2642
|
stdio: ['inherit', 'inherit', 'inherit'],
|
|
2567
2643
|
}));
|
|
2568
|
-
if (process.
|
|
2644
|
+
if (!(0, version_skew_guard_1.targetsExistingRun)(process.argv.slice(3)) &&
|
|
2645
|
+
process.env.NX_USE_LOCAL !== 'true' &&
|
|
2569
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
|
+
}
|
|
2570
2666
|
const p = await nxCliPath();
|
|
2571
2667
|
if (p === null) {
|
|
2572
2668
|
return runLocalMigrate();
|
|
@@ -2577,47 +2673,30 @@ async function runMigration() {
|
|
|
2577
2673
|
process.env.npm_config_registry.match(/^https:\/\/registry\.(npmjs\.org|yarnpkg\.com)/)) {
|
|
2578
2674
|
delete process.env.npm_config_registry;
|
|
2579
2675
|
}
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
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
|
+
}));
|
|
2584
2696
|
}
|
|
2585
2697
|
return runLocalMigrate();
|
|
2586
2698
|
});
|
|
2587
2699
|
}
|
|
2588
|
-
function readMigrationCollection(packageName, root) {
|
|
2589
|
-
const collectionPath = readPackageMigrationConfig(packageName, root).migrations;
|
|
2590
|
-
const collection = (0, fileutils_1.readJsonFile)(collectionPath);
|
|
2591
|
-
collection.name ??= packageName;
|
|
2592
|
-
return {
|
|
2593
|
-
collection,
|
|
2594
|
-
collectionPath,
|
|
2595
|
-
};
|
|
2596
|
-
}
|
|
2597
|
-
function getImplementationPath(collection, collectionPath, name, migrationVersion) {
|
|
2598
|
-
const g = collection.generators?.[name] || collection.schematics?.[name];
|
|
2599
|
-
if (!g) {
|
|
2600
|
-
throw new MigrationImplementationMissingError(`Unable to determine implementation path for "${collectionPath}:${name}"`, collectionPath, migrationVersion);
|
|
2601
|
-
}
|
|
2602
|
-
const implRelativePathAndMaybeSymbol = g.implementation || g.factory;
|
|
2603
|
-
const [implRelativePath, fnSymbol = 'default'] = implRelativePathAndMaybeSymbol.split('#');
|
|
2604
|
-
let implPath;
|
|
2605
|
-
try {
|
|
2606
|
-
implPath = require.resolve(implRelativePath, {
|
|
2607
|
-
paths: [(0, path_1.dirname)(collectionPath)],
|
|
2608
|
-
});
|
|
2609
|
-
}
|
|
2610
|
-
catch (e) {
|
|
2611
|
-
try {
|
|
2612
|
-
// workaround for a bug in node 12
|
|
2613
|
-
implPath = require.resolve(`${(0, path_1.dirname)(collectionPath)}/${implRelativePath}`);
|
|
2614
|
-
}
|
|
2615
|
-
catch {
|
|
2616
|
-
throw new MigrationImplementationMissingError(`Could not resolve implementation for migration "${name}" from "${collectionPath}"`, collectionPath, migrationVersion ?? g.version);
|
|
2617
|
-
}
|
|
2618
|
-
}
|
|
2619
|
-
return { path: implPath, fnSymbol };
|
|
2620
|
-
}
|
|
2621
2700
|
/**
|
|
2622
2701
|
* Resolves a migration's collection once and derives everything the run loop
|
|
2623
2702
|
* needs from that single read: the implementation context (`collection` +
|
|
@@ -2636,11 +2715,11 @@ function getImplementationPath(collection, collectionPath, name, migrationVersio
|
|
|
2636
2715
|
function resolveMigrationForRun(root, migration, resolveDocumentation) {
|
|
2637
2716
|
let resolvedCollection;
|
|
2638
2717
|
if (!(0, migration_shape_1.isPromptOnlyMigration)(migration)) {
|
|
2639
|
-
resolvedCollection = readMigrationCollection(migration.package, root);
|
|
2718
|
+
resolvedCollection = (0, execute_migration_1.readMigrationCollection)(migration.package, root);
|
|
2640
2719
|
}
|
|
2641
2720
|
else if (resolveDocumentation && migration.documentation) {
|
|
2642
2721
|
try {
|
|
2643
|
-
resolvedCollection = readMigrationCollection(migration.package, root);
|
|
2722
|
+
resolvedCollection = (0, execute_migration_1.readMigrationCollection)(migration.package, root);
|
|
2644
2723
|
}
|
|
2645
2724
|
catch {
|
|
2646
2725
|
// Non-fatal: documentation is supplementary; the warning below fires.
|
|
@@ -2649,7 +2728,7 @@ function resolveMigrationForRun(root, migration, resolveDocumentation) {
|
|
|
2649
2728
|
let documentationPath;
|
|
2650
2729
|
if (resolveDocumentation && migration.documentation) {
|
|
2651
2730
|
documentationPath = resolvedCollection
|
|
2652
|
-
? 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)
|
|
2653
2732
|
: undefined;
|
|
2654
2733
|
if (!documentationPath) {
|
|
2655
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.`);
|
|
@@ -2657,70 +2736,6 @@ function resolveMigrationForRun(root, migration, resolveDocumentation) {
|
|
|
2657
2736
|
}
|
|
2658
2737
|
return { resolvedCollection, documentationPath };
|
|
2659
2738
|
}
|
|
2660
|
-
// Resolves a `documentation` path (relative to the package's migrations dir) to
|
|
2661
|
-
// a workspace-relative path - or the absolute path when it resolves outside the
|
|
2662
|
-
// workspace (unusual hoisted/symlinked layouts). The agent runs with cwd =
|
|
2663
|
-
// workspace root, so the workspace-relative form is preferred. Returns
|
|
2664
|
-
// undefined when the file can't be resolved.
|
|
2665
|
-
function resolveDocumentationFileToWorkspacePath(root, migrationsDir, documentation) {
|
|
2666
|
-
let documentationFile;
|
|
2667
|
-
try {
|
|
2668
|
-
documentationFile = require.resolve(documentation, {
|
|
2669
|
-
paths: [migrationsDir],
|
|
2670
|
-
});
|
|
2671
|
-
}
|
|
2672
|
-
catch {
|
|
2673
|
-
return undefined;
|
|
2674
|
-
}
|
|
2675
|
-
const relativePath = (0, path_1.relative)(root, documentationFile);
|
|
2676
|
-
return relativePath.startsWith('..') ? documentationFile : relativePath;
|
|
2677
|
-
}
|
|
2678
|
-
class MigrationImplementationMissingError extends Error {
|
|
2679
|
-
constructor(baseMessage, collectionPath, migrationVersion) {
|
|
2680
|
-
super(buildMigrationMissingMessage(baseMessage, collectionPath, migrationVersion));
|
|
2681
|
-
this.name = 'MigrationImplementationMissingError';
|
|
2682
|
-
}
|
|
2683
|
-
}
|
|
2684
|
-
function buildMigrationMissingMessage(baseMessage, collectionPath, migrationVersion) {
|
|
2685
|
-
if (!migrationVersion) {
|
|
2686
|
-
return baseMessage;
|
|
2687
|
-
}
|
|
2688
|
-
try {
|
|
2689
|
-
const packageJsonPath = (0, path_1.join)((0, path_1.dirname)(collectionPath), 'package.json');
|
|
2690
|
-
if (!(0, fs_1.existsSync)(packageJsonPath)) {
|
|
2691
|
-
return baseMessage;
|
|
2692
|
-
}
|
|
2693
|
-
const packageJson = (0, fileutils_1.readJsonFile)(packageJsonPath);
|
|
2694
|
-
const installedVersion = packageJson.version;
|
|
2695
|
-
if (installedVersion &&
|
|
2696
|
-
(0, semver_1.lt)((0, version_utils_1.normalizeVersion)(installedVersion), (0, version_utils_1.normalizeVersion)(migrationVersion))) {
|
|
2697
|
-
const packageManager = (0, package_manager_1.detectPackageManager)();
|
|
2698
|
-
const pmc = (0, package_manager_1.getPackageManagerCommand)(packageManager);
|
|
2699
|
-
const overrideFieldName = getOverrideFieldName(packageManager);
|
|
2700
|
-
return (`${baseMessage}\n\n` +
|
|
2701
|
-
`The installed version of "${packageJson.name}" is ${installedVersion}, ` +
|
|
2702
|
-
`but this migration requires version ${migrationVersion}. ` +
|
|
2703
|
-
`This likely means the package version is being held back by an ${overrideFieldName} ` +
|
|
2704
|
-
`in your package.json. ` +
|
|
2705
|
-
`Remove the ${overrideFieldName} and run "${pmc.install}" to install the correct version.`);
|
|
2706
|
-
}
|
|
2707
|
-
}
|
|
2708
|
-
catch {
|
|
2709
|
-
// Fall through to return the base message if we can't read package info
|
|
2710
|
-
}
|
|
2711
|
-
return baseMessage;
|
|
2712
|
-
}
|
|
2713
|
-
function getOverrideFieldName(packageManager) {
|
|
2714
|
-
switch (packageManager) {
|
|
2715
|
-
case 'pnpm':
|
|
2716
|
-
return '"pnpm.overrides"';
|
|
2717
|
-
case 'yarn':
|
|
2718
|
-
return '"resolutions"';
|
|
2719
|
-
case 'npm':
|
|
2720
|
-
case 'bun':
|
|
2721
|
-
return '"overrides"';
|
|
2722
|
-
}
|
|
2723
|
-
}
|
|
2724
2739
|
async function nxCliPath(nxWorkspaceRoot) {
|
|
2725
2740
|
const version = process.env.NX_MIGRATE_CLI_VERSION || 'latest';
|
|
2726
2741
|
const isVerbose = process.env.NX_VERBOSE_LOGGING === 'true';
|
|
@@ -2771,7 +2786,7 @@ async function nxCliPath(nxWorkspaceRoot) {
|
|
|
2771
2786
|
return (0, path_1.join)(tmpDir, `node_modules`, '.bin', 'nx');
|
|
2772
2787
|
}
|
|
2773
2788
|
catch (e) {
|
|
2774
|
-
console.error(`Failed to install the ${version} version of the migration script.
|
|
2789
|
+
console.error(`Failed to install the ${version} version of the migration script. Falling back to the workspace's installed nx.`);
|
|
2775
2790
|
if (isVerbose) {
|
|
2776
2791
|
console.error(e);
|
|
2777
2792
|
}
|
|
@@ -2790,16 +2805,3 @@ function addToNodePath(dir) {
|
|
|
2790
2805
|
// Update the env variable.
|
|
2791
2806
|
process.env.NODE_PATH = paths.join(delimiter);
|
|
2792
2807
|
}
|
|
2793
|
-
function isAngularMigration(collection, name) {
|
|
2794
|
-
return !collection.generators?.[name] && collection.schematics?.[name];
|
|
2795
|
-
}
|
|
2796
|
-
const getNgCompatLayer = (() => {
|
|
2797
|
-
let _ngCliAdapter;
|
|
2798
|
-
return async function getNgCompatLayer() {
|
|
2799
|
-
if (!_ngCliAdapter) {
|
|
2800
|
-
_ngCliAdapter = await (0, handle_import_1.handleImport)('../../adapter/ngcli-adapter.js', __dirname);
|
|
2801
|
-
require('../../adapter/compat');
|
|
2802
|
-
}
|
|
2803
|
-
return _ngCliAdapter;
|
|
2804
|
-
};
|
|
2805
|
-
})();
|