@isaacriehm/cairn-core 0.1.10 → 0.3.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 (399) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/claude/runner.d.ts +1 -1
  3. package/dist/claude/runner.js +62 -1
  4. package/dist/claude/runner.js.map +1 -1
  5. package/dist/claude/types.d.ts +14 -7
  6. package/dist/claude/types.js +5 -7
  7. package/dist/claude/types.js.map +1 -1
  8. package/dist/context/index.d.ts +4 -4
  9. package/dist/context/index.js +3 -4
  10. package/dist/context/index.js.map +1 -1
  11. package/dist/context/spec-delta.js +3 -4
  12. package/dist/context/spec-delta.js.map +1 -1
  13. package/dist/context/task-summary.d.ts +18 -0
  14. package/dist/context/task-summary.js +89 -0
  15. package/dist/context/task-summary.js.map +1 -0
  16. package/dist/decision-capture/id.d.ts +21 -4
  17. package/dist/decision-capture/id.js +56 -5
  18. package/dist/decision-capture/id.js.map +1 -1
  19. package/dist/decision-capture/index.d.ts +7 -22
  20. package/dist/decision-capture/index.js +7 -17
  21. package/dist/decision-capture/index.js.map +1 -1
  22. package/dist/doctor/index.d.ts +2 -2
  23. package/dist/doctor/index.js +5 -60
  24. package/dist/doctor/index.js.map +1 -1
  25. package/dist/events/index.d.ts +1 -1
  26. package/dist/events/index.js +1 -1
  27. package/dist/events/writer.d.ts +1 -1
  28. package/dist/events/writer.js +1 -1
  29. package/dist/gc/canary.d.ts +13 -23
  30. package/dist/gc/canary.js +36 -92
  31. package/dist/gc/canary.js.map +1 -1
  32. package/dist/gc/citation-integrity.d.ts +6 -6
  33. package/dist/gc/citation-integrity.js +64 -20
  34. package/dist/gc/citation-integrity.js.map +1 -1
  35. package/dist/gc/frontmatter.js +1 -1
  36. package/dist/gc/generator-drift.js +1 -1
  37. package/dist/gc/generator-drift.js.map +1 -1
  38. package/dist/gc/index.d.ts +2 -2
  39. package/dist/gc/index.js +1 -1
  40. package/dist/gc/index.js.map +1 -1
  41. package/dist/gc/quality-update.d.ts +4 -4
  42. package/dist/gc/quality-update.js +5 -5
  43. package/dist/gc/quality-update.js.map +1 -1
  44. package/dist/gc/types.d.ts +1 -30
  45. package/dist/ground/index.d.ts +2 -2
  46. package/dist/ground/index.js +1 -1
  47. package/dist/ground/index.js.map +1 -1
  48. package/dist/ground/ledgers.d.ts +0 -4
  49. package/dist/ground/ledgers.js +10 -8
  50. package/dist/ground/ledgers.js.map +1 -1
  51. package/dist/ground/manifest.js +0 -4
  52. package/dist/ground/manifest.js.map +1 -1
  53. package/dist/ground/paths.js +0 -1
  54. package/dist/ground/paths.js.map +1 -1
  55. package/dist/ground/quality-grades.js +3 -1
  56. package/dist/ground/quality-grades.js.map +1 -1
  57. package/dist/ground/schemas.d.ts +2 -7
  58. package/dist/ground/schemas.js +7 -2
  59. package/dist/ground/schemas.js.map +1 -1
  60. package/dist/ground/scope-index.d.ts +62 -14
  61. package/dist/ground/scope-index.js +215 -45
  62. package/dist/ground/scope-index.js.map +1 -1
  63. package/dist/hooks/bypass-detection.js +14 -17
  64. package/dist/hooks/bypass-detection.js.map +1 -1
  65. package/dist/hooks/defer.d.ts +50 -0
  66. package/dist/hooks/defer.js +87 -0
  67. package/dist/hooks/defer.js.map +1 -0
  68. package/dist/hooks/post-tool-use/citation-scanner.d.ts +7 -5
  69. package/dist/hooks/post-tool-use/citation-scanner.js +15 -9
  70. package/dist/hooks/post-tool-use/citation-scanner.js.map +1 -1
  71. package/dist/hooks/post-tool-use/copy-scanner.js +1 -1
  72. package/dist/hooks/post-tool-use/copy-scanner.js.map +1 -1
  73. package/dist/hooks/post-tool-use/ledger-cache.d.ts +10 -2
  74. package/dist/hooks/post-tool-use/ledger-cache.js +58 -4
  75. package/dist/hooks/post-tool-use/ledger-cache.js.map +1 -1
  76. package/dist/hooks/post-tool-use/legend-builder.d.ts +3 -3
  77. package/dist/hooks/post-tool-use/legend-builder.js +30 -8
  78. package/dist/hooks/post-tool-use/legend-builder.js.map +1 -1
  79. package/dist/hooks/post-tool-use/read-enricher.d.ts +1 -1
  80. package/dist/hooks/post-tool-use/read-enricher.js +68 -21
  81. package/dist/hooks/post-tool-use/read-enricher.js.map +1 -1
  82. package/dist/hooks/post-tool-use/write-guardian.js +148 -18
  83. package/dist/hooks/post-tool-use/write-guardian.js.map +1 -1
  84. package/dist/hooks/runners/index.d.ts +3 -0
  85. package/dist/hooks/runners/index.js +2 -0
  86. package/dist/hooks/runners/index.js.map +1 -1
  87. package/dist/hooks/runners/payload.d.ts +1 -1
  88. package/dist/hooks/runners/payload.js +27 -12
  89. package/dist/hooks/runners/payload.js.map +1 -1
  90. package/dist/hooks/runners/session-start.js +250 -75
  91. package/dist/hooks/runners/session-start.js.map +1 -1
  92. package/dist/hooks/runners/stop.d.ts +9 -12
  93. package/dist/hooks/runners/stop.js +129 -41
  94. package/dist/hooks/runners/stop.js.map +1 -1
  95. package/dist/hooks/runners/user-prompt-submit.d.ts +15 -0
  96. package/dist/hooks/runners/user-prompt-submit.js +149 -0
  97. package/dist/hooks/runners/user-prompt-submit.js.map +1 -0
  98. package/dist/hooks/seed-attested.d.ts +25 -0
  99. package/dist/hooks/seed-attested.js +84 -0
  100. package/dist/hooks/seed-attested.js.map +1 -0
  101. package/dist/hooks/user-prompt-submit.d.ts +7 -0
  102. package/dist/hooks/user-prompt-submit.js +12 -0
  103. package/dist/hooks/user-prompt-submit.js.map +1 -0
  104. package/dist/index.d.ts +3 -6
  105. package/dist/index.js +14 -12
  106. package/dist/index.js.map +1 -1
  107. package/dist/init/baseline-audit.d.ts +5 -1
  108. package/dist/init/baseline-audit.js +25 -2
  109. package/dist/init/baseline-audit.js.map +1 -1
  110. package/dist/init/glob-inference.d.ts +16 -0
  111. package/dist/init/glob-inference.js +108 -0
  112. package/dist/init/glob-inference.js.map +1 -0
  113. package/dist/init/index.d.ts +4 -0
  114. package/dist/init/index.js +2 -0
  115. package/dist/init/index.js.map +1 -1
  116. package/dist/init/ingest-docs.d.ts +1 -1
  117. package/dist/init/ingest-docs.js +19 -6
  118. package/dist/init/ingest-docs.js.map +1 -1
  119. package/dist/init/init.js +17 -94
  120. package/dist/init/init.js.map +1 -1
  121. package/dist/init/mapper-merge.d.ts +8 -2
  122. package/dist/init/mapper-merge.js +50 -32
  123. package/dist/init/mapper-merge.js.map +1 -1
  124. package/dist/init/mapper-parallel.d.ts +2 -3
  125. package/dist/init/mapper-parallel.js +9 -38
  126. package/dist/init/mapper-parallel.js.map +1 -1
  127. package/dist/init/mapper-prompts.js +1 -1
  128. package/dist/init/mapper-prompts.js.map +1 -1
  129. package/dist/init/mapper.d.ts +7 -128
  130. package/dist/init/mapper.js +30 -7
  131. package/dist/init/mapper.js.map +1 -1
  132. package/dist/init/module-slicer.d.ts +1 -1
  133. package/dist/init/module-slicer.js +1 -1
  134. package/dist/init/multi-dev/install.d.ts +9 -10
  135. package/dist/init/multi-dev/install.js +15 -84
  136. package/dist/init/multi-dev/install.js.map +1 -1
  137. package/dist/init/overlay.d.ts +14 -0
  138. package/dist/init/overlay.js +65 -0
  139. package/dist/init/overlay.js.map +1 -0
  140. package/dist/init/phases/1-detect.d.ts +10 -0
  141. package/dist/init/phases/1-detect.js +36 -0
  142. package/dist/init/phases/1-detect.js.map +1 -0
  143. package/dist/init/phases/10-strip.d.ts +11 -0
  144. package/dist/init/phases/10-strip.js +79 -0
  145. package/dist/init/phases/10-strip.js.map +1 -0
  146. package/dist/init/phases/12-multidev.d.ts +6 -0
  147. package/dist/init/phases/12-multidev.js +34 -0
  148. package/dist/init/phases/12-multidev.js.map +1 -0
  149. package/dist/init/phases/2-walker.d.ts +8 -0
  150. package/dist/init/phases/2-walker.js +34 -0
  151. package/dist/init/phases/2-walker.js.map +1 -0
  152. package/dist/init/phases/3-mapper.d.ts +14 -0
  153. package/dist/init/phases/3-mapper.js +56 -0
  154. package/dist/init/phases/3-mapper.js.map +1 -0
  155. package/dist/init/phases/3b-seed.d.ts +18 -0
  156. package/dist/init/phases/3b-seed.js +140 -0
  157. package/dist/init/phases/3b-seed.js.map +1 -0
  158. package/dist/init/phases/4-pilot.d.ts +10 -0
  159. package/dist/init/phases/4-pilot.js +108 -0
  160. package/dist/init/phases/4-pilot.js.map +1 -0
  161. package/dist/init/phases/5-brand.d.ts +10 -0
  162. package/dist/init/phases/5-brand.js +66 -0
  163. package/dist/init/phases/5-brand.js.map +1 -0
  164. package/dist/init/phases/6-docs-ingest.d.ts +11 -0
  165. package/dist/init/phases/6-docs-ingest.js +39 -0
  166. package/dist/init/phases/6-docs-ingest.js.map +1 -0
  167. package/dist/init/phases/7b-source-comments.d.ts +6 -0
  168. package/dist/init/phases/7b-source-comments.js +34 -0
  169. package/dist/init/phases/7b-source-comments.js.map +1 -0
  170. package/dist/init/phases/7c-rules-merge.d.ts +6 -0
  171. package/dist/init/phases/7c-rules-merge.js +34 -0
  172. package/dist/init/phases/7c-rules-merge.js.map +1 -0
  173. package/dist/init/phases/8-baseline.d.ts +10 -0
  174. package/dist/init/phases/8-baseline.js +52 -0
  175. package/dist/init/phases/8-baseline.js.map +1 -0
  176. package/dist/init/phases/index.d.ts +15 -0
  177. package/dist/init/phases/index.js +16 -0
  178. package/dist/init/phases/index.js.map +1 -0
  179. package/dist/init/phases/orchestrator.d.ts +49 -0
  180. package/dist/init/phases/orchestrator.js +85 -0
  181. package/dist/init/phases/orchestrator.js.map +1 -0
  182. package/dist/init/phases/state-io.d.ts +19 -0
  183. package/dist/init/phases/state-io.js +73 -0
  184. package/dist/init/phases/state-io.js.map +1 -0
  185. package/dist/init/phases/types.d.ts +93 -0
  186. package/dist/init/phases/types.js +30 -0
  187. package/dist/init/phases/types.js.map +1 -0
  188. package/dist/init/prompts.d.ts +6 -8
  189. package/dist/init/prompts.js +3 -6
  190. package/dist/init/prompts.js.map +1 -1
  191. package/dist/init/rules-merge/ingest.js +1 -1
  192. package/dist/init/seed.js +11 -2
  193. package/dist/init/seed.js.map +1 -1
  194. package/dist/init/source-comments/classify.d.ts +1 -41
  195. package/dist/init/source-comments/classify.js +68 -37
  196. package/dist/init/source-comments/classify.js.map +1 -1
  197. package/dist/init/source-comments/index.d.ts +2 -2
  198. package/dist/init/source-comments/index.js +2 -2
  199. package/dist/init/source-comments/index.js.map +1 -1
  200. package/dist/init/source-comments/ingest.d.ts +38 -2
  201. package/dist/init/source-comments/ingest.js +237 -4
  202. package/dist/init/source-comments/ingest.js.map +1 -1
  203. package/dist/init/source-comments/strip-replace.d.ts +10 -19
  204. package/dist/init/source-comments/strip-replace.js +26 -2
  205. package/dist/init/source-comments/strip-replace.js.map +1 -1
  206. package/dist/init/source-comments/walker.d.ts +9 -2
  207. package/dist/init/source-comments/walker.js +38 -19
  208. package/dist/init/source-comments/walker.js.map +1 -1
  209. package/dist/init/submodules.d.ts +3 -2
  210. package/dist/init/types.d.ts +3 -5
  211. package/dist/init/types.js +3 -5
  212. package/dist/init/types.js.map +1 -1
  213. package/dist/init/visual.d.ts +4 -9
  214. package/dist/init/visual.js +1 -16
  215. package/dist/init/visual.js.map +1 -1
  216. package/dist/init/walker.d.ts +0 -6
  217. package/dist/init/walker.js +2 -3
  218. package/dist/init/walker.js.map +1 -1
  219. package/dist/join/index.js +49 -2
  220. package/dist/join/index.js.map +1 -1
  221. package/dist/logger.d.ts +1 -2
  222. package/dist/logger.js +5 -6
  223. package/dist/logger.js.map +1 -1
  224. package/dist/mcp/context.d.ts +2 -3
  225. package/dist/mcp/context.js.map +1 -1
  226. package/dist/mcp/errors.d.ts +1 -1
  227. package/dist/mcp/errors.js.map +1 -1
  228. package/dist/mcp/history/prompt.d.ts +2 -1
  229. package/dist/mcp/history/walker.js +1 -1
  230. package/dist/mcp/history/walker.js.map +1 -1
  231. package/dist/mcp/path-allowlist.d.ts +0 -6
  232. package/dist/mcp/path-allowlist.js +0 -10
  233. package/dist/mcp/path-allowlist.js.map +1 -1
  234. package/dist/mcp/schemas.d.ts +34 -72
  235. package/dist/mcp/schemas.js +40 -70
  236. package/dist/mcp/schemas.js.map +1 -1
  237. package/dist/mcp/serve.d.ts +1 -1
  238. package/dist/mcp/serve.js +2 -5
  239. package/dist/mcp/serve.js.map +1 -1
  240. package/dist/mcp/server.js +10 -4
  241. package/dist/mcp/server.js.map +1 -1
  242. package/dist/mcp/telemetry.d.ts +8 -1
  243. package/dist/mcp/telemetry.js +16 -0
  244. package/dist/mcp/telemetry.js.map +1 -1
  245. package/dist/mcp/tools/decision-get.js +37 -29
  246. package/dist/mcp/tools/decision-get.js.map +1 -1
  247. package/dist/mcp/tools/decisions-in-scope.js +22 -3
  248. package/dist/mcp/tools/decisions-in-scope.js.map +1 -1
  249. package/dist/mcp/tools/ground-get.js +2 -2
  250. package/dist/mcp/tools/ground-get.js.map +1 -1
  251. package/dist/mcp/tools/index.js +6 -2
  252. package/dist/mcp/tools/index.js.map +1 -1
  253. package/dist/mcp/tools/init-phases.d.ts +24 -0
  254. package/dist/mcp/tools/init-phases.js +140 -0
  255. package/dist/mcp/tools/init-phases.js.map +1 -0
  256. package/dist/mcp/tools/invariant-get.js +1 -1
  257. package/dist/mcp/tools/invariant-get.js.map +1 -1
  258. package/dist/mcp/tools/invariants-in-scope.js +26 -7
  259. package/dist/mcp/tools/invariants-in-scope.js.map +1 -1
  260. package/dist/mcp/tools/query-history.js +3 -3
  261. package/dist/mcp/tools/query-history.js.map +1 -1
  262. package/dist/mcp/tools/resolve-attention.d.ts +6 -4
  263. package/dist/mcp/tools/resolve-attention.js +253 -24
  264. package/dist/mcp/tools/resolve-attention.js.map +1 -1
  265. package/dist/mcp/tools/search.js +3 -4
  266. package/dist/mcp/tools/search.js.map +1 -1
  267. package/dist/mcp/tools/task-create.d.ts +15 -0
  268. package/dist/mcp/tools/task-create.js +96 -0
  269. package/dist/mcp/tools/task-create.js.map +1 -0
  270. package/dist/mcp/tools/timeline.js +3 -7
  271. package/dist/mcp/tools/timeline.js.map +1 -1
  272. package/dist/profiles/types.d.ts +2 -2
  273. package/dist/profiles/types.js +1 -1
  274. package/dist/sensors/catalog.js +8 -3
  275. package/dist/sensors/catalog.js.map +1 -1
  276. package/dist/session/id.d.ts +1 -3
  277. package/dist/session/id.js +1 -1
  278. package/dist/session/id.js.map +1 -1
  279. package/dist/session-start/build.d.ts +7 -11
  280. package/dist/session-start/build.js +62 -34
  281. package/dist/session-start/build.js.map +1 -1
  282. package/dist/session-start/index.d.ts +2 -2
  283. package/dist/session-start/index.js +2 -2
  284. package/dist/session-start/index.js.map +1 -1
  285. package/dist/session-start/templates.d.ts +20 -4
  286. package/dist/session-start/templates.js +45 -35
  287. package/dist/session-start/templates.js.map +1 -1
  288. package/dist/status-line/format.d.ts +20 -9
  289. package/dist/status-line/format.js +45 -35
  290. package/dist/status-line/format.js.map +1 -1
  291. package/dist/status-line/index.d.ts +3 -4
  292. package/dist/status-line/index.js +1 -1
  293. package/dist/status-line/index.js.map +1 -1
  294. package/dist/status-line/reader.d.ts +9 -6
  295. package/dist/status-line/reader.js +50 -18
  296. package/dist/status-line/reader.js.map +1 -1
  297. package/dist/status-line/writer.d.ts +6 -9
  298. package/dist/status-line/writer.js +10 -12
  299. package/dist/status-line/writer.js.map +1 -1
  300. package/dist/trace/index.d.ts +44 -0
  301. package/dist/trace/index.js +51 -0
  302. package/dist/trace/index.js.map +1 -0
  303. package/package.json +2 -3
  304. package/templates/.archive/README.md +3 -3
  305. package/templates/.cairn/JOIN.md +3 -9
  306. package/templates/.cairn/config/sensors.yaml +16 -19
  307. package/templates/.cairn/config/stub-patterns.yaml +4 -4
  308. package/templates/.cairn/config/trust-policy.yaml +3 -35
  309. package/templates/.cairn/config/workflow.md +13 -194
  310. package/templates/.cairn/git-hooks/commit-msg +15 -4
  311. package/templates/.cairn/git-hooks/pre-commit +22 -13
  312. package/templates/.cairn/ground/canonical-map/topics.yaml +3 -26
  313. package/templates/.cairn/ground/capabilities/snippets.yaml +0 -1
  314. package/templates/.cairn/ground/manifest.yaml +5 -8
  315. package/templates/.cairn/ground/product/personas.yaml +0 -1
  316. package/dist/context/checkpoint.d.ts +0 -10
  317. package/dist/context/checkpoint.js +0 -29
  318. package/dist/context/checkpoint.js.map +0 -1
  319. package/dist/decision-capture/capture.d.ts +0 -57
  320. package/dist/decision-capture/capture.js +0 -186
  321. package/dist/decision-capture/capture.js.map +0 -1
  322. package/dist/decision-capture/extractor.d.ts +0 -20
  323. package/dist/decision-capture/extractor.js +0 -103
  324. package/dist/decision-capture/extractor.js.map +0 -1
  325. package/dist/decision-capture/prompt.d.ts +0 -15
  326. package/dist/decision-capture/prompt.js +0 -68
  327. package/dist/decision-capture/prompt.js.map +0 -1
  328. package/dist/decision-capture/refinement-prompt.d.ts +0 -25
  329. package/dist/decision-capture/refinement-prompt.js +0 -146
  330. package/dist/decision-capture/refinement-prompt.js.map +0 -1
  331. package/dist/decision-capture/refinement-schema.d.ts +0 -52
  332. package/dist/decision-capture/refinement-schema.js +0 -61
  333. package/dist/decision-capture/refinement-schema.js.map +0 -1
  334. package/dist/decision-capture/refinement.d.ts +0 -60
  335. package/dist/decision-capture/refinement.js +0 -439
  336. package/dist/decision-capture/refinement.js.map +0 -1
  337. package/dist/decision-capture/schema.d.ts +0 -70
  338. package/dist/decision-capture/schema.js +0 -71
  339. package/dist/decision-capture/schema.js.map +0 -1
  340. package/dist/decision-capture/types.d.ts +0 -201
  341. package/dist/decision-capture/types.js +0 -20
  342. package/dist/decision-capture/types.js.map +0 -1
  343. package/dist/decision-capture/writer.d.ts +0 -90
  344. package/dist/decision-capture/writer.js +0 -267
  345. package/dist/decision-capture/writer.js.map +0 -1
  346. package/dist/frontend-types.d.ts +0 -243
  347. package/dist/frontend-types.js +0 -15
  348. package/dist/frontend-types.js.map +0 -1
  349. package/dist/hooks/index.d.ts +0 -12
  350. package/dist/hooks/index.js +0 -13
  351. package/dist/hooks/index.js.map +0 -1
  352. package/dist/inbox.d.ts +0 -17
  353. package/dist/inbox.js +0 -30
  354. package/dist/inbox.js.map +0 -1
  355. package/dist/mcp/tools/append-run-note.d.ts +0 -18
  356. package/dist/mcp/tools/append-run-note.js +0 -47
  357. package/dist/mcp/tools/append-run-note.js.map +0 -1
  358. package/dist/mcp/tools/append.d.ts +0 -8
  359. package/dist/mcp/tools/append.js +0 -37
  360. package/dist/mcp/tools/append.js.map +0 -1
  361. package/dist/mcp/tools/ask-operator.d.ts +0 -34
  362. package/dist/mcp/tools/ask-operator.js +0 -97
  363. package/dist/mcp/tools/ask-operator.js.map +0 -1
  364. package/dist/mcp/tools/drop-task.d.ts +0 -12
  365. package/dist/mcp/tools/drop-task.js +0 -68
  366. package/dist/mcp/tools/drop-task.js.map +0 -1
  367. package/dist/mcp/tools/record-run-event.d.ts +0 -10
  368. package/dist/mcp/tools/record-run-event.js +0 -32
  369. package/dist/mcp/tools/record-run-event.js.map +0 -1
  370. package/dist/prompt.d.ts +0 -19
  371. package/dist/prompt.js +0 -50
  372. package/dist/prompt.js.map +0 -1
  373. package/dist/tier0/classify.d.ts +0 -10
  374. package/dist/tier0/classify.js +0 -110
  375. package/dist/tier0/classify.js.map +0 -1
  376. package/dist/tier0/index.d.ts +0 -2
  377. package/dist/tier0/index.js +0 -2
  378. package/dist/tier0/index.js.map +0 -1
  379. package/dist/tier0/types.d.ts +0 -24
  380. package/dist/tier0/types.js +0 -9
  381. package/dist/tier0/types.js.map +0 -1
  382. package/dist/tightener/index.d.ts +0 -4
  383. package/dist/tightener/index.js +0 -4
  384. package/dist/tightener/index.js.map +0 -1
  385. package/dist/tightener/prompt.d.ts +0 -3
  386. package/dist/tightener/prompt.js +0 -67
  387. package/dist/tightener/prompt.js.map +0 -1
  388. package/dist/tightener/schema.d.ts +0 -68
  389. package/dist/tightener/schema.js +0 -44
  390. package/dist/tightener/schema.js.map +0 -1
  391. package/dist/tightener/tighten.d.ts +0 -2
  392. package/dist/tightener/tighten.js +0 -66
  393. package/dist/tightener/tighten.js.map +0 -1
  394. package/dist/tightener/types.d.ts +0 -74
  395. package/dist/tightener/types.js +0 -6
  396. package/dist/tightener/types.js.map +0 -1
  397. package/templates/.claude/settings.json +0 -57
  398. package/templates/.mcp.json +0 -8
  399. package/templates/README.md +0 -24
@@ -1,38 +1,48 @@
1
1
  /**
2
- * Static text fragments for the SessionStart payload.
2
+ * Static text fragments for the SessionStart payload. Kept compact —
3
+ * every static byte here ships in `additionalContext` on every session
4
+ * open, so verbosity scales linearly with operator session count.
5
+ *
6
+ * The agent's MCP client already receives full tool descriptions from
7
+ * the server's `registerTool` calls; SessionStart does NOT need to
8
+ * duplicate them. Bare `§DEC-NNNN` and `§INV-NNNN` citations resolve
9
+ * via the PostToolUse(Read) enricher hook.
3
10
  */
4
- export const TWO_ZONE_REMINDER_BASE = `## Two-zone reminder
5
-
6
- Default reads/grep/glob hit the **canonical zone** only:
7
- - AGENTS.md, CLAUDE.md, .claude/{rules,agents,skills}, docs/**,
8
- .cairn/config/**, .cairn/ground/** (excluding _inbox/),
9
- .cairn/tasks/active/**
10
-
11
- Historical content lives under .archive/, .cairn/runs/terminal/,
12
- .cairn/tasks/{done,archived}/, .cairn/ground/decisions/_inbox/. The
13
- cairn walkers and search tooling already exclude these paths you do
14
- not need to filter manually. If you genuinely need to consult historical
15
- context, call \`mcp__cairn__cairn_query_history(scope, question)\`. It
16
- returns LLM-summarized claims with supersedes-pointers; raw archive
17
- content never enters your context.`;
18
- export const TOOL_QUICK_REFERENCE = `## Cairn MCP tools (quick reference)
19
-
20
- Read:
21
- cairn_decision_get(id) — full ADR + assertions
22
- cairn_decisions_in_scope(path_globs[]) — decisions overlapping a path
23
- cairn_invariant_get(id) — §V invariant body + sensor
24
- cairn_canonical_for_topic(topic) — authoritative path + verified-at
25
- cairn_get_full(id, kind) fetch any artifact by id
26
- cairn_search(query, scope[]?) — substring index over ground+docs
27
- cairn_query_history(scope, question) Tier-1 summary of .archive/
28
-
29
- Write:
30
- cairn_record_decision(...) — drop draft to _inbox/ for operator confirm
31
- cairn_archive(path, reason) — move canonical .archive/
32
- `;
33
- export const SESSION_START_HEADER = `# Cairn state context
34
-
35
- This Claude Code session is running inside a cairn-adopted project. The
36
- cairn state layer has prepared the following grounding context for you.
37
- Treat each section as authoritative for the duration of this session.`;
11
+ export const TWO_ZONE_REMINDER_BASE = "## Two-zone reminder\n\n" +
12
+ "Reads/grep/glob default to the canonical zone (AGENTS.md, CLAUDE.md, " +
13
+ "docs/**, .cairn/ground/**, .cairn/tasks/active/**). Historical content " +
14
+ "(.archive/, .cairn/tasks/done/) is excluded by cairn's walkers — call " +
15
+ "`cairn_query_history(scope, question)` when you need a summarized read.";
16
+ export const SESSION_START_HEADER = "# Cairn ground state — authoritative for this session";
17
+ /**
18
+ * The code-change contract — system-level rule injected on every
19
+ * SessionStart so it sits above any skill body in the agent's context
20
+ * window. This is the operator-facing equivalent of the cairn-direction
21
+ * skill's "Hard contract" section, restated as a plain instruction
22
+ * Claude reads BEFORE the user prompt. Bypass detection in
23
+ * write-guardian remains the deterministic enforcement; this section
24
+ * is the up-front guidance.
25
+ */
26
+ export const CODE_CHANGE_CONTRACT = "## Cairn — code-change contract (BLOCKING)\n\n" +
27
+ "Source mutations (`Edit`/`Write` on tracked files) require a tightened " +
28
+ "spec first. Bypass → `PostToolUse` hook returns `decision: \"block\"`.\n\n" +
29
+ "Workflow on any code-change prompt:\n\n" +
30
+ "1. `ToolSearch(select:mcp__plugin_cairn_cairn__cairn_task_create," +
31
+ "mcp__plugin_cairn_cairn__cairn_decisions_in_scope," +
32
+ "mcp__plugin_cairn_cairn__cairn_invariants_in_scope,AskUserQuestion)`" +
33
+ "load deferred schemas. Required first call; without it `AskUserQuestion` " +
34
+ "is unavailable and clarifications fall back to inline prose.\n" +
35
+ "2. `cairn_decisions_in_scope({path_globs})` + `cairn_invariants_in_scope({path_globs})`.\n" +
36
+ "3. Forks unresolved → `AskUserQuestion` (≤3 options/round, A/B/C, cite " +
37
+ "DEC/§INV per option). Loop until deterministic.\n" +
38
+ "4. `cairn_task_create({slug, title, goal, target_path_globs, " +
39
+ "in_scope_decisions, in_scope_invariants, constraints, out_of_scope, " +
40
+ "acceptance, module})` server allocates `task_id` + atomically writes " +
41
+ "`spec.tightened.md` + `status.yaml`. Format-locked. **`title`** ≤50 " +
42
+ "chars renders in the statusline + lens (e.g. \"Fix token expiry\"). " +
43
+ "**`goal`** is the full 1–2 sentence description for the spec body.\n" +
44
+ "5. Edit/Write. Hook passes (active tightened task on disk).\n\n" +
45
+ "`/cairn-direction` is the long-form variant (multi-chunk dispatch, " +
46
+ "rich tightening). Above 5 steps = entire flow for straight bug fixes. " +
47
+ "NEVER skip Step 1 or Step 4.";
38
48
  //# sourceMappingURL=templates.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/session-start/templates.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,CAAC,MAAM,sBAAsB,GAAG;;;;;;;;;;;;;mCAaH,CAAC;AAEpC,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;CAcnC,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;sEAIkC,CAAC"}
1
+ {"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/session-start/templates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,CAAC,MAAM,sBAAsB,GACjC,0BAA0B;IAC1B,uEAAuE;IACvE,yEAAyE;IACzE,wEAAwE;IACxE,yEAAyE,CAAC;AAE5E,MAAM,CAAC,MAAM,oBAAoB,GAAG,uDAAuD,CAAC;AAE5F;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAC/B,gDAAgD;IAChD,yEAAyE;IACzE,4EAA4E;IAC5E,yCAAyC;IACzC,mEAAmE;IACnE,oDAAoD;IACpD,yEAAyE;IACzE,2EAA2E;IAC3E,gEAAgE;IAChE,4FAA4F;IAC5F,yEAAyE;IACzE,mDAAmD;IACnD,+DAA+D;IAC/D,sEAAsE;IACtE,yEAAyE;IACzE,sEAAsE;IACtE,sEAAsE;IACtE,sEAAsE;IACtE,iEAAiE;IACjE,qEAAqE;IACrE,wEAAwE;IACxE,8BAA8B,CAAC"}
@@ -1,14 +1,25 @@
1
1
  import type { StatusJson } from "./index.js";
2
2
  /**
3
- * Render a StatusJson as the single-line string Claude Code's status_line hook
4
- * displays. Pure function; no I/O.
3
+ * Render a single-line status string for Claude Code's status_line hook.
5
4
  *
6
- * Field priority for the "state" slot (single field):
7
- * daemon down > attention > 0 > gc running > task_state
5
+ * Layout: `⬡ cairn [signal] [ctx-meter]`
8
6
  *
9
- * Health icon:
10
- * daemon down
11
- * attention
12
- * else
7
+ * Signal priority (first match wins, blank when nothing applies):
8
+ * bypass_count > 0 `⚠ N unattested`
9
+ * attention_count > 0 `⚑ N draft[s]`
10
+ * gc_running `◐ gc`
11
+ * task_state != idle → `${task_id} ${task_module}` (or fallbacks)
12
+ *
13
+ * Ctx meter is omitted when no payload is supplied. Color thresholds are
14
+ * keyed on absolute used tokens (not percentage) so a 1M-window Opus
15
+ * session and a 200k-window Sonnet session signal danger at comparable
16
+ * absolute exhaustion points.
13
17
  */
14
- export declare function formatStatus(s: StatusJson): string;
18
+ export interface CtxMeterInput {
19
+ /** raw used % matches Claude Code's /context display (no buffer normalization). */
20
+ usedPct: number;
21
+ /** absolute used tokens — keys the color threshold. */
22
+ usedTokens: number;
23
+ }
24
+ export declare function renderCtxMeter(ctx: CtxMeterInput): string;
25
+ export declare function formatStatus(s: StatusJson, ctx?: CtxMeterInput): string;
@@ -1,40 +1,50 @@
1
- /**
2
- * Render a StatusJson as the single-line string Claude Code's status_line hook
3
- * displays. Pure function; no I/O.
4
- *
5
- * Field priority for the "state" slot (single field):
6
- * daemon down > attention > 0 > gc running > task_state
7
- *
8
- * Health icon:
9
- * daemon down →
10
- * attention → ⚑
11
- * else →
12
- */
13
- export function formatStatus(s) {
14
- const parts = ["⬡ cairn"];
15
- parts.push(`ctx:${s.ctx_tokens_used}/${s.ctx_tokens_budget}`);
16
- parts.push(`decisions:${s.decisions_in_scope}`);
17
- parts.push(`inv:${s.invariants_in_scope}`);
18
- let stateField;
19
- let icon;
20
- if (!s.daemon_alive) {
21
- stateField = "daemon:down";
22
- icon = "○";
23
- }
24
- else if (s.attention_count > 0) {
25
- stateField = `attention:${s.attention_count}`;
26
- icon = "⚑";
27
- }
28
- else if (s.gc_running) {
29
- stateField = "gc:active";
30
- icon = "●";
1
+ const ANSI_RESET = "\x1b[0m";
2
+ const ANSI_GREEN = "\x1b[32m";
3
+ const ANSI_YELLOW = "\x1b[33m";
4
+ const ANSI_ORANGE = "\x1b[38;5;208m";
5
+ const ANSI_RED = "\x1b[31m";
6
+ function ctxColor(usedTokens) {
7
+ if (usedTokens < 100_000)
8
+ return ANSI_GREEN;
9
+ if (usedTokens < 300_000)
10
+ return ANSI_YELLOW;
11
+ if (usedTokens < 600_000)
12
+ return ANSI_ORANGE;
13
+ return ANSI_RED;
14
+ }
15
+ export function renderCtxMeter(ctx) {
16
+ const pct = Math.max(0, Math.min(100, Math.round(ctx.usedPct)));
17
+ const filled = Math.floor(pct / 10);
18
+ const bar = "█".repeat(filled) + "░".repeat(10 - filled);
19
+ return `${ctxColor(ctx.usedTokens)}${bar} ${pct}%${ANSI_RESET}`;
20
+ }
21
+ function renderSignal(s) {
22
+ if (s.bypass_count > 0)
23
+ return `⚠ ${s.bypass_count} unattested`;
24
+ if (s.attention_count > 0) {
25
+ const noun = s.attention_count === 1 ? "draft" : "drafts";
26
+ return `⚑ ${s.attention_count} ${noun}`;
31
27
  }
32
- else {
33
- stateField = `task:${s.task_state}`;
34
- icon = "";
28
+ if (s.gc_running)
29
+ return "◐ gc";
30
+ if (s.task_state !== "idle") {
31
+ if (s.task_id && s.task_module)
32
+ return `${s.task_id} ${s.task_module}`;
33
+ if (s.task_id)
34
+ return s.task_id;
35
+ if (s.task_module)
36
+ return s.task_module;
37
+ return `task: ${s.task_state}`;
35
38
  }
36
- parts.push(stateField);
37
- parts.push(icon);
39
+ return null;
40
+ }
41
+ export function formatStatus(s, ctx) {
42
+ const parts = ["⬡ cairn"];
43
+ const signal = renderSignal(s);
44
+ if (signal)
45
+ parts.push(signal);
46
+ if (ctx)
47
+ parts.push(renderCtxMeter(ctx));
38
48
  return parts.join(" ");
39
49
  }
40
50
  //# sourceMappingURL=format.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/status-line/format.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,YAAY,CAAC,CAAa;IACxC,MAAM,KAAK,GAAa,CAAC,SAAS,CAAC,CAAC;IAEpC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,eAAe,IAAI,CAAC,CAAC,iBAAiB,EAAE,CAAC,CAAC;IAC9D,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,kBAAkB,EAAE,CAAC,CAAC;IAChD,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,mBAAmB,EAAE,CAAC,CAAC;IAE3C,IAAI,UAAkB,CAAC;IACvB,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC;QACpB,UAAU,GAAG,aAAa,CAAC;QAC3B,IAAI,GAAG,GAAG,CAAC;IACb,CAAC;SAAM,IAAI,CAAC,CAAC,eAAe,GAAG,CAAC,EAAE,CAAC;QACjC,UAAU,GAAG,aAAa,CAAC,CAAC,eAAe,EAAE,CAAC;QAC9C,IAAI,GAAG,GAAG,CAAC;IACb,CAAC;SAAM,IAAI,CAAC,CAAC,UAAU,EAAE,CAAC;QACxB,UAAU,GAAG,WAAW,CAAC;QACzB,IAAI,GAAG,GAAG,CAAC;IACb,CAAC;SAAM,CAAC;QACN,UAAU,GAAG,QAAQ,CAAC,CAAC,UAAU,EAAE,CAAC;QACpC,IAAI,GAAG,GAAG,CAAC;IACb,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACvB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEjB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/status-line/format.ts"],"names":[],"mappings":"AA0BA,MAAM,UAAU,GAAG,SAAS,CAAC;AAC7B,MAAM,UAAU,GAAG,UAAU,CAAC;AAC9B,MAAM,WAAW,GAAG,UAAU,CAAC;AAC/B,MAAM,WAAW,GAAG,gBAAgB,CAAC;AACrC,MAAM,QAAQ,GAAG,UAAU,CAAC;AAE5B,SAAS,QAAQ,CAAC,UAAkB;IAClC,IAAI,UAAU,GAAG,OAAO;QAAE,OAAO,UAAU,CAAC;IAC5C,IAAI,UAAU,GAAG,OAAO;QAAE,OAAO,WAAW,CAAC;IAC7C,IAAI,UAAU,GAAG,OAAO;QAAE,OAAO,WAAW,CAAC;IAC7C,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,GAAkB;IAC/C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAChE,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC;IACpC,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,GAAG,MAAM,CAAC,CAAC;IACzD,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,GAAG,IAAI,GAAG,IAAI,UAAU,EAAE,CAAC;AAClE,CAAC;AAED,SAAS,YAAY,CAAC,CAAa;IACjC,IAAI,CAAC,CAAC,YAAY,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC,CAAC,YAAY,aAAa,CAAC;IAChE,IAAI,CAAC,CAAC,eAAe,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,CAAC,CAAC,eAAe,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC;QAC1D,OAAO,KAAK,CAAC,CAAC,eAAe,IAAI,IAAI,EAAE,CAAC;IAC1C,CAAC;IACD,IAAI,CAAC,CAAC,UAAU;QAAE,OAAO,MAAM,CAAC;IAChC,IAAI,CAAC,CAAC,UAAU,KAAK,MAAM,EAAE,CAAC;QAC5B,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,WAAW;YAAE,OAAO,GAAG,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;QACvE,IAAI,CAAC,CAAC,OAAO;YAAE,OAAO,CAAC,CAAC,OAAO,CAAC;QAChC,IAAI,CAAC,CAAC,WAAW;YAAE,OAAO,CAAC,CAAC,WAAW,CAAC;QACxC,OAAO,SAAS,CAAC,CAAC,UAAU,EAAE,CAAC;IACjC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,CAAa,EAAE,GAAmB;IAC7D,MAAM,KAAK,GAAa,CAAC,SAAS,CAAC,CAAC;IACpC,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;IAC/B,IAAI,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC/B,IAAI,GAAG;QAAE,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC;IACzC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
@@ -12,18 +12,17 @@ export type TaskState = "idle" | "running" | "queued" | "tightening" | "sensing"
12
12
  export interface StatusJson {
13
13
  /** ISO timestamp of last write. */
14
14
  updated_at: string;
15
- daemon_alive: boolean;
16
- ctx_tokens_used: number;
17
- ctx_tokens_budget: number;
18
15
  decisions_in_scope: number;
19
16
  invariants_in_scope: number;
20
17
  task_state: TaskState;
18
+ task_id: string | null;
21
19
  task_module: string | null;
22
20
  gc_running: boolean;
23
21
  attention_count: number;
22
+ bypass_count: number;
24
23
  last_run_result: "succeeded" | "failed" | null;
25
24
  last_run_at: string | null;
26
25
  }
27
26
  export { defaultStatusJson, statusJsonPath, writeStatusJson, } from "./writer.js";
28
27
  export { readStatusForCLI } from "./reader.js";
29
- export { formatStatus } from "./format.js";
28
+ export { formatStatus, renderCtxMeter, type CtxMeterInput } from "./format.js";
@@ -10,5 +10,5 @@
10
10
  */
11
11
  export { defaultStatusJson, statusJsonPath, writeStatusJson, } from "./writer.js";
12
12
  export { readStatusForCLI } from "./reader.js";
13
- export { formatStatus } from "./format.js";
13
+ export { formatStatus, renderCtxMeter } from "./format.js";
14
14
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/status-line/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AA2BH,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,eAAe,GAChB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/status-line/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AA0BH,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,eAAe,GAChB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,cAAc,EAAsB,MAAM,aAAa,CAAC"}
@@ -1,13 +1,16 @@
1
+ import { type CtxMeterInput } from "./format.js";
1
2
  /**
2
3
  * Render the current status-line string for a session inside the
3
4
  * adopted repo at `repoRoot`. `sessionId` is the Claude Code session id
4
- * (passed via the status-line hook's stdin payload).
5
+ * (passed via the status-line hook's stdin payload). `ctx` is the
6
+ * decoded `context_window` block from the same payload.
5
7
  *
6
- * Returns the placeholder `⬡ cairn daemon:down ○` when:
7
- * - `sessionId` is null/empty (status-line invoked outside a session)
8
- * - the per-session status.json is missing
9
- * - the file is unreadable, malformed JSON, or fails shape validation
8
+ * Falls back to ground-state summary when:
9
+ * - `sessionId` is null/empty
10
+ * - the per-session status.json is missing, unreadable, or malformed
11
+ *
12
+ * Returns empty string when `.cairn/` doesn't exist (cairn not adopted).
10
13
  *
11
14
  * Hot path — invoked on every Claude Code prompt. Keep this cheap.
12
15
  */
13
- export declare function readStatusForCLI(repoRoot: string, sessionId: string | null): string;
16
+ export declare function readStatusForCLI(repoRoot: string, sessionId: string | null, ctx?: CtxMeterInput): string;
@@ -1,7 +1,7 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import { formatStatus } from "./format.js";
1
+ import { existsSync, readdirSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { formatStatus, renderCtxMeter } from "./format.js";
3
4
  import { statusJsonPath } from "./writer.js";
4
- const PLACEHOLDER = "⬡ cairn daemon:down ○";
5
5
  const TASK_STATES = [
6
6
  "idle",
7
7
  "running",
@@ -25,52 +25,84 @@ function isStatusJson(x) {
25
25
  return false;
26
26
  const o = x;
27
27
  return (typeof o["updated_at"] === "string" &&
28
- typeof o["daemon_alive"] === "boolean" &&
29
- typeof o["ctx_tokens_used"] === "number" &&
30
- typeof o["ctx_tokens_budget"] === "number" &&
31
28
  typeof o["decisions_in_scope"] === "number" &&
32
29
  typeof o["invariants_in_scope"] === "number" &&
33
30
  isTaskState(o["task_state"]) &&
31
+ isStringOrNull(o["task_id"]) &&
34
32
  isStringOrNull(o["task_module"]) &&
35
33
  typeof o["gc_running"] === "boolean" &&
36
34
  typeof o["attention_count"] === "number" &&
35
+ typeof o["bypass_count"] === "number" &&
37
36
  isLastRunResult(o["last_run_result"]) &&
38
37
  isStringOrNull(o["last_run_at"]));
39
38
  }
39
+ /**
40
+ * Ground-state fallback when no per-session status.json is available.
41
+ * Counts pending drafts from `_inbox/`; renders `⬡ cairn ⚑ N drafts` or
42
+ * just `⬡ cairn`. Returns empty string when `.cairn/` is absent.
43
+ *
44
+ * Ctx meter is appended when supplied — operator-side dropdown stays
45
+ * informative even when the session hook hasn't written status yet.
46
+ */
47
+ function groundStateFallback(repoRoot, ctx) {
48
+ const cairnDir = join(repoRoot, ".cairn");
49
+ if (!existsSync(cairnDir))
50
+ return "";
51
+ let drafts = 0;
52
+ const inboxDir = join(cairnDir, "ground", "decisions", "_inbox");
53
+ if (existsSync(inboxDir)) {
54
+ try {
55
+ drafts = readdirSync(inboxDir, { encoding: "utf8" }).filter((f) => f.endsWith(".draft.md")).length;
56
+ }
57
+ catch {
58
+ drafts = 0;
59
+ }
60
+ }
61
+ const parts = ["⬡ cairn"];
62
+ if (drafts > 0) {
63
+ const noun = drafts === 1 ? "draft" : "drafts";
64
+ parts.push(`⚑ ${drafts} ${noun}`);
65
+ }
66
+ if (ctx)
67
+ parts.push(renderCtxMeter(ctx));
68
+ return parts.join(" ");
69
+ }
40
70
  /**
41
71
  * Render the current status-line string for a session inside the
42
72
  * adopted repo at `repoRoot`. `sessionId` is the Claude Code session id
43
- * (passed via the status-line hook's stdin payload).
73
+ * (passed via the status-line hook's stdin payload). `ctx` is the
74
+ * decoded `context_window` block from the same payload.
75
+ *
76
+ * Falls back to ground-state summary when:
77
+ * - `sessionId` is null/empty
78
+ * - the per-session status.json is missing, unreadable, or malformed
44
79
  *
45
- * Returns the placeholder `⬡ cairn daemon:down ○` when:
46
- * - `sessionId` is null/empty (status-line invoked outside a session)
47
- * - the per-session status.json is missing
48
- * - the file is unreadable, malformed JSON, or fails shape validation
80
+ * Returns empty string when `.cairn/` doesn't exist (cairn not adopted).
49
81
  *
50
82
  * Hot path — invoked on every Claude Code prompt. Keep this cheap.
51
83
  */
52
- export function readStatusForCLI(repoRoot, sessionId) {
84
+ export function readStatusForCLI(repoRoot, sessionId, ctx) {
53
85
  if (sessionId === null || sessionId.length === 0)
54
- return PLACEHOLDER;
86
+ return groundStateFallback(repoRoot, ctx);
55
87
  const filePath = statusJsonPath(repoRoot, sessionId);
56
88
  if (!existsSync(filePath))
57
- return PLACEHOLDER;
89
+ return groundStateFallback(repoRoot, ctx);
58
90
  let raw;
59
91
  try {
60
92
  raw = readFileSync(filePath, "utf8");
61
93
  }
62
94
  catch {
63
- return PLACEHOLDER;
95
+ return groundStateFallback(repoRoot, ctx);
64
96
  }
65
97
  let parsed;
66
98
  try {
67
99
  parsed = JSON.parse(raw);
68
100
  }
69
101
  catch {
70
- return PLACEHOLDER;
102
+ return groundStateFallback(repoRoot, ctx);
71
103
  }
72
104
  if (!isStatusJson(parsed))
73
- return PLACEHOLDER;
74
- return formatStatus(parsed);
105
+ return groundStateFallback(repoRoot, ctx);
106
+ return formatStatus(parsed, ctx);
75
107
  }
76
108
  //# sourceMappingURL=reader.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"reader.js","sourceRoot":"","sources":["../../src/status-line/reader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,WAAW,GAAG,yBAAyB,CAAC;AAE9C,MAAM,WAAW,GAAyB;IACxC,MAAM;IACN,SAAS;IACT,QAAQ;IACR,YAAY;IACZ,SAAS;IACT,WAAW;IACX,UAAU;CACX,CAAC;AAEF,SAAS,WAAW,CAAC,CAAU;IAC7B,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAK,WAAiC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACjF,CAAC;AAED,SAAS,cAAc,CAAC,CAAU;IAChC,OAAO,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ,CAAC;AAC7C,CAAC;AAED,SAAS,eAAe,CAAC,CAAU;IACjC,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,WAAW,IAAI,CAAC,KAAK,QAAQ,CAAC;AAC3D,CAAC;AAED,SAAS,YAAY,CAAC,CAAU;IAC9B,IAAI,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACtD,MAAM,CAAC,GAAG,CAA4B,CAAC;IACvC,OAAO,CACL,OAAO,CAAC,CAAC,YAAY,CAAC,KAAK,QAAQ;QACnC,OAAO,CAAC,CAAC,cAAc,CAAC,KAAK,SAAS;QACtC,OAAO,CAAC,CAAC,iBAAiB,CAAC,KAAK,QAAQ;QACxC,OAAO,CAAC,CAAC,mBAAmB,CAAC,KAAK,QAAQ;QAC1C,OAAO,CAAC,CAAC,oBAAoB,CAAC,KAAK,QAAQ;QAC3C,OAAO,CAAC,CAAC,qBAAqB,CAAC,KAAK,QAAQ;QAC5C,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;QAC5B,cAAc,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;QAChC,OAAO,CAAC,CAAC,YAAY,CAAC,KAAK,SAAS;QACpC,OAAO,CAAC,CAAC,iBAAiB,CAAC,KAAK,QAAQ;QACxC,eAAe,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC;QACrC,cAAc,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CACjC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAgB,EAAE,SAAwB;IACzE,IAAI,SAAS,KAAK,IAAI,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,WAAW,CAAC;IACrE,MAAM,QAAQ,GAAG,cAAc,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IACrD,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,WAAW,CAAC;IAE9C,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;QAAE,OAAO,WAAW,CAAC;IAE9C,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC;AAC9B,CAAC"}
1
+ {"version":3,"file":"reader.js","sourceRoot":"","sources":["../../src/status-line/reader.ts"],"names":[],"mappings":"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"}
@@ -12,6 +12,11 @@ export declare function statusJsonPath(repoRoot: string, sessionId: string): str
12
12
  * the pretty-printed result back. Creates the per-session directory if
13
13
  * missing.
14
14
  *
15
+ * Refuses to write when the repo's `.cairn/` directory is missing — a
16
+ * caller that forgot to gate on `resolveRepoRoot` would otherwise
17
+ * `mkdir -p` a phantom `.cairn/sessions/` tree in a non-adopted
18
+ * project.
19
+ *
15
20
  * Best-effort write; no atomic-rename ceremony. The status file is
16
21
  * cosmetic — torn writes self-heal on the next hook tick.
17
22
  */
@@ -21,13 +26,5 @@ export declare function writeStatusJson(repoRoot: string, sessionId: string, pat
21
26
  * Subsequent patches (heartbeat updated_at, attention_count, etc.)
22
27
  * merge over this baseline so the shape-validating reader always sees
23
28
  * a complete object.
24
- *
25
- * `ctx_tokens_budget` defaults to 4000 — the SessionStart
26
- * additionalContext cap (Section 0–7 budget). Hooks may overwrite once
27
- * a tighter per-session value is computed.
28
- *
29
- * `daemon_alive` is retained on the wire for status-line format
30
- * back-compat; the daemon itself is dormant. SessionStart writes
31
- * `true` to indicate the session is live.
32
29
  */
33
- export declare function defaultStatusJson(sessionAlive: boolean): StatusJson;
30
+ export declare function defaultStatusJson(): StatusJson;
@@ -16,10 +16,17 @@ export function statusJsonPath(repoRoot, sessionId) {
16
16
  * the pretty-printed result back. Creates the per-session directory if
17
17
  * missing.
18
18
  *
19
+ * Refuses to write when the repo's `.cairn/` directory is missing — a
20
+ * caller that forgot to gate on `resolveRepoRoot` would otherwise
21
+ * `mkdir -p` a phantom `.cairn/sessions/` tree in a non-adopted
22
+ * project.
23
+ *
19
24
  * Best-effort write; no atomic-rename ceremony. The status file is
20
25
  * cosmetic — torn writes self-heal on the next hook tick.
21
26
  */
22
27
  export function writeStatusJson(repoRoot, sessionId, patch) {
28
+ if (!existsSync(join(repoRoot, ".cairn")))
29
+ return;
23
30
  const stateDir = sessionStateDir(repoRoot, sessionId);
24
31
  const filePath = join(stateDir, "status.json");
25
32
  let existing = {};
@@ -44,27 +51,18 @@ export function writeStatusJson(repoRoot, sessionId, patch) {
44
51
  * Subsequent patches (heartbeat updated_at, attention_count, etc.)
45
52
  * merge over this baseline so the shape-validating reader always sees
46
53
  * a complete object.
47
- *
48
- * `ctx_tokens_budget` defaults to 4000 — the SessionStart
49
- * additionalContext cap (Section 0–7 budget). Hooks may overwrite once
50
- * a tighter per-session value is computed.
51
- *
52
- * `daemon_alive` is retained on the wire for status-line format
53
- * back-compat; the daemon itself is dormant. SessionStart writes
54
- * `true` to indicate the session is live.
55
54
  */
56
- export function defaultStatusJson(sessionAlive) {
55
+ export function defaultStatusJson() {
57
56
  return {
58
57
  updated_at: new Date().toISOString(),
59
- daemon_alive: sessionAlive,
60
- ctx_tokens_used: 0,
61
- ctx_tokens_budget: 4000,
62
58
  decisions_in_scope: 0,
63
59
  invariants_in_scope: 0,
64
60
  task_state: "idle",
61
+ task_id: null,
65
62
  task_module: null,
66
63
  gc_running: false,
67
64
  attention_count: 0,
65
+ bypass_count: 0,
68
66
  last_run_result: null,
69
67
  last_run_at: null,
70
68
  };
@@ -1 +1 @@
1
- {"version":3,"file":"writer.js","sourceRoot":"","sources":["../../src/status-line/writer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGpD;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB,EAAE,SAAiB;IAChE,OAAO,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,SAAS,CAAC,EAAE,aAAa,CAAC,CAAC;AACnE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAC7B,QAAgB,EAChB,SAAiB,EACjB,KAA0B;IAE1B,MAAM,QAAQ,GAAG,eAAe,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IACtD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;IAE/C,IAAI,QAAQ,GAAwB,EAAE,CAAC;IACvC,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAY,CAAC;YAC1C,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;gBAClD,QAAQ,GAAG,MAA6B,CAAC;YAC3C,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,QAAQ,GAAG,EAAE,CAAC;QAChB,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAwB,EAAE,GAAG,QAAQ,EAAE,GAAG,KAAK,EAAE,CAAC;IAE9D,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,aAAa,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAC1E,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,iBAAiB,CAAC,YAAqB;IACrD,OAAO;QACL,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACpC,YAAY,EAAE,YAAY;QAC1B,eAAe,EAAE,CAAC;QAClB,iBAAiB,EAAE,IAAI;QACvB,kBAAkB,EAAE,CAAC;QACrB,mBAAmB,EAAE,CAAC;QACtB,UAAU,EAAE,MAAM;QAClB,WAAW,EAAE,IAAI;QACjB,UAAU,EAAE,KAAK;QACjB,eAAe,EAAE,CAAC;QAClB,eAAe,EAAE,IAAI;QACrB,WAAW,EAAE,IAAI;KAClB,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"writer.js","sourceRoot":"","sources":["../../src/status-line/writer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGpD;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB,EAAE,SAAiB;IAChE,OAAO,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,SAAS,CAAC,EAAE,aAAa,CAAC,CAAC;AACnE,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,eAAe,CAC7B,QAAgB,EAChB,SAAiB,EACjB,KAA0B;IAE1B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAAE,OAAO;IAElD,MAAM,QAAQ,GAAG,eAAe,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IACtD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;IAE/C,IAAI,QAAQ,GAAwB,EAAE,CAAC;IACvC,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAY,CAAC;YAC1C,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;gBAClD,QAAQ,GAAG,MAA6B,CAAC;YAC3C,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,QAAQ,GAAG,EAAE,CAAC;QAChB,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAwB,EAAE,GAAG,QAAQ,EAAE,GAAG,KAAK,EAAE,CAAC;IAE9D,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,aAAa,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAC1E,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO;QACL,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACpC,kBAAkB,EAAE,CAAC;QACrB,mBAAmB,EAAE,CAAC;QACtB,UAAU,EAAE,MAAM;QAClB,OAAO,EAAE,IAAI;QACb,WAAW,EAAE,IAAI;QACjB,UAAU,EAAE,KAAK;QACjB,eAAe,EAAE,CAAC;QAClB,YAAY,EAAE,CAAC;QACf,eAAe,EAAE,IAAI;QACrB,WAAW,EAAE,IAAI;KAClB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Unified trace log for live-session debugging.
3
+ *
4
+ * Every cairn surface (Claude Code hooks, MCP tools, `claude --print`
5
+ * subprocess calls, init phases) appends a single jsonl row per event
6
+ * to `~/.local/cairn/trace/trace-<YYYY-MM-DD>.jsonl`. The `cairn trace`
7
+ * CLI subcommand reads them back time-sorted across the most recent
8
+ * day(s) so the operator can post-mortem an entire live session in one
9
+ * pane.
10
+ *
11
+ * Best-effort: trace failures NEVER throw — debug logging that breaks
12
+ * the surface it's monitoring is worse than no logging.
13
+ */
14
+ export type TraceSource = "hook" | "mcp" | "claude" | "init-phase" | "subagent";
15
+ export interface TraceEvent {
16
+ /** ISO 8601 with millisecond precision. */
17
+ ts: string;
18
+ /** Top-level surface emitting the event. */
19
+ source: TraceSource;
20
+ /** Event-specific kind ("session-start", "tool-call", "claude-request", …). */
21
+ kind: string;
22
+ /** Adopted-repo root, when known. */
23
+ repo_root: string | null;
24
+ /** Claude Code session id, when known. */
25
+ session_id: string | null;
26
+ /** Wall time spent, when applicable. */
27
+ duration_ms?: number;
28
+ /** Success / failure outcome, when applicable. */
29
+ ok?: boolean;
30
+ /** Free-form payload — keep small; large bodies should be stored separately. */
31
+ payload: Record<string, unknown>;
32
+ }
33
+ export declare function traceDir(): string;
34
+ export declare function traceFilePath(now?: Date): string;
35
+ /**
36
+ * Append one trace row. Best-effort — swallows any IO error so callers
37
+ * never break their primary surface on trace-write failure.
38
+ */
39
+ export declare function appendTrace(event: TraceEvent): void;
40
+ /**
41
+ * Build a TraceEvent with `ts` set to now. Convenience for callsites
42
+ * that build the rest of the row inline.
43
+ */
44
+ export declare function nowEvent(args: Omit<TraceEvent, "ts">): TraceEvent;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Unified trace log for live-session debugging.
3
+ *
4
+ * Every cairn surface (Claude Code hooks, MCP tools, `claude --print`
5
+ * subprocess calls, init phases) appends a single jsonl row per event
6
+ * to `~/.local/cairn/trace/trace-<YYYY-MM-DD>.jsonl`. The `cairn trace`
7
+ * CLI subcommand reads them back time-sorted across the most recent
8
+ * day(s) so the operator can post-mortem an entire live session in one
9
+ * pane.
10
+ *
11
+ * Best-effort: trace failures NEVER throw — debug logging that breaks
12
+ * the surface it's monitoring is worse than no logging.
13
+ */
14
+ import { appendFileSync, existsSync, mkdirSync } from "node:fs";
15
+ import { homedir } from "node:os";
16
+ import { join } from "node:path";
17
+ export function traceDir() {
18
+ return join(homedir(), ".local", "cairn", "trace");
19
+ }
20
+ function todayFilename(now) {
21
+ const y = now.getUTCFullYear();
22
+ const m = String(now.getUTCMonth() + 1).padStart(2, "0");
23
+ const d = String(now.getUTCDate()).padStart(2, "0");
24
+ return `trace-${y}-${m}-${d}.jsonl`;
25
+ }
26
+ export function traceFilePath(now = new Date()) {
27
+ return join(traceDir(), todayFilename(now));
28
+ }
29
+ /**
30
+ * Append one trace row. Best-effort — swallows any IO error so callers
31
+ * never break their primary surface on trace-write failure.
32
+ */
33
+ export function appendTrace(event) {
34
+ try {
35
+ const dir = traceDir();
36
+ if (!existsSync(dir))
37
+ mkdirSync(dir, { recursive: true });
38
+ appendFileSync(traceFilePath(), `${JSON.stringify(event)}\n`, "utf8");
39
+ }
40
+ catch {
41
+ // best-effort
42
+ }
43
+ }
44
+ /**
45
+ * Build a TraceEvent with `ts` set to now. Convenience for callsites
46
+ * that build the rest of the row inline.
47
+ */
48
+ export function nowEvent(args) {
49
+ return { ts: new Date().toISOString(), ...args };
50
+ }
51
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/trace/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAuBjC,MAAM,UAAU,QAAQ;IACtB,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AACrD,CAAC;AAED,SAAS,aAAa,CAAC,GAAS;IAC9B,MAAM,CAAC,GAAG,GAAG,CAAC,cAAc,EAAE,CAAC;IAC/B,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACzD,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACpD,OAAO,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAY,IAAI,IAAI,EAAE;IAClD,OAAO,IAAI,CAAC,QAAQ,EAAE,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC;AAC9C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,KAAiB;IAC3C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,QAAQ,EAAE,CAAC;QACvB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1D,cAAc,CAAC,aAAa,EAAE,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACxE,CAAC;IAAC,MAAM,CAAC;QACP,cAAc;IAChB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,IAA4B;IACnD,OAAO,EAAE,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,GAAG,IAAI,EAAE,CAAC;AACnD,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@isaacriehm/cairn-core",
3
- "version": "0.1.10",
4
- "description": "Cairn core — state + context layer. Curated `.cairn/ground/` (decisions, §V invariants, canonical-map, brand, quality-grades), MCP server, init wizard, hook runners, sensors, GC drift sweep.",
3
+ "version": "0.3.0",
4
+ "description": "Cairn core — state + context layer. Curated `.cairn/ground/` (decisions, §INV invariants, canonical-map, brand, quality-grades), MCP server, init wizard, hook runners, sensors, GC drift sweep.",
5
5
  "author": "Isaac Riehm",
6
6
  "license": "MIT",
7
7
  "homepage": "https://github.com/isaacriehm/cairn",
@@ -43,7 +43,6 @@
43
43
  "devDependencies": {
44
44
  "@types/cli-progress": "^3.11.6",
45
45
  "@types/node": "^25.6.0",
46
- "tsx": "^4.21.0",
47
46
  "typescript": "^6.0.3"
48
47
  },
49
48
  "scripts": {