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,108 @@
1
+ /**
2
+ * @fileoverview Thin wrapper around `update-notifier` that checks npm
3
+ * hourly for a newer version of opensip-cli (see UPDATE_CHECK_INTERVAL_MS).
4
+ *
5
+ * `update-notifier` is used purely as the *fetcher* — it runs the throttled
6
+ * (hourly), detached, non-blocking network check. It is NOT used as the
7
+ * display source, because its `check()` deletes the cached result the instant
8
+ * it's read, which would make the notice show at most once per fetch cycle.
9
+ * Instead the newest known version is mirrored into a sticky store
10
+ * (`update-state.ts`) that {@link checkForUpdate} consults on EVERY run, so
11
+ * the notice persists until the running version catches up. See
12
+ * `update-state.ts` for the rationale in full.
13
+ *
14
+ * Two consumers, one resolved result:
15
+ * - {@link checkForUpdate} returns the newer version string (if any) so
16
+ * the `mini` banner can surface it inline as `(<new-version> available)`.
17
+ * - {@link formatUpdateNag} builds the stderr one-liner shown for the
18
+ * other banner sizes (which have no version line to annotate).
19
+ * The bootstrap calls `checkForUpdate` once and decides which surface to use.
20
+ *
21
+ * Design goals:
22
+ * - Silent by default when there's nothing to report.
23
+ * - Persistent while a genuinely newer release exists; self-clearing the
24
+ * run after the user upgrades.
25
+ * - Opt-out via OPENSIP_NO_UPDATE (and honours the upstream
26
+ * NO_UPDATE_NOTIFIER flag for convention).
27
+ * - Non-blocking: the check runs in a child process; the current
28
+ * command never waits on network I/O.
29
+ *
30
+ * Suppressed when:
31
+ * - Env var OPENSIP_NO_UPDATE=1 (our flag)
32
+ * - Env var NO_UPDATE_NOTIFIER=1 (convention for the npm package)
33
+ * - Env var CI set (update-notifier suppresses by default)
34
+ * - stdout is not a TTY (scripts, pipelines)
35
+ */
36
+ import { type UpdateNotifier } from 'update-notifier';
37
+ /**
38
+ * How often the detached background fetch may hit npm to learn the latest
39
+ * published version. `update-notifier` throttles its network check to this
40
+ * interval; the sticky store (`update-state.ts`) then drives *display* on
41
+ * every run. This is therefore the worst-case DETECTION latency: a freshly
42
+ * published release becomes visible within one interval of going live (on the
43
+ * run after the next fetch completes — the fetch is detached, so never the
44
+ * same run).
45
+ *
46
+ * Set to 1 hour rather than the conventional 24h: the fetch is non-blocking,
47
+ * so a shorter interval costs the user nothing at the command line and only a
48
+ * modest amount of extra npm traffic (≤1 request/hour/user), while shrinking
49
+ * the "I published but the CLI still says up-to-date" window from a day to an
50
+ * hour. One named constant so the two call sites can't drift.
51
+ */
52
+ export declare const UPDATE_CHECK_INTERVAL_MS: number;
53
+ export interface NotifyOptions {
54
+ readonly name: string;
55
+ readonly version: string;
56
+ /** Override stderr writer (for tests). */
57
+ readonly write?: (s: string) => void;
58
+ }
59
+ export interface CheckForUpdateOptions {
60
+ readonly name: string;
61
+ readonly version: string;
62
+ /**
63
+ * Override the sticky update-state file path (for tests). Defaults to
64
+ * `~/.opensip-cli/update-state.json`.
65
+ */
66
+ readonly stateFile?: string;
67
+ }
68
+ /**
69
+ * Strict semver "is `latest` newer than `current`". Compares the numeric
70
+ * MAJOR.MINOR.PATCH core; with equal cores a prerelease (`1.0.0-beta`) is
71
+ * treated as OLDER than its release (`1.0.0`), per semver.
72
+ *
73
+ * This is the guard the nag relies on: the previous `latest !== current`
74
+ * check fired on ANY difference, so running a build AHEAD of npm's `latest`
75
+ * (a local dev build, or a prerelease) wrongly prompted a "downgrade". We
76
+ * only notify when there is a genuinely newer release to move TO.
77
+ */
78
+ export declare function isNewerVersion(latest: string, current: string): boolean;
79
+ /**
80
+ * Resolve whether a newer published version is available, scheduling the
81
+ * hourly background fetch as a side effect. Returns the newer version
82
+ * string (e.g. `1.0.1`) when one is known, or `undefined` when up-to-date,
83
+ * opted-out, or non-TTY.
84
+ *
85
+ * Unlike `update-notifier`'s own delete-on-read result, this is **sticky**:
86
+ * the newest version the hourly check observes is mirrored into a small store
87
+ * (`update-state.ts`) that is read on EVERY run, so the notice persists until
88
+ * the running version catches up — at which point the store is cleared and
89
+ * the notice stops on its own.
90
+ *
91
+ * Never throws: a malformed cache or notifier failure degrades to "no update
92
+ * known" rather than breaking the command. Callers decide how to surface it
93
+ * (the `mini` banner inline, or {@link formatUpdateNag} on stderr).
94
+ */
95
+ export declare function checkForUpdate(opts: CheckForUpdateOptions): string | undefined;
96
+ /**
97
+ * Build the stderr update-nag line for the non-`mini` banner sizes (which
98
+ * have no version line to annotate inline) and the banner-less `--json` path.
99
+ * The `mini` banner surfaces the same information in-box, so the bootstrap
100
+ * skips this for `mini`.
101
+ */
102
+ export declare function formatUpdateNag(current: string, latest: string): string;
103
+ /**
104
+ * Run the update check. Returns the notifier instance (so tests can
105
+ * assert) or null if skipped.
106
+ */
107
+ export declare function maybeNotify(opts: NotifyOptions): UpdateNotifier | null;
108
+ //# sourceMappingURL=update-notifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-notifier.d.ts","sourceRoot":"","sources":["../src/update-notifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAuB,EAAE,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAKtE;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,wBAAwB,QAAiB,CAAC;AAEvD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,0CAA0C;IAC1C,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AASD;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAWvE;AAeD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,qBAAqB,GAAG,MAAM,GAAG,SAAS,CAgC9E;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAMvE;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,aAAa,GAAG,cAAc,GAAG,IAAI,CAwBtE"}
@@ -0,0 +1,188 @@
1
+ /**
2
+ * @fileoverview Thin wrapper around `update-notifier` that checks npm
3
+ * hourly for a newer version of opensip-cli (see UPDATE_CHECK_INTERVAL_MS).
4
+ *
5
+ * `update-notifier` is used purely as the *fetcher* — it runs the throttled
6
+ * (hourly), detached, non-blocking network check. It is NOT used as the
7
+ * display source, because its `check()` deletes the cached result the instant
8
+ * it's read, which would make the notice show at most once per fetch cycle.
9
+ * Instead the newest known version is mirrored into a sticky store
10
+ * (`update-state.ts`) that {@link checkForUpdate} consults on EVERY run, so
11
+ * the notice persists until the running version catches up. See
12
+ * `update-state.ts` for the rationale in full.
13
+ *
14
+ * Two consumers, one resolved result:
15
+ * - {@link checkForUpdate} returns the newer version string (if any) so
16
+ * the `mini` banner can surface it inline as `(<new-version> available)`.
17
+ * - {@link formatUpdateNag} builds the stderr one-liner shown for the
18
+ * other banner sizes (which have no version line to annotate).
19
+ * The bootstrap calls `checkForUpdate` once and decides which surface to use.
20
+ *
21
+ * Design goals:
22
+ * - Silent by default when there's nothing to report.
23
+ * - Persistent while a genuinely newer release exists; self-clearing the
24
+ * run after the user upgrades.
25
+ * - Opt-out via OPENSIP_NO_UPDATE (and honours the upstream
26
+ * NO_UPDATE_NOTIFIER flag for convention).
27
+ * - Non-blocking: the check runs in a child process; the current
28
+ * command never waits on network I/O.
29
+ *
30
+ * Suppressed when:
31
+ * - Env var OPENSIP_NO_UPDATE=1 (our flag)
32
+ * - Env var NO_UPDATE_NOTIFIER=1 (convention for the npm package)
33
+ * - Env var CI set (update-notifier suppresses by default)
34
+ * - stdout is not a TTY (scripts, pipelines)
35
+ */
36
+ import updateNotifier from 'update-notifier';
37
+ import { hostEnv } from './env/host-env-specs.js';
38
+ import { clearKnownLatest, readKnownLatest, writeKnownLatest } from './update-state.js';
39
+ /**
40
+ * How often the detached background fetch may hit npm to learn the latest
41
+ * published version. `update-notifier` throttles its network check to this
42
+ * interval; the sticky store (`update-state.ts`) then drives *display* on
43
+ * every run. This is therefore the worst-case DETECTION latency: a freshly
44
+ * published release becomes visible within one interval of going live (on the
45
+ * run after the next fetch completes — the fetch is detached, so never the
46
+ * same run).
47
+ *
48
+ * Set to 1 hour rather than the conventional 24h: the fetch is non-blocking,
49
+ * so a shorter interval costs the user nothing at the command line and only a
50
+ * modest amount of extra npm traffic (≤1 request/hour/user), while shrinking
51
+ * the "I published but the CLI still says up-to-date" window from a day to an
52
+ * hour. One named constant so the two call sites can't drift.
53
+ */
54
+ export const UPDATE_CHECK_INTERVAL_MS = 1000 * 60 * 60;
55
+ /** Split `1.0.0-beta.1` into `([1,0,0], 'beta.1')`; missing parts → 0 / ''. */
56
+ function splitPrerelease(version) {
57
+ const [core, ...rest] = version.split('-');
58
+ const nums = core.split('.').map((p) => Number.parseInt(p, 10) || 0);
59
+ return [nums, rest.join('-')];
60
+ }
61
+ /**
62
+ * Strict semver "is `latest` newer than `current`". Compares the numeric
63
+ * MAJOR.MINOR.PATCH core; with equal cores a prerelease (`1.0.0-beta`) is
64
+ * treated as OLDER than its release (`1.0.0`), per semver.
65
+ *
66
+ * This is the guard the nag relies on: the previous `latest !== current`
67
+ * check fired on ANY difference, so running a build AHEAD of npm's `latest`
68
+ * (a local dev build, or a prerelease) wrongly prompted a "downgrade". We
69
+ * only notify when there is a genuinely newer release to move TO.
70
+ */
71
+ export function isNewerVersion(latest, current) {
72
+ const [latestCore, latestPre] = splitPrerelease(latest);
73
+ const [currentCore, currentPre] = splitPrerelease(current);
74
+ for (let i = 0; i < 3; i++) {
75
+ const l = latestCore[i] ?? 0;
76
+ const c = currentCore[i] ?? 0;
77
+ if (l > c)
78
+ return true;
79
+ if (l < c)
80
+ return false;
81
+ }
82
+ // Cores equal: a full release is newer than a prerelease of the same core.
83
+ return latestPre === '' && currentPre !== '';
84
+ }
85
+ function shouldSkip() {
86
+ // Either opt-out (read through the registry) skips the check — byte-identical
87
+ // to the prior two independent truthy `process.env` checks.
88
+ if (hostEnv.get('OPENSIP_NO_UPDATE') === true)
89
+ return true;
90
+ if (hostEnv.get('NO_UPDATE_NOTIFIER') === true)
91
+ return true;
92
+ // The update-notifier package already suppresses in CI and non-TTY,
93
+ // but we short-circuit so we don't even construct the notifier —
94
+ // keeps the startup path minimal.
95
+ // eslint-disable-next-line no-restricted-properties -- a `.isTTY` capability READ (terminal detection), not run output; the seam rule targets stdout writes, not TTY probing.
96
+ if (!process.stdout.isTTY)
97
+ return true;
98
+ return false;
99
+ }
100
+ /**
101
+ * Resolve whether a newer published version is available, scheduling the
102
+ * hourly background fetch as a side effect. Returns the newer version
103
+ * string (e.g. `1.0.1`) when one is known, or `undefined` when up-to-date,
104
+ * opted-out, or non-TTY.
105
+ *
106
+ * Unlike `update-notifier`'s own delete-on-read result, this is **sticky**:
107
+ * the newest version the hourly check observes is mirrored into a small store
108
+ * (`update-state.ts`) that is read on EVERY run, so the notice persists until
109
+ * the running version catches up — at which point the store is cleared and
110
+ * the notice stops on its own.
111
+ *
112
+ * Never throws: a malformed cache or notifier failure degrades to "no update
113
+ * known" rather than breaking the command. Callers decide how to surface it
114
+ * (the `mini` banner inline, or {@link formatUpdateNag} on stderr).
115
+ */
116
+ export function checkForUpdate(opts) {
117
+ if (shouldSkip())
118
+ return undefined;
119
+ try {
120
+ // Fetcher: schedules the throttled, detached hourly network check. On the
121
+ // run right after that check completes, `notifier.update` is populated
122
+ // (then update-notifier deletes it from its own cache — hence the mirror).
123
+ const notifier = updateNotifier({
124
+ pkg: { name: opts.name, version: opts.version },
125
+ updateCheckInterval: UPDATE_CHECK_INTERVAL_MS,
126
+ shouldNotifyInNpmScript: false,
127
+ });
128
+ const fresh = notifier.update;
129
+ if (fresh && isNewerVersion(fresh.latest, fresh.current)) {
130
+ writeKnownLatest(fresh.latest, opts.stateFile);
131
+ }
132
+ // @fitness-ignore-next-line error-handling-quality -- the update fetch is best-effort cosmetic: any failure (corrupt cache, network helper error) must degrade silently, never break the user's command. The sticky store below still drives display from whatever was last known.
133
+ }
134
+ catch {
135
+ // Intentionally swallow — see the directive above. Display falls through
136
+ // to readKnownLatest, so a failed fetch just shows the last known state.
137
+ }
138
+ // Display: driven entirely by the sticky store so the notice persists across
139
+ // runs. Clear it once the running version has caught up so it self-stops
140
+ // after an upgrade.
141
+ const known = readKnownLatest(opts.stateFile);
142
+ if (known && isNewerVersion(known, opts.version)) {
143
+ return known;
144
+ }
145
+ if (known) {
146
+ clearKnownLatest(opts.stateFile);
147
+ }
148
+ return undefined;
149
+ }
150
+ /**
151
+ * Build the stderr update-nag line for the non-`mini` banner sizes (which
152
+ * have no version line to annotate inline) and the banner-less `--json` path.
153
+ * The `mini` banner surfaces the same information in-box, so the bootstrap
154
+ * skips this for `mini`.
155
+ */
156
+ export function formatUpdateNag(current, latest) {
157
+ return (`\nOpenSIP CLI ${current} -> ${latest} available. ` +
158
+ `Run \`curl -fsSL https://opensip.ai/cli/install.sh | bash\` to update.\n` +
159
+ `(Silence with OPENSIP_NO_UPDATE=1.)\n\n`);
160
+ }
161
+ /**
162
+ * Run the update check. Returns the notifier instance (so tests can
163
+ * assert) or null if skipped.
164
+ */
165
+ export function maybeNotify(opts) {
166
+ if (shouldSkip())
167
+ return null;
168
+ const notifier = updateNotifier({
169
+ pkg: { name: opts.name, version: opts.version },
170
+ // Hourly (UPDATE_CHECK_INTERVAL_MS) — the detached fetch never blocks the
171
+ // command, so we trade a little npm traffic for sub-hourly detection.
172
+ updateCheckInterval: UPDATE_CHECK_INTERVAL_MS,
173
+ shouldNotifyInNpmScript: false,
174
+ });
175
+ const update = notifier.update;
176
+ // Only nag when npm's latest is genuinely NEWER than what's running — not
177
+ // merely different. Guards against the "1.0.1 → 1.0.0 available" downgrade
178
+ // prompt seen when running a build ahead of the published `latest` tag.
179
+ if (update && isNewerVersion(update.latest, update.current)) {
180
+ const write = opts.write ?? ((s) => process.stderr.write(s));
181
+ const line = `\nOpenSIP CLI ${update.current} -> ${update.latest} available. ` +
182
+ `Run \`curl -fsSL https://opensip.ai/cli/install.sh | bash\` to update.\n` +
183
+ `(Silence with OPENSIP_NO_UPDATE=1.)\n\n`;
184
+ write(line);
185
+ }
186
+ return notifier;
187
+ }
188
+ //# sourceMappingURL=update-notifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-notifier.js","sourceRoot":"","sources":["../src/update-notifier.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * update-state — sticky persistence for the "update available" notice.
3
+ *
4
+ * `update-notifier` is a good *fetcher* (throttled — hourly here — detached
5
+ * background network check) but a poor *display* source: its `check()`
6
+ * deletes the cached result the instant it's read, so the notice would show
7
+ * at most once per fetch cycle. A user who blinks past one `fit` run would
8
+ * never see it again until the next hourly check repopulated the cache.
9
+ *
10
+ * This module owns the display state instead. The update notifier mirrors the
11
+ * newest known published version here; {@link readKnownLatest} is consulted on
12
+ * EVERY run so the notice persists, and {@link clearKnownLatest} wipes it the
13
+ * moment the running version catches up — so it stops on its own after an
14
+ * upgrade, with no stale "update available" lingering.
15
+ *
16
+ * The store is a tiny JSON file at `~/.opensip-cli/update-state.json`
17
+ * (see {@link resolveUserPaths}), kept separate from the user-authored
18
+ * `config.yml`. Reads and writes are best-effort: any failure degrades to
19
+ * "nothing known" rather than breaking the command.
20
+ */
21
+ /** Default store path: `~/.opensip-cli/update-state.json`. */
22
+ export declare function defaultUpdateStateFile(): string;
23
+ /**
24
+ * Read the last-known newer published version, or `undefined` when nothing is
25
+ * cached / the file is absent or unreadable. Never throws.
26
+ */
27
+ export declare function readKnownLatest(file?: string): string | undefined;
28
+ /**
29
+ * Persist the newest known published version so the notice survives across
30
+ * runs. No-ops on any I/O failure. Skips the write when the value is unchanged
31
+ * to avoid needless disk churn on every invocation.
32
+ */
33
+ export declare function writeKnownLatest(latest: string, file?: string): void;
34
+ /**
35
+ * Clear the cached version — called once the running version catches up, so
36
+ * the notice stops on its own after an upgrade. No-ops when already absent or
37
+ * on any I/O failure.
38
+ */
39
+ export declare function clearKnownLatest(file?: string): void;
40
+ //# sourceMappingURL=update-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-state.d.ts","sourceRoot":"","sources":["../src/update-state.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;GAmBG;AAaH,8DAA8D;AAC9D,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,GAAE,MAAiC,GAAG,MAAM,GAAG,SAAS,CAU3F;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE,MAAiC,GAAG,IAAI,CAS9F;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,GAAE,MAAiC,GAAG,IAAI,CAS9E"}
@@ -0,0 +1,81 @@
1
+ // @fitness-ignore-file error-handling-quality -- every function here is best-effort cosmetic state for the "update available" notice: any failure (missing dir, malformed JSON, EACCES) must degrade silently to "nothing known" and never break the user's command. Absence and corruption are deliberately equivalent to "no update known".
2
+ // @fitness-ignore-file unbounded-memory -- reads ~/.opensip-cli/update-state.json, a tiny tool-generated cache holding a single version string.
3
+ /**
4
+ * update-state — sticky persistence for the "update available" notice.
5
+ *
6
+ * `update-notifier` is a good *fetcher* (throttled — hourly here — detached
7
+ * background network check) but a poor *display* source: its `check()`
8
+ * deletes the cached result the instant it's read, so the notice would show
9
+ * at most once per fetch cycle. A user who blinks past one `fit` run would
10
+ * never see it again until the next hourly check repopulated the cache.
11
+ *
12
+ * This module owns the display state instead. The update notifier mirrors the
13
+ * newest known published version here; {@link readKnownLatest} is consulted on
14
+ * EVERY run so the notice persists, and {@link clearKnownLatest} wipes it the
15
+ * moment the running version catches up — so it stops on its own after an
16
+ * upgrade, with no stale "update available" lingering.
17
+ *
18
+ * The store is a tiny JSON file at `~/.opensip-cli/update-state.json`
19
+ * (see {@link resolveUserPaths}), kept separate from the user-authored
20
+ * `config.yml`. Reads and writes are best-effort: any failure degrades to
21
+ * "nothing known" rather than breaking the command.
22
+ */
23
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
24
+ import { dirname } from 'node:path';
25
+ import { resolveUserPaths } from '@opensip-cli/core';
26
+ /** Default store path: `~/.opensip-cli/update-state.json`. */
27
+ export function defaultUpdateStateFile() {
28
+ return resolveUserPaths().updateStateFile;
29
+ }
30
+ /**
31
+ * Read the last-known newer published version, or `undefined` when nothing is
32
+ * cached / the file is absent or unreadable. Never throws.
33
+ */
34
+ export function readKnownLatest(file = defaultUpdateStateFile()) {
35
+ if (!existsSync(file))
36
+ return undefined;
37
+ try {
38
+ const parsed = JSON.parse(readFileSync(file, 'utf8'));
39
+ return typeof parsed.latest === 'string' && parsed.latest.length > 0
40
+ ? parsed.latest
41
+ : undefined;
42
+ }
43
+ catch {
44
+ return undefined;
45
+ }
46
+ }
47
+ /**
48
+ * Persist the newest known published version so the notice survives across
49
+ * runs. No-ops on any I/O failure. Skips the write when the value is unchanged
50
+ * to avoid needless disk churn on every invocation.
51
+ */
52
+ export function writeKnownLatest(latest, file = defaultUpdateStateFile()) {
53
+ if (readKnownLatest(file) === latest)
54
+ return;
55
+ try {
56
+ mkdirSync(dirname(file), { recursive: true });
57
+ writeFileSync(file, `${JSON.stringify({ latest }, null, 2)}\n`, 'utf8');
58
+ }
59
+ catch {
60
+ // Best-effort: a missing cache just means the notice falls back to
61
+ // update-notifier's once-per-cycle behaviour. Never break the command.
62
+ }
63
+ }
64
+ /**
65
+ * Clear the cached version — called once the running version catches up, so
66
+ * the notice stops on its own after an upgrade. No-ops when already absent or
67
+ * on any I/O failure.
68
+ */
69
+ export function clearKnownLatest(file = defaultUpdateStateFile()) {
70
+ if (!existsSync(file))
71
+ return;
72
+ try {
73
+ // Overwrite rather than unlink: keeps the file (and its dir perms) stable,
74
+ // and an empty `{}` reads back as "nothing known" via readKnownLatest.
75
+ writeFileSync(file, '{}\n', 'utf8');
76
+ }
77
+ catch {
78
+ // Ignore — a stale file at worst re-shows a notice that clears next run.
79
+ }
80
+ }
81
+ //# sourceMappingURL=update-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-state.js","sourceRoot":"","sources":["../src/update-state.ts"],"names":[],"mappings":"AAAA,8UAA8U;AAC9U,gJAAgJ;AAChJ;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAQrD,8DAA8D;AAC9D,MAAM,UAAU,sBAAsB;IACpC,OAAO,gBAAgB,EAAE,CAAC,eAAe,CAAC;AAC5C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,OAAe,sBAAsB,EAAE;IACrE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IACxC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAyB,CAAC;QAC9E,OAAO,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;YAClE,CAAC,CAAC,MAAM,CAAC,MAAM;YACf,CAAC,CAAC,SAAS,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc,EAAE,OAAe,sBAAsB,EAAE;IACtF,IAAI,eAAe,CAAC,IAAI,CAAC,KAAK,MAAM;QAAE,OAAO;IAC7C,IAAI,CAAC;QACH,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,aAAa,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAwB,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAChG,CAAC;IAAC,MAAM,CAAC;QACP,mEAAmE;QACnE,uEAAuE;IACzE,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAe,sBAAsB,EAAE;IACtE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO;IAC9B,IAAI,CAAC;QACH,2EAA2E;QAC3E,uEAAuE;QACvE,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,yEAAyE;IAC3E,CAAC;AACH,CAAC"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * @fileoverview Welcome message printed when `opensip` is invoked
3
+ * with no subcommand and no flags.
4
+ *
5
+ * Design goal: a new user typing `opensip` sees the two primary
6
+ * subcommands (fit / sim), a minimal quickstart, and a pointer at
7
+ * `--help` for everything else. Progressive disclosure: the tool
8
+ * decides what to show first rather than dumping the full help dump
9
+ * produced by commander.
10
+ *
11
+ * Called only when `process.argv.length <= 2`. When the user passes
12
+ * `--help` or `--version`, commander owns the output and this is
13
+ * never invoked.
14
+ *
15
+ * Theme bypass — load-bearing
16
+ * ---------------------------
17
+ * This module emits raw ANSI escape sequences directly to
18
+ * `process.stdout` rather than routing through Ink and `theme.ts`. The
19
+ * bypass is INTENTIONAL and is the F6 promise's documented exception:
20
+ *
21
+ * - The welcome screen is the very first thing a zero-arg invocation
22
+ * does. Loading Ink/React (~50 ms cold-start on a typical machine)
23
+ * to print twelve lines of static help would be a regression on
24
+ * `opensip` (no args) → welcome.
25
+ * - The render is fully static — no progress, no live updates, no
26
+ * theme-driven palette decisions. The only colour roles in use are
27
+ * bold, dim, and a single accent — all NO_COLOR / FORCE_COLOR
28
+ * aware via `colorsEnabled()`.
29
+ * - Theme drift risk is bounded: if a user customises `theme.ts`,
30
+ * they will see their accent everywhere EXCEPT the welcome
31
+ * screen. Acceptable — they typed nothing, so the screen is a
32
+ * handshake, not user-facing output. Audit 2026-05-23 G4 picked
33
+ * this option (b: tolerate the bypass, document it).
34
+ *
35
+ * If welcome ever grows dynamic content (recipe suggestions, recent-run
36
+ * peek, etc.) it should move to an Ink renderer + a `WelcomeResult`;
37
+ * delete this header at the same time.
38
+ */
39
+ export interface WelcomeOptions {
40
+ readonly version: string;
41
+ readonly write?: (s: string) => void;
42
+ }
43
+ /**
44
+ * Render the welcome message as a single string. Exported for testing.
45
+ */
46
+ export declare function buildWelcome(opts: WelcomeOptions): string;
47
+ /**
48
+ * Write the welcome message to stdout. Separate from `buildWelcome`
49
+ * so tests can assert on the rendered string without capturing
50
+ * process.stdout.
51
+ */
52
+ export declare function printWelcome(opts: WelcomeOptions): void;
53
+ //# sourceMappingURL=welcome.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"welcome.d.ts","sourceRoot":"","sources":["../src/welcome.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAkBD;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAuBzD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,CAGvD"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * @fileoverview Welcome message printed when `opensip` is invoked
3
+ * with no subcommand and no flags.
4
+ *
5
+ * Design goal: a new user typing `opensip` sees the two primary
6
+ * subcommands (fit / sim), a minimal quickstart, and a pointer at
7
+ * `--help` for everything else. Progressive disclosure: the tool
8
+ * decides what to show first rather than dumping the full help dump
9
+ * produced by commander.
10
+ *
11
+ * Called only when `process.argv.length <= 2`. When the user passes
12
+ * `--help` or `--version`, commander owns the output and this is
13
+ * never invoked.
14
+ *
15
+ * Theme bypass — load-bearing
16
+ * ---------------------------
17
+ * This module emits raw ANSI escape sequences directly to
18
+ * `process.stdout` rather than routing through Ink and `theme.ts`. The
19
+ * bypass is INTENTIONAL and is the F6 promise's documented exception:
20
+ *
21
+ * - The welcome screen is the very first thing a zero-arg invocation
22
+ * does. Loading Ink/React (~50 ms cold-start on a typical machine)
23
+ * to print twelve lines of static help would be a regression on
24
+ * `opensip` (no args) → welcome.
25
+ * - The render is fully static — no progress, no live updates, no
26
+ * theme-driven palette decisions. The only colour roles in use are
27
+ * bold, dim, and a single accent — all NO_COLOR / FORCE_COLOR
28
+ * aware via `colorsEnabled()`.
29
+ * - Theme drift risk is bounded: if a user customises `theme.ts`,
30
+ * they will see their accent everywhere EXCEPT the welcome
31
+ * screen. Acceptable — they typed nothing, so the screen is a
32
+ * handshake, not user-facing output. Audit 2026-05-23 G4 picked
33
+ * this option (b: tolerate the bypass, document it).
34
+ *
35
+ * If welcome ever grows dynamic content (recipe suggestions, recent-run
36
+ * peek, etc.) it should move to an Ink renderer + a `WelcomeResult`;
37
+ * delete this header at the same time.
38
+ */
39
+ const ANSI_BOLD = '\u001B[1m';
40
+ const ANSI_DIM = '\u001B[2m';
41
+ const ANSI_CYAN = '\u001B[36m';
42
+ const ANSI_RESET = '\u001B[0m';
43
+ /** True when stdout is a terminal and colors are safe to emit. */
44
+ function colorsEnabled() {
45
+ if (process.env.NO_COLOR)
46
+ return false;
47
+ if (process.env.FORCE_COLOR)
48
+ return true;
49
+ return Boolean(process.stdout.isTTY);
50
+ }
51
+ function color(enabled, code, text) {
52
+ return enabled ? `${code}${text}${ANSI_RESET}` : text;
53
+ }
54
+ /**
55
+ * Render the welcome message as a single string. Exported for testing.
56
+ */
57
+ export function buildWelcome(opts) {
58
+ const c = colorsEnabled();
59
+ const bold = (s) => color(c, ANSI_BOLD, s);
60
+ const dim = (s) => color(c, ANSI_DIM, s);
61
+ const accent = (s) => color(c, ANSI_CYAN, s);
62
+ return [
63
+ '',
64
+ `${bold('OpenSIP CLI')} ${dim(opts.version)} — codebase analysis toolkit`,
65
+ '',
66
+ `${bold('Primary commands:')}`,
67
+ ` ${accent('opensip fit')} Run fitness checks against your codebase`,
68
+ ` ${accent('opensip sim')} Run simulation scenarios`,
69
+ '',
70
+ `${bold('Getting started:')}`,
71
+ ` $ cd your-project`,
72
+ ` $ opensip init ${dim('# create a targets config')}`,
73
+ ` $ opensip fit ${dim('# run every registered check')}`,
74
+ '',
75
+ `${dim('Full reference: opensip --help')}`,
76
+ `${dim('Docs: https://github.com/opensip-ai/opensip-cli')}`,
77
+ '',
78
+ ].join('\n');
79
+ }
80
+ /**
81
+ * Write the welcome message to stdout. Separate from `buildWelcome`
82
+ * so tests can assert on the rendered string without capturing
83
+ * process.stdout.
84
+ */
85
+ export function printWelcome(opts) {
86
+ const write = opts.write ?? ((s) => process.stdout.write(s));
87
+ write(buildWelcome(opts));
88
+ }
89
+ //# sourceMappingURL=welcome.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"welcome.js","sourceRoot":"","sources":["../src/welcome.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAOH,MAAM,SAAS,GAAG,WAAW,CAAC;AAC9B,MAAM,QAAQ,GAAG,WAAW,CAAC;AAC7B,MAAM,SAAS,GAAG,YAAY,CAAC;AAC/B,MAAM,UAAU,GAAG,WAAW,CAAC;AAE/B,kEAAkE;AAClE,SAAS,aAAa;IACpB,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ;QAAE,OAAO,KAAK,CAAC;IACvC,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW;QAAE,OAAO,IAAI,CAAC;IACzC,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACvC,CAAC;AAED,SAAS,KAAK,CAAC,OAAgB,EAAE,IAAY,EAAE,IAAY;IACzD,OAAO,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,GAAG,UAAU,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACxD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,IAAoB;IAC/C,MAAM,CAAC,GAAG,aAAa,EAAE,CAAC;IAC1B,MAAM,IAAI,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;IAC3D,MAAM,GAAG,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;IACzD,MAAM,MAAM,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;IAE7D,OAAO;QACL,EAAE;QACF,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,8BAA8B;QACzE,EAAE;QACF,GAAG,IAAI,CAAC,mBAAmB,CAAC,EAAE;QAC9B,KAAK,MAAM,CAAC,aAAa,CAAC,kDAAkD;QAC5E,KAAK,MAAM,CAAC,aAAa,CAAC,kCAAkC;QAC5D,EAAE;QACF,GAAG,IAAI,CAAC,kBAAkB,CAAC,EAAE;QAC7B,qBAAqB;QACrB,0BAA0B,GAAG,CAAC,2BAA2B,CAAC,EAAE;QAC5D,0BAA0B,GAAG,CAAC,8BAA8B,CAAC,EAAE;QAC/D,EAAE;QACF,GAAG,GAAG,CAAC,gCAAgC,CAAC,EAAE;QAC1C,GAAG,GAAG,CAAC,2DAA2D,CAAC,EAAE;QACrE,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,IAAoB;IAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACrE,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;AAC5B,CAAC"}