@soleri/core 9.0.4 → 9.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 (744) hide show
  1. package/data/flows/build.flow.yaml +8 -9
  2. package/data/flows/deliver.flow.yaml +9 -10
  3. package/data/flows/design.flow.yaml +3 -4
  4. package/data/flows/enhance.flow.yaml +5 -6
  5. package/data/flows/explore.flow.yaml +3 -4
  6. package/data/flows/fix.flow.yaml +5 -6
  7. package/data/flows/plan.flow.yaml +4 -5
  8. package/data/flows/review.flow.yaml +3 -4
  9. package/dist/brain/intelligence.d.ts +27 -0
  10. package/dist/brain/intelligence.d.ts.map +1 -1
  11. package/dist/brain/intelligence.js +160 -14
  12. package/dist/brain/intelligence.js.map +1 -1
  13. package/dist/brain/learning-radar.d.ts +4 -0
  14. package/dist/brain/learning-radar.d.ts.map +1 -1
  15. package/dist/brain/learning-radar.js +20 -1
  16. package/dist/brain/learning-radar.js.map +1 -1
  17. package/dist/brain/strength-scorer.d.ts +31 -0
  18. package/dist/brain/strength-scorer.d.ts.map +1 -0
  19. package/dist/brain/strength-scorer.js +264 -0
  20. package/dist/brain/strength-scorer.js.map +1 -0
  21. package/dist/chat/agent-loop.d.ts.map +1 -1
  22. package/dist/chat/agent-loop.js +2 -0
  23. package/dist/chat/agent-loop.js.map +1 -1
  24. package/dist/chat/notifications.d.ts.map +1 -1
  25. package/dist/chat/notifications.js +2 -0
  26. package/dist/chat/notifications.js.map +1 -1
  27. package/dist/claudemd/compose.js +1 -1
  28. package/dist/claudemd/compose.js.map +1 -1
  29. package/dist/control/intent-router.d.ts.map +1 -1
  30. package/dist/control/intent-router.js +12 -4
  31. package/dist/control/intent-router.js.map +1 -1
  32. package/dist/curator/contradiction-detector.d.ts +27 -0
  33. package/dist/curator/contradiction-detector.d.ts.map +1 -0
  34. package/dist/curator/contradiction-detector.js +62 -0
  35. package/dist/curator/contradiction-detector.js.map +1 -0
  36. package/dist/curator/curator.d.ts +3 -4
  37. package/dist/curator/curator.d.ts.map +1 -1
  38. package/dist/curator/curator.js +94 -453
  39. package/dist/curator/curator.js.map +1 -1
  40. package/dist/curator/duplicate-detector.d.ts +14 -0
  41. package/dist/curator/duplicate-detector.d.ts.map +1 -0
  42. package/dist/curator/duplicate-detector.js +77 -0
  43. package/dist/curator/duplicate-detector.js.map +1 -0
  44. package/dist/curator/health-audit.d.ts +15 -0
  45. package/dist/curator/health-audit.d.ts.map +1 -0
  46. package/dist/curator/health-audit.js +97 -0
  47. package/dist/curator/health-audit.js.map +1 -0
  48. package/dist/curator/metadata-enricher.d.ts +17 -0
  49. package/dist/curator/metadata-enricher.d.ts.map +1 -0
  50. package/dist/curator/metadata-enricher.js +60 -0
  51. package/dist/curator/metadata-enricher.js.map +1 -0
  52. package/dist/curator/schema.d.ts +7 -0
  53. package/dist/curator/schema.d.ts.map +1 -0
  54. package/dist/curator/schema.js +62 -0
  55. package/dist/curator/schema.js.map +1 -0
  56. package/dist/curator/tag-manager.d.ts +36 -0
  57. package/dist/curator/tag-manager.d.ts.map +1 -0
  58. package/dist/curator/tag-manager.js +78 -0
  59. package/dist/curator/tag-manager.js.map +1 -0
  60. package/dist/engine/bin/soleri-engine.js +24 -3
  61. package/dist/engine/bin/soleri-engine.js.map +1 -1
  62. package/dist/engine/core-ops.d.ts.map +1 -1
  63. package/dist/engine/core-ops.js +23 -8
  64. package/dist/engine/core-ops.js.map +1 -1
  65. package/dist/engine/module-manifest.d.ts.map +1 -1
  66. package/dist/engine/module-manifest.js +42 -2
  67. package/dist/engine/module-manifest.js.map +1 -1
  68. package/dist/engine/register-engine.d.ts.map +1 -1
  69. package/dist/engine/register-engine.js +50 -2
  70. package/dist/engine/register-engine.js.map +1 -1
  71. package/dist/errors/retry.d.ts.map +1 -1
  72. package/dist/errors/retry.js +2 -0
  73. package/dist/errors/retry.js.map +1 -1
  74. package/dist/facades/types.d.ts +1 -1
  75. package/dist/flows/chain-types.d.ts +18 -18
  76. package/dist/flows/gate-evaluator.d.ts.map +1 -1
  77. package/dist/flows/gate-evaluator.js +22 -0
  78. package/dist/flows/gate-evaluator.js.map +1 -1
  79. package/dist/flows/types.d.ts +157 -28
  80. package/dist/flows/types.d.ts.map +1 -1
  81. package/dist/flows/types.js +4 -0
  82. package/dist/flows/types.js.map +1 -1
  83. package/dist/index.d.ts +10 -2
  84. package/dist/index.d.ts.map +1 -1
  85. package/dist/index.js +9 -1
  86. package/dist/index.js.map +1 -1
  87. package/dist/intake/intake-pipeline.d.ts.map +1 -1
  88. package/dist/intake/intake-pipeline.js +1 -0
  89. package/dist/intake/intake-pipeline.js.map +1 -1
  90. package/dist/intake/text-ingester.d.ts.map +1 -1
  91. package/dist/intake/text-ingester.js +2 -0
  92. package/dist/intake/text-ingester.js.map +1 -1
  93. package/dist/llm/key-pool.d.ts +1 -1
  94. package/dist/llm/key-pool.d.ts.map +1 -1
  95. package/dist/llm/key-pool.js +3 -4
  96. package/dist/llm/key-pool.js.map +1 -1
  97. package/dist/llm/utils.d.ts.map +1 -1
  98. package/dist/llm/utils.js +2 -0
  99. package/dist/llm/utils.js.map +1 -1
  100. package/dist/migrations/migration-runner.test-helpers.d.ts +13 -0
  101. package/dist/migrations/migration-runner.test-helpers.d.ts.map +1 -0
  102. package/dist/migrations/migration-runner.test-helpers.js +47 -0
  103. package/dist/migrations/migration-runner.test-helpers.js.map +1 -0
  104. package/dist/operator/operator-profile.d.ts +44 -0
  105. package/dist/operator/operator-profile.d.ts.map +1 -0
  106. package/dist/operator/operator-profile.js +383 -0
  107. package/dist/operator/operator-profile.js.map +1 -0
  108. package/dist/operator/operator-signals.d.ts +45 -0
  109. package/dist/operator/operator-signals.d.ts.map +1 -0
  110. package/dist/operator/operator-signals.js +228 -0
  111. package/dist/operator/operator-signals.js.map +1 -0
  112. package/dist/operator/operator-types.d.ts +360 -0
  113. package/dist/operator/operator-types.d.ts.map +1 -0
  114. package/dist/operator/operator-types.js +24 -0
  115. package/dist/operator/operator-types.js.map +1 -0
  116. package/dist/packs/types.d.ts +27 -27
  117. package/dist/paths.d.ts +40 -0
  118. package/dist/paths.d.ts.map +1 -0
  119. package/dist/paths.js +98 -0
  120. package/dist/paths.js.map +1 -0
  121. package/dist/persistence/index.d.ts +1 -1
  122. package/dist/persistence/index.d.ts.map +1 -1
  123. package/dist/persistence/index.js +1 -1
  124. package/dist/persistence/index.js.map +1 -1
  125. package/dist/persistence/sqlite-provider.d.ts +2 -0
  126. package/dist/persistence/sqlite-provider.d.ts.map +1 -1
  127. package/dist/persistence/sqlite-provider.js +8 -5
  128. package/dist/persistence/sqlite-provider.js.map +1 -1
  129. package/dist/planning/evidence-collector.d.ts +13 -1
  130. package/dist/planning/evidence-collector.d.ts.map +1 -1
  131. package/dist/planning/evidence-collector.js +33 -0
  132. package/dist/planning/evidence-collector.js.map +1 -1
  133. package/dist/planning/gap-analysis.d.ts +5 -4
  134. package/dist/planning/gap-analysis.d.ts.map +1 -1
  135. package/dist/planning/gap-analysis.js +7 -341
  136. package/dist/planning/gap-analysis.js.map +1 -1
  137. package/dist/planning/gap-passes.d.ts +19 -0
  138. package/dist/planning/gap-passes.d.ts.map +1 -0
  139. package/dist/planning/gap-passes.js +174 -0
  140. package/dist/planning/gap-passes.js.map +1 -0
  141. package/dist/planning/gap-patterns.d.ts +29 -0
  142. package/dist/planning/gap-patterns.d.ts.map +1 -0
  143. package/dist/planning/gap-patterns.js +175 -0
  144. package/dist/planning/gap-patterns.js.map +1 -0
  145. package/dist/planning/gap-types.d.ts +1 -1
  146. package/dist/planning/gap-types.d.ts.map +1 -1
  147. package/dist/planning/gap-types.js +1 -0
  148. package/dist/planning/gap-types.js.map +1 -1
  149. package/dist/planning/github-projection.d.ts +122 -0
  150. package/dist/planning/github-projection.d.ts.map +1 -0
  151. package/dist/planning/github-projection.js +313 -0
  152. package/dist/planning/github-projection.js.map +1 -0
  153. package/dist/planning/impact-analyzer.d.ts +26 -0
  154. package/dist/planning/impact-analyzer.d.ts.map +1 -0
  155. package/dist/planning/impact-analyzer.js +201 -0
  156. package/dist/planning/impact-analyzer.js.map +1 -0
  157. package/dist/planning/plan-lifecycle.d.ts +136 -0
  158. package/dist/planning/plan-lifecycle.d.ts.map +1 -0
  159. package/dist/planning/plan-lifecycle.js +309 -0
  160. package/dist/planning/plan-lifecycle.js.map +1 -0
  161. package/dist/planning/planner-types.d.ts +202 -0
  162. package/dist/planning/planner-types.d.ts.map +1 -0
  163. package/dist/planning/planner-types.js +6 -0
  164. package/dist/planning/planner-types.js.map +1 -0
  165. package/dist/planning/planner.d.ts +31 -383
  166. package/dist/planning/planner.d.ts.map +1 -1
  167. package/dist/planning/planner.js +151 -832
  168. package/dist/planning/planner.js.map +1 -1
  169. package/dist/planning/rationalization-detector.d.ts +32 -0
  170. package/dist/planning/rationalization-detector.d.ts.map +1 -0
  171. package/dist/planning/rationalization-detector.js +89 -0
  172. package/dist/planning/rationalization-detector.js.map +1 -0
  173. package/dist/planning/reconciliation-engine.d.ts +47 -0
  174. package/dist/planning/reconciliation-engine.d.ts.map +1 -0
  175. package/dist/planning/reconciliation-engine.js +128 -0
  176. package/dist/planning/reconciliation-engine.js.map +1 -0
  177. package/dist/planning/task-verifier.d.ts +85 -0
  178. package/dist/planning/task-verifier.d.ts.map +1 -0
  179. package/dist/planning/task-verifier.js +235 -0
  180. package/dist/planning/task-verifier.js.map +1 -0
  181. package/dist/plugins/types.d.ts +4 -4
  182. package/dist/runtime/admin-ops.d.ts +2 -2
  183. package/dist/runtime/admin-ops.d.ts.map +1 -1
  184. package/dist/runtime/admin-ops.js +44 -17
  185. package/dist/runtime/admin-ops.js.map +1 -1
  186. package/dist/runtime/admin-setup-ops.d.ts.map +1 -1
  187. package/dist/runtime/admin-setup-ops.js +22 -46
  188. package/dist/runtime/admin-setup-ops.js.map +1 -1
  189. package/dist/runtime/archive-ops.d.ts +10 -0
  190. package/dist/runtime/archive-ops.d.ts.map +1 -0
  191. package/dist/runtime/archive-ops.js +310 -0
  192. package/dist/runtime/archive-ops.js.map +1 -0
  193. package/dist/runtime/branching-ops.d.ts +12 -0
  194. package/dist/runtime/branching-ops.d.ts.map +1 -0
  195. package/dist/runtime/branching-ops.js +100 -0
  196. package/dist/runtime/branching-ops.js.map +1 -0
  197. package/dist/runtime/capture-ops.d.ts.map +1 -1
  198. package/dist/runtime/capture-ops.js +42 -7
  199. package/dist/runtime/capture-ops.js.map +1 -1
  200. package/dist/runtime/claude-md-helpers.js +1 -1
  201. package/dist/runtime/claude-md-helpers.js.map +1 -1
  202. package/dist/runtime/context-health.d.ts +31 -0
  203. package/dist/runtime/context-health.d.ts.map +1 -0
  204. package/dist/runtime/context-health.js +57 -0
  205. package/dist/runtime/context-health.js.map +1 -0
  206. package/dist/runtime/facades/archive-facade.d.ts +10 -0
  207. package/dist/runtime/facades/archive-facade.d.ts.map +1 -0
  208. package/dist/runtime/facades/archive-facade.js +11 -0
  209. package/dist/runtime/facades/archive-facade.js.map +1 -0
  210. package/dist/runtime/facades/brain-facade.d.ts.map +1 -1
  211. package/dist/runtime/facades/brain-facade.js +2 -0
  212. package/dist/runtime/facades/brain-facade.js.map +1 -1
  213. package/dist/runtime/facades/branching-facade.d.ts +7 -0
  214. package/dist/runtime/facades/branching-facade.d.ts.map +1 -0
  215. package/dist/runtime/facades/branching-facade.js +8 -0
  216. package/dist/runtime/facades/branching-facade.js.map +1 -0
  217. package/dist/runtime/facades/chat-facade.d.ts +7 -0
  218. package/dist/runtime/facades/chat-facade.d.ts.map +1 -1
  219. package/dist/runtime/facades/chat-facade.js +15 -800
  220. package/dist/runtime/facades/chat-facade.js.map +1 -1
  221. package/dist/runtime/facades/chat-service-ops.d.ts +9 -0
  222. package/dist/runtime/facades/chat-service-ops.d.ts.map +1 -0
  223. package/dist/runtime/facades/chat-service-ops.js +332 -0
  224. package/dist/runtime/facades/chat-service-ops.js.map +1 -0
  225. package/dist/runtime/facades/chat-session-ops.d.ts +8 -0
  226. package/dist/runtime/facades/chat-session-ops.d.ts.map +1 -0
  227. package/dist/runtime/facades/chat-session-ops.js +136 -0
  228. package/dist/runtime/facades/chat-session-ops.js.map +1 -0
  229. package/dist/runtime/facades/chat-state.d.ts +31 -0
  230. package/dist/runtime/facades/chat-state.d.ts.map +1 -0
  231. package/dist/runtime/facades/chat-state.js +32 -0
  232. package/dist/runtime/facades/chat-state.js.map +1 -0
  233. package/dist/runtime/facades/chat-transport-ops.d.ts +9 -0
  234. package/dist/runtime/facades/chat-transport-ops.d.ts.map +1 -0
  235. package/dist/runtime/facades/chat-transport-ops.js +337 -0
  236. package/dist/runtime/facades/chat-transport-ops.js.map +1 -0
  237. package/dist/runtime/facades/control-facade.d.ts.map +1 -1
  238. package/dist/runtime/facades/control-facade.js +4 -1
  239. package/dist/runtime/facades/control-facade.js.map +1 -1
  240. package/dist/runtime/facades/index.d.ts.map +1 -1
  241. package/dist/runtime/facades/index.js +48 -0
  242. package/dist/runtime/facades/index.js.map +1 -1
  243. package/dist/runtime/facades/intake-facade.d.ts +9 -0
  244. package/dist/runtime/facades/intake-facade.d.ts.map +1 -0
  245. package/dist/runtime/facades/intake-facade.js +11 -0
  246. package/dist/runtime/facades/intake-facade.js.map +1 -0
  247. package/dist/runtime/facades/links-facade.d.ts +9 -0
  248. package/dist/runtime/facades/links-facade.d.ts.map +1 -0
  249. package/dist/runtime/facades/links-facade.js +10 -0
  250. package/dist/runtime/facades/links-facade.js.map +1 -0
  251. package/dist/runtime/facades/memory-facade.d.ts.map +1 -1
  252. package/dist/runtime/facades/memory-facade.js +75 -6
  253. package/dist/runtime/facades/memory-facade.js.map +1 -1
  254. package/dist/runtime/facades/operator-facade.d.ts +8 -0
  255. package/dist/runtime/facades/operator-facade.d.ts.map +1 -0
  256. package/dist/runtime/facades/operator-facade.js +220 -0
  257. package/dist/runtime/facades/operator-facade.js.map +1 -0
  258. package/dist/runtime/facades/orchestrate-facade.js +3 -3
  259. package/dist/runtime/facades/orchestrate-facade.js.map +1 -1
  260. package/dist/runtime/facades/plan-facade.d.ts.map +1 -1
  261. package/dist/runtime/facades/plan-facade.js +42 -6
  262. package/dist/runtime/facades/plan-facade.js.map +1 -1
  263. package/dist/runtime/facades/review-facade.d.ts +7 -0
  264. package/dist/runtime/facades/review-facade.d.ts.map +1 -0
  265. package/dist/runtime/facades/review-facade.js +8 -0
  266. package/dist/runtime/facades/review-facade.js.map +1 -0
  267. package/dist/runtime/facades/sync-facade.d.ts +7 -0
  268. package/dist/runtime/facades/sync-facade.d.ts.map +1 -0
  269. package/dist/runtime/facades/sync-facade.js +8 -0
  270. package/dist/runtime/facades/sync-facade.js.map +1 -0
  271. package/dist/runtime/facades/tier-facade.d.ts +7 -0
  272. package/dist/runtime/facades/tier-facade.d.ts.map +1 -0
  273. package/dist/runtime/facades/tier-facade.js +8 -0
  274. package/dist/runtime/facades/tier-facade.js.map +1 -0
  275. package/dist/runtime/facades/vault-facade.d.ts +12 -1
  276. package/dist/runtime/facades/vault-facade.d.ts.map +1 -1
  277. package/dist/runtime/facades/vault-facade.js +55 -251
  278. package/dist/runtime/facades/vault-facade.js.map +1 -1
  279. package/dist/runtime/github-integration.d.ts +49 -0
  280. package/dist/runtime/github-integration.d.ts.map +1 -0
  281. package/dist/runtime/github-integration.js +120 -0
  282. package/dist/runtime/github-integration.js.map +1 -0
  283. package/dist/runtime/grading-ops.js +1 -1
  284. package/dist/runtime/grading-ops.js.map +1 -1
  285. package/dist/runtime/memory-extra-ops.d.ts.map +1 -1
  286. package/dist/runtime/memory-extra-ops.js +6 -2
  287. package/dist/runtime/memory-extra-ops.js.map +1 -1
  288. package/dist/runtime/orchestrate-ops.d.ts.map +1 -1
  289. package/dist/runtime/orchestrate-ops.js +386 -37
  290. package/dist/runtime/orchestrate-ops.js.map +1 -1
  291. package/dist/runtime/planning-extra-ops.d.ts.map +1 -1
  292. package/dist/runtime/planning-extra-ops.js +69 -4
  293. package/dist/runtime/planning-extra-ops.js.map +1 -1
  294. package/dist/runtime/review-ops.d.ts +10 -0
  295. package/dist/runtime/review-ops.d.ts.map +1 -0
  296. package/dist/runtime/review-ops.js +97 -0
  297. package/dist/runtime/review-ops.js.map +1 -0
  298. package/dist/runtime/runtime.d.ts.map +1 -1
  299. package/dist/runtime/runtime.js +29 -12
  300. package/dist/runtime/runtime.js.map +1 -1
  301. package/dist/runtime/session-briefing.d.ts +3 -0
  302. package/dist/runtime/session-briefing.d.ts.map +1 -1
  303. package/dist/runtime/session-briefing.js +72 -1
  304. package/dist/runtime/session-briefing.js.map +1 -1
  305. package/dist/runtime/sync-ops.d.ts +12 -0
  306. package/dist/runtime/sync-ops.d.ts.map +1 -0
  307. package/dist/runtime/sync-ops.js +288 -0
  308. package/dist/runtime/sync-ops.js.map +1 -0
  309. package/dist/runtime/tier-ops.d.ts +13 -0
  310. package/dist/runtime/tier-ops.d.ts.map +1 -0
  311. package/dist/runtime/tier-ops.js +110 -0
  312. package/dist/runtime/tier-ops.js.map +1 -0
  313. package/dist/runtime/types.d.ts +10 -4
  314. package/dist/runtime/types.d.ts.map +1 -1
  315. package/dist/runtime/vault-extra-ops.d.ts +5 -4
  316. package/dist/runtime/vault-extra-ops.d.ts.map +1 -1
  317. package/dist/runtime/vault-extra-ops.js +5 -300
  318. package/dist/runtime/vault-extra-ops.js.map +1 -1
  319. package/dist/runtime/vault-sharing-ops.d.ts +4 -4
  320. package/dist/runtime/vault-sharing-ops.d.ts.map +1 -1
  321. package/dist/runtime/vault-sharing-ops.js +5 -300
  322. package/dist/runtime/vault-sharing-ops.js.map +1 -1
  323. package/dist/skills/sync-skills.d.ts +27 -0
  324. package/dist/skills/sync-skills.d.ts.map +1 -0
  325. package/dist/skills/sync-skills.js +81 -0
  326. package/dist/skills/sync-skills.js.map +1 -0
  327. package/dist/update-check.d.ts +14 -0
  328. package/dist/update-check.d.ts.map +1 -0
  329. package/dist/update-check.js +96 -0
  330. package/dist/update-check.js.map +1 -0
  331. package/dist/vault/linking.d.ts +10 -12
  332. package/dist/vault/linking.d.ts.map +1 -1
  333. package/dist/vault/linking.js +140 -161
  334. package/dist/vault/linking.js.map +1 -1
  335. package/dist/vault/vault-entries.d.ts +69 -0
  336. package/dist/vault/vault-entries.d.ts.map +1 -0
  337. package/dist/vault/vault-entries.js +299 -0
  338. package/dist/vault/vault-entries.js.map +1 -0
  339. package/dist/vault/vault-interfaces.d.ts +153 -0
  340. package/dist/vault/vault-interfaces.d.ts.map +1 -0
  341. package/dist/vault/vault-interfaces.js +2 -0
  342. package/dist/vault/vault-interfaces.js.map +1 -0
  343. package/dist/vault/vault-maintenance.d.ts +40 -0
  344. package/dist/vault/vault-maintenance.d.ts.map +1 -0
  345. package/dist/vault/vault-maintenance.js +146 -0
  346. package/dist/vault/vault-maintenance.js.map +1 -0
  347. package/dist/vault/vault-markdown-sync.d.ts +22 -0
  348. package/dist/vault/vault-markdown-sync.d.ts.map +1 -0
  349. package/dist/vault/vault-markdown-sync.js +143 -0
  350. package/dist/vault/vault-markdown-sync.js.map +1 -0
  351. package/dist/vault/vault-memories.d.ts +61 -0
  352. package/dist/vault/vault-memories.d.ts.map +1 -0
  353. package/dist/vault/vault-memories.js +242 -0
  354. package/dist/vault/vault-memories.js.map +1 -0
  355. package/dist/vault/vault-schema.d.ts +9 -0
  356. package/dist/vault/vault-schema.d.ts.map +1 -0
  357. package/dist/vault/vault-schema.js +205 -0
  358. package/dist/vault/vault-schema.js.map +1 -0
  359. package/dist/vault/vault.d.ts +29 -81
  360. package/dist/vault/vault.d.ts.map +1 -1
  361. package/dist/vault/vault.js +82 -931
  362. package/dist/vault/vault.js.map +1 -1
  363. package/package.json +7 -7
  364. package/src/agency/agency-manager.test.ts +620 -0
  365. package/src/agency/default-rules.test.ts +236 -0
  366. package/src/{__tests__ → brain}/brain-intelligence.test.ts +37 -14
  367. package/src/{__tests__ → brain}/brain.test.ts +1 -1
  368. package/src/brain/intelligence.ts +196 -15
  369. package/src/brain/learning-radar.ts +22 -1
  370. package/src/{__tests__ → brain}/second-brain-features.test.ts +4 -4
  371. package/src/{__tests__ → brain}/session-lifecycle.test.ts +2 -2
  372. package/src/capabilities/chain-mapping.test.ts +66 -0
  373. package/src/capabilities/registry.test.ts +359 -0
  374. package/src/chat/agent-loop.test.ts +384 -0
  375. package/src/chat/agent-loop.ts +2 -0
  376. package/src/{__tests__ → chat}/chat-differentiators.test.ts +3 -3
  377. package/src/{__tests__ → chat}/chat-enhanced.test.ts +4 -4
  378. package/src/{__tests__ → chat}/chat-transport.test.ts +6 -6
  379. package/src/chat/mcp-bridge.test.ts +178 -0
  380. package/src/chat/notifications.ts +2 -0
  381. package/src/chat/output-compressor.test.ts +164 -0
  382. package/src/claudemd/compose.test.ts +178 -0
  383. package/src/claudemd/compose.ts +1 -1
  384. package/src/claudemd/inject.test.ts +201 -0
  385. package/src/context/context-engine.test.ts +506 -0
  386. package/src/control/identity-manager.test.ts +305 -0
  387. package/src/control/intent-router.test.ts +360 -0
  388. package/src/control/intent-router.ts +13 -4
  389. package/src/curator/classifier.test.ts +110 -0
  390. package/src/curator/contradiction-detector.test.ts +205 -0
  391. package/src/curator/contradiction-detector.ts +87 -0
  392. package/src/{__tests__ → curator}/curator-pipeline-e2e.test.ts +10 -10
  393. package/src/{__tests__ → curator}/curator.test.ts +77 -1
  394. package/src/curator/curator.ts +160 -600
  395. package/src/curator/duplicate-detector.test.ts +245 -0
  396. package/src/curator/duplicate-detector.ts +103 -0
  397. package/src/curator/health-audit.ts +126 -0
  398. package/src/curator/metadata-enricher.ts +84 -0
  399. package/src/curator/quality-gate.test.ts +175 -0
  400. package/src/curator/schema.ts +65 -0
  401. package/src/curator/tag-manager.test.ts +173 -0
  402. package/src/curator/tag-manager.ts +109 -0
  403. package/src/domain-packs/inject-rules.test.ts +117 -0
  404. package/src/domain-packs/knowledge-installer.test.ts +163 -0
  405. package/src/domain-packs/loader.test.ts +86 -0
  406. package/src/domain-packs/pack-runtime.test.ts +140 -0
  407. package/src/domain-packs/skills-installer.test.ts +135 -0
  408. package/src/domain-packs/token-resolver.test.ts +148 -0
  409. package/src/domain-packs/types.test.ts +144 -0
  410. package/src/enforcement/adapters/claude-code.test.ts +216 -0
  411. package/src/enforcement/registry.test.ts +258 -0
  412. package/src/engine/bin/soleri-engine.ts +30 -4
  413. package/src/engine/core-ops.test.ts +254 -0
  414. package/src/engine/core-ops.ts +25 -8
  415. package/src/engine/module-manifest.test.ts +125 -0
  416. package/src/engine/module-manifest.ts +42 -2
  417. package/src/engine/register-engine.test.ts +235 -0
  418. package/src/engine/register-engine.ts +50 -3
  419. package/src/errors/classify.test.ts +203 -0
  420. package/src/errors/retry.test.ts +153 -0
  421. package/src/errors/retry.ts +2 -0
  422. package/src/errors/types.test.ts +108 -0
  423. package/src/events/event-bus.test.ts +149 -0
  424. package/src/extensions/middleware.test.ts +234 -0
  425. package/src/facades/facade-factory.test.ts +470 -0
  426. package/src/flows/chain-runner.test.ts +273 -0
  427. package/src/flows/context-router.test.ts +52 -0
  428. package/src/flows/dispatch-registry.test.ts +128 -0
  429. package/src/flows/epilogue.test.ts +113 -0
  430. package/src/flows/executor.test.ts +263 -0
  431. package/src/flows/gate-evaluator.test.ts +200 -0
  432. package/src/flows/gate-evaluator.ts +23 -0
  433. package/src/flows/types.ts +4 -0
  434. package/src/governance/governance.test.ts +842 -0
  435. package/src/{__tests__ → health}/health-registry.test.ts +75 -55
  436. package/src/health/vault-integrity.test.ts +110 -0
  437. package/src/index.ts +92 -0
  438. package/src/intake/content-classifier.test.ts +279 -0
  439. package/src/intake/dedup-gate.test.ts +147 -0
  440. package/src/intake/intake-pipeline.test.ts +508 -0
  441. package/src/intake/intake-pipeline.ts +1 -0
  442. package/src/intake/text-ingester.test.ts +200 -0
  443. package/src/intake/text-ingester.ts +2 -0
  444. package/src/llm/key-pool.test.ts +234 -0
  445. package/src/llm/key-pool.ts +3 -4
  446. package/src/llm/llm-client.test.ts +342 -0
  447. package/src/llm/oauth-discovery.test.ts +180 -0
  448. package/src/llm/utils.test.ts +371 -0
  449. package/src/llm/utils.ts +2 -0
  450. package/src/{__tests__ → logging}/logger.test.ts +44 -62
  451. package/src/loop/loop-manager.test.ts +515 -0
  452. package/src/migrations/migration-runner.edge-cases.test.ts +314 -0
  453. package/src/migrations/migration-runner.test-helpers.ts +64 -0
  454. package/src/migrations/migration-runner.test.ts +385 -0
  455. package/src/operator/auto-signal-pipeline.test.ts +207 -0
  456. package/src/operator/operator-profile-extended.test.ts +330 -0
  457. package/src/operator/operator-profile.test.ts +332 -0
  458. package/src/operator/operator-profile.ts +485 -0
  459. package/src/operator/operator-signals-extended.test.ts +257 -0
  460. package/src/operator/operator-signals.test.ts +277 -0
  461. package/src/operator/operator-signals.ts +262 -0
  462. package/src/operator/operator-types.ts +444 -0
  463. package/src/operator/prompts/hook-precompact-operator-dispatch.md +98 -0
  464. package/src/operator/prompts/subagent-soft-signal-extractor.md +130 -0
  465. package/src/operator/prompts/subagent-synthesis-cognition.md +190 -0
  466. package/src/operator/prompts/subagent-synthesis-communication.md +146 -0
  467. package/src/operator/prompts/subagent-synthesis-technical.md +170 -0
  468. package/src/operator/prompts/subagent-synthesis-trust.md +149 -0
  469. package/src/{__tests__ → packs}/pack-lockfile.test.ts +3 -3
  470. package/src/{__tests__ → packs}/pack-system.test.ts +2 -2
  471. package/src/paths.ts +115 -0
  472. package/src/persistence/index.ts +1 -1
  473. package/src/persistence/sqlite-provider.test.ts +540 -0
  474. package/src/persistence/sqlite-provider.ts +8 -5
  475. package/src/persona/defaults.test.ts +55 -0
  476. package/src/persona/loader.test.ts +67 -0
  477. package/src/persona/prompt-generator.test.ts +127 -0
  478. package/src/planning/evidence-collector.test.ts +515 -0
  479. package/src/planning/evidence-collector.ts +47 -0
  480. package/src/planning/gap-analysis-alternatives.test.ts +199 -0
  481. package/src/planning/gap-analysis.ts +21 -636
  482. package/src/planning/gap-passes.test.ts +554 -0
  483. package/src/planning/gap-passes.ts +367 -0
  484. package/src/planning/gap-patterns.test.ts +394 -0
  485. package/src/planning/gap-patterns.ts +317 -0
  486. package/src/planning/gap-types.ts +4 -1
  487. package/src/planning/github-projection.test.ts +182 -0
  488. package/src/planning/github-projection.ts +446 -0
  489. package/src/planning/impact-analyzer.test.ts +167 -0
  490. package/src/planning/impact-analyzer.ts +251 -0
  491. package/src/planning/plan-lifecycle.test.ts +379 -0
  492. package/src/planning/plan-lifecycle.ts +377 -0
  493. package/src/planning/planner-types.ts +215 -0
  494. package/src/{__tests__ → planning}/planner.test.ts +179 -15
  495. package/src/planning/planner.ts +221 -1112
  496. package/src/planning/rationalization-detector.test.ts +156 -0
  497. package/src/planning/rationalization-detector.ts +136 -0
  498. package/src/planning/reconciliation-engine.test.ts +158 -0
  499. package/src/planning/reconciliation-engine.ts +161 -0
  500. package/src/planning/task-verifier.test.ts +267 -0
  501. package/src/planning/task-verifier.ts +309 -0
  502. package/src/planning/verification-protocol.test.ts +201 -0
  503. package/src/playbooks/generic/generic-playbooks.test.ts +438 -0
  504. package/src/playbooks/index.test.ts +77 -0
  505. package/src/playbooks/playbook-executor.test.ts +253 -0
  506. package/src/playbooks/playbook-registry.test.ts +232 -0
  507. package/src/playbooks/playbook-seeder.test.ts +153 -0
  508. package/src/plugins/plugin-loader.test.ts +217 -0
  509. package/src/plugins/plugin-registry.test.ts +284 -0
  510. package/src/project/project-registry.test.ts +439 -0
  511. package/src/prompts/parser.test.ts +100 -0
  512. package/src/prompts/template-manager.test.ts +112 -0
  513. package/src/{__tests__ → queue}/async-infrastructure.test.ts +3 -3
  514. package/src/queue/job-queue.test.ts +327 -0
  515. package/src/queue/pipeline-runner.test.ts +209 -0
  516. package/src/runtime/admin-extra-ops.test.ts +513 -0
  517. package/src/runtime/admin-ops.test.ts +255 -0
  518. package/src/runtime/admin-ops.ts +45 -17
  519. package/src/runtime/admin-setup-ops.test.ts +327 -0
  520. package/src/runtime/admin-setup-ops.ts +26 -42
  521. package/src/runtime/archive-ops.test.ts +272 -0
  522. package/src/runtime/archive-ops.ts +347 -0
  523. package/src/runtime/branching-ops.test.ts +144 -0
  524. package/src/runtime/branching-ops.ts +107 -0
  525. package/src/runtime/capture-ops.test.ts +419 -0
  526. package/src/runtime/capture-ops.ts +50 -8
  527. package/src/runtime/chain-ops.test.ts +159 -0
  528. package/src/runtime/claude-md-helpers.test.ts +189 -0
  529. package/src/runtime/claude-md-helpers.ts +1 -1
  530. package/src/runtime/context-health.test.ts +76 -0
  531. package/src/runtime/context-health.ts +83 -0
  532. package/src/runtime/curator-extra-ops.test.ts +204 -0
  533. package/src/runtime/deprecation.test.ts +98 -0
  534. package/src/runtime/domain-ops.test.ts +278 -0
  535. package/src/runtime/facades/admin-facade.test.ts +330 -0
  536. package/src/runtime/facades/agency-facade.test.ts +278 -0
  537. package/src/runtime/facades/archive-facade.test.ts +308 -0
  538. package/src/runtime/facades/archive-facade.ts +14 -0
  539. package/src/runtime/facades/brain-facade.test.ts +818 -0
  540. package/src/runtime/facades/brain-facade.ts +2 -0
  541. package/src/runtime/facades/branching-facade.test.ts +43 -0
  542. package/src/runtime/facades/branching-facade.ts +11 -0
  543. package/src/runtime/facades/chat-facade.test.ts +219 -0
  544. package/src/runtime/facades/chat-facade.ts +15 -906
  545. package/src/runtime/facades/chat-service-ops.test.ts +381 -0
  546. package/src/runtime/facades/chat-service-ops.ts +376 -0
  547. package/src/runtime/facades/chat-session-ops.test.ts +212 -0
  548. package/src/runtime/facades/chat-session-ops.ts +146 -0
  549. package/src/runtime/facades/chat-state.ts +60 -0
  550. package/src/runtime/facades/chat-transport-ops.test.ts +336 -0
  551. package/src/runtime/facades/chat-transport-ops.ts +379 -0
  552. package/src/runtime/facades/context-facade.test.ts +123 -0
  553. package/src/runtime/facades/control-facade.test.ts +436 -0
  554. package/src/runtime/facades/control-facade.ts +6 -1
  555. package/src/runtime/facades/curator-facade.test.ts +303 -0
  556. package/src/runtime/facades/index.ts +48 -0
  557. package/src/runtime/facades/intake-facade.test.ts +215 -0
  558. package/src/runtime/facades/intake-facade.ts +14 -0
  559. package/src/runtime/facades/links-facade.test.ts +203 -0
  560. package/src/runtime/facades/links-facade.ts +13 -0
  561. package/src/runtime/facades/loop-facade.test.ts +262 -0
  562. package/src/runtime/facades/memory-facade.test.ts +283 -0
  563. package/src/runtime/facades/memory-facade.ts +78 -6
  564. package/src/runtime/facades/operator-facade.test.ts +221 -0
  565. package/src/runtime/facades/operator-facade.ts +244 -0
  566. package/src/runtime/facades/orchestrate-facade.test.ts +191 -0
  567. package/src/runtime/facades/orchestrate-facade.ts +3 -3
  568. package/src/runtime/facades/plan-facade.test.ts +283 -0
  569. package/src/runtime/facades/plan-facade.ts +47 -6
  570. package/src/runtime/facades/review-facade.test.ts +82 -0
  571. package/src/runtime/facades/review-facade.ts +11 -0
  572. package/src/runtime/facades/sync-facade.test.ts +113 -0
  573. package/src/runtime/facades/sync-facade.ts +11 -0
  574. package/src/runtime/facades/tier-facade.test.ts +47 -0
  575. package/src/runtime/facades/tier-facade.ts +11 -0
  576. package/src/runtime/facades/vault-facade.test.ts +563 -0
  577. package/src/runtime/facades/vault-facade.ts +66 -265
  578. package/src/runtime/feature-flags.test.ts +140 -0
  579. package/src/runtime/github-integration.test.ts +89 -0
  580. package/src/runtime/github-integration.ts +162 -0
  581. package/src/runtime/grading-ops.test.ts +172 -0
  582. package/src/runtime/grading-ops.ts +1 -1
  583. package/src/runtime/intake-ops.test.ts +261 -0
  584. package/src/runtime/loop-ops.test.ts +248 -0
  585. package/src/runtime/memory-cross-project-ops.test.ts +188 -0
  586. package/src/runtime/memory-extra-ops.test.ts +453 -0
  587. package/src/runtime/memory-extra-ops.ts +6 -2
  588. package/src/runtime/orchestrate-ops.test.ts +302 -0
  589. package/src/runtime/orchestrate-ops.ts +461 -45
  590. package/src/runtime/pack-ops.test.ts +175 -0
  591. package/src/runtime/planning-extra-ops.test.ts +593 -0
  592. package/src/runtime/planning-extra-ops.ts +74 -4
  593. package/src/{__tests__ → runtime}/playbook-ops-execution.test.ts +3 -3
  594. package/src/runtime/playbook-ops.test.ts +285 -0
  595. package/src/runtime/plugin-ops.test.ts +259 -0
  596. package/src/runtime/project-ops.test.ts +255 -0
  597. package/src/runtime/review-ops.test.ts +142 -0
  598. package/src/runtime/review-ops.ts +99 -0
  599. package/src/runtime/runtime.test.ts +363 -0
  600. package/src/runtime/runtime.ts +41 -12
  601. package/src/runtime/session-briefing.test.ts +431 -0
  602. package/src/runtime/session-briefing.ts +86 -1
  603. package/src/runtime/sync-ops.test.ts +212 -0
  604. package/src/runtime/sync-ops.ts +325 -0
  605. package/src/runtime/telemetry-ops.test.ts +157 -0
  606. package/src/runtime/tier-ops.test.ts +159 -0
  607. package/src/runtime/tier-ops.ts +119 -0
  608. package/src/runtime/types.ts +10 -4
  609. package/src/runtime/vault-extra-ops.test.ts +270 -0
  610. package/src/runtime/vault-extra-ops.ts +5 -332
  611. package/src/runtime/vault-linking-ops.test.ts +237 -0
  612. package/src/runtime/vault-sharing-ops.test.ts +127 -0
  613. package/src/runtime/vault-sharing-ops.ts +5 -329
  614. package/src/skills/sync-skills.ts +98 -0
  615. package/src/streams/normalize.test.ts +95 -0
  616. package/src/streams/replayable-stream.test.ts +166 -0
  617. package/src/telemetry/telemetry.test.ts +143 -0
  618. package/src/transport/http-server.test.ts +394 -0
  619. package/src/transport/lsp-server.test.ts +458 -0
  620. package/src/transport/rate-limiter.test.ts +126 -0
  621. package/src/transport/session-manager.test.ts +133 -0
  622. package/src/transport/token-auth.test.ts +136 -0
  623. package/src/transport/ws-server.test.ts +297 -0
  624. package/src/update-check.ts +111 -0
  625. package/src/vault/__tests__/vault-characterization.test.ts +579 -0
  626. package/src/vault/content-hash.test.ts +78 -0
  627. package/src/vault/git-vault-sync.test.ts +234 -0
  628. package/src/vault/knowledge-review.test.ts +269 -0
  629. package/src/vault/linking.test.ts +391 -0
  630. package/src/vault/linking.ts +188 -181
  631. package/src/vault/obsidian-sync.test.ts +345 -0
  632. package/src/vault/playbook.test.ts +152 -0
  633. package/src/vault/scope-detector.test.ts +185 -0
  634. package/src/vault/vault-branching.test.ts +252 -0
  635. package/src/{__tests__ → vault}/vault-connect.test.ts +1 -1
  636. package/src/vault/vault-entries.ts +426 -0
  637. package/src/vault/vault-maintenance.ts +200 -0
  638. package/src/vault/vault-manager.test.ts +206 -0
  639. package/src/vault/vault-markdown-sync.test.ts +203 -0
  640. package/src/vault/vault-markdown-sync.ts +163 -0
  641. package/src/vault/vault-memories.ts +339 -0
  642. package/src/{__tests__ → vault}/vault-scaling.test.ts +1 -1
  643. package/src/vault/vault-schema.ts +238 -0
  644. package/src/{__tests__ → vault}/vault-sharing.test.ts +4 -4
  645. package/src/{__tests__ → vault}/vault.test.ts +2 -2
  646. package/src/vault/vault.ts +87 -1123
  647. package/dist/cognee/client.d.ts +0 -43
  648. package/dist/cognee/client.d.ts.map +0 -1
  649. package/dist/cognee/client.js +0 -375
  650. package/dist/cognee/client.js.map +0 -1
  651. package/dist/cognee/sync-manager.d.ts +0 -153
  652. package/dist/cognee/sync-manager.d.ts.map +0 -1
  653. package/dist/cognee/sync-manager.js +0 -390
  654. package/dist/cognee/sync-manager.js.map +0 -1
  655. package/dist/cognee/types.d.ts +0 -62
  656. package/dist/cognee/types.d.ts.map +0 -1
  657. package/dist/cognee/types.js +0 -3
  658. package/dist/cognee/types.js.map +0 -1
  659. package/dist/governance/index.d.ts +0 -3
  660. package/dist/governance/index.d.ts.map +0 -1
  661. package/dist/governance/index.js +0 -2
  662. package/dist/governance/index.js.map +0 -1
  663. package/dist/health/doctor-checks.d.ts +0 -15
  664. package/dist/health/doctor-checks.d.ts.map +0 -1
  665. package/dist/health/doctor-checks.js +0 -98
  666. package/dist/health/doctor-checks.js.map +0 -1
  667. package/dist/persistence/postgres-provider.d.ts +0 -81
  668. package/dist/persistence/postgres-provider.d.ts.map +0 -1
  669. package/dist/persistence/postgres-provider.js +0 -256
  670. package/dist/persistence/postgres-provider.js.map +0 -1
  671. package/dist/runtime/cognee-sync-ops.d.ts +0 -12
  672. package/dist/runtime/cognee-sync-ops.d.ts.map +0 -1
  673. package/dist/runtime/cognee-sync-ops.js +0 -93
  674. package/dist/runtime/cognee-sync-ops.js.map +0 -1
  675. package/dist/runtime/core-ops.d.ts +0 -23
  676. package/dist/runtime/core-ops.d.ts.map +0 -1
  677. package/dist/runtime/core-ops.js +0 -1296
  678. package/dist/runtime/core-ops.js.map +0 -1
  679. package/dist/runtime/facades/cognee-facade.d.ts +0 -8
  680. package/dist/runtime/facades/cognee-facade.d.ts.map +0 -1
  681. package/dist/runtime/facades/cognee-facade.js +0 -156
  682. package/dist/runtime/facades/cognee-facade.js.map +0 -1
  683. package/src/__tests__/admin-extra-ops.test.ts +0 -484
  684. package/src/__tests__/admin-ops.test.ts +0 -268
  685. package/src/__tests__/admin-setup-ops.test.ts +0 -355
  686. package/src/__tests__/agency-manager.test.ts +0 -374
  687. package/src/__tests__/agent-loop.test.ts +0 -256
  688. package/src/__tests__/capture-ops.test.ts +0 -784
  689. package/src/__tests__/claudemd.test.ts +0 -282
  690. package/src/__tests__/content-hash.test.ts +0 -60
  691. package/src/__tests__/context-engine.test.ts +0 -251
  692. package/src/__tests__/core-ops.test.ts +0 -550
  693. package/src/__tests__/curator-extra-ops.test.ts +0 -383
  694. package/src/__tests__/deprecation.test.ts +0 -78
  695. package/src/__tests__/domain-ops.test.ts +0 -226
  696. package/src/__tests__/domain-packs.test.ts +0 -421
  697. package/src/__tests__/enforcement.test.ts +0 -153
  698. package/src/__tests__/errors.test.ts +0 -388
  699. package/src/__tests__/extensions.test.ts +0 -233
  700. package/src/__tests__/facade-factory.test.ts +0 -271
  701. package/src/__tests__/feature-flags.test.ts +0 -137
  702. package/src/__tests__/flows.test.ts +0 -604
  703. package/src/__tests__/git-vault-sync.test.ts +0 -230
  704. package/src/__tests__/governance.test.ts +0 -522
  705. package/src/__tests__/grading-ops.test.ts +0 -361
  706. package/src/__tests__/identity-manager.test.ts +0 -243
  707. package/src/__tests__/intake-pipeline.test.ts +0 -162
  708. package/src/__tests__/intent-router.test.ts +0 -222
  709. package/src/__tests__/knowledge-review.test.ts +0 -104
  710. package/src/__tests__/llm-client.test.ts +0 -69
  711. package/src/__tests__/llm.test.ts +0 -556
  712. package/src/__tests__/loader.test.ts +0 -176
  713. package/src/__tests__/loop-ops.test.ts +0 -469
  714. package/src/__tests__/lsp-transport.test.ts +0 -442
  715. package/src/__tests__/memory-cross-project-ops.test.ts +0 -248
  716. package/src/__tests__/memory-extra-ops.test.ts +0 -352
  717. package/src/__tests__/migration-runner.test.ts +0 -170
  718. package/src/__tests__/module-manifest-drift.test.ts +0 -59
  719. package/src/__tests__/normalize.test.ts +0 -85
  720. package/src/__tests__/obsidian-sync.test.ts +0 -354
  721. package/src/__tests__/orchestrate-ops.test.ts +0 -289
  722. package/src/__tests__/pack-ops.test.ts +0 -146
  723. package/src/__tests__/persistence.test.ts +0 -291
  724. package/src/__tests__/planning-extra-ops.test.ts +0 -706
  725. package/src/__tests__/playbook-executor.test.ts +0 -249
  726. package/src/__tests__/playbook-registry.test.ts +0 -326
  727. package/src/__tests__/playbook-seeder.test.ts +0 -163
  728. package/src/__tests__/playbook.test.ts +0 -389
  729. package/src/__tests__/plugin-ops.test.ts +0 -411
  730. package/src/__tests__/plugin-system.test.ts +0 -509
  731. package/src/__tests__/project-ops.test.ts +0 -381
  732. package/src/__tests__/replayable-stream.test.ts +0 -177
  733. package/src/__tests__/runtime.test.ts +0 -95
  734. package/src/__tests__/scope-detector.test.ts +0 -121
  735. package/src/__tests__/template-manager.test.ts +0 -222
  736. package/src/__tests__/token-resolver.test.ts +0 -79
  737. package/src/__tests__/transport.test.ts +0 -758
  738. package/src/__tests__/vault-branching.test.ts +0 -274
  739. package/src/__tests__/vault-extra-ops.test.ts +0 -482
  740. package/src/__tests__/vault-integrity.test.ts +0 -71
  741. package/src/__tests__/vault-manager.test.ts +0 -238
  742. package/src/__tests__/ws-transport.test.ts +0 -479
  743. package/src/engine/index.ts +0 -21
  744. package/src/persona/index.ts +0 -9
@@ -1,17 +1,10 @@
1
1
  import type { Vault } from '../vault/vault.js';
2
2
  import type { IntelligenceEntry } from '../intelligence/types.js';
3
3
  import type { PersistenceProvider } from '../persistence/types.js';
4
- import {
5
- tokenize,
6
- calculateTfIdf,
7
- cosineSimilarity,
8
- type SparseVector,
9
- } from '../text/similarity.js';
10
4
  import type {
11
5
  CuratorStatus,
12
6
  TagNormalizationResult,
13
7
  CanonicalTag,
14
- DuplicateCandidate,
15
8
  DuplicateDetectionResult,
16
9
  Contradiction,
17
10
  ContradictionStatus,
@@ -23,115 +16,78 @@ import type {
23
16
  HealthAuditResult,
24
17
  } from './types.js';
25
18
 
19
+ import {
20
+ detectDuplicates as detectDuplicatesPure,
21
+ DEFAULT_DUPLICATE_THRESHOLD,
22
+ } from './duplicate-detector.js';
23
+ import {
24
+ findContradictions,
25
+ DEFAULT_CONTRADICTION_THRESHOLD,
26
+ type ContradictionCandidate,
27
+ } from './contradiction-detector.js';
28
+ import {
29
+ normalizeTag as normalizeTagPure,
30
+ normalizeAndDedup,
31
+ addTagAlias as addTagAliasPure,
32
+ getCanonicalTags as getCanonicalTagsPure,
33
+ seedDefaultAliases,
34
+ type TagStore,
35
+ } from './tag-manager.js';
36
+ import { initializeTables } from './schema.js';
37
+ import { computeHealthAudit, type HealthDataProvider } from './health-audit.js';
38
+ import { enrichEntryMetadata } from './metadata-enricher.js';
39
+
26
40
  // ─── Constants ──────────────────────────────────────────────────────
27
41
 
28
- const DEFAULT_DUPLICATE_THRESHOLD = 0.45;
29
- const MERGE_SUGGESTION_THRESHOLD = 0.65;
30
- const DEFAULT_CONTRADICTION_THRESHOLD = 0.4;
31
42
  const DEFAULT_STALE_DAYS = 90;
32
43
 
33
- const DEFAULT_TAG_ALIASES: Array<[string, string]> = [
34
- ['a11y', 'accessibility'],
35
- ['ts', 'typescript'],
36
- ['js', 'javascript'],
37
- ['css', 'styling'],
38
- ['tailwind', 'styling'],
39
- ['tw', 'styling'],
40
- ['vitest', 'testing'],
41
- ['jest', 'testing'],
42
- ['perf', 'performance'],
43
- ['sec', 'security'],
44
- ['auth', 'authentication'],
45
- ['i18n', 'internationalization'],
46
- ['l10n', 'localization'],
47
- ];
48
-
49
44
  // ─── Curator Class ──────────────────────────────────────────────────
50
45
 
51
46
  export class Curator {
52
47
  private vault: Vault;
53
48
  private provider: PersistenceProvider;
49
+ private tagStore: TagStore;
54
50
 
55
51
  constructor(vault: Vault) {
56
52
  this.vault = vault;
57
53
  this.provider = vault.getProvider();
58
- this.initializeTables();
59
- this.seedDefaultAliases();
54
+ this.tagStore = this.createTagStore();
55
+ initializeTables(this.provider);
56
+ this.provider.transaction(() => seedDefaultAliases(this.tagStore));
60
57
  }
61
58
 
62
- // ─── Schema ─────────────────────────────────────────────────────
63
-
64
- private initializeTables(): void {
65
- this.provider.execSql(`
66
- CREATE TABLE IF NOT EXISTS curator_entry_state (
67
- entry_id TEXT PRIMARY KEY,
68
- status TEXT NOT NULL DEFAULT 'active' CHECK(status IN ('active', 'stale', 'archived')),
69
- confidence REAL NOT NULL DEFAULT 1.0,
70
- source TEXT NOT NULL DEFAULT 'unknown' CHECK(source IN ('manual', 'capture', 'seed', 'unknown')),
71
- last_groomed_at INTEGER,
72
- created_at INTEGER NOT NULL DEFAULT (unixepoch())
73
- );
74
-
75
- CREATE TABLE IF NOT EXISTS curator_tag_canonical (
76
- tag TEXT PRIMARY KEY,
77
- description TEXT,
78
- created_at INTEGER NOT NULL DEFAULT (unixepoch())
79
- );
80
-
81
- CREATE TABLE IF NOT EXISTS curator_tag_alias (
82
- alias TEXT PRIMARY KEY,
83
- canonical TEXT NOT NULL,
84
- created_at INTEGER NOT NULL DEFAULT (unixepoch()),
85
- FOREIGN KEY (canonical) REFERENCES curator_tag_canonical(tag)
86
- );
87
-
88
- CREATE TABLE IF NOT EXISTS curator_changelog (
89
- id INTEGER PRIMARY KEY AUTOINCREMENT,
90
- action TEXT NOT NULL,
91
- entry_id TEXT NOT NULL,
92
- before_value TEXT,
93
- after_value TEXT,
94
- reason TEXT NOT NULL,
95
- created_at INTEGER NOT NULL DEFAULT (unixepoch())
96
- );
97
-
98
- CREATE TABLE IF NOT EXISTS curator_entry_history (
99
- id INTEGER PRIMARY KEY AUTOINCREMENT,
100
- entry_id TEXT NOT NULL,
101
- snapshot TEXT NOT NULL,
102
- changed_by TEXT DEFAULT 'system',
103
- change_reason TEXT,
104
- created_at INTEGER NOT NULL DEFAULT (unixepoch())
105
- );
106
-
107
- CREATE TABLE IF NOT EXISTS curator_contradictions (
108
- id INTEGER PRIMARY KEY AUTOINCREMENT,
109
- pattern_id TEXT NOT NULL,
110
- antipattern_id TEXT NOT NULL,
111
- similarity REAL NOT NULL,
112
- status TEXT NOT NULL DEFAULT 'open' CHECK(status IN ('open', 'resolved', 'dismissed')),
113
- created_at INTEGER NOT NULL DEFAULT (unixepoch()),
114
- resolved_at INTEGER,
115
- UNIQUE(pattern_id, antipattern_id)
116
- );
117
- CREATE INDEX IF NOT EXISTS idx_curator_state_status ON curator_entry_state(status);
118
- CREATE INDEX IF NOT EXISTS idx_curator_changelog_entry ON curator_changelog(entry_id);
119
- `);
120
- }
121
-
122
- private seedDefaultAliases(): void {
123
- this.provider.transaction(() => {
124
- const canonicals = new Set(DEFAULT_TAG_ALIASES.map(([, c]) => c));
125
- for (const tag of canonicals) {
126
- this.provider.run('INSERT OR IGNORE INTO curator_tag_canonical (tag) VALUES (?)', [tag]);
127
- }
128
- for (const [alias, canonical] of DEFAULT_TAG_ALIASES) {
129
- this.provider.run(
130
- 'INSERT OR IGNORE INTO curator_tag_alias (alias, canonical) VALUES (?, ?)',
131
- [alias, canonical],
59
+ private createTagStore(): TagStore {
60
+ const p = this.provider;
61
+ return {
62
+ getAlias(lower: string) {
63
+ return (
64
+ p.get<{ canonical: string }>('SELECT canonical FROM curator_tag_alias WHERE alias = ?', [
65
+ lower,
66
+ ])?.canonical ?? null
132
67
  );
133
- }
134
- });
68
+ },
69
+ insertCanonical(tag: string) {
70
+ p.run('INSERT OR IGNORE INTO curator_tag_canonical (tag) VALUES (?)', [tag]);
71
+ },
72
+ upsertAlias(alias: string, canonical: string) {
73
+ p.run('INSERT OR REPLACE INTO curator_tag_alias (alias, canonical) VALUES (?, ?)', [
74
+ alias,
75
+ canonical,
76
+ ]);
77
+ },
78
+ getCanonicalRows() {
79
+ return p.all<{ tag: string; description: string | null; alias_count: number }>(
80
+ `SELECT c.tag, c.description, (SELECT COUNT(*) FROM curator_tag_alias a WHERE a.canonical = c.tag) as alias_count FROM curator_tag_canonical c ORDER BY c.tag`,
81
+ );
82
+ },
83
+ countTagUsage(tag: string) {
84
+ return (
85
+ p.get<{ count: number }>('SELECT COUNT(*) as count FROM entries WHERE tags LIKE ?', [
86
+ `%"${tag}"%`,
87
+ ])?.count ?? 0
88
+ );
89
+ },
90
+ };
135
91
  }
136
92
 
137
93
  // ─── Status ─────────────────────────────────────────────────────
@@ -143,11 +99,9 @@ export class Curator {
143
99
  count: 0,
144
100
  }
145
101
  ).count;
146
-
147
102
  const lastGroomed = this.provider.get<{ ts: number | null }>(
148
103
  'SELECT MAX(last_groomed_at) as ts FROM curator_entry_state WHERE last_groomed_at IS NOT NULL',
149
104
  ) ?? { ts: null };
150
-
151
105
  return {
152
106
  initialized: true,
153
107
  tables: {
@@ -161,37 +115,17 @@ export class Curator {
161
115
  };
162
116
  }
163
117
 
164
- // ─── Tag Normalization ──────────────────────────────────────────
118
+ // ─── Tags (delegates to tag-manager) ──────────────────────────
165
119
 
166
120
  normalizeTag(tag: string): TagNormalizationResult {
167
- const lower = tag.toLowerCase().trim();
168
- const row = this.provider.get<{ canonical: string }>(
169
- 'SELECT canonical FROM curator_tag_alias WHERE alias = ?',
170
- [lower],
171
- );
172
- if (row) {
173
- return { original: tag, normalized: row.canonical, wasAliased: true };
174
- }
175
- return { original: tag, normalized: lower, wasAliased: false };
121
+ return normalizeTagPure(tag, this.tagStore);
176
122
  }
177
123
 
178
124
  normalizeTags(entryId: string): TagNormalizationResult[] {
179
125
  const entry = this.vault.get(entryId);
180
126
  if (!entry) return [];
181
-
182
- const results: TagNormalizationResult[] = [];
183
- const normalizedTags: string[] = [];
184
- let changed = false;
185
-
186
- for (const tag of entry.tags) {
187
- const result = this.normalizeTag(tag);
188
- results.push(result);
189
- normalizedTags.push(result.normalized);
190
- if (result.normalized !== tag) changed = true;
191
- }
192
-
127
+ const { results, dedupedTags, changed } = normalizeAndDedup(entry.tags, this.tagStore);
193
128
  if (changed) {
194
- const dedupedTags = [...new Set(normalizedTags)];
195
129
  this.provider.run('UPDATE entries SET tags = ?, updated_at = unixepoch() WHERE id = ?', [
196
130
  JSON.stringify(dedupedTags),
197
131
  entryId,
@@ -204,161 +138,39 @@ export class Curator {
204
138
  'Tag normalization',
205
139
  );
206
140
  }
207
-
208
141
  return results;
209
142
  }
210
143
 
211
144
  addTagAlias(alias: string, canonical: string): void {
212
- const lower = alias.toLowerCase().trim();
213
- const canonicalLower = canonical.toLowerCase().trim();
214
- this.provider.run('INSERT OR IGNORE INTO curator_tag_canonical (tag) VALUES (?)', [
215
- canonicalLower,
216
- ]);
217
- this.provider.run('INSERT OR REPLACE INTO curator_tag_alias (alias, canonical) VALUES (?, ?)', [
218
- lower,
219
- canonicalLower,
220
- ]);
145
+ addTagAliasPure(alias, canonical, this.tagStore);
221
146
  }
222
-
223
147
  getCanonicalTags(): CanonicalTag[] {
224
- const rows = this.provider.all<{
225
- tag: string;
226
- description: string | null;
227
- alias_count: number;
228
- }>(
229
- `SELECT c.tag, c.description,
230
- (SELECT COUNT(*) FROM curator_tag_alias a WHERE a.canonical = c.tag) as alias_count
231
- FROM curator_tag_canonical c
232
- ORDER BY c.tag`,
233
- );
234
-
235
- return rows.map((row) => ({
236
- tag: row.tag,
237
- description: row.description,
238
- usageCount: this.countTagUsage(row.tag),
239
- aliasCount: row.alias_count,
240
- }));
148
+ return getCanonicalTagsPure(this.tagStore);
241
149
  }
242
150
 
243
- private countTagUsage(tag: string): number {
244
- const row = this.provider.get<{ count: number }>(
245
- 'SELECT COUNT(*) as count FROM entries WHERE tags LIKE ?',
246
- [`%"${tag}"%`],
247
- );
248
- return row?.count ?? 0;
249
- }
250
-
251
- // ─── Duplicate Detection ────────────────────────────────────────
151
+ // ─── Duplicates (delegates to duplicate-detector) ─────────────
252
152
 
253
153
  detectDuplicates(entryId?: string, threshold?: number): DuplicateDetectionResult[] {
254
- const effectiveThreshold = threshold ?? DEFAULT_DUPLICATE_THRESHOLD;
255
- const entries = this.vault.list({ limit: 100000 });
256
- if (entries.length === 0) return [];
257
-
258
- // Build transient vocabulary
259
- const vocabulary = this.buildVocabulary(entries);
260
-
261
- // Build vectors for all entries
262
- const vectors = new Map<string, SparseVector>();
263
- for (const entry of entries) {
264
- const text = [entry.title, entry.description, entry.context ?? '', entry.tags.join(' ')].join(
265
- ' ',
266
- );
267
- vectors.set(entry.id, calculateTfIdf(tokenize(text), vocabulary));
268
- }
269
-
270
- const targetEntries = entryId ? entries.filter((e) => e.id === entryId) : entries;
271
-
272
- const results: DuplicateDetectionResult[] = [];
273
-
274
- for (const entry of targetEntries) {
275
- const entryVec = vectors.get(entry.id)!;
276
- const matches: DuplicateCandidate[] = [];
277
-
278
- for (const other of entries) {
279
- if (other.id === entry.id) continue;
280
- const otherVec = vectors.get(other.id)!;
281
- const similarity = cosineSimilarity(entryVec, otherVec);
282
- if (similarity >= effectiveThreshold) {
283
- matches.push({
284
- entryId: other.id,
285
- title: other.title,
286
- similarity,
287
- suggestMerge: similarity >= MERGE_SUGGESTION_THRESHOLD,
288
- });
289
- }
290
- }
291
-
292
- if (matches.length > 0) {
293
- matches.sort((a, b) => b.similarity - a.similarity);
294
- results.push({
295
- entryId: entry.id,
296
- matches,
297
- scannedCount: entries.length - 1,
298
- });
299
- }
300
- }
301
-
302
- return results;
154
+ return detectDuplicatesPure(this.vault.list({ limit: 100000 }), entryId, threshold);
303
155
  }
304
156
 
305
- // ─── Contradictions ─────────────────────────────────────────────
157
+ // ─── Contradictions (delegates to contradiction-detector) ─────
306
158
 
307
159
  detectContradictions(threshold?: number): Contradiction[] {
308
- const effectiveThreshold = threshold ?? DEFAULT_CONTRADICTION_THRESHOLD;
309
- const entries = this.vault.list({ limit: 100000 });
310
- const antipatterns = entries.filter((e) => e.type === 'anti-pattern');
311
- const patterns = entries.filter((e) => e.type === 'pattern');
312
-
313
- if (antipatterns.length === 0 || patterns.length === 0) return [];
314
-
315
- const vocabulary = this.buildVocabulary(entries);
316
- const detected: Contradiction[] = [];
317
-
318
- for (const ap of antipatterns) {
319
- // Stage 1: FTS5 candidate retrieval (fall back to all patterns if FTS returns empty)
320
- let candidates: IntelligenceEntry[];
321
- try {
322
- const searchResults = this.vault.search(ap.title, { type: 'pattern', limit: 20 });
323
- candidates = searchResults.length > 0 ? searchResults.map((r) => r.entry) : patterns;
324
- } catch {
325
- candidates = patterns;
326
- }
327
-
328
- // Stage 2: TF-IDF cosine similarity
329
- const apText = [ap.title, ap.description, ap.context ?? ''].join(' ');
330
- const apVec = calculateTfIdf(tokenize(apText), vocabulary);
331
-
332
- for (const pattern of candidates) {
333
- const pText = [pattern.title, pattern.description, pattern.context ?? ''].join(' ');
334
- const pVec = calculateTfIdf(tokenize(pText), vocabulary);
335
- const similarity = cosineSimilarity(apVec, pVec);
336
-
337
- if (similarity >= effectiveThreshold) {
338
- const result = this.provider.run(
339
- 'INSERT OR IGNORE INTO curator_contradictions (pattern_id, antipattern_id, similarity) VALUES (?, ?, ?)',
340
- [pattern.id, ap.id, similarity],
341
- );
342
- if (result.changes > 0) {
343
- const row = this.provider.get<Record<string, unknown>>(
344
- 'SELECT * FROM curator_contradictions WHERE pattern_id = ? AND antipattern_id = ?',
345
- [pattern.id, ap.id],
346
- );
347
- if (row) detected.push(this.rowToContradiction(row));
348
- }
349
- }
350
- }
351
- }
352
-
353
- return detected;
160
+ const searchFn = (title: string) =>
161
+ this.vault.search(title, { type: 'pattern', limit: 20 }).map((r) => r.entry);
162
+ return this.persistContradictions(
163
+ findContradictions(this.vault.list({ limit: 100000 }), threshold, searchFn),
164
+ );
354
165
  }
355
166
 
356
167
  getContradictions(status?: ContradictionStatus): Contradiction[] {
357
168
  const query = status
358
169
  ? 'SELECT * FROM curator_contradictions WHERE status = ? ORDER BY similarity DESC'
359
170
  : 'SELECT * FROM curator_contradictions ORDER BY similarity DESC';
360
- const rows = this.provider.all<Record<string, unknown>>(query, status ? [status] : undefined);
361
- return rows.map((r) => this.rowToContradiction(r));
171
+ return this.provider
172
+ .all<Record<string, unknown>>(query, status ? [status] : undefined)
173
+ .map((r) => this.rowToContradiction(r));
362
174
  }
363
175
 
364
176
  resolveContradiction(id: number, resolution: 'resolved' | 'dismissed'): Contradiction | null {
@@ -373,103 +185,45 @@ export class Curator {
373
185
  return row ? this.rowToContradiction(row) : null;
374
186
  }
375
187
 
376
- async detectContradictionsHybrid(threshold?: number): Promise<{
377
- contradictions: Contradiction[];
378
- method: 'tfidf-only';
379
- }> {
380
- const effectiveThreshold = threshold ?? DEFAULT_CONTRADICTION_THRESHOLD;
381
- const entries = this.vault.list({ limit: 100000 });
382
- const antipatterns = entries.filter((e) => e.type === 'anti-pattern');
383
- const patterns = entries.filter((e) => e.type === 'pattern');
384
-
385
- if (antipatterns.length === 0 || patterns.length === 0) {
386
- return { contradictions: [], method: 'tfidf-only' };
387
- }
388
-
389
- const vocabulary = this.buildVocabulary(entries);
390
- const detected: Contradiction[] = [];
391
-
392
- for (const ap of antipatterns) {
393
- let candidates: IntelligenceEntry[];
394
- try {
395
- const searchResults = this.vault.search(ap.title, { type: 'pattern', limit: 20 });
396
- candidates = searchResults.length > 0 ? searchResults.map((r) => r.entry) : patterns;
397
- } catch {
398
- candidates = patterns;
399
- }
400
-
401
- const apText = [ap.title, ap.description, ap.context ?? ''].join(' ');
402
- const apVec = calculateTfIdf(tokenize(apText), vocabulary);
403
-
404
- for (const pattern of candidates) {
405
- const pText = [pattern.title, pattern.description, pattern.context ?? ''].join(' ');
406
- const pVec = calculateTfIdf(tokenize(pText), vocabulary);
407
- const finalScore = cosineSimilarity(apVec, pVec);
408
-
409
- if (finalScore >= effectiveThreshold) {
410
- const result = this.provider.run(
411
- 'INSERT OR IGNORE INTO curator_contradictions (pattern_id, antipattern_id, similarity) VALUES (?, ?, ?)',
412
- [pattern.id, ap.id, finalScore],
413
- );
414
- if (result.changes > 0) {
415
- const row = this.provider.get<Record<string, unknown>>(
416
- 'SELECT * FROM curator_contradictions WHERE pattern_id = ? AND antipattern_id = ?',
417
- [pattern.id, ap.id],
418
- );
419
- if (row) detected.push(this.rowToContradiction(row));
420
- }
421
- }
422
- }
423
- }
424
-
188
+ async detectContradictionsHybrid(
189
+ threshold?: number,
190
+ ): Promise<{ contradictions: Contradiction[]; method: 'tfidf-only' }> {
191
+ const searchFn = (title: string) =>
192
+ this.vault.search(title, { type: 'pattern', limit: 20 }).map((r) => r.entry);
425
193
  return {
426
- contradictions: detected,
194
+ contradictions: this.persistContradictions(
195
+ findContradictions(this.vault.list({ limit: 100000 }), threshold, searchFn),
196
+ ),
427
197
  method: 'tfidf-only',
428
198
  };
429
199
  }
430
200
 
431
- // ─── Grooming ───────────────────────────────────────────────────
201
+ // ─── Grooming ─────────────────────────────────────────────────
432
202
 
433
203
  groomEntry(entryId: string): GroomResult | null {
434
204
  const entry = this.vault.get(entryId);
435
205
  if (!entry) return null;
436
-
437
206
  const tagsNormalized = this.normalizeTags(entryId);
438
-
439
- // Check staleness based on entry's updated_at timestamp
440
207
  const row = this.provider.get<{ updated_at: number }>(
441
208
  'SELECT updated_at FROM entries WHERE id = ?',
442
209
  [entryId],
443
210
  );
444
211
  const now = Math.floor(Date.now() / 1000);
445
212
  const stale = row ? now - row.updated_at > DEFAULT_STALE_DAYS * 86400 : false;
446
-
447
213
  const status = stale ? 'stale' : 'active';
448
-
449
- // Upsert entry state
450
214
  this.provider.run(
451
- `INSERT INTO curator_entry_state (entry_id, status, last_groomed_at)
452
- VALUES (?, ?, unixepoch())
453
- ON CONFLICT(entry_id) DO UPDATE SET status = excluded.status, last_groomed_at = unixepoch()`,
215
+ `INSERT INTO curator_entry_state (entry_id, status, last_groomed_at) VALUES (?, ?, unixepoch()) ON CONFLICT(entry_id) DO UPDATE SET status = excluded.status, last_groomed_at = unixepoch()`,
454
216
  [entryId, status],
455
217
  );
456
-
457
218
  this.logChange('groom', entryId, null, `status=${status}`, 'Routine grooming');
458
-
459
- return {
460
- entryId,
461
- tagsNormalized,
462
- stale,
463
- lastGroomedAt: now,
464
- };
219
+ return { entryId, tagsNormalized, stale, lastGroomedAt: now };
465
220
  }
466
221
 
467
222
  groomAll(): GroomAllResult {
468
223
  const start = Date.now();
469
224
  const entries = this.vault.list({ limit: 100000 });
470
- let tagsNormalized = 0;
471
- let staleCount = 0;
472
-
225
+ let tagsNormalized = 0,
226
+ staleCount = 0;
473
227
  for (const entry of entries) {
474
228
  const result = this.groomEntry(entry.id);
475
229
  if (result) {
@@ -477,7 +231,6 @@ export class Curator {
477
231
  if (result.stale) staleCount++;
478
232
  }
479
233
  }
480
-
481
234
  return {
482
235
  totalEntries: entries.length,
483
236
  groomedCount: entries.length,
@@ -487,7 +240,7 @@ export class Curator {
487
240
  };
488
241
  }
489
242
 
490
- // ─── Consolidation ─────────────────────────────────────────────
243
+ // ─── Consolidation ───────────────────────────────────────────
491
244
 
492
245
  consolidate(options?: ConsolidationOptions): ConsolidationResult {
493
246
  const start = Date.now();
@@ -496,31 +249,19 @@ export class Curator {
496
249
  const duplicateThreshold = options?.duplicateThreshold ?? DEFAULT_DUPLICATE_THRESHOLD;
497
250
  const contradictionThreshold =
498
251
  options?.contradictionThreshold ?? DEFAULT_CONTRADICTION_THRESHOLD;
499
-
500
- // Detect duplicates
501
252
  const duplicates = this.detectDuplicates(undefined, duplicateThreshold);
502
-
503
- // Detect stale entries
504
253
  const now = Math.floor(Date.now() / 1000);
505
- const staleThreshold = now - staleDaysThreshold * 86400;
506
254
  const staleRows = this.provider.all<{ id: string }>(
507
255
  'SELECT id FROM entries WHERE updated_at < ?',
508
- [staleThreshold],
256
+ [now - staleDaysThreshold * 86400],
509
257
  );
510
258
  const staleEntries = staleRows.map((r) => r.id);
511
-
512
- // Detect contradictions
513
259
  const contradictions = this.detectContradictions(contradictionThreshold);
514
-
515
260
  let mutations = 0;
516
-
517
261
  if (!dryRun) {
518
- // Archive stale entries
519
262
  for (const entryId of staleEntries) {
520
263
  this.provider.run(
521
- `INSERT INTO curator_entry_state (entry_id, status, last_groomed_at)
522
- VALUES (?, 'archived', unixepoch())
523
- ON CONFLICT(entry_id) DO UPDATE SET status = 'archived', last_groomed_at = unixepoch()`,
264
+ `INSERT INTO curator_entry_state (entry_id, status, last_groomed_at) VALUES (?, 'archived', unixepoch()) ON CONFLICT(entry_id) DO UPDATE SET status = 'archived', last_groomed_at = unixepoch()`,
524
265
  [entryId],
525
266
  );
526
267
  this.logChange(
@@ -532,8 +273,6 @@ export class Curator {
532
273
  );
533
274
  mutations++;
534
275
  }
535
-
536
- // Remove lower-similarity duplicates (keep the first entry, remove matches)
537
276
  const removed = new Set<string>();
538
277
  for (const result of duplicates) {
539
278
  for (const match of result.matches) {
@@ -552,7 +291,6 @@ export class Curator {
552
291
  }
553
292
  }
554
293
  }
555
-
556
294
  return {
557
295
  dryRun,
558
296
  duplicates,
@@ -563,139 +301,42 @@ export class Curator {
563
301
  };
564
302
  }
565
303
 
566
- // ─── Changelog ──────────────────────────────────────────────────
304
+ // ─── Changelog ────────────────────────────────────────────────
567
305
 
568
306
  getEntryHistory(entryId: string, limit?: number): ChangelogEntry[] {
569
- const rows = this.provider.all<Record<string, unknown>>(
570
- 'SELECT * FROM curator_changelog WHERE entry_id = ? ORDER BY created_at DESC, id DESC LIMIT ?',
571
- [entryId, limit ?? 50],
572
- );
573
- return rows.map((r) => this.rowToChangelog(r));
307
+ return this.provider
308
+ .all<Record<string, unknown>>(
309
+ 'SELECT * FROM curator_changelog WHERE entry_id = ? ORDER BY created_at DESC, id DESC LIMIT ?',
310
+ [entryId, limit ?? 50],
311
+ )
312
+ .map((r) => this.rowToChangelog(r));
574
313
  }
575
314
 
576
- // ─── Health Audit ───────────────────────────────────────────────
315
+ // ─── Health Audit (delegates to health-audit) ─────────────────
577
316
 
578
317
  healthAudit(): HealthAuditResult {
579
318
  const entries = this.vault.list({ limit: 100000 });
580
- const recommendations: string[] = [];
581
-
582
- if (entries.length === 0) {
583
- return {
584
- score: 100,
585
- metrics: { coverage: 1, freshness: 1, quality: 1, tagHealth: 1 },
586
- recommendations: ['Vault is empty add knowledge entries to get started.'],
587
- };
588
- }
589
-
590
- let score = 100;
591
-
592
- // Coverage: penalize if no anti-patterns or no patterns
593
- const typeCount: Record<string, number> = { pattern: 0, 'anti-pattern': 0, rule: 0 };
594
- for (const e of entries) {
595
- typeCount[e.type] = (typeCount[e.type] ?? 0) + 1;
596
- }
597
- const hasPatterns = typeCount.pattern > 0;
598
- const hasAntiPatterns = typeCount['anti-pattern'] > 0;
599
- const hasRules = typeCount.rule > 0;
600
- let coverageScore = 1;
601
- if (!hasPatterns) {
602
- score -= 10;
603
- coverageScore -= 0.33;
604
- recommendations.push('No patterns found — add patterns to improve coverage.');
605
- }
606
- if (!hasAntiPatterns) {
607
- score -= 5;
608
- coverageScore -= 0.17;
609
- recommendations.push('No anti-patterns found — add anti-patterns to detect contradictions.');
610
- }
611
- if (!hasRules) {
612
- score -= 5;
613
- coverageScore -= 0.17;
614
- recommendations.push('No rules found — add rules for completeness.');
615
- }
616
- coverageScore = Math.max(0, coverageScore);
617
-
618
- // Freshness: penalize stale entries
619
- const now = Math.floor(Date.now() / 1000);
620
- const staleThreshold = now - DEFAULT_STALE_DAYS * 86400;
621
- const staleCount = (
622
- this.provider.get<{ count: number }>(
623
- 'SELECT COUNT(*) as count FROM entries WHERE updated_at < ?',
624
- [staleThreshold],
625
- ) ?? { count: 0 }
626
- ).count;
627
- const staleRatio = staleCount / entries.length;
628
- const freshnessScore = 1 - staleRatio;
629
- if (staleRatio > 0.3) {
630
- const penalty = Math.min(20, Math.round(staleRatio * 30));
631
- score -= penalty;
632
- recommendations.push(
633
- `${staleCount} stale entries (${Math.round(staleRatio * 100)}%) — run grooming to update.`,
634
- );
635
- }
636
-
637
- // Quality: penalize duplicates and contradictions
638
- const duplicates = this.detectDuplicates();
639
- const contradictions = this.getContradictions('open');
640
- let qualityScore = 1;
641
- if (duplicates.length > 0) {
642
- const penalty = Math.min(15, duplicates.length * 3);
643
- score -= penalty;
644
- qualityScore -= penalty / 30;
645
- recommendations.push(`${duplicates.length} entries have duplicates — run consolidation.`);
646
- }
647
- if (contradictions.length > 0) {
648
- const penalty = Math.min(15, contradictions.length * 5);
649
- score -= penalty;
650
- qualityScore -= penalty / 30;
651
- recommendations.push(`${contradictions.length} open contradictions — resolve or dismiss.`);
652
- }
653
- qualityScore = Math.max(0, qualityScore);
654
-
655
- // Tag health: penalize entries with few or no tags
656
- const lowTagEntries = entries.filter((e) => e.tags.length < 2);
657
- const lowTagRatio = lowTagEntries.length / entries.length;
658
- const tagHealthScore = 1 - lowTagRatio;
659
- if (lowTagRatio > 0.3) {
660
- const penalty = Math.min(10, Math.round(lowTagRatio * 15));
661
- score -= penalty;
662
- recommendations.push(
663
- `${lowTagEntries.length} entries have fewer than 2 tags — improve tagging.`,
664
- );
665
- }
666
-
667
- // Penalize ungroomed entries
668
- const groomedCount = (
669
- this.provider.get<{ count: number }>(
670
- 'SELECT COUNT(*) as count FROM curator_entry_state WHERE last_groomed_at IS NOT NULL',
671
- ) ?? { count: 0 }
672
- ).count;
673
- if (groomedCount < entries.length) {
674
- const ungroomed = entries.length - groomedCount;
675
- const penalty = Math.min(10, Math.round((ungroomed / entries.length) * 10));
676
- score -= penalty;
677
- recommendations.push(`${ungroomed} entries never groomed — run groomAll().`);
678
- }
679
-
680
- score = Math.max(0, score);
681
-
682
- if (recommendations.length === 0) {
683
- recommendations.push('Vault is healthy — no issues detected.');
684
- }
685
-
686
- return {
687
- score,
688
- metrics: {
689
- coverage: coverageScore,
690
- freshness: freshnessScore,
691
- quality: qualityScore,
692
- tagHealth: tagHealthScore,
693
- },
694
- recommendations,
319
+ const dataProvider: HealthDataProvider = {
320
+ getStaleCount: (threshold) =>
321
+ (
322
+ this.provider.get<{ count: number }>(
323
+ 'SELECT COUNT(*) as count FROM entries WHERE updated_at < ?',
324
+ [threshold],
325
+ ) ?? { count: 0 }
326
+ ).count,
327
+ getGroomedCount: () =>
328
+ (
329
+ this.provider.get<{ count: number }>(
330
+ 'SELECT COUNT(*) as count FROM curator_entry_state WHERE last_groomed_at IS NOT NULL',
331
+ ) ?? { count: 0 }
332
+ ).count,
333
+ getDuplicates: () => this.detectDuplicates(),
334
+ getOpenContradictions: () => this.getContradictions('open'),
695
335
  };
336
+ return computeHealthAudit(entries, dataProvider, DEFAULT_STALE_DAYS);
696
337
  }
697
338
 
698
- // ─── Entry History (Version Snapshots) ─────────────────────────
339
+ // ─── Entry History (Version Snapshots) ────────────────────────
699
340
 
700
341
  recordSnapshot(
701
342
  entryId: string,
@@ -704,12 +345,10 @@ export class Curator {
704
345
  ): { recorded: boolean; historyId: number } {
705
346
  const entry = this.vault.get(entryId);
706
347
  if (!entry) return { recorded: false, historyId: -1 };
707
-
708
348
  const result = this.provider.run(
709
349
  'INSERT INTO curator_entry_history (entry_id, snapshot, changed_by, change_reason, created_at) VALUES (?, ?, ?, ?, unixepoch())',
710
350
  [entryId, JSON.stringify(entry), changedBy ?? 'system', changeReason ?? null],
711
351
  );
712
-
713
352
  return { recorded: true, historyId: Number(result.lastInsertRowid) };
714
353
  }
715
354
 
@@ -721,22 +360,22 @@ export class Curator {
721
360
  changeReason: string | null;
722
361
  createdAt: number;
723
362
  }> {
724
- const rows = this.provider.all<Record<string, unknown>>(
725
- 'SELECT * FROM curator_entry_history WHERE entry_id = ? ORDER BY created_at ASC, id ASC',
726
- [entryId],
727
- );
728
-
729
- return rows.map((row) => ({
730
- historyId: row.id as number,
731
- entryId: row.entry_id as string,
732
- snapshot: JSON.parse(row.snapshot as string) as IntelligenceEntry,
733
- changedBy: row.changed_by as string,
734
- changeReason: (row.change_reason as string) ?? null,
735
- createdAt: row.created_at as number,
736
- }));
363
+ return this.provider
364
+ .all<Record<string, unknown>>(
365
+ 'SELECT * FROM curator_entry_history WHERE entry_id = ? ORDER BY created_at ASC, id ASC',
366
+ [entryId],
367
+ )
368
+ .map((row) => ({
369
+ historyId: row.id as number,
370
+ entryId: row.entry_id as string,
371
+ snapshot: JSON.parse(row.snapshot as string) as IntelligenceEntry,
372
+ changedBy: row.changed_by as string,
373
+ changeReason: (row.change_reason as string) ?? null,
374
+ createdAt: row.created_at as number,
375
+ }));
737
376
  }
738
377
 
739
- // ─── Queue Stats ──────────────────────────────────────────────
378
+ // ─── Queue Stats ─────────────────────────────────────────────
740
379
 
741
380
  getQueueStats(): {
742
381
  totalEntries: number;
@@ -746,57 +385,50 @@ export class Curator {
746
385
  freshEntries: number;
747
386
  avgDaysSinceGroom: number;
748
387
  } {
388
+ const p = this.provider;
749
389
  const totalEntries = (
750
- this.provider.get<{ count: number }>('SELECT COUNT(*) as count FROM entries') ?? { count: 0 }
390
+ p.get<{ count: number }>('SELECT COUNT(*) as count FROM entries') ?? { count: 0 }
751
391
  ).count;
752
-
753
392
  const groomedEntries = (
754
- this.provider.get<{ count: number }>(
393
+ p.get<{ count: number }>(
755
394
  'SELECT COUNT(*) as count FROM curator_entry_state WHERE last_groomed_at IS NOT NULL',
756
395
  ) ?? { count: 0 }
757
396
  ).count;
758
-
759
- const ungroomedEntries = totalEntries - groomedEntries;
760
-
761
397
  const now = Math.floor(Date.now() / 1000);
762
- const staleThreshold = now - 30 * 86400;
763
- const freshThreshold = now - 7 * 86400;
764
-
765
398
  const staleEntries = (
766
- this.provider.get<{ count: number }>(
399
+ p.get<{ count: number }>(
767
400
  'SELECT COUNT(*) as count FROM curator_entry_state WHERE last_groomed_at IS NOT NULL AND last_groomed_at < ?',
768
- [staleThreshold],
401
+ [now - 30 * 86400],
769
402
  ) ?? { count: 0 }
770
403
  ).count;
771
-
772
404
  const freshEntries = (
773
- this.provider.get<{ count: number }>(
405
+ p.get<{ count: number }>(
774
406
  'SELECT COUNT(*) as count FROM curator_entry_state WHERE last_groomed_at IS NOT NULL AND last_groomed_at >= ?',
775
- [freshThreshold],
407
+ [now - 7 * 86400],
776
408
  ) ?? { count: 0 }
777
409
  ).count;
778
-
779
410
  let avgDaysSinceGroom = 0;
780
411
  if (groomedEntries > 0) {
781
- const sumRow = this.provider.get<{ total: number | null }>(
782
- 'SELECT SUM(? - last_groomed_at) as total FROM curator_entry_state WHERE last_groomed_at IS NOT NULL',
783
- [now],
784
- ) ?? { total: 0 };
785
- const totalSeconds = sumRow.total ?? 0;
412
+ const totalSeconds =
413
+ (
414
+ p.get<{ total: number | null }>(
415
+ 'SELECT SUM(? - last_groomed_at) as total FROM curator_entry_state WHERE last_groomed_at IS NOT NULL',
416
+ [now],
417
+ ) ?? { total: 0 }
418
+ ).total ?? 0;
786
419
  avgDaysSinceGroom = Math.round((totalSeconds / groomedEntries / 86400) * 100) / 100;
787
420
  }
788
-
789
421
  return {
790
422
  totalEntries,
791
423
  groomedEntries,
792
- ungroomedEntries,
424
+ ungroomedEntries: totalEntries - groomedEntries,
793
425
  staleEntries,
794
426
  freshEntries,
795
427
  avgDaysSinceGroom,
796
428
  };
797
429
  }
798
430
 
799
- // ─── Metadata Enrichment ──────────────────────────────────────
431
+ // ─── Metadata Enrichment (delegates to metadata-enricher) ────
800
432
 
801
433
  enrichMetadata(entryId: string): {
802
434
  enriched: boolean;
@@ -804,79 +436,10 @@ export class Curator {
804
436
  } {
805
437
  const entry = this.vault.get(entryId);
806
438
  if (!entry) return { enriched: false, changes: [] };
807
-
808
- const changes: Array<{ field: string; before: string; after: string }> = [];
809
- const updates: Partial<
810
- Pick<IntelligenceEntry, 'title' | 'description' | 'tags' | 'severity' | 'type'>
811
- > = {};
812
-
813
- // Auto-capitalize title
814
- if (entry.title.length > 0 && entry.title[0] !== entry.title[0].toUpperCase()) {
815
- const capitalized = entry.title[0].toUpperCase() + entry.title.slice(1);
816
- changes.push({ field: 'title', before: entry.title, after: capitalized });
817
- updates.title = capitalized;
818
- }
819
-
820
- // Normalize tags: lowercase, trim, dedup
821
- const normalizedTags = [...new Set(entry.tags.map((t) => t.toLowerCase().trim()))];
822
- const tagsChanged =
823
- normalizedTags.length !== entry.tags.length ||
824
- normalizedTags.some((t, i) => t !== entry.tags[i]);
825
- if (tagsChanged) {
826
- changes.push({
827
- field: 'tags',
828
- before: JSON.stringify(entry.tags),
829
- after: JSON.stringify(normalizedTags),
830
- });
831
- updates.tags = normalizedTags;
832
- }
833
-
834
- // Infer severity from keywords if currently 'suggestion'
835
- if (entry.severity === 'suggestion') {
836
- const text = (entry.title + ' ' + entry.description).toLowerCase();
837
- const criticalKeywords = ['never', 'must not', 'critical', 'security', 'vulnerability'];
838
- const warningKeywords = ['avoid', 'should not', 'deprecated', 'careful', 'warning'];
839
- if (criticalKeywords.some((k) => text.includes(k))) {
840
- changes.push({ field: 'severity', before: entry.severity, after: 'critical' });
841
- updates.severity = 'critical';
842
- } else if (warningKeywords.some((k) => text.includes(k))) {
843
- changes.push({ field: 'severity', before: entry.severity, after: 'warning' });
844
- updates.severity = 'warning';
845
- }
846
- }
847
-
848
- // Infer type from title patterns
849
- if (entry.type === 'pattern') {
850
- const titleLower = entry.title.toLowerCase();
851
- if (
852
- titleLower.startsWith('avoid') ||
853
- titleLower.startsWith('never') ||
854
- titleLower.startsWith("don't") ||
855
- titleLower.startsWith('do not')
856
- ) {
857
- changes.push({ field: 'type', before: entry.type, after: 'anti-pattern' });
858
- updates.type = 'anti-pattern';
859
- }
860
- }
861
-
862
- // Trim whitespace from description
863
- const trimmed = entry.description.trim();
864
- if (trimmed !== entry.description) {
865
- changes.push({ field: 'description', before: entry.description, after: trimmed });
866
- updates.description = trimmed;
867
- }
868
-
869
- if (changes.length === 0) {
870
- return { enriched: false, changes: [] };
871
- }
872
-
873
- // Apply updates
439
+ const { changes, updates } = enrichEntryMetadata(entry);
440
+ if (changes.length === 0) return { enriched: false, changes: [] };
874
441
  this.vault.update(entryId, updates);
875
-
876
- // Record snapshot
877
442
  this.recordSnapshot(entryId, 'curator', 'Metadata enrichment');
878
-
879
- // Log change
880
443
  this.logChange(
881
444
  'enrich_metadata',
882
445
  entryId,
@@ -884,30 +447,27 @@ export class Curator {
884
447
  JSON.stringify(changes.map((c) => c.after)),
885
448
  'Rule-based metadata enrichment',
886
449
  );
887
-
888
450
  return { enriched: true, changes };
889
451
  }
890
452
 
891
- // ─── Private Helpers ────────────────────────────────────────────
453
+ // ─── Private Helpers ──────────────────────────────────────────
892
454
 
893
- private buildVocabulary(entries: IntelligenceEntry[]): Map<string, number> {
894
- const docCount = entries.length;
895
- const termDocFreq = new Map<string, number>();
896
- for (const entry of entries) {
897
- const text = [entry.title, entry.description, entry.context ?? '', entry.tags.join(' ')].join(
898
- ' ',
455
+ private persistContradictions(candidates: ContradictionCandidate[]): Contradiction[] {
456
+ const detected: Contradiction[] = [];
457
+ for (const c of candidates) {
458
+ const result = this.provider.run(
459
+ 'INSERT OR IGNORE INTO curator_contradictions (pattern_id, antipattern_id, similarity) VALUES (?, ?, ?)',
460
+ [c.patternId, c.antipatternId, c.similarity],
899
461
  );
900
- const tokens = new Set(tokenize(text));
901
- for (const token of tokens) {
902
- termDocFreq.set(token, (termDocFreq.get(token) ?? 0) + 1);
462
+ if (result.changes > 0) {
463
+ const row = this.provider.get<Record<string, unknown>>(
464
+ 'SELECT * FROM curator_contradictions WHERE pattern_id = ? AND antipattern_id = ?',
465
+ [c.patternId, c.antipatternId],
466
+ );
467
+ if (row) detected.push(this.rowToContradiction(row));
903
468
  }
904
469
  }
905
- const vocabulary = new Map<string, number>();
906
- for (const [term, df] of termDocFreq) {
907
- const idf = Math.log((docCount + 1) / (df + 1)) + 1;
908
- vocabulary.set(term, idf);
909
- }
910
- return vocabulary;
470
+ return detected;
911
471
  }
912
472
 
913
473
  private logChange(