@cstart/coldstart 2.0.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 (360) hide show
  1. package/README.md +236 -0
  2. package/dist/cache/disk-cache.d.ts +14 -0
  3. package/dist/cache/disk-cache.d.ts.map +1 -0
  4. package/dist/cache/disk-cache.js +371 -0
  5. package/dist/cache/disk-cache.js.map +1 -0
  6. package/dist/cli.d.ts +18 -0
  7. package/dist/cli.d.ts.map +1 -0
  8. package/dist/cli.js +206 -0
  9. package/dist/cli.js.map +1 -0
  10. package/dist/constants.d.ts +8 -0
  11. package/dist/constants.d.ts.map +1 -0
  12. package/dist/constants.js +111 -0
  13. package/dist/constants.js.map +1 -0
  14. package/dist/daemon-lock.d.ts +63 -0
  15. package/dist/daemon-lock.d.ts.map +1 -0
  16. package/dist/daemon-lock.js +218 -0
  17. package/dist/daemon-lock.js.map +1 -0
  18. package/dist/daemon-log.d.ts +26 -0
  19. package/dist/daemon-log.d.ts.map +1 -0
  20. package/dist/daemon-log.js +110 -0
  21. package/dist/daemon-log.js.map +1 -0
  22. package/dist/index-manager.d.ts +103 -0
  23. package/dist/index-manager.d.ts.map +1 -0
  24. package/dist/index-manager.js +361 -0
  25. package/dist/index-manager.js.map +1 -0
  26. package/dist/index.d.ts +4 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +724 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/indexer/content-tokens.d.ts +74 -0
  31. package/dist/indexer/content-tokens.d.ts.map +1 -0
  32. package/dist/indexer/content-tokens.js +406 -0
  33. package/dist/indexer/content-tokens.js.map +1 -0
  34. package/dist/indexer/cpp-include-roots.d.ts +7 -0
  35. package/dist/indexer/cpp-include-roots.d.ts.map +1 -0
  36. package/dist/indexer/cpp-include-roots.js +166 -0
  37. package/dist/indexer/cpp-include-roots.js.map +1 -0
  38. package/dist/indexer/csharp-synthetic.d.ts +9 -0
  39. package/dist/indexer/csharp-synthetic.d.ts.map +1 -0
  40. package/dist/indexer/csharp-synthetic.js +51 -0
  41. package/dist/indexer/csharp-synthetic.js.map +1 -0
  42. package/dist/indexer/django-synthetic.d.ts +12 -0
  43. package/dist/indexer/django-synthetic.d.ts.map +1 -0
  44. package/dist/indexer/django-synthetic.js +49 -0
  45. package/dist/indexer/django-synthetic.js.map +1 -0
  46. package/dist/indexer/extractors/angularjs.d.ts +16 -0
  47. package/dist/indexer/extractors/angularjs.d.ts.map +1 -0
  48. package/dist/indexer/extractors/angularjs.js +49 -0
  49. package/dist/indexer/extractors/angularjs.js.map +1 -0
  50. package/dist/indexer/extractors/cpp.d.ts +9 -0
  51. package/dist/indexer/extractors/cpp.d.ts.map +1 -0
  52. package/dist/indexer/extractors/cpp.js +254 -0
  53. package/dist/indexer/extractors/cpp.js.map +1 -0
  54. package/dist/indexer/extractors/csharp.d.ts +19 -0
  55. package/dist/indexer/extractors/csharp.d.ts.map +1 -0
  56. package/dist/indexer/extractors/csharp.js +327 -0
  57. package/dist/indexer/extractors/csharp.js.map +1 -0
  58. package/dist/indexer/extractors/env.d.ts +9 -0
  59. package/dist/indexer/extractors/env.d.ts.map +1 -0
  60. package/dist/indexer/extractors/env.js +43 -0
  61. package/dist/indexer/extractors/env.js.map +1 -0
  62. package/dist/indexer/extractors/go.d.ts +9 -0
  63. package/dist/indexer/extractors/go.d.ts.map +1 -0
  64. package/dist/indexer/extractors/go.js +227 -0
  65. package/dist/indexer/extractors/go.js.map +1 -0
  66. package/dist/indexer/extractors/graphql.d.ts +22 -0
  67. package/dist/indexer/extractors/graphql.d.ts.map +1 -0
  68. package/dist/indexer/extractors/graphql.js +88 -0
  69. package/dist/indexer/extractors/graphql.js.map +1 -0
  70. package/dist/indexer/extractors/groovy.d.ts +9 -0
  71. package/dist/indexer/extractors/groovy.d.ts.map +1 -0
  72. package/dist/indexer/extractors/groovy.js +356 -0
  73. package/dist/indexer/extractors/groovy.js.map +1 -0
  74. package/dist/indexer/extractors/java.d.ts +10 -0
  75. package/dist/indexer/extractors/java.d.ts.map +1 -0
  76. package/dist/indexer/extractors/java.js +586 -0
  77. package/dist/indexer/extractors/java.js.map +1 -0
  78. package/dist/indexer/extractors/kotlin.d.ts +10 -0
  79. package/dist/indexer/extractors/kotlin.d.ts.map +1 -0
  80. package/dist/indexer/extractors/kotlin.js +398 -0
  81. package/dist/indexer/extractors/kotlin.js.map +1 -0
  82. package/dist/indexer/extractors/node-helpers.d.ts +13 -0
  83. package/dist/indexer/extractors/node-helpers.d.ts.map +1 -0
  84. package/dist/indexer/extractors/node-helpers.js +17 -0
  85. package/dist/indexer/extractors/node-helpers.js.map +1 -0
  86. package/dist/indexer/extractors/parser-factory.d.ts +4 -0
  87. package/dist/indexer/extractors/parser-factory.d.ts.map +1 -0
  88. package/dist/indexer/extractors/parser-factory.js +28 -0
  89. package/dist/indexer/extractors/parser-factory.js.map +1 -0
  90. package/dist/indexer/extractors/php.d.ts +17 -0
  91. package/dist/indexer/extractors/php.d.ts.map +1 -0
  92. package/dist/indexer/extractors/php.js +363 -0
  93. package/dist/indexer/extractors/php.js.map +1 -0
  94. package/dist/indexer/extractors/python.d.ts +14 -0
  95. package/dist/indexer/extractors/python.d.ts.map +1 -0
  96. package/dist/indexer/extractors/python.js +449 -0
  97. package/dist/indexer/extractors/python.js.map +1 -0
  98. package/dist/indexer/extractors/ruby.d.ts +10 -0
  99. package/dist/indexer/extractors/ruby.d.ts.map +1 -0
  100. package/dist/indexer/extractors/ruby.js +996 -0
  101. package/dist/indexer/extractors/ruby.js.map +1 -0
  102. package/dist/indexer/extractors/rust.d.ts +9 -0
  103. package/dist/indexer/extractors/rust.d.ts.map +1 -0
  104. package/dist/indexer/extractors/rust.js +322 -0
  105. package/dist/indexer/extractors/rust.js.map +1 -0
  106. package/dist/indexer/extractors/toml.d.ts +9 -0
  107. package/dist/indexer/extractors/toml.d.ts.map +1 -0
  108. package/dist/indexer/extractors/toml.js +84 -0
  109. package/dist/indexer/extractors/toml.js.map +1 -0
  110. package/dist/indexer/extractors/xml.d.ts +9 -0
  111. package/dist/indexer/extractors/xml.d.ts.map +1 -0
  112. package/dist/indexer/extractors/xml.js +163 -0
  113. package/dist/indexer/extractors/xml.js.map +1 -0
  114. package/dist/indexer/extractors/yaml.d.ts +9 -0
  115. package/dist/indexer/extractors/yaml.d.ts.map +1 -0
  116. package/dist/indexer/extractors/yaml.js +117 -0
  117. package/dist/indexer/extractors/yaml.js.map +1 -0
  118. package/dist/indexer/git.d.ts +19 -0
  119. package/dist/indexer/git.d.ts.map +1 -0
  120. package/dist/indexer/git.js +55 -0
  121. package/dist/indexer/git.js.map +1 -0
  122. package/dist/indexer/graph.d.ts +7 -0
  123. package/dist/indexer/graph.d.ts.map +1 -0
  124. package/dist/indexer/graph.js +20 -0
  125. package/dist/indexer/graph.js.map +1 -0
  126. package/dist/indexer/indexed-file.d.ts +15 -0
  127. package/dist/indexer/indexed-file.d.ts.map +1 -0
  128. package/dist/indexer/indexed-file.js +50 -0
  129. package/dist/indexer/indexed-file.js.map +1 -0
  130. package/dist/indexer/invariants.d.ts +15 -0
  131. package/dist/indexer/invariants.d.ts.map +1 -0
  132. package/dist/indexer/invariants.js +96 -0
  133. package/dist/indexer/invariants.js.map +1 -0
  134. package/dist/indexer/laravel-synthetic.d.ts +10 -0
  135. package/dist/indexer/laravel-synthetic.d.ts.map +1 -0
  136. package/dist/indexer/laravel-synthetic.js +78 -0
  137. package/dist/indexer/laravel-synthetic.js.map +1 -0
  138. package/dist/indexer/parser.d.ts +4 -0
  139. package/dist/indexer/parser.d.ts.map +1 -0
  140. package/dist/indexer/parser.js +499 -0
  141. package/dist/indexer/parser.js.map +1 -0
  142. package/dist/indexer/patch.d.ts +3 -0
  143. package/dist/indexer/patch.d.ts.map +1 -0
  144. package/dist/indexer/patch.js +291 -0
  145. package/dist/indexer/patch.js.map +1 -0
  146. package/dist/indexer/rails-synthetic.d.ts +11 -0
  147. package/dist/indexer/rails-synthetic.d.ts.map +1 -0
  148. package/dist/indexer/rails-synthetic.js +80 -0
  149. package/dist/indexer/rails-synthetic.js.map +1 -0
  150. package/dist/indexer/reconcile.d.ts +9 -0
  151. package/dist/indexer/reconcile.d.ts.map +1 -0
  152. package/dist/indexer/reconcile.js +96 -0
  153. package/dist/indexer/reconcile.js.map +1 -0
  154. package/dist/indexer/resolvers/cpp.d.ts +15 -0
  155. package/dist/indexer/resolvers/cpp.d.ts.map +1 -0
  156. package/dist/indexer/resolvers/cpp.js +35 -0
  157. package/dist/indexer/resolvers/cpp.js.map +1 -0
  158. package/dist/indexer/resolvers/csharp.d.ts +2 -0
  159. package/dist/indexer/resolvers/csharp.d.ts.map +1 -0
  160. package/dist/indexer/resolvers/csharp.js +89 -0
  161. package/dist/indexer/resolvers/csharp.js.map +1 -0
  162. package/dist/indexer/resolvers/generic.d.ts +10 -0
  163. package/dist/indexer/resolvers/generic.d.ts.map +1 -0
  164. package/dist/indexer/resolvers/generic.js +35 -0
  165. package/dist/indexer/resolvers/generic.js.map +1 -0
  166. package/dist/indexer/resolvers/go.d.ts +2 -0
  167. package/dist/indexer/resolvers/go.d.ts.map +1 -0
  168. package/dist/indexer/resolvers/go.js +171 -0
  169. package/dist/indexer/resolvers/go.js.map +1 -0
  170. package/dist/indexer/resolvers/index.d.ts +26 -0
  171. package/dist/indexer/resolvers/index.d.ts.map +1 -0
  172. package/dist/indexer/resolvers/index.js +301 -0
  173. package/dist/indexer/resolvers/index.js.map +1 -0
  174. package/dist/indexer/resolvers/java.d.ts +17 -0
  175. package/dist/indexer/resolvers/java.d.ts.map +1 -0
  176. package/dist/indexer/resolvers/java.js +104 -0
  177. package/dist/indexer/resolvers/java.js.map +1 -0
  178. package/dist/indexer/resolvers/php.d.ts +2 -0
  179. package/dist/indexer/resolvers/php.d.ts.map +1 -0
  180. package/dist/indexer/resolvers/php.js +108 -0
  181. package/dist/indexer/resolvers/php.js.map +1 -0
  182. package/dist/indexer/resolvers/python.d.ts +17 -0
  183. package/dist/indexer/resolvers/python.d.ts.map +1 -0
  184. package/dist/indexer/resolvers/python.js +63 -0
  185. package/dist/indexer/resolvers/python.js.map +1 -0
  186. package/dist/indexer/resolvers/ruby.d.ts +13 -0
  187. package/dist/indexer/resolvers/ruby.d.ts.map +1 -0
  188. package/dist/indexer/resolvers/ruby.js +199 -0
  189. package/dist/indexer/resolvers/ruby.js.map +1 -0
  190. package/dist/indexer/resolvers/rust.d.ts +12 -0
  191. package/dist/indexer/resolvers/rust.d.ts.map +1 -0
  192. package/dist/indexer/resolvers/rust.js +61 -0
  193. package/dist/indexer/resolvers/rust.js.map +1 -0
  194. package/dist/indexer/resolvers/shared.d.ts +18 -0
  195. package/dist/indexer/resolvers/shared.d.ts.map +1 -0
  196. package/dist/indexer/resolvers/shared.js +71 -0
  197. package/dist/indexer/resolvers/shared.js.map +1 -0
  198. package/dist/indexer/rust-workspace.d.ts +25 -0
  199. package/dist/indexer/rust-workspace.d.ts.map +1 -0
  200. package/dist/indexer/rust-workspace.js +155 -0
  201. package/dist/indexer/rust-workspace.js.map +1 -0
  202. package/dist/indexer/symbol-edges.d.ts +19 -0
  203. package/dist/indexer/symbol-edges.d.ts.map +1 -0
  204. package/dist/indexer/symbol-edges.js +117 -0
  205. package/dist/indexer/symbol-edges.js.map +1 -0
  206. package/dist/indexer/tokenize.d.ts +26 -0
  207. package/dist/indexer/tokenize.d.ts.map +1 -0
  208. package/dist/indexer/tokenize.js +200 -0
  209. package/dist/indexer/tokenize.js.map +1 -0
  210. package/dist/indexer/ts-parser.d.ts +10 -0
  211. package/dist/indexer/ts-parser.d.ts.map +1 -0
  212. package/dist/indexer/ts-parser.js +605 -0
  213. package/dist/indexer/ts-parser.js.map +1 -0
  214. package/dist/indexer/walker.d.ts +9 -0
  215. package/dist/indexer/walker.d.ts.map +1 -0
  216. package/dist/indexer/walker.js +91 -0
  217. package/dist/indexer/walker.js.map +1 -0
  218. package/dist/init.d.ts +111 -0
  219. package/dist/init.d.ts.map +1 -0
  220. package/dist/init.js +787 -0
  221. package/dist/init.js.map +1 -0
  222. package/dist/kb/cli.d.ts +2 -0
  223. package/dist/kb/cli.d.ts.map +1 -0
  224. package/dist/kb/cli.js +377 -0
  225. package/dist/kb/cli.js.map +1 -0
  226. package/dist/kb/commit.d.ts +6 -0
  227. package/dist/kb/commit.d.ts.map +1 -0
  228. package/dist/kb/commit.js +84 -0
  229. package/dist/kb/commit.js.map +1 -0
  230. package/dist/kb/fold.d.ts +42 -0
  231. package/dist/kb/fold.d.ts.map +1 -0
  232. package/dist/kb/fold.js +285 -0
  233. package/dist/kb/fold.js.map +1 -0
  234. package/dist/kb/freshness.d.ts +9 -0
  235. package/dist/kb/freshness.d.ts.map +1 -0
  236. package/dist/kb/freshness.js +52 -0
  237. package/dist/kb/freshness.js.map +1 -0
  238. package/dist/kb/git.d.ts +4 -0
  239. package/dist/kb/git.d.ts.map +1 -0
  240. package/dist/kb/git.js +28 -0
  241. package/dist/kb/git.js.map +1 -0
  242. package/dist/kb/ids.d.ts +8 -0
  243. package/dist/kb/ids.d.ts.map +1 -0
  244. package/dist/kb/ids.js +42 -0
  245. package/dist/kb/ids.js.map +1 -0
  246. package/dist/kb/lint.d.ts +23 -0
  247. package/dist/kb/lint.d.ts.map +1 -0
  248. package/dist/kb/lint.js +102 -0
  249. package/dist/kb/lint.js.map +1 -0
  250. package/dist/kb/lookup.d.ts +55 -0
  251. package/dist/kb/lookup.d.ts.map +1 -0
  252. package/dist/kb/lookup.js +92 -0
  253. package/dist/kb/lookup.js.map +1 -0
  254. package/dist/kb/notes-index.d.ts +31 -0
  255. package/dist/kb/notes-index.d.ts.map +1 -0
  256. package/dist/kb/notes-index.js +0 -0
  257. package/dist/kb/notes-index.js.map +1 -0
  258. package/dist/kb/raw-log.d.ts +34 -0
  259. package/dist/kb/raw-log.d.ts.map +1 -0
  260. package/dist/kb/raw-log.js +106 -0
  261. package/dist/kb/raw-log.js.map +1 -0
  262. package/dist/kb/render.d.ts +17 -0
  263. package/dist/kb/render.d.ts.map +1 -0
  264. package/dist/kb/render.js +101 -0
  265. package/dist/kb/render.js.map +1 -0
  266. package/dist/kb/search.d.ts +110 -0
  267. package/dist/kb/search.d.ts.map +1 -0
  268. package/dist/kb/search.js +453 -0
  269. package/dist/kb/search.js.map +1 -0
  270. package/dist/kb/store.d.ts +35 -0
  271. package/dist/kb/store.d.ts.map +1 -0
  272. package/dist/kb/store.js +160 -0
  273. package/dist/kb/store.js.map +1 -0
  274. package/dist/kb/types.d.ts +142 -0
  275. package/dist/kb/types.d.ts.map +1 -0
  276. package/dist/kb/types.js +13 -0
  277. package/dist/kb/types.js.map +1 -0
  278. package/dist/kb/view-template.d.ts +8 -0
  279. package/dist/kb/view-template.d.ts.map +1 -0
  280. package/dist/kb/view-template.js +8 -0
  281. package/dist/kb/view-template.js.map +1 -0
  282. package/dist/kb/view.d.ts +42 -0
  283. package/dist/kb/view.d.ts.map +1 -0
  284. package/dist/kb/view.js +118 -0
  285. package/dist/kb/view.js.map +1 -0
  286. package/dist/kb/write.d.ts +72 -0
  287. package/dist/kb/write.d.ts.map +1 -0
  288. package/dist/kb/write.js +345 -0
  289. package/dist/kb/write.js.map +1 -0
  290. package/dist/keeper-state.d.ts +29 -0
  291. package/dist/keeper-state.d.ts.map +1 -0
  292. package/dist/keeper-state.js +89 -0
  293. package/dist/keeper-state.js.map +1 -0
  294. package/dist/keeper.d.ts +23 -0
  295. package/dist/keeper.d.ts.map +1 -0
  296. package/dist/keeper.js +105 -0
  297. package/dist/keeper.js.map +1 -0
  298. package/dist/migrate.d.ts +9 -0
  299. package/dist/migrate.d.ts.map +1 -0
  300. package/dist/migrate.js +102 -0
  301. package/dist/migrate.js.map +1 -0
  302. package/dist/restart.d.ts +15 -0
  303. package/dist/restart.d.ts.map +1 -0
  304. package/dist/restart.js +48 -0
  305. package/dist/restart.js.map +1 -0
  306. package/dist/server/find.d.ts +39 -0
  307. package/dist/server/find.d.ts.map +1 -0
  308. package/dist/server/find.js +979 -0
  309. package/dist/server/find.js.map +1 -0
  310. package/dist/server/mcp.d.ts +117 -0
  311. package/dist/server/mcp.d.ts.map +1 -0
  312. package/dist/server/mcp.js +301 -0
  313. package/dist/server/mcp.js.map +1 -0
  314. package/dist/server/searcher.d.ts +14 -0
  315. package/dist/server/searcher.d.ts.map +1 -0
  316. package/dist/server/searcher.js +146 -0
  317. package/dist/server/searcher.js.map +1 -0
  318. package/dist/server/tools.d.ts +17 -0
  319. package/dist/server/tools.d.ts.map +1 -0
  320. package/dist/server/tools.js +875 -0
  321. package/dist/server/tools.js.map +1 -0
  322. package/dist/status.d.ts +12 -0
  323. package/dist/status.d.ts.map +1 -0
  324. package/dist/status.js +157 -0
  325. package/dist/status.js.map +1 -0
  326. package/dist/types.d.ts +138 -0
  327. package/dist/types.d.ts.map +1 -0
  328. package/dist/types.js +3 -0
  329. package/dist/types.js.map +1 -0
  330. package/dist/watcher.d.ts +11 -0
  331. package/dist/watcher.d.ts.map +1 -0
  332. package/dist/watcher.js +67 -0
  333. package/dist/watcher.js.map +1 -0
  334. package/hooks/canonical-find-key.mjs +68 -0
  335. package/hooks/codex-find-nudge.mjs +15 -0
  336. package/hooks/codex-find-preguard.mjs +14 -0
  337. package/hooks/codex-kb-elicit.mjs +329 -0
  338. package/hooks/codex-kb-recall.mjs +151 -0
  339. package/hooks/codex-nudge-handler.mjs +370 -0
  340. package/hooks/codex-preguard-handler.mjs +75 -0
  341. package/hooks/codex-run-hook.mjs +132 -0
  342. package/hooks/coldstart-call.mjs +58 -0
  343. package/hooks/cursor-find-nudge.mjs +15 -0
  344. package/hooks/cursor-find-preguard.mjs +14 -0
  345. package/hooks/cursor-input.mjs +72 -0
  346. package/hooks/cursor-kb-elicit.mjs +335 -0
  347. package/hooks/cursor-kb-recall.mjs +138 -0
  348. package/hooks/cursor-nudge-handler.mjs +33 -0
  349. package/hooks/cursor-preguard-handler.mjs +39 -0
  350. package/hooks/cursor-run-hook.mjs +129 -0
  351. package/hooks/find-nudge.mjs +15 -0
  352. package/hooks/find-preguard.mjs +14 -0
  353. package/hooks/kb-elicit.mjs +334 -0
  354. package/hooks/kb-recall.mjs +151 -0
  355. package/hooks/nudge-handler.mjs +370 -0
  356. package/hooks/preguard-handler.mjs +75 -0
  357. package/hooks/run-hook.mjs +132 -0
  358. package/package.json +69 -0
  359. package/templates/coldstart.cli.md +60 -0
  360. package/templates/coldstart.mcp.md +59 -0
@@ -0,0 +1,285 @@
1
+ import { KB_RAW_VERSION } from './raw-log.js';
2
+ const ENVELOPE_KEYS = new Set(['v', 'ts', 'head', 'id', 'type', 'op']);
3
+ const PUT_KEYS = new Set([
4
+ 'title', 'aliases', 'anchors', 'verified', 'summary', 'character', 'facets',
5
+ 'behaviors', 'features', 'steps', 'invariants', 'kind', 'body', 'scope',
6
+ ]);
7
+ const OP_KEYS = new Set(['target', 'by']);
8
+ const NOTE_TYPES = new Set(['file', 'flow', 'lesson']);
9
+ const OPS = new Set(['put', 'retract', 'supersede']);
10
+ const LESSON_KINDS = new Set(['absence']);
11
+ const CHARACTERS = new Set(['hub', 'single']);
12
+ /** Canonical JSON (recursively key-sorted) — the deterministic ts tie-breaker. */
13
+ export function stableStringify(value) {
14
+ if (Array.isArray(value))
15
+ return '[' + value.map(stableStringify).join(',') + ']';
16
+ if (value && typeof value === 'object') {
17
+ const obj = value;
18
+ const keys = Object.keys(obj).sort();
19
+ return '{' + keys.map((k) => JSON.stringify(k) + ':' + stableStringify(obj[k])).join(',') + '}';
20
+ }
21
+ return JSON.stringify(value);
22
+ }
23
+ const isStr = (x) => typeof x === 'string';
24
+ const strArr = (x) => (Array.isArray(x) ? x.filter(isStr) : []);
25
+ export function fold(id, rawRecords) {
26
+ const warnings = [];
27
+ // ---- validate + order -----------------------------------------------------
28
+ const usable = [];
29
+ for (let i = 0; i < rawRecords.length; i++) {
30
+ const rec = rawRecords[i];
31
+ const at = `${id} record ${i + 1}`;
32
+ if (!rec || typeof rec !== 'object' || Array.isArray(rec)) {
33
+ warnings.push(`${at}: not an object — skipped`);
34
+ continue;
35
+ }
36
+ if (typeof rec.v !== 'number') {
37
+ warnings.push(`${at}: missing v — skipped`);
38
+ continue;
39
+ }
40
+ if (rec.v > KB_RAW_VERSION) {
41
+ warnings.push(`${at}: v${rec.v} is from a newer coldstart — skipped (run kb migrate after upgrading)`);
42
+ continue;
43
+ }
44
+ if (!isStr(rec.ts)) {
45
+ warnings.push(`${at}: missing ts — skipped`);
46
+ continue;
47
+ }
48
+ if (!isStr(rec.op) || !OPS.has(rec.op)) {
49
+ warnings.push(`${at}: unknown op ${JSON.stringify(rec.op)} — skipped`);
50
+ continue;
51
+ }
52
+ if (isStr(rec.id) && rec.id !== id) {
53
+ warnings.push(`${at}: id ${rec.id} does not match log ${id} — skipped`);
54
+ continue;
55
+ }
56
+ if (!isStr(rec.type) || !NOTE_TYPES.has(rec.type)) {
57
+ warnings.push(`${at}: unknown type ${JSON.stringify(rec.type)} — skipped`);
58
+ continue;
59
+ }
60
+ usable.push({ ts: rec.ts, key: stableStringify(rec), rec });
61
+ }
62
+ usable.sort((a, b) => (a.ts < b.ts ? -1 : a.ts > b.ts ? 1 : a.key < b.key ? -1 : a.key > b.key ? 1 : 0));
63
+ if (!usable.length)
64
+ return { note: null, warnings };
65
+ // ---- fold state -----------------------------------------------------------
66
+ const type = usable[0].rec.type;
67
+ const note = {
68
+ id, type,
69
+ title: '', aliases: [], anchors: [],
70
+ status: 'active', updated: usable[0].ts, edits: 0,
71
+ facets: [], behaviors: [], features: [], steps: [], invariants: [],
72
+ extra: {},
73
+ };
74
+ for (const { ts, rec } of usable) {
75
+ if (rec.type !== type) {
76
+ warnings.push(`${id}: type changed ${type}→${rec.type} at ${ts} — record skipped (type is immutable)`);
77
+ continue;
78
+ }
79
+ const op = rec.op;
80
+ if (op === 'put')
81
+ applyPut(note, rec, warnings);
82
+ else if (op === 'retract') {
83
+ if (!applyRetract(note, rec, warnings, `${id} @ ${ts}`))
84
+ continue;
85
+ }
86
+ else if (op === 'supersede') {
87
+ if (!isStr(rec.by)) {
88
+ warnings.push(`${id} @ ${ts}: supersede without "by" — skipped`);
89
+ continue;
90
+ }
91
+ note.status = 'superseded';
92
+ note.supersededBy = rec.by;
93
+ }
94
+ note.edits++;
95
+ if (ts > note.updated)
96
+ note.updated = ts;
97
+ }
98
+ if (!note.title) {
99
+ note.title = type === 'file' && note.anchors[0] ? note.anchors[0].path : id;
100
+ }
101
+ return { note, warnings };
102
+ }
103
+ function applyPut(note, rec, warnings) {
104
+ // A put revives a retracted note (agent re-learned it); a supersede is sticky.
105
+ if (note.status === 'retracted') {
106
+ note.status = 'active';
107
+ }
108
+ if (isStr(rec.title) && rec.title.trim()) {
109
+ const incoming = rec.title.trim();
110
+ // A replaced title stays searchable: demote the old one to an alias.
111
+ // (Titles are retrieval keys; --into merges must not erase them.)
112
+ if (note.title && note.title !== incoming && !note.aliases.includes(note.title)) {
113
+ note.aliases.push(note.title);
114
+ }
115
+ note.title = incoming;
116
+ }
117
+ for (const a of strArr(rec.aliases))
118
+ if (!note.aliases.includes(a))
119
+ note.aliases.push(a);
120
+ if (isStr(rec.summary))
121
+ note.summary = rec.summary;
122
+ if (isStr(rec.body))
123
+ note.body = rec.body;
124
+ if (isStr(rec.kind)) {
125
+ if (LESSON_KINDS.has(rec.kind))
126
+ note.kind = rec.kind;
127
+ else
128
+ warnings.push(`${note.id}: unknown lesson kind ${JSON.stringify(rec.kind)} — kept previous`);
129
+ }
130
+ if (isStr(rec.character)) {
131
+ if (CHARACTERS.has(rec.character))
132
+ note.character = rec.character;
133
+ else
134
+ warnings.push(`${note.id}: unknown character ${JSON.stringify(rec.character)} — kept previous`);
135
+ }
136
+ if (isStr(rec.head))
137
+ note.head = rec.head;
138
+ if (rec.scope && typeof rec.scope === 'object') {
139
+ const s = rec.scope;
140
+ note.scope = { terms: strArr(s.terms), ...(Array.isArray(s.globs) ? { globs: strArr(s.globs) } : {}) };
141
+ }
142
+ if (Array.isArray(rec.anchors)) {
143
+ for (const raw of rec.anchors) {
144
+ if (!raw || typeof raw !== 'object' || !isStr(raw.path))
145
+ continue;
146
+ const inc = raw;
147
+ const existing = note.anchors.find((a) => a.path === inc.path);
148
+ if (existing) {
149
+ // Symbols UNION (not replace): concurrent writers each stamp an array
150
+ // built from the note state THEY saw, so replace = last-writer-wins
151
+ // drops the others' symbols. Pruning a stale symbol = retract the
152
+ // anchor, re-put it with the trimmed list.
153
+ if (Array.isArray(inc.symbols)) {
154
+ const merged = existing.symbols ? [...existing.symbols] : [];
155
+ for (const s of strArr(inc.symbols))
156
+ if (!merged.includes(s))
157
+ merged.push(s);
158
+ existing.symbols = merged;
159
+ }
160
+ if (isStr(inc.hash))
161
+ existing.hash = inc.hash; // only verified appends carry a hash
162
+ if (isStr(inc.head))
163
+ existing.head = inc.head;
164
+ }
165
+ else {
166
+ note.anchors.push({
167
+ path: inc.path,
168
+ ...(Array.isArray(inc.symbols) ? { symbols: strArr(inc.symbols) } : {}),
169
+ ...(isStr(inc.hash) ? { hash: inc.hash } : {}),
170
+ ...(isStr(inc.head) ? { head: inc.head } : {}),
171
+ });
172
+ }
173
+ }
174
+ }
175
+ if (Array.isArray(rec.facets)) {
176
+ for (const raw of rec.facets) {
177
+ if (!raw || typeof raw !== 'object')
178
+ continue;
179
+ const f = raw;
180
+ if (!isStr(f.symbol) || !isStr(f.detail))
181
+ continue;
182
+ const existing = note.facets.find((x) => x.symbol === f.symbol);
183
+ const flows = strArr(f.flows);
184
+ if (existing) {
185
+ // Replace the knowledge, keep every flow that ever contributed.
186
+ existing.detail = f.detail;
187
+ for (const fl of flows)
188
+ if (!existing.flows?.includes(fl))
189
+ (existing.flows ??= []).push(fl);
190
+ if (isStr(rec.head))
191
+ existing.head = rec.head;
192
+ }
193
+ else {
194
+ note.facets.push({
195
+ symbol: f.symbol,
196
+ detail: f.detail,
197
+ ...(flows.length ? { flows } : {}),
198
+ ...(isStr(rec.head) ? { head: rec.head } : {}),
199
+ });
200
+ }
201
+ }
202
+ }
203
+ if (Array.isArray(rec.behaviors)) {
204
+ for (const raw of rec.behaviors) {
205
+ if (!raw || typeof raw !== 'object')
206
+ continue;
207
+ const b = raw;
208
+ if (!isStr(b.concept_id) || !isStr(b.detail))
209
+ continue;
210
+ const inc = { concept_id: b.concept_id, detail: b.detail, ...(Array.isArray(b.symbols) ? { symbols: strArr(b.symbols) } : {}) };
211
+ const idx = note.behaviors.findIndex((x) => x.concept_id === inc.concept_id);
212
+ if (idx >= 0)
213
+ note.behaviors[idx] = inc; // replace the matching entry, keep the others
214
+ else
215
+ note.behaviors.push(inc);
216
+ }
217
+ }
218
+ if (Array.isArray(rec.features)) {
219
+ for (const raw of rec.features) {
220
+ if (!raw || typeof raw !== 'object')
221
+ continue;
222
+ const f = raw;
223
+ if (!isStr(f.concept_id))
224
+ continue;
225
+ const existing = note.features.find((x) => x.concept_id === f.concept_id);
226
+ if (existing) {
227
+ if (isStr(f.role))
228
+ existing.role = f.role;
229
+ } // union; later role wins
230
+ else
231
+ note.features.push({ concept_id: f.concept_id, role: isStr(f.role) ? f.role : '' });
232
+ }
233
+ }
234
+ if (Array.isArray(rec.steps)) {
235
+ // Whole-array LWW: an ordered story is replaced, not spliced.
236
+ note.steps = rec.steps
237
+ .filter((s) => !!s && typeof s === 'object' && isStr(s.path) && isStr(s.role))
238
+ .map((s) => ({ path: s.path, role: s.role, ...(Array.isArray(s.symbols) ? { symbols: strArr(s.symbols) } : {}) }));
239
+ }
240
+ for (const inv of strArr(rec.invariants))
241
+ if (!note.invariants.includes(inv))
242
+ note.invariants.push(inv);
243
+ // Tolerant reader: unknown fields ride along, shallow LWW.
244
+ for (const [k, v] of Object.entries(rec)) {
245
+ if (ENVELOPE_KEYS.has(k) || PUT_KEYS.has(k) || OP_KEYS.has(k))
246
+ continue;
247
+ note.extra[k] = v;
248
+ }
249
+ }
250
+ /** Returns false when the retract was skipped (bad target). */
251
+ function applyRetract(note, rec, warnings, at) {
252
+ const target = rec.target;
253
+ if (!target || typeof target !== 'object' || !isStr(target.kind)) {
254
+ warnings.push(`${at}: retract without a valid target — skipped`);
255
+ return false;
256
+ }
257
+ const key = target.key;
258
+ switch (target.kind) {
259
+ case 'behavior':
260
+ note.behaviors = note.behaviors.filter((b) => b.concept_id !== key);
261
+ return true;
262
+ case 'facet':
263
+ note.facets = note.facets.filter((f) => f.symbol !== key);
264
+ return true;
265
+ case 'feature':
266
+ note.features = note.features.filter((f) => f.concept_id !== key);
267
+ return true;
268
+ case 'anchor':
269
+ note.anchors = note.anchors.filter((a) => a.path !== key);
270
+ return true;
271
+ case 'invariant':
272
+ note.invariants = note.invariants.filter((t) => t !== key);
273
+ return true;
274
+ case 'alias':
275
+ note.aliases = note.aliases.filter((t) => t !== key);
276
+ return true;
277
+ case 'note':
278
+ note.status = 'retracted';
279
+ return true;
280
+ default:
281
+ warnings.push(`${at}: unknown retract kind ${JSON.stringify(target.kind)} — skipped`);
282
+ return false;
283
+ }
284
+ }
285
+ //# sourceMappingURL=fold.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fold.js","sourceRoot":"","sources":["../../src/kb/fold.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { Anchor, StampedAnchor } from './types.js';
2
+ /** Hash a repo-relative file's current bytes. Missing/unreadable → "missing"
3
+ * (a note outliving its file is itself a signal). */
4
+ export declare function hashFile(root: string, relPath: string): string;
5
+ /** Compare each anchor's stored (last-verified) hash against the live file, NOW. */
6
+ export declare function stampAnchors(root: string, anchors: Anchor[]): StampedAnchor[];
7
+ /** One human line per anchor, used verbatim by search/status output. */
8
+ export declare function freshnessLine(s: StampedAnchor): string;
9
+ //# sourceMappingURL=freshness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"freshness.d.ts","sourceRoot":"","sources":["../../src/kb/freshness.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAExD;sDACsD;AACtD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAQ9D;AAED,oFAAoF;AACpF,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,aAAa,EAAE,CAS7E;AAED,wEAAwE;AACxE,wBAAgB,aAAa,CAAC,CAAC,EAAE,aAAa,GAAG,MAAM,CAOtD"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Freshness — the hash tripwire. One hash implementation, two call sites:
3
+ * write-time stamping of verified anchors (raw-log.ts) and read-time
4
+ * verification (search/status output).
5
+ *
6
+ * Whole-file raw-byte SHA-256, first 12 hex — never per-symbol. Freshness is
7
+ * computed at read/search time and NEVER rendered into md (it would be
8
+ * stale-at-write). Bias to false-positive staleness: a false alarm is cheap,
9
+ * silent rot is expensive.
10
+ *
11
+ * Absence-note re-runs need the code index and live in search.ts — this module
12
+ * stays index-free.
13
+ */
14
+ import { createHash } from 'node:crypto';
15
+ import { readFileSync } from 'node:fs';
16
+ import { join, isAbsolute } from 'node:path';
17
+ /** Hash a repo-relative file's current bytes. Missing/unreadable → "missing"
18
+ * (a note outliving its file is itself a signal). */
19
+ export function hashFile(root, relPath) {
20
+ try {
21
+ const abs = isAbsolute(relPath) ? relPath : join(root, relPath);
22
+ const buf = readFileSync(abs);
23
+ return 'sha256:' + createHash('sha256').update(buf).digest('hex').slice(0, 12);
24
+ }
25
+ catch {
26
+ return 'missing';
27
+ }
28
+ }
29
+ /** Compare each anchor's stored (last-verified) hash against the live file, NOW. */
30
+ export function stampAnchors(root, anchors) {
31
+ return anchors.map((a) => {
32
+ const live = hashFile(root, a.path);
33
+ let state;
34
+ if (live === 'missing')
35
+ state = 'missing';
36
+ else if (!a.hash || a.hash === 'missing')
37
+ state = a.hash === 'missing' ? 'changed' : 'unverified';
38
+ else
39
+ state = live === a.hash ? 'fresh' : 'changed';
40
+ return { path: a.path, symbols: a.symbols, state, hash: a.hash };
41
+ });
42
+ }
43
+ /** One human line per anchor, used verbatim by search/status output. */
44
+ export function freshnessLine(s) {
45
+ switch (s.state) {
46
+ case 'fresh': return `[fresh] ${s.path}`;
47
+ case 'changed': return `[evidence changed: ${s.path}]`;
48
+ case 'missing': return `[anchor missing: ${s.path}]`;
49
+ case 'unverified': return `[never verified: ${s.path}]`;
50
+ }
51
+ }
52
+ //# sourceMappingURL=freshness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"freshness.js","sourceRoot":"","sources":["../../src/kb/freshness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAG7C;sDACsD;AACtD,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,OAAe;IACpD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAChE,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;QAC9B,OAAO,SAAS,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACjF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,OAAiB;IAC1D,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACvB,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,KAA6B,CAAC;QAClC,IAAI,IAAI,KAAK,SAAS;YAAE,KAAK,GAAG,SAAS,CAAC;aACrC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS;YAAE,KAAK,GAAG,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC;;YAC7F,KAAK,GAAG,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;QACnD,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACnE,CAAC,CAAC,CAAC;AACL,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,aAAa,CAAC,CAAgB;IAC5C,QAAQ,CAAC,CAAC,KAAK,EAAE,CAAC;QAChB,KAAK,OAAO,CAAC,CAAC,OAAO,WAAW,CAAC,CAAC,IAAI,EAAE,CAAC;QACzC,KAAK,SAAS,CAAC,CAAC,OAAO,sBAAsB,CAAC,CAAC,IAAI,GAAG,CAAC;QACvD,KAAK,SAAS,CAAC,CAAC,OAAO,oBAAoB,CAAC,CAAC,IAAI,GAAG,CAAC;QACrD,KAAK,YAAY,CAAC,CAAC,OAAO,oBAAoB,CAAC,CAAC,IAAI,GAAG,CAAC;IAC1D,CAAC;AACH,CAAC"}
@@ -0,0 +1,4 @@
1
+ /** Current HEAD as 12 hex, or undefined when unavailable (non-git repo, no
2
+ * commits yet, no git binary). Never throws. */
3
+ export declare function gitHeadSha(root: string): string | undefined;
4
+ //# sourceMappingURL=git.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/kb/git.ts"],"names":[],"mappings":"AAYA;iDACiD;AACjD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAY3D"}
package/dist/kb/git.js ADDED
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Git provenance for the notebook — freshness = provenance, not verdicts.
3
+ *
4
+ * The append path stamps each record (and its verified anchors) with the repo's
5
+ * HEAD at write time; later readers render "what happened to this path since
6
+ * the note was written" (git log / diffstat) instead of a binary staleness
7
+ * verdict. Everything here is best-effort: no git binary, not a repo, or a
8
+ * repo with no commits all degrade to `undefined`, and the sha tripwire in
9
+ * freshness.ts remains the whole story (also the non-git-repo story).
10
+ */
11
+ import { execFileSync } from 'node:child_process';
12
+ /** Current HEAD as 12 hex, or undefined when unavailable (non-git repo, no
13
+ * commits yet, no git binary). Never throws. */
14
+ export function gitHeadSha(root) {
15
+ try {
16
+ const out = execFileSync('git', ['rev-parse', 'HEAD'], {
17
+ cwd: root,
18
+ encoding: 'utf8',
19
+ stdio: ['ignore', 'pipe', 'ignore'],
20
+ timeout: 3000,
21
+ }).trim();
22
+ return /^[0-9a-f]{40}/.test(out) ? out.slice(0, 12) : undefined;
23
+ }
24
+ catch {
25
+ return undefined;
26
+ }
27
+ }
28
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/kb/git.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD;iDACiD;AACjD,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE;YACrD,GAAG,EAAE,IAAI;YACT,QAAQ,EAAE,MAAM;YAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;YACnC,OAAO,EAAE,IAAI;SACd,CAAC,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAClE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC"}
@@ -0,0 +1,8 @@
1
+ export declare function slugify(s: string): string;
2
+ /** Derived, repeatable, collision-safe id for a file note. */
3
+ export declare function fileNoteId(relPath: string): string;
4
+ /** Coin a fresh flow/lesson id from a title; suffix -2, -3… if taken. */
5
+ export declare function coinId(title: string, existingIds: ReadonlySet<string>): string;
6
+ /** Ids double as `.raw`/md filenames — keep them filesystem- and wikilink-safe. */
7
+ export declare function isValidId(id: string): boolean;
8
+ //# sourceMappingURL=ids.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../../src/kb/ids.ts"],"names":[],"mappings":"AAeA,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAMzC;AAED,8DAA8D;AAC9D,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAIlD;AAED,yEAAyE;AACzE,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,MAAM,CAO9E;AAED,mFAAmF;AACnF,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAE7C"}
package/dist/kb/ids.js ADDED
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Note ids — opaque join keys. Coined once, then only ever reused; never
3
+ * searched, never re-derived (so they cannot rot). Retrieval runs over
4
+ * title/aliases/prose/anchors, not ids.
5
+ *
6
+ * - File notes: id derived from the repo-relative path, collision-safe
7
+ * (`a/b_c.py` and `a/b/c.py` slug identically — the sha1 suffix disambiguates).
8
+ * - Flow/lesson notes: id coined from the title at first write; uniqueness
9
+ * against existing ids by numeric suffix. Two-phase reuse is enforced at the
10
+ * `kb write` layer, not here.
11
+ */
12
+ import { createHash } from 'node:crypto';
13
+ const SLUG_MAX = 60;
14
+ export function slugify(s) {
15
+ const slug = String(s)
16
+ .toLowerCase()
17
+ .replace(/[^a-z0-9]+/g, '-')
18
+ .replace(/^-+|-+$/g, '');
19
+ return slug.slice(0, SLUG_MAX).replace(/-+$/g, '');
20
+ }
21
+ /** Derived, repeatable, collision-safe id for a file note. */
22
+ export function fileNoteId(relPath) {
23
+ const sha = createHash('sha1').update(relPath).digest('hex').slice(0, 8);
24
+ const slug = slugify(relPath);
25
+ return slug ? `${slug}-${sha}` : sha;
26
+ }
27
+ /** Coin a fresh flow/lesson id from a title; suffix -2, -3… if taken. */
28
+ export function coinId(title, existingIds) {
29
+ const base = slugify(title) || 'note';
30
+ if (!existingIds.has(base))
31
+ return base;
32
+ for (let n = 2;; n++) {
33
+ const candidate = `${base}-${n}`;
34
+ if (!existingIds.has(candidate))
35
+ return candidate;
36
+ }
37
+ }
38
+ /** Ids double as `.raw`/md filenames — keep them filesystem- and wikilink-safe. */
39
+ export function isValidId(id) {
40
+ return /^[a-z0-9][a-z0-9-]{0,99}$/.test(id);
41
+ }
42
+ //# sourceMappingURL=ids.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ids.js","sourceRoot":"","sources":["../../src/kb/ids.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,QAAQ,GAAG,EAAE,CAAC;AAEpB,MAAM,UAAU,OAAO,CAAC,CAAS;IAC/B,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC;SACnB,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC3B,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACrD,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,UAAU,CAAC,OAAe;IACxC,MAAM,GAAG,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACzE,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9B,OAAO,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;AACvC,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,MAAM,CAAC,KAAa,EAAE,WAAgC;IACpE,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC;IACtC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACxC,KAAK,IAAI,CAAC,GAAG,CAAC,GAAI,CAAC,EAAE,EAAE,CAAC;QACtB,MAAM,SAAS,GAAG,GAAG,IAAI,IAAI,CAAC,EAAE,CAAC;QACjC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC;YAAE,OAAO,SAAS,CAAC;IACpD,CAAC;AACH,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,SAAS,CAAC,EAAU;IAClC,OAAO,2BAA2B,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC9C,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * kb lint — mechanical checks ONLY. Flags, never auto-fixes; the output is a
3
+ * worklist for the next warm agent, never an auto-edit. (The staleness half is
4
+ * already the hash tripwire — that's search/status's job, not lint's.)
5
+ *
6
+ * Checks:
7
+ * dead-anchor anchor path no longer exists
8
+ * duplicate-flows two flow notes share most anchors (set math — catches
9
+ * cross-branch duplicate coinage where no agent was present)
10
+ * orphan flow/lesson never referenced by any other note
11
+ * absence-stale an absence note's stored search now returns hits
12
+ * malformed unparseable/invalid raw records (tolerant-reader warnings)
13
+ */
14
+ import { type KbNotesIndex } from './notes-index.js';
15
+ export interface LintFinding {
16
+ check: 'dead-anchor' | 'duplicate-flows' | 'orphan' | 'absence-stale' | 'malformed';
17
+ note: string;
18
+ detail: string;
19
+ }
20
+ export declare function kbLint(root: string, notesIndex?: KbNotesIndex | null): Promise<LintFinding[]>;
21
+ /** Orphan/duplicate lookups need `notes` too — expose the load for the CLI. */
22
+ export declare function lintSummary(findings: LintFinding[]): string;
23
+ //# sourceMappingURL=lint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../../src/kb/lint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAoB,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAIvE,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,aAAa,GAAG,iBAAiB,GAAG,QAAQ,GAAG,eAAe,GAAG,WAAW,CAAC;IACpF,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAID,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,YAAY,GAAG,IAAI,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CA8DnG;AAED,+EAA+E;AAC/E,wBAAgB,WAAW,CAAC,QAAQ,EAAE,WAAW,EAAE,GAAG,MAAM,CAc3D"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * kb lint — mechanical checks ONLY. Flags, never auto-fixes; the output is a
3
+ * worklist for the next warm agent, never an auto-edit. (The staleness half is
4
+ * already the hash tripwire — that's search/status's job, not lint's.)
5
+ *
6
+ * Checks:
7
+ * dead-anchor anchor path no longer exists
8
+ * duplicate-flows two flow notes share most anchors (set math — catches
9
+ * cross-branch duplicate coinage where no agent was present)
10
+ * orphan flow/lesson never referenced by any other note
11
+ * absence-stale an absence note's stored search now returns hits
12
+ * malformed unparseable/invalid raw records (tolerant-reader warnings)
13
+ */
14
+ import { stampCoversTerms } from './notes-index.js';
15
+ import { stampAnchors } from './freshness.js';
16
+ import { loadAll } from './store.js';
17
+ const DUP_JACCARD = 0.6;
18
+ export async function kbLint(root, notesIndex) {
19
+ const { notes, warnings } = loadAll(root);
20
+ const findings = [];
21
+ for (const w of warnings)
22
+ findings.push({ check: 'malformed', note: w.split(/[ .]/)[0], detail: w });
23
+ const active = notes.filter((n) => n.status === 'active');
24
+ // dead anchors
25
+ for (const n of active) {
26
+ for (const s of stampAnchors(root, n.anchors)) {
27
+ if (s.state === 'missing')
28
+ findings.push({ check: 'dead-anchor', note: n.id, detail: `anchor gone: ${s.path}` });
29
+ }
30
+ }
31
+ // duplicate flows by anchor-set overlap (pure set math)
32
+ const flows = active.filter((n) => n.type === 'flow' && n.anchors.length >= 2);
33
+ for (let i = 0; i < flows.length; i++) {
34
+ for (let j = i + 1; j < flows.length; j++) {
35
+ const a = new Set(flows[i].anchors.map((x) => x.path));
36
+ const b = new Set(flows[j].anchors.map((x) => x.path));
37
+ let shared = 0;
38
+ for (const p of a)
39
+ if (b.has(p))
40
+ shared++;
41
+ const jaccard = shared / (a.size + b.size - shared);
42
+ if (jaccard >= DUP_JACCARD) {
43
+ findings.push({
44
+ check: 'duplicate-flows', note: flows[i].id,
45
+ detail: `${flows[i].id} and ${flows[j].id} share ${shared} of ${a.size + b.size - shared} anchors — possible duplicate concept; a warm agent should merge (supersede one)`,
46
+ });
47
+ }
48
+ }
49
+ }
50
+ // orphans — flow/lesson nobody references (inbound = [[wikilink]] in prose or a file note's features)
51
+ const referenced = new Set();
52
+ for (const n of notes) {
53
+ for (const f of n.features)
54
+ referenced.add(f.concept_id);
55
+ for (const f of n.facets)
56
+ for (const id of f.flows ?? [])
57
+ referenced.add(id);
58
+ for (const text of [n.summary ?? '', n.body ?? '', ...n.behaviors.map((b) => b.detail), ...n.facets.map((f) => f.detail), ...n.invariants]) {
59
+ for (const m of text.matchAll(/\[\[([a-z0-9-]+)\]\]/g))
60
+ referenced.add(m[1]);
61
+ }
62
+ }
63
+ for (const n of active) {
64
+ if (n.type !== 'file' && !referenced.has(n.id)) {
65
+ findings.push({ check: 'orphan', note: n.id, detail: `no other note references ${n.id} — fine if new; a signal if old and unused` });
66
+ }
67
+ }
68
+ // absence stamps (keeper re-runs the stored searches; skipped without a notes index)
69
+ if (notesIndex) {
70
+ for (const n of active) {
71
+ if (n.type !== 'lesson' || n.kind !== 'absence' || !n.scope?.terms.length)
72
+ continue;
73
+ const stamp = notesIndex.absence[n.id];
74
+ if (!stampCoversTerms(stamp, n.scope.terms))
75
+ continue; // keeper hasn't stamped this note yet
76
+ const hits = stamp.matches;
77
+ if (hits.length) {
78
+ findings.push({ check: 'absence-stale', note: n.id, detail: `stored search now matches: ${hits.slice(0, 3).join(', ')}${hits.length > 3 ? ` +${hits.length - 3}` : ''}` });
79
+ }
80
+ }
81
+ }
82
+ return findings;
83
+ }
84
+ /** Orphan/duplicate lookups need `notes` too — expose the load for the CLI. */
85
+ export function lintSummary(findings) {
86
+ if (!findings.length)
87
+ return 'kb lint: clean — no flags.';
88
+ const byCheck = new Map();
89
+ for (const f of findings) {
90
+ const list = byCheck.get(f.check) ?? [];
91
+ list.push(f);
92
+ byCheck.set(f.check, list);
93
+ }
94
+ const parts = [`kb lint: ${findings.length} flag${findings.length === 1 ? '' : 's'} (worklist for the next warm agent — nothing is auto-fixed)`];
95
+ for (const [check, list] of byCheck) {
96
+ parts.push(`\n## ${check} (${list.length})`);
97
+ for (const f of list)
98
+ parts.push(`- ${f.note}: ${f.detail}`);
99
+ }
100
+ return parts.join('\n');
101
+ }
102
+ //# sourceMappingURL=lint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lint.js","sourceRoot":"","sources":["../../src/kb/lint.ts"],"names":[],"mappings":"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"}