@ohos-ports/nx 23.3.0-beta.3 → 24.0.2-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -6
- package/dist/bin/nx.js +2 -2
- package/dist/bin/post-install.js +5 -3
- package/dist/nx-cloud-internals.d.ts +1 -0
- package/dist/nx-cloud-internals.js +7 -1
- package/dist/src/adapter/ngcli-adapter.js +2 -2
- package/dist/src/ai/clone-ai-config-repo.js +49 -12
- package/dist/src/command-line/add/add.d.ts +2 -0
- package/dist/src/command-line/add/add.js +24 -6
- package/dist/src/command-line/affected/affected.js +2 -2
- package/dist/src/command-line/configure-ai-agents/configure-ai-agents.js +1 -13
- package/dist/src/command-line/graph/graph.js +38 -10
- package/dist/src/command-line/init/command-object.js +0 -12
- package/dist/src/command-line/init/implementation/add-nx-to-nest.js +21 -62
- package/dist/src/command-line/init/init-v2.js +1 -3
- package/dist/src/command-line/migrate/agentic/close-agent-session.d.ts +1 -1
- package/dist/src/command-line/migrate/agentic/close-agent-session.js +4 -3
- package/dist/src/command-line/migrate/agentic/definitions.d.ts +1 -3
- package/dist/src/command-line/migrate/agentic/definitions.js +5 -97
- package/dist/src/command-line/migrate/agentic/handoff-gitignore.d.ts +7 -45
- package/dist/src/command-line/migrate/agentic/handoff-gitignore.js +9 -51
- package/dist/src/command-line/migrate/agentic/handoff.d.ts +1 -43
- package/dist/src/command-line/migrate/agentic/handoff.js +3 -119
- package/dist/src/command-line/migrate/agentic/instruction-files.d.ts +0 -21
- package/dist/src/command-line/migrate/agentic/instruction-files.js +6 -27
- package/dist/src/command-line/migrate/agentic/master/run-master-session.d.ts +19 -1
- package/dist/src/command-line/migrate/agentic/master/run-master-session.js +88 -49
- package/dist/src/command-line/migrate/agentic/master/spawn-master.d.ts +1 -0
- package/dist/src/command-line/migrate/agentic/master/spawn-master.js +86 -24
- package/dist/src/command-line/migrate/agentic/print-dropped-agent-context.d.ts +2 -2
- package/dist/src/command-line/migrate/agentic/print-dropped-agent-context.js +2 -2
- package/dist/src/command-line/migrate/agentic/prompts/fragments.d.ts +1 -12
- package/dist/src/command-line/migrate/agentic/prompts/fragments.js +8 -17
- package/dist/src/command-line/migrate/agentic/prompts/shared-rendering.d.ts +0 -15
- package/dist/src/command-line/migrate/agentic/prompts/shared-rendering.js +3 -100
- package/dist/src/command-line/migrate/agentic/select.d.ts +12 -6
- package/dist/src/command-line/migrate/agentic/select.js +38 -8
- package/dist/src/command-line/migrate/agentic/types.d.ts +9 -68
- package/dist/src/command-line/migrate/agentic/types.js +6 -8
- package/dist/src/command-line/migrate/command-object.js +6 -10
- package/dist/src/command-line/migrate/execute-migration.d.ts +6 -6
- package/dist/src/command-line/migrate/execute-migration.js +25 -15
- package/dist/src/command-line/migrate/migrate-analytics.d.ts +18 -1
- package/dist/src/command-line/migrate/migrate-analytics.js +38 -0
- package/dist/src/command-line/migrate/migrate-commits.d.ts +29 -17
- package/dist/src/command-line/migrate/migrate-commits.js +86 -32
- package/dist/src/command-line/migrate/migrate-config.d.ts +6 -6
- package/dist/src/command-line/migrate/migrate-config.js +12 -6
- package/dist/src/command-line/migrate/migrate-output.d.ts +1 -6
- package/dist/src/command-line/migrate/migrate-output.js +1 -10
- package/dist/src/command-line/migrate/migrate.d.ts +6 -30
- package/dist/src/command-line/migrate/migrate.js +257 -255
- package/dist/src/command-line/migrate/resolve-package-version.d.ts +2 -4
- package/dist/src/command-line/migrate/resolve-package-version.js +2 -35
- package/dist/src/command-line/migrate/run/agent-output.d.ts +2 -0
- package/dist/src/command-line/migrate/run/agent-output.js +9 -0
- package/dist/src/command-line/migrate/run/broker.d.ts +14 -5
- package/dist/src/command-line/migrate/run/broker.js +69 -21
- package/dist/src/command-line/migrate/run/clean-retry.js +4 -2
- package/dist/src/command-line/migrate/run/existing-run-report.d.ts +1 -1
- package/dist/src/command-line/migrate/run/existing-run-report.js +7 -5
- package/dist/src/command-line/migrate/run/give-up.d.ts +4 -3
- package/dist/src/command-line/migrate/run/give-up.js +8 -5
- package/dist/src/command-line/migrate/run/index.d.ts +7 -5
- package/dist/src/command-line/migrate/run/index.js +16 -1
- package/dist/src/command-line/migrate/run/issues.js +7 -2
- package/dist/src/command-line/migrate/run/orchestrator.d.ts +61 -4
- package/dist/src/command-line/migrate/run/orchestrator.js +397 -133
- package/dist/src/command-line/migrate/run/run-state.d.ts +17 -1
- package/dist/src/command-line/migrate/run/run-state.js +41 -2
- package/dist/src/command-line/migrate/run/runbook.d.ts +1 -0
- package/dist/src/command-line/migrate/run/runbook.js +115 -18
- package/dist/src/command-line/migrate/run/state-lock.d.ts +29 -4
- package/dist/src/command-line/migrate/run/state-lock.js +102 -10
- package/dist/src/command-line/migrate/run/state-machine.js +4 -1
- package/dist/src/command-line/migrate/run/util.d.ts +7 -2
- package/dist/src/command-line/migrate/run/util.js +30 -3
- package/dist/src/command-line/migrate/run/worker.d.ts +1 -1
- package/dist/src/command-line/migrate/run/worker.js +252 -250
- package/dist/src/command-line/migrate/sort-migrations.d.ts +1 -7
- package/dist/src/command-line/migrate/sort-migrations.js +1 -12
- package/dist/src/command-line/nx-cloud/connect/connect-to-nx-cloud.js +17 -12
- package/dist/src/command-line/release/changelog.js +9 -6
- package/dist/src/command-line/release/config/config.d.ts +1 -0
- package/dist/src/command-line/release/config/config.js +48 -9
- package/dist/src/command-line/release/release.js +2 -2
- package/dist/src/command-line/release/utils/git.js +8 -7
- package/dist/src/command-line/release/utils/interpolate-release-config.d.ts +6 -0
- package/dist/src/command-line/release/utils/interpolate-release-config.js +39 -0
- package/dist/src/command-line/release/utils/release-graph.d.ts +5 -0
- package/dist/src/command-line/release/utils/release-graph.js +1 -0
- package/dist/src/command-line/release/utils/remote-release-clients/github.js +5 -6
- package/dist/src/command-line/release/utils/remote-release-clients/gitlab.js +5 -6
- package/dist/src/command-line/release/utils/resolve-changelog-renderer.js +2 -2
- package/dist/src/command-line/release/utils/shared.js +10 -10
- package/dist/src/command-line/release/utils/version-plan-utils.d.ts +3 -12
- package/dist/src/command-line/release/utils/version-plan-utils.js +33 -55
- package/dist/src/command-line/release/version/version-actions.js +2 -1
- package/dist/src/command-line/release/version.js +5 -2
- package/dist/src/command-line/repair/repair.js +1 -1
- package/dist/src/command-line/report/report.js +1 -1
- package/dist/src/command-line/reset/reset.js +58 -62
- package/dist/src/command-line/run/executor-utils.js +1 -0
- package/dist/src/command-line/run/run-one.d.ts +20 -1
- package/dist/src/command-line/run/run-one.js +153 -5
- package/dist/src/command-line/run/run.js +2 -1
- package/dist/src/command-line/show/projects.js +5 -3
- package/dist/src/command-line/show/show-target/info.d.ts +10 -1
- package/dist/src/command-line/show/show-target/info.js +100 -15
- package/dist/src/command-line/show/show-target/inputs.js +10 -2
- package/dist/src/command-line/show/show-target/utils.js +1 -0
- package/dist/src/command-line/watch/command-object.js +3 -22
- package/dist/src/command-line/watch/watch.d.ts +0 -7
- package/dist/src/command-line/watch/watch.js +1 -1
- package/dist/src/command-line/yargs-utils/shared-options.js +1 -1
- package/dist/src/config/misc-interfaces.d.ts +18 -0
- package/dist/src/config/nx-json.d.ts +22 -11
- package/dist/src/config/task-graph.d.ts +1 -1
- package/dist/src/config/workspace-json-project-json.d.ts +88 -0
- package/dist/src/core/graph/main.js +1 -1
- package/dist/src/core/graph/runtime.js +1 -1
- package/dist/src/core/graph/styles.css +1 -1
- package/dist/src/core/graph/styles.js +1 -1
- package/dist/src/daemon/client/client.d.ts +15 -0
- package/dist/src/daemon/client/client.js +181 -71
- package/dist/src/daemon/client/daemon-socket-messenger.d.ts +1 -1
- package/dist/src/daemon/client/daemon-socket-messenger.js +2 -2
- package/dist/src/daemon/server/client-socket-context.js +1 -1
- package/dist/src/daemon/server/handle-configure-ai-agents.js +2 -2
- package/dist/src/daemon/server/handle-process-in-background.js +21 -9
- package/dist/src/daemon/server/handle-select-affected-tasks.d.ts +2 -1
- package/dist/src/daemon/server/handle-select-affected-tasks.js +21 -13
- package/dist/src/daemon/server/native-js-loader.d.ts +1 -0
- package/dist/src/daemon/server/native-js-loader.js +21 -0
- package/dist/src/daemon/server/nx-console-operations.js +2 -2
- package/dist/src/daemon/server/project-graph-incremental-recomputation.js +4 -8
- package/dist/src/daemon/server/server.d.ts +2 -1
- package/dist/src/daemon/server/server.js +17 -4
- package/dist/src/daemon/server/shutdown-utils.js +1 -4
- package/dist/src/daemon/server/start.d.ts +1 -0
- package/dist/src/daemon/server/start.js +2 -0
- package/dist/src/daemon/socket-utils.d.ts +11 -9
- package/dist/src/daemon/socket-utils.js +31 -61
- package/dist/src/daemon/tmp-dir.d.ts +19 -14
- package/dist/src/daemon/tmp-dir.js +142 -354
- package/dist/src/devkit-exports.d.ts +9 -1
- package/dist/src/devkit-exports.js +12 -1
- package/dist/src/devkit-internals.d.ts +6 -5
- package/dist/src/devkit-internals.js +13 -4
- package/dist/src/executors/run-commands/run-commands.impl.d.ts +4 -2
- package/dist/src/executors/run-commands/run-commands.impl.js +53 -27
- package/dist/src/executors/run-commands/running-tasks.d.ts +13 -4
- package/dist/src/executors/run-commands/running-tasks.js +148 -95
- package/dist/src/executors/run-commands/schema.json +1 -1
- package/dist/src/hasher/check-task-files.js +5 -8
- package/dist/src/hasher/file-hasher.js +9 -7
- package/dist/src/hasher/hash-task.js +4 -0
- package/dist/src/hasher/native-task-hasher-impl.js +3 -1
- package/dist/src/hasher/task-hasher.d.ts +2 -0
- package/dist/src/hasher/task-hasher.js +4 -1
- package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.d.ts +1 -2
- package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.js +6 -11
- package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.md +2 -2
- package/dist/src/migrations/update-24-0-0/enable-legacy-affected.d.ts +4 -0
- package/dist/src/migrations/update-24-0-0/enable-legacy-affected.js +15 -0
- package/dist/src/migrations/update-24-0-0/enable-legacy-affected.md +30 -0
- package/dist/src/migrations/update-24-0-0/find-custom-hashers.d.ts +3 -0
- package/dist/src/migrations/update-24-0-0/find-custom-hashers.js +100 -0
- package/dist/src/migrations/update-24-0-0/find-custom-hashers.md +63 -0
- package/dist/src/migrations/update-24-0-0/move-custom-hashers-to-inputs.md +146 -0
- package/dist/src/migrations/update-24-0-0/rename-ultracache-ignore-options.d.ts +3 -0
- package/dist/src/migrations/update-24-0-0/rename-ultracache-ignore-options.js +130 -0
- package/dist/src/migrations/update-24-0-0/rename-ultracache-ignore-options.md +62 -0
- package/dist/src/native/assert-supported-platform.js +1 -1
- package/dist/src/native/index.d.ts +238 -18
- package/dist/src/native/index.js +6 -1
- package/dist/src/native/native-bindings.js +15 -6
- package/dist/src/native/nx.openharmony-arm64.node +0 -0
- package/dist/src/native/nx.wasi-browser.js +1 -0
- package/dist/src/native/nx.wasi.cjs +1 -0
- package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
- package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
- package/dist/src/nx-cloud/update-manager.d.ts +14 -0
- package/dist/src/nx-cloud/update-manager.js +237 -50
- package/dist/src/plugins/js/lock-file/pnpm-parser.js +3 -4
- package/dist/src/plugins/js/lock-file/pruned-output.d.ts +2 -2
- package/dist/src/plugins/js/lock-file/pruned-output.js +4 -4
- package/dist/src/plugins/js/utils/register.js +9 -4
- package/dist/src/project-graph/affected/affected-tasks.d.ts +9 -6
- package/dist/src/project-graph/affected/affected-tasks.js +31 -7
- package/dist/src/project-graph/plugins/isolation/isolated-plugin.js +7 -0
- package/dist/src/project-graph/plugins/loaded-nx-plugin.js +49 -6
- package/dist/src/project-graph/utils/project-configuration/target-merging.js +1 -1
- package/dist/src/project-graph/utils/project-configuration/target-normalization.js +12 -133
- package/dist/src/project-graph/utils/project-configuration-utils.js +2 -2
- package/dist/src/project-graph/utils/retrieve-workspace-files.js +27 -6
- package/dist/src/tasks-runner/create-task-graph.d.ts +8 -7
- package/dist/src/tasks-runner/create-task-graph.js +50 -27
- package/dist/src/tasks-runner/default-tasks-runner.js +1 -1
- package/dist/src/tasks-runner/init-tasks-runner.js +116 -59
- package/dist/src/tasks-runner/life-cycle.d.ts +4 -1
- package/dist/src/tasks-runner/life-cycle.js +7 -0
- package/dist/src/tasks-runner/life-cycles/performance-analysis.d.ts +5 -2
- package/dist/src/tasks-runner/life-cycles/performance-analysis.js +13 -7
- package/dist/src/tasks-runner/life-cycles/performance-life-cycle.d.ts +4 -3
- package/dist/src/tasks-runner/life-cycles/performance-life-cycle.js +9 -2
- package/dist/src/tasks-runner/life-cycles/static-run-many-terminal-output-life-cycle.js +5 -2
- package/dist/src/tasks-runner/life-cycles/static-run-one-terminal-output-life-cycle.js +4 -1
- package/dist/src/tasks-runner/life-cycles/summary-terminal-output-life-cycle.js +5 -1
- package/dist/src/tasks-runner/pseudo-ipc.d.ts +1 -0
- package/dist/src/tasks-runner/pseudo-ipc.js +4 -0
- package/dist/src/tasks-runner/pseudo-terminal.d.ts +1 -1
- package/dist/src/tasks-runner/pseudo-terminal.js +2 -2
- package/dist/src/tasks-runner/readiness/executor-ready-signal.d.ts +7 -0
- package/dist/src/tasks-runner/readiness/executor-ready-signal.js +43 -0
- package/dist/src/tasks-runner/readiness/probes.d.ts +14 -0
- package/dist/src/tasks-runner/readiness/probes.js +101 -0
- package/dist/src/tasks-runner/readiness/ready-signal-server.d.ts +18 -0
- package/dist/src/tasks-runner/readiness/ready-signal-server.js +72 -0
- package/dist/src/tasks-runner/readiness/ready-signal.d.ts +33 -0
- package/dist/src/tasks-runner/readiness/ready-signal.js +92 -0
- package/dist/src/tasks-runner/readiness/ready-when.d.ts +84 -0
- package/dist/src/tasks-runner/readiness/ready-when.js +371 -0
- package/dist/src/tasks-runner/readiness/startup-host.d.ts +1 -0
- package/dist/src/tasks-runner/readiness/startup-host.js +32 -0
- package/dist/src/tasks-runner/run-command.d.ts +6 -2
- package/dist/src/tasks-runner/run-command.js +21 -31
- package/dist/src/tasks-runner/run-outcome.d.ts +16 -0
- package/dist/src/tasks-runner/run-outcome.js +39 -0
- package/dist/src/tasks-runner/running-tasks/batch-process.js +6 -0
- package/dist/src/tasks-runner/running-tasks/node-child-process.js +5 -4
- package/dist/src/tasks-runner/running-tasks/running-task.d.ts +1 -1
- package/dist/src/tasks-runner/task-env.d.ts +10 -0
- package/dist/src/tasks-runner/task-env.js +37 -5
- package/dist/src/tasks-runner/task-graph-utils.d.ts +9 -6
- package/dist/src/tasks-runner/task-graph-utils.js +17 -12
- package/dist/src/tasks-runner/task-orchestrator.d.ts +62 -18
- package/dist/src/tasks-runner/task-orchestrator.js +750 -150
- package/dist/src/tasks-runner/tasks-runner.d.ts +1 -1
- package/dist/src/tasks-runner/tasks-schedule.d.ts +18 -1
- package/dist/src/tasks-runner/tasks-schedule.js +63 -6
- package/dist/src/tasks-runner/tokens.d.ts +54 -0
- package/dist/src/tasks-runner/tokens.js +161 -0
- package/dist/src/tasks-runner/utils.d.ts +35 -6
- package/dist/src/tasks-runner/utils.js +149 -68
- package/dist/src/ultracache/ci-status.d.ts +24 -0
- package/dist/src/ultracache/ci-status.js +87 -0
- package/dist/src/ultracache/config.d.ts +3 -3
- package/dist/src/ultracache/config.js +4 -4
- package/dist/src/ultracache/fetch.d.ts +2 -0
- package/dist/src/ultracache/fetch.js +1 -0
- package/dist/src/ultracache/overrides.js +4 -0
- package/dist/src/utils/acknowledge-build-scripts.d.ts +34 -1
- package/dist/src/utils/acknowledge-build-scripts.js +171 -32
- package/dist/src/utils/child-process.js +2 -1
- package/dist/src/utils/find-matching-projects.js +9 -6
- package/dist/src/utils/git-utils.d.ts +12 -5
- package/dist/src/utils/git-utils.js +69 -11
- package/dist/src/utils/long-running-target.d.ts +1 -3
- package/dist/src/utils/long-running-target.js +1 -3
- package/dist/src/utils/nx-package-group.js +1 -1
- package/dist/src/utils/output.d.ts +4 -3
- package/dist/src/utils/output.js +4 -3
- package/dist/src/utils/owned-private-dir.d.ts +1 -17
- package/dist/src/utils/owned-private-dir.js +10 -62
- package/dist/src/utils/package-json.js +1 -1
- package/dist/src/utils/package-manager.d.ts +8 -0
- package/dist/src/utils/package-manager.js +65 -8
- package/dist/src/utils/perf-hooks.d.ts +1 -0
- package/dist/src/utils/plugins/core-plugins.js +5 -1
- package/dist/src/utils/progress-topics.d.ts +1 -0
- package/dist/src/utils/progress-topics.js +1 -0
- package/dist/src/utils/safe-spawn.js +1 -5
- package/dist/src/utils/shell-quoting.d.ts +8 -1
- package/dist/src/utils/shell-quoting.js +12 -1
- package/dist/src/utils/spawn-without-terminal.d.ts +27 -0
- package/dist/src/utils/spawn-without-terminal.js +110 -0
- package/dist/src/utils/string-similarity.d.ts +38 -0
- package/dist/src/utils/string-similarity.js +108 -0
- package/dist/src/utils/versions.js +1 -1
- package/migrations.json +20 -6
- package/package.json +15 -24
- package/schemas/migrations-schema.json +11 -0
- package/schemas/nx-schema.json +133 -11
- package/schemas/project-schema.json +114 -4
- package/dist/src/command-line/migrate/agentic/prompts/generic-validation.d.ts +0 -56
- package/dist/src/command-line/migrate/agentic/prompts/generic-validation.js +0 -67
- package/dist/src/command-line/migrate/agentic/prompts/hybrid-prompt-migration.d.ts +0 -49
- package/dist/src/command-line/migrate/agentic/prompts/hybrid-prompt-migration.js +0 -53
- package/dist/src/command-line/migrate/agentic/prompts/prompt-migration.d.ts +0 -26
- package/dist/src/command-line/migrate/agentic/prompts/prompt-migration.js +0 -27
- package/dist/src/command-line/migrate/agentic/prompts/system-prompt.d.ts +0 -70
- package/dist/src/command-line/migrate/agentic/prompts/system-prompt.js +0 -113
- package/dist/src/command-line/migrate/agentic/run-step.d.ts +0 -68
- package/dist/src/command-line/migrate/agentic/run-step.js +0 -148
- package/dist/src/command-line/migrate/agentic/runner.d.ts +0 -21
- package/dist/src/command-line/migrate/agentic/runner.js +0 -262
- package/dist/src/migrations/update-23-0-0/consolidate-release-tag-config.d.ts +0 -9
- package/dist/src/migrations/update-23-0-0/consolidate-release-tag-config.js +0 -18
- package/dist/src/tasks-runner/legacy-depends-on-warning.d.ts +0 -18
- package/dist/src/tasks-runner/legacy-depends-on-warning.js +0 -109
|
@@ -2,14 +2,22 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.DirectoryRefusedError = void 0;
|
|
4
4
|
exports.describeRefusal = describeRefusal;
|
|
5
|
-
exports.remedyFor = remedyFor;
|
|
6
5
|
exports.canonicalDir = canonicalDir;
|
|
7
6
|
exports.isSafeSharedRoot = isSafeSharedRoot;
|
|
8
|
-
exports.isPeerWritable = isPeerWritable;
|
|
9
7
|
exports.ensureSafeSharedRoot = ensureSafeSharedRoot;
|
|
10
8
|
exports.isOwnedRealDirectory = isOwnedRealDirectory;
|
|
11
9
|
exports.getUserSegment = getUserSegment;
|
|
12
10
|
exports.ensureOwnedPrivateDir = ensureOwnedPrivateDir;
|
|
11
|
+
/**
|
|
12
|
+
* Directory guards for Nx's runtime state: create a directory only when it is
|
|
13
|
+
* ours and unreachable by other users on this machine.
|
|
14
|
+
*
|
|
15
|
+
* `native/utils/owned_dir.rs` implements the same rules and must change with
|
|
16
|
+
* this file. This copy exists because the native binding loader has to place
|
|
17
|
+
* and lock down the `.node` before Rust can be called, and `cache-directory.ts`,
|
|
18
|
+
* `git-utils.ts` and `nx-tmp-dir.ts` share it. Node builtins only, for the
|
|
19
|
+
* loader's sake.
|
|
20
|
+
*/
|
|
13
21
|
const node_fs_1 = require("node:fs");
|
|
14
22
|
const node_os_1 = require("node:os");
|
|
15
23
|
const node_path_1 = require("node:path");
|
|
@@ -56,42 +64,6 @@ function describeRefusal(r) {
|
|
|
56
64
|
}
|
|
57
65
|
}
|
|
58
66
|
}
|
|
59
|
-
/** Single-quoted for a shell, so a path with a space or quote survives a paste. */
|
|
60
|
-
const shellQuote = (s) => `'${s.replace(/'/g, `'\\''`)}'`;
|
|
61
|
-
/** What the user can do about a refusal, or `undefined` when there is nothing. */
|
|
62
|
-
function remedyFor(r) {
|
|
63
|
-
switch (r.kind) {
|
|
64
|
-
case 'not-a-directory':
|
|
65
|
-
return r.symlink
|
|
66
|
-
? `${r.dir} is a symlink where Nx expects a directory. If you did not create it, treat it as hostile: remove the link itself (not what it points at) and run the command again.`
|
|
67
|
-
: undefined;
|
|
68
|
-
case 'foreign-owner':
|
|
69
|
-
return `${r.dir} belongs to another user on this machine, so Nx cannot keep its own directory there. Set NX_SOCKET_DIR to a short directory your user owns, or move it aside — which you can do yourself if you own the directory it sits in, and otherwise needs an administrator.`;
|
|
70
|
-
case 'not-tightenable':
|
|
71
|
-
// Both producers reach here having already established that the directory
|
|
72
|
-
// is ours, so `chmod` is the user's to run. Names no cause: one producer
|
|
73
|
-
// is a mount that discards the mode, the other is any `chmod` failure.
|
|
74
|
-
return `${r.dir} is reachable by other users (mode ${asMode(r.mode)}) and Nx could not restrict it. Run \`chmod 0700 ${shellQuote(r.dir)}\` and try again; if the mode does not stick, set NX_SOCKET_DIR to a short directory on a filesystem that keeps POSIX permissions.`;
|
|
75
|
-
case 'foreign-shared-container':
|
|
76
|
-
// Unreachable today: `isSafeSharedRoot` denies with this kind only when
|
|
77
|
-
// `stats.uid !== 0`, so a root-owned container never reaches here.
|
|
78
|
-
if (r.uid === 0) {
|
|
79
|
-
return undefined;
|
|
80
|
-
}
|
|
81
|
-
const q = shellQuote(r.dir);
|
|
82
|
-
return `${r.dir} belongs to another user on this machine, so Nx cannot keep a private directory beneath it. Ask an administrator to hand it to root with \`sudo chown root ${q} && sudo chmod 1777 ${q}\`; every user can then keep their own directory under it.`;
|
|
83
|
-
case 'not-created':
|
|
84
|
-
case 'not-inspectable':
|
|
85
|
-
case 'peer-writable-not-sticky':
|
|
86
|
-
return undefined;
|
|
87
|
-
default: {
|
|
88
|
-
// Matches `describeRefusal`'s arm, so a new kind cannot ship with a
|
|
89
|
-
// sentence and no advice — which is how `not-tightenable` went unadvised.
|
|
90
|
-
const unhandled = r;
|
|
91
|
-
return undefined;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
67
|
/** One refusal as an `Error`, so several can travel in an `AggregateError`. */
|
|
96
68
|
class DirectoryRefusedError extends Error {
|
|
97
69
|
constructor(refusal) {
|
|
@@ -207,30 +179,6 @@ function isSafeSharedRoot(dir) {
|
|
|
207
179
|
return deny({ kind: 'not-inspectable', dir, code: e?.code });
|
|
208
180
|
}
|
|
209
181
|
}
|
|
210
|
-
/**
|
|
211
|
-
* Whether other users on this machine can write into `dir`. Gates whether a
|
|
212
|
-
* refusal message may cite other users, so it must not over-report: `false` on
|
|
213
|
-
* Windows, where libuv synthesizes `st_mode` from the READONLY attribute and
|
|
214
|
-
* reports an ordinary per-account directory as `0666`, and `false` on a path
|
|
215
|
-
* that cannot be inspected.
|
|
216
|
-
*
|
|
217
|
-
* `statSync`, not `lstatSync`: the question is about the directory that will be
|
|
218
|
-
* used, not the link pointing at it. Link modes mislead in both directions —
|
|
219
|
-
* Linux creates symlinks `0777`, macOS applies the umask. Nothing here decides
|
|
220
|
-
* whether a path is accepted, so following the link costs nothing the guards
|
|
221
|
-
* do not already re-check.
|
|
222
|
-
*/
|
|
223
|
-
function isPeerWritable(dir) {
|
|
224
|
-
if (process.platform === 'win32') {
|
|
225
|
-
return false;
|
|
226
|
-
}
|
|
227
|
-
try {
|
|
228
|
-
return !!((0, node_fs_1.statSync)(dir).mode & 0o022);
|
|
229
|
-
}
|
|
230
|
-
catch {
|
|
231
|
-
return false;
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
182
|
/**
|
|
235
183
|
* Create a shared container as sticky + world-writable if it does not exist,
|
|
236
184
|
* and report whether the resulting path is safe for the current user.
|
|
@@ -231,7 +231,7 @@ function readModulePackageJson(moduleSpecifier, requirePaths = (0, installation_
|
|
|
231
231
|
* path instead of the workspace path.
|
|
232
232
|
*
|
|
233
233
|
* 2. Package self-reference. When a file inside package `nx` calls
|
|
234
|
-
* `require.resolve('
|
|
234
|
+
* `require.resolve('nx/...')`, Node returns that calling package's
|
|
235
235
|
* own file regardless of `paths`. We avoid that by issuing the
|
|
236
236
|
* resolve from a `createRequire` rooted at a synthetic path that is
|
|
237
237
|
* outside any package, so the resolver has no "self" to reference
|
|
@@ -13,7 +13,15 @@ export interface PackageManagerCommands {
|
|
|
13
13
|
why: string;
|
|
14
14
|
run: (script: string, args?: string) => string;
|
|
15
15
|
getRegistryUrl?: string;
|
|
16
|
+
/**
|
|
17
|
+
* @deprecated Use `publishArgv` instead, which needs no shell off Windows.
|
|
18
|
+
* This will be removed in Nx 25.
|
|
19
|
+
*/
|
|
16
20
|
publish: (packageRoot: string, registry: string, registryConfigKey: string, tag: string) => string;
|
|
21
|
+
publishArgv: (packageRoot: string, registry: string, registryConfigKey: string, tag: string) => {
|
|
22
|
+
command: string;
|
|
23
|
+
args: string[];
|
|
24
|
+
};
|
|
17
25
|
ignoreScriptsFlag?: string;
|
|
18
26
|
}
|
|
19
27
|
/**
|
|
@@ -23,6 +23,7 @@ exports.addPackagePathToWorkspaces = addPackagePathToWorkspaces;
|
|
|
23
23
|
const child_process_1 = require("child_process");
|
|
24
24
|
const fs_1 = require("fs");
|
|
25
25
|
const promises_1 = require("node:fs/promises");
|
|
26
|
+
const node_os_1 = require("node:os");
|
|
26
27
|
const path_1 = require("path");
|
|
27
28
|
const semver_1 = require("semver");
|
|
28
29
|
const tmp_1 = require("tmp");
|
|
@@ -124,6 +125,13 @@ function isWorkspacesEnabled(packageManager = detectPackageManager(), root = wor
|
|
|
124
125
|
const packageJson = (0, file_utils_1.readPackageJson)(root);
|
|
125
126
|
return !!packageJson?.workspaces;
|
|
126
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* The registry and tag reach `publish` from `.npmrc`, which an install script
|
|
130
|
+
* can write, so every token is quoted before it becomes shell syntax.
|
|
131
|
+
*/
|
|
132
|
+
function publishCommandFromArgv({ command, args, }) {
|
|
133
|
+
return [command, ...args].map(shell_quoting_1.quoteShellArg).join(' ');
|
|
134
|
+
}
|
|
127
135
|
/**
|
|
128
136
|
* Returns commands for the package manager used in the workspace.
|
|
129
137
|
* By default, the package manager is derived based on the lock file,
|
|
@@ -150,6 +158,16 @@ function getPackageManagerCommand(packageManager = detectPackageManager(), root
|
|
|
150
158
|
yarnVersion = 'latest';
|
|
151
159
|
useBerry = true;
|
|
152
160
|
}
|
|
161
|
+
const publishArgv = (packageRoot, registry, registryConfigKey, tag) => ({
|
|
162
|
+
command: 'npm',
|
|
163
|
+
args: [
|
|
164
|
+
'publish',
|
|
165
|
+
packageRoot,
|
|
166
|
+
'--json',
|
|
167
|
+
`--${registryConfigKey}=${registry}`,
|
|
168
|
+
`--tag=${tag}`,
|
|
169
|
+
],
|
|
170
|
+
});
|
|
153
171
|
// new versions of yarn only support ignoring scripts via .yarnrc.yml
|
|
154
172
|
return {
|
|
155
173
|
preInstall: `yarn set version ${yarnVersion}`,
|
|
@@ -171,7 +189,8 @@ function getPackageManagerCommand(packageManager = detectPackageManager(), root
|
|
|
171
189
|
getRegistryUrl: useBerry
|
|
172
190
|
? 'yarn config get npmRegistryServer'
|
|
173
191
|
: 'yarn config get registry',
|
|
174
|
-
publish: (
|
|
192
|
+
publish: (...args) => publishCommandFromArgv(publishArgv(...args)),
|
|
193
|
+
publishArgv,
|
|
175
194
|
ignoreScriptsFlag: useBerry ? undefined : `--ignore-scripts`,
|
|
176
195
|
};
|
|
177
196
|
},
|
|
@@ -194,6 +213,21 @@ function getPackageManagerCommand(packageManager = detectPackageManager(), root
|
|
|
194
213
|
scopedForm = false;
|
|
195
214
|
}
|
|
196
215
|
const isPnpmWorkspace = (0, fs_1.existsSync)((0, path_1.join)(root, 'pnpm-workspace.yaml'));
|
|
216
|
+
const publishArgv = (packageRoot, registry, registryConfigKey, tag) => ({
|
|
217
|
+
command: 'pnpm',
|
|
218
|
+
args: [
|
|
219
|
+
'publish',
|
|
220
|
+
packageRoot,
|
|
221
|
+
'--json',
|
|
222
|
+
`--${configForm
|
|
223
|
+
? `config.${registryConfigKey}`
|
|
224
|
+
: scopedForm
|
|
225
|
+
? registryConfigKey
|
|
226
|
+
: 'registry'}=${registry}`,
|
|
227
|
+
`--tag=${tag}`,
|
|
228
|
+
'--no-git-checks',
|
|
229
|
+
],
|
|
230
|
+
});
|
|
197
231
|
return {
|
|
198
232
|
install: 'pnpm install --no-frozen-lockfile', // explicitly disable in case of CI
|
|
199
233
|
ciInstall: 'pnpm install --frozen-lockfile',
|
|
@@ -215,15 +249,22 @@ function getPackageManagerCommand(packageManager = detectPackageManager(), root
|
|
|
215
249
|
list: 'pnpm ls --depth 100',
|
|
216
250
|
why: 'pnpm why',
|
|
217
251
|
getRegistryUrl: 'pnpm config get registry',
|
|
218
|
-
publish: (
|
|
219
|
-
|
|
220
|
-
: scopedForm
|
|
221
|
-
? registryConfigKey
|
|
222
|
-
: 'registry'}=${registry}" --tag=${tag} --no-git-checks`,
|
|
252
|
+
publish: (...args) => publishCommandFromArgv(publishArgv(...args)),
|
|
253
|
+
publishArgv,
|
|
223
254
|
ignoreScriptsFlag: '--ignore-scripts',
|
|
224
255
|
};
|
|
225
256
|
},
|
|
226
257
|
npm: () => {
|
|
258
|
+
const publishArgv = (packageRoot, registry, registryConfigKey, tag) => ({
|
|
259
|
+
command: 'npm',
|
|
260
|
+
args: [
|
|
261
|
+
'publish',
|
|
262
|
+
packageRoot,
|
|
263
|
+
'--json',
|
|
264
|
+
`--${registryConfigKey}=${registry}`,
|
|
265
|
+
`--tag=${tag}`,
|
|
266
|
+
],
|
|
267
|
+
});
|
|
227
268
|
return {
|
|
228
269
|
install: 'npm install',
|
|
229
270
|
ciInstall: 'npm ci',
|
|
@@ -237,11 +278,22 @@ function getPackageManagerCommand(packageManager = detectPackageManager(), root
|
|
|
237
278
|
list: 'npm ls',
|
|
238
279
|
why: 'npm explain',
|
|
239
280
|
getRegistryUrl: 'npm config get registry',
|
|
240
|
-
publish: (
|
|
281
|
+
publish: (...args) => publishCommandFromArgv(publishArgv(...args)),
|
|
282
|
+
publishArgv,
|
|
241
283
|
ignoreScriptsFlag: '--ignore-scripts',
|
|
242
284
|
};
|
|
243
285
|
},
|
|
244
286
|
bun: () => {
|
|
287
|
+
const publishArgv = (packageRoot, registry, _registryConfigKey, tag) => ({
|
|
288
|
+
command: 'bun',
|
|
289
|
+
args: [
|
|
290
|
+
'publish',
|
|
291
|
+
`--cwd=${packageRoot}`,
|
|
292
|
+
'--json',
|
|
293
|
+
`--registry=${registry}`,
|
|
294
|
+
`--tag=${tag}`,
|
|
295
|
+
],
|
|
296
|
+
});
|
|
245
297
|
// bun doesn't current support programmatically reading config https://github.com/oven-sh/bun/issues/7140
|
|
246
298
|
return {
|
|
247
299
|
install: 'bun install',
|
|
@@ -256,7 +308,8 @@ function getPackageManagerCommand(packageManager = detectPackageManager(), root
|
|
|
256
308
|
list: 'bun pm ls',
|
|
257
309
|
why: 'bun why',
|
|
258
310
|
// Unlike npm, bun publish does not support a custom registryConfigKey option
|
|
259
|
-
publish: (
|
|
311
|
+
publish: (...args) => publishCommandFromArgv(publishArgv(...args)),
|
|
312
|
+
publishArgv,
|
|
260
313
|
ignoreScriptsFlag: '--ignore-scripts',
|
|
261
314
|
};
|
|
262
315
|
},
|
|
@@ -283,6 +336,10 @@ function getPackageManagerVersion(packageManager = detectPackageManager(), cwd =
|
|
|
283
336
|
cwd,
|
|
284
337
|
encoding: 'utf-8',
|
|
285
338
|
windowsHide: true,
|
|
339
|
+
// Store discovery creates temporary workspace files even for --version.
|
|
340
|
+
env: packageManager === 'pnpm'
|
|
341
|
+
? { ...process.env, PNPM_CONFIG_STORE_DIR: (0, node_os_1.tmpdir)() }
|
|
342
|
+
: undefined,
|
|
286
343
|
}).trim();
|
|
287
344
|
}
|
|
288
345
|
catch { }
|
|
@@ -25,9 +25,6 @@ function needsShell(binary) {
|
|
|
25
25
|
const ext = path_1.win32.extname(binary).toLowerCase();
|
|
26
26
|
return ext === '' || ext === '.cmd' || ext === '.bat';
|
|
27
27
|
}
|
|
28
|
-
// A line break ends the command line whatever the quoting, so nothing can carry
|
|
29
|
-
// one.
|
|
30
|
-
//
|
|
31
28
|
// `%` is deliberately NOT refused, and this is a known gap rather than a safe
|
|
32
29
|
// case. cmd.exe expands `%VAR%` whether or not the value is quoted — see
|
|
33
30
|
// `quoteShellArg`'s own docstring in ./shell-quoting, which says so and pins it
|
|
@@ -42,7 +39,6 @@ function needsShell(binary) {
|
|
|
42
39
|
// is bounded by the argument that bounds this whole class: a repo that can reach
|
|
43
40
|
// here already has `mvnw` / `pom.xml` executing on its behalf. Closing it
|
|
44
41
|
// properly is tracked as NXC-4798.
|
|
45
|
-
const LINE_BREAK = /[\r\n]/;
|
|
46
42
|
/**
|
|
47
43
|
* Spawn a binary that may be a Windows `.cmd`/`.bat` shim, without letting its
|
|
48
44
|
* arguments become shell syntax.
|
|
@@ -91,7 +87,7 @@ function quoteBinary(binary, shell) {
|
|
|
91
87
|
return quoteForCmd(binary, `the path ${JSON.stringify(binary)}`);
|
|
92
88
|
}
|
|
93
89
|
function quoteForCmd(value, described, remedy = '') {
|
|
94
|
-
if (LINE_BREAK.test(value)) {
|
|
90
|
+
if (shell_quoting_1.LINE_BREAK.test(value)) {
|
|
95
91
|
throw new Error(`Cannot pass ${described} to cmd.exe: a line break inside it would end the command line before cmd.exe reached the rest of it.${remedy}`);
|
|
96
92
|
}
|
|
97
93
|
return (0, shell_quoting_1.quoteShellArg)(value);
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A line break ends a cmd.exe command line whatever the quoting, so no quoted
|
|
3
|
+
* run can carry one. POSIX single quotes hold a newline fine, which is why the
|
|
4
|
+
* refusal in `quoteShellArg` is Windows-only.
|
|
5
|
+
*/
|
|
6
|
+
export declare const LINE_BREAK: RegExp;
|
|
1
7
|
/**
|
|
2
8
|
* Check if a string contains shell metacharacters that require quoting.
|
|
3
9
|
* These characters have special meaning in shell and would be interpreted
|
|
@@ -20,6 +26,7 @@ export declare function isAlreadyQuoted(str: string): boolean;
|
|
|
20
26
|
* @throws on Windows when the argument contains a double quote, which ends that
|
|
21
27
|
* run, since cmd.exe recognizes no backslash escape. Carrying one means
|
|
22
28
|
* caret-escaping every metacharacter instead, doubled for a `.cmd` shim, which
|
|
23
|
-
* this path does not implement.
|
|
29
|
+
* this path does not implement. Also throws on a line break, which ends the
|
|
30
|
+
* command line itself and so survives no quoting at all.
|
|
24
31
|
*/
|
|
25
32
|
export declare function quoteShellArg(arg: string): string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LINE_BREAK = void 0;
|
|
3
4
|
exports.needsShellQuoting = needsShellQuoting;
|
|
4
5
|
exports.isAlreadyQuoted = isAlreadyQuoted;
|
|
5
6
|
exports.quoteShellArg = quoteShellArg;
|
|
@@ -24,6 +25,12 @@ exports.quoteShellArg = quoteShellArg;
|
|
|
24
25
|
* - \s - whitespace (spaces, tabs, newlines)
|
|
25
26
|
*/
|
|
26
27
|
const SHELL_META_CHARS = /[|&;<>()$`\\!"'*?[\]{}~#\s]/;
|
|
28
|
+
/**
|
|
29
|
+
* A line break ends a cmd.exe command line whatever the quoting, so no quoted
|
|
30
|
+
* run can carry one. POSIX single quotes hold a newline fine, which is why the
|
|
31
|
+
* refusal in `quoteShellArg` is Windows-only.
|
|
32
|
+
*/
|
|
33
|
+
exports.LINE_BREAK = /[\r\n]/;
|
|
27
34
|
/**
|
|
28
35
|
* Check if a string contains shell metacharacters that require quoting.
|
|
29
36
|
* These characters have special meaning in shell and would be interpreted
|
|
@@ -52,10 +59,14 @@ function isAlreadyQuoted(str) {
|
|
|
52
59
|
* @throws on Windows when the argument contains a double quote, which ends that
|
|
53
60
|
* run, since cmd.exe recognizes no backslash escape. Carrying one means
|
|
54
61
|
* caret-escaping every metacharacter instead, doubled for a `.cmd` shim, which
|
|
55
|
-
* this path does not implement.
|
|
62
|
+
* this path does not implement. Also throws on a line break, which ends the
|
|
63
|
+
* command line itself and so survives no quoting at all.
|
|
56
64
|
*/
|
|
57
65
|
function quoteShellArg(arg) {
|
|
58
66
|
const isWindows = process.platform === 'win32';
|
|
67
|
+
if (isWindows && exports.LINE_BREAK.test(arg)) {
|
|
68
|
+
throw new Error(`Cannot safely pass ${arg} to cmd.exe as a single argument: a line break inside it would end the command line and leave the rest of the argument to be read as commands. Remove the line break and run the command again.`);
|
|
69
|
+
}
|
|
59
70
|
if (isWindows && arg.includes('"')) {
|
|
60
71
|
throw new Error(`Cannot safely pass ${arg} to cmd.exe as a single argument: a double quote inside it would end the quoting and leave the rest of the argument to be read as commands. Remove the double quote and run the command again.`);
|
|
61
72
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type ChildProcess, type SpawnOptions } from 'child_process';
|
|
2
|
+
/**
|
|
3
|
+
* Runs `command` in a shell that cannot reach the terminal nx shares with
|
|
4
|
+
* another program, so a prompt fails instead of waiting for keys that program
|
|
5
|
+
* reads. On POSIX the shell leads a new session with no controlling terminal,
|
|
6
|
+
* and loses every environment variable that names nx's terminal. Windows
|
|
7
|
+
* spawns it as usual, and with no stdio inherited it gets no console, so the
|
|
8
|
+
* terminal's Ctrl+C misses it there too. Whoever shares the terminal forwards
|
|
9
|
+
* signals with `signalCommandsWithoutTerminal`, and an nx that exits first
|
|
10
|
+
* kills each command whose output is still open.
|
|
11
|
+
*/
|
|
12
|
+
export declare function spawnWithoutTerminal(command: string, options: Omit<SpawnOptions, 'shell' | 'detached'>): ChildProcess;
|
|
13
|
+
/**
|
|
14
|
+
* Sends `signal` to every command started by `spawnWithoutTerminal` whose
|
|
15
|
+
* output is still open: to its process group on POSIX, and on a SIGKILL also to
|
|
16
|
+
* the processes still descending from its shell, since a parent killed outright
|
|
17
|
+
* cannot stop the ones it started in groups of their own. Windows has no
|
|
18
|
+
* process groups, so there those descendants are terminated, whatever the
|
|
19
|
+
* signal.
|
|
20
|
+
*/
|
|
21
|
+
export declare function signalCommandsWithoutTerminal(signal: NodeJS.Signals): void;
|
|
22
|
+
/**
|
|
23
|
+
* `env` without the variables whose value is the path of one of `terminals`
|
|
24
|
+
* (device ids). A process outside the new session, such as gpg-agent reading
|
|
25
|
+
* `GPG_TTY`, would otherwise open that terminal itself.
|
|
26
|
+
*/
|
|
27
|
+
export declare function withoutTerminalPaths(env: NodeJS.ProcessEnv, terminals: ReadonlySet<number>): NodeJS.ProcessEnv;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.spawnWithoutTerminal = spawnWithoutTerminal;
|
|
4
|
+
exports.signalCommandsWithoutTerminal = signalCommandsWithoutTerminal;
|
|
5
|
+
exports.withoutTerminalPaths = withoutTerminalPaths;
|
|
6
|
+
const child_process_1 = require("child_process");
|
|
7
|
+
const fs_1 = require("fs");
|
|
8
|
+
const tty_1 = require("tty");
|
|
9
|
+
// The commands spawned below whose output is still open, by pid. On POSIX each
|
|
10
|
+
// one leads its own process group.
|
|
11
|
+
const commands = new Map();
|
|
12
|
+
/**
|
|
13
|
+
* Runs `command` in a shell that cannot reach the terminal nx shares with
|
|
14
|
+
* another program, so a prompt fails instead of waiting for keys that program
|
|
15
|
+
* reads. On POSIX the shell leads a new session with no controlling terminal,
|
|
16
|
+
* and loses every environment variable that names nx's terminal. Windows
|
|
17
|
+
* spawns it as usual, and with no stdio inherited it gets no console, so the
|
|
18
|
+
* terminal's Ctrl+C misses it there too. Whoever shares the terminal forwards
|
|
19
|
+
* signals with `signalCommandsWithoutTerminal`, and an nx that exits first
|
|
20
|
+
* kills each command whose output is still open.
|
|
21
|
+
*/
|
|
22
|
+
function spawnWithoutTerminal(command, options) {
|
|
23
|
+
const child = (0, child_process_1.spawn)(command, {
|
|
24
|
+
...options,
|
|
25
|
+
shell: true,
|
|
26
|
+
windowsHide: true,
|
|
27
|
+
detached: process.platform !== 'win32',
|
|
28
|
+
...(process.platform !== 'win32' && {
|
|
29
|
+
env: withoutTerminalPaths(options.env ?? process.env, stdioTerminals()),
|
|
30
|
+
}),
|
|
31
|
+
});
|
|
32
|
+
const pid = child.pid;
|
|
33
|
+
if (pid !== undefined) {
|
|
34
|
+
if (commands.size === 0)
|
|
35
|
+
process.on('exit', killCommands);
|
|
36
|
+
commands.set(pid, child);
|
|
37
|
+
child.once('close', () => {
|
|
38
|
+
commands.delete(pid);
|
|
39
|
+
if (commands.size === 0)
|
|
40
|
+
process.removeListener('exit', killCommands);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
return child;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Sends `signal` to every command started by `spawnWithoutTerminal` whose
|
|
47
|
+
* output is still open: to its process group on POSIX, and on a SIGKILL also to
|
|
48
|
+
* the processes still descending from its shell, since a parent killed outright
|
|
49
|
+
* cannot stop the ones it started in groups of their own. Windows has no
|
|
50
|
+
* process groups, so there those descendants are terminated, whatever the
|
|
51
|
+
* signal.
|
|
52
|
+
*/
|
|
53
|
+
function signalCommandsWithoutTerminal(signal) {
|
|
54
|
+
for (const [pid, child] of commands) {
|
|
55
|
+
// Tree first: killing the group reparents its members' children.
|
|
56
|
+
if (process.platform === 'win32' || signal === 'SIGKILL') {
|
|
57
|
+
killTree(child, pid, signal);
|
|
58
|
+
}
|
|
59
|
+
if (process.platform !== 'win32') {
|
|
60
|
+
try {
|
|
61
|
+
process.kill(-pid, signal);
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// The command already ended; its `close` is on the way.
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Only while the shell lives: once it has exited, its pid can be reused.
|
|
70
|
+
function killTree(child, pid, signal) {
|
|
71
|
+
if (child.exitCode !== null || child.signalCode !== null)
|
|
72
|
+
return;
|
|
73
|
+
try {
|
|
74
|
+
const { killProcessTree } = require('../native');
|
|
75
|
+
killProcessTree(pid, signal);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// No native killer in this build; on POSIX the group signal still goes out.
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function killCommands() {
|
|
82
|
+
signalCommandsWithoutTerminal('SIGKILL');
|
|
83
|
+
}
|
|
84
|
+
function stdioTerminals() {
|
|
85
|
+
const devices = new Set();
|
|
86
|
+
for (const fd of [0, 1, 2]) {
|
|
87
|
+
if ((0, tty_1.isatty)(fd))
|
|
88
|
+
devices.add((0, fs_1.fstatSync)(fd).rdev);
|
|
89
|
+
}
|
|
90
|
+
return devices;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* `env` without the variables whose value is the path of one of `terminals`
|
|
94
|
+
* (device ids). A process outside the new session, such as gpg-agent reading
|
|
95
|
+
* `GPG_TTY`, would otherwise open that terminal itself.
|
|
96
|
+
*/
|
|
97
|
+
function withoutTerminalPaths(env, terminals) {
|
|
98
|
+
return Object.fromEntries(Object.entries(env).filter(([, value]) => !namesTerminal(value, terminals)));
|
|
99
|
+
}
|
|
100
|
+
function namesTerminal(value, terminals) {
|
|
101
|
+
if (!value?.startsWith('/dev/'))
|
|
102
|
+
return false;
|
|
103
|
+
try {
|
|
104
|
+
const stat = (0, fs_1.statSync)(value);
|
|
105
|
+
return stat.isCharacterDevice() && terminals.has(stat.rdev);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Computes the Levenshtein edit distance between two strings, i.e. the minimum
|
|
3
|
+
* number of single-character insertions, deletions, or substitutions required
|
|
4
|
+
* to turn `a` into `b`.
|
|
5
|
+
*/
|
|
6
|
+
export declare function levenshteinDistance(a: string, b: string): number;
|
|
7
|
+
/**
|
|
8
|
+
* Ranks every candidate by how closely it resembles `input`, from closest to
|
|
9
|
+
* furthest, tie-broken alphabetically so the order is deterministic. Each entry
|
|
10
|
+
* keeps its computed distance so callers can reuse it (e.g. to both pick the
|
|
11
|
+
* closest match and order a list) without recomputing.
|
|
12
|
+
*/
|
|
13
|
+
export declare function rankByDistance(input: string, candidates: readonly string[]): {
|
|
14
|
+
candidate: string;
|
|
15
|
+
distance: number;
|
|
16
|
+
}[];
|
|
17
|
+
/**
|
|
18
|
+
* Whether a candidate at edit `distance` from `input` is close enough to be a
|
|
19
|
+
* useful suggestion. Exposed so callers that already have a distance (e.g. from
|
|
20
|
+
* `rankByDistance`) can gate on it without recomputing.
|
|
21
|
+
*/
|
|
22
|
+
export declare function isWithinSuggestionThreshold(input: string, candidate: string, distance: number): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Ranks the candidates that are similar enough to `input` to be worth
|
|
25
|
+
* suggesting, closest first (ties broken alphabetically). Each entry keeps its
|
|
26
|
+
* distance so callers can compare suggestions found for different forms of the
|
|
27
|
+
* same input without recomputing.
|
|
28
|
+
*/
|
|
29
|
+
export declare function rankSuggestions(input: string, candidates: readonly string[]): {
|
|
30
|
+
candidate: string;
|
|
31
|
+
distance: number;
|
|
32
|
+
}[];
|
|
33
|
+
/**
|
|
34
|
+
* Returns up to `limit` candidates that most closely resemble `input`, sorted
|
|
35
|
+
* from closest to furthest. Candidates that are not similar enough to be a
|
|
36
|
+
* useful suggestion are excluded.
|
|
37
|
+
*/
|
|
38
|
+
export declare function findClosestMatches(input: string, candidates: readonly string[], limit?: number): string[];
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.levenshteinDistance = levenshteinDistance;
|
|
4
|
+
exports.rankByDistance = rankByDistance;
|
|
5
|
+
exports.isWithinSuggestionThreshold = isWithinSuggestionThreshold;
|
|
6
|
+
exports.rankSuggestions = rankSuggestions;
|
|
7
|
+
exports.findClosestMatches = findClosestMatches;
|
|
8
|
+
/**
|
|
9
|
+
* Computes the Levenshtein edit distance between two strings, i.e. the minimum
|
|
10
|
+
* number of single-character insertions, deletions, or substitutions required
|
|
11
|
+
* to turn `a` into `b`.
|
|
12
|
+
*/
|
|
13
|
+
function levenshteinDistance(a, b) {
|
|
14
|
+
if (a === b) {
|
|
15
|
+
return 0;
|
|
16
|
+
}
|
|
17
|
+
if (a.length === 0) {
|
|
18
|
+
return b.length;
|
|
19
|
+
}
|
|
20
|
+
if (b.length === 0) {
|
|
21
|
+
return a.length;
|
|
22
|
+
}
|
|
23
|
+
let previousRow = Array.from({ length: b.length + 1 }, (_, i) => i);
|
|
24
|
+
let currentRow = new Array(b.length + 1);
|
|
25
|
+
for (let i = 0; i < a.length; i++) {
|
|
26
|
+
currentRow[0] = i + 1;
|
|
27
|
+
for (let j = 0; j < b.length; j++) {
|
|
28
|
+
const cost = a[i] === b[j] ? 0 : 1;
|
|
29
|
+
currentRow[j + 1] = Math.min(currentRow[j] + 1, // insertion
|
|
30
|
+
previousRow[j + 1] + 1, // deletion
|
|
31
|
+
previousRow[j] + cost // substitution
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
[previousRow, currentRow] = [currentRow, previousRow];
|
|
35
|
+
}
|
|
36
|
+
return previousRow[b.length];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Ranks every candidate by how closely it resembles `input`, from closest to
|
|
40
|
+
* furthest, tie-broken alphabetically so the order is deterministic. Each entry
|
|
41
|
+
* keeps its computed distance so callers can reuse it (e.g. to both pick the
|
|
42
|
+
* closest match and order a list) without recomputing.
|
|
43
|
+
*/
|
|
44
|
+
function rankByDistance(input, candidates) {
|
|
45
|
+
return candidates
|
|
46
|
+
.map((candidate) => ({
|
|
47
|
+
candidate,
|
|
48
|
+
distance: levenshteinDistance(input, candidate),
|
|
49
|
+
}))
|
|
50
|
+
.sort((a, b) => a.distance - b.distance || a.candidate.localeCompare(b.candidate));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The number of edits tolerated before `candidate` stops being a useful
|
|
54
|
+
* suggestion for `input`.
|
|
55
|
+
*
|
|
56
|
+
* The tolerance scales with length so longer words allow for more typos, but it
|
|
57
|
+
* scales with the length of the part that actually *differs* — the shared
|
|
58
|
+
* prefix and suffix are stripped first. Scaling on the raw length lets text the
|
|
59
|
+
* user typed correctly buy a bigger budget for the part they got wrong, which
|
|
60
|
+
* matters because these inputs are joined `project:target[:configuration]`
|
|
61
|
+
* specifiers: `zzz:build` and `api:build` are 3 edits apart, but the shared
|
|
62
|
+
* `:build` inflates the raw-length budget to 4 and a project name with no
|
|
63
|
+
* character in common gets suggested.
|
|
64
|
+
*
|
|
65
|
+
* Stripping a common prefix and suffix does not change the Levenshtein
|
|
66
|
+
* distance, so a caller's precomputed `distance` remains directly comparable.
|
|
67
|
+
*/
|
|
68
|
+
function suggestionThreshold(input, candidate) {
|
|
69
|
+
const shortest = Math.min(input.length, candidate.length);
|
|
70
|
+
let prefix = 0;
|
|
71
|
+
while (prefix < shortest && input[prefix] === candidate[prefix]) {
|
|
72
|
+
prefix++;
|
|
73
|
+
}
|
|
74
|
+
let suffix = 0;
|
|
75
|
+
while (suffix < shortest - prefix &&
|
|
76
|
+
input[input.length - 1 - suffix] ===
|
|
77
|
+
candidate[candidate.length - 1 - suffix]) {
|
|
78
|
+
suffix++;
|
|
79
|
+
}
|
|
80
|
+
return Math.max(2, Math.ceil((input.length - prefix - suffix) * 0.4));
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Whether a candidate at edit `distance` from `input` is close enough to be a
|
|
84
|
+
* useful suggestion. Exposed so callers that already have a distance (e.g. from
|
|
85
|
+
* `rankByDistance`) can gate on it without recomputing.
|
|
86
|
+
*/
|
|
87
|
+
function isWithinSuggestionThreshold(input, candidate, distance) {
|
|
88
|
+
return distance <= suggestionThreshold(input, candidate);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Ranks the candidates that are similar enough to `input` to be worth
|
|
92
|
+
* suggesting, closest first (ties broken alphabetically). Each entry keeps its
|
|
93
|
+
* distance so callers can compare suggestions found for different forms of the
|
|
94
|
+
* same input without recomputing.
|
|
95
|
+
*/
|
|
96
|
+
function rankSuggestions(input, candidates) {
|
|
97
|
+
return rankByDistance(input, candidates).filter(({ candidate, distance }) => isWithinSuggestionThreshold(input, candidate, distance));
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Returns up to `limit` candidates that most closely resemble `input`, sorted
|
|
101
|
+
* from closest to furthest. Candidates that are not similar enough to be a
|
|
102
|
+
* useful suggestion are excluded.
|
|
103
|
+
*/
|
|
104
|
+
function findClosestMatches(input, candidates, limit = 3) {
|
|
105
|
+
return rankSuggestions(input, candidates)
|
|
106
|
+
.slice(0, limit)
|
|
107
|
+
.map(({ candidate }) => candidate);
|
|
108
|
+
}
|