@isaacriehm/cairn-core 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 (616) hide show
  1. package/LICENSE +21 -0
  2. package/dist/.tsbuildinfo +1 -0
  3. package/dist/claude/error.d.ts +33 -0
  4. package/dist/claude/error.js +58 -0
  5. package/dist/claude/error.js.map +1 -0
  6. package/dist/claude/index.d.ts +3 -0
  7. package/dist/claude/index.js +3 -0
  8. package/dist/claude/index.js.map +1 -0
  9. package/dist/claude/runner.d.ts +11 -0
  10. package/dist/claude/runner.js +132 -0
  11. package/dist/claude/runner.js.map +1 -0
  12. package/dist/claude/types.d.ts +52 -0
  13. package/dist/claude/types.js +14 -0
  14. package/dist/claude/types.js.map +1 -0
  15. package/dist/context/checkpoint.d.ts +10 -0
  16. package/dist/context/checkpoint.js +29 -0
  17. package/dist/context/checkpoint.js.map +1 -0
  18. package/dist/context/handoff-builder.d.ts +11 -0
  19. package/dist/context/handoff-builder.js +268 -0
  20. package/dist/context/handoff-builder.js.map +1 -0
  21. package/dist/context/index.d.ts +11 -0
  22. package/dist/context/index.js +11 -0
  23. package/dist/context/index.js.map +1 -0
  24. package/dist/context/spec-delta.d.ts +47 -0
  25. package/dist/context/spec-delta.js +237 -0
  26. package/dist/context/spec-delta.js.map +1 -0
  27. package/dist/decision-capture/capture.d.ts +57 -0
  28. package/dist/decision-capture/capture.js +186 -0
  29. package/dist/decision-capture/capture.js.map +1 -0
  30. package/dist/decision-capture/extractor.d.ts +20 -0
  31. package/dist/decision-capture/extractor.js +103 -0
  32. package/dist/decision-capture/extractor.js.map +1 -0
  33. package/dist/decision-capture/id.d.ts +21 -0
  34. package/dist/decision-capture/id.js +60 -0
  35. package/dist/decision-capture/id.js.map +1 -0
  36. package/dist/decision-capture/index.d.ts +25 -0
  37. package/dist/decision-capture/index.js +21 -0
  38. package/dist/decision-capture/index.js.map +1 -0
  39. package/dist/decision-capture/prompt.d.ts +15 -0
  40. package/dist/decision-capture/prompt.js +68 -0
  41. package/dist/decision-capture/prompt.js.map +1 -0
  42. package/dist/decision-capture/refinement-prompt.d.ts +25 -0
  43. package/dist/decision-capture/refinement-prompt.js +146 -0
  44. package/dist/decision-capture/refinement-prompt.js.map +1 -0
  45. package/dist/decision-capture/refinement-schema.d.ts +52 -0
  46. package/dist/decision-capture/refinement-schema.js +61 -0
  47. package/dist/decision-capture/refinement-schema.js.map +1 -0
  48. package/dist/decision-capture/refinement.d.ts +60 -0
  49. package/dist/decision-capture/refinement.js +439 -0
  50. package/dist/decision-capture/refinement.js.map +1 -0
  51. package/dist/decision-capture/schema.d.ts +70 -0
  52. package/dist/decision-capture/schema.js +71 -0
  53. package/dist/decision-capture/schema.js.map +1 -0
  54. package/dist/decision-capture/types.d.ts +201 -0
  55. package/dist/decision-capture/types.js +20 -0
  56. package/dist/decision-capture/types.js.map +1 -0
  57. package/dist/decision-capture/writer.d.ts +90 -0
  58. package/dist/decision-capture/writer.js +267 -0
  59. package/dist/decision-capture/writer.js.map +1 -0
  60. package/dist/doctor/index.d.ts +48 -0
  61. package/dist/doctor/index.js +460 -0
  62. package/dist/doctor/index.js.map +1 -0
  63. package/dist/events/index.d.ts +15 -0
  64. package/dist/events/index.js +14 -0
  65. package/dist/events/index.js.map +1 -0
  66. package/dist/events/paths.d.ts +2 -0
  67. package/dist/events/paths.js +6 -0
  68. package/dist/events/paths.js.map +1 -0
  69. package/dist/events/reader.d.ts +40 -0
  70. package/dist/events/reader.js +139 -0
  71. package/dist/events/reader.js.map +1 -0
  72. package/dist/events/writer.d.ts +61 -0
  73. package/dist/events/writer.js +68 -0
  74. package/dist/events/writer.js.map +1 -0
  75. package/dist/frontend-types.d.ts +243 -0
  76. package/dist/frontend-types.js +15 -0
  77. package/dist/frontend-types.js.map +1 -0
  78. package/dist/gc/apply.d.ts +26 -0
  79. package/dist/gc/apply.js +48 -0
  80. package/dist/gc/apply.js.map +1 -0
  81. package/dist/gc/canary.d.ts +42 -0
  82. package/dist/gc/canary.js +134 -0
  83. package/dist/gc/canary.js.map +1 -0
  84. package/dist/gc/citation-integrity.d.ts +24 -0
  85. package/dist/gc/citation-integrity.js +151 -0
  86. package/dist/gc/citation-integrity.js.map +1 -0
  87. package/dist/gc/classify.d.ts +25 -0
  88. package/dist/gc/classify.js +89 -0
  89. package/dist/gc/classify.js.map +1 -0
  90. package/dist/gc/completion-integrity.d.ts +22 -0
  91. package/dist/gc/completion-integrity.js +165 -0
  92. package/dist/gc/completion-integrity.js.map +1 -0
  93. package/dist/gc/doc-gardening.d.ts +29 -0
  94. package/dist/gc/doc-gardening.js +146 -0
  95. package/dist/gc/doc-gardening.js.map +1 -0
  96. package/dist/gc/frontmatter.d.ts +35 -0
  97. package/dist/gc/frontmatter.js +105 -0
  98. package/dist/gc/frontmatter.js.map +1 -0
  99. package/dist/gc/generator-drift.d.ts +28 -0
  100. package/dist/gc/generator-drift.js +53 -0
  101. package/dist/gc/generator-drift.js.map +1 -0
  102. package/dist/gc/index.d.ts +42 -0
  103. package/dist/gc/index.js +30 -0
  104. package/dist/gc/index.js.map +1 -0
  105. package/dist/gc/quality-update.d.ts +23 -0
  106. package/dist/gc/quality-update.js +69 -0
  107. package/dist/gc/quality-update.js.map +1 -0
  108. package/dist/gc/scope-coverage.d.ts +20 -0
  109. package/dist/gc/scope-coverage.js +70 -0
  110. package/dist/gc/scope-coverage.js.map +1 -0
  111. package/dist/gc/stub-hits.d.ts +31 -0
  112. package/dist/gc/stub-hits.js +78 -0
  113. package/dist/gc/stub-hits.js.map +1 -0
  114. package/dist/gc/sweep.d.ts +56 -0
  115. package/dist/gc/sweep.js +205 -0
  116. package/dist/gc/sweep.js.map +1 -0
  117. package/dist/gc/types.d.ts +129 -0
  118. package/dist/gc/types.js +26 -0
  119. package/dist/gc/types.js.map +1 -0
  120. package/dist/gc/walk-source.d.ts +14 -0
  121. package/dist/gc/walk-source.js +59 -0
  122. package/dist/gc/walk-source.js.map +1 -0
  123. package/dist/ground/drift.d.ts +8 -0
  124. package/dist/ground/drift.js +23 -0
  125. package/dist/ground/drift.js.map +1 -0
  126. package/dist/ground/frontmatter.d.ts +20 -0
  127. package/dist/ground/frontmatter.js +49 -0
  128. package/dist/ground/frontmatter.js.map +1 -0
  129. package/dist/ground/glob.d.ts +10 -0
  130. package/dist/ground/glob.js +46 -0
  131. package/dist/ground/glob.js.map +1 -0
  132. package/dist/ground/index.d.ts +16 -0
  133. package/dist/ground/index.js +11 -0
  134. package/dist/ground/index.js.map +1 -0
  135. package/dist/ground/ledgers.d.ts +18 -0
  136. package/dist/ground/ledgers.js +103 -0
  137. package/dist/ground/ledgers.js.map +1 -0
  138. package/dist/ground/manifest.d.ts +10 -0
  139. package/dist/ground/manifest.js +88 -0
  140. package/dist/ground/manifest.js.map +1 -0
  141. package/dist/ground/paths.d.ts +20 -0
  142. package/dist/ground/paths.js +61 -0
  143. package/dist/ground/paths.js.map +1 -0
  144. package/dist/ground/quality-grades.d.ts +11 -0
  145. package/dist/ground/quality-grades.js +98 -0
  146. package/dist/ground/quality-grades.js.map +1 -0
  147. package/dist/ground/schemas.d.ts +306 -0
  148. package/dist/ground/schemas.js +188 -0
  149. package/dist/ground/schemas.js.map +1 -0
  150. package/dist/ground/scope-index.d.ts +48 -0
  151. package/dist/ground/scope-index.js +120 -0
  152. package/dist/ground/scope-index.js.map +1 -0
  153. package/dist/ground/walk.d.ts +7 -0
  154. package/dist/ground/walk.js +53 -0
  155. package/dist/ground/walk.js.map +1 -0
  156. package/dist/hooks/bypass-detection.d.ts +28 -0
  157. package/dist/hooks/bypass-detection.js +106 -0
  158. package/dist/hooks/bypass-detection.js.map +1 -0
  159. package/dist/hooks/index.d.ts +12 -0
  160. package/dist/hooks/index.js +13 -0
  161. package/dist/hooks/index.js.map +1 -0
  162. package/dist/hooks/post-tool-use/allowlist-reader.d.ts +14 -0
  163. package/dist/hooks/post-tool-use/allowlist-reader.js +69 -0
  164. package/dist/hooks/post-tool-use/allowlist-reader.js.map +1 -0
  165. package/dist/hooks/post-tool-use/citation-scanner.d.ts +23 -0
  166. package/dist/hooks/post-tool-use/citation-scanner.js +59 -0
  167. package/dist/hooks/post-tool-use/citation-scanner.js.map +1 -0
  168. package/dist/hooks/post-tool-use/copy-scanner.d.ts +25 -0
  169. package/dist/hooks/post-tool-use/copy-scanner.js +192 -0
  170. package/dist/hooks/post-tool-use/copy-scanner.js.map +1 -0
  171. package/dist/hooks/post-tool-use/index.d.ts +19 -0
  172. package/dist/hooks/post-tool-use/index.js +15 -0
  173. package/dist/hooks/post-tool-use/index.js.map +1 -0
  174. package/dist/hooks/post-tool-use/ledger-cache.d.ts +32 -0
  175. package/dist/hooks/post-tool-use/ledger-cache.js +236 -0
  176. package/dist/hooks/post-tool-use/ledger-cache.js.map +1 -0
  177. package/dist/hooks/post-tool-use/legend-builder.d.ts +15 -0
  178. package/dist/hooks/post-tool-use/legend-builder.js +84 -0
  179. package/dist/hooks/post-tool-use/legend-builder.js.map +1 -0
  180. package/dist/hooks/post-tool-use/read-enricher.d.ts +13 -0
  181. package/dist/hooks/post-tool-use/read-enricher.js +157 -0
  182. package/dist/hooks/post-tool-use/read-enricher.js.map +1 -0
  183. package/dist/hooks/post-tool-use/write-guardian.d.ts +17 -0
  184. package/dist/hooks/post-tool-use/write-guardian.js +176 -0
  185. package/dist/hooks/post-tool-use/write-guardian.js.map +1 -0
  186. package/dist/hooks/read-enrich.d.ts +6 -0
  187. package/dist/hooks/read-enrich.js +11 -0
  188. package/dist/hooks/read-enrich.js.map +1 -0
  189. package/dist/hooks/runners/index.d.ts +12 -0
  190. package/dist/hooks/runners/index.js +11 -0
  191. package/dist/hooks/runners/index.js.map +1 -0
  192. package/dist/hooks/runners/payload.d.ts +32 -0
  193. package/dist/hooks/runners/payload.js +70 -0
  194. package/dist/hooks/runners/payload.js.map +1 -0
  195. package/dist/hooks/runners/session-end.d.ts +7 -0
  196. package/dist/hooks/runners/session-end.js +42 -0
  197. package/dist/hooks/runners/session-end.js.map +1 -0
  198. package/dist/hooks/runners/session-start.d.ts +10 -0
  199. package/dist/hooks/runners/session-start.js +167 -0
  200. package/dist/hooks/runners/session-start.js.map +1 -0
  201. package/dist/hooks/runners/stop.d.ts +18 -0
  202. package/dist/hooks/runners/stop.js +165 -0
  203. package/dist/hooks/runners/stop.js.map +1 -0
  204. package/dist/hooks/session-end.d.ts +5 -0
  205. package/dist/hooks/session-end.js +10 -0
  206. package/dist/hooks/session-end.js.map +1 -0
  207. package/dist/hooks/session-start.d.ts +7 -0
  208. package/dist/hooks/session-start.js +12 -0
  209. package/dist/hooks/session-start.js.map +1 -0
  210. package/dist/hooks/stop.d.ts +5 -0
  211. package/dist/hooks/stop.js +10 -0
  212. package/dist/hooks/stop.js.map +1 -0
  213. package/dist/hooks/write-guard.d.ts +6 -0
  214. package/dist/hooks/write-guard.js +11 -0
  215. package/dist/hooks/write-guard.js.map +1 -0
  216. package/dist/inbox.d.ts +17 -0
  217. package/dist/inbox.js +30 -0
  218. package/dist/inbox.js.map +1 -0
  219. package/dist/index.d.ts +33 -0
  220. package/dist/index.js +32 -0
  221. package/dist/index.js.map +1 -0
  222. package/dist/init/baseline-audit.d.ts +71 -0
  223. package/dist/init/baseline-audit.js +377 -0
  224. package/dist/init/baseline-audit.js.map +1 -0
  225. package/dist/init/brand-setup.d.ts +44 -0
  226. package/dist/init/brand-setup.js +201 -0
  227. package/dist/init/brand-setup.js.map +1 -0
  228. package/dist/init/daemon-autostart.d.ts +16 -0
  229. package/dist/init/daemon-autostart.js +95 -0
  230. package/dist/init/daemon-autostart.js.map +1 -0
  231. package/dist/init/detect.d.ts +25 -0
  232. package/dist/init/detect.js +319 -0
  233. package/dist/init/detect.js.map +1 -0
  234. package/dist/init/index.d.ts +32 -0
  235. package/dist/init/index.js +18 -0
  236. package/dist/init/index.js.map +1 -0
  237. package/dist/init/ingest-docs.d.ts +74 -0
  238. package/dist/init/ingest-docs.js +499 -0
  239. package/dist/init/ingest-docs.js.map +1 -0
  240. package/dist/init/init.d.ts +165 -0
  241. package/dist/init/init.js +1166 -0
  242. package/dist/init/init.js.map +1 -0
  243. package/dist/init/mapper-legacy.d.ts +148 -0
  244. package/dist/init/mapper-legacy.js +238 -0
  245. package/dist/init/mapper-legacy.js.map +1 -0
  246. package/dist/init/mapper-merge.d.ts +38 -0
  247. package/dist/init/mapper-merge.js +238 -0
  248. package/dist/init/mapper-merge.js.map +1 -0
  249. package/dist/init/mapper-parallel.d.ts +48 -0
  250. package/dist/init/mapper-parallel.js +409 -0
  251. package/dist/init/mapper-parallel.js.map +1 -0
  252. package/dist/init/mapper-prompts.d.ts +135 -0
  253. package/dist/init/mapper-prompts.js +189 -0
  254. package/dist/init/mapper-prompts.js.map +1 -0
  255. package/dist/init/mapper.d.ts +211 -0
  256. package/dist/init/mapper.js +151 -0
  257. package/dist/init/mapper.js.map +1 -0
  258. package/dist/init/module-slicer.d.ts +39 -0
  259. package/dist/init/module-slicer.js +809 -0
  260. package/dist/init/module-slicer.js.map +1 -0
  261. package/dist/init/multi-dev/index.d.ts +2 -0
  262. package/dist/init/multi-dev/index.js +2 -0
  263. package/dist/init/multi-dev/index.js.map +1 -0
  264. package/dist/init/multi-dev/install.d.ts +40 -0
  265. package/dist/init/multi-dev/install.js +139 -0
  266. package/dist/init/multi-dev/install.js.map +1 -0
  267. package/dist/init/preflight-guards.d.ts +42 -0
  268. package/dist/init/preflight-guards.js +108 -0
  269. package/dist/init/preflight-guards.js.map +1 -0
  270. package/dist/init/prompts.d.ts +61 -0
  271. package/dist/init/prompts.js +66 -0
  272. package/dist/init/prompts.js.map +1 -0
  273. package/dist/init/rules-merge/discover.d.ts +21 -0
  274. package/dist/init/rules-merge/discover.js +78 -0
  275. package/dist/init/rules-merge/discover.js.map +1 -0
  276. package/dist/init/rules-merge/index.d.ts +10 -0
  277. package/dist/init/rules-merge/index.js +6 -0
  278. package/dist/init/rules-merge/index.js.map +1 -0
  279. package/dist/init/rules-merge/ingest.d.ts +56 -0
  280. package/dist/init/rules-merge/ingest.js +336 -0
  281. package/dist/init/rules-merge/ingest.js.map +1 -0
  282. package/dist/init/rules-merge/keep-markers.d.ts +39 -0
  283. package/dist/init/rules-merge/keep-markers.js +97 -0
  284. package/dist/init/rules-merge/keep-markers.js.map +1 -0
  285. package/dist/init/rules-merge/parse-sections.d.ts +24 -0
  286. package/dist/init/rules-merge/parse-sections.js +71 -0
  287. package/dist/init/rules-merge/parse-sections.js.map +1 -0
  288. package/dist/init/rules-merge/regenerate.d.ts +33 -0
  289. package/dist/init/rules-merge/regenerate.js +163 -0
  290. package/dist/init/rules-merge/regenerate.js.map +1 -0
  291. package/dist/init/secrets.d.ts +18 -0
  292. package/dist/init/secrets.js +76 -0
  293. package/dist/init/secrets.js.map +1 -0
  294. package/dist/init/seed.d.ts +21 -0
  295. package/dist/init/seed.js +96 -0
  296. package/dist/init/seed.js.map +1 -0
  297. package/dist/init/setup-runners.d.ts +15 -0
  298. package/dist/init/setup-runners.js +143 -0
  299. package/dist/init/setup-runners.js.map +1 -0
  300. package/dist/init/source-comments/classify.d.ts +98 -0
  301. package/dist/init/source-comments/classify.js +244 -0
  302. package/dist/init/source-comments/classify.js.map +1 -0
  303. package/dist/init/source-comments/index.d.ts +8 -0
  304. package/dist/init/source-comments/index.js +5 -0
  305. package/dist/init/source-comments/index.js.map +1 -0
  306. package/dist/init/source-comments/ingest.d.ts +51 -0
  307. package/dist/init/source-comments/ingest.js +236 -0
  308. package/dist/init/source-comments/ingest.js.map +1 -0
  309. package/dist/init/source-comments/strip-replace.d.ts +106 -0
  310. package/dist/init/source-comments/strip-replace.js +284 -0
  311. package/dist/init/source-comments/strip-replace.js.map +1 -0
  312. package/dist/init/source-comments/walker.d.ts +65 -0
  313. package/dist/init/source-comments/walker.js +777 -0
  314. package/dist/init/source-comments/walker.js.map +1 -0
  315. package/dist/init/submodules.d.ts +48 -0
  316. package/dist/init/submodules.js +149 -0
  317. package/dist/init/submodules.js.map +1 -0
  318. package/dist/init/types.d.ts +55 -0
  319. package/dist/init/types.js +10 -0
  320. package/dist/init/types.js.map +1 -0
  321. package/dist/init/visual.d.ts +69 -0
  322. package/dist/init/visual.js +265 -0
  323. package/dist/init/visual.js.map +1 -0
  324. package/dist/init/walker.d.ts +82 -0
  325. package/dist/init/walker.js +585 -0
  326. package/dist/init/walker.js.map +1 -0
  327. package/dist/init/workflow-block.d.ts +34 -0
  328. package/dist/init/workflow-block.js +110 -0
  329. package/dist/init/workflow-block.js.map +1 -0
  330. package/dist/join/index.d.ts +67 -0
  331. package/dist/join/index.js +256 -0
  332. package/dist/join/index.js.map +1 -0
  333. package/dist/lock.d.ts +39 -0
  334. package/dist/lock.js +129 -0
  335. package/dist/lock.js.map +1 -0
  336. package/dist/logger.d.ts +13 -0
  337. package/dist/logger.js +78 -0
  338. package/dist/logger.js.map +1 -0
  339. package/dist/mcp/bootstrap-guard.d.ts +29 -0
  340. package/dist/mcp/bootstrap-guard.js +47 -0
  341. package/dist/mcp/bootstrap-guard.js.map +1 -0
  342. package/dist/mcp/context.d.ts +23 -0
  343. package/dist/mcp/context.js +9 -0
  344. package/dist/mcp/context.js.map +1 -0
  345. package/dist/mcp/errors.d.ts +17 -0
  346. package/dist/mcp/errors.js +23 -0
  347. package/dist/mcp/errors.js.map +1 -0
  348. package/dist/mcp/history/index.d.ts +6 -0
  349. package/dist/mcp/history/index.js +5 -0
  350. package/dist/mcp/history/index.js.map +1 -0
  351. package/dist/mcp/history/prompt.d.ts +32 -0
  352. package/dist/mcp/history/prompt.js +99 -0
  353. package/dist/mcp/history/prompt.js.map +1 -0
  354. package/dist/mcp/history/schema.d.ts +58 -0
  355. package/dist/mcp/history/schema.js +41 -0
  356. package/dist/mcp/history/schema.js.map +1 -0
  357. package/dist/mcp/history/summarizer.d.ts +81 -0
  358. package/dist/mcp/history/summarizer.js +196 -0
  359. package/dist/mcp/history/summarizer.js.map +1 -0
  360. package/dist/mcp/history/walker.d.ts +57 -0
  361. package/dist/mcp/history/walker.js +156 -0
  362. package/dist/mcp/history/walker.js.map +1 -0
  363. package/dist/mcp/index.d.ts +13 -0
  364. package/dist/mcp/index.js +9 -0
  365. package/dist/mcp/index.js.map +1 -0
  366. package/dist/mcp/path-allowlist.d.ts +29 -0
  367. package/dist/mcp/path-allowlist.js +71 -0
  368. package/dist/mcp/path-allowlist.js.map +1 -0
  369. package/dist/mcp/result.d.ts +8 -0
  370. package/dist/mcp/result.js +18 -0
  371. package/dist/mcp/result.js.map +1 -0
  372. package/dist/mcp/schemas.d.ts +192 -0
  373. package/dist/mcp/schemas.js +174 -0
  374. package/dist/mcp/schemas.js.map +1 -0
  375. package/dist/mcp/serve.d.ts +15 -0
  376. package/dist/mcp/serve.js +71 -0
  377. package/dist/mcp/serve.js.map +1 -0
  378. package/dist/mcp/server.d.ts +11 -0
  379. package/dist/mcp/server.js +58 -0
  380. package/dist/mcp/server.js.map +1 -0
  381. package/dist/mcp/telemetry.d.ts +15 -0
  382. package/dist/mcp/telemetry.js +13 -0
  383. package/dist/mcp/telemetry.js.map +1 -0
  384. package/dist/mcp/tools/append-run-note.d.ts +18 -0
  385. package/dist/mcp/tools/append-run-note.js +47 -0
  386. package/dist/mcp/tools/append-run-note.js.map +1 -0
  387. package/dist/mcp/tools/append.d.ts +8 -0
  388. package/dist/mcp/tools/append.js +37 -0
  389. package/dist/mcp/tools/append.js.map +1 -0
  390. package/dist/mcp/tools/archive.d.ts +8 -0
  391. package/dist/mcp/tools/archive.js +72 -0
  392. package/dist/mcp/tools/archive.js.map +1 -0
  393. package/dist/mcp/tools/ask-operator.d.ts +34 -0
  394. package/dist/mcp/tools/ask-operator.js +97 -0
  395. package/dist/mcp/tools/ask-operator.js.map +1 -0
  396. package/dist/mcp/tools/canonical-for-topic.d.ts +6 -0
  397. package/dist/mcp/tools/canonical-for-topic.js +40 -0
  398. package/dist/mcp/tools/canonical-for-topic.js.map +1 -0
  399. package/dist/mcp/tools/decision-get.d.ts +6 -0
  400. package/dist/mcp/tools/decision-get.js +49 -0
  401. package/dist/mcp/tools/decision-get.js.map +1 -0
  402. package/dist/mcp/tools/decisions-for-symbol.d.ts +7 -0
  403. package/dist/mcp/tools/decisions-for-symbol.js +42 -0
  404. package/dist/mcp/tools/decisions-for-symbol.js.map +1 -0
  405. package/dist/mcp/tools/decisions-in-scope.d.ts +7 -0
  406. package/dist/mcp/tools/decisions-in-scope.js +47 -0
  407. package/dist/mcp/tools/decisions-in-scope.js.map +1 -0
  408. package/dist/mcp/tools/drop-task.d.ts +12 -0
  409. package/dist/mcp/tools/drop-task.js +68 -0
  410. package/dist/mcp/tools/drop-task.js.map +1 -0
  411. package/dist/mcp/tools/get-full.d.ts +7 -0
  412. package/dist/mcp/tools/get-full.js +46 -0
  413. package/dist/mcp/tools/get-full.js.map +1 -0
  414. package/dist/mcp/tools/ground-get.d.ts +7 -0
  415. package/dist/mcp/tools/ground-get.js +77 -0
  416. package/dist/mcp/tools/ground-get.js.map +1 -0
  417. package/dist/mcp/tools/index.d.ts +3 -0
  418. package/dist/mcp/tools/index.js +40 -0
  419. package/dist/mcp/tools/index.js.map +1 -0
  420. package/dist/mcp/tools/invariant-get.d.ts +6 -0
  421. package/dist/mcp/tools/invariant-get.js +49 -0
  422. package/dist/mcp/tools/invariant-get.js.map +1 -0
  423. package/dist/mcp/tools/invariants-in-scope.d.ts +7 -0
  424. package/dist/mcp/tools/invariants-in-scope.js +62 -0
  425. package/dist/mcp/tools/invariants-in-scope.js.map +1 -0
  426. package/dist/mcp/tools/query-history.d.ts +20 -0
  427. package/dist/mcp/tools/query-history.js +51 -0
  428. package/dist/mcp/tools/query-history.js.map +1 -0
  429. package/dist/mcp/tools/record-decision.d.ts +14 -0
  430. package/dist/mcp/tools/record-decision.js +98 -0
  431. package/dist/mcp/tools/record-decision.js.map +1 -0
  432. package/dist/mcp/tools/record-run-event.d.ts +10 -0
  433. package/dist/mcp/tools/record-run-event.js +32 -0
  434. package/dist/mcp/tools/record-run-event.js.map +1 -0
  435. package/dist/mcp/tools/resolve-attention.d.ts +31 -0
  436. package/dist/mcp/tools/resolve-attention.js +191 -0
  437. package/dist/mcp/tools/resolve-attention.js.map +1 -0
  438. package/dist/mcp/tools/search.d.ts +9 -0
  439. package/dist/mcp/tools/search.js +164 -0
  440. package/dist/mcp/tools/search.js.map +1 -0
  441. package/dist/mcp/tools/supersedes-chain.d.ts +6 -0
  442. package/dist/mcp/tools/supersedes-chain.js +66 -0
  443. package/dist/mcp/tools/supersedes-chain.js.map +1 -0
  444. package/dist/mcp/tools/timeline.d.ts +9 -0
  445. package/dist/mcp/tools/timeline.js +65 -0
  446. package/dist/mcp/tools/timeline.js.map +1 -0
  447. package/dist/mcp/tools/types.d.ts +9 -0
  448. package/dist/mcp/tools/types.js +2 -0
  449. package/dist/mcp/tools/types.js.map +1 -0
  450. package/dist/mirror/clone.d.ts +6 -0
  451. package/dist/mirror/clone.js +48 -0
  452. package/dist/mirror/clone.js.map +1 -0
  453. package/dist/mirror/dirty-overlap.d.ts +13 -0
  454. package/dist/mirror/dirty-overlap.js +42 -0
  455. package/dist/mirror/dirty-overlap.js.map +1 -0
  456. package/dist/mirror/index.d.ts +7 -0
  457. package/dist/mirror/index.js +7 -0
  458. package/dist/mirror/index.js.map +1 -0
  459. package/dist/mirror/paths.d.ts +18 -0
  460. package/dist/mirror/paths.js +45 -0
  461. package/dist/mirror/paths.js.map +1 -0
  462. package/dist/mirror/push.d.ts +9 -0
  463. package/dist/mirror/push.js +27 -0
  464. package/dist/mirror/push.js.map +1 -0
  465. package/dist/mirror/state.d.ts +4 -0
  466. package/dist/mirror/state.js +36 -0
  467. package/dist/mirror/state.js.map +1 -0
  468. package/dist/mirror/sync.d.ts +9 -0
  469. package/dist/mirror/sync.js +33 -0
  470. package/dist/mirror/sync.js.map +1 -0
  471. package/dist/mirror/types.d.ts +77 -0
  472. package/dist/mirror/types.js +2 -0
  473. package/dist/mirror/types.js.map +1 -0
  474. package/dist/paths/index.d.ts +23 -0
  475. package/dist/paths/index.js +50 -0
  476. package/dist/paths/index.js.map +1 -0
  477. package/dist/profiles/index.d.ts +3 -0
  478. package/dist/profiles/index.js +3 -0
  479. package/dist/profiles/index.js.map +1 -0
  480. package/dist/profiles/registry.d.ts +5 -0
  481. package/dist/profiles/registry.js +31 -0
  482. package/dist/profiles/registry.js.map +1 -0
  483. package/dist/profiles/types.d.ts +48 -0
  484. package/dist/profiles/types.js +11 -0
  485. package/dist/profiles/types.js.map +1 -0
  486. package/dist/profiles/unknown.d.ts +9 -0
  487. package/dist/profiles/unknown.js +17 -0
  488. package/dist/profiles/unknown.js.map +1 -0
  489. package/dist/prompt.d.ts +19 -0
  490. package/dist/prompt.js +50 -0
  491. package/dist/prompt.js.map +1 -0
  492. package/dist/sensors/attestation.d.ts +44 -0
  493. package/dist/sensors/attestation.js +262 -0
  494. package/dist/sensors/attestation.js.map +1 -0
  495. package/dist/sensors/catalog.d.ts +41 -0
  496. package/dist/sensors/catalog.js +123 -0
  497. package/dist/sensors/catalog.js.map +1 -0
  498. package/dist/sensors/decisions.d.ts +30 -0
  499. package/dist/sensors/decisions.js +393 -0
  500. package/dist/sensors/decisions.js.map +1 -0
  501. package/dist/sensors/diff.d.ts +27 -0
  502. package/dist/sensors/diff.js +148 -0
  503. package/dist/sensors/diff.js.map +1 -0
  504. package/dist/sensors/index.d.ts +13 -0
  505. package/dist/sensors/index.js +9 -0
  506. package/dist/sensors/index.js.map +1 -0
  507. package/dist/sensors/remediation.d.ts +20 -0
  508. package/dist/sensors/remediation.js +65 -0
  509. package/dist/sensors/remediation.js.map +1 -0
  510. package/dist/sensors/runner.d.ts +44 -0
  511. package/dist/sensors/runner.js +95 -0
  512. package/dist/sensors/runner.js.map +1 -0
  513. package/dist/sensors/structural.d.ts +30 -0
  514. package/dist/sensors/structural.js +204 -0
  515. package/dist/sensors/structural.js.map +1 -0
  516. package/dist/sensors/stub-catalog.d.ts +39 -0
  517. package/dist/sensors/stub-catalog.js +115 -0
  518. package/dist/sensors/stub-catalog.js.map +1 -0
  519. package/dist/sensors/types.d.ts +135 -0
  520. package/dist/sensors/types.js +14 -0
  521. package/dist/sensors/types.js.map +1 -0
  522. package/dist/session/events-marker.d.ts +39 -0
  523. package/dist/session/events-marker.js +74 -0
  524. package/dist/session/events-marker.js.map +1 -0
  525. package/dist/session/id.d.ts +83 -0
  526. package/dist/session/id.js +166 -0
  527. package/dist/session/id.js.map +1 -0
  528. package/dist/session/index.d.ts +14 -0
  529. package/dist/session/index.js +13 -0
  530. package/dist/session/index.js.map +1 -0
  531. package/dist/session-start/build.d.ts +53 -0
  532. package/dist/session-start/build.js +645 -0
  533. package/dist/session-start/build.js.map +1 -0
  534. package/dist/session-start/index.d.ts +18 -0
  535. package/dist/session-start/index.js +18 -0
  536. package/dist/session-start/index.js.map +1 -0
  537. package/dist/session-start/templates.d.ts +6 -0
  538. package/dist/session-start/templates.js +38 -0
  539. package/dist/session-start/templates.js.map +1 -0
  540. package/dist/status-line/format.d.ts +14 -0
  541. package/dist/status-line/format.js +40 -0
  542. package/dist/status-line/format.js.map +1 -0
  543. package/dist/status-line/index.d.ts +29 -0
  544. package/dist/status-line/index.js +14 -0
  545. package/dist/status-line/index.js.map +1 -0
  546. package/dist/status-line/reader.d.ts +13 -0
  547. package/dist/status-line/reader.js +76 -0
  548. package/dist/status-line/reader.js.map +1 -0
  549. package/dist/status-line/writer.d.ts +33 -0
  550. package/dist/status-line/writer.js +72 -0
  551. package/dist/status-line/writer.js.map +1 -0
  552. package/dist/tier0/classify.d.ts +10 -0
  553. package/dist/tier0/classify.js +110 -0
  554. package/dist/tier0/classify.js.map +1 -0
  555. package/dist/tier0/index.d.ts +2 -0
  556. package/dist/tier0/index.js +2 -0
  557. package/dist/tier0/index.js.map +1 -0
  558. package/dist/tier0/ollama.d.ts +22 -0
  559. package/dist/tier0/ollama.js +63 -0
  560. package/dist/tier0/ollama.js.map +1 -0
  561. package/dist/tier0/types.d.ts +24 -0
  562. package/dist/tier0/types.js +9 -0
  563. package/dist/tier0/types.js.map +1 -0
  564. package/dist/tightener/index.d.ts +4 -0
  565. package/dist/tightener/index.js +4 -0
  566. package/dist/tightener/index.js.map +1 -0
  567. package/dist/tightener/prompt.d.ts +3 -0
  568. package/dist/tightener/prompt.js +67 -0
  569. package/dist/tightener/prompt.js.map +1 -0
  570. package/dist/tightener/schema.d.ts +68 -0
  571. package/dist/tightener/schema.js +44 -0
  572. package/dist/tightener/schema.js.map +1 -0
  573. package/dist/tightener/tighten.d.ts +2 -0
  574. package/dist/tightener/tighten.js +66 -0
  575. package/dist/tightener/tighten.js.map +1 -0
  576. package/dist/tightener/types.d.ts +74 -0
  577. package/dist/tightener/types.js +6 -0
  578. package/dist/tightener/types.js.map +1 -0
  579. package/dist/voice/index.d.ts +4 -0
  580. package/dist/voice/index.js +4 -0
  581. package/dist/voice/index.js.map +1 -0
  582. package/dist/voice/model.d.ts +23 -0
  583. package/dist/voice/model.js +46 -0
  584. package/dist/voice/model.js.map +1 -0
  585. package/dist/voice/pipe.d.ts +9 -0
  586. package/dist/voice/pipe.js +47 -0
  587. package/dist/voice/pipe.js.map +1 -0
  588. package/dist/voice/transcribe.d.ts +3 -0
  589. package/dist/voice/transcribe.js +43 -0
  590. package/dist/voice/transcribe.js.map +1 -0
  591. package/dist/voice/types.d.ts +26 -0
  592. package/dist/voice/types.js +9 -0
  593. package/dist/voice/types.js.map +1 -0
  594. package/package.json +54 -0
  595. package/templates/.archive/README.md +67 -0
  596. package/templates/.cairn/JOIN.md +87 -0
  597. package/templates/.cairn/config/sensors.yaml +185 -0
  598. package/templates/.cairn/config/stub-patterns.yaml +231 -0
  599. package/templates/.cairn/config/trust-policy.yaml +95 -0
  600. package/templates/.cairn/config/workflow.md +230 -0
  601. package/templates/.cairn/git-hooks/commit-msg +17 -0
  602. package/templates/.cairn/git-hooks/post-commit +28 -0
  603. package/templates/.cairn/git-hooks/pre-commit +24 -0
  604. package/templates/.cairn/ground/brand/overview.md +24 -0
  605. package/templates/.cairn/ground/brand/voice.md +20 -0
  606. package/templates/.cairn/ground/canonical-map/topics.yaml +54 -0
  607. package/templates/.cairn/ground/capabilities/mcp-tools.yaml +4 -0
  608. package/templates/.cairn/ground/capabilities/skills.yaml +3 -0
  609. package/templates/.cairn/ground/capabilities/snippets.yaml +3 -0
  610. package/templates/.cairn/ground/manifest.yaml +16 -0
  611. package/templates/.cairn/ground/product/personas.yaml +4 -0
  612. package/templates/.cairn/ground/product/positioning.md +21 -0
  613. package/templates/.claude/settings.json +57 -0
  614. package/templates/.github/workflows/cairn-check.yml +31 -0
  615. package/templates/.mcp.json +8 -0
  616. package/templates/README.md +24 -0
@@ -0,0 +1,1166 @@
1
+ /**
2
+ * `cairn init` orchestrator — full guided adoption.
3
+ *
4
+ * Stages:
5
+ * 1. Detect → print summary
6
+ * 2. Proceed dialog (cancel exits cleanly, no writes)
7
+ * 3. Seed `.cairn/` + `.archive/` from templates with `<project_name>`
8
+ * substituted; write `.cairn/config.yaml` (including `cairn_version`).
9
+ * 4. Mapper (Tier-2 chunked Sonnet) → seed `<slug>:` workflow.md block +
10
+ * `.cairn/config.yaml` project_globs.
11
+ * 5. Brand setup (4-question wizard).
12
+ * 6. Phase 6 docs ingestion + baseline sensor sweep.
13
+ * 7. Phase 7b source-comment ingestion + 7c rules merge (mock-friendly
14
+ * via `mockSourceCommentClassify` / `mockRulesMergeClassify`).
15
+ * 8. Phase 12 multi-dev install (deterministic, idempotent).
16
+ */
17
+ import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync, } from "node:fs";
18
+ import { join, relative } from "node:path";
19
+ import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
20
+ import { VERSION } from "../index.js";
21
+ import { scopeIndexPath, writeScopeIndex, } from "../ground/scope-index.js";
22
+ import { normalizeProjectName } from "../paths/index.js";
23
+ import { homedir } from "node:os";
24
+ import { logger, setLogFile } from "../logger.js";
25
+ import { applyBrandAnswers, runBrandSetup, } from "./brand-setup.js";
26
+ import { defaultBaselineLanguages, runBaselineAudit, } from "./baseline-audit.js";
27
+ import { runDocsIngestion, } from "./ingest-docs.js";
28
+ import { runSourceCommentsIngestion, } from "./source-comments/index.js";
29
+ import { runRulesMerge, } from "./rules-merge/index.js";
30
+ import { installMultiDev, } from "./multi-dev/index.js";
31
+ import { detectMonorepoContext, findGitRoot, isCairnSourceRepo, } from "./preflight-guards.js";
32
+ import { detectAll } from "./detect.js";
33
+ import { runGitSubmoduleUpdate, scanSubmodules, } from "./submodules.js";
34
+ import { c as visualC, discoveryRow, installInitCancelHandlers, startSpinner, } from "./visual.js";
35
+ import { runMapper, } from "./mapper.js";
36
+ import { done, freeTextWithDefault, header, info, yesNo, } from "./prompts.js";
37
+ import { seedCairnLayout } from "./seed.js";
38
+ import { buildRepoSummary } from "./walker.js";
39
+ import { updateWorkflowSlugBlock } from "./workflow-block.js";
40
+ const log = logger("init");
41
+ const DEFAULT_OFF_LIMITS = [
42
+ ".env",
43
+ ".env.*",
44
+ "node_modules/",
45
+ "dist/",
46
+ "build/",
47
+ "target/",
48
+ "__pycache__/",
49
+ "vendor/",
50
+ ".venv/",
51
+ ".direnv/",
52
+ ".cache/",
53
+ "coverage/",
54
+ ];
55
+ export async function runInit(args = {}) {
56
+ const repoRoot = args.repoRoot ?? process.cwd();
57
+ const cwd = process.cwd();
58
+ const mode = args.mode ?? "interactive";
59
+ const warnings = [];
60
+ // ── Phase -1: self-adoption hard stop ──────────────────────────────
61
+ // If repoRoot or cwd looks like the Cairn source repo itself, refuse —
62
+ // running init here would overwrite cairn internals.
63
+ if (args.skipSelfAdoptionGuard !== true) {
64
+ if (isCairnSourceRepo(repoRoot) || isCairnSourceRepo(cwd)) {
65
+ info("");
66
+ info(" ✗ This looks like the Cairn source repository.");
67
+ info(" Running init here would overwrite cairn internals.");
68
+ info("");
69
+ info(" cairn init is for projects that USE Cairn, not for Cairn itself.");
70
+ info(" If you're developing Cairn, you don't need to run init.");
71
+ info("");
72
+ process.exit(1);
73
+ }
74
+ }
75
+ // ── Phase 0: install cancel handlers + redirect pino logs to a file.
76
+ // Cancel handlers are interactive-only; auto mode (smokes) skips them so
77
+ // the SIGINT trap doesn't keep the test process alive.
78
+ if (mode === "interactive") {
79
+ installInitCancelHandlers();
80
+ }
81
+ const logFilePath = redirectInitLogs();
82
+ header(`Cairn init — ${repoRoot}`);
83
+ if (!existsSync(join(repoRoot, ".git"))) {
84
+ warnings.push("no .git directory — mirror init will be skipped; the cairn expects a git-tracked working tree");
85
+ }
86
+ // ── Phase 0a: monorepo subdir guard ────────────────────────────────
87
+ // Walk cwd → gitRoot looking for a workspace marker. If cwd is inside a
88
+ // monorepo PACKAGE rather than at the workspace root, the mapper would
89
+ // only see the package subtree — usually not what the operator wants.
90
+ const monorepoContext = await preflightMonorepoGuard({
91
+ cwd,
92
+ repoRoot,
93
+ mode,
94
+ skip: args.skipMonorepoGuard === true,
95
+ autoMonorepo: args.autoMonorepo ?? "abort",
96
+ warnings,
97
+ });
98
+ // ── Phase 1: submodule pre-flight ──────────────────────────────────
99
+ const submoduleSummary = await preflightSubmodules({
100
+ repoRoot,
101
+ mode,
102
+ skip: args.skipSubmoduleCheck === true,
103
+ autoSubmodule: args.autoSubmodule ?? "init",
104
+ warnings,
105
+ });
106
+ const detection = await detectAll(repoRoot);
107
+ const decidedSlug = args.slugOverride !== undefined
108
+ ? normalizeProjectName(args.slugOverride)
109
+ : detection.project_slug;
110
+ // Walk repo here so the scan row appears in the Phase-1 discovery output.
111
+ // The same summary feeds the mapper later — no re-walk.
112
+ const repoSummary = buildRepoSummary({ repoRoot });
113
+ if (repoSummary.truncated_at_file_cap) {
114
+ warnings.push("repo walk truncated at file cap — pilot scope will be conservative");
115
+ }
116
+ if (repoSummary.truncated_at_depth_cap) {
117
+ warnings.push("repo walk truncated at depth cap");
118
+ }
119
+ printDiscovery(detection, decidedSlug, warnings, repoSummary);
120
+ // ── Dialog 1 (legacy proceed?) — only fired in auto mode for smoke compat.
121
+ // Interactive runs skip the explicit confirm per INIT_SPEC.md §3 (single
122
+ // confirm). The pilot-module prompt at the end of mapper proposal is the
123
+ // single operator gate.
124
+ const proceedChoice = mode === "auto"
125
+ ? args.autoProceed ?? "a"
126
+ : "a";
127
+ if (proceedChoice === "b") {
128
+ info("\ncancelled — no files written.");
129
+ return {
130
+ detection,
131
+ decided_slug: decidedSlug,
132
+ proceed: false,
133
+ seeded_files: [],
134
+ collisions: [],
135
+ config_path: "",
136
+ mapper_output: null,
137
+ mapper_applied_to_workflow: false,
138
+ mapper_applied_to_config: false,
139
+ brand_setup: null,
140
+ ingestion: null,
141
+ baseline_audit: null,
142
+ source_comments: null,
143
+ rules_merge: null,
144
+ multi_dev: null,
145
+ log_file_path: logFilePath,
146
+ monorepo_context: monorepoContext,
147
+ submodules: submoduleSummary,
148
+ warnings,
149
+ };
150
+ }
151
+ // ── Prerequisite state — derived from the discovery scan only. The
152
+ // pre-visual-overhaul "Guided setup" section that re-printed ✓ rows for
153
+ // each prereq was removed — the scanning section above is the sole place
154
+ // those checks appear.
155
+ const envState = detection.environment;
156
+ // ── Init mapper (Tier 2 / Sonnet) — proposes pilot_module + project_globs.
157
+ // Without this, project_globs.{route_handler,dto,generator_source,high_stakes}
158
+ // sit empty and Layer-D sensors never fire on real diffs (rework brief §3.1).
159
+ const mapperRunResult = await maybeRunMapper({
160
+ repoRoot,
161
+ detection,
162
+ repoSummary,
163
+ mode,
164
+ skipMapper: args.skipMapper === true,
165
+ ...(args.mockMapperOutput !== undefined
166
+ ? { mockMapperOutput: args.mockMapperOutput }
167
+ : {}),
168
+ envClaudeAuth: envState.claude_auth,
169
+ warnings,
170
+ });
171
+ const mapperOutput = mapperRunResult === null ? null : mapperRunResult.output;
172
+ const mapperFallbackSlugs = mapperRunResult === null ? [] : mapperRunResult.fallbackSlugs;
173
+ // ── Step 2: seed templates ─────────────────────────────────────────
174
+ header("Seeding .cairn/ + .archive/");
175
+ const seed = seedCairnLayout({
176
+ repoRoot,
177
+ projectSlug: decidedSlug,
178
+ ...(args.force === true ? { force: true } : {}),
179
+ });
180
+ for (const f of seed.written_files)
181
+ done(`+ ${f}`);
182
+ for (const c of seed.collisions) {
183
+ warnings.push(`collision (kept existing): ${c}`);
184
+ done(`= ${c} (kept existing — pass --force to overwrite)`);
185
+ }
186
+ // ── Step 2b: apply mapper output to workflow.md `<slug>:` block.
187
+ // Only when workflow.md was just seeded (or --force re-seeded). Re-runs that
188
+ // kept the existing workflow.md skip this so operator edits aren't clobbered.
189
+ const wfRelPath = ".cairn/config/workflow.md";
190
+ const wfWasSeeded = seed.written_files.includes(wfRelPath);
191
+ let mapperAppliedToWorkflow = false;
192
+ if (mapperOutput !== null && wfWasSeeded) {
193
+ const wfPath = join(repoRoot, wfRelPath);
194
+ try {
195
+ const r = updateWorkflowSlugBlock({
196
+ workflowMdPath: wfPath,
197
+ slug: decidedSlug,
198
+ update: {
199
+ pilot_module: mapperOutput.pilot_module,
200
+ route_handler_globs: mapperOutput.route_handler_globs,
201
+ dto_globs: mapperOutput.dto_globs,
202
+ generator_source_globs: mapperOutput.generator_source_globs,
203
+ high_stakes_globs: mapperOutput.high_stakes_globs,
204
+ off_limits_append: mapperOutput.off_limits_globs,
205
+ },
206
+ });
207
+ done(`+ patched <${decidedSlug}>: block in ${wfRelPath} (${r.applied_keys.join(", ")}; +${r.off_limits_added.length} off-limits)`);
208
+ mapperAppliedToWorkflow = true;
209
+ }
210
+ catch (err) {
211
+ warnings.push(`workflow.md slug-block update failed: ${String(err)}`);
212
+ }
213
+ }
214
+ else if (mapperOutput !== null && !wfWasSeeded) {
215
+ warnings.push(`mapper output NOT applied to ${wfRelPath} — kept existing; re-run with --force to overwrite, or merge globs manually`);
216
+ }
217
+ // ── Step 3: write project-overlay config.yaml ──────────────────────
218
+ header("Writing .cairn/config.yaml");
219
+ const configPath = join(repoRoot, ".cairn", "config.yaml");
220
+ mkdirSync(join(repoRoot, ".cairn"), { recursive: true });
221
+ let mapperAppliedToConfig = false;
222
+ if (existsSync(configPath) && args.force !== true) {
223
+ warnings.push(`.cairn/config.yaml already exists — kept existing (use --force to overwrite)`);
224
+ done(`= .cairn/config.yaml (kept)`);
225
+ if (mapperOutput !== null) {
226
+ warnings.push(`mapper output NOT applied to .cairn/config.yaml — kept existing; project_globs may be stale`);
227
+ }
228
+ }
229
+ else {
230
+ const config = buildProjectOverlay({
231
+ detection,
232
+ decidedSlug,
233
+ ...(mapperOutput !== null ? { mapperOutput } : {}),
234
+ });
235
+ writeFileSync(configPath, stringifyYaml(config), "utf8");
236
+ done(`+ .cairn/config.yaml`);
237
+ if (mapperOutput !== null)
238
+ mapperAppliedToConfig = true;
239
+ }
240
+ // ── Step 3b: scope-index.yaml ──────────────────────────────────────
241
+ header("Writing .cairn/ground/scope-index.yaml");
242
+ const scopeIndexFile = scopeIndexPath(repoRoot);
243
+ if (existsSync(scopeIndexFile) && args.force !== true) {
244
+ warnings.push(".cairn/ground/scope-index.yaml already exists — kept existing (use --force to overwrite)");
245
+ done(`= .cairn/ground/scope-index.yaml (kept)`);
246
+ }
247
+ else {
248
+ const seedFiles = {};
249
+ const mapperFiles = mapperOutput?.scope_index?.files ?? {};
250
+ for (const [path, e] of Object.entries(mapperFiles)) {
251
+ const entry = {
252
+ decisions: e.decisions,
253
+ invariants: e.invariants,
254
+ };
255
+ if (e.unscoped === true)
256
+ entry.unscoped = true;
257
+ seedFiles[path] = entry;
258
+ }
259
+ const seed = {
260
+ generated: new Date().toISOString(),
261
+ files: seedFiles,
262
+ };
263
+ writeScopeIndex(repoRoot, seed);
264
+ done(`+ .cairn/ground/scope-index.yaml`);
265
+ }
266
+ // ── Step 5b: brand setup (interactive 4-question wizard) ───────────
267
+ let brandSetup = null;
268
+ if (args.skipBrandSetup !== true) {
269
+ const answers = await runBrandSetup({
270
+ projectName: decidedSlug,
271
+ ...(mode === "auto" ? { skip: true } : {}),
272
+ ...(args.scriptedBrandAnswers !== undefined
273
+ ? { scriptedAnswers: args.scriptedBrandAnswers }
274
+ : {}),
275
+ });
276
+ const answered = (answers.whatItDoes.length > 0 ? 1 : 0) +
277
+ (answers.mainUsers.length > 0 ? 1 : 0) +
278
+ (answers.voice.length > 0 ? 1 : 0) +
279
+ (answers.avoid.length > 0 ? 1 : 0);
280
+ if (answered > 0) {
281
+ const apply = applyBrandAnswers(repoRoot, answers);
282
+ for (const w of apply.warnings)
283
+ warnings.push(w);
284
+ brandSetup = { answered, updated_files: apply.updated };
285
+ }
286
+ else {
287
+ brandSetup = { answered: 0, updated_files: [] };
288
+ }
289
+ }
290
+ // ── Phase 6: ingestion sweep + baseline audit ──────────────────────
291
+ // Populates project brain from docs that already exist in the repo, then
292
+ // runs every runnable sensor against the full codebase to surface pre-
293
+ // Cairn debt. Both pieces are best-effort; failures degrade to empty
294
+ // result, never block the init.
295
+ const phase6 = await runPhaseSix({
296
+ repoRoot,
297
+ decidedSlug,
298
+ detection,
299
+ mapperOutput,
300
+ skip: args.skipIngestion === true || mode === "auto",
301
+ warnings,
302
+ });
303
+ // ── Phase 7b: source-comment ingestion ─────────────────────────────
304
+ // Walks every source file, batches block-comments through Haiku, files
305
+ // DEC drafts + invariant proposals + canonical citations into
306
+ // `.cairn/baseline/`. Skipped under the same condition as Phase 6
307
+ // unless a `mockSourceCommentClassify` is supplied (smokes).
308
+ let sourceComments = null;
309
+ const skip7b = args.skipPhase7b === true ||
310
+ ((args.skipIngestion === true || mode === "auto") &&
311
+ args.mockSourceCommentClassify === undefined);
312
+ if (!skip7b) {
313
+ process.stdout.write("\n");
314
+ process.stdout.write(` ${visualC.bold("Phase 7b")} — source-comment ingestion…\n`);
315
+ try {
316
+ sourceComments = await runSourceCommentsIngestion({
317
+ repoRoot,
318
+ ...(args.mockSourceCommentClassify !== undefined
319
+ ? { mockClassify: args.mockSourceCommentClassify }
320
+ : {}),
321
+ onBatchProgress: (row) => {
322
+ if (row.index === row.total - 1) {
323
+ process.stdout.write(` ${row.classified} classified, ${row.failed} failed (${row.total} batch${row.total === 1 ? "" : "es"})\n`);
324
+ }
325
+ },
326
+ });
327
+ process.stdout.write(` DEC drafts: ${sourceComments.decDraftsWritten.length}; ` +
328
+ `invariant proposals: ${sourceComments.invariantProposalsAdded}; ` +
329
+ `citations: ${sourceComments.canonicalCitationsAdded}\n`);
330
+ }
331
+ catch (err) {
332
+ const msg = err instanceof Error ? err.message : String(err);
333
+ warnings.push(`source-comment ingestion failed: ${msg}`);
334
+ process.stdout.write(` ${visualC.yellow("⚠")} source-comment ingestion failed — ${msg}\n`);
335
+ }
336
+ }
337
+ // ── Phase 7c: existing-rules merge + first regenerate ──────────────
338
+ // Reads CLAUDE.md / AGENTS.md / .claude/CLAUDE.md / .claude/rules/**.md,
339
+ // classifies sections via Haiku into rule-net-new / rule-conflict /
340
+ // informational / operator-keep, persists net-new as DEC drafts. The
341
+ // initial regenerate of CLAUDE.md + AGENTS.md from ground state is
342
+ // deferred until after operator accepts the drafts in the attention
343
+ // pass — we don't auto-overwrite their existing rule files at adoption.
344
+ let rulesMerge = null;
345
+ const skip7c = args.skipPhase7c === true ||
346
+ ((args.skipIngestion === true || mode === "auto") &&
347
+ args.mockRulesMergeClassify === undefined);
348
+ if (!skip7c) {
349
+ process.stdout.write("\n");
350
+ process.stdout.write(` ${visualC.bold("Phase 7c")} — existing-rules merge…\n`);
351
+ try {
352
+ rulesMerge = await runRulesMerge({
353
+ repoRoot,
354
+ ...(args.mockRulesMergeClassify !== undefined
355
+ ? { mockClassify: args.mockRulesMergeClassify }
356
+ : {}),
357
+ });
358
+ process.stdout.write(` Sources: ${rulesMerge.sources.length}; ` +
359
+ `net-new: ${rulesMerge.kindCounts["rule-net-new"]}; ` +
360
+ `conflicts: ${rulesMerge.kindCounts["rule-conflict"]}; ` +
361
+ `informational: ${rulesMerge.kindCounts.informational}; ` +
362
+ `operator-keep: ${rulesMerge.kindCounts["operator-keep"]}\n`);
363
+ }
364
+ catch (err) {
365
+ const msg = err instanceof Error ? err.message : String(err);
366
+ warnings.push(`rules merge failed: ${msg}`);
367
+ process.stdout.write(` ${visualC.yellow("⚠")} rules merge failed — ${msg}\n`);
368
+ }
369
+ }
370
+ // ── Phase 12: multi-developer enforcement install ──────────────────
371
+ // Idempotent + deterministic. Patches `package.json` `scripts.prepare`
372
+ // for Node projects so every clone runs `cairn join` on install.
373
+ // Surfaces manual hints for non-Node hosts. Templates (.cairn/
374
+ // git-hooks/*, JOIN.md, .github/workflows/cairn-check.yml) were
375
+ // landed by `seedCairnLayout` in Phase 4.
376
+ let multiDev = null;
377
+ if (args.skipPhase12 !== true) {
378
+ process.stdout.write("\n");
379
+ process.stdout.write(` ${visualC.bold("Phase 12")} — multi-dev enforcement install…\n`);
380
+ try {
381
+ multiDev = installMultiDev({ repoRoot });
382
+ const hostList = multiDev.hostKinds.join(", ");
383
+ process.stdout.write(` Hosts detected: ${hostList}; prepare patched: ${multiDev.preparePatched ? "yes" : "no"}\n`);
384
+ for (const hint of multiDev.manualHints) {
385
+ process.stdout.write(` ${visualC.dim(hint)}\n`);
386
+ }
387
+ }
388
+ catch (err) {
389
+ const msg = err instanceof Error ? err.message : String(err);
390
+ warnings.push(`multi-dev install failed: ${msg}`);
391
+ process.stdout.write(` ${visualC.yellow("⚠")} multi-dev install failed — ${msg}\n`);
392
+ }
393
+ }
394
+ // Per-session status.json is owned by the plugin's SessionStart hook
395
+ // (PLUGIN_ARCHITECTURE §7). Init no longer writes it; the next
396
+ // SessionStart in any clone seeds the per-session file with the
397
+ // current attention_count derived from drafts + baseline findings.
398
+ // ── Step 6: completion summary (structured) ────────────────────────
399
+ printCompletionSummary({
400
+ projectName: decidedSlug,
401
+ repoRoot,
402
+ seededFiles: seed.written_files,
403
+ brandSetup,
404
+ submodules: submoduleSummary,
405
+ scanTruncated: repoSummary.truncated_at_file_cap ||
406
+ repoSummary.truncated_at_depth_cap,
407
+ mapperFallbackSlugs,
408
+ ingestion: phase6.ingestion,
409
+ baselineAudit: phase6.baselineAudit,
410
+ logFilePath,
411
+ warnings,
412
+ });
413
+ log.info({
414
+ repo_root: repoRoot,
415
+ slug: decidedSlug,
416
+ seeded: seed.written_files.length,
417
+ collisions: seed.collisions.length,
418
+ mapper_ran: mapperOutput !== null,
419
+ mapper_applied_to_workflow: mapperAppliedToWorkflow,
420
+ mapper_applied_to_config: mapperAppliedToConfig,
421
+ brand_answered: brandSetup?.answered ?? null,
422
+ ingestion_drafts: phase6.ingestion?.decDraftsWritten.length ?? null,
423
+ baseline_findings: phase6.baselineAudit?.totalFindings ?? null,
424
+ warnings: warnings.length,
425
+ }, "init complete");
426
+ return {
427
+ detection,
428
+ decided_slug: decidedSlug,
429
+ proceed: true,
430
+ seeded_files: seed.written_files,
431
+ collisions: seed.collisions,
432
+ config_path: ".cairn/config.yaml",
433
+ mapper_output: mapperOutput,
434
+ mapper_applied_to_workflow: mapperAppliedToWorkflow,
435
+ mapper_applied_to_config: mapperAppliedToConfig,
436
+ brand_setup: brandSetup,
437
+ ingestion: phase6.ingestion,
438
+ baseline_audit: phase6.baselineAudit,
439
+ source_comments: sourceComments,
440
+ rules_merge: rulesMerge,
441
+ multi_dev: multiDev,
442
+ log_file_path: logFilePath,
443
+ monorepo_context: monorepoContext,
444
+ submodules: submoduleSummary,
445
+ warnings,
446
+ };
447
+ }
448
+ function buildProjectOverlay(args) {
449
+ const detected_sensor_commands = args.detection.proposed_sensors.map((s) => ({
450
+ id: s.id,
451
+ command: s.command,
452
+ args: s.args,
453
+ applies_to: s.applies_to,
454
+ reason: s.reason,
455
+ }));
456
+ const m = args.mapperOutput;
457
+ const offLimits = [...DEFAULT_OFF_LIMITS];
458
+ if (m !== undefined) {
459
+ for (const x of m.off_limits_globs) {
460
+ if (!offLimits.includes(x))
461
+ offLimits.push(x);
462
+ }
463
+ }
464
+ const overlay = {
465
+ version: 1,
466
+ cairn_version: VERSION,
467
+ slug: args.decidedSlug,
468
+ origin_url: args.detection.origin_url,
469
+ stack_signatures: args.detection.stack_signatures.map((s) => s.kind),
470
+ hook_capability: args.detection.hook_capability,
471
+ start_command: args.detection.start_command,
472
+ detected_sensor_commands,
473
+ off_limits: offLimits,
474
+ high_stakes_globs: m?.high_stakes_globs ?? [],
475
+ project_globs: {
476
+ route_handler_globs: m?.route_handler_globs ?? [],
477
+ dto_globs: m?.dto_globs ?? [],
478
+ generator_source_globs: m?.generator_source_globs ?? [],
479
+ high_stakes_globs: m?.high_stakes_globs ?? [],
480
+ },
481
+ };
482
+ if (m !== undefined) {
483
+ overlay["pilot_module"] = m.pilot_module;
484
+ overlay["domain_summary"] = m.domain_summary;
485
+ overlay["key_modules"] = m.key_modules;
486
+ overlay["mapper_proposed_sensors"] = m.proposed_sensors;
487
+ if (m.notes.trim().length > 0)
488
+ overlay["mapper_notes"] = m.notes;
489
+ }
490
+ return overlay;
491
+ }
492
+ async function maybeRunMapper(args) {
493
+ if (args.mockMapperOutput !== undefined) {
494
+ info("\n── Init mapper — using injected mockMapperOutput (smoke / scripted adoption)");
495
+ return { output: args.mockMapperOutput, fallbackSlugs: [] };
496
+ }
497
+ if (args.skipMapper) {
498
+ info("\n── Init mapper skipped (--skip-mapper); project_globs left empty");
499
+ args.warnings.push("mapper skipped via --skip-mapper — project_globs left empty");
500
+ return null;
501
+ }
502
+ if (args.mode === "auto") {
503
+ info("\n── Init mapper skipped (--no-prompt mode; pass mockMapperOutput to test the apply path)");
504
+ return null;
505
+ }
506
+ if (!args.envClaudeAuth) {
507
+ args.warnings.push("mapper skipped — claude CLI not available; project_globs left empty");
508
+ info("\n── Init mapper skipped — claude CLI not available; re-run init after `claude` auth to fill project_globs");
509
+ return null;
510
+ }
511
+ // Reuse the summary built during Phase-1 discovery — no second walk.
512
+ const summary = args.repoSummary;
513
+ // Mapper dispatches automatically per INIT_SPEC §3 — no per-run cost prompt.
514
+ // The orchestrator handles parallel module calls + Haiku merge internally;
515
+ // legacy single-call path is its own fallback when every module call fails.
516
+ let mapperResult;
517
+ const spinner = startSpinner("Analyzing codebase…");
518
+ let totalSlices = 0;
519
+ let completed = 0;
520
+ let failedModules = 0;
521
+ const t0 = Date.now();
522
+ try {
523
+ mapperResult = await runMapper({
524
+ detection: args.detection,
525
+ summary,
526
+ repoRoot: args.repoRoot,
527
+ onSlicesDetected: (slices) => {
528
+ totalSlices = slices.length;
529
+ spinner.update(totalSlices === 1
530
+ ? `Analyzing codebase (1 module)…`
531
+ : `Analyzing codebase (${totalSlices} modules)…`);
532
+ },
533
+ onModuleEnd: (slice, p) => {
534
+ completed++;
535
+ if (p.failed)
536
+ failedModules++;
537
+ const mark = p.failed ? "✗" : "✓";
538
+ const dur = `${(p.durationMs / 1000).toFixed(0)}s`;
539
+ spinner.update(`Analyzing codebase (${completed}/${totalSlices}) — ${mark} ${slice.moduleSlug} ${dur}`);
540
+ },
541
+ });
542
+ const ms = Date.now() - t0;
543
+ const seconds = `${(ms / 1000).toFixed(0)}s`;
544
+ if (failedModules > 0) {
545
+ spinner.succeed(`Analysis complete (${seconds} · ${completed - failedModules}/${totalSlices} modules ok)`);
546
+ }
547
+ else {
548
+ spinner.succeed(`Analysis complete (${seconds} · ${completed} module${completed === 1 ? "" : "s"})`);
549
+ }
550
+ }
551
+ catch (err) {
552
+ spinner.fail(`Analysis failed — ${err instanceof Error ? err.message : String(err)}`);
553
+ args.warnings.push(`mapper dispatch failed: ${String(err)}`);
554
+ return null;
555
+ }
556
+ printMapperProposal(mapperResult);
557
+ // Single confirm — pilot module. Operator presses Enter to apply or types
558
+ // an alternate path to override. (args.mode narrowed to "interactive" above.)
559
+ const pilotChoice = await freeTextWithDefault({
560
+ mode: args.mode,
561
+ prompt: "Press Enter to apply, or type a different pilot path",
562
+ defaultValue: mapperResult.output.pilot_module,
563
+ });
564
+ if (pilotChoice.length > 0 && pilotChoice !== mapperResult.output.pilot_module) {
565
+ mapperResult.output.pilot_module = pilotChoice;
566
+ }
567
+ const fallbackSlugs = mapperResult.module_proposals === undefined
568
+ ? []
569
+ : mapperResult.module_proposals.filter((p) => p.failed).map((p) => p.moduleSlug);
570
+ if (fallbackSlugs.length > 0) {
571
+ args.warnings.push(`mapper fallback used for: ${fallbackSlugs.join(", ")} — rerun \`cairn scope rebuild\` for full classification`);
572
+ }
573
+ return { output: mapperResult.output, fallbackSlugs };
574
+ }
575
+ function printMapperProposal(r, opts = {}) {
576
+ const o = r.output;
577
+ process.stdout.write("\n");
578
+ // Project line: slug — domain summary (truncated)
579
+ const projectName = "(detected)";
580
+ process.stdout.write(` ${visualC.bold("Project")} ${projectName} — ${truncateOneLine(o.domain_summary, 100)}\n`);
581
+ process.stdout.write("\n");
582
+ // Modules line: dot-separated module names
583
+ const moduleLabels = o.key_modules.map((km) => km.path);
584
+ if (moduleLabels.length > 0) {
585
+ process.stdout.write(` ${visualC.bold("Modules")} ${moduleLabels.join(" · ")}\n`);
586
+ process.stdout.write("\n");
587
+ }
588
+ // Sensors block
589
+ const sensors = o.proposed_sensors;
590
+ if (sensors.length > 0) {
591
+ const headLine = `${sensors.length} proposed`;
592
+ process.stdout.write(` ${visualC.bold("Sensors")} ${headLine}\n`);
593
+ const widest = Math.max(...sensors.slice(0, 3).map((s) => s.id.length), 1);
594
+ for (const s of sensors.slice(0, 3)) {
595
+ process.stdout.write(` ${s.id.padEnd(widest + 2)}${truncateOneLine(s.description, 80 - widest)}\n`);
596
+ }
597
+ if (sensors.length > 3) {
598
+ process.stdout.write(` ${visualC.dim(`+ ${sensors.length - 3} more`)}\n`);
599
+ }
600
+ process.stdout.write("\n");
601
+ }
602
+ // Pilot line
603
+ const pilotNote = opts.partialModules !== undefined && opts.partialModules.length > 0
604
+ ? ` ${visualC.dim(`(only fully-visible module — run cairn scope rebuild after submodules initialize)`)}`
605
+ : "";
606
+ process.stdout.write(` ${visualC.bold("Pilot")} ${o.pilot_module}${pilotNote}\n`);
607
+ }
608
+ function truncateOneLine(s, max) {
609
+ const collapsed = s.replace(/\s+/g, " ").trim();
610
+ return collapsed.length > max ? `${collapsed.slice(0, max - 1)}…` : collapsed;
611
+ }
612
+ function redirectInitLogs() {
613
+ const stamp = new Date()
614
+ .toISOString()
615
+ .replace(/[:.]/g, "-");
616
+ const path = join(homedir(), ".local", "cairn", "logs", `init-${stamp}.log`);
617
+ try {
618
+ setLogFile(path);
619
+ return path;
620
+ }
621
+ catch {
622
+ // best-effort — falls through to whatever the default destination is.
623
+ return path;
624
+ }
625
+ }
626
+ async function preflightMonorepoGuard(args) {
627
+ if (args.skip)
628
+ return null;
629
+ // The guard applies only when the operator launched init at their cwd.
630
+ // When a different repoRoot is targeted (`--repo <path>`, smokes), the
631
+ // process.cwd() relationship to the workspace is irrelevant.
632
+ if (args.repoRoot !== args.cwd)
633
+ return null;
634
+ const gitRoot = findGitRoot(args.cwd);
635
+ if (gitRoot === null)
636
+ return null;
637
+ const ctx = detectMonorepoContext(args.cwd, gitRoot);
638
+ if (ctx === null)
639
+ return null;
640
+ const relScope = relative(ctx.workspaceRoot, args.cwd) || ".";
641
+ info("");
642
+ info(` ${visualC.yellow("⚠")} You're inside a monorepo package.`);
643
+ info(` init from here will only analyse: ${visualC.bold(relScope + "/")}`);
644
+ info(` Monorepo root detected at: ${visualC.dim(ctx.workspaceRoot)}`);
645
+ info("");
646
+ info(" Run from the monorepo root for full codebase analysis.");
647
+ const choice = args.mode === "auto"
648
+ ? args.autoMonorepo === "continue"
649
+ : await yesNo({
650
+ mode: args.mode,
651
+ prompt: "Continue here anyway? (not recommended)",
652
+ defaultYes: false,
653
+ });
654
+ if (!choice) {
655
+ info("");
656
+ info(` Aborted. To run from the workspace root:`);
657
+ info(` cd ${ctx.workspaceRoot} && cairn init`);
658
+ info("");
659
+ process.exit(1);
660
+ }
661
+ args.warnings.push(`init ran from a monorepo sub-package (scope=${relScope}); workspace root at ${ctx.workspaceRoot} was bypassed. Re-run from there for full codebase analysis.`);
662
+ return ctx;
663
+ }
664
+ async function preflightSubmodules(args) {
665
+ if (args.skip)
666
+ return null;
667
+ const scan = await scanSubmodules(args.repoRoot);
668
+ if (!scan.hasGitmodules)
669
+ return null;
670
+ const uninitialized = scan.submodules.filter((s) => s.uninitialized);
671
+ if (uninitialized.length === 0) {
672
+ // All submodules already initialized — no prompt, no warning.
673
+ return {
674
+ detected_uninitialized: [],
675
+ initialized: false,
676
+ success: true,
677
+ };
678
+ }
679
+ info("");
680
+ info("Git submodules detected — not initialized");
681
+ const widest = Math.max(...uninitialized.map((s) => s.path.length), 1);
682
+ for (const s of uninitialized) {
683
+ info(` ${s.path.padEnd(widest + 2)}(uninitialized)`);
684
+ }
685
+ info("");
686
+ const initFlag = args.mode === "auto"
687
+ ? args.autoSubmodule !== "skip"
688
+ : await yesNo({
689
+ mode: args.mode,
690
+ prompt: "Initialize submodules now? Required for full codebase analysis.",
691
+ defaultYes: true,
692
+ });
693
+ if (!initFlag) {
694
+ args.warnings.push(`submodules left uninitialized — mapper has partial visibility on: ${uninitialized
695
+ .map((s) => s.path)
696
+ .join(", ")}. Re-run \`git submodule update --init --recursive\` then \`cairn scope rebuild\`.`);
697
+ info(` ⚠ submodule init skipped — mapper will see partial codebase`);
698
+ return {
699
+ detected_uninitialized: uninitialized.map((s) => s.path),
700
+ initialized: false,
701
+ success: false,
702
+ };
703
+ }
704
+ info(" ↻ initializing submodules…");
705
+ const result = await runGitSubmoduleUpdate({
706
+ repoRoot: args.repoRoot,
707
+ onProgress: (event) => {
708
+ const m = event.line.match(/Submodule path '([^']+)':/);
709
+ if (m && typeof m[1] === "string") {
710
+ info(` ✓ ${m[1]}`);
711
+ }
712
+ },
713
+ });
714
+ if (!result.ok) {
715
+ args.warnings.push(`submodule init failed (${result.errorSummary ?? "unknown"}) — mapper has partial visibility. Re-run \`git submodule update --init --recursive\` manually then \`cairn scope rebuild\`.`);
716
+ info(` ✗ submodule init failed — continuing with partial codebase`);
717
+ return {
718
+ detected_uninitialized: uninitialized.map((s) => s.path),
719
+ initialized: true,
720
+ success: false,
721
+ };
722
+ }
723
+ info(" ✓ submodules ready");
724
+ return {
725
+ detected_uninitialized: uninitialized.map((s) => s.path),
726
+ initialized: true,
727
+ success: true,
728
+ };
729
+ }
730
+ function printCompletionSummary(args) {
731
+ const groundCount = countGroundFiles(args.repoRoot);
732
+ const sensorCount = countSensorEntries(args.repoRoot);
733
+ const scopeReport = describeScopeIndex(args.repoRoot, args.submodules, args.scanTruncated);
734
+ const brandReport = describeBrandStatus(args.repoRoot);
735
+ const hookReport = describeHooks(args.repoRoot);
736
+ const mcpReport = describeMcpRegistration(args.repoRoot);
737
+ info("");
738
+ info(` ✓ Cairn ready — ${args.projectName}`);
739
+ info("");
740
+ info(` Ground state .cairn/ground/ (${groundCount} files)`);
741
+ info(` MCP server ${mcpReport}`);
742
+ info(` Hooks ${hookReport}`);
743
+ info(` Sensors ${sensorCount} active`);
744
+ if (args.mapperFallbackSlugs.length > 0) {
745
+ const head = args.mapperFallbackSlugs.slice(0, 3).join(", ");
746
+ const more = args.mapperFallbackSlugs.length > 3
747
+ ? ` +${args.mapperFallbackSlugs.length - 3} more`
748
+ : "";
749
+ info(` ${head}${more} used fallback — rerun cairn scope rebuild`);
750
+ }
751
+ info(` Brand ${brandReport}`);
752
+ info(` Scope index ${scopeReport.line}`);
753
+ if (scopeReport.followUp !== null) {
754
+ info(` ${scopeReport.followUp}`);
755
+ }
756
+ if (args.logFilePath !== null) {
757
+ info(` Log ${shortenHomePath(args.logFilePath)}`);
758
+ }
759
+ // Project brain populated from existing codebase.
760
+ const ingestionReport = describeIngestion(args.ingestion);
761
+ const canonicalReport = describeCanonical(args.ingestion);
762
+ const baselineReport = describeBaseline(args.baselineAudit);
763
+ if (ingestionReport !== null ||
764
+ canonicalReport !== null ||
765
+ baselineReport !== null) {
766
+ info("");
767
+ info(" Project brain populated from existing codebase:");
768
+ if (ingestionReport !== null) {
769
+ info(` DEC drafts ${ingestionReport}`);
770
+ }
771
+ if (canonicalReport !== null) {
772
+ info(` Canonical map ${canonicalReport}`);
773
+ }
774
+ if (baselineReport !== null) {
775
+ info(` Baseline debt ${baselineReport}`);
776
+ }
777
+ }
778
+ info("");
779
+ info(" Open Claude Code in this directory. Cairn is live immediately.");
780
+ info("");
781
+ info(" Next: cairn attention see pending items");
782
+ info(" cairn doctor verify everything is working");
783
+ info(" cairn configure brand fill in brand guidelines");
784
+ if (args.warnings.length > 0) {
785
+ info("");
786
+ info(` ${args.warnings.length} warning${args.warnings.length === 1 ? "" : "s"}:`);
787
+ for (const w of args.warnings)
788
+ info(` ! ${w}`);
789
+ }
790
+ }
791
+ function shortenHomePath(abs) {
792
+ const home = homedir();
793
+ if (abs.startsWith(home))
794
+ return `~${abs.slice(home.length)}`;
795
+ return abs;
796
+ }
797
+ function countGroundFiles(repoRoot) {
798
+ const groundDir = join(repoRoot, ".cairn", "ground");
799
+ if (!existsSync(groundDir))
800
+ return 0;
801
+ let count = 0;
802
+ const stack = [groundDir];
803
+ while (stack.length > 0) {
804
+ const dir = stack.pop();
805
+ if (dir === undefined)
806
+ break;
807
+ let entries;
808
+ try {
809
+ entries = readdirSync(dir, { withFileTypes: true, encoding: "utf8" });
810
+ }
811
+ catch {
812
+ continue;
813
+ }
814
+ for (const e of entries) {
815
+ const abs = join(dir, e.name);
816
+ if (e.isDirectory()) {
817
+ if (e.name === "_inbox")
818
+ continue;
819
+ stack.push(abs);
820
+ }
821
+ else if (e.isFile()) {
822
+ count++;
823
+ }
824
+ }
825
+ }
826
+ return count;
827
+ }
828
+ function countSensorEntries(repoRoot) {
829
+ const path = join(repoRoot, ".cairn", "config", "sensors.yaml");
830
+ if (!existsSync(path))
831
+ return 0;
832
+ try {
833
+ const parsed = parseYaml(readFileSync(path, "utf8"));
834
+ if (typeof parsed !== "object" || parsed === null)
835
+ return 0;
836
+ const sensorsRaw = parsed["sensors"];
837
+ if (!Array.isArray(sensorsRaw))
838
+ return 0;
839
+ return sensorsRaw.length;
840
+ }
841
+ catch {
842
+ return 0;
843
+ }
844
+ }
845
+ function describeScopeIndex(repoRoot, submodules, scanTruncated) {
846
+ const path = join(repoRoot, ".cairn", "ground", "scope-index.yaml");
847
+ const submoduleNoteJustInitialized = submodules !== null &&
848
+ submodules.initialized &&
849
+ submodules.success;
850
+ const truncationFollowUp = "Run cairn scope rebuild for full classification";
851
+ if (!existsSync(path)) {
852
+ return {
853
+ line: "missing — run cairn scope rebuild",
854
+ followUp: null,
855
+ };
856
+ }
857
+ try {
858
+ const parsed = parseYaml(readFileSync(path, "utf8"));
859
+ if (typeof parsed !== "object" || parsed === null) {
860
+ return {
861
+ line: "empty — run cairn scope rebuild",
862
+ followUp: null,
863
+ };
864
+ }
865
+ const filesRaw = parsed["files"];
866
+ if (typeof filesRaw !== "object" || filesRaw === null) {
867
+ return {
868
+ line: "empty — run cairn scope rebuild",
869
+ followUp: null,
870
+ };
871
+ }
872
+ const count = Object.keys(filesRaw).length;
873
+ if (count === 0) {
874
+ if (scanTruncated) {
875
+ return {
876
+ line: "empty — analysis was truncated during init",
877
+ followUp: truncationFollowUp,
878
+ };
879
+ }
880
+ return {
881
+ line: submoduleNoteJustInitialized
882
+ ? "empty — submodules now initialized, run cairn scope rebuild"
883
+ : "empty — run cairn scope rebuild",
884
+ followUp: null,
885
+ };
886
+ }
887
+ if (scanTruncated) {
888
+ return {
889
+ line: "partial — analysis was truncated during init",
890
+ followUp: truncationFollowUp,
891
+ };
892
+ }
893
+ if (submoduleNoteJustInitialized) {
894
+ return {
895
+ line: `partial — ${count} file${count === 1 ? "" : "s"} classified (submodules now initialized)`,
896
+ followUp: truncationFollowUp,
897
+ };
898
+ }
899
+ return {
900
+ line: `ready (${count} file${count === 1 ? "" : "s"} classified)`,
901
+ followUp: null,
902
+ };
903
+ }
904
+ catch {
905
+ return {
906
+ line: "unreadable — run cairn scope rebuild",
907
+ followUp: null,
908
+ };
909
+ }
910
+ }
911
+ function describeBrandStatus(repoRoot) {
912
+ const overview = join(repoRoot, ".cairn", "ground", "brand", "overview.md");
913
+ const positioning = join(repoRoot, ".cairn", "ground", "product", "positioning.md");
914
+ const voice = join(repoRoot, ".cairn", "ground", "brand", "voice.md");
915
+ const all = [overview, positioning, voice];
916
+ let currentCount = 0;
917
+ let total = 0;
918
+ for (const p of all) {
919
+ if (!existsSync(p))
920
+ continue;
921
+ total++;
922
+ if (readFrontmatterStatus(p) === "current")
923
+ currentCount++;
924
+ }
925
+ if (total === 0)
926
+ return "missing — re-run cairn init";
927
+ if (currentCount === total)
928
+ return "ready";
929
+ if (currentCount === 0)
930
+ return "draft — run cairn configure brand";
931
+ return `partial (${currentCount}/${total} current) — run cairn configure brand`;
932
+ }
933
+ function readFrontmatterStatus(path) {
934
+ try {
935
+ const text = readFileSync(path, "utf8");
936
+ const m = text.match(/^---\n([\s\S]*?\n)---/);
937
+ if (!m)
938
+ return null;
939
+ const fm = m[1] ?? "";
940
+ const sm = fm.match(/^status:\s*(\S+)\s*$/m);
941
+ return sm && sm[1] ? sm[1] : null;
942
+ }
943
+ catch {
944
+ return null;
945
+ }
946
+ }
947
+ function describeHooks(repoRoot) {
948
+ const path = join(repoRoot, ".claude", "settings.json");
949
+ if (!existsSync(path))
950
+ return "missing .claude/settings.json";
951
+ try {
952
+ const parsed = JSON.parse(readFileSync(path, "utf8"));
953
+ const hooks = parsed["hooks"];
954
+ if (typeof hooks !== "object" || hooks === null)
955
+ return "missing entries";
956
+ const sessionStart = hooks["SessionStart"];
957
+ const postToolUse = hooks["PostToolUse"];
958
+ const labels = [];
959
+ if (Array.isArray(sessionStart) && sessionStart.length > 0) {
960
+ labels.push("SessionStart");
961
+ }
962
+ if (Array.isArray(postToolUse) && postToolUse.length > 0) {
963
+ labels.push("PostToolUse (read-enricher, write-guardian)");
964
+ }
965
+ return labels.length === 0 ? "no entries" : labels.join(" · ");
966
+ }
967
+ catch {
968
+ return "unreadable";
969
+ }
970
+ }
971
+ function describeMcpRegistration(repoRoot) {
972
+ const path = join(repoRoot, ".mcp.json");
973
+ if (!existsSync(path))
974
+ return ".mcp.json · missing entry";
975
+ try {
976
+ const parsed = JSON.parse(readFileSync(path, "utf8"));
977
+ const servers = parsed["mcpServers"];
978
+ if (typeof servers !== "object" || servers === null) {
979
+ return ".mcp.json · missing cairn entry";
980
+ }
981
+ if (servers["cairn"] !== undefined) {
982
+ return ".mcp.json · ready";
983
+ }
984
+ return ".mcp.json · missing cairn entry";
985
+ }
986
+ catch {
987
+ return ".mcp.json · unreadable";
988
+ }
989
+ }
990
+ function printDiscovery(d, decidedSlug, warnings, summary) {
991
+ process.stdout.write("\n");
992
+ process.stdout.write(` ${visualC.bold("Scanning")}${visualC.dim("…")}\n`);
993
+ // git root (we always have repo_root after detection)
994
+ discoveryRow({ status: "ok", label: "git root", value: visualC.dim(d.repo_root) });
995
+ // project slug
996
+ const slugVal = decidedSlug + (decidedSlug === d.project_slug ? "" : visualC.dim(" (override)"));
997
+ discoveryRow({ status: "ok", label: "project slug", value: slugVal });
998
+ // remote
999
+ const remote = d.origin_url;
1000
+ discoveryRow({
1001
+ status: remote !== null ? "ok" : "warn",
1002
+ label: "remote",
1003
+ value: remote !== null
1004
+ ? visualC.dim(remoteShorthand(remote))
1005
+ : visualC.dim("local-only repo"),
1006
+ });
1007
+ // stack signatures
1008
+ const stackKinds = d.stack_signatures.map((s) => s.kind);
1009
+ discoveryRow({
1010
+ status: stackKinds.length > 0 ? "ok" : "warn",
1011
+ label: "stack",
1012
+ value: stackKinds.length > 0
1013
+ ? visualC.dim(stackKinds.join(", "))
1014
+ : visualC.dim("unknown"),
1015
+ });
1016
+ // codebase scan — surfaces walker truncation so a degraded mapper input
1017
+ // can be acted on (run `cairn scope rebuild` after init).
1018
+ if (summary.truncated_at_file_cap) {
1019
+ discoveryRow({
1020
+ status: "warn",
1021
+ label: "codebase scan",
1022
+ value: visualC.dim("incomplete — file cap reached"),
1023
+ });
1024
+ process.stdout.write(` ${visualC.dim("some source trees may be missing from analysis")}\n`);
1025
+ process.stdout.write(` ${visualC.dim("run: cairn scope rebuild after init for full classification")}\n`);
1026
+ }
1027
+ else if (summary.truncated_at_depth_cap) {
1028
+ discoveryRow({
1029
+ status: "warn",
1030
+ label: "codebase scan",
1031
+ value: visualC.dim("incomplete — depth cap reached"),
1032
+ });
1033
+ process.stdout.write(` ${visualC.dim("run: cairn scope rebuild after init for full classification")}\n`);
1034
+ }
1035
+ else {
1036
+ discoveryRow({
1037
+ status: "ok",
1038
+ label: "codebase scan",
1039
+ value: visualC.dim(`${summary.total_files} files, ${summary.total_dirs} dirs`),
1040
+ });
1041
+ }
1042
+ // claude code
1043
+ const e = d.environment;
1044
+ discoveryRow({
1045
+ status: e.claude_auth ? "ok" : "err",
1046
+ label: "Claude Code",
1047
+ value: e.claude_auth
1048
+ ? visualC.dim("authenticated")
1049
+ : visualC.dim("missing or unauthenticated"),
1050
+ });
1051
+ if (!e.claude_auth)
1052
+ warnings.push("claude CLI not available");
1053
+ }
1054
+ async function runPhaseSix(args) {
1055
+ if (args.skip) {
1056
+ return { ingestion: null, baselineAudit: null };
1057
+ }
1058
+ process.stdout.write("\n");
1059
+ process.stdout.write(` ${visualC.bold("Phase 6")} — ingesting existing project knowledge…\n`);
1060
+ // ── 6.1 — docs ingestion (Haiku per doc; cap 20 largest) ───────────
1061
+ let ingestion = null;
1062
+ try {
1063
+ ingestion = await runDocsIngestion({
1064
+ repoRoot: args.repoRoot,
1065
+ onGroupProgress: (row) => {
1066
+ const status = row.ok ? "✓" : "✗";
1067
+ const label = row.group.padEnd(20);
1068
+ const summary = row.drafts > 0
1069
+ ? `${row.drafts} DEC draft${row.drafts === 1 ? "" : "s"} proposed`
1070
+ : `${row.total} doc${row.total === 1 ? "" : "s"} scanned`;
1071
+ process.stdout.write(` ${label} ${status} ${summary}\n`);
1072
+ },
1073
+ });
1074
+ }
1075
+ catch (err) {
1076
+ const msg = err instanceof Error ? err.message : String(err);
1077
+ args.warnings.push(`docs ingestion failed: ${msg}`);
1078
+ process.stdout.write(` ${visualC.yellow("⚠")} docs ingestion failed — ${msg}\n`);
1079
+ ingestion = null;
1080
+ }
1081
+ // ── 6.4 — baseline sensor sweep (full repo, not a diff) ────────────
1082
+ let baselineAudit = null;
1083
+ try {
1084
+ const stackKinds = args.detection.stack_signatures.map((s) => s.kind);
1085
+ const projectGlobs = {
1086
+ route_handler_globs: args.mapperOutput?.route_handler_globs ?? [],
1087
+ dto_globs: args.mapperOutput?.dto_globs ?? [],
1088
+ generator_source_globs: args.mapperOutput?.generator_source_globs ?? [],
1089
+ high_stakes_globs: args.mapperOutput?.high_stakes_globs ?? [],
1090
+ };
1091
+ const printedSensors = [];
1092
+ let suppressedCount = 0;
1093
+ baselineAudit = await runBaselineAudit({
1094
+ repoRoot: args.repoRoot,
1095
+ languages: defaultBaselineLanguages(stackKinds),
1096
+ projectGlobs,
1097
+ onSensorProgress: (row) => {
1098
+ if (printedSensors.length < 3) {
1099
+ const id = row.sensor_id.padEnd(22);
1100
+ const status = row.skipped
1101
+ ? visualC.dim("skipped")
1102
+ : row.finding_count > 0
1103
+ ? `${row.finding_count} existing violation${row.finding_count === 1 ? "" : "s"} found`
1104
+ : "clean";
1105
+ process.stdout.write(` ${id} ${row.skipped ? "○" : row.finding_count > 0 ? "⚠" : "✓"} ${status}\n`);
1106
+ printedSensors.push(row.sensor_id);
1107
+ }
1108
+ else {
1109
+ suppressedCount += 1;
1110
+ }
1111
+ },
1112
+ });
1113
+ if (suppressedCount > 0) {
1114
+ process.stdout.write(` ${visualC.dim(`+ ${suppressedCount} more…`)}\n`);
1115
+ }
1116
+ }
1117
+ catch (err) {
1118
+ const msg = err instanceof Error ? err.message : String(err);
1119
+ args.warnings.push(`baseline audit failed: ${msg}`);
1120
+ process.stdout.write(` ${visualC.yellow("⚠")} baseline audit failed — ${msg}\n`);
1121
+ baselineAudit = null;
1122
+ }
1123
+ return { ingestion, baselineAudit };
1124
+ }
1125
+ function describeIngestion(ingestion) {
1126
+ if (ingestion === null)
1127
+ return null;
1128
+ const draftCount = ingestion.decDraftsWritten.length;
1129
+ if (draftCount === 0 && !ingestion.voiceUpdated) {
1130
+ return `0 proposed (no actionable docs found)`;
1131
+ }
1132
+ const parts = [];
1133
+ parts.push(`${draftCount} proposed${draftCount > 0 ? " (run cairn attention to review)" : ""}`);
1134
+ if (ingestion.voiceUpdated) {
1135
+ parts.push("brand/voice.md filled from existing doc");
1136
+ }
1137
+ return parts.join("; ");
1138
+ }
1139
+ function describeCanonical(ingestion) {
1140
+ if (ingestion === null)
1141
+ return null;
1142
+ const n = ingestion.canonicalTopicsAdded.length;
1143
+ if (n === 0)
1144
+ return null;
1145
+ return `${n} topic${n === 1 ? "" : "s"} seeded`;
1146
+ }
1147
+ function describeBaseline(audit) {
1148
+ if (audit === null)
1149
+ return null;
1150
+ if (audit.totalFindings === 0) {
1151
+ if (audit.skippedSensorIds.length > 0 && audit.cleanSensorIds.length === 0) {
1152
+ return null;
1153
+ }
1154
+ return `0 findings (run on ${audit.filesScanned} files)`;
1155
+ }
1156
+ return `${audit.totalFindings} existing sensor finding${audit.totalFindings === 1 ? "" : "s"} (run cairn attention)`;
1157
+ }
1158
+ function remoteShorthand(url) {
1159
+ // https://github.com/foo/bar.git → github.com/foo/bar
1160
+ // git@github.com:foo/bar.git → github.com/foo/bar
1161
+ let s = url.replace(/\.git$/, "");
1162
+ s = s.replace(/^https?:\/\//, "");
1163
+ s = s.replace(/^git@([^:]+):/, "$1/");
1164
+ return s;
1165
+ }
1166
+ //# sourceMappingURL=init.js.map