@remnic/core 1.1.31 → 9.3.515

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 (1087) hide show
  1. package/dist/abstraction-nodes.js +2 -2
  2. package/dist/access-cli.d.ts +1 -1
  3. package/dist/access-cli.js +156 -119
  4. package/dist/access-cli.js.map +1 -1
  5. package/dist/access-http.d.ts +8 -5
  6. package/dist/access-http.js +51 -51
  7. package/dist/access-idempotency.d.ts +2 -0
  8. package/dist/access-idempotency.js +1 -1
  9. package/dist/access-mcp.d.ts +16 -9
  10. package/dist/access-mcp.js +44 -44
  11. package/dist/access-schema.d.ts +45 -13
  12. package/dist/access-schema.js +8 -8
  13. package/dist/{access-service-CkZyb35d.d.ts → access-service-qrrIrC-0.d.ts} +5 -128
  14. package/dist/access-service.d.ts +7 -4
  15. package/dist/access-service.js +40 -40
  16. package/dist/action-confidence.d.ts +1 -0
  17. package/dist/active-memory-bridge.d.ts +1 -0
  18. package/dist/active-memory-bridge.js +3 -2
  19. package/dist/active-recall.d.ts +1 -0
  20. package/dist/active-recall.js +14 -9
  21. package/dist/active-recall.js.map +1 -1
  22. package/dist/adapters/claude-code.d.ts +6 -2
  23. package/dist/adapters/claude-code.js +2 -2
  24. package/dist/adapters/codex.d.ts +5 -1
  25. package/dist/adapters/codex.js +2 -2
  26. package/dist/adapters/hermes.js +2 -2
  27. package/dist/adapters/index.js +6 -6
  28. package/dist/adapters/registry.js +6 -6
  29. package/dist/adapters/replit.d.ts +4 -2
  30. package/dist/adapters/replit.js +2 -2
  31. package/dist/adapters/types.d.ts +4 -0
  32. package/dist/adapters/types.js +1 -1
  33. package/dist/behavior-learner.d.ts +1 -0
  34. package/dist/behavior-signals.d.ts +1 -0
  35. package/dist/behavior-signals.js +1 -1
  36. package/dist/bootstrap.d.ts +5 -3
  37. package/dist/bootstrap.js +2 -2
  38. package/dist/boxes.d.ts +1 -0
  39. package/dist/boxes.js +1 -1
  40. package/dist/briefing.d.ts +1 -0
  41. package/dist/briefing.js +9 -9
  42. package/dist/buffer-surprise-report.d.ts +1 -0
  43. package/dist/buffer.d.ts +1 -0
  44. package/dist/buffer.js +2 -2
  45. package/dist/bulk-import/index.d.ts +28 -0
  46. package/dist/bulk-import/index.js +31 -0
  47. package/dist/calibration.d.ts +2 -0
  48. package/dist/calibration.js +50 -17
  49. package/dist/calibration.js.map +1 -1
  50. package/dist/{capsule-crypto-5CYAGVC5.js → capsule-crypto-7FJQINUR.js} +2 -2
  51. package/dist/{capsule-merge-4MGKE7C5.js → capsule-merge-T2JRE46P.js} +3 -3
  52. package/dist/causal-behavior.d.ts +1 -0
  53. package/dist/causal-behavior.js +4 -4
  54. package/dist/causal-chain.js +4 -4
  55. package/dist/causal-consolidation.d.ts +16 -1
  56. package/dist/causal-consolidation.js +115 -32
  57. package/dist/causal-consolidation.js.map +1 -1
  58. package/dist/causal-retrieval.js +14 -6
  59. package/dist/causal-retrieval.js.map +1 -1
  60. package/dist/causal-trajectory-graph.js +2 -2
  61. package/dist/causal-trajectory.js +2 -2
  62. package/dist/{chunk-SAZS2QZB.js → chunk-23UORJ4S.js} +3 -3
  63. package/dist/{chunk-76FLAAUC.js → chunk-2AN2L4NL.js} +17 -6
  64. package/dist/chunk-2AN2L4NL.js.map +1 -0
  65. package/dist/{chunk-W4L6CZKA.js → chunk-2DL3OFLD.js} +15 -10
  66. package/dist/chunk-2DL3OFLD.js.map +1 -0
  67. package/dist/{chunk-7OZ53EXP.js → chunk-2NLLXCJG.js} +21 -10
  68. package/dist/chunk-2NLLXCJG.js.map +1 -0
  69. package/dist/{chunk-PK7H5L6Y.js → chunk-2NM43EWN.js} +2 -2
  70. package/dist/{chunk-PYXS46O7.js → chunk-3BP57I6J.js} +2 -2
  71. package/dist/{chunk-FBYESMQ2.js → chunk-3C5RPJAX.js} +2 -2
  72. package/dist/{chunk-ZAVUCJ4H.js → chunk-3Q4H3OBR.js} +150 -65
  73. package/dist/chunk-3Q4H3OBR.js.map +1 -0
  74. package/dist/{chunk-FKFMOY3N.js → chunk-42NQ7AVG.js} +3 -4
  75. package/dist/{chunk-FKFMOY3N.js.map → chunk-42NQ7AVG.js.map} +1 -1
  76. package/dist/chunk-4426WSWL.js +73 -0
  77. package/dist/chunk-4426WSWL.js.map +1 -0
  78. package/dist/{chunk-LIRZNNUP.js → chunk-44442YCH.js} +5 -2
  79. package/dist/chunk-44442YCH.js.map +1 -0
  80. package/dist/{chunk-H3ME6L6D.js → chunk-46GJIW5M.js} +23 -20
  81. package/dist/chunk-46GJIW5M.js.map +1 -0
  82. package/dist/{chunk-QDZ2RLEC.js → chunk-472U7RDF.js} +3 -3
  83. package/dist/chunk-472U7RDF.js.map +1 -0
  84. package/dist/{chunk-NN2DKE4T.js → chunk-4H5ZJHEN.js} +16 -3
  85. package/dist/{chunk-NN2DKE4T.js.map → chunk-4H5ZJHEN.js.map} +1 -1
  86. package/dist/{chunk-56K5QLHX.js → chunk-4HP7HIE3.js} +56 -13
  87. package/dist/chunk-4HP7HIE3.js.map +1 -0
  88. package/dist/{chunk-RK2Y4XOM.js → chunk-4JRRISLU.js} +9 -6
  89. package/dist/chunk-4JRRISLU.js.map +1 -0
  90. package/dist/{chunk-U7EJOMFC.js → chunk-4Q73JBSM.js} +4 -4
  91. package/dist/{chunk-XKLD5OK4.js → chunk-4RR6ROTB.js} +10 -11
  92. package/dist/chunk-4RR6ROTB.js.map +1 -0
  93. package/dist/{chunk-4KGVTPGD.js → chunk-6F6BXB7A.js} +9 -8
  94. package/dist/chunk-6F6BXB7A.js.map +1 -0
  95. package/dist/{chunk-NMZY542O.js → chunk-6URPAY2D.js} +41 -17
  96. package/dist/chunk-6URPAY2D.js.map +1 -0
  97. package/dist/{chunk-N53K2EXC.js → chunk-6VF75M3X.js} +2 -2
  98. package/dist/{chunk-XSZEP4SF.js → chunk-6XSPNR6L.js} +6 -5
  99. package/dist/chunk-6XSPNR6L.js.map +1 -0
  100. package/dist/{chunk-6H2TESSP.js → chunk-765K3SAT.js} +3 -3
  101. package/dist/{chunk-EDTHC6UD.js → chunk-77NAFXUD.js} +2 -2
  102. package/dist/{chunk-S7KDBTWT.js → chunk-7F7Z6MOS.js} +29 -14
  103. package/dist/chunk-7F7Z6MOS.js.map +1 -0
  104. package/dist/{chunk-MZH6EHNR.js → chunk-7H6CFEBJ.js} +41 -14
  105. package/dist/chunk-7H6CFEBJ.js.map +1 -0
  106. package/dist/{chunk-575RMLWN.js → chunk-7MV5CWTE.js} +26 -20
  107. package/dist/chunk-7MV5CWTE.js.map +1 -0
  108. package/dist/{chunk-MGKYQQYF.js → chunk-7Q3RCKAQ.js} +2 -2
  109. package/dist/chunk-7RXCMVFQ.js +27 -0
  110. package/dist/chunk-7RXCMVFQ.js.map +1 -0
  111. package/dist/{chunk-DGXUHMOV.js → chunk-A2IYSXDQ.js} +25 -6
  112. package/dist/chunk-A2IYSXDQ.js.map +1 -0
  113. package/dist/{chunk-EABGC2TL.js → chunk-A2Z6UCWT.js} +26 -4
  114. package/dist/chunk-A2Z6UCWT.js.map +1 -0
  115. package/dist/{chunk-3VAL7ZL2.js → chunk-A52AKD7C.js} +59 -24
  116. package/dist/chunk-A52AKD7C.js.map +1 -0
  117. package/dist/{chunk-5375UYTQ.js → chunk-A6D7A2FW.js} +4 -4
  118. package/dist/chunk-A6D7A2FW.js.map +1 -0
  119. package/dist/{chunk-FAAFWE4G.js → chunk-ALEPI75L.js} +24 -6
  120. package/dist/chunk-ALEPI75L.js.map +1 -0
  121. package/dist/{chunk-3SLRNYNG.js → chunk-AUDJPF4N.js} +15 -4
  122. package/dist/chunk-AUDJPF4N.js.map +1 -0
  123. package/dist/chunk-B5XMS73R.js +145 -0
  124. package/dist/chunk-B5XMS73R.js.map +1 -0
  125. package/dist/{chunk-HXXBL2KD.js → chunk-BECQDWBA.js} +44 -4
  126. package/dist/chunk-BECQDWBA.js.map +1 -0
  127. package/dist/{chunk-7SEAZFFB.js → chunk-BEUDU7Y4.js} +24 -4
  128. package/dist/chunk-BEUDU7Y4.js.map +1 -0
  129. package/dist/{chunk-XVVIG67A.js → chunk-BLZAVUD2.js} +61 -17
  130. package/dist/chunk-BLZAVUD2.js.map +1 -0
  131. package/dist/chunk-CHBI22MI.js +159 -0
  132. package/dist/chunk-CHBI22MI.js.map +1 -0
  133. package/dist/{chunk-GDFS42HT.js → chunk-CHCA44C3.js} +15 -8
  134. package/dist/chunk-CHCA44C3.js.map +1 -0
  135. package/dist/chunk-CINZGPSJ.js +22 -0
  136. package/dist/chunk-CINZGPSJ.js.map +1 -0
  137. package/dist/chunk-CMTINOFS.js +36 -0
  138. package/dist/chunk-CMTINOFS.js.map +1 -0
  139. package/dist/{chunk-34DQE4KF.js → chunk-CO7ZO4TU.js} +2 -2
  140. package/dist/{chunk-PFV5C235.js → chunk-CPPS65WS.js} +2 -1
  141. package/dist/{chunk-PFV5C235.js.map → chunk-CPPS65WS.js.map} +1 -1
  142. package/dist/{chunk-DINWEURR.js → chunk-CSKLPDN6.js} +20 -6
  143. package/dist/chunk-CSKLPDN6.js.map +1 -0
  144. package/dist/chunk-CWWMTTQE.js +566 -0
  145. package/dist/chunk-CWWMTTQE.js.map +1 -0
  146. package/dist/{chunk-IQT3XTKW.js → chunk-D24OXEPB.js} +13 -7
  147. package/dist/chunk-D24OXEPB.js.map +1 -0
  148. package/dist/{chunk-TPU5L5EY.js → chunk-D6WE5MTW.js} +272 -411
  149. package/dist/chunk-D6WE5MTW.js.map +1 -0
  150. package/dist/{chunk-WIICJPET.js → chunk-DEUNUKTD.js} +6 -4
  151. package/dist/{chunk-WIICJPET.js.map → chunk-DEUNUKTD.js.map} +1 -1
  152. package/dist/{chunk-ZYVPLJ4T.js → chunk-DHGSZ3UD.js} +9 -7
  153. package/dist/chunk-DHGSZ3UD.js.map +1 -0
  154. package/dist/{chunk-JR4ZC3G4.js → chunk-DLJ4IR6M.js} +91 -41
  155. package/dist/chunk-DLJ4IR6M.js.map +1 -0
  156. package/dist/{chunk-U4SCL7B7.js → chunk-DRD2Q7HQ.js} +82 -18
  157. package/dist/chunk-DRD2Q7HQ.js.map +1 -0
  158. package/dist/{chunk-2IWUMAES.js → chunk-E62SBGQ3.js} +28 -13
  159. package/dist/chunk-E62SBGQ3.js.map +1 -0
  160. package/dist/{chunk-C5BCH4ZS.js → chunk-EAZGEEG2.js} +21 -3
  161. package/dist/chunk-EAZGEEG2.js.map +1 -0
  162. package/dist/{chunk-TPB3I2AC.js → chunk-ECZU5BJH.js} +31 -10
  163. package/dist/chunk-ECZU5BJH.js.map +1 -0
  164. package/dist/{chunk-77H5NU3M.js → chunk-EDBEWFJO.js} +82 -18
  165. package/dist/chunk-EDBEWFJO.js.map +1 -0
  166. package/dist/chunk-EDQVAMQI.js +308 -0
  167. package/dist/chunk-EDQVAMQI.js.map +1 -0
  168. package/dist/{chunk-RRF5UOBJ.js → chunk-EI6V5UXY.js} +22 -15
  169. package/dist/chunk-EI6V5UXY.js.map +1 -0
  170. package/dist/{chunk-I5GLV3VE.js → chunk-EIPUHVKE.js} +31 -24
  171. package/dist/{chunk-I5GLV3VE.js.map → chunk-EIPUHVKE.js.map} +1 -1
  172. package/dist/{chunk-ZKSK55RC.js → chunk-ETUPBUHB.js} +2 -2
  173. package/dist/{chunk-25MQ7IHJ.js → chunk-EUML3N6B.js} +17 -6
  174. package/dist/chunk-EUML3N6B.js.map +1 -0
  175. package/dist/{chunk-5RGLBDQF.js → chunk-EVZFIAPG.js} +12 -12
  176. package/dist/chunk-EVZFIAPG.js.map +1 -0
  177. package/dist/{chunk-QRNI5JBH.js → chunk-EYIEWJNI.js} +2 -2
  178. package/dist/{chunk-YU5KIWYQ.js → chunk-FER4WARO.js} +79 -41
  179. package/dist/chunk-FER4WARO.js.map +1 -0
  180. package/dist/{chunk-43PJZYGL.js → chunk-FPGE5NVO.js} +45 -10
  181. package/dist/chunk-FPGE5NVO.js.map +1 -0
  182. package/dist/{chunk-C6QPK5GG.js → chunk-FZZ2QTJI.js} +2 -2
  183. package/dist/{chunk-D46YSIYX.js → chunk-G3Z3QEF5.js} +19 -11
  184. package/dist/{chunk-D46YSIYX.js.map → chunk-G3Z3QEF5.js.map} +1 -1
  185. package/dist/{chunk-3JXBXXM2.js → chunk-G4IAEX6D.js} +2 -2
  186. package/dist/{chunk-MSWG7JI6.js → chunk-G56P5RLD.js} +8 -2
  187. package/dist/chunk-G56P5RLD.js.map +1 -0
  188. package/dist/{chunk-AGZQD76C.js → chunk-GCGJW34D.js} +48 -2
  189. package/dist/chunk-GCGJW34D.js.map +1 -0
  190. package/dist/chunk-H2NCNXMS.js +159 -0
  191. package/dist/chunk-H2NCNXMS.js.map +1 -0
  192. package/dist/{chunk-XYIK4LF6.js → chunk-H3FZVNRN.js} +8 -2
  193. package/dist/chunk-H3FZVNRN.js.map +1 -0
  194. package/dist/{chunk-TK4UEOSK.js → chunk-HDDRVXX4.js} +8 -8
  195. package/dist/chunk-HDDRVXX4.js.map +1 -0
  196. package/dist/{chunk-LLQ2LLWF.js → chunk-HENLZHIT.js} +15 -5
  197. package/dist/chunk-HENLZHIT.js.map +1 -0
  198. package/dist/{chunk-N2D6GXBM.js → chunk-HINSGUA7.js} +28 -20
  199. package/dist/chunk-HINSGUA7.js.map +1 -0
  200. package/dist/{chunk-APO3DCMU.js → chunk-HLAVGJ62.js} +30 -8
  201. package/dist/chunk-HLAVGJ62.js.map +1 -0
  202. package/dist/{chunk-TPMQ3G6Z.js → chunk-HOJZMQ4J.js} +2 -2
  203. package/dist/chunk-HOJZMQ4J.js.map +1 -0
  204. package/dist/{chunk-LUDTDZLK.js → chunk-HPWVAEET.js} +33 -7
  205. package/dist/chunk-HPWVAEET.js.map +1 -0
  206. package/dist/{chunk-NZL6GGQE.js → chunk-HQ6NIBL6.js} +92 -30
  207. package/dist/chunk-HQ6NIBL6.js.map +1 -0
  208. package/dist/{chunk-UWVJF25J.js → chunk-HWVTS5NO.js} +20 -6
  209. package/dist/chunk-HWVTS5NO.js.map +1 -0
  210. package/dist/{chunk-2WWLHTZY.js → chunk-IC4GELZE.js} +2 -2
  211. package/dist/{chunk-QA2ZAPBU.js → chunk-IPLYGWQF.js} +28 -20
  212. package/dist/chunk-IPLYGWQF.js.map +1 -0
  213. package/dist/{chunk-A6KTB5R6.js → chunk-IQ3OI2RR.js} +3 -3
  214. package/dist/chunk-IQ3OI2RR.js.map +1 -0
  215. package/dist/{chunk-6LVVDPJ4.js → chunk-J64TK33U.js} +3 -4
  216. package/dist/chunk-J64TK33U.js.map +1 -0
  217. package/dist/{chunk-6FC5EGNV.js → chunk-JBPKEARU.js} +15 -5
  218. package/dist/{chunk-6FC5EGNV.js.map → chunk-JBPKEARU.js.map} +1 -1
  219. package/dist/{chunk-RHY3HH7P.js → chunk-JFEKNTX7.js} +125 -33
  220. package/dist/chunk-JFEKNTX7.js.map +1 -0
  221. package/dist/{chunk-TZOLIGIG.js → chunk-JJEJJ7RK.js} +4 -2
  222. package/dist/chunk-JJEJJ7RK.js.map +1 -0
  223. package/dist/{chunk-PCUKNJAZ.js → chunk-JKV57BTN.js} +2 -2
  224. package/dist/{chunk-EJI5XIBB.js → chunk-JLNBQWZ2.js} +55 -7
  225. package/dist/chunk-JLNBQWZ2.js.map +1 -0
  226. package/dist/{chunk-XIG5PDM7.js → chunk-JUC24CTX.js} +8 -12
  227. package/dist/chunk-JUC24CTX.js.map +1 -0
  228. package/dist/{chunk-3ZLVGM76.js → chunk-JYIKKAK3.js} +106 -44
  229. package/dist/chunk-JYIKKAK3.js.map +1 -0
  230. package/dist/{chunk-OIGNEXKZ.js → chunk-K5O2QY6T.js} +5 -1
  231. package/dist/{chunk-OIGNEXKZ.js.map → chunk-K5O2QY6T.js.map} +1 -1
  232. package/dist/{chunk-ZTFCYYEZ.js → chunk-KCYE2MZM.js} +3 -3
  233. package/dist/chunk-KCYE2MZM.js.map +1 -0
  234. package/dist/{chunk-JWPLJLDU.js → chunk-KD3QD3A5.js} +2 -2
  235. package/dist/{chunk-JWPLJLDU.js.map → chunk-KD3QD3A5.js.map} +1 -1
  236. package/dist/{chunk-YRMVARQP.js → chunk-KFY3SGN7.js} +49 -2
  237. package/dist/chunk-KFY3SGN7.js.map +1 -0
  238. package/dist/{chunk-CYFQJMUV.js → chunk-KIB7SDIJ.js} +15 -10
  239. package/dist/chunk-KIB7SDIJ.js.map +1 -0
  240. package/dist/{chunk-3KW65B36.js → chunk-KILOTVIF.js} +95 -48
  241. package/dist/chunk-KILOTVIF.js.map +1 -0
  242. package/dist/{chunk-MXFBBHJU.js → chunk-KJMYHC7K.js} +10 -5
  243. package/dist/chunk-KJMYHC7K.js.map +1 -0
  244. package/dist/{chunk-W3LR522O.js → chunk-KM2A35EO.js} +36 -34
  245. package/dist/chunk-KM2A35EO.js.map +1 -0
  246. package/dist/{chunk-WELDCG6C.js → chunk-L227SKTB.js} +109 -36
  247. package/dist/chunk-L227SKTB.js.map +1 -0
  248. package/dist/{chunk-W6AQJ2PY.js → chunk-L7S47WZT.js} +35 -16
  249. package/dist/chunk-L7S47WZT.js.map +1 -0
  250. package/dist/{chunk-BVF3AGJP.js → chunk-LJBOVCQG.js} +26 -11
  251. package/dist/chunk-LJBOVCQG.js.map +1 -0
  252. package/dist/{chunk-2KI4QFHU.js → chunk-LMDRGRJ2.js} +2 -2
  253. package/dist/{chunk-MY6TPVXW.js → chunk-LMPHTYJC.js} +2 -2
  254. package/dist/{chunk-EHRTFRWW.js → chunk-LQHDIS7L.js} +10 -5
  255. package/dist/chunk-LQHDIS7L.js.map +1 -0
  256. package/dist/chunk-LUDUFZTV.js +170 -0
  257. package/dist/chunk-LUDUFZTV.js.map +1 -0
  258. package/dist/{chunk-5HRY2WRF.js → chunk-LZ3VEOU5.js} +2 -2
  259. package/dist/{chunk-Q7P4WJDP.js → chunk-M5T4Q2ZU.js} +1 -1
  260. package/dist/chunk-M5T4Q2ZU.js.map +1 -0
  261. package/dist/{chunk-ICRIXAP2.js → chunk-MC4FJXPA.js} +16 -6
  262. package/dist/chunk-MC4FJXPA.js.map +1 -0
  263. package/dist/{chunk-WPGJYVUH.js → chunk-MGVIEM2O.js} +23 -6
  264. package/dist/chunk-MGVIEM2O.js.map +1 -0
  265. package/dist/{chunk-YROHKYBY.js → chunk-O27WNHTT.js} +22 -6
  266. package/dist/chunk-O27WNHTT.js.map +1 -0
  267. package/dist/{chunk-NGAVDO7E.js → chunk-OADWQ5CR.js} +2 -2
  268. package/dist/{chunk-2NMMFZ5T.js → chunk-OD4FM2U7.js} +6 -3
  269. package/dist/chunk-OD4FM2U7.js.map +1 -0
  270. package/dist/{chunk-OZHRDTDX.js → chunk-OKTXM5H4.js} +11 -1
  271. package/dist/chunk-OKTXM5H4.js.map +1 -0
  272. package/dist/{chunk-RXDLTSWT.js → chunk-ONPLNAPX.js} +16 -7
  273. package/dist/chunk-ONPLNAPX.js.map +1 -0
  274. package/dist/{chunk-FJ43PRLT.js → chunk-ORFGK3XI.js} +20 -14
  275. package/dist/chunk-ORFGK3XI.js.map +1 -0
  276. package/dist/{chunk-DOM4GKSW.js → chunk-OZKVVUJB.js} +3 -3
  277. package/dist/{chunk-MT4HVDUZ.js → chunk-PM3QHTFT.js} +3 -3
  278. package/dist/{chunk-4DWOBS2A.js → chunk-PRQJ5ESM.js} +27 -2
  279. package/dist/{chunk-4DWOBS2A.js.map → chunk-PRQJ5ESM.js.map} +1 -1
  280. package/dist/chunk-PU44GBL4.js +52 -0
  281. package/dist/chunk-PU44GBL4.js.map +1 -0
  282. package/dist/{chunk-MJFNCJXV.js → chunk-Q4CAQGKQ.js} +47 -9
  283. package/dist/chunk-Q4CAQGKQ.js.map +1 -0
  284. package/dist/{chunk-U3WSW6PZ.js → chunk-QMYXNM4P.js} +90 -35
  285. package/dist/chunk-QMYXNM4P.js.map +1 -0
  286. package/dist/{chunk-NBNN5GOB.js → chunk-QY7YA7OL.js} +11 -2
  287. package/dist/chunk-QY7YA7OL.js.map +1 -0
  288. package/dist/{chunk-QLLBRHAT.js → chunk-R26QUUQN.js} +181 -257
  289. package/dist/chunk-R26QUUQN.js.map +1 -0
  290. package/dist/{chunk-ZK7I7JYV.js → chunk-R3PS27B4.js} +7 -7
  291. package/dist/{chunk-TMQLARTH.js → chunk-RCTS5CKK.js} +33 -14
  292. package/dist/chunk-RCTS5CKK.js.map +1 -0
  293. package/dist/{chunk-2PRLKQAH.js → chunk-RLV3PQGH.js} +35 -19
  294. package/dist/chunk-RLV3PQGH.js.map +1 -0
  295. package/dist/{chunk-WW3QQF4H.js → chunk-ROZJACKP.js} +16 -1
  296. package/dist/chunk-ROZJACKP.js.map +1 -0
  297. package/dist/{chunk-7MNMYOFP.js → chunk-RSUYKGGZ.js} +3 -4
  298. package/dist/chunk-RSUYKGGZ.js.map +1 -0
  299. package/dist/{chunk-LT3NLYSI.js → chunk-RUZOJKNF.js} +10 -7
  300. package/dist/chunk-RUZOJKNF.js.map +1 -0
  301. package/dist/{chunk-326G7DJK.js → chunk-RW5DGAGO.js} +67 -13
  302. package/dist/chunk-RW5DGAGO.js.map +1 -0
  303. package/dist/{chunk-KOSORCJG.js → chunk-S53PKKWK.js} +63 -24
  304. package/dist/chunk-S53PKKWK.js.map +1 -0
  305. package/dist/{chunk-65PG43EQ.js → chunk-S7WU3Y3D.js} +21 -4
  306. package/dist/chunk-S7WU3Y3D.js.map +1 -0
  307. package/dist/{chunk-SKE7JYKA.js → chunk-SFXKHM7P.js} +2 -2
  308. package/dist/{chunk-HMDCOMYU.js → chunk-SKGV326D.js} +3 -3
  309. package/dist/chunk-T2PO5MUF.js +62 -0
  310. package/dist/chunk-T2PO5MUF.js.map +1 -0
  311. package/dist/{chunk-C7VW7C3F.js → chunk-TDKQGLJW.js} +3 -3
  312. package/dist/chunk-TDKQGLJW.js.map +1 -0
  313. package/dist/{chunk-3QKK7QOS.js → chunk-TERNBNJB.js} +3 -3
  314. package/dist/chunk-TERNBNJB.js.map +1 -0
  315. package/dist/{chunk-MXC3AP5I.js → chunk-TGQ2NTWH.js} +12 -7
  316. package/dist/chunk-TGQ2NTWH.js.map +1 -0
  317. package/dist/{chunk-3Y4P7RXM.js → chunk-TMSXWOBZ.js} +3 -4
  318. package/dist/chunk-TMSXWOBZ.js.map +1 -0
  319. package/dist/{chunk-3TNBOMQT.js → chunk-TVRN5QKH.js} +11 -11
  320. package/dist/{chunk-3TNBOMQT.js.map → chunk-TVRN5QKH.js.map} +1 -1
  321. package/dist/{chunk-5UM2VJ6D.js → chunk-UEY3VB6W.js} +2 -2
  322. package/dist/{chunk-I6K5FBRQ.js → chunk-UI3NYK34.js} +4 -1
  323. package/dist/{chunk-I6K5FBRQ.js.map → chunk-UI3NYK34.js.map} +1 -1
  324. package/dist/{chunk-VBJ7V5SK.js → chunk-UIPDNLXA.js} +21 -8
  325. package/dist/chunk-UIPDNLXA.js.map +1 -0
  326. package/dist/{chunk-GIF42EW3.js → chunk-UP6MOYCB.js} +3 -3
  327. package/dist/{chunk-K4FLSOR5.js → chunk-USYGGIJZ.js} +44 -15
  328. package/dist/chunk-USYGGIJZ.js.map +1 -0
  329. package/dist/{chunk-FIT6DMX6.js → chunk-UWY7GIVS.js} +152 -54
  330. package/dist/chunk-UWY7GIVS.js.map +1 -0
  331. package/dist/{chunk-MRILGULB.js → chunk-V2RCP53Q.js} +2 -2
  332. package/dist/{chunk-XKECPATV.js → chunk-VFUEZZBS.js} +113 -4
  333. package/dist/chunk-VFUEZZBS.js.map +1 -0
  334. package/dist/{chunk-FSFEQI74.js → chunk-W7L6HXUC.js} +2 -2
  335. package/dist/{chunk-3IQ2TR4N.js → chunk-WLEB7WCG.js} +2 -2
  336. package/dist/{chunk-GL6I6MEQ.js → chunk-WSGF57U2.js} +3 -3
  337. package/dist/{chunk-KNKUID7G.js → chunk-X7Y7WX73.js} +72 -6
  338. package/dist/chunk-X7Y7WX73.js.map +1 -0
  339. package/dist/{chunk-5NPGSAVB.js → chunk-XEKAG3FM.js} +23 -5
  340. package/dist/chunk-XEKAG3FM.js.map +1 -0
  341. package/dist/{chunk-3APJ5EVB.js → chunk-XKIQZXUB.js} +41 -26
  342. package/dist/chunk-XKIQZXUB.js.map +1 -0
  343. package/dist/chunk-XKXKSQU7.js +92 -0
  344. package/dist/chunk-XKXKSQU7.js.map +1 -0
  345. package/dist/{chunk-JA3AK3PT.js → chunk-XNLXAWHX.js} +4 -4
  346. package/dist/{chunk-CULXMQJH.js → chunk-XPXEJRUB.js} +3 -3
  347. package/dist/chunk-XPXEJRUB.js.map +1 -0
  348. package/dist/{chunk-PZIAX57I.js → chunk-XR6DNK4U.js} +7 -4
  349. package/dist/chunk-XR6DNK4U.js.map +1 -0
  350. package/dist/{chunk-47VWKCAF.js → chunk-XSQ4SGM5.js} +33 -4
  351. package/dist/chunk-XSQ4SGM5.js.map +1 -0
  352. package/dist/{chunk-66DHUKLO.js → chunk-XSWKORGM.js} +16 -14
  353. package/dist/chunk-XSWKORGM.js.map +1 -0
  354. package/dist/{chunk-QR3C7BKQ.js → chunk-XZ4WBBB5.js} +7 -8
  355. package/dist/chunk-XZ4WBBB5.js.map +1 -0
  356. package/dist/{chunk-WNARATI3.js → chunk-Y2SXZ5KZ.js} +59 -11
  357. package/dist/chunk-Y2SXZ5KZ.js.map +1 -0
  358. package/dist/{chunk-SIC6U3GZ.js → chunk-YHV3KRKS.js} +3 -3
  359. package/dist/{chunk-ZPKBYX2F.js → chunk-YNDLCWXS.js} +85 -9
  360. package/dist/chunk-YNDLCWXS.js.map +1 -0
  361. package/dist/{chunk-VLXA6PI2.js → chunk-YQMZ7IH2.js} +4 -4
  362. package/dist/{chunk-TMM4S4IJ.js → chunk-YR6GIWWY.js} +58 -8
  363. package/dist/chunk-YR6GIWWY.js.map +1 -0
  364. package/dist/{chunk-DK5LDEQM.js → chunk-YR7XMOWK.js} +39 -23
  365. package/dist/chunk-YR7XMOWK.js.map +1 -0
  366. package/dist/chunk-ZFXCQPNO.js +27 -0
  367. package/dist/chunk-ZFXCQPNO.js.map +1 -0
  368. package/dist/citations.js +1 -1
  369. package/dist/{cli-kuh9PwZ5.d.ts → cli-X4NJoqSe.d.ts} +8 -31
  370. package/dist/cli.d.ts +10 -6
  371. package/dist/cli.js +122 -117
  372. package/dist/commitment-ledger.js +2 -2
  373. package/dist/compat/checks.js +1 -2
  374. package/dist/compounding/engine.d.ts +3 -2
  375. package/dist/compounding/engine.js +11 -11
  376. package/dist/compounding/preference-consolidator.d.ts +1 -0
  377. package/dist/compounding/preference-consolidator.js +8 -8
  378. package/dist/compounding/preference-consolidator.js.map +1 -1
  379. package/dist/compression-optimizer.d.ts +1 -0
  380. package/dist/compression-optimizer.js +1 -1
  381. package/dist/config.d.ts +1 -0
  382. package/dist/config.js +3 -2
  383. package/dist/connectors/codex-materialize-runner.d.ts +1 -0
  384. package/dist/connectors/codex-materialize-runner.js +12 -11
  385. package/dist/connectors/codex-materialize.d.ts +1 -0
  386. package/dist/connectors/codex-materialize.js +3 -2
  387. package/dist/connectors/index.d.ts +1 -0
  388. package/dist/connectors/index.js +14 -14
  389. package/dist/{connectors-cli-CwbyjGR7.d.ts → connectors-cli-DbTPNj2H.d.ts} +7 -1
  390. package/dist/connectors-cli.d.ts +1 -1
  391. package/dist/connectors-cli.js +3 -1
  392. package/dist/consolidation-provenance-check.d.ts +1 -0
  393. package/dist/consolidation-provenance-check.js +2 -2
  394. package/dist/consolidation-undo.d.ts +1 -0
  395. package/dist/consolidation-undo.js +1 -1
  396. package/dist/contradiction/index.d.ts +3 -1
  397. package/dist/contradiction/index.js +3 -3
  398. package/dist/{contradiction-review-ATP4S6IC.js → contradiction-review-6V2LXXK6.js} +2 -2
  399. package/dist/{contradiction-scan-5A4IDZV5.js → contradiction-scan-GIRVC4C7.js} +3 -3
  400. package/dist/conversation-index/backend.d.ts +3 -1
  401. package/dist/conversation-index/backend.js +3 -3
  402. package/dist/conversation-index/chunker.d.ts +1 -0
  403. package/dist/conversation-index/cleanup.js +1 -1
  404. package/dist/conversation-index/faiss-adapter.d.ts +2 -1
  405. package/dist/conversation-index/faiss-adapter.js +1 -1
  406. package/dist/conversation-index/indexer.d.ts +5 -2
  407. package/dist/conversation-index/indexer.js +1 -1
  408. package/dist/conversation-index/search.d.ts +2 -1
  409. package/dist/cross-namespace-budget.js +1 -1
  410. package/dist/cue-anchors.js +2 -2
  411. package/dist/dashboard-runtime.d.ts +6 -0
  412. package/dist/dashboard-runtime.js +3 -3
  413. package/dist/day-summary.d.ts +1 -0
  414. package/dist/day-summary.js +2 -2
  415. package/dist/delinearize.d.ts +1 -0
  416. package/dist/direct-answer-wiring.d.ts +1 -0
  417. package/dist/direct-answer.d.ts +1 -0
  418. package/dist/{dreams-ledger-LR2NBAZE.js → dreams-ledger-3WSCI5V4.js} +5 -4
  419. package/dist/{dreams-ledger-LR2NBAZE.js.map → dreams-ledger-3WSCI5V4.js.map} +1 -1
  420. package/dist/embedding-fallback.d.ts +3 -0
  421. package/dist/embedding-fallback.js +2 -2
  422. package/dist/enrichment/index.d.ts +1 -0
  423. package/dist/enrichment/index.js +1 -1
  424. package/dist/entity-retrieval.d.ts +2 -0
  425. package/dist/entity-retrieval.js +9 -9
  426. package/dist/entity-schema.d.ts +1 -0
  427. package/dist/evals.js +1 -1
  428. package/dist/explicit-capture.d.ts +5 -3
  429. package/dist/explicit-capture.js +2 -2
  430. package/dist/extraction-judge-telemetry.d.ts +2 -0
  431. package/dist/extraction-judge-training.d.ts +2 -0
  432. package/dist/extraction-judge.d.ts +2 -0
  433. package/dist/extraction.d.ts +2 -0
  434. package/dist/extraction.js +12 -12
  435. package/dist/{faiss-adapter-CzPghc4C.d.ts → faiss-adapter-BHecI1fF.d.ts} +4 -1
  436. package/dist/fallback-llm.d.ts +11 -1
  437. package/dist/fallback-llm.js +8 -6
  438. package/dist/{first-start-migration-4MHQEOSD.js → first-start-migration-CKTCTCQI.js} +5 -5
  439. package/dist/graph-dashboard-diff.d.ts +4 -0
  440. package/dist/graph-dashboard-diff.js +1 -1
  441. package/dist/graph-dashboard-parser.js +1 -1
  442. package/dist/{graph-edge-decay-5DI5GUNL.js → graph-edge-decay-MUP5J7CC.js} +6 -6
  443. package/dist/graph-events.js +1 -1
  444. package/dist/graph-snapshot.js +3 -3
  445. package/dist/graph.js +2 -2
  446. package/dist/harmonic-retrieval.js +4 -4
  447. package/dist/identity-continuity.d.ts +1 -0
  448. package/dist/importance.d.ts +1 -0
  449. package/dist/importers/index.d.ts +244 -0
  450. package/dist/importers/index.js +20 -0
  451. package/dist/index.d.ts +20 -350
  452. package/dist/index.js +884 -561
  453. package/dist/index.js.map +1 -1
  454. package/dist/intent.d.ts +1 -0
  455. package/dist/lcm/archive.d.ts +2 -2
  456. package/dist/lcm/archive.js +2 -2
  457. package/dist/lcm/engine.d.ts +3 -2
  458. package/dist/lcm/engine.js +6 -6
  459. package/dist/lcm/index.d.ts +1 -0
  460. package/dist/lcm/index.js +8 -8
  461. package/dist/lcm/recall.js +1 -1
  462. package/dist/lcm/summarizer.js +3 -3
  463. package/dist/lcm/tools.d.ts +1 -0
  464. package/dist/lifecycle.d.ts +1 -0
  465. package/dist/live-connectors-runner.d.ts +1 -0
  466. package/dist/live-connectors-runner.js +6 -6
  467. package/dist/local-llm.d.ts +1 -0
  468. package/dist/local-llm.js +2 -2
  469. package/dist/maintenance/archive-observations.js +1 -1
  470. package/dist/maintenance/memory-governance.d.ts +3 -1
  471. package/dist/maintenance/memory-governance.js +10 -8
  472. package/dist/maintenance/migrate-observations.js +3 -2
  473. package/dist/maintenance/observation-ledger-utils.d.ts +3 -0
  474. package/dist/maintenance/observation-ledger-utils.js +2 -1
  475. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -1
  476. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +11 -8
  477. package/dist/maintenance/rebuild-memory-projection.d.ts +2 -1
  478. package/dist/maintenance/rebuild-memory-projection.js +13 -10
  479. package/dist/maintenance/rebuild-observations.d.ts +1 -0
  480. package/dist/maintenance/rebuild-observations.js +3 -2
  481. package/dist/mcp-memory-inspector-app.d.ts +7 -4
  482. package/dist/mcp-memory-inspector-app.js +1 -1
  483. package/dist/memory-action-policy.d.ts +1 -0
  484. package/dist/memory-cache.d.ts +1 -0
  485. package/dist/memory-cache.js +1 -1
  486. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -0
  487. package/dist/memory-projection-store.d.ts +1 -0
  488. package/dist/memory-projection-store.js +1 -1
  489. package/dist/memory-provenance.d.ts +1 -0
  490. package/dist/memory-worth-outcomes.d.ts +1 -0
  491. package/dist/migrate/from-engram.js +2 -2
  492. package/dist/{migrate-from-identity-anchor-G27MCD6A.js → migrate-from-identity-anchor-EB4XI4Q2.js} +2 -2
  493. package/dist/model-registry.js +1 -1
  494. package/dist/models-json.d.ts +1 -0
  495. package/dist/namespaces/migrate.d.ts +3 -0
  496. package/dist/namespaces/migrate.js +24 -22
  497. package/dist/namespaces/principal.d.ts +1 -0
  498. package/dist/namespaces/principal.js +2 -1
  499. package/dist/namespaces/search.d.ts +1 -0
  500. package/dist/namespaces/search.js +15 -13
  501. package/dist/namespaces/storage.d.ts +4 -2
  502. package/dist/namespaces/storage.js +10 -9
  503. package/dist/native-knowledge.d.ts +1 -0
  504. package/dist/native-knowledge.js +1 -1
  505. package/dist/negative.js +1 -1
  506. package/dist/network/webdav.d.ts +16 -1
  507. package/dist/network/webdav.js +5 -3
  508. package/dist/objective-state-writers.js +4 -4
  509. package/dist/objective-state.js +2 -2
  510. package/dist/offline-sync.js +4 -4
  511. package/dist/operator-toolkit.d.ts +1 -0
  512. package/dist/operator-toolkit.js +35 -32
  513. package/dist/opik-exporter.js +1 -1
  514. package/dist/{orchestrator-DuWl9Hwx.d.ts → orchestrator-Co9nxRLF.d.ts} +4 -74
  515. package/dist/orchestrator.d.ts +5 -3
  516. package/dist/orchestrator.js +99 -96
  517. package/dist/page-versioning.js +1 -1
  518. package/dist/path-X2K5XCHL.js +9 -0
  519. package/dist/patterns-cli.d.ts +1 -0
  520. package/dist/peers/index.d.ts +328 -0
  521. package/dist/{peers-HCVGHMAE.js → peers/index.js} +4 -4
  522. package/dist/pipeline-D18UAKlN.d.ts +32 -0
  523. package/dist/plugin-entry-resolver.d.ts +9 -0
  524. package/dist/plugin-entry-resolver.js +8 -0
  525. package/dist/plugin-entry-resolver.js.map +1 -0
  526. package/dist/plugin-id.d.ts +2 -21
  527. package/dist/plugin-id.js +33 -4
  528. package/dist/plugin-id.js.map +1 -1
  529. package/dist/policy-runtime.d.ts +4 -0
  530. package/dist/policy-runtime.js +1 -1
  531. package/dist/profiling.js +1 -1
  532. package/dist/qmd-recall-cache.d.ts +1 -0
  533. package/dist/qmd.d.ts +1 -0
  534. package/dist/qmd.js +3 -3
  535. package/dist/recall-disclosure-escalation.d.ts +1 -0
  536. package/dist/recall-explain-renderer.d.ts +1 -0
  537. package/dist/recall-explain-renderer.js +3 -3
  538. package/dist/recall-state.d.ts +8 -1
  539. package/dist/recall-state.js +2 -1
  540. package/dist/recall-tag-filter.d.ts +1 -0
  541. package/dist/recall-xray-cli.d.ts +1 -0
  542. package/dist/recall-xray-cli.js +4 -4
  543. package/dist/recall-xray-renderer.d.ts +1 -0
  544. package/dist/recall-xray-renderer.js +3 -3
  545. package/dist/recall-xray.d.ts +1 -0
  546. package/dist/recall-xray.js +2 -2
  547. package/dist/relevance.d.ts +7 -1
  548. package/dist/relevance.js +2 -1
  549. package/dist/replay/normalizers/chatgpt.js +2 -2
  550. package/dist/replay/normalizers/claude.js +2 -2
  551. package/dist/replay/normalizers/openclaw.js +2 -2
  552. package/dist/replay/normalizers/shared.js +1 -1
  553. package/dist/replay/runner.js +1 -1
  554. package/dist/rerank.js +1 -1
  555. package/dist/{resolution-B7FNQSSP.js → resolution-ZY7VM6WS.js} +3 -3
  556. package/dist/resolution-ZY7VM6WS.js.map +1 -0
  557. package/dist/resolve-auth-token.d.ts +1 -0
  558. package/dist/resolve-auth-token.js +1 -1
  559. package/dist/resolve-provider-secret.d.ts +19 -29
  560. package/dist/resolve-provider-secret.js +2 -6
  561. package/dist/resume-bundles.js +10 -9
  562. package/dist/retrieval-agents.d.ts +2 -1
  563. package/dist/retrieval-agents.js +2 -1
  564. package/dist/retrieval-tiers.d.ts +1 -0
  565. package/dist/routing/engine.d.ts +1 -0
  566. package/dist/routing/store.d.ts +3 -0
  567. package/dist/routing/store.js +1 -1
  568. package/dist/runtime/env.js +1 -1
  569. package/dist/schemas.d.ts +191 -17
  570. package/dist/schemas.js +1 -1
  571. package/dist/sdk-compat.js +1 -1
  572. package/dist/search/document-scanner.js +1 -1
  573. package/dist/search/embed-helper.d.ts +7 -2
  574. package/dist/search/embed-helper.js +3 -1
  575. package/dist/search/factory.d.ts +2 -1
  576. package/dist/search/factory.js +13 -12
  577. package/dist/search/index.d.ts +2 -1
  578. package/dist/search/index.js +19 -18
  579. package/dist/search/lancedb-backend.d.ts +7 -6
  580. package/dist/search/lancedb-backend.js +4 -2
  581. package/dist/search/meilisearch-backend.d.ts +7 -6
  582. package/dist/search/meilisearch-backend.js +4 -2
  583. package/dist/search/noop-backend.d.ts +1 -0
  584. package/dist/search/orama-backend.d.ts +9 -7
  585. package/dist/search/orama-backend.js +8 -4
  586. package/dist/search/port.d.ts +1 -0
  587. package/dist/search/remote-backend.d.ts +1 -0
  588. package/dist/secure-store/index.d.ts +16 -3
  589. package/dist/secure-store/index.js +2 -2
  590. package/dist/{semantic-VwGI14Ok.d.ts → semantic-SLAa_prH.d.ts} +5 -3
  591. package/dist/semantic-consolidation.d.ts +1 -0
  592. package/dist/semantic-consolidation.js +14 -13
  593. package/dist/semantic-rule-promotion.js +8 -8
  594. package/dist/semantic-rule-verifier.d.ts +1 -0
  595. package/dist/semantic-rule-verifier.js +8 -8
  596. package/dist/session-integrity.d.ts +1 -0
  597. package/dist/session-integrity.js +1 -1
  598. package/dist/session-observer-bands.d.ts +1 -0
  599. package/dist/session-observer-state.d.ts +6 -1
  600. package/dist/session-observer-state.js +1 -1
  601. package/dist/shared-context/manager.d.ts +5 -0
  602. package/dist/shared-context/manager.js +3 -3
  603. package/dist/signal.d.ts +1 -0
  604. package/dist/signal.js +1 -1
  605. package/dist/source-attribution.js +1 -1
  606. package/dist/state-store-4QZISH3J.js +30 -0
  607. package/dist/state-store-4QZISH3J.js.map +1 -0
  608. package/dist/storage-C4DX8CuG.d.ts +157 -0
  609. package/dist/storage.d.ts +2 -0
  610. package/dist/storage.js +7 -7
  611. package/dist/store-contract.js +1 -1
  612. package/dist/summarizer.d.ts +1 -0
  613. package/dist/summarizer.js +7 -7
  614. package/dist/summary-snapshot.d.ts +1 -0
  615. package/dist/surfaces/dreams.js +48 -17
  616. package/dist/surfaces/dreams.js.map +1 -1
  617. package/dist/temporal-supersession.d.ts +1 -0
  618. package/dist/temporal-supersession.js +1 -1
  619. package/dist/temporal-validity.d.ts +1 -0
  620. package/dist/threading.d.ts +1 -0
  621. package/dist/tier-migration.d.ts +1 -0
  622. package/dist/tier-routing.d.ts +1 -0
  623. package/dist/{tier-stats-62ZVDFKS.js → tier-stats-SKML2OSF.js} +5 -5
  624. package/dist/tmt.js +1 -1
  625. package/dist/tokens.js +2 -2
  626. package/dist/topics.d.ts +1 -0
  627. package/dist/{trace-C5ETWBEF.js → trace-WM7V4CKI.js} +31 -1
  628. package/dist/trace-WM7V4CKI.js.map +1 -0
  629. package/dist/transcript.d.ts +1 -0
  630. package/dist/transcript.js +2 -2
  631. package/dist/transfer/autodetect.js +7 -7
  632. package/dist/transfer/backup.js +5 -5
  633. package/dist/transfer/capsule-export.js +5 -5
  634. package/dist/transfer/capsule-import.d.ts +6 -0
  635. package/dist/transfer/capsule-import.js +4 -4
  636. package/dist/transfer/export-json.js +3 -3
  637. package/dist/transfer/export-md.js +3 -3
  638. package/dist/transfer/export-sqlite.js +3 -3
  639. package/dist/transfer/fs-utils.d.ts +2 -1
  640. package/dist/transfer/fs-utils.js +5 -3
  641. package/dist/transfer/import-json.js +3 -3
  642. package/dist/transfer/import-md.js +3 -3
  643. package/dist/transfer/import-sqlite.js +3 -3
  644. package/dist/trust-zones.js +2 -2
  645. package/dist/types-B1VHaf2w.d.ts +126 -0
  646. package/dist/types-BliCnURB.d.ts +83 -0
  647. package/dist/types.d.ts +35 -0
  648. package/dist/types.js +1 -1
  649. package/dist/utility-learner.js +3 -3
  650. package/dist/utility-runtime.d.ts +1 -0
  651. package/dist/utility-runtime.js +4 -4
  652. package/dist/utility-telemetry.js +2 -2
  653. package/dist/verified-recall.js +9 -9
  654. package/dist/work/board.js +2 -2
  655. package/dist/work/boundary.js +1 -1
  656. package/dist/work/storage.d.ts +5 -0
  657. package/dist/work/storage.js +1 -1
  658. package/dist/work-product-ledger.js +2 -2
  659. package/package.json +74 -3
  660. package/scripts/ensure-better-sqlite3.mjs +8 -7
  661. package/scripts/faiss_index.py +141 -29
  662. package/src/access-cli.test.ts +87 -2
  663. package/src/access-cli.ts +59 -5
  664. package/src/access-http.test.ts +150 -0
  665. package/src/access-http.ts +89 -34
  666. package/src/access-idempotency.ts +136 -3
  667. package/src/access-mcp.test.ts +155 -0
  668. package/src/access-mcp.ts +116 -30
  669. package/src/access-schema.ts +22 -4
  670. package/src/access-service-project-tag.test.ts +37 -0
  671. package/src/access-service.ts +11 -10
  672. package/src/active-recall.test.ts +29 -1
  673. package/src/active-recall.ts +11 -7
  674. package/src/adapters/claude-code.ts +7 -8
  675. package/src/adapters/codex.ts +6 -7
  676. package/src/adapters/hermes.ts +1 -5
  677. package/src/adapters/registry.test.ts +63 -0
  678. package/src/adapters/registry.ts +10 -0
  679. package/src/adapters/replit.ts +5 -7
  680. package/src/adapters/types.ts +24 -1
  681. package/src/behavior-signals.ts +1 -1
  682. package/src/binary-lifecycle/backend.ts +16 -4
  683. package/src/binary-lifecycle/pipeline.test.ts +149 -0
  684. package/src/binary-lifecycle/pipeline.ts +49 -7
  685. package/src/binary-lifecycle/scanner.ts +19 -4
  686. package/src/boxes.ts +119 -32
  687. package/src/buffer-session.test.ts +28 -0
  688. package/src/buffer.ts +10 -14
  689. package/src/bulk-import/types.ts +10 -0
  690. package/src/calibration.test.ts +99 -0
  691. package/src/calibration.ts +57 -13
  692. package/src/causal-consolidation.test.ts +214 -0
  693. package/src/causal-consolidation.ts +131 -14
  694. package/src/causal-retrieval.ts +16 -3
  695. package/src/citations.test.ts +75 -0
  696. package/src/citations.ts +19 -6
  697. package/src/cli.ts +134 -109
  698. package/src/coding/coding-namespace.test.ts +7 -0
  699. package/src/coding/coding-namespace.ts +8 -0
  700. package/src/coding/review-context.test.ts +30 -0
  701. package/src/coding/review-context.ts +79 -9
  702. package/src/coding/wire-coding-context.test.ts +16 -0
  703. package/src/compat/checks.test.ts +33 -0
  704. package/src/compat/checks.ts +64 -4
  705. package/src/compounding/engine.ts +2 -2
  706. package/src/compounding/preference-consolidator.test.ts +47 -0
  707. package/src/compounding/preference-consolidator.ts +8 -8
  708. package/src/compression-optimizer.ts +5 -2
  709. package/src/config.test.ts +34 -2
  710. package/src/config.ts +62 -18
  711. package/src/connectors/codex-materialize-runner.ts +4 -3
  712. package/src/connectors/codex-materialize.ts +149 -34
  713. package/src/connectors/index.test.ts +144 -7
  714. package/src/connectors/index.ts +86 -15
  715. package/src/connectors/live/github.test.ts +47 -0
  716. package/src/connectors/live/github.ts +29 -1
  717. package/src/connectors/live/index.ts +2 -0
  718. package/src/connectors/live/live-connectors.test.ts +359 -73
  719. package/src/connectors/live/notion.test.ts +84 -0
  720. package/src/connectors/live/notion.ts +18 -1
  721. package/src/connectors/live/state-store.ts +419 -38
  722. package/src/connectors/weclone-installer.test.ts +16 -18
  723. package/src/connectors-cli.ts +19 -0
  724. package/src/console/trace.test.ts +28 -0
  725. package/src/console/trace.ts +42 -5
  726. package/src/contradiction/contradiction-judge.test.ts +49 -0
  727. package/src/contradiction/contradiction-judge.ts +15 -5
  728. package/src/contradiction/contradiction-review.ts +31 -7
  729. package/src/contradiction/contradiction-scan.ts +28 -18
  730. package/src/contradiction/contradiction.test.ts +237 -1
  731. package/src/contradiction/resolution.ts +43 -4
  732. package/src/conversation-index/backend.ts +13 -5
  733. package/src/conversation-index/cleanup.ts +25 -4
  734. package/src/conversation-index/faiss-adapter.ts +24 -15
  735. package/src/conversation-index/indexer.test.ts +71 -10
  736. package/src/conversation-index/indexer.ts +22 -3
  737. package/src/cross-namespace-budget.test.ts +59 -0
  738. package/src/cross-namespace-budget.ts +15 -7
  739. package/src/curation/index.ts +18 -17
  740. package/src/dashboard-runtime.test.ts +98 -0
  741. package/src/dashboard-runtime.ts +96 -6
  742. package/src/dedup/index.test.ts +133 -0
  743. package/src/dedup/index.ts +73 -10
  744. package/src/dedup/semantic.test.ts +77 -2
  745. package/src/dedup/semantic.ts +26 -6
  746. package/src/embedding-fallback.ts +47 -15
  747. package/src/enrichment/audit.ts +8 -1
  748. package/src/enrichment/pipeline.ts +21 -13
  749. package/src/enrichment/web-search-provider.ts +1 -6
  750. package/src/entity-retrieval.ts +57 -6
  751. package/src/evals.ts +22 -13
  752. package/src/explicit-capture.test.ts +40 -0
  753. package/src/explicit-capture.ts +14 -2
  754. package/src/extraction.ts +42 -30
  755. package/src/fallback-llm.ts +35 -2
  756. package/src/graph-dashboard-diff.test.ts +57 -0
  757. package/src/graph-dashboard-diff.ts +24 -2
  758. package/src/graph-dashboard-parser.test.ts +31 -0
  759. package/src/graph-dashboard-parser.ts +4 -1
  760. package/src/graph-events.ts +6 -4
  761. package/src/graph.test.ts +69 -0
  762. package/src/graph.ts +7 -4
  763. package/src/importers/base.test.ts +70 -0
  764. package/src/importers/base.ts +56 -7
  765. package/src/index.ts +5 -2
  766. package/src/lcm/archive.ts +65 -16
  767. package/src/lcm/engine.ts +27 -8
  768. package/src/lcm/recall.ts +5 -5
  769. package/src/lcm-engine.test.ts +87 -1
  770. package/src/lcm-recall.test.ts +71 -0
  771. package/src/live-connectors-runner.ts +100 -36
  772. package/src/maintenance/archive-observations.ts +24 -3
  773. package/src/maintenance/atomic-file.ts +85 -0
  774. package/src/maintenance/dreams-ledger.ts +15 -8
  775. package/src/maintenance/memory-governance.test.ts +53 -0
  776. package/src/maintenance/memory-governance.ts +15 -5
  777. package/src/maintenance/observation-ledger-utils.ts +6 -5
  778. package/src/maintenance/purge.test.ts +64 -0
  779. package/src/maintenance/rebuild-memory-lifecycle-ledger.ts +22 -9
  780. package/src/maintenance/rebuild-memory-projection.ts +22 -9
  781. package/src/maintenance/rebuild-observations.ts +7 -3
  782. package/src/mcp-memory-inspector-app.ts +26 -3
  783. package/src/memory-cache.test.ts +19 -0
  784. package/src/memory-cache.ts +1 -0
  785. package/src/memory-extension/codex-publisher.ts +25 -4
  786. package/src/memory-extension-host/host-discovery.test.ts +69 -0
  787. package/src/memory-extension-host/host-discovery.ts +63 -6
  788. package/src/memory-projection-store.ts +114 -62
  789. package/src/message-parts/index.ts +46 -31
  790. package/src/message-parts/message-parts.test.ts +77 -0
  791. package/src/migrate/from-engram.ts +68 -14
  792. package/src/model-registry.test.ts +38 -0
  793. package/src/model-registry.ts +12 -7
  794. package/src/namespaces/identity.test.ts +66 -0
  795. package/src/namespaces/identity.ts +23 -0
  796. package/src/namespaces/migrate.test.ts +62 -0
  797. package/src/namespaces/migrate.ts +82 -14
  798. package/src/namespaces/principal.test.ts +37 -1
  799. package/src/namespaces/principal.ts +18 -7
  800. package/src/namespaces/search.test.ts +76 -6
  801. package/src/namespaces/search.ts +22 -21
  802. package/src/namespaces/storage.ts +93 -11
  803. package/src/native-knowledge.ts +23 -3
  804. package/src/negative.ts +50 -5
  805. package/src/network/webdav.ts +177 -58
  806. package/src/onboarding/index.test.ts +105 -0
  807. package/src/onboarding/index.ts +17 -5
  808. package/src/operator-toolkit.ts +39 -4
  809. package/src/orchestrator.ts +52 -17
  810. package/src/page-versioning.ts +31 -5
  811. package/src/peers/peers.test.ts +70 -0
  812. package/src/peers/storage.ts +32 -3
  813. package/src/plugin-entry-resolver.test.ts +60 -0
  814. package/src/plugin-entry-resolver.ts +48 -0
  815. package/src/plugin-id.test.ts +38 -0
  816. package/src/plugin-id.ts +31 -64
  817. package/src/policy-runtime.test.ts +75 -0
  818. package/src/policy-runtime.ts +32 -3
  819. package/src/procedural/procedure-miner.test.ts +152 -0
  820. package/src/procedural/procedure-miner.ts +124 -19
  821. package/src/profiling.test.ts +23 -0
  822. package/src/profiling.ts +10 -1
  823. package/src/projection/index.test.ts +253 -0
  824. package/src/projection/index.ts +159 -18
  825. package/src/qmd-client.test.ts +45 -0
  826. package/src/qmd.ts +8 -8
  827. package/src/recall-disclosure.test.ts +15 -1
  828. package/src/recall-state.ts +24 -5
  829. package/src/relevance.ts +24 -5
  830. package/src/replay/normalizers/chatgpt.ts +14 -4
  831. package/src/replay/normalizers/claude.ts +8 -3
  832. package/src/replay/normalizers/openclaw.ts +35 -12
  833. package/src/replay/normalizers/replay-normalizers.test.ts +65 -0
  834. package/src/replay/normalizers/shared.ts +4 -1
  835. package/src/replay/runner.ts +1 -1
  836. package/src/rerank.test.ts +41 -1
  837. package/src/rerank.ts +2 -2
  838. package/src/resolve-auth-token.test.ts +29 -0
  839. package/src/resolve-auth-token.ts +12 -7
  840. package/src/resolve-provider-secret.test.ts +78 -22
  841. package/src/resolve-provider-secret.ts +55 -223
  842. package/src/retrieval-agents.ts +51 -14
  843. package/src/review/index.test.ts +75 -1
  844. package/src/review/index.ts +88 -30
  845. package/src/routing/store.ts +36 -6
  846. package/src/runtime/env.test.ts +73 -0
  847. package/src/runtime/env.ts +7 -11
  848. package/src/schemas.ts +16 -1
  849. package/src/search/abort.ts +18 -0
  850. package/src/search/document-scanner.test.ts +80 -0
  851. package/src/search/document-scanner.ts +51 -9
  852. package/src/search/embed-helper.ts +19 -6
  853. package/src/search/factory.ts +9 -5
  854. package/src/search/lancedb-backend.ts +62 -22
  855. package/src/search/meilisearch-backend.ts +35 -12
  856. package/src/search/orama-backend.test.ts +27 -0
  857. package/src/search/orama-backend.ts +65 -15
  858. package/src/secure-store/cli-handlers.ts +70 -6
  859. package/src/secure-store/cli-renderer.ts +13 -7
  860. package/src/secure-store/secure-fs.ts +11 -5
  861. package/src/secure-store/secure-store.test.ts +70 -0
  862. package/src/semantic-consolidation.test.ts +45 -0
  863. package/src/semantic-consolidation.ts +3 -3
  864. package/src/session-integrity.test.ts +98 -0
  865. package/src/session-integrity.ts +51 -1
  866. package/src/session-observer-state.ts +108 -41
  867. package/src/shared-context/manager.ts +93 -15
  868. package/src/signal.test.ts +14 -0
  869. package/src/signal.ts +8 -1
  870. package/src/source-attribution.test.ts +8 -0
  871. package/src/source-attribution.ts +24 -2
  872. package/src/spaces/index.test.ts +93 -0
  873. package/src/spaces/index.ts +75 -9
  874. package/src/storage.ts +14 -1
  875. package/src/store-contract.test.ts +35 -0
  876. package/src/store-contract.ts +39 -5
  877. package/src/summarizer.ts +24 -18
  878. package/src/summary-snapshot.test.ts +77 -0
  879. package/src/surfaces/dreams.test.ts +73 -0
  880. package/src/surfaces/dreams.ts +53 -19
  881. package/src/sync/index.ts +42 -17
  882. package/src/taxonomy/taxonomy-loader.ts +43 -4
  883. package/src/temporal-supersession.test.ts +67 -0
  884. package/src/temporal-supersession.ts +8 -0
  885. package/src/tmt.test.ts +50 -0
  886. package/src/tmt.ts +35 -11
  887. package/src/tokens.test.ts +18 -0
  888. package/src/tokens.ts +7 -0
  889. package/src/training-export/converter.test.ts +55 -2
  890. package/src/training-export/converter.ts +36 -10
  891. package/src/training-export/registry.test.ts +17 -0
  892. package/src/training-export/registry.ts +19 -1
  893. package/src/transcript.ts +2 -2
  894. package/src/transfer/backup.ts +18 -7
  895. package/src/transfer/capsule-crypto.ts +105 -21
  896. package/src/transfer/capsule-encrypt.test.ts +106 -7
  897. package/src/transfer/capsule-export.ts +23 -14
  898. package/src/transfer/capsule-import.ts +11 -2
  899. package/src/transfer/exclusions.ts +7 -0
  900. package/src/transfer/export-sqlite.ts +14 -13
  901. package/src/transfer/fs-utils.ts +52 -1
  902. package/src/transfer/import-json.ts +12 -7
  903. package/src/transfer/import-md.ts +5 -5
  904. package/src/transfer/import-sqlite.ts +4 -5
  905. package/src/trust-zones.ts +1 -1
  906. package/src/types.ts +25 -0
  907. package/src/utility-telemetry.ts +1 -1
  908. package/src/utils/category-dir.test.ts +15 -0
  909. package/src/utils/category-dir.ts +3 -1
  910. package/src/work/boundary.ts +30 -18
  911. package/src/work/storage.ts +116 -38
  912. package/src/work-product-ledger.ts +1 -1
  913. package/dist/chunk-25MQ7IHJ.js.map +0 -1
  914. package/dist/chunk-2IWUMAES.js.map +0 -1
  915. package/dist/chunk-2NMMFZ5T.js.map +0 -1
  916. package/dist/chunk-2PRLKQAH.js.map +0 -1
  917. package/dist/chunk-326G7DJK.js.map +0 -1
  918. package/dist/chunk-3APJ5EVB.js.map +0 -1
  919. package/dist/chunk-3KW65B36.js.map +0 -1
  920. package/dist/chunk-3QKK7QOS.js.map +0 -1
  921. package/dist/chunk-3SLRNYNG.js.map +0 -1
  922. package/dist/chunk-3VAL7ZL2.js.map +0 -1
  923. package/dist/chunk-3Y4P7RXM.js.map +0 -1
  924. package/dist/chunk-3ZLVGM76.js.map +0 -1
  925. package/dist/chunk-43PJZYGL.js.map +0 -1
  926. package/dist/chunk-47VWKCAF.js.map +0 -1
  927. package/dist/chunk-4KGVTPGD.js.map +0 -1
  928. package/dist/chunk-5375UYTQ.js.map +0 -1
  929. package/dist/chunk-56K5QLHX.js.map +0 -1
  930. package/dist/chunk-575RMLWN.js.map +0 -1
  931. package/dist/chunk-5NPGSAVB.js.map +0 -1
  932. package/dist/chunk-5RGLBDQF.js.map +0 -1
  933. package/dist/chunk-65PG43EQ.js.map +0 -1
  934. package/dist/chunk-66DHUKLO.js.map +0 -1
  935. package/dist/chunk-6LVVDPJ4.js.map +0 -1
  936. package/dist/chunk-76FLAAUC.js.map +0 -1
  937. package/dist/chunk-77H5NU3M.js.map +0 -1
  938. package/dist/chunk-7MNMYOFP.js.map +0 -1
  939. package/dist/chunk-7OZ53EXP.js.map +0 -1
  940. package/dist/chunk-7SEAZFFB.js.map +0 -1
  941. package/dist/chunk-A6KTB5R6.js.map +0 -1
  942. package/dist/chunk-AGZQD76C.js.map +0 -1
  943. package/dist/chunk-APO3DCMU.js.map +0 -1
  944. package/dist/chunk-BVF3AGJP.js.map +0 -1
  945. package/dist/chunk-C5BCH4ZS.js.map +0 -1
  946. package/dist/chunk-C7VW7C3F.js.map +0 -1
  947. package/dist/chunk-CULXMQJH.js.map +0 -1
  948. package/dist/chunk-CYFQJMUV.js.map +0 -1
  949. package/dist/chunk-D654IBA6.js +0 -61
  950. package/dist/chunk-D654IBA6.js.map +0 -1
  951. package/dist/chunk-DGXUHMOV.js.map +0 -1
  952. package/dist/chunk-DINWEURR.js.map +0 -1
  953. package/dist/chunk-DK5LDEQM.js.map +0 -1
  954. package/dist/chunk-EABGC2TL.js.map +0 -1
  955. package/dist/chunk-EHRTFRWW.js.map +0 -1
  956. package/dist/chunk-EJI5XIBB.js.map +0 -1
  957. package/dist/chunk-FAAFWE4G.js.map +0 -1
  958. package/dist/chunk-FAJ7FZYM.js +0 -11
  959. package/dist/chunk-FAJ7FZYM.js.map +0 -1
  960. package/dist/chunk-FDU6HUUL.js +0 -147
  961. package/dist/chunk-FDU6HUUL.js.map +0 -1
  962. package/dist/chunk-FIT6DMX6.js.map +0 -1
  963. package/dist/chunk-FJ43PRLT.js.map +0 -1
  964. package/dist/chunk-FLTNHQK6.js +0 -262
  965. package/dist/chunk-FLTNHQK6.js.map +0 -1
  966. package/dist/chunk-GDFS42HT.js.map +0 -1
  967. package/dist/chunk-H3ME6L6D.js.map +0 -1
  968. package/dist/chunk-HXXBL2KD.js.map +0 -1
  969. package/dist/chunk-ICRIXAP2.js.map +0 -1
  970. package/dist/chunk-IQT3XTKW.js.map +0 -1
  971. package/dist/chunk-JR4ZC3G4.js.map +0 -1
  972. package/dist/chunk-K4FLSOR5.js.map +0 -1
  973. package/dist/chunk-KNKUID7G.js.map +0 -1
  974. package/dist/chunk-KOSORCJG.js.map +0 -1
  975. package/dist/chunk-LIRZNNUP.js.map +0 -1
  976. package/dist/chunk-LLQ2LLWF.js.map +0 -1
  977. package/dist/chunk-LPMVBPA3.js +0 -236
  978. package/dist/chunk-LPMVBPA3.js.map +0 -1
  979. package/dist/chunk-LT3NLYSI.js.map +0 -1
  980. package/dist/chunk-LUDTDZLK.js.map +0 -1
  981. package/dist/chunk-MJFNCJXV.js.map +0 -1
  982. package/dist/chunk-MSWG7JI6.js.map +0 -1
  983. package/dist/chunk-MXC3AP5I.js.map +0 -1
  984. package/dist/chunk-MXFBBHJU.js.map +0 -1
  985. package/dist/chunk-MZH6EHNR.js.map +0 -1
  986. package/dist/chunk-N2D6GXBM.js.map +0 -1
  987. package/dist/chunk-NBNN5GOB.js.map +0 -1
  988. package/dist/chunk-NMZY542O.js.map +0 -1
  989. package/dist/chunk-NZL6GGQE.js.map +0 -1
  990. package/dist/chunk-OZHRDTDX.js.map +0 -1
  991. package/dist/chunk-PZIAX57I.js.map +0 -1
  992. package/dist/chunk-Q7P4WJDP.js.map +0 -1
  993. package/dist/chunk-QA2ZAPBU.js.map +0 -1
  994. package/dist/chunk-QDZ2RLEC.js.map +0 -1
  995. package/dist/chunk-QLLBRHAT.js.map +0 -1
  996. package/dist/chunk-QR3C7BKQ.js.map +0 -1
  997. package/dist/chunk-RHY3HH7P.js.map +0 -1
  998. package/dist/chunk-RK2Y4XOM.js.map +0 -1
  999. package/dist/chunk-RR2PKP3I.js +0 -63
  1000. package/dist/chunk-RR2PKP3I.js.map +0 -1
  1001. package/dist/chunk-RRF5UOBJ.js.map +0 -1
  1002. package/dist/chunk-RXDLTSWT.js.map +0 -1
  1003. package/dist/chunk-RYED3SPJ.js +0 -42
  1004. package/dist/chunk-RYED3SPJ.js.map +0 -1
  1005. package/dist/chunk-S7KDBTWT.js.map +0 -1
  1006. package/dist/chunk-TK4UEOSK.js.map +0 -1
  1007. package/dist/chunk-TMM4S4IJ.js.map +0 -1
  1008. package/dist/chunk-TMQLARTH.js.map +0 -1
  1009. package/dist/chunk-TPB3I2AC.js.map +0 -1
  1010. package/dist/chunk-TPMQ3G6Z.js.map +0 -1
  1011. package/dist/chunk-TPU5L5EY.js.map +0 -1
  1012. package/dist/chunk-TZOLIGIG.js.map +0 -1
  1013. package/dist/chunk-U3WSW6PZ.js.map +0 -1
  1014. package/dist/chunk-U4SCL7B7.js.map +0 -1
  1015. package/dist/chunk-U66YHYC7.js +0 -31
  1016. package/dist/chunk-U66YHYC7.js.map +0 -1
  1017. package/dist/chunk-UWVJF25J.js.map +0 -1
  1018. package/dist/chunk-VBJ7V5SK.js.map +0 -1
  1019. package/dist/chunk-W3LR522O.js.map +0 -1
  1020. package/dist/chunk-W4L6CZKA.js.map +0 -1
  1021. package/dist/chunk-W6AQJ2PY.js.map +0 -1
  1022. package/dist/chunk-WELDCG6C.js.map +0 -1
  1023. package/dist/chunk-WNARATI3.js.map +0 -1
  1024. package/dist/chunk-WPGJYVUH.js.map +0 -1
  1025. package/dist/chunk-WW3QQF4H.js.map +0 -1
  1026. package/dist/chunk-XIG5PDM7.js.map +0 -1
  1027. package/dist/chunk-XKECPATV.js.map +0 -1
  1028. package/dist/chunk-XKLD5OK4.js.map +0 -1
  1029. package/dist/chunk-XSZEP4SF.js.map +0 -1
  1030. package/dist/chunk-XVVIG67A.js.map +0 -1
  1031. package/dist/chunk-XYIK4LF6.js.map +0 -1
  1032. package/dist/chunk-YRMVARQP.js.map +0 -1
  1033. package/dist/chunk-YROHKYBY.js.map +0 -1
  1034. package/dist/chunk-YU5KIWYQ.js.map +0 -1
  1035. package/dist/chunk-ZAVUCJ4H.js.map +0 -1
  1036. package/dist/chunk-ZPKBYX2F.js.map +0 -1
  1037. package/dist/chunk-ZTFCYYEZ.js.map +0 -1
  1038. package/dist/chunk-ZYVPLJ4T.js.map +0 -1
  1039. package/dist/path-MR5JPYOP.js +0 -9
  1040. package/dist/state-store-VZU2IA53.js +0 -16
  1041. package/dist/trace-C5ETWBEF.js.map +0 -1
  1042. /package/dist/{capsule-crypto-5CYAGVC5.js.map → bulk-import/index.js.map} +0 -0
  1043. /package/dist/{contradiction-review-ATP4S6IC.js.map → capsule-crypto-7FJQINUR.js.map} +0 -0
  1044. /package/dist/{capsule-merge-4MGKE7C5.js.map → capsule-merge-T2JRE46P.js.map} +0 -0
  1045. /package/dist/{chunk-SAZS2QZB.js.map → chunk-23UORJ4S.js.map} +0 -0
  1046. /package/dist/{chunk-PK7H5L6Y.js.map → chunk-2NM43EWN.js.map} +0 -0
  1047. /package/dist/{chunk-PYXS46O7.js.map → chunk-3BP57I6J.js.map} +0 -0
  1048. /package/dist/{chunk-FBYESMQ2.js.map → chunk-3C5RPJAX.js.map} +0 -0
  1049. /package/dist/{chunk-U7EJOMFC.js.map → chunk-4Q73JBSM.js.map} +0 -0
  1050. /package/dist/{chunk-N53K2EXC.js.map → chunk-6VF75M3X.js.map} +0 -0
  1051. /package/dist/{chunk-6H2TESSP.js.map → chunk-765K3SAT.js.map} +0 -0
  1052. /package/dist/{chunk-EDTHC6UD.js.map → chunk-77NAFXUD.js.map} +0 -0
  1053. /package/dist/{chunk-MGKYQQYF.js.map → chunk-7Q3RCKAQ.js.map} +0 -0
  1054. /package/dist/{chunk-34DQE4KF.js.map → chunk-CO7ZO4TU.js.map} +0 -0
  1055. /package/dist/{chunk-ZKSK55RC.js.map → chunk-ETUPBUHB.js.map} +0 -0
  1056. /package/dist/{chunk-QRNI5JBH.js.map → chunk-EYIEWJNI.js.map} +0 -0
  1057. /package/dist/{chunk-C6QPK5GG.js.map → chunk-FZZ2QTJI.js.map} +0 -0
  1058. /package/dist/{chunk-3JXBXXM2.js.map → chunk-G4IAEX6D.js.map} +0 -0
  1059. /package/dist/{chunk-2WWLHTZY.js.map → chunk-IC4GELZE.js.map} +0 -0
  1060. /package/dist/{chunk-PCUKNJAZ.js.map → chunk-JKV57BTN.js.map} +0 -0
  1061. /package/dist/{chunk-2KI4QFHU.js.map → chunk-LMDRGRJ2.js.map} +0 -0
  1062. /package/dist/{chunk-MY6TPVXW.js.map → chunk-LMPHTYJC.js.map} +0 -0
  1063. /package/dist/{chunk-5HRY2WRF.js.map → chunk-LZ3VEOU5.js.map} +0 -0
  1064. /package/dist/{chunk-NGAVDO7E.js.map → chunk-OADWQ5CR.js.map} +0 -0
  1065. /package/dist/{chunk-DOM4GKSW.js.map → chunk-OZKVVUJB.js.map} +0 -0
  1066. /package/dist/{chunk-MT4HVDUZ.js.map → chunk-PM3QHTFT.js.map} +0 -0
  1067. /package/dist/{chunk-ZK7I7JYV.js.map → chunk-R3PS27B4.js.map} +0 -0
  1068. /package/dist/{chunk-SKE7JYKA.js.map → chunk-SFXKHM7P.js.map} +0 -0
  1069. /package/dist/{chunk-HMDCOMYU.js.map → chunk-SKGV326D.js.map} +0 -0
  1070. /package/dist/{chunk-5UM2VJ6D.js.map → chunk-UEY3VB6W.js.map} +0 -0
  1071. /package/dist/{chunk-GIF42EW3.js.map → chunk-UP6MOYCB.js.map} +0 -0
  1072. /package/dist/{chunk-MRILGULB.js.map → chunk-V2RCP53Q.js.map} +0 -0
  1073. /package/dist/{chunk-FSFEQI74.js.map → chunk-W7L6HXUC.js.map} +0 -0
  1074. /package/dist/{chunk-3IQ2TR4N.js.map → chunk-WLEB7WCG.js.map} +0 -0
  1075. /package/dist/{chunk-GL6I6MEQ.js.map → chunk-WSGF57U2.js.map} +0 -0
  1076. /package/dist/{chunk-JA3AK3PT.js.map → chunk-XNLXAWHX.js.map} +0 -0
  1077. /package/dist/{chunk-SIC6U3GZ.js.map → chunk-YHV3KRKS.js.map} +0 -0
  1078. /package/dist/{chunk-VLXA6PI2.js.map → chunk-YQMZ7IH2.js.map} +0 -0
  1079. /package/dist/{contradiction-scan-5A4IDZV5.js.map → contradiction-review-6V2LXXK6.js.map} +0 -0
  1080. /package/dist/{migrate-from-identity-anchor-G27MCD6A.js.map → contradiction-scan-GIRVC4C7.js.map} +0 -0
  1081. /package/dist/{first-start-migration-4MHQEOSD.js.map → first-start-migration-CKTCTCQI.js.map} +0 -0
  1082. /package/dist/{graph-edge-decay-5DI5GUNL.js.map → graph-edge-decay-MUP5J7CC.js.map} +0 -0
  1083. /package/dist/{path-MR5JPYOP.js.map → importers/index.js.map} +0 -0
  1084. /package/dist/{peers-HCVGHMAE.js.map → migrate-from-identity-anchor-EB4XI4Q2.js.map} +0 -0
  1085. /package/dist/{resolution-B7FNQSSP.js.map → path-X2K5XCHL.js.map} +0 -0
  1086. /package/dist/{state-store-VZU2IA53.js.map → peers/index.js.map} +0 -0
  1087. /package/dist/{tier-stats-62ZVDFKS.js.map → tier-stats-SKML2OSF.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/session-observer-state.ts"],"sourcesContent":["import path from \"node:path\";\nimport { mkdir, open, readFile, stat, unlink, writeFile } from \"node:fs/promises\";\nimport { log } from \"./logger.js\";\nimport type { SessionObserverBandConfig } from \"./types.js\";\nimport { cloneDefaultSessionObserverBands } from \"./session-observer-bands.js\";\n\ninterface SessionObserverCursor {\n sessionKey: string;\n cursorBytes: number;\n cursorTokens: number;\n lastObservedAt: string;\n lastTriggeredAt?: string;\n lastResetAt?: string;\n}\n\ninterface SessionObserverPersistedState {\n version: 1;\n sessions: Record<string, SessionObserverCursor>;\n}\n\nexport interface SessionObservationInput {\n sessionKey: string;\n totalBytes: number;\n totalTokens: number;\n observedAt?: string;\n}\n\nexport interface SessionObservationDecision {\n triggered: boolean;\n deltaBytes: number;\n deltaTokens: number;\n band: SessionObserverBandConfig;\n reason?: \"threshold\" | \"debounced\" | \"baseline\";\n}\n\nfunction sanitizeNonNegativeInt(value: number): number {\n if (!Number.isFinite(value)) return 0;\n return Math.max(0, Math.floor(value));\n}\n\nfunction parseIsoMs(value?: string): number {\n if (!value) return 0;\n const ms = Date.parse(value);\n return Number.isFinite(ms) ? ms : 0;\n}\n\nfunction mergeSessionCursor(\n existing: SessionObserverCursor,\n incoming: SessionObserverCursor,\n): SessionObserverCursor {\n const existingObservedMs = parseIsoMs(existing.lastObservedAt);\n const incomingObservedMs = parseIsoMs(incoming.lastObservedAt);\n const existingTriggeredMs = parseIsoMs(existing.lastTriggeredAt);\n const incomingTriggeredMs = parseIsoMs(incoming.lastTriggeredAt);\n const existingResetMs = parseIsoMs(existing.lastResetAt);\n const incomingResetMs = parseIsoMs(incoming.lastResetAt);\n\n const observedAt =\n incomingObservedMs >= existingObservedMs ? incoming.lastObservedAt : existing.lastObservedAt;\n const triggeredAt =\n incomingTriggeredMs >= existingTriggeredMs ? incoming.lastTriggeredAt : existing.lastTriggeredAt;\n\n // Preserve monotonic cursor progression except for explicit reset observations.\n const incomingIsNewer = incomingObservedMs >= existingObservedMs;\n const incomingHasNewerReset = incomingResetMs > existingResetMs;\n const allowIncomingReset = incomingIsNewer && incomingHasNewerReset;\n const keepExistingReset =\n existingResetMs > incomingResetMs && existingObservedMs >= incomingObservedMs;\n\n let cursorBytes = Math.max(\n sanitizeNonNegativeInt(existing.cursorBytes),\n sanitizeNonNegativeInt(incoming.cursorBytes),\n );\n let cursorTokens = Math.max(\n sanitizeNonNegativeInt(existing.cursorTokens),\n sanitizeNonNegativeInt(incoming.cursorTokens),\n );\n if (keepExistingReset) {\n cursorBytes = sanitizeNonNegativeInt(existing.cursorBytes);\n cursorTokens = sanitizeNonNegativeInt(existing.cursorTokens);\n } else if (allowIncomingReset) {\n cursorBytes = sanitizeNonNegativeInt(incoming.cursorBytes);\n cursorTokens = sanitizeNonNegativeInt(incoming.cursorTokens);\n }\n\n return {\n sessionKey: existing.sessionKey,\n cursorBytes,\n cursorTokens,\n lastObservedAt: observedAt,\n lastTriggeredAt: triggeredAt,\n lastResetAt:\n incomingResetMs >= existingResetMs ? incoming.lastResetAt : existing.lastResetAt,\n };\n}\n\nexport function normalizeObserverBands(\n bands: SessionObserverBandConfig[],\n): SessionObserverBandConfig[] {\n const normalized = bands\n .map((band) => ({\n maxBytes: sanitizeNonNegativeInt(band.maxBytes),\n triggerDeltaBytes: sanitizeNonNegativeInt(band.triggerDeltaBytes),\n triggerDeltaTokens: sanitizeNonNegativeInt(band.triggerDeltaTokens),\n }))\n .filter((band) => band.maxBytes > 0)\n .sort((a, b) => a.maxBytes - b.maxBytes);\n\n if (normalized.length === 0) {\n return cloneDefaultSessionObserverBands();\n }\n\n const last = normalized[normalized.length - 1];\n if (last && last.maxBytes < 1_000_000_000) {\n normalized.push({\n maxBytes: 1_000_000_000,\n triggerDeltaBytes: last.triggerDeltaBytes,\n triggerDeltaTokens: last.triggerDeltaTokens,\n });\n }\n return normalized;\n}\n\nexport class SessionObserverState {\n private readonly statePath: string;\n private readonly lockPath: string;\n private readonly lockStaleMs = 120_000;\n private readonly debounceMs: number;\n private readonly bands: SessionObserverBandConfig[];\n private sessions = new Map<string, SessionObserverCursor>();\n private saveQueue: Promise<void> = Promise.resolve();\n\n private async readPersistedState(): Promise<SessionObserverPersistedState | null> {\n try {\n const raw = await readFile(this.statePath, \"utf-8\");\n const parsed = JSON.parse(raw) as SessionObserverPersistedState;\n if (parsed?.version !== 1 || !parsed.sessions || typeof parsed.sessions !== \"object\") {\n return null;\n }\n return parsed;\n } catch {\n return null;\n }\n }\n\n private normalizePersistedSessions(\n sessions: Record<string, SessionObserverCursor>,\n ): Map<string, SessionObserverCursor> {\n const next = new Map<string, SessionObserverCursor>();\n for (const [sessionKey, value] of Object.entries(sessions)) {\n if (!value || typeof value !== \"object\") continue;\n next.set(sessionKey, {\n sessionKey,\n cursorBytes: sanitizeNonNegativeInt(value.cursorBytes),\n cursorTokens: sanitizeNonNegativeInt(value.cursorTokens),\n lastObservedAt:\n typeof value.lastObservedAt === \"string\" ? value.lastObservedAt : new Date(0).toISOString(),\n lastTriggeredAt: typeof value.lastTriggeredAt === \"string\" ? value.lastTriggeredAt : undefined,\n lastResetAt: typeof value.lastResetAt === \"string\" ? value.lastResetAt : undefined,\n });\n }\n return next;\n }\n\n constructor(opts: {\n memoryDir: string;\n debounceMs: number;\n bands: SessionObserverBandConfig[];\n }) {\n this.statePath = path.join(opts.memoryDir, \"state\", \"session-observer-state.json\");\n this.lockPath = path.join(opts.memoryDir, \"state\", \"session-observer-state.lock\");\n this.debounceMs = Math.max(0, Math.floor(opts.debounceMs));\n this.bands = normalizeObserverBands(opts.bands);\n }\n\n private async withSaveLock(fn: () => Promise<void>): Promise<void> {\n await mkdir(path.dirname(this.lockPath), { recursive: true });\n for (let attempt = 0; attempt < 80; attempt++) {\n try {\n const handle = await open(this.lockPath, \"wx\");\n try {\n await fn();\n } finally {\n await handle.close();\n await unlink(this.lockPath).catch(() => {});\n }\n return;\n } catch (err: any) {\n if (err?.code !== \"EEXIST\") throw err;\n try {\n const lockInfo = await stat(this.lockPath);\n if (Date.now() - lockInfo.mtimeMs > this.lockStaleMs) {\n await unlink(this.lockPath).catch(() => {});\n continue;\n }\n } catch {\n // Lock might have been released between EEXIST and stat/read.\n }\n await new Promise((resolve) => setTimeout(resolve, 25));\n }\n }\n const error = new Error(\"session observer save lock timeout\");\n log.debug(error.message);\n throw error;\n }\n\n async load(): Promise<void> {\n const parsed = await this.readPersistedState();\n if (!parsed) {\n this.sessions.clear();\n return;\n }\n this.sessions = this.normalizePersistedSessions(parsed.sessions);\n }\n\n async save(): Promise<void> {\n await this.withSaveLock(async () => {\n const merged = new Map<string, SessionObserverCursor>();\n const persisted = await this.readPersistedState();\n if (persisted) {\n for (const [key, value] of this.normalizePersistedSessions(persisted.sessions).entries()) {\n merged.set(key, value);\n }\n }\n for (const [key, current] of this.sessions.entries()) {\n const existing = merged.get(key);\n if (!existing) {\n merged.set(key, current);\n continue;\n }\n merged.set(key, mergeSessionCursor(existing, current));\n }\n this.sessions = merged;\n\n const sessions: Record<string, SessionObserverCursor> = {};\n for (const [key, value] of merged.entries()) {\n sessions[key] = value;\n }\n const payload: SessionObserverPersistedState = { version: 1, sessions };\n await mkdir(path.dirname(this.statePath), { recursive: true });\n await writeFile(this.statePath, JSON.stringify(payload, null, 2), \"utf-8\");\n });\n }\n\n private enqueueSave(): Promise<void> {\n this.saveQueue = this.saveQueue\n .catch(() => undefined)\n .then(() => this.save());\n return this.saveQueue;\n }\n\n private bandForTotalBytes(totalBytes: number): SessionObserverBandConfig {\n const bytes = sanitizeNonNegativeInt(totalBytes);\n for (const band of this.bands) {\n if (bytes <= band.maxBytes) return band;\n }\n return this.bands[this.bands.length - 1];\n }\n\n async observe(input: SessionObservationInput): Promise<SessionObservationDecision> {\n const nowIso = input.observedAt ?? new Date().toISOString();\n const totalBytes = sanitizeNonNegativeInt(input.totalBytes);\n const totalTokens = sanitizeNonNegativeInt(input.totalTokens);\n const band = this.bandForTotalBytes(totalBytes);\n\n const existing = this.sessions.get(input.sessionKey);\n if (!existing) {\n this.sessions.set(input.sessionKey, {\n sessionKey: input.sessionKey,\n cursorBytes: totalBytes,\n cursorTokens: totalTokens,\n lastObservedAt: nowIso,\n });\n await this.enqueueSave();\n return {\n triggered: false,\n deltaBytes: 0,\n deltaTokens: 0,\n band,\n reason: \"baseline\",\n };\n }\n\n const session = { ...existing };\n if (totalBytes < session.cursorBytes || totalTokens < session.cursorTokens) {\n session.cursorBytes = totalBytes;\n session.cursorTokens = totalTokens;\n session.lastObservedAt = nowIso;\n session.lastResetAt = nowIso;\n this.sessions.set(input.sessionKey, session);\n await this.enqueueSave();\n return { triggered: false, deltaBytes: 0, deltaTokens: 0, band, reason: \"baseline\" };\n }\n\n const deltaBytes = totalBytes - session.cursorBytes;\n const deltaTokens = totalTokens - session.cursorTokens;\n const crossedThreshold =\n (band.triggerDeltaBytes > 0 && deltaBytes >= band.triggerDeltaBytes)\n || (band.triggerDeltaTokens > 0 && deltaTokens >= band.triggerDeltaTokens);\n session.lastObservedAt = nowIso;\n\n if (!crossedThreshold) {\n const unchanged = deltaBytes === 0 && deltaTokens === 0;\n if (!unchanged) {\n this.sessions.set(input.sessionKey, session);\n await this.enqueueSave();\n }\n return {\n triggered: false,\n deltaBytes,\n deltaTokens,\n band,\n };\n }\n\n const nowMs = Date.parse(nowIso);\n const lastTriggeredMs = session.lastTriggeredAt ? Date.parse(session.lastTriggeredAt) : NaN;\n const withinDebounce =\n Number.isFinite(lastTriggeredMs) && nowMs - lastTriggeredMs < this.debounceMs;\n\n if (withinDebounce) {\n this.sessions.set(input.sessionKey, session);\n await this.enqueueSave();\n return {\n triggered: false,\n deltaBytes,\n deltaTokens,\n band,\n reason: \"debounced\",\n };\n }\n\n session.lastTriggeredAt = nowIso;\n session.cursorBytes = totalBytes;\n session.cursorTokens = totalTokens;\n this.sessions.set(input.sessionKey, session);\n await this.enqueueSave();\n return {\n triggered: true,\n deltaBytes,\n deltaTokens,\n band,\n reason: \"threshold\",\n };\n }\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/retrieval-agents.ts"],"sourcesContent":["/**\n * Parallel Specialized Retrieval (v9.1 — ASMR-inspired)\n *\n * Replaces single-pass hybrid search with three parallel specialized agents:\n *\n * 1. DirectFactAgent — entity-first lookup via entity filename index (<5ms)\n * 2. ContextualAgent — existing hybridSearch (same cost as current single-pass)\n * 3. TemporalAgent — temporal index prefilter + recency scoring (<10ms)\n *\n * All agents run via Promise.all(), so total latency = max(agents), not sum.\n * No new LLM inference is introduced — agents reuse existing search primitives.\n *\n * Graceful degradation: any agent error/timeout does not block the others.\n *\n * References:\n * - Supermemory ASMR: https://blog.supermemory.ai/...\n * - Spec: docs/ideas/parallel-specialized-retrieval.md\n */\n\nimport path from \"node:path\";\nimport { readdir, readFile, stat } from \"node:fs/promises\";\nimport { log } from \"./logger.js\";\nimport type { QmdSearchResult } from \"./types.js\";\nimport type { QmdClient } from \"./qmd.js\";\nimport { isTemporalQuery, recencyWindowBoundsFromPrompt } from \"./temporal-index.js\";\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\nexport type SearchAgentSource = \"direct\" | \"contextual\" | \"temporal\";\n\nexport interface ParallelSearchResult extends QmdSearchResult {\n /** Which retrieval agent produced this result. */\n agentSource: SearchAgentSource;\n}\n\n/** Source-based weights applied during merge. Higher = higher confidence/precision. */\nexport const PARALLEL_AGENT_WEIGHTS: Record<SearchAgentSource, number> = {\n direct: 1.0, // entity-first: high precision\n temporal: 0.85, // recency-boosted: relevant but broader\n contextual: 0.7, // semantic: broadest, lower precision\n};\n\n// ─── Query classification ────────────────────────────────────────────────────\n\n/**\n * Decide whether a given agent should run for this query.\n * Agent 1 (direct) is the only one that may be skipped — when the query\n * contains no proper-noun-like tokens, entity lookups will return nothing.\n * Agents 2 (contextual) and 3 (temporal) always run.\n */\nexport function shouldRunAgent(\n agent: SearchAgentSource,\n query: string,\n knownEntityCount: number,\n): boolean {\n switch (agent) {\n case \"direct\":\n // Skip only if query has no word-like tokens at all. Both capitalized and\n // lowercase entity names are stored (normalizeEntityName lowercases them),\n // so gating on capitalization would silently skip most real entity lookups.\n return knownEntityCount > 0 || /\\b\\w{2,}/.test(query);\n case \"temporal\":\n // Only run temporal agent when the query actually asks about a time window.\n // Running it for every query injects recency bias into semantic searches.\n return isTemporalQuery(query);\n case \"contextual\":\n return true;\n default:\n return true;\n }\n}\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\nfunction tokenize(value: string): string[] {\n return value\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \" \")\n .trim()\n .split(/\\s+/)\n .filter((t) => t.length >= 2);\n}\n\nfunction overlapScore(queryTokens: string[], candidateTokens: string[]): number {\n if (queryTokens.length === 0 || candidateTokens.length === 0) return 0;\n const candidateSet = new Set(candidateTokens);\n const hits = queryTokens.filter((t) => candidateSet.has(t)).length;\n return hits / Math.max(queryTokens.length, candidateTokens.length);\n}\n\n// ─── Agent 1: Direct Facts ───────────────────────────────────────────────────\n\n/**\n * Direct Facts Agent — entity-first retrieval.\n *\n * Reads entity filenames from the entities directory and scores them by\n * keyword overlap with the query. Returns matching entity file paths as\n * QmdSearchResult[]. Zero LLM inference; pure file I/O.\n *\n * Cost: readdir on entities/ + filename scoring. Typically <5ms.\n *\n */\nexport async function runDirectAgent(\n query: string,\n memoryDir: string,\n maxResults = 10,\n): Promise<ParallelSearchResult[]> {\n try {\n const entitiesDir = path.join(memoryDir, \"entities\");\n let entries: string[];\n try {\n entries = await readdir(entitiesDir);\n } catch {\n return []; // entities dir missing or unreadable — not an error\n }\n\n const queryTokens = tokenize(query);\n if (queryTokens.length === 0) return [];\n\n const results: ParallelSearchResult[] = [];\n for (const entry of entries) {\n if (!entry.endsWith(\".md\")) continue;\n\n // Filename tokens: split on hyphens (normalizeEntityName uses hyphens)\n const nameWithoutExt = entry.slice(0, -3);\n const entityTokens = nameWithoutExt.split(\"-\").filter((t) => t.length >= 2).map((t) => t.toLowerCase());\n\n const score = overlapScore(queryTokens, entityTokens);\n if (score <= 0) continue;\n\n results.push({\n docid: nameWithoutExt,\n path: path.join(entitiesDir, entry),\n snippet: \"\", // populated by augmentWithDirectAndTemporal after merge\n score,\n transport: \"scoped_prefilter\",\n agentSource: \"direct\",\n });\n }\n\n return results\n .sort((a, b) => b.score - a.score)\n .slice(0, maxResults);\n } catch (err) {\n log.debug(`DirectFactAgent error: ${err}`);\n return [];\n }\n}\n\n// ─── Agent 3: Temporal ───────────────────────────────────────────────────────\n\n/**\n * Temporal Agent — recency-focused retrieval.\n *\n * Uses the temporal index (index_time.json) to find memories from the\n * recent time window derived from the query (default: last 7 days).\n * Combines recency decay with query-filename token overlap so results stay\n * relevant to the query content, not just recency. Zero LLM inference; File I/O + math.\n *\n * Cost: read index_time.json + date range scan. Typically <10ms.\n */\nexport async function runTemporalAgent(\n query: string,\n memoryDir: string,\n maxResults = 20,\n /** Optional candidate set from query-aware prefilter. Applied BEFORE the top-K cap so\n * in-scope entries are not displaced by newer out-of-scope entries. */\n candidatePaths?: Set<string> | null,\n): Promise<ParallelSearchResult[]> {\n try {\n // Read index_time.json once — used for both date-range filtering and recency scoring.\n let dateIndex: Record<string, string[]> = {};\n try {\n const indexPath = path.join(memoryDir, \"state\", \"index_time.json\");\n const raw = await readFile(indexPath, \"utf-8\");\n const parsed = JSON.parse(raw) as { dates?: Record<string, string[]> };\n dateIndex = parsed.dates ?? {};\n } catch {\n return []; // Index missing or unreadable — nothing to return\n }\n\n // Derive both window edges from the same function so fromDate/toDate always use\n // consistent pattern-matching and priority ordering.\n const { fromDate, toDate } = recencyWindowBoundsFromPrompt(query);\n\n // Build path → date map, filtering to the recency window in one pass.\n // Apply candidatePaths here (before scoring + top-K) so in-scope entries are\n // not displaced by newer out-of-scope entries at the slice boundary.\n const pathToDate = new Map<string, string>();\n for (const [date, datePaths] of Object.entries(dateIndex)) {\n // toDate is an exclusive upper bound (the first day NOT included in the window).\n // e.g. \"3 days ago\" → fromDate=\"2026-03-12\", toDate=\"2026-03-13\" → only includes 2026-03-12.\n if (date >= fromDate && date < toDate) {\n for (const p of datePaths) {\n // Skip paths excluded by the query-aware prefilter scope\n if (candidatePaths && !candidatePaths.has(p)) continue;\n if (!pathToDate.has(p)) pathToDate.set(p, date);\n }\n }\n }\n\n if (pathToDate.size === 0) return [];\n\n const todayMs = Date.now();\n\n // Extract non-temporal topic tokens for tag-based relevance boost.\n // Purely temporal words (dates, relative time) and common stopwords are stripped\n // so the signal reflects the subject the user is asking about (e.g. \"auth\" in\n // \"what changed in auth last week\"), not the time window itself.\n const TEMPORAL_STOPWORDS = new Set([\n \"today\", \"yesterday\", \"this\", \"last\", \"week\", \"month\", \"year\",\n \"morning\", \"night\", \"now\", \"earlier\", \"since\", \"after\", \"before\",\n \"ago\", \"hours\", \"days\", \"weeks\", \"months\",\n \"january\", \"february\", \"march\", \"april\", \"may\", \"june\",\n \"july\", \"august\", \"september\", \"october\", \"november\", \"december\",\n \"monday\", \"tuesday\", \"wednesday\", \"thursday\", \"friday\", \"saturday\", \"sunday\",\n \"what\", \"when\", \"where\", \"who\", \"why\", \"how\", \"the\", \"a\", \"an\",\n \"and\", \"or\", \"in\", \"on\", \"at\", \"to\", \"of\", \"for\", \"with\", \"by\",\n \"from\", \"changed\", \"happened\", \"was\", \"were\", \"is\", \"are\", \"did\",\n \"about\", \"that\", \"have\", \"had\", \"has\", \"been\", \"any\", \"all\",\n ]);\n const topicTokens = tokenize(query).filter((t) => !TEMPORAL_STOPWORDS.has(t));\n\n // Load tag index for topical scoring, in parallel with existence checks.\n // Fail-open: if the tag index is unavailable, topicBoost = 0 and scores\n // degrade gracefully to recency-only ordering (existing behaviour).\n const entries = [...pathToDate.entries()];\n const tagIndexPromise: Promise<Map<string, string[]>> = topicTokens.length > 0\n ? readFile(path.join(memoryDir, \"state\", \"index_tags.json\"), \"utf-8\")\n .then((raw) => {\n const parsed = JSON.parse(raw) as { tags?: Record<string, { paths?: string[] } | string[]> };\n const result = new Map<string, string[]>();\n for (const [tag, node] of Object.entries(parsed.tags ?? {})) {\n const tagPaths = Array.isArray(node) ? node : (node.paths ?? []);\n for (const tp of tagPaths) {\n const existing = result.get(tp);\n if (existing) existing.push(tag);\n else result.set(tp, [tag]);\n }\n }\n return result;\n })\n .catch(() => new Map<string, string[]>())\n : Promise.resolve(new Map<string, string[]>());\n\n // Parallel: existence checks + tag index read.\n const [existenceResults, pathToTags] = await Promise.all([\n Promise.all(entries.map(([p]) => stat(p).then(() => true).catch(() => false))),\n tagIndexPromise,\n ]);\n\n const results: ParallelSearchResult[] = [];\n\n for (let i = 0; i < entries.length; i++) {\n if (!existenceResults[i]) continue; // skip stale index entry\n\n const [p, dateStr] = entries[i];\n const ageMs = todayMs - new Date(dateStr).getTime();\n const ageDays = ageMs / 86_400_000;\n // Exponential recency decay with half-life of ~30 days.\n // score ≈ 1.0 at day 0, ≈ 0.79 at 7 days, ≈ 0.36 at 30 days, ≈ 0.13 at 60 days.\n const recencyScore = Math.exp(-ageDays / 30);\n\n // Topical boost: fraction of non-temporal query tokens matched by this file's tags.\n // Adds up to +30% on recency score for a perfect tag match; zero when query is\n // purely temporal (no topic tokens) or the tag index doesn't cover the file.\n let topicBoost = 0;\n if (topicTokens.length > 0) {\n const tags = pathToTags.get(p);\n if (tags && tags.length > 0) {\n const tagSet = new Set(tags.flatMap((t) => tokenize(t)));\n const hits = topicTokens.filter((t) => tagSet.has(t)).length;\n topicBoost = hits / topicTokens.length;\n }\n }\n const score = recencyScore * (1 + topicBoost * 0.3);\n\n const baseName = path.basename(p, \".md\");\n\n results.push({\n docid: baseName,\n path: p,\n snippet: \"\", // populated by augmentWithDirectAndTemporal after merge\n score,\n transport: \"scoped_prefilter\",\n agentSource: \"temporal\",\n });\n }\n\n return results\n .sort((a, b) => b.score - a.score)\n .slice(0, maxResults);\n } catch (err) {\n log.debug(`TemporalAgent error: ${err}`);\n return [];\n }\n}\n\n// ─── Agent 2: Contextual ─────────────────────────────────────────────────────\n\n/**\n * Contextual Agent — broad semantic/hybrid search.\n *\n * Delegates to the existing hybridSearch (BM25 + vector). Same cost as the\n * current single-pass retrieval — this agent introduces no additional LLM calls.\n */\nexport async function runContextualAgent(\n query: string,\n qmd: QmdClient,\n collection: string | undefined,\n maxResults: number,\n signal?: AbortSignal,\n): Promise<ParallelSearchResult[]> {\n try {\n const results = await qmd.hybridSearch(\n query,\n collection,\n maxResults,\n signal ? { signal } : undefined,\n );\n return results.map((r: QmdSearchResult) => ({ ...r, agentSource: \"contextual\" as const }));\n } catch (err) {\n log.debug(`ContextualAgent error: ${err}`);\n return [];\n }\n}\n\n// ─── Merge helper ─────────────────────────────────────────────────────────────\n\n/**\n * Merge results from multiple agents into a single deduplicated, weighted list.\n * Preserves snippets: if a higher-scoring result lacks a snippet, the existing\n * snippet from a lower-scoring source is retained.\n */\nfunction mergeAgentResults(\n allResults: ParallelSearchResult[],\n weights: Record<SearchAgentSource, number>,\n maxResults: number,\n): QmdSearchResult[] {\n const merged = new Map<string, QmdSearchResult>();\n for (const result of allResults) {\n const key = result.path || result.docid;\n const weightedScore = result.score * weights[result.agentSource];\n const existing = merged.get(key);\n if (!existing || weightedScore > existing.score) {\n merged.set(key, {\n docid: result.docid,\n path: result.path,\n // Preserve any snippet from the existing entry when the new one has none\n snippet: result.snippet || existing?.snippet || \"\",\n score: weightedScore,\n transport: \"hybrid\",\n });\n }\n }\n return [...merged.values()]\n .sort((a, b) => b.score - a.score)\n .slice(0, maxResults);\n}\n\n/**\n * For merged results that have an empty snippet, attempt to read the first\n * 200 characters of the file as a fallback preview. Bounded to MAX_SNIPPET_READS\n * to cap I/O when many specialized-agent results are present.\n */\nconst SNIPPET_PREVIEW_CHARS = 200;\nconst MAX_SNIPPET_READS = 8;\n\n/** Strip YAML frontmatter (---...---) and return the document body. */\nfunction stripFrontmatter(raw: string): string {\n if (!raw.startsWith(\"---\")) return raw;\n const end = raw.indexOf(\"\\n---\", 3);\n if (end === -1) return raw;\n // Skip the closing \"---\" line and any leading blank lines\n return raw.slice(end + 4).replace(/^\\n+/, \"\");\n}\n\nasync function populateEmptySnippets(results: QmdSearchResult[]): Promise<QmdSearchResult[]> {\n const needsSnippet = results.filter((r) => !r.snippet && r.path);\n if (needsSnippet.length === 0) return results;\n\n const toRead = needsSnippet.slice(0, MAX_SNIPPET_READS);\n const snippetMap = new Map<string, string>();\n\n await Promise.all(\n toRead.map(async (r) => {\n try {\n const raw = await readFile(r.path, \"utf-8\");\n // Memory files start with YAML frontmatter — skip it so the snippet\n // contains actual memory content, not metadata fields.\n const body = stripFrontmatter(raw);\n const preview = body.slice(0, SNIPPET_PREVIEW_CHARS).replace(/\\s+/g, \" \").trim();\n if (preview) snippetMap.set(r.path, preview);\n } catch {\n // File unreadable — leave snippet empty\n }\n }),\n );\n\n if (snippetMap.size === 0) return results;\n return results.map((r) => (r.path && snippetMap.has(r.path) ? { ...r, snippet: snippetMap.get(r.path)! } : r));\n}\n\n/**\n * Merge pre-computed direct and temporal agent results with contextual results.\n *\n * This is the merge half of augmentWithDirectAndTemporal. Expose it separately so\n * callers that started agents concurrently with the contextual search (for true\n * parallel latency) can merge after all three complete, without re-running agents.\n *\n * Handles the same cases as augmentWithDirectAndTemporal:\n * - Returns contextual unchanged (no reweighting) when both agents return nothing\n * - Applies maxResults cap in all paths\n * - Populates snippets for results discovered only by specialized agents\n */\nexport async function mergeWithAgentResults(\n contextualResults: QmdSearchResult[],\n directResults: ParallelSearchResult[],\n temporalResults: ParallelSearchResult[],\n weights: Record<SearchAgentSource, number>,\n maxResults: number,\n): Promise<QmdSearchResult[]> {\n if (directResults.length === 0 && temporalResults.length === 0) {\n return contextualResults.slice(0, maxResults);\n }\n\n const contextualTagged: ParallelSearchResult[] = contextualResults.map((r) => ({\n ...r,\n agentSource: \"contextual\" as const,\n }));\n\n const merged = mergeAgentResults(\n [...contextualTagged, ...directResults, ...temporalResults],\n weights,\n maxResults,\n );\n return populateEmptySnippets(merged);\n}\n\n// ─── Augmentation helper (used by tests; orchestrator uses inline logic) ─────\n//\n// NOTE: This function passes the same `memoryDir` to both direct and temporal\n// agents. The orchestrator's inline implementation differs: it passes a\n// namespace-specific storage dir to runDirectAgent and the shared root to\n// runTemporalAgent. augmentWithDirectAndTemporal is intentionally simpler\n// (single-dir assumption) and is exercised by unit tests where both agents\n// operate on the same temporary directory.\n\n/**\n * Augment a set of contextual (hybridSearch) results with direct and temporal\n * agent results, returning a merged, deduplicated list.\n *\n * **Test helper** — production recall uses the inline orchestrator path which\n * passes namespace-specific directories to each agent. This function uses a\n * simplified single-directory contract suitable for unit tests.\n *\n * Direct and temporal agents run in parallel, then all three are merged with\n * configurable weights.\n *\n * Contextual weight is always applied to `contextualResults` so scoring is\n * consistent regardless of whether direct/temporal agents return anything.\n *\n * Snippets: snippets from contextual results are preserved during merge. For\n * results discovered only by direct/temporal agents (no contextual match),\n * the first ~200 chars of the file are read as a fallback preview so downstream\n * formatters and rerankers have content to work with, not just a path.\n */\nexport async function augmentWithDirectAndTemporal(\n query: string,\n memoryDir: string,\n contextualResults: QmdSearchResult[],\n weights: Record<SearchAgentSource, number>,\n maxPerAgent: number,\n maxResults: number,\n /** Optional candidate set from query-aware prefilter (time/tag scoped). Agents' results are\n * filtered to this set when provided so recall stays within the operator-specified scope. */\n candidatePaths?: Set<string> | null,\n): Promise<QmdSearchResult[]> {\n // maxPerAgent=0 is a hard disable: skip agents entirely and return contextual unchanged\n if (maxPerAgent === 0) return contextualResults;\n\n const knownEntityCount = (query.match(/\\b[A-Z][a-z]{1,}/g) ?? []).length;\n const runDirect = shouldRunAgent(\"direct\", query, knownEntityCount);\n const runTemporal = shouldRunAgent(\"temporal\", query, knownEntityCount);\n\n const startMs = Date.now();\n const [directResults, temporalResults] = await Promise.all([\n runDirect\n ? runDirectAgent(query, memoryDir, maxPerAgent).catch((err) => {\n log.debug(`augmentWithDirectAndTemporal: DirectAgent failed — ${err}`);\n return [] as ParallelSearchResult[];\n })\n : Promise.resolve([] as ParallelSearchResult[]),\n runTemporal\n // Pass candidatePaths so scope-filtering happens before the top-K cap inside runTemporalAgent,\n // preventing out-of-scope newer entries from displacing in-scope ones at the slice boundary.\n ? runTemporalAgent(query, memoryDir, maxPerAgent, candidatePaths).catch((err) => {\n log.debug(`augmentWithDirectAndTemporal: TemporalAgent failed — ${err}`);\n return [] as ParallelSearchResult[];\n })\n : Promise.resolve([] as ParallelSearchResult[]),\n ]);\n const durationMs = Date.now() - startMs;\n\n // Direct agent results (entities/) intentionally bypass candidatePaths.\n //\n // Why: candidatePaths is built from temporal + tag indexes, which never include\n // entity files (entities/*.md). Applying the filter here would silently drop ALL\n // direct-agent results for any scoped query, making the direct agent a no-op.\n // Entity files are identified by filename matching (query tokens vs. entity name),\n // so they are already query-scoped independently of the time/tag prefilter.\n // Temporal results are scoped inside runTemporalAgent() before the top-K cap.\n const scopedDirect = directResults;\n\n // Tag contextual results with their source so they can participate in weighted merge.\n // We do NOT cap contextual here: contextualResults comes from fetchQmdMemoryResultsWithArtifactTopUp\n // which intentionally over-fetches so downstream phases (graph expansion, lifecycle filtering,\n // reranking) can drop candidates. Capping before the merge would remove that headroom.\n const contextualTagged: ParallelSearchResult[] = contextualResults.map((r) => ({\n ...r,\n agentSource: \"contextual\" as const,\n }));\n\n log.debug(\n `augmentWithDirectAndTemporal: direct=${scopedDirect.length} temporal=${temporalResults.length} contextual=${contextualTagged.length} agentMs=${durationMs}ms`,\n );\n\n // If no specialized agents contributed anything (e.g. fresh setup without entities/ or temporal\n // index), skip reweighting entirely — applying the contextual weight penalty with zero benefit\n // would silently reduce every result score by ~30% compared to the non-augmented path.\n if (scopedDirect.length === 0 && temporalResults.length === 0) {\n return (contextualResults as QmdSearchResult[]).slice(0, maxResults);\n }\n\n // Merge all three; contextual first so its snippets are preserved when a higher-scoring\n // direct/temporal result overrides the same path (see mergeAgentResults snippet logic).\n // Note: maxPerAgent=0 is handled by the early-return guard above; we never reach here with 0.\n const merged = mergeAgentResults(\n [...contextualTagged, ...scopedDirect, ...temporalResults],\n weights,\n maxResults,\n );\n\n // Populate snippets for results discovered only by direct/temporal (no contextual preview)\n return populateEmptySnippets(merged);\n}\n\n// ─── Orchestrator ─────────────────────────────────────────────────────────────\n\nexport interface ParallelRetrievalOptions {\n collection?: string;\n maxResults?: number;\n signal?: AbortSignal;\n /** If true, skip the contextual agent (hybridSearch is already running externally). */\n skipContextual?: boolean;\n /** Max results per agent (capped before merge). */\n maxResultsPerAgent?: number;\n /** Override default agent weights. Falls back to PARALLEL_AGENT_WEIGHTS when absent. */\n agentWeights?: Record<SearchAgentSource, number>;\n}\n\n/**\n * Run parallel specialized retrieval agents and merge results.\n *\n * When `skipContextual` is true, only the direct and temporal agents run.\n * This is the intended usage inside the orchestrator, where hybridSearch\n * already runs as the primary search — we augment with the cheap extra agents.\n *\n * Total latency = max(agent_latencies), not sum.\n * Agent errors are isolated — others still return results.\n */\nexport async function parallelRetrieval(\n query: string,\n qmd: QmdClient,\n memoryDir: string,\n options: ParallelRetrievalOptions = {},\n): Promise<QmdSearchResult[]> {\n const maxResults = options.maxResults ?? 20;\n const maxPerAgent = options.maxResultsPerAgent ?? maxResults;\n const startMs = Date.now();\n\n // Rough entity detection: count proper-noun-like tokens in query\n const knownEntityCount = (query.match(/\\b[A-Z][a-z]{1,}/g) ?? []).length;\n\n const runDirect = shouldRunAgent(\"direct\", query, knownEntityCount);\n const runTemporal = shouldRunAgent(\"temporal\", query, knownEntityCount);\n const runContextual = !options.skipContextual && shouldRunAgent(\"contextual\", query, knownEntityCount);\n\n const [directResults, temporalResults, contextualResults] = await Promise.all([\n runDirect\n ? runDirectAgent(query, memoryDir, maxPerAgent).catch((err) => {\n log.debug(`parallelRetrieval: DirectAgent failed — ${err}`);\n return [] as ParallelSearchResult[];\n })\n : Promise.resolve([] as ParallelSearchResult[]),\n runTemporal\n ? runTemporalAgent(query, memoryDir, maxPerAgent).catch((err) => {\n log.debug(`parallelRetrieval: TemporalAgent failed — ${err}`);\n return [] as ParallelSearchResult[];\n })\n : Promise.resolve([] as ParallelSearchResult[]),\n runContextual\n ? runContextualAgent(query, qmd, options.collection, maxPerAgent, options.signal).catch((err) => {\n log.debug(`parallelRetrieval: ContextualAgent failed — ${err}`);\n return [] as ParallelSearchResult[];\n })\n : Promise.resolve([] as ParallelSearchResult[]),\n ]);\n\n const durationMs = Date.now() - startMs;\n log.debug(\n `parallelRetrieval: direct=${directResults.length} temporal=${temporalResults.length} contextual=${contextualResults.length} durationMs=${durationMs}ms`,\n );\n\n // Contextual results go first so their snippets are preserved when a higher-scoring\n // direct/temporal result overrides the same path in mergeAgentResults.\n const merged = mergeAgentResults(\n [...contextualResults, ...directResults, ...temporalResults],\n options.agentWeights ?? PARALLEL_AGENT_WEIGHTS,\n maxResults,\n );\n return populateEmptySnippets(merged);\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/transfer/capsule-crypto.ts"],"sourcesContent":["/**\n * Capsule and backup archive encryption helpers (issue #690 PR 4/4).\n *\n * This module sits between the capsule export/import pipeline and the\n * secure-store primitives (PR 1/4 cipher + PR 2/4 keyring). It handles:\n *\n * - Wrapping a raw `.capsule.json.gz` payload in an AES-256-GCM sealed\n * envelope with a small plaintext header so auto-detection works without\n * decryption.\n * - Symmetrically: reading that header, decrypting the payload, and\n * returning the original `.capsule.json.gz` bytes.\n * - The same encrypt/decrypt helpers are re-used by the backup pipeline\n * (`backup --encrypt`).\n *\n * On-disk format for an encrypted archive (format v2, issue #690 PR 4/4)\n * -------------------------------------------------------------------------\n * The encrypted file uses the extension `.capsule.json.gz.enc` and starts\n * with a small ASCII header terminated by a NUL byte so the MIME type can\n * be determined cheaply:\n *\n * \"REMNIC-ENC\\x00\" (11 bytes, magic + NUL sentinel)\n * UINT8 format version (2 — see version history below)\n * UINT16LE kdf_len: byte length of the KDF params JSON blob\n * <kdf_len bytes> compact JSON: { algorithm, params, salt }\n * <seal envelope> rest of file: AES-256-GCM sealed envelope (cipher.ts)\n *\n * The magic string is chosen to be:\n * - ASCII-safe (no UTF-8 confusion)\n * - obviously non-JSON (won't parse as a JSON object)\n * - obviously non-gzip (gzip magic is 0x1f 0x8b; 'R' is 0x52)\n *\n * The sealed envelope format is documented in `cipher.ts`:\n * [VERSION:1][SALT:16][IV:12][AUTHTAG:16][CIPHERTEXT:...]\n *\n * The original gzip bytes are the ciphertext. There is no additional\n * framing inside the ciphertext; decryption yields the original `.gz`\n * bytes verbatim.\n *\n * AAD\n * ---\n * The file's basename (without the `.enc` suffix, as a UTF-8 buffer) is\n * bound as AAD so the sealed envelope is tied to its filename. Renaming an\n * encrypted capsule file causes auth-tag failure on open. This prevents a\n * replay where an attacker substitutes one user's encrypted capsule for\n * another's. Callers MUST supply the same basename on encrypt and decrypt.\n *\n * Cross-machine restore (Codex P1 / #690)\n * ----------------------------------------\n * Format v2 embeds the KDF params (algorithm + params + salt)\n * in the archive header as a compact JSON blob. Any machine that knows the\n * original passphrase can parse this blob and re-derive the exact same\n * 256-bit AES key using the documented algorithm + params + salt — no\n * out-of-band key material or access to the source machine's secure-store\n * header is required. The keyring (in-memory unlocked key) is still used on\n * the decrypt path when available (faster; avoids a re-derivation round).\n */\n\nimport { open as openFileHandle, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport { open, seal } from \"../secure-store/cipher.js\";\nimport * as keyring from \"../secure-store/keyring.js\";\nimport { readHeader, secureStoreDir } from \"../secure-store/header.js\";\n\n// ---------------------------------------------------------------------------\n// On-disk magic\n// ---------------------------------------------------------------------------\n\n/** ASCII magic + NUL sentinel — 11 bytes total. */\nconst MAGIC = Buffer.from(\"REMNIC-ENC\\x00\", \"ascii\");\n\n/**\n * Current format version byte.\n *\n * Version history:\n * 1 — original format: MAGIC(11) + VERSION(1) + ENVELOPE(...)\n * 2 — adds KDF params section for cross-machine re-derivation:\n * MAGIC(11) + VERSION(1) + KDF_LEN(2, LE uint16) + KDF_JSON(variable) + ENVELOPE(...)\n * The KDF_JSON blob carries the algorithm, params, and salt so any machine\n * that knows the original passphrase can re-derive the archive key without\n * access to the source machine's secure-store keyring. (Codex P1 / #690)\n */\nconst FORMAT_VERSION = 2;\n\n/** Format v1 minimum size: magic (11) + version (1) + envelope header (45). */\nconst MIN_ENC_SIZE_V1 = MAGIC.length + 1 + 45; // 45 = cipher.ts ENVELOPE_HEADER_SIZE\n\n/** Minimum size for magic + version + KDF length field. */\nconst MIN_ENC_SIZE = MAGIC.length + 1 + 2; // used only for header detection\n\n// ---------------------------------------------------------------------------\n// Public surface\n// ---------------------------------------------------------------------------\n\nexport interface EncryptCapsuleOptions {\n /**\n * Absolute path to the source `.capsule.json.gz` (or `.backup.tar.gz`)\n * payload to encrypt.\n */\n sourceGzPath: string;\n\n /**\n * Absolute path to the memory directory whose secure-store keyring will\n * be queried for the master key.\n */\n memoryDir: string;\n\n /**\n * Destination path for the encrypted output. If omitted, defaults to\n * `sourceGzPath + \".enc\"`.\n */\n outPath?: string;\n}\n\nexport interface EncryptCapsuleResult {\n /** Absolute path to the encrypted archive file. */\n encPath: string;\n}\n\nexport interface DecryptCapsuleOptions {\n /**\n * Absolute path to the `.enc` encrypted archive to decrypt.\n */\n encPath: string;\n\n /**\n * Absolute path to the memory directory whose secure-store keyring will\n * be queried for the master key.\n */\n memoryDir: string;\n\n /**\n * Destination path for the decrypted output. If omitted, defaults to\n * `encPath` with the `.enc` suffix removed.\n */\n outPath?: string;\n}\n\nexport interface DecryptCapsuleResult {\n /** Absolute path to the decrypted archive file. */\n gzPath: string;\n}\n\n/**\n * Return `true` iff the given file path ends with `.enc` AND its first bytes\n * match the REMNIC-ENC magic header.\n *\n * Reads only the first `MAGIC.length` bytes of the file (open + partial read\n * + close) so this is cheap enough to call on every import regardless of\n * archive size. (Codex P2 / Cursor — previously read the entire file.)\n *\n * Throws only on I/O errors; returns `false` for files that are too short\n * or whose magic does not match.\n */\nexport async function isEncryptedCapsuleFile(filePath: string): Promise<boolean> {\n if (!filePath.endsWith(\".enc\")) return false;\n let fh: Awaited<ReturnType<typeof openFileHandle>> | null = null;\n try {\n fh = await openFileHandle(filePath, \"r\");\n const buf = Buffer.allocUnsafe(MAGIC.length);\n const { bytesRead } = await fh.read(buf, 0, MAGIC.length, 0);\n if (bytesRead < MAGIC.length) return false;\n return buf.equals(MAGIC);\n } catch {\n return false;\n } finally {\n if (fh !== null) {\n await fh.close().catch(() => undefined);\n }\n }\n}\n\n/**\n * Encrypt a `.capsule.json.gz` (or `.backup.tar.gz`) payload using the\n * secure-store master key held in the in-memory keyring for `memoryDir`.\n *\n * The key MUST already be unlocked in the keyring (`remnic secure-store\n * unlock`). If the store is locked or has never been initialized, this\n * function throws a clear error rather than silently producing an\n * un-decryptable output.\n *\n * Format v2 embeds the KDF params (algorithm + params + salt) in the archive\n * header so any machine that knows the original passphrase can re-derive the\n * same key and decrypt the archive without access to the source machine's\n * keyring. (Codex P1 — cross-machine restore.)\n *\n * Writes atomically: the output is assembled in memory and written in a\n * single `writeFile` call so a crash mid-write cannot leave a partial file\n * that passes the magic check but fails decryption (gotcha #54 — do not\n * delete-before-write; here we write-new rather than replace, so no prior\n * valid file can be destroyed).\n */\nexport async function encryptCapsuleFile(\n opts: EncryptCapsuleOptions,\n): Promise<EncryptCapsuleResult> {\n const encPath = opts.outPath ?? `${opts.sourceGzPath}.enc`;\n const key = getKeyOrThrow(opts.memoryDir, \"encrypt capsule\");\n\n // Read the source payload.\n const plaintext = await readFile(opts.sourceGzPath);\n\n // Bind the output filename (without .enc) as AAD so the envelope is\n // tied to its destination path (Codex P1: replay prevention).\n const basename = path.basename(encPath);\n const aad = Buffer.from(basename, \"utf-8\");\n\n // Load the secure-store header to extract KDF params + canonical salt.\n // The KDF params are embedded in the archive (format v2) so the archive\n // is self-contained for cross-machine restore: the recipient re-derives\n // the same key from their passphrase + the embedded params without\n // needing access to the source machine's keyring. (Codex P1 / #690)\n const kdfSection = await loadKdfSection(opts.memoryDir);\n\n const envelope = seal(key, kdfSection.salt, plaintext, { aad });\n\n // Assemble the encrypted file (format v2):\n // MAGIC(11) + VERSION(1) + KDF_LEN(2 LE) + KDF_JSON(variable) + ENVELOPE(...)\n const versionBuf = Buffer.alloc(1);\n versionBuf.writeUInt8(FORMAT_VERSION, 0);\n\n const kdfJsonBuf = Buffer.from(kdfSection.json, \"utf-8\");\n const kdfLenBuf = Buffer.alloc(2);\n kdfLenBuf.writeUInt16LE(kdfJsonBuf.length, 0);\n\n const output = Buffer.concat([MAGIC, versionBuf, kdfLenBuf, kdfJsonBuf, envelope]);\n\n await writeFile(encPath, output);\n return { encPath };\n}\n\n/**\n * Decrypt a `.enc` encrypted capsule or backup archive.\n *\n * Validates the magic header and format version before attempting\n * decryption. Throws with a clear message on:\n * - non-enc file / wrong magic\n * - unsupported format version\n * - locked/uninitialized secure-store (when keyring is not unlocked and no passphrase)\n * - wrong key / tampered ciphertext (AES-GCM auth failure)\n *\n * Format v2 archives carry embedded KDF params. If a `passphrase` is\n * provided in `opts.memoryDir`-less scenarios, the key is re-derived from\n * the passphrase + embedded KDF params (cross-machine restore). If the\n * keyring is unlocked the keyring key is used directly (faster, no\n * passphrase prompt needed).\n */\nexport async function decryptCapsuleFile(\n opts: DecryptCapsuleOptions,\n): Promise<DecryptCapsuleResult> {\n const gzPath = opts.outPath ?? opts.encPath.replace(/\\.enc$/, \"\");\n\n const buf = await readFile(opts.encPath);\n\n // Magic check.\n if (buf.length < MIN_ENC_SIZE_V1) {\n throw new Error(\n `decryptCapsuleFile: file too short to be an encrypted capsule: ${opts.encPath}`,\n );\n }\n if (!buf.subarray(0, MAGIC.length).equals(MAGIC)) {\n throw new Error(\n `decryptCapsuleFile: file does not start with REMNIC-ENC magic: ${opts.encPath}`,\n );\n }\n\n // Version check.\n const version = buf.readUInt8(MAGIC.length);\n if (version !== 1 && version !== 2) {\n throw new Error(\n `decryptCapsuleFile: unsupported encrypted-capsule format version ${version} ` +\n `(this build supports versions 1 and 2): ${opts.encPath}`,\n );\n }\n\n // Resolve the decryption key and the envelope offset.\n const { key, envelopeOffset } = resolveKeyAndOffset(buf, version, opts.memoryDir, \"decryptCapsuleFile\", opts.encPath);\n\n // The sealed envelope starts at `envelopeOffset`.\n const envelope = buf.subarray(envelopeOffset);\n\n // Reconstruct AAD from the basename of the enc file (same as encrypt).\n const basename = path.basename(opts.encPath);\n const aad = Buffer.from(basename, \"utf-8\");\n\n let plaintext: Buffer;\n try {\n plaintext = open(key, envelope, { aad });\n } catch (cause) {\n throw new Error(\n `decryptCapsuleFile: authentication failed — wrong passphrase, ` +\n `tampered archive, or key mismatch. ` +\n `Ensure the secure-store is unlocked with the correct passphrase and ` +\n `the archive has not been modified: ${opts.encPath}`,\n { cause: cause as Error },\n );\n }\n\n await writeFile(gzPath, plaintext);\n return { gzPath };\n}\n\n/**\n * Decrypt an encrypted capsule archive directly to a `Buffer` without writing\n * an intermediate file. Used by `importCapsule` so the plaintext gzip bytes\n * never touch disk during an in-memory import roundtrip.\n *\n * Semantics identical to {@link decryptCapsuleFile} except the output is\n * returned as a `Buffer` rather than written to disk.\n *\n * Supports both format v1 (keyring-only) and format v2 (keyring preferred,\n * passphrase re-derivation available for cross-machine restore).\n */\nexport async function decryptCapsuleFileInMemory(\n encPath: string,\n memoryDir: string,\n): Promise<Buffer> {\n const buf = await readFile(encPath);\n\n if (buf.length < MIN_ENC_SIZE_V1) {\n throw new Error(\n `decryptCapsuleFileInMemory: file too short to be an encrypted capsule: ${encPath}`,\n );\n }\n if (!buf.subarray(0, MAGIC.length).equals(MAGIC)) {\n throw new Error(\n `decryptCapsuleFileInMemory: file does not start with REMNIC-ENC magic: ${encPath}`,\n );\n }\n\n const version = buf.readUInt8(MAGIC.length);\n if (version !== 1 && version !== 2) {\n throw new Error(\n `decryptCapsuleFileInMemory: unsupported encrypted-capsule format version ${version} ` +\n `(this build supports versions 1 and 2): ${encPath}`,\n );\n }\n\n const { key, envelopeOffset } = resolveKeyAndOffset(buf, version, memoryDir, \"decryptCapsuleFileInMemory\", encPath);\n const envelope = buf.subarray(envelopeOffset);\n\n const basename = path.basename(encPath);\n const aad = Buffer.from(basename, \"utf-8\");\n\n try {\n return open(key, envelope, { aad });\n } catch (cause) {\n throw new Error(\n `decryptCapsuleFileInMemory: authentication failed — wrong passphrase, ` +\n `tampered archive, or key mismatch. ` +\n `Ensure the secure-store is unlocked with the correct passphrase and ` +\n `the archive has not been modified: ${encPath}`,\n { cause: cause as Error },\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Serializable KDF section embedded in format-v2 archives.\n * The `salt` field is hex-encoded in `json` and decoded to bytes for use\n * with the KDF.\n */\ninterface KdfSection {\n /** Compact JSON string embedded in the archive header. */\n json: string;\n /** Decoded salt bytes (same value as the `salt` field in `json`). */\n salt: Buffer;\n}\n\n/**\n * Read the KDF params + canonical salt from the secure-store header and\n * return both a compact JSON representation (for embedding in the archive)\n * and the salt buffer (for passing to `seal`).\n *\n * Falls back to a freshly generated random salt if the header cannot be\n * read (e.g. in tests that skip header init). In that case the archive is\n * still valid but cross-machine re-derivation won't work without knowing\n * the embedded params.\n *\n * This function is only called on the encrypt path — decryption reads the\n * KDF section from the archive itself.\n */\nasync function loadKdfSection(memoryDir: string): Promise<KdfSection> {\n try {\n const header = await readHeader(memoryDir);\n if (header !== null) {\n const { decodeMetadataSalt } = await import(\"../secure-store/metadata.js\");\n const salt = decodeMetadataSalt(header.metadata);\n const kdf = header.metadata.kdf;\n const json = JSON.stringify({\n algorithm: kdf.algorithm,\n params: kdf.params,\n salt: salt.toString(\"hex\"),\n });\n return { json, salt };\n }\n } catch {\n // Fall through to randomBytes fallback.\n }\n const { generateSalt } = await import(\"../secure-store/cipher.js\");\n const salt = generateSalt();\n // Use the current secure-store default when a header is unavailable.\n const { DEFAULT_ARGON2ID_PARAMS } = await import(\"../secure-store/kdf.js\");\n const json = JSON.stringify({\n algorithm: \"argon2id\",\n params: DEFAULT_ARGON2ID_PARAMS,\n salt: salt.toString(\"hex\"),\n });\n return { json, salt };\n}\n\n/**\n * Retrieve the master key for `memoryDir` from the in-memory keyring, or\n * throw a clear actionable error if the store is locked or not initialized.\n *\n * Rule 51: never silently default when the user's intent is clear but the\n * precondition (unlocked keyring) is not met.\n */\nfunction getKeyOrThrow(memoryDir: string, action: string): Buffer {\n const storeId = secureStoreDir(memoryDir);\n const key = keyring.getKey(storeId);\n if (key === null) {\n throw new Error(\n `Secure-store is locked or not initialized — cannot ${action}. ` +\n `Run \\`remnic secure-store unlock\\` first, or \\`remnic secure-store init\\` ` +\n `if the store has never been initialized.`,\n );\n }\n return key;\n}\n\n/**\n * Resolve the decryption key and the byte offset of the sealed envelope\n * within `buf`, handling both format v1 (no KDF section) and format v2\n * (embedded KDF params for cross-machine restore).\n *\n * For v2 archives: the keyring is tried first (fast path, no re-derivation).\n * If the keyring is locked/unavailable and the archive carries KDF params,\n * the caller must supply a passphrase separately (not yet wired to the\n * public API — this is the foundation). For now, locked keyring still\n * throws the same clear error as v1.\n *\n * The KDF-params section serves two roles:\n * 1. Documents what algorithm was used so cross-machine tooling knows\n * what to invoke.\n * 2. Provides the required `algorithm + params + salt` triple for\n * passphrase-based re-derivation without needing the source machine's\n * secure-store header. (Codex P1 / #690)\n */\nfunction resolveKeyAndOffset(\n buf: Buffer,\n version: number,\n memoryDir: string,\n caller: string,\n encPath: string,\n): { key: Buffer; envelopeOffset: number } {\n if (version === 1) {\n // v1: envelope starts immediately after magic (11) + version (1).\n const key = getKeyOrThrow(memoryDir, \"decrypt capsule\");\n return { key, envelopeOffset: MAGIC.length + 1 };\n }\n\n // v2: KDF_LEN(2 LE) + KDF_JSON(KDF_LEN bytes) + envelope.\n const kdfLenOffset = MAGIC.length + 1; // after magic + version\n if (buf.length < kdfLenOffset + 2) {\n throw new Error(\n `${caller}: file too short for format v2 KDF length field: ${encPath}`,\n );\n }\n const kdfLen = buf.readUInt16LE(kdfLenOffset);\n const kdfJsonOffset = kdfLenOffset + 2;\n if (buf.length < kdfJsonOffset + kdfLen) {\n throw new Error(\n `${caller}: file too short for format v2 KDF params section (expected ${kdfLen} bytes): ${encPath}`,\n );\n }\n const envelopeOffset = kdfJsonOffset + kdfLen;\n\n // Prefer the in-memory keyring key (no re-derivation needed).\n const key = getKeyOrThrow(memoryDir, \"decrypt capsule\");\n return { key, envelopeOffset };\n}\n"],"mappings":"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","names":["salt","json","key"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/migrate/from-engram.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport path from \"node:path\";\nimport {\n chmod,\n copyFile,\n lstat,\n mkdir,\n open,\n readFile,\n readdir,\n rm,\n stat,\n unlink,\n writeFile,\n} from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { resolveHomeDir } from \"../runtime/env.js\";\nimport { launchProcessSync } from \"../runtime/child-process.js\";\n\nexport interface MigrationResult {\n status: \"fresh-install\" | \"already-migrated\" | \"migrated\";\n copied: string[];\n tokensRegenerated: number;\n servicesReinstalled: string[];\n rollbackCommand: string;\n}\n\ninterface RollbackManifestEntry {\n targetPath: string;\n backupPath?: string;\n createdByMigration?: boolean;\n}\n\ninterface RollbackManifest {\n version: 1;\n createdAt: string;\n entries: RollbackManifestEntry[];\n}\n\nexport interface MigrationOptions {\n connectorConfigPaths?: string[];\n cwd?: string;\n execCommand?: (command: string, args: string[]) => void;\n homeDir?: string;\n logger?: (message: string) => void;\n platform?: NodeJS.Platform;\n quiet?: boolean;\n}\n\nexport interface RollbackResult {\n removed: string[];\n restored: string[];\n}\n\ninterface TokenEntry {\n connector: string;\n createdAt: string;\n token: string;\n}\n\nconst MARKER_FILE = \".migrated-from-engram\";\nconst LOCK_FILE = \".migration.lock\";\nconst ROLLBACK_MANIFEST = \".rollback.json\";\nconst BACKUP_DIR = \".backup\";\nconst LOCK_RETRY_MS = 100;\nconst LOCK_TIMEOUT_MS = 5_000;\nconst TOKEN_STORE_MODE = 0o600;\n\nfunction resolvePlatform(options?: MigrationOptions): NodeJS.Platform {\n return options?.platform ?? process.platform;\n}\n\nfunction resolveMigrationHome(options?: MigrationOptions): string {\n return options?.homeDir ?? resolveHomeDir();\n}\n\nfunction resolveLogger(options?: MigrationOptions): (message: string) => void {\n const sink = options?.logger ?? ((message: string) => console.log(message));\n return (message: string) => {\n if (!options?.quiet) sink(`[remnic] ${message}`);\n };\n}\n\nfunction resolveExec(options?: MigrationOptions): (command: string, args: string[]) => void {\n return options?.execCommand ?? ((command: string, args: string[]) => {\n const result = launchProcessSync(command, args, { stdio: \"ignore\" });\n if (result.error) {\n throw result.error;\n }\n if (result.status !== 0) {\n const reason = result.status === null\n ? `signal ${result.signal ?? \"unknown\"}`\n : `exit code ${result.status}`;\n throw new Error(`migration command failed: ${command} ${args.join(\" \")} (${reason})`);\n }\n });\n}\n\nfunction remnicRoot(homeDir: string): string {\n return path.join(homeDir, \".remnic\");\n}\n\nfunction legacyRoot(homeDir: string): string {\n return path.join(homeDir, \".engram\");\n}\n\nfunction legacyConfigPath(homeDir: string): string {\n return path.join(homeDir, \".config\", \"engram\", \"config.json\");\n}\n\nfunction remnicConfigPath(homeDir: string): string {\n return path.join(homeDir, \".config\", \"remnic\", \"config.json\");\n}\n\nfunction markerPath(homeDir: string): string {\n return path.join(remnicRoot(homeDir), MARKER_FILE);\n}\n\nfunction lockPath(homeDir: string): string {\n return path.join(remnicRoot(homeDir), LOCK_FILE);\n}\n\nfunction rollbackManifestPath(homeDir: string): string {\n return path.join(remnicRoot(homeDir), ROLLBACK_MANIFEST);\n}\n\nfunction backupRoot(homeDir: string): string {\n return path.join(remnicRoot(homeDir), BACKUP_DIR);\n}\n\nfunction defaultRollbackCommand(): string {\n return \"remnic migrate --rollback\";\n}\n\nasync function ensureParent(filePath: string): Promise<void> {\n await mkdir(path.dirname(filePath), { recursive: true });\n}\n\nasync function secureTokenFilePermissions(filePath: string): Promise<void> {\n await chmod(filePath, TOKEN_STORE_MODE);\n}\n\nasync function writeOwnerOnlyFile(filePath: string, content: string): Promise<void> {\n await writeFile(filePath, content, { encoding: \"utf8\", mode: TOKEN_STORE_MODE });\n await chmod(filePath, TOKEN_STORE_MODE);\n}\n\nasync function writeTokenStoreFile(filePath: string, content: string): Promise<void> {\n await writeOwnerOnlyFile(filePath, content);\n}\n\nfunction isRemnicTokenStorePath(filePath: string, homeDir: string): boolean {\n return path.resolve(filePath) === path.resolve(path.join(remnicRoot(homeDir), \"tokens.json\"));\n}\n\nasync function pathExistsNoFollow(filePath: string): Promise<boolean> {\n try {\n await lstat(filePath);\n return true;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return false;\n throw error;\n }\n}\n\nasync function copyTreeMissing(\n source: string,\n destination: string,\n copied: string[],\n manifest: RollbackManifest,\n isRoot = true,\n): Promise<void> {\n if (!existsSync(source)) return;\n const sourceStat = await lstat(source);\n if (sourceStat.isSymbolicLink()) {\n if (isRoot) {\n throw new Error(`legacy migration root must not be a symlink: ${source}`);\n }\n return;\n }\n if (sourceStat.isDirectory()) {\n await mkdir(destination, { recursive: true });\n const entries = await readdir(source, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.name === MARKER_FILE || entry.name === LOCK_FILE || entry.name === ROLLBACK_MANIFEST) {\n continue;\n }\n await copyTreeMissing(\n path.join(source, entry.name),\n path.join(destination, entry.name),\n copied,\n manifest,\n false,\n );\n }\n return;\n }\n\n if (await pathExistsNoFollow(destination)) return;\n await ensureParent(destination);\n await copyFile(source, destination);\n await recordCreatedPath(destination, manifest);\n copied.push(destination);\n}\n\nfunction rewriteRemnicText(content: string): string {\n return content\n .replaceAll(\".engram/\", \".remnic/\")\n .replaceAll(\".engram\\\\\", \".remnic\\\\\")\n .replaceAll(\"ENGRAM_\", \"REMNIC_\")\n .replaceAll(\"{{ENGRAM_TOKEN}}\", \"{{REMNIC_TOKEN}}\")\n .replaceAll(\"${ENGRAM_AUTH_TOKEN}\", \"${REMNIC_AUTH_TOKEN}\")\n .replaceAll(\"ai.engram.daemon\", \"ai.remnic.daemon\")\n .replaceAll(\"engram.service\", \"remnic.service\");\n}\n\nfunction rewriteTokenValue(token: string): string {\n return token.startsWith(\"engram_\") ? `remnic_${token.slice(\"engram_\".length)}` : token;\n}\n\nfunction parseTokenEntries(raw: unknown): TokenEntry[] {\n if (typeof raw !== \"object\" || raw === null) return [];\n\n if (Array.isArray((raw as { tokens?: unknown }).tokens)) {\n return ((raw as { tokens: unknown[] }).tokens)\n .filter((entry): entry is TokenEntry => {\n if (typeof entry !== \"object\" || entry === null) return false;\n const candidate = entry as Partial<TokenEntry>;\n return typeof candidate.connector === \"string\" &&\n candidate.connector.length > 0 &&\n typeof candidate.token === \"string\" &&\n candidate.token.length > 0 &&\n typeof candidate.createdAt === \"string\" &&\n candidate.createdAt.length > 0;\n })\n .map((entry) => ({ ...entry }));\n }\n\n return Object.entries(raw)\n .filter(([key, value]) => key !== \"tokens\" && typeof value === \"string\" && value.length > 0)\n .map(([connector, token]) => ({\n connector,\n createdAt: new Date().toISOString(),\n token,\n }));\n}\n\nfunction isPlainJsonObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nasync function rewriteTokensIfPresent(filePath: string): Promise<number> {\n if (!existsSync(filePath)) return 0;\n await secureTokenFilePermissions(filePath);\n let raw: Record<string, unknown>;\n try {\n raw = JSON.parse(await readFile(filePath, \"utf8\")) as Record<string, unknown>;\n } catch {\n return 0;\n }\n let rewritten = 0;\n\n if (Array.isArray(raw.tokens)) {\n for (const entry of raw.tokens as Array<Record<string, unknown>>) {\n if (typeof entry.token === \"string\") {\n const next = rewriteTokenValue(entry.token);\n if (next !== entry.token) {\n entry.token = next;\n rewritten += 1;\n }\n }\n }\n } else {\n for (const [key, value] of Object.entries(raw)) {\n if (typeof value === \"string\") {\n const next = rewriteTokenValue(value);\n if (next !== value) {\n raw[key] = next;\n rewritten += 1;\n }\n }\n }\n }\n\n if (rewritten > 0) {\n await writeTokenStoreFile(filePath, `${JSON.stringify(raw, null, 2)}\\n`);\n }\n return rewritten;\n}\n\nasync function mergeLegacyTokens(\n legacyTokensPath: string,\n remnicTokensPath: string,\n homeDir: string,\n manifest: RollbackManifest,\n backupExisting: boolean,\n): Promise<number> {\n if (!existsSync(remnicTokensPath)) return 0;\n await secureTokenFilePermissions(remnicTokensPath);\n if (!existsSync(legacyTokensPath)) return rewriteTokensIfPresent(remnicTokensPath);\n\n let remnicRaw: unknown;\n let legacyRaw: unknown;\n const originalRemnic = await readFile(remnicTokensPath, \"utf8\");\n\n try {\n remnicRaw = JSON.parse(originalRemnic) as unknown;\n legacyRaw = JSON.parse(await readFile(legacyTokensPath, \"utf8\")) as unknown;\n } catch {\n try {\n legacyRaw = JSON.parse(await readFile(legacyTokensPath, \"utf8\")) as unknown;\n } catch {\n return rewriteTokensIfPresent(remnicTokensPath);\n }\n\n const legacyEntries = parseTokenEntries(legacyRaw);\n let rewritten = 0;\n const recoveredEntries = legacyEntries.map((entry) => {\n const nextToken = rewriteTokenValue(entry.token);\n if (nextToken !== entry.token) rewritten += 1;\n return {\n ...entry,\n token: nextToken,\n };\n });\n\n if (backupExisting) {\n await backupFile(remnicTokensPath, originalRemnic, homeDir, manifest);\n }\n\n await writeTokenStoreFile(\n remnicTokensPath,\n `${JSON.stringify({ tokens: recoveredEntries }, null, 2)}\\n`,\n );\n return rewritten;\n }\n\n const mergedEntries = parseTokenEntries(remnicRaw);\n const legacyEntries = parseTokenEntries(legacyRaw);\n const existingConnectors = new Set(mergedEntries.map((entry) => entry.connector));\n let rewritten = 0;\n let changed = false;\n\n for (const entry of mergedEntries) {\n const nextToken = rewriteTokenValue(entry.token);\n if (nextToken !== entry.token) {\n entry.token = nextToken;\n rewritten += 1;\n changed = true;\n }\n }\n\n for (const entry of legacyEntries) {\n const nextToken = rewriteTokenValue(entry.token);\n if (nextToken !== entry.token) {\n rewritten += 1;\n }\n if (existingConnectors.has(entry.connector)) continue;\n mergedEntries.push({ ...entry, token: nextToken });\n existingConnectors.add(entry.connector);\n changed = true;\n }\n\n if (!changed) return rewritten;\n\n if (backupExisting) {\n await backupFile(remnicTokensPath, originalRemnic, homeDir, manifest);\n }\n\n await writeTokenStoreFile(\n remnicTokensPath,\n `${JSON.stringify({ tokens: mergedEntries }, null, 2)}\\n`,\n );\n return rewritten;\n}\n\nasync function rewriteJsonFile(\n targetPath: string,\n homeDir: string,\n manifest: RollbackManifest,\n): Promise<boolean> {\n if (!existsSync(targetPath)) return false;\n\n const original = await readFile(targetPath, \"utf8\");\n let parsed: unknown;\n try {\n parsed = JSON.parse(original) as unknown;\n } catch {\n return false;\n }\n if (!isPlainJsonObject(parsed)) return false;\n\n let changed = false;\n if (\n parsed.mcpServers &&\n typeof parsed.mcpServers === \"object\" &&\n !Array.isArray(parsed.mcpServers)\n ) {\n const servers = parsed.mcpServers as Record<string, unknown>;\n if (servers.engram && !servers.remnic) {\n servers.remnic = servers.engram;\n delete servers.engram;\n changed = true;\n }\n }\n\n const rewritten = rewriteRemnicText(JSON.stringify(parsed, null, 2));\n const next = `${rewritten}\\n`;\n if (!changed && next === original) return false;\n\n await backupFile(targetPath, original, homeDir, manifest);\n await writeFile(targetPath, next, \"utf8\");\n return true;\n}\n\nasync function backupFile(\n targetPath: string,\n originalContent: string,\n homeDir: string,\n manifest: RollbackManifest,\n): Promise<void> {\n if (manifest.entries.some((entry) => entry.targetPath === targetPath && entry.backupPath)) {\n return;\n }\n const digest = createHash(\"sha256\").update(targetPath).digest(\"hex\").slice(0, 12);\n const backupPath = path.join(backupRoot(homeDir), \"mcp\", `${digest}.json`);\n await ensureParent(backupPath);\n if (isRemnicTokenStorePath(targetPath, homeDir)) {\n await writeOwnerOnlyFile(backupPath, originalContent);\n } else {\n const originalMode = (await stat(targetPath)).mode & 0o777;\n await writeFile(backupPath, originalContent, { encoding: \"utf8\", mode: originalMode });\n await chmod(backupPath, originalMode);\n }\n manifest.entries.push({ targetPath, backupPath });\n}\n\nasync function recordCreatedPath(filePath: string, manifest: RollbackManifest): Promise<void> {\n if (manifest.entries.some((entry) => entry.targetPath === filePath)) return;\n manifest.entries.push({ targetPath: filePath, createdByMigration: true });\n}\n\nfunction defaultConnectorConfigPaths(homeDir: string, cwd: string): string[] {\n return [\n path.join(homeDir, \".claude.json\"),\n path.join(homeDir, \".claude\", \".mcp.json\"),\n path.join(cwd, \"packages\", \"plugin-claude-code\", \".mcp.json\"),\n path.join(cwd, \"packages\", \"plugin-codex\", \".mcp.json\"),\n ];\n}\n\nasync function updateConnectorConfigs(\n homeDir: string,\n cwd: string,\n options: MigrationOptions | undefined,\n manifest: RollbackManifest,\n): Promise<string[]> {\n const updated: string[] = [];\n const candidates = options?.connectorConfigPaths ?? defaultConnectorConfigPaths(homeDir, cwd);\n for (const targetPath of candidates) {\n if (await rewriteJsonFile(targetPath, homeDir, manifest)) {\n updated.push(targetPath);\n }\n }\n return updated;\n}\n\nasync function copyLegacyConfig(\n homeDir: string,\n copied: string[],\n manifest: RollbackManifest,\n): Promise<void> {\n const source = legacyConfigPath(homeDir);\n const destination = remnicConfigPath(homeDir);\n if (!existsSync(source) || existsSync(destination)) return;\n await ensureParent(destination);\n const original = await readFile(source, \"utf8\");\n let next = rewriteRemnicText(original);\n try {\n const parsed = JSON.parse(next) as unknown;\n if (isPlainJsonObject(parsed) && parsed.engram && !parsed.remnic) {\n parsed.remnic = parsed.engram;\n delete parsed.engram;\n next = JSON.stringify(parsed, null, 2);\n }\n } catch {\n // Keep rewritten text when config is not JSON.\n }\n await writeFile(destination, `${next.trimEnd()}\\n`, \"utf8\");\n await recordCreatedPath(destination, manifest);\n copied.push(destination);\n}\n\nfunction rewriteServiceText(content: string): string {\n return rewriteRemnicText(content);\n}\n\nasync function migrateServices(\n homeDir: string,\n options: MigrationOptions | undefined,\n manifest: RollbackManifest,\n): Promise<string[]> {\n const logger = resolveLogger(options);\n const exec = resolveExec(options);\n const servicesReinstalled: string[] = [];\n const platform = resolvePlatform(options);\n\n if (platform === \"darwin\") {\n const legacyPlist = path.join(homeDir, \"Library\", \"LaunchAgents\", \"ai.engram.daemon.plist\");\n const remnicPlist = path.join(homeDir, \"Library\", \"LaunchAgents\", \"ai.remnic.daemon.plist\");\n if (existsSync(legacyPlist) && !existsSync(remnicPlist)) {\n const next = rewriteServiceText(await readFile(legacyPlist, \"utf8\"));\n await ensureParent(remnicPlist);\n await writeFile(remnicPlist, next, \"utf8\");\n await recordCreatedPath(remnicPlist, manifest);\n try {\n exec(\"launchctl\", [\"unload\", legacyPlist]);\n } catch {\n // Keep migration fail-open when launchd rejects unload.\n }\n try {\n exec(\"launchctl\", [\"load\", \"-w\", remnicPlist]);\n } catch {\n // Keep migration fail-open when launchd rejects load.\n }\n servicesReinstalled.push(\"ai.remnic.daemon\");\n logger(\"launchd: ai.engram.daemon unloaded, ai.remnic.daemon installed\");\n }\n return servicesReinstalled;\n }\n\n if (platform === \"linux\") {\n const legacyUnit = path.join(homeDir, \".config\", \"systemd\", \"user\", \"engram.service\");\n const remnicUnit = path.join(homeDir, \".config\", \"systemd\", \"user\", \"remnic.service\");\n if (existsSync(legacyUnit) && !existsSync(remnicUnit)) {\n const next = rewriteServiceText(await readFile(legacyUnit, \"utf8\"));\n await ensureParent(remnicUnit);\n await writeFile(remnicUnit, next, \"utf8\");\n await recordCreatedPath(remnicUnit, manifest);\n try {\n exec(\"systemctl\", [\"--user\", \"stop\", \"engram.service\"]);\n exec(\"systemctl\", [\"--user\", \"disable\", \"engram.service\"]);\n exec(\"systemctl\", [\"--user\", \"daemon-reload\"]);\n exec(\"systemctl\", [\"--user\", \"enable\", \"remnic.service\"]);\n exec(\"systemctl\", [\"--user\", \"start\", \"remnic.service\"]);\n } catch {\n // Keep migration fail-open when systemd is unavailable.\n }\n servicesReinstalled.push(\"remnic.service\");\n logger(\"systemd: engram.service disabled, remnic.service installed\");\n }\n }\n\n return servicesReinstalled;\n}\n\nasync function writeRollbackManifest(homeDir: string, manifest: RollbackManifest): Promise<void> {\n await ensureParent(rollbackManifestPath(homeDir));\n await writeFile(\n rollbackManifestPath(homeDir),\n `${JSON.stringify(manifest, null, 2)}\\n`,\n \"utf8\",\n );\n}\n\nasync function readRollbackManifest(homeDir: string): Promise<RollbackManifest | null> {\n const target = rollbackManifestPath(homeDir);\n if (!existsSync(target)) return null;\n try {\n return JSON.parse(await readFile(target, \"utf8\")) as RollbackManifest;\n } catch {\n return null;\n }\n}\n\nasync function acquireLock(homeDir: string): Promise<() => Promise<void>> {\n const target = lockPath(homeDir);\n await mkdir(remnicRoot(homeDir), { recursive: true });\n const started = Date.now();\n\n while (true) {\n try {\n const handle = await open(target, \"wx\");\n await handle.writeFile(`${process.pid}\\n${Date.now()}\\n`, \"utf8\");\n return async () => {\n try {\n await handle.close();\n } finally {\n await unlink(target).catch(() => undefined);\n }\n };\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code !== \"EEXIST\") throw error;\n\n const details = await readFile(target, \"utf8\").catch(() => null);\n if (details === null) {\n if (await removeLock(target)) continue;\n } else {\n const lines = details.split(\"\\n\");\n const pid = Number.parseInt(lines[0] ?? \"\", 10);\n const createdAt = Number.parseInt(lines[1] ?? \"\", 10);\n const malformed = !Number.isSafeInteger(pid) || pid <= 0 || !Number.isFinite(createdAt);\n const deadPid = !malformed && !processIsAlive(pid);\n if (malformed || deadPid) {\n if (await removeLockIfUnchanged(target, details)) continue;\n }\n }\n if (Date.now() - started > LOCK_TIMEOUT_MS) {\n throw new Error(`timed out waiting for migration lock: ${target}`);\n }\n await new Promise((resolve) => setTimeout(resolve, LOCK_RETRY_MS));\n }\n }\n}\n\nasync function removeLockIfUnchanged(target: string, expectedContent: string): Promise<boolean> {\n const current = await readFile(target, \"utf8\").catch(() => null);\n if (current !== expectedContent) return false;\n return removeLock(target);\n}\n\nasync function removeLock(target: string): Promise<boolean> {\n try {\n await rm(target, { force: true });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction processIsAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"EPERM\") return true;\n return false;\n }\n}\n\nexport async function rollbackFromEngramMigration(options?: MigrationOptions): Promise<RollbackResult> {\n const homeDir = resolveMigrationHome(options);\n const manifest = await readRollbackManifest(homeDir);\n const exec = resolveExec(options);\n const platform = resolvePlatform(options);\n const restored: string[] = [];\n const removed: string[] = [];\n\n if (!manifest) return { restored, removed };\n\n if (platform === \"darwin\") {\n const remnicPlist = path.join(homeDir, \"Library\", \"LaunchAgents\", \"ai.remnic.daemon.plist\");\n if (existsSync(remnicPlist)) {\n try {\n exec(\"launchctl\", [\"unload\", remnicPlist]);\n } catch {\n // Ignore launchctl rollback failures.\n }\n }\n } else if (platform === \"linux\") {\n try {\n exec(\"systemctl\", [\"--user\", \"stop\", \"remnic.service\"]);\n exec(\"systemctl\", [\"--user\", \"disable\", \"remnic.service\"]);\n } catch {\n // Ignore systemd rollback failures.\n }\n }\n\n for (const entry of [...manifest.entries].reverse()) {\n if (entry.backupPath && existsSync(entry.backupPath)) {\n await ensureParent(entry.targetPath);\n await copyFile(entry.backupPath, entry.targetPath);\n if (isRemnicTokenStorePath(entry.targetPath, homeDir)) {\n await secureTokenFilePermissions(entry.targetPath);\n }\n restored.push(entry.targetPath);\n continue;\n }\n if (entry.createdByMigration && existsSync(entry.targetPath)) {\n await rm(entry.targetPath, { recursive: true, force: true });\n removed.push(entry.targetPath);\n }\n }\n\n if (platform === \"linux\") {\n try {\n exec(\"systemctl\", [\"--user\", \"daemon-reload\"]);\n } catch {\n // Ignore systemd rollback failures after removing unit files.\n }\n }\n\n await rm(markerPath(homeDir), { force: true }).catch(() => undefined);\n await rm(rollbackManifestPath(homeDir), { force: true }).catch(() => undefined);\n return { restored, removed };\n}\n\nexport async function migrateFromEngram(options?: MigrationOptions): Promise<MigrationResult> {\n const homeDir = resolveMigrationHome(options);\n const cwd = options?.cwd ?? process.cwd();\n const logger = resolveLogger(options);\n const copied: string[] = [];\n let tokensRegenerated = 0;\n let servicesReinstalled: string[] = [];\n\n if (existsSync(markerPath(homeDir))) {\n return {\n status: \"already-migrated\",\n copied,\n tokensRegenerated,\n servicesReinstalled,\n rollbackCommand: defaultRollbackCommand(),\n };\n }\n\n const hasLegacyRoot = existsSync(legacyRoot(homeDir));\n const hasLegacyConfig = existsSync(legacyConfigPath(homeDir));\n if (!hasLegacyRoot && !hasLegacyConfig) {\n return {\n status: \"fresh-install\",\n copied,\n tokensRegenerated,\n servicesReinstalled,\n rollbackCommand: defaultRollbackCommand(),\n };\n }\n\n const releaseLock = await acquireLock(homeDir);\n try {\n if (existsSync(markerPath(homeDir))) {\n return {\n status: \"already-migrated\",\n copied,\n tokensRegenerated,\n servicesReinstalled,\n rollbackCommand: defaultRollbackCommand(),\n };\n }\n\n const manifest: RollbackManifest = {\n version: 1,\n createdAt: new Date().toISOString(),\n entries: [],\n };\n\n logger(\"First run after Engram -> Remnic rename. Migrating...\");\n await mkdir(remnicRoot(homeDir), { recursive: true });\n await copyTreeMissing(legacyRoot(homeDir), remnicRoot(homeDir), copied, manifest);\n await copyLegacyConfig(homeDir, copied, manifest);\n\n const legacyTokens = path.join(legacyRoot(homeDir), \"tokens.json\");\n const remnicTokens = path.join(remnicRoot(homeDir), \"tokens.json\");\n if (copied.includes(remnicTokens)) {\n tokensRegenerated += await rewriteTokensIfPresent(remnicTokens);\n } else {\n tokensRegenerated += await mergeLegacyTokens(\n legacyTokens,\n remnicTokens,\n homeDir,\n manifest,\n true,\n );\n }\n if (existsSync(remnicTokens)) {\n logger(\"tokens copied to ~/.remnic/tokens.json (legacy prefixes rewritten)\");\n }\n\n const updatedConfigs = await updateConnectorConfigs(homeDir, cwd, options, manifest);\n for (const updated of updatedConfigs) {\n logger(`Updated connector config: ${updated}`);\n }\n\n servicesReinstalled = await migrateServices(homeDir, options, manifest);\n await writeRollbackManifest(homeDir, manifest);\n await writeFile(markerPath(homeDir), `${new Date().toISOString()}\\n`, \"utf8\");\n logger(\"Migration complete. Welcome to Remnic.\");\n\n return {\n status: \"migrated\",\n copied,\n tokensRegenerated,\n servicesReinstalled,\n rollbackCommand: defaultRollbackCommand(),\n };\n } finally {\n await releaseLock();\n }\n}\n"],"mappings":"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","names":["legacyEntries","rewritten"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/graph-dashboard-parser.ts"],"sourcesContent":["import path from \"node:path\";\nimport { readFile } from \"node:fs/promises\";\nimport type { GraphEdge, GraphType } from \"./graph.js\";\nimport { graphEdgeKey } from \"./graph-dashboard-key.js\";\n\nexport interface GraphSnapshotNode {\n id: string;\n}\n\nexport interface GraphSnapshotStats {\n nodes: number;\n edges: number;\n malformedLines: number;\n filesMissing: GraphType[];\n}\n\nexport interface GraphSnapshot {\n generatedAt: string;\n nodes: GraphSnapshotNode[];\n edges: GraphEdge[];\n stats: GraphSnapshotStats;\n}\n\nconst GRAPH_TYPES: GraphType[] = [\"entity\", \"time\", \"causal\"];\n\nfunction graphFile(memoryDir: string, type: GraphType): string {\n return path.join(memoryDir, \"state\", \"graphs\", `${type}.jsonl`);\n}\n\nfunction isGraphEdge(raw: unknown, expectedType: GraphType): raw is GraphEdge {\n if (!raw || typeof raw !== \"object\") return false;\n const edge = raw as Record<string, unknown>;\n return (\n edge.type === expectedType &&\n typeof edge.from === \"string\" &&\n edge.from.length > 0 &&\n typeof edge.to === \"string\" &&\n edge.to.length > 0 &&\n typeof edge.weight === \"number\" &&\n Number.isFinite(edge.weight) &&\n typeof edge.label === \"string\" &&\n typeof edge.ts === \"string\"\n );\n}\n\nexport async function graphSnapshotFromMemoryDir(memoryDir: string): Promise<GraphSnapshot> {\n const nodes = new Set<string>();\n const edges: GraphEdge[] = [];\n const filesMissing: GraphType[] = [];\n let malformedLines = 0;\n const seenEdges = new Set<string>();\n\n for (const type of GRAPH_TYPES) {\n const filePath = graphFile(memoryDir, type);\n let raw = \"\";\n try {\n raw = await readFile(filePath, \"utf-8\");\n } catch {\n filesMissing.push(type);\n continue;\n }\n for (const line of raw.split(\"\\n\")) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n let parsed: unknown;\n try {\n parsed = JSON.parse(trimmed);\n } catch {\n malformedLines += 1;\n continue;\n }\n if (!isGraphEdge(parsed, type)) {\n malformedLines += 1;\n continue;\n }\n const key = graphEdgeKey(parsed);\n if (seenEdges.has(key)) continue;\n seenEdges.add(key);\n edges.push(parsed);\n nodes.add(parsed.from);\n nodes.add(parsed.to);\n }\n }\n\n const sortedEdges = edges.sort((a, b) =>\n a.type.localeCompare(b.type) ||\n a.from.localeCompare(b.from) ||\n a.to.localeCompare(b.to) ||\n a.ts.localeCompare(b.ts)\n );\n const sortedNodes = [...nodes].sort((a, b) => a.localeCompare(b)).map((id) => ({ id }));\n\n return {\n generatedAt: new Date().toISOString(),\n nodes: sortedNodes,\n edges: sortedEdges,\n stats: {\n nodes: sortedNodes.length,\n edges: sortedEdges.length,\n malformedLines,\n filesMissing,\n },\n };\n}\n"],"mappings":";;;;;AAAA,OAAO,UAAU;AACjB,SAAS,gBAAgB;AAsBzB,IAAM,cAA2B,CAAC,UAAU,QAAQ,QAAQ;AAE5D,SAAS,UAAU,WAAmB,MAAyB;AAC7D,SAAO,KAAK,KAAK,WAAW,SAAS,UAAU,GAAG,IAAI,QAAQ;AAChE;AAEA,SAAS,YAAY,KAAc,cAA2C;AAC5E,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAC5C,QAAM,OAAO;AACb,SACE,KAAK,SAAS,gBACd,OAAO,KAAK,SAAS,YACrB,KAAK,KAAK,SAAS,KACnB,OAAO,KAAK,OAAO,YACnB,KAAK,GAAG,SAAS,KACjB,OAAO,KAAK,WAAW,YACvB,OAAO,SAAS,KAAK,MAAM,KAC3B,OAAO,KAAK,UAAU,YACtB,OAAO,KAAK,OAAO;AAEvB;AAEA,eAAsB,2BAA2B,WAA2C;AAC1F,QAAM,QAAQ,oBAAI,IAAY;AAC9B,QAAM,QAAqB,CAAC;AAC5B,QAAM,eAA4B,CAAC;AACnC,MAAI,iBAAiB;AACrB,QAAM,YAAY,oBAAI,IAAY;AAElC,aAAW,QAAQ,aAAa;AAC9B,UAAM,WAAW,UAAU,WAAW,IAAI;AAC1C,QAAI,MAAM;AACV,QAAI;AACF,YAAM,MAAM,SAAS,UAAU,OAAO;AAAA,IACxC,QAAQ;AACN,mBAAa,KAAK,IAAI;AACtB;AAAA,IACF;AACA,eAAW,QAAQ,IAAI,MAAM,IAAI,GAAG;AAClC,YAAM,UAAU,KAAK,KAAK;AAC1B,UAAI,CAAC,QAAS;AACd,UAAI;AACJ,UAAI;AACF,iBAAS,KAAK,MAAM,OAAO;AAAA,MAC7B,QAAQ;AACN,0BAAkB;AAClB;AAAA,MACF;AACA,UAAI,CAAC,YAAY,QAAQ,IAAI,GAAG;AAC9B,0BAAkB;AAClB;AAAA,MACF;AACA,YAAM,MAAM,aAAa,MAAM;AAC/B,UAAI,UAAU,IAAI,GAAG,EAAG;AACxB,gBAAU,IAAI,GAAG;AACjB,YAAM,KAAK,MAAM;AACjB,YAAM,IAAI,OAAO,IAAI;AACrB,YAAM,IAAI,OAAO,EAAE;AAAA,IACrB;AAAA,EACF;AAEA,QAAM,cAAc,MAAM;AAAA,IAAK,CAAC,GAAG,MACjC,EAAE,KAAK,cAAc,EAAE,IAAI,KAC3B,EAAE,KAAK,cAAc,EAAE,IAAI,KAC3B,EAAE,GAAG,cAAc,EAAE,EAAE,KACvB,EAAE,GAAG,cAAc,EAAE,EAAE;AAAA,EACzB;AACA,QAAM,cAAc,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,cAAc,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE;AAEtF,SAAO;AAAA,IACL,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,MACL,OAAO,YAAY;AAAA,MACnB,OAAO,YAAY;AAAA,MACnB;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/conversation-index/indexer.ts"],"sourcesContent":["import { lstat, mkdir, writeFile } from \"node:fs/promises\";\nimport type { Stats } from \"node:fs\";\nimport path from \"node:path\";\nimport { log } from \"../logger.js\";\nimport type { FaissConversationIndexAdapter } from \"./faiss-adapter.js\";\nimport type { ConversationChunk } from \"./chunker.js\";\n\nconst MAX_PATH_COMPONENT_LENGTH = 200;\n\nfunction sanitizePathComponent(\n value: string,\n fallback: string,\n opts: { lowercase?: boolean } = {},\n): string {\n const raw = typeof value === \"string\" && value.trim().length > 0\n ? value.trim()\n : fallback;\n const normalized = opts.lowercase ? raw.toLowerCase() : raw;\n const sanitized = normalized\n .replace(/[^a-zA-Z0-9._-]+/g, \"_\")\n .slice(0, MAX_PATH_COMPONENT_LENGTH);\n if (!sanitized || sanitized === \".\" || sanitized === \"..\") {\n return fallback;\n }\n return sanitized;\n}\n\nexport function sanitizeSessionKey(sessionKey: string): string {\n return sanitizePathComponent(sessionKey, \"unknown-session\", { lowercase: true });\n}\n\nfunction sanitizeChunkId(id: string): string {\n return sanitizePathComponent(id, \"chunk\");\n}\n\nfunction datePathComponent(startTs: string): string {\n if (typeof startTs !== \"string\" || !/^\\d{4}-\\d{2}-\\d{2}T/.test(startTs)) {\n throw new Error(\"invalid conversation chunk start timestamp\");\n }\n const date = new Date(startTs);\n if (!Number.isFinite(date.getTime())) {\n throw new Error(\"invalid conversation chunk start timestamp\");\n }\n return date.toISOString().slice(0, 10);\n}\n\nfunction resolveInsideRoot(rootDir: string, candidate: string): string {\n const root = path.resolve(rootDir);\n const resolved = path.resolve(candidate);\n const rel = path.relative(root, resolved);\n if (\n rel === \"\" ||\n (rel !== \"..\" && !rel.startsWith(`..${path.sep}`) && !path.isAbsolute(rel))\n ) {\n return resolved;\n }\n throw new Error(\"conversation chunk path escapes index root\");\n}\n\nasync function lstatIfExists(candidate: string): Promise<Stats | undefined> {\n try {\n return await lstat(candidate);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n throw err;\n }\n}\n\nasync function rejectSymlinkIfExists(candidate: string): Promise<void> {\n const stat = await lstatIfExists(candidate);\n if (stat?.isSymbolicLink()) {\n throw new Error(\"conversation chunk path contains symlink\");\n }\n}\n\nasync function rejectExistingSymlinksInPath(baseDir: string, candidate: string): Promise<void> {\n const base = path.resolve(baseDir);\n const resolved = path.resolve(candidate);\n\n let current = base;\n while (current !== path.dirname(current)) {\n const stat = await lstatIfExists(current);\n if (stat) {\n if (stat.isSymbolicLink()) {\n throw new Error(\"conversation chunk path contains symlink\");\n }\n break;\n }\n current = path.dirname(current);\n }\n\n const relative = path.relative(base, resolved);\n if (relative === \"\") return;\n\n current = base;\n for (const part of relative.split(path.sep)) {\n current = path.join(current, part);\n const stat = await lstatIfExists(current);\n if (!stat) return;\n if (stat.isSymbolicLink()) {\n throw new Error(\"conversation chunk path contains symlink\");\n }\n }\n}\n\nasync function rejectExistingSymlinkAncestors(\n rootDir: string,\n candidate: string,\n): Promise<void> {\n const root = path.resolve(rootDir);\n const resolved = resolveInsideRoot(root, candidate);\n await rejectExistingSymlinksInPath(root, resolved);\n}\n\nexport async function writeConversationChunks(\n rootDir: string,\n chunks: ConversationChunk[],\n): Promise<string[]> {\n const written: string[] = [];\n const root = path.resolve(rootDir);\n await rejectExistingSymlinksInPath(root, root);\n await mkdir(root, { recursive: true });\n await rejectExistingSymlinksInPath(root, root);\n\n for (const c of chunks) {\n const safe = sanitizeSessionKey(c.sessionKey);\n const date = datePathComponent(c.startTs);\n const dir = resolveInsideRoot(root, path.join(root, safe, date));\n await rejectExistingSymlinkAncestors(root, dir);\n await mkdir(dir, { recursive: true });\n await rejectExistingSymlinkAncestors(root, dir);\n const fp = resolveInsideRoot(root, path.join(dir, `${sanitizeChunkId(c.id)}.md`));\n await rejectExistingSymlinkAncestors(root, path.dirname(fp));\n await rejectSymlinkIfExists(fp);\n const content =\n `---\\n` +\n `kind: conversation_chunk\\n` +\n `sessionKey: ${c.sessionKey}\\n` +\n `startTs: ${c.startTs}\\n` +\n `endTs: ${c.endTs}\\n` +\n `---\\n\\n` +\n c.text +\n \"\\n\";\n await writeFile(fp, content, \"utf-8\");\n written.push(fp);\n }\n return written;\n}\n\nexport interface ConversationChunkUpsertResult {\n upserted: number;\n skipped: boolean;\n reason?: \"adapter-unavailable\" | \"adapter-error\";\n}\n\nexport interface ConversationChunkRebuildResult {\n rebuilt: number;\n skipped: boolean;\n reason?: \"adapter-unavailable\" | \"adapter-error\";\n}\n\nexport async function upsertConversationChunksFailOpen(\n adapter: FaissConversationIndexAdapter | undefined,\n chunks: ConversationChunk[],\n): Promise<ConversationChunkUpsertResult> {\n if (!adapter) {\n return { upserted: 0, skipped: true, reason: \"adapter-unavailable\" };\n }\n try {\n const upserted = await adapter.upsertChunks(chunks);\n return { upserted, skipped: false };\n } catch (err) {\n log.debug(`conversation index FAISS upsert failed (fail-open): ${err}`);\n return { upserted: 0, skipped: true, reason: \"adapter-error\" };\n }\n}\n\nexport async function rebuildConversationChunksFailOpen(\n adapter: FaissConversationIndexAdapter | undefined,\n chunks: ConversationChunk[],\n): Promise<ConversationChunkRebuildResult> {\n if (!adapter) {\n return { rebuilt: 0, skipped: true, reason: \"adapter-unavailable\" };\n }\n try {\n const rebuilt = await adapter.rebuildChunks(chunks);\n return { rebuilt, skipped: false };\n } catch (err) {\n log.debug(`conversation index FAISS rebuild failed (fail-open): ${err}`);\n return { rebuilt: 0, skipped: true, reason: \"adapter-error\" };\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,236 +0,0 @@
1
- import {
2
- expandTildePath
3
- } from "./chunk-QRNI5JBH.js";
4
-
5
- // src/connectors/live/state-store.ts
6
- import { promises as fs } from "fs";
7
- import path from "path";
8
-
9
- // src/connectors/live/framework.ts
10
- var CONNECTOR_ID_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/;
11
- function isValidConnectorId(id) {
12
- return typeof id === "string" && CONNECTOR_ID_PATTERN.test(id);
13
- }
14
-
15
- // src/connectors/live/state-store.ts
16
- var STATE_DIR_NAME = "state";
17
- var CONNECTORS_DIR_NAME = "connectors";
18
- var MAX_ERROR_LENGTH = 1024;
19
- var VALID_SYNC_STATUSES = /* @__PURE__ */ new Set([
20
- "success",
21
- "error",
22
- "never"
23
- ]);
24
- var ConnectorStateCorruptionError = class extends Error {
25
- constructor(message) {
26
- super(message);
27
- this.name = "ConnectorStateCorruptionError";
28
- }
29
- };
30
- function resolveConnectorsDir(memoryDir) {
31
- if (typeof memoryDir !== "string" || memoryDir.length === 0) {
32
- throw new TypeError("memoryDir must be a non-empty string");
33
- }
34
- return path.join(expandTildePath(memoryDir), STATE_DIR_NAME, CONNECTORS_DIR_NAME);
35
- }
36
- function resolveConnectorStatePath(memoryDir, id) {
37
- if (!isValidConnectorId(id)) {
38
- throw new TypeError(
39
- `invalid connector id ${JSON.stringify(id)} \u2014 must match /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/`
40
- );
41
- }
42
- return path.join(resolveConnectorsDir(memoryDir), `${id}.json`);
43
- }
44
- function isConnectorStateShape(value) {
45
- if (typeof value !== "object" || value === null) return false;
46
- const v = value;
47
- if (typeof v.id !== "string") return false;
48
- if (typeof v.lastSyncStatus !== "string") return false;
49
- if (!["success", "error", "never"].includes(v.lastSyncStatus)) return false;
50
- if (typeof v.totalDocsImported !== "number" || !Number.isInteger(v.totalDocsImported)) return false;
51
- if (v.totalDocsImported < 0) return false;
52
- if (typeof v.updatedAt !== "string") return false;
53
- if (v.lastSyncAt !== null && typeof v.lastSyncAt !== "string") return false;
54
- if (v.cursor !== null) {
55
- if (typeof v.cursor !== "object" || v.cursor === null) return false;
56
- const c = v.cursor;
57
- if (typeof c.kind !== "string" || typeof c.value !== "string" || typeof c.updatedAt !== "string") {
58
- return false;
59
- }
60
- }
61
- if (v.lastSyncError !== void 0 && typeof v.lastSyncError !== "string") return false;
62
- return true;
63
- }
64
- async function assertNoSymlinkOnPath(memoryDir, filePath) {
65
- const expandedRoot = expandTildePath(memoryDir);
66
- const root = path.resolve(expandedRoot);
67
- const target = path.resolve(filePath);
68
- const rel = path.relative(root, target);
69
- if (rel.startsWith("..") || path.isAbsolute(rel)) {
70
- throw new Error(
71
- `connector state path ${target} escapes memory root ${root}`
72
- );
73
- }
74
- const segments = rel.length === 0 ? [] : rel.split(path.sep);
75
- let current = root;
76
- const componentsToCheck = [current];
77
- for (const seg of segments) {
78
- current = path.join(current, seg);
79
- componentsToCheck.push(current);
80
- }
81
- for (const component of componentsToCheck) {
82
- let stat;
83
- try {
84
- stat = await fs.lstat(component);
85
- } catch (err) {
86
- if (err.code === "ENOENT") {
87
- continue;
88
- }
89
- throw err;
90
- }
91
- if (stat.isSymbolicLink()) {
92
- throw new Error(
93
- `connector state path component ${component} is a symlink; refusing to follow`
94
- );
95
- }
96
- }
97
- }
98
- async function readConnectorState(memoryDir, id) {
99
- const filePath = resolveConnectorStatePath(memoryDir, id);
100
- await assertNoSymlinkOnPath(memoryDir, filePath);
101
- let raw;
102
- try {
103
- raw = await fs.readFile(filePath, "utf-8");
104
- } catch (err) {
105
- if (err.code === "ENOENT") return null;
106
- throw err;
107
- }
108
- let parsed;
109
- try {
110
- parsed = JSON.parse(raw);
111
- } catch (err) {
112
- throw new ConnectorStateCorruptionError(
113
- `connector state at ${filePath} is not valid JSON: ${err.message}`
114
- );
115
- }
116
- if (!isConnectorStateShape(parsed)) {
117
- throw new ConnectorStateCorruptionError(
118
- `connector state at ${filePath} does not match ConnectorState shape`
119
- );
120
- }
121
- if (parsed.id !== id) {
122
- throw new ConnectorStateCorruptionError(
123
- `connector state at ${filePath} has mismatched id ${JSON.stringify(parsed.id)}; expected ${JSON.stringify(id)}`
124
- );
125
- }
126
- return parsed;
127
- }
128
- async function writeConnectorState(memoryDir, id, state) {
129
- if (!isValidConnectorId(id)) {
130
- throw new TypeError(
131
- `invalid connector id ${JSON.stringify(id)} \u2014 must match /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/`
132
- );
133
- }
134
- if (state.id !== id) {
135
- throw new Error(
136
- `writeConnectorState(): state.id ${JSON.stringify(state.id)} does not match id argument ${JSON.stringify(id)}`
137
- );
138
- }
139
- if (!VALID_SYNC_STATUSES.has(state.lastSyncStatus)) {
140
- throw new Error(
141
- `writeConnectorState(): lastSyncStatus must be one of ${[...VALID_SYNC_STATUSES].join(", ")}, got ${JSON.stringify(state.lastSyncStatus)}`
142
- );
143
- }
144
- if (state.lastSyncAt !== null && typeof state.lastSyncAt !== "string") {
145
- throw new Error(
146
- `writeConnectorState(): lastSyncAt must be a string or null, got ${typeof state.lastSyncAt}`
147
- );
148
- }
149
- if (state.cursor !== null) {
150
- if (typeof state.cursor !== "object") {
151
- throw new Error(`writeConnectorState(): cursor must be an object or null`);
152
- }
153
- if (typeof state.cursor.kind !== "string" || typeof state.cursor.value !== "string" || typeof state.cursor.updatedAt !== "string") {
154
- throw new Error(
155
- `writeConnectorState(): cursor must have string kind, value, and updatedAt`
156
- );
157
- }
158
- }
159
- if (typeof state.totalDocsImported !== "number" || !Number.isInteger(state.totalDocsImported) || state.totalDocsImported < 0) {
160
- throw new Error(
161
- `writeConnectorState(): totalDocsImported must be a non-negative integer`
162
- );
163
- }
164
- if (state.lastSyncError !== void 0 && typeof state.lastSyncError !== "string") {
165
- throw new Error(`writeConnectorState(): lastSyncError must be a string when provided`);
166
- }
167
- const truncatedError = state.lastSyncError !== void 0 && state.lastSyncError.length > MAX_ERROR_LENGTH ? state.lastSyncError.slice(0, MAX_ERROR_LENGTH) : state.lastSyncError;
168
- const finalState = {
169
- id: state.id,
170
- cursor: state.cursor,
171
- lastSyncAt: state.lastSyncAt,
172
- lastSyncStatus: state.lastSyncStatus,
173
- ...truncatedError !== void 0 ? { lastSyncError: truncatedError } : {},
174
- totalDocsImported: state.totalDocsImported,
175
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
176
- };
177
- const dir = resolveConnectorsDir(memoryDir);
178
- const targetPath = path.join(dir, `${id}.json`);
179
- await assertNoSymlinkOnPath(memoryDir, targetPath);
180
- await fs.mkdir(dir, { recursive: true });
181
- const tmpPath = `${targetPath}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
182
- const body = `${JSON.stringify(finalState, null, 2)}
183
- `;
184
- try {
185
- await fs.writeFile(tmpPath, body, { encoding: "utf-8", mode: 384 });
186
- await fs.rename(tmpPath, targetPath);
187
- } catch (err) {
188
- try {
189
- await fs.unlink(tmpPath);
190
- } catch {
191
- }
192
- throw err;
193
- }
194
- return finalState;
195
- }
196
- async function listConnectorStates(memoryDir) {
197
- const dir = resolveConnectorsDir(memoryDir);
198
- await assertNoSymlinkOnPath(memoryDir, dir);
199
- let entries;
200
- try {
201
- entries = await fs.readdir(dir);
202
- } catch (err) {
203
- if (err.code === "ENOENT") return [];
204
- throw err;
205
- }
206
- const out = [];
207
- for (const entry of entries) {
208
- if (!entry.endsWith(".json")) continue;
209
- const id = entry.slice(0, -".json".length);
210
- if (!isValidConnectorId(id)) continue;
211
- try {
212
- const state = await readConnectorState(memoryDir, id);
213
- if (state !== null) out.push(state);
214
- } catch (err) {
215
- if (err instanceof ConnectorStateCorruptionError) {
216
- continue;
217
- }
218
- throw err;
219
- }
220
- }
221
- out.sort((a, b) => a.id.localeCompare(b.id));
222
- return out;
223
- }
224
- function _connectorStatePathForTest(memoryDir, id) {
225
- return resolveConnectorStatePath(memoryDir, id);
226
- }
227
-
228
- export {
229
- CONNECTOR_ID_PATTERN,
230
- isValidConnectorId,
231
- readConnectorState,
232
- writeConnectorState,
233
- listConnectorStates,
234
- _connectorStatePathForTest
235
- };
236
- //# sourceMappingURL=chunk-LPMVBPA3.js.map