@remnic/core 1.1.31 → 9.3.516
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.
- package/dist/abstraction-nodes.js +2 -2
- package/dist/access-cli.d.ts +1 -1
- package/dist/access-cli.js +158 -121
- package/dist/access-cli.js.map +1 -1
- package/dist/access-http.d.ts +9 -5
- package/dist/access-http.js +51 -51
- package/dist/access-idempotency.d.ts +2 -0
- package/dist/access-idempotency.js +1 -1
- package/dist/access-mcp.d.ts +16 -9
- package/dist/access-mcp.js +44 -44
- package/dist/access-schema.d.ts +45 -13
- package/dist/access-schema.js +8 -8
- package/dist/{access-service-CkZyb35d.d.ts → access-service-CZfksQuS.d.ts} +11 -130
- package/dist/access-service.d.ts +7 -4
- package/dist/access-service.js +40 -40
- package/dist/action-confidence.d.ts +1 -0
- package/dist/active-memory-bridge.d.ts +1 -0
- package/dist/active-memory-bridge.js +3 -2
- package/dist/active-recall.d.ts +1 -0
- package/dist/active-recall.js +14 -9
- package/dist/active-recall.js.map +1 -1
- package/dist/adapters/claude-code.d.ts +6 -2
- package/dist/adapters/claude-code.js +2 -2
- package/dist/adapters/codex.d.ts +5 -1
- package/dist/adapters/codex.js +2 -2
- package/dist/adapters/hermes.js +2 -2
- package/dist/adapters/index.js +6 -6
- package/dist/adapters/registry.js +6 -6
- package/dist/adapters/replit.d.ts +4 -2
- package/dist/adapters/replit.js +2 -2
- package/dist/adapters/types.d.ts +4 -0
- package/dist/adapters/types.js +1 -1
- package/dist/behavior-learner.d.ts +1 -0
- package/dist/behavior-signals.d.ts +1 -0
- package/dist/behavior-signals.js +1 -1
- package/dist/bootstrap.d.ts +5 -3
- package/dist/bootstrap.js +2 -2
- package/dist/boxes.d.ts +1 -0
- package/dist/boxes.js +1 -1
- package/dist/briefing.d.ts +1 -0
- package/dist/briefing.js +9 -9
- package/dist/buffer-surprise-report.d.ts +1 -0
- package/dist/buffer.d.ts +1 -0
- package/dist/buffer.js +2 -2
- package/dist/bulk-import/index.d.ts +28 -0
- package/dist/bulk-import/index.js +31 -0
- package/dist/calibration.d.ts +2 -0
- package/dist/calibration.js +50 -17
- package/dist/calibration.js.map +1 -1
- package/dist/{capsule-crypto-5CYAGVC5.js → capsule-crypto-7FJQINUR.js} +2 -2
- package/dist/{capsule-merge-4MGKE7C5.js → capsule-merge-T2JRE46P.js} +3 -3
- package/dist/causal-behavior.d.ts +1 -0
- package/dist/causal-behavior.js +4 -4
- package/dist/causal-chain.js +4 -4
- package/dist/causal-consolidation.d.ts +16 -1
- package/dist/causal-consolidation.js +115 -32
- package/dist/causal-consolidation.js.map +1 -1
- package/dist/causal-retrieval.js +14 -6
- package/dist/causal-retrieval.js.map +1 -1
- package/dist/causal-trajectory-graph.js +2 -2
- package/dist/causal-trajectory.js +2 -2
- package/dist/{chunk-SAZS2QZB.js → chunk-23UORJ4S.js} +3 -3
- package/dist/{chunk-76FLAAUC.js → chunk-2AN2L4NL.js} +17 -6
- package/dist/chunk-2AN2L4NL.js.map +1 -0
- package/dist/{chunk-W4L6CZKA.js → chunk-2DL3OFLD.js} +15 -10
- package/dist/chunk-2DL3OFLD.js.map +1 -0
- package/dist/{chunk-NJ3MJQZX.js → chunk-2I5JGH3M.js} +2 -2
- package/dist/{chunk-NJ3MJQZX.js.map → chunk-2I5JGH3M.js.map} +1 -1
- package/dist/{chunk-7OZ53EXP.js → chunk-2NLLXCJG.js} +21 -10
- package/dist/chunk-2NLLXCJG.js.map +1 -0
- package/dist/{chunk-PK7H5L6Y.js → chunk-2NM43EWN.js} +2 -2
- package/dist/{chunk-PYXS46O7.js → chunk-3BP57I6J.js} +2 -2
- package/dist/{chunk-FBYESMQ2.js → chunk-3C5RPJAX.js} +2 -2
- package/dist/{chunk-FKFMOY3N.js → chunk-42NQ7AVG.js} +3 -4
- package/dist/{chunk-FKFMOY3N.js.map → chunk-42NQ7AVG.js.map} +1 -1
- package/dist/chunk-4426WSWL.js +73 -0
- package/dist/chunk-4426WSWL.js.map +1 -0
- package/dist/{chunk-LIRZNNUP.js → chunk-44442YCH.js} +5 -2
- package/dist/chunk-44442YCH.js.map +1 -0
- package/dist/{chunk-H3ME6L6D.js → chunk-46GJIW5M.js} +23 -20
- package/dist/chunk-46GJIW5M.js.map +1 -0
- package/dist/{chunk-QDZ2RLEC.js → chunk-472U7RDF.js} +3 -3
- package/dist/chunk-472U7RDF.js.map +1 -0
- package/dist/{chunk-NN2DKE4T.js → chunk-4H5ZJHEN.js} +16 -3
- package/dist/{chunk-NN2DKE4T.js.map → chunk-4H5ZJHEN.js.map} +1 -1
- package/dist/{chunk-56K5QLHX.js → chunk-4HP7HIE3.js} +56 -13
- package/dist/chunk-4HP7HIE3.js.map +1 -0
- package/dist/{chunk-RK2Y4XOM.js → chunk-4JRRISLU.js} +9 -6
- package/dist/chunk-4JRRISLU.js.map +1 -0
- package/dist/{chunk-XKLD5OK4.js → chunk-4RR6ROTB.js} +10 -11
- package/dist/chunk-4RR6ROTB.js.map +1 -0
- package/dist/{chunk-YROHKYBY.js → chunk-5UHVGNZD.js} +22 -6
- package/dist/chunk-5UHVGNZD.js.map +1 -0
- package/dist/{chunk-ZAVUCJ4H.js → chunk-5V456VRV.js} +154 -69
- package/dist/chunk-5V456VRV.js.map +1 -0
- package/dist/{chunk-77H5NU3M.js → chunk-6BR7L222.js} +82 -18
- package/dist/chunk-6BR7L222.js.map +1 -0
- package/dist/{chunk-4KGVTPGD.js → chunk-6F6BXB7A.js} +9 -8
- package/dist/chunk-6F6BXB7A.js.map +1 -0
- package/dist/{chunk-NMZY542O.js → chunk-6URPAY2D.js} +41 -17
- package/dist/chunk-6URPAY2D.js.map +1 -0
- package/dist/{chunk-N53K2EXC.js → chunk-6VF75M3X.js} +2 -2
- package/dist/{chunk-XSZEP4SF.js → chunk-6XSPNR6L.js} +6 -5
- package/dist/chunk-6XSPNR6L.js.map +1 -0
- package/dist/{chunk-6H2TESSP.js → chunk-765K3SAT.js} +3 -3
- package/dist/{chunk-EDTHC6UD.js → chunk-77NAFXUD.js} +2 -2
- package/dist/{chunk-S7KDBTWT.js → chunk-7F7Z6MOS.js} +29 -14
- package/dist/chunk-7F7Z6MOS.js.map +1 -0
- package/dist/{chunk-MZH6EHNR.js → chunk-7H6CFEBJ.js} +41 -14
- package/dist/chunk-7H6CFEBJ.js.map +1 -0
- package/dist/{chunk-MGKYQQYF.js → chunk-7Q3RCKAQ.js} +2 -2
- package/dist/chunk-7RXCMVFQ.js +27 -0
- package/dist/chunk-7RXCMVFQ.js.map +1 -0
- package/dist/{chunk-DGXUHMOV.js → chunk-A2IYSXDQ.js} +25 -6
- package/dist/chunk-A2IYSXDQ.js.map +1 -0
- package/dist/{chunk-EABGC2TL.js → chunk-A2Z6UCWT.js} +26 -4
- package/dist/chunk-A2Z6UCWT.js.map +1 -0
- package/dist/{chunk-5375UYTQ.js → chunk-A6D7A2FW.js} +4 -4
- package/dist/chunk-A6D7A2FW.js.map +1 -0
- package/dist/{chunk-FAAFWE4G.js → chunk-ALEPI75L.js} +24 -6
- package/dist/chunk-ALEPI75L.js.map +1 -0
- package/dist/{chunk-3SLRNYNG.js → chunk-AUDJPF4N.js} +15 -4
- package/dist/chunk-AUDJPF4N.js.map +1 -0
- package/dist/chunk-B5XMS73R.js +145 -0
- package/dist/chunk-B5XMS73R.js.map +1 -0
- package/dist/{chunk-HXXBL2KD.js → chunk-BECQDWBA.js} +44 -4
- package/dist/chunk-BECQDWBA.js.map +1 -0
- package/dist/{chunk-7SEAZFFB.js → chunk-BEUDU7Y4.js} +24 -4
- package/dist/chunk-BEUDU7Y4.js.map +1 -0
- package/dist/chunk-CHBI22MI.js +159 -0
- package/dist/chunk-CHBI22MI.js.map +1 -0
- package/dist/{chunk-GDFS42HT.js → chunk-CHCA44C3.js} +15 -8
- package/dist/chunk-CHCA44C3.js.map +1 -0
- package/dist/chunk-CINZGPSJ.js +22 -0
- package/dist/chunk-CINZGPSJ.js.map +1 -0
- package/dist/chunk-CMTINOFS.js +36 -0
- package/dist/chunk-CMTINOFS.js.map +1 -0
- package/dist/{chunk-34DQE4KF.js → chunk-CO7ZO4TU.js} +2 -2
- package/dist/{chunk-PFV5C235.js → chunk-CPPS65WS.js} +2 -1
- package/dist/{chunk-PFV5C235.js.map → chunk-CPPS65WS.js.map} +1 -1
- package/dist/{chunk-DINWEURR.js → chunk-CSKLPDN6.js} +20 -6
- package/dist/chunk-CSKLPDN6.js.map +1 -0
- package/dist/chunk-CWWMTTQE.js +566 -0
- package/dist/chunk-CWWMTTQE.js.map +1 -0
- package/dist/{chunk-IQT3XTKW.js → chunk-D24OXEPB.js} +13 -7
- package/dist/chunk-D24OXEPB.js.map +1 -0
- package/dist/{chunk-WIICJPET.js → chunk-DEUNUKTD.js} +6 -4
- package/dist/{chunk-WIICJPET.js.map → chunk-DEUNUKTD.js.map} +1 -1
- package/dist/{chunk-ZYVPLJ4T.js → chunk-DHGSZ3UD.js} +9 -7
- package/dist/chunk-DHGSZ3UD.js.map +1 -0
- package/dist/{chunk-JR4ZC3G4.js → chunk-DLJ4IR6M.js} +91 -41
- package/dist/chunk-DLJ4IR6M.js.map +1 -0
- package/dist/{chunk-U4SCL7B7.js → chunk-DRD2Q7HQ.js} +82 -18
- package/dist/chunk-DRD2Q7HQ.js.map +1 -0
- package/dist/{chunk-2IWUMAES.js → chunk-E62SBGQ3.js} +28 -13
- package/dist/chunk-E62SBGQ3.js.map +1 -0
- package/dist/{chunk-C5BCH4ZS.js → chunk-EAZGEEG2.js} +21 -3
- package/dist/chunk-EAZGEEG2.js.map +1 -0
- package/dist/{chunk-TPB3I2AC.js → chunk-ECZU5BJH.js} +31 -10
- package/dist/chunk-ECZU5BJH.js.map +1 -0
- package/dist/chunk-EDQVAMQI.js +308 -0
- package/dist/chunk-EDQVAMQI.js.map +1 -0
- package/dist/{chunk-RRF5UOBJ.js → chunk-EI6V5UXY.js} +22 -15
- package/dist/chunk-EI6V5UXY.js.map +1 -0
- package/dist/{chunk-ZKSK55RC.js → chunk-ETUPBUHB.js} +2 -2
- package/dist/{chunk-25MQ7IHJ.js → chunk-EUML3N6B.js} +17 -6
- package/dist/chunk-EUML3N6B.js.map +1 -0
- package/dist/{chunk-5RGLBDQF.js → chunk-EVZFIAPG.js} +12 -12
- package/dist/chunk-EVZFIAPG.js.map +1 -0
- package/dist/{chunk-QRNI5JBH.js → chunk-EYIEWJNI.js} +2 -2
- package/dist/{chunk-TPU5L5EY.js → chunk-FCOQXV3T.js} +272 -411
- package/dist/chunk-FCOQXV3T.js.map +1 -0
- package/dist/{chunk-TMQLARTH.js → chunk-FK556DDH.js} +34 -15
- package/dist/chunk-FK556DDH.js.map +1 -0
- package/dist/{chunk-43PJZYGL.js → chunk-FPGE5NVO.js} +45 -10
- package/dist/chunk-FPGE5NVO.js.map +1 -0
- package/dist/{chunk-3VAL7ZL2.js → chunk-FUC4LZMD.js} +60 -25
- package/dist/chunk-FUC4LZMD.js.map +1 -0
- package/dist/{chunk-C6QPK5GG.js → chunk-FZZ2QTJI.js} +2 -2
- package/dist/{chunk-D46YSIYX.js → chunk-G3Z3QEF5.js} +19 -11
- package/dist/{chunk-D46YSIYX.js.map → chunk-G3Z3QEF5.js.map} +1 -1
- package/dist/{chunk-3JXBXXM2.js → chunk-G4IAEX6D.js} +2 -2
- package/dist/{chunk-MSWG7JI6.js → chunk-G56P5RLD.js} +8 -2
- package/dist/chunk-G56P5RLD.js.map +1 -0
- package/dist/{chunk-AGZQD76C.js → chunk-GCGJW34D.js} +48 -2
- package/dist/chunk-GCGJW34D.js.map +1 -0
- package/dist/chunk-H2NCNXMS.js +159 -0
- package/dist/chunk-H2NCNXMS.js.map +1 -0
- package/dist/{chunk-XYIK4LF6.js → chunk-H3FZVNRN.js} +8 -2
- package/dist/chunk-H3FZVNRN.js.map +1 -0
- package/dist/{chunk-YU5KIWYQ.js → chunk-HC6EKOID.js} +94 -43
- package/dist/chunk-HC6EKOID.js.map +1 -0
- package/dist/{chunk-TK4UEOSK.js → chunk-HDDRVXX4.js} +8 -8
- package/dist/chunk-HDDRVXX4.js.map +1 -0
- package/dist/{chunk-LLQ2LLWF.js → chunk-HENLZHIT.js} +15 -5
- package/dist/chunk-HENLZHIT.js.map +1 -0
- package/dist/{chunk-N2D6GXBM.js → chunk-HINSGUA7.js} +28 -20
- package/dist/chunk-HINSGUA7.js.map +1 -0
- package/dist/{chunk-APO3DCMU.js → chunk-HLAVGJ62.js} +30 -8
- package/dist/chunk-HLAVGJ62.js.map +1 -0
- package/dist/{chunk-TPMQ3G6Z.js → chunk-HOJZMQ4J.js} +2 -2
- package/dist/chunk-HOJZMQ4J.js.map +1 -0
- package/dist/{chunk-LUDTDZLK.js → chunk-HPWVAEET.js} +33 -7
- package/dist/chunk-HPWVAEET.js.map +1 -0
- package/dist/{chunk-NZL6GGQE.js → chunk-HQ6NIBL6.js} +92 -30
- package/dist/chunk-HQ6NIBL6.js.map +1 -0
- package/dist/{chunk-UWVJF25J.js → chunk-HWVTS5NO.js} +20 -6
- package/dist/chunk-HWVTS5NO.js.map +1 -0
- package/dist/{chunk-2WWLHTZY.js → chunk-IC4GELZE.js} +2 -2
- package/dist/{chunk-QA2ZAPBU.js → chunk-IPLYGWQF.js} +28 -20
- package/dist/chunk-IPLYGWQF.js.map +1 -0
- package/dist/{chunk-A6KTB5R6.js → chunk-IQ3OI2RR.js} +3 -3
- package/dist/chunk-IQ3OI2RR.js.map +1 -0
- package/dist/{chunk-6LVVDPJ4.js → chunk-J64TK33U.js} +3 -4
- package/dist/chunk-J64TK33U.js.map +1 -0
- package/dist/{chunk-6FC5EGNV.js → chunk-JBPKEARU.js} +15 -5
- package/dist/{chunk-6FC5EGNV.js.map → chunk-JBPKEARU.js.map} +1 -1
- package/dist/{chunk-RHY3HH7P.js → chunk-JFEKNTX7.js} +125 -33
- package/dist/chunk-JFEKNTX7.js.map +1 -0
- package/dist/{chunk-TZOLIGIG.js → chunk-JJEJJ7RK.js} +4 -2
- package/dist/chunk-JJEJJ7RK.js.map +1 -0
- package/dist/{chunk-PCUKNJAZ.js → chunk-JKV57BTN.js} +2 -2
- package/dist/{chunk-EJI5XIBB.js → chunk-JLNBQWZ2.js} +55 -7
- package/dist/chunk-JLNBQWZ2.js.map +1 -0
- package/dist/{chunk-PIRJPV5T.js → chunk-JNANKJLN.js} +2 -2
- package/dist/chunk-JNANKJLN.js.map +1 -0
- package/dist/{chunk-XIG5PDM7.js → chunk-JUC24CTX.js} +8 -12
- package/dist/chunk-JUC24CTX.js.map +1 -0
- package/dist/{chunk-OIGNEXKZ.js → chunk-K5O2QY6T.js} +5 -1
- package/dist/{chunk-OIGNEXKZ.js.map → chunk-K5O2QY6T.js.map} +1 -1
- package/dist/{chunk-ZTFCYYEZ.js → chunk-KCYE2MZM.js} +3 -3
- package/dist/chunk-KCYE2MZM.js.map +1 -0
- package/dist/{chunk-JWPLJLDU.js → chunk-KD3QD3A5.js} +2 -2
- package/dist/{chunk-JWPLJLDU.js.map → chunk-KD3QD3A5.js.map} +1 -1
- package/dist/{chunk-YRMVARQP.js → chunk-KFY3SGN7.js} +49 -2
- package/dist/chunk-KFY3SGN7.js.map +1 -0
- package/dist/{chunk-CYFQJMUV.js → chunk-KIB7SDIJ.js} +15 -10
- package/dist/chunk-KIB7SDIJ.js.map +1 -0
- package/dist/{chunk-3KW65B36.js → chunk-KILOTVIF.js} +95 -48
- package/dist/chunk-KILOTVIF.js.map +1 -0
- package/dist/{chunk-MXFBBHJU.js → chunk-KJMYHC7K.js} +10 -5
- package/dist/chunk-KJMYHC7K.js.map +1 -0
- package/dist/{chunk-W3LR522O.js → chunk-KM2A35EO.js} +36 -34
- package/dist/chunk-KM2A35EO.js.map +1 -0
- package/dist/{chunk-575RMLWN.js → chunk-KXULCVOC.js} +30 -24
- package/dist/chunk-KXULCVOC.js.map +1 -0
- package/dist/{chunk-WELDCG6C.js → chunk-L227SKTB.js} +109 -36
- package/dist/chunk-L227SKTB.js.map +1 -0
- package/dist/{chunk-BVF3AGJP.js → chunk-LJBOVCQG.js} +26 -11
- package/dist/chunk-LJBOVCQG.js.map +1 -0
- package/dist/{chunk-2KI4QFHU.js → chunk-LMDRGRJ2.js} +2 -2
- package/dist/{chunk-MY6TPVXW.js → chunk-LMPHTYJC.js} +2 -2
- package/dist/{chunk-EHRTFRWW.js → chunk-LQHDIS7L.js} +10 -5
- package/dist/chunk-LQHDIS7L.js.map +1 -0
- package/dist/chunk-LUDUFZTV.js +170 -0
- package/dist/chunk-LUDUFZTV.js.map +1 -0
- package/dist/{chunk-5HRY2WRF.js → chunk-LZ3VEOU5.js} +2 -2
- package/dist/{chunk-Q7P4WJDP.js → chunk-M5T4Q2ZU.js} +1 -1
- package/dist/chunk-M5T4Q2ZU.js.map +1 -0
- package/dist/{chunk-ICRIXAP2.js → chunk-MC4FJXPA.js} +16 -6
- package/dist/chunk-MC4FJXPA.js.map +1 -0
- package/dist/{chunk-WPGJYVUH.js → chunk-MGVIEM2O.js} +23 -6
- package/dist/chunk-MGVIEM2O.js.map +1 -0
- package/dist/{chunk-NGAVDO7E.js → chunk-OADWQ5CR.js} +2 -2
- package/dist/{chunk-2NMMFZ5T.js → chunk-OD4FM2U7.js} +6 -3
- package/dist/chunk-OD4FM2U7.js.map +1 -0
- package/dist/{chunk-OZHRDTDX.js → chunk-OKTXM5H4.js} +11 -1
- package/dist/chunk-OKTXM5H4.js.map +1 -0
- package/dist/{chunk-RXDLTSWT.js → chunk-ONPLNAPX.js} +16 -7
- package/dist/chunk-ONPLNAPX.js.map +1 -0
- package/dist/{chunk-FJ43PRLT.js → chunk-ORFGK3XI.js} +20 -14
- package/dist/chunk-ORFGK3XI.js.map +1 -0
- package/dist/{chunk-DOM4GKSW.js → chunk-OZKVVUJB.js} +3 -3
- package/dist/{chunk-3TNBOMQT.js → chunk-PCI747N2.js} +13 -13
- package/dist/{chunk-3TNBOMQT.js.map → chunk-PCI747N2.js.map} +1 -1
- package/dist/{chunk-MT4HVDUZ.js → chunk-PM3QHTFT.js} +3 -3
- package/dist/{chunk-4DWOBS2A.js → chunk-PRQJ5ESM.js} +27 -2
- package/dist/{chunk-4DWOBS2A.js.map → chunk-PRQJ5ESM.js.map} +1 -1
- package/dist/chunk-PU44GBL4.js +52 -0
- package/dist/chunk-PU44GBL4.js.map +1 -0
- package/dist/{chunk-MJFNCJXV.js → chunk-Q4CAQGKQ.js} +47 -9
- package/dist/chunk-Q4CAQGKQ.js.map +1 -0
- package/dist/{chunk-U3WSW6PZ.js → chunk-QMYXNM4P.js} +90 -35
- package/dist/chunk-QMYXNM4P.js.map +1 -0
- package/dist/{chunk-XVVIG67A.js → chunk-QVJ4NWL2.js} +62 -18
- package/dist/chunk-QVJ4NWL2.js.map +1 -0
- package/dist/{chunk-NBNN5GOB.js → chunk-QY7YA7OL.js} +11 -2
- package/dist/chunk-QY7YA7OL.js.map +1 -0
- package/dist/{chunk-ZK7I7JYV.js → chunk-R3PS27B4.js} +7 -7
- package/dist/{chunk-2PRLKQAH.js → chunk-RLV3PQGH.js} +35 -19
- package/dist/chunk-RLV3PQGH.js.map +1 -0
- package/dist/{chunk-WW3QQF4H.js → chunk-ROZJACKP.js} +16 -1
- package/dist/chunk-ROZJACKP.js.map +1 -0
- package/dist/{chunk-7MNMYOFP.js → chunk-RSUYKGGZ.js} +3 -4
- package/dist/chunk-RSUYKGGZ.js.map +1 -0
- package/dist/{chunk-LT3NLYSI.js → chunk-RUZOJKNF.js} +10 -7
- package/dist/chunk-RUZOJKNF.js.map +1 -0
- package/dist/{chunk-326G7DJK.js → chunk-RW5DGAGO.js} +67 -13
- package/dist/chunk-RW5DGAGO.js.map +1 -0
- package/dist/{chunk-KOSORCJG.js → chunk-S53PKKWK.js} +63 -24
- package/dist/chunk-S53PKKWK.js.map +1 -0
- package/dist/{chunk-65PG43EQ.js → chunk-S7WU3Y3D.js} +21 -4
- package/dist/chunk-S7WU3Y3D.js.map +1 -0
- package/dist/{chunk-SKE7JYKA.js → chunk-SFXKHM7P.js} +2 -2
- package/dist/{chunk-HMDCOMYU.js → chunk-SKGV326D.js} +3 -3
- package/dist/{chunk-I5GLV3VE.js → chunk-SML26KED.js} +33 -26
- package/dist/{chunk-I5GLV3VE.js.map → chunk-SML26KED.js.map} +1 -1
- package/dist/chunk-T2PO5MUF.js +62 -0
- package/dist/chunk-T2PO5MUF.js.map +1 -0
- package/dist/{chunk-C7VW7C3F.js → chunk-TDKQGLJW.js} +3 -3
- package/dist/chunk-TDKQGLJW.js.map +1 -0
- package/dist/{chunk-3QKK7QOS.js → chunk-TERNBNJB.js} +3 -3
- package/dist/chunk-TERNBNJB.js.map +1 -0
- package/dist/{chunk-MXC3AP5I.js → chunk-TGQ2NTWH.js} +12 -7
- package/dist/chunk-TGQ2NTWH.js.map +1 -0
- package/dist/{chunk-3Y4P7RXM.js → chunk-TMSXWOBZ.js} +3 -4
- package/dist/chunk-TMSXWOBZ.js.map +1 -0
- package/dist/{chunk-3ZLVGM76.js → chunk-TTGZV5R3.js} +106 -44
- package/dist/chunk-TTGZV5R3.js.map +1 -0
- package/dist/{chunk-5UM2VJ6D.js → chunk-UEY3VB6W.js} +2 -2
- package/dist/{chunk-I6K5FBRQ.js → chunk-UI3NYK34.js} +4 -1
- package/dist/{chunk-I6K5FBRQ.js.map → chunk-UI3NYK34.js.map} +1 -1
- package/dist/{chunk-VBJ7V5SK.js → chunk-UIPDNLXA.js} +21 -8
- package/dist/chunk-UIPDNLXA.js.map +1 -0
- package/dist/{chunk-GIF42EW3.js → chunk-UP6MOYCB.js} +3 -3
- package/dist/{chunk-K4FLSOR5.js → chunk-USYGGIJZ.js} +44 -15
- package/dist/chunk-USYGGIJZ.js.map +1 -0
- package/dist/{chunk-FIT6DMX6.js → chunk-UWY7GIVS.js} +152 -54
- package/dist/chunk-UWY7GIVS.js.map +1 -0
- package/dist/{chunk-MRILGULB.js → chunk-V2RCP53Q.js} +2 -2
- package/dist/{chunk-XKECPATV.js → chunk-VFUEZZBS.js} +113 -4
- package/dist/chunk-VFUEZZBS.js.map +1 -0
- package/dist/{chunk-FSFEQI74.js → chunk-W7L6HXUC.js} +2 -2
- package/dist/{chunk-3IQ2TR4N.js → chunk-WLEB7WCG.js} +2 -2
- package/dist/{chunk-GL6I6MEQ.js → chunk-WSGF57U2.js} +3 -3
- package/dist/{chunk-KNKUID7G.js → chunk-X7Y7WX73.js} +72 -6
- package/dist/chunk-X7Y7WX73.js.map +1 -0
- package/dist/{chunk-5NPGSAVB.js → chunk-XEKAG3FM.js} +23 -5
- package/dist/chunk-XEKAG3FM.js.map +1 -0
- package/dist/{chunk-3APJ5EVB.js → chunk-XKIQZXUB.js} +41 -26
- package/dist/chunk-XKIQZXUB.js.map +1 -0
- package/dist/chunk-XKXKSQU7.js +92 -0
- package/dist/chunk-XKXKSQU7.js.map +1 -0
- package/dist/{chunk-JA3AK3PT.js → chunk-XNLXAWHX.js} +4 -4
- package/dist/{chunk-CULXMQJH.js → chunk-XPXEJRUB.js} +3 -3
- package/dist/chunk-XPXEJRUB.js.map +1 -0
- package/dist/{chunk-PZIAX57I.js → chunk-XR6DNK4U.js} +7 -4
- package/dist/chunk-XR6DNK4U.js.map +1 -0
- package/dist/{chunk-47VWKCAF.js → chunk-XSQ4SGM5.js} +33 -4
- package/dist/chunk-XSQ4SGM5.js.map +1 -0
- package/dist/{chunk-66DHUKLO.js → chunk-XSWKORGM.js} +16 -14
- package/dist/chunk-XSWKORGM.js.map +1 -0
- package/dist/{chunk-QR3C7BKQ.js → chunk-XZ4WBBB5.js} +7 -8
- package/dist/chunk-XZ4WBBB5.js.map +1 -0
- package/dist/{chunk-WNARATI3.js → chunk-Y2SXZ5KZ.js} +59 -11
- package/dist/chunk-Y2SXZ5KZ.js.map +1 -0
- package/dist/{chunk-QLLBRHAT.js → chunk-YDMVYYD2.js} +229 -264
- package/dist/chunk-YDMVYYD2.js.map +1 -0
- package/dist/{chunk-SIC6U3GZ.js → chunk-YHV3KRKS.js} +3 -3
- package/dist/{chunk-ZPKBYX2F.js → chunk-YNDLCWXS.js} +85 -9
- package/dist/chunk-YNDLCWXS.js.map +1 -0
- package/dist/{chunk-W6AQJ2PY.js → chunk-YNXOKMJP.js} +35 -16
- package/dist/chunk-YNXOKMJP.js.map +1 -0
- package/dist/{chunk-VLXA6PI2.js → chunk-YQMZ7IH2.js} +4 -4
- package/dist/{chunk-TMM4S4IJ.js → chunk-YR6GIWWY.js} +58 -8
- package/dist/chunk-YR6GIWWY.js.map +1 -0
- package/dist/{chunk-DK5LDEQM.js → chunk-YR7XMOWK.js} +39 -23
- package/dist/chunk-YR7XMOWK.js.map +1 -0
- package/dist/{chunk-U7EJOMFC.js → chunk-ZEY4KYRQ.js} +41 -14
- package/dist/chunk-ZEY4KYRQ.js.map +1 -0
- package/dist/chunk-ZFXCQPNO.js +27 -0
- package/dist/chunk-ZFXCQPNO.js.map +1 -0
- package/dist/citations.js +1 -1
- package/dist/{cli-kuh9PwZ5.d.ts → cli-CPe_2KB1.d.ts} +8 -31
- package/dist/cli.d.ts +10 -6
- package/dist/cli.js +124 -119
- package/dist/commitment-ledger.js +2 -2
- package/dist/compat/checks.js +1 -2
- package/dist/compounding/engine.d.ts +3 -2
- package/dist/compounding/engine.js +11 -11
- package/dist/compounding/preference-consolidator.d.ts +1 -0
- package/dist/compounding/preference-consolidator.js +8 -8
- package/dist/compounding/preference-consolidator.js.map +1 -1
- package/dist/compression-optimizer.d.ts +1 -0
- package/dist/compression-optimizer.js +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.js +3 -2
- package/dist/connectors/codex-materialize-runner.d.ts +1 -0
- package/dist/connectors/codex-materialize-runner.js +12 -11
- package/dist/connectors/codex-materialize.d.ts +1 -0
- package/dist/connectors/codex-materialize.js +3 -2
- package/dist/connectors/index.d.ts +1 -0
- package/dist/connectors/index.js +14 -14
- package/dist/{connectors-cli-CwbyjGR7.d.ts → connectors-cli-DbTPNj2H.d.ts} +7 -1
- package/dist/connectors-cli.d.ts +1 -1
- package/dist/connectors-cli.js +3 -1
- package/dist/consolidation-provenance-check.d.ts +1 -0
- package/dist/consolidation-provenance-check.js +2 -2
- package/dist/consolidation-undo.d.ts +1 -0
- package/dist/consolidation-undo.js +1 -1
- package/dist/contradiction/index.d.ts +3 -1
- package/dist/contradiction/index.js +3 -3
- package/dist/{contradiction-review-ATP4S6IC.js → contradiction-review-6V2LXXK6.js} +2 -2
- package/dist/{contradiction-scan-5A4IDZV5.js → contradiction-scan-GIRVC4C7.js} +3 -3
- package/dist/conversation-index/backend.d.ts +3 -1
- package/dist/conversation-index/backend.js +3 -3
- package/dist/conversation-index/chunker.d.ts +1 -0
- package/dist/conversation-index/cleanup.js +1 -1
- package/dist/conversation-index/faiss-adapter.d.ts +2 -1
- package/dist/conversation-index/faiss-adapter.js +1 -1
- package/dist/conversation-index/indexer.d.ts +5 -2
- package/dist/conversation-index/indexer.js +1 -1
- package/dist/conversation-index/search.d.ts +2 -1
- package/dist/cross-namespace-budget.js +1 -1
- package/dist/cue-anchors.js +2 -2
- package/dist/dashboard-runtime.d.ts +6 -0
- package/dist/dashboard-runtime.js +3 -3
- package/dist/day-summary.d.ts +1 -0
- package/dist/day-summary.js +2 -2
- package/dist/delinearize.d.ts +1 -0
- package/dist/direct-answer-wiring.d.ts +1 -0
- package/dist/direct-answer.d.ts +1 -0
- package/dist/{dreams-ledger-LR2NBAZE.js → dreams-ledger-3WSCI5V4.js} +5 -4
- package/dist/{dreams-ledger-LR2NBAZE.js.map → dreams-ledger-3WSCI5V4.js.map} +1 -1
- package/dist/embedding-fallback.d.ts +3 -0
- package/dist/embedding-fallback.js +2 -2
- package/dist/enrichment/index.d.ts +1 -0
- package/dist/enrichment/index.js +1 -1
- package/dist/entity-retrieval.d.ts +2 -0
- package/dist/entity-retrieval.js +9 -9
- package/dist/entity-schema.d.ts +1 -0
- package/dist/evals.js +1 -1
- package/dist/explicit-capture.d.ts +5 -3
- package/dist/explicit-capture.js +2 -2
- package/dist/extraction-judge-telemetry.d.ts +2 -0
- package/dist/extraction-judge-training.d.ts +2 -0
- package/dist/extraction-judge.d.ts +2 -0
- package/dist/extraction.d.ts +2 -0
- package/dist/extraction.js +12 -12
- package/dist/{faiss-adapter-CzPghc4C.d.ts → faiss-adapter-BHecI1fF.d.ts} +4 -1
- package/dist/fallback-llm.d.ts +11 -1
- package/dist/fallback-llm.js +8 -6
- package/dist/{first-start-migration-4MHQEOSD.js → first-start-migration-CKTCTCQI.js} +5 -5
- package/dist/graph-dashboard-diff.d.ts +4 -0
- package/dist/graph-dashboard-diff.js +1 -1
- package/dist/graph-dashboard-parser.js +1 -1
- package/dist/{graph-edge-decay-5DI5GUNL.js → graph-edge-decay-MUP5J7CC.js} +6 -6
- package/dist/graph-events.js +1 -1
- package/dist/graph-snapshot.js +3 -3
- package/dist/graph.js +2 -2
- package/dist/harmonic-retrieval.js +4 -4
- package/dist/identity-continuity.d.ts +1 -0
- package/dist/importance.d.ts +1 -0
- package/dist/importers/index.d.ts +244 -0
- package/dist/importers/index.js +20 -0
- package/dist/index.d.ts +20 -350
- package/dist/index.js +885 -562
- package/dist/index.js.map +1 -1
- package/dist/intent.d.ts +1 -0
- package/dist/lcm/archive.d.ts +2 -2
- package/dist/lcm/archive.js +2 -2
- package/dist/lcm/engine.d.ts +3 -2
- package/dist/lcm/engine.js +6 -6
- package/dist/lcm/index.d.ts +1 -0
- package/dist/lcm/index.js +8 -8
- package/dist/lcm/recall.js +1 -1
- package/dist/lcm/summarizer.js +3 -3
- package/dist/lcm/tools.d.ts +1 -0
- package/dist/lifecycle.d.ts +1 -0
- package/dist/live-connectors-runner.d.ts +1 -0
- package/dist/live-connectors-runner.js +6 -6
- package/dist/local-llm.d.ts +1 -0
- package/dist/local-llm.js +2 -2
- package/dist/maintenance/archive-observations.js +1 -1
- package/dist/maintenance/memory-governance.d.ts +3 -1
- package/dist/maintenance/memory-governance.js +10 -8
- package/dist/maintenance/migrate-observations.js +3 -2
- package/dist/maintenance/observation-ledger-utils.d.ts +3 -0
- package/dist/maintenance/observation-ledger-utils.js +2 -1
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -1
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +11 -8
- package/dist/maintenance/rebuild-memory-projection.d.ts +2 -1
- package/dist/maintenance/rebuild-memory-projection.js +13 -10
- package/dist/maintenance/rebuild-observations.d.ts +1 -0
- package/dist/maintenance/rebuild-observations.js +3 -2
- package/dist/mcp-memory-inspector-app.d.ts +7 -4
- package/dist/mcp-memory-inspector-app.js +1 -1
- package/dist/memory-action-policy.d.ts +1 -0
- package/dist/memory-cache.d.ts +1 -0
- package/dist/memory-cache.js +1 -1
- package/dist/memory-lifecycle-ledger-utils.d.ts +1 -0
- package/dist/memory-projection-store.d.ts +1 -0
- package/dist/memory-projection-store.js +1 -1
- package/dist/memory-provenance.d.ts +1 -0
- package/dist/memory-worth-outcomes.d.ts +1 -0
- package/dist/migrate/from-engram.js +2 -2
- package/dist/{migrate-from-identity-anchor-G27MCD6A.js → migrate-from-identity-anchor-EB4XI4Q2.js} +2 -2
- package/dist/model-registry.js +1 -1
- package/dist/models-json.d.ts +1 -0
- package/dist/namespaces/migrate.d.ts +3 -0
- package/dist/namespaces/migrate.js +26 -24
- package/dist/namespaces/principal.d.ts +1 -0
- package/dist/namespaces/principal.js +2 -1
- package/dist/namespaces/search.d.ts +2 -1
- package/dist/namespaces/search.js +17 -15
- package/dist/namespaces/storage.d.ts +4 -2
- package/dist/namespaces/storage.js +10 -9
- package/dist/native-knowledge.d.ts +1 -0
- package/dist/native-knowledge.js +1 -1
- package/dist/negative.js +1 -1
- package/dist/network/webdav.d.ts +16 -1
- package/dist/network/webdav.js +5 -3
- package/dist/objective-state-writers.js +4 -4
- package/dist/objective-state.js +2 -2
- package/dist/offline-sync.d.ts +4 -0
- package/dist/offline-sync.js +4 -4
- package/dist/operator-toolkit.d.ts +4 -1
- package/dist/operator-toolkit.js +37 -34
- package/dist/opik-exporter.js +1 -1
- package/dist/{orchestrator-DuWl9Hwx.d.ts → orchestrator-Co9nxRLF.d.ts} +4 -74
- package/dist/orchestrator.d.ts +5 -3
- package/dist/orchestrator.js +101 -98
- package/dist/page-versioning.js +1 -1
- package/dist/path-X2K5XCHL.js +9 -0
- package/dist/patterns-cli.d.ts +1 -0
- package/dist/peers/index.d.ts +328 -0
- package/dist/{peers-HCVGHMAE.js → peers/index.js} +4 -4
- package/dist/pipeline-D18UAKlN.d.ts +32 -0
- package/dist/plugin-entry-resolver.d.ts +9 -0
- package/dist/plugin-entry-resolver.js +8 -0
- package/dist/plugin-entry-resolver.js.map +1 -0
- package/dist/plugin-id.d.ts +2 -21
- package/dist/plugin-id.js +33 -4
- package/dist/plugin-id.js.map +1 -1
- package/dist/policy-runtime.d.ts +4 -0
- package/dist/policy-runtime.js +1 -1
- package/dist/profiling.js +1 -1
- package/dist/qmd-recall-cache.d.ts +1 -0
- package/dist/qmd.d.ts +2 -1
- package/dist/qmd.js +3 -3
- package/dist/recall-disclosure-escalation.d.ts +1 -0
- package/dist/recall-explain-renderer.d.ts +1 -0
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-state.d.ts +8 -1
- package/dist/recall-state.js +2 -1
- package/dist/recall-tag-filter.d.ts +1 -0
- package/dist/recall-xray-cli.d.ts +1 -0
- package/dist/recall-xray-cli.js +4 -4
- package/dist/recall-xray-renderer.d.ts +1 -0
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.d.ts +1 -0
- package/dist/recall-xray.js +2 -2
- package/dist/relevance.d.ts +7 -1
- package/dist/relevance.js +2 -1
- package/dist/replay/normalizers/chatgpt.js +2 -2
- package/dist/replay/normalizers/claude.js +2 -2
- package/dist/replay/normalizers/openclaw.js +2 -2
- package/dist/replay/normalizers/shared.js +1 -1
- package/dist/replay/runner.js +1 -1
- package/dist/rerank.js +1 -1
- package/dist/{resolution-B7FNQSSP.js → resolution-ZY7VM6WS.js} +3 -3
- package/dist/resolution-ZY7VM6WS.js.map +1 -0
- package/dist/resolve-auth-token.d.ts +1 -0
- package/dist/resolve-auth-token.js +1 -1
- package/dist/resolve-provider-secret.d.ts +19 -29
- package/dist/resolve-provider-secret.js +2 -6
- package/dist/resume-bundles.js +10 -9
- package/dist/retrieval-agents.d.ts +2 -1
- package/dist/retrieval-agents.js +2 -1
- package/dist/retrieval-tiers.d.ts +1 -0
- package/dist/routing/engine.d.ts +1 -0
- package/dist/routing/store.d.ts +3 -0
- package/dist/routing/store.js +1 -1
- package/dist/runtime/env.js +1 -1
- package/dist/schemas.d.ts +191 -17
- package/dist/schemas.js +1 -1
- package/dist/sdk-compat.js +1 -1
- package/dist/search/document-scanner.js +1 -1
- package/dist/search/embed-helper.d.ts +7 -2
- package/dist/search/embed-helper.js +3 -1
- package/dist/search/factory.d.ts +2 -1
- package/dist/search/factory.js +15 -14
- package/dist/search/index.d.ts +2 -1
- package/dist/search/index.js +21 -20
- package/dist/search/lancedb-backend.d.ts +8 -7
- package/dist/search/lancedb-backend.js +4 -2
- package/dist/search/meilisearch-backend.d.ts +8 -7
- package/dist/search/meilisearch-backend.js +4 -2
- package/dist/search/noop-backend.d.ts +2 -1
- package/dist/search/noop-backend.js +1 -1
- package/dist/search/orama-backend.d.ts +10 -8
- package/dist/search/orama-backend.js +8 -4
- package/dist/search/port.d.ts +2 -1
- package/dist/search/remote-backend.d.ts +2 -1
- package/dist/search/remote-backend.js +1 -1
- package/dist/secure-store/index.d.ts +16 -3
- package/dist/secure-store/index.js +2 -2
- package/dist/{semantic-VwGI14Ok.d.ts → semantic-SLAa_prH.d.ts} +5 -3
- package/dist/semantic-consolidation.d.ts +1 -0
- package/dist/semantic-consolidation.js +14 -13
- package/dist/semantic-rule-promotion.js +8 -8
- package/dist/semantic-rule-verifier.d.ts +1 -0
- package/dist/semantic-rule-verifier.js +8 -8
- package/dist/session-integrity.d.ts +1 -0
- package/dist/session-integrity.js +1 -1
- package/dist/session-observer-bands.d.ts +1 -0
- package/dist/session-observer-state.d.ts +6 -1
- package/dist/session-observer-state.js +1 -1
- package/dist/shared-context/manager.d.ts +5 -0
- package/dist/shared-context/manager.js +3 -3
- package/dist/signal.d.ts +1 -0
- package/dist/signal.js +1 -1
- package/dist/source-attribution.js +1 -1
- package/dist/state-store-4QZISH3J.js +30 -0
- package/dist/state-store-4QZISH3J.js.map +1 -0
- package/dist/storage-C4DX8CuG.d.ts +157 -0
- package/dist/storage.d.ts +2 -0
- package/dist/storage.js +7 -7
- package/dist/store-contract.js +1 -1
- package/dist/summarizer.d.ts +1 -0
- package/dist/summarizer.js +7 -7
- package/dist/summary-snapshot.d.ts +1 -0
- package/dist/surfaces/dreams.js +48 -17
- package/dist/surfaces/dreams.js.map +1 -1
- package/dist/temporal-supersession.d.ts +1 -0
- package/dist/temporal-supersession.js +1 -1
- package/dist/temporal-validity.d.ts +1 -0
- package/dist/threading.d.ts +1 -0
- package/dist/tier-migration.d.ts +1 -0
- package/dist/tier-routing.d.ts +1 -0
- package/dist/{tier-stats-62ZVDFKS.js → tier-stats-SKML2OSF.js} +5 -5
- package/dist/tmt.js +1 -1
- package/dist/tokens.js +2 -2
- package/dist/topics.d.ts +1 -0
- package/dist/{trace-C5ETWBEF.js → trace-WM7V4CKI.js} +31 -1
- package/dist/trace-WM7V4CKI.js.map +1 -0
- package/dist/transcript.d.ts +1 -0
- package/dist/transcript.js +2 -2
- package/dist/transfer/autodetect.js +7 -7
- package/dist/transfer/backup.js +5 -5
- package/dist/transfer/capsule-export.js +5 -5
- package/dist/transfer/capsule-import.d.ts +6 -0
- package/dist/transfer/capsule-import.js +4 -4
- package/dist/transfer/export-json.js +3 -3
- package/dist/transfer/export-md.js +3 -3
- package/dist/transfer/export-sqlite.js +3 -3
- package/dist/transfer/fs-utils.d.ts +2 -1
- package/dist/transfer/fs-utils.js +5 -3
- package/dist/transfer/import-json.js +3 -3
- package/dist/transfer/import-md.js +3 -3
- package/dist/transfer/import-sqlite.js +3 -3
- package/dist/trust-zones.js +2 -2
- package/dist/types-B1VHaf2w.d.ts +126 -0
- package/dist/types-BliCnURB.d.ts +83 -0
- package/dist/types.d.ts +35 -0
- package/dist/types.js +1 -1
- package/dist/utility-learner.js +3 -3
- package/dist/utility-runtime.d.ts +1 -0
- package/dist/utility-runtime.js +4 -4
- package/dist/utility-telemetry.js +2 -2
- package/dist/verified-recall.js +9 -9
- package/dist/work/board.js +2 -2
- package/dist/work/boundary.js +1 -1
- package/dist/work/storage.d.ts +5 -0
- package/dist/work/storage.js +1 -1
- package/dist/work-product-ledger.js +2 -2
- package/package.json +74 -3
- package/scripts/ensure-better-sqlite3.mjs +8 -7
- package/scripts/faiss_index.py +141 -29
- package/src/access-cli.test.ts +87 -2
- package/src/access-cli.ts +59 -5
- package/src/access-http.test.ts +150 -0
- package/src/access-http.ts +103 -34
- package/src/access-idempotency.ts +136 -3
- package/src/access-mcp.test.ts +155 -0
- package/src/access-mcp.ts +116 -30
- package/src/access-schema.ts +22 -4
- package/src/access-service-namespace.test.ts +9 -9
- package/src/access-service-project-tag.test.ts +37 -0
- package/src/access-service.ts +15 -14
- package/src/active-recall.test.ts +29 -1
- package/src/active-recall.ts +11 -7
- package/src/adapters/claude-code.ts +7 -8
- package/src/adapters/codex.ts +6 -7
- package/src/adapters/hermes.ts +1 -5
- package/src/adapters/registry.test.ts +63 -0
- package/src/adapters/registry.ts +10 -0
- package/src/adapters/replit.ts +5 -7
- package/src/adapters/types.ts +24 -1
- package/src/behavior-signals.ts +1 -1
- package/src/binary-lifecycle/backend.ts +16 -4
- package/src/binary-lifecycle/pipeline.test.ts +149 -0
- package/src/binary-lifecycle/pipeline.ts +49 -7
- package/src/binary-lifecycle/scanner.ts +19 -4
- package/src/boxes.ts +119 -32
- package/src/buffer-session.test.ts +28 -0
- package/src/buffer.ts +10 -14
- package/src/bulk-import/types.ts +10 -0
- package/src/calibration.test.ts +99 -0
- package/src/calibration.ts +57 -13
- package/src/causal-consolidation.test.ts +214 -0
- package/src/causal-consolidation.ts +131 -14
- package/src/causal-retrieval.ts +16 -3
- package/src/citations.test.ts +75 -0
- package/src/citations.ts +19 -6
- package/src/cli.ts +134 -109
- package/src/coding/coding-namespace.test.ts +7 -0
- package/src/coding/coding-namespace.ts +8 -0
- package/src/coding/review-context.test.ts +30 -0
- package/src/coding/review-context.ts +79 -9
- package/src/coding/wire-coding-context.test.ts +16 -0
- package/src/compat/checks.test.ts +33 -0
- package/src/compat/checks.ts +64 -4
- package/src/compounding/engine.ts +2 -2
- package/src/compounding/preference-consolidator.test.ts +47 -0
- package/src/compounding/preference-consolidator.ts +8 -8
- package/src/compression-optimizer.ts +5 -2
- package/src/config.test.ts +34 -2
- package/src/config.ts +62 -18
- package/src/connectors/codex-materialize-runner.ts +4 -3
- package/src/connectors/codex-materialize.ts +149 -34
- package/src/connectors/index.test.ts +144 -7
- package/src/connectors/index.ts +86 -15
- package/src/connectors/live/github.test.ts +47 -0
- package/src/connectors/live/github.ts +29 -1
- package/src/connectors/live/index.ts +2 -0
- package/src/connectors/live/live-connectors.test.ts +359 -73
- package/src/connectors/live/notion.test.ts +84 -0
- package/src/connectors/live/notion.ts +18 -1
- package/src/connectors/live/state-store.ts +419 -38
- package/src/connectors/weclone-installer.test.ts +16 -18
- package/src/connectors-cli.ts +19 -0
- package/src/console/trace.test.ts +28 -0
- package/src/console/trace.ts +42 -5
- package/src/contradiction/contradiction-judge.test.ts +49 -0
- package/src/contradiction/contradiction-judge.ts +15 -5
- package/src/contradiction/contradiction-review.ts +31 -7
- package/src/contradiction/contradiction-scan.ts +28 -18
- package/src/contradiction/contradiction.test.ts +237 -1
- package/src/contradiction/resolution.ts +43 -4
- package/src/conversation-index/backend.ts +13 -5
- package/src/conversation-index/cleanup.ts +25 -4
- package/src/conversation-index/faiss-adapter.ts +24 -15
- package/src/conversation-index/indexer.test.ts +71 -10
- package/src/conversation-index/indexer.ts +22 -3
- package/src/cross-namespace-budget.test.ts +59 -0
- package/src/cross-namespace-budget.ts +15 -7
- package/src/curation/index.ts +18 -17
- package/src/dashboard-runtime.test.ts +98 -0
- package/src/dashboard-runtime.ts +96 -6
- package/src/dedup/index.test.ts +133 -0
- package/src/dedup/index.ts +73 -10
- package/src/dedup/semantic.test.ts +77 -2
- package/src/dedup/semantic.ts +26 -6
- package/src/embedding-fallback.ts +47 -15
- package/src/enrichment/audit.ts +8 -1
- package/src/enrichment/pipeline.ts +21 -13
- package/src/enrichment/web-search-provider.ts +1 -6
- package/src/entity-retrieval.ts +57 -6
- package/src/evals.ts +22 -13
- package/src/explicit-capture.test.ts +40 -0
- package/src/explicit-capture.ts +14 -2
- package/src/extraction.ts +42 -30
- package/src/fallback-llm.ts +35 -2
- package/src/graph-dashboard-diff.test.ts +57 -0
- package/src/graph-dashboard-diff.ts +24 -2
- package/src/graph-dashboard-parser.test.ts +31 -0
- package/src/graph-dashboard-parser.ts +4 -1
- package/src/graph-events.ts +6 -4
- package/src/graph.test.ts +69 -0
- package/src/graph.ts +7 -4
- package/src/importers/base.test.ts +70 -0
- package/src/importers/base.ts +56 -7
- package/src/index.ts +5 -2
- package/src/lcm/archive.ts +65 -16
- package/src/lcm/engine.ts +27 -8
- package/src/lcm/recall.ts +5 -5
- package/src/lcm-engine.test.ts +87 -1
- package/src/lcm-recall.test.ts +71 -0
- package/src/live-connectors-runner.ts +100 -36
- package/src/maintenance/archive-observations.ts +24 -3
- package/src/maintenance/atomic-file.ts +85 -0
- package/src/maintenance/dreams-ledger.ts +15 -8
- package/src/maintenance/memory-governance.test.ts +53 -0
- package/src/maintenance/memory-governance.ts +15 -5
- package/src/maintenance/observation-ledger-utils.ts +6 -5
- package/src/maintenance/purge.test.ts +64 -0
- package/src/maintenance/rebuild-memory-lifecycle-ledger.ts +22 -9
- package/src/maintenance/rebuild-memory-projection.ts +22 -9
- package/src/maintenance/rebuild-observations.ts +7 -3
- package/src/mcp-memory-inspector-app.ts +26 -3
- package/src/memory-cache.test.ts +19 -0
- package/src/memory-cache.ts +1 -0
- package/src/memory-extension/codex-publisher.ts +25 -4
- package/src/memory-extension-host/host-discovery.test.ts +69 -0
- package/src/memory-extension-host/host-discovery.ts +63 -6
- package/src/memory-projection-store.ts +114 -62
- package/src/message-parts/index.ts +46 -31
- package/src/message-parts/message-parts.test.ts +77 -0
- package/src/migrate/from-engram.ts +68 -14
- package/src/model-registry.test.ts +38 -0
- package/src/model-registry.ts +12 -7
- package/src/namespaces/identity.test.ts +66 -0
- package/src/namespaces/identity.ts +23 -0
- package/src/namespaces/migrate.test.ts +62 -0
- package/src/namespaces/migrate.ts +82 -14
- package/src/namespaces/principal.test.ts +37 -1
- package/src/namespaces/principal.ts +18 -7
- package/src/namespaces/search.test.ts +96 -7
- package/src/namespaces/search.ts +32 -25
- package/src/namespaces/storage.ts +93 -11
- package/src/native-knowledge.ts +23 -3
- package/src/negative.ts +50 -5
- package/src/network/webdav.ts +177 -58
- package/src/offline-sync.test.ts +128 -18
- package/src/offline-sync.ts +41 -7
- package/src/onboarding/index.test.ts +105 -0
- package/src/onboarding/index.ts +17 -5
- package/src/operator-toolkit.ts +43 -5
- package/src/orchestrator.ts +120 -27
- package/src/page-versioning.ts +31 -5
- package/src/peers/peers.test.ts +70 -0
- package/src/peers/storage.ts +32 -3
- package/src/plugin-entry-resolver.test.ts +60 -0
- package/src/plugin-entry-resolver.ts +48 -0
- package/src/plugin-id.test.ts +38 -0
- package/src/plugin-id.ts +31 -64
- package/src/policy-runtime.test.ts +75 -0
- package/src/policy-runtime.ts +32 -3
- package/src/procedural/procedure-miner.test.ts +152 -0
- package/src/procedural/procedure-miner.ts +124 -19
- package/src/profiling.test.ts +23 -0
- package/src/profiling.ts +10 -1
- package/src/projection/index.test.ts +253 -0
- package/src/projection/index.ts +159 -18
- package/src/qmd-client.test.ts +45 -0
- package/src/qmd.ts +13 -10
- package/src/recall-disclosure.test.ts +15 -1
- package/src/recall-state.ts +24 -5
- package/src/relevance.ts +24 -5
- package/src/replay/normalizers/chatgpt.ts +14 -4
- package/src/replay/normalizers/claude.ts +8 -3
- package/src/replay/normalizers/openclaw.ts +35 -12
- package/src/replay/normalizers/replay-normalizers.test.ts +65 -0
- package/src/replay/normalizers/shared.ts +4 -1
- package/src/replay/runner.ts +1 -1
- package/src/rerank.test.ts +41 -1
- package/src/rerank.ts +2 -2
- package/src/resolve-auth-token.test.ts +29 -0
- package/src/resolve-auth-token.ts +12 -7
- package/src/resolve-provider-secret.test.ts +78 -22
- package/src/resolve-provider-secret.ts +55 -223
- package/src/retrieval-agents.ts +51 -14
- package/src/review/index.test.ts +75 -1
- package/src/review/index.ts +88 -30
- package/src/routing/store.ts +36 -6
- package/src/runtime/env.test.ts +73 -0
- package/src/runtime/env.ts +7 -11
- package/src/schemas.ts +16 -1
- package/src/search/abort.ts +18 -0
- package/src/search/document-scanner.test.ts +80 -0
- package/src/search/document-scanner.ts +51 -9
- package/src/search/embed-helper.ts +19 -6
- package/src/search/factory.ts +9 -5
- package/src/search/lancedb-backend.ts +66 -23
- package/src/search/meilisearch-backend.ts +39 -13
- package/src/search/noop-backend.ts +1 -1
- package/src/search/orama-backend.test.ts +27 -0
- package/src/search/orama-backend.ts +69 -16
- package/src/search/port.ts +4 -1
- package/src/search/remote-backend.ts +1 -1
- package/src/secure-store/cli-handlers.ts +70 -6
- package/src/secure-store/cli-renderer.ts +13 -7
- package/src/secure-store/secure-fs.ts +11 -5
- package/src/secure-store/secure-store.test.ts +70 -0
- package/src/semantic-consolidation.test.ts +45 -0
- package/src/semantic-consolidation.ts +3 -3
- package/src/session-integrity.test.ts +98 -0
- package/src/session-integrity.ts +51 -1
- package/src/session-observer-state.ts +108 -41
- package/src/shared-context/manager.ts +93 -15
- package/src/signal.test.ts +14 -0
- package/src/signal.ts +8 -1
- package/src/source-attribution.test.ts +8 -0
- package/src/source-attribution.ts +24 -2
- package/src/spaces/index.test.ts +93 -0
- package/src/spaces/index.ts +75 -9
- package/src/storage.ts +14 -1
- package/src/store-contract.test.ts +35 -0
- package/src/store-contract.ts +39 -5
- package/src/summarizer.ts +24 -18
- package/src/summary-snapshot.test.ts +77 -0
- package/src/surfaces/dreams.test.ts +73 -0
- package/src/surfaces/dreams.ts +53 -19
- package/src/sync/index.ts +42 -17
- package/src/taxonomy/taxonomy-loader.ts +43 -4
- package/src/temporal-supersession.test.ts +67 -0
- package/src/temporal-supersession.ts +8 -0
- package/src/tmt.test.ts +50 -0
- package/src/tmt.ts +35 -11
- package/src/tokens.test.ts +18 -0
- package/src/tokens.ts +7 -0
- package/src/training-export/converter.test.ts +55 -2
- package/src/training-export/converter.ts +36 -10
- package/src/training-export/registry.test.ts +17 -0
- package/src/training-export/registry.ts +19 -1
- package/src/transcript.ts +2 -2
- package/src/transfer/backup.ts +18 -7
- package/src/transfer/capsule-crypto.ts +105 -21
- package/src/transfer/capsule-encrypt.test.ts +106 -7
- package/src/transfer/capsule-export.ts +23 -14
- package/src/transfer/capsule-import.ts +11 -2
- package/src/transfer/exclusions.ts +7 -0
- package/src/transfer/export-sqlite.ts +14 -13
- package/src/transfer/fs-utils.ts +52 -1
- package/src/transfer/import-json.ts +12 -7
- package/src/transfer/import-md.ts +5 -5
- package/src/transfer/import-sqlite.ts +4 -5
- package/src/trust-zones.ts +1 -1
- package/src/types.ts +25 -0
- package/src/utility-telemetry.ts +1 -1
- package/src/utils/category-dir.test.ts +15 -0
- package/src/utils/category-dir.ts +3 -1
- package/src/work/boundary.ts +30 -18
- package/src/work/storage.ts +116 -38
- package/src/work-product-ledger.ts +1 -1
- package/dist/chunk-25MQ7IHJ.js.map +0 -1
- package/dist/chunk-2IWUMAES.js.map +0 -1
- package/dist/chunk-2NMMFZ5T.js.map +0 -1
- package/dist/chunk-2PRLKQAH.js.map +0 -1
- package/dist/chunk-326G7DJK.js.map +0 -1
- package/dist/chunk-3APJ5EVB.js.map +0 -1
- package/dist/chunk-3KW65B36.js.map +0 -1
- package/dist/chunk-3QKK7QOS.js.map +0 -1
- package/dist/chunk-3SLRNYNG.js.map +0 -1
- package/dist/chunk-3VAL7ZL2.js.map +0 -1
- package/dist/chunk-3Y4P7RXM.js.map +0 -1
- package/dist/chunk-3ZLVGM76.js.map +0 -1
- package/dist/chunk-43PJZYGL.js.map +0 -1
- package/dist/chunk-47VWKCAF.js.map +0 -1
- package/dist/chunk-4KGVTPGD.js.map +0 -1
- package/dist/chunk-5375UYTQ.js.map +0 -1
- package/dist/chunk-56K5QLHX.js.map +0 -1
- package/dist/chunk-575RMLWN.js.map +0 -1
- package/dist/chunk-5NPGSAVB.js.map +0 -1
- package/dist/chunk-5RGLBDQF.js.map +0 -1
- package/dist/chunk-65PG43EQ.js.map +0 -1
- package/dist/chunk-66DHUKLO.js.map +0 -1
- package/dist/chunk-6LVVDPJ4.js.map +0 -1
- package/dist/chunk-76FLAAUC.js.map +0 -1
- package/dist/chunk-77H5NU3M.js.map +0 -1
- package/dist/chunk-7MNMYOFP.js.map +0 -1
- package/dist/chunk-7OZ53EXP.js.map +0 -1
- package/dist/chunk-7SEAZFFB.js.map +0 -1
- package/dist/chunk-A6KTB5R6.js.map +0 -1
- package/dist/chunk-AGZQD76C.js.map +0 -1
- package/dist/chunk-APO3DCMU.js.map +0 -1
- package/dist/chunk-BVF3AGJP.js.map +0 -1
- package/dist/chunk-C5BCH4ZS.js.map +0 -1
- package/dist/chunk-C7VW7C3F.js.map +0 -1
- package/dist/chunk-CULXMQJH.js.map +0 -1
- package/dist/chunk-CYFQJMUV.js.map +0 -1
- package/dist/chunk-D654IBA6.js +0 -61
- package/dist/chunk-D654IBA6.js.map +0 -1
- package/dist/chunk-DGXUHMOV.js.map +0 -1
- package/dist/chunk-DINWEURR.js.map +0 -1
- package/dist/chunk-DK5LDEQM.js.map +0 -1
- package/dist/chunk-EABGC2TL.js.map +0 -1
- package/dist/chunk-EHRTFRWW.js.map +0 -1
- package/dist/chunk-EJI5XIBB.js.map +0 -1
- package/dist/chunk-FAAFWE4G.js.map +0 -1
- package/dist/chunk-FAJ7FZYM.js +0 -11
- package/dist/chunk-FAJ7FZYM.js.map +0 -1
- package/dist/chunk-FDU6HUUL.js +0 -147
- package/dist/chunk-FDU6HUUL.js.map +0 -1
- package/dist/chunk-FIT6DMX6.js.map +0 -1
- package/dist/chunk-FJ43PRLT.js.map +0 -1
- package/dist/chunk-FLTNHQK6.js +0 -262
- package/dist/chunk-FLTNHQK6.js.map +0 -1
- package/dist/chunk-GDFS42HT.js.map +0 -1
- package/dist/chunk-H3ME6L6D.js.map +0 -1
- package/dist/chunk-HXXBL2KD.js.map +0 -1
- package/dist/chunk-ICRIXAP2.js.map +0 -1
- package/dist/chunk-IQT3XTKW.js.map +0 -1
- package/dist/chunk-JR4ZC3G4.js.map +0 -1
- package/dist/chunk-K4FLSOR5.js.map +0 -1
- package/dist/chunk-KNKUID7G.js.map +0 -1
- package/dist/chunk-KOSORCJG.js.map +0 -1
- package/dist/chunk-LIRZNNUP.js.map +0 -1
- package/dist/chunk-LLQ2LLWF.js.map +0 -1
- package/dist/chunk-LPMVBPA3.js +0 -236
- package/dist/chunk-LPMVBPA3.js.map +0 -1
- package/dist/chunk-LT3NLYSI.js.map +0 -1
- package/dist/chunk-LUDTDZLK.js.map +0 -1
- package/dist/chunk-MJFNCJXV.js.map +0 -1
- package/dist/chunk-MSWG7JI6.js.map +0 -1
- package/dist/chunk-MXC3AP5I.js.map +0 -1
- package/dist/chunk-MXFBBHJU.js.map +0 -1
- package/dist/chunk-MZH6EHNR.js.map +0 -1
- package/dist/chunk-N2D6GXBM.js.map +0 -1
- package/dist/chunk-NBNN5GOB.js.map +0 -1
- package/dist/chunk-NMZY542O.js.map +0 -1
- package/dist/chunk-NZL6GGQE.js.map +0 -1
- package/dist/chunk-OZHRDTDX.js.map +0 -1
- package/dist/chunk-PIRJPV5T.js.map +0 -1
- package/dist/chunk-PZIAX57I.js.map +0 -1
- package/dist/chunk-Q7P4WJDP.js.map +0 -1
- package/dist/chunk-QA2ZAPBU.js.map +0 -1
- package/dist/chunk-QDZ2RLEC.js.map +0 -1
- package/dist/chunk-QLLBRHAT.js.map +0 -1
- package/dist/chunk-QR3C7BKQ.js.map +0 -1
- package/dist/chunk-RHY3HH7P.js.map +0 -1
- package/dist/chunk-RK2Y4XOM.js.map +0 -1
- package/dist/chunk-RR2PKP3I.js +0 -63
- package/dist/chunk-RR2PKP3I.js.map +0 -1
- package/dist/chunk-RRF5UOBJ.js.map +0 -1
- package/dist/chunk-RXDLTSWT.js.map +0 -1
- package/dist/chunk-RYED3SPJ.js +0 -42
- package/dist/chunk-RYED3SPJ.js.map +0 -1
- package/dist/chunk-S7KDBTWT.js.map +0 -1
- package/dist/chunk-TK4UEOSK.js.map +0 -1
- package/dist/chunk-TMM4S4IJ.js.map +0 -1
- package/dist/chunk-TMQLARTH.js.map +0 -1
- package/dist/chunk-TPB3I2AC.js.map +0 -1
- package/dist/chunk-TPMQ3G6Z.js.map +0 -1
- package/dist/chunk-TPU5L5EY.js.map +0 -1
- package/dist/chunk-TZOLIGIG.js.map +0 -1
- package/dist/chunk-U3WSW6PZ.js.map +0 -1
- package/dist/chunk-U4SCL7B7.js.map +0 -1
- package/dist/chunk-U66YHYC7.js +0 -31
- package/dist/chunk-U66YHYC7.js.map +0 -1
- package/dist/chunk-U7EJOMFC.js.map +0 -1
- package/dist/chunk-UWVJF25J.js.map +0 -1
- package/dist/chunk-VBJ7V5SK.js.map +0 -1
- package/dist/chunk-W3LR522O.js.map +0 -1
- package/dist/chunk-W4L6CZKA.js.map +0 -1
- package/dist/chunk-W6AQJ2PY.js.map +0 -1
- package/dist/chunk-WELDCG6C.js.map +0 -1
- package/dist/chunk-WNARATI3.js.map +0 -1
- package/dist/chunk-WPGJYVUH.js.map +0 -1
- package/dist/chunk-WW3QQF4H.js.map +0 -1
- package/dist/chunk-XIG5PDM7.js.map +0 -1
- package/dist/chunk-XKECPATV.js.map +0 -1
- package/dist/chunk-XKLD5OK4.js.map +0 -1
- package/dist/chunk-XSZEP4SF.js.map +0 -1
- package/dist/chunk-XVVIG67A.js.map +0 -1
- package/dist/chunk-XYIK4LF6.js.map +0 -1
- package/dist/chunk-YRMVARQP.js.map +0 -1
- package/dist/chunk-YROHKYBY.js.map +0 -1
- package/dist/chunk-YU5KIWYQ.js.map +0 -1
- package/dist/chunk-ZAVUCJ4H.js.map +0 -1
- package/dist/chunk-ZPKBYX2F.js.map +0 -1
- package/dist/chunk-ZTFCYYEZ.js.map +0 -1
- package/dist/chunk-ZYVPLJ4T.js.map +0 -1
- package/dist/path-MR5JPYOP.js +0 -9
- package/dist/state-store-VZU2IA53.js +0 -16
- package/dist/trace-C5ETWBEF.js.map +0 -1
- /package/dist/{capsule-crypto-5CYAGVC5.js.map → bulk-import/index.js.map} +0 -0
- /package/dist/{contradiction-review-ATP4S6IC.js.map → capsule-crypto-7FJQINUR.js.map} +0 -0
- /package/dist/{capsule-merge-4MGKE7C5.js.map → capsule-merge-T2JRE46P.js.map} +0 -0
- /package/dist/{chunk-SAZS2QZB.js.map → chunk-23UORJ4S.js.map} +0 -0
- /package/dist/{chunk-PK7H5L6Y.js.map → chunk-2NM43EWN.js.map} +0 -0
- /package/dist/{chunk-PYXS46O7.js.map → chunk-3BP57I6J.js.map} +0 -0
- /package/dist/{chunk-FBYESMQ2.js.map → chunk-3C5RPJAX.js.map} +0 -0
- /package/dist/{chunk-N53K2EXC.js.map → chunk-6VF75M3X.js.map} +0 -0
- /package/dist/{chunk-6H2TESSP.js.map → chunk-765K3SAT.js.map} +0 -0
- /package/dist/{chunk-EDTHC6UD.js.map → chunk-77NAFXUD.js.map} +0 -0
- /package/dist/{chunk-MGKYQQYF.js.map → chunk-7Q3RCKAQ.js.map} +0 -0
- /package/dist/{chunk-34DQE4KF.js.map → chunk-CO7ZO4TU.js.map} +0 -0
- /package/dist/{chunk-ZKSK55RC.js.map → chunk-ETUPBUHB.js.map} +0 -0
- /package/dist/{chunk-QRNI5JBH.js.map → chunk-EYIEWJNI.js.map} +0 -0
- /package/dist/{chunk-C6QPK5GG.js.map → chunk-FZZ2QTJI.js.map} +0 -0
- /package/dist/{chunk-3JXBXXM2.js.map → chunk-G4IAEX6D.js.map} +0 -0
- /package/dist/{chunk-2WWLHTZY.js.map → chunk-IC4GELZE.js.map} +0 -0
- /package/dist/{chunk-PCUKNJAZ.js.map → chunk-JKV57BTN.js.map} +0 -0
- /package/dist/{chunk-2KI4QFHU.js.map → chunk-LMDRGRJ2.js.map} +0 -0
- /package/dist/{chunk-MY6TPVXW.js.map → chunk-LMPHTYJC.js.map} +0 -0
- /package/dist/{chunk-5HRY2WRF.js.map → chunk-LZ3VEOU5.js.map} +0 -0
- /package/dist/{chunk-NGAVDO7E.js.map → chunk-OADWQ5CR.js.map} +0 -0
- /package/dist/{chunk-DOM4GKSW.js.map → chunk-OZKVVUJB.js.map} +0 -0
- /package/dist/{chunk-MT4HVDUZ.js.map → chunk-PM3QHTFT.js.map} +0 -0
- /package/dist/{chunk-ZK7I7JYV.js.map → chunk-R3PS27B4.js.map} +0 -0
- /package/dist/{chunk-SKE7JYKA.js.map → chunk-SFXKHM7P.js.map} +0 -0
- /package/dist/{chunk-HMDCOMYU.js.map → chunk-SKGV326D.js.map} +0 -0
- /package/dist/{chunk-5UM2VJ6D.js.map → chunk-UEY3VB6W.js.map} +0 -0
- /package/dist/{chunk-GIF42EW3.js.map → chunk-UP6MOYCB.js.map} +0 -0
- /package/dist/{chunk-MRILGULB.js.map → chunk-V2RCP53Q.js.map} +0 -0
- /package/dist/{chunk-FSFEQI74.js.map → chunk-W7L6HXUC.js.map} +0 -0
- /package/dist/{chunk-3IQ2TR4N.js.map → chunk-WLEB7WCG.js.map} +0 -0
- /package/dist/{chunk-GL6I6MEQ.js.map → chunk-WSGF57U2.js.map} +0 -0
- /package/dist/{chunk-JA3AK3PT.js.map → chunk-XNLXAWHX.js.map} +0 -0
- /package/dist/{chunk-SIC6U3GZ.js.map → chunk-YHV3KRKS.js.map} +0 -0
- /package/dist/{chunk-VLXA6PI2.js.map → chunk-YQMZ7IH2.js.map} +0 -0
- /package/dist/{contradiction-scan-5A4IDZV5.js.map → contradiction-review-6V2LXXK6.js.map} +0 -0
- /package/dist/{migrate-from-identity-anchor-G27MCD6A.js.map → contradiction-scan-GIRVC4C7.js.map} +0 -0
- /package/dist/{first-start-migration-4MHQEOSD.js.map → first-start-migration-CKTCTCQI.js.map} +0 -0
- /package/dist/{graph-edge-decay-5DI5GUNL.js.map → graph-edge-decay-MUP5J7CC.js.map} +0 -0
- /package/dist/{path-MR5JPYOP.js.map → importers/index.js.map} +0 -0
- /package/dist/{peers-HCVGHMAE.js.map → migrate-from-identity-anchor-EB4XI4Q2.js.map} +0 -0
- /package/dist/{resolution-B7FNQSSP.js.map → path-X2K5XCHL.js.map} +0 -0
- /package/dist/{state-store-VZU2IA53.js.map → peers/index.js.map} +0 -0
- /package/dist/{tier-stats-62ZVDFKS.js.map → tier-stats-SKML2OSF.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/entity-retrieval.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { sanitizeMemoryContent } from \"./sanitize.js\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { collectNativeKnowledgeChunks, type NativeKnowledgeChunk } from \"./native-knowledge.js\";\nimport { compareEntityTimestamps, normalizeEntityName, type StorageManager } from \"./storage.js\";\nimport { normalizeEntityText, resolveRequestedEntitySectionKeys } from \"./entity-schema.js\";\nimport type { EntityStructuredSection, MemoryFile, PluginConfig, TranscriptEntry } from \"./types.js\";\n\nconst ENTITY_INDEX_VERSION = 3;\nconst RECENT_TRANSCRIPT_LOOKBACK_HOURS = 24;\nconst INSTRUCTION_LIKE_RE = /\\b(always|never|must|should|remember to|do not|don't|process|workflow|template|checklist|instruction)\\b/i;\nconst METADATA_WRAPPER_RE = /^(source|context|metadata|notes?):/i;\nconst ENTITY_PRONOUN_RE = /\\b(he|him|his|she|her|they|them|their|it|its)\\b/i;\n\ntype EntityQueryMode = \"direct\" | \"timeline\" | \"follow_up\";\n\ntype EntityMentionIndexEntry = {\n canonicalId: string;\n name: string;\n type: string;\n aliases: string[];\n summary?: string;\n facts: string[];\n timelineFacts: string[];\n structuredSections: EntityStructuredSection[];\n timeline: Array<{\n timestamp: string;\n text: string;\n source?: string;\n sessionKey?: string;\n principal?: string;\n }>;\n relationships: Array<{ target: string; label: string }>;\n activity: Array<{ date: string; note: string }>;\n factCount: number;\n memorySnippets: string[];\n nativeChunks: Array<{\n chunkId: string;\n title: string;\n sourceKind: NativeKnowledgeChunk[\"sourceKind\"];\n sourcePath: string;\n snippet: string;\n derivedDate?: string;\n }>;\n};\n\ntype EntityMentionIndex = {\n version: number;\n updatedAt: string;\n entities: EntityMentionIndexEntry[];\n};\n\ntype EntityCandidate = {\n entry: EntityMentionIndexEntry;\n alias: string;\n score: number;\n source: \"query\" | \"recent_turn\";\n};\n\ntype EntityHintSnippet = {\n text: string;\n score: number;\n kind: \"summary\" | \"fact\" | \"section\" | \"relationship\" | \"activity\" | \"memory\" | \"native\";\n};\n\nexport interface BuildEntityRecallSectionOptions {\n config: PluginConfig;\n storage: StorageManager;\n query: string;\n recallNamespaces?: string[];\n recentTurns: number;\n maxHints: number;\n maxSupportingFacts: number;\n maxRelatedEntities: number;\n maxChars: number;\n transcriptEntries: TranscriptEntry[];\n}\n\nfunction tokenize(value: string): string[] {\n return normalizeEntityText(value).split(/\\s+/).filter((token) => token.length >= 2);\n}\n\nfunction uniqueStrings(values: string[]): string[] {\n return [...new Set(values.map((value) => value.trim()).filter((value) => value.length > 0))];\n}\n\nfunction containsPhrase(haystack: string, needle: string): boolean {\n if (!needle) return false;\n const escaped = needle.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n return new RegExp(`(^|\\\\b)${escaped}(\\\\b|$)`, \"i\").test(haystack);\n}\n\nfunction compactLine(value: string, maxLength: number = 220): string {\n const normalized = value.replace(/\\s+/g, \" \").trim();\n if (normalized.length <= maxLength) return normalized;\n return `${normalized.slice(0, Math.max(0, maxLength - 1)).trimEnd()}…`;\n}\n\nfunction dedupeHintSnippetsByText(snippets: EntityHintSnippet[]): EntityHintSnippet[] {\n const seen = new Set<string>();\n const result: EntityHintSnippet[] = [];\n for (const snippet of snippets) {\n const key = normalizeEntityText(snippet.text);\n if (seen.has(key)) continue;\n seen.add(key);\n result.push(snippet);\n }\n return result;\n}\n\nfunction relationLine(entry: EntityMentionIndexEntry, relationship: { target: string; label: string }): string {\n const normalizedLabel = relationship.label.replace(/\\s+/g, \" \").trim();\n if (normalizedLabel.length === 0) return `${entry.name} is connected to ${relationship.target}`;\n return `${entry.name} ${normalizedLabel} ${relationship.target}`;\n}\n\nfunction detectEntityQueryMode(query: string): EntityQueryMode | null {\n const normalized = normalizeEntityText(query);\n if (!normalized) return null;\n if (\n /^(what about|and what about|how about|what happened (with|to) (he|him|his|she|her|they|them|their|it|its)|did (he|she|they|it)|is (he|she|they|it)|was (he|she|they|it))\\b/.test(normalized)\n ) {\n return \"follow_up\";\n }\n if (\n /^(who is|who s|what do we know about|what does|tell me about|what can you tell me about|what s new with|what happened with|what happened to|status of|where is|how is)\\b/.test(normalized)\n ) {\n if (/^what does\\b/.test(normalized)) {\n if (/^what does (?:this|that|it|the|a|an|my|our|your|their)\\b/.test(normalized)) {\n return null;\n }\n if (\n /^what does [a-z0-9-]+ (?:error|warning|exception|failure|stack|trace|code|message|log)\\b/.test(normalized)\n && /\\b(mean|means|indicate|indicates|imply|implies)\\b/.test(normalized)\n ) {\n return null;\n }\n }\n return /what happened|what s new|status of|how is|where is/.test(normalized) ? \"timeline\" : \"direct\";\n }\n if (ENTITY_PRONOUN_RE.test(normalized) && normalized.split(/\\s+/).length <= 8) {\n return \"follow_up\";\n }\n return null;\n}\n\nfunction scoreAliasMatch(query: string, alias: string): number {\n const normalizedQuery = normalizeEntityText(query);\n const normalizedAlias = normalizeEntityText(alias);\n if (!normalizedAlias) return 0;\n if (normalizedQuery === normalizedAlias) return 10;\n if (containsPhrase(normalizedQuery, normalizedAlias)) return 8 + Math.min(normalizedAlias.split(/\\s+/).length, 3);\n const queryTokens = new Set(tokenize(normalizedQuery));\n const aliasTokens = tokenize(normalizedAlias);\n if (aliasTokens.length === 0) return 0;\n const overlap = aliasTokens.filter((token) => queryTokens.has(token)).length;\n if (overlap === 0) return 0;\n // Cross-entity contamination guard (#682 PR 2/3 R-2). For multi-token\n // aliases, partial-token overlap that hits ONLY shared common tokens\n // (like \"person\" in \"Person-A1\" / \"Person-B1\") would surface every\n // similarly-prefixed entity for a query that named only one. Require\n // that the overlap include at least one DISTINCTIVE alias token —\n // i.e. a token that does not also appear in any other entity's\n // alias-token vocabulary. Since this function is pure / per-pair, we\n // approximate \"distinctive\" by requiring the overlap to include at\n // least one token that is not a substring-of common identifier\n // affixes. The aliasTokens with length > 1 must contribute at least\n // one non-affix overlap. \"Alice Example\" ([\"alice\", \"example\"])\n // matched by query \"Tell me about Alice\" → overlap = 1 on \"alice\",\n // and \"alice\" is not an affix → score = 1. \"Person-A1\" tokens\n // [\"person\", \"a1\"] matched by query \"Who is Person-B1?\" → overlap =\n // 1 on \"person\", and \"person\" IS an affix → score = 0.\n if (aliasTokens.length > 1) {\n const nonAffixOverlap = aliasTokens.filter(\n (token) => queryTokens.has(token) && !isAliasAffixToken(token),\n ).length;\n if (nonAffixOverlap === 0) return 0;\n }\n return overlap;\n}\n\n/**\n * Tokens that look like type prefixes / generic role identifiers and\n * therefore should not, on their own, count as evidence that a\n * multi-token alias matches a query (#682 PR 2/3 R-2).\n *\n * Kept as a small explicit list rather than a regex so additions are\n * deliberate. The list mirrors the entity types listed in\n * `entity-schema.ts` plus the most common generic role identifiers\n * that frequently appear as the leading token of a display name.\n */\nconst ALIAS_AFFIX_TOKENS = new Set<string>([\n \"person\", \"people\", \"user\", \"users\", \"team\", \"teams\",\n \"project\", \"projects\", \"topic\", \"topics\",\n \"org\", \"orgs\", \"organization\", \"organizations\", \"company\", \"companies\",\n \"place\", \"places\", \"tool\", \"tools\", \"service\", \"services\",\n \"system\", \"systems\", \"agent\", \"agents\", \"bot\", \"bots\",\n]);\n\nfunction isAliasAffixToken(token: string): boolean {\n return ALIAS_AFFIX_TOKENS.has(token);\n}\n\nfunction isLikelyInstructionLike(value: string): boolean {\n return INSTRUCTION_LIKE_RE.test(value) || METADATA_WRAPPER_RE.test(value);\n}\n\nfunction sanitizeEntityFact(fact: string): string {\n const sanitized = sanitizeMemoryContent(fact);\n const clean = sanitized.text.trim();\n if (!clean) return \"\";\n if (INSTRUCTION_LIKE_RE.test(clean) && clean.length > 100) return \"\";\n return clean;\n}\n\nfunction scoreHintSnippet(snippet: EntityHintSnippet, queryTokens: string[]): EntityHintSnippet | null {\n const normalized = normalizeEntityText(snippet.text);\n if (!normalized) return null;\n const scored = { ...snippet };\n if (isLikelyInstructionLike(scored.text) && scored.kind !== \"summary\") {\n scored.score -= 3;\n }\n const overlap = queryTokens.filter((token) => normalized.includes(token)).length;\n scored.score += overlap * 2;\n if (METADATA_WRAPPER_RE.test(scored.text)) scored.score -= 2;\n if (scored.text.length <= 160) scored.score += 1;\n return scored.score > 0 ? scored : null;\n}\n\nfunction sortTimelineEntriesDesc(\n left: EntityMentionIndexEntry[\"timeline\"][number],\n right: EntityMentionIndexEntry[\"timeline\"][number],\n): number {\n const timestampOrder = compareEntityTimestamps(right.timestamp, left.timestamp);\n if (timestampOrder !== 0) {\n return timestampOrder;\n }\n return right.text.localeCompare(left.text);\n}\n\nfunction jaccardSimilarity(a: string, b: string): number {\n const aTokens = new Set(tokenize(a));\n const bTokens = new Set(tokenize(b));\n if (aTokens.size === 0 || bTokens.size === 0) return 0;\n let intersection = 0;\n for (const token of aTokens) {\n if (bTokens.has(token)) intersection += 1;\n }\n const union = new Set([...aTokens, ...bTokens]).size;\n return union === 0 ? 0 : intersection / union;\n}\n\nfunction buildAliasIndex(entries: EntityMentionIndexEntry[]): Map<string, EntityMentionIndexEntry[]> {\n const index = new Map<string, EntityMentionIndexEntry[]>();\n for (const entry of entries) {\n const aliases = uniqueStrings([entry.name, ...entry.aliases]).map(normalizeEntityText).filter(Boolean);\n for (const alias of aliases) {\n const existing = index.get(alias) ?? [];\n existing.push(entry);\n index.set(alias, existing);\n }\n }\n return index;\n}\n\nasync function readNativeChunks(\n config: PluginConfig,\n recallNamespaces?: string[],\n): Promise<NativeKnowledgeChunk[]> {\n if (!config.nativeKnowledge?.enabled) return [];\n return collectNativeKnowledgeChunks({\n workspaceDir: config.workspaceDir,\n memoryDir: config.memoryDir,\n config: config.nativeKnowledge,\n recallNamespaces: config.namespacesEnabled ? recallNamespaces : undefined,\n defaultNamespace: config.defaultNamespace,\n }).catch(() => []);\n}\n\nfunction entityIndexStatePath(storage: StorageManager): string {\n return path.join(storage.dir, \"state\", \"entity-mention-index.json\");\n}\n\nasync function readEntityIndexState(storage: StorageManager): Promise<EntityMentionIndex | null> {\n const raw = await readFile(entityIndexStatePath(storage), \"utf-8\").catch(() => \"\");\n if (!raw) return null;\n try {\n const parsed = JSON.parse(raw) as Partial<EntityMentionIndex>;\n if (parsed.version !== ENTITY_INDEX_VERSION || !Array.isArray(parsed.entities)) return null;\n return parsed as EntityMentionIndex;\n } catch {\n return null;\n }\n}\n\nasync function writeEntityIndexState(storage: StorageManager, index: EntityMentionIndex): Promise<void> {\n const statePath = entityIndexStatePath(storage);\n await mkdir(path.dirname(statePath), { recursive: true });\n const nextContent = JSON.stringify(index, null, 2) + \"\\n\";\n const currentContent = await readFile(statePath, \"utf-8\").catch(() => \"\");\n if (currentContent === nextContent) return;\n await writeFile(statePath, nextContent, \"utf-8\");\n}\n\nfunction nativePseudoCanonicalId(chunk: NativeKnowledgeChunk): string {\n return `native:${createHash(\"sha256\").update(chunk.sourcePath).digest(\"hex\").slice(0, 12)}`;\n}\n\nfunction createPseudoNativeEntry(chunk: NativeKnowledgeChunk): EntityMentionIndexEntry {\n const canonicalId = nativePseudoCanonicalId(chunk);\n return {\n canonicalId,\n name: chunk.title,\n type: chunk.sourceKind,\n aliases: uniqueStrings(chunk.aliases ?? []),\n facts: [],\n structuredSections: [],\n timelineFacts: [],\n timeline: [],\n relationships: [],\n activity: [],\n factCount: 0,\n memorySnippets: [],\n nativeChunks: [\n {\n chunkId: chunk.chunkId,\n title: chunk.title,\n sourceKind: chunk.sourceKind,\n sourcePath: chunk.sourcePath,\n snippet: compactLine(chunk.content, 180),\n derivedDate: chunk.derivedDate,\n },\n ],\n };\n}\n\nfunction mergeNativeChunk(entry: EntityMentionIndexEntry, chunk: NativeKnowledgeChunk): void {\n const existing = entry.nativeChunks.find((item) => item.chunkId === chunk.chunkId);\n if (existing) return;\n entry.nativeChunks.push({\n chunkId: chunk.chunkId,\n title: chunk.title,\n sourceKind: chunk.sourceKind,\n sourcePath: chunk.sourcePath,\n snippet: compactLine(chunk.content, 180),\n derivedDate: chunk.derivedDate,\n });\n entry.aliases = uniqueStrings([...entry.aliases, ...(chunk.aliases ?? [])]);\n}\n\nasync function buildEntityMentionIndex(\n storage: StorageManager,\n config: PluginConfig,\n recallNamespaces?: string[],\n): Promise<EntityMentionIndex> {\n const [previousIndex, entityFiles, memories, nativeChunks] = await Promise.all([\n readEntityIndexState(storage),\n storage.readAllEntityFiles(),\n storage.readAllMemories(),\n readNativeChunks(config, recallNamespaces),\n ]);\n\n const entities = new Map<string, EntityMentionIndexEntry>();\n for (const entity of entityFiles) {\n const canonicalId = normalizeEntityName(entity.name, entity.type);\n const sanitizedFacts = entity.facts.map((fact) => sanitizeEntityFact(fact)).filter(Boolean).map((fact) => compactLine(fact, 180));\n const sanitizedTimelineFacts = entity.timeline\n .map((entry) => sanitizeEntityFact(entry.text))\n .filter(Boolean)\n .map((fact) => compactLine(fact, 180));\n entities.set(canonicalId, {\n canonicalId,\n name: entity.name,\n type: entity.type,\n aliases: uniqueStrings(entity.aliases),\n summary: entity.synthesis?.trim() || entity.summary?.trim() || undefined,\n facts: sanitizedFacts,\n timelineFacts: uniqueStrings(sanitizedTimelineFacts),\n structuredSections: (entity.structuredSections ?? []).map((section) => ({\n key: section.key,\n title: section.title,\n facts: section.facts\n .map((fact) => sanitizeEntityFact(fact))\n .filter(Boolean)\n .map((fact) => compactLine(fact, 180)),\n })).filter((section) => section.facts.length > 0),\n timeline: entity.timeline.map((entry) => ({ ...entry })),\n relationships: entity.relationships.map((relationship) => ({ ...relationship })),\n activity: entity.activity.map((activity) => ({ ...activity })),\n factCount: sanitizedFacts.length,\n memorySnippets: [],\n nativeChunks: [],\n });\n }\n\n for (const memory of memories) {\n const entityRef = typeof memory.frontmatter.entityRef === \"string\" ? memory.frontmatter.entityRef : \"\";\n if (!entityRef) continue;\n const entry = entities.get(entityRef);\n if (!entry) continue;\n const snippet = await readMemorySnippet(memory);\n if (!entry.memorySnippets.includes(snippet)) {\n entry.memorySnippets.push(snippet);\n }\n }\n\n const aliasIndex = buildAliasIndex([...entities.values()]);\n for (const chunk of nativeChunks) {\n const existingPseudo = entities.get(nativePseudoCanonicalId(chunk));\n if (existingPseudo) {\n mergeNativeChunk(existingPseudo, chunk);\n continue;\n }\n const candidateAliases = uniqueStrings([chunk.title, ...(chunk.aliases ?? [])]).map(normalizeEntityText).filter(Boolean);\n let matched = false;\n for (const alias of candidateAliases) {\n for (const entry of aliasIndex.get(alias) ?? []) {\n mergeNativeChunk(entry, chunk);\n matched = true;\n }\n }\n if (matched) continue;\n const pseudoEntry = createPseudoNativeEntry(chunk);\n entities.set(pseudoEntry.canonicalId, pseudoEntry);\n }\n\n const sortedEntities = [...entities.values()].sort((left, right) => left.name.localeCompare(right.name));\n const previousEntities = previousIndex ? JSON.stringify(previousIndex.entities) : \"\";\n const nextEntities = JSON.stringify(sortedEntities);\n const index: EntityMentionIndex = {\n version: ENTITY_INDEX_VERSION,\n updatedAt:\n previousIndex && previousEntities === nextEntities\n ? previousIndex.updatedAt\n : new Date().toISOString(),\n entities: sortedEntities,\n };\n await writeEntityIndexState(storage, index);\n return index;\n}\n\nfunction resolveExplicitCandidates(\n index: EntityMentionIndex,\n query: string,\n): EntityCandidate[] {\n const candidates: EntityCandidate[] = [];\n for (const entry of index.entities) {\n const aliases = uniqueStrings([entry.name, ...entry.aliases]);\n let bestAlias = \"\";\n let bestScore = 0;\n for (const alias of aliases) {\n const score = scoreAliasMatch(query, alias);\n if (score > bestScore) {\n bestAlias = alias;\n bestScore = score;\n }\n }\n if (bestScore <= 0) continue;\n candidates.push({ entry, alias: bestAlias, score: bestScore, source: \"query\" });\n }\n return candidates.sort((left, right) => right.score - left.score);\n}\n\nfunction resolveRecentTurnCandidates(\n index: EntityMentionIndex,\n transcriptEntries: TranscriptEntry[],\n recentTurns: number,\n): EntityCandidate[] {\n if (recentTurns <= 0 || transcriptEntries.length === 0) return [];\n const recentEntries = transcriptEntries.slice(-recentTurns);\n const candidates = new Map<string, EntityCandidate>();\n for (let indexOffset = recentEntries.length - 1; indexOffset >= 0; indexOffset -= 1) {\n const turn = recentEntries[indexOffset];\n const recencyBoost = recentEntries.length - indexOffset;\n const roleWeight = turn.role === \"user\" ? 2 : turn.role === \"assistant\" ? -1 : 0;\n for (const entry of index.entities) {\n const aliases = uniqueStrings([entry.name, ...entry.aliases]);\n for (const alias of aliases) {\n const score = scoreAliasMatch(turn.content, alias);\n if (score <= 0) continue;\n const current = candidates.get(entry.canonicalId);\n const weightedScore = score + Math.max(0, 6 - recencyBoost) + roleWeight;\n if (!current || weightedScore > current.score) {\n candidates.set(entry.canonicalId, {\n entry,\n alias,\n score: weightedScore,\n source: \"recent_turn\",\n });\n }\n }\n }\n }\n return [...candidates.values()].sort((left, right) => right.score - left.score);\n}\n\nasync function readMemorySnippet(memory: MemoryFile): Promise<string> {\n const content = memory.content.replace(/\\s+/g, \" \").trim();\n return compactLine(content, 180);\n}\n\nasync function buildHintSnippets(\n entry: EntityMentionIndexEntry,\n queryTokens: string[],\n mode: EntityQueryMode,\n maxSupportingFacts: number,\n requestedSectionKeys: Set<string>,\n): Promise<EntityHintSnippet[]> {\n const snippets: EntityHintSnippet[] = [];\n const aliasTokens = new Set(tokenize(uniqueStrings([entry.name, ...entry.aliases]).join(\" \")));\n if (entry.summary) {\n snippets.push({ text: compactLine(entry.summary, 180), score: 10, kind: \"summary\" });\n }\n\n if (requestedSectionKeys.size > 0) {\n for (const section of entry.structuredSections) {\n if (!requestedSectionKeys.has(normalizeEntityText(section.key).replace(/\\s+/g, \"_\"))) continue;\n for (const fact of section.facts) {\n snippets.push({ text: fact, score: mode === \"direct\" ? 8 : 9, kind: \"section\" });\n }\n }\n } else {\n for (const fact of entry.timelineFacts) {\n snippets.push({ text: fact, score: mode === \"direct\" ? 6 : 7, kind: \"fact\" });\n }\n for (const section of entry.structuredSections) {\n for (const fact of section.facts) {\n const normalizedFact = normalizeEntityText(fact);\n const hasNonAliasQueryOverlap = queryTokens.some((token) =>\n !aliasTokens.has(token) && normalizedFact.includes(token)\n );\n if (entry.timelineFacts.length > 0 && !hasNonAliasQueryOverlap) {\n continue;\n }\n snippets.push({ text: fact, score: mode === \"direct\" ? 6 : 7, kind: \"fact\" });\n }\n }\n if (entry.timelineFacts.length === 0 && entry.structuredSections.length === 0) {\n for (const fact of entry.facts) {\n if (!fact.trim()) continue;\n snippets.push({ text: fact, score: mode === \"direct\" ? 6 : 7, kind: \"fact\" });\n }\n }\n }\n\n if (requestedSectionKeys.size === 0) {\n for (const relationship of entry.relationships) {\n snippets.push({\n text: compactLine(relationLine(entry, relationship), 180),\n score: mode === \"direct\" && entry.type.toLowerCase() === \"person\" ? 6 : 4,\n kind: \"relationship\",\n });\n }\n\n for (const activity of entry.activity) {\n snippets.push({\n text: compactLine(`${activity.date}: ${activity.note}`, 180),\n score: 4,\n kind: \"activity\",\n });\n }\n\n for (const memorySnippet of entry.memorySnippets.slice(0, Math.min(maxSupportingFacts, 4))) {\n snippets.push({\n text: memorySnippet,\n score: 5,\n kind: \"memory\",\n });\n }\n\n for (const chunk of entry.nativeChunks) {\n snippets.push({\n text: compactLine(chunk.snippet, 180),\n score: 3,\n kind: \"native\",\n });\n }\n }\n\n const deduped = new Map<string, EntityHintSnippet>();\n for (const snippet of snippets) {\n const scored = scoreHintSnippet(snippet, queryTokens);\n if (!scored) continue;\n const normalized = normalizeEntityText(scored.text);\n const existing = deduped.get(normalized);\n if (!existing || scored.score > existing.score) deduped.set(normalized, scored);\n }\n\n return [...deduped.values()]\n .filter((snippet) => snippet.score > 0)\n .sort((left, right) => right.score - left.score)\n .slice(0, maxSupportingFacts);\n}\n\nfunction summarizeUncertainty(snippets: EntityHintSnippet[]): string | null {\n const direct = snippets.filter((snippet) =>\n snippet.kind === \"summary\"\n || snippet.kind === \"fact\"\n || snippet.kind === \"section\"\n || snippet.kind === \"memory\"\n );\n if (direct.length < 2) return null;\n for (let index = 0; index < direct.length; index += 1) {\n for (let compare = index + 1; compare < direct.length; compare += 1) {\n if (jaccardSimilarity(direct[index].text, direct[compare].text) < 0.2) {\n return \"Evidence is mixed across stored facts; treat the hints below as partial and verify before answering definitively.\";\n }\n }\n }\n return null;\n}\n\nfunction formatEntityHintSection(\n candidates: Array<{\n candidate: EntityCandidate;\n snippets: EntityHintSnippet[];\n uncertainty: string | null;\n }>,\n queryTokens: string[],\n mode: EntityQueryMode,\n maxRelatedEntities: number,\n maxChars: number,\n): string | null {\n if (candidates.length === 0) return null;\n const lines: string[] = [\"## entity_answer_hints\", \"\"];\n for (const { candidate, snippets, uncertainty } of candidates) {\n const hasSummary = Boolean(candidate.entry.summary?.trim());\n const preferredTopSnippets = hasSummary\n ? snippets.filter((snippet) => snippet.kind !== \"fact\")\n : snippets;\n let topSnippets = (\n preferredTopSnippets.length > 0 ? preferredTopSnippets : snippets\n ).slice(0, 3);\n const buildTimelineSnippets = (seedExcludedTexts: Set<string>): EntityHintSnippet[] => {\n const explicitTimelinePool = dedupeHintSnippetsByText(\n (candidate.entry.timeline ?? [])\n .slice()\n .sort(sortTimelineEntriesDesc)\n .map((entry) => sanitizeEntityFact(entry.text))\n .filter(Boolean)\n .map((text) => scoreHintSnippet({\n text: compactLine(text, 180),\n score: 7,\n kind: \"activity\" as const,\n }, queryTokens))\n .filter((snippet): snippet is EntityHintSnippet => snippet !== null)\n .filter((snippet) => !seedExcludedTexts.has(normalizeEntityText(snippet.text))),\n ).slice(0, 2);\n const activityTimelinePool = dedupeHintSnippetsByText(\n snippets\n .filter((snippet) => (\n snippet.kind === \"activity\" || snippet.kind === \"memory\"\n ) && !seedExcludedTexts.has(normalizeEntityText(snippet.text))),\n ).slice(0, 2);\n return explicitTimelinePool.length > 0\n ? explicitTimelinePool\n : activityTimelinePool.length > 0\n ? activityTimelinePool\n : dedupeHintSnippetsByText(\n snippets\n .filter((snippet) => (\n snippet.kind === \"fact\" || snippet.kind === \"summary\"\n ) && !seedExcludedTexts.has(normalizeEntityText(snippet.text))),\n ).slice(0, 2);\n };\n const baseTopSnippetTexts = new Set(topSnippets.map((snippet) => normalizeEntityText(snippet.text)));\n const timelinePool = mode !== \"direct\" ? buildTimelineSnippets(baseTopSnippetTexts) : [];\n if (mode !== \"direct\" && hasSummary && topSnippets.length < 2) {\n if (timelinePool.length > 0) {\n topSnippets = [...topSnippets, timelinePool[0]!].slice(0, 3);\n }\n }\n const topSnippetTexts = new Set(topSnippets.map((snippet) => normalizeEntityText(snippet.text)));\n lines.push(`- target: ${candidate.entry.name} (${candidate.entry.type})`);\n if (candidate.source === \"recent_turn\") {\n lines.push(`- resolution: carried forward from recent turns via alias \"${candidate.alias}\"`);\n } else {\n lines.push(`- resolution: matched alias \"${candidate.alias}\" in the query`);\n }\n if (uncertainty) lines.push(`- uncertainty: ${uncertainty}`);\n if (topSnippets.length > 0) {\n lines.push(\"- likely answer:\");\n for (const snippet of topSnippets) {\n lines.push(` - ${snippet.text}`);\n }\n }\n if (mode !== \"direct\") {\n const fallbackTimeline = timelinePool.filter(\n (snippet) => !topSnippetTexts.has(normalizeEntityText(snippet.text)),\n );\n if (fallbackTimeline.length > 0) {\n lines.push(\"- recent timeline:\");\n for (const snippet of fallbackTimeline) {\n lines.push(` - ${snippet.text}`);\n }\n }\n }\n const related = candidate.entry.relationships.slice(0, maxRelatedEntities).map((relationship) => relationship.target);\n if (related.length > 0) {\n lines.push(`- related entities: ${related.join(\", \")}`);\n }\n lines.push(`- support counts: facts=${candidate.entry.factCount}, memories=${candidate.entry.memorySnippets.length}, native=${candidate.entry.nativeChunks.length}`);\n lines.push(\"\");\n }\n\n let result = lines.join(\"\\n\");\n if (result.length > maxChars) {\n result = `${result.slice(0, Math.max(0, maxChars - 15)).trimEnd()}\\n\\n...(trimmed)\\n`;\n }\n return result.trim().length > 0 ? result.trimEnd() : null;\n}\n\nexport async function buildEntityRecallSection(options: BuildEntityRecallSectionOptions): Promise<string | null> {\n const mode = detectEntityQueryMode(options.query);\n if (!mode) return null;\n\n const index = await buildEntityMentionIndex(options.storage, options.config, options.recallNamespaces);\n if (index.entities.length === 0) return null;\n\n const explicitCandidates = resolveExplicitCandidates(index, options.query);\n const candidates = explicitCandidates.length > 0\n ? explicitCandidates\n : resolveRecentTurnCandidates(index, options.transcriptEntries, options.recentTurns);\n\n if (candidates.length === 0) return null;\n\n const queryTokens = tokenize(options.query);\n const candidateLimit = explicitCandidates.length === 0 && mode === \"follow_up\"\n ? 1\n : options.maxHints;\n const rankedCandidates = candidates.slice(0, candidateLimit);\n const enriched = await Promise.all(\n rankedCandidates.map(async (candidate) => {\n const requestedSectionKeys = new Set(\n resolveRequestedEntitySectionKeys(\n options.query,\n candidate.entry.type,\n candidate.entry.structuredSections,\n options.config.entitySchemas,\n ),\n );\n const snippets = await buildHintSnippets(\n candidate.entry,\n queryTokens,\n mode,\n options.maxSupportingFacts,\n requestedSectionKeys,\n );\n return {\n candidate,\n snippets,\n uncertainty: summarizeUncertainty(snippets),\n };\n }),\n );\n\n const section = formatEntityHintSection(enriched, queryTokens, mode, options.maxRelatedEntities, options.maxChars);\n if (!section) return null;\n return section;\n}\n\nexport async function readRecentEntityTranscriptEntries(\n transcriptEntriesPromise: Promise<TranscriptEntry[]>,\n recentTurns: number,\n): Promise<TranscriptEntry[]> {\n if (recentTurns <= 0) return [];\n const transcriptEntries = await transcriptEntriesPromise.catch(() => []);\n if (transcriptEntries.length === 0) return [];\n return transcriptEntries.slice(-Math.max(1, recentTurns * 2));\n}\n\nexport const entityIndexVersion = ENTITY_INDEX_VERSION;\nexport const entityRecentTranscriptLookbackHours = RECENT_TRANSCRIPT_LOOKBACK_HOURS;\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/contradiction/resolution.ts"],"sourcesContent":["/**\n * Resolution Verbs — executes user-chosen resolution actions on contradiction pairs (issue #520).\n *\n * All resolution paths delegate to StorageManager.supersedeMemory. Do not\n * reimplement supersession logic here (rule 22: deduplicate resolution).\n */\n\nimport type { StorageManager } from \"../storage.js\";\nimport type { MemoryCategory, MemoryFile } from \"../types.js\";\nimport type { ResolutionVerb } from \"./contradiction-review.js\";\nimport { resolvePair, readPair } from \"./contradiction-review.js\";\nimport { log } from \"../logger.js\";\n\nexport interface ResolutionResult {\n pairId: string;\n verb: ResolutionVerb;\n /** Memory IDs affected by the resolution. */\n affectedIds: string[];\n /** Human-readable status. */\n message: string;\n}\n\nexport interface ExecuteResolutionOptions {\n /** Existing merged memory to supersede both source memories to. */\n mergedMemoryId?: string;\n /** Content for a new merged memory. Required for merge when mergedMemoryId is omitted. */\n mergedContent?: string;\n /** Category for a newly created merged memory. Defaults to the shared source category, or fact. */\n mergedCategory?: MemoryCategory;\n /** Resolve storage for the pair namespace, or the default namespace for legacy unscoped pairs. */\n storageForNamespace?: (namespace: string | undefined) => StorageManager | Promise<StorageManager>;\n}\n\nconst VALID_VERBS: ResolutionVerb[] = [\"keep-a\", \"keep-b\", \"merge\", \"both-valid\", \"needs-more-context\"];\n\nexport function isValidResolutionVerb(value: string): value is ResolutionVerb {\n return VALID_VERBS.includes(value as ResolutionVerb);\n}\n\n/**\n * Execute a resolution verb on a contradiction pair.\n *\n * - `keep-a`: Supersede B, keep A active.\n * - `keep-b`: Supersede A, keep B active.\n * - `merge`: Create or verify a real merged memory, then supersede both inputs.\n * - `both-valid`: Mark pair as reviewed; no memories are superseded.\n * - `needs-more-context`: Defer; no action, short cooldown.\n */\nexport async function executeResolution(\n memoryDir: string,\n storage: StorageManager,\n pairId: string,\n verb: ResolutionVerb,\n options: ExecuteResolutionOptions = {},\n): Promise<ResolutionResult> {\n if (typeof verb !== \"string\" || !isValidResolutionVerb(verb)) {\n throw new Error(`Invalid contradiction resolution verb: ${String(verb)}`);\n }\n\n const pair = readPair(memoryDir, pairId);\n if (!pair) {\n return { pairId, verb, affectedIds: [], message: `Pair ${pairId} not found` };\n }\n\n if (pair.namespace && !options.storageForNamespace) {\n throw new Error(\n \"contradiction resolution requires storageForNamespace for namespaced pairs so callers resolve the correct namespace storage\",\n );\n }\n\n const resolutionStorage = options.storageForNamespace\n ? await options.storageForNamespace(pair.namespace)\n : storage;\n\n if (pair.resolution && pair.resolution !== \"needs-more-context\") {\n return { pairId, verb, affectedIds: [], message: `Pair already resolved with verb \"${pair.resolution}\"` };\n }\n\n const [idA, idB] = pair.memoryIds;\n const affectedIds: string[] = [];\n let message = \"\";\n let supersedeFailed = false;\n\n switch (verb) {\n case \"keep-a\": {\n const keepTarget = await validateKeepTarget(resolutionStorage, pairId, idA);\n if (!keepTarget.ok) {\n supersedeFailed = true;\n message = keepTarget.message;\n break;\n }\n const sourceB = await loadSourceSnapshot(resolutionStorage, idB);\n const ok = sourceB\n ? await supersedeSafe(resolutionStorage, idB, idA, \"contradiction-resolution:keep-a\")\n : false;\n if (ok) { affectedIds.push(idB); message = `Kept ${idA}, superseded ${idB}`; }\n else {\n supersedeFailed = true;\n const rolledBack = sourceB\n ? await restoreMemorySnapshot(resolutionStorage, sourceB, \"contradiction-resolution:keep-a-rollback\")\n : false;\n message = rolledBack\n ? `Supersede failed for ${idB}; restored ${idB} and did not resolve`\n : `Supersede failed for ${idB}; rollback incomplete for ${idB} and pair is not resolved`;\n }\n break;\n }\n case \"keep-b\": {\n const keepTarget = await validateKeepTarget(resolutionStorage, pairId, idB);\n if (!keepTarget.ok) {\n supersedeFailed = true;\n message = keepTarget.message;\n break;\n }\n const sourceA = await loadSourceSnapshot(resolutionStorage, idA);\n const ok = sourceA\n ? await supersedeSafe(resolutionStorage, idA, idB, \"contradiction-resolution:keep-b\")\n : false;\n if (ok) { affectedIds.push(idA); message = `Kept ${idB}, superseded ${idA}`; }\n else {\n supersedeFailed = true;\n const rolledBack = sourceA\n ? await restoreMemorySnapshot(resolutionStorage, sourceA, \"contradiction-resolution:keep-b-rollback\")\n : false;\n message = rolledBack\n ? `Supersede failed for ${idA}; restored ${idA} and did not resolve`\n : `Supersede failed for ${idA}; rollback incomplete for ${idA} and pair is not resolved`;\n }\n break;\n }\n case \"merge\": {\n const replacement = await prepareMergeReplacement(resolutionStorage, pairId, idA, idB, options);\n if (!replacement.ok) {\n supersedeFailed = true;\n message = replacement.message;\n break;\n }\n\n const okA = await supersedeSafe(resolutionStorage, idA, replacement.mergedId, \"contradiction-resolution:merge\");\n if (!okA) {\n supersedeFailed = true;\n const rolledBackA = await restoreMemorySnapshot(resolutionStorage, replacement.sourceA);\n message = rolledBackA\n ? `Merge failed for ${idA}; restored ${idA} and did not resolve`\n : `Merge failed for ${idA}; rollback incomplete for ${idA} and pair is not resolved`;\n if (rolledBackA) {\n await cleanupCreatedReplacement(resolutionStorage, replacement);\n }\n break;\n }\n\n const okB = await supersedeSafe(resolutionStorage, idB, replacement.mergedId, \"contradiction-resolution:merge\");\n if (!okB) {\n supersedeFailed = true;\n const rolledBackA = await restoreMemorySnapshot(resolutionStorage, replacement.sourceA);\n const rolledBackB = await restoreMemorySnapshot(resolutionStorage, replacement.sourceB);\n message = rolledBackA && rolledBackB\n ? `Merge failed for ${idB}; restored ${idA} and ${idB} and did not resolve`\n : `Merge failed for ${idB}; rollback incomplete for ${[\n rolledBackA ? undefined : idA,\n rolledBackB ? undefined : idB,\n ].filter(Boolean).join(\", \")} and pair is not resolved`;\n if (rolledBackA && rolledBackB) {\n await cleanupCreatedReplacement(resolutionStorage, replacement);\n }\n break;\n }\n\n affectedIds.push(idA, idB);\n message = `Both memories superseded by merged ${replacement.mergedId}`;\n break;\n }\n case \"both-valid\": {\n message = \"Pair marked as both-valid; cooldown applied\";\n break;\n }\n case \"needs-more-context\": {\n message = \"Deferred; no action taken, short cooldown applied\";\n break;\n }\n }\n\n if (!supersedeFailed) {\n resolvePair(memoryDir, pairId, verb);\n }\n log.info(\"[contradiction-resolution] pair=%s verb=%s affected=%d\", pairId, verb, affectedIds.length);\n return { pairId, verb, affectedIds, message };\n}\n\ntype MergeReplacement =\n | {\n ok: true;\n mergedId: string;\n sourceA: MemoryFile;\n sourceB: MemoryFile;\n created: boolean;\n }\n | {\n ok: false;\n message: string;\n };\n\nasync function prepareMergeReplacement(\n storage: StorageManager,\n pairId: string,\n idA: string,\n idB: string,\n options: ExecuteResolutionOptions,\n): Promise<MergeReplacement> {\n const sourceA = await storage.getMemoryById(idA);\n const sourceB = await storage.getMemoryById(idB);\n if (!sourceA || !sourceB) {\n return { ok: false, message: `Merge requires both source memories to exist; not resolving ${pairId}` };\n }\n\n const requestedMergedId = options.mergedMemoryId?.trim();\n if (requestedMergedId) {\n if (requestedMergedId === idA || requestedMergedId === idB) {\n return { ok: false, message: \"Merge replacement must be distinct from both source memories; not resolving\" };\n }\n const replacement = await storage.getMemoryById(requestedMergedId);\n if (!replacement) {\n return { ok: false, message: `Merged memory ${requestedMergedId} not found; not resolving` };\n }\n const replacementStatus = replacement.frontmatter.status ?? \"active\";\n if (replacementStatus !== \"active\") {\n return {\n ok: false,\n message: `Merged memory ${requestedMergedId} is ${replacementStatus}; not resolving`,\n };\n }\n return { ok: true, mergedId: requestedMergedId, sourceA, sourceB, created: false };\n }\n\n const mergedContent = options.mergedContent;\n if (typeof mergedContent !== \"string\" || mergedContent.trim().length === 0) {\n return {\n ok: false,\n message: \"Merge requires mergedMemoryId or mergedContent; no memories changed\",\n };\n }\n\n const category = options.mergedCategory ?? mergedMemoryCategory(sourceA, sourceB);\n let mergedId: string;\n try {\n mergedId = await storage.writeMemory(category, mergedContent, {\n actor: \"contradiction-resolution\",\n confidence: Math.min(sourceA.frontmatter.confidence ?? 0.8, sourceB.frontmatter.confidence ?? 0.8),\n tags: [\"contradiction-resolution\", \"merge\"],\n source: \"contradiction-resolution\",\n lineage: [idA, idB],\n derivedFrom: [idA, idB],\n derivedVia: \"merge\",\n });\n } catch (err) {\n log.warn(\n \"[contradiction-resolution] merged memory creation failed for %s: %s\",\n pairId,\n err instanceof Error ? err.message : err,\n );\n return { ok: false, message: `Merged memory could not be created; not resolving ${pairId}` };\n }\n const replacement = await storage.getMemoryById(mergedId);\n if (!replacement) {\n await cleanupMemoryId(storage, mergedId);\n return { ok: false, message: `Merged memory ${mergedId} could not be verified; not resolving` };\n }\n return { ok: true, mergedId, sourceA, sourceB, created: true };\n}\n\nfunction mergedMemoryCategory(sourceA: MemoryFile, sourceB: MemoryFile): MemoryCategory {\n return sourceA.frontmatter.category === sourceB.frontmatter.category\n ? sourceA.frontmatter.category\n : \"fact\";\n}\n\ntype KeepTargetValidation =\n | { ok: true }\n | { ok: false; message: string };\n\nasync function validateKeepTarget(\n storage: StorageManager,\n pairId: string,\n keepId: string,\n): Promise<KeepTargetValidation> {\n const target = await loadSourceSnapshot(storage, keepId);\n if (!target) {\n return { ok: false, message: `Kept memory ${keepId} not found; not resolving ${pairId}` };\n }\n\n const status = target.frontmatter.status ?? \"active\";\n if (status !== \"active\") {\n return { ok: false, message: `Kept memory ${keepId} is ${status}; not resolving ${pairId}` };\n }\n\n return { ok: true };\n}\n\nasync function loadSourceSnapshot(storage: StorageManager, memoryId: string): Promise<MemoryFile | null> {\n try {\n return await storage.getMemoryById(memoryId);\n } catch (err) {\n log.warn(\n \"[contradiction-resolution] source snapshot failed for %s: %s\",\n memoryId,\n err instanceof Error ? err.message : err,\n );\n return null;\n }\n}\n\nasync function restoreMemorySnapshot(\n storage: StorageManager,\n memory: MemoryFile,\n reasonCode = \"contradiction-resolution:merge-rollback\",\n): Promise<boolean> {\n try {\n const current = await storage.getMemoryById(memory.frontmatter.id);\n if (!current) return false;\n const restoredFrontmatter: Partial<MemoryFile[\"frontmatter\"]> = {\n ...memory.frontmatter,\n status: memory.frontmatter.status,\n supersededBy: memory.frontmatter.supersededBy,\n supersededAt: memory.frontmatter.supersededAt,\n };\n return await storage.writeMemoryFrontmatter(current, restoredFrontmatter, {\n actor: \"contradiction-resolution\",\n reasonCode,\n });\n } catch (err) {\n log.warn(\n \"[contradiction-resolution] rollback failed for %s: %s\",\n memory.frontmatter.id,\n err instanceof Error ? err.message : err,\n );\n return false;\n }\n}\n\nasync function cleanupCreatedReplacement(storage: StorageManager, replacement: Extract<MergeReplacement, { ok: true }>): Promise<void> {\n if (!replacement.created) return;\n await cleanupMemoryId(storage, replacement.mergedId);\n}\n\nasync function cleanupMemoryId(storage: StorageManager, memoryId: string): Promise<void> {\n try {\n const memory = await storage.getMemoryById(memoryId);\n const invalidated = await storage.invalidateMemory(memoryId);\n if (invalidated && memory?.frontmatter.category === \"fact\") {\n await storage.removeFactContentHashesForMemories([memory]);\n }\n } catch (err) {\n log.warn(\n \"[contradiction-resolution] cleanup failed for merged memory %s: %s\",\n memoryId,\n err instanceof Error ? err.message : err,\n );\n }\n}\n\nasync function supersedeSafe(\n storage: StorageManager,\n oldId: string,\n newId: string,\n reason: string,\n): Promise<boolean> {\n try {\n const result = await storage.supersedeMemory(oldId, newId, reason);\n if (result === false) {\n log.warn(\"[contradiction-resolution] supersede returned false for %s → %s\", oldId, newId);\n return false;\n }\n return true;\n } catch (err) {\n log.warn(\n \"[contradiction-resolution] supersede failed %s → %s: %s\",\n oldId,\n newId,\n err instanceof Error ? err.message : err,\n );\n return false;\n }\n}\n"],"mappings":"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","names":["replacement"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/connectors/codex-materialize-runner.ts"],"sourcesContent":["/**\n * codex-materialize-runner.ts — Thin I/O bridge for the Codex materializer.\n *\n * The pure rendering logic lives in {@link ./codex-materialize.js}. This file\n * is the place callers (consolidation hooks, CLI, session-end hook) go when\n * they want the whole \"load memories from storage → render → write\" flow.\n *\n * Kept deliberately small so #378 never has to reach into orchestrator.ts /\n * importance.ts — the two files Wave 1 agents are editing concurrently.\n */\n\nimport { existsSync } from \"node:fs\";\n\nimport { log } from \"../logger.js\";\nimport { resolveNamespaceChildRoot } from \"../namespaces/path.js\";\nimport { isSafeRouteNamespace } from \"../routing/engine.js\";\nimport { StorageManager } from \"../storage.js\";\nimport type { PluginConfig, MemoryFile } from \"../types.js\";\nimport {\n hasCodexMaterializeSentinel,\n materializeForNamespace,\n type MaterializeResult,\n type RolloutSummaryInput,\n} from \"./codex-materialize.js\";\n\n/** Options accepted by the shared post-consolidation materialize helper. */\nexport interface PostConsolidationMaterializeOptions {\n config: PluginConfig;\n namespace?: string;\n memories?: MemoryFile[];\n memoryDir?: string;\n codexHome?: string;\n rolloutSummaries?: RolloutSummaryInput[];\n now?: Date;\n}\n\n/** Options accepted by the runner. */\nexport interface RunMaterializeOptions {\n /** Remnic config — we only read the `codexMaterialize*` fields. */\n config: PluginConfig;\n /** Namespace to materialize. Overrides the config's `codexMaterializeNamespace`. */\n namespace?: string;\n /** Override the memory directory (defaults to `config.memoryDir`). */\n memoryDir?: string;\n /** Override `<codex_home>` (useful for tests). */\n codexHome?: string;\n /** Optional pre-loaded memories (bypasses disk read — used in tests). */\n memories?: MemoryFile[];\n /** Optional rollout summaries supplied by the caller. */\n rolloutSummaries?: RolloutSummaryInput[];\n /** Current time injection for deterministic runs. */\n now?: Date;\n /** Reason string — logged for observability. */\n reason?: \"consolidation\" | \"session_end\" | \"manual\" | \"cli\";\n}\n\n/**\n * Run the Codex materialization end-to-end. Returns `null` when the feature\n * is disabled in config or when the user hasn't opted in via the sentinel.\n * Never throws for \"expected\" skips; only throws on schema validation or I/O\n * errors that callers actually need to surface.\n */\nexport async function runCodexMaterialize(\n options: RunMaterializeOptions,\n): Promise<MaterializeResult | null> {\n const cfg = options.config;\n if (!cfg.codexMaterializeMemories) {\n log.debug(`[codex-materialize] skipped — codexMaterializeMemories=false`);\n return null;\n }\n\n // Per-trigger gate: session-end runs must honor codexMaterializeOnSessionEnd.\n // session-end.sh passes reason=\"session_end\"; when the user has turned off the\n // session-end trigger we short-circuit here without touching disk.\n if (options.reason === \"session_end\" && cfg.codexMaterializeOnSessionEnd === false) {\n log.debug(\n `[codex-materialize] skipped — session-end disabled via codexMaterializeOnSessionEnd=false`,\n );\n return null;\n }\n\n const namespace = resolveNamespace(options.namespace, cfg);\n const memoryDir = options.memoryDir ?? cfg.memoryDir;\n if (!memoryDir) {\n log.warn(`[codex-materialize] skipped — no memoryDir available`);\n return null;\n }\n\n let memories: MemoryFile[];\n if (options.memories) {\n memories = options.memories;\n } else {\n if (!hasCodexMaterializeSentinel(options.codexHome)) {\n return materializeForNamespace(namespace, {\n memories: [],\n codexHome: options.codexHome,\n maxSummaryTokens: cfg.codexMaterializeMaxSummaryTokens,\n rolloutRetentionDays: cfg.codexMaterializeRolloutRetentionDays,\n rolloutSummaries: options.rolloutSummaries,\n now: options.now,\n });\n }\n const nsDir = resolveNamespaceDir(memoryDir, namespace, cfg);\n const storage = new StorageManager(nsDir);\n memories = await storage.readAllMemories();\n }\n\n // Intentionally NOT catching here: per the JSDoc contract above,\n // schema-validation and I/O errors from `materializeForNamespace` must\n // surface to callers so they can exit non-zero (CLI) or log + recover\n // (consolidation post-hook, which has its own narrower try/catch).\n // Catching everything would make a broken MEMORY.md render look like a\n // successful skip, and invisible failures are strictly worse than loud\n // ones for a feature that writes to `~/.codex/memories`.\n const result = materializeForNamespace(namespace, {\n memories,\n codexHome: options.codexHome,\n maxSummaryTokens: cfg.codexMaterializeMaxSummaryTokens,\n rolloutRetentionDays: cfg.codexMaterializeRolloutRetentionDays,\n rolloutSummaries: options.rolloutSummaries,\n now: options.now,\n });\n if (options.reason) {\n log.debug(\n `[codex-materialize] ran reason=${options.reason} wrote=${result.wrote} files=${result.filesWritten.length}`,\n );\n }\n return result;\n}\n\n/**\n * Shared helper for post-consolidation materialize hooks.\n *\n * `materializeAfterSemanticConsolidation` and `materializeAfterCausalConsolidation`\n * used to be two nearly-identical copies of this logic; keeping the actual\n * body here means any future guard/logging change happens in one place.\n *\n * The only per-caller knob is `logPrefix`, which is used to tag the\n * non-fatal warning emitted when the materializer throws.\n */\nexport async function runPostConsolidationMaterialize(\n logPrefix: string,\n options: PostConsolidationMaterializeOptions,\n): Promise<MaterializeResult | null> {\n if (!options.config.codexMaterializeMemories) return null;\n if (!options.config.codexMaterializeOnConsolidation) return null;\n try {\n return await runCodexMaterialize({\n config: options.config,\n namespace: options.namespace,\n memories: options.memories,\n memoryDir: options.memoryDir,\n codexHome: options.codexHome,\n rolloutSummaries: options.rolloutSummaries,\n now: options.now,\n reason: \"consolidation\",\n });\n } catch (error) {\n log.warn(\n `${logPrefix} Codex materialize post-hook failed (non-fatal): ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n return null;\n }\n}\n\nfunction resolveNamespace(override: string | undefined, cfg: PluginConfig): string {\n const requested = (override ?? cfg.codexMaterializeNamespace ?? \"auto\").trim();\n const defaultNamespace = (cfg.defaultNamespace ?? \"\").trim();\n const namespace =\n requested.length === 0 || requested === \"auto\"\n ? (defaultNamespace.length > 0 ? defaultNamespace : \"default\")\n : requested;\n if (!isSafeRouteNamespace(namespace)) {\n throw new Error(`invalid materialize namespace: ${namespace}`);\n }\n return namespace;\n}\n\n/**\n * Resolve the on-disk storage root for a namespace, matching\n * `NamespaceStorageRouter` in `packages/remnic-core/src/namespaces/storage.ts`.\n *\n * Contract:\n * - When namespaces are disabled, every namespace maps to `memoryDir` itself.\n * - When namespaces are enabled, non-default namespaces always live under\n * `memoryDir/namespaces/<namespace>`.\n * - The default namespace prefers `memoryDir/namespaces/<defaultNamespace>`\n * when that directory already exists (migrated install); otherwise it\n * falls back to the legacy `memoryDir` root so materialization does not\n * silently switch directories out from under an existing install.\n */\nfunction resolveNamespaceDir(\n memoryDir: string,\n namespace: string,\n cfg: PluginConfig,\n): string {\n if (!cfg.namespacesEnabled) return memoryDir;\n\n const defaultNamespace = (cfg.defaultNamespace ?? \"\").trim();\n const ns = (namespace || defaultNamespace || \"default\").trim();\n if (!isSafeRouteNamespace(ns)) {\n throw new Error(`invalid materialize namespace: ${ns}`);\n }\n const namespacedRoot = resolveNamespaceChildRoot(memoryDir, ns, \"materialize namespace path\");\n\n if (ns === defaultNamespace) {\n return existsSync(namespacedRoot) ? namespacedRoot : memoryDir;\n }\n return namespacedRoot;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAWA,SAAS,kBAAkB;AAmD3B,eAAsB,oBACpB,SACmC;AACnC,QAAM,MAAM,QAAQ;AACpB,MAAI,CAAC,IAAI,0BAA0B;AACjC,QAAI,MAAM,mEAA8D;AACxE,WAAO;AAAA,EACT;AAKA,MAAI,QAAQ,WAAW,iBAAiB,IAAI,iCAAiC,OAAO;AAClF,QAAI;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,iBAAiB,QAAQ,WAAW,GAAG;AACzD,QAAM,YAAY,QAAQ,aAAa,IAAI;AAC3C,MAAI,CAAC,WAAW;AACd,QAAI,KAAK,2DAAsD;AAC/D,WAAO;AAAA,EACT;AAEA,MAAI;AACJ,MAAI,QAAQ,UAAU;AACpB,eAAW,QAAQ;AAAA,EACrB,OAAO;AACL,QAAI,CAAC,4BAA4B,QAAQ,SAAS,GAAG;AACnD,aAAO,wBAAwB,WAAW;AAAA,QACxC,UAAU,CAAC;AAAA,QACX,WAAW,QAAQ;AAAA,QACnB,kBAAkB,IAAI;AAAA,QACtB,sBAAsB,IAAI;AAAA,QAC1B,kBAAkB,QAAQ;AAAA,QAC1B,KAAK,QAAQ;AAAA,MACf,CAAC;AAAA,IACH;AACA,UAAM,QAAQ,oBAAoB,WAAW,WAAW,GAAG;AAC3D,UAAM,UAAU,IAAI,eAAe,KAAK;AACxC,eAAW,MAAM,QAAQ,gBAAgB;AAAA,EAC3C;AASA,QAAM,SAAS,wBAAwB,WAAW;AAAA,IAChD;AAAA,IACA,WAAW,QAAQ;AAAA,IACnB,kBAAkB,IAAI;AAAA,IACtB,sBAAsB,IAAI;AAAA,IAC1B,kBAAkB,QAAQ;AAAA,IAC1B,KAAK,QAAQ;AAAA,EACf,CAAC;AACD,MAAI,QAAQ,QAAQ;AAClB,QAAI;AAAA,MACF,kCAAkC,QAAQ,MAAM,UAAU,OAAO,KAAK,UAAU,OAAO,aAAa,MAAM;AAAA,IAC5G;AAAA,EACF;AACA,SAAO;AACT;AAYA,eAAsB,gCACpB,WACA,SACmC;AACnC,MAAI,CAAC,QAAQ,OAAO,yBAA0B,QAAO;AACrD,MAAI,CAAC,QAAQ,OAAO,gCAAiC,QAAO;AAC5D,MAAI;AACF,WAAO,MAAM,oBAAoB;AAAA,MAC/B,QAAQ,QAAQ;AAAA,MAChB,WAAW,QAAQ;AAAA,MACnB,UAAU,QAAQ;AAAA,MAClB,WAAW,QAAQ;AAAA,MACnB,WAAW,QAAQ;AAAA,MACnB,kBAAkB,QAAQ;AAAA,MAC1B,KAAK,QAAQ;AAAA,MACb,QAAQ;AAAA,IACV,CAAC;AAAA,EACH,SAAS,OAAO;AACd,QAAI;AAAA,MACF,GAAG,SAAS,oDACV,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CACvD;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;AAEA,SAAS,iBAAiB,UAA8B,KAA2B;AACjF,QAAM,aAAa,YAAY,IAAI,6BAA6B,QAAQ,KAAK;AAC7E,QAAM,oBAAoB,IAAI,oBAAoB,IAAI,KAAK;AAC3D,QAAM,YACJ,UAAU,WAAW,KAAK,cAAc,SACnC,iBAAiB,SAAS,IAAI,mBAAmB,YAClD;AACN,MAAI,CAAC,qBAAqB,SAAS,GAAG;AACpC,UAAM,IAAI,MAAM,kCAAkC,SAAS,EAAE;AAAA,EAC/D;AACA,SAAO;AACT;AAeA,SAAS,oBACP,WACA,WACA,KACQ;AACR,MAAI,CAAC,IAAI,kBAAmB,QAAO;AAEnC,QAAM,oBAAoB,IAAI,oBAAoB,IAAI,KAAK;AAC3D,QAAM,MAAM,aAAa,oBAAoB,WAAW,KAAK;AAC7D,MAAI,CAAC,qBAAqB,EAAE,GAAG;AAC7B,UAAM,IAAI,MAAM,kCAAkC,EAAE,EAAE;AAAA,EACxD;AACA,QAAM,iBAAiB,0BAA0B,WAAW,IAAI,4BAA4B;AAE5F,MAAI,OAAO,kBAAkB;AAC3B,WAAO,WAAW,cAAc,IAAI,iBAAiB;AAAA,EACvD;AACA,SAAO;AACT;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/transcript.ts"],"sourcesContent":["import { appendFile, mkdir, readdir, readFile, stat, unlink, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { log } from \"./logger.js\";\nimport type { TranscriptEntry, Checkpoint, PluginConfig } from \"./types.js\";\nimport { analyzeSessionIntegrity, type SessionIntegrityReport } from \"./session-integrity.js\";\nimport {\n encodeStoragePathSegment,\n encodeStoragePathSegmentWithHash,\n isSafeLegacyPathSegment,\n resolveSafeStoragePath,\n storagePathHash,\n} from \"./storage-paths.js\";\n\ntype DirectorySessionStatus = \"missing\" | \"empty\" | \"matches\" | \"occupied\";\ntype DirectoryOwnershipCacheEntry = {\n status: \"empty\" | \"matches\";\n fileSizes: Map<string, number>;\n};\n\nfunction legacyTranscriptDirFor(\n channelType: string,\n channelId: string,\n encodedDir: string,\n): string | undefined {\n if (!isSafeLegacyPathSegment(channelType) || !isSafeLegacyPathSegment(channelId)) {\n return undefined;\n }\n const legacyDir = path.join(channelType, channelId);\n return legacyDir === encodedDir ? undefined : legacyDir;\n}\n\n/**\n * Manages conversation transcript storage, checkpointing, and recall formatting.\n *\n * Transcripts are stored as JSONL files in a hierarchical structure:\n * transcripts/{channelType}/{channelId}.jsonl\n *\n * Channel types are extracted from sessionKey (discord, slack, cron, main, etc.)\n * Checkpoints are used to preserve conversation context across compaction events.\n */\nexport class TranscriptManager {\n private transcriptsDir: string;\n private checkpointPath: string;\n private stateDir: string;\n private toolUsageDir: string;\n private config: PluginConfig;\n private sessionFootprintCache = new Map<\n string,\n { totalBytes: number; fileBytes: Map<string, number>; fileSizes: Map<string, number> }\n >();\n private directoryOwnershipCache = new Map<string, DirectoryOwnershipCacheEntry>();\n\n /** Default checkpoint TTL in hours */\n private static readonly DEFAULT_CHECKPOINT_TTL_HOURS = 24;\n /** Approximate characters per token for rough estimation */\n private static readonly CHARS_PER_TOKEN = 4;\n\n constructor(config: PluginConfig) {\n this.config = config;\n this.transcriptsDir = path.join(config.memoryDir, \"transcripts\");\n this.stateDir = path.join(config.memoryDir, \"state\");\n this.checkpointPath = path.join(this.stateDir, \"checkpoint.json\");\n this.toolUsageDir = path.join(this.stateDir, \"tool-usage\");\n }\n\n /**\n * Parse a sessionKey to extract channel type and ID.\n *\n * SessionKey patterns:\n * - agent:<agent-id>:main → type=\"main\", id=\"default\"\n * - agent:<agent-id>:discord:channel:<channel-id> → type=\"discord\", id=\"<channel-id>\"\n * - agent:<agent-id>:cron:<job-id> → type=\"cron\", id=\"<job-id>\"\n * - agent:<agent-id>:slack:channel:<channel-id> → type=\"slack\", id=\"<channel-id>\"\n *\n * @returns Object with raw channel identifiers and encoded storage path pieces.\n */\n getTranscriptPath(sessionKey: string): {\n dir: string;\n file: string;\n channelType: string;\n channelId: string;\n alternateDir: string;\n legacyDir?: string;\n } {\n const parts = sessionKey.split(\":\");\n\n // Default fallback\n let channelType = \"other\";\n let channelId = \"default\";\n\n if (parts.length >= 3) {\n // parts[0] = \"agent\", parts[1] = agent name, parts[2] = channel type\n channelType = parts[2];\n\n // Extract channel ID based on pattern\n if (channelType === \"main\") {\n channelId = \"default\";\n } else if (channelType === \"discord\" && parts.length >= 5 && parts[3] === \"channel\") {\n channelId = parts[4];\n } else if (channelType === \"slack\" && parts.length >= 5 && parts[3] === \"channel\") {\n channelId = parts[4];\n } else if (channelType === \"cron\" && parts.length >= 4) {\n channelId = parts[3];\n } else if (parts.length >= 4) {\n // For other types, use the 4th part as ID if available\n channelId = parts[3];\n }\n }\n\n // Daily rotation: transcripts/{channelType}/{channelId}/YYYY-MM-DD.jsonl\n const today = new Date().toISOString().slice(0, 10);\n const dir = path.join(\n encodeStoragePathSegment(channelType),\n encodeStoragePathSegment(channelId),\n );\n const alternateDir = path.join(\n encodeStoragePathSegmentWithHash(channelType),\n `${encodeStoragePathSegmentWithHash(channelId)}--session-${storagePathHash(sessionKey)}`,\n );\n return {\n dir,\n file: `${today}.jsonl`,\n channelType,\n channelId,\n alternateDir,\n legacyDir: legacyTranscriptDirFor(channelType, channelId, dir),\n };\n }\n\n /**\n * Initialize the transcript manager by ensuring directories exist.\n */\n async initialize(): Promise<void> {\n await mkdir(this.transcriptsDir, { recursive: true });\n await mkdir(this.stateDir, { recursive: true });\n await mkdir(this.toolUsageDir, { recursive: true });\n log.info(\"transcript manager initialized\");\n }\n\n /**\n * Best-effort list of sessionKeys that have transcript files on disk.\n * This is used by cron-style tooling (hourly summaries, conversation indexing)\n * to iterate across \"active\" sessions.\n */\n async listSessionKeys(): Promise<string[]> {\n const transcriptDir = this.transcriptsDir;\n const sessionKeys = new Set<string>();\n\n try {\n const typeEntries = await readdir(transcriptDir, { withFileTypes: true });\n for (const typeEnt of typeEntries) {\n if (!typeEnt.isDirectory()) continue;\n const typeDir = path.join(transcriptDir, typeEnt.name);\n const idEntries = await readdir(typeDir, { withFileTypes: true });\n for (const idEnt of idEntries) {\n if (!idEnt.isDirectory()) continue;\n const chanDir = path.join(typeDir, idEnt.name);\n const files = (await readdir(chanDir)).filter((f) => f.endsWith(\".jsonl\")).sort();\n const last = files[files.length - 1];\n if (!last) continue;\n try {\n const raw = await readFile(path.join(chanDir, last), \"utf-8\");\n const firstLine = raw.split(\"\\n\").find((l) => l.trim().length > 0);\n if (!firstLine) continue;\n const entry = JSON.parse(firstLine) as TranscriptEntry;\n if (typeof entry.sessionKey === \"string\" && entry.sessionKey.length > 0) {\n sessionKeys.add(entry.sessionKey);\n }\n } catch {\n // ignore\n }\n }\n }\n } catch {\n return [];\n }\n\n return Array.from(sessionKeys);\n }\n\n getToolUsagePath(sessionKey: string): {\n dir: string;\n file: string;\n alternateDir: string;\n legacyDir?: string;\n } {\n const p = this.getTranscriptPath(sessionKey);\n return { dir: p.dir, file: p.file, alternateDir: p.alternateDir, legacyDir: p.legacyDir };\n }\n\n private async selectStorageDirForWrite(\n root: string,\n dir: string,\n legacyDir?: string,\n sessionKey?: string,\n alternateDir?: string,\n ): Promise<{ dir: string; channelDir: string }> {\n const channelDir = await resolveSafeStoragePath(root, dir);\n const encodedStatus = await this.directorySessionStatus(root, dir, sessionKey);\n if (encodedStatus === \"matches\" || encodedStatus === \"empty\") return { dir, channelDir };\n\n if (legacyDir) {\n const legacyChannelDir = await resolveSafeStoragePath(root, legacyDir);\n if ((await this.directorySessionStatus(root, legacyDir, sessionKey)) === \"matches\") {\n return { dir: legacyDir, channelDir: legacyChannelDir };\n }\n }\n\n if (encodedStatus === \"missing\") return { dir, channelDir };\n\n if (alternateDir) {\n const alternateChannelDir = await resolveSafeStoragePath(root, alternateDir);\n const alternateStatus = await this.directorySessionStatus(root, alternateDir, sessionKey);\n if (\n alternateStatus === \"missing\" ||\n alternateStatus === \"empty\" ||\n alternateStatus === \"matches\"\n ) {\n return { dir: alternateDir, channelDir: alternateChannelDir };\n }\n }\n\n throw new Error(`transcript storage path collision for session: ${sessionKey ?? \"(unknown)\"}`);\n }\n\n private async directorySessionStatus(\n root: string,\n dir: string,\n sessionKey?: string,\n ): Promise<DirectorySessionStatus> {\n let channelDir: string;\n try {\n channelDir = await resolveSafeStoragePath(root, dir);\n if (!(await stat(channelDir)).isDirectory()) return \"occupied\";\n } catch (err) {\n const code =\n err && typeof err === \"object\" && \"code\" in err\n ? (err as { code?: string }).code\n : undefined;\n if (code === \"ENOENT\") return \"missing\";\n throw err;\n }\n\n let names: string[];\n try {\n names = (await readdir(channelDir)).filter((file) => file.endsWith(\".jsonl\"));\n } catch {\n return \"occupied\";\n }\n\n const fileSizes = await this.directoryJsonlFileSizes(root, dir, names);\n if (!fileSizes) return \"occupied\";\n\n if (!sessionKey) return \"matches\";\n const cacheKey = this.directoryOwnershipCacheKey(root, dir, sessionKey);\n const cached = this.directoryOwnershipCache.get(cacheKey);\n if (cached && this.sameFileSizes(cached.fileSizes, fileSizes)) {\n return cached.status;\n }\n\n let hasEntries = false;\n let hasMatchingEntry = false;\n\n for (const name of names) {\n const filePath = await resolveSafeStoragePath(root, dir, name).catch(() => null);\n if (filePath === null) return \"occupied\";\n try {\n const raw = await readFile(filePath, \"utf-8\");\n for (const line of raw.split(\"\\n\")) {\n if (!line.trim()) continue;\n hasEntries = true;\n try {\n const obj = JSON.parse(line) as { sessionKey?: string };\n if (obj.sessionKey === sessionKey) {\n hasMatchingEntry = true;\n } else {\n return \"occupied\";\n }\n } catch {\n return \"occupied\";\n }\n }\n } catch {\n return \"occupied\";\n }\n }\n\n const status = hasMatchingEntry ? \"matches\" : hasEntries ? \"occupied\" : \"empty\";\n if (status === \"matches\" || status === \"empty\") {\n this.directoryOwnershipCache.set(cacheKey, { status, fileSizes });\n }\n return status;\n }\n\n private directoryOwnershipCacheKey(root: string, dir: string, sessionKey: string): string {\n return `${path.resolve(root)}\\0${dir}\\0${sessionKey}`;\n }\n\n private sameFileSizes(left: Map<string, number>, right: Map<string, number>): boolean {\n if (left.size !== right.size) return false;\n for (const [name, size] of left) {\n if (right.get(name) !== size) return false;\n }\n return true;\n }\n\n private async directoryJsonlFileSizes(\n root: string,\n dir: string,\n names: string[],\n ): Promise<Map<string, number> | null> {\n const fileSizes = new Map<string, number>();\n for (const name of names) {\n const filePath = await resolveSafeStoragePath(root, dir, name).catch(() => null);\n if (filePath === null) return null;\n const fileInfo = await stat(filePath).catch(() => null);\n if (!fileInfo?.isFile()) return null;\n fileSizes.set(name, Math.max(0, fileInfo.size));\n }\n return fileSizes;\n }\n\n private async rememberDirectoryOwnership(\n root: string,\n dir: string,\n sessionKey: string,\n ): Promise<void> {\n try {\n const channelDir = await resolveSafeStoragePath(root, dir);\n const names = (await readdir(channelDir)).filter((file) => file.endsWith(\".jsonl\"));\n const fileSizes = await this.directoryJsonlFileSizes(root, dir, names);\n if (!fileSizes) return;\n this.directoryOwnershipCache.set(\n this.directoryOwnershipCacheKey(root, dir, sessionKey),\n { status: \"matches\", fileSizes },\n );\n } catch {\n // Cache refresh is best-effort; write path correctness does not depend on it.\n }\n }\n\n private async getSessionStorageFiles(\n root: string,\n dir: string,\n legacyDir?: string,\n alternateDir?: string,\n ): Promise<Array<{ cacheKey: string; name: string; path: string }>> {\n const files: Array<{ cacheKey: string; name: string; path: string }> = [];\n const seenDirs = new Set<string>();\n\n for (const candidateDir of [dir, alternateDir, legacyDir]) {\n if (!candidateDir || seenDirs.has(candidateDir)) continue;\n seenDirs.add(candidateDir);\n\n let channelDir: string;\n try {\n channelDir = await resolveSafeStoragePath(root, candidateDir);\n } catch {\n continue;\n }\n\n let names: string[];\n try {\n names = (await readdir(channelDir)).filter((file) => file.endsWith(\".jsonl\")).sort();\n } catch {\n continue;\n }\n\n for (const name of names) {\n const filePath = await resolveSafeStoragePath(root, candidateDir, name).catch(() => null);\n if (filePath === null) continue;\n files.push({\n cacheKey: path.join(candidateDir, name),\n name,\n path: filePath,\n });\n }\n }\n\n return files.sort((a, b) => a.cacheKey.localeCompare(b.cacheKey));\n }\n\n async appendToolUse(entry: { timestamp: string; sessionKey: string; tool: string }): Promise<void> {\n const { dir, file, alternateDir, legacyDir } = this.getToolUsagePath(entry.sessionKey);\n const { dir: writeDir, channelDir } = await this.selectStorageDirForWrite(\n this.toolUsageDir,\n dir,\n legacyDir,\n entry.sessionKey,\n alternateDir,\n );\n await mkdir(channelDir, { recursive: true });\n const filePath = await resolveSafeStoragePath(this.toolUsageDir, writeDir, file);\n await appendFile(filePath, JSON.stringify(entry) + \"\\n\", \"utf-8\");\n await this.rememberDirectoryOwnership(this.toolUsageDir, writeDir, entry.sessionKey);\n }\n\n async readToolUse(\n sessionKey: string,\n startTime: Date,\n endTime: Date,\n ): Promise<Array<{ timestamp: string; sessionKey: string; tool: string }>> {\n const { dir, alternateDir, legacyDir } = this.getToolUsagePath(sessionKey);\n try {\n const files = await this.getSessionStorageFiles(this.toolUsageDir, dir, legacyDir, alternateDir);\n const out: Array<{ timestamp: string; sessionKey: string; tool: string }> = [];\n for (const file of files) {\n const raw = await readFile(file.path, \"utf-8\");\n for (const line of raw.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n const obj = JSON.parse(line) as any;\n const ts = new Date(String(obj.timestamp ?? \"\")).getTime();\n if (!Number.isFinite(ts)) continue;\n if (ts >= startTime.getTime() && ts < endTime.getTime()) {\n if (typeof obj.tool === \"string\" && typeof obj.sessionKey === \"string\") {\n if (obj.sessionKey === sessionKey) {\n out.push({ timestamp: obj.timestamp, sessionKey: obj.sessionKey, tool: obj.tool });\n }\n }\n }\n } catch {\n // ignore\n }\n }\n }\n return out;\n } catch {\n return [];\n }\n }\n\n async estimateSessionFootprint(sessionKey: string): Promise<{ bytes: number; tokens: number }> {\n const { dir, alternateDir, legacyDir } = this.getTranscriptPath(sessionKey);\n let bytes = 0;\n\n try {\n const files = await this.getSessionStorageFiles(this.transcriptsDir, dir, legacyDir, alternateDir);\n const cached = this.sessionFootprintCache.get(sessionKey);\n if (!cached) {\n const fileBytes = new Map<string, number>();\n const fileSizes = new Map<string, number>();\n for (const file of files) {\n try {\n const fileInfo = await stat(file.path);\n const sessionBytes = await this.estimateSessionBytesInFile(\n file.path,\n sessionKey,\n );\n fileBytes.set(file.cacheKey, sessionBytes);\n fileSizes.set(file.cacheKey, Math.max(0, fileInfo.size));\n bytes += sessionBytes;\n } catch {\n // fail-open\n }\n }\n this.sessionFootprintCache.set(sessionKey, { totalBytes: bytes, fileBytes, fileSizes });\n } else {\n bytes = cached.totalBytes;\n const seen = new Set(files.map((file) => file.cacheKey));\n\n // Drop removed files from the cached total.\n for (const [cachedFile, cachedSessionBytes] of cached.fileBytes.entries()) {\n if (!seen.has(cachedFile)) {\n bytes -= cachedSessionBytes;\n cached.fileBytes.delete(cachedFile);\n cached.fileSizes.delete(cachedFile);\n }\n }\n\n // Read only newly discovered files.\n for (const file of files) {\n if (cached.fileBytes.has(file.cacheKey)) continue;\n try {\n const fileInfo = await stat(file.path);\n const sessionBytes = await this.estimateSessionBytesInFile(file.path, sessionKey);\n cached.fileBytes.set(file.cacheKey, sessionBytes);\n cached.fileSizes.set(file.cacheKey, Math.max(0, fileInfo.size));\n bytes += sessionBytes;\n } catch {\n // fail-open\n }\n }\n\n // Recompute any shard whose file size changed. A session can have both\n // encoded and legacy directories during migration, so path ordering does\n // not reliably identify the file that can grow.\n for (const file of files) {\n try {\n const fileInfo = await stat(file.path);\n const size = Math.max(0, fileInfo.size);\n const previousSessionBytes = cached.fileBytes.get(file.cacheKey) ?? 0;\n const previousSize = cached.fileSizes.get(file.cacheKey) ?? -1;\n if (size !== previousSize) {\n const sessionBytes = await this.estimateSessionBytesInFile(file.path, sessionKey);\n cached.fileBytes.set(file.cacheKey, sessionBytes);\n cached.fileSizes.set(file.cacheKey, size);\n bytes += sessionBytes - previousSessionBytes;\n }\n } catch {\n // fail-open\n }\n }\n\n if (bytes < 0) bytes = 0;\n cached.totalBytes = bytes;\n }\n } catch {\n // fail-open\n this.sessionFootprintCache.delete(sessionKey);\n }\n\n return {\n bytes,\n tokens: Math.floor(bytes / TranscriptManager.CHARS_PER_TOKEN),\n };\n }\n\n private async estimateSessionBytesInFile(filePath: string, sessionKey: string): Promise<number> {\n try {\n const raw = await readFile(filePath, \"utf-8\");\n let total = 0;\n for (const line of raw.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n const parsed = JSON.parse(line) as { sessionKey?: string };\n if (parsed.sessionKey === sessionKey) {\n total += Buffer.byteLength(`${line}\\n`, \"utf-8\");\n }\n } catch {\n // fail-open for malformed lines\n }\n }\n return total;\n } catch {\n return 0;\n }\n }\n\n /**\n * Check if a file is a legacy flat transcript file (YYYY-MM-DD.jsonl format).\n */\n private isLegacyTranscriptFile(filename: string): boolean {\n return /^\\d{4}-\\d{2}-\\d{2}\\.jsonl$/.test(filename);\n }\n\n /**\n * Append a turn to the appropriate transcript file.\n * Files are stored hierarchically: transcripts/{channelType}/{channelId}.jsonl\n *\n * Skips channel types in config.transcriptSkipChannelTypes (e.g., \"cron\").\n */\n async append(entry: TranscriptEntry): Promise<void> {\n try {\n const { dir, file, channelType, alternateDir, legacyDir } = this.getTranscriptPath(entry.sessionKey);\n\n // Skip if this channel type is in the skip list\n if (this.config.transcriptSkipChannelTypes.includes(channelType)) {\n return;\n }\n\n const { dir: writeDir, channelDir } = await this.selectStorageDirForWrite(\n this.transcriptsDir,\n dir,\n legacyDir,\n entry.sessionKey,\n alternateDir,\n );\n const filePath = await resolveSafeStoragePath(this.transcriptsDir, writeDir, file);\n\n // Ensure channel directory exists\n await mkdir(channelDir, { recursive: true });\n\n const line = JSON.stringify(entry) + \"\\n\";\n await appendFile(filePath, line, \"utf-8\");\n await this.rememberDirectoryOwnership(this.transcriptsDir, writeDir, entry.sessionKey);\n log.debug(`appended transcript entry for ${entry.sessionKey}: ${entry.turnId}`);\n } catch (err) {\n log.error(\"failed to append transcript entry:\", err);\n throw err;\n }\n }\n\n /**\n * Get all transcript files from the hierarchical directory structure.\n * Recursively finds all .jsonl files in transcripts/{channelType}/{channelId}/ subdirectories.\n */\n private async getAllTranscriptFiles(): Promise<string[]> {\n const files: string[] = [];\n\n try {\n const entries = await readdir(this.transcriptsDir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (entry.isDirectory()) {\n // This is a channel type directory (discord, slack, cron, main, etc.)\n const channelTypeDir = path.join(this.transcriptsDir, entry.name);\n try {\n const channelTypeEntries = await readdir(channelTypeDir, { withFileTypes: true });\n\n for (const channelTypeEntry of channelTypeEntries) {\n if (channelTypeEntry.isDirectory()) {\n // This is a channel ID directory - contains daily transcript files\n const channelDir = path.join(channelTypeDir, channelTypeEntry.name);\n try {\n const channelFiles = await readdir(channelDir);\n for (const file of channelFiles) {\n if (file.endsWith(\".jsonl\")) {\n files.push(path.join(entry.name, channelTypeEntry.name, file));\n }\n }\n } catch {\n // Skip unreadable directories\n }\n } else if (channelTypeEntry.isFile() && channelTypeEntry.name.endsWith(\".jsonl\")) {\n // Legacy: channel type dir contains .jsonl files directly\n files.push(path.join(entry.name, channelTypeEntry.name));\n }\n }\n } catch {\n // Skip unreadable directories\n }\n } else if (entry.isFile() && entry.name.endsWith(\".jsonl\")) {\n // Legacy flat file - still include for backward compatibility\n files.push(entry.name);\n }\n }\n } catch {\n // Directory doesn't exist or is unreadable\n }\n\n return files;\n }\n\n /**\n * Read transcript entries for a date range.\n * Returns entries within the time range, optionally filtered by sessionKey.\n * Reads from all channel subdirectories in the hierarchical structure.\n */\n async readRange(startTime: string, endTime: string, sessionKey?: string): Promise<TranscriptEntry[]> {\n const start = new Date(startTime);\n const end = new Date(endTime);\n const entries: TranscriptEntry[] = [];\n\n try {\n // Get all transcript files from the hierarchical structure\n const transcriptFiles = await this.getAllTranscriptFiles();\n\n // Read each relevant file\n for (const relativePath of transcriptFiles) {\n const filePath = path.join(this.transcriptsDir, relativePath);\n try {\n const content = await readFile(filePath, \"utf-8\");\n const lines = content.trim().split(\"\\n\").filter(Boolean);\n\n for (const line of lines) {\n try {\n const entry = JSON.parse(line) as TranscriptEntry;\n const entryTime = new Date(entry.timestamp);\n\n // Check if entry is within time range\n if (entryTime >= start && entryTime <= end) {\n // Filter by sessionKey if provided\n if (!sessionKey || entry.sessionKey === sessionKey) {\n entries.push(entry);\n }\n }\n } catch {\n // Skip malformed lines\n log.debug(`skipped malformed transcript line in ${relativePath}`);\n }\n }\n } catch {\n // File doesn't exist or is unreadable - skip\n }\n }\n\n // Sort by timestamp\n entries.sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());\n\n log.debug(`read ${entries.length} transcript entries from ${transcriptFiles.length} file(s)`);\n return entries;\n } catch (err) {\n log.error(\"failed to read transcript range:\", err);\n return [];\n }\n }\n\n /**\n * Read the last N hours of transcript.\n *\n * Fast path: when sessionKey is given, reads only the 1-2 daily files for that\n * specific channel instead of scanning all 95+ transcript files across all channels.\n */\n async readRecent(hours: number, sessionKey?: string): Promise<TranscriptEntry[]> {\n const end = new Date();\n const start = new Date(end.getTime() - hours * 60 * 60 * 1000);\n\n if (sessionKey) {\n return this.readRecentForSession(start, end, sessionKey);\n }\n return this.readRange(start.toISOString(), end.toISOString(), undefined);\n }\n\n /**\n * Optimized read for a specific session: only looks in that session's channel\n * directory and only reads files whose date falls within the lookback window.\n */\n private async readRecentForSession(\n start: Date,\n end: Date,\n sessionKey: string,\n ): Promise<TranscriptEntry[]> {\n const { dir, alternateDir, legacyDir } = this.getTranscriptPath(sessionKey);\n\n // Build set of date strings that overlap with [start, end].\n // Always include end's date to handle midnight-crossing lookbacks\n // (e.g. start=23:30 yesterday, end=00:30 today).\n const dateStrings = new Set<string>();\n const cursor = new Date(start);\n while (cursor <= end) {\n dateStrings.add(cursor.toISOString().slice(0, 10));\n cursor.setDate(cursor.getDate() + 1);\n }\n dateStrings.add(end.toISOString().slice(0, 10));\n\n const entries: TranscriptEntry[] = [];\n const files = await this.getSessionStorageFiles(this.transcriptsDir, dir, legacyDir, alternateDir);\n\n for (const file of files) {\n // Only read files whose date is within the window\n const dateStr = file.name.slice(0, 10);\n if (!dateStrings.has(dateStr)) continue;\n\n try {\n const content = await readFile(file.path, \"utf-8\");\n for (const line of content.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n const entry = JSON.parse(line) as TranscriptEntry;\n const ts = new Date(entry.timestamp);\n if (ts >= start && ts <= end && entry.sessionKey === sessionKey) {\n entries.push(entry);\n }\n } catch {\n // skip malformed line\n }\n }\n } catch {\n // skip unreadable file\n }\n }\n\n entries.sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());\n log.debug(`readRecentForSession: ${entries.length} entries from ${files.length} file(s) in ${dir}`);\n return entries;\n }\n\n /**\n * Cleanup old transcript entries that are older than retentionDays.\n * For hierarchical structure, reads each file and rewrites without old entries.\n * Legacy flat files are deleted if their date is older than retentionDays.\n * Returns the number of files processed (cleaned or deleted).\n */\n async cleanup(retentionDays: number): Promise<number> {\n if (retentionDays <= 0) {\n log.warn(\"cleanup called with invalid retentionDays:\", retentionDays);\n return 0;\n }\n\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - retentionDays);\n cutoff.setHours(0, 0, 0, 0);\n\n let processed = 0;\n\n try {\n const entries = await readdir(this.transcriptsDir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (entry.isDirectory()) {\n // This is a channel type directory (discord, slack, cron, main, etc.)\n const channelTypeDir = path.join(this.transcriptsDir, entry.name);\n try {\n const channelTypeEntries = await readdir(channelTypeDir, { withFileTypes: true });\n\n for (const channelTypeEntry of channelTypeEntries) {\n if (channelTypeEntry.isDirectory()) {\n // This is a channel ID directory - contains daily transcript files\n const channelDir = path.join(channelTypeDir, channelTypeEntry.name);\n try {\n const channelFiles = await readdir(channelDir);\n for (const file of channelFiles) {\n if (!file.endsWith(\".jsonl\")) continue;\n\n const filePath = path.join(channelDir, file);\n\n // Check if file is a daily transcript file (YYYY-MM-DD.jsonl)\n if (this.isLegacyTranscriptFile(file)) {\n const dateStr = file.slice(0, 10);\n const fileDate = new Date(dateStr);\n\n if (!isNaN(fileDate.getTime()) && fileDate < cutoff) {\n try {\n await unlink(filePath);\n processed++;\n log.debug(`deleted old daily transcript file: ${entry.name}/${channelTypeEntry.name}/${file}`);\n } catch (err) {\n log.error(`failed to delete transcript file ${filePath}:`, err);\n }\n }\n } else {\n // Legacy file in new structure - clean up old entries\n const cleaned = await this.cleanupTranscriptFile(filePath, cutoff);\n if (cleaned) {\n processed++;\n }\n }\n }\n } catch (err) {\n log.debug(`failed to process channel directory ${entry.name}/${channelTypeEntry.name}:`, err);\n }\n } else if (channelTypeEntry.isFile() && channelTypeEntry.name.endsWith(\".jsonl\")) {\n // Legacy: channel type dir contains .jsonl files directly\n const filePath = path.join(channelTypeDir, channelTypeEntry.name);\n const cleaned = await this.cleanupTranscriptFile(filePath, cutoff);\n if (cleaned) {\n processed++;\n }\n }\n }\n } catch (err) {\n log.debug(`failed to process channel type directory ${entry.name}:`, err);\n }\n } else if (entry.isFile() && entry.name.endsWith(\".jsonl\")) {\n // Handle legacy flat files - delete if older than retentionDays\n if (this.isLegacyTranscriptFile(entry.name)) {\n const dateStr = entry.name.slice(0, 10);\n const fileDate = new Date(dateStr);\n\n if (!isNaN(fileDate.getTime()) && fileDate < cutoff) {\n const filePath = path.join(this.transcriptsDir, entry.name);\n try {\n await unlink(filePath);\n processed++;\n log.debug(`deleted old legacy transcript file: ${entry.name}`);\n } catch (err) {\n log.error(`failed to delete legacy transcript file ${entry.name}:`, err);\n }\n }\n }\n }\n }\n\n if (processed > 0) {\n log.info(`cleaned up ${processed} transcript file(s) older than ${retentionDays} days`);\n }\n\n return processed;\n } catch (err) {\n log.error(\"failed to cleanup old transcripts:\", err);\n return 0;\n }\n }\n\n /**\n * Clean up old entries from a single transcript file.\n * Reads the file, filters out entries older than cutoff, and rewrites if needed.\n * Returns true if the file was processed (cleaned or deleted).\n */\n private async cleanupTranscriptFile(filePath: string, cutoff: Date): Promise<boolean> {\n try {\n const content = await readFile(filePath, \"utf-8\");\n const lines = content.trim().split(\"\\n\").filter(Boolean);\n\n const validLines: string[] = [];\n let hasOldEntries = false;\n\n for (const line of lines) {\n try {\n const entry = JSON.parse(line) as TranscriptEntry;\n const entryTime = new Date(entry.timestamp);\n\n if (entryTime >= cutoff) {\n validLines.push(line);\n } else {\n hasOldEntries = true;\n }\n } catch {\n // Keep malformed lines to avoid data loss\n validLines.push(line);\n }\n }\n\n if (validLines.length === 0) {\n // No valid entries left, delete the file\n try {\n await unlink(filePath);\n log.debug(`deleted empty transcript file: ${filePath}`);\n return true;\n } catch (err) {\n log.error(`failed to delete empty transcript file ${filePath}:`, err);\n return false;\n }\n }\n\n if (hasOldEntries) {\n // Rewrite file without old entries\n await writeFile(filePath, validLines.join(\"\\n\") + \"\\n\", \"utf-8\");\n log.debug(`cleaned old entries from transcript file: ${filePath}`);\n return true;\n }\n\n // No old entries found, no action needed\n return false;\n } catch (err) {\n // File doesn't exist or is unreadable\n return false;\n }\n }\n\n /**\n * Save a checkpoint to preserve conversation context.\n * Called when compaction is detected.\n */\n async saveCheckpoint(checkpoint: Checkpoint): Promise<void> {\n try {\n await writeFile(this.checkpointPath, JSON.stringify(checkpoint, null, 2), \"utf-8\");\n log.info(`saved checkpoint for session ${checkpoint.sessionKey} with ${checkpoint.turns.length} turn(s)`);\n } catch (err) {\n log.error(\"failed to save checkpoint:\", err);\n throw err;\n }\n }\n\n /**\n * Load a checkpoint if one exists and is not expired.\n * Returns null if no checkpoint exists or if it has expired.\n */\n async loadCheckpoint(sessionKey?: string): Promise<Checkpoint | null> {\n try {\n const raw = await readFile(this.checkpointPath, \"utf-8\");\n const checkpoint = JSON.parse(raw) as Checkpoint;\n\n // Validate checkpoint structure\n if (!checkpoint.sessionKey || !checkpoint.capturedAt || !checkpoint.ttl || !Array.isArray(checkpoint.turns)) {\n log.warn(\"checkpoint file has invalid structure\");\n return null;\n }\n\n // Check if checkpoint is for the requested session (if specified)\n if (sessionKey && checkpoint.sessionKey !== sessionKey) {\n log.debug(`checkpoint session mismatch: ${checkpoint.sessionKey} vs ${sessionKey}`);\n return null;\n }\n\n // Check if checkpoint has expired\n const ttl = new Date(checkpoint.ttl);\n if (isNaN(ttl.getTime())) {\n log.warn(\"checkpoint has invalid TTL format\");\n return null;\n }\n\n if (ttl < new Date()) {\n log.info(`checkpoint expired at ${checkpoint.ttl}`);\n return null;\n }\n\n log.info(`loaded checkpoint with ${checkpoint.turns.length} turn(s), expires at ${checkpoint.ttl}`);\n return checkpoint;\n } catch (err) {\n // File doesn't exist or is unreadable - that's fine\n log.debug(\"no valid checkpoint found\");\n return null;\n }\n }\n\n /**\n * Clear (delete) the checkpoint file.\n * Called after successful injection of checkpoint context.\n */\n async clearCheckpoint(): Promise<void> {\n try {\n await unlink(this.checkpointPath);\n log.info(\"cleared checkpoint\");\n } catch (err) {\n // File doesn't exist - that's fine\n log.debug(\"no checkpoint to clear\");\n }\n }\n\n /**\n * Format entries for recall injection.\n * Returns a formatted string suitable for injecting into agent context.\n *\n * Format:\n * ## Recent Conversation (last X hours)\n * [10:32] User: message content\n * [10:33] Assistant: response content\n *\n * Content is trimmed to approximately maxTokens.\n */\n formatForRecall(entries: TranscriptEntry[], maxTokens: number): string {\n if (entries.length === 0) {\n return \"\";\n }\n\n const maxChars = maxTokens * TranscriptManager.CHARS_PER_TOKEN;\n const lines: string[] = [];\n\n // Calculate time range for header\n const firstEntry = new Date(entries[0].timestamp);\n const lastEntry = new Date(entries[entries.length - 1].timestamp);\n const hoursDiff = Math.round((lastEntry.getTime() - firstEntry.getTime()) / (60 * 60 * 1000));\n\n // Add header\n if (hoursDiff < 1) {\n lines.push(\"## Recent Conversation (last few minutes)\");\n } else {\n lines.push(`## Recent Conversation (last ${hoursDiff} hour${hoursDiff === 1 ? \"\" : \"s\"})`);\n }\n lines.push(\"\");\n\n // Format each entry\n const formattedEntries: string[] = [];\n for (const entry of entries) {\n const time = new Date(entry.timestamp);\n const timeStr = time.toLocaleTimeString(\"en-US\", {\n hour: \"2-digit\",\n minute: \"2-digit\",\n hour12: false,\n });\n const roleLabel = entry.role === \"user\" ? \"User\" : \"Assistant\";\n formattedEntries.push(`[${timeStr}] ${roleLabel}: ${entry.content}`);\n }\n\n // Build output, trimming from the beginning if too long\n // (we want to keep the most recent context)\n let totalChars = lines.join(\"\\n\").length;\n const selectedEntries: string[] = [];\n\n for (let i = formattedEntries.length - 1; i >= 0; i--) {\n const entry = formattedEntries[i];\n const entryChars = entry.length + 1; // +1 for newline\n\n if (totalChars + entryChars > maxChars && selectedEntries.length > 0) {\n // Adding this entry would exceed limit, and we have some entries already\n break;\n }\n\n selectedEntries.unshift(entry);\n totalChars += entryChars;\n }\n\n lines.push(...selectedEntries);\n lines.push(\"\"); // Trailing newline\n\n const result = lines.join(\"\\n\");\n log.debug(`formatted ${selectedEntries.length}/${entries.length} transcript entries for recall (~${result.length} chars)`);\n\n return result;\n }\n\n /**\n * Create a checkpoint from the current buffer state.\n * Helper method for creating checkpoints before compaction.\n */\n createCheckpoint(sessionKey: string, turns: TranscriptEntry[], ttlHours?: number): Checkpoint {\n const ttl = ttlHours ?? TranscriptManager.DEFAULT_CHECKPOINT_TTL_HOURS;\n const expiresAt = new Date();\n expiresAt.setHours(expiresAt.getHours() + ttl);\n\n return {\n sessionKey,\n capturedAt: new Date().toISOString(),\n turns: [...turns], // Copy turns to avoid mutation\n ttl: expiresAt.toISOString(),\n };\n }\n\n /**\n * Get statistics about stored transcripts.\n * Returns counts from the hierarchical directory structure.\n */\n async getStats(): Promise<{\n totalFiles: number;\n totalEntries: number;\n oldestFile: string | null;\n newestFile: string | null;\n channelTypes: Record<string, number>;\n }> {\n try {\n const allFiles = await this.getAllTranscriptFiles();\n\n if (allFiles.length === 0) {\n return {\n totalFiles: 0,\n totalEntries: 0,\n oldestFile: null,\n newestFile: null,\n channelTypes: {},\n };\n }\n\n // Sort files by path\n const sortedFiles = allFiles.sort();\n\n let totalEntries = 0;\n const channelTypes: Record<string, number> = {};\n\n for (const relativePath of allFiles) {\n const filePath = path.join(this.transcriptsDir, relativePath);\n try {\n const content = await readFile(filePath, \"utf-8\");\n const lines = content.trim().split(\"\\n\").filter(Boolean);\n totalEntries += lines.length;\n\n // Count by channel type (first directory in path)\n const channelType = relativePath.includes(path.sep)\n ? relativePath.split(path.sep)[0]\n : \"legacy\";\n channelTypes[channelType] = (channelTypes[channelType] || 0) + 1;\n } catch {\n // Skip unreadable files\n }\n }\n\n return {\n totalFiles: allFiles.length,\n totalEntries,\n oldestFile: sortedFiles[0],\n newestFile: sortedFiles[sortedFiles.length - 1],\n channelTypes,\n };\n } catch (err) {\n log.error(\"failed to get transcript stats:\", err);\n return {\n totalFiles: 0,\n totalEntries: 0,\n oldestFile: null,\n newestFile: null,\n channelTypes: {},\n };\n }\n }\n\n async analyzeIntegrity(): Promise<SessionIntegrityReport> {\n return analyzeSessionIntegrity({ memoryDir: this.config.memoryDir });\n }\n\n async getRecoverySummary(sessionKey?: string): Promise<{\n generatedAt: string;\n sessionKey?: string;\n healthy: boolean;\n issueCount: number;\n incompleteTurns: number;\n brokenChains: number;\n checkpointHealthy: boolean;\n }> {\n const report = await this.analyzeIntegrity();\n const selectedSessions = sessionKey\n ? report.sessions.filter((session) => session.sessionKey === sessionKey)\n : report.sessions;\n const incompleteTurns = selectedSessions.reduce((sum, session) => sum + session.incompleteTurns, 0);\n const brokenChains = selectedSessions.reduce((sum, session) => sum + session.brokenChains, 0);\n const filteredIssues = report.issues.filter((issue) => !sessionKey || issue.sessionKey === sessionKey);\n const issueCount = filteredIssues.length;\n const severeIssueCount = filteredIssues.filter((issue) => issue.severity !== \"info\").length;\n return {\n generatedAt: report.generatedAt,\n sessionKey,\n healthy: sessionKey ? severeIssueCount === 0 && report.checkpoint.healthy : report.healthy,\n issueCount,\n incompleteTurns,\n brokenChains,\n checkpointHealthy: report.checkpoint.healthy,\n };\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lcm/archive.ts"],"sourcesContent":["import type Database from \"better-sqlite3\";\nimport { log } from \"../logger.js\";\nimport {\n parseMessageParts,\n type LcmMessagePartInput,\n type MessagePartSourceFormat,\n} from \"../message-parts/index.js\";\n\nexport interface LcmMessage {\n id: number;\n session_id: string;\n turn_index: number;\n role: string;\n content: string;\n token_count: number;\n created_at: string;\n metadata: string | null;\n}\n\nexport interface LcmSearchResult {\n turn_index: number;\n role: string;\n snippet: string;\n session_id: string;\n score: number;\n}\n\nexport interface LcmSearchWithContentResult {\n id: number;\n turn_index: number;\n role: string;\n content: string;\n session_id: string;\n score: number;\n}\n\nexport interface LcmStructuredRecallMatch {\n part_id: number;\n message_id: number;\n turn_index: number;\n role: string;\n content: string;\n session_id: string;\n kind: string;\n tool_name: string | null;\n file_path: string | null;\n payload: string;\n score: number;\n}\n\n/** Rough token count: ~4 chars per token. */\nexport function estimateTokens(text: string): number {\n return Math.ceil(text.length / 4);\n}\n\nexport class LcmArchive {\n constructor(private readonly db: Database.Database) {}\n\n /** Append a message to the archive. Returns the row id. */\n appendMessage(\n sessionId: string,\n turnIndex: number,\n role: string,\n content: string,\n metadata?: Record<string, unknown>,\n parts?: LcmMessagePartInput[],\n ): number {\n const tokenCount = estimateTokens(content);\n const now = new Date().toISOString();\n const metaJson = metadata ? JSON.stringify(metadata) : null;\n\n const stmt = this.db.prepare(`\n INSERT INTO lcm_messages (session_id, turn_index, role, content, token_count, created_at, metadata)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n `);\n const result = stmt.run(sessionId, turnIndex, role, content, tokenCount, now, metaJson);\n const rowId = Number(result.lastInsertRowid);\n\n // Keep FTS in sync\n this.db\n .prepare(\"INSERT INTO lcm_messages_fts (rowid, content) VALUES (?, ?)\")\n .run(rowId, content);\n\n if (parts && parts.length > 0) {\n this.insertMessageParts(rowId, parts, now);\n }\n\n return rowId;\n }\n\n /** Append multiple messages in a single transaction. */\n appendMessages(\n sessionId: string,\n messages: Array<{\n turnIndex: number;\n role: string;\n content: string;\n metadata?: Record<string, unknown>;\n parts?: LcmMessagePartInput[];\n rawContent?: unknown;\n sourceFormat?: MessagePartSourceFormat;\n }>,\n options: { messagePartsEnabled?: boolean } = {},\n ): void {\n if (messages.length === 0) return;\n const captureMessageParts = options.messagePartsEnabled !== false;\n\n const txn = this.db.transaction(() => {\n for (const msg of messages) {\n const explicitParts =\n msg.parts && msg.parts.length > 0 ? msg.parts : undefined;\n const rawContent = msg.rawContent ?? msg.content;\n const parts =\n captureMessageParts\n ? explicitParts ??\n parseMessageParts(rawContent, {\n sourceFormat: msg.sourceFormat,\n renderedContent: msg.content,\n })\n : undefined;\n this.appendMessage(\n sessionId,\n msg.turnIndex,\n msg.role,\n msg.content,\n msg.metadata,\n parts,\n );\n }\n });\n txn();\n }\n\n insertMessageParts(\n messageId: number,\n parts: LcmMessagePartInput[],\n fallbackCreatedAt: string,\n ): void {\n if (parts.length === 0) return;\n const stmt = this.db.prepare(`\n INSERT INTO lcm_message_parts (message_id, ordinal, kind, payload, tool_name, file_path, created_at)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n `);\n for (let index = 0; index < parts.length; index += 1) {\n const part = parts[index]!;\n const rawPart = part as unknown as Record<string, unknown>;\n const toolName = part.toolName ?? asNullableString(rawPart.tool_name);\n const filePath = part.filePath ?? asNullableString(rawPart.file_path);\n const createdAt = part.createdAt ?? asNullableString(rawPart.created_at);\n stmt.run(\n messageId,\n part.ordinal ?? index,\n part.kind,\n JSON.stringify(part.payload ?? {}),\n toolName ?? null,\n filePath ?? null,\n createdAt ?? fallbackCreatedAt,\n );\n }\n }\n\n /** Get the highest turn_index for a session, or -1 if none. */\n getMaxTurnIndex(sessionId: string): number {\n const row = this.db\n .prepare(\"SELECT MAX(turn_index) as max_turn FROM lcm_messages WHERE session_id = ?\")\n .get(sessionId) as { max_turn: number | null } | undefined;\n return row?.max_turn ?? -1;\n }\n\n /** Retrieve messages in a turn range (inclusive). */\n getMessages(sessionId: string, fromTurn: number, toTurn: number): LcmMessage[] {\n return this.db\n .prepare(\n \"SELECT * FROM lcm_messages WHERE session_id = ? AND turn_index >= ? AND turn_index <= ? ORDER BY turn_index\",\n )\n .all(sessionId, fromTurn, toTurn) as LcmMessage[];\n }\n\n /** Retrieve unsummarized messages (after last leaf summary). */\n getUnsummarizedMessages(sessionId: string): LcmMessage[] {\n const lastLeafEnd = this.db\n .prepare(\n \"SELECT MAX(msg_end) as last_end FROM lcm_summary_nodes WHERE session_id = ? AND depth = 0\",\n )\n .get(sessionId) as { last_end: number | null } | undefined;\n\n const lastSummarized = lastLeafEnd?.last_end ?? -1;\n return this.db\n .prepare(\n \"SELECT * FROM lcm_messages WHERE session_id = ? AND turn_index > ? ORDER BY turn_index\",\n )\n .all(sessionId, lastSummarized) as LcmMessage[];\n }\n\n /** Full-text search across all messages. */\n search(query: string, limit: number, sessionId?: string): LcmSearchResult[] {\n try {\n const ftsQuery = sanitizeFtsQuery(query);\n if (!ftsQuery) return [];\n\n let sql: string;\n const params: unknown[] = [ftsQuery];\n\n if (sessionId) {\n sql = `\n SELECT m.turn_index, m.role, snippet(lcm_messages_fts, 0, '>>>', '<<<', '...', 48) as snippet,\n m.session_id, rank\n FROM lcm_messages_fts f\n JOIN lcm_messages m ON m.id = f.rowid\n WHERE lcm_messages_fts MATCH ?\n AND m.session_id = ?\n ORDER BY rank\n LIMIT ?\n `;\n params.push(sessionId, limit);\n } else {\n sql = `\n SELECT m.turn_index, m.role, snippet(lcm_messages_fts, 0, '>>>', '<<<', '...', 48) as snippet,\n m.session_id, rank\n FROM lcm_messages_fts f\n JOIN lcm_messages m ON m.id = f.rowid\n WHERE lcm_messages_fts MATCH ?\n ORDER BY rank\n LIMIT ?\n `;\n params.push(limit);\n }\n\n const rows = this.db.prepare(sql).all(...params) as Array<{\n turn_index: number;\n role: string;\n snippet: string;\n session_id: string;\n rank: number;\n }>;\n\n return rows.map((r) => ({\n turn_index: r.turn_index,\n role: r.role,\n snippet: r.snippet,\n session_id: r.session_id,\n score: -r.rank, // FTS5 rank is negative; negate for ascending score\n }));\n } catch (err) {\n log.debug(`LCM FTS search error: ${err}`);\n return [];\n }\n }\n\n /**\n * Full-text search returning focused excerpts around matching terms.\n * Returns ~1000-char windows centered on query term matches.\n * Deduplicates by message id and returns results sorted by FTS rank.\n */\n searchWithContent(query: string, limit: number, sessionId?: string, excerptChars = 1000): LcmSearchWithContentResult[] {\n try {\n const ftsQuery = sanitizeFtsQuery(query);\n if (!ftsQuery) return [];\n\n // Extract content words from query for excerpt windowing\n const queryWords = query\n .replace(/[^\\w\\s]/g, \" \")\n .split(/\\s+/)\n .filter((w) => w.length > 1 && !STOPWORDS.has(w.toLowerCase()))\n .map((w) => w.toLowerCase());\n\n let sql: string;\n const params: unknown[] = [ftsQuery];\n\n if (sessionId) {\n sql = `\n SELECT m.id, m.turn_index, m.role, m.content, m.session_id, rank\n FROM lcm_messages_fts f\n JOIN lcm_messages m ON m.id = f.rowid\n WHERE lcm_messages_fts MATCH ?\n AND m.session_id = ?\n ORDER BY rank\n LIMIT ?\n `;\n params.push(sessionId, limit);\n } else {\n sql = `\n SELECT m.id, m.turn_index, m.role, m.content, m.session_id, rank\n FROM lcm_messages_fts f\n JOIN lcm_messages m ON m.id = f.rowid\n WHERE lcm_messages_fts MATCH ?\n ORDER BY rank\n LIMIT ?\n `;\n params.push(limit);\n }\n\n const rows = this.db.prepare(sql).all(...params) as Array<{\n id: number;\n turn_index: number;\n role: string;\n content: string;\n session_id: string;\n rank: number;\n }>;\n\n // Deduplicate by message id (same message may match multiple terms)\n const seen = new Set<number>();\n const results: LcmSearchWithContentResult[] = [];\n for (const r of rows) {\n if (seen.has(r.id)) continue;\n seen.add(r.id);\n results.push({\n id: r.id,\n turn_index: r.turn_index,\n role: r.role,\n content: extractExcerpt(r.content, queryWords, excerptChars),\n session_id: r.session_id,\n score: -r.rank,\n });\n }\n return results;\n } catch (err) {\n log.debug(`LCM FTS searchWithContent error: ${err}`);\n return [];\n }\n }\n\n searchStructuredParts(\n query: string,\n limit: number,\n sessionId?: string,\n ): LcmStructuredRecallMatch[] {\n const cappedLimit = Math.max(0, Math.min(20, Math.floor(limit)));\n if (cappedLimit === 0) return [];\n\n const fileTerms = extractStructuredFileTerms(query);\n const toolTerms = extractStructuredToolTerms(query);\n if (fileTerms.length === 0 && toolTerms.length === 0) return [];\n\n const matchWhere: string[] = [];\n const whereParams: unknown[] = [];\n for (const term of fileTerms) {\n matchWhere.push(\"(p.file_path = ? OR p.file_path LIKE ? ESCAPE '\\\\')\");\n whereParams.push(term, `%${escapeLike(term)}%`);\n }\n for (const term of toolTerms) {\n matchWhere.push(\"p.tool_name LIKE ? ESCAPE '\\\\'\");\n whereParams.push(`%${escapeLike(term)}%`);\n }\n const where = [`(${matchWhere.join(\" OR \")})`];\n if (sessionId) {\n where.push(\"m.session_id = ?\");\n whereParams.push(sessionId);\n }\n const exactFileScoreParams = [...fileTerms];\n const sqlParams = [...exactFileScoreParams, ...whereParams, cappedLimit];\n\n const rows = this.db.prepare(`\n SELECT\n p.id AS part_id,\n p.message_id AS message_id,\n m.turn_index AS turn_index,\n m.role AS role,\n m.content AS content,\n m.session_id AS session_id,\n p.kind AS kind,\n p.tool_name AS tool_name,\n p.file_path AS file_path,\n p.payload AS payload,\n CASE\n WHEN p.file_path IN (${fileTerms.map(() => \"?\").join(\",\") || \"NULL\"}) THEN 3\n WHEN p.file_path IS NOT NULL THEN 2\n WHEN p.tool_name IS NOT NULL THEN 1\n ELSE 0\n END AS score\n FROM lcm_message_parts p\n JOIN lcm_messages m ON m.id = p.message_id\n WHERE ${where.join(\" AND \")}\n ORDER BY score DESC, m.turn_index DESC, p.ordinal ASC\n LIMIT ?\n `).all(...sqlParams) as LcmStructuredRecallMatch[];\n\n return rows;\n }\n\n /** Get total message count for a session. */\n getMessageCount(sessionId: string): number {\n const row = this.db\n .prepare(\"SELECT COUNT(*) as cnt FROM lcm_messages WHERE session_id = ?\")\n .get(sessionId) as { cnt: number };\n return row.cnt;\n }\n\n /** Get total message count across all sessions. */\n getTotalMessageCount(): number {\n const row = this.db\n .prepare(\"SELECT COUNT(*) as cnt FROM lcm_messages\")\n .get() as { cnt: number };\n return row.cnt;\n }\n\n /** Delete all archived messages for one session. */\n deleteSession(sessionId: string): number {\n const txn = this.db.transaction(() => {\n this.db\n .prepare(\n \"DELETE FROM lcm_messages_fts WHERE rowid IN (SELECT id FROM lcm_messages WHERE session_id = ?)\",\n )\n .run(sessionId);\n this.db\n .prepare(\n \"DELETE FROM lcm_message_parts WHERE message_id IN (SELECT id FROM lcm_messages WHERE session_id = ?)\",\n )\n .run(sessionId);\n const result = this.db\n .prepare(\"DELETE FROM lcm_messages WHERE session_id = ?\")\n .run(sessionId);\n return result.changes;\n });\n return txn();\n }\n\n /** Delete all archived messages. */\n deleteAll(): number {\n const txn = this.db.transaction(() => {\n this.db.prepare(\"DELETE FROM lcm_messages_fts\").run();\n this.db.prepare(\"DELETE FROM lcm_message_parts\").run();\n const result = this.db.prepare(\"DELETE FROM lcm_messages\").run();\n return result.changes;\n });\n return txn();\n }\n\n /** Prune messages older than retentionDays. */\n pruneOldMessages(retentionDays: number): number {\n const cutoff = new Date(Date.now() - retentionDays * 86400_000).toISOString();\n\n // Delete from FTS first\n this.db\n .prepare(\n \"DELETE FROM lcm_messages_fts WHERE rowid IN (SELECT id FROM lcm_messages WHERE created_at < ?)\",\n )\n .run(cutoff);\n\n const result = this.db\n .prepare(\"DELETE FROM lcm_messages WHERE created_at < ?\")\n .run(cutoff);\n return result.changes;\n }\n}\n\n/**\n * Extract a focused excerpt from content centered on query term matches.\n * Returns a window of ~excerptChars around the first matching term.\n * If content is shorter than excerptChars, returns the full content.\n */\nfunction extractExcerpt(content: string, queryWords: string[], excerptChars: number): string {\n if (content.length <= excerptChars) return content;\n\n // Find the earliest position of any query word in the content\n const contentLower = content.toLowerCase();\n let bestPos = -1;\n for (const word of queryWords) {\n const pos = contentLower.indexOf(word);\n if (pos !== -1 && (bestPos === -1 || pos < bestPos)) {\n bestPos = pos;\n }\n }\n\n // If no match found (shouldn't happen for FTS results), return start\n if (bestPos === -1) {\n return content.slice(0, excerptChars) + \"...\";\n }\n\n // Center the window around the match\n const halfWindow = Math.floor(excerptChars / 2);\n let start = Math.max(0, bestPos - halfWindow);\n let end = Math.min(content.length, start + excerptChars);\n\n // Adjust start if we hit the end\n if (end === content.length) {\n start = Math.max(0, end - excerptChars);\n }\n\n // Extend to sentence boundaries if possible\n if (start > 0) {\n const sentenceStart = content.lastIndexOf(\". \", start);\n if (sentenceStart !== -1 && start - sentenceStart < 200) {\n start = sentenceStart + 2;\n }\n }\n if (end < content.length) {\n const sentenceEnd = content.indexOf(\". \", end - 1);\n if (sentenceEnd !== -1 && sentenceEnd - end < 200) {\n end = sentenceEnd + 1;\n }\n }\n\n const prefix = start > 0 ? \"...\" : \"\";\n const suffix = end < content.length ? \"...\" : \"\";\n return prefix + content.slice(start, end) + suffix;\n}\n\nconst STOPWORDS = new Set([\n \"a\", \"an\", \"the\", \"is\", \"are\", \"was\", \"were\", \"be\", \"been\", \"being\",\n \"have\", \"has\", \"had\", \"do\", \"does\", \"did\", \"will\", \"would\", \"could\",\n \"should\", \"may\", \"might\", \"shall\", \"can\", \"to\", \"of\", \"in\", \"for\",\n \"on\", \"with\", \"at\", \"by\", \"from\", \"as\", \"into\", \"about\", \"between\",\n \"through\", \"during\", \"before\", \"after\", \"and\", \"but\", \"or\", \"nor\",\n \"not\", \"so\", \"if\", \"then\", \"than\", \"that\", \"this\", \"it\", \"its\",\n \"what\", \"which\", \"who\", \"whom\", \"how\", \"when\", \"where\", \"why\",\n \"all\", \"each\", \"every\", \"both\", \"few\", \"more\", \"most\", \"other\",\n \"some\", \"such\", \"no\", \"only\", \"own\", \"same\", \"just\", \"very\",\n \"my\", \"your\", \"his\", \"her\", \"our\", \"their\", \"me\", \"him\", \"us\", \"them\",\n \"i\", \"you\", \"he\", \"she\", \"we\", \"they\",\n]);\n\nfunction extractStructuredFileTerms(query: string): string[] {\n const terms = new Set<string>();\n for (const raw of splitQueryTerms(query)) {\n const cleaned = trimStructuredQueryTerm(raw);\n if (\n cleaned.includes(\"/\") ||\n hasStructuredFileExtension(cleaned)\n ) {\n terms.add(cleaned);\n const basename = cleaned.split(\"/\").pop();\n if (basename && basename !== cleaned) terms.add(basename);\n }\n }\n return [...terms].filter((term) => term.length > 1).slice(0, 12);\n}\n\nfunction splitQueryTerms(query: string): string[] {\n const terms: string[] = [];\n let term = \"\";\n for (const char of query.slice(0, 20_000)) {\n if (char === \" \" || char === \"\\n\" || char === \"\\r\" || char === \"\\t\") {\n if (term.length > 0) terms.push(term);\n term = \"\";\n continue;\n }\n term += char;\n if (term.length > 512) {\n terms.push(term);\n term = \"\";\n }\n }\n if (term.length > 0) terms.push(term);\n return terms;\n}\n\nfunction trimStructuredQueryTerm(raw: string): string {\n const leading = new Set([\"`\", \"'\", \"\\\"\", \"(\", \"[\", \"{\"]);\n const trailing = new Set([\"`\", \"'\", \"\\\"\", \",\", \".\", \"?\", \"!\", \":\", \";\", \")\", \"]\", \"}\"]);\n let start = 0;\n let end = raw.length;\n while (start < end && leading.has(raw[start]!)) start += 1;\n while (end > start && trailing.has(raw[end - 1]!)) end -= 1;\n return raw.slice(start, end);\n}\n\nfunction hasStructuredFileExtension(value: string): boolean {\n const slash = value.lastIndexOf(\"/\");\n const basename = value.slice(slash + 1);\n const dot = basename.lastIndexOf(\".\");\n if (dot <= 0 || dot === basename.length - 1) return false;\n const ext = basename.slice(dot + 1);\n if (ext.length < 1 || ext.length > 12) return false;\n for (const char of ext) {\n const code = char.charCodeAt(0);\n const valid =\n (code >= 48 && code <= 57) ||\n (code >= 65 && code <= 90) ||\n (code >= 97 && code <= 122) ||\n char === \"_\" ||\n char === \"+\" ||\n char === \"-\";\n if (!valid) return false;\n }\n return true;\n}\n\nfunction extractStructuredToolTerms(query: string): string[] {\n const lower = query.toLowerCase();\n if (!/\\b(tool|command|invocation|called|used|ran|read|write|patch|edit|grep|search)\\b/.test(lower)) {\n return [];\n }\n return query\n .replace(/[^\\w.-]/g, \" \")\n .split(/\\s+/)\n .filter((term) => term.length > 2 && !STOPWORDS.has(term.toLowerCase()))\n .slice(0, 8);\n}\n\nfunction escapeLike(value: string): string {\n return value.replace(/[\\\\%_]/g, (char) => `\\\\${char}`);\n}\n\nfunction asNullableString(value: unknown): string | null {\n return typeof value === \"string\" && value.trim().length > 0 ? value : null;\n}\n\n/**\n * Sanitize a query for FTS5 MATCH.\n * Uses OR logic so partial matches rank higher than no matches.\n * Filters stopwords to focus on content words.\n */\nfunction sanitizeFtsQuery(raw: string): string {\n const words = raw\n .replace(/[^\\w\\s]/g, \" \")\n .split(/\\s+/)\n .filter((w) => w.length > 1 && !STOPWORDS.has(w.toLowerCase()));\n if (words.length === 0) {\n // If all words were stopwords, fall back to using all words\n const allWords = raw.replace(/[^\\w\\s]/g, \" \").split(/\\s+/).filter((w) => w.length > 1);\n if (allWords.length === 0) return \"\";\n return allWords.map((w) => `\"${w}\"`).join(\" OR \");\n }\n return words.map((w) => `\"${w}\"`).join(\" OR \");\n}\n"],"mappings":";;;;;;;;AAmDO,SAAS,eAAe,MAAsB;AACnD,SAAO,KAAK,KAAK,KAAK,SAAS,CAAC;AAClC;AAEO,IAAM,aAAN,MAAiB;AAAA,EACtB,YAA6B,IAAuB;AAAvB;AAAA,EAAwB;AAAA,EAAxB;AAAA;AAAA,EAG7B,cACE,WACA,WACA,MACA,SACA,UACA,OACQ;AACR,UAAM,aAAa,eAAe,OAAO;AACzC,UAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,UAAM,WAAW,WAAW,KAAK,UAAU,QAAQ,IAAI;AAEvD,UAAM,OAAO,KAAK,GAAG,QAAQ;AAAA;AAAA;AAAA,KAG5B;AACD,UAAM,SAAS,KAAK,IAAI,WAAW,WAAW,MAAM,SAAS,YAAY,KAAK,QAAQ;AACtF,UAAM,QAAQ,OAAO,OAAO,eAAe;AAG3C,SAAK,GACF,QAAQ,6DAA6D,EACrE,IAAI,OAAO,OAAO;AAErB,QAAI,SAAS,MAAM,SAAS,GAAG;AAC7B,WAAK,mBAAmB,OAAO,OAAO,GAAG;AAAA,IAC3C;AAEA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,eACE,WACA,UASA,UAA6C,CAAC,GACxC;AACN,QAAI,SAAS,WAAW,EAAG;AAC3B,UAAM,sBAAsB,QAAQ,wBAAwB;AAE5D,UAAM,MAAM,KAAK,GAAG,YAAY,MAAM;AACpC,iBAAW,OAAO,UAAU;AAC1B,cAAM,gBACJ,IAAI,SAAS,IAAI,MAAM,SAAS,IAAI,IAAI,QAAQ;AAClD,cAAM,aAAa,IAAI,cAAc,IAAI;AACzC,cAAM,QACJ,sBACI,iBACA,kBAAkB,YAAY;AAAA,UAC5B,cAAc,IAAI;AAAA,UAClB,iBAAiB,IAAI;AAAA,QACvB,CAAC,IACD;AACN,aAAK;AAAA,UACH;AAAA,UACA,IAAI;AAAA,UACJ,IAAI;AAAA,UACJ,IAAI;AAAA,UACJ,IAAI;AAAA,UACJ;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AACD,QAAI;AAAA,EACN;AAAA,EAEA,mBACE,WACA,OACA,mBACM;AACN,QAAI,MAAM,WAAW,EAAG;AACxB,UAAM,OAAO,KAAK,GAAG,QAAQ;AAAA;AAAA;AAAA,KAG5B;AACD,aAAS,QAAQ,GAAG,QAAQ,MAAM,QAAQ,SAAS,GAAG;AACpD,YAAM,OAAO,MAAM,KAAK;AACxB,YAAM,UAAU;AAChB,YAAM,WAAW,KAAK,YAAY,iBAAiB,QAAQ,SAAS;AACpE,YAAM,WAAW,KAAK,YAAY,iBAAiB,QAAQ,SAAS;AACpE,YAAM,YAAY,KAAK,aAAa,iBAAiB,QAAQ,UAAU;AACvE,WAAK;AAAA,QACH;AAAA,QACA,KAAK,WAAW;AAAA,QAChB,KAAK;AAAA,QACL,KAAK,UAAU,KAAK,WAAW,CAAC,CAAC;AAAA,QACjC,YAAY;AAAA,QACZ,YAAY;AAAA,QACZ,aAAa;AAAA,MACf;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,gBAAgB,WAA2B;AACzC,UAAM,MAAM,KAAK,GACd,QAAQ,2EAA2E,EACnF,IAAI,SAAS;AAChB,WAAO,KAAK,YAAY;AAAA,EAC1B;AAAA;AAAA,EAGA,YAAY,WAAmB,UAAkB,QAA8B;AAC7E,WAAO,KAAK,GACT;AAAA,MACC;AAAA,IACF,EACC,IAAI,WAAW,UAAU,MAAM;AAAA,EACpC;AAAA;AAAA,EAGA,wBAAwB,WAAiC;AACvD,UAAM,cAAc,KAAK,GACtB;AAAA,MACC;AAAA,IACF,EACC,IAAI,SAAS;AAEhB,UAAM,iBAAiB,aAAa,YAAY;AAChD,WAAO,KAAK,GACT;AAAA,MACC;AAAA,IACF,EACC,IAAI,WAAW,cAAc;AAAA,EAClC;AAAA;AAAA,EAGA,OAAO,OAAe,OAAe,WAAuC;AAC1E,QAAI;AACF,YAAM,WAAW,iBAAiB,KAAK;AACvC,UAAI,CAAC,SAAU,QAAO,CAAC;AAEvB,UAAI;AACJ,YAAM,SAAoB,CAAC,QAAQ;AAEnC,UAAI,WAAW;AACb,cAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUN,eAAO,KAAK,WAAW,KAAK;AAAA,MAC9B,OAAO;AACL,cAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASN,eAAO,KAAK,KAAK;AAAA,MACnB;AAEA,YAAM,OAAO,KAAK,GAAG,QAAQ,GAAG,EAAE,IAAI,GAAG,MAAM;AAQ/C,aAAO,KAAK,IAAI,CAAC,OAAO;AAAA,QACtB,YAAY,EAAE;AAAA,QACd,MAAM,EAAE;AAAA,QACR,SAAS,EAAE;AAAA,QACX,YAAY,EAAE;AAAA,QACd,OAAO,CAAC,EAAE;AAAA;AAAA,MACZ,EAAE;AAAA,IACJ,SAAS,KAAK;AACZ,UAAI,MAAM,yBAAyB,GAAG,EAAE;AACxC,aAAO,CAAC;AAAA,IACV;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,kBAAkB,OAAe,OAAe,WAAoB,eAAe,KAAoC;AACrH,QAAI;AACF,YAAM,WAAW,iBAAiB,KAAK;AACvC,UAAI,CAAC,SAAU,QAAO,CAAC;AAGvB,YAAM,aAAa,MAChB,QAAQ,YAAY,GAAG,EACvB,MAAM,KAAK,EACX,OAAO,CAAC,MAAM,EAAE,SAAS,KAAK,CAAC,UAAU,IAAI,EAAE,YAAY,CAAC,CAAC,EAC7D,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC;AAE7B,UAAI;AACJ,YAAM,SAAoB,CAAC,QAAQ;AAEnC,UAAI,WAAW;AACb,cAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASN,eAAO,KAAK,WAAW,KAAK;AAAA,MAC9B,OAAO;AACL,cAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQN,eAAO,KAAK,KAAK;AAAA,MACnB;AAEA,YAAM,OAAO,KAAK,GAAG,QAAQ,GAAG,EAAE,IAAI,GAAG,MAAM;AAU/C,YAAM,OAAO,oBAAI,IAAY;AAC7B,YAAM,UAAwC,CAAC;AAC/C,iBAAW,KAAK,MAAM;AACpB,YAAI,KAAK,IAAI,EAAE,EAAE,EAAG;AACpB,aAAK,IAAI,EAAE,EAAE;AACb,gBAAQ,KAAK;AAAA,UACX,IAAI,EAAE;AAAA,UACN,YAAY,EAAE;AAAA,UACd,MAAM,EAAE;AAAA,UACR,SAAS,eAAe,EAAE,SAAS,YAAY,YAAY;AAAA,UAC3D,YAAY,EAAE;AAAA,UACd,OAAO,CAAC,EAAE;AAAA,QACZ,CAAC;AAAA,MACH;AACA,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,UAAI,MAAM,oCAAoC,GAAG,EAAE;AACnD,aAAO,CAAC;AAAA,IACV;AAAA,EACF;AAAA,EAEA,sBACE,OACA,OACA,WAC4B;AAC5B,UAAM,cAAc,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,MAAM,KAAK,CAAC,CAAC;AAC/D,QAAI,gBAAgB,EAAG,QAAO,CAAC;AAE/B,UAAM,YAAY,2BAA2B,KAAK;AAClD,UAAM,YAAY,2BAA2B,KAAK;AAClD,QAAI,UAAU,WAAW,KAAK,UAAU,WAAW,EAAG,QAAO,CAAC;AAE9D,UAAM,aAAuB,CAAC;AAC9B,UAAM,cAAyB,CAAC;AAChC,eAAW,QAAQ,WAAW;AAC5B,iBAAW,KAAK,qDAAqD;AACrE,kBAAY,KAAK,MAAM,IAAI,WAAW,IAAI,CAAC,GAAG;AAAA,IAChD;AACA,eAAW,QAAQ,WAAW;AAC5B,iBAAW,KAAK,gCAAgC;AAChD,kBAAY,KAAK,IAAI,WAAW,IAAI,CAAC,GAAG;AAAA,IAC1C;AACA,UAAM,QAAQ,CAAC,IAAI,WAAW,KAAK,MAAM,CAAC,GAAG;AAC7C,QAAI,WAAW;AACb,YAAM,KAAK,kBAAkB;AAC7B,kBAAY,KAAK,SAAS;AAAA,IAC5B;AACA,UAAM,uBAAuB,CAAC,GAAG,SAAS;AAC1C,UAAM,YAAY,CAAC,GAAG,sBAAsB,GAAG,aAAa,WAAW;AAEvE,UAAM,OAAO,KAAK,GAAG,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iCAaA,UAAU,IAAI,MAAM,GAAG,EAAE,KAAK,GAAG,KAAK,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,cAO/D,MAAM,KAAK,OAAO,CAAC;AAAA;AAAA;AAAA,KAG5B,EAAE,IAAI,GAAG,SAAS;AAEnB,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,gBAAgB,WAA2B;AACzC,UAAM,MAAM,KAAK,GACd,QAAQ,+DAA+D,EACvE,IAAI,SAAS;AAChB,WAAO,IAAI;AAAA,EACb;AAAA;AAAA,EAGA,uBAA+B;AAC7B,UAAM,MAAM,KAAK,GACd,QAAQ,0CAA0C,EAClD,IAAI;AACP,WAAO,IAAI;AAAA,EACb;AAAA;AAAA,EAGA,cAAc,WAA2B;AACvC,UAAM,MAAM,KAAK,GAAG,YAAY,MAAM;AACpC,WAAK,GACF;AAAA,QACC;AAAA,MACF,EACC,IAAI,SAAS;AAChB,WAAK,GACF;AAAA,QACC;AAAA,MACF,EACC,IAAI,SAAS;AAChB,YAAM,SAAS,KAAK,GACjB,QAAQ,+CAA+C,EACvD,IAAI,SAAS;AAChB,aAAO,OAAO;AAAA,IAChB,CAAC;AACD,WAAO,IAAI;AAAA,EACb;AAAA;AAAA,EAGA,YAAoB;AAClB,UAAM,MAAM,KAAK,GAAG,YAAY,MAAM;AACpC,WAAK,GAAG,QAAQ,8BAA8B,EAAE,IAAI;AACpD,WAAK,GAAG,QAAQ,+BAA+B,EAAE,IAAI;AACrD,YAAM,SAAS,KAAK,GAAG,QAAQ,0BAA0B,EAAE,IAAI;AAC/D,aAAO,OAAO;AAAA,IAChB,CAAC;AACD,WAAO,IAAI;AAAA,EACb;AAAA;AAAA,EAGA,iBAAiB,eAA+B;AAC9C,UAAM,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,gBAAgB,KAAS,EAAE,YAAY;AAG5E,SAAK,GACF;AAAA,MACC;AAAA,IACF,EACC,IAAI,MAAM;AAEb,UAAM,SAAS,KAAK,GACjB,QAAQ,+CAA+C,EACvD,IAAI,MAAM;AACb,WAAO,OAAO;AAAA,EAChB;AACF;AAOA,SAAS,eAAe,SAAiB,YAAsB,cAA8B;AAC3F,MAAI,QAAQ,UAAU,aAAc,QAAO;AAG3C,QAAM,eAAe,QAAQ,YAAY;AACzC,MAAI,UAAU;AACd,aAAW,QAAQ,YAAY;AAC7B,UAAM,MAAM,aAAa,QAAQ,IAAI;AACrC,QAAI,QAAQ,OAAO,YAAY,MAAM,MAAM,UAAU;AACnD,gBAAU;AAAA,IACZ;AAAA,EACF;AAGA,MAAI,YAAY,IAAI;AAClB,WAAO,QAAQ,MAAM,GAAG,YAAY,IAAI;AAAA,EAC1C;AAGA,QAAM,aAAa,KAAK,MAAM,eAAe,CAAC;AAC9C,MAAI,QAAQ,KAAK,IAAI,GAAG,UAAU,UAAU;AAC5C,MAAI,MAAM,KAAK,IAAI,QAAQ,QAAQ,QAAQ,YAAY;AAGvD,MAAI,QAAQ,QAAQ,QAAQ;AAC1B,YAAQ,KAAK,IAAI,GAAG,MAAM,YAAY;AAAA,EACxC;AAGA,MAAI,QAAQ,GAAG;AACb,UAAM,gBAAgB,QAAQ,YAAY,MAAM,KAAK;AACrD,QAAI,kBAAkB,MAAM,QAAQ,gBAAgB,KAAK;AACvD,cAAQ,gBAAgB;AAAA,IAC1B;AAAA,EACF;AACA,MAAI,MAAM,QAAQ,QAAQ;AACxB,UAAM,cAAc,QAAQ,QAAQ,MAAM,MAAM,CAAC;AACjD,QAAI,gBAAgB,MAAM,cAAc,MAAM,KAAK;AACjD,YAAM,cAAc;AAAA,IACtB;AAAA,EACF;AAEA,QAAM,SAAS,QAAQ,IAAI,QAAQ;AACnC,QAAM,SAAS,MAAM,QAAQ,SAAS,QAAQ;AAC9C,SAAO,SAAS,QAAQ,MAAM,OAAO,GAAG,IAAI;AAC9C;AAEA,IAAM,YAAY,oBAAI,IAAI;AAAA,EACxB;AAAA,EAAK;AAAA,EAAM;AAAA,EAAO;AAAA,EAAM;AAAA,EAAO;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAM;AAAA,EAAQ;AAAA,EAC5D;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAO;AAAA,EAAM;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAS;AAAA,EAC5D;AAAA,EAAU;AAAA,EAAO;AAAA,EAAS;AAAA,EAAS;AAAA,EAAO;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAC5D;AAAA,EAAM;AAAA,EAAQ;AAAA,EAAM;AAAA,EAAM;AAAA,EAAQ;AAAA,EAAM;AAAA,EAAQ;AAAA,EAAS;AAAA,EACzD;AAAA,EAAW;AAAA,EAAU;AAAA,EAAU;AAAA,EAAS;AAAA,EAAO;AAAA,EAAO;AAAA,EAAM;AAAA,EAC5D;AAAA,EAAO;AAAA,EAAM;AAAA,EAAM;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAM;AAAA,EACzD;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAS;AAAA,EACxD;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAQ;AAAA,EACvD;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAM;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAQ;AAAA,EACrD;AAAA,EAAM;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAO;AAAA,EAAO;AAAA,EAAS;AAAA,EAAM;AAAA,EAAO;AAAA,EAAM;AAAA,EAC/D;AAAA,EAAK;AAAA,EAAO;AAAA,EAAM;AAAA,EAAO;AAAA,EAAM;AACjC,CAAC;AAED,SAAS,2BAA2B,OAAyB;AAC3D,QAAM,QAAQ,oBAAI,IAAY;AAC9B,aAAW,OAAO,gBAAgB,KAAK,GAAG;AACxC,UAAM,UAAU,wBAAwB,GAAG;AAC3C,QACE,QAAQ,SAAS,GAAG,KACpB,2BAA2B,OAAO,GAClC;AACA,YAAM,IAAI,OAAO;AACjB,YAAM,WAAW,QAAQ,MAAM,GAAG,EAAE,IAAI;AACxC,UAAI,YAAY,aAAa,QAAS,OAAM,IAAI,QAAQ;AAAA,IAC1D;AAAA,EACF;AACA,SAAO,CAAC,GAAG,KAAK,EAAE,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC,EAAE,MAAM,GAAG,EAAE;AACjE;AAEA,SAAS,gBAAgB,OAAyB;AAChD,QAAM,QAAkB,CAAC;AACzB,MAAI,OAAO;AACX,aAAW,QAAQ,MAAM,MAAM,GAAG,GAAM,GAAG;AACzC,QAAI,SAAS,OAAO,SAAS,QAAQ,SAAS,QAAQ,SAAS,KAAM;AACnE,UAAI,KAAK,SAAS,EAAG,OAAM,KAAK,IAAI;AACpC,aAAO;AACP;AAAA,IACF;AACA,YAAQ;AACR,QAAI,KAAK,SAAS,KAAK;AACrB,YAAM,KAAK,IAAI;AACf,aAAO;AAAA,IACT;AAAA,EACF;AACA,MAAI,KAAK,SAAS,EAAG,OAAM,KAAK,IAAI;AACpC,SAAO;AACT;AAEA,SAAS,wBAAwB,KAAqB;AACpD,QAAM,UAAU,oBAAI,IAAI,CAAC,KAAK,KAAK,KAAM,KAAK,KAAK,GAAG,CAAC;AACvD,QAAM,WAAW,oBAAI,IAAI,CAAC,KAAK,KAAK,KAAM,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,GAAG,CAAC;AACtF,MAAI,QAAQ;AACZ,MAAI,MAAM,IAAI;AACd,SAAO,QAAQ,OAAO,QAAQ,IAAI,IAAI,KAAK,CAAE,EAAG,UAAS;AACzD,SAAO,MAAM,SAAS,SAAS,IAAI,IAAI,MAAM,CAAC,CAAE,EAAG,QAAO;AAC1D,SAAO,IAAI,MAAM,OAAO,GAAG;AAC7B;AAEA,SAAS,2BAA2B,OAAwB;AAC1D,QAAM,QAAQ,MAAM,YAAY,GAAG;AACnC,QAAM,WAAW,MAAM,MAAM,QAAQ,CAAC;AACtC,QAAM,MAAM,SAAS,YAAY,GAAG;AACpC,MAAI,OAAO,KAAK,QAAQ,SAAS,SAAS,EAAG,QAAO;AACpD,QAAM,MAAM,SAAS,MAAM,MAAM,CAAC;AAClC,MAAI,IAAI,SAAS,KAAK,IAAI,SAAS,GAAI,QAAO;AAC9C,aAAW,QAAQ,KAAK;AACtB,UAAM,OAAO,KAAK,WAAW,CAAC;AAC9B,UAAM,QACH,QAAQ,MAAM,QAAQ,MACtB,QAAQ,MAAM,QAAQ,MACtB,QAAQ,MAAM,QAAQ,OACvB,SAAS,OACT,SAAS,OACT,SAAS;AACX,QAAI,CAAC,MAAO,QAAO;AAAA,EACrB;AACA,SAAO;AACT;AAEA,SAAS,2BAA2B,OAAyB;AAC3D,QAAM,QAAQ,MAAM,YAAY;AAChC,MAAI,CAAC,kFAAkF,KAAK,KAAK,GAAG;AAClG,WAAO,CAAC;AAAA,EACV;AACA,SAAO,MACJ,QAAQ,YAAY,GAAG,EACvB,MAAM,KAAK,EACX,OAAO,CAAC,SAAS,KAAK,SAAS,KAAK,CAAC,UAAU,IAAI,KAAK,YAAY,CAAC,CAAC,EACtE,MAAM,GAAG,CAAC;AACf;AAEA,SAAS,WAAW,OAAuB;AACzC,SAAO,MAAM,QAAQ,WAAW,CAAC,SAAS,KAAK,IAAI,EAAE;AACvD;AAEA,SAAS,iBAAiB,OAA+B;AACvD,SAAO,OAAO,UAAU,YAAY,MAAM,KAAK,EAAE,SAAS,IAAI,QAAQ;AACxE;AAOA,SAAS,iBAAiB,KAAqB;AAC7C,QAAM,QAAQ,IACX,QAAQ,YAAY,GAAG,EACvB,MAAM,KAAK,EACX,OAAO,CAAC,MAAM,EAAE,SAAS,KAAK,CAAC,UAAU,IAAI,EAAE,YAAY,CAAC,CAAC;AAChE,MAAI,MAAM,WAAW,GAAG;AAEtB,UAAM,WAAW,IAAI,QAAQ,YAAY,GAAG,EAAE,MAAM,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC;AACrF,QAAI,SAAS,WAAW,EAAG,QAAO;AAClC,WAAO,SAAS,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,KAAK,MAAM;AAAA,EAClD;AACA,SAAO,MAAM,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,KAAK,MAAM;AAC/C;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/namespaces/search.ts"],"sourcesContent":["import type { PluginConfig, QmdSearchResult } from \"../types.js\";\nimport type { SearchBackend, SearchExecutionOptions, SearchQueryOptions } from \"../search/port.js\";\nimport { createSearchBackend } from \"../search/factory.js\";\n\nexport function namespaceCollectionName(\n baseCollection: string,\n namespace: string,\n options?: {\n defaultNamespace?: string;\n useLegacyDefaultCollection?: boolean;\n },\n): string {\n const trimmed = namespace.trim();\n const defaultNamespace = options?.defaultNamespace?.trim() || \"default\";\n if (\n options?.useLegacyDefaultCollection === true &&\n trimmed === defaultNamespace\n ) {\n return baseCollection;\n }\n\n const normalized = trimmed\n .toLowerCase()\n .replace(/[^a-z0-9._-]+/g, \"-\");\n let start = 0;\n let end = normalized.length;\n while (start < end && normalized[start] === \"-\") start += 1;\n while (end > start && normalized[end - 1] === \"-\") end -= 1;\n const token = normalized.slice(start, end) || defaultNamespace;\n return `${baseCollection}--ns--${token}`;\n}\n\ntype StorageRouterLike = {\n storageFor(namespace: string): Promise<{ dir: string }>;\n};\n\ntype NamespaceBackendRecord = {\n backend: SearchBackend;\n collection: string;\n memoryDir: string;\n available: boolean;\n collectionState: \"present\" | \"missing\" | \"unknown\" | \"skipped\";\n};\n\nexport class NamespaceSearchRouter {\n private readonly cache = new Map<string, Promise<NamespaceBackendRecord>>();\n\n constructor(\n private readonly config: PluginConfig,\n private readonly storageRouter: StorageRouterLike,\n private readonly createBackend: (config: PluginConfig) => SearchBackend = createSearchBackend,\n ) {}\n\n async collectionForNamespace(namespace: string): Promise<string> {\n return (await this.backendRecordFor(namespace)).collection;\n }\n\n async searchAcrossNamespaces(options: {\n query: string;\n namespaces: string[];\n maxResults?: number;\n mode?: \"search\" | \"hybrid\" | \"bm25\" | \"vector\";\n searchOptions?: SearchQueryOptions;\n execution?: SearchExecutionOptions;\n }): Promise<QmdSearchResult[]> {\n const query = options.query.trim();\n if (!query) return [];\n const maxResults = Math.max(0, Math.floor(options.maxResults ?? this.config.qmdMaxResults));\n if (maxResults === 0) return [];\n\n const method = options.mode ?? \"search\";\n const namespaces = Array.from(new Set(options.namespaces.map((value) => value.trim()).filter(Boolean)));\n if (namespaces.length === 0) return [];\n\n const resultsByNamespace = await Promise.all(\n namespaces.map(async (namespace) => {\n const record = await this.backendRecordFor(namespace);\n if (!record.available || record.collectionState === \"missing\") return [] as QmdSearchResult[];\n switch (method) {\n case \"hybrid\":\n return await record.backend.hybridSearch(query, undefined, maxResults, options.execution);\n case \"bm25\":\n return await record.backend.bm25Search(query, undefined, maxResults, options.execution);\n case \"vector\":\n return await record.backend.vectorSearch(query, undefined, maxResults, options.execution);\n default:\n return await record.backend.search(\n query,\n undefined,\n maxResults,\n options.searchOptions,\n options.execution,\n );\n }\n }),\n );\n\n return mergeNamespaceSearchResults(resultsByNamespace, maxResults);\n }\n\n /**\n * Update all namespace backends.\n * Returns the number of backends for which an update was attempted\n * (i.e., available and collection present). Callers can treat 0 as a\n * signal that no backend was eligible — useful for success-verification in\n * startup-sync when namespacesEnabled is true.\n */\n async updateNamespaces(\n namespaces: string[],\n execution?: SearchExecutionOptions,\n ): Promise<number> {\n const unique = Array.from(new Set(namespaces.map((value) => value.trim()).filter(Boolean)));\n const eligible = (await Promise.all(\n unique.map(async (namespace) => {\n const record = await this.backendRecordFor(namespace);\n return record.available && record.collectionState !== \"missing\"\n ? record\n : null;\n }),\n )).filter((record): record is NamespaceBackendRecord => record !== null);\n\n const globalRecord = eligible.find((record) => record.backend.updatesAllCollections?.() === true);\n const scopedRecords = globalRecord\n ? eligible.filter((record) => record.backend.updatesAllCollections?.() !== true)\n : eligible;\n\n await Promise.all([\n globalRecord ? globalRecord.backend.update(execution) : Promise.resolve(),\n ...scopedRecords.map((record) => record.backend.update(execution)),\n ]);\n\n return (globalRecord ? 1 : 0) + scopedRecords.length;\n }\n\n async embedNamespaces(namespaces: string[]): Promise<void> {\n const unique = Array.from(new Set(namespaces.map((value) => value.trim()).filter(Boolean)));\n await Promise.all(\n unique.map(async (namespace) => {\n const record = await this.backendRecordFor(namespace);\n if (!record.available || record.collectionState === \"missing\") return;\n await record.backend.embed();\n }),\n );\n }\n\n async ensureNamespaceCollection(namespace: string): Promise<\"present\" | \"missing\" | \"unknown\" | \"skipped\"> {\n const record = await this.backendRecordFor(namespace);\n return record.collectionState;\n }\n\n /** Clear cached backend records so the next access re-probes availability. */\n clearCache(): void {\n this.cache.clear();\n }\n\n /** Release any per-namespace backend handles held by cached records. */\n async dispose(): Promise<void> {\n const pendingRecords = Array.from(this.cache.values());\n this.cache.clear();\n const settled = await Promise.allSettled(pendingRecords);\n await Promise.allSettled(\n settled.flatMap((entry) => {\n if (entry.status !== \"fulfilled\") return [];\n const dispose = (entry.value.backend as { dispose?: () => void | Promise<void> }).dispose;\n return dispose ? [dispose.call(entry.value.backend)] : [];\n }),\n );\n }\n\n private async backendRecordFor(namespace: string): Promise<NamespaceBackendRecord> {\n const key = namespace.trim() || this.config.defaultNamespace;\n const existing = this.cache.get(key);\n if (existing) return await existing;\n\n const pending = (async (): Promise<NamespaceBackendRecord> => {\n const storage = await this.storageRouter.storageFor(key);\n const useLegacyDefaultCollection =\n key === this.config.defaultNamespace && storage.dir === this.config.memoryDir;\n const scopedConfig: PluginConfig = {\n ...this.config,\n memoryDir: storage.dir,\n qmdCollection: namespaceCollectionName(this.config.qmdCollection, key, {\n defaultNamespace: this.config.defaultNamespace,\n useLegacyDefaultCollection,\n }),\n };\n\n const backend = this.createBackend(scopedConfig);\n const available = await backend.probe().catch(() => false);\n const collectionState = available\n ? await backend.ensureCollection(storage.dir).catch(() => \"unknown\" as const)\n : \"unknown\";\n return {\n backend,\n collection: scopedConfig.qmdCollection,\n memoryDir: storage.dir,\n available,\n collectionState,\n };\n })();\n\n this.cache.set(key, pending);\n return await pending;\n }\n}\n\nfunction mergeNamespaceSearchResults(\n lists: QmdSearchResult[][],\n maxResults: number,\n): QmdSearchResult[] {\n const merged = new Map<string, QmdSearchResult>();\n\n for (const list of lists) {\n for (const result of list) {\n const key = result.path || result.docid;\n const existing = merged.get(key);\n if (!existing) {\n merged.set(key, result);\n continue;\n }\n if (result.score > existing.score) {\n merged.set(key, {\n ...result,\n snippet: existing.snippet || result.snippet || \"\",\n });\n }\n }\n }\n\n return [...merged.values()]\n .sort((a, b) => b.score - a.score)\n .slice(0, maxResults);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/relevance.ts"],"sourcesContent":["import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { log } from \"./logger.js\";\nimport type { RelevanceFeedback } from \"./types.js\";\n\ntype RelevanceState = Record<string, RelevanceFeedback>;\n\nexport class RelevanceStore {\n private readonly statePath: string;\n private state: RelevanceState = {};\n\n constructor(memoryDir: string) {\n this.statePath = path.join(memoryDir, \"state\", \"relevance.json\");\n }\n\n async load(): Promise<void> {\n try {\n const raw = await readFile(this.statePath, \"utf-8\");\n const parsed = JSON.parse(raw) as RelevanceState;\n if (parsed && typeof parsed === \"object\") this.state = parsed;\n } catch {\n this.state = {};\n }\n }\n\n /**\n * Record a thumbs up/down for a memory ID.\n * This is intentionally lightweight; it should never block agent execution.\n */\n async record(memoryId: string, vote: \"up\" | \"down\", note?: string): Promise<void> {\n const now = new Date().toISOString();\n const existing = this.state[memoryId] ?? { up: 0, down: 0, lastUpdatedAt: now };\n const next: RelevanceFeedback = {\n up: existing.up + (vote === \"up\" ? 1 : 0),\n down: existing.down + (vote === \"down\" ? 1 : 0),\n lastUpdatedAt: now,\n notes: note\n ? [...(existing.notes ?? []).slice(-19), note]\n : existing.notes,\n };\n this.state[memoryId] = next;\n\n try {\n await mkdir(path.dirname(this.statePath), { recursive: true });\n await writeFile(this.statePath, JSON.stringify(this.state, null, 2), \"utf-8\");\n } catch (err) {\n log.debug(`relevance store write failed: ${err}`);\n }\n }\n\n /**\n * Convert feedback into a small score adjustment.\n * Intended to be used as a tie-breaker/soft bias, not a hard filter.\n */\n adjustment(memoryId: string): number {\n const fb = this.state[memoryId];\n if (!fb) return 0;\n\n // Cap effect to avoid runaway ranking distortion.\n const up = Math.min(3, fb.up);\n const down = Math.min(3, fb.down);\n\n // Typical QMD scores are around 0-1; keep adjustments small.\n return up * 0.05 - down * 0.10; // max +0.15, min -0.30\n }\n}\n\n"],"mappings":";;;;;AAAA,SAAS,OAAO,UAAU,iBAAiB;AAC3C,OAAO,UAAU;AAMV,IAAM,iBAAN,MAAqB;AAAA,EACT;AAAA,EACT,QAAwB,CAAC;AAAA,EAEjC,YAAY,WAAmB;AAC7B,SAAK,YAAY,KAAK,KAAK,WAAW,SAAS,gBAAgB;AAAA,EACjE;AAAA,EAEA,MAAM,OAAsB;AAC1B,QAAI;AACF,YAAM,MAAM,MAAM,SAAS,KAAK,WAAW,OAAO;AAClD,YAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,UAAI,UAAU,OAAO,WAAW,SAAU,MAAK,QAAQ;AAAA,IACzD,QAAQ;AACN,WAAK,QAAQ,CAAC;AAAA,IAChB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,OAAO,UAAkB,MAAqB,MAA8B;AAChF,UAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,UAAM,WAAW,KAAK,MAAM,QAAQ,KAAK,EAAE,IAAI,GAAG,MAAM,GAAG,eAAe,IAAI;AAC9E,UAAM,OAA0B;AAAA,MAC9B,IAAI,SAAS,MAAM,SAAS,OAAO,IAAI;AAAA,MACvC,MAAM,SAAS,QAAQ,SAAS,SAAS,IAAI;AAAA,MAC7C,eAAe;AAAA,MACf,OAAO,OACH,CAAC,IAAI,SAAS,SAAS,CAAC,GAAG,MAAM,GAAG,GAAG,IAAI,IAC3C,SAAS;AAAA,IACf;AACA,SAAK,MAAM,QAAQ,IAAI;AAEvB,QAAI;AACF,YAAM,MAAM,KAAK,QAAQ,KAAK,SAAS,GAAG,EAAE,WAAW,KAAK,CAAC;AAC7D,YAAM,UAAU,KAAK,WAAW,KAAK,UAAU,KAAK,OAAO,MAAM,CAAC,GAAG,OAAO;AAAA,IAC9E,SAAS,KAAK;AACZ,UAAI,MAAM,iCAAiC,GAAG,EAAE;AAAA,IAClD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WAAW,UAA0B;AACnC,UAAM,KAAK,KAAK,MAAM,QAAQ;AAC9B,QAAI,CAAC,GAAI,QAAO;AAGhB,UAAM,KAAK,KAAK,IAAI,GAAG,GAAG,EAAE;AAC5B,UAAM,OAAO,KAAK,IAAI,GAAG,GAAG,IAAI;AAGhC,WAAO,KAAK,OAAO,OAAO;AAAA,EAC5B;AACF;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/buffer.ts"],"sourcesContent":["import { log } from \"./logger.js\";\nimport { scanSignals } from \"./signal.js\";\nimport type { StorageManager } from \"./storage.js\";\nimport type {\n BufferEntryState,\n BufferState,\n BufferSurpriseEvent,\n BufferTurn,\n PluginConfig,\n SignalLevel,\n} from \"./types.js\";\n\nexport type TriggerDecision = \"extract_now\" | \"extract_batch\" | \"keep_buffering\";\n\nexport interface AddTurnOutcome {\n decision: TriggerDecision;\n extractionTurns?: BufferTurn[];\n}\n\n/**\n * Optional surprise probe injected into `SmartBuffer`.\n *\n * Computes a D-MEM-style novelty score in `[0, 1]` for an incoming turn.\n * The buffer treats the probe as purely additive: if it is not provided, if\n * the feature flag is off, or if the probe throws/times out, the buffer\n * falls back to the existing signal/turn-count/time triggers unchanged.\n *\n * Callers are responsible for sampling recent memories and passing them\n * through the embedding pipeline — the buffer does not want to know about\n * storage, embeddings, or QMD.\n *\n * @param bufferKey Identifier for the active buffer (session/thread).\n * @param turn The incoming turn whose novelty is being scored.\n * @param recentTurns Turns already buffered for this key (most recent first\n * is NOT guaranteed — treat as unordered corpus).\n * @returns A surprise score in `[0, 1]`, or `null` if no score could be\n * produced (e.g. empty corpus, probe declined to embed).\n */\nexport interface BufferSurpriseProbe {\n scoreTurn(\n bufferKey: string,\n turn: BufferTurn,\n recentTurns: readonly BufferTurn[],\n ): Promise<number | null>;\n}\n\nconst MAX_BUFFER_ENTRY_COUNT = 200;\n\n/**\n * Minimal data carried on the serialized telemetry write chain\n * (issue #563 PR 3).\n *\n * We intentionally do NOT capture the full `BufferTurn` here: under\n * slow filesystem latency the chain can back up, and retaining\n * `turn.content` for every pending append causes memory pressure on\n * large conversations. Only the fields the ledger row actually needs\n * cross the chain boundary.\n */\ninterface SurpriseTelemetryQueueEntry {\n bufferKey: string;\n turnRole: \"user\" | \"assistant\";\n sessionKey: string | null;\n surpriseScore: number;\n triggered: boolean;\n turnCountInWindow: number;\n /**\n * ISO timestamp captured at the moment the turn was scored, NOT when\n * the ledger append eventually runs. Backpressure on the serialized\n * write chain could otherwise shift event timestamps away from the\n * real decision moment and distort the distribution report (p90\n * inflated, current-threshold row misidentified).\n */\n timestamp: string;\n /**\n * Threshold value in force when `triggered` was computed. Must be\n * snapshot here rather than read from `config` at emit time — a\n * concurrent config change between queue and write would otherwise\n * record `triggered=true` against a newer threshold the operator\n * never set, distorting precision/recall interpretation.\n */\n threshold: number;\n}\n\ninterface AddTurnMutationResult {\n decision: TriggerDecision;\n signalLevel: SignalLevel;\n priorTurns: BufferTurn[];\n turnSnapshot: BufferTurn;\n turnCountInWindow: number;\n}\n\nexport class SmartBuffer {\n private state: BufferState;\n private loaded = false;\n private loadPromise: Promise<void> | null = null;\n private readonly surpriseProbe: BufferSurpriseProbe | null;\n private mutationChain: Promise<unknown> = Promise.resolve();\n /**\n * Serialized write chain for `BUFFER_SURPRISE` telemetry events.\n *\n * The telemetry path is fire-and-forget (`addTurn` does not await the\n * ledger append), but multiple concurrent appends would still settle\n * out of order under variable filesystem latency. The report path\n * assumes chronological ordering — it slices the tail of the ledger\n * and treats the most recent entry as the current threshold in force.\n * Chaining ensures each append only runs after the previous settles,\n * preserving wall-clock order.\n *\n * We include a `.catch` on every link so a rejected append does not\n * poison the chain (CLAUDE.md rule #40).\n */\n private surpriseTelemetryWriteChain: Promise<unknown> = Promise.resolve();\n\n constructor(\n private readonly config: PluginConfig,\n private readonly storage: StorageManager,\n surpriseProbe: BufferSurpriseProbe | null = null,\n ) {\n this.state = { turns: [], lastExtractionAt: null, extractionCount: 0 };\n this.surpriseProbe = surpriseProbe;\n }\n\n private enqueueMutation<T>(op: () => Promise<T>): Promise<T> {\n const run = this.mutationChain.catch(() => {}).then(op);\n this.mutationChain = run.catch(() => {});\n return run;\n }\n\n private entryFor(key: string): BufferEntryState {\n this.state.entries ??= {};\n // Reject prototype-polluting keys outright so no downstream\n // assignment can mutate Object.prototype.\n if (key === \"__proto__\" || key === \"constructor\" || key === \"prototype\") {\n key = `__safe_${key}`;\n }\n if (Object.hasOwn(this.state.entries, key)) {\n const stored = this.state.entries[key];\n // Guard against corrupted state/buffer.json — if the stored entry\n // is not a valid object shape, discard it and recreate.\n if (stored && typeof stored === \"object\" && Array.isArray(stored.turns)) {\n return stored;\n }\n // Corrupted — fall through to recreate.\n }\n const created: BufferEntryState = {\n turns: [],\n lastExtractionAt: null,\n extractionCount: 0,\n };\n this.state.entries[key] = created;\n return created;\n }\n\n private peekEntry(key: string): BufferEntryState | null {\n // Apply the same prototype-pollution guard as entryFor so reads and\n // writes use the same key namespace for dangerous keys.\n if (key === \"__proto__\" || key === \"constructor\" || key === \"prototype\") {\n key = `__safe_${key}`;\n }\n const existing = this.state.entries?.[key];\n if (existing) return existing;\n if (key !== \"default\") return null;\n return {\n turns: Array.isArray(this.state.turns) ? this.state.turns : [],\n lastExtractionAt: this.state.lastExtractionAt ?? null,\n extractionCount:\n typeof this.state.extractionCount === \"number\" ? this.state.extractionCount : 0,\n };\n }\n\n private normalizeState(state: BufferState): BufferState {\n const entries = state.entries ?? {};\n if (!entries.default) {\n entries.default = {\n turns: Array.isArray(state.turns) ? [...state.turns] : [],\n lastExtractionAt: state.lastExtractionAt ?? null,\n extractionCount:\n typeof state.extractionCount === \"number\" ? state.extractionCount : 0,\n };\n }\n return {\n turns: entries.default.turns,\n lastExtractionAt: entries.default.lastExtractionAt,\n extractionCount: entries.default.extractionCount,\n entries,\n };\n }\n\n private entryActivityAt(entry: BufferEntryState): number {\n const lastTurnAt = entry.turns.reduce((latest, turn) => {\n const parsed = Date.parse(turn.timestamp);\n return Number.isFinite(parsed) ? Math.max(latest, parsed) : latest;\n }, -1);\n const lastExtractionAt =\n typeof entry.lastExtractionAt === \"string\"\n ? Date.parse(entry.lastExtractionAt)\n : Number.NaN;\n return Math.max(\n lastTurnAt,\n Number.isFinite(lastExtractionAt) ? lastExtractionAt : -1,\n );\n }\n\n private pruneEntries(retainKeys: string[]): void {\n const entries = this.state.entries;\n if (!entries) return;\n const keys = Object.keys(entries);\n if (keys.length <= MAX_BUFFER_ENTRY_COUNT) return;\n\n const insertionOrder = new Map(keys.map((key, index) => [key, index]));\n const removable = keys\n .filter((key) => key !== \"default\" && !retainKeys.includes(key))\n .filter((key) => (entries[key]?.turns.length ?? 0) === 0)\n .sort((left, right) => {\n const leftAt = this.entryActivityAt(entries[left] ?? {\n turns: [],\n lastExtractionAt: null,\n extractionCount: 0,\n });\n const rightAt = this.entryActivityAt(entries[right] ?? {\n turns: [],\n lastExtractionAt: null,\n extractionCount: 0,\n });\n if (leftAt !== rightAt) return leftAt - rightAt;\n return (insertionOrder.get(left) ?? 0) - (insertionOrder.get(right) ?? 0);\n });\n\n const removableCount = Math.max(0, keys.length - MAX_BUFFER_ENTRY_COUNT);\n for (const key of removable.slice(0, removableCount)) {\n delete entries[key];\n }\n }\n\n private async loadUnlocked(): Promise<void> {\n if (this.loaded) return;\n if (!this.loadPromise) {\n this.loadPromise = this.storage.loadBuffer()\n .then((state) => {\n this.state = this.normalizeState(state);\n this.loaded = true;\n })\n .finally(() => {\n this.loadPromise = null;\n });\n }\n await this.loadPromise;\n }\n\n async load(): Promise<void> {\n await this.enqueueMutation(async () => this.loadUnlocked());\n }\n\n /**\n * Reset the buffer to an empty, usable state.\n * Called when the persisted buffer file is corrupt and load() fails,\n * so the buffer can still accept new turns for the rest of the session.\n */\n resetToEmpty(): void {\n this.state = { turns: [], lastExtractionAt: null, extractionCount: 0 };\n this.loaded = true;\n }\n\n private async saveUnlocked(): Promise<void> {\n await this.storage.saveBuffer(this.state);\n }\n\n async save(): Promise<void> {\n await this.enqueueMutation(async () => this.saveUnlocked());\n }\n\n async addTurn(bufferKey: string, turn: BufferTurn): Promise<TriggerDecision> {\n return (await this.addTurnWithOutcome(bufferKey, turn)).decision;\n }\n\n async addTurnWithOutcome(\n bufferKey: string,\n turn: BufferTurn,\n ): Promise<AddTurnOutcome> {\n const mutation = await this.enqueueMutation(() => this.recordTurnUnlocked(bufferKey, turn));\n let decision = mutation.decision;\n let extractionTurns: BufferTurn[] | undefined;\n\n // Surprise-gated flush (issue #563). Additive only: if the probe is\n // disabled, unavailable, or the score is below threshold, the decision\n // from the existing trigger logic stands. The probe only ever *promotes*\n // `keep_buffering` → `extract_now`; it never suppresses an existing\n // flush. This preserves the invariant that enabling surprise cannot\n // *reduce* extraction frequency.\n if (\n decision === \"keep_buffering\" &&\n this.config.bufferSurpriseTriggerEnabled &&\n this.surpriseProbe !== null &&\n // Matching the existing \"smart\" branch: surprise is a lower-tier\n // novelty signal that should not second-guess a high-signal hit\n // (which already flushes) or fight `every_n` / `time_based` modes.\n this.config.triggerMode === \"smart\" &&\n mutation.signalLevel !== \"high\"\n ) {\n const surprise = await this.computeSurpriseSafe(bufferKey, turn, mutation.priorTurns);\n if (surprise !== null) {\n const shouldPromote = surprise > this.config.bufferSurpriseThreshold;\n let triggered = false;\n if (shouldPromote) {\n const currentTurns = await this.getExtractionTurnsIfTurnSnapshotStillCurrent(\n bufferKey,\n mutation.turnSnapshot,\n );\n if (currentTurns) {\n log.debug(\n `buffer[${bufferKey}]: surprise=${surprise.toFixed(3)} > threshold=${this.config.bufferSurpriseThreshold} → extract_now`,\n );\n decision = \"extract_now\";\n triggered = true;\n extractionTurns = currentTurns;\n } else {\n log.debug(\n `buffer[${bufferKey}]: surprise=${surprise.toFixed(3)} ignored because buffer changed before probe resolved`,\n );\n }\n }\n // Emit telemetry on every scored turn — both triggering and\n // non-triggering — so operators can fit the threshold to real\n // traffic distributions. Fire-and-forget: `addTurn` does NOT\n // await the ledger append, so slow/contended filesystems cannot\n // add JSONL-append latency to every `processTurn`. But we DO\n // serialize writes through a promise chain so concurrent\n // appends settle in wall-clock order — the report path assumes\n // chronological tail rows and reads the most recent as the\n // \"current\" threshold.\n //\n // Project only the fields we need into the queue entry rather\n // than capturing the full `BufferTurn` — under slow filesystem\n // latency the chain can back up, and we must not retain the\n // (potentially large) `turn.content` string for every pending\n // append.\n this.queueSurpriseTelemetryWrite({\n bufferKey,\n turnRole: turn.role,\n sessionKey:\n typeof turn.sessionKey === \"string\" ? turn.sessionKey : null,\n surpriseScore: surprise,\n triggered,\n turnCountInWindow: mutation.turnCountInWindow,\n // Stamp at decision time so backpressure on the write chain\n // does not shift the event's apparent moment away from when\n // the turn was actually scored.\n timestamp: new Date().toISOString(),\n // Snapshot the threshold used to compute `triggered` so a\n // concurrent config mutation cannot retroactively change\n // what the ledger row claims the decision was against.\n threshold: this.config.bufferSurpriseThreshold,\n });\n }\n }\n\n log.debug(\n `buffer[${bufferKey}]: ${mutation.turnCountInWindow} turns, signal=${mutation.signalLevel}, decision=${decision}`,\n );\n return extractionTurns ? { decision, extractionTurns } : { decision };\n }\n\n private async recordTurnUnlocked(bufferKey: string, turn: BufferTurn): Promise<AddTurnMutationResult> {\n await this.loadUnlocked();\n const entry = this.entryFor(bufferKey);\n const priorTurns = entry.turns.slice();\n entry.turns.push(turn);\n const turnSnapshot = copyBufferTurn(turn);\n if (bufferKey === \"default\") {\n this.state.turns = entry.turns;\n }\n\n const signal = scanSignals(turn.content, this.config.highSignalPatterns);\n const decision = this.evaluate(entry, signal.level);\n const turnCountInWindow = entry.turns.length;\n\n this.pruneEntries([bufferKey]);\n await this.saveUnlocked();\n return {\n decision,\n signalLevel: signal.level,\n priorTurns,\n turnSnapshot,\n turnCountInWindow,\n };\n }\n\n private async getExtractionTurnsIfTurnSnapshotStillCurrent(\n bufferKey: string,\n turnSnapshot: BufferTurn,\n ): Promise<BufferTurn[] | null> {\n return this.enqueueMutation(async () => {\n await this.loadUnlocked();\n const entry = this.peekEntry(bufferKey);\n if (!entry) return null;\n const stillCurrent = entry.turns.some((turn) =>\n bufferTurnsEqual(turn, turnSnapshot),\n );\n if (!stillCurrent) return null;\n const retained = entry.retainedTurns ?? [];\n return [...retained, ...entry.turns];\n });\n }\n\n /**\n * Enqueue a telemetry append on the serialized write chain.\n *\n * The chain is a classic `writeChain = writeChain.then(fn).catch(...)`\n * — each link waits for the previous to settle before its append\n * starts, so out-of-order chronology cannot happen even under\n * variable filesystem latency. We always attach `.catch` so one\n * rejection does not poison the chain for the rest of the session\n * (CLAUDE.md rule #40). The error is logged through\n * `emitSurpriseEventSafe` itself, which swallows its own rejections.\n *\n * Public surface is deliberately narrow — only `addTurn` should call\n * this, so the surprise telemetry path stays centralized.\n */\n private queueSurpriseTelemetryWrite(params: SurpriseTelemetryQueueEntry): void {\n this.surpriseTelemetryWriteChain = this.surpriseTelemetryWriteChain\n .then(() => this.emitSurpriseEventSafe(params))\n .catch(() => {\n // `emitSurpriseEventSafe` already handles the logging. We\n // swallow here only so one failure does not break the chain\n // for future writes.\n });\n }\n\n /**\n * Append a single `BUFFER_SURPRISE` telemetry row (issue #563 PR 3).\n *\n * Deliberately swallows write errors: the buffer must never fail to\n * record a turn because the observation ledger is read-only, out of\n * disk, or otherwise unhappy. The log line at debug lets operators\n * confirm the path fired without polluting the error channel.\n */\n private async emitSurpriseEventSafe(\n params: SurpriseTelemetryQueueEntry,\n ): Promise<void> {\n const storage = this.storage as StorageManager & {\n appendBufferSurpriseEvents?: (\n events: BufferSurpriseEvent[],\n ) => Promise<number>;\n };\n if (typeof storage.appendBufferSurpriseEvents !== \"function\") {\n // Older StorageManager / test double without the telemetry sink.\n // Silently skip — core path is still covered by the log line above.\n return;\n }\n const event: BufferSurpriseEvent = {\n event: \"BUFFER_SURPRISE\",\n // Use the decision-time stamp captured when the event was\n // queued, NOT `Date.now()` here — backpressure on the write\n // chain could otherwise shift timestamps into the future relative\n // to when the turn was scored.\n timestamp: params.timestamp,\n bufferKey: params.bufferKey,\n sessionKey: params.sessionKey,\n turnRole: params.turnRole,\n surpriseScore: params.surpriseScore,\n // Use the snapshotted threshold from the queue entry, not the\n // live config — see `SurpriseTelemetryQueueEntry.threshold`\n // doc for the rationale.\n threshold: params.threshold,\n triggeredFlush: params.triggered,\n turnCountInWindow: params.turnCountInWindow,\n };\n try {\n await storage.appendBufferSurpriseEvents([event]);\n } catch (err) {\n // Same guard as `computeSurpriseSafe`: non-Error rejections must\n // not crash the telemetry helper, which would defeat the whole\n // point of isolating the ledger write from the hot path.\n log.debug(\n `buffer[${params.bufferKey}]: surprise telemetry write failed, continuing: ${describeError(err)}`,\n );\n }\n }\n\n /**\n * Invoke the injected surprise probe defensively. Any error (probe throws,\n * embedder unavailable, timeout) is swallowed and logged at debug: the\n * surprise path must never crash the happy-path trigger evaluation. A\n * `null` return indicates \"no score available, fall through to existing\n * triggers\".\n */\n private async computeSurpriseSafe(\n bufferKey: string,\n turn: BufferTurn,\n priorTurns: readonly BufferTurn[],\n ): Promise<number | null> {\n if (!this.surpriseProbe) return null;\n try {\n // Hard timeout around the probe so a hung embedder cannot stall\n // `addTurn()` before `save()`. A slow probe would otherwise\n // prevent the just-appended turn from ever being persisted. The\n // timeout is a soft bound — we race it against the probe, take\n // whichever settles first, and treat the timeout as\n // \"probe unavailable, fall through\" rather than an error that\n // surfaces to the caller.\n const score = await probeWithTimeout(\n this.surpriseProbe.scoreTurn(bufferKey, turn, priorTurns),\n this.config.bufferSurpriseProbeTimeoutMs,\n );\n if (score === null) return null;\n if (typeof score !== \"number\" || !Number.isFinite(score)) {\n log.debug(\n `buffer[${bufferKey}]: surprise probe returned non-finite score (${String(score)}), ignoring`,\n );\n return null;\n }\n // Defensive clamp: formula lives in buffer-surprise.ts, but we never\n // want a misbehaving probe to inject an out-of-range value into the\n // threshold comparison.\n if (score < 0) return 0;\n if (score > 1) return 1;\n return score;\n } catch (err) {\n // `err` may be any thrown value — `throw null` and\n // `Promise.reject(\"x\")` are both legal. Accessing `.message` on a\n // non-Error would itself throw and defeat the failure-isolation\n // contract, so describe the value safely.\n log.debug(\n `buffer[${bufferKey}]: surprise probe failed, falling back to existing triggers: ${describeError(err)}`,\n );\n return null;\n }\n }\n\n private evaluate(entry: BufferEntryState, signalLevel: SignalLevel): TriggerDecision {\n if (this.config.triggerMode === \"smart\") {\n if (signalLevel === \"high\") return \"extract_now\";\n\n if (entry.turns.length >= this.config.bufferMaxTurns) {\n return \"extract_batch\";\n }\n\n if (entry.lastExtractionAt) {\n const elapsed =\n Date.now() - new Date(entry.lastExtractionAt).getTime();\n if (elapsed >= this.config.bufferMaxMinutes * 60_000) {\n return \"extract_batch\";\n }\n }\n\n return \"keep_buffering\";\n }\n\n if (this.config.triggerMode === \"every_n\") {\n return entry.turns.length >= this.config.bufferMaxTurns\n ? \"extract_batch\"\n : \"keep_buffering\";\n }\n\n if (this.config.triggerMode === \"time_based\") {\n if (!entry.lastExtractionAt) {\n return entry.turns.length >= this.config.bufferMaxTurns\n ? \"extract_batch\"\n : \"keep_buffering\";\n }\n const elapsed =\n Date.now() - new Date(entry.lastExtractionAt).getTime();\n return elapsed >= this.config.bufferMaxMinutes * 60_000\n ? \"extract_batch\"\n : \"keep_buffering\";\n }\n\n return \"keep_buffering\";\n }\n\n getTurns(bufferKey = \"default\"): BufferTurn[] {\n const entry = this.peekEntry(bufferKey);\n if (!entry) return [];\n const retained = entry.retainedTurns ?? [];\n // Retained turns (from a previous defer verdict, issue #562 PR 2) are\n // prepended so the chronological order — oldest context first — is\n // preserved for the next extraction pass.\n return [...retained, ...entry.turns];\n }\n\n /**\n * Retain a subset of the current turns across `clearAfterExtraction` so a\n * future extraction pass sees the context behind a deferred candidate\n * (issue #562, PR 2). Callers pass the turns that were seen during the\n * current extraction; the buffer keeps the tail (latest `max` turns) as\n * the retention window. Passing an empty array or `max <= 0` clears the\n * retention slot instead.\n */\n async retainDeferredTurns(\n bufferKey: string,\n turns: BufferTurn[],\n max = 10,\n ): Promise<void> {\n await this.enqueueMutation(async () => {\n await this.loadUnlocked();\n const entry = this.entryFor(bufferKey);\n if (!Array.isArray(turns) || turns.length === 0 || max <= 0) {\n delete entry.retainedTurns;\n } else {\n // Guard `slice(-max)` against `max === 0` (CLAUDE.md gotcha 27):\n // `slice(-0)` equals `slice(0)` and would return ALL entries. We\n // already early-return above when max <= 0.\n const tail = turns.slice(-max);\n // Copy explicit fields only — never spread an external object into a\n // plain object because spread preserves any own `__proto__` /\n // `constructor` keys that may have arrived via JSON deserialization\n // of untrusted input (CodeQL js/prototype-polluting-assignment).\n entry.retainedTurns = tail.map<BufferTurn>((t) => {\n const copy: BufferTurn = {\n role: t.role,\n content: typeof t.content === \"string\" ? t.content : \"\",\n timestamp:\n typeof t.timestamp === \"string\"\n ? t.timestamp\n : new Date().toISOString(),\n };\n if (typeof t.sessionKey === \"string\") copy.sessionKey = t.sessionKey;\n if (typeof t.logicalSessionKey === \"string\") {\n copy.logicalSessionKey = t.logicalSessionKey;\n }\n if (\n t.providerThreadId === null ||\n typeof t.providerThreadId === \"string\"\n ) {\n copy.providerThreadId = t.providerThreadId;\n }\n if (typeof t.turnFingerprint === \"string\") {\n copy.turnFingerprint = t.turnFingerprint;\n }\n if (typeof t.persistProcessedFingerprint === \"boolean\") {\n copy.persistProcessedFingerprint = t.persistProcessedFingerprint;\n }\n return copy;\n });\n }\n await this.saveUnlocked();\n });\n }\n\n /**\n * Return the current retention window (issue #562, PR 2). Primarily for\n * tests and diagnostics.\n */\n getRetainedDeferredTurns(bufferKey = \"default\"): BufferTurn[] {\n const entry = this.peekEntry(bufferKey);\n return entry?.retainedTurns ? [...entry.retainedTurns] : [];\n }\n\n async findBufferKeyForSession(sessionKey: string): Promise<string | null> {\n const bufferKeys = await this.findBufferKeysForSession(sessionKey);\n return bufferKeys[0] ?? null;\n }\n\n async findBufferKeysForSession(sessionKey: string): Promise<string[]> {\n if (typeof sessionKey !== \"string\" || sessionKey.length === 0) return [];\n await this.mutationChain.catch(() => {});\n await this.load();\n\n const matches: string[] = [];\n const directEntry = this.peekEntry(sessionKey);\n if ((directEntry?.turns.length ?? 0) > 0) {\n matches.push(sessionKey);\n }\n\n const entries = this.state.entries ?? {};\n for (const [bufferKey, entry] of Object.entries(entries)) {\n if (\n !matches.includes(bufferKey) &&\n entry.turns.some(\n (turn) =>\n typeof turn.sessionKey === \"string\" && turn.sessionKey === sessionKey,\n )\n ) {\n matches.push(bufferKey);\n }\n }\n\n return matches;\n }\n\n async clearAfterExtraction(\n bufferKey = \"default\",\n extractedTurns?: readonly BufferTurn[],\n ): Promise<void> {\n await this.enqueueMutation(async () => {\n await this.loadUnlocked();\n const entry = this.entryFor(bufferKey);\n if (Array.isArray(extractedTurns)) {\n const liveExtractedTurns = liveTurnsFromExtractionSnapshot(\n entry,\n extractedTurns,\n );\n let clearedLiveTurns = false;\n if (liveExtractedTurns.length > 0) {\n const matchedCount = matchingQueuedExtractionPrefixLength(\n entry.turns,\n liveExtractedTurns,\n );\n if (matchedCount > 0) {\n entry.turns = entry.turns.slice(matchedCount);\n clearedLiveTurns = true;\n } else {\n log.debug(\n `buffer[${bufferKey}]: extraction clear skipped because live turns changed before clear`,\n );\n }\n }\n if (!clearedLiveTurns) {\n await this.saveUnlocked();\n return;\n }\n } else {\n entry.turns = [];\n }\n entry.lastExtractionAt = new Date().toISOString();\n entry.extractionCount += 1;\n if (bufferKey === \"default\") {\n this.state.turns = entry.turns;\n this.state.lastExtractionAt = entry.lastExtractionAt;\n this.state.extractionCount = entry.extractionCount;\n }\n this.pruneEntries([bufferKey]);\n await this.saveUnlocked();\n });\n }\n\n getExtractionCount(bufferKey = \"default\"): number {\n return this.peekEntry(bufferKey)?.extractionCount ?? 0;\n }\n\n /**\n * Await any pending `BUFFER_SURPRISE` telemetry writes.\n *\n * The telemetry path is fire-and-forget from the hot path's point of\n * view, but tests and before-exit hooks sometimes need to make sure\n * the ledger has been flushed before they assert on its contents or\n * close the process. This method resolves once the current chain\n * head has settled; new writes scheduled after this call return a\n * separate, later settlement.\n *\n * Never throws — the chain already catches its own rejections.\n */\n async flushSurpriseTelemetry(): Promise<void> {\n await this.surpriseTelemetryWriteChain;\n }\n}\n\n/**\n * Render an arbitrary thrown value as a short string for debug logging.\n *\n * JavaScript permits throwing *any* value (`throw null`,\n * `Promise.reject(\"x\")`, `throw { reason: \"timeout\" }`) — not just\n * `Error` instances. The defensive catch blocks in `SmartBuffer` must\n * never themselves throw while trying to log the failure, or they\n * would defeat the whole point of isolating the surprise path from the\n * core extraction decision.\n */\nfunction describeError(err: unknown): string {\n if (err instanceof Error) return err.message;\n if (err === null) return \"null\";\n if (err === undefined) return \"undefined\";\n if (typeof err === \"string\") return err;\n try {\n return JSON.stringify(err);\n } catch {\n return String(err);\n }\n}\n\nfunction copyBufferTurn(turn: BufferTurn): BufferTurn {\n const copy: BufferTurn = {\n role: turn.role,\n content: turn.content,\n timestamp: turn.timestamp,\n };\n if (typeof turn.sessionKey === \"string\") copy.sessionKey = turn.sessionKey;\n if (typeof turn.logicalSessionKey === \"string\") {\n copy.logicalSessionKey = turn.logicalSessionKey;\n }\n if (\n turn.providerThreadId === null ||\n typeof turn.providerThreadId === \"string\"\n ) {\n copy.providerThreadId = turn.providerThreadId;\n }\n if (typeof turn.turnFingerprint === \"string\") {\n copy.turnFingerprint = turn.turnFingerprint;\n }\n if (typeof turn.persistProcessedFingerprint === \"boolean\") {\n copy.persistProcessedFingerprint = turn.persistProcessedFingerprint;\n }\n return copy;\n}\n\nfunction bufferTurnsEqual(left: BufferTurn | undefined, right: BufferTurn): boolean {\n if (!left) return false;\n return (\n left.role === right.role &&\n left.content === right.content &&\n left.timestamp === right.timestamp &&\n left.sessionKey === right.sessionKey &&\n left.logicalSessionKey === right.logicalSessionKey &&\n left.providerThreadId === right.providerThreadId &&\n left.turnFingerprint === right.turnFingerprint &&\n left.persistProcessedFingerprint === right.persistProcessedFingerprint\n );\n}\n\nfunction liveTurnsFromExtractionSnapshot(\n entry: BufferEntryState,\n extractedTurns: readonly BufferTurn[],\n): readonly BufferTurn[] {\n const retainedTurns = entry.retainedTurns ?? [];\n if (\n retainedTurns.length > 0 &&\n extractedTurns.length >= retainedTurns.length &&\n retainedTurns.every((turn, index) =>\n bufferTurnsEqual(extractedTurns[index], turn),\n )\n ) {\n const withoutRetainedPrefix = extractedTurns.slice(retainedTurns.length);\n if (\n withoutRetainedPrefix.length > 0 &&\n matchingPrefixLength(entry.turns, withoutRetainedPrefix) > 0\n ) {\n return withoutRetainedPrefix;\n }\n }\n return extractedTurns;\n}\n\nfunction matchingPrefixLength(\n liveTurns: readonly BufferTurn[],\n extractedTurns: readonly BufferTurn[],\n): number {\n let index = 0;\n while (\n index < liveTurns.length &&\n index < extractedTurns.length &&\n bufferTurnsEqual(liveTurns[index], extractedTurns[index])\n ) {\n index += 1;\n }\n return index;\n}\n\nfunction matchingQueuedExtractionPrefixLength(\n liveTurns: readonly BufferTurn[],\n extractedTurns: readonly BufferTurn[],\n): number {\n let bestMatchedCount = 0;\n for (let start = 0; start < extractedTurns.length; start += 1) {\n const matchedCount = matchingPrefixLength(\n liveTurns,\n extractedTurns.slice(start),\n );\n if (matchedCount > bestMatchedCount) {\n bestMatchedCount = matchedCount;\n if (bestMatchedCount === liveTurns.length) break;\n }\n }\n return bestMatchedCount;\n}\n\n/**\n * Sentinel error class for the probe timeout path. Catching it via\n * `instanceof` lets the buffer's surprise helper distinguish a timeout\n * from a probe rejection (which could carry operational context the\n * operator wants to see).\n */\nclass ProbeTimeoutError extends Error {\n constructor(timeoutMs: number) {\n super(`probe exceeded ${timeoutMs}ms`);\n this.name = \"ProbeTimeoutError\";\n }\n}\n\n/**\n * Race `inflight` against a timeout clock. Resolves with `inflight`'s\n * value if it settles first, otherwise rejects with `ProbeTimeoutError`.\n * The timer is cleared in both branches so a fast-resolving probe does\n * not leak a handle that would keep the Node event loop alive.\n */\nfunction probeWithTimeout<T>(\n inflight: Promise<T>,\n timeoutMs: number,\n): Promise<T> {\n let timer: NodeJS.Timeout | null = null;\n const timeout = new Promise<T>((_, reject) => {\n timer = setTimeout(() => reject(new ProbeTimeoutError(timeoutMs)), timeoutMs);\n // `.unref()` so the timer does not hold the event loop open if the\n // caller decides the probe result is no longer interesting.\n if (typeof (timer as NodeJS.Timeout).unref === \"function\") {\n (timer as NodeJS.Timeout).unref();\n }\n });\n return Promise.race([inflight, timeout]).finally(() => {\n if (timer) clearTimeout(timer);\n });\n}\n"],"mappings":"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","names":[]}
|