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,155 @@
1
+ /**
2
+ * Pre-existing file classification for `opensip init`.
3
+ *
4
+ * Walks `opensip-cli/` (skipping `.runtime/`) and tags each file as
5
+ * 'scaffolded', 'stale-scaffolded', or 'custom' so `--keep` / `--remove`
6
+ * can decide what to overwrite and what to preserve.
7
+ */
8
+ import { createHash } from 'node:crypto';
9
+ import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
10
+ import { basename as pathBasename, join } from 'node:path';
11
+ import { ALL_LANGUAGES } from './language-detection.js';
12
+ /**
13
+ * Build the full set of scaffold templates that init would write for the given
14
+ * language set — registry-driven (ADR-0038): each tool's `scaffoldExamples` over
15
+ * the current languages, mapped to `userPluginDir(domain, file.kind)/filename`.
16
+ * Same bytes as before; the classifier detects "scaffolded" files via SHA-256.
17
+ */
18
+ function buildScaffoldTemplates(paths, languages, toolScaffolds) {
19
+ const templates = new Map();
20
+ for (const ts of toolScaffolds) {
21
+ if (!ts.scaffoldExamples)
22
+ continue;
23
+ for (const file of ts.scaffoldExamples({ languages })) {
24
+ templates.set(join(paths.userPluginDir(ts.layout.domain, file.kind), file.filename), file.content);
25
+ }
26
+ }
27
+ return templates;
28
+ }
29
+ function sha256(content) {
30
+ return createHash('sha256').update(content).digest('hex');
31
+ }
32
+ /**
33
+ * Walk every file under `opensip-cli/` (excluding `.runtime/`, which
34
+ * is gitignored runtime state and not user-authored) and tag each one.
35
+ *
36
+ * Classification rules:
37
+ *
38
+ * - 'scaffolded' — content matches a current-template byte-for-byte.
39
+ * - 'stale-scaffolded' — file shape matches a previous-language scaffold:
40
+ * filename `example-check-<lang>.mjs` for <lang>
41
+ * NOT in the current detection set, OR the file
42
+ * carries a pinned EXAMPLE_CHECK_IDS UUID for a
43
+ * language not in the current set.
44
+ * - 'custom' — anything else (user-authored).
45
+ *
46
+ * The walk is bounded to the `opensip-cli/` subtree (kilobytes in
47
+ * practice). The `.runtime/` subdir is skipped so caches/logs/sessions
48
+ * don't pollute the file list.
49
+ *
50
+ * Note on hash-based scaffolded detection: a scaffolded file that has
51
+ * been line-ending normalized (CRLF↔LF) or stripped of a trailing
52
+ * newline by an editor will not byte-for-byte match the template. In
53
+ * that case it falls back to 'custom' or 'stale-scaffolded' (when the
54
+ * UUID still matches but content drifted). The UUID-based fallback
55
+ * catches the common "stale language" case; cosmetic drift on a
56
+ * current-language file is treated as custom — which is the safer
57
+ * outcome (won't silently overwrite).
58
+ */
59
+ export function classifyFiles(paths, currentLanguages, toolScaffolds) {
60
+ if (!existsSync(paths.userSourceDir))
61
+ return [];
62
+ const templates = buildScaffoldTemplates(paths, currentLanguages, toolScaffolds);
63
+ const templateHashes = new Map();
64
+ for (const [absPath, body] of templates) {
65
+ templateHashes.set(absPath, sha256(body));
66
+ }
67
+ const currentLangSet = new Set(currentLanguages);
68
+ // Stale-id detection (ADR-0038): the COMPLETE id universe each tool owns
69
+ // (`stableExampleIds`), minus the ids the CURRENT languages scaffold. A file
70
+ // carrying a complete-but-not-current id is a stale scaffold for a config the
71
+ // project no longer uses; current-config ids are excluded so an edited
72
+ // current-language example (no content-hash match) stays `custom`.
73
+ const completeIds = new Set(toolScaffolds.flatMap((ts) => ts.stableExampleIds?.() ?? []));
74
+ const currentIds = new Set(toolScaffolds.flatMap((ts) => (ts.scaffoldExamples?.({ languages: currentLanguages }) ?? []).map((f) => f.stableId)));
75
+ const staleIds = [...completeIds].filter((id) => !currentIds.has(id));
76
+ const out = [];
77
+ // Walk the dir, skipping `.runtime/`.
78
+ const visit = (dir) => {
79
+ let entries;
80
+ try {
81
+ entries = readdirSync(dir);
82
+ }
83
+ catch {
84
+ // @fitness-ignore-next-line error-handling-quality -- directory walk probe: an unreadable directory means "no entries to classify here", same as a genuinely empty dir; failure IS the signal.
85
+ return;
86
+ }
87
+ for (const name of entries) {
88
+ const full = join(dir, name);
89
+ // Skip runtime state (gitignored, tool-managed).
90
+ if (full === paths.runtimeDir)
91
+ continue;
92
+ let st;
93
+ try {
94
+ st = statSync(full);
95
+ }
96
+ catch {
97
+ continue;
98
+ }
99
+ if (st.isDirectory()) {
100
+ visit(full);
101
+ continue;
102
+ }
103
+ if (!st.isFile())
104
+ continue;
105
+ out.push(classifyOneFile(full, templateHashes, currentLangSet, staleIds));
106
+ }
107
+ };
108
+ visit(paths.userSourceDir);
109
+ // Stable order — relative path ascending — so callers can render a
110
+ // deterministic list and tests can assert without sort gymnastics.
111
+ out.sort((a, b) => a.path.localeCompare(b.path));
112
+ return out;
113
+ }
114
+ const STALE_FILENAME_PATTERN = /^example-check-([a-z+]+)\.mjs$/;
115
+ function classifyOneFile(absPath, templateHashes, currentLangSet, staleIds) {
116
+ let content;
117
+ try {
118
+ content = readFileSync(absPath, 'utf8');
119
+ }
120
+ catch {
121
+ // Unreadable: surface as custom so we err on the side of preservation.
122
+ return { path: absPath, classification: 'custom' };
123
+ }
124
+ // 1) Content-hash match against current-template set.
125
+ const hash = sha256(content);
126
+ if (templateHashes.get(absPath) === hash) {
127
+ return { path: absPath, classification: 'scaffolded' };
128
+ }
129
+ // 2) Stale-by-filename: example-check-<lang>.mjs for <lang> not in
130
+ // current set.
131
+ // Use node:path basename so the separator extraction works on Windows.
132
+ // A hard-coded '/' would leave `basename` equal to the whole absolute
133
+ // Windows path (`lastIndexOf('/')` returns -1), and STALE_FILENAME_PATTERN
134
+ // would never match — silently misclassifying every stale-scaffolded
135
+ // file as 'custom' and breaking `--keep` semantics on Windows.
136
+ const basename = pathBasename(absPath);
137
+ const filenameMatch = STALE_FILENAME_PATTERN.exec(basename);
138
+ if (filenameMatch) {
139
+ const fileLang = filenameMatch[1];
140
+ if (fileLang &&
141
+ !currentLangSet.has(fileLang) &&
142
+ ALL_LANGUAGES.includes(fileLang)) {
143
+ return { path: absPath, classification: 'stale-scaffolded' };
144
+ }
145
+ }
146
+ // 3) Stale-by-pinned-id: any of the aggregated stale ids (the complete tool id
147
+ // universe minus the current-config ids) embedded in the file.
148
+ for (const id of staleIds) {
149
+ if (content.includes(id)) {
150
+ return { path: absPath, classification: 'stale-scaffolded' };
151
+ }
152
+ }
153
+ return { path: absPath, classification: 'custom' };
154
+ }
155
+ //# sourceMappingURL=file-classifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-classifier.js","sourceRoot":"","sources":["../../../src/commands/init/file-classifier.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Language detection for `opensip init`.
3
+ *
4
+ * Inspects the cwd for well-known language markers (Cargo.toml,
5
+ * pyproject.toml, go.mod, pom.xml/build.gradle, CMakeLists.txt,
6
+ * tsconfig.json/package.json) and returns the unique set of detected
7
+ * languages. Also parses the `--language <comma-separated>` flag that
8
+ * overrides detection.
9
+ */
10
+ export type SupportedLanguage = 'typescript' | 'rust' | 'python' | 'go' | 'java' | 'cpp';
11
+ export declare const ALL_LANGUAGES: readonly SupportedLanguage[];
12
+ /**
13
+ * Inspect the cwd for language markers. Returns the unique set of
14
+ * detected languages. TypeScript is detected only when there's a
15
+ * `tsconfig.json` (or a `package.json` with no other marker
16
+ * present — fallback for plain JS/TS projects).
17
+ */
18
+ export declare function detectLanguages(cwd: string): SupportedLanguage[];
19
+ /**
20
+ * Parse the `--language <comma-separated>` argv string into a list of
21
+ * known languages. Throws on unknown entries — the CLI surfaces it as
22
+ * an exit-2 configuration error.
23
+ *
24
+ * @throws {Error} When `raw` contains a token not present in `ALL_LANGUAGES`.
25
+ */
26
+ export declare function parseLanguageFlag(raw: string): SupportedLanguage[];
27
+ export type LanguageResolution = {
28
+ ok: true;
29
+ languages: SupportedLanguage[];
30
+ } | {
31
+ ok: false;
32
+ error: {
33
+ detected: SupportedLanguage[];
34
+ message: string;
35
+ };
36
+ };
37
+ /**
38
+ * Resolve the language set for an init run: either parse the explicit
39
+ * --language flag, or fall back to filesystem detection. Returns an
40
+ * error variant when no markers are found, or when multiple languages
41
+ * are detected without --language to disambiguate.
42
+ */
43
+ export declare function resolveLanguages(cwd: string, languageFlag: readonly string[] | undefined): LanguageResolution;
44
+ //# sourceMappingURL=language-detection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"language-detection.d.ts","sourceRoot":"","sources":["../../../src/commands/init/language-detection.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,MAAM,MAAM,iBAAiB,GAAG,YAAY,GAAG,MAAM,GAAG,QAAQ,GAAG,IAAI,GAAG,MAAM,GAAG,KAAK,CAAC;AAEzF,eAAO,MAAM,aAAa,EAAE,SAAS,iBAAiB,EAOrD,CAAC;AAmBF;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAiBhE;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAmBlE;AAED,MAAM,MAAM,kBAAkB,GAC1B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,iBAAiB,EAAE,CAAA;CAAE,GAC5C;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE;QAAE,QAAQ,EAAE,iBAAiB,EAAE,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC;AAE7E;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,GAC1C,kBAAkB,CAuCpB"}
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Language detection for `opensip init`.
3
+ *
4
+ * Inspects the cwd for well-known language markers (Cargo.toml,
5
+ * pyproject.toml, go.mod, pom.xml/build.gradle, CMakeLists.txt,
6
+ * tsconfig.json/package.json) and returns the unique set of detected
7
+ * languages. Also parses the `--language <comma-separated>` flag that
8
+ * overrides detection.
9
+ */
10
+ import { existsSync } from 'node:fs';
11
+ import { join } from 'node:path';
12
+ export const ALL_LANGUAGES = [
13
+ 'typescript',
14
+ 'rust',
15
+ 'python',
16
+ 'go',
17
+ 'java',
18
+ 'cpp',
19
+ ];
20
+ const ALL_LANGUAGES_SET = new Set(ALL_LANGUAGES);
21
+ const MARKERS = [
22
+ { language: 'rust', file: 'Cargo.toml', description: 'Rust workspace' },
23
+ { language: 'python', file: 'pyproject.toml', description: 'Python project' },
24
+ { language: 'python', file: 'setup.py', description: 'Python project (setup.py)' },
25
+ { language: 'go', file: 'go.mod', description: 'Go module' },
26
+ { language: 'java', file: 'pom.xml', description: 'Maven project' },
27
+ { language: 'java', file: 'build.gradle', description: 'Gradle project' },
28
+ { language: 'cpp', file: 'CMakeLists.txt', description: 'CMake project' },
29
+ ];
30
+ /**
31
+ * Inspect the cwd for language markers. Returns the unique set of
32
+ * detected languages. TypeScript is detected only when there's a
33
+ * `tsconfig.json` (or a `package.json` with no other marker
34
+ * present — fallback for plain JS/TS projects).
35
+ */
36
+ export function detectLanguages(cwd) {
37
+ const detected = new Set();
38
+ for (const marker of MARKERS) {
39
+ if (existsSync(join(cwd, marker.file)))
40
+ detected.add(marker.language);
41
+ }
42
+ // TypeScript: tsconfig.json is the strong signal. package.json alone
43
+ // is ambiguous — a Rust project might have a docs site with one — but
44
+ // ONLY when no other marker is present, treat it as a TS project.
45
+ const hasTsconfig = existsSync(join(cwd, 'tsconfig.json'));
46
+ const hasPackageJson = existsSync(join(cwd, 'package.json'));
47
+ if (hasTsconfig || (hasPackageJson && detected.size === 0)) {
48
+ detected.add('typescript');
49
+ }
50
+ return [...detected];
51
+ }
52
+ /**
53
+ * Parse the `--language <comma-separated>` argv string into a list of
54
+ * known languages. Throws on unknown entries — the CLI surfaces it as
55
+ * an exit-2 configuration error.
56
+ *
57
+ * @throws {Error} When `raw` contains a token not present in `ALL_LANGUAGES`.
58
+ */
59
+ export function parseLanguageFlag(raw) {
60
+ const out = [];
61
+ const seen = new Set();
62
+ for (const part of raw.split(',')) {
63
+ const trimmed = part.trim().toLowerCase();
64
+ if (trimmed.length === 0)
65
+ continue;
66
+ if (seen.has(trimmed))
67
+ continue;
68
+ if (!ALL_LANGUAGES_SET.has(trimmed)) {
69
+ throw new Error(`Unknown language '${trimmed}'. Expected one of: ${ALL_LANGUAGES.join(', ')}`);
70
+ }
71
+ seen.add(trimmed);
72
+ out.push(trimmed);
73
+ }
74
+ if (out.length === 0) {
75
+ throw new Error('--language received an empty list');
76
+ }
77
+ return out;
78
+ }
79
+ /**
80
+ * Resolve the language set for an init run: either parse the explicit
81
+ * --language flag, or fall back to filesystem detection. Returns an
82
+ * error variant when no markers are found, or when multiple languages
83
+ * are detected without --language to disambiguate.
84
+ */
85
+ export function resolveLanguages(cwd, languageFlag) {
86
+ if (languageFlag && languageFlag.length > 0) {
87
+ try {
88
+ // The flag is an accumulator (`--language ts --language rust`) whose
89
+ // elements may also be comma-separated (`--language ts,rust`). Join into
90
+ // one canonical comma-list and delegate to the established parser, which
91
+ // splits, trims, dedupes, and validates.
92
+ return { ok: true, languages: parseLanguageFlag(languageFlag.join(',')) };
93
+ }
94
+ catch (error) {
95
+ const msg = error instanceof Error ? error.message : String(error);
96
+ return { ok: false, error: { detected: [], message: msg } };
97
+ }
98
+ }
99
+ const detected = detectLanguages(cwd);
100
+ if (detected.length === 0) {
101
+ return {
102
+ ok: false,
103
+ error: {
104
+ detected: [],
105
+ message: 'No language markers found. Specify with: ' +
106
+ 'opensip init --language <typescript|rust|python|go|java|cpp> ' +
107
+ '(comma-separated for polyglot projects).',
108
+ },
109
+ };
110
+ }
111
+ if (detected.length > 1) {
112
+ return {
113
+ ok: false,
114
+ error: {
115
+ detected,
116
+ message: `Detected multiple languages: ${detected.join(', ')}. ` +
117
+ `Pass --language <comma-separated-list> to choose. ` +
118
+ `Example: opensip init --language ${detected.join(',')}`,
119
+ },
120
+ };
121
+ }
122
+ return { ok: true, languages: detected };
123
+ }
124
+ //# sourceMappingURL=language-detection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"language-detection.js","sourceRoot":"","sources":["../../../src/commands/init/language-detection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Disk-write phase for `opensip init`.
3
+ *
4
+ * Writes the config + example files, optionally preserving pre-existing
5
+ * custom/stale-scaffolded files (`--keep`) or wiping the user-source
6
+ * dir first (`--remove`). Also patches `.gitignore` to exclude the
7
+ * runtime state subtree.
8
+ */
9
+ import type { SupportedLanguage } from './language-detection.js';
10
+ import type { WorkingDirState } from './state-machine.js';
11
+ import type { ToolScaffold } from '../shared.js';
12
+ import type { InitResult, PreExistingFile } from '@opensip-cli/contracts';
13
+ import type { ProjectPaths } from '@opensip-cli/core';
14
+ export interface ScaffoldRunInputs {
15
+ readonly paths: ProjectPaths;
16
+ readonly languages: SupportedLanguage[];
17
+ readonly cwd: string;
18
+ readonly state: WorkingDirState;
19
+ readonly preExistingFiles: readonly PreExistingFile[];
20
+ readonly removeFirst: boolean;
21
+ readonly keepCustom: boolean;
22
+ /** Per-tool scaffold contributions (ADR-0038) — the directory layout + example bytes. */
23
+ readonly toolScaffolds: readonly ToolScaffold[];
24
+ }
25
+ export declare function runScaffold(inputs: ScaffoldRunInputs, baseResult: Pick<InitResult, 'type' | 'path' | 'cwd' | 'configFilename'>): InitResult;
26
+ //# sourceMappingURL=scaffold-writer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold-writer.d.ts","sourceRoot":"","sources":["../../../src/commands/init/scaffold-writer.ts"],"names":[],"mappings":"AACA;;;;;;;GAOG;AAOH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC1E,OAAO,KAAK,EAAE,YAAY,EAAmB,MAAM,mBAAmB,CAAC;AA2FvE,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,iBAAiB,EAAE,CAAC;IACxC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;IAChC,QAAQ,CAAC,gBAAgB,EAAE,SAAS,eAAe,EAAE,CAAC;IACtD,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,yFAAyF;IACzF,QAAQ,CAAC,aAAa,EAAE,SAAS,YAAY,EAAE,CAAC;CACjD;AAED,wBAAgB,WAAW,CACzB,MAAM,EAAE,iBAAiB,EACzB,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,gBAAgB,CAAC,GACvE,UAAU,CAuCZ"}
@@ -0,0 +1,102 @@
1
+ // @fitness-ignore-file unbounded-memory -- reads scaffold template files shipped with the CLI; bounded by the package's own embedded examples
2
+ /**
3
+ * Disk-write phase for `opensip init`.
4
+ *
5
+ * Writes the config + example files, optionally preserving pre-existing
6
+ * custom/stale-scaffolded files (`--keep`) or wiping the user-source
7
+ * dir first (`--remove`). Also patches `.gitignore` to exclude the
8
+ * runtime state subtree.
9
+ */
10
+ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
11
+ import { join } from 'node:path';
12
+ import { generateConfig } from './config-templates.js';
13
+ const GITIGNORE_LINE = 'opensip-cli/.runtime/';
14
+ function ensureGitignore(cwd) {
15
+ const path = join(cwd, '.gitignore');
16
+ if (!existsSync(path)) {
17
+ writeFileSync(path, `${GITIGNORE_LINE}\n`, 'utf8');
18
+ return true;
19
+ }
20
+ const content = readFileSync(path, 'utf8');
21
+ // @fitness-ignore-next-line silent-early-returns -- idempotent "did I modify?" return: boolean IS the function's contract (caller dispatches on "already present" vs "I appended")
22
+ if (content.split('\n').some((line) => line.trim() === GITIGNORE_LINE)) {
23
+ return false; // already present, idempotent
24
+ }
25
+ const sep = content.endsWith('\n') ? '' : '\n';
26
+ writeFileSync(path, `${content}${sep}\n# opensip-cli runtime state\n${GITIGNORE_LINE}\n`, 'utf8');
27
+ return true;
28
+ }
29
+ /**
30
+ * Write `content` to `filePath` according to the scaffold rules:
31
+ * - keepCustom = false → always overwrite (or create) the file.
32
+ * - keepCustom = true → preserve any pre-existing file we classified
33
+ * as 'custom' or 'stale-scaffolded'; overwrite
34
+ * 'scaffolded' files (and create missing ones).
35
+ */
36
+ function writeScaffoldedFile(filePath, content, keepCustom, preExistingByPath, createdFiles) {
37
+ if (keepCustom) {
38
+ const existing = preExistingByPath.get(filePath);
39
+ // Preserve user content. Stale-scaffolded is also preserved — the
40
+ // user may have been working with it; we surface it but don't
41
+ // overwrite.
42
+ if (existing &&
43
+ (existing.classification === 'custom' || existing.classification === 'stale-scaffolded')) {
44
+ return;
45
+ }
46
+ }
47
+ writeFileSync(filePath, content, 'utf8');
48
+ createdFiles.push(filePath);
49
+ }
50
+ /**
51
+ * ADR-0038: generic, registry-driven scaffold. For each registered tool's
52
+ * contribution: `mkdir` every `userSubdirs` kind under its `pluginLayout.domain`,
53
+ * then write each `ScaffoldFile` the tool's `scaffoldExamples(ctx)` returns under
54
+ * `userPluginDir(domain, file.kind)/file.filename`. No fit/sim/checks/recipes
55
+ * literals — the directory layout comes from each tool's `pluginLayout`, the
56
+ * example bytes from the tool (ADR-0009 corollary 1).
57
+ */
58
+ function scaffoldToolExamples(paths, toolScaffolds, ctx, options, createdFiles) {
59
+ for (const ts of toolScaffolds) {
60
+ if (!ts.scaffoldExamples)
61
+ continue;
62
+ for (const kind of ts.layout.userSubdirs) {
63
+ mkdirSync(paths.userPluginDir(ts.layout.domain, kind), { recursive: true });
64
+ }
65
+ for (const file of ts.scaffoldExamples(ctx)) {
66
+ writeScaffoldedFile(join(paths.userPluginDir(ts.layout.domain, file.kind), file.filename), file.content, options.keepCustom, options.preExistingByPath, createdFiles);
67
+ }
68
+ }
69
+ }
70
+ export function runScaffold(inputs, baseResult) {
71
+ const { paths, languages, cwd, state, preExistingFiles, removeFirst, keepCustom, toolScaffolds } = inputs;
72
+ // --remove: blow away the user-source dir before scaffolding. The
73
+ // config file is always rewritten below regardless.
74
+ if (removeFirst && existsSync(paths.userSourceDir)) {
75
+ rmSync(paths.userSourceDir, { recursive: true, force: true });
76
+ }
77
+ const createdFiles = [];
78
+ // Always rewrite the config — its content is a function of the
79
+ // selected languages, and a re-init with new --language values must
80
+ // refresh it. (The legacy code rewrote it unconditionally on --force
81
+ // too; we keep that semantics.)
82
+ writeFileSync(paths.configFile, generateConfig(languages, toolScaffolds), 'utf8');
83
+ createdFiles.push(paths.configFile);
84
+ // After --remove the dir is gone, so nothing pre-existed; pass an
85
+ // empty map so writeScaffoldedFile creates everything fresh.
86
+ const preExistingByPath = removeFirst
87
+ ? new Map()
88
+ : new Map(preExistingFiles.map((f) => [f.path, f]));
89
+ const ctx = { languages };
90
+ scaffoldToolExamples(paths, toolScaffolds, ctx, { keepCustom, preExistingByPath }, createdFiles);
91
+ const gitignoreUpdated = ensureGitignore(cwd);
92
+ return {
93
+ ...baseResult,
94
+ created: true,
95
+ state,
96
+ languages,
97
+ createdFiles,
98
+ gitignoreUpdated,
99
+ preExistingFiles: state === 'pristine' ? [] : preExistingFiles,
100
+ };
101
+ }
102
+ //# sourceMappingURL=scaffold-writer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold-writer.js","sourceRoot":"","sources":["../../../src/commands/init/scaffold-writer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Working-directory state classification for `opensip init`.
3
+ *
4
+ * Decides one of four states (pristine / fully-initialized /
5
+ * partial-config-only / partial-dir-only) based on whether the config
6
+ * file and the user-source dir exist, and renders the partial-state
7
+ * refusal message + the "discovered inside existing project" message.
8
+ */
9
+ import type { InitResult, PreExistingFile } from '@opensip-cli/contracts';
10
+ import type { ProjectPaths } from '@opensip-cli/core';
11
+ export type WorkingDirState = NonNullable<InitResult['state']>;
12
+ /**
13
+ * Classify the working directory into one of four states based on the
14
+ * presence of the config file and the `opensip-cli/` directory.
15
+ *
16
+ * The dir-presence check ignores `opensip-cli/.runtime/` — that
17
+ * subtree is tool-managed (logs, sessions, caches, plugin installs)
18
+ * and the CLI's `preAction` hook creates `.runtime/logs/` before any
19
+ * subcommand runs. Treating a runtime-only dir as a "partial-dir"
20
+ * would misclassify a pristine project the moment the bootstrap hook
21
+ * touches the disk. User-authored content lives under
22
+ * `opensip-cli/{fit,sim}/`; only those count as "the dir is present".
23
+ */
24
+ export declare function classifyWorkingDir(paths: ProjectPaths): WorkingDirState;
25
+ export declare function buildPartialStateMessage(state: WorkingDirState, preExistingFiles: readonly PreExistingFile[], cwd: string): string;
26
+ /**
27
+ * Build the "✗ This directory is already inside an OpenSIP CLI project"
28
+ * refusal message. Same string is embedded in the InitResult.insideExistingProject
29
+ * for --json consumers and rendered by InitFeedback for human-readable output.
30
+ */
31
+ export declare function formatInsideExistingProjectMessage(discoveredRoot: string): string;
32
+ //# sourceMappingURL=state-machine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-machine.d.ts","sourceRoot":"","sources":["../../../src/commands/init/state-machine.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC1E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;AAE/D;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,YAAY,GAAG,eAAe,CAOvE;AAoBD,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,eAAe,EACtB,gBAAgB,EAAE,SAAS,eAAe,EAAE,EAC5C,GAAG,EAAE,MAAM,GACV,MAAM,CAmCR;AAED;;;;GAIG;AACH,wBAAgB,kCAAkC,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAkBjF"}
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Working-directory state classification for `opensip init`.
3
+ *
4
+ * Decides one of four states (pristine / fully-initialized /
5
+ * partial-config-only / partial-dir-only) based on whether the config
6
+ * file and the user-source dir exist, and renders the partial-state
7
+ * refusal message + the "discovered inside existing project" message.
8
+ */
9
+ import { existsSync, readdirSync } from 'node:fs';
10
+ import { relative } from 'node:path';
11
+ /**
12
+ * Classify the working directory into one of four states based on the
13
+ * presence of the config file and the `opensip-cli/` directory.
14
+ *
15
+ * The dir-presence check ignores `opensip-cli/.runtime/` — that
16
+ * subtree is tool-managed (logs, sessions, caches, plugin installs)
17
+ * and the CLI's `preAction` hook creates `.runtime/logs/` before any
18
+ * subcommand runs. Treating a runtime-only dir as a "partial-dir"
19
+ * would misclassify a pristine project the moment the bootstrap hook
20
+ * touches the disk. User-authored content lives under
21
+ * `opensip-cli/{fit,sim}/`; only those count as "the dir is present".
22
+ */
23
+ export function classifyWorkingDir(paths) {
24
+ const hasConfig = existsSync(paths.configFile);
25
+ const hasDir = userSourceDirHasUserContent(paths);
26
+ if (!hasConfig && !hasDir)
27
+ return 'pristine';
28
+ if (hasConfig && hasDir)
29
+ return 'fully-initialized';
30
+ if (hasConfig)
31
+ return 'partial-config-only';
32
+ return 'partial-dir-only';
33
+ }
34
+ function userSourceDirHasUserContent(paths) {
35
+ if (!existsSync(paths.userSourceDir))
36
+ return false;
37
+ let entries;
38
+ try {
39
+ entries = readdirSync(paths.userSourceDir);
40
+ }
41
+ catch {
42
+ // @fitness-ignore-next-line error-handling-quality -- directory probe: an unreadable userSourceDir means "no user content present", treated identically to an empty dir; failure IS the signal.
43
+ return false;
44
+ }
45
+ // Anything other than `.runtime/` (tool-managed) counts as user content.
46
+ return entries.some((name) => name !== '.runtime');
47
+ }
48
+ function relativize(absPath, cwd) {
49
+ const rel = relative(cwd, absPath);
50
+ return rel === '' ? absPath : rel;
51
+ }
52
+ export function buildPartialStateMessage(state, preExistingFiles, cwd) {
53
+ const lines = [];
54
+ switch (state) {
55
+ case 'fully-initialized': {
56
+ lines.push('OpenSIP CLI is already initialized in this directory.');
57
+ break;
58
+ }
59
+ case 'partial-config-only': {
60
+ lines.push('opensip-cli.config.yml exists but opensip-cli/ does not.');
61
+ break;
62
+ }
63
+ case 'partial-dir-only': {
64
+ lines.push('opensip-cli/ exists but opensip-cli.config.yml does not.');
65
+ break;
66
+ }
67
+ case 'pristine': {
68
+ // Should not happen in this code path — pristine never errors.
69
+ return 'Unexpected pristine state.';
70
+ }
71
+ }
72
+ if (preExistingFiles.length > 0) {
73
+ lines.push('', `Found ${String(preExistingFiles.length)} file(s) under opensip-cli/:`);
74
+ for (const f of preExistingFiles) {
75
+ lines.push(` ${relativize(f.path, cwd)} (${f.classification})`);
76
+ }
77
+ }
78
+ lines.push('', 'Choose one:', ' opensip init --keep Re-scaffold examples; preserve custom files.', ' opensip init --remove Delete opensip-cli/ and scaffold fresh.');
79
+ return lines.join('\n');
80
+ }
81
+ /**
82
+ * Build the "✗ This directory is already inside an OpenSIP CLI project"
83
+ * refusal message. Same string is embedded in the InitResult.insideExistingProject
84
+ * for --json consumers and rendered by InitFeedback for human-readable output.
85
+ */
86
+ export function formatInsideExistingProjectMessage(discoveredRoot) {
87
+ return [
88
+ `✗ This directory is already inside an OpenSIP CLI project:`,
89
+ ` ${discoveredRoot}`,
90
+ ` (config: opensip-cli.config.yml)`,
91
+ ``,
92
+ ` What did you want to do?`,
93
+ ``,
94
+ ` • Re-scaffold examples, keep your custom files:`,
95
+ ` opensip init --keep --cwd ${discoveredRoot}`,
96
+ ``,
97
+ ` • Reset the existing project (delete everything, start over):`,
98
+ ` opensip init --remove --cwd ${discoveredRoot}`,
99
+ ``,
100
+ ` • Create a NEW separate project here (rare — only for`,
101
+ ` truly independent sub-projects in a monorepo):`,
102
+ ` opensip init --cwd .`,
103
+ ].join('\n');
104
+ }
105
+ //# sourceMappingURL=state-machine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-machine.js","sourceRoot":"","sources":["../../../src/commands/init/state-machine.ts"],"names":[],"mappings":"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"}