@isaacriehm/cairn-core 0.6.0 → 0.7.1

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 (431) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/align-undo/undo.js +2 -2
  3. package/dist/align-undo/undo.js.map +1 -1
  4. package/dist/attention/bulk-accept.js +104 -55
  5. package/dist/attention/bulk-accept.js.map +1 -1
  6. package/dist/attention/dedup.js +23 -10
  7. package/dist/attention/dedup.js.map +1 -1
  8. package/dist/attention/restore.js +2 -2
  9. package/dist/attention/restore.js.map +1 -1
  10. package/dist/attention/scoring.js +1 -1
  11. package/dist/attention/scoring.js.map +1 -1
  12. package/dist/attention/serve/api.d.ts +1 -0
  13. package/dist/attention/serve/api.js +130 -77
  14. package/dist/attention/serve/api.js.map +1 -1
  15. package/dist/attention/serve/index.d.ts +1 -0
  16. package/dist/attention/serve/index.js +21 -7
  17. package/dist/attention/serve/index.js.map +1 -1
  18. package/dist/attention/source-strip.js +41 -46
  19. package/dist/attention/source-strip.js.map +1 -1
  20. package/dist/claude/cache.d.ts +10 -19
  21. package/dist/claude/cache.js +0 -0
  22. package/dist/claude/cache.js.map +1 -1
  23. package/dist/claude/runner.d.ts +4 -6
  24. package/dist/claude/runner.js +242 -203
  25. package/dist/claude/runner.js.map +1 -1
  26. package/dist/claude/types.d.ts +5 -5
  27. package/dist/context/handoff-builder.d.ts +28 -4
  28. package/dist/context/handoff-builder.js +75 -157
  29. package/dist/context/handoff-builder.js.map +1 -1
  30. package/dist/context/spec-delta.js +61 -9
  31. package/dist/context/spec-delta.js.map +1 -1
  32. package/dist/context/task-summary.js +5 -1
  33. package/dist/context/task-summary.js.map +1 -1
  34. package/dist/decision-capture/id.js +1 -1
  35. package/dist/decision-capture/id.js.map +1 -1
  36. package/dist/doctor/index.d.ts +9 -11
  37. package/dist/doctor/index.js +118 -175
  38. package/dist/doctor/index.js.map +1 -1
  39. package/dist/drain/drain.d.ts +1 -1
  40. package/dist/drain/drain.js +16 -16
  41. package/dist/drain/drain.js.map +1 -1
  42. package/dist/drain/index.d.ts +1 -1
  43. package/dist/drain/index.js +1 -1
  44. package/dist/events/reader.d.ts +9 -10
  45. package/dist/events/reader.js +46 -57
  46. package/dist/events/reader.js.map +1 -1
  47. package/dist/events/writer.js +1 -1
  48. package/dist/events/writer.js.map +1 -1
  49. package/dist/fix-align/index.d.ts +1 -1
  50. package/dist/fix-align/index.js +1 -1
  51. package/dist/fix-align/run.d.ts +1 -1
  52. package/dist/fix-align/run.js +4 -3
  53. package/dist/fix-align/run.js.map +1 -1
  54. package/dist/fix-align/sentinel.d.ts +1 -2
  55. package/dist/fix-align/sentinel.js +3 -4
  56. package/dist/fix-align/sentinel.js.map +1 -1
  57. package/dist/gc/apply.js +1 -1
  58. package/dist/gc/apply.js.map +1 -1
  59. package/dist/gc/attested-commits.d.ts +19 -0
  60. package/dist/gc/attested-commits.js +48 -0
  61. package/dist/gc/attested-commits.js.map +1 -0
  62. package/dist/gc/canary.d.ts +11 -21
  63. package/dist/gc/canary.js +18 -24
  64. package/dist/gc/canary.js.map +1 -1
  65. package/dist/gc/citation-integrity.d.ts +11 -14
  66. package/dist/gc/citation-integrity.js +124 -125
  67. package/dist/gc/citation-integrity.js.map +1 -1
  68. package/dist/gc/classify.d.ts +1 -1
  69. package/dist/gc/classify.js +2 -2
  70. package/dist/gc/classify.js.map +1 -1
  71. package/dist/gc/completion-integrity.d.ts +6 -7
  72. package/dist/gc/completion-integrity.js +45 -53
  73. package/dist/gc/completion-integrity.js.map +1 -1
  74. package/dist/gc/doc-gardening.js +1 -9
  75. package/dist/gc/doc-gardening.js.map +1 -1
  76. package/dist/gc/frontmatter.js +2 -2
  77. package/dist/gc/frontmatter.js.map +1 -1
  78. package/dist/gc/index.d.ts +7 -6
  79. package/dist/gc/index.js +3 -2
  80. package/dist/gc/index.js.map +1 -1
  81. package/dist/gc/quality-update.d.ts +6 -10
  82. package/dist/gc/quality-update.js +12 -15
  83. package/dist/gc/quality-update.js.map +1 -1
  84. package/dist/gc/scope-coverage.js +1 -1
  85. package/dist/gc/scope-coverage.js.map +1 -1
  86. package/dist/gc/stub-hits.d.ts +7 -25
  87. package/dist/gc/stub-hits.js +14 -40
  88. package/dist/gc/stub-hits.js.map +1 -1
  89. package/dist/gc/sweep.js +15 -6
  90. package/dist/gc/sweep.js.map +1 -1
  91. package/dist/gc/types.d.ts +5 -5
  92. package/dist/gc/types.js +2 -2
  93. package/dist/gc/walk-source.js +8 -28
  94. package/dist/gc/walk-source.js.map +1 -1
  95. package/dist/hooks/defer.d.ts +9 -20
  96. package/dist/hooks/defer.js +10 -27
  97. package/dist/hooks/defer.js.map +1 -1
  98. package/dist/hooks/post-tool-use/allowlist-reader.d.ts +2 -1
  99. package/dist/hooks/post-tool-use/allowlist-reader.js +49 -34
  100. package/dist/hooks/post-tool-use/allowlist-reader.js.map +1 -1
  101. package/dist/hooks/post-tool-use/index.d.ts +3 -4
  102. package/dist/hooks/post-tool-use/index.js +3 -3
  103. package/dist/hooks/post-tool-use/index.js.map +1 -1
  104. package/dist/hooks/post-tool-use/legend-builder.d.ts +11 -2
  105. package/dist/hooks/post-tool-use/legend-builder.js +27 -2
  106. package/dist/hooks/post-tool-use/legend-builder.js.map +1 -1
  107. package/dist/hooks/post-tool-use/post-write.d.ts +8 -0
  108. package/dist/hooks/post-tool-use/post-write.js +112 -0
  109. package/dist/hooks/post-tool-use/post-write.js.map +1 -0
  110. package/dist/hooks/post-tool-use/read-enricher.d.ts +10 -5
  111. package/dist/hooks/post-tool-use/read-enricher.js +114 -149
  112. package/dist/hooks/post-tool-use/read-enricher.js.map +1 -1
  113. package/dist/hooks/post-tool-use/sot-align.d.ts +12 -0
  114. package/dist/hooks/post-tool-use/sot-align.js +73 -49
  115. package/dist/hooks/post-tool-use/sot-align.js.map +1 -1
  116. package/dist/hooks/post-tool-use/write-guardian.d.ts +40 -8
  117. package/dist/hooks/post-tool-use/write-guardian.js +202 -254
  118. package/dist/hooks/post-tool-use/write-guardian.js.map +1 -1
  119. package/dist/hooks/pre-commit/sot-align-precommit.js +2 -2
  120. package/dist/hooks/pre-commit/sot-align-precommit.js.map +1 -1
  121. package/dist/hooks/runners/index.d.ts +2 -2
  122. package/dist/hooks/runners/index.js +1 -1
  123. package/dist/hooks/runners/index.js.map +1 -1
  124. package/dist/hooks/runners/payload.d.ts +34 -19
  125. package/dist/hooks/runners/payload.js +47 -44
  126. package/dist/hooks/runners/payload.js.map +1 -1
  127. package/dist/hooks/runners/session-end.js +12 -11
  128. package/dist/hooks/runners/session-end.js.map +1 -1
  129. package/dist/hooks/runners/session-start.d.ts +4 -2
  130. package/dist/hooks/runners/session-start.js +88 -261
  131. package/dist/hooks/runners/session-start.js.map +1 -1
  132. package/dist/hooks/runners/stop.js +27 -8
  133. package/dist/hooks/runners/stop.js.map +1 -1
  134. package/dist/hooks/runners/user-prompt-submit.js +7 -1
  135. package/dist/hooks/runners/user-prompt-submit.js.map +1 -1
  136. package/dist/hooks/sot-align-common.d.ts +1 -2
  137. package/dist/hooks/sot-align-common.js +2 -2
  138. package/dist/hooks/sot-align-common.js.map +1 -1
  139. package/dist/index.d.ts +1 -1
  140. package/dist/index.js +12 -3
  141. package/dist/index.js.map +1 -1
  142. package/dist/init/baseline-audit.d.ts +14 -58
  143. package/dist/init/baseline-audit.js +92 -320
  144. package/dist/init/baseline-audit.js.map +1 -1
  145. package/dist/init/brand-derive.d.ts +11 -15
  146. package/dist/init/brand-derive.js +21 -46
  147. package/dist/init/brand-derive.js.map +1 -1
  148. package/dist/init/brand-setup.d.ts +1 -1
  149. package/dist/init/brand-setup.js +1 -1
  150. package/dist/init/detect.d.ts +25 -6
  151. package/dist/init/detect.js +107 -136
  152. package/dist/init/detect.js.map +1 -1
  153. package/dist/init/index.d.ts +4 -4
  154. package/dist/init/index.js +2 -2
  155. package/dist/init/index.js.map +1 -1
  156. package/dist/init/ingest-docs.d.ts +83 -23
  157. package/dist/init/ingest-docs.js +648 -136
  158. package/dist/init/ingest-docs.js.map +1 -1
  159. package/dist/init/init.d.ts +29 -20
  160. package/dist/init/init.js +132 -290
  161. package/dist/init/init.js.map +1 -1
  162. package/dist/init/mapper-merge.js +1 -1
  163. package/dist/init/mapper-merge.js.map +1 -1
  164. package/dist/init/mapper-parallel.d.ts +1 -1
  165. package/dist/init/mapper-parallel.js +10 -1
  166. package/dist/init/mapper-parallel.js.map +1 -1
  167. package/dist/init/mapper.js +1 -1
  168. package/dist/init/mapper.js.map +1 -1
  169. package/dist/init/multi-dev/install.d.ts +5 -5
  170. package/dist/init/multi-dev/install.js +4 -4
  171. package/dist/init/overlay.js +1 -0
  172. package/dist/init/overlay.js.map +1 -1
  173. package/dist/init/phases/1-detect.js +1 -1
  174. package/dist/init/phases/1-detect.js.map +1 -1
  175. package/dist/init/phases/{7c-rules-merge.d.ts → 10-rules-merge.d.ts} +2 -2
  176. package/dist/init/phases/{7c-rules-merge.js → 10-rules-merge.js} +6 -12
  177. package/dist/init/phases/10-rules-merge.js.map +1 -0
  178. package/dist/init/phases/11-baseline.d.ts +7 -0
  179. package/dist/init/phases/{8-baseline.js → 11-baseline.js} +5 -9
  180. package/dist/init/phases/11-baseline.js.map +1 -0
  181. package/dist/init/phases/12-strip.d.ts +10 -0
  182. package/dist/init/phases/{10-strip.js → 12-strip.js} +10 -14
  183. package/dist/init/phases/12-strip.js.map +1 -0
  184. package/dist/init/phases/{12-multidev.d.ts → 13-multidev.d.ts} +2 -2
  185. package/dist/init/phases/{12-multidev.js → 13-multidev.js} +4 -4
  186. package/dist/init/phases/{12-multidev.js.map → 13-multidev.js.map} +1 -1
  187. package/dist/init/phases/3-mapper.d.ts +1 -1
  188. package/dist/init/phases/3-mapper.js +2 -2
  189. package/dist/init/phases/3-mapper.js.map +1 -1
  190. package/dist/init/phases/{3b-seed.d.ts → 4-seed.d.ts} +2 -2
  191. package/dist/init/phases/{3b-seed.js → 4-seed.js} +7 -7
  192. package/dist/init/phases/4-seed.js.map +1 -0
  193. package/dist/init/phases/{4-pilot.d.ts → 5-pilot.d.ts} +2 -2
  194. package/dist/init/phases/{4-pilot.js → 5-pilot.js} +9 -9
  195. package/dist/init/phases/{4-pilot.js.map → 5-pilot.js.map} +1 -1
  196. package/dist/init/phases/{5-brand.d.ts → 6-brand.d.ts} +2 -7
  197. package/dist/init/phases/{5-brand.js → 6-brand.js} +6 -14
  198. package/dist/init/phases/6-brand.js.map +1 -0
  199. package/dist/init/phases/{5b-topic-index.d.ts → 7-topic-index.d.ts} +2 -11
  200. package/dist/init/phases/{5b-topic-index.js → 7-topic-index.js} +9 -18
  201. package/dist/init/phases/7-topic-index.js.map +1 -0
  202. package/dist/init/phases/8-docs-ingest.d.ts +10 -0
  203. package/dist/init/phases/{6-docs-ingest.js → 8-docs-ingest.js} +12 -14
  204. package/dist/init/phases/8-docs-ingest.js.map +1 -0
  205. package/dist/init/phases/9-source-comments.d.ts +6 -0
  206. package/dist/init/phases/{7b-source-comments.js → 9-source-comments.js} +7 -26
  207. package/dist/init/phases/9-source-comments.js.map +1 -0
  208. package/dist/init/phases/index.d.ts +12 -12
  209. package/dist/init/phases/index.js +11 -11
  210. package/dist/init/phases/index.js.map +1 -1
  211. package/dist/init/phases/{parallel-678.d.ts → parallel-8910.d.ts} +7 -8
  212. package/dist/init/phases/{parallel-678.js → parallel-8910.js} +34 -46
  213. package/dist/init/phases/parallel-8910.js.map +1 -0
  214. package/dist/init/phases/source-comments-output-io.d.ts +3 -3
  215. package/dist/init/phases/source-comments-output-io.js +3 -3
  216. package/dist/init/phases/types.d.ts +1 -1
  217. package/dist/init/phases/types.js +10 -10
  218. package/dist/init/phases/types.js.map +1 -1
  219. package/dist/init/rules-merge/discover.d.ts +2 -2
  220. package/dist/init/rules-merge/discover.js +28 -43
  221. package/dist/init/rules-merge/discover.js.map +1 -1
  222. package/dist/init/rules-merge/ingest.d.ts +6 -6
  223. package/dist/init/rules-merge/ingest.js +9 -10
  224. package/dist/init/rules-merge/ingest.js.map +1 -1
  225. package/dist/init/rules-merge/keep-markers.d.ts +1 -1
  226. package/dist/init/rules-merge/keep-markers.js +1 -1
  227. package/dist/init/rules-merge/regenerate.d.ts +3 -3
  228. package/dist/init/rules-merge/regenerate.js +3 -3
  229. package/dist/init/seed.js +17 -24
  230. package/dist/init/seed.js.map +1 -1
  231. package/dist/init/sot-emit.d.ts +48 -8
  232. package/dist/init/sot-emit.js +88 -10
  233. package/dist/init/sot-emit.js.map +1 -1
  234. package/dist/init/source-comments/classify.d.ts +2 -2
  235. package/dist/init/source-comments/classify.js +9 -1
  236. package/dist/init/source-comments/classify.js.map +1 -1
  237. package/dist/init/source-comments/index.d.ts +1 -1
  238. package/dist/init/source-comments/index.js.map +1 -1
  239. package/dist/init/source-comments/ingest.d.ts +2 -2
  240. package/dist/init/source-comments/ingest.js +110 -12
  241. package/dist/init/source-comments/ingest.js.map +1 -1
  242. package/dist/init/source-comments/strip-replace.js +3 -2
  243. package/dist/init/source-comments/strip-replace.js.map +1 -1
  244. package/dist/init/source-comments/walker.d.ts +3 -26
  245. package/dist/init/source-comments/walker.js +18 -30
  246. package/dist/init/source-comments/walker.js.map +1 -1
  247. package/dist/init/topic-index/index.d.ts +15 -1
  248. package/dist/init/topic-index/index.js +84 -5
  249. package/dist/init/topic-index/index.js.map +1 -1
  250. package/dist/init/topic-index/judge.d.ts +5 -9
  251. package/dist/init/topic-index/judge.js +25 -17
  252. package/dist/init/topic-index/judge.js.map +1 -1
  253. package/dist/init/topic-index/resolve.d.ts +23 -3
  254. package/dist/init/topic-index/resolve.js +102 -16
  255. package/dist/init/topic-index/resolve.js.map +1 -1
  256. package/dist/init/topic-index/walk.d.ts +36 -4
  257. package/dist/init/topic-index/walk.js +78 -12
  258. package/dist/init/topic-index/walk.js.map +1 -1
  259. package/dist/lock.js +4 -1
  260. package/dist/lock.js.map +1 -1
  261. package/dist/logger.js +3 -0
  262. package/dist/logger.js.map +1 -1
  263. package/dist/mcp/history/summarizer.js +6 -1
  264. package/dist/mcp/history/summarizer.js.map +1 -1
  265. package/dist/mcp/history/walker.js +1 -1
  266. package/dist/mcp/history/walker.js.map +1 -1
  267. package/dist/mcp/path-allowlist.js +1 -1
  268. package/dist/mcp/path-allowlist.js.map +1 -1
  269. package/dist/mcp/schemas.d.ts +47 -21
  270. package/dist/mcp/schemas.js +38 -9
  271. package/dist/mcp/schemas.js.map +1 -1
  272. package/dist/mcp/server.js +10 -0
  273. package/dist/mcp/server.js.map +1 -1
  274. package/dist/mcp/tools/archive.js +1 -1
  275. package/dist/mcp/tools/archive.js.map +1 -1
  276. package/dist/mcp/tools/attention-wait.js +12 -2
  277. package/dist/mcp/tools/attention-wait.js.map +1 -1
  278. package/dist/mcp/tools/bulk-accept-attention.js +29 -30
  279. package/dist/mcp/tools/bulk-accept-attention.js.map +1 -1
  280. package/dist/mcp/tools/canonical-for-topic.js +37 -15
  281. package/dist/mcp/tools/canonical-for-topic.js.map +1 -1
  282. package/dist/mcp/tools/decision-get.js +2 -2
  283. package/dist/mcp/tools/decision-get.js.map +1 -1
  284. package/dist/mcp/tools/decisions-for-symbol.js +2 -2
  285. package/dist/mcp/tools/decisions-for-symbol.js.map +1 -1
  286. package/dist/mcp/tools/get-full.js +1 -1
  287. package/dist/mcp/tools/get-full.js.map +1 -1
  288. package/dist/mcp/tools/ground-get.js +1 -1
  289. package/dist/mcp/tools/ground-get.js.map +1 -1
  290. package/dist/mcp/tools/in-scope.d.ts +8 -0
  291. package/dist/mcp/tools/in-scope.js +125 -0
  292. package/dist/mcp/tools/in-scope.js.map +1 -0
  293. package/dist/mcp/tools/index.js +11 -6
  294. package/dist/mcp/tools/index.js.map +1 -1
  295. package/dist/mcp/tools/init-phases.d.ts +3 -2
  296. package/dist/mcp/tools/init-phases.js +125 -124
  297. package/dist/mcp/tools/init-phases.js.map +1 -1
  298. package/dist/mcp/tools/invariant-get.js +2 -2
  299. package/dist/mcp/tools/invariant-get.js.map +1 -1
  300. package/dist/mcp/tools/record-decision.d.ts +4 -3
  301. package/dist/mcp/tools/record-decision.js +111 -36
  302. package/dist/mcp/tools/record-decision.js.map +1 -1
  303. package/dist/mcp/tools/reject-candidate.d.ts +24 -0
  304. package/dist/mcp/tools/reject-candidate.js +71 -0
  305. package/dist/mcp/tools/reject-candidate.js.map +1 -0
  306. package/dist/mcp/tools/resolve-attention.d.ts +5 -18
  307. package/dist/mcp/tools/resolve-attention.js +58 -158
  308. package/dist/mcp/tools/resolve-attention.js.map +1 -1
  309. package/dist/mcp/tools/search-candidates.d.ts +20 -0
  310. package/dist/mcp/tools/search-candidates.js +93 -0
  311. package/dist/mcp/tools/search-candidates.js.map +1 -0
  312. package/dist/mcp/tools/search.js +5 -4
  313. package/dist/mcp/tools/search.js.map +1 -1
  314. package/dist/mcp/tools/supersedes-chain.js +2 -2
  315. package/dist/mcp/tools/supersedes-chain.js.map +1 -1
  316. package/dist/mcp/tools/task-create.d.ts +1 -0
  317. package/dist/mcp/tools/task-create.js +2 -0
  318. package/dist/mcp/tools/task-create.js.map +1 -1
  319. package/dist/mcp/tools/timeline.js +1 -1
  320. package/dist/mcp/tools/timeline.js.map +1 -1
  321. package/dist/mcp/tools/types.d.ts +1 -0
  322. package/dist/mcp/tools/types.js +9 -1
  323. package/dist/mcp/tools/types.js.map +1 -1
  324. package/dist/sensors/attestation.d.ts +1 -1
  325. package/dist/sensors/attestation.js +2 -2
  326. package/dist/sensors/attestation.js.map +1 -1
  327. package/dist/sensors/catalog.d.ts +26 -28
  328. package/dist/sensors/catalog.js +79 -81
  329. package/dist/sensors/catalog.js.map +1 -1
  330. package/dist/sensors/decisions.d.ts +1 -1
  331. package/dist/sensors/decisions.js +15 -14
  332. package/dist/sensors/decisions.js.map +1 -1
  333. package/dist/sensors/diff.js +46 -22
  334. package/dist/sensors/diff.js.map +1 -1
  335. package/dist/sensors/runner.d.ts +2 -2
  336. package/dist/sensors/runner.js +3 -3
  337. package/dist/sensors/shell.d.ts +4 -0
  338. package/dist/sensors/shell.js +16 -0
  339. package/dist/sensors/shell.js.map +1 -0
  340. package/dist/sensors/structural.d.ts +3 -2
  341. package/dist/sensors/structural.js +3 -11
  342. package/dist/sensors/structural.js.map +1 -1
  343. package/dist/sensors/stub-catalog.d.ts +2 -1
  344. package/dist/sensors/stub-catalog.js +2 -9
  345. package/dist/sensors/stub-catalog.js.map +1 -1
  346. package/dist/sensors/types.d.ts +3 -4
  347. package/dist/sensors/types.js +1 -2
  348. package/dist/sensors/types.js.map +1 -1
  349. package/dist/session-start/build.js +1 -1
  350. package/dist/session-start/build.js.map +1 -1
  351. package/dist/status-line/event-queue.js +1 -1
  352. package/dist/status-line/index.d.ts +1 -1
  353. package/package.json +3 -2
  354. package/templates/.cairn/config/sensors.yaml +8 -8
  355. package/templates/attention-ui/app.js +101 -39
  356. package/dist/fs.d.ts +0 -5
  357. package/dist/fs.js +0 -11
  358. package/dist/fs.js.map +0 -1
  359. package/dist/ground/alignment-pending.d.ts +0 -28
  360. package/dist/ground/alignment-pending.js +0 -83
  361. package/dist/ground/alignment-pending.js.map +0 -1
  362. package/dist/ground/anchor-map.d.ts +0 -14
  363. package/dist/ground/anchor-map.js +0 -56
  364. package/dist/ground/anchor-map.js.map +0 -1
  365. package/dist/ground/drift.d.ts +0 -8
  366. package/dist/ground/drift.js +0 -23
  367. package/dist/ground/drift.js.map +0 -1
  368. package/dist/ground/frontmatter.d.ts +0 -32
  369. package/dist/ground/frontmatter.js +0 -77
  370. package/dist/ground/frontmatter.js.map +0 -1
  371. package/dist/ground/glob.d.ts +0 -10
  372. package/dist/ground/glob.js +0 -46
  373. package/dist/ground/glob.js.map +0 -1
  374. package/dist/ground/index.d.ts +0 -23
  375. package/dist/ground/index.js +0 -17
  376. package/dist/ground/index.js.map +0 -1
  377. package/dist/ground/ledgers.d.ts +0 -14
  378. package/dist/ground/ledgers.js +0 -105
  379. package/dist/ground/ledgers.js.map +0 -1
  380. package/dist/ground/manifest.d.ts +0 -10
  381. package/dist/ground/manifest.js +0 -84
  382. package/dist/ground/manifest.js.map +0 -1
  383. package/dist/ground/paths.d.ts +0 -41
  384. package/dist/ground/paths.js +0 -103
  385. package/dist/ground/paths.js.map +0 -1
  386. package/dist/ground/quality-grades.d.ts +0 -11
  387. package/dist/ground/quality-grades.js +0 -100
  388. package/dist/ground/quality-grades.js.map +0 -1
  389. package/dist/ground/schemas.d.ts +0 -502
  390. package/dist/ground/schemas.js +0 -318
  391. package/dist/ground/schemas.js.map +0 -1
  392. package/dist/ground/scope-index.d.ts +0 -96
  393. package/dist/ground/scope-index.js +0 -290
  394. package/dist/ground/scope-index.js.map +0 -1
  395. package/dist/ground/slug.d.ts +0 -60
  396. package/dist/ground/slug.js +0 -103
  397. package/dist/ground/slug.js.map +0 -1
  398. package/dist/ground/sot-bindings.d.ts +0 -14
  399. package/dist/ground/sot-bindings.js +0 -79
  400. package/dist/ground/sot-bindings.js.map +0 -1
  401. package/dist/ground/sot-cache.d.ts +0 -18
  402. package/dist/ground/sot-cache.js +0 -62
  403. package/dist/ground/sot-cache.js.map +0 -1
  404. package/dist/ground/topic-index.d.ts +0 -27
  405. package/dist/ground/topic-index.js +0 -82
  406. package/dist/ground/topic-index.js.map +0 -1
  407. package/dist/ground/walk.d.ts +0 -7
  408. package/dist/ground/walk.js +0 -53
  409. package/dist/ground/walk.js.map +0 -1
  410. package/dist/hooks/post-tool-use/ledger-cache.d.ts +0 -40
  411. package/dist/hooks/post-tool-use/ledger-cache.js +0 -290
  412. package/dist/hooks/post-tool-use/ledger-cache.js.map +0 -1
  413. package/dist/init/phases/10-strip.d.ts +0 -11
  414. package/dist/init/phases/10-strip.js.map +0 -1
  415. package/dist/init/phases/3b-seed.js.map +0 -1
  416. package/dist/init/phases/5-brand.js.map +0 -1
  417. package/dist/init/phases/5b-topic-index.js.map +0 -1
  418. package/dist/init/phases/6-docs-ingest.d.ts +0 -10
  419. package/dist/init/phases/6-docs-ingest.js.map +0 -1
  420. package/dist/init/phases/7b-source-comments.d.ts +0 -15
  421. package/dist/init/phases/7b-source-comments.js.map +0 -1
  422. package/dist/init/phases/7c-rules-merge.js.map +0 -1
  423. package/dist/init/phases/8-baseline.d.ts +0 -10
  424. package/dist/init/phases/8-baseline.js.map +0 -1
  425. package/dist/init/phases/parallel-678.js.map +0 -1
  426. package/dist/mcp/tools/decisions-in-scope.d.ts +0 -7
  427. package/dist/mcp/tools/decisions-in-scope.js +0 -66
  428. package/dist/mcp/tools/decisions-in-scope.js.map +0 -1
  429. package/dist/mcp/tools/invariants-in-scope.d.ts +0 -7
  430. package/dist/mcp/tools/invariants-in-scope.js +0 -81
  431. package/dist/mcp/tools/invariants-in-scope.js.map +0 -1
package/dist/init/init.js CHANGED
@@ -9,15 +9,16 @@
9
9
  * 4. Mapper (Tier-2 chunked Sonnet) → seed `<slug>:` workflow.md block +
10
10
  * `.cairn/config.yaml` project_globs.
11
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
12
+ * 6. Phase 8 docs ingestion + baseline sensor sweep.
13
+ * 7. Phase 9 source-comment ingestion + Phase 10 rules merge (mock-friendly
14
14
  * via `mockSourceCommentClassify` / `mockRulesMergeClassify`).
15
- * 8. Phase 12 multi-dev install (deterministic, idempotent).
15
+ * 8. Phase 13 multi-dev install (deterministic, idempotent).
16
16
  */
17
17
  import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync, } from "node:fs";
18
18
  import { join, relative } from "node:path";
19
19
  import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
20
- import { scopeIndexPath, writeScopeIndex, } from "../ground/scope-index.js";
20
+ import { z } from "zod";
21
+ import { scopeIndexPath, writeScopeIndex, } from "@isaacriehm/cairn-state";
21
22
  import { normalizeProjectName } from "../paths/index.js";
22
23
  import { homedir } from "node:os";
23
24
  import { logger, setLogFile } from "../logger.js";
@@ -46,6 +47,7 @@ export async function runInit(args = {}) {
46
47
  const cwd = process.cwd();
47
48
  const mode = args.mode ?? "interactive";
48
49
  const warnings = [];
50
+ const initStartMs = Date.now();
49
51
  // ── Phase -1: self-adoption hard stop ──────────────────────────────
50
52
  // If repoRoot or cwd looks like the Cairn source repo itself, refuse —
51
53
  // running init here would overwrite cairn internals.
@@ -92,7 +94,7 @@ export async function runInit(args = {}) {
92
94
  autoSubmodule: args.autoSubmodule ?? "init",
93
95
  warnings,
94
96
  });
95
- const detection = await detectAll(repoRoot);
97
+ const detection = await detectAll({ repoRoot });
96
98
  const decidedSlug = args.slugOverride !== undefined
97
99
  ? normalizeProjectName(args.slugOverride)
98
100
  : detection.project_slug;
@@ -275,19 +277,19 @@ export async function runInit(args = {}) {
275
277
  brandSetup = { answered: 0, updated_files: [] };
276
278
  }
277
279
  }
278
- // ── Phase 5b (topic-index): cross-source dedup pre-pass ────────────
280
+ // ── Phase 7 (topic-index): cross-source dedup pre-pass ────────────
279
281
  // Walks every prose-bearing markdown source the SoT model recognizes
280
282
  // (`docs/*`, `CLAUDE.md`, `AGENTS.md`, `.claude/rules/*`) and writes
281
283
  // `topic-index.yaml` + `anchor-map.yaml`. Phases 6 / 7b / 7c read both
282
284
  // before emitting so a single fact never duplicates across sources.
283
- // Skipped under the same condition as Phase 6.
285
+ // Skipped under the same condition as Phase 8.
284
286
  const skipTopicIndex = args.skipIngestion === true ||
285
287
  (mode === "auto" &&
286
288
  args.mockSourceCommentClassify === undefined &&
287
289
  args.mockRulesMergeClassify === undefined);
288
290
  if (!skipTopicIndex) {
289
291
  process.stdout.write("\n");
290
- process.stdout.write(` ${visualC.bold("Phase 5b")} — topic-index (cross-source dedup)…\n`);
292
+ process.stdout.write(` ${visualC.bold("Phase 7")} — topic-index (cross-source dedup)…\n`);
291
293
  try {
292
294
  const topicArgs = { repoRoot };
293
295
  if (args.mockTopicIndexJudge !== undefined)
@@ -304,23 +306,32 @@ export async function runInit(args = {}) {
304
306
  process.stdout.write(` ${visualC.yellow("⚠")} topic-index build failed — ${msg}\n`);
305
307
  }
306
308
  }
307
- // ── Phase 6: ingestion sweep + baseline audit ──────────────────────
309
+ // ── Phase 8: ingestion sweep + baseline audit ──────────────────────
308
310
  // Populates project brain from docs that already exist in the repo, then
309
311
  // runs every runnable sensor against the full codebase to surface pre-
310
312
  // Cairn debt. Both pieces are best-effort; failures degrade to empty
311
313
  // result, never block the init.
312
- const phase6 = await runPhaseSix({
314
+ const phase6Args = {
313
315
  repoRoot,
314
316
  decidedSlug,
315
317
  detection,
316
318
  mapperOutput,
317
- skip: args.skipIngestion === true || mode === "auto",
319
+ // Auto mode skips Haiku-backed ingestion by default. Smokes that
320
+ // need to exercise the phase-6 emit path (e2e-adoption,
321
+ // ingestion-baseline) provide `mockIngestionClassify` so the
322
+ // pipeline runs end-to-end without burning Haiku.
323
+ skip: args.skipIngestion === true ||
324
+ (mode === "auto" && args.mockIngestionClassify === undefined),
318
325
  warnings,
319
- });
320
- // ── Phase 7b: source-comment ingestion ─────────────────────────────
326
+ };
327
+ if (args.mockIngestionClassify !== undefined) {
328
+ phase6Args.mockClassify = args.mockIngestionClassify;
329
+ }
330
+ const phase6 = await runPhaseSix(phase6Args);
331
+ // ── Phase 9: source-comment ingestion ─────────────────────────────
321
332
  // Walks every source file, batches block-comments through Haiku, files
322
333
  // DEC drafts + invariant proposals + canonical citations into
323
- // `.cairn/baseline/`. Skipped under the same condition as Phase 6
334
+ // `.cairn/baseline/`. Skipped under the same condition as Phase 8
324
335
  // unless a `mockSourceCommentClassify` is supplied (smokes).
325
336
  let sourceComments = null;
326
337
  const skip7b = args.skipPhase7b === true ||
@@ -328,7 +339,7 @@ export async function runInit(args = {}) {
328
339
  args.mockSourceCommentClassify === undefined);
329
340
  if (!skip7b) {
330
341
  process.stdout.write("\n");
331
- process.stdout.write(` ${visualC.bold("Phase 7b")} — source-comment ingestion…\n`);
342
+ process.stdout.write(` ${visualC.bold("Phase 9")} — source-comment ingestion…\n`);
332
343
  try {
333
344
  sourceComments = await runSourceCommentsIngestion({
334
345
  repoRoot,
@@ -344,7 +355,7 @@ export async function runInit(args = {}) {
344
355
  process.stdout.write(` DECs: ${sourceComments.decsWritten.length}; ` +
345
356
  `invariants: ${sourceComments.invsWritten.length}; ` +
346
357
  `cites: ${sourceComments.citesEmitted.length}; ` +
347
- `strip applied: ${sourceComments.stripItemsApplied}\n`);
358
+ `strip applied: ${sourceComments.decsWritten.length + sourceComments.invsWritten.length}\n`);
348
359
  }
349
360
  catch (err) {
350
361
  const msg = err instanceof Error ? err.message : String(err);
@@ -352,7 +363,7 @@ export async function runInit(args = {}) {
352
363
  process.stdout.write(` ${visualC.yellow("⚠")} source-comment ingestion failed — ${msg}\n`);
353
364
  }
354
365
  }
355
- // ── Phase 7c: existing-rules merge + first regenerate ──────────────
366
+ // ── Phase 10: existing-rules merge + first regenerate ──────────────
356
367
  // Reads CLAUDE.md / AGENTS.md / .claude/CLAUDE.md / .claude/rules/**.md,
357
368
  // classifies sections via Haiku into rule-net-new / rule-conflict /
358
369
  // informational / operator-keep, persists net-new as DEC drafts. The
@@ -365,7 +376,7 @@ export async function runInit(args = {}) {
365
376
  args.mockRulesMergeClassify === undefined);
366
377
  if (!skip7c) {
367
378
  process.stdout.write("\n");
368
- process.stdout.write(` ${visualC.bold("Phase 7c")} — existing-rules merge…\n`);
379
+ process.stdout.write(` ${visualC.bold("Phase 10")} — existing-rules merge…\n`);
369
380
  try {
370
381
  rulesMerge = await runRulesMerge({
371
382
  repoRoot,
@@ -374,12 +385,10 @@ export async function runInit(args = {}) {
374
385
  : {}),
375
386
  });
376
387
  process.stdout.write(` Sources: ${rulesMerge.sources.length}; ` +
377
- `DECs: ${rulesMerge.decsWritten.length}; ` +
378
- `INVs: ${rulesMerge.invsWritten.length}; ` +
388
+ `Emitted: ${rulesMerge.decsWritten.length + rulesMerge.invsWritten.length}; ` +
379
389
  `cites: ${rulesMerge.citesEmitted.length}; ` +
380
390
  `conflicts: ${rulesMerge.conflicts.length}; ` +
381
- `informational: ${rulesMerge.kindCounts.informational}; ` +
382
- `operator-keep: ${rulesMerge.kindCounts["operator-keep"]}\n`);
391
+ `informational: ${rulesMerge.kindCounts["informational"] ?? 0}\n`);
383
392
  }
384
393
  catch (err) {
385
394
  const msg = err instanceof Error ? err.message : String(err);
@@ -387,7 +396,7 @@ export async function runInit(args = {}) {
387
396
  process.stdout.write(` ${visualC.yellow("⚠")} rules merge failed — ${msg}\n`);
388
397
  }
389
398
  }
390
- // ── Phase 12: multi-developer enforcement install ──────────────────
399
+ // ── Phase 13: multi-developer enforcement install ──────────────────
391
400
  // Idempotent + deterministic. Patches `package.json` `scripts.prepare`
392
401
  // for Node projects so every clone runs `cairn join` on install.
393
402
  // Surfaces manual hints for non-Node hosts. Templates (.cairn/
@@ -396,7 +405,7 @@ export async function runInit(args = {}) {
396
405
  let multiDev = null;
397
406
  if (args.skipPhase12 !== true) {
398
407
  process.stdout.write("\n");
399
- process.stdout.write(` ${visualC.bold("Phase 12")} — multi-dev enforcement install…\n`);
408
+ process.stdout.write(` ${visualC.bold("Phase 13")} — multi-dev enforcement install…\n`);
400
409
  try {
401
410
  multiDev = installMultiDev({ repoRoot });
402
411
  const hostList = multiDev.hostKinds.join(", ");
@@ -415,20 +424,15 @@ export async function runInit(args = {}) {
415
424
  // (PLUGIN_ARCHITECTURE §7). Init no longer writes it; the next
416
425
  // SessionStart in any clone seeds the per-session file with the
417
426
  // current attention_count derived from drafts + baseline findings.
418
- // ── Step 6: completion summary (structured) ────────────────────────
427
+ // ── Step 6: completion summary (terse, per ) ──
419
428
  printCompletionSummary({
420
429
  projectName: decidedSlug,
421
430
  repoRoot,
422
- seededFiles: seed.written_files,
423
- brandSetup,
424
- submodules: submoduleSummary,
425
- scanTruncated: repoSummary.truncated_at_file_cap ||
426
- repoSummary.truncated_at_depth_cap,
427
431
  mapperFallbackSlugs,
428
- ingestion: phase6.ingestion,
429
432
  baselineAudit: phase6.baselineAudit,
430
433
  logFilePath,
431
434
  warnings,
435
+ durationMs: Date.now() - initStartMs,
432
436
  });
433
437
  log.info({
434
438
  repo_root: repoRoot,
@@ -440,7 +444,7 @@ export async function runInit(args = {}) {
440
444
  mapper_applied_to_config: mapperAppliedToConfig,
441
445
  brand_answered: brandSetup?.answered ?? null,
442
446
  ingestion_drafts: phase6.ingestion?.decsWritten.length ?? null,
443
- baseline_findings: phase6.baselineAudit?.totalFindings ?? null,
447
+ baseline_findings: phase6.baselineAudit?.findingsCount ?? null,
444
448
  warnings: warnings.length,
445
449
  }, "init complete");
446
450
  return {
@@ -706,58 +710,43 @@ async function preflightSubmodules(args) {
706
710
  success: true,
707
711
  };
708
712
  }
713
+ /**
714
+ * Cold-start summary, locked wording from
715
+ *
716
+ * Adopted <project> in <duration>.
717
+ * - <N> active rules baseline verified.
718
+ * - <M> new decision drafts found.
719
+ * - <K> unpromoted candidates indexed.
720
+ *
721
+ * Run `cairn attention` to review drafts and commit them to the ledger.
722
+ *
723
+ * No auto-wizard. No statusline drumbeat. Operator drives the next
724
+ * step. Warnings (if any) tail the locked block. Rich operational
725
+ * status moved to `cairn doctor`.
726
+ */
709
727
  function printCompletionSummary(args) {
710
- const groundCount = countGroundFiles(args.repoRoot);
711
- const sensorCount = countSensorEntries(args.repoRoot);
712
- const scopeReport = describeScopeIndex(args.repoRoot, args.submodules, args.scanTruncated);
713
- const brandReport = describeBrandStatus(args.repoRoot);
714
- const mcpReport = describeMcpRegistration(args.repoRoot);
728
+ const N = describeActiveRulesVerified(args.baselineAudit);
729
+ const M = countInboxDrafts(args.repoRoot);
730
+ const K = countUnpromotedCandidates(args.repoRoot);
731
+ const duration = formatDuration(args.durationMs);
715
732
  info("");
716
- info(` Cairn ready — ${args.projectName}`);
733
+ info(` Adopted ${args.projectName} in ${duration}.`);
734
+ info(` - ${N} active rules baseline verified.`);
735
+ info(` - ${M} new decision drafts found.`);
736
+ info(` - ${K} unpromoted candidates indexed.`);
717
737
  info("");
718
- info(` Ground state .cairn/ground/ (${groundCount} files)`);
719
- info(` MCP server ${mcpReport}`);
720
- info(` Sensors ${sensorCount} active`);
738
+ info(" Run `cairn attention` to review drafts and commit them to the ledger.");
739
+ if (args.logFilePath !== null) {
740
+ info("");
741
+ info(` Log ${shortenHomePath(args.logFilePath)}`);
742
+ }
721
743
  if (args.mapperFallbackSlugs.length > 0) {
722
744
  const head = args.mapperFallbackSlugs.slice(0, 3).join(", ");
723
745
  const more = args.mapperFallbackSlugs.length > 3
724
746
  ? ` +${args.mapperFallbackSlugs.length - 3} more`
725
747
  : "";
726
- info(` ${head}${more} used fallback — rerun cairn scope rebuild`);
727
- }
728
- info(` Brand ${brandReport}`);
729
- info(` Scope index ${scopeReport.line}`);
730
- if (scopeReport.followUp !== null) {
731
- info(` ${scopeReport.followUp}`);
732
- }
733
- if (args.logFilePath !== null) {
734
- info(` Log ${shortenHomePath(args.logFilePath)}`);
735
- }
736
- // Project brain populated from existing codebase.
737
- const ingestionReport = describeIngestion(args.ingestion);
738
- const canonicalReport = describeCanonical(args.ingestion);
739
- const baselineReport = describeBaseline(args.baselineAudit);
740
- if (ingestionReport !== null ||
741
- canonicalReport !== null ||
742
- baselineReport !== null) {
743
- info("");
744
- info(" Project brain populated from existing codebase:");
745
- if (ingestionReport !== null) {
746
- info(` DEC drafts ${ingestionReport}`);
747
- }
748
- if (canonicalReport !== null) {
749
- info(` Canonical map ${canonicalReport}`);
750
- }
751
- if (baselineReport !== null) {
752
- info(` Baseline debt ${baselineReport}`);
753
- }
748
+ info(` Mapper fallback ${head}${more} — rerun cairn scope rebuild`);
754
749
  }
755
- info("");
756
- info(" Open Claude Code in this directory. Cairn is live immediately.");
757
- info("");
758
- info(" Next: cairn attention see pending items");
759
- info(" cairn doctor verify everything is working");
760
- info(" cairn configure brand fill in brand guidelines");
761
750
  if (args.warnings.length > 0) {
762
751
  info("");
763
752
  info(` ${args.warnings.length} warning${args.warnings.length === 1 ? "" : "s"}:`);
@@ -765,181 +754,73 @@ function printCompletionSummary(args) {
765
754
  info(` ! ${w}`);
766
755
  }
767
756
  }
768
- function shortenHomePath(abs) {
769
- const home = homedir();
770
- if (abs.startsWith(home))
771
- return `~${abs.slice(home.length)}`;
772
- return abs;
773
- }
774
- function countGroundFiles(repoRoot) {
775
- const groundDir = join(repoRoot, ".cairn", "ground");
776
- if (!existsSync(groundDir))
757
+ function describeActiveRulesVerified(audit) {
758
+ if (audit === null)
777
759
  return 0;
778
- let count = 0;
779
- const stack = [groundDir];
780
- while (stack.length > 0) {
781
- const dir = stack.pop();
782
- if (dir === undefined)
783
- break;
784
- let entries;
785
- try {
786
- entries = readdirSync(dir, { withFileTypes: true, encoding: "utf8" });
787
- }
788
- catch {
789
- continue;
790
- }
791
- for (const e of entries) {
792
- const abs = join(dir, e.name);
793
- if (e.isDirectory()) {
794
- if (e.name === "_inbox")
795
- continue;
796
- stack.push(abs);
797
- }
798
- else if (e.isFile()) {
799
- count++;
800
- }
801
- }
802
- }
803
- return count;
760
+ return 0; // Deprecated field
804
761
  }
805
- function countSensorEntries(repoRoot) {
806
- const path = join(repoRoot, ".cairn", "config", "sensors.yaml");
807
- if (!existsSync(path))
762
+ function countInboxDrafts(repoRoot) {
763
+ const inbox = join(repoRoot, ".cairn", "ground", "decisions", "_inbox");
764
+ if (!existsSync(inbox))
808
765
  return 0;
766
+ let entries;
809
767
  try {
810
- const parsed = parseYaml(readFileSync(path, "utf8"));
811
- if (typeof parsed !== "object" || parsed === null)
812
- return 0;
813
- const sensorsRaw = parsed["sensors"];
814
- if (!Array.isArray(sensorsRaw))
815
- return 0;
816
- return sensorsRaw.length;
768
+ entries = readdirSync(inbox, { withFileTypes: true, encoding: "utf8" });
817
769
  }
818
770
  catch {
819
771
  return 0;
820
772
  }
821
- }
822
- function describeScopeIndex(repoRoot, submodules, scanTruncated) {
823
- const path = join(repoRoot, ".cairn", "ground", "scope-index.yaml");
824
- const submoduleNoteJustInitialized = submodules !== null &&
825
- submodules.initialized &&
826
- submodules.success;
827
- const truncationFollowUp = "Run cairn scope rebuild for full classification";
828
- if (!existsSync(path)) {
829
- return {
830
- line: "missing — run cairn scope rebuild",
831
- followUp: null,
832
- };
833
- }
834
- try {
835
- const parsed = parseYaml(readFileSync(path, "utf8"));
836
- if (typeof parsed !== "object" || parsed === null) {
837
- return {
838
- line: "empty — run cairn scope rebuild",
839
- followUp: null,
840
- };
841
- }
842
- const filesRaw = parsed["files"];
843
- if (typeof filesRaw !== "object" || filesRaw === null) {
844
- return {
845
- line: "empty — run cairn scope rebuild",
846
- followUp: null,
847
- };
848
- }
849
- const count = Object.keys(filesRaw).length;
850
- if (count === 0) {
851
- if (scanTruncated) {
852
- return {
853
- line: "empty — analysis was truncated during init",
854
- followUp: truncationFollowUp,
855
- };
856
- }
857
- return {
858
- line: submoduleNoteJustInitialized
859
- ? "empty — submodules now initialized, run cairn scope rebuild"
860
- : "empty — run cairn scope rebuild",
861
- followUp: null,
862
- };
863
- }
864
- if (scanTruncated) {
865
- return {
866
- line: "partial — analysis was truncated during init",
867
- followUp: truncationFollowUp,
868
- };
869
- }
870
- if (submoduleNoteJustInitialized) {
871
- return {
872
- line: `partial — ${count} file${count === 1 ? "" : "s"} classified (submodules now initialized)`,
873
- followUp: truncationFollowUp,
874
- };
875
- }
876
- return {
877
- line: `ready (${count} file${count === 1 ? "" : "s"} classified)`,
878
- followUp: null,
879
- };
880
- }
881
- catch {
882
- return {
883
- line: "unreadable — run cairn scope rebuild",
884
- followUp: null,
885
- };
886
- }
887
- }
888
- function describeBrandStatus(repoRoot) {
889
- const overview = join(repoRoot, ".cairn", "ground", "brand", "overview.md");
890
- const positioning = join(repoRoot, ".cairn", "ground", "product", "positioning.md");
891
- const voice = join(repoRoot, ".cairn", "ground", "brand", "voice.md");
892
- const all = [overview, positioning, voice];
893
- let currentCount = 0;
894
- let total = 0;
895
- for (const p of all) {
896
- if (!existsSync(p))
773
+ let n = 0;
774
+ for (const e of entries) {
775
+ if (!e.isFile())
897
776
  continue;
898
- total++;
899
- if (readFrontmatterStatus(p) === "current")
900
- currentCount++;
901
- }
902
- if (total === 0)
903
- return "missing — re-run cairn init";
904
- if (currentCount === total)
905
- return "ready";
906
- if (currentCount === 0)
907
- return "draft — run cairn configure brand";
908
- return `partial (${currentCount}/${total} current) — run cairn configure brand`;
909
- }
910
- function readFrontmatterStatus(path) {
911
- try {
912
- const text = readFileSync(path, "utf8");
913
- const m = text.match(/^---\n([\s\S]*?\n)---/);
914
- if (!m)
915
- return null;
916
- const fm = m[1] ?? "";
917
- const sm = fm.match(/^status:\s*(\S+)\s*$/m);
918
- return sm && sm[1] ? sm[1] : null;
919
- }
920
- catch {
921
- return null;
777
+ if (e.name.endsWith(".draft.md"))
778
+ n += 1;
922
779
  }
780
+ return n;
923
781
  }
924
- function describeMcpRegistration(repoRoot) {
925
- const path = join(repoRoot, ".mcp.json");
782
+ const TopicIndexSchema = z.object({
783
+ topics: z.record(z.string(), z.object({
784
+ dec_id: z.string().optional(),
785
+ }).passthrough()),
786
+ }).passthrough();
787
+ function countUnpromotedCandidates(repoRoot) {
788
+ const path = join(repoRoot, ".cairn", "ground", "topic-index.yaml");
926
789
  if (!existsSync(path))
927
- return ".mcp.json · missing entry";
790
+ return 0;
928
791
  try {
929
- const parsed = JSON.parse(readFileSync(path, "utf8"));
930
- const servers = parsed["mcpServers"];
931
- if (typeof servers !== "object" || servers === null) {
932
- return ".mcp.json · missing cairn entry";
933
- }
934
- if (servers["cairn"] !== undefined) {
935
- return ".mcp.json · ready";
792
+ const raw = readFileSync(path, "utf8");
793
+ const parsed = parseYaml(raw);
794
+ const result = TopicIndexSchema.safeParse(parsed);
795
+ if (!result.success)
796
+ return 0;
797
+ let n = 0;
798
+ for (const entry of Object.values(result.data.topics)) {
799
+ if (entry.dec_id === undefined)
800
+ n += 1;
936
801
  }
937
- return ".mcp.json · missing cairn entry";
802
+ return n;
938
803
  }
939
804
  catch {
940
- return ".mcp.json · unreadable";
805
+ return 0;
941
806
  }
942
807
  }
808
+ function formatDuration(ms) {
809
+ if (ms < 1_000)
810
+ return `${ms}ms`;
811
+ const seconds = ms / 1_000;
812
+ if (seconds < 60)
813
+ return `${seconds.toFixed(1)}s`;
814
+ const minutes = Math.floor(seconds / 60);
815
+ const remSeconds = Math.round(seconds - minutes * 60);
816
+ return `${minutes}m ${remSeconds}s`;
817
+ }
818
+ function shortenHomePath(abs) {
819
+ const home = homedir();
820
+ if (abs.startsWith(home))
821
+ return `~${abs.slice(home.length)}`;
822
+ return abs;
823
+ }
943
824
  function printDiscovery(d, decidedSlug, warnings, summary) {
944
825
  process.stdout.write("\n");
945
826
  process.stdout.write(` ${visualC.bold("Scanning")}${visualC.dim("…")}\n`);
@@ -1009,22 +890,30 @@ async function runPhaseSix(args) {
1009
890
  return { ingestion: null, baselineAudit: null };
1010
891
  }
1011
892
  process.stdout.write("\n");
1012
- process.stdout.write(` ${visualC.bold("Phase 6")} — ingesting existing project knowledge…\n`);
1013
- // ── 6.1 — docs ingestion (Haiku per doc; cap 20 largest) ───────────
893
+ process.stdout.write(` ${visualC.bold("Phase 8")} — ingesting existing project knowledge…\n`);
894
+ // ── 6.1 — docs ingestion (staged: marker file-filter section) ──
1014
895
  let ingestion = null;
1015
896
  try {
1016
- let lastTotal = 0;
1017
- let processedCount = 0;
1018
- ingestion = await runDocsIngestion({
897
+ let lastStage = null;
898
+ const ingestionArgs = {
1019
899
  repoRoot: args.repoRoot,
1020
- onEntryProgress: (row) => {
1021
- processedCount += 1;
1022
- lastTotal = row.total;
1023
- if (processedCount === row.total) {
1024
- process.stdout.write(` ${"docs".padEnd(20)} ✓ ${processedCount}/${lastTotal} entries processed\n`);
900
+ onChunkProgress: (row) => {
901
+ // Print one trailer line per stage so the operator sees the
902
+ // staged pipeline land — Stage 1 (file filter) finishes first
903
+ // and is usually the smaller batch; Stage 2 (section classify)
904
+ // follows once authoritative files are known.
905
+ if (row.chunksDone === row.totalChunks && row.stage !== lastStage) {
906
+ lastStage = row.stage;
907
+ const label = row.stage === "file-filter"
908
+ ? "stage 1 file filter"
909
+ : "stage 2 section classify";
910
+ process.stdout.write(` ${label.padEnd(28)} ✓ ${row.entriesDone}/${row.totalEntries} in ${row.totalChunks} batches\n`);
1025
911
  }
1026
912
  },
1027
- });
913
+ };
914
+ if (args.mockClassify !== undefined)
915
+ ingestionArgs.mockClassify = args.mockClassify;
916
+ ingestion = await runDocsIngestion(ingestionArgs);
1028
917
  }
1029
918
  catch (err) {
1030
919
  const msg = err instanceof Error ? err.message : String(err);
@@ -1047,22 +936,6 @@ async function runPhaseSix(args) {
1047
936
  baselineAudit = await runBaselineAudit({
1048
937
  repoRoot: args.repoRoot,
1049
938
  languages: defaultBaselineLanguages(stackKinds),
1050
- projectGlobs,
1051
- onSensorProgress: (row) => {
1052
- if (printedSensors.length < 3) {
1053
- const id = row.sensor_id.padEnd(22);
1054
- const status = row.skipped
1055
- ? visualC.dim("skipped")
1056
- : row.finding_count > 0
1057
- ? `${row.finding_count} existing violation${row.finding_count === 1 ? "" : "s"} found`
1058
- : "clean";
1059
- process.stdout.write(` ${id} ${row.skipped ? "○" : row.finding_count > 0 ? "⚠" : "✓"} ${status}\n`);
1060
- printedSensors.push(row.sensor_id);
1061
- }
1062
- else {
1063
- suppressedCount += 1;
1064
- }
1065
- },
1066
939
  });
1067
940
  if (suppressedCount > 0) {
1068
941
  process.stdout.write(` ${visualC.dim(`+ ${suppressedCount} more…`)}\n`);
@@ -1076,37 +949,6 @@ async function runPhaseSix(args) {
1076
949
  }
1077
950
  return { ingestion, baselineAudit };
1078
951
  }
1079
- function describeIngestion(ingestion) {
1080
- if (ingestion === null)
1081
- return null;
1082
- const decCount = ingestion.decsWritten.length;
1083
- if (decCount === 0) {
1084
- if (ingestion.scannedEntries === 0) {
1085
- return `0 emitted (no docs/* paragraphs in topic-index)`;
1086
- }
1087
- return `0 emitted (${ingestion.scannedEntries} entries scanned, none classified as decision/domain-rule)`;
1088
- }
1089
- return `${decCount} DEC${decCount === 1 ? "" : "s"} written verbatim from docs/* (auto-promoted)`;
1090
- }
1091
- function describeCanonical(_ingestion) {
1092
- // canonical-map seeding moved out of phase 6 in v0.5.0 — handled by
1093
- // the standalone topic-index pipeline instead.
1094
- return null;
1095
- }
1096
- function describeBaseline(audit) {
1097
- if (audit === null)
1098
- return null;
1099
- const fileNote = audit.truncatedAtFileCap
1100
- ? `${audit.filesScanned}/${audit.filesAvailable} files — sample mode`
1101
- : `${audit.filesScanned} files`;
1102
- if (audit.totalFindings === 0) {
1103
- if (audit.skippedSensorIds.length > 0 && audit.cleanSensorIds.length === 0) {
1104
- return null;
1105
- }
1106
- return `0 findings (run on ${fileNote})`;
1107
- }
1108
- return `${audit.totalFindings} existing sensor finding${audit.totalFindings === 1 ? "" : "s"} (run cairn attention; ${fileNote})`;
1109
- }
1110
952
  function remoteShorthand(url) {
1111
953
  // https://github.com/foo/bar.git → github.com/foo/bar
1112
954
  // git@github.com:foo/bar.git → github.com/foo/bar