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.
Files changed (348) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +8 -0
  3. package/README.md +51 -0
  4. package/dist/api.d.ts +17 -0
  5. package/dist/api.d.ts.map +1 -0
  6. package/dist/api.js +16 -0
  7. package/dist/api.js.map +1 -0
  8. package/dist/bootstrap/admit-tool-package.d.ts +117 -0
  9. package/dist/bootstrap/admit-tool-package.d.ts.map +1 -0
  10. package/dist/bootstrap/admit-tool-package.js +170 -0
  11. package/dist/bootstrap/admit-tool-package.js.map +1 -0
  12. package/dist/bootstrap/baseline-seams.d.ts +30 -0
  13. package/dist/bootstrap/baseline-seams.d.ts.map +1 -0
  14. package/dist/bootstrap/baseline-seams.js +156 -0
  15. package/dist/bootstrap/baseline-seams.js.map +1 -0
  16. package/dist/bootstrap/bootstrap-error.d.ts +41 -0
  17. package/dist/bootstrap/bootstrap-error.d.ts.map +1 -0
  18. package/dist/bootstrap/bootstrap-error.js +33 -0
  19. package/dist/bootstrap/bootstrap-error.js.map +1 -0
  20. package/dist/bootstrap/build-command-registration-input.d.ts +34 -0
  21. package/dist/bootstrap/build-command-registration-input.d.ts.map +1 -0
  22. package/dist/bootstrap/build-command-registration-input.js +73 -0
  23. package/dist/bootstrap/build-command-registration-input.js.map +1 -0
  24. package/dist/bootstrap/build-per-run-scope.d.ts +62 -0
  25. package/dist/bootstrap/build-per-run-scope.d.ts.map +1 -0
  26. package/dist/bootstrap/build-per-run-scope.js +152 -0
  27. package/dist/bootstrap/build-per-run-scope.js.map +1 -0
  28. package/dist/bootstrap/build-targets.d.ts +42 -0
  29. package/dist/bootstrap/build-targets.d.ts.map +1 -0
  30. package/dist/bootstrap/build-targets.js +117 -0
  31. package/dist/bootstrap/build-targets.js.map +1 -0
  32. package/dist/bootstrap/cli-defaults.d.ts +35 -0
  33. package/dist/bootstrap/cli-defaults.d.ts.map +1 -0
  34. package/dist/bootstrap/cli-defaults.js +65 -0
  35. package/dist/bootstrap/cli-defaults.js.map +1 -0
  36. package/dist/bootstrap/config-and-capabilities.d.ts +74 -0
  37. package/dist/bootstrap/config-and-capabilities.d.ts.map +1 -0
  38. package/dist/bootstrap/config-and-capabilities.js +224 -0
  39. package/dist/bootstrap/config-and-capabilities.js.map +1 -0
  40. package/dist/bootstrap/deliver-envelope.d.ts +80 -0
  41. package/dist/bootstrap/deliver-envelope.d.ts.map +1 -0
  42. package/dist/bootstrap/deliver-envelope.js +195 -0
  43. package/dist/bootstrap/deliver-envelope.js.map +1 -0
  44. package/dist/bootstrap/egress-plane.d.ts +22 -0
  45. package/dist/bootstrap/egress-plane.d.ts.map +1 -0
  46. package/dist/bootstrap/egress-plane.js +37 -0
  47. package/dist/bootstrap/egress-plane.js.map +1 -0
  48. package/dist/bootstrap/host-planes.d.ts +28 -0
  49. package/dist/bootstrap/host-planes.d.ts.map +1 -0
  50. package/dist/bootstrap/host-planes.js +152 -0
  51. package/dist/bootstrap/host-planes.js.map +1 -0
  52. package/dist/bootstrap/index.d.ts +76 -0
  53. package/dist/bootstrap/index.d.ts.map +1 -0
  54. package/dist/bootstrap/index.js +109 -0
  55. package/dist/bootstrap/index.js.map +1 -0
  56. package/dist/bootstrap/live-plane.d.ts +51 -0
  57. package/dist/bootstrap/live-plane.d.ts.map +1 -0
  58. package/dist/bootstrap/live-plane.js +72 -0
  59. package/dist/bootstrap/live-plane.js.map +1 -0
  60. package/dist/bootstrap/load-tool-capabilities.d.ts +42 -0
  61. package/dist/bootstrap/load-tool-capabilities.d.ts.map +1 -0
  62. package/dist/bootstrap/load-tool-capabilities.js +76 -0
  63. package/dist/bootstrap/load-tool-capabilities.js.map +1 -0
  64. package/dist/bootstrap/output-plane.d.ts +37 -0
  65. package/dist/bootstrap/output-plane.d.ts.map +1 -0
  66. package/dist/bootstrap/output-plane.js +114 -0
  67. package/dist/bootstrap/output-plane.js.map +1 -0
  68. package/dist/bootstrap/owning-tool-init.d.ts +32 -0
  69. package/dist/bootstrap/owning-tool-init.d.ts.map +1 -0
  70. package/dist/bootstrap/owning-tool-init.js +69 -0
  71. package/dist/bootstrap/owning-tool-init.js.map +1 -0
  72. package/dist/bootstrap/pre-action-guards.d.ts +44 -0
  73. package/dist/bootstrap/pre-action-guards.d.ts.map +1 -0
  74. package/dist/bootstrap/pre-action-guards.js +136 -0
  75. package/dist/bootstrap/pre-action-guards.js.map +1 -0
  76. package/dist/bootstrap/pre-action-hook.d.ts +68 -0
  77. package/dist/bootstrap/pre-action-hook.d.ts.map +1 -0
  78. package/dist/bootstrap/pre-action-hook.js +289 -0
  79. package/dist/bootstrap/pre-action-hook.js.map +1 -0
  80. package/dist/bootstrap/pre-action-messages.d.ts +32 -0
  81. package/dist/bootstrap/pre-action-messages.d.ts.map +1 -0
  82. package/dist/bootstrap/pre-action-messages.js +49 -0
  83. package/dist/bootstrap/pre-action-messages.js.map +1 -0
  84. package/dist/bootstrap/process-idempotency.d.ts +17 -0
  85. package/dist/bootstrap/process-idempotency.d.ts.map +1 -0
  86. package/dist/bootstrap/process-idempotency.js +20 -0
  87. package/dist/bootstrap/process-idempotency.js.map +1 -0
  88. package/dist/bootstrap/register-language-adapters.d.ts +23 -0
  89. package/dist/bootstrap/register-language-adapters.d.ts.map +1 -0
  90. package/dist/bootstrap/register-language-adapters.js +35 -0
  91. package/dist/bootstrap/register-language-adapters.js.map +1 -0
  92. package/dist/bootstrap/register-tools.d.ts +228 -0
  93. package/dist/bootstrap/register-tools.d.ts.map +1 -0
  94. package/dist/bootstrap/register-tools.js +696 -0
  95. package/dist/bootstrap/register-tools.js.map +1 -0
  96. package/dist/bootstrap/render.d.ts +27 -0
  97. package/dist/bootstrap/render.d.ts.map +1 -0
  98. package/dist/bootstrap/render.js +53 -0
  99. package/dist/bootstrap/render.js.map +1 -0
  100. package/dist/bootstrap/report.d.ts +34 -0
  101. package/dist/bootstrap/report.d.ts.map +1 -0
  102. package/dist/bootstrap/report.js +47 -0
  103. package/dist/bootstrap/report.js.map +1 -0
  104. package/dist/bootstrap/run-plane.d.ts +105 -0
  105. package/dist/bootstrap/run-plane.d.ts.map +1 -0
  106. package/dist/bootstrap/run-plane.js +190 -0
  107. package/dist/bootstrap/run-plane.js.map +1 -0
  108. package/dist/bootstrap/scope-access.d.ts +68 -0
  109. package/dist/bootstrap/scope-access.d.ts.map +1 -0
  110. package/dist/bootstrap/scope-access.js +115 -0
  111. package/dist/bootstrap/scope-access.js.map +1 -0
  112. package/dist/bootstrap/state-seams.d.ts +14 -0
  113. package/dist/bootstrap/state-seams.d.ts.map +1 -0
  114. package/dist/bootstrap/state-seams.js +26 -0
  115. package/dist/bootstrap/state-seams.js.map +1 -0
  116. package/dist/bootstrap/tool-lifecycle.d.ts +102 -0
  117. package/dist/bootstrap/tool-lifecycle.d.ts.map +1 -0
  118. package/dist/bootstrap/tool-lifecycle.js +103 -0
  119. package/dist/bootstrap/tool-lifecycle.js.map +1 -0
  120. package/dist/bootstrap/tool-trust.d.ts +49 -0
  121. package/dist/bootstrap/tool-trust.d.ts.map +1 -0
  122. package/dist/bootstrap/tool-trust.js +65 -0
  123. package/dist/bootstrap/tool-trust.js.map +1 -0
  124. package/dist/bootstrap/validate-tool.d.ts +22 -0
  125. package/dist/bootstrap/validate-tool.d.ts.map +1 -0
  126. package/dist/bootstrap/validate-tool.js +38 -0
  127. package/dist/bootstrap/validate-tool.js.map +1 -0
  128. package/dist/cli-context.d.ts +38 -0
  129. package/dist/cli-context.d.ts.map +1 -0
  130. package/dist/cli-context.js +134 -0
  131. package/dist/cli-context.js.map +1 -0
  132. package/dist/commands/agent-catalog.d.ts +45 -0
  133. package/dist/commands/agent-catalog.d.ts.map +1 -0
  134. package/dist/commands/agent-catalog.js +115 -0
  135. package/dist/commands/agent-catalog.js.map +1 -0
  136. package/dist/commands/assemble-outcome.d.ts +69 -0
  137. package/dist/commands/assemble-outcome.d.ts.map +1 -0
  138. package/dist/commands/assemble-outcome.js +121 -0
  139. package/dist/commands/assemble-outcome.js.map +1 -0
  140. package/dist/commands/clear.d.ts +32 -0
  141. package/dist/commands/clear.d.ts.map +1 -0
  142. package/dist/commands/clear.js +73 -0
  143. package/dist/commands/clear.js.map +1 -0
  144. package/dist/commands/completion.d.ts +90 -0
  145. package/dist/commands/completion.d.ts.map +1 -0
  146. package/dist/commands/completion.js +233 -0
  147. package/dist/commands/completion.js.map +1 -0
  148. package/dist/commands/configure.d.ts +32 -0
  149. package/dist/commands/configure.d.ts.map +1 -0
  150. package/dist/commands/configure.js +94 -0
  151. package/dist/commands/configure.js.map +1 -0
  152. package/dist/commands/history.d.ts +18 -0
  153. package/dist/commands/history.d.ts.map +1 -0
  154. package/dist/commands/history.js +48 -0
  155. package/dist/commands/history.js.map +1 -0
  156. package/dist/commands/host-command-specs.d.ts +49 -0
  157. package/dist/commands/host-command-specs.d.ts.map +1 -0
  158. package/dist/commands/host-command-specs.js +331 -0
  159. package/dist/commands/host-command-specs.js.map +1 -0
  160. package/dist/commands/host-subcommand-groups.d.ts +69 -0
  161. package/dist/commands/host-subcommand-groups.d.ts.map +1 -0
  162. package/dist/commands/host-subcommand-groups.js +374 -0
  163. package/dist/commands/host-subcommand-groups.js.map +1 -0
  164. package/dist/commands/index.d.ts +36 -0
  165. package/dist/commands/index.d.ts.map +1 -0
  166. package/dist/commands/index.js +36 -0
  167. package/dist/commands/index.js.map +1 -0
  168. package/dist/commands/init/config-templates.d.ts +16 -0
  169. package/dist/commands/init/config-templates.d.ts.map +1 -0
  170. package/dist/commands/init/config-templates.js +108 -0
  171. package/dist/commands/init/config-templates.js.map +1 -0
  172. package/dist/commands/init/file-classifier.d.ts +40 -0
  173. package/dist/commands/init/file-classifier.d.ts.map +1 -0
  174. package/dist/commands/init/file-classifier.js +155 -0
  175. package/dist/commands/init/file-classifier.js.map +1 -0
  176. package/dist/commands/init/language-detection.d.ts +44 -0
  177. package/dist/commands/init/language-detection.d.ts.map +1 -0
  178. package/dist/commands/init/language-detection.js +124 -0
  179. package/dist/commands/init/language-detection.js.map +1 -0
  180. package/dist/commands/init/scaffold-writer.d.ts +26 -0
  181. package/dist/commands/init/scaffold-writer.d.ts.map +1 -0
  182. package/dist/commands/init/scaffold-writer.js +102 -0
  183. package/dist/commands/init/scaffold-writer.js.map +1 -0
  184. package/dist/commands/init/state-machine.d.ts +32 -0
  185. package/dist/commands/init/state-machine.d.ts.map +1 -0
  186. package/dist/commands/init/state-machine.js +105 -0
  187. package/dist/commands/init/state-machine.js.map +1 -0
  188. package/dist/commands/init.d.ts +95 -0
  189. package/dist/commands/init.d.ts.map +1 -0
  190. package/dist/commands/init.js +209 -0
  191. package/dist/commands/init.js.map +1 -0
  192. package/dist/commands/mount-command-spec.d.ts +106 -0
  193. package/dist/commands/mount-command-spec.d.ts.map +1 -0
  194. package/dist/commands/mount-command-spec.js +313 -0
  195. package/dist/commands/mount-command-spec.js.map +1 -0
  196. package/dist/commands/mount-result-command.d.ts +71 -0
  197. package/dist/commands/mount-result-command.d.ts.map +1 -0
  198. package/dist/commands/mount-result-command.js +76 -0
  199. package/dist/commands/mount-result-command.js.map +1 -0
  200. package/dist/commands/plugin/config-edit.d.ts +20 -0
  201. package/dist/commands/plugin/config-edit.d.ts.map +1 -0
  202. package/dist/commands/plugin/config-edit.js +102 -0
  203. package/dist/commands/plugin/config-edit.js.map +1 -0
  204. package/dist/commands/plugin/domain-resolution.d.ts +38 -0
  205. package/dist/commands/plugin/domain-resolution.d.ts.map +1 -0
  206. package/dist/commands/plugin/domain-resolution.js +98 -0
  207. package/dist/commands/plugin/domain-resolution.js.map +1 -0
  208. package/dist/commands/plugin/host-dir.d.ts +42 -0
  209. package/dist/commands/plugin/host-dir.d.ts.map +1 -0
  210. package/dist/commands/plugin/host-dir.js +168 -0
  211. package/dist/commands/plugin/host-dir.js.map +1 -0
  212. package/dist/commands/plugin-host-ops.d.ts +41 -0
  213. package/dist/commands/plugin-host-ops.d.ts.map +1 -0
  214. package/dist/commands/plugin-host-ops.js +114 -0
  215. package/dist/commands/plugin-host-ops.js.map +1 -0
  216. package/dist/commands/plugin.d.ts +81 -0
  217. package/dist/commands/plugin.d.ts.map +1 -0
  218. package/dist/commands/plugin.js +287 -0
  219. package/dist/commands/plugin.js.map +1 -0
  220. package/dist/commands/render-outcome.d.ts +52 -0
  221. package/dist/commands/render-outcome.d.ts.map +1 -0
  222. package/dist/commands/render-outcome.js +55 -0
  223. package/dist/commands/render-outcome.js.map +1 -0
  224. package/dist/commands/session-show.d.ts +27 -0
  225. package/dist/commands/session-show.d.ts.map +1 -0
  226. package/dist/commands/session-show.js +166 -0
  227. package/dist/commands/session-show.js.map +1 -0
  228. package/dist/commands/shared.d.ts +107 -0
  229. package/dist/commands/shared.d.ts.map +1 -0
  230. package/dist/commands/shared.js +13 -0
  231. package/dist/commands/shared.js.map +1 -0
  232. package/dist/commands/tools/data-purge.d.ts +20 -0
  233. package/dist/commands/tools/data-purge.d.ts.map +1 -0
  234. package/dist/commands/tools/data-purge.js +59 -0
  235. package/dist/commands/tools/data-purge.js.map +1 -0
  236. package/dist/commands/tools/index.d.ts +16 -0
  237. package/dist/commands/tools/index.d.ts.map +1 -0
  238. package/dist/commands/tools/index.js +213 -0
  239. package/dist/commands/tools/index.js.map +1 -0
  240. package/dist/commands/tools/install.d.ts +24 -0
  241. package/dist/commands/tools/install.d.ts.map +1 -0
  242. package/dist/commands/tools/install.js +83 -0
  243. package/dist/commands/tools/install.js.map +1 -0
  244. package/dist/commands/tools/list.d.ts +41 -0
  245. package/dist/commands/tools/list.d.ts.map +1 -0
  246. package/dist/commands/tools/list.js +103 -0
  247. package/dist/commands/tools/list.js.map +1 -0
  248. package/dist/commands/tools/runtime-probe-entry.d.ts +14 -0
  249. package/dist/commands/tools/runtime-probe-entry.d.ts.map +1 -0
  250. package/dist/commands/tools/runtime-probe-entry.js +36 -0
  251. package/dist/commands/tools/runtime-probe-entry.js.map +1 -0
  252. package/dist/commands/tools/runtime-probe.d.ts +29 -0
  253. package/dist/commands/tools/runtime-probe.d.ts.map +1 -0
  254. package/dist/commands/tools/runtime-probe.js +66 -0
  255. package/dist/commands/tools/runtime-probe.js.map +1 -0
  256. package/dist/commands/tools/storage-contract-checks.d.ts +37 -0
  257. package/dist/commands/tools/storage-contract-checks.d.ts.map +1 -0
  258. package/dist/commands/tools/storage-contract-checks.js +91 -0
  259. package/dist/commands/tools/storage-contract-checks.js.map +1 -0
  260. package/dist/commands/tools/uninstall.d.ts +29 -0
  261. package/dist/commands/tools/uninstall.d.ts.map +1 -0
  262. package/dist/commands/tools/uninstall.js +77 -0
  263. package/dist/commands/tools/uninstall.js.map +1 -0
  264. package/dist/commands/tools/validate.d.ts +44 -0
  265. package/dist/commands/tools/validate.d.ts.map +1 -0
  266. package/dist/commands/tools/validate.js +202 -0
  267. package/dist/commands/tools/validate.js.map +1 -0
  268. package/dist/commands/uninstall/targets.d.ts +53 -0
  269. package/dist/commands/uninstall/targets.d.ts.map +1 -0
  270. package/dist/commands/uninstall/targets.js +205 -0
  271. package/dist/commands/uninstall/targets.js.map +1 -0
  272. package/dist/commands/uninstall.d.ts +88 -0
  273. package/dist/commands/uninstall.d.ts.map +1 -0
  274. package/dist/commands/uninstall.js +184 -0
  275. package/dist/commands/uninstall.js.map +1 -0
  276. package/dist/env/host-env-specs.d.ts +52 -0
  277. package/dist/env/host-env-specs.d.ts.map +1 -0
  278. package/dist/env/host-env-specs.js +129 -0
  279. package/dist/env/host-env-specs.js.map +1 -0
  280. package/dist/error-handler.d.ts +64 -0
  281. package/dist/error-handler.d.ts.map +1 -0
  282. package/dist/error-handler.js +180 -0
  283. package/dist/error-handler.js.map +1 -0
  284. package/dist/index.d.ts +21 -0
  285. package/dist/index.d.ts.map +1 -0
  286. package/dist/index.js +154 -0
  287. package/dist/index.js.map +1 -0
  288. package/dist/open-report.d.ts +40 -0
  289. package/dist/open-report.d.ts.map +1 -0
  290. package/dist/open-report.js +54 -0
  291. package/dist/open-report.js.map +1 -0
  292. package/dist/report-compose.d.ts +35 -0
  293. package/dist/report-compose.d.ts.map +1 -0
  294. package/dist/report-compose.js +103 -0
  295. package/dist/report-compose.js.map +1 -0
  296. package/dist/session-replay-registry.d.ts +20 -0
  297. package/dist/session-replay-registry.d.ts.map +1 -0
  298. package/dist/session-replay-registry.js +38 -0
  299. package/dist/session-replay-registry.js.map +1 -0
  300. package/dist/telemetry/profiling.d.ts +42 -0
  301. package/dist/telemetry/profiling.d.ts.map +1 -0
  302. package/dist/telemetry/profiling.js +160 -0
  303. package/dist/telemetry/profiling.js.map +1 -0
  304. package/dist/telemetry/sdk-init.d.ts +87 -0
  305. package/dist/telemetry/sdk-init.d.ts.map +1 -0
  306. package/dist/telemetry/sdk-init.js +235 -0
  307. package/dist/telemetry/sdk-init.js.map +1 -0
  308. package/dist/ui/App.d.ts +32 -0
  309. package/dist/ui/App.d.ts.map +1 -0
  310. package/dist/ui/App.js +35 -0
  311. package/dist/ui/App.js.map +1 -0
  312. package/dist/ui/render.d.ts +15 -0
  313. package/dist/ui/render.d.ts.map +1 -0
  314. package/dist/ui/render.js +21 -0
  315. package/dist/ui/render.js.map +1 -0
  316. package/dist/ui/result-to-view.d.ts +40 -0
  317. package/dist/ui/result-to-view.d.ts.map +1 -0
  318. package/dist/ui/result-to-view.js +389 -0
  319. package/dist/ui/result-to-view.js.map +1 -0
  320. package/dist/ui/views/init-view.d.ts +9 -0
  321. package/dist/ui/views/init-view.d.ts.map +1 -0
  322. package/dist/ui/views/init-view.js +119 -0
  323. package/dist/ui/views/init-view.js.map +1 -0
  324. package/dist/ui/views/misc-views.d.ts +18 -0
  325. package/dist/ui/views/misc-views.d.ts.map +1 -0
  326. package/dist/ui/views/misc-views.js +244 -0
  327. package/dist/ui/views/misc-views.js.map +1 -0
  328. package/dist/ui/views/plugin-view.d.ts +8 -0
  329. package/dist/ui/views/plugin-view.d.ts.map +1 -0
  330. package/dist/ui/views/plugin-view.js +135 -0
  331. package/dist/ui/views/plugin-view.js.map +1 -0
  332. package/dist/ui/views/tools-views.d.ts +12 -0
  333. package/dist/ui/views/tools-views.d.ts.map +1 -0
  334. package/dist/ui/views/tools-views.js +152 -0
  335. package/dist/ui/views/tools-views.js.map +1 -0
  336. package/dist/update-notifier.d.ts +108 -0
  337. package/dist/update-notifier.d.ts.map +1 -0
  338. package/dist/update-notifier.js +188 -0
  339. package/dist/update-notifier.js.map +1 -0
  340. package/dist/update-state.d.ts +40 -0
  341. package/dist/update-state.d.ts.map +1 -0
  342. package/dist/update-state.js +81 -0
  343. package/dist/update-state.js.map +1 -0
  344. package/dist/welcome.d.ts +53 -0
  345. package/dist/welcome.d.ts.map +1 -0
  346. package/dist/welcome.js +89 -0
  347. package/dist/welcome.js.map +1 -0
  348. 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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"}