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