opensip-cli 0.1.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/LICENSE +202 -0
- package/NOTICE +8 -0
- package/README.md +51 -0
- package/dist/api.d.ts +17 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +16 -0
- package/dist/api.js.map +1 -0
- package/dist/bootstrap/admit-tool-package.d.ts +117 -0
- package/dist/bootstrap/admit-tool-package.d.ts.map +1 -0
- package/dist/bootstrap/admit-tool-package.js +170 -0
- package/dist/bootstrap/admit-tool-package.js.map +1 -0
- package/dist/bootstrap/baseline-seams.d.ts +30 -0
- package/dist/bootstrap/baseline-seams.d.ts.map +1 -0
- package/dist/bootstrap/baseline-seams.js +156 -0
- package/dist/bootstrap/baseline-seams.js.map +1 -0
- package/dist/bootstrap/bootstrap-error.d.ts +41 -0
- package/dist/bootstrap/bootstrap-error.d.ts.map +1 -0
- package/dist/bootstrap/bootstrap-error.js +33 -0
- package/dist/bootstrap/bootstrap-error.js.map +1 -0
- package/dist/bootstrap/build-command-registration-input.d.ts +34 -0
- package/dist/bootstrap/build-command-registration-input.d.ts.map +1 -0
- package/dist/bootstrap/build-command-registration-input.js +73 -0
- package/dist/bootstrap/build-command-registration-input.js.map +1 -0
- package/dist/bootstrap/build-per-run-scope.d.ts +62 -0
- package/dist/bootstrap/build-per-run-scope.d.ts.map +1 -0
- package/dist/bootstrap/build-per-run-scope.js +152 -0
- package/dist/bootstrap/build-per-run-scope.js.map +1 -0
- package/dist/bootstrap/build-targets.d.ts +42 -0
- package/dist/bootstrap/build-targets.d.ts.map +1 -0
- package/dist/bootstrap/build-targets.js +117 -0
- package/dist/bootstrap/build-targets.js.map +1 -0
- package/dist/bootstrap/cli-defaults.d.ts +35 -0
- package/dist/bootstrap/cli-defaults.d.ts.map +1 -0
- package/dist/bootstrap/cli-defaults.js +65 -0
- package/dist/bootstrap/cli-defaults.js.map +1 -0
- package/dist/bootstrap/config-and-capabilities.d.ts +74 -0
- package/dist/bootstrap/config-and-capabilities.d.ts.map +1 -0
- package/dist/bootstrap/config-and-capabilities.js +224 -0
- package/dist/bootstrap/config-and-capabilities.js.map +1 -0
- package/dist/bootstrap/deliver-envelope.d.ts +80 -0
- package/dist/bootstrap/deliver-envelope.d.ts.map +1 -0
- package/dist/bootstrap/deliver-envelope.js +195 -0
- package/dist/bootstrap/deliver-envelope.js.map +1 -0
- package/dist/bootstrap/egress-plane.d.ts +22 -0
- package/dist/bootstrap/egress-plane.d.ts.map +1 -0
- package/dist/bootstrap/egress-plane.js +37 -0
- package/dist/bootstrap/egress-plane.js.map +1 -0
- package/dist/bootstrap/host-planes.d.ts +28 -0
- package/dist/bootstrap/host-planes.d.ts.map +1 -0
- package/dist/bootstrap/host-planes.js +152 -0
- package/dist/bootstrap/host-planes.js.map +1 -0
- package/dist/bootstrap/index.d.ts +76 -0
- package/dist/bootstrap/index.d.ts.map +1 -0
- package/dist/bootstrap/index.js +109 -0
- package/dist/bootstrap/index.js.map +1 -0
- package/dist/bootstrap/live-plane.d.ts +51 -0
- package/dist/bootstrap/live-plane.d.ts.map +1 -0
- package/dist/bootstrap/live-plane.js +72 -0
- package/dist/bootstrap/live-plane.js.map +1 -0
- package/dist/bootstrap/load-tool-capabilities.d.ts +42 -0
- package/dist/bootstrap/load-tool-capabilities.d.ts.map +1 -0
- package/dist/bootstrap/load-tool-capabilities.js +76 -0
- package/dist/bootstrap/load-tool-capabilities.js.map +1 -0
- package/dist/bootstrap/output-plane.d.ts +37 -0
- package/dist/bootstrap/output-plane.d.ts.map +1 -0
- package/dist/bootstrap/output-plane.js +114 -0
- package/dist/bootstrap/output-plane.js.map +1 -0
- package/dist/bootstrap/owning-tool-init.d.ts +32 -0
- package/dist/bootstrap/owning-tool-init.d.ts.map +1 -0
- package/dist/bootstrap/owning-tool-init.js +69 -0
- package/dist/bootstrap/owning-tool-init.js.map +1 -0
- package/dist/bootstrap/pre-action-guards.d.ts +44 -0
- package/dist/bootstrap/pre-action-guards.d.ts.map +1 -0
- package/dist/bootstrap/pre-action-guards.js +136 -0
- package/dist/bootstrap/pre-action-guards.js.map +1 -0
- package/dist/bootstrap/pre-action-hook.d.ts +68 -0
- package/dist/bootstrap/pre-action-hook.d.ts.map +1 -0
- package/dist/bootstrap/pre-action-hook.js +289 -0
- package/dist/bootstrap/pre-action-hook.js.map +1 -0
- package/dist/bootstrap/pre-action-messages.d.ts +32 -0
- package/dist/bootstrap/pre-action-messages.d.ts.map +1 -0
- package/dist/bootstrap/pre-action-messages.js +49 -0
- package/dist/bootstrap/pre-action-messages.js.map +1 -0
- package/dist/bootstrap/process-idempotency.d.ts +17 -0
- package/dist/bootstrap/process-idempotency.d.ts.map +1 -0
- package/dist/bootstrap/process-idempotency.js +20 -0
- package/dist/bootstrap/process-idempotency.js.map +1 -0
- package/dist/bootstrap/register-language-adapters.d.ts +23 -0
- package/dist/bootstrap/register-language-adapters.d.ts.map +1 -0
- package/dist/bootstrap/register-language-adapters.js +35 -0
- package/dist/bootstrap/register-language-adapters.js.map +1 -0
- package/dist/bootstrap/register-tools.d.ts +228 -0
- package/dist/bootstrap/register-tools.d.ts.map +1 -0
- package/dist/bootstrap/register-tools.js +696 -0
- package/dist/bootstrap/register-tools.js.map +1 -0
- package/dist/bootstrap/render.d.ts +27 -0
- package/dist/bootstrap/render.d.ts.map +1 -0
- package/dist/bootstrap/render.js +53 -0
- package/dist/bootstrap/render.js.map +1 -0
- package/dist/bootstrap/report.d.ts +34 -0
- package/dist/bootstrap/report.d.ts.map +1 -0
- package/dist/bootstrap/report.js +47 -0
- package/dist/bootstrap/report.js.map +1 -0
- package/dist/bootstrap/run-plane.d.ts +105 -0
- package/dist/bootstrap/run-plane.d.ts.map +1 -0
- package/dist/bootstrap/run-plane.js +190 -0
- package/dist/bootstrap/run-plane.js.map +1 -0
- package/dist/bootstrap/scope-access.d.ts +68 -0
- package/dist/bootstrap/scope-access.d.ts.map +1 -0
- package/dist/bootstrap/scope-access.js +115 -0
- package/dist/bootstrap/scope-access.js.map +1 -0
- package/dist/bootstrap/state-seams.d.ts +14 -0
- package/dist/bootstrap/state-seams.d.ts.map +1 -0
- package/dist/bootstrap/state-seams.js +26 -0
- package/dist/bootstrap/state-seams.js.map +1 -0
- package/dist/bootstrap/tool-lifecycle.d.ts +102 -0
- package/dist/bootstrap/tool-lifecycle.d.ts.map +1 -0
- package/dist/bootstrap/tool-lifecycle.js +103 -0
- package/dist/bootstrap/tool-lifecycle.js.map +1 -0
- package/dist/bootstrap/tool-trust.d.ts +49 -0
- package/dist/bootstrap/tool-trust.d.ts.map +1 -0
- package/dist/bootstrap/tool-trust.js +65 -0
- package/dist/bootstrap/tool-trust.js.map +1 -0
- package/dist/bootstrap/validate-tool.d.ts +22 -0
- package/dist/bootstrap/validate-tool.d.ts.map +1 -0
- package/dist/bootstrap/validate-tool.js +38 -0
- package/dist/bootstrap/validate-tool.js.map +1 -0
- package/dist/cli-context.d.ts +38 -0
- package/dist/cli-context.d.ts.map +1 -0
- package/dist/cli-context.js +134 -0
- package/dist/cli-context.js.map +1 -0
- package/dist/commands/agent-catalog.d.ts +45 -0
- package/dist/commands/agent-catalog.d.ts.map +1 -0
- package/dist/commands/agent-catalog.js +115 -0
- package/dist/commands/agent-catalog.js.map +1 -0
- package/dist/commands/assemble-outcome.d.ts +69 -0
- package/dist/commands/assemble-outcome.d.ts.map +1 -0
- package/dist/commands/assemble-outcome.js +121 -0
- package/dist/commands/assemble-outcome.js.map +1 -0
- package/dist/commands/clear.d.ts +32 -0
- package/dist/commands/clear.d.ts.map +1 -0
- package/dist/commands/clear.js +73 -0
- package/dist/commands/clear.js.map +1 -0
- package/dist/commands/completion.d.ts +90 -0
- package/dist/commands/completion.d.ts.map +1 -0
- package/dist/commands/completion.js +233 -0
- package/dist/commands/completion.js.map +1 -0
- package/dist/commands/configure.d.ts +32 -0
- package/dist/commands/configure.d.ts.map +1 -0
- package/dist/commands/configure.js +94 -0
- package/dist/commands/configure.js.map +1 -0
- package/dist/commands/history.d.ts +18 -0
- package/dist/commands/history.d.ts.map +1 -0
- package/dist/commands/history.js +48 -0
- package/dist/commands/history.js.map +1 -0
- package/dist/commands/host-command-specs.d.ts +49 -0
- package/dist/commands/host-command-specs.d.ts.map +1 -0
- package/dist/commands/host-command-specs.js +331 -0
- package/dist/commands/host-command-specs.js.map +1 -0
- package/dist/commands/host-subcommand-groups.d.ts +69 -0
- package/dist/commands/host-subcommand-groups.d.ts.map +1 -0
- package/dist/commands/host-subcommand-groups.js +374 -0
- package/dist/commands/host-subcommand-groups.js.map +1 -0
- package/dist/commands/index.d.ts +36 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +36 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/init/config-templates.d.ts +16 -0
- package/dist/commands/init/config-templates.d.ts.map +1 -0
- package/dist/commands/init/config-templates.js +108 -0
- package/dist/commands/init/config-templates.js.map +1 -0
- package/dist/commands/init/file-classifier.d.ts +40 -0
- package/dist/commands/init/file-classifier.d.ts.map +1 -0
- package/dist/commands/init/file-classifier.js +155 -0
- package/dist/commands/init/file-classifier.js.map +1 -0
- package/dist/commands/init/language-detection.d.ts +44 -0
- package/dist/commands/init/language-detection.d.ts.map +1 -0
- package/dist/commands/init/language-detection.js +124 -0
- package/dist/commands/init/language-detection.js.map +1 -0
- package/dist/commands/init/scaffold-writer.d.ts +26 -0
- package/dist/commands/init/scaffold-writer.d.ts.map +1 -0
- package/dist/commands/init/scaffold-writer.js +102 -0
- package/dist/commands/init/scaffold-writer.js.map +1 -0
- package/dist/commands/init/state-machine.d.ts +32 -0
- package/dist/commands/init/state-machine.d.ts.map +1 -0
- package/dist/commands/init/state-machine.js +105 -0
- package/dist/commands/init/state-machine.js.map +1 -0
- package/dist/commands/init.d.ts +95 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +209 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/mount-command-spec.d.ts +106 -0
- package/dist/commands/mount-command-spec.d.ts.map +1 -0
- package/dist/commands/mount-command-spec.js +313 -0
- package/dist/commands/mount-command-spec.js.map +1 -0
- package/dist/commands/mount-result-command.d.ts +71 -0
- package/dist/commands/mount-result-command.d.ts.map +1 -0
- package/dist/commands/mount-result-command.js +76 -0
- package/dist/commands/mount-result-command.js.map +1 -0
- package/dist/commands/plugin/config-edit.d.ts +20 -0
- package/dist/commands/plugin/config-edit.d.ts.map +1 -0
- package/dist/commands/plugin/config-edit.js +102 -0
- package/dist/commands/plugin/config-edit.js.map +1 -0
- package/dist/commands/plugin/domain-resolution.d.ts +38 -0
- package/dist/commands/plugin/domain-resolution.d.ts.map +1 -0
- package/dist/commands/plugin/domain-resolution.js +98 -0
- package/dist/commands/plugin/domain-resolution.js.map +1 -0
- package/dist/commands/plugin/host-dir.d.ts +42 -0
- package/dist/commands/plugin/host-dir.d.ts.map +1 -0
- package/dist/commands/plugin/host-dir.js +168 -0
- package/dist/commands/plugin/host-dir.js.map +1 -0
- package/dist/commands/plugin-host-ops.d.ts +41 -0
- package/dist/commands/plugin-host-ops.d.ts.map +1 -0
- package/dist/commands/plugin-host-ops.js +114 -0
- package/dist/commands/plugin-host-ops.js.map +1 -0
- package/dist/commands/plugin.d.ts +81 -0
- package/dist/commands/plugin.d.ts.map +1 -0
- package/dist/commands/plugin.js +287 -0
- package/dist/commands/plugin.js.map +1 -0
- package/dist/commands/render-outcome.d.ts +52 -0
- package/dist/commands/render-outcome.d.ts.map +1 -0
- package/dist/commands/render-outcome.js +55 -0
- package/dist/commands/render-outcome.js.map +1 -0
- package/dist/commands/session-show.d.ts +27 -0
- package/dist/commands/session-show.d.ts.map +1 -0
- package/dist/commands/session-show.js +166 -0
- package/dist/commands/session-show.js.map +1 -0
- package/dist/commands/shared.d.ts +107 -0
- package/dist/commands/shared.d.ts.map +1 -0
- package/dist/commands/shared.js +13 -0
- package/dist/commands/shared.js.map +1 -0
- package/dist/commands/tools/data-purge.d.ts +20 -0
- package/dist/commands/tools/data-purge.d.ts.map +1 -0
- package/dist/commands/tools/data-purge.js +59 -0
- package/dist/commands/tools/data-purge.js.map +1 -0
- package/dist/commands/tools/index.d.ts +16 -0
- package/dist/commands/tools/index.d.ts.map +1 -0
- package/dist/commands/tools/index.js +213 -0
- package/dist/commands/tools/index.js.map +1 -0
- package/dist/commands/tools/install.d.ts +24 -0
- package/dist/commands/tools/install.d.ts.map +1 -0
- package/dist/commands/tools/install.js +83 -0
- package/dist/commands/tools/install.js.map +1 -0
- package/dist/commands/tools/list.d.ts +41 -0
- package/dist/commands/tools/list.d.ts.map +1 -0
- package/dist/commands/tools/list.js +103 -0
- package/dist/commands/tools/list.js.map +1 -0
- package/dist/commands/tools/runtime-probe-entry.d.ts +14 -0
- package/dist/commands/tools/runtime-probe-entry.d.ts.map +1 -0
- package/dist/commands/tools/runtime-probe-entry.js +36 -0
- package/dist/commands/tools/runtime-probe-entry.js.map +1 -0
- package/dist/commands/tools/runtime-probe.d.ts +29 -0
- package/dist/commands/tools/runtime-probe.d.ts.map +1 -0
- package/dist/commands/tools/runtime-probe.js +66 -0
- package/dist/commands/tools/runtime-probe.js.map +1 -0
- package/dist/commands/tools/storage-contract-checks.d.ts +37 -0
- package/dist/commands/tools/storage-contract-checks.d.ts.map +1 -0
- package/dist/commands/tools/storage-contract-checks.js +91 -0
- package/dist/commands/tools/storage-contract-checks.js.map +1 -0
- package/dist/commands/tools/uninstall.d.ts +29 -0
- package/dist/commands/tools/uninstall.d.ts.map +1 -0
- package/dist/commands/tools/uninstall.js +77 -0
- package/dist/commands/tools/uninstall.js.map +1 -0
- package/dist/commands/tools/validate.d.ts +44 -0
- package/dist/commands/tools/validate.d.ts.map +1 -0
- package/dist/commands/tools/validate.js +202 -0
- package/dist/commands/tools/validate.js.map +1 -0
- package/dist/commands/uninstall/targets.d.ts +53 -0
- package/dist/commands/uninstall/targets.d.ts.map +1 -0
- package/dist/commands/uninstall/targets.js +205 -0
- package/dist/commands/uninstall/targets.js.map +1 -0
- package/dist/commands/uninstall.d.ts +88 -0
- package/dist/commands/uninstall.d.ts.map +1 -0
- package/dist/commands/uninstall.js +184 -0
- package/dist/commands/uninstall.js.map +1 -0
- package/dist/env/host-env-specs.d.ts +52 -0
- package/dist/env/host-env-specs.d.ts.map +1 -0
- package/dist/env/host-env-specs.js +129 -0
- package/dist/env/host-env-specs.js.map +1 -0
- package/dist/error-handler.d.ts +64 -0
- package/dist/error-handler.d.ts.map +1 -0
- package/dist/error-handler.js +180 -0
- package/dist/error-handler.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +154 -0
- package/dist/index.js.map +1 -0
- package/dist/open-report.d.ts +40 -0
- package/dist/open-report.d.ts.map +1 -0
- package/dist/open-report.js +54 -0
- package/dist/open-report.js.map +1 -0
- package/dist/report-compose.d.ts +35 -0
- package/dist/report-compose.d.ts.map +1 -0
- package/dist/report-compose.js +103 -0
- package/dist/report-compose.js.map +1 -0
- package/dist/session-replay-registry.d.ts +20 -0
- package/dist/session-replay-registry.d.ts.map +1 -0
- package/dist/session-replay-registry.js +38 -0
- package/dist/session-replay-registry.js.map +1 -0
- package/dist/telemetry/profiling.d.ts +42 -0
- package/dist/telemetry/profiling.d.ts.map +1 -0
- package/dist/telemetry/profiling.js +160 -0
- package/dist/telemetry/profiling.js.map +1 -0
- package/dist/telemetry/sdk-init.d.ts +87 -0
- package/dist/telemetry/sdk-init.d.ts.map +1 -0
- package/dist/telemetry/sdk-init.js +235 -0
- package/dist/telemetry/sdk-init.js.map +1 -0
- package/dist/ui/App.d.ts +32 -0
- package/dist/ui/App.d.ts.map +1 -0
- package/dist/ui/App.js +35 -0
- package/dist/ui/App.js.map +1 -0
- package/dist/ui/render.d.ts +15 -0
- package/dist/ui/render.d.ts.map +1 -0
- package/dist/ui/render.js +21 -0
- package/dist/ui/render.js.map +1 -0
- package/dist/ui/result-to-view.d.ts +40 -0
- package/dist/ui/result-to-view.d.ts.map +1 -0
- package/dist/ui/result-to-view.js +389 -0
- package/dist/ui/result-to-view.js.map +1 -0
- package/dist/ui/views/init-view.d.ts +9 -0
- package/dist/ui/views/init-view.d.ts.map +1 -0
- package/dist/ui/views/init-view.js +119 -0
- package/dist/ui/views/init-view.js.map +1 -0
- package/dist/ui/views/misc-views.d.ts +18 -0
- package/dist/ui/views/misc-views.d.ts.map +1 -0
- package/dist/ui/views/misc-views.js +244 -0
- package/dist/ui/views/misc-views.js.map +1 -0
- package/dist/ui/views/plugin-view.d.ts +8 -0
- package/dist/ui/views/plugin-view.d.ts.map +1 -0
- package/dist/ui/views/plugin-view.js +135 -0
- package/dist/ui/views/plugin-view.js.map +1 -0
- package/dist/ui/views/tools-views.d.ts +12 -0
- package/dist/ui/views/tools-views.d.ts.map +1 -0
- package/dist/ui/views/tools-views.js +152 -0
- package/dist/ui/views/tools-views.js.map +1 -0
- package/dist/update-notifier.d.ts +108 -0
- package/dist/update-notifier.d.ts.map +1 -0
- package/dist/update-notifier.js +188 -0
- package/dist/update-notifier.js.map +1 -0
- package/dist/update-state.d.ts +40 -0
- package/dist/update-state.d.ts.map +1 -0
- package/dist/update-state.js +81 -0
- package/dist/update-state.js.map +1 -0
- package/dist/welcome.d.ts +53 -0
- package/dist/welcome.d.ts.map +1 -0
- package/dist/welcome.js +89 -0
- package/dist/welcome.js.map +1 -0
- package/package.json +100 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
// @fitness-ignore-file error-handling-quality -- file/dir walks for uninstall planning and best-effort tidy-up: missing/unreadable entries (TOCTOU vanish between readdir+stat, permission-denied subdirs, already-removed parent shells) are the expected non-terminal signal to skip; failure-IS-the-signal is the function contract in each catch.
|
|
2
|
+
// @fitness-ignore-file only-documented-toolcli-seams -- interactive TTY UX: the readline confirmation prompt + human-readable removal-progress notes go to stdout via an injectable `write` (defaulted to process.stdout for the real run, stubbed in tests); this is not machine run output through a ToolCliContext seam (same category as clear.ts/configure.ts).
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview `opensip uninstall` — remove opensip-cli state
|
|
5
|
+
* from a user account and/or project.
|
|
6
|
+
*
|
|
7
|
+
* Two modes:
|
|
8
|
+
*
|
|
9
|
+
* • Default (no flag) — remove the user-level directory
|
|
10
|
+
* `~/.opensip-cli/`. Contract: this dir holds `config.yml` only
|
|
11
|
+
* (cloud API key + per-user defaults). Persistence and logging code
|
|
12
|
+
* throws if asked to write anywhere user-global, so the dir does
|
|
13
|
+
* not grow over time. Any pre-existing `sessions/`, `reports/`,
|
|
14
|
+
* `logs/`, or `fit/` subdirectories on disk are legacy cruft from
|
|
15
|
+
* earlier versions and are swept up by the same removal.
|
|
16
|
+
*
|
|
17
|
+
* • `--project [path]` — remove project-local state at `[path]` (or
|
|
18
|
+
* cwd if omitted): both `<path>/opensip-cli/` (user-authored
|
|
19
|
+
* checks + recipes plus the gitignored `.runtime/` cache) and
|
|
20
|
+
* `<path>/opensip-cli.config.yml`. Refuses to run if neither
|
|
21
|
+
* target exists at the resolved path, to avoid `rm -rf`-ing an
|
|
22
|
+
* unrelated directory.
|
|
23
|
+
*
|
|
24
|
+
* The recursive removal of `<path>/opensip-cli/` transitively
|
|
25
|
+
* sweeps up `.runtime/datastore.sqlite` and its `-wal`/`-shm` SQLite
|
|
26
|
+
* sidecars — no datastore-specific path needs to be
|
|
27
|
+
* enumerated here. Caveat for Windows: open file handles can block
|
|
28
|
+
* removal of WAL/SHM files; ensure no opensip-cli CLI process is
|
|
29
|
+
* active when running uninstall.
|
|
30
|
+
*
|
|
31
|
+
* Does NOT remove the npm global install — the running binary can't
|
|
32
|
+
* safely self-delete. Prints the exact next-step command for that.
|
|
33
|
+
*
|
|
34
|
+
* Flags:
|
|
35
|
+
* --project [path] Remove project-local state instead of user-level.
|
|
36
|
+
* --yes Skip confirmation prompt.
|
|
37
|
+
* --dry-run Print what would be removed; take no action.
|
|
38
|
+
*
|
|
39
|
+
* Result-shape contract (audit 2026-05-23 G5)
|
|
40
|
+
* -------------------------------------------
|
|
41
|
+
* `executeUninstall` returns a discriminated `UninstallDoneResult` whose
|
|
42
|
+
* `type === 'uninstall-done'` makes it a valid `CommandResult`. The
|
|
43
|
+
* trailing success / cancelled / dry-run / empty notice — previously
|
|
44
|
+
* raw-stdout writes that bypassed the theme — is rendered via Ink in
|
|
45
|
+
* `App.tsx`'s `case 'uninstall-done':` branch. The pre-confirmation
|
|
46
|
+
* target listing stays as a direct `write()` because it must appear
|
|
47
|
+
* BEFORE the readline confirmation prompt; same pattern as
|
|
48
|
+
* `configure.ts` printing the "current key" hint above the prompt.
|
|
49
|
+
*
|
|
50
|
+
* Module layout
|
|
51
|
+
* -------------
|
|
52
|
+
* - This file owns `executeUninstall` and removal orchestration.
|
|
53
|
+
* - `uninstall/targets.ts` owns Target collection + pre-prompt display.
|
|
54
|
+
*/
|
|
55
|
+
import { existsSync, rmSync } from 'node:fs';
|
|
56
|
+
import { homedir } from 'node:os';
|
|
57
|
+
import { join, resolve } from 'node:path';
|
|
58
|
+
import { createInterface } from 'node:readline/promises';
|
|
59
|
+
import { resolveProjectPaths } from '@opensip-cli/core';
|
|
60
|
+
import { collectTargets, printProjectDefault, printProjectPurge, printUserModeTargets, } from './uninstall/targets.js';
|
|
61
|
+
const DEFAULT_USER_ROOT = join(homedir(), '.opensip-cli');
|
|
62
|
+
async function confirm(prompt, message) {
|
|
63
|
+
const raw = await prompt(message);
|
|
64
|
+
const answer = raw.trim().toLowerCase();
|
|
65
|
+
return answer === 'y' || answer === 'yes';
|
|
66
|
+
}
|
|
67
|
+
function defaultPrompt(question) {
|
|
68
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
69
|
+
return rl.question(question).finally(() => rl.close());
|
|
70
|
+
}
|
|
71
|
+
/** Resolve the project directory for `--project [path]`. */
|
|
72
|
+
function resolveProjectDir(opts) {
|
|
73
|
+
if (typeof opts.project === 'string')
|
|
74
|
+
return resolve(opts.project);
|
|
75
|
+
// Prefer the discovered project root (set by pre-action-hook). Falls
|
|
76
|
+
// back to literal cwd, then process.cwd(). Without the discovered
|
|
77
|
+
// root, `uninstall` from a subdir would target the wrong .runtime/.
|
|
78
|
+
return opts.projectContext?.projectRoot ?? opts.cwd ?? process.cwd();
|
|
79
|
+
}
|
|
80
|
+
/** Project a `Target[]` into the result-shape `{path, kind}[]`. */
|
|
81
|
+
function targetsForResult(targets) {
|
|
82
|
+
return targets.map((t) => ({ path: t.path, kind: t.kind }));
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Build the canonical "no-op" / "post-removal" result. The `action`
|
|
86
|
+
* discriminator is the single source of truth for what happened
|
|
87
|
+
* (`removed` / `dry-run` / `cancelled` / `empty`); consumers branch on
|
|
88
|
+
* it rather than on derived boolean flags.
|
|
89
|
+
*/
|
|
90
|
+
function buildResult(args) {
|
|
91
|
+
const sizeBytes = args.targets.reduce((sum, t) => sum + t.sizeBytes, 0);
|
|
92
|
+
return {
|
|
93
|
+
type: 'uninstall-done',
|
|
94
|
+
action: args.action,
|
|
95
|
+
mode: args.mode,
|
|
96
|
+
targets: targetsForResult(args.targets),
|
|
97
|
+
sizeBytes,
|
|
98
|
+
rootPath: args.rootPath,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/** Filter all-targets into (toDelete, toKeep) per mode + purge flag. */
|
|
102
|
+
function filterTargetsForAction(mode, purge, allTargets) {
|
|
103
|
+
if (mode === 'user' || purge) {
|
|
104
|
+
return { toDelete: allTargets, toKeep: [] };
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
toDelete: allTargets.filter((t) => t.bucket === 'runtime'),
|
|
108
|
+
toKeep: allTargets.filter((t) => t.bucket !== 'runtime'),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/** Print the pre-prompt summary appropriate to mode + purge state. */
|
|
112
|
+
function printPreambleForRun(write, input) {
|
|
113
|
+
const { mode, purge, toDelete, toKeep, rootPath } = input;
|
|
114
|
+
if (mode === 'user') {
|
|
115
|
+
printUserModeTargets(write, toDelete);
|
|
116
|
+
}
|
|
117
|
+
else if (purge) {
|
|
118
|
+
printProjectPurge(write, toDelete, rootPath);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
printProjectDefault(write, toDelete, toKeep, rootPath);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
export async function executeUninstall(opts = {}) {
|
|
125
|
+
const mode = opts.project === undefined ? 'user' : 'project';
|
|
126
|
+
const userRoot = opts.rootDir ?? DEFAULT_USER_ROOT;
|
|
127
|
+
const projectDir = resolveProjectDir(opts);
|
|
128
|
+
const rootPath = mode === 'user' ? userRoot : projectDir;
|
|
129
|
+
const write = opts.write ?? ((s) => process.stdout.write(s));
|
|
130
|
+
const purge = opts.purge === true;
|
|
131
|
+
const allTargets = collectTargets(mode, userRoot, projectDir);
|
|
132
|
+
if (allTargets.length === 0) {
|
|
133
|
+
const where = mode === 'user' ? userRoot : projectDir;
|
|
134
|
+
const note = mode === 'project'
|
|
135
|
+
? `\nNothing to remove — no OpenSIP CLI state found at ${where}.\n\n`
|
|
136
|
+
: `\nNothing to remove — ${where} does not exist.\n\n`;
|
|
137
|
+
write(note);
|
|
138
|
+
return buildResult({ action: 'empty', mode, targets: [], rootPath });
|
|
139
|
+
}
|
|
140
|
+
const { toDelete, toKeep } = filterTargetsForAction(mode, purge, allTargets);
|
|
141
|
+
// Empty-after-filter (project default with no .runtime/ but existing
|
|
142
|
+
// user content). Print the KEPT block so the user sees what survived.
|
|
143
|
+
if (mode === 'project' && toDelete.length === 0) {
|
|
144
|
+
printProjectDefault(write, [], toKeep, rootPath);
|
|
145
|
+
return buildResult({ action: 'empty', mode, targets: [], rootPath });
|
|
146
|
+
}
|
|
147
|
+
printPreambleForRun(write, { mode, purge, toDelete, toKeep, rootPath });
|
|
148
|
+
if (opts.dryRun) {
|
|
149
|
+
return buildResult({ action: 'dry-run', mode, targets: toDelete, rootPath });
|
|
150
|
+
}
|
|
151
|
+
if (opts.yes !== true) {
|
|
152
|
+
const prompt = opts.prompt ?? defaultPrompt;
|
|
153
|
+
const ok = await confirm(prompt, `Proceed? [y/N] `);
|
|
154
|
+
if (!ok) {
|
|
155
|
+
return buildResult({ action: 'cancelled', mode, targets: toDelete, rootPath });
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
performRemoval(toDelete, mode, purge, projectDir);
|
|
159
|
+
return buildResult({ action: 'removed', mode, targets: toDelete, rootPath });
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Delete the resolved targets and, after --purge, tidy the now-empty
|
|
163
|
+
* `opensip-cli/` shell. Extracted so executeUninstall stays under the
|
|
164
|
+
* cognitive-complexity threshold.
|
|
165
|
+
*/
|
|
166
|
+
function performRemoval(toDelete, mode, purge, projectDir) {
|
|
167
|
+
for (const t of toDelete) {
|
|
168
|
+
rmSync(t.path, { recursive: true, force: true });
|
|
169
|
+
}
|
|
170
|
+
if (mode !== 'project' || !purge)
|
|
171
|
+
return;
|
|
172
|
+
// --purge removed children individually (each enumerated for display).
|
|
173
|
+
// Tidy the parent shell so --purge matches "removes EVERYTHING."
|
|
174
|
+
const paths = resolveProjectPaths(projectDir);
|
|
175
|
+
if (existsSync(paths.userSourceDir)) {
|
|
176
|
+
try {
|
|
177
|
+
rmSync(paths.userSourceDir, { recursive: true, force: true });
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
/* ignore */
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=uninstall.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uninstall.js","sourceRoot":"","sources":["../../src/commands/uninstall.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* host-env-specs — the CLI's environment-variable surface (launch, §5.12).
|
|
3
|
+
*
|
|
4
|
+
* The env surface is governed exactly like the config document: every variable is
|
|
5
|
+
* declared as an immutable {@link EnvVarSpec} and read through the {@link EnvRegistry}
|
|
6
|
+
* primitive, so it can be documented (the generated env-surface reference) and
|
|
7
|
+
* deprecated coherently. The `env-via-registry` guardrail fails CI on any raw
|
|
8
|
+
* `process.env` read outside the registry.
|
|
9
|
+
*
|
|
10
|
+
* This module owns the CLI-layer infra variables (telemetry + update-notifier) and
|
|
11
|
+
* AGGREGATES the per-package specs (config, graph) plus the documented pre-scope
|
|
12
|
+
* exceptions into one `describeHostEnv()` for the reference doc — the CLI is the
|
|
13
|
+
* composition root, so it is the one place that can name every layer's specs.
|
|
14
|
+
*
|
|
15
|
+
* Pre-scope exceptions: the terminal-theme color vars (`@opensip-cli/cli-ui` has
|
|
16
|
+
* no `core` dependency and resolves colors before any scope exists) and
|
|
17
|
+
* `NODE_OPTIONS` (the graph heap-preflight mutates it before any opensip module
|
|
18
|
+
* loads) are read raw at their sites. They are declared here for documentation
|
|
19
|
+
* only and allow-listed by the `env-via-registry` guardrail.
|
|
20
|
+
*/
|
|
21
|
+
import { EnvRegistry, type EnvVarSpec } from '@opensip-cli/core';
|
|
22
|
+
/** CLI-layer infra variables: OpenTelemetry + the update-notifier opt-outs. */
|
|
23
|
+
export declare const CLI_ENV_SPECS: readonly EnvVarSpec<unknown>[];
|
|
24
|
+
/** The composed CLI-layer registry. Telemetry + update-notifier read through it. */
|
|
25
|
+
export declare const hostEnv: EnvRegistry;
|
|
26
|
+
/**
|
|
27
|
+
* Env vars a BUNDLED TOOL reads through its own `EnvRegistry`, documented here
|
|
28
|
+
* at the composition root for the env-surface reference.
|
|
29
|
+
*
|
|
30
|
+
* The host does not statically import tool packages just to read env specs
|
|
31
|
+
* (e.g. `GRAPH_ENV_SPECS` from `@opensip-cli/graph`) — that would couple the
|
|
32
|
+
* host to a tool runtime and break the install-source-independence the
|
|
33
|
+
* `no-bootstrap-tool-import` guardrail enforces. The tool keeps OWNING the
|
|
34
|
+
* runtime read (its registry, its coercion); the composition root names the
|
|
35
|
+
* variable for documentation only, the same way it already documents the
|
|
36
|
+
* graph-related `NODE_OPTIONS` below. The `host-env-specs` drift test asserts
|
|
37
|
+
* this list stays a superset of each bundled tool's actual specs (e.g. graph's
|
|
38
|
+
* `GRAPH_ENV_SPECS`), so a tool adding an env var fails CI until it is
|
|
39
|
+
* documented here.
|
|
40
|
+
*/
|
|
41
|
+
export declare const BUNDLED_TOOL_ENV_SPECS: readonly EnvVarSpec<unknown>[];
|
|
42
|
+
/**
|
|
43
|
+
* Pre-scope variables read raw at their sites (documented `env-via-registry`
|
|
44
|
+
* allowance), declared here so the env-surface reference is complete.
|
|
45
|
+
*/
|
|
46
|
+
export declare const PRE_SCOPE_ENV_SPECS: readonly EnvVarSpec<unknown>[];
|
|
47
|
+
/**
|
|
48
|
+
* Every environment variable the platform reads, across all layers — the source
|
|
49
|
+
* of truth for the generated env-surface reference (Phase 6).
|
|
50
|
+
*/
|
|
51
|
+
export declare function describeHostEnv(): readonly EnvVarSpec<unknown>[];
|
|
52
|
+
//# sourceMappingURL=host-env-specs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-env-specs.d.ts","sourceRoot":"","sources":["../../src/env/host-env-specs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,EAAE,WAAW,EAAE,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEjE,+EAA+E;AAC/E,eAAO,MAAM,aAAa,EAAE,SAAS,UAAU,CAAC,OAAO,CAAC,EAwDvD,CAAC;AAEF,oFAAoF;AAEpF,eAAO,MAAM,OAAO,aAAiC,CAAC;AAEtD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,sBAAsB,EAAE,SAAS,UAAU,CAAC,OAAO,CAAC,EAKhE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,mBAAmB,EAAE,SAAS,UAAU,CAAC,OAAO,CAAC,EAgB7D,CAAC;AAEF;;;GAGG;AACH,wBAAgB,eAAe,IAAI,SAAS,UAAU,CAAC,OAAO,CAAC,EAAE,CAEhE"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* host-env-specs — the CLI's environment-variable surface (launch, §5.12).
|
|
3
|
+
*
|
|
4
|
+
* The env surface is governed exactly like the config document: every variable is
|
|
5
|
+
* declared as an immutable {@link EnvVarSpec} and read through the {@link EnvRegistry}
|
|
6
|
+
* primitive, so it can be documented (the generated env-surface reference) and
|
|
7
|
+
* deprecated coherently. The `env-via-registry` guardrail fails CI on any raw
|
|
8
|
+
* `process.env` read outside the registry.
|
|
9
|
+
*
|
|
10
|
+
* This module owns the CLI-layer infra variables (telemetry + update-notifier) and
|
|
11
|
+
* AGGREGATES the per-package specs (config, graph) plus the documented pre-scope
|
|
12
|
+
* exceptions into one `describeHostEnv()` for the reference doc — the CLI is the
|
|
13
|
+
* composition root, so it is the one place that can name every layer's specs.
|
|
14
|
+
*
|
|
15
|
+
* Pre-scope exceptions: the terminal-theme color vars (`@opensip-cli/cli-ui` has
|
|
16
|
+
* no `core` dependency and resolves colors before any scope exists) and
|
|
17
|
+
* `NODE_OPTIONS` (the graph heap-preflight mutates it before any opensip module
|
|
18
|
+
* loads) are read raw at their sites. They are declared here for documentation
|
|
19
|
+
* only and allow-listed by the `env-via-registry` guardrail.
|
|
20
|
+
*/
|
|
21
|
+
import { CONFIG_ENV_SPECS } from '@opensip-cli/config';
|
|
22
|
+
import { EnvRegistry } from '@opensip-cli/core';
|
|
23
|
+
/** CLI-layer infra variables: OpenTelemetry + the update-notifier opt-outs. */
|
|
24
|
+
export const CLI_ENV_SPECS = [
|
|
25
|
+
{
|
|
26
|
+
canonical: 'OTEL_EXPORTER_OTLP_ENDPOINT',
|
|
27
|
+
docs: 'OTLP/HTTP endpoint. When set, the CLI enables OpenTelemetry tracing; unset is a hard no-op.',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
canonical: 'OPENSIP_PROFILING',
|
|
31
|
+
docs: 'Explicit gate for the optional CPU profiling path (ADR-0049). "1" or "true" forces on when OTEL_EXPORTER_OTLP_ENDPOINT is set; "0"/"false" forces off. When omitted and the OTLP endpoint is present, falls back to the documented OTEL-only mode (with cost warnings emitted).',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
canonical: 'TRACEPARENT',
|
|
35
|
+
docs: 'W3C traceparent of a parent trace (read only when telemetry is on); run spans nest under it.',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
canonical: 'OPENSIP_NO_UPDATE',
|
|
39
|
+
coerce: (raw) => raw.length > 0,
|
|
40
|
+
default: false,
|
|
41
|
+
docs: 'Set to any non-empty value to skip the CLI update check.',
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
canonical: 'NO_UPDATE_NOTIFIER',
|
|
45
|
+
coerce: (raw) => raw.length > 0,
|
|
46
|
+
default: false,
|
|
47
|
+
docs: 'npm-convention update-notifier opt-out; honoured as an equivalent of OPENSIP_NO_UPDATE.',
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
canonical: 'OPENSIP_CLI_SKIP_BUNDLED',
|
|
51
|
+
coerce: (raw) => raw
|
|
52
|
+
.split(',')
|
|
53
|
+
.map((s) => s.trim())
|
|
54
|
+
.filter((s) => s.length > 0),
|
|
55
|
+
default: [],
|
|
56
|
+
docs: 'Comma-separated bundled-tool ids (fitness/simulation/graph) to NOT load as bundled. ' +
|
|
57
|
+
'A skipped tool can instead be loaded from an installed/project-local package of the same id ' +
|
|
58
|
+
'— the install-source-independence escape hatch. Unset = load all bundled tools.',
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
canonical: 'OPENSIP_CLI_ALLOW_PROJECT_TOOLS',
|
|
62
|
+
// Mirror parseAllowlist's split (whitespace AND comma) so the registry value
|
|
63
|
+
// and tool-trust's set agree exactly — including the `*` token, which passes
|
|
64
|
+
// through as a plain id the trust check tests for.
|
|
65
|
+
coerce: (raw) => raw
|
|
66
|
+
.split(/[\s,]+/)
|
|
67
|
+
.map((s) => s.trim())
|
|
68
|
+
.filter((s) => s.length > 0),
|
|
69
|
+
default: [],
|
|
70
|
+
docs: 'Comma/whitespace-separated project-authored Tool ids to admit (deny-by-default). ' +
|
|
71
|
+
"Use '*' to admit all project-authored tools. A project-authored sidecar tool under " +
|
|
72
|
+
'<project>/opensip-cli/tools/ is NOT loaded unless its id (or *) appears here — it ' +
|
|
73
|
+
'rides in with git clone, so loading it runs untrusted code. Global-authored tools ' +
|
|
74
|
+
'(~/.opensip-cli/tools/) are trusted-by-default and ignore this list.',
|
|
75
|
+
},
|
|
76
|
+
];
|
|
77
|
+
/** The composed CLI-layer registry. Telemetry + update-notifier read through it. */
|
|
78
|
+
// @allow-module-singleton EnvRegistry is IMMUTABLE — a constant spec table + on-demand process.env reads; it holds no per-run mutable state, so it is not the scope-isolation hazard no-module-singleton targets (spec §5.12 resolved decision: the env definition table is a permitted module constant).
|
|
79
|
+
export const hostEnv = new EnvRegistry(CLI_ENV_SPECS);
|
|
80
|
+
/**
|
|
81
|
+
* Env vars a BUNDLED TOOL reads through its own `EnvRegistry`, documented here
|
|
82
|
+
* at the composition root for the env-surface reference.
|
|
83
|
+
*
|
|
84
|
+
* The host does not statically import tool packages just to read env specs
|
|
85
|
+
* (e.g. `GRAPH_ENV_SPECS` from `@opensip-cli/graph`) — that would couple the
|
|
86
|
+
* host to a tool runtime and break the install-source-independence the
|
|
87
|
+
* `no-bootstrap-tool-import` guardrail enforces. The tool keeps OWNING the
|
|
88
|
+
* runtime read (its registry, its coercion); the composition root names the
|
|
89
|
+
* variable for documentation only, the same way it already documents the
|
|
90
|
+
* graph-related `NODE_OPTIONS` below. The `host-env-specs` drift test asserts
|
|
91
|
+
* this list stays a superset of each bundled tool's actual specs (e.g. graph's
|
|
92
|
+
* `GRAPH_ENV_SPECS`), so a tool adding an env var fails CI until it is
|
|
93
|
+
* documented here.
|
|
94
|
+
*/
|
|
95
|
+
export const BUNDLED_TOOL_ENV_SPECS = [
|
|
96
|
+
{
|
|
97
|
+
canonical: 'OPENSIP_HEAP_NO_MONITOR',
|
|
98
|
+
docs: 'Set to 1 to disable the graph V8 heap-pressure monitor (REPL embedding / custom allocators).',
|
|
99
|
+
},
|
|
100
|
+
];
|
|
101
|
+
/**
|
|
102
|
+
* Pre-scope variables read raw at their sites (documented `env-via-registry`
|
|
103
|
+
* allowance), declared here so the env-surface reference is complete.
|
|
104
|
+
*/
|
|
105
|
+
export const PRE_SCOPE_ENV_SPECS = [
|
|
106
|
+
{
|
|
107
|
+
canonical: 'NO_COLOR',
|
|
108
|
+
docs: 'Disable ANSI colours (https://no-color.org). Resolved by the terminal theme.',
|
|
109
|
+
},
|
|
110
|
+
{ canonical: 'FORCE_COLOR', docs: 'Force ANSI colours even when the stream is not a TTY.' },
|
|
111
|
+
{ canonical: 'COLORTERM', docs: 'Terminal colour capability hint (e.g. truecolor).' },
|
|
112
|
+
{ canonical: 'TERM', docs: 'Terminal type; consulted for colour support.' },
|
|
113
|
+
{
|
|
114
|
+
canonical: 'TERM_PROGRAM',
|
|
115
|
+
docs: 'Terminal program (e.g. iTerm.app); consulted for colour support.',
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
canonical: 'NODE_OPTIONS',
|
|
119
|
+
docs: 'Node flags; the graph heap-preflight reads/extends this before relaunch (pre-module).',
|
|
120
|
+
},
|
|
121
|
+
];
|
|
122
|
+
/**
|
|
123
|
+
* Every environment variable the platform reads, across all layers — the source
|
|
124
|
+
* of truth for the generated env-surface reference (Phase 6).
|
|
125
|
+
*/
|
|
126
|
+
export function describeHostEnv() {
|
|
127
|
+
return [...CONFIG_ENV_SPECS, ...BUNDLED_TOOL_ENV_SPECS, ...CLI_ENV_SPECS, ...PRE_SCOPE_ENV_SPECS];
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=host-env-specs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-env-specs.js","sourceRoot":"","sources":["../../src/env/host-env-specs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* error-handler — single-responsibility catch handler for the
|
|
3
|
+
* top-level `parseAsync().catch(...)` block.
|
|
4
|
+
*
|
|
5
|
+
* Goals:
|
|
6
|
+
* - One `process.exitCode` write path: route every exit-code change
|
|
7
|
+
* through the supplied `setExitCode` callback (which `cli-context.ts`
|
|
8
|
+
* centralises).
|
|
9
|
+
* - Match on `instanceof` against the typed error hierarchy in
|
|
10
|
+
* `@opensip-cli/core`; fall back to the data-driven
|
|
11
|
+
* `getErrorSuggestion` (Layer 2 Phase 1) for unknown shapes.
|
|
12
|
+
* - The typed-error → exit-code policy lives in contracts'
|
|
13
|
+
* `mapToolErrorToExitCode` (audit-round-2 Finding C). This handler
|
|
14
|
+
* keeps only the *CLI-specific* layer: per-class action hints (e.g.
|
|
15
|
+
* "Run opensip fit --list...") that don't belong in the
|
|
16
|
+
* headless contracts package.
|
|
17
|
+
* - Keep the renderer pluggable so unit tests can capture the rendered
|
|
18
|
+
* `ErrorResult` without touching Ink.
|
|
19
|
+
*/
|
|
20
|
+
import { type ErrorResult } from '@opensip-cli/contracts';
|
|
21
|
+
export interface HandleParseErrorOptions {
|
|
22
|
+
readonly setExitCode: (code: number) => void;
|
|
23
|
+
readonly render: (result: ErrorResult) => Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Whether `--json` was requested (read from argv at the composition root —
|
|
26
|
+
* these errors fire outside a handler, so no parsed opts are available). When
|
|
27
|
+
* true, every error becomes a structured `CommandOutcome` on stdout (the
|
|
28
|
+
* `one-outcome-shape` contract, §5.5); when false, human rendering is
|
|
29
|
+
* byte-identical to launch.
|
|
30
|
+
*/
|
|
31
|
+
readonly jsonRequested: boolean;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The catch handler for `program.parseAsync()`. Maps the thrown error to a
|
|
35
|
+
* `CommandOutcome` (launch, §5.5): `--json` emits the structured outcome
|
|
36
|
+
* on stdout, human mode renders byte-identically to launch. Routes the exit code
|
|
37
|
+
* through `setExitCode`. Never throws.
|
|
38
|
+
*/
|
|
39
|
+
export declare function handleParseError(error: unknown, opts: HandleParseErrorOptions): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* Top-level fatal-error handler for failures BEFORE Commander's parse
|
|
42
|
+
* loop runs (bootstrap registration, dynamic plugin imports, preflight
|
|
43
|
+
* I/O). Sets `process.exitCode` (not `process.exit(N)` — the latter
|
|
44
|
+
* skips the pending stderr flush, and any structured-logging hook on
|
|
45
|
+
* bootstrap failure has nowhere to attach), writes the error line to
|
|
46
|
+
* stderr, and emits a `cli.bootstrap.failed` log event so observability
|
|
47
|
+
* pipelines see the failure. Audit 2026-05-23 G1.
|
|
48
|
+
*
|
|
49
|
+
* Exit code: a typed `ToolError` (e.g. the `PluginIncompatibleError` the
|
|
50
|
+
* Phase-3 fail-closed admission path throws) routes through the canonical
|
|
51
|
+
* `mapToolErrorToExitCode` policy so a fail-closed plugin yields exit 5
|
|
52
|
+
* (`PLUGIN_INCOMPATIBLE`) even when it surfaces from bootstrap rather than
|
|
53
|
+
* Commander's parse loop. Untyped errors keep the historical exit 1.
|
|
54
|
+
*
|
|
55
|
+
* Synchronous because every step here is sync — stderr write,
|
|
56
|
+
* structured-log call, exit-code set. The top-level caller doesn't
|
|
57
|
+
* need to `await` it (Node exits naturally with the configured
|
|
58
|
+
* `process.exitCode` after the event loop drains), but the call site
|
|
59
|
+
* is fine to `await` either way.
|
|
60
|
+
*/
|
|
61
|
+
export declare function handleFatalBootstrapError(error: unknown, log: {
|
|
62
|
+
error: (entry: Record<string, unknown>) => void;
|
|
63
|
+
}): void;
|
|
64
|
+
//# sourceMappingURL=error-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../src/error-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAIL,KAAK,WAAW,EAEjB,MAAM,wBAAwB,CAAC;AAgFhC,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,QAAQ,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD;;;;;;OAMG;IACH,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;CACjC;AAKD;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,uBAAuB,GAC5B,OAAO,CAAC,IAAI,CAAC,CA0Df;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,OAAO,EACd,GAAG,EAAE;IAAE,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAA;CAAE,GACvD,IAAI,CAaN"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* error-handler — single-responsibility catch handler for the
|
|
3
|
+
* top-level `parseAsync().catch(...)` block.
|
|
4
|
+
*
|
|
5
|
+
* Goals:
|
|
6
|
+
* - One `process.exitCode` write path: route every exit-code change
|
|
7
|
+
* through the supplied `setExitCode` callback (which `cli-context.ts`
|
|
8
|
+
* centralises).
|
|
9
|
+
* - Match on `instanceof` against the typed error hierarchy in
|
|
10
|
+
* `@opensip-cli/core`; fall back to the data-driven
|
|
11
|
+
* `getErrorSuggestion` (Layer 2 Phase 1) for unknown shapes.
|
|
12
|
+
* - The typed-error → exit-code policy lives in contracts'
|
|
13
|
+
* `mapToolErrorToExitCode` (audit-round-2 Finding C). This handler
|
|
14
|
+
* keeps only the *CLI-specific* layer: per-class action hints (e.g.
|
|
15
|
+
* "Run opensip fit --list...") that don't belong in the
|
|
16
|
+
* headless contracts package.
|
|
17
|
+
* - Keep the renderer pluggable so unit tests can capture the rendered
|
|
18
|
+
* `ErrorResult` without touching Ink.
|
|
19
|
+
*/
|
|
20
|
+
import { EXIT_CODES, getErrorSuggestion, mapToolErrorToExitCode, } from '@opensip-cli/contracts';
|
|
21
|
+
import { ConfigurationError, NetworkError, NotFoundError, PluginIncompatibleError, ToolError, } from '@opensip-cli/core';
|
|
22
|
+
import { CommanderError } from 'commander';
|
|
23
|
+
import { BootstrapError } from './bootstrap/bootstrap-error.js';
|
|
24
|
+
import { outcomeFromError, outcomeFromErrorMessage } from './commands/assemble-outcome.js';
|
|
25
|
+
import { renderOutcome } from './commands/render-outcome.js';
|
|
26
|
+
/**
|
|
27
|
+
* Commander error codes that denote an INVALID ARGUMENT VALUE — a declared
|
|
28
|
+
* `choices` rejection or a custom `argParser` that threw `InvalidArgumentError`
|
|
29
|
+
* (e.g. graph's `--resolution` once its value validation moved from an
|
|
30
|
+
* in-handler `ValidationError` to a declarative `choices` in the launch command
|
|
31
|
+
* plane). These are usage errors and must exit `CONFIGURATION_ERROR` (2) — the
|
|
32
|
+
* same code `mapToolErrorToExitCode(ValidationError)` yields — preserving the
|
|
33
|
+
* pre-command-plane contract. Every OTHER Commander code (unknown command /
|
|
34
|
+
* option, missing argument, help/version display) keeps Commander's own
|
|
35
|
+
* `exitCode`, which already matched launch.
|
|
36
|
+
*/
|
|
37
|
+
const COMMANDER_INVALID_ARGUMENT_CODES = new Set([
|
|
38
|
+
'commander.invalidArgument',
|
|
39
|
+
'commander.invalidOptionArgument',
|
|
40
|
+
]);
|
|
41
|
+
/**
|
|
42
|
+
* Map a Commander `exitOverride` error to an exit code, re-mapping only the
|
|
43
|
+
* invalid-argument-value codes to `CONFIGURATION_ERROR` (2) to match the typed
|
|
44
|
+
* `ValidationError` semantics the declarative `choices` replaced. All other
|
|
45
|
+
* Commander conditions retain Commander's own `exitCode`.
|
|
46
|
+
*/
|
|
47
|
+
function commanderExitCode(error) {
|
|
48
|
+
return COMMANDER_INVALID_ARGUMENT_CODES.has(error.code)
|
|
49
|
+
? EXIT_CODES.CONFIGURATION_ERROR
|
|
50
|
+
: error.exitCode;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Per-class action hints. Adding a new ToolError subclass with a
|
|
54
|
+
* suggested user action is one tuple here; the exit code comes from
|
|
55
|
+
* `mapToolErrorToExitCode` so the policy stays in one place.
|
|
56
|
+
*/
|
|
57
|
+
const ACTION_HINTS = [
|
|
58
|
+
{
|
|
59
|
+
is: (e) => e instanceof NotFoundError,
|
|
60
|
+
action: 'Run opensip fit --list to see available checks.',
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
is: (e) => e instanceof ConfigurationError,
|
|
64
|
+
action: 'Check opensip-cli.config.yml or your --language flag.',
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
is: (e) => e instanceof NetworkError,
|
|
68
|
+
action: 'Check the --report-to URL and your network connection.',
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
is: (e) => e instanceof PluginIncompatibleError,
|
|
72
|
+
action: 'Upgrade OpenSIP CLI (or the tool), or allowlist a project-local tool via OPENSIP_CLI_ALLOW_PROJECT_TOOLS.',
|
|
73
|
+
},
|
|
74
|
+
];
|
|
75
|
+
function suggestionFromTypedError(error) {
|
|
76
|
+
if (!(error instanceof ToolError))
|
|
77
|
+
return null;
|
|
78
|
+
const hint = ACTION_HINTS.find((rule) => rule.is(error));
|
|
79
|
+
return {
|
|
80
|
+
message: error.message,
|
|
81
|
+
...(hint ? { action: hint.action } : {}),
|
|
82
|
+
exitCode: mapToolErrorToExitCode(error),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/** Inert renderer for the `--json` paths — `renderOutcome` never renders in JSON mode. */
|
|
86
|
+
const NOOP_RENDER = () => Promise.resolve();
|
|
87
|
+
/**
|
|
88
|
+
* The catch handler for `program.parseAsync()`. Maps the thrown error to a
|
|
89
|
+
* `CommandOutcome` (launch, §5.5): `--json` emits the structured outcome
|
|
90
|
+
* on stdout, human mode renders byte-identically to launch. Routes the exit code
|
|
91
|
+
* through `setExitCode`. Never throws.
|
|
92
|
+
*/
|
|
93
|
+
export async function handleParseError(error, opts) {
|
|
94
|
+
// Commander's own parse failures (surfaced because the root program calls
|
|
95
|
+
// `.exitOverride()`). Commander has ALREADY written its error/usage line to
|
|
96
|
+
// stderr (or the help text to stdout), so we set the exit code and render
|
|
97
|
+
// nothing — re-rendering would duplicate Commander's output and regress the
|
|
98
|
+
// legacy-identical stderr for unknown-command/option/missing-arg cases. Only
|
|
99
|
+
// the invalid-argument-value codes are re-mapped to exit 2 (ValidationError
|
|
100
|
+
// parity); every other code keeps Commander's exit code.
|
|
101
|
+
if (error instanceof CommanderError) {
|
|
102
|
+
opts.setExitCode(commanderExitCode(error));
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
// Pre-handler bootstrap failures (§4.7): no-project, schema-too-old,
|
|
106
|
+
// config-resolve, tool-init. The guard threw a typed BootstrapError carrying its
|
|
107
|
+
// own exit code, a clean message, and the original multi-line human text. In
|
|
108
|
+
// human mode we write that text to stderr verbatim — byte-identical to the
|
|
109
|
+
// legacy guard output; in `--json` we emit a structured `bootstrap.error`.
|
|
110
|
+
if (error instanceof BootstrapError) {
|
|
111
|
+
opts.setExitCode(error.exitCode);
|
|
112
|
+
if (opts.jsonRequested) {
|
|
113
|
+
await renderOutcome(outcomeFromErrorMessage({
|
|
114
|
+
message: error.message,
|
|
115
|
+
exitCode: error.exitCode,
|
|
116
|
+
kind: 'bootstrap.error',
|
|
117
|
+
...(error.suggestion ? { suggestion: error.suggestion } : {}),
|
|
118
|
+
}), { jsonRequested: true, render: NOOP_RENDER });
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
process.stderr.write(`${error.humanMessage}\n`);
|
|
122
|
+
}
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const typed = suggestionFromTypedError(error);
|
|
126
|
+
const suggestion = typed ?? getErrorSuggestion(error);
|
|
127
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
128
|
+
const exitCode = suggestion?.exitCode ?? EXIT_CODES.RUNTIME_ERROR;
|
|
129
|
+
opts.setExitCode(exitCode);
|
|
130
|
+
// `--json`: one outcome shape for every error (no Ink to stdout).
|
|
131
|
+
if (opts.jsonRequested) {
|
|
132
|
+
await renderOutcome(outcomeFromError(error, { kind: 'command.error' }), {
|
|
133
|
+
jsonRequested: true,
|
|
134
|
+
render: NOOP_RENDER,
|
|
135
|
+
});
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
// Human: the existing Ink `ErrorResult` render (byte-identical to launch).
|
|
139
|
+
await opts.render({
|
|
140
|
+
type: 'error',
|
|
141
|
+
message: suggestion?.message ?? message,
|
|
142
|
+
...(suggestion?.action ? { suggestion: suggestion.action } : {}),
|
|
143
|
+
exitCode,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Top-level fatal-error handler for failures BEFORE Commander's parse
|
|
148
|
+
* loop runs (bootstrap registration, dynamic plugin imports, preflight
|
|
149
|
+
* I/O). Sets `process.exitCode` (not `process.exit(N)` — the latter
|
|
150
|
+
* skips the pending stderr flush, and any structured-logging hook on
|
|
151
|
+
* bootstrap failure has nowhere to attach), writes the error line to
|
|
152
|
+
* stderr, and emits a `cli.bootstrap.failed` log event so observability
|
|
153
|
+
* pipelines see the failure. Audit 2026-05-23 G1.
|
|
154
|
+
*
|
|
155
|
+
* Exit code: a typed `ToolError` (e.g. the `PluginIncompatibleError` the
|
|
156
|
+
* Phase-3 fail-closed admission path throws) routes through the canonical
|
|
157
|
+
* `mapToolErrorToExitCode` policy so a fail-closed plugin yields exit 5
|
|
158
|
+
* (`PLUGIN_INCOMPATIBLE`) even when it surfaces from bootstrap rather than
|
|
159
|
+
* Commander's parse loop. Untyped errors keep the historical exit 1.
|
|
160
|
+
*
|
|
161
|
+
* Synchronous because every step here is sync — stderr write,
|
|
162
|
+
* structured-log call, exit-code set. The top-level caller doesn't
|
|
163
|
+
* need to `await` it (Node exits naturally with the configured
|
|
164
|
+
* `process.exitCode` after the event loop drains), but the call site
|
|
165
|
+
* is fine to `await` either way.
|
|
166
|
+
*/
|
|
167
|
+
export function handleFatalBootstrapError(error, log) {
|
|
168
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
169
|
+
const exitCode = error instanceof ToolError ? mapToolErrorToExitCode(error) : EXIT_CODES.RUNTIME_ERROR;
|
|
170
|
+
process.stderr.write(`opensip: fatal error: ${message}\n`);
|
|
171
|
+
log.error({
|
|
172
|
+
evt: 'cli.bootstrap.failed',
|
|
173
|
+
module: 'cli:bootstrap',
|
|
174
|
+
error: message,
|
|
175
|
+
exitCode,
|
|
176
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
177
|
+
});
|
|
178
|
+
process.exitCode = exitCode;
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=error-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-handler.js","sourceRoot":"","sources":["../src/error-handler.ts"],"names":[],"mappings":"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"}
|