@remnic/core 1.1.2 → 1.1.3

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 (485) hide show
  1. package/dist/abort-error.js +1 -0
  2. package/dist/abstraction-nodes.js +1 -0
  3. package/dist/access-audit.js +1 -0
  4. package/dist/access-cli.js +70 -45
  5. package/dist/access-cli.js.map +1 -1
  6. package/dist/access-http.d.ts +50 -5
  7. package/dist/access-http.js +37 -15
  8. package/dist/access-idempotency.js +1 -0
  9. package/dist/access-mcp.d.ts +10 -5
  10. package/dist/access-mcp.js +36 -13
  11. package/dist/access-schema.d.ts +133 -13
  12. package/dist/access-schema.js +20 -1
  13. package/dist/access-service-_AEUMVyX.d.ts +1981 -0
  14. package/dist/access-service.d.ts +11 -6
  15. package/dist/access-service.js +38 -14
  16. package/dist/active-memory-bridge.js +1 -0
  17. package/dist/active-recall.js +1 -0
  18. package/dist/active-recall.js.map +1 -1
  19. package/dist/behavior-learner.js +1 -0
  20. package/dist/behavior-learner.js.map +1 -1
  21. package/dist/behavior-signals.js +1 -0
  22. package/dist/bootstrap.d.ts +6 -4
  23. package/dist/bootstrap.js +1 -0
  24. package/dist/boxes.js +1 -0
  25. package/dist/briefing.d.ts +9 -5
  26. package/dist/briefing.js +9 -6
  27. package/dist/buffer-surprise-report.js +1 -0
  28. package/dist/buffer-surprise.js +1 -0
  29. package/dist/buffer.d.ts +1 -1
  30. package/dist/buffer.js +1 -0
  31. package/dist/calibration.d.ts +8 -1
  32. package/dist/calibration.js +10 -2
  33. package/dist/calibration.js.map +1 -1
  34. package/dist/capsule-cli.d.ts +137 -0
  35. package/dist/capsule-cli.js +34 -0
  36. package/dist/capsule-crypto-5CYAGVC5.js +18 -0
  37. package/dist/capsule-export-NZQPOTQ4.js +17 -0
  38. package/dist/capsule-export-NZQPOTQ4.js.map +1 -0
  39. package/dist/capsule-import-SDCUXLEV.js +16 -0
  40. package/dist/capsule-import-SDCUXLEV.js.map +1 -0
  41. package/dist/capsule-merge-DI7PNQ2H.js +189 -0
  42. package/dist/capsule-merge-DI7PNQ2H.js.map +1 -0
  43. package/dist/causal-behavior.js +1 -0
  44. package/dist/causal-behavior.js.map +1 -1
  45. package/dist/causal-chain.js +1 -0
  46. package/dist/causal-consolidation.js +11 -8
  47. package/dist/causal-consolidation.js.map +1 -1
  48. package/dist/causal-retrieval.js +2 -1
  49. package/dist/causal-retrieval.js.map +1 -1
  50. package/dist/causal-trajectory-graph.js +4 -1
  51. package/dist/causal-trajectory-graph.js.map +1 -1
  52. package/dist/causal-trajectory.js +2 -1
  53. package/dist/chunk-2LSZVONP.js +67 -0
  54. package/dist/chunk-2LSZVONP.js.map +1 -0
  55. package/dist/chunk-32KD5IHZ.js +245 -0
  56. package/dist/chunk-32KD5IHZ.js.map +1 -0
  57. package/dist/{chunk-VDX363PS.js → chunk-34F3PLWZ.js} +10 -3
  58. package/dist/chunk-34F3PLWZ.js.map +1 -0
  59. package/dist/chunk-3KIS4VGT.js +228 -0
  60. package/dist/chunk-3KIS4VGT.js.map +1 -0
  61. package/dist/chunk-3LCWFNVS.js +350 -0
  62. package/dist/chunk-3LCWFNVS.js.map +1 -0
  63. package/dist/chunk-43EKP2UK.js +26 -0
  64. package/dist/chunk-43EKP2UK.js.map +1 -0
  65. package/dist/chunk-457A4P3L.js +119 -0
  66. package/dist/chunk-457A4P3L.js.map +1 -0
  67. package/dist/{chunk-TMYO7B5P.js → chunk-47WOM4YW.js} +2 -2
  68. package/dist/{chunk-OC5OXUQ4.js → chunk-4PLGJRBV.js} +653 -17
  69. package/dist/chunk-4PLGJRBV.js.map +1 -0
  70. package/dist/{chunk-PVICZTKG.js → chunk-55FXRRSJ.js} +5 -5
  71. package/dist/{chunk-PVICZTKG.js.map → chunk-55FXRRSJ.js.map} +1 -1
  72. package/dist/{chunk-ULYOGL6R.js → chunk-5HRY2WRF.js} +7 -3
  73. package/dist/chunk-5HRY2WRF.js.map +1 -0
  74. package/dist/chunk-6TBWYBJ3.js +236 -0
  75. package/dist/chunk-6TBWYBJ3.js.map +1 -0
  76. package/dist/chunk-74EMIVE4.js +329 -0
  77. package/dist/chunk-74EMIVE4.js.map +1 -0
  78. package/dist/chunk-74WWN7ZW.js +82 -0
  79. package/dist/chunk-74WWN7ZW.js.map +1 -0
  80. package/dist/{chunk-6YJHX2DL.js → chunk-7GCMLT7J.js} +242 -22
  81. package/dist/chunk-7GCMLT7J.js.map +1 -0
  82. package/dist/chunk-A6XUJE5D.js +126 -0
  83. package/dist/chunk-A6XUJE5D.js.map +1 -0
  84. package/dist/chunk-AJA46VX5.js +393 -0
  85. package/dist/chunk-AJA46VX5.js.map +1 -0
  86. package/dist/{chunk-UWB5LMWY.js → chunk-AKUCB2OG.js} +525 -24
  87. package/dist/chunk-AKUCB2OG.js.map +1 -0
  88. package/dist/chunk-ASIQZXYO.js +277 -0
  89. package/dist/chunk-ASIQZXYO.js.map +1 -0
  90. package/dist/{chunk-DG6YMRDC.js → chunk-B2TL6GA2.js} +2 -2
  91. package/dist/chunk-BJMBJZ2Y.js +290 -0
  92. package/dist/chunk-BJMBJZ2Y.js.map +1 -0
  93. package/dist/chunk-BT7NVCML.js +79 -0
  94. package/dist/chunk-BT7NVCML.js.map +1 -0
  95. package/dist/chunk-CK5NTM2S.js +454 -0
  96. package/dist/chunk-CK5NTM2S.js.map +1 -0
  97. package/dist/{chunk-AYXIPSZO.js → chunk-CRU27Q4J.js} +2 -2
  98. package/dist/{chunk-F5VP6YCB.js → chunk-DCE6SQLA.js} +572 -155
  99. package/dist/chunk-DCE6SQLA.js.map +1 -0
  100. package/dist/{chunk-CUPFXL3J.js → chunk-DHRQHX36.js} +4 -4
  101. package/dist/chunk-DHRQHX36.js.map +1 -0
  102. package/dist/{chunk-STGWEHYR.js → chunk-DR7MCMPS.js} +981 -61
  103. package/dist/chunk-DR7MCMPS.js.map +1 -0
  104. package/dist/chunk-FP2373TW.js +149 -0
  105. package/dist/chunk-FP2373TW.js.map +1 -0
  106. package/dist/{chunk-RBBWYEFJ.js → chunk-G2WADRQ3.js} +1 -1
  107. package/dist/chunk-G7D6GZ5J.js +48 -0
  108. package/dist/chunk-G7D6GZ5J.js.map +1 -0
  109. package/dist/chunk-H7XKCNR6.js +60 -0
  110. package/dist/chunk-H7XKCNR6.js.map +1 -0
  111. package/dist/{chunk-3YGHKTBF.js → chunk-IM3JSE73.js} +953 -322
  112. package/dist/chunk-IM3JSE73.js.map +1 -0
  113. package/dist/chunk-IXEJRKCZ.js +18 -0
  114. package/dist/chunk-IXEJRKCZ.js.map +1 -0
  115. package/dist/chunk-IYY4MCPG.js +275 -0
  116. package/dist/chunk-IYY4MCPG.js.map +1 -0
  117. package/dist/{chunk-BECYBZLX.js → chunk-JWSENLQI.js} +502 -22
  118. package/dist/chunk-JWSENLQI.js.map +1 -0
  119. package/dist/chunk-KNKUID7G.js +183 -0
  120. package/dist/chunk-KNKUID7G.js.map +1 -0
  121. package/dist/chunk-L2IO2QPY.js +2036 -0
  122. package/dist/chunk-L2IO2QPY.js.map +1 -0
  123. package/dist/{chunk-SPI27QT6.js → chunk-L5IIGA5V.js} +9 -4
  124. package/dist/chunk-L5IIGA5V.js.map +1 -0
  125. package/dist/{chunk-XXVWLXSG.js → chunk-LVYGDT5V.js} +56 -82
  126. package/dist/chunk-LVYGDT5V.js.map +1 -0
  127. package/dist/{chunk-ZAIM4TUE.js → chunk-LW2NMHDW.js} +46 -1
  128. package/dist/chunk-LW2NMHDW.js.map +1 -0
  129. package/dist/{chunk-3OGMS3PE.js → chunk-LZRYQK6L.js} +3 -2
  130. package/dist/chunk-LZRYQK6L.js.map +1 -0
  131. package/dist/chunk-MDYG7VI7.js +48 -0
  132. package/dist/chunk-MDYG7VI7.js.map +1 -0
  133. package/dist/chunk-MXC3AP5I.js +74 -0
  134. package/dist/chunk-MXC3AP5I.js.map +1 -0
  135. package/dist/{chunk-DIXB44VE.js → chunk-N7X62G74.js} +25 -10
  136. package/dist/chunk-N7X62G74.js.map +1 -0
  137. package/dist/chunk-NN3TS5BM.js +147 -0
  138. package/dist/chunk-NN3TS5BM.js.map +1 -0
  139. package/dist/chunk-OA3L7BFR.js +183 -0
  140. package/dist/chunk-OA3L7BFR.js.map +1 -0
  141. package/dist/chunk-OZHRDTDX.js +240 -0
  142. package/dist/chunk-OZHRDTDX.js.map +1 -0
  143. package/dist/chunk-PCUKNJAZ.js +165 -0
  144. package/dist/chunk-PCUKNJAZ.js.map +1 -0
  145. package/dist/{chunk-6PFRXT4K.js → chunk-PFV5C235.js} +11 -6
  146. package/dist/chunk-PFV5C235.js.map +1 -0
  147. package/dist/chunk-PZ5AY32C.js +10 -0
  148. package/dist/chunk-PZ5AY32C.js.map +1 -0
  149. package/dist/{chunk-Y7R2XJ5Q.js → chunk-Q7FJ5ZHM.js} +6 -2
  150. package/dist/chunk-Q7FJ5ZHM.js.map +1 -0
  151. package/dist/{chunk-NBVAS5MT.js → chunk-R2L7SUX2.js} +6 -6
  152. package/dist/{chunk-WCLICCGB.js → chunk-RILIVK4O.js} +91 -4
  153. package/dist/chunk-RILIVK4O.js.map +1 -0
  154. package/dist/{chunk-C2EFFULQ.js → chunk-RK2Y4XOM.js} +163 -20
  155. package/dist/chunk-RK2Y4XOM.js.map +1 -0
  156. package/dist/{chunk-TP4FZJIZ.js → chunk-RULE4VG5.js} +5 -1
  157. package/dist/chunk-RULE4VG5.js.map +1 -0
  158. package/dist/{chunk-PVPWZSSI.js → chunk-SMA4IMHV.js} +19 -3
  159. package/dist/chunk-SMA4IMHV.js.map +1 -0
  160. package/dist/{chunk-L7IXWRYE.js → chunk-SS253RXF.js} +22 -13
  161. package/dist/chunk-SS253RXF.js.map +1 -0
  162. package/dist/chunk-TUFG6VXY.js +875 -0
  163. package/dist/chunk-TUFG6VXY.js.map +1 -0
  164. package/dist/chunk-TYEOAFH3.js +251 -0
  165. package/dist/chunk-TYEOAFH3.js.map +1 -0
  166. package/dist/chunk-UKJAGEXH.js +260 -0
  167. package/dist/chunk-UKJAGEXH.js.map +1 -0
  168. package/dist/{chunk-KVBLZUKV.js → chunk-USFPPRAF.js} +93 -3
  169. package/dist/chunk-USFPPRAF.js.map +1 -0
  170. package/dist/{chunk-GA5P7RST.js → chunk-VTJVUHRK.js} +22 -36
  171. package/dist/chunk-VTJVUHRK.js.map +1 -0
  172. package/dist/chunk-WIICJPET.js +45 -0
  173. package/dist/chunk-WIICJPET.js.map +1 -0
  174. package/dist/{chunk-VBVG2M5G.js → chunk-WPGJYVUH.js} +6 -2
  175. package/dist/chunk-WPGJYVUH.js.map +1 -0
  176. package/dist/{chunk-4HQS2HPX.js → chunk-WSZIHQBK.js} +29 -9
  177. package/dist/{chunk-4HQS2HPX.js.map → chunk-WSZIHQBK.js.map} +1 -1
  178. package/dist/{chunk-NZLQTHS5.js → chunk-WW3QQF4H.js} +4 -1
  179. package/dist/chunk-WW3QQF4H.js.map +1 -0
  180. package/dist/{chunk-FVA6TGI3.js → chunk-Y3WQ4ZWK.js} +42 -2
  181. package/dist/chunk-Y3WQ4ZWK.js.map +1 -0
  182. package/dist/chunk-YNJHCGDT.js +309 -0
  183. package/dist/chunk-YNJHCGDT.js.map +1 -0
  184. package/dist/{chunk-LOIMBRDE.js → chunk-ZGXSCMQN.js} +1993 -411
  185. package/dist/chunk-ZGXSCMQN.js.map +1 -0
  186. package/dist/{chunk-W6SL7OFG.js → chunk-ZTSE2ZJ6.js} +12 -2
  187. package/dist/{chunk-W6SL7OFG.js.map → chunk-ZTSE2ZJ6.js.map} +1 -1
  188. package/dist/chunking.js +1 -0
  189. package/dist/cipher-GVE2GQ5H.js +28 -0
  190. package/dist/cipher-GVE2GQ5H.js.map +1 -0
  191. package/dist/citations.js +1 -0
  192. package/dist/{cli-BkeRaYfk.d.ts → cli-x2APT9a6.d.ts} +26 -7
  193. package/dist/cli.d.ts +11 -6
  194. package/dist/cli.js +67 -33
  195. package/dist/codex-thread-key.js +1 -0
  196. package/dist/commitment-ledger.js +1 -0
  197. package/dist/compression-optimizer.js +1 -0
  198. package/dist/config.d.ts +2 -1
  199. package/dist/config.js +4 -1
  200. package/dist/connectors-cli-DFGtY2DB.d.ts +257 -0
  201. package/dist/connectors-cli.d.ts +2 -0
  202. package/dist/connectors-cli.js +22 -0
  203. package/dist/connectors-cli.js.map +1 -0
  204. package/dist/consolidation-operator.d.ts +65 -5
  205. package/dist/consolidation-operator.js +6 -1
  206. package/dist/consolidation-provenance-check.d.ts +1 -1
  207. package/dist/consolidation-provenance-check.js +3 -2
  208. package/dist/consolidation-undo.d.ts +1 -1
  209. package/dist/consolidation-undo.js +1 -0
  210. package/dist/consolidation-undo.js.map +1 -1
  211. package/dist/{contradiction-review-WIUBAR52.js → contradiction-review-5LTTVDQV.js} +2 -1
  212. package/dist/contradiction-review-5LTTVDQV.js.map +1 -0
  213. package/dist/{contradiction-scan-E3GJTI4F.js → contradiction-scan-3Z6YW7YA.js} +2 -1
  214. package/dist/{contradiction-scan-E3GJTI4F.js.map → contradiction-scan-3Z6YW7YA.js.map} +1 -1
  215. package/dist/cross-namespace-budget.js +1 -0
  216. package/dist/cue-anchors.js +1 -0
  217. package/dist/dashboard-runtime.js +1 -0
  218. package/dist/day-summary.js +1 -0
  219. package/dist/delinearize.js +1 -0
  220. package/dist/direct-answer-wiring.js +1 -0
  221. package/dist/direct-answer.js +1 -0
  222. package/dist/dreams-ledger-LR2NBAZE.js +286 -0
  223. package/dist/dreams-ledger-LR2NBAZE.js.map +1 -0
  224. package/dist/embedding-fallback.js +1 -0
  225. package/dist/{engine-72LSIWQP.js → engine-ICC2DSQF.js} +10 -7
  226. package/dist/engine-ICC2DSQF.js.map +1 -0
  227. package/dist/entity-retrieval.d.ts +1 -1
  228. package/dist/entity-retrieval.js +9 -6
  229. package/dist/entity-schema.js +1 -0
  230. package/dist/evals.js +1 -0
  231. package/dist/evidence-pack.d.ts +16 -0
  232. package/dist/evidence-pack.js +8 -0
  233. package/dist/evidence-pack.js.map +1 -0
  234. package/dist/explicit-capture.d.ts +6 -4
  235. package/dist/explicit-capture.js +1 -0
  236. package/dist/extraction-judge-telemetry.js +1 -0
  237. package/dist/extraction-judge-training.js +1 -0
  238. package/dist/extraction-judge.js +1 -0
  239. package/dist/extraction.js +7 -6
  240. package/dist/fallback-llm.js +3 -2
  241. package/dist/first-start-migration-4MHQEOSD.js +263 -0
  242. package/dist/first-start-migration-4MHQEOSD.js.map +1 -0
  243. package/dist/forget-PLR6J5DN.js +69 -0
  244. package/dist/forget-PLR6J5DN.js.map +1 -0
  245. package/dist/framework-CyHYDcri.d.ts +153 -0
  246. package/dist/fs-utils-IRVUFB6G.js +30 -0
  247. package/dist/fs-utils-IRVUFB6G.js.map +1 -0
  248. package/dist/graph-dashboard-diff.js +1 -0
  249. package/dist/graph-dashboard-key.js +1 -0
  250. package/dist/graph-dashboard-parser.js +1 -0
  251. package/dist/graph-edge-decay-PWB63GRE.js +207 -0
  252. package/dist/graph-edge-decay-PWB63GRE.js.map +1 -0
  253. package/dist/graph-edge-reinforcement.d.ts +81 -0
  254. package/dist/graph-edge-reinforcement.js +24 -0
  255. package/dist/graph-edge-reinforcement.js.map +1 -0
  256. package/dist/graph-events.d.ts +87 -0
  257. package/dist/graph-events.js +14 -0
  258. package/dist/graph-events.js.map +1 -0
  259. package/dist/graph-recall.js +1 -0
  260. package/dist/graph-retrieval.js +1 -0
  261. package/dist/graph-snapshot.d.ts +112 -0
  262. package/dist/graph-snapshot.js +19 -0
  263. package/dist/graph-snapshot.js.map +1 -0
  264. package/dist/graph.d.ts +105 -7
  265. package/dist/graph.js +20 -3
  266. package/dist/harmonic-retrieval.js +1 -0
  267. package/dist/himem.js +1 -0
  268. package/dist/hygiene.js +1 -0
  269. package/dist/identity-continuity.js +1 -0
  270. package/dist/importance.js +1 -0
  271. package/dist/index.d.ts +562 -13
  272. package/dist/index.js +329 -67
  273. package/dist/index.js.map +1 -1
  274. package/dist/intent.js +1 -0
  275. package/dist/json-extract.js +1 -0
  276. package/dist/json-store.js +1 -0
  277. package/dist/kdf-7S6RWKLZ.js +26 -0
  278. package/dist/kdf-7S6RWKLZ.js.map +1 -0
  279. package/dist/legacy-hook-compat.js +1 -0
  280. package/dist/legacy-hook-compat.js.map +1 -1
  281. package/dist/lifecycle.js +1 -0
  282. package/dist/live-connectors-runner.d.ts +48 -0
  283. package/dist/live-connectors-runner.js +17 -0
  284. package/dist/live-connectors-runner.js.map +1 -0
  285. package/dist/local-llm.js +1 -0
  286. package/dist/logger.js +1 -0
  287. package/dist/memory-action-policy.js +1 -0
  288. package/dist/memory-cache.d.ts +2 -1
  289. package/dist/memory-cache.js +4 -1
  290. package/dist/memory-governance-KG52RITE.js +37 -0
  291. package/dist/memory-governance-KG52RITE.js.map +1 -0
  292. package/dist/memory-lifecycle-ledger-utils.d.ts +2 -1
  293. package/dist/memory-lifecycle-ledger-utils.js +4 -1
  294. package/dist/memory-projection-format.js +1 -0
  295. package/dist/{memory-projection-store-DeSXPh1j.d.ts → memory-projection-store-D3vBHS4J.d.ts} +1 -0
  296. package/dist/memory-projection-store.d.ts +1 -1
  297. package/dist/memory-projection-store.js +1 -0
  298. package/dist/memory-worth-bench.js +1 -0
  299. package/dist/memory-worth-bench.js.map +1 -1
  300. package/dist/memory-worth-filter.js +1 -0
  301. package/dist/memory-worth-outcomes.d.ts +1 -1
  302. package/dist/memory-worth-outcomes.js +1 -0
  303. package/dist/memory-worth.js +1 -0
  304. package/dist/metadata-FC3XPDRQ.js +21 -0
  305. package/dist/metadata-FC3XPDRQ.js.map +1 -0
  306. package/dist/migrate-from-identity-anchor-TTEDEJGX.js +8 -0
  307. package/dist/migrate-from-identity-anchor-TTEDEJGX.js.map +1 -0
  308. package/dist/model-registry.js +1 -0
  309. package/dist/models-json.js +1 -0
  310. package/dist/native-knowledge.js +1 -0
  311. package/dist/negative.js +1 -0
  312. package/dist/objective-state-writers.js +1 -0
  313. package/dist/objective-state-writers.js.map +1 -1
  314. package/dist/objective-state.js +1 -0
  315. package/dist/openai-chat-compat.js +1 -0
  316. package/dist/operator-toolkit.d.ts +46 -2
  317. package/dist/operator-toolkit.js +28 -16
  318. package/dist/opik-exporter.js +1 -0
  319. package/dist/opik-exporter.js.map +1 -1
  320. package/dist/{orchestrator-CmJ-NTdJ.d.ts → orchestrator-ChkesB8U.d.ts} +177 -13
  321. package/dist/orchestrator.d.ts +6 -4
  322. package/dist/orchestrator.js +55 -39
  323. package/dist/page-versioning.js +1 -0
  324. package/dist/path-RMTY5Y5A.js +9 -0
  325. package/dist/path-RMTY5Y5A.js.map +1 -0
  326. package/dist/patterns-cli.d.ts +160 -0
  327. package/dist/patterns-cli.js +29 -0
  328. package/dist/patterns-cli.js.map +1 -0
  329. package/dist/peers-6OSQ3NK6.js +44 -0
  330. package/dist/peers-6OSQ3NK6.js.map +1 -0
  331. package/dist/plugin-id.js +1 -0
  332. package/dist/policy-runtime.js +1 -0
  333. package/dist/{port-BADbLZU5.d.ts → port-hqGnoStS.d.ts} +6 -0
  334. package/dist/profiling.js +1 -0
  335. package/dist/purge-6ATBGT77.js +205 -0
  336. package/dist/purge-6ATBGT77.js.map +1 -0
  337. package/dist/qmd-recall-cache.d.ts +1 -1
  338. package/dist/qmd-recall-cache.js +1 -0
  339. package/dist/qmd.d.ts +2 -1
  340. package/dist/qmd.js +4 -3
  341. package/dist/reasoning-trace-recall.js +1 -0
  342. package/dist/reasoning-trace-types.js +1 -0
  343. package/dist/recall-audit-anomaly.js +1 -0
  344. package/dist/recall-audit.js +1 -0
  345. package/dist/recall-disclosure-escalation.d.ts +84 -0
  346. package/dist/recall-disclosure-escalation.js +14 -0
  347. package/dist/recall-disclosure-escalation.js.map +1 -0
  348. package/dist/recall-explain-renderer.js +4 -1
  349. package/dist/recall-mmr.js +1 -0
  350. package/dist/recall-qos.js +1 -0
  351. package/dist/recall-query-policy.js +1 -0
  352. package/dist/recall-state.d.ts +7 -0
  353. package/dist/recall-state.js +2 -1
  354. package/dist/recall-tag-filter.d.ts +56 -0
  355. package/dist/recall-tag-filter.js +14 -0
  356. package/dist/recall-tag-filter.js.map +1 -0
  357. package/dist/recall-tokenization.js +1 -0
  358. package/dist/recall-xray-cli.d.ts +9 -2
  359. package/dist/recall-xray-cli.js +9 -4
  360. package/dist/recall-xray-renderer.js +4 -1
  361. package/dist/recall-xray.d.ts +116 -2
  362. package/dist/recall-xray.js +9 -3
  363. package/dist/reconstruct.js +1 -0
  364. package/dist/release-changelog.js +2 -0
  365. package/dist/release-changelog.js.map +1 -1
  366. package/dist/relevance.js +1 -0
  367. package/dist/rerank.js +1 -0
  368. package/dist/{resolution-QBTDHTG7.js → resolution-YGIBORXI.js} +2 -1
  369. package/dist/{resolution-QBTDHTG7.js.map → resolution-YGIBORXI.js.map} +1 -1
  370. package/dist/resolve-auth-token.d.ts +51 -0
  371. package/dist/resolve-auth-token.js +12 -0
  372. package/dist/resolve-auth-token.js.map +1 -0
  373. package/dist/resolve-provider-secret.d.ts +9 -1
  374. package/dist/resolve-provider-secret.js +4 -1
  375. package/dist/resume-bundles.js +4 -3
  376. package/dist/retrieval-agents.d.ts +1 -1
  377. package/dist/retrieval-agents.js +1 -0
  378. package/dist/retrieval-tiers.js +1 -0
  379. package/dist/retrieval.js +1 -0
  380. package/dist/sanitize.js +1 -0
  381. package/dist/schemas.d.ts +37 -24
  382. package/dist/schemas.js +2 -1
  383. package/dist/sdk-compat.js +1 -0
  384. package/dist/sdk-compat.js.map +1 -1
  385. package/dist/secure-store-4R2GSO7S.js +156 -0
  386. package/dist/secure-store-4R2GSO7S.js.map +1 -0
  387. package/dist/semantic-chunking.js +1 -0
  388. package/dist/{semantic-consolidation-CxJU6MJk.d.ts → semantic-consolidation-ByBXb-sf.d.ts} +3 -3
  389. package/dist/semantic-consolidation.d.ts +2 -2
  390. package/dist/semantic-consolidation.js +11 -6
  391. package/dist/semantic-rule-promotion.d.ts +1 -1
  392. package/dist/semantic-rule-promotion.js +9 -6
  393. package/dist/semantic-rule-verifier.d.ts +1 -1
  394. package/dist/semantic-rule-verifier.js +9 -6
  395. package/dist/session-integrity.js +1 -0
  396. package/dist/session-observer-bands.js +1 -0
  397. package/dist/session-observer-state.js +1 -0
  398. package/dist/session-toggles.js +2 -0
  399. package/dist/session-toggles.js.map +1 -1
  400. package/dist/signal.js +1 -0
  401. package/dist/skills-registry.js +2 -0
  402. package/dist/skills-registry.js.map +1 -1
  403. package/dist/source-attribution.js +1 -0
  404. package/dist/state-NCHQ4TRG.js +8 -0
  405. package/dist/state-NCHQ4TRG.js.map +1 -0
  406. package/dist/state-store-3EH7HYIN.js +16 -0
  407. package/dist/state-store-3EH7HYIN.js.map +1 -0
  408. package/dist/storage.d.ts +76 -2
  409. package/dist/storage.js +8 -5
  410. package/dist/store-contract.js +1 -0
  411. package/dist/summarizer.js +5 -4
  412. package/dist/summary-snapshot.js +1 -0
  413. package/dist/temporal-index.js +1 -0
  414. package/dist/temporal-supersession.d.ts +1 -1
  415. package/dist/temporal-supersession.js +2 -1
  416. package/dist/temporal-validity.d.ts +52 -0
  417. package/dist/temporal-validity.js +14 -0
  418. package/dist/temporal-validity.js.map +1 -0
  419. package/dist/threading.js +1 -0
  420. package/dist/tier-migration.d.ts +2 -2
  421. package/dist/tier-migration.js +1 -0
  422. package/dist/tier-routing.js +1 -0
  423. package/dist/tier-stats-62ZVDFKS.js +152 -0
  424. package/dist/tier-stats-62ZVDFKS.js.map +1 -0
  425. package/dist/tmt.js +1 -0
  426. package/dist/tokens.js +1 -0
  427. package/dist/topics.js +1 -0
  428. package/dist/trace-C5ETWBEF.js +290 -0
  429. package/dist/trace-C5ETWBEF.js.map +1 -0
  430. package/dist/transcript.js +1 -0
  431. package/dist/trust-zones.js +1 -0
  432. package/dist/tui-RI7P6PBS.js +13 -0
  433. package/dist/tui-RI7P6PBS.js.map +1 -0
  434. package/dist/types-V3FJ26TF.js +30 -0
  435. package/dist/types-V3FJ26TF.js.map +1 -0
  436. package/dist/types.d.ts +634 -9
  437. package/dist/types.js +10 -3
  438. package/dist/utility-learner.js +1 -0
  439. package/dist/utility-runtime.js +1 -0
  440. package/dist/utility-telemetry.js +1 -0
  441. package/dist/verified-recall.js +9 -6
  442. package/dist/version-utils.js +1 -0
  443. package/dist/whitespace.js +1 -0
  444. package/dist/work-product-ledger.js +1 -0
  445. package/package.json +2 -1
  446. package/dist/access-service-Br8ZydTK.d.ts +0 -827
  447. package/dist/chunk-3OGMS3PE.js.map +0 -1
  448. package/dist/chunk-3YGHKTBF.js.map +0 -1
  449. package/dist/chunk-6PFRXT4K.js.map +0 -1
  450. package/dist/chunk-6YJHX2DL.js.map +0 -1
  451. package/dist/chunk-BECYBZLX.js.map +0 -1
  452. package/dist/chunk-C2EFFULQ.js.map +0 -1
  453. package/dist/chunk-CUPFXL3J.js.map +0 -1
  454. package/dist/chunk-DIXB44VE.js.map +0 -1
  455. package/dist/chunk-F5VP6YCB.js.map +0 -1
  456. package/dist/chunk-FVA6TGI3.js.map +0 -1
  457. package/dist/chunk-GA5P7RST.js.map +0 -1
  458. package/dist/chunk-KVBLZUKV.js.map +0 -1
  459. package/dist/chunk-L7IXWRYE.js.map +0 -1
  460. package/dist/chunk-LOIMBRDE.js.map +0 -1
  461. package/dist/chunk-LTCGGW2D.js +0 -14
  462. package/dist/chunk-LTCGGW2D.js.map +0 -1
  463. package/dist/chunk-NZLQTHS5.js.map +0 -1
  464. package/dist/chunk-OC5OXUQ4.js.map +0 -1
  465. package/dist/chunk-PVPWZSSI.js.map +0 -1
  466. package/dist/chunk-SPI27QT6.js.map +0 -1
  467. package/dist/chunk-STGWEHYR.js.map +0 -1
  468. package/dist/chunk-TP4FZJIZ.js.map +0 -1
  469. package/dist/chunk-ULYOGL6R.js.map +0 -1
  470. package/dist/chunk-UWB5LMWY.js.map +0 -1
  471. package/dist/chunk-VBVG2M5G.js.map +0 -1
  472. package/dist/chunk-VDX363PS.js.map +0 -1
  473. package/dist/chunk-WCLICCGB.js.map +0 -1
  474. package/dist/chunk-X6GF3FX2.js +0 -26
  475. package/dist/chunk-X6GF3FX2.js.map +0 -1
  476. package/dist/chunk-XXVWLXSG.js.map +0 -1
  477. package/dist/chunk-Y7R2XJ5Q.js.map +0 -1
  478. package/dist/chunk-ZAIM4TUE.js.map +0 -1
  479. /package/dist/{contradiction-review-WIUBAR52.js.map → capsule-cli.js.map} +0 -0
  480. /package/dist/{engine-72LSIWQP.js.map → capsule-crypto-5CYAGVC5.js.map} +0 -0
  481. /package/dist/{chunk-TMYO7B5P.js.map → chunk-47WOM4YW.js.map} +0 -0
  482. /package/dist/{chunk-DG6YMRDC.js.map → chunk-B2TL6GA2.js.map} +0 -0
  483. /package/dist/{chunk-AYXIPSZO.js.map → chunk-CRU27Q4J.js.map} +0 -0
  484. /package/dist/{chunk-RBBWYEFJ.js.map → chunk-G2WADRQ3.js.map} +0 -0
  485. /package/dist/{chunk-NBVAS5MT.js.map → chunk-R2L7SUX2.js.map} +0 -0
@@ -10,6 +10,7 @@ import {
10
10
  import {
11
11
  log
12
12
  } from "./chunk-2ODBA7MQ.js";
13
+ import "./chunk-PZ5AY32C.js";
13
14
 
14
15
  // src/contradiction/contradiction-judge.ts
15
16
  import { createHash } from "crypto";
@@ -409,4 +410,4 @@ export {
409
410
  ACTIVE_STATUSES,
410
411
  runContradictionScan
411
412
  };
412
- //# sourceMappingURL=contradiction-scan-E3GJTI4F.js.map
413
+ //# sourceMappingURL=contradiction-scan-3Z6YW7YA.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/contradiction/contradiction-judge.ts","../src/contradiction/contradiction-scan.ts"],"sourcesContent":["/**\n * Contradiction Judge — LLM-as-judge for semantic contradiction detection (issue #520).\n *\n * Pairs semantically-similar memories and classifies their relationship.\n * Reuses the extraction-judge adapter pattern but with a contradiction-specific\n * prompt and verdict taxonomy.\n *\n * Design constraints:\n * - Default verdict on any failure is \"needs-user\" (rule 48: least-privileged default).\n * - Never auto-resolve; all verdicts enter the review queue.\n * - Content-hash caching avoids redundant LLM calls across runs.\n */\n\nimport { createHash } from \"node:crypto\";\nimport { log } from \"../logger.js\";\nimport type { PluginConfig } from \"../types.js\";\nimport type { LocalLlmClient } from \"../local-llm.js\";\nimport type { FallbackLlmClient } from \"../fallback-llm.js\";\nimport { extractJsonCandidates } from \"../json-extract.js\";\n\n// ── Types ──────────────────────────────────────────────────────────────────────\n\nexport type ContradictionVerdict =\n | \"contradicts\"\n | \"independent\"\n | \"duplicates\"\n | \"needs-user\";\n\nexport interface ContradictionJudgeInput {\n /** Memory ID of the first fact. */\n memoryIdA: string;\n /** Memory ID of the second fact. */\n memoryIdB: string;\n /** Content text of the first fact. */\n textA: string;\n /** Content text of the second fact. */\n textB: string;\n /** Category of the first fact (optional context). */\n categoryA?: string;\n /** Category of the second fact (optional context). */\n categoryB?: string;\n}\n\nexport interface ContradictionJudgeResult {\n /** Memory IDs of the pair. */\n memoryIdA: string;\n memoryIdB: string;\n /** Verdict from the judge. */\n verdict: ContradictionVerdict;\n /** Human-readable rationale. */\n rationale: string;\n /** Confidence in [0, 1]. */\n confidence: number;\n}\n\nexport interface ContradictionJudgeBatchResult {\n /** Results keyed by pair key (\"idA:idB\"). */\n results: Map<string, ContradictionJudgeResult>;\n /** Number served from cache. */\n cached: number;\n /** Number produced by LLM call. */\n judged: number;\n /** Total wall-clock time in ms. */\n elapsed: number;\n}\n\n// ── Prompt ─────────────────────────────────────────────────────────────────────\n\nconst CONTRADICTION_JUDGE_PROMPT = `You are a memory contradiction classifier. You will receive pairs of stored memories and must classify their semantic relationship.\n\nFor each pair, respond with a JSON array where each element has:\n- \"pairKey\": the pairKey provided in the input\n- \"verdict\": one of \"contradicts\", \"independent\", \"duplicates\", \"needs-user\"\n- \"rationale\": one sentence explaining why\n- \"confidence\": number between 0 and 1\n\nVERDICT DEFINITIONS:\n- \"contradicts\": The two memories make claims that cannot both be true. One must be wrong or outdated.\n- \"duplicates\": The two memories convey essentially the same information (near-paraphrase).\n- \"independent\": The memories are topically similar but do not conflict or duplicate.\n- \"needs-user\": Cannot determine with sufficient confidence; requires human review.\n\nIMPORTANT:\n- Be conservative. When in doubt, prefer \"needs-user\" over a wrong classification.\n- Two memories about the same entity/topic are NOT necessarily contradictory.\n- Temporal changes (\"Joshua uses pnpm\" vs \"Joshua switched to npm\") ARE contradictions.\n- Different aspects of the same entity (\"Joshua uses pnpm\" vs \"Joshua works on Remnic\") are \"independent\".`;\n\n// ── Cache ──────────────────────────────────────────────────────────────────────\n\n/** Module-level fallback cache — only used when caller does not supply one. */\nlet defaultVerdictCache: Map<string, ContradictionJudgeResult> = new Map();\nconst CACHE_MAX = 10_000;\n\nfunction pairKey(idA: string, idB: string): string {\n const sorted = [idA, idB].sort();\n return `${sorted[0]}:${sorted[1]}`;\n}\n\nfunction contentHash(a: ContradictionJudgeInput): string {\n // Sort each side pair to be order-independent (matching pairKey behavior)\n const sides = [\n [a.textA.trim(), (a.categoryA ?? \"\").trim()].join(\"|\"),\n [a.textB.trim(), (a.categoryB ?? \"\").trim()].join(\"|\"),\n ].sort();\n const normalized = sides.join(\"|||\");\n return createHash(\"sha256\").update(normalized).digest(\"hex\").slice(0, 16);\n}\n\nexport function createVerdictCache(): Map<string, ContradictionJudgeResult> {\n return new Map();\n}\n\nexport function clearVerdictCache(): void {\n defaultVerdictCache.clear();\n}\n\nexport function verdictCacheSize(): number {\n return defaultVerdictCache.size;\n}\n\n// ── Public API ──────────────────────────────────────────────────────────────────\n\n/**\n * Judge a batch of memory pairs for contradiction.\n *\n * Uses content-hash caching to skip pairs already judged in a prior run.\n * On any LLM failure, all unresolved pairs default to \"needs-user\".\n */\nexport async function judgeContradictionPairs(\n pairs: ContradictionJudgeInput[],\n config: PluginConfig,\n localLlm: LocalLlmClient | null,\n fallbackLlm: FallbackLlmClient | null,\n cache?: Map<string, ContradictionJudgeResult>,\n): Promise<ContradictionJudgeBatchResult> {\n const startTime = Date.now();\n const results = new Map<string, ContradictionJudgeResult>();\n const activeCache = cache ?? defaultVerdictCache;\n let cached = 0;\n let judged = 0;\n\n // Partition into cached vs needs-judging\n const toJudge: ContradictionJudgeInput[] = [];\n for (const pair of pairs) {\n const key = pairKey(pair.memoryIdA, pair.memoryIdB);\n const hash = contentHash(pair);\n const cachedResult = activeCache.get(hash);\n if (cachedResult) {\n results.set(key, { ...cachedResult, memoryIdA: pair.memoryIdA, memoryIdB: pair.memoryIdB });\n cached++;\n } else {\n toJudge.push(pair);\n }\n }\n\n if (toJudge.length === 0) {\n return { results, cached, judged, elapsed: Date.now() - startTime };\n }\n\n // Build the prompt with all pairs\n const pairDescriptions = toJudge.map((p, i) => {\n const pk = pairKey(p.memoryIdA, p.memoryIdB);\n const catA = p.categoryA ? ` [${p.categoryA}]` : \"\";\n const catB = p.categoryB ? ` [${p.categoryB}]` : \"\";\n return `Pair ${i + 1} (pairKey: \"${pk}\"):${catA} \"${p.textA}\"${catB} \"${p.textB}\"`;\n });\n\n const userMessage = `Classify these ${toJudge.length} memory pair(s):\\n\\n${pairDescriptions.join(\"\\n\\n\")}`;\n\n // Try LLM call\n let llmResponse: string | null = null;\n\n if (localLlm) {\n try {\n llmResponse = await callLlm(localLlm, config, userMessage);\n } catch (err) {\n log.warn(\"[contradiction-judge] local LLM call failed: %s\", err instanceof Error ? err.message : err);\n }\n }\n\n if (!llmResponse && fallbackLlm) {\n try {\n llmResponse = await callLlm(fallbackLlm, config, userMessage);\n } catch (err) {\n log.warn(\"[contradiction-judge] fallback LLM call failed: %s\", err instanceof Error ? err.message : err);\n }\n }\n\n // Parse response or default to needs-user\n if (llmResponse) {\n const candidates = extractJsonCandidates(llmResponse);\n const parsed = parseJudgeResponse(candidates, toJudge);\n\n for (const result of parsed) {\n const key = pairKey(result.memoryIdA, result.memoryIdB);\n results.set(key, result);\n\n // Update cache\n const input = toJudge.find(\n (p) => pairKey(p.memoryIdA, p.memoryIdB) === key,\n );\n if (input) {\n const hash = contentHash(input);\n if (activeCache.size >= CACHE_MAX) {\n const firstKey = activeCache.keys().next().value;\n if (firstKey !== undefined) activeCache.delete(firstKey);\n }\n activeCache.set(hash, result);\n }\n judged++;\n }\n } else {\n // All unresolved → needs-user (rule 48)\n for (const pair of toJudge) {\n const key = pairKey(pair.memoryIdA, pair.memoryIdB);\n const result: ContradictionJudgeResult = {\n memoryIdA: pair.memoryIdA,\n memoryIdB: pair.memoryIdB,\n verdict: \"needs-user\",\n rationale: \"LLM call failed; requires manual review\",\n confidence: 0,\n };\n results.set(key, result);\n judged++;\n }\n }\n\n return { results, cached, judged, elapsed: Date.now() - startTime };\n}\n\n// ── Internals ──────────────────────────────────────────────────────────────────\n\nasync function callLlm(\n client: LocalLlmClient | FallbackLlmClient,\n config: PluginConfig,\n userMessage: string,\n): Promise<string> {\n const messages: Array<{ role: \"user\" | \"assistant\" | \"system\"; content: string }> = [\n { role: \"system\", content: CONTRADICTION_JUDGE_PROMPT },\n { role: \"user\", content: userMessage },\n ];\n if (\"chatCompletion\" in client && typeof client.chatCompletion === \"function\") {\n const result = await client.chatCompletion(messages, {\n temperature: 0.1,\n maxTokens: 4096,\n });\n return result?.content ?? \"\";\n }\n // FallbackLlmClient — try OpenAI-compatible chat completions\n if (\"complete\" in client && typeof (client as Record<string, unknown>).complete === \"function\") {\n const result = await (client as { complete: (msg: Array<{ role: string; content: string }>) => Promise<{ content: string }> }).complete(messages);\n return result.content ?? \"\";\n }\n return \"\";\n}\n\nfunction parseJudgeResponse(\n candidates: string[],\n inputs: ContradictionJudgeInput[],\n): ContradictionJudgeResult[] {\n const VALID_VERDICTS: ContradictionVerdict[] = [\"contradicts\", \"independent\", \"duplicates\", \"needs-user\"];\n\n for (const candidate of candidates) {\n try {\n const parsed = JSON.parse(candidate);\n const items = Array.isArray(parsed) ? parsed : [parsed];\n const results: ContradictionJudgeResult[] = [];\n const matchedKeys = new Set<string>();\n\n for (const item of items) {\n if (!item || typeof item !== \"object\") continue;\n\n const verdict = typeof item.verdict === \"string\" && VALID_VERDICTS.includes(item.verdict as ContradictionVerdict)\n ? (item.verdict as ContradictionVerdict)\n : \"needs-user\";\n\n const pairKeyVal = typeof item.pairKey === \"string\" ? item.pairKey : null;\n const input = pairKeyVal\n ? inputs.find((p) => pairKey(p.memoryIdA, p.memoryIdB) === pairKeyVal)\n : null;\n\n // If we can't match the pairKey, fall back to index-based matching\n const fallbackInput = input ?? inputs[results.length] ?? inputs[0];\n if (!fallbackInput) continue;\n\n matchedKeys.add(pairKey(fallbackInput.memoryIdA, fallbackInput.memoryIdB));\n\n const confidence = typeof item.confidence === \"number\"\n ? Math.min(1, Math.max(0, item.confidence))\n : 0.5;\n\n results.push({\n memoryIdA: fallbackInput.memoryIdA,\n memoryIdB: fallbackInput.memoryIdB,\n verdict,\n rationale: typeof item.rationale === \"string\" ? item.rationale : \"No rationale provided\",\n confidence,\n });\n }\n\n // Backfill any inputs the LLM omitted with needs-user\n for (const inp of inputs) {\n const key = pairKey(inp.memoryIdA, inp.memoryIdB);\n if (!matchedKeys.has(key)) {\n results.push({\n memoryIdA: inp.memoryIdA,\n memoryIdB: inp.memoryIdB,\n verdict: \"needs-user\",\n rationale: \"LLM response omitted this pair\",\n confidence: 0,\n });\n }\n }\n\n if (results.length > 0) return results;\n } catch {\n continue;\n }\n }\n\n // All parse attempts failed → needs-user for every input\n return inputs.map((p) => ({\n memoryIdA: p.memoryIdA,\n memoryIdB: p.memoryIdB,\n verdict: \"needs-user\" as ContradictionVerdict,\n rationale: \"Failed to parse judge response\",\n confidence: 0,\n }));\n}\n\nexport { pairKey as _pairKey, contentHash as _contentHash };\n","/**\n * Contradiction Scan — pair generator + scan driver (issue #520).\n *\n * Nightly cron that pairs semantically-similar active memories within\n * the same namespace, sends candidate pairs to the LLM-as-judge\n * contradiction classifier, and drops contradicting pairs into a\n * review queue for user resolution.\n *\n * Pair generation (cheap pre-filter):\n * 1. Find candidate peers via embedding cosine >= similarityFloor.\n * 2. Restrict to pairs sharing at least one entityRef OR overlapping\n * topic tokens >= topicOverlapFloor.\n * 3. Skip pairs already judged independent/both-valid within cooldown.\n * 4. Cap per-run work at maxPairsPerRun.\n */\n\nimport type { StorageManager } from \"../storage.js\";\nimport type { PluginConfig, MemoryFile, MemoryStatus } from \"../types.js\";\nimport type { SemanticDedupLookup } from \"../dedup/semantic.js\";\nimport { log } from \"../logger.js\";\nimport { judgeContradictionPairs, type ContradictionJudgeInput } from \"./contradiction-judge.js\";\nimport {\n writePairs,\n listPairs,\n isCoolingDown,\n computePairId,\n type ContradictionPair,\n} from \"./contradiction-review.js\";\nimport type { LocalLlmClient } from \"../local-llm.js\";\nimport type { FallbackLlmClient } from \"../fallback-llm.js\";\n\n// ── Types ──────────────────────────────────────────────────────────────────────\n\n/** The set of statuses that represent \"live\" memories eligible for scanning. */\nexport const ACTIVE_STATUSES: Set<MemoryStatus> = new Set([\"active\"]);\n\n/** High-value taxonomy buckets to scan. */\nconst SCAN_CATEGORIES = new Set([\n \"decision\",\n \"principle\",\n \"rule\",\n \"entity\",\n \"fact\",\n \"preference\",\n]);\n\nexport interface ScanResult {\n /** Total active memories scanned. */\n scanned: number;\n /** Candidate pairs generated by the pre-filter. */\n candidates: number;\n /** Pairs sent to judge. */\n judged: number;\n /** Pairs written to review queue. */\n queued: number;\n /** Pairs skipped due to cooldown. */\n cooledDown: number;\n /** Total wall-clock time in ms. */\n elapsedMs: number;\n}\n\nexport interface ScanDependencies {\n storage: StorageManager;\n config: PluginConfig;\n memoryDir: string;\n /** Pre-built embedding lookup. When provided, used as-is for Strategy 3. */\n embeddingLookup?: SemanticDedupLookup;\n /**\n * Factory to build a namespace-scoped embedding lookup.\n * When provided, takes precedence over `embeddingLookup`.\n * The scan driver passes its own `storage` so the lookup queries the correct index.\n */\n embeddingLookupFactory?: (storage: StorageManager) => SemanticDedupLookup | undefined;\n localLlm: LocalLlmClient | null;\n fallbackLlm: FallbackLlmClient | null;\n namespace?: string;\n}\n\n// ── Main scan driver ───────────────────────────────────────────────────────────\n\n/**\n * Run a contradiction scan over the memory corpus.\n *\n * This is the entry point called by the nightly cron and by the CLI.\n */\nexport async function runContradictionScan(deps: ScanDependencies): Promise<ScanResult> {\n const startTime = Date.now();\n const { storage, config, memoryDir, embeddingLookup, embeddingLookupFactory, localLlm, fallbackLlm, namespace } = deps;\n const scanConfig = config.contradictionScan;\n\n // Prefer the factory (which uses the scan's own storage for correct namespace scoping)\n // over a pre-built lookup (which may use default-namespace storage).\n const scopedEmbeddingLookup = embeddingLookupFactory\n ? embeddingLookupFactory(storage)\n : embeddingLookup;\n\n if (!scanConfig.enabled) {\n log.info(\"[contradiction-scan] disabled by config\");\n return { scanned: 0, candidates: 0, judged: 0, queued: 0, cooledDown: 0, elapsedMs: 0 };\n }\n\n // 1. Load active memories in scan categories\n const memories = await loadEligibleMemories(storage, namespace);\n log.info(\"[contradiction-scan] loaded %d eligible memories\", memories.length);\n\n if (memories.length < 2) {\n return { scanned: memories.length, candidates: 0, judged: 0, queued: 0, cooledDown: 0, elapsedMs: Date.now() - startTime };\n }\n\n // 2. Load existing review pairs for cooldown checking\n const existingPairs = listPairs(memoryDir, { filter: \"all\", namespace, limit: 10000 }).pairs;\n const existingMap = new Map<string, ContradictionPair>();\n for (const p of existingPairs) {\n existingMap.set(p.pairId, p);\n }\n\n // 3. Generate candidate pairs\n const candidates = await generatePairs(memories, existingMap, scanConfig, scopedEmbeddingLookup);\n const cooledDown = candidates.skipped;\n log.info(\"[contradiction-scan] generated %d candidates (%d cooled down)\", candidates.pairs.length, cooledDown);\n\n if (candidates.pairs.length === 0) {\n return {\n scanned: memories.length,\n candidates: 0,\n judged: 0,\n queued: 0,\n cooledDown,\n elapsedMs: Date.now() - startTime,\n };\n }\n\n // 4. Cap at maxPairsPerRun (deterministic selection by pairId)\n const capped = candidates.pairs\n .sort((a, b) => computePairId(a.idA, a.idB).localeCompare(computePairId(b.idA, b.idB)))\n .slice(0, scanConfig.maxPairsPerRun);\n\n // 5. Build judge inputs\n const judgeInputs: ContradictionJudgeInput[] = capped.map((pair) => ({\n memoryIdA: pair.idA,\n memoryIdB: pair.idB,\n textA: pair.textA,\n textB: pair.textB,\n categoryA: pair.categoryA,\n categoryB: pair.categoryB,\n }));\n\n // 6. Send to judge (per-scan cache avoids module-level singleton leak)\n const scanCache = new Map<string, import(\"./contradiction-judge.js\").ContradictionJudgeResult>();\n const judgeResult = await judgeContradictionPairs(judgeInputs, config, localLlm, fallbackLlm, scanCache);\n log.info(\"[contradiction-scan] judge completed: %d judged, %d cached in %dms\", judgeResult.judged, judgeResult.cached, judgeResult.elapsed);\n\n // 7. Write to review queue\n const queueEntries: Array<Omit<ContradictionPair, \"pairId\"> & { memoryIds: [string, string] }> = [];\n for (const [key, result] of judgeResult.results) {\n queueEntries.push({\n memoryIds: [result.memoryIdA, result.memoryIdB],\n verdict: result.verdict,\n rationale: result.rationale,\n confidence: result.confidence,\n detectedAt: new Date().toISOString(),\n // Set lastReviewedAt for non-actionable verdicts so cooldown prevents re-judging\n lastReviewedAt: result.verdict === \"independent\" ? new Date().toISOString() : undefined,\n namespace,\n });\n }\n\n const written = writePairs(memoryDir, queueEntries);\n const elapsed = Date.now() - startTime;\n log.info(\"[contradiction-scan] complete: %d queued in %dms\", written.length, elapsed);\n\n return {\n scanned: memories.length,\n candidates: candidates.pairs.length,\n judged: judgeResult.judged,\n queued: written.length,\n cooledDown,\n elapsedMs: elapsed,\n };\n}\n\n// ── Pair generation ────────────────────────────────────────────────────────────\n\ninterface CandidatePair {\n idA: string;\n idB: string;\n textA: string;\n textB: string;\n categoryA?: string;\n categoryB?: string;\n}\n\ninterface PairGenResult {\n pairs: CandidatePair[];\n skipped: number;\n}\n\nasync function generatePairs(\n memories: MemoryFile[],\n existingPairs: Map<string, ContradictionPair>,\n scanConfig: PluginConfig[\"contradictionScan\"],\n embeddingLookup?: SemanticDedupLookup,\n): Promise<PairGenResult> {\n const pairs: CandidatePair[] = [];\n const embeddingPairs: CandidatePair[] = [];\n let skipped = 0;\n const seen = new Set<string>();\n\n // Build index by entityRef for fast lookup\n const byEntity = new Map<string, MemoryFile[]>();\n for (const mem of memories) {\n const entity = mem.frontmatter.entityRef;\n if (entity) {\n const existing = byEntity.get(entity) ?? [];\n existing.push(mem);\n byEntity.set(entity, existing);\n }\n }\n\n // Strategy 1: Entity-ref based pairing (high precision)\n for (const [, group] of byEntity) {\n if (group.length < 2) continue;\n for (let i = 0; i < group.length; i++) {\n for (let j = i + 1; j < group.length; j++) {\n const a = group[i];\n const b = group[j];\n const pairId = computePairId(a.frontmatter.id!, b.frontmatter.id!);\n\n if (seen.has(pairId)) continue;\n seen.add(pairId);\n\n // Check cooldown\n const existing = existingPairs.get(pairId);\n if (existing && isCoolingDown(existing, scanConfig.cooldownDays)) {\n skipped++;\n continue;\n }\n\n pairs.push({\n idA: a.frontmatter.id!,\n idB: b.frontmatter.id!,\n textA: a.content,\n textB: b.content,\n categoryA: a.frontmatter.category as string | undefined,\n categoryB: b.frontmatter.category as string | undefined,\n });\n }\n }\n }\n\n // Strategy 2: Tag/topic overlap for memories without shared entityRef\n const noEntity = memories.filter((m) => !m.frontmatter.entityRef);\n for (let i = 0; i < noEntity.length; i++) {\n for (let j = i + 1; j < noEntity.length; j++) {\n const a = noEntity[i];\n const b = noEntity[j];\n const overlap = jaccardOverlap(\n (a.frontmatter.tags as string[]) ?? [],\n (b.frontmatter.tags as string[]) ?? [],\n );\n\n if (overlap < scanConfig.topicOverlapFloor) continue;\n\n const pairId = computePairId(a.frontmatter.id!, b.frontmatter.id!);\n if (seen.has(pairId)) continue;\n seen.add(pairId);\n\n const existing = existingPairs.get(pairId);\n if (existing && isCoolingDown(existing, scanConfig.cooldownDays)) {\n skipped++;\n continue;\n }\n\n pairs.push({\n idA: a.frontmatter.id!,\n idB: b.frontmatter.id!,\n textA: a.content,\n textB: b.content,\n categoryA: a.frontmatter.category as string | undefined,\n categoryB: b.frontmatter.category as string | undefined,\n });\n }\n }\n\n // Strategy 3: Embedding cosine similarity (enforces similarityFloor config)\n if (embeddingLookup) {\n const memoryById = new Map(memories.map((m) => [m.frontmatter.id!, m]));\n for (const mem of memories) {\n const id = mem.frontmatter.id!;\n try {\n const hits = await embeddingLookup(mem.content, 20);\n for (const hit of hits) {\n if (hit.score < scanConfig.similarityFloor) continue;\n if (hit.id === id) continue;\n const peer = memoryById.get(hit.id);\n if (!peer) continue;\n\n const pairId = computePairId(id, hit.id);\n if (seen.has(pairId)) continue;\n seen.add(pairId);\n\n const existing = existingPairs.get(pairId);\n if (existing && isCoolingDown(existing, scanConfig.cooldownDays)) {\n skipped++;\n continue;\n }\n\n embeddingPairs.push({\n idA: id,\n idB: hit.id,\n textA: mem.content,\n textB: peer.content,\n categoryA: mem.frontmatter.category as string | undefined,\n categoryB: peer.frontmatter.category as string | undefined,\n });\n }\n } catch {\n // Embedding backend unavailable — skip, entity-ref/tag strategies already covered\n }\n }\n }\n\n // Append embedding pairs after high-precision entity/topic pairs so the\n // downstream sort+slice(maxPairsPerRun) keeps precision-first ordering.\n pairs.push(...embeddingPairs);\n\n return { pairs, skipped };\n}\n\n// ── Helpers ────────────────────────────────────────────────────────────────────\n\nasync function loadEligibleMemories(storage: StorageManager, namespace?: string): Promise<MemoryFile[]> {\n let all: MemoryFile[];\n try {\n all = await storage.readAllMemories();\n } catch {\n return [];\n }\n\n return all.filter((mem) => {\n const fm = mem.frontmatter;\n // Only active memories (rule 53: explicit ACTIVE_STATUSES set)\n const status = (fm.status as MemoryStatus) ?? \"active\";\n if (!ACTIVE_STATUSES.has(status)) return false;\n\n // Only scan high-value categories\n const category = fm.category as string | undefined;\n if (category && !SCAN_CATEGORIES.has(category)) return false;\n\n // Must have content\n if (!mem.content || mem.content.trim().length === 0) return false;\n\n // Must have an ID\n if (!fm.id) return false;\n\n // Namespace scoping is handled at the storage layer — memoryDir is\n // already namespace-scoped, so readAllMemories() returns only memories\n // within the requested namespace.\n\n return true;\n });\n}\n\nfunction jaccardOverlap(a: string[], b: string[]): number {\n if (a.length === 0 && b.length === 0) return 0;\n const setA = new Set(a.map((t) => t.toLowerCase()));\n const setB = new Set(b.map((t) => t.toLowerCase()));\n let intersection = 0;\n for (const item of setA) {\n if (setB.has(item)) intersection++;\n }\n const union = setA.size + setB.size - intersection;\n return union === 0 ? 0 : intersection / union;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/contradiction/contradiction-judge.ts","../src/contradiction/contradiction-scan.ts"],"sourcesContent":["/**\n * Contradiction Judge — LLM-as-judge for semantic contradiction detection (issue #520).\n *\n * Pairs semantically-similar memories and classifies their relationship.\n * Reuses the extraction-judge adapter pattern but with a contradiction-specific\n * prompt and verdict taxonomy.\n *\n * Design constraints:\n * - Default verdict on any failure is \"needs-user\" (rule 48: least-privileged default).\n * - Never auto-resolve; all verdicts enter the review queue.\n * - Content-hash caching avoids redundant LLM calls across runs.\n */\n\nimport { createHash } from \"node:crypto\";\nimport { log } from \"../logger.js\";\nimport type { PluginConfig } from \"../types.js\";\nimport type { LocalLlmClient } from \"../local-llm.js\";\nimport type { FallbackLlmClient } from \"../fallback-llm.js\";\nimport { extractJsonCandidates } from \"../json-extract.js\";\n\n// ── Types ──────────────────────────────────────────────────────────────────────\n\nexport type ContradictionVerdict =\n | \"contradicts\"\n | \"independent\"\n | \"duplicates\"\n | \"needs-user\";\n\nexport interface ContradictionJudgeInput {\n /** Memory ID of the first fact. */\n memoryIdA: string;\n /** Memory ID of the second fact. */\n memoryIdB: string;\n /** Content text of the first fact. */\n textA: string;\n /** Content text of the second fact. */\n textB: string;\n /** Category of the first fact (optional context). */\n categoryA?: string;\n /** Category of the second fact (optional context). */\n categoryB?: string;\n}\n\nexport interface ContradictionJudgeResult {\n /** Memory IDs of the pair. */\n memoryIdA: string;\n memoryIdB: string;\n /** Verdict from the judge. */\n verdict: ContradictionVerdict;\n /** Human-readable rationale. */\n rationale: string;\n /** Confidence in [0, 1]. */\n confidence: number;\n}\n\nexport interface ContradictionJudgeBatchResult {\n /** Results keyed by pair key (\"idA:idB\"). */\n results: Map<string, ContradictionJudgeResult>;\n /** Number served from cache. */\n cached: number;\n /** Number produced by LLM call. */\n judged: number;\n /** Total wall-clock time in ms. */\n elapsed: number;\n}\n\n// ── Prompt ─────────────────────────────────────────────────────────────────────\n\nconst CONTRADICTION_JUDGE_PROMPT = `You are a memory contradiction classifier. You will receive pairs of stored memories and must classify their semantic relationship.\n\nFor each pair, respond with a JSON array where each element has:\n- \"pairKey\": the pairKey provided in the input\n- \"verdict\": one of \"contradicts\", \"independent\", \"duplicates\", \"needs-user\"\n- \"rationale\": one sentence explaining why\n- \"confidence\": number between 0 and 1\n\nVERDICT DEFINITIONS:\n- \"contradicts\": The two memories make claims that cannot both be true. One must be wrong or outdated.\n- \"duplicates\": The two memories convey essentially the same information (near-paraphrase).\n- \"independent\": The memories are topically similar but do not conflict or duplicate.\n- \"needs-user\": Cannot determine with sufficient confidence; requires human review.\n\nIMPORTANT:\n- Be conservative. When in doubt, prefer \"needs-user\" over a wrong classification.\n- Two memories about the same entity/topic are NOT necessarily contradictory.\n- Temporal changes (\"Joshua uses pnpm\" vs \"Joshua switched to npm\") ARE contradictions.\n- Different aspects of the same entity (\"Joshua uses pnpm\" vs \"Joshua works on Remnic\") are \"independent\".`;\n\n// ── Cache ──────────────────────────────────────────────────────────────────────\n\n/** Module-level fallback cache — only used when caller does not supply one. */\nlet defaultVerdictCache: Map<string, ContradictionJudgeResult> = new Map();\nconst CACHE_MAX = 10_000;\n\nfunction pairKey(idA: string, idB: string): string {\n const sorted = [idA, idB].sort();\n return `${sorted[0]}:${sorted[1]}`;\n}\n\nfunction contentHash(a: ContradictionJudgeInput): string {\n // Sort each side pair to be order-independent (matching pairKey behavior)\n const sides = [\n [a.textA.trim(), (a.categoryA ?? \"\").trim()].join(\"|\"),\n [a.textB.trim(), (a.categoryB ?? \"\").trim()].join(\"|\"),\n ].sort();\n const normalized = sides.join(\"|||\");\n return createHash(\"sha256\").update(normalized).digest(\"hex\").slice(0, 16);\n}\n\nexport function createVerdictCache(): Map<string, ContradictionJudgeResult> {\n return new Map();\n}\n\nexport function clearVerdictCache(): void {\n defaultVerdictCache.clear();\n}\n\nexport function verdictCacheSize(): number {\n return defaultVerdictCache.size;\n}\n\n// ── Public API ──────────────────────────────────────────────────────────────────\n\n/**\n * Judge a batch of memory pairs for contradiction.\n *\n * Uses content-hash caching to skip pairs already judged in a prior run.\n * On any LLM failure, all unresolved pairs default to \"needs-user\".\n */\nexport async function judgeContradictionPairs(\n pairs: ContradictionJudgeInput[],\n config: PluginConfig,\n localLlm: LocalLlmClient | null,\n fallbackLlm: FallbackLlmClient | null,\n cache?: Map<string, ContradictionJudgeResult>,\n): Promise<ContradictionJudgeBatchResult> {\n const startTime = Date.now();\n const results = new Map<string, ContradictionJudgeResult>();\n const activeCache = cache ?? defaultVerdictCache;\n let cached = 0;\n let judged = 0;\n\n // Partition into cached vs needs-judging\n const toJudge: ContradictionJudgeInput[] = [];\n for (const pair of pairs) {\n const key = pairKey(pair.memoryIdA, pair.memoryIdB);\n const hash = contentHash(pair);\n const cachedResult = activeCache.get(hash);\n if (cachedResult) {\n results.set(key, { ...cachedResult, memoryIdA: pair.memoryIdA, memoryIdB: pair.memoryIdB });\n cached++;\n } else {\n toJudge.push(pair);\n }\n }\n\n if (toJudge.length === 0) {\n return { results, cached, judged, elapsed: Date.now() - startTime };\n }\n\n // Build the prompt with all pairs\n const pairDescriptions = toJudge.map((p, i) => {\n const pk = pairKey(p.memoryIdA, p.memoryIdB);\n const catA = p.categoryA ? ` [${p.categoryA}]` : \"\";\n const catB = p.categoryB ? ` [${p.categoryB}]` : \"\";\n return `Pair ${i + 1} (pairKey: \"${pk}\"):${catA} \"${p.textA}\"${catB} \"${p.textB}\"`;\n });\n\n const userMessage = `Classify these ${toJudge.length} memory pair(s):\\n\\n${pairDescriptions.join(\"\\n\\n\")}`;\n\n // Try LLM call\n let llmResponse: string | null = null;\n\n if (localLlm) {\n try {\n llmResponse = await callLlm(localLlm, config, userMessage);\n } catch (err) {\n log.warn(\"[contradiction-judge] local LLM call failed: %s\", err instanceof Error ? err.message : err);\n }\n }\n\n if (!llmResponse && fallbackLlm) {\n try {\n llmResponse = await callLlm(fallbackLlm, config, userMessage);\n } catch (err) {\n log.warn(\"[contradiction-judge] fallback LLM call failed: %s\", err instanceof Error ? err.message : err);\n }\n }\n\n // Parse response or default to needs-user\n if (llmResponse) {\n const candidates = extractJsonCandidates(llmResponse);\n const parsed = parseJudgeResponse(candidates, toJudge);\n\n for (const result of parsed) {\n const key = pairKey(result.memoryIdA, result.memoryIdB);\n results.set(key, result);\n\n // Update cache\n const input = toJudge.find(\n (p) => pairKey(p.memoryIdA, p.memoryIdB) === key,\n );\n if (input) {\n const hash = contentHash(input);\n if (activeCache.size >= CACHE_MAX) {\n const firstKey = activeCache.keys().next().value;\n if (firstKey !== undefined) activeCache.delete(firstKey);\n }\n activeCache.set(hash, result);\n }\n judged++;\n }\n } else {\n // All unresolved → needs-user (rule 48)\n for (const pair of toJudge) {\n const key = pairKey(pair.memoryIdA, pair.memoryIdB);\n const result: ContradictionJudgeResult = {\n memoryIdA: pair.memoryIdA,\n memoryIdB: pair.memoryIdB,\n verdict: \"needs-user\",\n rationale: \"LLM call failed; requires manual review\",\n confidence: 0,\n };\n results.set(key, result);\n judged++;\n }\n }\n\n return { results, cached, judged, elapsed: Date.now() - startTime };\n}\n\n// ── Internals ──────────────────────────────────────────────────────────────────\n\nasync function callLlm(\n client: LocalLlmClient | FallbackLlmClient,\n config: PluginConfig,\n userMessage: string,\n): Promise<string> {\n const messages: Array<{ role: \"user\" | \"assistant\" | \"system\"; content: string }> = [\n { role: \"system\", content: CONTRADICTION_JUDGE_PROMPT },\n { role: \"user\", content: userMessage },\n ];\n if (\"chatCompletion\" in client && typeof client.chatCompletion === \"function\") {\n const result = await client.chatCompletion(messages, {\n temperature: 0.1,\n maxTokens: 4096,\n });\n return result?.content ?? \"\";\n }\n // FallbackLlmClient — try OpenAI-compatible chat completions\n if (\"complete\" in client && typeof (client as Record<string, unknown>).complete === \"function\") {\n const result = await (client as { complete: (msg: Array<{ role: string; content: string }>) => Promise<{ content: string }> }).complete(messages);\n return result.content ?? \"\";\n }\n return \"\";\n}\n\nfunction parseJudgeResponse(\n candidates: string[],\n inputs: ContradictionJudgeInput[],\n): ContradictionJudgeResult[] {\n const VALID_VERDICTS: ContradictionVerdict[] = [\"contradicts\", \"independent\", \"duplicates\", \"needs-user\"];\n\n for (const candidate of candidates) {\n try {\n const parsed = JSON.parse(candidate);\n const items = Array.isArray(parsed) ? parsed : [parsed];\n const results: ContradictionJudgeResult[] = [];\n const matchedKeys = new Set<string>();\n\n for (const item of items) {\n if (!item || typeof item !== \"object\") continue;\n\n const verdict = typeof item.verdict === \"string\" && VALID_VERDICTS.includes(item.verdict as ContradictionVerdict)\n ? (item.verdict as ContradictionVerdict)\n : \"needs-user\";\n\n const pairKeyVal = typeof item.pairKey === \"string\" ? item.pairKey : null;\n const input = pairKeyVal\n ? inputs.find((p) => pairKey(p.memoryIdA, p.memoryIdB) === pairKeyVal)\n : null;\n\n // If we can't match the pairKey, fall back to index-based matching\n const fallbackInput = input ?? inputs[results.length] ?? inputs[0];\n if (!fallbackInput) continue;\n\n matchedKeys.add(pairKey(fallbackInput.memoryIdA, fallbackInput.memoryIdB));\n\n const confidence = typeof item.confidence === \"number\"\n ? Math.min(1, Math.max(0, item.confidence))\n : 0.5;\n\n results.push({\n memoryIdA: fallbackInput.memoryIdA,\n memoryIdB: fallbackInput.memoryIdB,\n verdict,\n rationale: typeof item.rationale === \"string\" ? item.rationale : \"No rationale provided\",\n confidence,\n });\n }\n\n // Backfill any inputs the LLM omitted with needs-user\n for (const inp of inputs) {\n const key = pairKey(inp.memoryIdA, inp.memoryIdB);\n if (!matchedKeys.has(key)) {\n results.push({\n memoryIdA: inp.memoryIdA,\n memoryIdB: inp.memoryIdB,\n verdict: \"needs-user\",\n rationale: \"LLM response omitted this pair\",\n confidence: 0,\n });\n }\n }\n\n if (results.length > 0) return results;\n } catch {\n continue;\n }\n }\n\n // All parse attempts failed → needs-user for every input\n return inputs.map((p) => ({\n memoryIdA: p.memoryIdA,\n memoryIdB: p.memoryIdB,\n verdict: \"needs-user\" as ContradictionVerdict,\n rationale: \"Failed to parse judge response\",\n confidence: 0,\n }));\n}\n\nexport { pairKey as _pairKey, contentHash as _contentHash };\n","/**\n * Contradiction Scan — pair generator + scan driver (issue #520).\n *\n * Nightly cron that pairs semantically-similar active memories within\n * the same namespace, sends candidate pairs to the LLM-as-judge\n * contradiction classifier, and drops contradicting pairs into a\n * review queue for user resolution.\n *\n * Pair generation (cheap pre-filter):\n * 1. Find candidate peers via embedding cosine >= similarityFloor.\n * 2. Restrict to pairs sharing at least one entityRef OR overlapping\n * topic tokens >= topicOverlapFloor.\n * 3. Skip pairs already judged independent/both-valid within cooldown.\n * 4. Cap per-run work at maxPairsPerRun.\n */\n\nimport type { StorageManager } from \"../storage.js\";\nimport type { PluginConfig, MemoryFile, MemoryStatus } from \"../types.js\";\nimport type { SemanticDedupLookup } from \"../dedup/semantic.js\";\nimport { log } from \"../logger.js\";\nimport { judgeContradictionPairs, type ContradictionJudgeInput } from \"./contradiction-judge.js\";\nimport {\n writePairs,\n listPairs,\n isCoolingDown,\n computePairId,\n type ContradictionPair,\n} from \"./contradiction-review.js\";\nimport type { LocalLlmClient } from \"../local-llm.js\";\nimport type { FallbackLlmClient } from \"../fallback-llm.js\";\n\n// ── Types ──────────────────────────────────────────────────────────────────────\n\n/** The set of statuses that represent \"live\" memories eligible for scanning. */\nexport const ACTIVE_STATUSES: Set<MemoryStatus> = new Set([\"active\"]);\n\n/** High-value taxonomy buckets to scan. */\nconst SCAN_CATEGORIES = new Set([\n \"decision\",\n \"principle\",\n \"rule\",\n \"entity\",\n \"fact\",\n \"preference\",\n]);\n\nexport interface ScanResult {\n /** Total active memories scanned. */\n scanned: number;\n /** Candidate pairs generated by the pre-filter. */\n candidates: number;\n /** Pairs sent to judge. */\n judged: number;\n /** Pairs written to review queue. */\n queued: number;\n /** Pairs skipped due to cooldown. */\n cooledDown: number;\n /** Total wall-clock time in ms. */\n elapsedMs: number;\n}\n\nexport interface ScanDependencies {\n storage: StorageManager;\n config: PluginConfig;\n memoryDir: string;\n /** Pre-built embedding lookup. When provided, used as-is for Strategy 3. */\n embeddingLookup?: SemanticDedupLookup;\n /**\n * Factory to build a namespace-scoped embedding lookup.\n * When provided, takes precedence over `embeddingLookup`.\n * The scan driver passes its own `storage` so the lookup queries the correct index.\n */\n embeddingLookupFactory?: (storage: StorageManager) => SemanticDedupLookup | undefined;\n localLlm: LocalLlmClient | null;\n fallbackLlm: FallbackLlmClient | null;\n namespace?: string;\n}\n\n// ── Main scan driver ───────────────────────────────────────────────────────────\n\n/**\n * Run a contradiction scan over the memory corpus.\n *\n * This is the entry point called by the nightly cron and by the CLI.\n */\nexport async function runContradictionScan(deps: ScanDependencies): Promise<ScanResult> {\n const startTime = Date.now();\n const { storage, config, memoryDir, embeddingLookup, embeddingLookupFactory, localLlm, fallbackLlm, namespace } = deps;\n const scanConfig = config.contradictionScan;\n\n // Prefer the factory (which uses the scan's own storage for correct namespace scoping)\n // over a pre-built lookup (which may use default-namespace storage).\n const scopedEmbeddingLookup = embeddingLookupFactory\n ? embeddingLookupFactory(storage)\n : embeddingLookup;\n\n if (!scanConfig.enabled) {\n log.info(\"[contradiction-scan] disabled by config\");\n return { scanned: 0, candidates: 0, judged: 0, queued: 0, cooledDown: 0, elapsedMs: 0 };\n }\n\n // 1. Load active memories in scan categories\n const memories = await loadEligibleMemories(storage, namespace);\n log.info(\"[contradiction-scan] loaded %d eligible memories\", memories.length);\n\n if (memories.length < 2) {\n return { scanned: memories.length, candidates: 0, judged: 0, queued: 0, cooledDown: 0, elapsedMs: Date.now() - startTime };\n }\n\n // 2. Load existing review pairs for cooldown checking\n const existingPairs = listPairs(memoryDir, { filter: \"all\", namespace, limit: 10000 }).pairs;\n const existingMap = new Map<string, ContradictionPair>();\n for (const p of existingPairs) {\n existingMap.set(p.pairId, p);\n }\n\n // 3. Generate candidate pairs\n const candidates = await generatePairs(memories, existingMap, scanConfig, scopedEmbeddingLookup);\n const cooledDown = candidates.skipped;\n log.info(\"[contradiction-scan] generated %d candidates (%d cooled down)\", candidates.pairs.length, cooledDown);\n\n if (candidates.pairs.length === 0) {\n return {\n scanned: memories.length,\n candidates: 0,\n judged: 0,\n queued: 0,\n cooledDown,\n elapsedMs: Date.now() - startTime,\n };\n }\n\n // 4. Cap at maxPairsPerRun (deterministic selection by pairId)\n const capped = candidates.pairs\n .sort((a, b) => computePairId(a.idA, a.idB).localeCompare(computePairId(b.idA, b.idB)))\n .slice(0, scanConfig.maxPairsPerRun);\n\n // 5. Build judge inputs\n const judgeInputs: ContradictionJudgeInput[] = capped.map((pair) => ({\n memoryIdA: pair.idA,\n memoryIdB: pair.idB,\n textA: pair.textA,\n textB: pair.textB,\n categoryA: pair.categoryA,\n categoryB: pair.categoryB,\n }));\n\n // 6. Send to judge (per-scan cache avoids module-level singleton leak)\n const scanCache = new Map<string, import(\"./contradiction-judge.js\").ContradictionJudgeResult>();\n const judgeResult = await judgeContradictionPairs(judgeInputs, config, localLlm, fallbackLlm, scanCache);\n log.info(\"[contradiction-scan] judge completed: %d judged, %d cached in %dms\", judgeResult.judged, judgeResult.cached, judgeResult.elapsed);\n\n // 7. Write to review queue\n const queueEntries: Array<Omit<ContradictionPair, \"pairId\"> & { memoryIds: [string, string] }> = [];\n for (const [key, result] of judgeResult.results) {\n queueEntries.push({\n memoryIds: [result.memoryIdA, result.memoryIdB],\n verdict: result.verdict,\n rationale: result.rationale,\n confidence: result.confidence,\n detectedAt: new Date().toISOString(),\n // Set lastReviewedAt for non-actionable verdicts so cooldown prevents re-judging\n lastReviewedAt: result.verdict === \"independent\" ? new Date().toISOString() : undefined,\n namespace,\n });\n }\n\n const written = writePairs(memoryDir, queueEntries);\n const elapsed = Date.now() - startTime;\n log.info(\"[contradiction-scan] complete: %d queued in %dms\", written.length, elapsed);\n\n return {\n scanned: memories.length,\n candidates: candidates.pairs.length,\n judged: judgeResult.judged,\n queued: written.length,\n cooledDown,\n elapsedMs: elapsed,\n };\n}\n\n// ── Pair generation ────────────────────────────────────────────────────────────\n\ninterface CandidatePair {\n idA: string;\n idB: string;\n textA: string;\n textB: string;\n categoryA?: string;\n categoryB?: string;\n}\n\ninterface PairGenResult {\n pairs: CandidatePair[];\n skipped: number;\n}\n\nasync function generatePairs(\n memories: MemoryFile[],\n existingPairs: Map<string, ContradictionPair>,\n scanConfig: PluginConfig[\"contradictionScan\"],\n embeddingLookup?: SemanticDedupLookup,\n): Promise<PairGenResult> {\n const pairs: CandidatePair[] = [];\n const embeddingPairs: CandidatePair[] = [];\n let skipped = 0;\n const seen = new Set<string>();\n\n // Build index by entityRef for fast lookup\n const byEntity = new Map<string, MemoryFile[]>();\n for (const mem of memories) {\n const entity = mem.frontmatter.entityRef;\n if (entity) {\n const existing = byEntity.get(entity) ?? [];\n existing.push(mem);\n byEntity.set(entity, existing);\n }\n }\n\n // Strategy 1: Entity-ref based pairing (high precision)\n for (const [, group] of byEntity) {\n if (group.length < 2) continue;\n for (let i = 0; i < group.length; i++) {\n for (let j = i + 1; j < group.length; j++) {\n const a = group[i];\n const b = group[j];\n const pairId = computePairId(a.frontmatter.id!, b.frontmatter.id!);\n\n if (seen.has(pairId)) continue;\n seen.add(pairId);\n\n // Check cooldown\n const existing = existingPairs.get(pairId);\n if (existing && isCoolingDown(existing, scanConfig.cooldownDays)) {\n skipped++;\n continue;\n }\n\n pairs.push({\n idA: a.frontmatter.id!,\n idB: b.frontmatter.id!,\n textA: a.content,\n textB: b.content,\n categoryA: a.frontmatter.category as string | undefined,\n categoryB: b.frontmatter.category as string | undefined,\n });\n }\n }\n }\n\n // Strategy 2: Tag/topic overlap for memories without shared entityRef\n const noEntity = memories.filter((m) => !m.frontmatter.entityRef);\n for (let i = 0; i < noEntity.length; i++) {\n for (let j = i + 1; j < noEntity.length; j++) {\n const a = noEntity[i];\n const b = noEntity[j];\n const overlap = jaccardOverlap(\n (a.frontmatter.tags as string[]) ?? [],\n (b.frontmatter.tags as string[]) ?? [],\n );\n\n if (overlap < scanConfig.topicOverlapFloor) continue;\n\n const pairId = computePairId(a.frontmatter.id!, b.frontmatter.id!);\n if (seen.has(pairId)) continue;\n seen.add(pairId);\n\n const existing = existingPairs.get(pairId);\n if (existing && isCoolingDown(existing, scanConfig.cooldownDays)) {\n skipped++;\n continue;\n }\n\n pairs.push({\n idA: a.frontmatter.id!,\n idB: b.frontmatter.id!,\n textA: a.content,\n textB: b.content,\n categoryA: a.frontmatter.category as string | undefined,\n categoryB: b.frontmatter.category as string | undefined,\n });\n }\n }\n\n // Strategy 3: Embedding cosine similarity (enforces similarityFloor config)\n if (embeddingLookup) {\n const memoryById = new Map(memories.map((m) => [m.frontmatter.id!, m]));\n for (const mem of memories) {\n const id = mem.frontmatter.id!;\n try {\n const hits = await embeddingLookup(mem.content, 20);\n for (const hit of hits) {\n if (hit.score < scanConfig.similarityFloor) continue;\n if (hit.id === id) continue;\n const peer = memoryById.get(hit.id);\n if (!peer) continue;\n\n const pairId = computePairId(id, hit.id);\n if (seen.has(pairId)) continue;\n seen.add(pairId);\n\n const existing = existingPairs.get(pairId);\n if (existing && isCoolingDown(existing, scanConfig.cooldownDays)) {\n skipped++;\n continue;\n }\n\n embeddingPairs.push({\n idA: id,\n idB: hit.id,\n textA: mem.content,\n textB: peer.content,\n categoryA: mem.frontmatter.category as string | undefined,\n categoryB: peer.frontmatter.category as string | undefined,\n });\n }\n } catch {\n // Embedding backend unavailable — skip, entity-ref/tag strategies already covered\n }\n }\n }\n\n // Append embedding pairs after high-precision entity/topic pairs so the\n // downstream sort+slice(maxPairsPerRun) keeps precision-first ordering.\n pairs.push(...embeddingPairs);\n\n return { pairs, skipped };\n}\n\n// ── Helpers ────────────────────────────────────────────────────────────────────\n\nasync function loadEligibleMemories(storage: StorageManager, namespace?: string): Promise<MemoryFile[]> {\n let all: MemoryFile[];\n try {\n all = await storage.readAllMemories();\n } catch {\n return [];\n }\n\n return all.filter((mem) => {\n const fm = mem.frontmatter;\n // Only active memories (rule 53: explicit ACTIVE_STATUSES set)\n const status = (fm.status as MemoryStatus) ?? \"active\";\n if (!ACTIVE_STATUSES.has(status)) return false;\n\n // Only scan high-value categories\n const category = fm.category as string | undefined;\n if (category && !SCAN_CATEGORIES.has(category)) return false;\n\n // Must have content\n if (!mem.content || mem.content.trim().length === 0) return false;\n\n // Must have an ID\n if (!fm.id) return false;\n\n // Namespace scoping is handled at the storage layer — memoryDir is\n // already namespace-scoped, so readAllMemories() returns only memories\n // within the requested namespace.\n\n return true;\n });\n}\n\nfunction jaccardOverlap(a: string[], b: string[]): number {\n if (a.length === 0 && b.length === 0) return 0;\n const setA = new Set(a.map((t) => t.toLowerCase()));\n const setB = new Set(b.map((t) => t.toLowerCase()));\n let intersection = 0;\n for (const item of setA) {\n if (setB.has(item)) intersection++;\n }\n const union = setA.size + setB.size - intersection;\n return union === 0 ? 0 : intersection / union;\n}\n"],"mappings":"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","names":[]}
@@ -2,6 +2,7 @@ import {
2
2
  CrossNamespaceBudget,
3
3
  DEFAULT_CROSS_NAMESPACE_BUDGET
4
4
  } from "./chunk-GDFS42HT.js";
5
+ import "./chunk-PZ5AY32C.js";
5
6
  export {
6
7
  CrossNamespaceBudget,
7
8
  DEFAULT_CROSS_NAMESPACE_BUDGET
@@ -6,6 +6,7 @@ import {
6
6
  } from "./chunk-C6QPK5GG.js";
7
7
  import "./chunk-DGXUHMOV.js";
8
8
  import "./chunk-LPSF4OQH.js";
9
+ import "./chunk-PZ5AY32C.js";
9
10
  export {
10
11
  getCueAnchorStoreStatus,
11
12
  recordCueAnchor,
@@ -4,6 +4,7 @@ import {
4
4
  import "./chunk-3SLRNYNG.js";
5
5
  import "./chunk-LIRZNNUP.js";
6
6
  import "./chunk-Y4Z4I6WK.js";
7
+ import "./chunk-PZ5AY32C.js";
7
8
  export {
8
9
  GraphDashboardServer
9
10
  };
@@ -5,6 +5,7 @@ import {
5
5
  } from "./chunk-GZCUW5IC.js";
6
6
  import "./chunk-EJI5XIBB.js";
7
7
  import "./chunk-2ODBA7MQ.js";
8
+ import "./chunk-PZ5AY32C.js";
8
9
  export {
9
10
  buildExtensionsFooterForSummary,
10
11
  formatDaySummaryMemories,
@@ -3,6 +3,7 @@ import {
3
3
  delinearize,
4
4
  resolveCoReferences
5
5
  } from "./chunk-VEWZZM3H.js";
6
+ import "./chunk-PZ5AY32C.js";
6
7
  export {
7
8
  anchorTemporalExpressions,
8
9
  delinearize,
@@ -4,6 +4,7 @@ import {
4
4
  import "./chunk-Y4FHOFJ2.js";
5
5
  import "./chunk-PVGDJXVK.js";
6
6
  import "./chunk-DT5TVLJE.js";
7
+ import "./chunk-PZ5AY32C.js";
7
8
  export {
8
9
  tryDirectAnswer
9
10
  };
@@ -3,6 +3,7 @@ import {
3
3
  isDirectAnswerEligible
4
4
  } from "./chunk-Y4FHOFJ2.js";
5
5
  import "./chunk-DT5TVLJE.js";
6
+ import "./chunk-PZ5AY32C.js";
6
7
  export {
7
8
  FILTER_LABELS,
8
9
  isDirectAnswerEligible
@@ -0,0 +1,286 @@
1
+ import "./chunk-PZ5AY32C.js";
2
+
3
+ // src/maintenance/dreams-ledger.ts
4
+ import path from "path";
5
+ import { appendFile, lstat, mkdir, readdir, readFile } from "fs/promises";
6
+ function dreamsLedgerPath(memoryDir) {
7
+ return path.join(memoryDir, "state", "dreams-ledger.jsonl");
8
+ }
9
+ async function appendDreamsLedgerEntry(memoryDir, entry) {
10
+ const ledgerPath = dreamsLedgerPath(memoryDir);
11
+ await mkdir(path.dirname(ledgerPath), { recursive: true });
12
+ await appendFile(ledgerPath, JSON.stringify(entry) + "\n", "utf-8");
13
+ }
14
+ async function readDreamsLedgerEntries(memoryDir) {
15
+ const ledgerPath = dreamsLedgerPath(memoryDir);
16
+ let raw;
17
+ try {
18
+ raw = await readFile(ledgerPath, "utf-8");
19
+ } catch (err) {
20
+ const code = err.code;
21
+ if (code === "ENOENT") return [];
22
+ throw err;
23
+ }
24
+ const entries = [];
25
+ for (const line of raw.split("\n")) {
26
+ const trimmed = line.trim();
27
+ if (!trimmed) continue;
28
+ try {
29
+ const parsed = JSON.parse(trimmed);
30
+ if (typeof parsed !== "object" || parsed === null) continue;
31
+ if (typeof parsed.phase === "string" && (parsed.phase === "lightSleep" || parsed.phase === "rem" || parsed.phase === "deepSleep") && typeof parsed.startedAt === "string" && typeof parsed.completedAt === "string" && typeof parsed.durationMs === "number" && typeof parsed.itemsProcessed === "number") {
32
+ entries.push({
33
+ schemaVersion: 1,
34
+ startedAt: parsed.startedAt,
35
+ completedAt: parsed.completedAt,
36
+ durationMs: parsed.durationMs,
37
+ phase: parsed.phase,
38
+ itemsProcessed: parsed.itemsProcessed,
39
+ dryRun: parsed.dryRun === true,
40
+ trigger: parsed.trigger === "manual" ? "manual" : "scheduled",
41
+ notes: typeof parsed.notes === "string" ? parsed.notes : void 0
42
+ });
43
+ }
44
+ } catch {
45
+ }
46
+ }
47
+ return entries;
48
+ }
49
+ var ALL_PHASES = ["lightSleep", "rem", "deepSleep"];
50
+ var MAX_WINDOW_HOURS = 24 * 365 * 100;
51
+ function normalizeDreamsStatusWindowHours(value, fallback = 24) {
52
+ const raw = value === void 0 || value === null ? fallback : value;
53
+ if (typeof raw !== "number" || !Number.isFinite(raw) || !Number.isInteger(raw) || raw < 1 || raw > MAX_WINDOW_HOURS) {
54
+ throw new RangeError(`windowHours must be a positive integer no greater than ${MAX_WINDOW_HOURS}`);
55
+ }
56
+ return raw;
57
+ }
58
+ async function getDreamsStatus(memoryDir, windowHours = 24, now = /* @__PURE__ */ new Date()) {
59
+ const boundedWindowHours = normalizeDreamsStatusWindowHours(windowHours);
60
+ const nowMs = now.getTime();
61
+ if (!Number.isFinite(nowMs)) {
62
+ throw new RangeError("now must be a valid Date");
63
+ }
64
+ const windowMs = boundedWindowHours * 60 * 60 * 1e3;
65
+ const windowStart = new Date(nowMs - windowMs);
66
+ const windowEnd = now;
67
+ if (!Number.isFinite(windowStart.getTime())) {
68
+ throw new RangeError("windowHours produces an invalid status window");
69
+ }
70
+ const entries = await readDreamsLedgerEntries(memoryDir);
71
+ const windowEntries = entries.filter((e) => {
72
+ const ts = Date.parse(e.completedAt);
73
+ return Number.isFinite(ts) && ts >= windowStart.getTime() && ts < windowEnd.getTime();
74
+ });
75
+ const statusMap = /* @__PURE__ */ new Map();
76
+ for (const phase of ALL_PHASES) {
77
+ statusMap.set(phase, {
78
+ phase,
79
+ runCount: 0,
80
+ totalDurationMs: 0,
81
+ totalItemsProcessed: 0,
82
+ lastRunAt: null,
83
+ lastDurationMs: null
84
+ });
85
+ }
86
+ for (const entry of windowEntries) {
87
+ const status = statusMap.get(entry.phase);
88
+ if (!status) continue;
89
+ status.runCount += 1;
90
+ status.totalDurationMs += entry.durationMs;
91
+ status.totalItemsProcessed += entry.itemsProcessed;
92
+ if (status.lastRunAt === null || Date.parse(entry.completedAt) > Date.parse(status.lastRunAt)) {
93
+ status.lastRunAt = entry.completedAt;
94
+ status.lastDurationMs = entry.durationMs;
95
+ }
96
+ }
97
+ return {
98
+ windowStart: windowStart.toISOString(),
99
+ windowEnd: windowEnd.toISOString(),
100
+ phases: {
101
+ lightSleep: statusMap.get("lightSleep"),
102
+ rem: statusMap.get("rem"),
103
+ deepSleep: statusMap.get("deepSleep")
104
+ }
105
+ };
106
+ }
107
+ async function recordDreamsPhaseRun(options) {
108
+ const startedAt = options.startedAt ?? (/* @__PURE__ */ new Date()).toISOString();
109
+ const completedAt = options.completedAt ?? (/* @__PURE__ */ new Date()).toISOString();
110
+ const durationMs = Math.max(0, Date.parse(completedAt) - Date.parse(startedAt));
111
+ const ledgerEntry = {
112
+ schemaVersion: 1,
113
+ startedAt,
114
+ completedAt,
115
+ durationMs: Number.isFinite(durationMs) ? durationMs : 0,
116
+ phase: options.phase,
117
+ itemsProcessed: Math.max(0, Math.floor(options.itemsProcessed)),
118
+ dryRun: options.dryRun === true,
119
+ trigger: options.trigger,
120
+ notes: options.notes
121
+ };
122
+ if (!ledgerEntry.dryRun) {
123
+ await appendDreamsLedgerEntry(options.memoryDir, ledgerEntry);
124
+ }
125
+ return ledgerEntry;
126
+ }
127
+ async function runDreamsPhase(options, governanceRunner, phaseRunner) {
128
+ const { memoryDir, phase, dryRun = false } = options;
129
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
130
+ let itemsProcessed = 0;
131
+ let notes;
132
+ if (phase === "lightSleep") {
133
+ if (!dryRun) {
134
+ if (!phaseRunner) {
135
+ throw new Error("light-sleep manual runs require a phase runner");
136
+ }
137
+ const result = await phaseRunner({ memoryDir, phase });
138
+ itemsProcessed = Math.max(0, Math.floor(result.itemsProcessed));
139
+ notes = result.notes ?? `scored ${itemsProcessed} memories`;
140
+ } else {
141
+ try {
142
+ const ledgerPath = path.join(memoryDir, "state", "observation-ledger", "rebuilt-observations.jsonl");
143
+ let raw = "";
144
+ try {
145
+ raw = await readFile(ledgerPath, "utf-8");
146
+ } catch {
147
+ }
148
+ const lines = raw.split("\n").filter((l) => l.trim().length > 0);
149
+ const cutoff = Date.now() - 24 * 60 * 60 * 1e3;
150
+ itemsProcessed = lines.filter((line) => {
151
+ try {
152
+ const obj = JSON.parse(line);
153
+ const timestamp = typeof obj.ts === "string" ? obj.ts : typeof obj.timestamp === "string" ? obj.timestamp : null;
154
+ if (!timestamp) return false;
155
+ const ms = Date.parse(timestamp);
156
+ return Number.isFinite(ms) && ms >= cutoff;
157
+ } catch {
158
+ return false;
159
+ }
160
+ }).length;
161
+ notes = `dry-run: would score ${itemsProcessed} observation entries`;
162
+ } catch (err) {
163
+ throw new Error(`light-sleep scan failed: ${err instanceof Error ? err.message : String(err)}`);
164
+ }
165
+ }
166
+ } else if (phase === "rem") {
167
+ if (!dryRun) {
168
+ if (!phaseRunner) {
169
+ throw new Error("REM manual runs require a phase runner");
170
+ }
171
+ const result = await phaseRunner({ memoryDir, phase });
172
+ itemsProcessed = Math.max(0, Math.floor(result.itemsProcessed));
173
+ notes = result.notes ?? `REM pass assessed ${itemsProcessed} memories`;
174
+ } else {
175
+ try {
176
+ const stateFilePath = path.join(memoryDir, "state", "semantic-consolidation-last-run.json");
177
+ let lastRunAt = null;
178
+ try {
179
+ const stateRaw = await readFile(stateFilePath, "utf-8");
180
+ const stateData = JSON.parse(stateRaw);
181
+ lastRunAt = stateData.lastRunAt ?? null;
182
+ } catch {
183
+ }
184
+ const memFiles = await listMemoryFiles(memoryDir);
185
+ itemsProcessed = memFiles.length;
186
+ notes = `dry-run: ${itemsProcessed} memories would enter REM consolidation pass${lastRunAt ? ` (last run: ${lastRunAt})` : " (never run)"}`;
187
+ } catch (err) {
188
+ throw new Error(`REM scan failed: ${err instanceof Error ? err.message : String(err)}`);
189
+ }
190
+ }
191
+ } else {
192
+ if (governanceRunner) {
193
+ try {
194
+ const result = await governanceRunner({ memoryDir, dryRun });
195
+ itemsProcessed = result.scannedMemories;
196
+ notes = result.notes ?? (dryRun ? `dry-run: ${result.appliedActionCount} actions proposed` : `${result.appliedActionCount} actions applied`);
197
+ } catch (err) {
198
+ throw new Error(`deep-sleep governance run failed: ${err instanceof Error ? err.message : String(err)}`);
199
+ }
200
+ } else {
201
+ const memFiles = await listMemoryFiles(memoryDir);
202
+ itemsProcessed = memFiles.length;
203
+ notes = dryRun ? `dry-run: ${itemsProcessed} memories eligible for deep-sleep governance` : `assessed ${itemsProcessed} memories for deep-sleep governance`;
204
+ }
205
+ }
206
+ const completedAt = (/* @__PURE__ */ new Date()).toISOString();
207
+ const durationMs = Math.max(0, Date.parse(completedAt) - Date.parse(startedAt));
208
+ let ledgerEntry;
209
+ try {
210
+ ledgerEntry = await recordDreamsPhaseRun({
211
+ memoryDir,
212
+ startedAt,
213
+ completedAt,
214
+ phase,
215
+ itemsProcessed,
216
+ dryRun,
217
+ trigger: "manual",
218
+ notes
219
+ });
220
+ } catch {
221
+ }
222
+ return {
223
+ phase,
224
+ dryRun,
225
+ durationMs: ledgerEntry?.durationMs ?? durationMs,
226
+ itemsProcessed,
227
+ notes,
228
+ ledgerEntry
229
+ };
230
+ }
231
+ function summarizeGovernanceResultForDreams(govResult, dryRun) {
232
+ const proposedCount = govResult.proposedActions.length;
233
+ const appliedCount = govResult.appliedActions.length;
234
+ const scannedCount = typeof govResult.summary?.scannedMemories === "number" && Number.isFinite(govResult.summary.scannedMemories) ? Math.max(0, Math.floor(govResult.summary.scannedMemories)) : govResult.reviewQueue.length;
235
+ return {
236
+ scannedMemories: scannedCount,
237
+ appliedActionCount: appliedCount,
238
+ notes: dryRun ? `shadow mode: ${proposedCount} actions proposed` : `applied ${appliedCount} actions`
239
+ };
240
+ }
241
+ async function listMemoryFiles(memoryDir) {
242
+ const out = [];
243
+ try {
244
+ const root = await lstat(memoryDir);
245
+ if (root.isSymbolicLink()) {
246
+ throw new Error(`memoryDir must not be a symlink: ${memoryDir}`);
247
+ }
248
+ if (!root.isDirectory()) return out;
249
+ } catch (err) {
250
+ if (err instanceof Error && /must not be a symlink/.test(err.message)) {
251
+ throw err;
252
+ }
253
+ return out;
254
+ }
255
+ async function walk(dir) {
256
+ let entries;
257
+ try {
258
+ entries = await readdir(dir, { withFileTypes: true });
259
+ } catch {
260
+ return;
261
+ }
262
+ for (const entry of entries) {
263
+ if (entry.isSymbolicLink()) continue;
264
+ const full = path.join(dir, entry.name);
265
+ if (entry.isDirectory()) {
266
+ if (entry.name === "state" || entry.name === "archive" || entry.name === "namespaces" || entry.name === ".git") continue;
267
+ await walk(full);
268
+ } else if (entry.isFile() && entry.name.endsWith(".md")) {
269
+ out.push(full);
270
+ }
271
+ }
272
+ }
273
+ await walk(memoryDir);
274
+ return out;
275
+ }
276
+ export {
277
+ appendDreamsLedgerEntry,
278
+ dreamsLedgerPath,
279
+ getDreamsStatus,
280
+ normalizeDreamsStatusWindowHours,
281
+ readDreamsLedgerEntries,
282
+ recordDreamsPhaseRun,
283
+ runDreamsPhase,
284
+ summarizeGovernanceResultForDreams
285
+ };
286
+ //# sourceMappingURL=dreams-ledger-LR2NBAZE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/maintenance/dreams-ledger.ts"],"sourcesContent":["/**\n * dreams-ledger.ts — per-phase telemetry for the Dreams consolidation pipeline.\n *\n * Every scheduled or manual phase run appends one JSONL entry to\n * <memoryDir>/state/dreams-ledger.jsonl\n *\n * The entry records which phase ran, how long it took, and a small\n * itemsProcessed counter so `remnic dreams status` can aggregate the last\n * 24-hour window without scanning the full memory corpus.\n *\n * This module is intentionally side-effect-free on import (no fs calls at\n * module load time) so tests can import it without touching the filesystem.\n */\n\nimport path from \"node:path\";\nimport { appendFile, lstat, mkdir, readdir, readFile } from \"node:fs/promises\";\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\n/** The three named phases of the Dreams consolidation pipeline. */\nexport type DreamsPhase = \"lightSleep\" | \"rem\" | \"deepSleep\";\n\n/**\n * One entry written to the dreams ledger for every phase run.\n * Older entries that predate this field simply won't have it (no backfill).\n */\nexport interface DreamsLedgerEntry {\n /** Schema version — always 1 for entries written by this module. */\n schemaVersion: 1;\n /** ISO-8601 timestamp when the phase run started. */\n startedAt: string;\n /** ISO-8601 timestamp when the phase run completed. */\n completedAt: string;\n /** Wall-clock duration in milliseconds. */\n durationMs: number;\n /**\n * Which Dreams phase this entry represents.\n * - `lightSleep` — recent activity scoring + clustering\n * - `rem` — cross-session synthesis, supersession, consolidation\n * - `deepSleep` — tier migration, page-version snapshots, archive\n */\n phase: DreamsPhase;\n /** How many memory items were evaluated (scored / clustered / migrated). */\n itemsProcessed: number;\n /** Whether this was a dry-run (no writes committed). */\n dryRun: boolean;\n /**\n * How the phase was triggered.\n * - `scheduled` — invoked by the governance cron or orchestrator maintenance pass\n * - `manual` — invoked via `remnic dreams run`\n */\n trigger: \"scheduled\" | \"manual\";\n /** Free-form notes for debugging (optional, never required). */\n notes?: string;\n}\n\n/** Aggregated stats for a single phase over a time window. */\nexport interface DreamsPhaseStatus {\n phase: DreamsPhase;\n /** Number of phase runs in the window. */\n runCount: number;\n /** Total wall-clock milliseconds across all runs in the window. */\n totalDurationMs: number;\n /** Total items processed across all runs in the window. */\n totalItemsProcessed: number;\n /** ISO-8601 timestamp of the most recent completed run, or null if none. */\n lastRunAt: string | null;\n /** Duration of the most recent run in ms, or null if none. */\n lastDurationMs: number | null;\n}\n\n/** Shape returned by `getDreamsStatus` — the canonical telemetry response. */\nexport interface DreamsStatusResult {\n /** ISO-8601 start of the query window (inclusive). */\n windowStart: string;\n /** ISO-8601 end of the query window (exclusive). */\n windowEnd: string;\n /** Per-phase summaries, always present for all three phases. */\n phases: {\n lightSleep: DreamsPhaseStatus;\n rem: DreamsPhaseStatus;\n deepSleep: DreamsPhaseStatus;\n };\n}\n\n// ── Path helpers ──────────────────────────────────────────────────────────────\n\nexport function dreamsLedgerPath(memoryDir: string): string {\n return path.join(memoryDir, \"state\", \"dreams-ledger.jsonl\");\n}\n\n// ── Writer ────────────────────────────────────────────────────────────────────\n\n/**\n * Append a single entry to the dreams ledger.\n * Creates the file (and its parent directory) if needed.\n * Uses `appendFile` (O_APPEND) so concurrent callers never overwrite each other.\n */\nexport async function appendDreamsLedgerEntry(\n memoryDir: string,\n entry: DreamsLedgerEntry,\n): Promise<void> {\n const ledgerPath = dreamsLedgerPath(memoryDir);\n await mkdir(path.dirname(ledgerPath), { recursive: true });\n await appendFile(ledgerPath, JSON.stringify(entry) + \"\\n\", \"utf-8\");\n}\n\n// ── Reader ────────────────────────────────────────────────────────────────────\n\n/**\n * Parse all valid `DreamsLedgerEntry` rows from the ledger file.\n * Malformed lines are silently skipped (resilience over strictness for telemetry).\n */\nexport async function readDreamsLedgerEntries(memoryDir: string): Promise<DreamsLedgerEntry[]> {\n const ledgerPath = dreamsLedgerPath(memoryDir);\n let raw: string;\n try {\n raw = await readFile(ledgerPath, \"utf-8\");\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === \"ENOENT\") return [];\n throw err;\n }\n\n const entries: DreamsLedgerEntry[] = [];\n for (const line of raw.split(\"\\n\")) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n const parsed = JSON.parse(trimmed) as Partial<DreamsLedgerEntry>;\n if (typeof parsed !== \"object\" || parsed === null) continue;\n if (\n typeof parsed.phase === \"string\" &&\n (parsed.phase === \"lightSleep\" || parsed.phase === \"rem\" || parsed.phase === \"deepSleep\") &&\n typeof parsed.startedAt === \"string\" &&\n typeof parsed.completedAt === \"string\" &&\n typeof parsed.durationMs === \"number\" &&\n typeof parsed.itemsProcessed === \"number\"\n ) {\n entries.push({\n schemaVersion: 1,\n startedAt: parsed.startedAt,\n completedAt: parsed.completedAt,\n durationMs: parsed.durationMs,\n phase: parsed.phase,\n itemsProcessed: parsed.itemsProcessed,\n dryRun: parsed.dryRun === true,\n trigger: parsed.trigger === \"manual\" ? \"manual\" : \"scheduled\",\n notes: typeof parsed.notes === \"string\" ? parsed.notes : undefined,\n });\n }\n } catch {\n // Malformed line — skip.\n }\n }\n return entries;\n}\n\n// ── Aggregator ────────────────────────────────────────────────────────────────\n\nconst ALL_PHASES: DreamsPhase[] = [\"lightSleep\", \"rem\", \"deepSleep\"];\nconst MAX_WINDOW_HOURS = 24 * 365 * 100;\n\nexport function normalizeDreamsStatusWindowHours(value: unknown, fallback = 24): number {\n const raw = value === undefined || value === null ? fallback : value;\n if (\n typeof raw !== \"number\" ||\n !Number.isFinite(raw) ||\n !Number.isInteger(raw) ||\n raw < 1 ||\n raw > MAX_WINDOW_HOURS\n ) {\n throw new RangeError(`windowHours must be a positive integer no greater than ${MAX_WINDOW_HOURS}`);\n }\n return raw;\n}\n\n/**\n * Build per-phase 24-hour summary.\n *\n * @param memoryDir The memory directory (parent of `state/`).\n * @param windowHours How many hours to look back (default 24).\n * @param now Reference time (default `new Date()`).\n */\nexport async function getDreamsStatus(\n memoryDir: string,\n windowHours = 24,\n now: Date = new Date(),\n): Promise<DreamsStatusResult> {\n const boundedWindowHours = normalizeDreamsStatusWindowHours(windowHours);\n const nowMs = now.getTime();\n if (!Number.isFinite(nowMs)) {\n throw new RangeError(\"now must be a valid Date\");\n }\n const windowMs = boundedWindowHours * 60 * 60 * 1000;\n const windowStart = new Date(nowMs - windowMs);\n const windowEnd = now;\n if (!Number.isFinite(windowStart.getTime())) {\n throw new RangeError(\"windowHours produces an invalid status window\");\n }\n\n const entries = await readDreamsLedgerEntries(memoryDir);\n\n // Filter to entries within the window based on completedAt.\n const windowEntries = entries.filter((e) => {\n const ts = Date.parse(e.completedAt);\n return Number.isFinite(ts) && ts >= windowStart.getTime() && ts < windowEnd.getTime();\n });\n\n const statusMap = new Map<DreamsPhase, DreamsPhaseStatus>();\n for (const phase of ALL_PHASES) {\n statusMap.set(phase, {\n phase,\n runCount: 0,\n totalDurationMs: 0,\n totalItemsProcessed: 0,\n lastRunAt: null,\n lastDurationMs: null,\n });\n }\n\n for (const entry of windowEntries) {\n const status = statusMap.get(entry.phase);\n if (!status) continue;\n status.runCount += 1;\n status.totalDurationMs += entry.durationMs;\n status.totalItemsProcessed += entry.itemsProcessed;\n\n // Track the most recent run (by completedAt).\n if (\n status.lastRunAt === null ||\n Date.parse(entry.completedAt) > Date.parse(status.lastRunAt)\n ) {\n status.lastRunAt = entry.completedAt;\n status.lastDurationMs = entry.durationMs;\n }\n }\n\n return {\n windowStart: windowStart.toISOString(),\n windowEnd: windowEnd.toISOString(),\n phases: {\n lightSleep: statusMap.get(\"lightSleep\")!,\n rem: statusMap.get(\"rem\")!,\n deepSleep: statusMap.get(\"deepSleep\")!,\n },\n };\n}\n\n// ── Phase runner (PR 4/4: manual invocation) ─────────────────────────────────\n\nexport interface DreamsRunOptions {\n memoryDir: string;\n phase: DreamsPhase;\n dryRun?: boolean;\n}\n\n/** Public result shape — identical to what HTTP, MCP, and CLI surfaces expose. */\nexport interface DreamsRunResult {\n phase: DreamsPhase;\n dryRun: boolean;\n durationMs: number;\n itemsProcessed: number;\n notes?: string;\n}\n\n/** Internal result shape returned by `runDreamsPhase` — includes the raw ledger entry. */\nexport interface DreamsRunResultInternal extends DreamsRunResult {\n ledgerEntry?: DreamsLedgerEntry;\n}\n\nexport async function recordDreamsPhaseRun(options: {\n memoryDir: string;\n phase: DreamsPhase;\n trigger: DreamsLedgerEntry[\"trigger\"];\n dryRun?: boolean;\n itemsProcessed: number;\n notes?: string;\n startedAt?: string;\n completedAt?: string;\n}): Promise<DreamsLedgerEntry> {\n const startedAt = options.startedAt ?? new Date().toISOString();\n const completedAt = options.completedAt ?? new Date().toISOString();\n const durationMs = Math.max(0, Date.parse(completedAt) - Date.parse(startedAt));\n const ledgerEntry: DreamsLedgerEntry = {\n schemaVersion: 1,\n startedAt,\n completedAt,\n durationMs: Number.isFinite(durationMs) ? durationMs : 0,\n phase: options.phase,\n itemsProcessed: Math.max(0, Math.floor(options.itemsProcessed)),\n dryRun: options.dryRun === true,\n trigger: options.trigger,\n notes: options.notes,\n };\n if (!ledgerEntry.dryRun) {\n await appendDreamsLedgerEntry(options.memoryDir, ledgerEntry);\n }\n return ledgerEntry;\n}\n\n/**\n * Manually invoke a single Dreams phase pass.\n *\n * For light sleep and REM: runs a lightweight scan against the observation\n * ledger and returns a count of items that would be (or were, if not dry-run)\n * processed. The actual heavy consolidation is long-running and orchestrator-\n * bound; the manual surface delegates to existing ledger utilities and returns\n * the phase telemetry so callers get the same shape as a scheduled run.\n *\n * For deep sleep: delegates to the memory governance run (shadow mode when\n * dryRun is true, apply mode otherwise).\n */\nexport async function runDreamsPhase(\n options: DreamsRunOptions,\n governanceRunner?: (opts: { memoryDir: string; dryRun: boolean }) => Promise<{ scannedMemories: number; appliedActionCount: number; notes?: string }>,\n phaseRunner?: (opts: { memoryDir: string; phase: Exclude<DreamsPhase, \"deepSleep\"> }) => Promise<{ itemsProcessed: number; notes?: string }>,\n): Promise<DreamsRunResultInternal> {\n const { memoryDir, phase, dryRun = false } = options;\n const startedAt = new Date().toISOString();\n\n let itemsProcessed = 0;\n let notes: string | undefined;\n\n if (phase === \"lightSleep\") {\n // Dry-run light sleep counts recent observation entries as a preview.\n // Live runs must be backed by the orchestrator phase runner so the command\n // never reports success without executing the phase.\n if (!dryRun) {\n if (!phaseRunner) {\n throw new Error(\"light-sleep manual runs require a phase runner\");\n }\n const result = await phaseRunner({ memoryDir, phase });\n itemsProcessed = Math.max(0, Math.floor(result.itemsProcessed));\n notes = result.notes ?? `scored ${itemsProcessed} memories`;\n } else {\n // Light sleep: count observation ledger entries from the last 24h as a\n // proxy for \"items scored\". The live value-scoring pass runs through the\n // phase runner above.\n try {\n const ledgerPath = path.join(memoryDir, \"state\", \"observation-ledger\", \"rebuilt-observations.jsonl\");\n let raw = \"\";\n try {\n raw = await readFile(ledgerPath, \"utf-8\");\n } catch {\n // No ledger yet — zero items.\n }\n const lines = raw.split(\"\\n\").filter((l) => l.trim().length > 0);\n const cutoff = Date.now() - 24 * 60 * 60 * 1000;\n itemsProcessed = lines.filter((line) => {\n try {\n const obj = JSON.parse(line) as { timestamp?: string; ts?: string };\n const timestamp = typeof obj.ts === \"string\"\n ? obj.ts\n : typeof obj.timestamp === \"string\"\n ? obj.timestamp\n : null;\n if (!timestamp) return false;\n const ms = Date.parse(timestamp);\n return Number.isFinite(ms) && ms >= cutoff;\n } catch {\n return false;\n }\n }).length;\n notes = `dry-run: would score ${itemsProcessed} observation entries`;\n } catch (err) {\n throw new Error(`light-sleep scan failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n } else if (phase === \"rem\") {\n if (!dryRun) {\n if (!phaseRunner) {\n throw new Error(\"REM manual runs require a phase runner\");\n }\n const result = await phaseRunner({ memoryDir, phase });\n itemsProcessed = Math.max(0, Math.floor(result.itemsProcessed));\n notes = result.notes ?? `REM pass assessed ${itemsProcessed} memories`;\n } else {\n // REM dry-runs estimate candidates without synthesizing or archiving.\n try {\n const stateFilePath = path.join(memoryDir, \"state\", \"semantic-consolidation-last-run.json\");\n let lastRunAt: string | null = null;\n try {\n const stateRaw = await readFile(stateFilePath, \"utf-8\");\n const stateData = JSON.parse(stateRaw) as { lastRunAt?: string };\n lastRunAt = stateData.lastRunAt ?? null;\n } catch {\n // No state file — never run.\n }\n const memFiles = await listMemoryFiles(memoryDir);\n itemsProcessed = memFiles.length;\n notes = `dry-run: ${itemsProcessed} memories would enter REM consolidation pass${lastRunAt ? ` (last run: ${lastRunAt})` : \" (never run)\"}`;\n } catch (err) {\n throw new Error(`REM scan failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n } else {\n // deep sleep\n if (governanceRunner) {\n try {\n const result = await governanceRunner({ memoryDir, dryRun });\n itemsProcessed = result.scannedMemories;\n notes = result.notes ?? (dryRun ? `dry-run: ${result.appliedActionCount} actions proposed` : `${result.appliedActionCount} actions applied`);\n } catch (err) {\n throw new Error(`deep-sleep governance run failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n } else {\n // Fallback: count memory files.\n const memFiles = await listMemoryFiles(memoryDir);\n itemsProcessed = memFiles.length;\n notes = dryRun\n ? `dry-run: ${itemsProcessed} memories eligible for deep-sleep governance`\n : `assessed ${itemsProcessed} memories for deep-sleep governance`;\n }\n }\n\n const completedAt = new Date().toISOString();\n const durationMs = Math.max(0, Date.parse(completedAt) - Date.parse(startedAt));\n let ledgerEntry: DreamsLedgerEntry | undefined;\n try {\n ledgerEntry = await recordDreamsPhaseRun({\n memoryDir,\n startedAt,\n completedAt,\n phase,\n itemsProcessed,\n dryRun,\n trigger: \"manual\",\n notes,\n });\n } catch {\n // Telemetry is best-effort: the phase work has already completed.\n }\n\n return {\n phase,\n dryRun,\n durationMs: ledgerEntry?.durationMs ?? durationMs,\n itemsProcessed,\n notes,\n ledgerEntry,\n };\n}\n\n// ── Shared governance result mapping ──────────────────────────────────────────\n\nexport function summarizeGovernanceResultForDreams(\n govResult: {\n summary?: { scannedMemories?: number };\n proposedActions: unknown[];\n appliedActions: unknown[];\n reviewQueue: unknown[];\n },\n dryRun: boolean,\n): { scannedMemories: number; appliedActionCount: number; notes?: string } {\n const proposedCount = govResult.proposedActions.length;\n const appliedCount = govResult.appliedActions.length;\n const scannedCount =\n typeof govResult.summary?.scannedMemories === \"number\" &&\n Number.isFinite(govResult.summary.scannedMemories)\n ? Math.max(0, Math.floor(govResult.summary.scannedMemories))\n : govResult.reviewQueue.length;\n return {\n scannedMemories: scannedCount,\n appliedActionCount: appliedCount,\n notes: dryRun\n ? `shadow mode: ${proposedCount} actions proposed`\n : `applied ${appliedCount} actions`,\n };\n}\n\n// ── Internal helpers ──────────────────────────────────────────────────────────\n\nasync function listMemoryFiles(memoryDir: string): Promise<string[]> {\n const out: string[] = [];\n try {\n const root = await lstat(memoryDir);\n if (root.isSymbolicLink()) {\n throw new Error(`memoryDir must not be a symlink: ${memoryDir}`);\n }\n if (!root.isDirectory()) return out;\n } catch (err) {\n if (err instanceof Error && /must not be a symlink/.test(err.message)) {\n throw err;\n }\n return out;\n }\n\n async function walk(dir: string): Promise<void> {\n let entries: Array<{ name: string; isDirectory(): boolean; isFile(): boolean; isSymbolicLink(): boolean }>;\n try {\n entries = (await readdir(dir, { withFileTypes: true })) as typeof entries;\n } catch {\n return;\n }\n for (const entry of entries) {\n if (entry.isSymbolicLink()) continue;\n const full = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n // Skip state/ and archive/ subdirs.\n if (\n entry.name === \"state\" ||\n entry.name === \"archive\" ||\n entry.name === \"namespaces\" ||\n entry.name === \".git\"\n ) continue;\n await walk(full);\n } else if (entry.isFile() && entry.name.endsWith(\".md\")) {\n out.push(full);\n }\n }\n }\n\n await walk(memoryDir);\n return out;\n}\n"],"mappings":"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","names":[]}
@@ -4,6 +4,7 @@ import {
4
4
  } from "./chunk-Z2E7VW55.js";
5
5
  import "./chunk-MARWOCVP.js";
6
6
  import "./chunk-2ODBA7MQ.js";
7
+ import "./chunk-PZ5AY32C.js";
7
8
  export {
8
9
  EmbeddingFallback,
9
10
  EmbeddingTimeoutError