@remnic/core 9.49.0 → 9.50.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (606) hide show
  1. package/dist/abstraction-nodes.d.ts +12 -1
  2. package/dist/abstraction-nodes.js +9 -2
  3. package/dist/access-admin-ops-surface.d.ts +10 -10
  4. package/dist/access-admin-ops-surface.js +48 -48
  5. package/dist/access-authorization-probe.d.ts +10 -10
  6. package/dist/access-authorization-probe.js +49 -49
  7. package/dist/access-boundary.d.ts +10 -10
  8. package/dist/access-boundary.js +48 -48
  9. package/dist/access-cli.js +132 -127
  10. package/dist/access-cli.js.map +1 -1
  11. package/dist/access-coding-context-resolution.d.ts +1 -1
  12. package/dist/access-extraction-force-flush.d.ts +10 -10
  13. package/dist/access-extraction-force-flush.js +48 -48
  14. package/dist/access-health-types.d.ts +1 -1
  15. package/dist/access-http-lcm-compaction.d.ts +10 -10
  16. package/dist/access-http-lifecycle-flush.d.ts +10 -10
  17. package/dist/access-http-offline-stream.d.ts +10 -10
  18. package/dist/access-http-query.js +48 -48
  19. package/dist/access-http.d.ts +10 -10
  20. package/dist/access-http.js +60 -60
  21. package/dist/access-identity-continuity-surface.d.ts +8 -8
  22. package/dist/access-identity-continuity-surface.js +48 -48
  23. package/dist/access-lcm-surface.d.ts +10 -10
  24. package/dist/access-lcm-surface.js +48 -48
  25. package/dist/access-mcp.d.ts +10 -10
  26. package/dist/access-mcp.js +55 -55
  27. package/dist/access-memory-search-fanout.d.ts +2 -2
  28. package/dist/{access-namespace-preflight--H6HwN85.d.ts → access-namespace-preflight-DuDU301-.d.ts} +1 -1
  29. package/dist/access-namespace-preflight.d.ts +3 -3
  30. package/dist/access-namespace-preflight.js +48 -48
  31. package/dist/access-observe-write-surface.d.ts +10 -10
  32. package/dist/access-observe-write-surface.js +48 -48
  33. package/dist/access-offline-manifest.d.ts +8 -8
  34. package/dist/access-offline-manifest.js +3 -3
  35. package/dist/access-operations-batch.js +51 -51
  36. package/dist/access-operations.d.ts +13 -13
  37. package/dist/access-operations.js +54 -54
  38. package/dist/access-recall-concurrency.d.ts +10 -10
  39. package/dist/access-recall-concurrency.js +48 -48
  40. package/dist/access-recall-response.d.ts +10 -10
  41. package/dist/access-recall-response.js +48 -48
  42. package/dist/access-recall-surface.d.ts +10 -10
  43. package/dist/access-recall-surface.js +48 -48
  44. package/dist/access-schema.d.ts +105 -105
  45. package/dist/access-schema.js +4 -4
  46. package/dist/{access-service-DvXOzCrM.d.ts → access-service--_3T_v23.d.ts} +7 -7
  47. package/dist/access-service-helpers.d.ts +10 -10
  48. package/dist/access-service.d.ts +10 -10
  49. package/dist/access-service.js +48 -48
  50. package/dist/access-surface-catalog.d.ts +10 -10
  51. package/dist/access-wearables-meetings-surface.d.ts +3 -3
  52. package/dist/action-confidence.d.ts +1 -1
  53. package/dist/active-memory-bridge.d.ts +1 -1
  54. package/dist/active-recall.d.ts +1 -1
  55. package/dist/active-recall.js +3 -2
  56. package/dist/active-recall.js.map +1 -1
  57. package/dist/adapters/index.js +4 -4
  58. package/dist/adapters/registry.js +2 -2
  59. package/dist/ambient-provenance.d.ts +1 -1
  60. package/dist/artifact-search.d.ts +1 -1
  61. package/dist/{auto-sync-7O6RP2RT.js → auto-sync-QFQGOEO2.js} +4 -4
  62. package/dist/behavior-learner.d.ts +1 -1
  63. package/dist/behavior-signals.d.ts +1 -1
  64. package/dist/bootstrap.d.ts +8 -8
  65. package/dist/briefing.d.ts +2 -2
  66. package/dist/briefing.js +12 -12
  67. package/dist/buffer-surprise-report.d.ts +1 -1
  68. package/dist/buffer-turn-helpers.d.ts +1 -1
  69. package/dist/buffer.d.ts +2 -2
  70. package/dist/buffer.js +4 -4
  71. package/dist/bulk-import/index.d.ts +3 -3
  72. package/dist/calibration.d.ts +1 -1
  73. package/dist/calibration.js +1 -1
  74. package/dist/capabilities.d.ts +1 -1
  75. package/dist/{capsule-crypto-YO5QJ6L3.js → capsule-crypto-7FJQINUR.js} +2 -2
  76. package/dist/{capsule-merge-6GFHWECG.js → capsule-merge-KXTRZ23Z.js} +4 -4
  77. package/dist/{catalog-Iwbk9h5E.d.ts → catalog-DjUmUIal.d.ts} +1 -1
  78. package/dist/causal-behavior.d.ts +1 -1
  79. package/dist/causal-behavior.js +3 -3
  80. package/dist/causal-chain.js +3 -3
  81. package/dist/causal-consolidation.d.ts +1 -1
  82. package/dist/causal-consolidation.js +16 -16
  83. package/dist/causal-retrieval.js +3 -3
  84. package/dist/causal-trajectory-graph.d.ts +1 -1
  85. package/dist/causal-trajectory.d.ts +51 -2
  86. package/dist/causal-trajectory.js +8 -2
  87. package/dist/{chunk-EY64JLOM.js → chunk-24BKGKGO.js} +30 -19
  88. package/dist/chunk-24BKGKGO.js.map +1 -0
  89. package/dist/{chunk-ICP53SKG.js → chunk-2HIJHXB3.js} +2 -2
  90. package/dist/{chunk-BXLOS5AJ.js → chunk-2NLLXCJG.js} +2 -2
  91. package/dist/{chunk-LZGCJSQR.js → chunk-3LD4N2TF.js} +151 -37
  92. package/dist/chunk-3LD4N2TF.js.map +1 -0
  93. package/dist/{chunk-5JRC6BYS.js → chunk-47J4EDGR.js} +11 -11
  94. package/dist/{chunk-2VHLLPTX.js → chunk-4EABKPZS.js} +4 -4
  95. package/dist/{chunk-RJV6Q2FT.js → chunk-4JWJMRPJ.js} +2 -2
  96. package/dist/{chunk-MXPB6PJQ.js → chunk-4S3ECH3U.js} +2 -2
  97. package/dist/{chunk-CGASUJVP.js → chunk-5V6IXHPI.js} +4 -4
  98. package/dist/{chunk-R5IGA2NH.js → chunk-5XCN4XBU.js} +4 -4
  99. package/dist/{chunk-2RPJ4NEE.js → chunk-64BHFFKZ.js} +2 -2
  100. package/dist/{chunk-FQC3DHH2.js → chunk-66SE3BNH.js} +2 -2
  101. package/dist/{chunk-TERNBNJB.js → chunk-6FC3IZ26.js} +2 -2
  102. package/dist/{chunk-K7VKAHFE.js → chunk-6XGEBQ3R.js} +4 -4
  103. package/dist/{chunk-JFLOOTXU.js → chunk-7BLWBSRL.js} +3 -3
  104. package/dist/{chunk-ABR2HEJO.js → chunk-7NDM2PNK.js} +3 -3
  105. package/dist/{chunk-JXZ7NLYH.js → chunk-7VWZ4LRW.js} +2 -2
  106. package/dist/{chunk-RN53QBM4.js → chunk-A4QMKFFO.js} +5 -1
  107. package/dist/chunk-A4QMKFFO.js.map +1 -0
  108. package/dist/chunk-ACPCA4NO.js +321 -0
  109. package/dist/chunk-ACPCA4NO.js.map +1 -0
  110. package/dist/chunk-AMTEYNYK.js +72 -0
  111. package/dist/chunk-AMTEYNYK.js.map +1 -0
  112. package/dist/{chunk-R6YJI3HE.js → chunk-AW4QUFQF.js} +1 -1
  113. package/dist/{chunk-P65YJEEL.js → chunk-AXFWMRKI.js} +2 -2
  114. package/dist/{chunk-WG5HSQ4P.js → chunk-BAKXNQ3C.js} +2 -2
  115. package/dist/{chunk-NM2WP3B7.js → chunk-BJYET5TX.js} +2 -2
  116. package/dist/{chunk-HLKPRWF4.js → chunk-DATDLJAO.js} +6 -6
  117. package/dist/chunk-DJUKBGAD.js +260 -0
  118. package/dist/chunk-DJUKBGAD.js.map +1 -0
  119. package/dist/{chunk-DX3XRGLH.js → chunk-DQTCGVFK.js} +2 -2
  120. package/dist/{chunk-IPBNC77A.js → chunk-E633OXMH.js} +11 -11
  121. package/dist/{chunk-J7T4MX7P.js → chunk-EEAMSNSG.js} +12 -1
  122. package/dist/chunk-EEAMSNSG.js.map +1 -0
  123. package/dist/{chunk-Z5UC3OKB.js → chunk-ELQCS47S.js} +7 -7
  124. package/dist/{chunk-FMXJ555A.js → chunk-EURCX6PS.js} +2 -2
  125. package/dist/{chunk-MZZR3J6M.js → chunk-FV7YQTN3.js} +2 -2
  126. package/dist/chunk-G73MCJKL.js +20 -0
  127. package/dist/chunk-G73MCJKL.js.map +1 -0
  128. package/dist/{chunk-3R6D33UF.js → chunk-GGBSF2X7.js} +2 -2
  129. package/dist/{chunk-SYUBB3WM.js → chunk-GKEYXXKX.js} +2 -2
  130. package/dist/{chunk-5AGR7SAI.js → chunk-GSEPRIZC.js} +3 -3
  131. package/dist/{chunk-UTVZKHJK.js → chunk-GUKBW4HL.js} +2 -2
  132. package/dist/chunk-GXSOUIA4.js +293 -0
  133. package/dist/chunk-GXSOUIA4.js.map +1 -0
  134. package/dist/{chunk-2F6NP3NT.js → chunk-HDQUQBPW.js} +2 -2
  135. package/dist/{chunk-6HMYUWXR.js → chunk-HTP6XRUI.js} +2 -2
  136. package/dist/{chunk-UYUYZ4WY.js → chunk-IARXXZU4.js} +2 -2
  137. package/dist/{chunk-MNB5RMAY.js → chunk-IIFFC3RL.js} +2 -2
  138. package/dist/{chunk-VDX2J7OX.js → chunk-IPLYGWQF.js} +6 -6
  139. package/dist/{chunk-NZBZ7IS2.js → chunk-JDCQK3C5.js} +2 -2
  140. package/dist/{chunk-C3KVFJH5.js → chunk-JI62YGPI.js} +2 -2
  141. package/dist/{chunk-LULR4IUW.js → chunk-KATEWTQJ.js} +2 -2
  142. package/dist/{chunk-BMCHFWGX.js → chunk-KMWYZTIE.js} +2 -2
  143. package/dist/{chunk-JGSKJHF7.js → chunk-KQS72GCR.js} +2 -2
  144. package/dist/{chunk-3S63QIFQ.js → chunk-LAQ33B5D.js} +1 -1
  145. package/dist/chunk-LAQ33B5D.js.map +1 -0
  146. package/dist/chunk-LNTUXKBT.js +224 -0
  147. package/dist/chunk-LNTUXKBT.js.map +1 -0
  148. package/dist/{chunk-2RIWJUSQ.js → chunk-LQKXVQZR.js} +12 -12
  149. package/dist/{chunk-LQL7ARIC.js → chunk-LTOAJXZB.js} +4 -4
  150. package/dist/{chunk-QKD65RGL.js → chunk-LYMNZZIM.js} +2 -2
  151. package/dist/{chunk-W4FBGYGK.js → chunk-M4MP34AQ.js} +189 -5
  152. package/dist/chunk-M4MP34AQ.js.map +1 -0
  153. package/dist/{chunk-3PY7VHV7.js → chunk-MCA2X4WH.js} +2 -2
  154. package/dist/{chunk-S5NZBKKQ.js → chunk-N3CXAYPJ.js} +3 -3
  155. package/dist/{chunk-WQIHRA5F.js → chunk-N3LL5NEU.js} +2 -2
  156. package/dist/{chunk-Z4U6U3M3.js → chunk-NKL25FCF.js} +2 -2
  157. package/dist/{chunk-LMDRGRJ2.js → chunk-NOB2T2FC.js} +2 -2
  158. package/dist/{chunk-P2OTGMTR.js → chunk-NSGU76YO.js} +2 -2
  159. package/dist/{chunk-L6DCVUCA.js → chunk-O76MWTVS.js} +2 -2
  160. package/dist/{chunk-WZFAPHIK.js → chunk-OIOZ6MOP.js} +3 -3
  161. package/dist/{chunk-DNHVPZOD.js → chunk-P26YHAQH.js} +201 -1
  162. package/dist/chunk-P26YHAQH.js.map +1 -0
  163. package/dist/{chunk-UMOO7IY7.js → chunk-P2KBDJJ6.js} +2 -2
  164. package/dist/{chunk-KVJRXN2E.js → chunk-P4QOYG52.js} +125 -13
  165. package/dist/chunk-P4QOYG52.js.map +1 -0
  166. package/dist/chunk-P77QX3ID.js +332 -0
  167. package/dist/chunk-P77QX3ID.js.map +1 -0
  168. package/dist/{chunk-SXWHN7GC.js → chunk-PDEKQWDV.js} +2 -2
  169. package/dist/{chunk-ENEA47UC.js → chunk-PLCHU56K.js} +3 -3
  170. package/dist/{chunk-IXPKESVP.js → chunk-PWIMF7LP.js} +37 -37
  171. package/dist/{chunk-RHTO4HTL.js → chunk-PWLB4TRK.js} +2 -2
  172. package/dist/{chunk-RVYVMQK4.js → chunk-QSYL5CXK.js} +3 -3
  173. package/dist/{chunk-B6KGGRUL.js → chunk-QWLW3VQH.js} +2 -2
  174. package/dist/{chunk-YQIVWS7Y.js → chunk-RBPH3GZV.js} +405 -101
  175. package/dist/chunk-RBPH3GZV.js.map +1 -0
  176. package/dist/{chunk-JBPKEARU.js → chunk-RKNJBZ55.js} +4 -4
  177. package/dist/{chunk-QCECHYZL.js → chunk-RVO6TCTU.js} +6 -6
  178. package/dist/{chunk-SHDZNSK4.js → chunk-S2SJEOTM.js} +2 -2
  179. package/dist/{chunk-ULWHRQEQ.js → chunk-S75UQ3T3.js} +3 -3
  180. package/dist/{chunk-LXOM6IQU.js → chunk-SEF4IOFE.js} +2 -2
  181. package/dist/{chunk-I3YHVVT4.js → chunk-SHYIMIX5.js} +2 -2
  182. package/dist/{chunk-IZANPXMV.js → chunk-T35UJI5R.js} +86 -82
  183. package/dist/chunk-T35UJI5R.js.map +1 -0
  184. package/dist/{chunk-G5OB4XZX.js → chunk-VANZKHTN.js} +4 -4
  185. package/dist/{chunk-I4TQST3L.js → chunk-VFS3MK5F.js} +2 -2
  186. package/dist/chunk-VUDMT5CP.js +86 -0
  187. package/dist/chunk-VUDMT5CP.js.map +1 -0
  188. package/dist/{chunk-CMQZNEIF.js → chunk-WFLBP5GC.js} +8 -1
  189. package/dist/chunk-WFLBP5GC.js.map +1 -0
  190. package/dist/{chunk-SMPVHGHG.js → chunk-WPZX7MEA.js} +3 -3
  191. package/dist/{chunk-ZRWB5D4H.js → chunk-WT6UL3UA.js} +2 -2
  192. package/dist/{chunk-DQEMWVMT.js → chunk-X7Y7WX73.js} +1 -1
  193. package/dist/{chunk-JHMAYABJ.js → chunk-XL3TATMJ.js} +4 -4
  194. package/dist/{chunk-MC6XO7T4.js → chunk-YLBE6PLR.js} +2 -2
  195. package/dist/{chunk-OLX2HJFW.js → chunk-YLHM5BQQ.js} +4 -4
  196. package/dist/{chunk-EZ25VE3G.js → chunk-YNDLCWXS.js} +4 -4
  197. package/dist/{chunk-GF22HWS2.js → chunk-Z54EM5YZ.js} +4 -4
  198. package/dist/{chunk-GVX3NAUU.js → chunk-ZDAYWJV6.js} +2 -2
  199. package/dist/{chunk-EYAIZBLM.js → chunk-ZJIFYUJI.js} +5 -5
  200. package/dist/{chunk-CNQQMB67.js → chunk-ZN4EYMKJ.js} +2 -2
  201. package/dist/{cli-PyAUaozE.d.ts → cli-BLNmNEMT.d.ts} +16 -14
  202. package/dist/cli.d.ts +13 -13
  203. package/dist/cli.js +96 -94
  204. package/dist/coding/pre-action-gate.d.ts +66 -0
  205. package/dist/coding/pre-action-gate.js +22 -0
  206. package/dist/commitment-ledger.js +2 -2
  207. package/dist/compounding/engine.d.ts +2 -2
  208. package/dist/compounding/engine.js +13 -13
  209. package/dist/compounding/preference-consolidator.d.ts +1 -1
  210. package/dist/compression-optimizer.d.ts +1 -1
  211. package/dist/config.d.ts +1 -1
  212. package/dist/config.js +3 -2
  213. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  214. package/dist/connectors/codex-materialize-runner.js +12 -12
  215. package/dist/connectors/codex-materialize.d.ts +1 -1
  216. package/dist/connectors/index.d.ts +1 -1
  217. package/dist/connectors/index.js +12 -12
  218. package/dist/consolidation-provenance-check.d.ts +2 -2
  219. package/dist/consolidation-provenance-check.js +4 -4
  220. package/dist/consolidation-undo.d.ts +2 -2
  221. package/dist/consolidation-undo.js +3 -3
  222. package/dist/contradiction/index.d.ts +2 -2
  223. package/dist/contradiction/index.js +3 -3
  224. package/dist/converge-config.d.ts +1 -1
  225. package/dist/convergence-refresh.d.ts +2 -2
  226. package/dist/convergence-refresh.js +15 -15
  227. package/dist/conversation-index/backend.d.ts +1 -1
  228. package/dist/conversation-index/chunker.d.ts +1 -1
  229. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  230. package/dist/conversation-index/indexer.d.ts +1 -1
  231. package/dist/conversation-index/search.d.ts +1 -1
  232. package/dist/corpus-watermark.d.ts +1 -1
  233. package/dist/corpus-watermark.js +23 -23
  234. package/dist/cue-anchors.d.ts +19 -1
  235. package/dist/cue-anchors.js +10 -2
  236. package/dist/dashboard-runtime.js +2 -2
  237. package/dist/day-summary.d.ts +1 -1
  238. package/dist/delinearize.d.ts +1 -1
  239. package/dist/dependency-propagation-config.d.ts +10 -0
  240. package/dist/dependency-propagation-config.js +10 -0
  241. package/dist/dependency-propagation-config.js.map +1 -0
  242. package/dist/deterministic-order.d.ts +4 -0
  243. package/dist/deterministic-order.js +10 -0
  244. package/dist/deterministic-order.js.map +1 -0
  245. package/dist/direct-answer-wiring.d.ts +1 -1
  246. package/dist/direct-answer.d.ts +1 -1
  247. package/dist/embedding-fallback.d.ts +1 -1
  248. package/dist/enrichment/index.d.ts +1 -1
  249. package/dist/entity-retrieval.d.ts +2 -2
  250. package/dist/entity-retrieval.js +12 -12
  251. package/dist/entity-schema.d.ts +1 -1
  252. package/dist/evals.js +2 -2
  253. package/dist/explicit-capture.d.ts +8 -8
  254. package/dist/explicit-capture.js +6 -6
  255. package/dist/external-wiki-access.d.ts +10 -10
  256. package/dist/external-wiki-access.js +49 -49
  257. package/dist/external-wiki-collection-registration.d.ts +1 -1
  258. package/dist/external-wiki-collection.d.ts +1 -1
  259. package/dist/external-wiki-mcp-tools.d.ts +10 -10
  260. package/dist/extraction-error-classification.d.ts +1 -1
  261. package/dist/extraction-faithfulness.d.ts +1 -1
  262. package/dist/extraction-judge-telemetry.d.ts +1 -1
  263. package/dist/extraction-judge-training.d.ts +1 -1
  264. package/dist/extraction-judge.d.ts +1 -1
  265. package/dist/extraction-liveness.d.ts +1 -1
  266. package/dist/extraction-normalization.d.ts +14 -0
  267. package/dist/extraction-normalization.js +22 -0
  268. package/dist/extraction-normalization.js.map +1 -0
  269. package/dist/extraction-prompt.d.ts +4 -3
  270. package/dist/extraction-prompt.js +3 -1
  271. package/dist/extraction-source-grounding-rules.d.ts +1 -1
  272. package/dist/extraction-source-grounding.d.ts +1 -1
  273. package/dist/extraction.d.ts +18 -1
  274. package/dist/extraction.js +21 -19
  275. package/dist/fallback-llm.d.ts +1 -1
  276. package/dist/{first-start-migration-ZSHEFEI3.js → first-start-migration-626C5554.js} +5 -5
  277. package/dist/{forget-DNAJ66ZD.js → forget-GJ42LCBW.js} +2 -2
  278. package/dist/graph-dashboard-diff.d.ts +1 -1
  279. package/dist/graph-dashboard-key.d.ts +1 -1
  280. package/dist/graph-dashboard-parser.d.ts +1 -1
  281. package/dist/graph-edge-reinforcement.d.ts +1 -1
  282. package/dist/graph-snapshot.d.ts +1 -1
  283. package/dist/graph.d.ts +1 -1
  284. package/dist/harmonic-construction.d.ts +43 -0
  285. package/dist/harmonic-construction.js +26 -0
  286. package/dist/harmonic-construction.js.map +1 -0
  287. package/dist/harmonic-retrieval.d.ts +1 -0
  288. package/dist/harmonic-retrieval.js +10 -4
  289. package/dist/importance.d.ts +1 -1
  290. package/dist/importers/index.d.ts +1 -1
  291. package/dist/in-flight-reads.d.ts +1 -1
  292. package/dist/index.d.ts +698 -696
  293. package/dist/index.js +207 -161
  294. package/dist/intent.d.ts +1 -1
  295. package/dist/json-store.d.ts +15 -1
  296. package/dist/json-store.js +11 -3
  297. package/dist/lcm/engine.d.ts +1 -1
  298. package/dist/lcm/engine.js +2 -2
  299. package/dist/lcm/index.d.ts +1 -1
  300. package/dist/lcm/index.js +4 -4
  301. package/dist/lcm/tools.d.ts +1 -1
  302. package/dist/lifecycle.d.ts +1 -1
  303. package/dist/live-connectors-runner.d.ts +1 -1
  304. package/dist/local-llm.d.ts +1 -1
  305. package/dist/local-model-endpoint.d.ts +1 -1
  306. package/dist/maintenance/archive-observations.js +2 -2
  307. package/dist/maintenance/atomic-file.d.ts +5 -0
  308. package/dist/maintenance/atomic-file.js +12 -0
  309. package/dist/maintenance/atomic-file.js.map +1 -0
  310. package/dist/maintenance/memory-governance.d.ts +1 -1
  311. package/dist/maintenance/memory-governance.js +12 -12
  312. package/dist/maintenance/migrate-observations.js +3 -3
  313. package/dist/maintenance/observation-ledger-utils.d.ts +1 -1
  314. package/dist/maintenance/observation-ledger-utils.js +2 -2
  315. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
  316. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +13 -13
  317. package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
  318. package/dist/maintenance/rebuild-memory-projection.js +14 -14
  319. package/dist/maintenance/rebuild-observations.js +3 -3
  320. package/dist/{maintenance-j7sfNQdK.d.ts → maintenance-DKbKZi3u.d.ts} +3 -3
  321. package/dist/mcp-memory-inspector-app.d.ts +10 -10
  322. package/dist/memory-action-policy.d.ts +1 -1
  323. package/dist/memory-cache.d.ts +1 -1
  324. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  325. package/dist/memory-projection-store.d.ts +1 -1
  326. package/dist/memory-provenance.d.ts +1 -1
  327. package/dist/memory-snapshot.d.ts +1 -1
  328. package/dist/memory-worth-outcomes.d.ts +2 -2
  329. package/dist/models-json.d.ts +1 -1
  330. package/dist/namespaces/migrate.d.ts +3 -3
  331. package/dist/namespaces/migrate.js +22 -22
  332. package/dist/namespaces/principal.d.ts +1 -1
  333. package/dist/namespaces/search.d.ts +1 -1
  334. package/dist/namespaces/search.js +9 -9
  335. package/dist/namespaces/storage.d.ts +3 -3
  336. package/dist/namespaces/storage.js +12 -12
  337. package/dist/native-knowledge.d.ts +1 -1
  338. package/dist/objective-state-writers.js +3 -3
  339. package/dist/objective-state.js +2 -2
  340. package/dist/offline-sync-impression-drain.d.ts +1 -1
  341. package/dist/offline-sync-impression-drain.js +2 -2
  342. package/dist/operator-doctor-corpus.d.ts +1 -1
  343. package/dist/operator-doctor-corpus.js +24 -24
  344. package/dist/operator-doctor-replica.d.ts +1 -1
  345. package/dist/operator-toolkit.d.ts +3 -3
  346. package/dist/operator-toolkit.js +33 -32
  347. package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
  348. package/dist/orchestration/maintenance.d.ts +4 -4
  349. package/dist/orchestration/maintenance.js +18 -18
  350. package/dist/{orchestrator-Haa9xVPV.d.ts → orchestrator-BRwD7ceU.d.ts} +7 -7
  351. package/dist/orchestrator.d.ts +8 -8
  352. package/dist/orchestrator.js +132 -127
  353. package/dist/page-versioning.js +3 -3
  354. package/dist/patterns-cli.d.ts +1 -1
  355. package/dist/{pipeline-1h2GpiHP.d.ts → pipeline-DC-1C9T8.d.ts} +1 -1
  356. package/dist/policy-runtime.d.ts +1 -1
  357. package/dist/proactive-contention.d.ts +1 -1
  358. package/dist/provenance.d.ts +1 -1
  359. package/dist/{qmd-UdwoF71D.d.ts → qmd-DdeCEZdb.d.ts} +1 -1
  360. package/dist/qmd-preflight.d.ts +2 -2
  361. package/dist/qmd-recall-cache.d.ts +1 -1
  362. package/dist/qmd.d.ts +2 -2
  363. package/dist/qmd.js +4 -4
  364. package/dist/recall-concurrency-config.d.ts +1 -1
  365. package/dist/recall-disclosure-escalation.d.ts +1 -1
  366. package/dist/recall-explain-renderer.d.ts +1 -1
  367. package/dist/recall-explain-renderer.js +3 -3
  368. package/dist/recall-memory-map.d.ts +1 -1
  369. package/dist/recall-planner-llm.d.ts +1 -1
  370. package/dist/recall-state.d.ts +1 -1
  371. package/dist/recall-state.js +2 -2
  372. package/dist/recall-tag-filter.d.ts +1 -1
  373. package/dist/recall-timings.d.ts +1 -1
  374. package/dist/recall-xray-cli.d.ts +1 -1
  375. package/dist/recall-xray-cli.js +4 -4
  376. package/dist/recall-xray-renderer.d.ts +1 -1
  377. package/dist/recall-xray-renderer.js +3 -3
  378. package/dist/recall-xray.d.ts +1 -1
  379. package/dist/recall-xray.js +2 -2
  380. package/dist/reconcile/cursor.d.ts +1 -1
  381. package/dist/reconcile/manifest.d.ts +1 -1
  382. package/dist/reconcile/plan.d.ts +1 -1
  383. package/dist/relevance.js +2 -2
  384. package/dist/replay/normalizers/chatgpt.d.ts +1 -1
  385. package/dist/replay/normalizers/claude.d.ts +1 -1
  386. package/dist/replay/normalizers/openclaw.d.ts +1 -1
  387. package/dist/replay/normalizers/shared.d.ts +1 -1
  388. package/dist/replay/runner.d.ts +1 -1
  389. package/dist/replay/types.d.ts +1 -1
  390. package/dist/replica-divergence.d.ts +1 -1
  391. package/dist/replica-peers-config.d.ts +1 -1
  392. package/dist/{resolution-3K27T4VO.js → resolution-MDPNOEG6.js} +4 -4
  393. package/dist/resolution-MDPNOEG6.js.map +1 -0
  394. package/dist/resolve-auth-token.d.ts +1 -1
  395. package/dist/resume-bundles.js +8 -7
  396. package/dist/retrieval-agents.d.ts +2 -2
  397. package/dist/retrieval-tiers.d.ts +1 -1
  398. package/dist/routing/engine.d.ts +1 -1
  399. package/dist/routing/store.d.ts +1 -1
  400. package/dist/salvage-envelope.d.ts +1 -1
  401. package/dist/salvage-envelope.js +3 -3
  402. package/dist/schemas.d.ts +213 -116
  403. package/dist/schemas.js +1 -1
  404. package/dist/{scope-profiles-APjhSe-w.d.ts → scope-profiles-BXVq4Jv0.d.ts} +1 -1
  405. package/dist/search/embed-helper.d.ts +1 -1
  406. package/dist/search/factory.d.ts +1 -1
  407. package/dist/search/factory.js +8 -8
  408. package/dist/search/index.d.ts +1 -1
  409. package/dist/search/index.js +13 -13
  410. package/dist/search/lancedb-backend.d.ts +1 -1
  411. package/dist/search/lancedb-backend.js +2 -2
  412. package/dist/search/meilisearch-backend.d.ts +1 -1
  413. package/dist/search/meilisearch-backend.js +2 -2
  414. package/dist/search/noop-backend.d.ts +1 -1
  415. package/dist/search/orama-backend.d.ts +1 -1
  416. package/dist/search/orama-backend.js +2 -2
  417. package/dist/search/port.d.ts +1 -1
  418. package/dist/search/remote-backend.d.ts +1 -1
  419. package/dist/{semantic-consolidation-CrySDbk3.d.ts → semantic-consolidation-CGYxfa8F.d.ts} +1 -1
  420. package/dist/semantic-consolidation.d.ts +2 -2
  421. package/dist/semantic-consolidation.js +13 -13
  422. package/dist/semantic-rule-promotion.js +12 -12
  423. package/dist/semantic-rule-verifier.d.ts +1 -1
  424. package/dist/semantic-rule-verifier.js +12 -12
  425. package/dist/{service-Da_BI4S8.d.ts → service-CBDBQFCN.d.ts} +2 -2
  426. package/dist/session-observer-bands.d.ts +1 -1
  427. package/dist/session-observer-state.d.ts +1 -1
  428. package/dist/shared-context/manager.d.ts +11 -11
  429. package/dist/signal.d.ts +1 -1
  430. package/dist/source-agent-qualifier.d.ts +1 -1
  431. package/dist/source-agent-qualifier.js +16 -16
  432. package/dist/{storage-D1apCiCS.d.ts → storage-V--MQi7w.d.ts} +1 -1
  433. package/dist/storage.d.ts +2 -2
  434. package/dist/storage.js +11 -11
  435. package/dist/summarizer.d.ts +1 -1
  436. package/dist/summary-snapshot.d.ts +1 -1
  437. package/dist/temporal-supersession.d.ts +13 -2
  438. package/dist/temporal-supersession.js +1 -1
  439. package/dist/temporal-timeline-recall.d.ts +1 -1
  440. package/dist/temporal-validity.d.ts +1 -1
  441. package/dist/threading.d.ts +1 -1
  442. package/dist/tier-migration.d.ts +2 -2
  443. package/dist/tier-routing.d.ts +1 -1
  444. package/dist/{tier-stats-OPTSBNRH.js → tier-stats-2JCZYEF7.js} +5 -5
  445. package/dist/topics.d.ts +1 -1
  446. package/dist/transcript.d.ts +1 -1
  447. package/dist/transfer/autodetect.js +1 -1
  448. package/dist/transfer/backup.js +2 -2
  449. package/dist/transfer/capsule-export.js +3 -3
  450. package/dist/transfer/capsule-import.js +5 -5
  451. package/dist/transfer/types.d.ts +66 -66
  452. package/dist/trust-score-stage.d.ts +1 -1
  453. package/dist/trust-score.d.ts +1 -1
  454. package/dist/trust-zones.js +2 -2
  455. package/dist/{types-D_Au9qJO.d.ts → types-D_a6Sqjz.d.ts} +25 -8
  456. package/dist/types.d.ts +1 -1
  457. package/dist/types.js +1 -1
  458. package/dist/utility-learner.js +3 -3
  459. package/dist/utility-runtime.d.ts +1 -1
  460. package/dist/utility-runtime.js +4 -4
  461. package/dist/utility-telemetry.js +2 -2
  462. package/dist/verified-recall.js +12 -12
  463. package/dist/work-product-ledger.js +2 -2
  464. package/dist/write-envelope.d.ts +1 -1
  465. package/dist/write-envelope.js +2 -2
  466. package/package.json +32 -2
  467. package/src/abstraction-nodes.ts +182 -4
  468. package/src/causal-trajectory.ts +258 -3
  469. package/src/cli/harmonic-search.ts +23 -0
  470. package/src/cli/research-status-commands.ts +2 -1
  471. package/src/cli.ts +1 -24
  472. package/src/coding/pre-action-gate.test.ts +516 -0
  473. package/src/coding/pre-action-gate.ts +320 -0
  474. package/src/config.test.ts +85 -0
  475. package/src/config.ts +2 -0
  476. package/src/cue-anchors.test.ts +90 -0
  477. package/src/cue-anchors.ts +264 -11
  478. package/src/dependency-frontmatter.test.ts +83 -0
  479. package/src/dependency-propagation-config.ts +94 -0
  480. package/src/deterministic-order.ts +14 -0
  481. package/src/extraction-normalization.ts +71 -0
  482. package/src/extraction-prompt.ts +45 -11
  483. package/src/extraction.ts +48 -32
  484. package/src/faithfulness-graph-guard.test.ts +27 -0
  485. package/src/harmonic-construction.test.ts +1799 -0
  486. package/src/harmonic-construction.ts +367 -0
  487. package/src/harmonic-retrieval.ts +166 -25
  488. package/src/index.ts +4 -5
  489. package/src/json-store.ts +354 -12
  490. package/src/orchestration/consolidation-run.ts +192 -0
  491. package/src/orchestration/contradiction-linking-coordinator.ts +35 -1
  492. package/src/orchestration/dependency-propagation-triggers.test.ts +286 -0
  493. package/src/orchestration/dependency-propagation.test.ts +487 -0
  494. package/src/orchestration/dependency-propagation.ts +263 -0
  495. package/src/orchestration/dependency-revalidation.ts +173 -0
  496. package/src/orchestration/extraction-persist-deps.ts +93 -0
  497. package/src/orchestration/extraction-persist.ts +101 -94
  498. package/src/orchestration/harmonic-construction-persist.ts +86 -0
  499. package/src/orchestration/recall-internal.ts +1 -0
  500. package/src/orchestrator.ts +2 -1
  501. package/src/schemas.ts +15 -0
  502. package/src/storage.ts +14 -0
  503. package/src/temporal-supersession.ts +29 -1
  504. package/src/testing/orchestrator-lite.ts +27 -8
  505. package/src/testing/subjects/extraction-lifecycle.test.ts +91 -50
  506. package/src/types.ts +22 -7
  507. package/dist/chunk-3S63QIFQ.js.map +0 -1
  508. package/dist/chunk-CMQZNEIF.js.map +0 -1
  509. package/dist/chunk-DNHVPZOD.js.map +0 -1
  510. package/dist/chunk-EY64JLOM.js.map +0 -1
  511. package/dist/chunk-FZZ2QTJI.js +0 -111
  512. package/dist/chunk-FZZ2QTJI.js.map +0 -1
  513. package/dist/chunk-IZANPXMV.js.map +0 -1
  514. package/dist/chunk-J7T4MX7P.js.map +0 -1
  515. package/dist/chunk-KVJRXN2E.js.map +0 -1
  516. package/dist/chunk-LPSF4OQH.js +0 -47
  517. package/dist/chunk-LPSF4OQH.js.map +0 -1
  518. package/dist/chunk-LZGCJSQR.js.map +0 -1
  519. package/dist/chunk-OADWQ5CR.js +0 -115
  520. package/dist/chunk-OADWQ5CR.js.map +0 -1
  521. package/dist/chunk-RN53QBM4.js.map +0 -1
  522. package/dist/chunk-W4FBGYGK.js.map +0 -1
  523. package/dist/chunk-YQIVWS7Y.js.map +0 -1
  524. /package/dist/{auto-sync-7O6RP2RT.js.map → auto-sync-QFQGOEO2.js.map} +0 -0
  525. /package/dist/{capsule-crypto-YO5QJ6L3.js.map → capsule-crypto-7FJQINUR.js.map} +0 -0
  526. /package/dist/{capsule-merge-6GFHWECG.js.map → capsule-merge-KXTRZ23Z.js.map} +0 -0
  527. /package/dist/{chunk-ICP53SKG.js.map → chunk-2HIJHXB3.js.map} +0 -0
  528. /package/dist/{chunk-BXLOS5AJ.js.map → chunk-2NLLXCJG.js.map} +0 -0
  529. /package/dist/{chunk-5JRC6BYS.js.map → chunk-47J4EDGR.js.map} +0 -0
  530. /package/dist/{chunk-2VHLLPTX.js.map → chunk-4EABKPZS.js.map} +0 -0
  531. /package/dist/{chunk-RJV6Q2FT.js.map → chunk-4JWJMRPJ.js.map} +0 -0
  532. /package/dist/{chunk-MXPB6PJQ.js.map → chunk-4S3ECH3U.js.map} +0 -0
  533. /package/dist/{chunk-CGASUJVP.js.map → chunk-5V6IXHPI.js.map} +0 -0
  534. /package/dist/{chunk-R5IGA2NH.js.map → chunk-5XCN4XBU.js.map} +0 -0
  535. /package/dist/{chunk-2RPJ4NEE.js.map → chunk-64BHFFKZ.js.map} +0 -0
  536. /package/dist/{chunk-FQC3DHH2.js.map → chunk-66SE3BNH.js.map} +0 -0
  537. /package/dist/{chunk-TERNBNJB.js.map → chunk-6FC3IZ26.js.map} +0 -0
  538. /package/dist/{chunk-K7VKAHFE.js.map → chunk-6XGEBQ3R.js.map} +0 -0
  539. /package/dist/{chunk-JFLOOTXU.js.map → chunk-7BLWBSRL.js.map} +0 -0
  540. /package/dist/{chunk-ABR2HEJO.js.map → chunk-7NDM2PNK.js.map} +0 -0
  541. /package/dist/{chunk-JXZ7NLYH.js.map → chunk-7VWZ4LRW.js.map} +0 -0
  542. /package/dist/{chunk-R6YJI3HE.js.map → chunk-AW4QUFQF.js.map} +0 -0
  543. /package/dist/{chunk-P65YJEEL.js.map → chunk-AXFWMRKI.js.map} +0 -0
  544. /package/dist/{chunk-WG5HSQ4P.js.map → chunk-BAKXNQ3C.js.map} +0 -0
  545. /package/dist/{chunk-NM2WP3B7.js.map → chunk-BJYET5TX.js.map} +0 -0
  546. /package/dist/{chunk-HLKPRWF4.js.map → chunk-DATDLJAO.js.map} +0 -0
  547. /package/dist/{chunk-DX3XRGLH.js.map → chunk-DQTCGVFK.js.map} +0 -0
  548. /package/dist/{chunk-IPBNC77A.js.map → chunk-E633OXMH.js.map} +0 -0
  549. /package/dist/{chunk-Z5UC3OKB.js.map → chunk-ELQCS47S.js.map} +0 -0
  550. /package/dist/{chunk-FMXJ555A.js.map → chunk-EURCX6PS.js.map} +0 -0
  551. /package/dist/{chunk-MZZR3J6M.js.map → chunk-FV7YQTN3.js.map} +0 -0
  552. /package/dist/{chunk-3R6D33UF.js.map → chunk-GGBSF2X7.js.map} +0 -0
  553. /package/dist/{chunk-SYUBB3WM.js.map → chunk-GKEYXXKX.js.map} +0 -0
  554. /package/dist/{chunk-5AGR7SAI.js.map → chunk-GSEPRIZC.js.map} +0 -0
  555. /package/dist/{chunk-UTVZKHJK.js.map → chunk-GUKBW4HL.js.map} +0 -0
  556. /package/dist/{chunk-2F6NP3NT.js.map → chunk-HDQUQBPW.js.map} +0 -0
  557. /package/dist/{chunk-6HMYUWXR.js.map → chunk-HTP6XRUI.js.map} +0 -0
  558. /package/dist/{chunk-UYUYZ4WY.js.map → chunk-IARXXZU4.js.map} +0 -0
  559. /package/dist/{chunk-MNB5RMAY.js.map → chunk-IIFFC3RL.js.map} +0 -0
  560. /package/dist/{chunk-VDX2J7OX.js.map → chunk-IPLYGWQF.js.map} +0 -0
  561. /package/dist/{chunk-NZBZ7IS2.js.map → chunk-JDCQK3C5.js.map} +0 -0
  562. /package/dist/{chunk-C3KVFJH5.js.map → chunk-JI62YGPI.js.map} +0 -0
  563. /package/dist/{chunk-LULR4IUW.js.map → chunk-KATEWTQJ.js.map} +0 -0
  564. /package/dist/{chunk-BMCHFWGX.js.map → chunk-KMWYZTIE.js.map} +0 -0
  565. /package/dist/{chunk-JGSKJHF7.js.map → chunk-KQS72GCR.js.map} +0 -0
  566. /package/dist/{chunk-2RIWJUSQ.js.map → chunk-LQKXVQZR.js.map} +0 -0
  567. /package/dist/{chunk-LQL7ARIC.js.map → chunk-LTOAJXZB.js.map} +0 -0
  568. /package/dist/{chunk-QKD65RGL.js.map → chunk-LYMNZZIM.js.map} +0 -0
  569. /package/dist/{chunk-3PY7VHV7.js.map → chunk-MCA2X4WH.js.map} +0 -0
  570. /package/dist/{chunk-S5NZBKKQ.js.map → chunk-N3CXAYPJ.js.map} +0 -0
  571. /package/dist/{chunk-WQIHRA5F.js.map → chunk-N3LL5NEU.js.map} +0 -0
  572. /package/dist/{chunk-Z4U6U3M3.js.map → chunk-NKL25FCF.js.map} +0 -0
  573. /package/dist/{chunk-LMDRGRJ2.js.map → chunk-NOB2T2FC.js.map} +0 -0
  574. /package/dist/{chunk-P2OTGMTR.js.map → chunk-NSGU76YO.js.map} +0 -0
  575. /package/dist/{chunk-L6DCVUCA.js.map → chunk-O76MWTVS.js.map} +0 -0
  576. /package/dist/{chunk-WZFAPHIK.js.map → chunk-OIOZ6MOP.js.map} +0 -0
  577. /package/dist/{chunk-UMOO7IY7.js.map → chunk-P2KBDJJ6.js.map} +0 -0
  578. /package/dist/{chunk-SXWHN7GC.js.map → chunk-PDEKQWDV.js.map} +0 -0
  579. /package/dist/{chunk-ENEA47UC.js.map → chunk-PLCHU56K.js.map} +0 -0
  580. /package/dist/{chunk-IXPKESVP.js.map → chunk-PWIMF7LP.js.map} +0 -0
  581. /package/dist/{chunk-RHTO4HTL.js.map → chunk-PWLB4TRK.js.map} +0 -0
  582. /package/dist/{chunk-RVYVMQK4.js.map → chunk-QSYL5CXK.js.map} +0 -0
  583. /package/dist/{chunk-B6KGGRUL.js.map → chunk-QWLW3VQH.js.map} +0 -0
  584. /package/dist/{chunk-JBPKEARU.js.map → chunk-RKNJBZ55.js.map} +0 -0
  585. /package/dist/{chunk-QCECHYZL.js.map → chunk-RVO6TCTU.js.map} +0 -0
  586. /package/dist/{chunk-SHDZNSK4.js.map → chunk-S2SJEOTM.js.map} +0 -0
  587. /package/dist/{chunk-ULWHRQEQ.js.map → chunk-S75UQ3T3.js.map} +0 -0
  588. /package/dist/{chunk-LXOM6IQU.js.map → chunk-SEF4IOFE.js.map} +0 -0
  589. /package/dist/{chunk-I3YHVVT4.js.map → chunk-SHYIMIX5.js.map} +0 -0
  590. /package/dist/{chunk-G5OB4XZX.js.map → chunk-VANZKHTN.js.map} +0 -0
  591. /package/dist/{chunk-I4TQST3L.js.map → chunk-VFS3MK5F.js.map} +0 -0
  592. /package/dist/{chunk-SMPVHGHG.js.map → chunk-WPZX7MEA.js.map} +0 -0
  593. /package/dist/{chunk-ZRWB5D4H.js.map → chunk-WT6UL3UA.js.map} +0 -0
  594. /package/dist/{chunk-DQEMWVMT.js.map → chunk-X7Y7WX73.js.map} +0 -0
  595. /package/dist/{chunk-JHMAYABJ.js.map → chunk-XL3TATMJ.js.map} +0 -0
  596. /package/dist/{chunk-MC6XO7T4.js.map → chunk-YLBE6PLR.js.map} +0 -0
  597. /package/dist/{chunk-OLX2HJFW.js.map → chunk-YLHM5BQQ.js.map} +0 -0
  598. /package/dist/{chunk-EZ25VE3G.js.map → chunk-YNDLCWXS.js.map} +0 -0
  599. /package/dist/{chunk-GF22HWS2.js.map → chunk-Z54EM5YZ.js.map} +0 -0
  600. /package/dist/{chunk-GVX3NAUU.js.map → chunk-ZDAYWJV6.js.map} +0 -0
  601. /package/dist/{chunk-EYAIZBLM.js.map → chunk-ZJIFYUJI.js.map} +0 -0
  602. /package/dist/{chunk-CNQQMB67.js.map → chunk-ZN4EYMKJ.js.map} +0 -0
  603. /package/dist/{resolution-3K27T4VO.js.map → coding/pre-action-gate.js.map} +0 -0
  604. /package/dist/{first-start-migration-ZSHEFEI3.js.map → first-start-migration-626C5554.js.map} +0 -0
  605. /package/dist/{forget-DNAJ66ZD.js.map → forget-GJ42LCBW.js.map} +0 -0
  606. /package/dist/{tier-stats-OPTSBNRH.js.map → tier-stats-2JCZYEF7.js.map} +0 -0
@@ -1,6 +1,8 @@
1
+ import { mkdir, unlink, writeFile } from "node:fs/promises";
1
2
  import path from "node:path";
2
- import { mkdir, writeFile } from "node:fs/promises";
3
- import { listJsonFiles, readJsonFile } from "./json-store.js";
3
+ import { resolveAbstractionNodeStoreDir, validateAbstractionNode, type AbstractionNode } from "./abstraction-nodes.js";
4
+ import { listJsonFilesStrict, readJsonFile, withJsonStoreMutationLock, writeJsonFileAtomic } from "./json-store.js";
5
+ import { compareDeterministicStrings, mergeSortedUniqueStrings } from "./deterministic-order.js";
4
6
  import {
5
7
  assertIsoRecordedAt,
6
8
  assertSafePathSegment,
@@ -21,6 +23,7 @@ export interface CueAnchor {
21
23
  recordedAt: string;
22
24
  sessionKey: string;
23
25
  nodeRefs: string[];
26
+ sourceMemoryIdsByNodeRef?: Record<string, string[]>;
24
27
  tags?: string[];
25
28
  metadata?: Record<string, string>;
26
29
  }
@@ -62,10 +65,58 @@ function validateNodeRefs(raw: unknown): string[] {
62
65
  return nodeRefs.map((nodeRef, index) => assertSafePathSegment(nodeRef, `nodeRefs[${index}]`));
63
66
  }
64
67
 
65
- export function resolveCueAnchorStoreDir(
66
- abstractionNodeStoreDir: string,
67
- overrideDir?: string,
68
- ): string {
68
+ function validateSourceMemoryIdsByNodeRef(raw: unknown): Record<string, string[]> | undefined {
69
+ if (raw === undefined) return undefined;
70
+ if (!isRecord(raw)) throw new Error("sourceMemoryIdsByNodeRef must be an object of string arrays");
71
+ const entries: Array<[string, string[]]> = [];
72
+ for (const [rawNodeRef, rawSourceMemoryIds] of Object.entries(raw)) {
73
+ const nodeRef = assertSafePathSegment(
74
+ assertString(rawNodeRef, "sourceMemoryIdsByNodeRef key"),
75
+ "sourceMemoryIdsByNodeRef.nodeRef"
76
+ );
77
+ const sourceMemoryIds = optionalStringArray(rawSourceMemoryIds, `sourceMemoryIdsByNodeRef.${nodeRef}`);
78
+ if (sourceMemoryIds) entries.push([nodeRef, mergeSortedUniqueStrings(sourceMemoryIds)]);
79
+ }
80
+ if (entries.length === 0) return undefined;
81
+ return Object.fromEntries(entries.sort(([left], [right]) => compareDeterministicStrings(left, right)));
82
+ }
83
+
84
+ function mergeSourceMemoryIdsByNodeRef(
85
+ existing: Record<string, string[]> | undefined,
86
+ incoming: Record<string, string[]> | undefined
87
+ ): Record<string, string[]> | undefined {
88
+ const merged = new Map<string, string[]>();
89
+ for (const [nodeRef, sourceMemoryIds] of Object.entries(existing ?? {})) {
90
+ merged.set(nodeRef, [...sourceMemoryIds]);
91
+ }
92
+ for (const [nodeRef, sourceMemoryIds] of Object.entries(incoming ?? {})) {
93
+ merged.set(nodeRef, mergeSortedUniqueStrings(merged.get(nodeRef), sourceMemoryIds));
94
+ }
95
+ return validateSourceMemoryIdsByNodeRef(Object.fromEntries(merged));
96
+ }
97
+
98
+ function boundSourceMemoryIdsByNodeRef(
99
+ sourceMemoryIdsByNodeRef: Record<string, string[]> | undefined,
100
+ nodeRefs: string[],
101
+ liveNodes?: Map<string, AbstractionNode>
102
+ ): Record<string, string[]> | undefined {
103
+ if (!sourceMemoryIdsByNodeRef) return undefined;
104
+ const retained = Object.fromEntries(
105
+ nodeRefs.flatMap((nodeRef) => {
106
+ const sourceMemoryIds = sourceMemoryIdsByNodeRef[nodeRef];
107
+ if (!sourceMemoryIds) return [];
108
+ const liveSourceMemoryIds = liveNodes?.get(nodeRef)?.sourceMemoryIds;
109
+ if (liveNodes && !liveSourceMemoryIds) return [];
110
+ const retainedSourceMemoryIds = mergeSortedUniqueStrings(sourceMemoryIds).filter((sourceMemoryId) =>
111
+ liveSourceMemoryIds ? liveSourceMemoryIds.includes(sourceMemoryId) : true
112
+ );
113
+ return retainedSourceMemoryIds.length > 0 ? [[nodeRef, retainedSourceMemoryIds] as const] : [];
114
+ })
115
+ );
116
+ return validateSourceMemoryIdsByNodeRef(retained);
117
+ }
118
+
119
+ export function resolveCueAnchorStoreDir(abstractionNodeStoreDir: string, overrideDir?: string): string {
69
120
  if (typeof overrideDir === "string" && overrideDir.trim().length > 0) {
70
121
  return overrideDir.trim();
71
122
  }
@@ -85,6 +136,7 @@ export function validateCueAnchor(raw: unknown): CueAnchor {
85
136
  recordedAt: assertIsoRecordedAt(assertString(raw.recordedAt, "recordedAt")),
86
137
  sessionKey: assertString(raw.sessionKey, "sessionKey"),
87
138
  nodeRefs: validateNodeRefs(raw.nodeRefs),
139
+ sourceMemoryIdsByNodeRef: validateSourceMemoryIdsByNodeRef(raw.sourceMemoryIdsByNodeRef),
88
140
  tags: optionalStringArray(raw.tags, "tags"),
89
141
  metadata: validateStringRecord(raw.metadata, "metadata"),
90
142
  };
@@ -101,13 +153,212 @@ export async function recordCueAnchor(options: {
101
153
  : path.join(options.memoryDir, "state", "abstraction-nodes");
102
154
  const rootDir = resolveCueAnchorStoreDir(abstractionNodeStoreDir, options.cueAnchorStoreDir);
103
155
  const validated = validateCueAnchor(options.anchor);
104
- const anchorDir = path.join(rootDir, validated.anchorType);
105
- const filePath = path.join(anchorDir, `${validated.anchorId}.json`);
156
+ const boundedNodeRefs = boundNodeRefs(validated.nodeRefs);
157
+ const bounded = validateCueAnchor({
158
+ ...validated,
159
+ nodeRefs: boundedNodeRefs,
160
+ sourceMemoryIdsByNodeRef: boundSourceMemoryIdsByNodeRef(validated.sourceMemoryIdsByNodeRef, boundedNodeRefs),
161
+ });
162
+ const anchorDir = path.join(rootDir, bounded.anchorType);
163
+ const filePath = path.join(anchorDir, `${bounded.anchorId}.json`);
106
164
  await mkdir(anchorDir, { recursive: true });
107
- await writeFile(filePath, JSON.stringify(validated, null, 2), "utf8");
165
+ await writeFile(filePath, JSON.stringify(bounded, null, 2), "utf8");
166
+ return filePath;
167
+ }
168
+
169
+ function mergeSortedValues(existing: string[] | undefined, incoming: string[] | undefined): string[] {
170
+ return mergeSortedUniqueStrings(existing, incoming);
171
+ }
172
+
173
+ function isNotFoundError(error: unknown): boolean {
174
+ return (
175
+ typeof error === "object" && error !== null && "code" in error && (error as { code?: unknown }).code === "ENOENT"
176
+ );
177
+ }
178
+
179
+ function boundNodeRefs(nodeRefs: string[], liveNodes?: Map<string, AbstractionNode>): string[] {
180
+ const uniqueRefs = mergeSortedUniqueStrings(nodeRefs);
181
+ if (!liveNodes) return uniqueRefs.slice(0, 50);
182
+ return uniqueRefs
183
+ .filter((nodeRef) => liveNodes.has(nodeRef))
184
+ .sort(
185
+ (left, right) =>
186
+ Date.parse(liveNodes.get(right)?.recordedAt ?? "") - Date.parse(liveNodes.get(left)?.recordedAt ?? "") ||
187
+ compareDeterministicStrings(left, right)
188
+ )
189
+ .slice(0, 50);
190
+ }
191
+
192
+ async function readLiveNodes(nodesDir: string): Promise<Map<string, AbstractionNode> | undefined> {
193
+ const liveNodes = new Map<string, AbstractionNode>();
194
+ let nodeFiles: string[];
195
+ try {
196
+ nodeFiles = await listJsonFilesStrict(nodesDir);
197
+ } catch (error) {
198
+ if (isNotFoundError(error)) return undefined;
199
+ throw error;
200
+ }
201
+ for (const filePath of nodeFiles) {
202
+ const node = validateAbstractionNode(await readJsonFile(filePath));
203
+ const previous = liveNodes.get(node.nodeId);
204
+ if (
205
+ !previous ||
206
+ Date.parse(previous.recordedAt) < Date.parse(node.recordedAt) ||
207
+ (Date.parse(previous.recordedAt) === Date.parse(node.recordedAt) &&
208
+ compareDeterministicStrings(previous.sessionKey, node.sessionKey) < 0)
209
+ ) {
210
+ liveNodes.set(node.nodeId, node);
211
+ }
212
+ }
213
+ return liveNodes;
214
+ }
215
+
216
+ export async function upsertCueAnchors(options: {
217
+ memoryDir: string;
218
+ abstractionNodeStoreDir?: string;
219
+ cueAnchorStoreDir?: string;
220
+ anchors: CueAnchor[];
221
+ }): Promise<string[]> {
222
+ const abstractionNodeStoreDir = resolveAbstractionNodeStoreDir(options.memoryDir, options.abstractionNodeStoreDir);
223
+ const incomingAnchors = options.anchors.map(validateCueAnchor);
224
+ if (incomingAnchors.length === 0) return [];
225
+
226
+ return withJsonStoreMutationLock(abstractionNodeStoreDir, async () => {
227
+ const rootDir = resolveCueAnchorStoreDir(abstractionNodeStoreDir, options.cueAnchorStoreDir);
228
+ const liveNodes = await readLiveNodes(path.join(abstractionNodeStoreDir, "nodes"));
229
+ const incomingByKey = new Map<string, CueAnchor[]>();
230
+ for (const anchor of incomingAnchors) {
231
+ const key = `${anchor.anchorType}\u0000${anchor.anchorId}`;
232
+ const grouped = incomingByKey.get(key) ?? [];
233
+ grouped.push(anchor);
234
+ incomingByKey.set(key, grouped);
235
+ }
236
+ const filePaths: string[] = [];
237
+ for (const key of [...incomingByKey.keys()].sort(compareDeterministicStrings)) {
238
+ const grouped = incomingByKey.get(key) ?? [];
239
+ grouped.sort(compareIncomingCueAnchors);
240
+ const incoming = grouped.shift();
241
+ if (!incoming) throw new Error(`cue anchor batch has no anchor: ${key}`);
242
+ const filePath = path.join(rootDir, incoming.anchorType, `${incoming.anchorId}.json`);
243
+ let existing: CueAnchor | undefined;
244
+ try {
245
+ existing = validateCueAnchor(await readJsonFile(filePath));
246
+ } catch (error) {
247
+ if (!isNotFoundError(error)) throw error;
248
+ }
249
+ let merged = mergeCueAnchors(existing, incoming, liveNodes);
250
+ for (const next of grouped) merged = mergeCueAnchors(merged, next, liveNodes);
251
+ await writeJsonFileAtomic(filePath, merged);
252
+ filePaths.push(filePath);
253
+ }
254
+ return filePaths;
255
+ });
256
+ }
257
+
258
+ function compareIncomingCueAnchors(left: CueAnchor, right: CueAnchor): number {
259
+ const recordedAtComparison = Date.parse(left.recordedAt) - Date.parse(right.recordedAt);
260
+ if (recordedAtComparison < 0) return -1;
261
+ if (recordedAtComparison > 0) return 1;
262
+ return compareDeterministicStrings(canonicalCueAnchorKey(left), canonicalCueAnchorKey(right));
263
+ }
264
+
265
+ function canonicalMetadata(metadata: Record<string, string> | undefined): Record<string, string> {
266
+ return Object.fromEntries(
267
+ Object.entries(metadata ?? {}).sort(([left], [right]) => compareDeterministicStrings(left, right))
268
+ );
269
+ }
270
+
271
+ function canonicalCueAnchorKey(anchor: CueAnchor): string {
272
+ return JSON.stringify({
273
+ ...anchor,
274
+ metadata: canonicalMetadata(anchor.metadata),
275
+ });
276
+ }
277
+
278
+ function mergeCueAnchors(
279
+ existing: CueAnchor | undefined,
280
+ incoming: CueAnchor,
281
+ liveNodes: Map<string, AbstractionNode> | undefined
282
+ ): CueAnchor {
283
+ const incomingIsNewest = !existing || Date.parse(existing.recordedAt) <= Date.parse(incoming.recordedAt);
284
+ const newest = incomingIsNewest ? incoming : existing;
285
+ const older = incomingIsNewest ? existing : incoming;
286
+ const mergedMetadata = canonicalMetadata({
287
+ ...(older?.metadata ?? {}),
288
+ ...(newest.metadata ?? {}),
289
+ });
290
+ const nodeRefs = boundNodeRefs(mergeSortedValues(existing?.nodeRefs, incoming.nodeRefs), liveNodes);
291
+ return validateCueAnchor({
292
+ ...newest,
293
+ nodeRefs,
294
+ sourceMemoryIdsByNodeRef: boundSourceMemoryIdsByNodeRef(
295
+ mergeSourceMemoryIdsByNodeRef(existing?.sourceMemoryIdsByNodeRef, incoming.sourceMemoryIdsByNodeRef),
296
+ nodeRefs,
297
+ liveNodes
298
+ ),
299
+ tags: mergeSortedValues(existing?.tags, incoming.tags),
300
+ metadata: mergedMetadata,
301
+ });
302
+ }
303
+
304
+ export async function upsertCueAnchor(options: {
305
+ memoryDir: string;
306
+ abstractionNodeStoreDir?: string;
307
+ cueAnchorStoreDir?: string;
308
+ anchor: CueAnchor;
309
+ }): Promise<string> {
310
+ const [filePath] = await upsertCueAnchors({ ...options, anchors: [options.anchor] });
311
+ if (!filePath) throw new Error("cue anchor upsert did not write a file");
108
312
  return filePath;
109
313
  }
110
314
 
315
+ export async function pruneOrphanCueAnchors(options: {
316
+ memoryDir: string;
317
+ abstractionNodeStoreDir?: string;
318
+ cueAnchorStoreDir?: string;
319
+ }): Promise<number> {
320
+ const abstractionNodeStoreDir = resolveAbstractionNodeStoreDir(options.memoryDir, options.abstractionNodeStoreDir);
321
+ return withJsonStoreMutationLock(abstractionNodeStoreDir, async () => {
322
+ const cueAnchorStoreDir = resolveCueAnchorStoreDir(abstractionNodeStoreDir, options.cueAnchorStoreDir);
323
+ const liveNodes = (await readLiveNodes(path.join(abstractionNodeStoreDir, "nodes"))) ?? new Map();
324
+ let removed = 0;
325
+ const anchorFiles = await listJsonFilesStrict(cueAnchorStoreDir, {
326
+ allowMissingDirectory: true,
327
+ });
328
+ for (const filePath of anchorFiles) {
329
+ let anchor: CueAnchor;
330
+ try {
331
+ anchor = validateCueAnchor(await readJsonFile(filePath));
332
+ } catch {
333
+ continue;
334
+ }
335
+ const nodeRefs = boundNodeRefs(anchor.nodeRefs, liveNodes);
336
+ const sourceMemoryIdsByNodeRef = boundSourceMemoryIdsByNodeRef(
337
+ anchor.sourceMemoryIdsByNodeRef,
338
+ nodeRefs,
339
+ liveNodes
340
+ );
341
+ if (nodeRefs.length === 0) {
342
+ try {
343
+ await unlink(filePath);
344
+ removed++;
345
+ } catch (error) {
346
+ if (!isNotFoundError(error)) throw error;
347
+ }
348
+ continue;
349
+ }
350
+ if (
351
+ nodeRefs.length !== anchor.nodeRefs.length ||
352
+ nodeRefs.some((nodeRef, index) => nodeRef !== anchor.nodeRefs[index]) ||
353
+ JSON.stringify(sourceMemoryIdsByNodeRef) !== JSON.stringify(anchor.sourceMemoryIdsByNodeRef)
354
+ ) {
355
+ await writeJsonFileAtomic(filePath, validateCueAnchor({ ...anchor, nodeRefs, sourceMemoryIdsByNodeRef }));
356
+ }
357
+ }
358
+ return removed;
359
+ });
360
+ }
361
+
111
362
  export async function getCueAnchorStoreStatus(options: {
112
363
  memoryDir: string;
113
364
  abstractionNodeStoreDir?: string;
@@ -119,7 +370,7 @@ export async function getCueAnchorStoreStatus(options: {
119
370
  ? options.abstractionNodeStoreDir.trim()
120
371
  : path.join(options.memoryDir, "state", "abstraction-nodes");
121
372
  const rootDir = resolveCueAnchorStoreDir(abstractionNodeStoreDir, options.cueAnchorStoreDir);
122
- const files = await listJsonFiles(rootDir);
373
+ const files = await listJsonFilesStrict(rootDir, { allowMissingDirectory: true });
123
374
  const anchors: CueAnchor[] = [];
124
375
  const invalidAnchors: Array<{ path: string; error: string }> = [];
125
376
 
@@ -134,7 +385,9 @@ export async function getCueAnchorStoreStatus(options: {
134
385
  }
135
386
  }
136
387
 
137
- anchors.sort((a, b) => b.recordedAt.localeCompare(a.recordedAt));
388
+ anchors.sort(
389
+ (a, b) => Date.parse(b.recordedAt) - Date.parse(a.recordedAt) || compareDeterministicStrings(a.anchorId, b.anchorId)
390
+ );
138
391
 
139
392
  const byType: Partial<Record<CueAnchorType, number>> = {};
140
393
  let totalNodeRefs = 0;
@@ -0,0 +1,83 @@
1
+ import assert from "node:assert/strict";
2
+ import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import test from "node:test";
6
+
7
+ import { clearMemoryCache } from "./memory-cache.js";
8
+ import { StorageManager } from "./storage.js";
9
+
10
+ async function writeFactFile(storage: StorageManager, body: string): Promise<{ id: string; filePath: string }> {
11
+ const today = new Date().toISOString().slice(0, 10);
12
+ const id = `fact-${Date.now()}-${Math.random().toString(36).slice(2)}`;
13
+ const factsDir = path.join(storage.dir, "facts", today);
14
+ const filePath = path.join(factsDir, `${id}.md`);
15
+ const now = new Date().toISOString();
16
+ await mkdir(factsDir, { recursive: true });
17
+ await writeFile(
18
+ filePath,
19
+ [
20
+ "---",
21
+ `id: ${id}`,
22
+ "category: fact",
23
+ `created: ${now}`,
24
+ `updated: ${now}`,
25
+ "source: extraction",
26
+ "confidence: 0.8",
27
+ "confidenceTier: high",
28
+ "tags: []",
29
+ "---",
30
+ "",
31
+ body,
32
+ "",
33
+ ].join("\n"),
34
+ "utf-8",
35
+ );
36
+ clearMemoryCache(storage.dir);
37
+ return { id, filePath };
38
+ }
39
+
40
+ test("dependency supersession fields survive serialize and parse", async () => {
41
+ const dir = await mkdtemp(path.join(os.tmpdir(), "remnic-dependency-frontmatter-"));
42
+ try {
43
+ const storage = new StorageManager(dir);
44
+ await storage.ensureDirectories();
45
+ const { id, filePath } = await writeFactFile(storage, "A dependent claim.");
46
+
47
+ await storage.updateMemoryFrontmatter(id, {
48
+ supersessionCause: "dependency",
49
+ invalidatedBy: "fact-support-1",
50
+ });
51
+
52
+ const raw = await readFile(filePath, "utf-8");
53
+ assert.match(raw, /\nsupersessionCause: dependency\n/);
54
+ assert.match(raw, /\ninvalidatedBy: fact-support-1\n/);
55
+
56
+ const memory = (await storage.readAllMemories()).find(
57
+ (candidate) => candidate.frontmatter.id === id,
58
+ );
59
+ assert.ok(memory);
60
+ assert.equal(memory.frontmatter.supersessionCause, "dependency");
61
+ assert.equal(memory.frontmatter.invalidatedBy, "fact-support-1");
62
+ } finally {
63
+ await rm(dir, { recursive: true, force: true });
64
+ }
65
+ });
66
+
67
+ test("legacy memory omits dependency supersession fields", async () => {
68
+ const dir = await mkdtemp(path.join(os.tmpdir(), "remnic-dependency-legacy-"));
69
+ try {
70
+ const storage = new StorageManager(dir);
71
+ await storage.ensureDirectories();
72
+ const { id } = await writeFactFile(storage, "A legacy claim.");
73
+
74
+ const memory = (await storage.readAllMemories()).find(
75
+ (candidate) => candidate.frontmatter.id === id,
76
+ );
77
+ assert.ok(memory);
78
+ assert.equal(memory.frontmatter.supersessionCause, undefined);
79
+ assert.equal(memory.frontmatter.invalidatedBy, undefined);
80
+ } finally {
81
+ await rm(dir, { recursive: true, force: true });
82
+ }
83
+ });
@@ -0,0 +1,94 @@
1
+ import { coerceBooleanLike, coerceNumber } from "./connectors/coerce.js";
2
+ import type { DependencyPropagationConfig } from "./types.js";
3
+
4
+ const DEFAULT_LINK_TYPES: DependencyPropagationConfig["linkTypes"] = ["supports", "follows"];
5
+ const ALLOWED_LINK_TYPES: Record<DependencyPropagationConfig["linkTypes"][number], true> = {
6
+ supports: true,
7
+ follows: true,
8
+ references: true,
9
+ };
10
+
11
+ function parseBoolean(value: unknown, fallback: boolean, keyName: string): boolean {
12
+ if (value === undefined) return fallback;
13
+ const parsed = coerceBooleanLike(value, keyName);
14
+ if (parsed === undefined) {
15
+ throw new Error(`${keyName} must be a boolean; got ${JSON.stringify(value)}`);
16
+ }
17
+ return parsed;
18
+ }
19
+
20
+ function parseIntegerAtLeast(value: unknown, min: number, fallback: number, keyName: string): number {
21
+ if (value === undefined) return fallback;
22
+ const parsed = coerceNumber(value, keyName);
23
+ if (
24
+ parsed === undefined ||
25
+ !Number.isFinite(parsed) ||
26
+ !Number.isInteger(parsed) ||
27
+ parsed < min
28
+ ) {
29
+ throw new Error(
30
+ `${keyName} must be ${min === 0 ? "a non-negative" : "a positive"} integer; got ${JSON.stringify(value)}`,
31
+ );
32
+ }
33
+ return parsed;
34
+ }
35
+
36
+ function parseLinkTypes(value: unknown): DependencyPropagationConfig["linkTypes"] {
37
+ if (value === undefined) return [...DEFAULT_LINK_TYPES];
38
+ if (!Array.isArray(value)) {
39
+ throw new Error(`dependencyPropagation.linkTypes must be an array; got ${JSON.stringify(value)}`);
40
+ }
41
+ const linkTypes: DependencyPropagationConfig["linkTypes"] = [];
42
+ for (const linkType of value) {
43
+ if (
44
+ typeof linkType !== "string" ||
45
+ !Object.hasOwn(ALLOWED_LINK_TYPES, linkType)
46
+ ) {
47
+ throw new Error(
48
+ "dependencyPropagation.linkTypes must contain only supports, follows, references",
49
+ );
50
+ }
51
+ if (!linkTypes.includes(linkType as DependencyPropagationConfig["linkTypes"][number])) {
52
+ linkTypes.push(linkType as DependencyPropagationConfig["linkTypes"][number]);
53
+ }
54
+ }
55
+ return linkTypes;
56
+ }
57
+
58
+ export function parseDependencyPropagationConfig(
59
+ cfg: Record<string, unknown>,
60
+ ): DependencyPropagationConfig {
61
+ const raw = cfg.dependencyPropagation;
62
+ if (raw === undefined) {
63
+ return {
64
+ enabled: false,
65
+ linkTypes: [...DEFAULT_LINK_TYPES],
66
+ maxDependents: 10,
67
+ timeoutMs: 20_000,
68
+ dryRun: false,
69
+ };
70
+ }
71
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
72
+ throw new Error(`dependencyPropagation must be a plain object; got ${JSON.stringify(raw)}`);
73
+ }
74
+
75
+ const block = raw as Record<string, unknown>;
76
+
77
+ return {
78
+ enabled: parseBoolean(block.enabled, false, "dependencyPropagation.enabled"),
79
+ linkTypes: parseLinkTypes(block.linkTypes),
80
+ maxDependents: parseIntegerAtLeast(
81
+ block.maxDependents,
82
+ 0,
83
+ 10,
84
+ "dependencyPropagation.maxDependents",
85
+ ),
86
+ timeoutMs: parseIntegerAtLeast(
87
+ block.timeoutMs,
88
+ 1,
89
+ 20_000,
90
+ "dependencyPropagation.timeoutMs",
91
+ ),
92
+ dryRun: parseBoolean(block.dryRun, false, "dependencyPropagation.dryRun"),
93
+ };
94
+ }
@@ -0,0 +1,14 @@
1
+ export function compareDeterministicStrings(left: string, right: string): number {
2
+ if (left < right) return -1;
3
+ if (left > right) return 1;
4
+ return 0;
5
+ }
6
+
7
+ export function mergeSortedUniqueStrings(...collections: Array<Iterable<string> | undefined>): string[] {
8
+ const values = new Set<string>();
9
+ for (const collection of collections) {
10
+ if (!collection) continue;
11
+ for (const value of collection) values.add(value);
12
+ }
13
+ return [...values].sort(compareDeterministicStrings);
14
+ }
@@ -0,0 +1,71 @@
1
+ import { EXTRACTION_RESPONSE_PLACEHOLDERS } from "./extraction-prompt.js";
2
+ import { normalizeRecallTokens } from "./recall-tokenization.js";
3
+ import { sanitizeMemoryContent } from "./sanitize.js";
4
+ import type { ExtractedFact } from "./types.js";
5
+
6
+ export function isPlainRecord(value: unknown): value is Record<string, unknown> {
7
+ return typeof value === "object" && value !== null && !Array.isArray(value);
8
+ }
9
+
10
+ export function containsExtractionPlaceholder(value: unknown): boolean {
11
+ if (typeof value === "string") return EXTRACTION_RESPONSE_PLACEHOLDERS[value.trim()] === true;
12
+ if (Array.isArray(value)) return value.some(containsExtractionPlaceholder);
13
+ return isPlainRecord(value) && Object.values(value).some(containsExtractionPlaceholder);
14
+ }
15
+
16
+ export function extractionText(value: unknown): string | undefined {
17
+ if (typeof value !== "string") return undefined;
18
+ const text = value.trim();
19
+ return text.length > 0 && !containsExtractionPlaceholder(text) ? text : undefined;
20
+ }
21
+
22
+ export function extractionAttributes(value: unknown): Record<string, string> | undefined {
23
+ if (!isPlainRecord(value)) return undefined;
24
+ const attributes: Record<string, string> = {};
25
+ for (const [key, candidate] of Object.entries(value).sort(([left], [right]) => left.localeCompare(right))) {
26
+ const normalizedKey = extractionText(key);
27
+ const normalizedValue = extractionText(candidate);
28
+ if (normalizedKey !== undefined && normalizedValue !== undefined) {
29
+ attributes[normalizedKey] = normalizedValue;
30
+ }
31
+ }
32
+ return Object.keys(attributes).length > 0 ? attributes : undefined;
33
+ }
34
+
35
+ const EXTRACTION_CUE_ANCHOR_TYPES = new Set(["entity", "file", "tool", "outcome", "constraint", "date"]);
36
+
37
+ export function extractionCueAnchors(value: unknown): NonNullable<ExtractedFact["cueAnchors"]> | undefined {
38
+ if (!Array.isArray(value)) return undefined;
39
+ const anchorsByIdentity = new Map<string, NonNullable<ExtractedFact["cueAnchors"]>[number]>();
40
+ for (const candidate of value) {
41
+ if (!isPlainRecord(candidate)) continue;
42
+ const type = extractionText(candidate.type);
43
+ const anchorValue = extractionText(candidate.value);
44
+ const sanitizedAnchor = anchorValue === undefined ? undefined : sanitizeMemoryContent(anchorValue);
45
+ const sanitizedAnchorValue = sanitizedAnchor?.clean === true ? sanitizedAnchor.text.trim() : undefined;
46
+ if (
47
+ type === undefined ||
48
+ sanitizedAnchorValue === undefined ||
49
+ sanitizedAnchorValue.length === 0 ||
50
+ sanitizedAnchorValue.length > 120 ||
51
+ !EXTRACTION_CUE_ANCHOR_TYPES.has(type)
52
+ ) {
53
+ continue;
54
+ }
55
+ const normalizedCue = normalizeRecallTokens(sanitizedAnchorValue).join(" ");
56
+ if (normalizedCue.length === 0) continue;
57
+ const identity = `${type}:${normalizedCue}`;
58
+ const existing = anchorsByIdentity.get(identity);
59
+ if (!existing || sanitizedAnchorValue.localeCompare(existing.value) < 0) {
60
+ anchorsByIdentity.set(identity, {
61
+ type: type as NonNullable<ExtractedFact["cueAnchors"]>[number]["type"],
62
+ value: sanitizedAnchorValue,
63
+ });
64
+ }
65
+ }
66
+ const anchors = [...anchorsByIdentity.entries()]
67
+ .sort(([left], [right]) => left.localeCompare(right))
68
+ .slice(0, 3)
69
+ .map(([, anchor]) => anchor);
70
+ return anchors.length > 0 ? anchors : undefined;
71
+ }