@remnic/core 1.1.2 → 1.1.4

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 (489) 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 +72 -47
  5. package/dist/access-cli.js.map +1 -1
  6. package/dist/access-http.d.ts +50 -5
  7. package/dist/access-http.js +39 -16
  8. package/dist/access-idempotency.js +1 -0
  9. package/dist/access-mcp.d.ts +10 -5
  10. package/dist/access-mcp.js +38 -14
  11. package/dist/access-schema.d.ts +133 -13
  12. package/dist/access-schema.js +20 -1
  13. package/dist/access-service-CtXFnprR.d.ts +2033 -0
  14. package/dist/access-service.d.ts +11 -6
  15. package/dist/access-service.js +40 -15
  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 +10 -7
  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 +12 -9
  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-3KIS4VGT.js +228 -0
  58. package/dist/chunk-3KIS4VGT.js.map +1 -0
  59. package/dist/chunk-3LCWFNVS.js +350 -0
  60. package/dist/chunk-3LCWFNVS.js.map +1 -0
  61. package/dist/chunk-43EKP2UK.js +26 -0
  62. package/dist/chunk-43EKP2UK.js.map +1 -0
  63. package/dist/chunk-457A4P3L.js +119 -0
  64. package/dist/chunk-457A4P3L.js.map +1 -0
  65. package/dist/{chunk-TMYO7B5P.js → chunk-47WOM4YW.js} +2 -2
  66. package/dist/{chunk-FVA6TGI3.js → chunk-52PDY6GD.js} +42 -2
  67. package/dist/chunk-52PDY6GD.js.map +1 -0
  68. package/dist/{chunk-ULYOGL6R.js → chunk-5HRY2WRF.js} +7 -3
  69. package/dist/chunk-5HRY2WRF.js.map +1 -0
  70. package/dist/{chunk-BOUYNNYD.js → chunk-67YLUWLG.js} +32 -13
  71. package/dist/{chunk-BOUYNNYD.js.map → chunk-67YLUWLG.js.map} +1 -1
  72. package/dist/chunk-6TBWYBJ3.js +236 -0
  73. package/dist/chunk-6TBWYBJ3.js.map +1 -0
  74. package/dist/chunk-74EMIVE4.js +329 -0
  75. package/dist/chunk-74EMIVE4.js.map +1 -0
  76. package/dist/chunk-74WWN7ZW.js +82 -0
  77. package/dist/chunk-74WWN7ZW.js.map +1 -0
  78. package/dist/chunk-A6XUJE5D.js +126 -0
  79. package/dist/chunk-A6XUJE5D.js.map +1 -0
  80. package/dist/{chunk-STGWEHYR.js → chunk-AEMBDV7M.js} +1187 -62
  81. package/dist/chunk-AEMBDV7M.js.map +1 -0
  82. package/dist/{chunk-PVICZTKG.js → chunk-AGZHRWPT.js} +5 -5
  83. package/dist/{chunk-PVICZTKG.js.map → chunk-AGZHRWPT.js.map} +1 -1
  84. package/dist/chunk-AJA46VX5.js +393 -0
  85. package/dist/chunk-AJA46VX5.js.map +1 -0
  86. package/dist/chunk-ASIQZXYO.js +277 -0
  87. package/dist/chunk-ASIQZXYO.js.map +1 -0
  88. package/dist/{chunk-DG6YMRDC.js → chunk-B2TL6GA2.js} +2 -2
  89. package/dist/chunk-BJMBJZ2Y.js +290 -0
  90. package/dist/chunk-BJMBJZ2Y.js.map +1 -0
  91. package/dist/chunk-BT7NVCML.js +79 -0
  92. package/dist/chunk-BT7NVCML.js.map +1 -0
  93. package/dist/chunk-CK5NTM2S.js +454 -0
  94. package/dist/chunk-CK5NTM2S.js.map +1 -0
  95. package/dist/{chunk-AYXIPSZO.js → chunk-CRU27Q4J.js} +2 -2
  96. package/dist/{chunk-UWB5LMWY.js → chunk-CUI2STX6.js} +526 -24
  97. package/dist/chunk-CUI2STX6.js.map +1 -0
  98. package/dist/{chunk-CUPFXL3J.js → chunk-EGEPUGN4.js} +4 -4
  99. package/dist/chunk-EGEPUGN4.js.map +1 -0
  100. package/dist/{chunk-3OGMS3PE.js → chunk-F5VQOQ2E.js} +3 -2
  101. package/dist/chunk-F5VQOQ2E.js.map +1 -0
  102. package/dist/chunk-FP2373TW.js +149 -0
  103. package/dist/chunk-FP2373TW.js.map +1 -0
  104. package/dist/{chunk-RBBWYEFJ.js → chunk-G2WADRQ3.js} +1 -1
  105. package/dist/chunk-G7D6GZ5J.js +48 -0
  106. package/dist/chunk-G7D6GZ5J.js.map +1 -0
  107. package/dist/chunk-H7XKCNR6.js +60 -0
  108. package/dist/chunk-H7XKCNR6.js.map +1 -0
  109. package/dist/{chunk-LOIMBRDE.js → chunk-HIRKCQGF.js} +1994 -412
  110. package/dist/chunk-HIRKCQGF.js.map +1 -0
  111. package/dist/chunk-IXEJRKCZ.js +18 -0
  112. package/dist/chunk-IXEJRKCZ.js.map +1 -0
  113. package/dist/chunk-IYY4MCPG.js +275 -0
  114. package/dist/chunk-IYY4MCPG.js.map +1 -0
  115. package/dist/{chunk-BECYBZLX.js → chunk-JWSENLQI.js} +502 -22
  116. package/dist/chunk-JWSENLQI.js.map +1 -0
  117. package/dist/chunk-KNKUID7G.js +183 -0
  118. package/dist/chunk-KNKUID7G.js.map +1 -0
  119. package/dist/chunk-L2IO2QPY.js +2036 -0
  120. package/dist/chunk-L2IO2QPY.js.map +1 -0
  121. package/dist/{chunk-ZAIM4TUE.js → chunk-LW2NMHDW.js} +46 -1
  122. package/dist/chunk-LW2NMHDW.js.map +1 -0
  123. package/dist/chunk-MDYG7VI7.js +48 -0
  124. package/dist/chunk-MDYG7VI7.js.map +1 -0
  125. package/dist/{chunk-VDX363PS.js → chunk-MUELDH4F.js} +10 -3
  126. package/dist/chunk-MUELDH4F.js.map +1 -0
  127. package/dist/chunk-MXC3AP5I.js +74 -0
  128. package/dist/chunk-MXC3AP5I.js.map +1 -0
  129. package/dist/chunk-NN3TS5BM.js +147 -0
  130. package/dist/chunk-NN3TS5BM.js.map +1 -0
  131. package/dist/{chunk-3YGHKTBF.js → chunk-NZS2BLTP.js} +963 -326
  132. package/dist/chunk-NZS2BLTP.js.map +1 -0
  133. package/dist/chunk-OA3L7BFR.js +183 -0
  134. package/dist/chunk-OA3L7BFR.js.map +1 -0
  135. package/dist/chunk-OZHRDTDX.js +240 -0
  136. package/dist/chunk-OZHRDTDX.js.map +1 -0
  137. package/dist/chunk-PCUKNJAZ.js +165 -0
  138. package/dist/chunk-PCUKNJAZ.js.map +1 -0
  139. package/dist/{chunk-6PFRXT4K.js → chunk-PFV5C235.js} +11 -6
  140. package/dist/chunk-PFV5C235.js.map +1 -0
  141. package/dist/chunk-PZ5AY32C.js +10 -0
  142. package/dist/chunk-PZ5AY32C.js.map +1 -0
  143. package/dist/{chunk-Y7R2XJ5Q.js → chunk-Q7FJ5ZHM.js} +6 -2
  144. package/dist/chunk-Q7FJ5ZHM.js.map +1 -0
  145. package/dist/{chunk-WCLICCGB.js → chunk-RILIVK4O.js} +91 -4
  146. package/dist/chunk-RILIVK4O.js.map +1 -0
  147. package/dist/{chunk-C2EFFULQ.js → chunk-RK2Y4XOM.js} +163 -20
  148. package/dist/chunk-RK2Y4XOM.js.map +1 -0
  149. package/dist/{chunk-TP4FZJIZ.js → chunk-RULE4VG5.js} +5 -1
  150. package/dist/chunk-RULE4VG5.js.map +1 -0
  151. package/dist/{chunk-PVPWZSSI.js → chunk-SMA4IMHV.js} +19 -3
  152. package/dist/chunk-SMA4IMHV.js.map +1 -0
  153. package/dist/{chunk-6YJHX2DL.js → chunk-TIFRGAKO.js} +242 -22
  154. package/dist/chunk-TIFRGAKO.js.map +1 -0
  155. package/dist/chunk-TUFG6VXY.js +875 -0
  156. package/dist/chunk-TUFG6VXY.js.map +1 -0
  157. package/dist/chunk-TYEOAFH3.js +251 -0
  158. package/dist/chunk-TYEOAFH3.js.map +1 -0
  159. package/dist/chunk-UKJAGEXH.js +260 -0
  160. package/dist/chunk-UKJAGEXH.js.map +1 -0
  161. package/dist/{chunk-KVBLZUKV.js → chunk-USFPPRAF.js} +93 -3
  162. package/dist/chunk-USFPPRAF.js.map +1 -0
  163. package/dist/{chunk-NBVAS5MT.js → chunk-V7TEH5I2.js} +6 -6
  164. package/dist/{chunk-GA5P7RST.js → chunk-VTJVUHRK.js} +22 -36
  165. package/dist/chunk-VTJVUHRK.js.map +1 -0
  166. package/dist/{chunk-SPI27QT6.js → chunk-W7WWT4FJ.js} +9 -4
  167. package/dist/chunk-W7WWT4FJ.js.map +1 -0
  168. package/dist/chunk-WIICJPET.js +45 -0
  169. package/dist/chunk-WIICJPET.js.map +1 -0
  170. package/dist/{chunk-VBVG2M5G.js → chunk-WPGJYVUH.js} +6 -2
  171. package/dist/chunk-WPGJYVUH.js.map +1 -0
  172. package/dist/{chunk-4HQS2HPX.js → chunk-WSZIHQBK.js} +29 -9
  173. package/dist/{chunk-4HQS2HPX.js.map → chunk-WSZIHQBK.js.map} +1 -1
  174. package/dist/{chunk-NZLQTHS5.js → chunk-WW3QQF4H.js} +4 -1
  175. package/dist/chunk-WW3QQF4H.js.map +1 -0
  176. package/dist/{chunk-DIXB44VE.js → chunk-X6VBWOVZ.js} +28 -13
  177. package/dist/chunk-X6VBWOVZ.js.map +1 -0
  178. package/dist/{chunk-XXVWLXSG.js → chunk-XQ4EJLUD.js} +64 -92
  179. package/dist/chunk-XQ4EJLUD.js.map +1 -0
  180. package/dist/{chunk-OC5OXUQ4.js → chunk-XRCYKJ3V.js} +780 -17
  181. package/dist/chunk-XRCYKJ3V.js.map +1 -0
  182. package/dist/{chunk-F5VP6YCB.js → chunk-Y4A6M3B6.js} +573 -156
  183. package/dist/chunk-Y4A6M3B6.js.map +1 -0
  184. package/dist/chunk-YNJHCGDT.js +309 -0
  185. package/dist/chunk-YNJHCGDT.js.map +1 -0
  186. package/dist/{chunk-L7IXWRYE.js → chunk-ZIBOQULP.js} +22 -13
  187. package/dist/chunk-ZIBOQULP.js.map +1 -0
  188. package/dist/{chunk-W6SL7OFG.js → chunk-ZTSE2ZJ6.js} +12 -2
  189. package/dist/{chunk-W6SL7OFG.js.map → chunk-ZTSE2ZJ6.js.map} +1 -1
  190. package/dist/chunking.js +1 -0
  191. package/dist/cipher-GVE2GQ5H.js +28 -0
  192. package/dist/cipher-GVE2GQ5H.js.map +1 -0
  193. package/dist/citations.js +1 -0
  194. package/dist/{cli-BkeRaYfk.d.ts → cli-lMql2FCr.d.ts} +26 -7
  195. package/dist/cli.d.ts +11 -6
  196. package/dist/cli.js +69 -34
  197. package/dist/codex-thread-key.js +1 -0
  198. package/dist/commitment-ledger.js +1 -0
  199. package/dist/compression-optimizer.js +1 -0
  200. package/dist/config.d.ts +2 -1
  201. package/dist/config.js +4 -1
  202. package/dist/connectors-cli-DFGtY2DB.d.ts +257 -0
  203. package/dist/connectors-cli.d.ts +2 -0
  204. package/dist/connectors-cli.js +22 -0
  205. package/dist/connectors-cli.js.map +1 -0
  206. package/dist/consolidation-operator.d.ts +65 -5
  207. package/dist/consolidation-operator.js +6 -1
  208. package/dist/consolidation-provenance-check.d.ts +1 -1
  209. package/dist/consolidation-provenance-check.js +3 -2
  210. package/dist/consolidation-undo.d.ts +1 -1
  211. package/dist/consolidation-undo.js +1 -0
  212. package/dist/consolidation-undo.js.map +1 -1
  213. package/dist/{contradiction-review-WIUBAR52.js → contradiction-review-5LTTVDQV.js} +2 -1
  214. package/dist/contradiction-review-5LTTVDQV.js.map +1 -0
  215. package/dist/{contradiction-scan-E3GJTI4F.js → contradiction-scan-3Z6YW7YA.js} +2 -1
  216. package/dist/{contradiction-scan-E3GJTI4F.js.map → contradiction-scan-3Z6YW7YA.js.map} +1 -1
  217. package/dist/cross-namespace-budget.js +1 -0
  218. package/dist/cue-anchors.js +1 -0
  219. package/dist/dashboard-runtime.js +1 -0
  220. package/dist/day-summary.js +1 -0
  221. package/dist/delinearize.js +1 -0
  222. package/dist/direct-answer-wiring.js +1 -0
  223. package/dist/direct-answer.js +1 -0
  224. package/dist/dreams-ledger-LR2NBAZE.js +286 -0
  225. package/dist/dreams-ledger-LR2NBAZE.js.map +1 -0
  226. package/dist/embedding-fallback.js +1 -0
  227. package/dist/engine-O6YWKQM3.js +28 -0
  228. package/dist/engine-O6YWKQM3.js.map +1 -0
  229. package/dist/entity-retrieval.d.ts +1 -1
  230. package/dist/entity-retrieval.js +10 -7
  231. package/dist/entity-schema.js +1 -0
  232. package/dist/evals.js +1 -0
  233. package/dist/evidence-pack.d.ts +16 -0
  234. package/dist/evidence-pack.js +8 -0
  235. package/dist/evidence-pack.js.map +1 -0
  236. package/dist/explicit-capture.d.ts +6 -4
  237. package/dist/explicit-capture.js +1 -0
  238. package/dist/extraction-judge-telemetry.js +1 -0
  239. package/dist/extraction-judge-training.js +1 -0
  240. package/dist/extraction-judge.js +1 -0
  241. package/dist/extraction.js +8 -7
  242. package/dist/fallback-llm.js +3 -2
  243. package/dist/first-start-migration-4MHQEOSD.js +263 -0
  244. package/dist/first-start-migration-4MHQEOSD.js.map +1 -0
  245. package/dist/forget-PLR6J5DN.js +69 -0
  246. package/dist/forget-PLR6J5DN.js.map +1 -0
  247. package/dist/framework-CyHYDcri.d.ts +153 -0
  248. package/dist/fs-utils-IRVUFB6G.js +30 -0
  249. package/dist/fs-utils-IRVUFB6G.js.map +1 -0
  250. package/dist/graph-dashboard-diff.js +1 -0
  251. package/dist/graph-dashboard-key.js +1 -0
  252. package/dist/graph-dashboard-parser.js +1 -0
  253. package/dist/graph-edge-decay-PWB63GRE.js +207 -0
  254. package/dist/graph-edge-decay-PWB63GRE.js.map +1 -0
  255. package/dist/graph-edge-reinforcement.d.ts +81 -0
  256. package/dist/graph-edge-reinforcement.js +24 -0
  257. package/dist/graph-edge-reinforcement.js.map +1 -0
  258. package/dist/graph-events.d.ts +87 -0
  259. package/dist/graph-events.js +14 -0
  260. package/dist/graph-events.js.map +1 -0
  261. package/dist/graph-recall.js +1 -0
  262. package/dist/graph-retrieval.js +1 -0
  263. package/dist/graph-snapshot.d.ts +112 -0
  264. package/dist/graph-snapshot.js +19 -0
  265. package/dist/graph-snapshot.js.map +1 -0
  266. package/dist/graph.d.ts +105 -7
  267. package/dist/graph.js +20 -3
  268. package/dist/harmonic-retrieval.js +1 -0
  269. package/dist/himem.js +1 -0
  270. package/dist/hygiene.js +1 -0
  271. package/dist/identity-continuity.js +1 -0
  272. package/dist/importance.js +1 -0
  273. package/dist/index.d.ts +574 -13
  274. package/dist/index.js +337 -69
  275. package/dist/index.js.map +1 -1
  276. package/dist/intent.js +1 -0
  277. package/dist/json-extract.js +1 -0
  278. package/dist/json-store.js +1 -0
  279. package/dist/kdf-7S6RWKLZ.js +26 -0
  280. package/dist/kdf-7S6RWKLZ.js.map +1 -0
  281. package/dist/legacy-hook-compat.js +1 -0
  282. package/dist/legacy-hook-compat.js.map +1 -1
  283. package/dist/lifecycle.js +1 -0
  284. package/dist/live-connectors-runner.d.ts +48 -0
  285. package/dist/live-connectors-runner.js +17 -0
  286. package/dist/live-connectors-runner.js.map +1 -0
  287. package/dist/local-llm.js +1 -0
  288. package/dist/logger.js +1 -0
  289. package/dist/memory-action-policy.js +1 -0
  290. package/dist/memory-cache.d.ts +2 -1
  291. package/dist/memory-cache.js +4 -1
  292. package/dist/memory-governance-JZHZDOLN.js +37 -0
  293. package/dist/memory-governance-JZHZDOLN.js.map +1 -0
  294. package/dist/memory-lifecycle-ledger-utils.d.ts +2 -1
  295. package/dist/memory-lifecycle-ledger-utils.js +4 -1
  296. package/dist/memory-projection-format.js +1 -0
  297. package/dist/{memory-projection-store-DeSXPh1j.d.ts → memory-projection-store-CY8TU40w.d.ts} +2 -1
  298. package/dist/memory-projection-store.d.ts +1 -1
  299. package/dist/memory-projection-store.js +2 -1
  300. package/dist/memory-worth-bench.js +1 -0
  301. package/dist/memory-worth-bench.js.map +1 -1
  302. package/dist/memory-worth-filter.js +1 -0
  303. package/dist/memory-worth-outcomes.d.ts +1 -1
  304. package/dist/memory-worth-outcomes.js +1 -0
  305. package/dist/memory-worth.js +1 -0
  306. package/dist/metadata-FC3XPDRQ.js +21 -0
  307. package/dist/metadata-FC3XPDRQ.js.map +1 -0
  308. package/dist/migrate-from-identity-anchor-TTEDEJGX.js +8 -0
  309. package/dist/migrate-from-identity-anchor-TTEDEJGX.js.map +1 -0
  310. package/dist/model-registry.js +1 -0
  311. package/dist/models-json.js +1 -0
  312. package/dist/native-knowledge.js +1 -0
  313. package/dist/negative.js +1 -0
  314. package/dist/objective-state-writers.js +1 -0
  315. package/dist/objective-state-writers.js.map +1 -1
  316. package/dist/objective-state.js +1 -0
  317. package/dist/openai-chat-compat.js +1 -0
  318. package/dist/operator-toolkit.d.ts +46 -2
  319. package/dist/operator-toolkit.js +29 -17
  320. package/dist/opik-exporter.js +1 -0
  321. package/dist/opik-exporter.js.map +1 -1
  322. package/dist/{orchestrator-CmJ-NTdJ.d.ts → orchestrator-ChkesB8U.d.ts} +177 -13
  323. package/dist/orchestrator.d.ts +6 -4
  324. package/dist/orchestrator.js +57 -41
  325. package/dist/page-versioning.js +1 -0
  326. package/dist/path-RMTY5Y5A.js +9 -0
  327. package/dist/path-RMTY5Y5A.js.map +1 -0
  328. package/dist/patterns-cli.d.ts +160 -0
  329. package/dist/patterns-cli.js +29 -0
  330. package/dist/patterns-cli.js.map +1 -0
  331. package/dist/peers-6OSQ3NK6.js +44 -0
  332. package/dist/peers-6OSQ3NK6.js.map +1 -0
  333. package/dist/plugin-id.js +1 -0
  334. package/dist/policy-runtime.js +1 -0
  335. package/dist/{port-BADbLZU5.d.ts → port-hqGnoStS.d.ts} +6 -0
  336. package/dist/profiling.js +1 -0
  337. package/dist/purge-6ATBGT77.js +205 -0
  338. package/dist/purge-6ATBGT77.js.map +1 -0
  339. package/dist/qmd-recall-cache.d.ts +1 -1
  340. package/dist/qmd-recall-cache.js +1 -0
  341. package/dist/qmd.d.ts +2 -1
  342. package/dist/qmd.js +4 -3
  343. package/dist/reasoning-trace-recall.js +1 -0
  344. package/dist/reasoning-trace-types.js +1 -0
  345. package/dist/recall-audit-anomaly.js +1 -0
  346. package/dist/recall-audit.js +1 -0
  347. package/dist/recall-disclosure-escalation.d.ts +84 -0
  348. package/dist/recall-disclosure-escalation.js +14 -0
  349. package/dist/recall-disclosure-escalation.js.map +1 -0
  350. package/dist/recall-explain-renderer.js +4 -1
  351. package/dist/recall-mmr.js +1 -0
  352. package/dist/recall-qos.js +1 -0
  353. package/dist/recall-query-policy.js +1 -0
  354. package/dist/recall-state.d.ts +7 -0
  355. package/dist/recall-state.js +2 -1
  356. package/dist/recall-tag-filter.d.ts +56 -0
  357. package/dist/recall-tag-filter.js +14 -0
  358. package/dist/recall-tag-filter.js.map +1 -0
  359. package/dist/recall-tokenization.js +1 -0
  360. package/dist/recall-xray-cli.d.ts +9 -2
  361. package/dist/recall-xray-cli.js +9 -4
  362. package/dist/recall-xray-renderer.js +4 -1
  363. package/dist/recall-xray.d.ts +116 -2
  364. package/dist/recall-xray.js +9 -3
  365. package/dist/reconstruct.js +1 -0
  366. package/dist/release-changelog.js +2 -0
  367. package/dist/release-changelog.js.map +1 -1
  368. package/dist/relevance.js +1 -0
  369. package/dist/rerank.js +1 -0
  370. package/dist/{resolution-QBTDHTG7.js → resolution-YGIBORXI.js} +2 -1
  371. package/dist/{resolution-QBTDHTG7.js.map → resolution-YGIBORXI.js.map} +1 -1
  372. package/dist/resolve-auth-token.d.ts +51 -0
  373. package/dist/resolve-auth-token.js +12 -0
  374. package/dist/resolve-auth-token.js.map +1 -0
  375. package/dist/resolve-provider-secret.d.ts +9 -1
  376. package/dist/resolve-provider-secret.js +4 -1
  377. package/dist/resume-bundles.js +4 -3
  378. package/dist/retrieval-agents.d.ts +1 -1
  379. package/dist/retrieval-agents.js +1 -0
  380. package/dist/retrieval-tiers.js +1 -0
  381. package/dist/retrieval.js +1 -0
  382. package/dist/sanitize.js +1 -0
  383. package/dist/schemas.d.ts +15 -2
  384. package/dist/schemas.js +2 -1
  385. package/dist/sdk-compat.js +1 -0
  386. package/dist/sdk-compat.js.map +1 -1
  387. package/dist/secure-store-4R2GSO7S.js +156 -0
  388. package/dist/secure-store-4R2GSO7S.js.map +1 -0
  389. package/dist/semantic-chunking.js +1 -0
  390. package/dist/{semantic-consolidation-CxJU6MJk.d.ts → semantic-consolidation-ByBXb-sf.d.ts} +3 -3
  391. package/dist/semantic-consolidation.d.ts +2 -2
  392. package/dist/semantic-consolidation.js +12 -7
  393. package/dist/semantic-rule-promotion.d.ts +1 -1
  394. package/dist/semantic-rule-promotion.js +10 -7
  395. package/dist/semantic-rule-verifier.d.ts +1 -1
  396. package/dist/semantic-rule-verifier.js +10 -7
  397. package/dist/session-integrity.js +1 -0
  398. package/dist/session-observer-bands.js +1 -0
  399. package/dist/session-observer-state.js +1 -0
  400. package/dist/session-toggles.js +2 -0
  401. package/dist/session-toggles.js.map +1 -1
  402. package/dist/signal.js +1 -0
  403. package/dist/skills-registry.js +2 -0
  404. package/dist/skills-registry.js.map +1 -1
  405. package/dist/source-attribution.js +1 -0
  406. package/dist/state-NCHQ4TRG.js +8 -0
  407. package/dist/state-NCHQ4TRG.js.map +1 -0
  408. package/dist/state-store-3EH7HYIN.js +16 -0
  409. package/dist/state-store-3EH7HYIN.js.map +1 -0
  410. package/dist/storage.d.ts +76 -2
  411. package/dist/storage.js +9 -6
  412. package/dist/store-contract.js +1 -0
  413. package/dist/summarizer.js +5 -4
  414. package/dist/summary-snapshot.js +1 -0
  415. package/dist/temporal-index.js +1 -0
  416. package/dist/temporal-supersession.d.ts +1 -1
  417. package/dist/temporal-supersession.js +2 -1
  418. package/dist/temporal-validity.d.ts +52 -0
  419. package/dist/temporal-validity.js +14 -0
  420. package/dist/temporal-validity.js.map +1 -0
  421. package/dist/threading.js +1 -0
  422. package/dist/tier-migration.d.ts +2 -2
  423. package/dist/tier-migration.js +1 -0
  424. package/dist/tier-routing.js +1 -0
  425. package/dist/tier-stats-62ZVDFKS.js +152 -0
  426. package/dist/tier-stats-62ZVDFKS.js.map +1 -0
  427. package/dist/tmt.js +1 -0
  428. package/dist/tokens.js +1 -0
  429. package/dist/topics.js +1 -0
  430. package/dist/trace-C5ETWBEF.js +290 -0
  431. package/dist/trace-C5ETWBEF.js.map +1 -0
  432. package/dist/transcript.js +1 -0
  433. package/dist/trust-zones.js +1 -0
  434. package/dist/tui-RI7P6PBS.js +13 -0
  435. package/dist/tui-RI7P6PBS.js.map +1 -0
  436. package/dist/types-V3FJ26TF.js +30 -0
  437. package/dist/types-V3FJ26TF.js.map +1 -0
  438. package/dist/types.d.ts +634 -9
  439. package/dist/types.js +10 -3
  440. package/dist/utility-learner.js +1 -0
  441. package/dist/utility-runtime.js +1 -0
  442. package/dist/utility-telemetry.js +1 -0
  443. package/dist/verified-recall.js +10 -7
  444. package/dist/version-utils.js +1 -0
  445. package/dist/whitespace.js +1 -0
  446. package/dist/work-product-ledger.js +1 -0
  447. package/package.json +7 -3
  448. package/scripts/ensure-better-sqlite3.mjs +124 -0
  449. package/dist/access-service-Br8ZydTK.d.ts +0 -827
  450. package/dist/chunk-3OGMS3PE.js.map +0 -1
  451. package/dist/chunk-3YGHKTBF.js.map +0 -1
  452. package/dist/chunk-6PFRXT4K.js.map +0 -1
  453. package/dist/chunk-6YJHX2DL.js.map +0 -1
  454. package/dist/chunk-BECYBZLX.js.map +0 -1
  455. package/dist/chunk-C2EFFULQ.js.map +0 -1
  456. package/dist/chunk-CUPFXL3J.js.map +0 -1
  457. package/dist/chunk-DIXB44VE.js.map +0 -1
  458. package/dist/chunk-F5VP6YCB.js.map +0 -1
  459. package/dist/chunk-FVA6TGI3.js.map +0 -1
  460. package/dist/chunk-GA5P7RST.js.map +0 -1
  461. package/dist/chunk-KVBLZUKV.js.map +0 -1
  462. package/dist/chunk-L7IXWRYE.js.map +0 -1
  463. package/dist/chunk-LOIMBRDE.js.map +0 -1
  464. package/dist/chunk-LTCGGW2D.js +0 -14
  465. package/dist/chunk-LTCGGW2D.js.map +0 -1
  466. package/dist/chunk-NZLQTHS5.js.map +0 -1
  467. package/dist/chunk-OC5OXUQ4.js.map +0 -1
  468. package/dist/chunk-PVPWZSSI.js.map +0 -1
  469. package/dist/chunk-SPI27QT6.js.map +0 -1
  470. package/dist/chunk-STGWEHYR.js.map +0 -1
  471. package/dist/chunk-TP4FZJIZ.js.map +0 -1
  472. package/dist/chunk-ULYOGL6R.js.map +0 -1
  473. package/dist/chunk-UWB5LMWY.js.map +0 -1
  474. package/dist/chunk-VBVG2M5G.js.map +0 -1
  475. package/dist/chunk-VDX363PS.js.map +0 -1
  476. package/dist/chunk-WCLICCGB.js.map +0 -1
  477. package/dist/chunk-X6GF3FX2.js +0 -26
  478. package/dist/chunk-X6GF3FX2.js.map +0 -1
  479. package/dist/chunk-XXVWLXSG.js.map +0 -1
  480. package/dist/chunk-Y7R2XJ5Q.js.map +0 -1
  481. package/dist/chunk-ZAIM4TUE.js.map +0 -1
  482. package/dist/engine-72LSIWQP.js +0 -23
  483. /package/dist/{contradiction-review-WIUBAR52.js.map → capsule-cli.js.map} +0 -0
  484. /package/dist/{engine-72LSIWQP.js.map → capsule-crypto-5CYAGVC5.js.map} +0 -0
  485. /package/dist/{chunk-TMYO7B5P.js.map → chunk-47WOM4YW.js.map} +0 -0
  486. /package/dist/{chunk-DG6YMRDC.js.map → chunk-B2TL6GA2.js.map} +0 -0
  487. /package/dist/{chunk-AYXIPSZO.js.map → chunk-CRU27Q4J.js.map} +0 -0
  488. /package/dist/{chunk-RBBWYEFJ.js.map → chunk-G2WADRQ3.js.map} +0 -0
  489. /package/dist/{chunk-NBVAS5MT.js.map → chunk-V7TEH5I2.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/memory-lifecycle-ledger-utils.ts"],"sourcesContent":["import path from \"node:path\";\nimport type {\n MemoryFile,\n MemoryLifecycleEvent,\n MemoryLifecycleEventType,\n MemoryLifecycleStateSummary,\n MemoryFrontmatter,\n MemoryStatus,\n} from \"./types.js\";\n\nexport const MEMORY_LIFECYCLE_RULE_VERSION = \"memory-lifecycle-ledger.v1\";\n\nexport const MEMORY_LIFECYCLE_EVENT_SORT_ORDER: Record<MemoryLifecycleEventType, number> = {\n created: 0,\n updated: 1,\n promoted: 2,\n explicit_capture_accepted: 3,\n explicit_capture_queued: 4,\n imported: 5,\n merged: 6,\n restored: 7,\n superseded: 8,\n rejected: 9,\n archived: 10,\n};\n\nexport function toMemoryPathRel(baseDir: string, filePath: string): string {\n if (!baseDir) return filePath.split(path.sep).join(\"/\");\n return path.relative(baseDir, filePath).split(path.sep).join(\"/\");\n}\n\nexport function isArchivedMemoryPath(pathRel: string): boolean {\n return pathRel === \"archive\" || pathRel.startsWith(\"archive/\");\n}\n\nexport function inferMemoryStatus(\n frontmatter: MemoryFrontmatter,\n pathRel: string,\n fallbackStatus: MemoryStatus = \"active\",\n): MemoryStatus {\n if (frontmatter.status && frontmatter.status !== \"active\") return frontmatter.status;\n if (frontmatter.archivedAt) return \"archived\";\n if (isArchivedMemoryPath(pathRel)) return \"archived\";\n if (frontmatter.status) return frontmatter.status;\n return fallbackStatus;\n}\n\nexport function summarizeMemoryLifecycleState(memory: MemoryFile): MemoryLifecycleStateSummary {\n return {\n category: memory.frontmatter.category,\n path: memory.path,\n status: memory.frontmatter.status ?? \"active\",\n lifecycleState: memory.frontmatter.lifecycleState,\n };\n}\n\nexport function makeRebuiltMemoryLifecycleEvent(\n memory: MemoryFile,\n eventType: MemoryLifecycleEventType,\n timestamp: string,\n): MemoryLifecycleEvent {\n return {\n eventId: `rebuild-${memory.frontmatter.id}-${eventType}-${timestamp}`,\n memoryId: memory.frontmatter.id,\n eventType,\n timestamp,\n actor: \"maintenance.rebuildMemoryLifecycleLedger\",\n ruleVersion: MEMORY_LIFECYCLE_RULE_VERSION,\n after: summarizeMemoryLifecycleState(memory),\n relatedMemoryIds: [\n ...(memory.frontmatter.supersededBy ? [memory.frontmatter.supersededBy] : []),\n ...(memory.frontmatter.supersedes ? [memory.frontmatter.supersedes] : []),\n ...((memory.frontmatter.lineage ?? []).filter(Boolean)),\n ],\n };\n}\n\nexport function buildLifecycleEventsForMemory(memory: MemoryFile): MemoryLifecycleEvent[] {\n const events: MemoryLifecycleEvent[] = [];\n const created = memory.frontmatter.created;\n const updated = memory.frontmatter.updated;\n const archivedAt = memory.frontmatter.archivedAt;\n const supersededAt = memory.frontmatter.supersededAt;\n const effectiveArchivedAt =\n archivedAt ?? (memory.frontmatter.status === \"archived\" && updated ? updated : undefined);\n\n events.push(makeRebuiltMemoryLifecycleEvent(memory, \"created\", created));\n if (\n updated &&\n updated !== created &&\n updated !== effectiveArchivedAt &&\n updated !== supersededAt\n ) {\n events.push(makeRebuiltMemoryLifecycleEvent(memory, \"updated\", updated));\n }\n if (supersededAt) {\n events.push(makeRebuiltMemoryLifecycleEvent(memory, \"superseded\", supersededAt));\n }\n if (effectiveArchivedAt) {\n events.push(makeRebuiltMemoryLifecycleEvent(memory, \"archived\", effectiveArchivedAt));\n }\n\n return events;\n}\n\nexport function sortMemoryLifecycleEvents(events: MemoryLifecycleEvent[]): MemoryLifecycleEvent[] {\n return [...events].sort((a, b) => {\n if (a.memoryId !== b.memoryId) return a.memoryId.localeCompare(b.memoryId);\n if (a.timestamp !== b.timestamp) return a.timestamp.localeCompare(b.timestamp);\n return MEMORY_LIFECYCLE_EVENT_SORT_ORDER[a.eventType] - MEMORY_LIFECYCLE_EVENT_SORT_ORDER[b.eventType];\n });\n}\n"],"mappings":";AAAA,OAAO,UAAU;AAUV,IAAM,gCAAgC;AAEtC,IAAM,oCAA8E;AAAA,EACzF,SAAS;AAAA,EACT,SAAS;AAAA,EACT,UAAU;AAAA,EACV,2BAA2B;AAAA,EAC3B,yBAAyB;AAAA,EACzB,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,UAAU;AACZ;AAEO,SAAS,gBAAgB,SAAiB,UAA0B;AACzE,MAAI,CAAC,QAAS,QAAO,SAAS,MAAM,KAAK,GAAG,EAAE,KAAK,GAAG;AACtD,SAAO,KAAK,SAAS,SAAS,QAAQ,EAAE,MAAM,KAAK,GAAG,EAAE,KAAK,GAAG;AAClE;AAEO,SAAS,qBAAqB,SAA0B;AAC7D,SAAO,YAAY,aAAa,QAAQ,WAAW,UAAU;AAC/D;AAEO,SAAS,kBACd,aACA,SACA,iBAA+B,UACjB;AACd,MAAI,YAAY,UAAU,YAAY,WAAW,SAAU,QAAO,YAAY;AAC9E,MAAI,YAAY,WAAY,QAAO;AACnC,MAAI,qBAAqB,OAAO,EAAG,QAAO;AAC1C,MAAI,YAAY,OAAQ,QAAO,YAAY;AAC3C,SAAO;AACT;AAEO,SAAS,8BAA8B,QAAiD;AAC7F,SAAO;AAAA,IACL,UAAU,OAAO,YAAY;AAAA,IAC7B,MAAM,OAAO;AAAA,IACb,QAAQ,OAAO,YAAY,UAAU;AAAA,IACrC,gBAAgB,OAAO,YAAY;AAAA,EACrC;AACF;AAEO,SAAS,gCACd,QACA,WACA,WACsB;AACtB,SAAO;AAAA,IACL,SAAS,WAAW,OAAO,YAAY,EAAE,IAAI,SAAS,IAAI,SAAS;AAAA,IACnE,UAAU,OAAO,YAAY;AAAA,IAC7B;AAAA,IACA;AAAA,IACA,OAAO;AAAA,IACP,aAAa;AAAA,IACb,OAAO,8BAA8B,MAAM;AAAA,IAC3C,kBAAkB;AAAA,MAChB,GAAI,OAAO,YAAY,eAAe,CAAC,OAAO,YAAY,YAAY,IAAI,CAAC;AAAA,MAC3E,GAAI,OAAO,YAAY,aAAa,CAAC,OAAO,YAAY,UAAU,IAAI,CAAC;AAAA,MACvE,IAAK,OAAO,YAAY,WAAW,CAAC,GAAG,OAAO,OAAO;AAAA,IACvD;AAAA,EACF;AACF;AAEO,SAAS,8BAA8B,QAA4C;AACxF,QAAM,SAAiC,CAAC;AACxC,QAAM,UAAU,OAAO,YAAY;AACnC,QAAM,UAAU,OAAO,YAAY;AACnC,QAAM,aAAa,OAAO,YAAY;AACtC,QAAM,eAAe,OAAO,YAAY;AACxC,QAAM,sBACJ,eAAe,OAAO,YAAY,WAAW,cAAc,UAAU,UAAU;AAEjF,SAAO,KAAK,gCAAgC,QAAQ,WAAW,OAAO,CAAC;AACvE,MACE,WACA,YAAY,WACZ,YAAY,uBACZ,YAAY,cACZ;AACA,WAAO,KAAK,gCAAgC,QAAQ,WAAW,OAAO,CAAC;AAAA,EACzE;AACA,MAAI,cAAc;AAChB,WAAO,KAAK,gCAAgC,QAAQ,cAAc,YAAY,CAAC;AAAA,EACjF;AACA,MAAI,qBAAqB;AACvB,WAAO,KAAK,gCAAgC,QAAQ,YAAY,mBAAmB,CAAC;AAAA,EACtF;AAEA,SAAO;AACT;AAEO,SAAS,0BAA0B,QAAwD;AAChG,SAAO,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM;AAChC,QAAI,EAAE,aAAa,EAAE,SAAU,QAAO,EAAE,SAAS,cAAc,EAAE,QAAQ;AACzE,QAAI,EAAE,cAAc,EAAE,UAAW,QAAO,EAAE,UAAU,cAAc,EAAE,SAAS;AAC7E,WAAO,kCAAkC,EAAE,SAAS,IAAI,kCAAkC,EAAE,SAAS;AAAA,EACvG,CAAC;AACH;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/consolidation-provenance-check.ts"],"sourcesContent":["/**\n * Consolidation provenance integrity check (issue #561 PR 4).\n *\n * Validates that every memory carrying consolidation provenance frontmatter\n * (`derived_from`, `derived_via`) resolves to real data:\n *\n * - Each `derived_from` entry `\"<path>:<version>\"` must name a\n * page-version snapshot that exists on disk (via the sidecar layout\n * documented in `page-versioning.ts`).\n * - Each `derived_via` must be one of the known\n * `ConsolidationOperator` values — malformed values are surfaced as\n * warnings rather than crashes so legacy or future operators survive a\n * rollback.\n *\n * Non-fatal: every failure renders a warning with the offending file path\n * and a human-readable reason. Integrity problems are informational for\n * now — we do not auto-heal or archive broken memories.\n */\n\nimport path from \"node:path\";\nimport { access, readdir, readFile, stat } from \"node:fs/promises\";\nimport { constants as fsConstants } from \"node:fs\";\nimport type { StorageManager } from \"./storage.js\";\nimport { isConsolidationOperator } from \"./consolidation-operator.js\";\n// Import the canonical `sidecarKey` from page-versioning (PR #634\n// review, cursor Medium) so a future key-format change stays in\n// lock-step with the doctor scan.\nimport { sidecarKey } from \"./page-versioning.js\";\n\n/**\n * Regex to spot a `derived_via: <value>` line in the raw YAML frontmatter\n * between the opening and first closing `---` delimiters. We use the raw\n * text rather than the parsed `frontmatter.derived_via` because the\n * read-path parser coerces unknown values back to `undefined` — that\n * would silently hide corrupted-or-future operators from the doctor scan\n * (PR #634 review feedback, codex P2).\n */\n// Allow empty capture groups so truncated/blank `derived_via:` and\n// `derived_from:` lines (key present, no value) are distinguishable\n// from \"key missing entirely\" (regex returns null). Optional\n// leading whitespace accepts indented keys which `parseFrontmatter`\n// also accepts (PR #634 round-6 review, codex P2).\nconst DERIVED_VIA_RAW_RE = /^[\\t ]*derived_via:[\\t ]*(.*)$/mu;\nconst DERIVED_FROM_RAW_RE = /^[\\t ]*derived_from:[\\t ]*(.*)$/mu;\n\n/**\n * Tokenize a YAML-block-style list under `key:` in the given\n * frontmatter slice. Looks for lines matching `^ - <value>` after a\n * `key:` line and before the next non-list line. Returns `null` when\n * the key is missing or the value is a scalar / flow list (no block\n * entries found).\n *\n * Only used for the mixed-list malformed-entry detection — it does\n * not try to decode YAML escape sequences since we only need the\n * entry count + raw token text to compare against the parsed array.\n */\nfunction tokenizeRawBlockList(fmSlice: string, key: string): string[] | null {\n const lines = fmSlice.split(\"\\n\");\n // Accept indented keys too — parseFrontmatter does (PR #634 round-7\n // review, codex P2 / cursor Low).\n const keyRe = new RegExp(`^[\\\\t ]*${key}:[\\\\t ]*(.*)$`, \"u\");\n let startIdx = -1;\n for (let i = 0; i < lines.length; i++) {\n const m = lines[i].match(keyRe);\n if (m) {\n if (m[1].trim().length === 0) {\n startIdx = i + 1;\n }\n break;\n }\n }\n if (startIdx < 0) return null;\n const items: string[] = [];\n for (let i = startIdx; i < lines.length; i++) {\n const line = lines[i];\n if (!/^\\s+-/.test(line)) break; // not a block-list entry\n const m = line.match(/^\\s+-\\s*(.*)$/u);\n if (!m) break;\n let tok = m[1].trim();\n if (\n (tok.startsWith('\"') && tok.endsWith('\"') && tok.length >= 2) ||\n (tok.startsWith(\"'\") && tok.endsWith(\"'\") && tok.length >= 2)\n ) {\n tok = tok.slice(1, -1);\n }\n items.push(tok);\n }\n return items.length > 0 ? items : null;\n}\n\n/**\n * Tokenize a YAML-flow-style list (`[\"a\", \"b\", ...]`) into a flat\n * string array. Returns `null` when the input isn't a flow list.\n * Best-effort — we don't implement a full YAML parser, just enough to\n * detect mixed valid/invalid entries for the doctor integrity check.\n */\nfunction tokenizeRawFlowList(raw: string): string[] | null {\n const trimmed = raw.trim();\n if (!trimmed.startsWith(\"[\") || !trimmed.endsWith(\"]\")) return null;\n const inner = trimmed.slice(1, -1);\n const parts: string[] = [];\n let current = \"\";\n let inSingle = false;\n let inDouble = false;\n for (let i = 0; i < inner.length; i++) {\n const ch = inner[i];\n if (inDouble) {\n if (ch === \"\\\\\" && i + 1 < inner.length) {\n current += inner[++i];\n continue;\n }\n if (ch === '\"') {\n inDouble = false;\n continue;\n }\n current += ch;\n } else if (inSingle) {\n if (ch === \"'\" && inner[i + 1] === \"'\") {\n current += \"'\";\n i++;\n continue;\n }\n if (ch === \"'\") {\n inSingle = false;\n continue;\n }\n current += ch;\n } else if (ch === '\"') {\n inDouble = true;\n } else if (ch === \"'\") {\n inSingle = true;\n } else if (ch === \",\") {\n parts.push(current.trim());\n current = \"\";\n } else {\n current += ch;\n }\n }\n if (current.trim().length > 0 || parts.length > 0) {\n parts.push(current.trim());\n }\n return parts;\n}\n\n/**\n * One integrity warning attached to a specific memory.\n */\nexport interface ConsolidationProvenanceIssue {\n /** Absolute path to the memory markdown file. */\n memoryPath: string;\n /** Memory id from frontmatter. */\n memoryId: string;\n /** Type of integrity issue. */\n kind:\n | \"derived_from_missing_snapshot\"\n | \"derived_from_malformed_entry\"\n | \"derived_via_unknown_operator\";\n /** Human-readable detail — includes the offending value when relevant. */\n detail: string;\n}\n\n/**\n * Summary of a provenance-integrity scan. Used by the operator-doctor\n * report and surfaced in the CLI output.\n */\nexport interface ConsolidationProvenanceReport {\n /** Total memories inspected. */\n scanned: number;\n /** Memories that carry `derived_from` and/or `derived_via`. */\n withProvenance: number;\n /** One entry per problem detected (may be empty). */\n issues: ConsolidationProvenanceIssue[];\n}\n\nconst DERIVED_FROM_ENTRY_RE = /^(.+):(\\d+)$/;\n\n/**\n * Build the on-disk snapshot path for a `\"<relpath>:<version>\"` entry,\n * relative to the given memory directory. Mirrors the layout documented\n * in `page-versioning.ts`:\n *\n * memoryDir/<sidecarDir>/<sidecarKey>/<version><ext>\n */\nfunction resolveSnapshotPath(\n memoryDir: string,\n sidecarDir: string,\n entry: string,\n): { ok: true; snapshotPath: string } | { ok: false; reason: string } {\n const match = entry.match(DERIVED_FROM_ENTRY_RE);\n if (!match) {\n return { ok: false, reason: `malformed entry (expected \"<path>:<version>\")` };\n }\n const pagePath = match[1];\n const versionId = match[2];\n const ext = path.extname(pagePath) || \".md\";\n const key = sidecarKey(pagePath);\n const snapshotPath = path.join(memoryDir, sidecarDir, key, `${versionId}${ext}`);\n return { ok: true, snapshotPath };\n}\n\n/**\n * Scan every memory under `storage` and flag consolidation-provenance\n * problems. Does not throw on individual failures — collects them in the\n * returned report.\n */\nexport async function runConsolidationProvenanceCheck(options: {\n storage: StorageManager;\n memoryDir: string;\n /**\n * Page-versioning sidecar directory name. Defaults to `.versions` —\n * matches the baked-in default used by `setVersioningConfig` when\n * versioning is enabled via config.\n */\n sidecarDir?: string;\n}): Promise<ConsolidationProvenanceReport> {\n const { storage, memoryDir } = options;\n const sidecarDir = options.sidecarDir ?? \".versions\";\n\n const report: ConsolidationProvenanceReport = {\n scanned: 0,\n withProvenance: 0,\n issues: [],\n };\n\n let memories;\n try {\n memories = await storage.readAllMemories();\n } catch {\n // If we can't enumerate memories at all, surface a single synthetic\n // issue rather than throwing — the doctor wrapper treats an empty\n // issues list as \"ok\" and we don't want a filesystem hiccup to crash\n // the whole diagnostic.\n return {\n scanned: 0,\n withProvenance: 0,\n issues: [\n {\n memoryPath: memoryDir,\n memoryId: \"(unreadable)\",\n kind: \"derived_from_malformed_entry\",\n detail: \"Could not enumerate memory directory to scan provenance.\",\n },\n ],\n };\n }\n\n for (const memory of memories) {\n report.scanned += 1;\n const fm = memory.frontmatter;\n const derivedFrom = fm.derived_from;\n const derivedVia = fm.derived_via;\n\n // Raw frontmatter values from disk — the read-path parser coerces\n // malformed `derived_from` and unknown `derived_via` back to\n // `undefined`, which would silently hide on-disk corruption from\n // the doctor scan (PR #634 review feedback, codex P2). We\n // re-extract both via regex so integrity issues are reported even\n // when the parser normalized them away. `rawDerivedVia` /\n // `rawDerivedFrom` being `\"\"` (empty string) represents a\n // corrupted file with the key present but the value truncated —\n // that's distinct from \"key missing entirely\" (undefined).\n let rawDerivedVia: string | undefined;\n let rawDerivedFrom: string | undefined;\n let rawDerivedViaKeyPresent = false;\n let rawDerivedFromKeyPresent = false;\n let duplicateViaKeys = false;\n let duplicateFromKeys = false;\n let viaMatchCount = 0;\n let fromMatchCount = 0;\n let fmSlice = \"\";\n try {\n const raw = await readFile(memory.path, \"utf-8\");\n const frontmatterEnd = raw.indexOf(\"\\n---\", raw.indexOf(\"---\") + 3);\n fmSlice = frontmatterEnd > 0 ? raw.slice(0, frontmatterEnd) : raw;\n // Use matchAll to find ALL occurrences of `derived_via` / `derived_from`\n // in the raw YAML. `parseFrontmatter` keeps the LAST assignment when\n // duplicate keys appear, so the doctor must read the last occurrence\n // to match what the storage reader actually uses (PR #634 review,\n // codex P2 — duplicate `derived_via` keys caused false-clean or\n // false-unknown-operator warnings depending on order).\n const viaMatches = [...fmSlice.matchAll(new RegExp(DERIVED_VIA_RAW_RE.source, DERIVED_VIA_RAW_RE.flags + \"g\"))];\n viaMatchCount = viaMatches.length;\n duplicateViaKeys = viaMatches.length > 1;\n if (viaMatches.length > 0) {\n rawDerivedViaKeyPresent = true;\n // Use the last occurrence — `parseFrontmatter` keeps the last\n // assignment when duplicate keys appear, so the doctor must\n // match that behavior to produce accurate warnings (PR #634\n // review, codex P2).\n const lastVia = viaMatches[viaMatches.length - 1];\n let val = lastVia[1].trim();\n if (\n (val.startsWith('\"') && val.endsWith('\"')) ||\n (val.startsWith(\"'\") && val.endsWith(\"'\"))\n ) {\n val = val.slice(1, -1);\n }\n rawDerivedVia = val;\n }\n const fromMatches = [...fmSlice.matchAll(new RegExp(DERIVED_FROM_RAW_RE.source, DERIVED_FROM_RAW_RE.flags + \"g\"))];\n fromMatchCount = fromMatches.length;\n duplicateFromKeys = fromMatches.length > 1;\n if (fromMatches.length > 0) {\n rawDerivedFromKeyPresent = true;\n const lastFrom = fromMatches[fromMatches.length - 1];\n rawDerivedFrom = lastFrom[1].trim();\n }\n } catch {\n // Fall through to the parsed values.\n }\n\n const hasFrom = Array.isArray(derivedFrom) && derivedFrom.length > 0;\n const hasVia = derivedVia !== undefined && derivedVia !== null;\n const hasRawVia = rawDerivedVia !== undefined && rawDerivedVia.length > 0;\n // A raw `derived_from` that the parser dropped indicates on-disk\n // corruption we must surface. We detect this by: (a) the raw YAML\n // contains a `derived_from:` key, AND (b) the parsed frontmatter\n // has no valid array. A scalar like `derived_from: facts/a.md:7`\n // (list brackets omitted) or a blank `derived_from:` both hit this\n // branch.\n const hasRawMalformedFrom = rawDerivedFromKeyPresent && !hasFrom;\n // A blank `derived_via:` with no value is also corrupt — the\n // parser drops it to undefined, but the raw key is still present\n // on disk (PR #634 round-3 review, codex P2).\n const hasBlankRawVia =\n rawDerivedViaKeyPresent &&\n (rawDerivedVia === undefined || rawDerivedVia.length === 0) &&\n !hasVia;\n if (\n !hasFrom && !hasVia && !hasRawVia &&\n !hasRawMalformedFrom && !hasBlankRawVia\n ) continue;\n report.withProvenance += 1;\n\n // Duplicate-key detection (PR #634 review, codex P2): when the raw\n // YAML contains multiple `derived_via` or `derived_from` lines,\n // `parseFrontmatter` silently uses the last one. Flag this as a\n // malformed entry so operators can inspect and fix the file.\n if (duplicateViaKeys) {\n report.issues.push({\n memoryPath: memory.path,\n memoryId: fm.id,\n kind: \"derived_via_unknown_operator\",\n detail: `raw YAML contains ${viaMatchCount} \"derived_via\" keys; parseFrontmatter uses the last occurrence`,\n });\n }\n if (duplicateFromKeys) {\n report.issues.push({\n memoryPath: memory.path,\n memoryId: fm.id,\n kind: \"derived_from_malformed_entry\",\n detail: `raw YAML contains ${fromMatchCount} \"derived_from\" keys; parseFrontmatter uses the last occurrence`,\n });\n }\n\n if (hasRawMalformedFrom) {\n const display = rawDerivedFrom ?? \"(blank)\";\n report.issues.push({\n memoryPath: memory.path,\n memoryId: fm.id,\n kind: \"derived_from_malformed_entry\",\n detail: `raw YAML \"derived_from: ${display}\" could not be parsed as a list`,\n });\n }\n\n // Mixed-list detection (PR #634 round-4 + round-5 review, codex\n // P2): when the parser DID return a valid list but the raw YAML\n // includes additional tokens that got dropped, flag those as\n // malformed. Handles both flow-style (`[\"a\", \"\", \"b\"]`) and\n // block-style (`\\n - a\\n - \\n - b`) YAML lists.\n if (hasFrom && rawDerivedFromKeyPresent) {\n let rawList: string[] | null = null;\n if (rawDerivedFrom && rawDerivedFrom.length > 0) {\n rawList = tokenizeRawFlowList(rawDerivedFrom);\n }\n if (rawList === null) {\n // Fall back to block-list tokenization by re-reading the full\n // frontmatter (already loaded above as `raw`) and scanning\n // the lines following `derived_from:`.\n rawList = tokenizeRawBlockList(fmSlice, \"derived_from\");\n }\n if (rawList !== null && rawList.length > derivedFrom!.length) {\n for (const tok of rawList) {\n if (tok.length === 0) {\n report.issues.push({\n memoryPath: memory.path,\n memoryId: fm.id,\n kind: \"derived_from_malformed_entry\",\n detail: `raw YAML derived_from contains an empty entry (mixed list)`,\n });\n continue;\n }\n if (!derivedFrom!.includes(tok)) {\n if (!/^(.+):(\\d+)$/u.test(tok)) {\n report.issues.push({\n memoryPath: memory.path,\n memoryId: fm.id,\n kind: \"derived_from_malformed_entry\",\n detail: `raw YAML derived_from contains a malformed entry: ${JSON.stringify(tok)}`,\n });\n }\n }\n }\n }\n }\n if (hasBlankRawVia) {\n report.issues.push({\n memoryPath: memory.path,\n memoryId: fm.id,\n kind: \"derived_via_unknown_operator\",\n detail: \"raw YAML has `derived_via:` key with empty value\",\n });\n }\n\n if (hasFrom) {\n for (const entry of derivedFrom!) {\n const resolved = resolveSnapshotPath(memoryDir, sidecarDir, entry);\n if (!resolved.ok) {\n report.issues.push({\n memoryPath: memory.path,\n memoryId: fm.id,\n kind: \"derived_from_malformed_entry\",\n detail: `${JSON.stringify(entry)}: ${resolved.reason}`,\n });\n continue;\n }\n // Require a regular file at the snapshot path (PR #634\n // round-8 review, codex P2) — a directory or device node at\n // that path means the sidecar was corrupted and the snapshot\n // is effectively missing.\n let snapshotOk = false;\n try {\n const st = await stat(resolved.snapshotPath);\n snapshotOk = st.isFile();\n } catch {\n snapshotOk = false;\n }\n if (!snapshotOk) {\n report.issues.push({\n memoryPath: memory.path,\n memoryId: fm.id,\n kind: \"derived_from_missing_snapshot\",\n detail: `${entry} → ${resolved.snapshotPath} (not a regular file)`,\n });\n }\n }\n }\n\n // Check the RAW YAML value for unknown operators. The parsed value\n // (`fm.derived_via`) is always known-good because the read-path\n // normalizer dropped anything else to undefined.\n if (hasRawVia && !isConsolidationOperator(rawDerivedVia)) {\n report.issues.push({\n memoryPath: memory.path,\n memoryId: fm.id,\n kind: \"derived_via_unknown_operator\",\n detail: `unknown operator: ${JSON.stringify(rawDerivedVia)}`,\n });\n }\n }\n\n // Parse-failure detection (PR #634 round-4 review, codex P2):\n // `readAllMemories()` silently drops files whose frontmatter\n // doesn't parse. Walk the facts/ and corrections/ directories for\n // `.md` files that DO reference provenance frontmatter but didn't\n // come back from the reader — those are the corruption cases the\n // doctor is meant to surface.\n try {\n const seenPaths = new Set(memories.map((m) => m.path));\n const scanRoots = [\"facts\", \"corrections\", \"procedures\", \"reasoning-traces\"];\n for (const rootName of scanRoots) {\n const rootPath = path.join(memoryDir, rootName);\n for await (const file of walkMarkdownFiles(rootPath)) {\n if (seenPaths.has(file)) continue;\n try {\n const raw = await readFile(file, \"utf-8\");\n if (\n DERIVED_FROM_RAW_RE.test(raw) ||\n DERIVED_VIA_RAW_RE.test(raw)\n ) {\n report.withProvenance += 1;\n report.issues.push({\n memoryPath: file,\n memoryId: \"(parse failed)\",\n kind: \"derived_from_malformed_entry\",\n detail:\n \"frontmatter could not be parsed by storage reader; provenance fields visible in raw YAML\",\n });\n }\n } catch {\n // Unreadable file — skip.\n }\n }\n }\n } catch {\n // Best-effort; don't fail the whole scan on a filesystem hiccup.\n }\n\n return report;\n}\n\n/**\n * Recursively yield all `.md` file paths under `root`. Silent on\n * missing directories — the facts/corrections dirs may not exist in\n * fresh installs.\n */\nasync function* walkMarkdownFiles(root: string): AsyncGenerator<string> {\n let entries;\n try {\n entries = await readdir(root, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n const full = path.join(root, entry.name);\n if (entry.isDirectory()) {\n yield* walkMarkdownFiles(full);\n } else if (entry.isFile() && entry.name.endsWith(\".md\")) {\n yield full;\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/access-http.ts","../src/adapters/types.ts","../src/adapters/claude-code.ts","../src/adapters/codex.ts","../src/adapters/replit.ts","../src/adapters/hermes.ts","../src/adapters/registry.ts"],"sourcesContent":["import { createServer, type IncomingMessage, type Server, type ServerResponse } from \"node:http\";\nimport { randomUUID, timingSafeEqual } from \"node:crypto\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { fileURLToPath, URL } from \"node:url\";\nimport { log } from \"./logger.js\";\nimport { EngramAccessInputError, type EngramAccessService } from \"./access-service.js\";\nimport { EngramMcpServer } from \"./access-mcp.js\";\nimport { validateRequest, type SchemaName, type SchemaTypeFor } from \"./access-schema.js\";\nimport type { RecallPlanMode } from \"./types.js\";\nimport { isTrustZoneName, type TrustZoneName, type TrustZoneRecordKind, type TrustZoneSourceClass } from \"./trust-zones.js\";\nimport { AdapterRegistry, type ResolvedIdentity } from \"./adapters/index.js\";\nimport type { CitationEntry } from \"./citations.js\";\n\nexport interface EngramAccessHttpServerOptions {\n service: EngramAccessService;\n host?: string;\n port?: number;\n authToken?: string;\n /** Additional valid tokens (for multi-connector auth). Checked alongside authToken. */\n authTokens?: string[];\n /** Dynamic token loader — called on each auth check so new/revoked tokens take effect without restart. */\n authTokensGetter?: () => string[];\n principal?: string;\n maxBodyBytes?: number;\n adminConsoleEnabled?: boolean;\n adminConsolePublicDir?: string;\n trustPrincipalHeader?: boolean;\n /** Enable adapter-based identity resolution from request headers */\n enableAdapters?: boolean;\n /** Custom adapter registry (defaults to built-in adapters) */\n adapterRegistry?: AdapterRegistry;\n /** Enable oai-mem-citation blocks in recall responses (issue #379). */\n citationsEnabled?: boolean;\n /** Auto-enable citations for Codex adapter connections (issue #379). */\n citationsAutoDetect?: boolean;\n}\n\nexport interface EngramAccessHttpServerStatus {\n running: boolean;\n host: string;\n port: number;\n maxBodyBytes: number;\n}\n\nfunction resolveDefaultAdminConsolePublicDir(): string {\n const candidates = [\n fileURLToPath(new URL(\"../admin-console/public\", import.meta.url)),\n fileURLToPath(new URL(\"./admin-console/public\", import.meta.url)),\n ];\n return candidates.find((candidate) => existsSync(candidate)) ?? candidates[0];\n}\n\nconst defaultAdminConsolePublicDir = resolveDefaultAdminConsolePublicDir();\nconst correlationIdStore = new AsyncLocalStorage<string>();\n\nconst WRITE_RATE_LIMIT_WINDOW_MS = 60_000;\nconst WRITE_RATE_LIMIT_MAX_REQUESTS = 30;\nconst TRUST_ZONE_RECORD_KINDS = [\"memory\", \"artifact\", \"state\", \"trajectory\", \"external\"] as const;\nconst TRUST_ZONE_SOURCE_CLASSES = [\"tool_output\", \"web_content\", \"subagent_trace\", \"system_memory\", \"user_input\", \"manual\"] as const;\n\nclass HttpError extends Error {\n readonly code: string;\n readonly details?: unknown;\n constructor(readonly status: number, message: string, code?: string, details?: unknown) {\n super(message);\n this.code = code ?? `http_${status}`;\n this.details = details;\n }\n}\n\nfunction hostToUrlAuthority(host: string): string {\n if (host.includes(\":\") && !host.startsWith(\"[\") && !host.endsWith(\"]\")) {\n return `[${host}]`;\n }\n return host;\n}\n\nfunction parseTrustZoneKindFilter(raw: string | null): TrustZoneRecordKind | undefined {\n if (raw === null) return undefined;\n if ((TRUST_ZONE_RECORD_KINDS as readonly string[]).includes(raw)) {\n return raw as TrustZoneRecordKind;\n }\n throw new HttpError(400, `kind must be one of ${TRUST_ZONE_RECORD_KINDS.join(\"|\")}`, \"invalid_kind_filter\");\n}\n\nfunction parseTrustZoneSourceClassFilter(raw: string | null): TrustZoneSourceClass | undefined {\n if (raw === null) return undefined;\n if ((TRUST_ZONE_SOURCE_CLASSES as readonly string[]).includes(raw)) {\n return raw as TrustZoneSourceClass;\n }\n throw new HttpError(400, `sourceClass must be one of ${TRUST_ZONE_SOURCE_CLASSES.join(\"|\")}`, \"invalid_source_class_filter\");\n}\n\nfunction parseTrustZoneFilter(raw: string | null): TrustZoneName | undefined {\n if (raw === null) return undefined;\n if (isTrustZoneName(raw)) {\n return raw;\n }\n throw new HttpError(400, \"zone must be one of quarantine|working|trusted\", \"invalid_zone_filter\");\n}\n\nexport class EngramAccessHttpServer {\n private readonly service: EngramAccessService;\n private readonly host: string;\n private readonly requestedPort: number;\n private readonly authToken?: string;\n private readonly authTokens: string[];\n private readonly authTokensGetter?: () => string[];\n private readonly authenticatedPrincipal?: string;\n private readonly maxBodyBytes: number;\n private readonly adminConsoleEnabled: boolean;\n private readonly adminConsolePublicDir: string;\n private readonly trustPrincipalHeader: boolean;\n private readonly adapterRegistry: AdapterRegistry | null;\n private readonly writeRequestTimestamps: number[] = [];\n private readonly mcpServer: EngramMcpServer;\n private server: Server | null = null;\n private boundPort = 0;\n\n constructor(options: EngramAccessHttpServerOptions) {\n this.service = options.service;\n this.host = options.host?.trim() || \"127.0.0.1\";\n this.requestedPort = Number.isFinite(options.port) ? Math.max(0, Math.floor(options.port ?? 0)) : 0;\n this.authToken = options.authToken?.trim() || undefined;\n this.authTokens = (options.authTokens ?? []).map((t) => t.trim()).filter(Boolean);\n this.authTokensGetter = options.authTokensGetter;\n this.authenticatedPrincipal = options.principal?.trim() || undefined;\n this.maxBodyBytes = Number.isFinite(options.maxBodyBytes)\n ? Math.max(1, Math.floor(options.maxBodyBytes ?? 131072))\n : 131072;\n this.adminConsoleEnabled = options.adminConsoleEnabled !== false;\n this.adminConsolePublicDir = options.adminConsolePublicDir ?? defaultAdminConsolePublicDir;\n this.trustPrincipalHeader = options.trustPrincipalHeader === true;\n this.adapterRegistry = options.enableAdapters !== false\n ? (options.adapterRegistry ?? new AdapterRegistry())\n : null;\n this.mcpServer = new EngramMcpServer(this.service, {\n principal: options.principal,\n citationsEnabled: options.citationsEnabled,\n citationsAutoDetect: options.citationsAutoDetect,\n });\n }\n\n async start(): Promise<EngramAccessHttpServerStatus> {\n if (!this.authToken && this.authTokens.length === 0 && !this.authTokensGetter) {\n throw new Error(\"engram access HTTP requires authToken or authTokens\");\n }\n if (this.server) return this.status();\n\n const server = createServer((req, res) => {\n const correlationId = randomUUID();\n correlationIdStore.run(correlationId, () => {\n void this.handle(req, res, correlationId).catch((err) => {\n log.debug(`engram access HTTP request failed [${correlationId}]: ${err}`);\n if (err instanceof HttpError) {\n const payload: Record<string, unknown> = { error: err.message, code: err.code };\n if (err.details) payload.details = err.details;\n this.respondJson(res, err.status, payload);\n return;\n }\n if (err instanceof EngramAccessInputError) {\n this.respondJson(res, 400, { error: err.message, code: \"input_error\" });\n return;\n }\n if (res.headersSent) {\n res.destroy(err as Error);\n return;\n }\n this.respondJson(res, 500, { error: \"internal_error\", code: \"internal_error\" });\n });\n });\n });\n\n try {\n await new Promise<void>((resolve, reject) => {\n const onError = (err: Error) => {\n server.off(\"listening\", onListening);\n reject(err);\n };\n const onListening = () => {\n server.off(\"error\", onError);\n resolve();\n };\n server.once(\"error\", onError);\n server.once(\"listening\", onListening);\n server.listen(this.requestedPort, this.host);\n });\n } catch (err) {\n server.close();\n throw err;\n }\n\n this.server = server;\n const address = server.address();\n this.boundPort = typeof address === \"object\" && address ? address.port : this.requestedPort;\n return this.status();\n }\n\n async stop(): Promise<void> {\n if (!this.server) return;\n const server = this.server;\n this.server = null;\n this.boundPort = 0;\n await new Promise<void>((resolve, reject) => {\n server.close((err) => (err ? reject(err) : resolve()));\n });\n }\n\n status(): EngramAccessHttpServerStatus {\n return {\n running: this.server !== null,\n host: this.host,\n port: this.boundPort,\n maxBodyBytes: this.maxBodyBytes,\n };\n }\n\n /**\n * Resolve the adapter identity for the incoming request.\n * Includes MCP clientInfo from the last initialize handshake if available.\n * Returns null if no adapter matches or adapters are disabled.\n */\n resolveAdapterIdentity(req: IncomingMessage): ResolvedIdentity | null {\n if (!this.adapterRegistry) return null;\n // Look up clientInfo for this specific MCP session to avoid cross-session leaks.\n // Non-MCP requests (no mcp-session-id header) get undefined clientInfo and\n // rely on HTTP headers for adapter matching.\n const sessionId = (() => {\n const raw = req.headers[\"mcp-session-id\"];\n return typeof raw === \"string\" ? raw.trim() : undefined;\n })();\n return this.adapterRegistry.resolve({\n headers: req.headers as Record<string, string | string[] | undefined>,\n clientInfo: this.mcpServer.getClientInfo(sessionId),\n });\n }\n\n /** Cache for per-request identity resolution (avoids double adapter resolution) */\n private identityCache = new WeakMap<IncomingMessage, { principal?: string; namespace?: string }>();\n\n /** Resolve principal and namespace from request headers and adapter identity */\n private resolveRequestIdentity(req: IncomingMessage): { principal?: string; namespace?: string } {\n const cached = this.identityCache.get(req);\n if (cached) return cached;\n let principal: string | undefined;\n let namespace: string | undefined;\n\n // Explicit header override takes priority for principal\n if (this.trustPrincipalHeader) {\n const headerVal = req.headers[\"x-engram-principal\"];\n const raw = Array.isArray(headerVal) ? headerVal[0] : headerVal;\n if (typeof raw === \"string\") {\n const trimmed = raw.trim();\n if (trimmed.length > 0) {\n principal = trimmed;\n }\n }\n }\n\n // Try adapter-based identity resolution for both principal and namespace\n const adapterIdentity = this.resolveAdapterIdentity(req);\n if (adapterIdentity) {\n if (!principal) {\n principal = adapterIdentity.principal;\n }\n namespace = adapterIdentity.namespace;\n }\n\n if (!principal) {\n principal = this.authenticatedPrincipal;\n }\n\n const result = { principal, namespace };\n this.identityCache.set(req, result);\n return result;\n }\n\n private resolveRequestPrincipal(req: IncomingMessage): string | undefined {\n return this.resolveRequestIdentity(req).principal;\n }\n\n /** Resolve namespace: only use the explicit body value. Adapter-inferred namespace\n * is intentionally NOT used as a fallback for REST requests — omitting namespace\n * should default to the server's global namespace, not silently scope to an adapter. */\n private resolveNamespace(_req: IncomingMessage, bodyNamespace?: string): string | undefined {\n return bodyNamespace || undefined;\n }\n\n private async handle(req: IncomingMessage, res: ServerResponse, correlationId: string): Promise<void> {\n const parsed = new URL(req.url ?? \"/\", `http://${hostToUrlAuthority(this.host)}`);\n const pathname = parsed.pathname;\n\n if (this.adminConsoleEnabled && await this.handleAdminConsole(req, res, pathname)) {\n return;\n }\n\n if (!this.isAuthorized(req)) {\n const body = JSON.stringify({ error: \"unauthorized\", code: \"unauthorized\" });\n res.writeHead(401, {\n \"content-type\": \"application/json; charset=utf-8\",\n \"www-authenticate\": \"Bearer\",\n \"x-request-id\": correlationId,\n });\n res.end(body);\n return;\n }\n\n if (req.method === \"POST\" && pathname === \"/mcp\") {\n await this.handleMcpRequest(req, res);\n return;\n }\n\n if (req.method === \"GET\" && pathname === \"/engram/v1/health\") {\n this.respondJson(res, 200, await this.service.health());\n return;\n }\n\n if (req.method === \"GET\" && pathname === \"/engram/v1/adapters\") {\n const identity = this.resolveAdapterIdentity(req);\n this.respondJson(res, 200, {\n adaptersEnabled: this.adapterRegistry !== null,\n registered: this.adapterRegistry?.list() ?? [],\n resolved: identity,\n });\n return;\n }\n\n if (req.method === \"POST\" && pathname === \"/engram/v1/recall\") {\n const body = await this.readValidatedBody(req, \"recall\");\n // Preserve the distinction between `codingContext: null` (explicit\n // clear) and `codingContext` missing from the JSON payload\n // (untouched). The previous `?? undefined` collapsed both into\n // undefined, so callers lost the ability to clear the session's\n // attached context through the recall endpoint.\n const codingContext =\n \"codingContext\" in body ? body.codingContext : undefined;\n const response = await this.service.recall({\n query: body.query ?? \"\",\n sessionKey: body.sessionKey,\n namespace: this.resolveNamespace(req, body.namespace),\n topK: body.topK,\n mode: body.mode as RecallPlanMode | \"auto\" | undefined,\n includeDebug: body.includeDebug === true,\n codingContext,\n });\n this.respondJson(res, 200, response);\n return;\n }\n\n // Attach / clear coding-agent context for a session (issue #569 PR 5).\n // Mirrors `setCodingContext` on the access service. Connectors call this\n // at session start after resolving a git context for the cwd; `remnic\n // doctor` (PR 8) surfaces the attached context.\n if (req.method === \"POST\" && pathname === \"/engram/v1/coding-context\") {\n const body = await this.readValidatedBody(req, \"setCodingContext\");\n this.service.setCodingContext({\n sessionKey: body.sessionKey,\n codingContext: body.codingContext,\n });\n this.respondJson(res, 200, { ok: true });\n return;\n }\n\n if (req.method === \"POST\" && pathname === \"/engram/v1/recall/explain\") {\n const body = await this.readValidatedBody(req, \"recallExplain\");\n const response = await this.service.recallExplain({\n sessionKey: body.sessionKey,\n namespace: this.resolveNamespace(req, body.namespace),\n });\n this.respondJson(res, 200, response);\n return;\n }\n\n // Tier-explain (issue #518): structured per-result annotation from\n // the direct-answer retrieval tier. Orthogonal to /recall/explain\n // above, which returns a graph-path explanation document.\n if (req.method === \"GET\" && pathname === \"/engram/v1/recall/tier-explain\") {\n const sessionParam = parsed.searchParams.get(\"session\");\n const sessionKey = sessionParam && sessionParam.length > 0 ? sessionParam : undefined;\n const namespaceParam = parsed.searchParams.get(\"namespace\");\n const namespace = this.resolveNamespace(\n req,\n namespaceParam && namespaceParam.length > 0 ? namespaceParam : undefined,\n );\n const payload = await this.service.recallTierExplain(\n sessionKey,\n namespace,\n this.resolveRequestPrincipal(req),\n );\n this.respondJson(res, 200, payload);\n return;\n }\n\n // Recall X-ray (issue #570 PR 4): unified per-result attribution\n // snapshot. Requires bearer auth (same as every other endpoint\n // here) and enforces namespace scope before the recall fires\n // (CLAUDE.md rule 42). Query comes from the `q` search param so\n // GET stays cacheable; `namespace` / `session` / `budget` are\n // optional.\n if (req.method === \"GET\" && pathname === \"/engram/v1/recall/xray\") {\n const queryParam = parsed.searchParams.get(\"q\");\n if (!queryParam || queryParam.trim().length === 0) {\n this.respondJson(res, 400, {\n error: \"missing_query\",\n code: \"missing_query\",\n message: \"q search parameter is required and must be non-empty\",\n });\n return;\n }\n const sessionParam = parsed.searchParams.get(\"session\");\n const sessionKey = sessionParam && sessionParam.length > 0\n ? sessionParam\n : undefined;\n const namespaceParam = parsed.searchParams.get(\"namespace\");\n const namespace = this.resolveNamespace(\n req,\n namespaceParam && namespaceParam.length > 0\n ? namespaceParam\n : undefined,\n );\n const budgetParam = parsed.searchParams.get(\"budget\");\n // Reject invalid `budget` with 400 rather than silently\n // defaulting (CLAUDE.md rules 14 + 51).\n let budget: number | undefined;\n if (budgetParam !== null && budgetParam !== \"\") {\n const parsedBudget = Number(budgetParam);\n if (\n !Number.isFinite(parsedBudget)\n || parsedBudget <= 0\n || !Number.isInteger(parsedBudget)\n ) {\n this.respondJson(res, 400, {\n error: \"invalid_budget\",\n code: \"invalid_budget\",\n message:\n \"budget expects a positive integer\",\n });\n return;\n }\n budget = parsedBudget;\n }\n // Only translate validation errors (empty query, bad budget)\n // into 400s. Backend faults (timeouts, storage errors,\n // unexpected orchestrator failures) must bubble to the global\n // `handle()` error handler so they return 500 and get logged\n // properly. `service.recallXray` prefixes its validation\n // errors with \"recallXray:\" so we key off that prefix rather\n // than catching everything.\n let payload: Awaited<ReturnType<typeof this.service.recallXray>>;\n try {\n payload = await this.service.recallXray({\n query: queryParam,\n sessionKey,\n namespace,\n budget,\n authenticatedPrincipal: this.resolveRequestPrincipal(req),\n });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n if (message.startsWith(\"recallXray:\")) {\n this.respondJson(res, 400, {\n error: \"invalid_request\",\n code: \"invalid_request\",\n message,\n });\n return;\n }\n // Anything else is a server-side fault; rethrow so the\n // outer `handle()` catch returns 500 + logs the error.\n throw err;\n }\n this.respondJson(res, 200, payload);\n return;\n }\n\n if (req.method === \"POST\" && pathname === \"/engram/v1/observe\") {\n const body = await this.readValidatedBody(req, \"observe\");\n this.ensureWriteRateLimitAvailable();\n const response = await this.service.observe({\n sessionKey: body.sessionKey,\n messages: body.messages,\n namespace: this.resolveNamespace(req, body.namespace),\n authenticatedPrincipal: this.resolveRequestPrincipal(req),\n skipExtraction: body.skipExtraction === true,\n });\n this.recordWriteRateLimitHit();\n this.respondJson(res, 202, response);\n return;\n }\n\n if (req.method === \"POST\" && pathname === \"/engram/v1/lcm/search\") {\n const body = await this.readValidatedBody(req, \"lcmSearch\");\n const response = await this.service.lcmSearch({\n query: body.query,\n sessionKey: body.sessionKey,\n namespace: this.resolveNamespace(req, body.namespace),\n authenticatedPrincipal: this.resolveRequestPrincipal(req),\n limit: body.limit,\n });\n this.respondJson(res, 200, response);\n return;\n }\n\n if (req.method === \"GET\" && pathname === \"/engram/v1/lcm/status\") {\n this.respondJson(res, 200, await this.service.lcmStatus());\n return;\n }\n\n if (req.method === \"POST\" && pathname === \"/engram/v1/memories\") {\n const body = await this.readValidatedBody(req, \"memoryStore\");\n const request = {\n schemaVersion: body.schemaVersion,\n idempotencyKey: body.idempotencyKey,\n dryRun: body.dryRun === true,\n sessionKey: body.sessionKey,\n authenticatedPrincipal: this.resolveRequestPrincipal(req),\n content: body.content,\n category: body.category,\n confidence: body.confidence,\n namespace: this.resolveNamespace(req, body.namespace),\n tags: body.tags,\n entityRef: body.entityRef,\n ttl: body.ttl,\n sourceReason: body.sourceReason,\n };\n const idempotencyStatus = await this.service.peekMemoryStoreIdempotency(request);\n if (idempotencyStatus === \"miss\" && request.dryRun !== true) {\n this.ensureWriteRateLimitAvailable();\n }\n const response = await this.service.memoryStore(request);\n if (this.shouldCountWriteRateLimit(response as { dryRun?: boolean; idempotencyReplay?: boolean })) {\n this.recordWriteRateLimitHit();\n }\n this.respondJson(res, this.writeResponseStatus(response), response);\n return;\n }\n\n if (req.method === \"POST\" && pathname === \"/engram/v1/suggestions\") {\n const body = await this.readValidatedBody(req, \"suggestionSubmit\");\n const request = {\n schemaVersion: body.schemaVersion,\n idempotencyKey: body.idempotencyKey,\n dryRun: body.dryRun === true,\n sessionKey: body.sessionKey,\n authenticatedPrincipal: this.resolveRequestPrincipal(req),\n content: body.content,\n category: body.category,\n confidence: body.confidence,\n namespace: this.resolveNamespace(req, body.namespace),\n tags: body.tags,\n entityRef: body.entityRef,\n ttl: body.ttl,\n sourceReason: body.sourceReason,\n };\n const idempotencyStatus = await this.service.peekSuggestionSubmitIdempotency(request);\n if (idempotencyStatus === \"miss\" && request.dryRun !== true) {\n this.ensureWriteRateLimitAvailable();\n }\n const response = await this.service.suggestionSubmit(request);\n if (this.shouldCountWriteRateLimit(response as { dryRun?: boolean; idempotencyReplay?: boolean })) {\n this.recordWriteRateLimitHit();\n }\n this.respondJson(res, this.writeResponseStatus(response), response);\n return;\n }\n\n if (req.method === \"GET\" && pathname === \"/engram/v1/memories\") {\n const limitRaw = parseInt(parsed.searchParams.get(\"limit\") ?? \"50\", 10);\n const offsetRaw = parseInt(parsed.searchParams.get(\"offset\") ?? \"0\", 10);\n const sortParam = parsed.searchParams.get(\"sort\") ?? undefined;\n const sort = sortParam === \"updated_desc\"\n || sortParam === \"updated_asc\"\n || sortParam === \"created_desc\"\n || sortParam === \"created_asc\"\n ? sortParam\n : undefined;\n const response = await this.service.memoryBrowse({\n query: parsed.searchParams.get(\"q\") ?? undefined,\n status: parsed.searchParams.get(\"status\") ?? undefined,\n category: parsed.searchParams.get(\"category\") ?? undefined,\n namespace: parsed.searchParams.get(\"namespace\") ?? undefined,\n sort,\n limit: Number.isFinite(limitRaw) ? limitRaw : 50,\n offset: Number.isFinite(offsetRaw) ? offsetRaw : 0,\n });\n this.respondJson(res, 200, response);\n return;\n }\n\n const memoryMatch = pathname.match(/^\\/engram\\/v1\\/memories\\/([^/]+)$/);\n if (req.method === \"GET\" && memoryMatch) {\n const memoryId = decodeURIComponent(memoryMatch[1] ?? \"\");\n const namespace = parsed.searchParams.get(\"namespace\") ?? undefined;\n const response = await this.service.memoryGet(memoryId, namespace, this.resolveRequestPrincipal(req));\n this.respondJson(res, response.found ? 200 : 404, response);\n return;\n }\n\n const timelineMatch = pathname.match(/^\\/engram\\/v1\\/memories\\/([^/]+)\\/timeline$/);\n if (req.method === \"GET\" && timelineMatch) {\n const memoryId = decodeURIComponent(timelineMatch[1] ?? \"\");\n const namespace = parsed.searchParams.get(\"namespace\") ?? undefined;\n const limitRaw = parseInt(parsed.searchParams.get(\"limit\") ?? \"200\", 10);\n const limit = Number.isFinite(limitRaw) ? limitRaw : 200;\n const response = await this.service.memoryTimeline(memoryId, namespace, limit, this.resolveRequestPrincipal(req));\n this.respondJson(res, response.found ? 200 : 404, response);\n return;\n }\n\n if (req.method === \"GET\" && pathname === \"/engram/v1/entities\") {\n const limitRaw = parseInt(parsed.searchParams.get(\"limit\") ?? \"50\", 10);\n const offsetRaw = parseInt(parsed.searchParams.get(\"offset\") ?? \"0\", 10);\n const response = await this.service.entityList({\n namespace: parsed.searchParams.get(\"namespace\") ?? undefined,\n query: parsed.searchParams.get(\"q\") ?? undefined,\n limit: Number.isFinite(limitRaw) ? limitRaw : 50,\n offset: Number.isFinite(offsetRaw) ? offsetRaw : 0,\n });\n this.respondJson(res, 200, response);\n return;\n }\n\n const entityMatch = pathname.match(/^\\/engram\\/v1\\/entities\\/([^/]+)$/);\n if (req.method === \"GET\" && entityMatch) {\n const entityName = decodeURIComponent(entityMatch[1] ?? \"\");\n const namespace = parsed.searchParams.get(\"namespace\") ?? undefined;\n const response = await this.service.entityGet(entityName, namespace);\n this.respondJson(res, response.found ? 200 : 404, response);\n return;\n }\n\n if (req.method === \"GET\" && pathname === \"/engram/v1/review-queue\") {\n const response = await this.service.reviewQueue(\n parsed.searchParams.get(\"runId\") ?? undefined,\n parsed.searchParams.get(\"namespace\") ?? undefined,\n this.resolveRequestPrincipal(req),\n );\n this.respondJson(res, 200, response);\n return;\n }\n\n if (req.method === \"GET\" && pathname === \"/engram/v1/maintenance\") {\n this.respondJson(res, 200, await this.service.maintenance(parsed.searchParams.get(\"namespace\") ?? undefined, this.resolveRequestPrincipal(req)));\n return;\n }\n\n if (req.method === \"GET\" && pathname === \"/engram/v1/quality\") {\n this.respondJson(res, 200, await this.service.quality(parsed.searchParams.get(\"namespace\") ?? undefined, this.resolveRequestPrincipal(req)));\n return;\n }\n\n if (req.method === \"GET\" && pathname === \"/engram/v1/trust-zones/status\") {\n this.respondJson(\n res,\n 200,\n await this.service.trustZoneStatus(parsed.searchParams.get(\"namespace\") ?? undefined, this.resolveRequestPrincipal(req)),\n );\n return;\n }\n\n // Procedural memory stats (issue #567 PR 5/5). Read-only; namespace is\n // scoped via the same resolver used by recall/trust-zones so cross-\n // tenant reads aren't possible (CLAUDE.md rule 42).\n if (req.method === \"GET\" && pathname === \"/engram/v1/procedural/stats\") {\n const namespaceParam = parsed.searchParams.get(\"namespace\");\n this.respondJson(\n res,\n 200,\n await this.service.procedureStats(\n {\n namespace: this.resolveNamespace(\n req,\n namespaceParam && namespaceParam.length > 0\n ? namespaceParam\n : undefined,\n ),\n },\n this.resolveRequestPrincipal(req),\n ),\n );\n return;\n }\n\n if (req.method === \"GET\" && pathname === \"/engram/v1/trust-zones/records\") {\n const limitRaw = parseInt(parsed.searchParams.get(\"limit\") ?? \"25\", 10);\n const offsetRaw = parseInt(parsed.searchParams.get(\"offset\") ?? \"0\", 10);\n const response = await this.service.trustZoneBrowse({\n query: parsed.searchParams.get(\"q\") ?? undefined,\n zone: parseTrustZoneFilter(parsed.searchParams.get(\"zone\")),\n kind: parseTrustZoneKindFilter(parsed.searchParams.get(\"kind\")),\n sourceClass: parseTrustZoneSourceClassFilter(parsed.searchParams.get(\"sourceClass\")),\n namespace: parsed.searchParams.get(\"namespace\") ?? undefined,\n limit: Number.isFinite(limitRaw) ? limitRaw : 25,\n offset: Number.isFinite(offsetRaw) ? offsetRaw : 0,\n }, this.resolveRequestPrincipal(req));\n this.respondJson(res, 200, response);\n return;\n }\n\n if (req.method === \"POST\" && pathname === \"/engram/v1/review-disposition\") {\n const body = await this.readValidatedBody(req, \"reviewDisposition\");\n this.ensureWriteRateLimitAvailable();\n const response = await this.service.reviewDisposition({\n memoryId: body.memoryId,\n status: body.status,\n reasonCode: body.reasonCode,\n namespace: this.resolveNamespace(req, body.namespace),\n authenticatedPrincipal: this.resolveRequestPrincipal(req),\n });\n if (this.shouldCountWriteRateLimit(response as unknown as { dryRun?: boolean; idempotencyReplay?: boolean })) {\n this.recordWriteRateLimitHit();\n }\n this.respondJson(res, 200, response);\n return;\n }\n\n if (req.method === \"POST\" && pathname === \"/engram/v1/trust-zones/promote\") {\n const body = await this.readValidatedBody(req, \"trustZonePromote\");\n const dryRun = body.dryRun === true;\n if (!dryRun) {\n this.ensureWriteRateLimitAvailable();\n }\n const response = await this.service.trustZonePromote({\n recordId: body.recordId,\n targetZone: body.targetZone,\n promotionReason: body.promotionReason,\n recordedAt: body.recordedAt,\n summary: body.summary,\n dryRun,\n namespace: this.resolveNamespace(req, body.namespace),\n authenticatedPrincipal: this.resolveRequestPrincipal(req),\n });\n if (this.shouldCountWriteRateLimit(response as unknown as { dryRun?: boolean; idempotencyReplay?: boolean })) {\n this.recordWriteRateLimitHit();\n }\n this.respondJson(res, response.dryRun ? 200 : 201, response);\n return;\n }\n\n if (req.method === \"POST\" && pathname === \"/engram/v1/trust-zones/demo-seed\") {\n const body = await this.readValidatedBody(req, \"trustZoneDemoSeed\");\n const dryRun = body.dryRun === true;\n if (!dryRun) {\n this.ensureWriteRateLimitAvailable();\n }\n const response = await this.service.trustZoneDemoSeed({\n scenario: body.scenario,\n recordedAt: body.recordedAt,\n dryRun,\n namespace: this.resolveNamespace(req, body.namespace),\n authenticatedPrincipal: this.resolveRequestPrincipal(req),\n });\n if (this.shouldCountWriteRateLimit(response as unknown as { dryRun?: boolean; idempotencyReplay?: boolean })) {\n this.recordWriteRateLimitHit();\n }\n this.respondJson(res, response.dryRun ? 200 : 201, response);\n return;\n }\n\n // Citation usage tracking (issue #379)\n if (req.method === \"POST\" && pathname === \"/v1/citations/observed\") {\n const body = await this.readJsonBody(req);\n if (!body || typeof body !== \"object\" || Array.isArray(body)) {\n throw new HttpError(400, \"request body must be a JSON object\", \"invalid_body\");\n }\n const payload = body as Record<string, unknown>;\n const sessionId = typeof payload.sessionId === \"string\" ? payload.sessionId : undefined;\n const namespace = typeof payload.namespace === \"string\" ? payload.namespace : undefined;\n const citationsRaw = payload.citations;\n if (!citationsRaw || typeof citationsRaw !== \"object\" || Array.isArray(citationsRaw)) {\n throw new HttpError(400, \"citations must be a JSON object with entries and rolloutIds\", \"invalid_citations\");\n }\n const citObj = citationsRaw as Record<string, unknown>;\n const entries: CitationEntry[] = [];\n if (Array.isArray(citObj.entries)) {\n for (const raw of citObj.entries) {\n if (raw && typeof raw === \"object\" && !Array.isArray(raw)) {\n const e = raw as Record<string, unknown>;\n if (\n typeof e.path === \"string\" &&\n typeof e.lineStart === \"number\" &&\n typeof e.lineEnd === \"number\"\n ) {\n entries.push({\n path: e.path,\n lineStart: e.lineStart,\n lineEnd: e.lineEnd,\n note: typeof e.note === \"string\" ? e.note : \"\",\n });\n }\n }\n }\n }\n const rolloutIds: string[] = [];\n if (Array.isArray(citObj.rolloutIds)) {\n for (const id of citObj.rolloutIds) {\n if (typeof id === \"string\" && id.length > 0) {\n rolloutIds.push(id);\n }\n }\n }\n\n // Record usage: for each citation entry, try to increment usage on the\n // matching memory. The service exposes recordAccess for this purpose.\n // Pass authenticatedPrincipal so namespace ACL checks use the same\n // identity resolution as other write endpoints (Finding #1, issue #379).\n let matched = 0;\n let submitted = 0;\n if (typeof this.service.recordCitationUsage === \"function\") {\n const result = await this.service.recordCitationUsage({\n sessionId,\n namespace: this.resolveNamespace(req, namespace),\n authenticatedPrincipal: this.resolveRequestPrincipal(req),\n entries,\n rolloutIds,\n });\n submitted = result.submitted;\n matched = result.matched;\n }\n\n this.respondJson(res, 200, {\n ok: true,\n submitted,\n matched,\n entriesReceived: entries.length,\n rolloutIdsReceived: rolloutIds.length,\n });\n return;\n }\n\n // ── Contradiction Review (issue #520) ─────────────────────────────────────\n if (req.method === \"GET\" && pathname === \"/engram/v1/review/contradictions\") {\n const VALID_FILTERS = new Set([\"all\", \"unresolved\", \"contradicts\", \"independent\", \"duplicates\", \"needs-user\"]);\n const rawFilter = parsed.searchParams.get(\"filter\") ?? \"unresolved\";\n if (!VALID_FILTERS.has(rawFilter)) {\n this.respondJson(res, 400, { error: `Invalid filter '${rawFilter}'. Valid: ${[...VALID_FILTERS].join(\", \")}` });\n return;\n }\n const namespace = parsed.searchParams.get(\"namespace\") ?? undefined;\n const limitRaw = parseInt(parsed.searchParams.get(\"limit\") ?? \"50\", 10);\n const { listPairs } = await import(\"./contradiction/contradiction-review.js\");\n const result = listPairs(this.service.memoryDir, {\n filter: rawFilter as \"all\" | \"unresolved\" | \"contradicts\" | \"independent\" | \"duplicates\" | \"needs-user\",\n namespace,\n limit: Number.isFinite(limitRaw) ? limitRaw : 50,\n });\n this.respondJson(res, 200, result);\n return;\n }\n\n if (req.method === \"GET\" && pathname.startsWith(\"/engram/v1/review/contradictions/\")) {\n const pairId = pathname.split(\"/\").pop() ?? \"\";\n const { readPair } = await import(\"./contradiction/contradiction-review.js\");\n const pair = readPair(this.service.memoryDir, pairId);\n if (!pair) {\n this.respondJson(res, 404, { error: \"pair_not_found\" });\n return;\n }\n this.respondJson(res, 200, pair);\n return;\n }\n\n if (req.method === \"POST\" && pathname === \"/engram/v1/review/resolve\") {\n const body = await this.readJsonBody(req) as Record<string, unknown>;\n const pairId = typeof body.pairId === \"string\" ? body.pairId : \"\";\n const verb = typeof body.verb === \"string\" ? body.verb : \"\";\n if (!pairId || !verb) {\n this.respondJson(res, 400, { error: \"pairId and verb are required\" });\n return;\n }\n const { isValidResolutionVerb, executeResolution } = await import(\"./contradiction/resolution.js\");\n if (!isValidResolutionVerb(verb)) {\n this.respondJson(res, 400, { error: `Invalid verb: ${verb}. Must be one of: keep-a, keep-b, merge, both-valid, needs-more-context` });\n return;\n }\n const result = await executeResolution(this.service.memoryDir, this.service.storageRef, pairId, verb);\n this.respondJson(res, 200, result);\n return;\n }\n\n if (req.method === \"POST\" && pathname === \"/engram/v1/contradiction-scan\") {\n const body = await this.readJsonBody(req) as Record<string, unknown>;\n const { runContradictionScan } = await import(\"./contradiction/contradiction-scan.js\");\n const result = await runContradictionScan({\n storage: this.service.storageRef,\n config: this.service.configRef,\n memoryDir: this.service.memoryDir,\n embeddingLookupFactory: this.service.embeddingLookupFactoryRef,\n localLlm: this.service.localLlmRef,\n fallbackLlm: this.service.fallbackLlmRef,\n namespace: typeof body.namespace === \"string\" ? body.namespace : undefined,\n });\n this.respondJson(res, 200, result);\n return;\n }\n\n this.respondJson(res, 404, { error: \"not_found\", code: \"not_found\" });\n }\n\n private async handleMcpRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const body = await this.readJsonBody(req);\n const request = body as {\n jsonrpc?: string;\n id?: string | number | null;\n method?: string;\n params?: Record<string, unknown>;\n };\n\n // Enforce write rate limiting for MCP tool calls that mutate state,\n // matching the same protection applied to the REST write endpoints.\n // Pre-check ensures capacity; post-check skips counting dry runs and\n // idempotency replays, consistent with the REST handlers.\n const isMcpWrite =\n request.method === \"tools/call\" &&\n typeof request.params?.name === \"string\" &&\n (request.params.name === \"engram.memory_store\" || request.params.name === \"engram.suggestion_submit\" || request.params.name === \"engram.observe\");\n if (isMcpWrite) {\n this.ensureWriteRateLimitAvailable();\n }\n\n const sessionId = (() => {\n const raw = req.headers[\"mcp-session-id\"];\n return typeof raw === \"string\" ? raw.trim() : undefined;\n })();\n const mcpCorrelationId = correlationIdStore.getStore() ?? randomUUID();\n const response = await this.mcpServer.handleRequest(request, {\n principalOverride: this.resolveRequestPrincipal(req),\n sessionId,\n correlationId: mcpCorrelationId,\n });\n\n if (isMcpWrite && response !== null) {\n const result = (response as Record<string, unknown>).result as Record<string, unknown> | undefined;\n const isError = result?.isError === true;\n const structured = result?.structuredContent as { dryRun?: boolean; idempotencyReplay?: boolean } | undefined;\n if (!isError && structured && this.shouldCountWriteRateLimit(structured)) {\n this.recordWriteRateLimitHit();\n }\n }\n if (response === null) {\n res.statusCode = 202;\n res.end();\n return;\n }\n // If this was an initialize response, pop the session ID keyed by\n // correlation ID (unique per HTTP request, not client-chosen JSON-RPC id).\n const assignedSessionId = this.mcpServer.popInitSessionId(mcpCorrelationId);\n if (assignedSessionId) {\n res.setHeader(\"mcp-session-id\", assignedSessionId);\n }\n this.respondJson(res, 200, response);\n }\n\n private respondJson(res: ServerResponse, status: number, payload: unknown): void {\n const body = JSON.stringify(payload, null, 2);\n res.statusCode = status;\n res.setHeader(\"content-type\", \"application/json; charset=utf-8\");\n res.setHeader(\"content-length\", String(Buffer.byteLength(body)));\n const cid = correlationIdStore.getStore();\n if (cid) {\n res.setHeader(\"x-request-id\", cid);\n }\n res.end(body);\n }\n\n private async handleAdminConsole(\n req: IncomingMessage,\n res: ServerResponse,\n pathname: string,\n ): Promise<boolean> {\n if (req.method !== \"GET\") return false;\n if (pathname === \"/engram/ui\" || pathname === \"/engram/ui/\") {\n await this.respondStatic(res, path.join(this.adminConsolePublicDir, \"index.html\"), \"text/html; charset=utf-8\");\n return true;\n }\n if (pathname === \"/engram/ui/app.js\") {\n await this.respondStatic(res, path.join(this.adminConsolePublicDir, \"app.js\"), \"application/javascript; charset=utf-8\");\n return true;\n }\n return false;\n }\n\n private async respondStatic(res: ServerResponse, filePath: string, contentType: string): Promise<void> {\n try {\n const body = await readFile(filePath, \"utf-8\");\n res.statusCode = 200;\n res.setHeader(\"content-type\", contentType);\n res.setHeader(\"content-length\", String(Buffer.byteLength(body)));\n res.end(body);\n } catch {\n this.respondJson(res, 404, { error: \"not_found\" });\n }\n }\n\n private async readJsonBody(req: IncomingMessage): Promise<Record<string, unknown>> {\n const chunks: Buffer[] = [];\n let total = 0;\n for await (const chunk of req) {\n const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);\n total += buffer.length;\n if (total > this.maxBodyBytes) {\n throw new HttpError(413, \"request_body_too_large\", \"request_body_too_large\");\n }\n chunks.push(buffer);\n }\n if (chunks.length === 0) return {};\n const raw = Buffer.concat(chunks).toString(\"utf-8\").trim();\n if (raw.length === 0) return {};\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new HttpError(400, \"invalid_json\", \"invalid_json\");\n }\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n throw new HttpError(400, \"invalid_json_object\", \"invalid_json_object\");\n }\n return parsed as Record<string, unknown>;\n }\n\n private async readValidatedBody<S extends SchemaName>(req: IncomingMessage, schemaName: S): Promise<SchemaTypeFor<S>> {\n const raw = await this.readJsonBody(req);\n const result = validateRequest(schemaName, raw);\n if (!result.success) {\n throw new HttpError(400, result.error.error, \"validation_error\", result.error.details);\n }\n return result.data as SchemaTypeFor<S>;\n }\n\n private isAuthorized(req: IncomingMessage): boolean {\n if (!this.authToken && this.authTokens.length === 0 && !this.authTokensGetter) return false;\n const raw = req.headers.authorization;\n if (!raw) return false;\n const separator = raw.indexOf(\" \");\n if (separator <= 0) return false;\n const scheme = raw.slice(0, separator).toLowerCase();\n if (scheme !== \"bearer\") return false;\n const token = raw.slice(separator + 1).trim();\n // Check primary token\n if (this.authToken && this.timingSafeStringEqual(token, this.authToken)) return true;\n // Check static multi-connector tokens\n for (const valid of this.authTokens) {\n if (this.timingSafeStringEqual(token, valid)) return true;\n }\n // Check dynamic tokens (reloaded per request for generate/revoke without restart)\n if (this.authTokensGetter) {\n for (const valid of this.authTokensGetter()) {\n if (this.timingSafeStringEqual(token, valid)) return true;\n }\n }\n return false;\n }\n\n private timingSafeStringEqual(a: string, b: string): boolean {\n const left = this.encodeSecret(a);\n const right = this.encodeSecret(b);\n if (!left || !right) return false;\n return timingSafeEqual(left, right);\n }\n\n private encodeSecret(value: string): Buffer | null {\n const encoded = Buffer.from(value, \"utf-8\");\n if (encoded.length > 1024) return null;\n const out = Buffer.alloc(2 + 1024);\n out.writeUInt16BE(encoded.length, 0);\n encoded.copy(out, 2);\n return out;\n }\n\n private writeResponseStatus(response: { dryRun: boolean; status: string }): number {\n if (response.dryRun === true) return 200;\n if (response.status === \"stored\" || response.status === \"queued_for_review\") return 201;\n return 200;\n }\n\n private ensureWriteRateLimitAvailable(): void {\n const now = Date.now();\n while (\n this.writeRequestTimestamps.length > 0 &&\n now - (this.writeRequestTimestamps[0] ?? 0) > WRITE_RATE_LIMIT_WINDOW_MS\n ) {\n this.writeRequestTimestamps.shift();\n }\n if (this.writeRequestTimestamps.length >= WRITE_RATE_LIMIT_MAX_REQUESTS) {\n throw new HttpError(429, \"write_rate_limited\", \"write_rate_limited\");\n }\n }\n\n private recordWriteRateLimitHit(): void {\n this.writeRequestTimestamps.push(Date.now());\n }\n\n private shouldCountWriteRateLimit(response: { dryRun?: boolean; idempotencyReplay?: boolean }): boolean {\n return response.dryRun !== true && response.idempotencyReplay !== true;\n }\n}\n","/**\n * Adapter interface for external system identity resolution.\n *\n * Each adapter maps an external system's session/identity conventions\n * to Engram's namespace + principal model. Adapters are stateless and\n * lightweight — they don't manage lifecycles or load plugins.\n */\n\nexport interface AdapterContext {\n /** Raw HTTP headers from the incoming request */\n headers: Record<string, string | string[] | undefined>;\n /** MCP client info (from initialize handshake, if available) */\n clientInfo?: { name: string; version?: string };\n /** Explicit session key from request args */\n sessionKey?: string;\n}\n\nexport interface ResolvedIdentity {\n /** Engram namespace (scopes memory access) */\n namespace: string;\n /** Engram principal (authorization subject) */\n principal: string;\n /** Session key for continuity tracking */\n sessionKey?: string;\n /** Which adapter resolved this identity */\n adapterId: string;\n}\n\nexport interface EngramAdapter {\n /** Adapter identifier (e.g., \"claude-code\", \"codex\", \"hermes\", \"replit\") */\n readonly id: string;\n\n /** Whether this adapter recognizes the given request context */\n matches(context: AdapterContext): boolean;\n\n /** Map external session/identity to Engram namespace + principal */\n resolveIdentity(context: AdapterContext): ResolvedIdentity;\n}\n\n/**\n * Extract and trim a single header value from a headers record.\n * Returns undefined if the header is missing, empty, or all whitespace.\n */\nexport function headerValue(\n headers: Record<string, string | string[] | undefined>,\n key: string,\n): string | undefined {\n const raw = headers[key];\n const value = Array.isArray(raw) ? raw[0] : raw;\n return typeof value === \"string\" && value.trim().length > 0 ? value.trim() : undefined;\n}\n","import { headerValue, type AdapterContext, type EngramAdapter, type ResolvedIdentity } from \"./types.js\";\n\n/**\n * Claude Code adapter.\n *\n * Detection: Claude Code sends clientInfo.name = \"claude-code\" in the\n * MCP initialize handshake, and User-Agent: claude-code/<version> in\n * HTTP requests. Project path is available via MCP ListRoots capability\n * (server receives the cwd as a file:// URI root), not via headers.\n *\n * For HTTP REST (non-MCP) requests, detection relies on User-Agent or\n * user-configured X-Engram-Client-Id header in .claude.json headers.\n *\n * Namespace/principal can be set by configuring custom headers in\n * .claude.json or .mcp.json:\n * \"headers\": { \"X-Engram-Namespace\": \"my-project\", \"X-Engram-Principal\": \"my-team\" }\n */\nexport class ClaudeCodeAdapter implements EngramAdapter {\n readonly id = \"claude-code\";\n\n matches(context: AdapterContext): boolean {\n // Primary: MCP clientInfo from initialize handshake (exact match)\n if (context.clientInfo?.name === \"claude-code\") return true;\n\n // Fallback: User-Agent header (Claude Code sends \"claude-code/<version>\")\n const ua = headerValue(context.headers, \"user-agent\");\n if (ua && ua.toLowerCase().startsWith(\"claude-code/\")) return true;\n\n // Fallback: user-configured client identifier header\n const clientId = headerValue(context.headers, \"x-engram-client-id\");\n if (clientId?.toLowerCase() === \"claude-code\") return true;\n\n return false;\n }\n\n resolveIdentity(context: AdapterContext): ResolvedIdentity {\n // MCP session ID (standard MCP header, server-assigned)\n const mcpSessionId = headerValue(context.headers, \"mcp-session-id\");\n\n // Principal: explicit header > default\n const principal = headerValue(context.headers, \"x-engram-principal\")\n || \"claude-code\";\n\n // Namespace: explicit header > default\n const namespace = headerValue(context.headers, \"x-engram-namespace\")\n || \"claude-code\";\n\n return {\n namespace,\n principal,\n sessionKey: mcpSessionId ?? context.sessionKey,\n adapterId: this.id,\n };\n }\n}\n\n","import { headerValue, type AdapterContext, type EngramAdapter, type ResolvedIdentity } from \"./types.js\";\n\n/**\n * Codex CLI adapter.\n *\n * Detection: Codex CLI sends clientInfo.name = \"codex-mcp-client\" and\n * clientInfo.title = \"Codex\" in the MCP initialize handshake. It does\n * NOT send agent names, session IDs, or project context automatically.\n *\n * For Streamable HTTP transport, Codex supports custom headers via\n * http_headers in ~/.codex/config.toml:\n * [mcp_servers.engram]\n * url = \"http://localhost:4318/mcp\"\n * http_headers = { \"X-Engram-Namespace\" = \"my-project\", \"X-Engram-Principal\" = \"codex-agent\" }\n *\n * Codex also sends a custom \"sandbox_state\" RPC notification after\n * init with sandbox policy info (read-only/writable paths).\n */\nexport class CodexAdapter implements EngramAdapter {\n readonly id = \"codex\";\n\n matches(context: AdapterContext): boolean {\n // Primary: MCP clientInfo from initialize handshake (exact match)\n if (context.clientInfo?.name === \"codex-mcp-client\") return true;\n\n // Also match on clientInfo name containing \"codex\" for forward compat\n const clientName = context.clientInfo?.name?.toLowerCase() ?? \"\";\n if (clientName.includes(\"codex\") && clientName !== \"codex-mcp-client\") return true;\n\n // Fallback: user-configured client identifier header\n const clientId = headerValue(context.headers, \"x-engram-client-id\");\n if (clientId?.toLowerCase() === \"codex\") return true;\n\n return false;\n }\n\n resolveIdentity(context: AdapterContext): ResolvedIdentity {\n // MCP session ID (standard MCP header, server-assigned)\n const mcpSessionId = headerValue(context.headers, \"mcp-session-id\");\n\n // Principal: explicit header > default\n const principal = headerValue(context.headers, \"x-engram-principal\")\n || \"codex\";\n\n // Namespace: explicit header > default\n const namespace = headerValue(context.headers, \"x-engram-namespace\")\n || \"codex\";\n\n return {\n namespace,\n principal,\n sessionKey: mcpSessionId ?? context.sessionKey,\n adapterId: this.id,\n };\n }\n}\n\n","import { headerValue, type AdapterContext, type EngramAdapter, type ResolvedIdentity } from \"./types.js\";\n\n/**\n * Replit Agent adapter.\n *\n * Detection: Replit Agent supports MCP natively (HTTP-only, configured\n * via the Integrations pane). It does NOT send identifying headers\n * automatically — detection relies on user-configured custom headers\n * in Replit's MCP Integrations UI.\n *\n * Replit provides env vars to running code (REPL_ID, REPL_OWNER,\n * REPL_SLUG) but these are NOT sent as HTTP headers to MCP servers.\n *\n * To identify Replit connections, users should configure a custom header\n * in the Replit Integrations pane when adding the Engram MCP server:\n * Header Name: X-Engram-Client-Id\n * Header Value: replit\n *\n * Optionally also set X-Engram-Namespace and X-Engram-Principal for\n * project/user scoping.\n */\nexport class ReplitAdapter implements EngramAdapter {\n readonly id = \"replit\";\n\n matches(context: AdapterContext): boolean {\n // Primary: user-configured client identifier header\n const clientId = headerValue(context.headers, \"x-engram-client-id\");\n if (clientId?.toLowerCase() === \"replit\") return true;\n\n // MCP clientInfo (Replit's MCP client name is not publicly documented,\n // but check for it in case it becomes available)\n const clientName = context.clientInfo?.name?.toLowerCase() ?? \"\";\n if (clientName.includes(\"replit\")) return true;\n\n return false;\n }\n\n resolveIdentity(context: AdapterContext): ResolvedIdentity {\n const mcpSessionId = headerValue(context.headers, \"mcp-session-id\");\n\n const principal = headerValue(context.headers, \"x-engram-principal\")\n || \"replit-agent\";\n\n const namespace = headerValue(context.headers, \"x-engram-namespace\")\n || \"replit\";\n\n return {\n namespace,\n principal,\n sessionKey: mcpSessionId ?? context.sessionKey,\n adapterId: this.id,\n };\n }\n}\n\n","import { headerValue, type AdapterContext, type EngramAdapter, type ResolvedIdentity } from \"./types.js\";\n\n/**\n * Hermes Agent adapter.\n *\n * Detection: Hermes supports both MCP (via config.yaml mcp_servers)\n * and a dedicated MemoryProvider plugin protocol (Python). The MCP\n * client name is not yet publicly documented, so detection uses:\n *\n * 1. X-Hermes-Session-Id header — confirmed in v0.7.0 API server\n * 2. User-configured headers in Hermes MCP config:\n * mcp_servers:\n * engram:\n * url: \"http://localhost:4318/mcp\"\n * headers:\n * X-Engram-Client-Id: \"hermes\"\n * X-Engram-Namespace: \"my-profile\"\n * 3. MCP clientInfo name containing \"hermes\" (for forward compat)\n *\n * Hermes profiles isolate agent state under ~/.hermes/profiles/<name>/.\n * Each profile can map to a separate Engram namespace via the\n * X-Engram-Namespace header.\n *\n * For deeper integration, Hermes v0.7.0+ supports MemoryProvider\n * plugins (Python protocol with initialize/enrich_turn/sync_turn/\n * shutdown). A Python Engram MemoryProvider plugin would be the\n * optimal integration path — see docs/integration/hermes-setup.md.\n */\nexport class HermesAdapter implements EngramAdapter {\n readonly id = \"hermes\";\n\n matches(context: AdapterContext): boolean {\n // Confirmed header from Hermes v0.7.0 API server\n if (headerValue(context.headers, \"x-hermes-session-id\")) return true;\n\n // User-configured client identifier header\n const clientId = headerValue(context.headers, \"x-engram-client-id\");\n if (clientId?.toLowerCase() === \"hermes\") return true;\n\n // MCP clientInfo (for forward compat when Hermes documents its name)\n const clientName = context.clientInfo?.name?.toLowerCase() ?? \"\";\n if (clientName.includes(\"hermes\")) return true;\n\n return false;\n }\n\n resolveIdentity(context: AdapterContext): ResolvedIdentity {\n const sessionId = headerValue(context.headers, \"x-hermes-session-id\");\n\n const principal = headerValue(context.headers, \"x-engram-principal\")\n || \"hermes-agent\";\n\n const namespace = headerValue(context.headers, \"x-engram-namespace\")\n || \"hermes\";\n\n return {\n namespace,\n principal,\n sessionKey: sessionId ?? context.sessionKey,\n adapterId: this.id,\n };\n }\n}\n\n","import type { AdapterContext, EngramAdapter, ResolvedIdentity } from \"./types.js\";\nimport { ClaudeCodeAdapter } from \"./claude-code.js\";\nimport { CodexAdapter } from \"./codex.js\";\nimport { ReplitAdapter } from \"./replit.js\";\nimport { HermesAdapter } from \"./hermes.js\";\n\n/**\n * Adapter registry. Attempts to identify which external system is\n * connecting by checking each registered adapter in order. Falls back\n * to explicit namespace/principal from the request args.\n */\nexport class AdapterRegistry {\n private readonly adapters: EngramAdapter[];\n\n constructor(adapters?: EngramAdapter[]) {\n this.adapters = adapters ?? [\n new HermesAdapter(),\n new ReplitAdapter(),\n new CodexAdapter(),\n new ClaudeCodeAdapter(),\n ];\n }\n\n /**\n * Try each adapter in order. Return the first match, or null if\n * no adapter recognizes the request context.\n */\n resolve(context: AdapterContext): ResolvedIdentity | null {\n for (const adapter of this.adapters) {\n if (adapter.matches(context)) {\n return adapter.resolveIdentity(context);\n }\n }\n return null;\n }\n\n /** List registered adapter IDs */\n list(): string[] {\n return this.adapters.map((a) => a.id);\n }\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/recall-state.ts"],"sourcesContent":["import { appendFile, mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { createHash, randomUUID } from \"node:crypto\";\nimport { log } from \"./logger.js\";\nimport type {\n IdentityInjectionMode,\n RecallPlanMode,\n RecallTierExplain,\n} from \"./types.js\";\n\nexport interface LastRecallBudgetSummary {\n requestedTopK?: number;\n appliedTopK: number;\n recallBudgetChars: number;\n maxMemoryTokens: number;\n qmdFetchLimit?: number;\n qmdHybridFetchLimit?: number;\n finalContextChars?: number;\n truncated?: boolean;\n includedSections?: string[];\n omittedSections?: string[];\n}\n\nexport interface LastRecallSnapshot {\n sessionKey: string;\n recordedAt: string;\n queryHash: string;\n queryLen: number;\n memoryIds: string[];\n namespace?: string;\n traceId?: string;\n plannerMode?: RecallPlanMode;\n requestedMode?: RecallPlanMode;\n source?: string;\n fallbackUsed?: boolean;\n sourcesUsed?: string[];\n budgetsApplied?: LastRecallBudgetSummary;\n latencyMs?: number;\n resultPaths?: string[];\n policyVersion?: string;\n identityInjectionMode?: IdentityInjectionMode | \"none\";\n identityInjectedChars?: number;\n identityInjectionTruncated?: boolean;\n /**\n * Collision-safe write nonce. Random UUID set on every `record()`\n * call so the observation-mode direct-answer hook can detect stale\n * snapshots and avoid annotating a snapshot that a subsequent recall\n * already replaced (issue #518).\n */\n writeNonce?: string;\n /**\n * Optional tier-level explanation of how recall was served\n * (issue #518). Populated by orchestrator call sites that can\n * identify a concrete tier; surfaces expose the block via\n * `engram query --explain`, the `?explain=1` HTTP flag, and the\n * `remnic_recall_explain` MCP tool. Orthogonal to the existing\n * graph-path `recallExplain` operation.\n */\n tierExplain?: RecallTierExplain;\n}\n\nexport interface GraphRecallExpandedEntry {\n path: string;\n score: number;\n namespace: string;\n seed: string;\n hopDepth: number;\n decayedWeight: number;\n graphType: \"entity\" | \"time\" | \"causal\";\n}\n\nexport function clampGraphRecallExpandedEntries(\n entries: unknown,\n maxEntries: number = 64,\n): GraphRecallExpandedEntry[] {\n const limit = Math.max(1, Math.floor(maxEntries));\n if (!Array.isArray(entries)) return [];\n return entries\n .filter((item): item is Record<string, unknown> => !!item && typeof item === \"object\")\n .map((item) => {\n const graphType: \"entity\" | \"time\" | \"causal\" =\n item.graphType === \"entity\" || item.graphType === \"time\" || item.graphType === \"causal\"\n ? item.graphType\n : \"entity\";\n return {\n path: typeof item.path === \"string\" ? item.path : \"\",\n score: typeof item.score === \"number\" && Number.isFinite(item.score) ? item.score : 0,\n namespace: typeof item.namespace === \"string\" ? item.namespace : \"\",\n seed: typeof item.seed === \"string\" ? item.seed : \"\",\n hopDepth:\n typeof item.hopDepth === \"number\" && Number.isFinite(item.hopDepth)\n ? Math.max(0, Math.floor(item.hopDepth))\n : 0,\n decayedWeight:\n typeof item.decayedWeight === \"number\" && Number.isFinite(item.decayedWeight)\n ? Math.max(0, item.decayedWeight)\n : 0,\n graphType,\n };\n })\n .filter((item) => item.path.length > 0 && item.namespace.length > 0)\n .slice(0, limit);\n}\n\ntype LastRecallState = Record<string, LastRecallSnapshot>;\n\n/**\n * Deep-copy a RecallTierExplain block. Used by both the write path\n * (so caller mutation after `record()` cannot tear the persisted\n * snapshot) and the read path (so caller mutation after `get()` /\n * `getMostRecent()` cannot tear the in-memory store).\n *\n * Uses structuredClone so future additions to RecallTierExplain do\n * not silently share references through hand-enumerated fields —\n * matching the pattern used elsewhere in the codebase (e.g.,\n * qmd-recall-cache.ts). The payload is pure JSON-shaped data, so\n * structuredClone is both safe and complete here.\n */\nfunction cloneTierExplain(\n tierExplain: RecallTierExplain | undefined,\n): RecallTierExplain | undefined {\n if (!tierExplain) return undefined;\n return structuredClone(tierExplain);\n}\n\n/**\n * Deep-copy a LastRecallSnapshot so callers that receive it cannot\n * mutate the store's internal state through mutable array/object\n * fields. Same structuredClone rationale as cloneTierExplain above.\n */\nfunction cloneLastRecallSnapshot(\n snapshot: LastRecallSnapshot | null,\n): LastRecallSnapshot | null {\n if (!snapshot) return null;\n return structuredClone(snapshot);\n}\n\nexport interface TierMigrationCycleSummary {\n trigger: \"extraction\" | \"maintenance\" | \"manual\";\n scanned: number;\n migrated: number;\n promoted: number;\n demoted: number;\n limit: number;\n dryRun: boolean;\n skipped?: string;\n errorCount?: number;\n}\n\nexport interface TierMigrationStatusSnapshot {\n updatedAt: string;\n lastCycle: TierMigrationCycleSummary | null;\n totals: {\n cycles: number;\n scanned: number;\n migrated: number;\n promoted: number;\n demoted: number;\n errors: number;\n };\n}\n\nconst DEFAULT_TIER_MIGRATION_STATUS: TierMigrationStatusSnapshot = {\n updatedAt: new Date(0).toISOString(),\n lastCycle: null,\n totals: {\n cycles: 0,\n scanned: 0,\n migrated: 0,\n promoted: 0,\n demoted: 0,\n errors: 0,\n },\n};\n\nexport class LastRecallStore {\n private readonly statePath: string;\n private readonly impressionsPath: string;\n private state: LastRecallState = {};\n\n constructor(memoryDir: string) {\n this.statePath = path.join(memoryDir, \"state\", \"last_recall.json\");\n this.impressionsPath = path.join(memoryDir, \"state\", \"recall_impressions.jsonl\");\n }\n\n async load(): Promise<void> {\n try {\n const raw = await readFile(this.statePath, \"utf-8\");\n const parsed = JSON.parse(raw) as LastRecallState;\n if (parsed && typeof parsed === \"object\") this.state = parsed;\n } catch {\n this.state = {};\n }\n }\n\n get(sessionKey: string): LastRecallSnapshot | null {\n // Defensive copy: callers must not be able to mutate internal state\n // by reaching into array/object fields on the returned snapshot.\n return cloneLastRecallSnapshot(this.state[sessionKey] ?? null);\n }\n\n getMostRecent(): LastRecallSnapshot | null {\n const snapshots = Object.values(this.state);\n if (snapshots.length === 0) return null;\n // Secondary key on sessionKey keeps the sort stable when two\n // snapshots share a recordedAt timestamp (CLAUDE.md rule 19).\n snapshots.sort((a, b) => {\n const byTime = b.recordedAt.localeCompare(a.recordedAt);\n if (byTime !== 0) return byTime;\n return a.sessionKey.localeCompare(b.sessionKey);\n });\n return cloneLastRecallSnapshot(snapshots[0] ?? null);\n }\n\n /**\n * Persist last-recall snapshot and append an impression log entry.\n * Does not store raw query text; uses a stable hash for correlation.\n */\n async record(opts: {\n sessionKey: string;\n query: string;\n memoryIds: string[];\n namespace?: string;\n traceId?: string;\n plannerMode?: RecallPlanMode;\n requestedMode?: RecallPlanMode;\n source?: string;\n fallbackUsed?: boolean;\n sourcesUsed?: string[];\n budgetsApplied?: LastRecallBudgetSummary;\n latencyMs?: number;\n resultPaths?: string[];\n policyVersion?: string;\n appendImpression?: boolean;\n identityInjection?: {\n mode: IdentityInjectionMode | \"none\";\n injectedChars: number;\n truncated: boolean;\n };\n /**\n * Per-tier explain annotation (issue #518). When supplied, the\n * snapshot carries it so downstream surfaces (CLI / HTTP / MCP)\n * can render which retrieval tier served the query.\n */\n tierExplain?: RecallTierExplain;\n }): Promise<void> {\n const now = new Date().toISOString();\n const queryHash = createHash(\"sha256\").update(opts.query).digest(\"hex\");\n\n // Build the snapshot from opts, then deep-copy it via\n // cloneLastRecallSnapshot so caller arrays/objects passed in\n // `opts` cannot retain a live reference to the persisted state\n // and tear it after record() returns.\n const liveSnapshot: LastRecallSnapshot = {\n sessionKey: opts.sessionKey,\n recordedAt: now,\n queryHash,\n writeNonce: randomUUID(),\n queryLen: opts.query.length,\n memoryIds: opts.memoryIds,\n namespace: opts.namespace,\n traceId: opts.traceId,\n plannerMode: opts.plannerMode,\n requestedMode: opts.requestedMode,\n source: opts.source,\n fallbackUsed: opts.fallbackUsed,\n sourcesUsed: opts.sourcesUsed,\n budgetsApplied: opts.budgetsApplied,\n latencyMs: opts.latencyMs,\n resultPaths: opts.resultPaths,\n policyVersion: opts.policyVersion,\n identityInjectionMode: opts.identityInjection?.mode,\n identityInjectedChars: opts.identityInjection?.injectedChars,\n identityInjectionTruncated: opts.identityInjection?.truncated,\n tierExplain: opts.tierExplain,\n };\n // `cloneLastRecallSnapshot` handles `null` but that never applies\n // at this call site — the non-null assertion keeps the type\n // checker honest.\n const snapshot = cloneLastRecallSnapshot(liveSnapshot)!;\n\n this.state[opts.sessionKey] = snapshot;\n\n // Keep the state bounded; the impression log is append-only.\n const keys = Object.keys(this.state);\n if (keys.length > 50) {\n const ordered = keys\n .map((k) => ({ k, at: this.state[k]?.recordedAt ?? \"\" }))\n .sort((a, b) => b.at.localeCompare(a.at));\n for (const doomed of ordered.slice(50)) {\n delete this.state[doomed.k];\n }\n }\n\n try {\n await mkdir(path.dirname(this.statePath), { recursive: true });\n await writeFile(this.statePath, JSON.stringify(this.state, null, 2), \"utf-8\");\n } catch (err) {\n log.debug(`last recall store write failed: ${err}`);\n }\n\n if (opts.appendImpression !== false) {\n try {\n await mkdir(path.dirname(this.impressionsPath), { recursive: true });\n await appendFile(this.impressionsPath, JSON.stringify(snapshot) + \"\\n\", \"utf-8\");\n } catch (err) {\n log.debug(`recall impressions append failed: ${err}`);\n }\n }\n }\n\n /**\n * Attach a RecallTierExplain block to the existing snapshot for a\n * session without rewriting the entire snapshot. Used by the\n * post-recall direct-answer annotation path (issue #518 slice 3c):\n * recallInternal records the snapshot first, then the orchestrator\n * fires the direct-answer tier in observation mode and annotates\n * the stored snapshot with whichever tier served the query.\n *\n * No-op when no snapshot exists for the given session; callers do\n * not need to guard on existence.\n */\n async annotateTierExplain(\n sessionKey: string,\n tierExplain: RecallTierExplain,\n expected?: { writeNonce?: string; traceId?: string; recordedAt?: string },\n ): Promise<void> {\n const current = this.state[sessionKey];\n if (!current) return;\n if (expected) {\n if (\n typeof expected.writeNonce === \"string\" &&\n expected.writeNonce.length > 0\n ) {\n if (current.writeNonce !== expected.writeNonce) return;\n } else {\n const hasExpectedTraceId =\n typeof expected.traceId === \"string\" && expected.traceId.length > 0;\n const traceIdMatches =\n hasExpectedTraceId && current.traceId === expected.traceId;\n const recordedAtMatches =\n expected.recordedAt !== undefined &&\n current.recordedAt === expected.recordedAt;\n if (hasExpectedTraceId) {\n if (!traceIdMatches) return;\n } else if (expected.recordedAt !== undefined && !recordedAtMatches) {\n return;\n }\n }\n }\n this.state[sessionKey] = {\n ...current,\n tierExplain: cloneTierExplain(tierExplain),\n };\n try {\n await mkdir(path.dirname(this.statePath), { recursive: true });\n await writeFile(this.statePath, JSON.stringify(this.state, null, 2), \"utf-8\");\n } catch (err) {\n log.debug(`last recall tier-explain annotate failed: ${err}`);\n }\n }\n}\n\nexport class TierMigrationStatusStore {\n private readonly statePath: string;\n private state: TierMigrationStatusSnapshot = structuredClone(DEFAULT_TIER_MIGRATION_STATUS);\n\n constructor(memoryDir: string) {\n this.statePath = path.join(memoryDir, \"state\", \"tier-migration-status.json\");\n }\n\n async load(): Promise<void> {\n try {\n const raw = await readFile(this.statePath, \"utf-8\");\n const parsed = JSON.parse(raw) as Partial<TierMigrationStatusSnapshot> | null;\n if (!parsed || typeof parsed !== \"object\") {\n this.state = structuredClone(DEFAULT_TIER_MIGRATION_STATUS);\n return;\n }\n const totals = parsed.totals && typeof parsed.totals === \"object\"\n ? parsed.totals\n : DEFAULT_TIER_MIGRATION_STATUS.totals;\n this.state = {\n updatedAt:\n typeof parsed.updatedAt === \"string\" && parsed.updatedAt.length > 0\n ? parsed.updatedAt\n : DEFAULT_TIER_MIGRATION_STATUS.updatedAt,\n lastCycle:\n parsed.lastCycle && typeof parsed.lastCycle === \"object\"\n ? (parsed.lastCycle as TierMigrationCycleSummary)\n : null,\n totals: {\n cycles: typeof totals.cycles === \"number\" && Number.isFinite(totals.cycles) ? totals.cycles : 0,\n scanned: typeof totals.scanned === \"number\" && Number.isFinite(totals.scanned) ? totals.scanned : 0,\n migrated: typeof totals.migrated === \"number\" && Number.isFinite(totals.migrated) ? totals.migrated : 0,\n promoted: typeof totals.promoted === \"number\" && Number.isFinite(totals.promoted) ? totals.promoted : 0,\n demoted: typeof totals.demoted === \"number\" && Number.isFinite(totals.demoted) ? totals.demoted : 0,\n errors: typeof totals.errors === \"number\" && Number.isFinite(totals.errors) ? totals.errors : 0,\n },\n };\n } catch {\n this.state = structuredClone(DEFAULT_TIER_MIGRATION_STATUS);\n }\n }\n\n get(): TierMigrationStatusSnapshot {\n return {\n updatedAt: this.state.updatedAt,\n lastCycle: this.state.lastCycle ? { ...this.state.lastCycle } : null,\n totals: { ...this.state.totals },\n };\n }\n\n async recordCycle(summary: TierMigrationCycleSummary): Promise<void> {\n const now = new Date().toISOString();\n const migratedDelta = summary.dryRun ? 0 : Math.max(0, summary.migrated);\n const promotedDelta = summary.dryRun ? 0 : Math.max(0, summary.promoted);\n const demotedDelta = summary.dryRun ? 0 : Math.max(0, summary.demoted);\n const next: TierMigrationStatusSnapshot = {\n updatedAt: now,\n lastCycle: { ...summary },\n totals: {\n cycles: this.state.totals.cycles + 1,\n scanned: this.state.totals.scanned + Math.max(0, summary.scanned),\n migrated: this.state.totals.migrated + migratedDelta,\n promoted: this.state.totals.promoted + promotedDelta,\n demoted: this.state.totals.demoted + demotedDelta,\n errors: this.state.totals.errors + Math.max(0, summary.errorCount ?? 0),\n },\n };\n this.state = next;\n try {\n await mkdir(path.dirname(this.statePath), { recursive: true });\n await writeFile(this.statePath, JSON.stringify(next, null, 2), \"utf-8\");\n } catch (err) {\n log.debug(`tier migration status write failed: ${err}`);\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/semantic-rule-promotion.ts"],"sourcesContent":["import { StorageManager } from \"./storage.js\";\nimport type { MemoryFile, MemoryLink } from \"./types.js\";\n\nexport interface SemanticRulePromotionCandidate {\n id: string;\n sourceMemoryId: string;\n content: string;\n confidence: number;\n tags: string[];\n memoryKind: \"note\";\n lineage: string[];\n}\n\nexport interface SemanticRulePromotionSkip {\n sourceMemoryId: string;\n reason:\n | \"disabled\"\n | \"source-memory-missing\"\n | \"source-memory-not-episode\"\n | \"no-explicit-rule\"\n | \"duplicate-rule\";\n existingRuleId?: string;\n}\n\nexport interface SemanticRulePromotionReport {\n enabled: boolean;\n dryRun: boolean;\n promoted: SemanticRulePromotionCandidate[];\n skipped: SemanticRulePromotionSkip[];\n}\n\nfunction normalizeRuleWhitespace(value: string): string {\n return value.replace(/\\s+/g, \" \").trim();\n}\n\nfunction stripTrailingClausePunctuation(value: string): string {\n return value.replace(/[,:;]+$/g, \"\").trim();\n}\n\nfunction canonicalizeRuleContent(value: string): string {\n return extractExplicitIfThenRule(value) ?? normalizeRuleWhitespace(value);\n}\n\nfunction canonicalizeRuleKey(value: string): string {\n return canonicalizeRuleContent(value).toLowerCase();\n}\n\nfunction extractExplicitIfThenRule(content: string): string | null {\n const match = content.match(/\\bif\\b([\\s\\S]+?)\\bthen\\b([\\s\\S]+?)(?:[.!?](?:\\s|$)|$)/i);\n if (!match) return null;\n const condition = stripTrailingClausePunctuation(normalizeRuleWhitespace(match[1] ?? \"\"));\n const outcome = stripTrailingClausePunctuation(normalizeRuleWhitespace(match[2] ?? \"\"));\n if (condition.length === 0 || outcome.length === 0) return null;\n return `IF ${condition} THEN ${outcome}.`;\n}\n\nfunction promotionConfidence(memory: MemoryFile): number {\n const base = Number.isFinite(memory.frontmatter.confidence) ? memory.frontmatter.confidence : 0.8;\n return Math.max(0.6, Math.min(0.98, base));\n}\n\nfunction promotionTags(memory: MemoryFile): string[] {\n return Array.from(new Set([...(memory.frontmatter.tags ?? []), \"semantic-rule\", \"promoted-rule\"]));\n}\n\nfunction buildSupportLinks(sourceMemoryId: string, confidence: number): MemoryLink[] {\n return [\n {\n targetId: sourceMemoryId,\n linkType: \"supports\",\n strength: confidence,\n reason: \"Promoted from verified episodic memory\",\n },\n ];\n}\n\nexport async function promoteSemanticRuleFromMemory(options: {\n memoryDir: string;\n enabled: boolean;\n sourceMemoryId: string;\n dryRun?: boolean;\n}): Promise<SemanticRulePromotionReport> {\n const report: SemanticRulePromotionReport = {\n enabled: options.enabled,\n dryRun: options.dryRun === true,\n promoted: [],\n skipped: [],\n };\n if (!options.enabled) {\n report.skipped.push({\n sourceMemoryId: options.sourceMemoryId,\n reason: \"disabled\",\n });\n return report;\n }\n\n const storage = new StorageManager(options.memoryDir);\n const sourceMemory = await storage.getMemoryById(options.sourceMemoryId);\n if (!sourceMemory) {\n report.skipped.push({\n sourceMemoryId: options.sourceMemoryId,\n reason: \"source-memory-missing\",\n });\n return report;\n }\n if (sourceMemory.frontmatter.status === \"archived\" || sourceMemory.frontmatter.memoryKind !== \"episode\") {\n report.skipped.push({\n sourceMemoryId: options.sourceMemoryId,\n reason: \"source-memory-not-episode\",\n });\n return report;\n }\n\n const content = extractExplicitIfThenRule(sourceMemory.content);\n if (!content) {\n report.skipped.push({\n sourceMemoryId: options.sourceMemoryId,\n reason: \"no-explicit-rule\",\n });\n return report;\n }\n\n const ruleKey = canonicalizeRuleKey(content);\n const existingRule = (await storage.readAllMemories()).find(\n (memory) =>\n memory.frontmatter.category === \"rule\" &&\n memory.frontmatter.status !== \"archived\" &&\n canonicalizeRuleKey(memory.content) === ruleKey,\n );\n if (existingRule) {\n report.skipped.push({\n sourceMemoryId: options.sourceMemoryId,\n reason: \"duplicate-rule\",\n existingRuleId: existingRule.frontmatter.id,\n });\n return report;\n }\n\n const confidence = promotionConfidence(sourceMemory);\n const candidateBase = {\n sourceMemoryId: options.sourceMemoryId,\n content,\n confidence,\n tags: promotionTags(sourceMemory),\n memoryKind: \"note\" as const,\n lineage: [options.sourceMemoryId],\n };\n\n if (options.dryRun === true) {\n report.promoted.push({\n id: `dry-run:${options.sourceMemoryId}`,\n ...candidateBase,\n });\n return report;\n }\n\n const id = await storage.writeMemory(\"rule\", content, {\n confidence,\n tags: candidateBase.tags,\n source: \"semantic-rule-promotion\",\n lineage: candidateBase.lineage,\n sourceMemoryId: options.sourceMemoryId,\n memoryKind: \"note\",\n links: buildSupportLinks(options.sourceMemoryId, confidence),\n });\n report.promoted.push({\n id,\n ...candidateBase,\n });\n return report;\n}\n"],"mappings":";;;;;AA+BA,SAAS,wBAAwB,OAAuB;AACtD,SAAO,MAAM,QAAQ,QAAQ,GAAG,EAAE,KAAK;AACzC;AAEA,SAAS,+BAA+B,OAAuB;AAC7D,SAAO,MAAM,QAAQ,YAAY,EAAE,EAAE,KAAK;AAC5C;AAEA,SAAS,wBAAwB,OAAuB;AACtD,SAAO,0BAA0B,KAAK,KAAK,wBAAwB,KAAK;AAC1E;AAEA,SAAS,oBAAoB,OAAuB;AAClD,SAAO,wBAAwB,KAAK,EAAE,YAAY;AACpD;AAEA,SAAS,0BAA0B,SAAgC;AACjE,QAAM,QAAQ,QAAQ,MAAM,wDAAwD;AACpF,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,YAAY,+BAA+B,wBAAwB,MAAM,CAAC,KAAK,EAAE,CAAC;AACxF,QAAM,UAAU,+BAA+B,wBAAwB,MAAM,CAAC,KAAK,EAAE,CAAC;AACtF,MAAI,UAAU,WAAW,KAAK,QAAQ,WAAW,EAAG,QAAO;AAC3D,SAAO,MAAM,SAAS,SAAS,OAAO;AACxC;AAEA,SAAS,oBAAoB,QAA4B;AACvD,QAAM,OAAO,OAAO,SAAS,OAAO,YAAY,UAAU,IAAI,OAAO,YAAY,aAAa;AAC9F,SAAO,KAAK,IAAI,KAAK,KAAK,IAAI,MAAM,IAAI,CAAC;AAC3C;AAEA,SAAS,cAAc,QAA8B;AACnD,SAAO,MAAM,KAAK,oBAAI,IAAI,CAAC,GAAI,OAAO,YAAY,QAAQ,CAAC,GAAI,iBAAiB,eAAe,CAAC,CAAC;AACnG;AAEA,SAAS,kBAAkB,gBAAwB,YAAkC;AACnF,SAAO;AAAA,IACL;AAAA,MACE,UAAU;AAAA,MACV,UAAU;AAAA,MACV,UAAU;AAAA,MACV,QAAQ;AAAA,IACV;AAAA,EACF;AACF;AAEA,eAAsB,8BAA8B,SAKX;AACvC,QAAM,SAAsC;AAAA,IAC1C,SAAS,QAAQ;AAAA,IACjB,QAAQ,QAAQ,WAAW;AAAA,IAC3B,UAAU,CAAC;AAAA,IACX,SAAS,CAAC;AAAA,EACZ;AACA,MAAI,CAAC,QAAQ,SAAS;AACpB,WAAO,QAAQ,KAAK;AAAA,MAClB,gBAAgB,QAAQ;AAAA,MACxB,QAAQ;AAAA,IACV,CAAC;AACD,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,IAAI,eAAe,QAAQ,SAAS;AACpD,QAAM,eAAe,MAAM,QAAQ,cAAc,QAAQ,cAAc;AACvE,MAAI,CAAC,cAAc;AACjB,WAAO,QAAQ,KAAK;AAAA,MAClB,gBAAgB,QAAQ;AAAA,MACxB,QAAQ;AAAA,IACV,CAAC;AACD,WAAO;AAAA,EACT;AACA,MAAI,aAAa,YAAY,WAAW,cAAc,aAAa,YAAY,eAAe,WAAW;AACvG,WAAO,QAAQ,KAAK;AAAA,MAClB,gBAAgB,QAAQ;AAAA,MACxB,QAAQ;AAAA,IACV,CAAC;AACD,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,0BAA0B,aAAa,OAAO;AAC9D,MAAI,CAAC,SAAS;AACZ,WAAO,QAAQ,KAAK;AAAA,MAClB,gBAAgB,QAAQ;AAAA,MACxB,QAAQ;AAAA,IACV,CAAC;AACD,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,oBAAoB,OAAO;AAC3C,QAAM,gBAAgB,MAAM,QAAQ,gBAAgB,GAAG;AAAA,IACrD,CAAC,WACC,OAAO,YAAY,aAAa,UAChC,OAAO,YAAY,WAAW,cAC9B,oBAAoB,OAAO,OAAO,MAAM;AAAA,EAC5C;AACA,MAAI,cAAc;AAChB,WAAO,QAAQ,KAAK;AAAA,MAClB,gBAAgB,QAAQ;AAAA,MACxB,QAAQ;AAAA,MACR,gBAAgB,aAAa,YAAY;AAAA,IAC3C,CAAC;AACD,WAAO;AAAA,EACT;AAEA,QAAM,aAAa,oBAAoB,YAAY;AACnD,QAAM,gBAAgB;AAAA,IACpB,gBAAgB,QAAQ;AAAA,IACxB;AAAA,IACA;AAAA,IACA,MAAM,cAAc,YAAY;AAAA,IAChC,YAAY;AAAA,IACZ,SAAS,CAAC,QAAQ,cAAc;AAAA,EAClC;AAEA,MAAI,QAAQ,WAAW,MAAM;AAC3B,WAAO,SAAS,KAAK;AAAA,MACnB,IAAI,WAAW,QAAQ,cAAc;AAAA,MACrC,GAAG;AAAA,IACL,CAAC;AACD,WAAO;AAAA,EACT;AAEA,QAAM,KAAK,MAAM,QAAQ,YAAY,QAAQ,SAAS;AAAA,IACpD;AAAA,IACA,MAAM,cAAc;AAAA,IACpB,QAAQ;AAAA,IACR,SAAS,cAAc;AAAA,IACvB,gBAAgB,QAAQ;AAAA,IACxB,YAAY;AAAA,IACZ,OAAO,kBAAkB,QAAQ,gBAAgB,UAAU;AAAA,EAC7D,CAAC;AACD,SAAO,SAAS,KAAK;AAAA,IACnB;AAAA,IACA,GAAG;AAAA,EACL,CAAC;AACD,SAAO;AACT;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/access-schema.ts"],"sourcesContent":["// Request/response schema validation for the Remnic HTTP API.\n// Uses zod for runtime validation — returns structured 400 errors with\n// field-level detail so consumers get clear feedback on malformed requests.\n\nimport { z } from \"zod\";\n\n// ---------------------------------------------------------------------------\n// Error formatting\n// ---------------------------------------------------------------------------\n\nexport interface SchemaValidationError {\n error: string;\n code: \"validation_error\";\n details: Array<{ field: string; message: string }>;\n}\n\nexport function formatZodError(error: z.ZodError): SchemaValidationError {\n return {\n error: \"request validation failed\",\n code: \"validation_error\",\n details: error.issues.map((issue) => ({\n field: issue.path.join(\".\") || \"(root)\",\n message: issue.message,\n })),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Shared fields\n// ---------------------------------------------------------------------------\n\nconst namespaceSchema = z.string().trim().max(256).optional();\nconst sessionKeySchema = z.string().trim().min(1).max(512).optional();\nconst idempotencyKeySchema = z.string().trim().min(1).max(256).optional();\nconst dryRunSchema = z.boolean().optional();\nconst schemaVersionSchema = z.number().int().optional();\n\n// ---------------------------------------------------------------------------\n// Recall\n// ---------------------------------------------------------------------------\n\n/**\n * Coding-agent context (issue #569). Optional payload that connectors may\n * ship with a recall request so the project/branch namespace overlay\n * applies to that recall. All fields are validated per CLAUDE.md #51 —\n * empty-string projectId / rootPath is rejected, not silently accepted.\n */\nexport const codingContextSchema = z\n .object({\n projectId: z.string().trim().min(1, \"codingContext.projectId is required\").max(128),\n branch: z.string().trim().max(256).nullable(),\n rootPath: z.string().trim().min(1, \"codingContext.rootPath is required\").max(1024),\n defaultBranch: z.string().trim().max(256).nullable(),\n })\n .nullable();\n\nexport const recallRequestSchema = z.object({\n query: z.string().min(1, \"query is required\"),\n sessionKey: sessionKeySchema,\n namespace: namespaceSchema,\n topK: z.number().int().min(0).max(200).optional(),\n mode: z.enum([\"auto\", \"no_recall\", \"minimal\", \"full\", \"graph_mode\"]).optional(),\n includeDebug: z.boolean().optional(),\n codingContext: codingContextSchema.optional(),\n});\n\nexport const recallExplainRequestSchema = z.object({\n sessionKey: sessionKeySchema,\n namespace: namespaceSchema,\n});\n\n/**\n * Standalone \"set coding context\" request. Used by the HTTP endpoint\n * `POST /engram/v1/coding-context` and the MCP `remnic.set_coding_context`\n * tool (PR 7). `codingContext: null` clears the attached context.\n */\nexport const setCodingContextRequestSchema = z.object({\n sessionKey: z.string().trim().min(1, \"sessionKey is required\").max(512),\n codingContext: codingContextSchema,\n});\n\n// ---------------------------------------------------------------------------\n// Observe\n// ---------------------------------------------------------------------------\n\nconst messageSchema = z.object({\n role: z.enum([\"user\", \"assistant\"]),\n content: z.string().min(1, \"message content must be non-empty\"),\n});\n\nexport const observeRequestSchema = z.object({\n sessionKey: z.string().trim().min(1, \"sessionKey is required\").max(512),\n messages: z.array(messageSchema).min(1, \"messages must be a non-empty array\"),\n namespace: namespaceSchema,\n skipExtraction: z.boolean().optional(),\n});\n\n// ---------------------------------------------------------------------------\n// Memory store / suggestion submit\n// ---------------------------------------------------------------------------\n\nconst writeContentSchema = z.string().min(1, \"content is required\").max(50000);\nconst categorySchema = z\n .enum([\n \"fact\", \"preference\", \"correction\", \"entity\", \"decision\",\n \"relationship\", \"principle\", \"commitment\", \"moment\", \"skill\", \"rule\", \"procedure\",\n \"reasoning_trace\",\n ])\n .optional();\nconst confidenceSchema = z.number().min(0).max(1).optional();\nconst tagsSchema = z.array(z.string().max(256)).max(50).optional();\nconst entityRefSchema = z.string().trim().max(512).optional();\nconst ttlSchema = z.string().trim().max(128).optional();\nconst sourceReasonSchema = z.string().trim().max(2000).optional();\n\nexport const memoryStoreRequestSchema = z.object({\n schemaVersion: schemaVersionSchema,\n idempotencyKey: idempotencyKeySchema,\n dryRun: dryRunSchema,\n sessionKey: sessionKeySchema,\n content: writeContentSchema,\n category: categorySchema,\n confidence: confidenceSchema,\n namespace: namespaceSchema,\n tags: tagsSchema,\n entityRef: entityRefSchema,\n ttl: ttlSchema,\n sourceReason: sourceReasonSchema,\n});\n\nexport const suggestionSubmitRequestSchema = memoryStoreRequestSchema;\n\n// ---------------------------------------------------------------------------\n// Review disposition\n// ---------------------------------------------------------------------------\n\nexport const reviewDispositionRequestSchema = z.object({\n memoryId: z.string().trim().min(1, \"memoryId is required\"),\n status: z.enum([\n \"active\", \"pending_review\", \"quarantined\", \"rejected\", \"superseded\", \"archived\",\n ]),\n reasonCode: z.string().trim().min(1, \"reasonCode is required\"),\n namespace: namespaceSchema,\n});\n\n// ---------------------------------------------------------------------------\n// Trust-zone promote\n// ---------------------------------------------------------------------------\n\nexport const trustZonePromoteRequestSchema = z.object({\n recordId: z.string().trim().min(1, \"recordId is required\"),\n targetZone: z.enum([\"working\", \"trusted\"], {\n errorMap: () => ({ message: \"targetZone must be 'working' or 'trusted'\" }),\n }),\n promotionReason: z.string().trim().min(1, \"promotionReason is required\"),\n recordedAt: z.string().trim().optional(),\n summary: z.string().trim().max(5000).optional(),\n dryRun: dryRunSchema,\n namespace: namespaceSchema,\n});\n\n// ---------------------------------------------------------------------------\n// Trust-zone demo-seed\n// ---------------------------------------------------------------------------\n\nexport const trustZoneDemoSeedRequestSchema = z.object({\n scenario: z.string().trim().max(256).optional(),\n recordedAt: z.string().trim().optional(),\n dryRun: dryRunSchema,\n namespace: namespaceSchema,\n});\n\n// ---------------------------------------------------------------------------\n// LCM search\n// ---------------------------------------------------------------------------\n\nexport const lcmSearchRequestSchema = z.object({\n query: z.string().min(1, \"query is required\"),\n sessionKey: sessionKeySchema,\n namespace: namespaceSchema,\n limit: z.number().int().min(1).max(100).optional(),\n});\n\n// ---------------------------------------------------------------------------\n// Day summary\n// ---------------------------------------------------------------------------\n\nexport const daySummaryRequestSchema = z.object({\n memories: z.string().max(100000).optional(),\n sessionKey: sessionKeySchema,\n namespace: namespaceSchema,\n});\n\n// ---------------------------------------------------------------------------\n// Inferred types\n// ---------------------------------------------------------------------------\n\nexport type RecallRequest = z.infer<typeof recallRequestSchema>;\nexport type RecallExplainRequest = z.infer<typeof recallExplainRequestSchema>;\nexport type SetCodingContextRequest = z.infer<typeof setCodingContextRequestSchema>;\nexport type ObserveRequest = z.infer<typeof observeRequestSchema>;\nexport type MemoryStoreRequest = z.infer<typeof memoryStoreRequestSchema>;\nexport type SuggestionSubmitRequest = z.infer<typeof suggestionSubmitRequestSchema>;\nexport type ReviewDispositionRequest = z.infer<typeof reviewDispositionRequestSchema>;\nexport type TrustZonePromoteRequest = z.infer<typeof trustZonePromoteRequestSchema>;\nexport type TrustZoneDemoSeedRequest = z.infer<typeof trustZoneDemoSeedRequestSchema>;\nexport type LcmSearchRequest = z.infer<typeof lcmSearchRequestSchema>;\nexport type DaySummaryRequest = z.infer<typeof daySummaryRequestSchema>;\n\n// ---------------------------------------------------------------------------\n// Validation helper\n// ---------------------------------------------------------------------------\n\nexport type SchemaName =\n | \"recall\"\n | \"recallExplain\"\n | \"setCodingContext\"\n | \"observe\"\n | \"memoryStore\"\n | \"suggestionSubmit\"\n | \"reviewDisposition\"\n | \"trustZonePromote\"\n | \"trustZoneDemoSeed\"\n | \"lcmSearch\"\n | \"daySummary\";\n\nexport type SchemaTypeFor<N extends SchemaName> =\n N extends \"recall\" ? RecallRequest\n : N extends \"recallExplain\" ? RecallExplainRequest\n : N extends \"setCodingContext\" ? SetCodingContextRequest\n : N extends \"observe\" ? ObserveRequest\n : N extends \"memoryStore\" ? MemoryStoreRequest\n : N extends \"suggestionSubmit\" ? SuggestionSubmitRequest\n : N extends \"reviewDisposition\" ? ReviewDispositionRequest\n : N extends \"trustZonePromote\" ? TrustZonePromoteRequest\n : N extends \"trustZoneDemoSeed\" ? TrustZoneDemoSeedRequest\n : N extends \"lcmSearch\" ? LcmSearchRequest\n : N extends \"daySummary\" ? DaySummaryRequest\n : never;\n\nconst schemas: Record<SchemaName, z.ZodTypeAny> = {\n recall: recallRequestSchema,\n recallExplain: recallExplainRequestSchema,\n setCodingContext: setCodingContextRequestSchema,\n observe: observeRequestSchema,\n memoryStore: memoryStoreRequestSchema,\n suggestionSubmit: suggestionSubmitRequestSchema,\n reviewDisposition: reviewDispositionRequestSchema,\n trustZonePromote: trustZonePromoteRequestSchema,\n trustZoneDemoSeed: trustZoneDemoSeedRequestSchema,\n lcmSearch: lcmSearchRequestSchema,\n daySummary: daySummaryRequestSchema,\n};\n\n/**\n * Validate a request body against the named schema.\n * Returns `{ success: true, data }` on pass or\n * `{ success: false, error }` on failure with field-level detail.\n */\nexport function validateRequest<T = unknown>(\n schemaName: SchemaName,\n body: unknown,\n): { success: true; data: T } | { success: false; error: SchemaValidationError } {\n const schema = schemas[schemaName];\n if (!schema) {\n return {\n success: false,\n error: {\n error: `unknown schema: ${schemaName}`,\n code: \"validation_error\",\n details: [],\n },\n };\n }\n const result = schema.safeParse(body);\n if (result.success) {\n return { success: true, data: result.data as T };\n }\n return { success: false, error: formatZodError(result.error) };\n}\n"],"mappings":"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","names":[]}
@@ -1,26 +0,0 @@
1
- // src/consolidation-operator.ts
2
- var CONSOLIDATION_OPERATORS = [
3
- "split",
4
- "merge",
5
- "update"
6
- ];
7
- var DERIVED_FROM_ENTRY_RE = /^(.+):(\d+)$/;
8
- function isValidDerivedFromEntry(entry) {
9
- if (typeof entry !== "string") return false;
10
- const match = entry.match(DERIVED_FROM_ENTRY_RE);
11
- if (!match) return false;
12
- const pathPart = match[1];
13
- if (pathPart.length === 0 || pathPart.trim().length === 0) return false;
14
- const versionNum = Number(match[2]);
15
- return Number.isInteger(versionNum) && versionNum >= 0;
16
- }
17
- function isConsolidationOperator(value) {
18
- return typeof value === "string" && CONSOLIDATION_OPERATORS.includes(value);
19
- }
20
-
21
- export {
22
- CONSOLIDATION_OPERATORS,
23
- isValidDerivedFromEntry,
24
- isConsolidationOperator
25
- };
26
- //# sourceMappingURL=chunk-X6GF3FX2.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/consolidation-operator.ts"],"sourcesContent":["/**\n * consolidation-operator.ts — Standalone operator vocabulary + validators\n * for the consolidation subsystem (issue #561, All-Mem paper\n * arxiv:2603.19595).\n *\n * This module is intentionally dependency-free so storage, the `remnic\n * doctor` check (PR 4), and the undo CLI (PR 5) can import the validators\n * without dragging in the full consolidation engine — which in turn pulls\n * in the Codex materialize runner and creates a `storage → consolidation\n * → codex-materialize-runner → storage` import cycle.\n *\n * The `semantic-consolidation.ts` module re-exports these symbols so\n * existing import paths continue to work.\n */\n\n/**\n * Operator algebra for non-destructive consolidation.\n *\n * - `split` — one source memory is rewritten as multiple smaller memories.\n * - `merge` — multiple source memories are collapsed into one canonical\n * memory.\n * - `update` — a newer value supersedes an older value within the same\n * logical fact.\n */\nexport type ConsolidationOperator = \"split\" | \"merge\" | \"update\";\n\n/**\n * Allowed values for the `derived_via` frontmatter field. Used by storage\n * validation to reject unknown operator values on write.\n */\nexport const CONSOLIDATION_OPERATORS: readonly ConsolidationOperator[] = [\n \"split\",\n \"merge\",\n \"update\",\n] as const;\n\n/**\n * Regular expression for validating a single `derived_from` entry.\n *\n * Format: `<non-empty memory path>:<integer version >= 0>`. Matches the\n * `path:versionNumber` convention used by `page-versioning.ts` snapshots\n * (e.g. `\"facts/preferences.md:3\"`). The path portion is greedy-last so\n * paths that themselves contain a colon remain parseable — only the final\n * `:<digits>` is consumed as the version.\n */\nconst DERIVED_FROM_ENTRY_RE = /^(.+):(\\d+)$/;\n\n/**\n * Validate a `derived_from` entry string. Returns `true` if the entry\n * parses as `<non-empty path>:<integer >= 0>`. Kept pure so storage and\n * future CLI/doctor paths can share the same validator.\n */\nexport function isValidDerivedFromEntry(entry: unknown): entry is string {\n if (typeof entry !== \"string\") return false;\n const match = entry.match(DERIVED_FROM_ENTRY_RE);\n if (!match) return false;\n const pathPart = match[1];\n if (pathPart.length === 0 || pathPart.trim().length === 0) return false;\n const versionNum = Number(match[2]);\n return Number.isInteger(versionNum) && versionNum >= 0;\n}\n\n/**\n * Type guard for `ConsolidationOperator`.\n */\nexport function isConsolidationOperator(value: unknown): value is ConsolidationOperator {\n return (\n typeof value === \"string\" &&\n (CONSOLIDATION_OPERATORS as readonly string[]).includes(value)\n );\n}\n"],"mappings":";AA8BO,IAAM,0BAA4D;AAAA,EACvE;AAAA,EACA;AAAA,EACA;AACF;AAWA,IAAM,wBAAwB;AAOvB,SAAS,wBAAwB,OAAiC;AACvE,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,QAAM,QAAQ,MAAM,MAAM,qBAAqB;AAC/C,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,WAAW,MAAM,CAAC;AACxB,MAAI,SAAS,WAAW,KAAK,SAAS,KAAK,EAAE,WAAW,EAAG,QAAO;AAClE,QAAM,aAAa,OAAO,MAAM,CAAC,CAAC;AAClC,SAAO,OAAO,UAAU,UAAU,KAAK,cAAc;AACvD;AAKO,SAAS,wBAAwB,OAAgD;AACtF,SACE,OAAO,UAAU,YAChB,wBAA8C,SAAS,KAAK;AAEjE;","names":[]}