@theokit/sdk 4.24.0 → 4.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/a2a/index.cjs +10 -171
- package/dist/a2a/index.cjs.map +1 -1
- package/dist/a2a/index.js +3 -170
- package/dist/a2a/index.js.map +1 -1
- package/dist/agent-factory-registry-UU46BUMU.cjs +16 -0
- package/dist/agent-factory-registry-UU46BUMU.cjs.map +1 -0
- package/dist/agent-factory-registry-ZVTABLEY.js +3 -0
- package/dist/agent-factory-registry-ZVTABLEY.js.map +1 -0
- package/dist/auth/index.cjs +63 -367
- package/dist/auth/index.cjs.map +1 -1
- package/dist/auth/index.js +6 -342
- package/dist/auth/index.js.map +1 -1
- package/dist/batch-2FSD2UNL.cjs +244 -0
- package/dist/batch-2FSD2UNL.cjs.map +1 -0
- package/dist/batch-MR2HKYMS.js +241 -0
- package/dist/batch-MR2HKYMS.js.map +1 -0
- package/dist/chunk-2HRYBRD7.cjs +31 -0
- package/dist/chunk-2HRYBRD7.cjs.map +1 -0
- package/dist/chunk-2MF3IE2D.cjs +2863 -0
- package/dist/chunk-2MF3IE2D.cjs.map +1 -0
- package/dist/chunk-2ONFGMBV.js +6 -0
- package/dist/chunk-2ONFGMBV.js.map +1 -0
- package/dist/chunk-2SFBB54R.js +23 -0
- package/dist/chunk-2SFBB54R.js.map +1 -0
- package/dist/chunk-2XLKLVVR.js +18 -0
- package/dist/chunk-2XLKLVVR.js.map +1 -0
- package/dist/chunk-4SXHEZIV.cjs +240 -0
- package/dist/chunk-4SXHEZIV.cjs.map +1 -0
- package/dist/chunk-4VPXM6UU.js +10 -0
- package/dist/chunk-4VPXM6UU.js.map +1 -0
- package/dist/chunk-4WL52CXU.cjs +148 -0
- package/dist/chunk-4WL52CXU.cjs.map +1 -0
- package/dist/chunk-5NBUH3NO.js +39 -0
- package/dist/chunk-5NBUH3NO.js.map +1 -0
- package/dist/chunk-5PZMMF4H.js +43 -0
- package/dist/chunk-5PZMMF4H.js.map +1 -0
- package/dist/chunk-6CLRANZA.js +289 -0
- package/dist/chunk-6CLRANZA.js.map +1 -0
- package/dist/chunk-6JSIEDKL.cjs +121 -0
- package/dist/chunk-6JSIEDKL.cjs.map +1 -0
- package/dist/chunk-6M4ODB2V.cjs +145 -0
- package/dist/chunk-6M4ODB2V.cjs.map +1 -0
- package/dist/chunk-6X6ID4MO.js +20 -0
- package/dist/chunk-6X6ID4MO.js.map +1 -0
- package/dist/chunk-77FOZCOT.js +165 -0
- package/dist/chunk-77FOZCOT.js.map +1 -0
- package/dist/chunk-7AD3ZTZL.js +25 -0
- package/dist/chunk-7AD3ZTZL.js.map +1 -0
- package/dist/chunk-7GFX45DD.js +57 -0
- package/dist/chunk-7GFX45DD.js.map +1 -0
- package/dist/chunk-7S7KKUO6.cjs +45 -0
- package/dist/chunk-7S7KKUO6.cjs.map +1 -0
- package/dist/chunk-7W7ZWMLQ.js +99 -0
- package/dist/chunk-7W7ZWMLQ.js.map +1 -0
- package/dist/chunk-A44COQJJ.cjs +353 -0
- package/dist/chunk-A44COQJJ.cjs.map +1 -0
- package/dist/chunk-AKSBP7OO.js +185 -0
- package/dist/chunk-AKSBP7OO.js.map +1 -0
- package/dist/chunk-ANIZEWTU.cjs +196 -0
- package/dist/chunk-ANIZEWTU.cjs.map +1 -0
- package/dist/chunk-BEURCLDV.cjs +139 -0
- package/dist/chunk-BEURCLDV.cjs.map +1 -0
- package/dist/chunk-BFWPZMG7.js +379 -0
- package/dist/chunk-BFWPZMG7.js.map +1 -0
- package/dist/chunk-BUUUWQMB.cjs +34 -0
- package/dist/chunk-BUUUWQMB.cjs.map +1 -0
- package/dist/chunk-BV2MWEMV.cjs +26 -0
- package/dist/chunk-BV2MWEMV.cjs.map +1 -0
- package/dist/chunk-BWT67BI4.cjs +268 -0
- package/dist/chunk-BWT67BI4.cjs.map +1 -0
- package/dist/chunk-BXV2QUIC.js +191 -0
- package/dist/chunk-BXV2QUIC.js.map +1 -0
- package/dist/chunk-C6Y6CWYD.cjs +44 -0
- package/dist/chunk-C6Y6CWYD.cjs.map +1 -0
- package/dist/chunk-C7PICHRF.cjs +68 -0
- package/dist/chunk-C7PICHRF.cjs.map +1 -0
- package/dist/chunk-CAH3G4IS.js +13 -0
- package/dist/chunk-CAH3G4IS.js.map +1 -0
- package/dist/chunk-D42XHI4O.cjs +565 -0
- package/dist/chunk-D42XHI4O.cjs.map +1 -0
- package/dist/chunk-DGRZNMTU.js +104 -0
- package/dist/chunk-DGRZNMTU.js.map +1 -0
- package/dist/chunk-DUK5WMKJ.js +71 -0
- package/dist/chunk-DUK5WMKJ.js.map +1 -0
- package/dist/chunk-EEZ7CFMM.js +14 -0
- package/dist/chunk-EEZ7CFMM.js.map +1 -0
- package/dist/chunk-EPYZOCOL.cjs +82 -0
- package/dist/chunk-EPYZOCOL.cjs.map +1 -0
- package/dist/chunk-EVADEGM7.cjs +168 -0
- package/dist/chunk-EVADEGM7.cjs.map +1 -0
- package/dist/chunk-FD2UT76F.js +3 -0
- package/dist/chunk-FD2UT76F.js.map +1 -0
- package/dist/chunk-FV3YEMQ7.js +179 -0
- package/dist/chunk-FV3YEMQ7.js.map +1 -0
- package/dist/chunk-G2F67XUR.cjs +184 -0
- package/dist/chunk-G2F67XUR.cjs.map +1 -0
- package/dist/chunk-G6GO6BXD.js +994 -0
- package/dist/chunk-G6GO6BXD.js.map +1 -0
- package/dist/chunk-GIW4L6HY.cjs +27 -0
- package/dist/chunk-GIW4L6HY.cjs.map +1 -0
- package/dist/chunk-GJAGKFTR.js +74 -0
- package/dist/chunk-GJAGKFTR.js.map +1 -0
- package/dist/chunk-HFPGOTVF.cjs +324 -0
- package/dist/chunk-HFPGOTVF.cjs.map +1 -0
- package/dist/chunk-HRA3CPGG.js +486 -0
- package/dist/chunk-HRA3CPGG.js.map +1 -0
- package/dist/chunk-HZQEDNF6.js +66 -0
- package/dist/chunk-HZQEDNF6.js.map +1 -0
- package/dist/chunk-IT3PWBW4.cjs +19 -0
- package/dist/chunk-IT3PWBW4.cjs.map +1 -0
- package/dist/chunk-JD74LN7R.cjs +171 -0
- package/dist/chunk-JD74LN7R.cjs.map +1 -0
- package/dist/chunk-JTFYYKDT.js +135 -0
- package/dist/chunk-JTFYYKDT.js.map +1 -0
- package/dist/chunk-K2BQQ445.js +30 -0
- package/dist/chunk-K2BQQ445.js.map +1 -0
- package/dist/chunk-KAP4GJHO.js +546 -0
- package/dist/chunk-KAP4GJHO.js.map +1 -0
- package/dist/chunk-KDNBTPY2.js +458 -0
- package/dist/chunk-KDNBTPY2.js.map +1 -0
- package/dist/chunk-KIO7QFIV.cjs +223 -0
- package/dist/chunk-KIO7QFIV.cjs.map +1 -0
- package/dist/chunk-KSKU6JY6.cjs +71 -0
- package/dist/chunk-KSKU6JY6.cjs.map +1 -0
- package/dist/chunk-LSLPF6OI.cjs +192 -0
- package/dist/chunk-LSLPF6OI.cjs.map +1 -0
- package/dist/chunk-LU7VALW5.js +312 -0
- package/dist/chunk-LU7VALW5.js.map +1 -0
- package/dist/chunk-LUSXDZPV.cjs +296 -0
- package/dist/chunk-LUSXDZPV.cjs.map +1 -0
- package/dist/chunk-M72RJVPC.js +69 -0
- package/dist/chunk-M72RJVPC.js.map +1 -0
- package/dist/chunk-MQLCZ4HJ.cjs +1010 -0
- package/dist/chunk-MQLCZ4HJ.cjs.map +1 -0
- package/dist/chunk-MUUQ2WFJ.cjs +4 -0
- package/dist/chunk-MUUQ2WFJ.cjs.map +1 -0
- package/dist/chunk-MZ5ZRORA.cjs +496 -0
- package/dist/chunk-MZ5ZRORA.cjs.map +1 -0
- package/dist/chunk-N24XBYNX.cjs +140 -0
- package/dist/chunk-N24XBYNX.cjs.map +1 -0
- package/dist/chunk-NINIJCHU.cjs +23 -0
- package/dist/chunk-NINIJCHU.cjs.map +1 -0
- package/dist/chunk-NRSH7RJY.js +2841 -0
- package/dist/chunk-NRSH7RJY.js.map +1 -0
- package/dist/chunk-OIYQBUW4.cjs +111 -0
- package/dist/chunk-OIYQBUW4.cjs.map +1 -0
- package/dist/chunk-PNVDQL5Y.cjs +15 -0
- package/dist/chunk-PNVDQL5Y.cjs.map +1 -0
- package/dist/chunk-POQT2OIF.js +214 -0
- package/dist/chunk-POQT2OIF.js.map +1 -0
- package/dist/chunk-PSJN532Q.js +10573 -0
- package/dist/chunk-PSJN532Q.js.map +1 -0
- package/dist/chunk-QUTUJ6P6.cjs +76 -0
- package/dist/chunk-QUTUJ6P6.cjs.map +1 -0
- package/dist/chunk-R43CNCES.cjs +460 -0
- package/dist/chunk-R43CNCES.cjs.map +1 -0
- package/dist/chunk-S2BBRVQX.js +68 -0
- package/dist/chunk-S2BBRVQX.js.map +1 -0
- package/dist/chunk-S5RCBTSF.js +145 -0
- package/dist/chunk-S5RCBTSF.js.map +1 -0
- package/dist/chunk-S7OEXQMI.cjs +136 -0
- package/dist/chunk-S7OEXQMI.cjs.map +1 -0
- package/dist/chunk-SKWVAQAY.js +129 -0
- package/dist/chunk-SKWVAQAY.js.map +1 -0
- package/dist/chunk-SQLZ7ONU.js +152 -0
- package/dist/chunk-SQLZ7ONU.js.map +1 -0
- package/dist/chunk-TIZ4TS5V.cjs +72 -0
- package/dist/chunk-TIZ4TS5V.cjs.map +1 -0
- package/dist/chunk-TQKCU7CL.js +142 -0
- package/dist/chunk-TQKCU7CL.js.map +1 -0
- package/dist/chunk-U54XCYG3.js +116 -0
- package/dist/chunk-U54XCYG3.js.map +1 -0
- package/dist/chunk-U6QGZHPN.js +29 -0
- package/dist/chunk-U6QGZHPN.js.map +1 -0
- package/dist/chunk-UCFONJBG.js +79 -0
- package/dist/chunk-UCFONJBG.js.map +1 -0
- package/dist/chunk-UJ7IQJAG.js +141 -0
- package/dist/chunk-UJ7IQJAG.js.map +1 -0
- package/dist/chunk-UVNG67DG.js +253 -0
- package/dist/chunk-UVNG67DG.js.map +1 -0
- package/dist/chunk-V4XRLPEF.js +25 -0
- package/dist/chunk-V4XRLPEF.js.map +1 -0
- package/dist/chunk-VJ26EKGJ.cjs +28 -0
- package/dist/chunk-VJ26EKGJ.cjs.map +1 -0
- package/dist/chunk-VK7MAV65.cjs +90 -0
- package/dist/chunk-VK7MAV65.cjs.map +1 -0
- package/dist/chunk-VYCKUKPA.cjs +106 -0
- package/dist/chunk-VYCKUKPA.cjs.map +1 -0
- package/dist/chunk-VYHJZVL5.cjs +29 -0
- package/dist/chunk-VYHJZVL5.cjs.map +1 -0
- package/dist/chunk-WA3FO4R7.js +155 -0
- package/dist/chunk-WA3FO4R7.js.map +1 -0
- package/dist/chunk-WJVHMTKB.cjs +12 -0
- package/dist/chunk-WJVHMTKB.cjs.map +1 -0
- package/dist/chunk-WLKFWQSJ.js +333 -0
- package/dist/chunk-WLKFWQSJ.js.map +1 -0
- package/dist/chunk-WPZTYOUX.cjs +59 -0
- package/dist/chunk-WPZTYOUX.cjs.map +1 -0
- package/dist/chunk-X2FR4OIT.js +27 -0
- package/dist/chunk-X2FR4OIT.js.map +1 -0
- package/dist/chunk-XIG2IE3L.js +134 -0
- package/dist/chunk-XIG2IE3L.js.map +1 -0
- package/dist/chunk-YLQQX5W2.cjs +20 -0
- package/dist/chunk-YLQQX5W2.cjs.map +1 -0
- package/dist/chunk-YPEPCZHF.cjs +147 -0
- package/dist/chunk-YPEPCZHF.cjs.map +1 -0
- package/dist/chunk-YPQF26X7.cjs +8 -0
- package/dist/chunk-YPQF26X7.cjs.map +1 -0
- package/dist/chunk-YU6KON2I.cjs +160 -0
- package/dist/chunk-YU6KON2I.cjs.map +1 -0
- package/dist/chunk-Z2OC3UIW.cjs +388 -0
- package/dist/chunk-Z2OC3UIW.cjs.map +1 -0
- package/dist/chunk-ZUBIEQJF.cjs +10590 -0
- package/dist/chunk-ZUBIEQJF.cjs.map +1 -0
- package/dist/chunk-ZZWTY3RX.js +230 -0
- package/dist/chunk-ZZWTY3RX.js.map +1 -0
- package/dist/compact-session-OO2GD76G.js +17 -0
- package/dist/compact-session-OO2GD76G.js.map +1 -0
- package/dist/compact-session-OO7NVWPB.cjs +54 -0
- package/dist/compact-session-OO7NVWPB.cjs.map +1 -0
- package/dist/compaction.cjs +54 -303
- package/dist/compaction.cjs.map +1 -1
- package/dist/compaction.js +3 -292
- package/dist/compaction.js.map +1 -1
- package/dist/concurrency.cjs +9 -81
- package/dist/concurrency.cjs.map +1 -1
- package/dist/concurrency.js +5 -80
- package/dist/concurrency.js.map +1 -1
- package/dist/context-GWANQLX4.js +5 -0
- package/dist/context-GWANQLX4.js.map +1 -0
- package/dist/context-KNWVTZSY.cjs +22 -0
- package/dist/context-KNWVTZSY.cjs.map +1 -0
- package/dist/{cron-x3muPNgg.d.cts → cron-D0JKR-yX.d.cts} +2 -1
- package/dist/{cron-B_NkE_VM.d.ts → cron-DivRaEmN.d.ts} +2 -1
- package/dist/cron.cjs +44 -20676
- package/dist/cron.cjs.map +1 -1
- package/dist/cron.d.cts +1 -1
- package/dist/cron.d.ts +1 -1
- package/dist/cron.js +38 -20676
- package/dist/cron.js.map +1 -1
- package/dist/errors.cjs +78 -470
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.ts +3 -424
- package/dist/errors.js +2 -455
- package/dist/errors.js.map +1 -1
- package/dist/eval.cjs +72 -20411
- package/dist/eval.cjs.map +1 -1
- package/dist/eval.js +59 -20402
- package/dist/eval.js.map +1 -1
- package/dist/executor-ORJS5GV2.js +981 -0
- package/dist/executor-ORJS5GV2.js.map +1 -0
- package/dist/executor-Y4MKPIUD.cjs +985 -0
- package/dist/executor-Y4MKPIUD.cjs.map +1 -0
- package/dist/filesystem/index.cjs +7 -112
- package/dist/filesystem/index.cjs.map +1 -1
- package/dist/filesystem/index.js +4 -109
- package/dist/filesystem/index.js.map +1 -1
- package/dist/fork-agent-RSV4E3EA.js +61 -0
- package/dist/fork-agent-RSV4E3EA.js.map +1 -0
- package/dist/fork-agent-Y2IK2RYU.cjs +64 -0
- package/dist/fork-agent-Y2IK2RYU.cjs.map +1 -0
- package/dist/fs-session-store-KAUQYSGI.cjs +17 -0
- package/dist/fs-session-store-KAUQYSGI.cjs.map +1 -0
- package/dist/fs-session-store-ZKB5NN37.js +8 -0
- package/dist/fs-session-store-ZKB5NN37.js.map +1 -0
- package/dist/generate-object-H3RNAM6S.cjs +20 -0
- package/dist/generate-object-H3RNAM6S.cjs.map +1 -0
- package/dist/generate-object-YJPDV5BS.js +7 -0
- package/dist/generate-object-YJPDV5BS.js.map +1 -0
- package/dist/index-manager-CB6I7XFQ.cjs +19 -0
- package/dist/index-manager-CB6I7XFQ.cjs.map +1 -0
- package/dist/index-manager-L27Q3QAC.js +10 -0
- package/dist/index-manager-L27Q3QAC.js.map +1 -0
- package/dist/index.cjs +371 -22888
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -21
- package/dist/index.d.ts +16 -21
- package/dist/index.js +92 -22713
- package/dist/index.js.map +1 -1
- package/dist/inject-session-6MJUSGZP.cjs +27 -0
- package/dist/inject-session-6MJUSGZP.cjs.map +1 -0
- package/dist/inject-session-KOFHS5K3.js +25 -0
- package/dist/inject-session-KOFHS5K3.js.map +1 -0
- package/dist/internal/judge/judge-call.d.ts +32 -19
- package/dist/internal/persistence/index.cjs +93 -508
- package/dist/internal/persistence/index.cjs.map +1 -1
- package/dist/internal/persistence/index.js +11 -489
- package/dist/internal/persistence/index.js.map +1 -1
- package/dist/internal/security/index.cjs +44 -361
- package/dist/internal/security/index.cjs.map +1 -1
- package/dist/internal/security/index.js +4 -355
- package/dist/internal/security/index.js.map +1 -1
- package/dist/judge-call-CEQ3FYYD.js +126 -0
- package/dist/judge-call-CEQ3FYYD.js.map +1 -0
- package/dist/judge-call-QG4WZ7F3.cjs +130 -0
- package/dist/judge-call-QG4WZ7F3.cjs.map +1 -0
- package/dist/models.cjs +24 -919
- package/dist/models.cjs.map +1 -1
- package/dist/models.js +11 -907
- package/dist/models.js.map +1 -1
- package/dist/oauth-transaction-store-7CKHPQRN.cjs +32 -0
- package/dist/oauth-transaction-store-7CKHPQRN.cjs.map +1 -0
- package/dist/oauth-transaction-store-W74I6EFD.js +3 -0
- package/dist/oauth-transaction-store-W74I6EFD.js.map +1 -0
- package/dist/path-safety.cjs +31 -200
- package/dist/path-safety.cjs.map +1 -1
- package/dist/path-safety.js +3 -197
- package/dist/path-safety.js.map +1 -1
- package/dist/persistence.cjs +73 -393
- package/dist/persistence.cjs.map +1 -1
- package/dist/persistence.js +9 -381
- package/dist/persistence.js.map +1 -1
- package/dist/project.cjs +8 -112
- package/dist/project.cjs.map +1 -1
- package/dist/project.js +6 -110
- package/dist/project.js.map +1 -1
- package/dist/registry-34IWWDQQ.js +9 -0
- package/dist/registry-34IWWDQQ.js.map +1 -0
- package/dist/registry-APYDISL6.cjs +46 -0
- package/dist/registry-APYDISL6.cjs.map +1 -0
- package/dist/retry.cjs +7 -87
- package/dist/retry.cjs.map +1 -1
- package/dist/retry.js +3 -90
- package/dist/retry.js.map +1 -1
- package/dist/run-to-completion-J73I6IY4.cjs +48 -0
- package/dist/run-to-completion-J73I6IY4.cjs.map +1 -0
- package/dist/run-to-completion-JDPIUKSH.js +3 -0
- package/dist/run-to-completion-JDPIUKSH.js.map +1 -0
- package/dist/run-until-PNO3QQLI.cjs +180 -0
- package/dist/run-until-PNO3QQLI.cjs.map +1 -0
- package/dist/run-until-XLHEHRQM.js +177 -0
- package/dist/run-until-XLHEHRQM.js.map +1 -0
- package/dist/sandbox/index.cjs +35 -337
- package/dist/sandbox/index.cjs.map +1 -1
- package/dist/sandbox/index.js +7 -323
- package/dist/sandbox/index.js.map +1 -1
- package/dist/sanitize/index.cjs +5 -112
- package/dist/sanitize/index.cjs.map +1 -1
- package/dist/sanitize/index.js +1 -114
- package/dist/sanitize/index.js.map +1 -1
- package/dist/server/auth/index.cjs +35 -175
- package/dist/server/auth/index.cjs.map +1 -1
- package/dist/server/auth/index.js +7 -161
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/errors-envelope.cjs +17 -328
- package/dist/server/errors-envelope.cjs.map +1 -1
- package/dist/server/errors-envelope.js +4 -317
- package/dist/server/errors-envelope.js.map +1 -1
- package/dist/session-transcript-LPNZR3YS.cjs +46 -0
- package/dist/session-transcript-LPNZR3YS.cjs.map +1 -0
- package/dist/session-transcript-T7LGJUGW.js +5 -0
- package/dist/session-transcript-T7LGJUGW.js.map +1 -0
- package/dist/skills.cjs +12 -280
- package/dist/skills.cjs.map +1 -1
- package/dist/skills.js +4 -282
- package/dist/skills.js.map +1 -1
- package/dist/stream-object-QEQJJDTI.cjs +20 -0
- package/dist/stream-object-QEQJJDTI.cjs.map +1 -0
- package/dist/stream-object-WUQSSRY2.js +7 -0
- package/dist/stream-object-WUQSSRY2.js.map +1 -0
- package/dist/stream-to-completion-DFJ5T3BK.js +30 -0
- package/dist/stream-to-completion-DFJ5T3BK.js.map +1 -0
- package/dist/stream-to-completion-H2MHISSK.cjs +32 -0
- package/dist/stream-to-completion-H2MHISSK.cjs.map +1 -0
- package/dist/subagents.cjs +2 -8
- package/dist/subagents.cjs.map +1 -1
- package/dist/subagents.js +1 -7
- package/dist/subagents.js.map +1 -1
- package/dist/subscription/index.cjs +4 -17
- package/dist/subscription/index.cjs.map +1 -1
- package/dist/subscription/index.js +3 -16
- package/dist/subscription/index.js.map +1 -1
- package/dist/task-store.cjs +16 -258
- package/dist/task-store.cjs.map +1 -1
- package/dist/task-store.js +4 -259
- package/dist/task-store.js.map +1 -1
- package/dist/types/goal-events.d.ts +2 -1
- package/dist/workflow.cjs +71 -2797
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.js +8 -2812
- package/dist/workflow.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,994 @@
|
|
|
1
|
+
import { openSqliteResilient, sanitizeFts5Query } from './chunk-77FOZCOT.js';
|
|
2
|
+
import { withCwdMutex } from './chunk-2XLKLVVR.js';
|
|
3
|
+
import { sanitizeIdentifier, safePathJoin, safeFilenameForId } from './chunk-POQT2OIF.js';
|
|
4
|
+
import { replaceFileAtomic } from './chunk-S2BBRVQX.js';
|
|
5
|
+
import { ConfigurationError } from './chunk-WLKFWQSJ.js';
|
|
6
|
+
import { redactSecrets } from './chunk-JTFYYKDT.js';
|
|
7
|
+
import { createHash } from 'crypto';
|
|
8
|
+
import { readFile, mkdir, stat, readdir } from 'fs/promises';
|
|
9
|
+
import { join, resolve, relative } from 'path';
|
|
10
|
+
import { mkdirSync } from 'fs';
|
|
11
|
+
import { createRequire } from 'module';
|
|
12
|
+
|
|
13
|
+
// src/internal/memory/embedding-cache.ts
|
|
14
|
+
var LruEmbeddingCache = class {
|
|
15
|
+
constructor(capacity = 5e3) {
|
|
16
|
+
this.capacity = capacity;
|
|
17
|
+
}
|
|
18
|
+
capacity;
|
|
19
|
+
map = /* @__PURE__ */ new Map();
|
|
20
|
+
get(key) {
|
|
21
|
+
const value = this.map.get(key);
|
|
22
|
+
if (value === void 0) return void 0;
|
|
23
|
+
this.map.delete(key);
|
|
24
|
+
this.map.set(key, value);
|
|
25
|
+
return value;
|
|
26
|
+
}
|
|
27
|
+
set(key, value) {
|
|
28
|
+
if (this.map.has(key)) this.map.delete(key);
|
|
29
|
+
else if (this.map.size >= this.capacity) {
|
|
30
|
+
const oldest = this.map.keys().next().value;
|
|
31
|
+
if (oldest !== void 0) this.map.delete(oldest);
|
|
32
|
+
}
|
|
33
|
+
this.map.set(key, value);
|
|
34
|
+
}
|
|
35
|
+
size() {
|
|
36
|
+
return this.map.size;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
var globalEmbeddingCache = new LruEmbeddingCache();
|
|
40
|
+
|
|
41
|
+
// src/internal/memory/index-schema.ts
|
|
42
|
+
var SCHEMA_STATEMENTS = [
|
|
43
|
+
`CREATE TABLE IF NOT EXISTS files (
|
|
44
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
45
|
+
path TEXT UNIQUE NOT NULL,
|
|
46
|
+
rel_path TEXT NOT NULL,
|
|
47
|
+
mtime INTEGER NOT NULL,
|
|
48
|
+
hash TEXT NOT NULL,
|
|
49
|
+
source TEXT NOT NULL DEFAULT 'memory'
|
|
50
|
+
)`,
|
|
51
|
+
`CREATE TABLE IF NOT EXISTS chunks (
|
|
52
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
53
|
+
file_id INTEGER NOT NULL REFERENCES files(id) ON DELETE CASCADE,
|
|
54
|
+
start_line INTEGER NOT NULL,
|
|
55
|
+
end_line INTEGER NOT NULL,
|
|
56
|
+
text TEXT NOT NULL,
|
|
57
|
+
hash TEXT NOT NULL,
|
|
58
|
+
session_key TEXT
|
|
59
|
+
)`,
|
|
60
|
+
`CREATE VIRTUAL TABLE IF NOT EXISTS chunks_fts USING fts5(
|
|
61
|
+
text,
|
|
62
|
+
content='chunks',
|
|
63
|
+
content_rowid='id'
|
|
64
|
+
)`,
|
|
65
|
+
`CREATE TRIGGER IF NOT EXISTS chunks_fts_insert AFTER INSERT ON chunks BEGIN
|
|
66
|
+
INSERT INTO chunks_fts(rowid, text) VALUES (new.id, new.text);
|
|
67
|
+
END`,
|
|
68
|
+
`CREATE TRIGGER IF NOT EXISTS chunks_fts_delete AFTER DELETE ON chunks BEGIN
|
|
69
|
+
INSERT INTO chunks_fts(chunks_fts, rowid, text) VALUES ('delete', old.id, old.text);
|
|
70
|
+
END`,
|
|
71
|
+
`CREATE TABLE IF NOT EXISTS meta (
|
|
72
|
+
key TEXT PRIMARY KEY,
|
|
73
|
+
value TEXT
|
|
74
|
+
)`,
|
|
75
|
+
`CREATE INDEX IF NOT EXISTS idx_chunks_file_id ON chunks(file_id)`
|
|
76
|
+
];
|
|
77
|
+
var PRAGMA_STATEMENTS = [
|
|
78
|
+
"PRAGMA synchronous=NORMAL",
|
|
79
|
+
"PRAGMA foreign_keys=ON"
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
// src/internal/memory/index-db.ts
|
|
83
|
+
async function openMemoryDb(opts) {
|
|
84
|
+
return openSqliteResilient({
|
|
85
|
+
filePath: opts.filePath,
|
|
86
|
+
label: "memory-index",
|
|
87
|
+
recoverCorrupt: opts.recoverCorrupt,
|
|
88
|
+
onOpen: (db) => {
|
|
89
|
+
for (const pragma of PRAGMA_STATEMENTS) db.exec(pragma);
|
|
90
|
+
for (const stmt of SCHEMA_STATEMENTS) db.exec(stmt);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
function defaultIndexPath(cwd) {
|
|
95
|
+
return join(cwd, ".theokit", "memory", ".index", "memory.sqlite");
|
|
96
|
+
}
|
|
97
|
+
function requireLance() {
|
|
98
|
+
try {
|
|
99
|
+
const r = createRequire(import.meta.url);
|
|
100
|
+
return r("@lancedb/lancedb");
|
|
101
|
+
} catch (cause) {
|
|
102
|
+
throw new ConfigurationError(
|
|
103
|
+
'Lance backend selected but `@lancedb/lancedb` is not installed. Install with: `pnpm add @lancedb/lancedb`. SQLite remains available as the default (omit `backend: "lance"`).',
|
|
104
|
+
{ code: "lance_backend_unavailable", cause }
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
var LanceIndex = class _LanceIndex {
|
|
109
|
+
constructor(table, embedding, embeddingDim) {
|
|
110
|
+
this.table = table;
|
|
111
|
+
this.embedding = embedding;
|
|
112
|
+
this.embeddingDim = embeddingDim;
|
|
113
|
+
}
|
|
114
|
+
table;
|
|
115
|
+
embedding;
|
|
116
|
+
embeddingDim;
|
|
117
|
+
static async open(opts) {
|
|
118
|
+
const lance = requireLance();
|
|
119
|
+
const storagePath = opts.storagePath ?? join(opts.cwd, ".theokit", "memory", "lance");
|
|
120
|
+
mkdirSync(storagePath, { recursive: true });
|
|
121
|
+
const conn = await lance.connect(storagePath);
|
|
122
|
+
const dim = opts.embedding.dimension;
|
|
123
|
+
const tableName = "facts";
|
|
124
|
+
const existing = await conn.tableNames();
|
|
125
|
+
let table;
|
|
126
|
+
if (existing.includes(tableName)) {
|
|
127
|
+
table = await conn.openTable(tableName);
|
|
128
|
+
const schema = await table.schema();
|
|
129
|
+
const embField = schema.fields.find((f) => f.name === "embedding");
|
|
130
|
+
const existingDim = embField?.type?.listSize ?? embField?.type?.fixedSize;
|
|
131
|
+
if (typeof existingDim === "number" && existingDim !== dim) {
|
|
132
|
+
throw new ConfigurationError(
|
|
133
|
+
`Embedding dimension mismatch in Lance index: storage has ${existingDim}-dim vectors, current provider yields ${dim}-dim. Run \`theokit-migrate-memory\` after switching providers, or use a different storagePath.`,
|
|
134
|
+
{ code: "embedding_dimension_mismatch" }
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
} else {
|
|
138
|
+
const bootstrap = {
|
|
139
|
+
id: "__bootstrap__",
|
|
140
|
+
text: "",
|
|
141
|
+
source: "memory",
|
|
142
|
+
embedding: new Array(dim).fill(0),
|
|
143
|
+
namespace: "__bootstrap__",
|
|
144
|
+
scope: "__bootstrap__",
|
|
145
|
+
user_id: "__bootstrap__",
|
|
146
|
+
timestamp: 0
|
|
147
|
+
};
|
|
148
|
+
table = await conn.createTable(tableName, [bootstrap]);
|
|
149
|
+
await table.delete("namespace = '__bootstrap__'");
|
|
150
|
+
}
|
|
151
|
+
return new _LanceIndex(table, opts.embedding, dim);
|
|
152
|
+
}
|
|
153
|
+
async addFacts(facts) {
|
|
154
|
+
if (facts.length === 0) return;
|
|
155
|
+
const texts = facts.map((f) => f.text);
|
|
156
|
+
const embeddings = await this.embedding.embed(texts);
|
|
157
|
+
const rows = facts.map((f, i) => ({
|
|
158
|
+
...f,
|
|
159
|
+
embedding: embeddings[i] ?? new Array(this.embeddingDim).fill(0)
|
|
160
|
+
}));
|
|
161
|
+
await this.table.add(rows);
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Search facts by semantic similarity. EC-1: filters use Lance's
|
|
165
|
+
* structured object filter — NEVER string interpolation.
|
|
166
|
+
*/
|
|
167
|
+
async search(query, opts) {
|
|
168
|
+
const [embedding] = await this.embedding.embed([query]);
|
|
169
|
+
if (embedding === void 0) return [];
|
|
170
|
+
const predicates = [`namespace = '${escapeSqlValue(opts.namespace)}'`];
|
|
171
|
+
if (opts.scope !== void 0) {
|
|
172
|
+
predicates.push(`scope = '${escapeSqlValue(opts.scope)}'`);
|
|
173
|
+
}
|
|
174
|
+
let q = this.table.search(embedding).where(predicates.join(" AND "));
|
|
175
|
+
if (opts.limit !== void 0) q = q.limit(opts.limit);
|
|
176
|
+
const results = await q.toArray();
|
|
177
|
+
return results.filter((r) => opts.sources === void 0 || opts.sources.includes(r.source)).map((r) => ({
|
|
178
|
+
id: r.id,
|
|
179
|
+
text: r.text,
|
|
180
|
+
source: r.source,
|
|
181
|
+
namespace: r.namespace,
|
|
182
|
+
scope: r.scope,
|
|
183
|
+
userId: r.user_id,
|
|
184
|
+
// Lower _distance = better match; normalize to 0..1 (1=best).
|
|
185
|
+
score: 1 / (1 + (r._distance ?? 1))
|
|
186
|
+
}));
|
|
187
|
+
}
|
|
188
|
+
async countFacts(namespace) {
|
|
189
|
+
return this.table.countRows();
|
|
190
|
+
}
|
|
191
|
+
async removeFacts(ids) {
|
|
192
|
+
if (ids.length === 0) return;
|
|
193
|
+
const escaped = ids.map((id) => `'${id.replace(/'/g, "''")}'`).join(", ");
|
|
194
|
+
await this.table.delete(`id IN (${escaped})`);
|
|
195
|
+
}
|
|
196
|
+
async close() {
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
function escapeSqlValue(value) {
|
|
200
|
+
for (let i = 0; i < value.length; i++) {
|
|
201
|
+
const code = value.charCodeAt(i);
|
|
202
|
+
if (code === 0 || code >= 1 && code <= 31 || code === 127) {
|
|
203
|
+
throw new ConfigurationError(
|
|
204
|
+
`SQL filter value contains control character at position ${i} (0x${code.toString(16)}). This may indicate an injection attempt.`,
|
|
205
|
+
{ code: "sql_injection_blocked" }
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return value.replace(/\\/g, "\\\\").replace(/'/g, "''");
|
|
210
|
+
}
|
|
211
|
+
function lanceStoragePath(cwd) {
|
|
212
|
+
return join(cwd, ".theokit", "memory", "lance");
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// src/internal/memory/memory-index.ts
|
|
216
|
+
function parseSearchOptions(options = {}) {
|
|
217
|
+
return {
|
|
218
|
+
maxResults: Math.max(1, options.maxResults ?? 10),
|
|
219
|
+
minScore: options.minScore ?? 0
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// src/internal/memory/lance-memory-adapter.ts
|
|
224
|
+
var DEFAULT_NAMESPACE = "default";
|
|
225
|
+
var EMPTY_SYNC_RESULT = Object.freeze({
|
|
226
|
+
filesScanned: 0,
|
|
227
|
+
filesUpdated: 0,
|
|
228
|
+
chunksWritten: 0,
|
|
229
|
+
chunksEmbedded: 0
|
|
230
|
+
});
|
|
231
|
+
var LanceMemoryAdapter = class {
|
|
232
|
+
constructor(inner) {
|
|
233
|
+
this.inner = inner;
|
|
234
|
+
}
|
|
235
|
+
inner;
|
|
236
|
+
/**
|
|
237
|
+
* No-op for Lance — see file header. Returns zero counts so callers'
|
|
238
|
+
* existing logging (`filesScanned: X`) does not break.
|
|
239
|
+
*/
|
|
240
|
+
async sync() {
|
|
241
|
+
return EMPTY_SYNC_RESULT;
|
|
242
|
+
}
|
|
243
|
+
// jscpd:ignore-start — search signature + early-out is idiomatic
|
|
244
|
+
// overlap with IndexManager.search; further factoring would hurt
|
|
245
|
+
// readability (the bodies diverge sharply right after).
|
|
246
|
+
async search(query, options = {}) {
|
|
247
|
+
if (query.trim().length === 0) return [];
|
|
248
|
+
const { maxResults, minScore } = parseSearchOptions(options);
|
|
249
|
+
const lanceHits = await this.inner.search(query, {
|
|
250
|
+
namespace: DEFAULT_NAMESPACE,
|
|
251
|
+
limit: maxResults * 2,
|
|
252
|
+
...options.sources !== void 0 ? { sources: options.sources } : {}
|
|
253
|
+
});
|
|
254
|
+
return lanceHits.filter((h) => h.score >= minScore).slice(0, maxResults).map((h) => translateLanceHit(h, query));
|
|
255
|
+
}
|
|
256
|
+
status() {
|
|
257
|
+
return {
|
|
258
|
+
backend: "hybrid",
|
|
259
|
+
filesIndexed: 0,
|
|
260
|
+
chunksIndexed: 0
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
async close() {
|
|
264
|
+
await this.inner.close();
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Escape hatch for advanced callers (migration tool, benchmark script)
|
|
268
|
+
* that need direct access to addFacts/countFacts/removeFacts.
|
|
269
|
+
*/
|
|
270
|
+
unwrap() {
|
|
271
|
+
return this.inner;
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
function translateLanceHit(hit, query) {
|
|
275
|
+
const textScore = query !== void 0 ? computeTermOverlapScore(query, hit.text) : 0;
|
|
276
|
+
const vectorScore = hit.score;
|
|
277
|
+
const combined = 0.7 * vectorScore + 0.3 * textScore;
|
|
278
|
+
return {
|
|
279
|
+
path: hit.id,
|
|
280
|
+
startLine: 0,
|
|
281
|
+
endLine: 0,
|
|
282
|
+
score: combined,
|
|
283
|
+
textScore,
|
|
284
|
+
vectorScore,
|
|
285
|
+
snippet: hit.text.slice(0, 200),
|
|
286
|
+
source: hit.source,
|
|
287
|
+
citation: hit.id
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
function computeTermOverlapScore(query, text) {
|
|
291
|
+
const queryTerms = query.toLowerCase().split(/\s+/).filter((t) => t.length > 1);
|
|
292
|
+
if (queryTerms.length === 0) return 0;
|
|
293
|
+
const textLower = text.toLowerCase();
|
|
294
|
+
const matched = queryTerms.filter((term) => textLower.includes(term)).length;
|
|
295
|
+
return matched / queryTerms.length;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// src/internal/memory/index-manager-dispatch.ts
|
|
299
|
+
var VALID_BACKENDS = ["sqlite-vec", "lance"];
|
|
300
|
+
function assertValidBackend(backend) {
|
|
301
|
+
if (!VALID_BACKENDS.includes(backend)) {
|
|
302
|
+
throw new ConfigurationError(
|
|
303
|
+
`Invalid memory backend "${backend}". Valid values: ${VALID_BACKENDS.join(", ")}.`,
|
|
304
|
+
{ code: "invalid_memory_backend" }
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
async function openLanceIndex(opts) {
|
|
309
|
+
if (opts.embedding === void 0) {
|
|
310
|
+
throw new ConfigurationError(
|
|
311
|
+
"Lance backend requires an embedding runtime. Pass `embedding: { provider, model, apiKey }` in Memory.create options (or omit `backend` to use SQLite default).",
|
|
312
|
+
{ code: "lance_requires_embedding" }
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
const lance = await LanceIndex.open({
|
|
316
|
+
cwd: opts.cwd,
|
|
317
|
+
embedding: opts.embedding,
|
|
318
|
+
...opts.filePath !== void 0 ? { storagePath: opts.filePath } : {}
|
|
319
|
+
});
|
|
320
|
+
return new LanceMemoryAdapter(lance);
|
|
321
|
+
}
|
|
322
|
+
function legacyMemoryJsonPath(cwd, config) {
|
|
323
|
+
if (config.storePath !== void 0) {
|
|
324
|
+
return resolve(cwd, config.storePath);
|
|
325
|
+
}
|
|
326
|
+
const namespace = sanitizeIdentifier(config.namespace ?? "default");
|
|
327
|
+
const scope = sanitizeIdentifier(config.scope ?? "agent", { maxLen: 16 });
|
|
328
|
+
const userId = sanitizeIdentifier(config.userId ?? "default");
|
|
329
|
+
return safePathJoin(cwd, ".theokit", "memory", namespace, `${scope}-${userId}.json`);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// src/internal/memory/storage/markdown-store.ts
|
|
333
|
+
var MEMORY_MD_HEADER = "# Memory\n\n> Auto-managed by @theokit/sdk. Edit freely \u2014 the SDK reads from here.\n";
|
|
334
|
+
var FACTS_HEADING = "## Facts";
|
|
335
|
+
function memoryDir(cwd) {
|
|
336
|
+
return join(cwd, ".theokit", "memory");
|
|
337
|
+
}
|
|
338
|
+
function memoryMdPath(cwd) {
|
|
339
|
+
return join(memoryDir(cwd), "MEMORY.md");
|
|
340
|
+
}
|
|
341
|
+
function notesDir(cwd) {
|
|
342
|
+
return join(memoryDir(cwd), "notes");
|
|
343
|
+
}
|
|
344
|
+
async function readFactsFromMarkdown(cwd) {
|
|
345
|
+
let raw;
|
|
346
|
+
try {
|
|
347
|
+
raw = await readFile(memoryMdPath(cwd), "utf8");
|
|
348
|
+
} catch {
|
|
349
|
+
return [];
|
|
350
|
+
}
|
|
351
|
+
return parseFactsSection(raw);
|
|
352
|
+
}
|
|
353
|
+
function appendFactToMarkdown(cwd, fact) {
|
|
354
|
+
return withCwdMutex(memoryDir(cwd), async () => {
|
|
355
|
+
const path = memoryMdPath(cwd);
|
|
356
|
+
let raw = "";
|
|
357
|
+
try {
|
|
358
|
+
raw = await readFile(path, "utf8");
|
|
359
|
+
} catch {
|
|
360
|
+
raw = "";
|
|
361
|
+
}
|
|
362
|
+
const sanitized = redactSecrets(fact.text);
|
|
363
|
+
const next = insertFactBullet(raw, sanitized);
|
|
364
|
+
await mkdir(memoryDir(cwd), { recursive: true });
|
|
365
|
+
await replaceFileAtomic(path, next);
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
function parseFactsSection(raw) {
|
|
369
|
+
const idx = raw.indexOf(FACTS_HEADING);
|
|
370
|
+
if (idx === -1) return [];
|
|
371
|
+
const tail = raw.slice(idx + FACTS_HEADING.length);
|
|
372
|
+
const nextHeading = tail.search(/\n#{1,2}\s/);
|
|
373
|
+
const block = nextHeading === -1 ? tail : tail.slice(0, nextHeading);
|
|
374
|
+
return block.split("\n").map((line) => line.trim()).filter((line) => line.startsWith("- ")).map((line) => ({ text: line.slice(2).trim() }));
|
|
375
|
+
}
|
|
376
|
+
function insertFactBullet(raw, fact) {
|
|
377
|
+
const bullet = `- ${fact}`;
|
|
378
|
+
if (raw.length === 0) {
|
|
379
|
+
return `${MEMORY_MD_HEADER}
|
|
380
|
+
${FACTS_HEADING}
|
|
381
|
+
|
|
382
|
+
${bullet}
|
|
383
|
+
`;
|
|
384
|
+
}
|
|
385
|
+
const idx = raw.indexOf(FACTS_HEADING);
|
|
386
|
+
if (idx === -1) {
|
|
387
|
+
const sep = raw.endsWith("\n") ? "" : "\n";
|
|
388
|
+
return `${raw}${sep}
|
|
389
|
+
${FACTS_HEADING}
|
|
390
|
+
|
|
391
|
+
${bullet}
|
|
392
|
+
`;
|
|
393
|
+
}
|
|
394
|
+
const after = idx + FACTS_HEADING.length;
|
|
395
|
+
const nextHeading = raw.slice(after).search(/\n#{1,2}\s/);
|
|
396
|
+
if (nextHeading === -1) {
|
|
397
|
+
const trailing = raw.endsWith("\n") ? "" : "\n";
|
|
398
|
+
return `${raw}${trailing}${bullet}
|
|
399
|
+
`;
|
|
400
|
+
}
|
|
401
|
+
const insertAt = after + nextHeading;
|
|
402
|
+
return `${raw.slice(0, insertAt)}
|
|
403
|
+
${bullet}${raw.slice(insertAt)}`;
|
|
404
|
+
}
|
|
405
|
+
async function readFacts(cwd, config) {
|
|
406
|
+
if (!config.enabled) return [];
|
|
407
|
+
return readFactsFromMarkdown(cwd);
|
|
408
|
+
}
|
|
409
|
+
async function appendFact(cwd, config, fact) {
|
|
410
|
+
if (!config.enabled) return;
|
|
411
|
+
await appendFactToMarkdown(cwd, fact);
|
|
412
|
+
}
|
|
413
|
+
var MAX_TURN_CHARS = 2e3;
|
|
414
|
+
function sessionsDir(cwd) {
|
|
415
|
+
return join(memoryDir(cwd), "sessions");
|
|
416
|
+
}
|
|
417
|
+
function sessionSummaryPath(cwd, runId) {
|
|
418
|
+
return join(sessionsDir(cwd), `${safeFilenameForId(runId, { maxLen: 128 })}.md`);
|
|
419
|
+
}
|
|
420
|
+
function truncate(text) {
|
|
421
|
+
if (text.length <= MAX_TURN_CHARS) return text;
|
|
422
|
+
return `${text.slice(0, MAX_TURN_CHARS)}\u2026`;
|
|
423
|
+
}
|
|
424
|
+
async function writeSessionSummary(input) {
|
|
425
|
+
if (input.status !== "finished") return;
|
|
426
|
+
const path = sessionSummaryPath(input.cwd, input.runId);
|
|
427
|
+
await mkdir(sessionsDir(input.cwd), { recursive: true });
|
|
428
|
+
const safeUser = redactSecrets(truncate(input.userText));
|
|
429
|
+
const safeAssistant = redactSecrets(truncate(input.assistantText));
|
|
430
|
+
const iso = new Date(input.at).toISOString();
|
|
431
|
+
const body = [
|
|
432
|
+
"---",
|
|
433
|
+
`runId: ${input.runId}`,
|
|
434
|
+
`agentId: ${input.agentId}`,
|
|
435
|
+
`at: ${iso}`,
|
|
436
|
+
`status: ${input.status}`,
|
|
437
|
+
"---",
|
|
438
|
+
"",
|
|
439
|
+
"## User",
|
|
440
|
+
"",
|
|
441
|
+
safeUser,
|
|
442
|
+
"",
|
|
443
|
+
"## Assistant",
|
|
444
|
+
"",
|
|
445
|
+
safeAssistant,
|
|
446
|
+
""
|
|
447
|
+
].join("\n");
|
|
448
|
+
await replaceFileAtomic(path, body);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// src/internal/memory/storage/session-loader.ts
|
|
452
|
+
async function discoverSessionFiles(cwd) {
|
|
453
|
+
let entries;
|
|
454
|
+
try {
|
|
455
|
+
entries = await readdir(sessionsDir(cwd));
|
|
456
|
+
} catch {
|
|
457
|
+
return [];
|
|
458
|
+
}
|
|
459
|
+
const root = memoryDir(cwd);
|
|
460
|
+
return entries.filter((entry) => entry.endsWith(".md")).map((entry) => {
|
|
461
|
+
const absolutePath = join(sessionsDir(cwd), entry);
|
|
462
|
+
return {
|
|
463
|
+
absolutePath,
|
|
464
|
+
relPath: relativeToRoot(root, absolutePath)
|
|
465
|
+
};
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
function relativeToRoot(root, absolutePath) {
|
|
469
|
+
if (absolutePath.startsWith(`${root}/`)) return absolutePath.slice(root.length + 1);
|
|
470
|
+
return absolutePath;
|
|
471
|
+
}
|
|
472
|
+
function wikiDir(cwd) {
|
|
473
|
+
return join(memoryDir(cwd), "wiki");
|
|
474
|
+
}
|
|
475
|
+
async function discoverWikiFiles(cwd) {
|
|
476
|
+
let entries;
|
|
477
|
+
try {
|
|
478
|
+
entries = await readdir(wikiDir(cwd));
|
|
479
|
+
} catch {
|
|
480
|
+
return [];
|
|
481
|
+
}
|
|
482
|
+
const root = memoryDir(cwd);
|
|
483
|
+
return entries.filter((entry) => entry.endsWith(".md")).map((entry) => ({
|
|
484
|
+
absolutePath: join(wikiDir(cwd), entry),
|
|
485
|
+
relPath: join("wiki", entry)
|
|
486
|
+
})).map((file) => ({
|
|
487
|
+
absolutePath: file.absolutePath,
|
|
488
|
+
relPath: relativeToRoot2(root, file.absolutePath)
|
|
489
|
+
}));
|
|
490
|
+
}
|
|
491
|
+
function relativeToRoot2(root, absolutePath) {
|
|
492
|
+
if (absolutePath.startsWith(`${root}/`)) return absolutePath.slice(root.length + 1);
|
|
493
|
+
return absolutePath;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// src/internal/memory/index-manager-helpers.ts
|
|
497
|
+
function resolveWeights(options) {
|
|
498
|
+
const vectorWeight = options.vectorWeight ?? 0.6;
|
|
499
|
+
const textWeight = options.textWeight ?? 0.4;
|
|
500
|
+
const total = vectorWeight + textWeight || 1;
|
|
501
|
+
return { vectorWeight, textWeight, total };
|
|
502
|
+
}
|
|
503
|
+
function blendScores(hit, vectorScore, weights) {
|
|
504
|
+
const score = (vectorScore * weights.vectorWeight + hit.textScore * weights.textWeight) / weights.total;
|
|
505
|
+
return {
|
|
506
|
+
path: hit.path,
|
|
507
|
+
startLine: hit.startLine,
|
|
508
|
+
endLine: hit.endLine,
|
|
509
|
+
score,
|
|
510
|
+
textScore: hit.textScore,
|
|
511
|
+
snippet: hit.snippet,
|
|
512
|
+
source: hit.source,
|
|
513
|
+
citation: hit.citation,
|
|
514
|
+
...vectorScore > 0 ? { vectorScore } : {}
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
async function collectMarkdownFiles(cwd) {
|
|
518
|
+
const root = memoryDir(cwd);
|
|
519
|
+
const results = [];
|
|
520
|
+
try {
|
|
521
|
+
await stat(memoryMdPath(cwd));
|
|
522
|
+
results.push({
|
|
523
|
+
absolutePath: memoryMdPath(cwd),
|
|
524
|
+
relPath: relative(root, memoryMdPath(cwd)),
|
|
525
|
+
source: "memory"
|
|
526
|
+
});
|
|
527
|
+
} catch {
|
|
528
|
+
}
|
|
529
|
+
try {
|
|
530
|
+
const entries = await readdir(notesDir(cwd));
|
|
531
|
+
for (const entry of entries) {
|
|
532
|
+
if (!entry.endsWith(".md")) continue;
|
|
533
|
+
const abs = join(notesDir(cwd), entry);
|
|
534
|
+
results.push({ absolutePath: abs, relPath: relative(root, abs), source: "memory" });
|
|
535
|
+
}
|
|
536
|
+
} catch {
|
|
537
|
+
}
|
|
538
|
+
const wikiFiles = await discoverWikiFiles(cwd);
|
|
539
|
+
for (const wiki of wikiFiles) {
|
|
540
|
+
results.push({
|
|
541
|
+
absolutePath: wiki.absolutePath,
|
|
542
|
+
relPath: wiki.relPath,
|
|
543
|
+
source: "wiki"
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
const sessionFiles = await discoverSessionFiles(cwd);
|
|
547
|
+
for (const session of sessionFiles) {
|
|
548
|
+
results.push({
|
|
549
|
+
absolutePath: session.absolutePath,
|
|
550
|
+
relPath: session.relPath,
|
|
551
|
+
source: "sessions"
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
return results;
|
|
555
|
+
}
|
|
556
|
+
function sha256(text) {
|
|
557
|
+
return createHash("sha256").update(text).digest("hex");
|
|
558
|
+
}
|
|
559
|
+
function truncateSnippet(text) {
|
|
560
|
+
const max = 500;
|
|
561
|
+
return text.length <= max ? text : `${text.slice(0, max)}\u2026`;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// src/internal/memory/sqlite-vec-loader.ts
|
|
565
|
+
async function loadSqliteVecExtension(db) {
|
|
566
|
+
try {
|
|
567
|
+
const mod = await import('sqlite-vec');
|
|
568
|
+
const loadFn = mod.load;
|
|
569
|
+
if (typeof loadFn !== "function") {
|
|
570
|
+
throw new Error("sqlite-vec module exposes no `load` export");
|
|
571
|
+
}
|
|
572
|
+
loadFn(db);
|
|
573
|
+
} catch (cause) {
|
|
574
|
+
const message = cause instanceof Error ? cause.message : String(cause);
|
|
575
|
+
throw new ConfigurationError(
|
|
576
|
+
`sqlite-vec extension unavailable. Install \`sqlite-vec\` and ensure the native binary matches your Node + OS. Cause: ${message}`,
|
|
577
|
+
{ code: "sqlite_vec_unavailable", cause }
|
|
578
|
+
);
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
var HEADING_RE = /^(#{1,6})\s+(.+?)\s*$/;
|
|
582
|
+
function chunkMarkdown(text, options = {}) {
|
|
583
|
+
const maxChars = options.maxChars ?? 800;
|
|
584
|
+
if (text.length === 0) return [];
|
|
585
|
+
const lines = text.split("\n");
|
|
586
|
+
const acc = { chunks: [], lines: [], start: 1, heading: void 0 };
|
|
587
|
+
for (let i = 0; i < lines.length; i++) {
|
|
588
|
+
const line = lines[i] ?? "";
|
|
589
|
+
const lineNumber = i + 1;
|
|
590
|
+
processLine(acc, line, lineNumber, maxChars);
|
|
591
|
+
}
|
|
592
|
+
flushAccumulator(acc, lines.length, maxChars);
|
|
593
|
+
return acc.chunks;
|
|
594
|
+
}
|
|
595
|
+
function processLine(acc, line, lineNumber, maxChars) {
|
|
596
|
+
const headingMatch = HEADING_RE.exec(line);
|
|
597
|
+
const isBlank = line.trim().length === 0;
|
|
598
|
+
if (headingMatch !== null && acc.lines.length > 0) {
|
|
599
|
+
flushAccumulator(acc, lineNumber - 1, maxChars);
|
|
600
|
+
}
|
|
601
|
+
if (headingMatch !== null) acc.heading = headingMatch[2];
|
|
602
|
+
acc.lines.push(line);
|
|
603
|
+
if (isBlank && acc.lines.length > 1) {
|
|
604
|
+
const joined = acc.lines.join("\n");
|
|
605
|
+
if (joined.trim().length > 0) flushAccumulator(acc, lineNumber, maxChars);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
function flushAccumulator(acc, endLineExclusive, maxChars) {
|
|
609
|
+
if (acc.lines.length === 0) return;
|
|
610
|
+
const chunkText = acc.lines.join("\n");
|
|
611
|
+
if (chunkText.trim().length === 0) {
|
|
612
|
+
acc.lines = [];
|
|
613
|
+
acc.start = endLineExclusive + 1;
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
if (chunkText.length > maxChars) {
|
|
617
|
+
pushOversizedSlices(acc.chunks, chunkText, acc.start, acc.heading, maxChars);
|
|
618
|
+
} else {
|
|
619
|
+
acc.chunks.push(buildChunk(chunkText, acc.start, endLineExclusive, acc.heading));
|
|
620
|
+
}
|
|
621
|
+
acc.lines = [];
|
|
622
|
+
acc.start = endLineExclusive + 1;
|
|
623
|
+
}
|
|
624
|
+
function buildChunk(text, startLine, endLine, heading) {
|
|
625
|
+
return {
|
|
626
|
+
startLine,
|
|
627
|
+
endLine,
|
|
628
|
+
text,
|
|
629
|
+
hash: createHash("sha256").update(text).digest("hex"),
|
|
630
|
+
...heading !== void 0 ? { heading } : {}
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
function pushOversizedSlices(chunks, text, startLine, heading, maxChars) {
|
|
634
|
+
let remaining = text;
|
|
635
|
+
let lineCursor = startLine;
|
|
636
|
+
while (remaining.length > maxChars) {
|
|
637
|
+
const splitAt = findWordBoundarySplit(remaining, maxChars);
|
|
638
|
+
const slice = remaining.slice(0, splitAt);
|
|
639
|
+
const sliceLines = slice.split("\n").length;
|
|
640
|
+
chunks.push(buildChunk(slice, lineCursor, lineCursor + sliceLines - 1, heading));
|
|
641
|
+
remaining = remaining.slice(splitAt).replace(/^\s+/, "");
|
|
642
|
+
lineCursor += sliceLines - 1;
|
|
643
|
+
}
|
|
644
|
+
if (remaining.length > 0) {
|
|
645
|
+
const sliceLines = remaining.split("\n").length;
|
|
646
|
+
chunks.push(buildChunk(remaining, lineCursor, lineCursor + sliceLines - 1, heading));
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
function findWordBoundarySplit(text, maxChars) {
|
|
650
|
+
if (text.length <= maxChars) return text.length;
|
|
651
|
+
for (let i = maxChars; i > Math.max(0, maxChars - 200); i--) {
|
|
652
|
+
if (/\s/.test(text[i] ?? "x")) return i;
|
|
653
|
+
}
|
|
654
|
+
return maxChars;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
// src/internal/memory/vec-index.ts
|
|
658
|
+
var META_KEY_PROVIDER_ID = "embedding.providerId";
|
|
659
|
+
var META_KEY_MODEL = "embedding.model";
|
|
660
|
+
var META_KEY_DIMENSION = "embedding.dimension";
|
|
661
|
+
function readEmbeddingIdentity(db) {
|
|
662
|
+
const get = (key) => {
|
|
663
|
+
const row = db.prepare("SELECT value FROM meta WHERE key = ?").get(key);
|
|
664
|
+
return row !== void 0 ? String(row.value) : void 0;
|
|
665
|
+
};
|
|
666
|
+
const providerId = get(META_KEY_PROVIDER_ID);
|
|
667
|
+
const model = get(META_KEY_MODEL);
|
|
668
|
+
const dimRaw = get(META_KEY_DIMENSION);
|
|
669
|
+
if (providerId === void 0 || model === void 0 || dimRaw === void 0) return void 0;
|
|
670
|
+
const dimension = Number(dimRaw);
|
|
671
|
+
if (!Number.isFinite(dimension) || dimension <= 0) return void 0;
|
|
672
|
+
return { providerId, model, dimension };
|
|
673
|
+
}
|
|
674
|
+
function writeEmbeddingIdentity(db, identity) {
|
|
675
|
+
const stmt = db.prepare(
|
|
676
|
+
"INSERT INTO meta (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value"
|
|
677
|
+
);
|
|
678
|
+
stmt.run(META_KEY_PROVIDER_ID, identity.providerId);
|
|
679
|
+
stmt.run(META_KEY_MODEL, identity.model);
|
|
680
|
+
stmt.run(META_KEY_DIMENSION, String(identity.dimension));
|
|
681
|
+
}
|
|
682
|
+
function identityMatches(a, b) {
|
|
683
|
+
return a.providerId === b.providerId && a.model === b.model && a.dimension === b.dimension;
|
|
684
|
+
}
|
|
685
|
+
function dropVectorIndex(db) {
|
|
686
|
+
db.exec("DROP TABLE IF EXISTS embeddings");
|
|
687
|
+
}
|
|
688
|
+
function createVectorIndex(db, dimension) {
|
|
689
|
+
db.exec(`CREATE VIRTUAL TABLE IF NOT EXISTS embeddings USING vec0(
|
|
690
|
+
chunk_id INTEGER PRIMARY KEY,
|
|
691
|
+
vec FLOAT[${dimension}]
|
|
692
|
+
)`);
|
|
693
|
+
}
|
|
694
|
+
function packVector(vec) {
|
|
695
|
+
const f32 = new Float32Array(vec.length);
|
|
696
|
+
for (let i = 0; i < vec.length; i++) f32[i] = vec[i] ?? 0;
|
|
697
|
+
return Buffer.from(f32.buffer);
|
|
698
|
+
}
|
|
699
|
+
function upsertEmbedding(db, chunkId, vec) {
|
|
700
|
+
const id = BigInt(chunkId);
|
|
701
|
+
db.prepare("DELETE FROM embeddings WHERE chunk_id = ?").run(id);
|
|
702
|
+
db.prepare("INSERT INTO embeddings (chunk_id, vec) VALUES (?, ?)").run(id, packVector(vec));
|
|
703
|
+
}
|
|
704
|
+
function vectorSearch(db, query, k) {
|
|
705
|
+
const rows = db.prepare(
|
|
706
|
+
`SELECT chunk_id, distance FROM embeddings
|
|
707
|
+
WHERE vec MATCH ? AND k = ?
|
|
708
|
+
ORDER BY distance`
|
|
709
|
+
).all(packVector(query), BigInt(k));
|
|
710
|
+
return rows.map((row) => ({ chunk_id: Number(row.chunk_id), distance: Number(row.distance) }));
|
|
711
|
+
}
|
|
712
|
+
async function embedMissingChunks(args) {
|
|
713
|
+
const rows = args.db.prepare(
|
|
714
|
+
`SELECT chunks.id as id, chunks.text as text
|
|
715
|
+
FROM chunks
|
|
716
|
+
LEFT JOIN embeddings ON embeddings.chunk_id = chunks.id
|
|
717
|
+
WHERE embeddings.chunk_id IS NULL`
|
|
718
|
+
).all();
|
|
719
|
+
if (rows.length === 0) return 0;
|
|
720
|
+
const normalized = rows.map((row) => ({ id: Number(row.id), text: String(row.text ?? "") }));
|
|
721
|
+
const vectors = await args.runtime.embed(normalized.map((r) => r.text));
|
|
722
|
+
for (let i = 0; i < normalized.length; i++) {
|
|
723
|
+
const row = normalized[i];
|
|
724
|
+
const vector = vectors[i];
|
|
725
|
+
if (row === void 0 || vector === void 0) continue;
|
|
726
|
+
upsertEmbedding(args.db, row.id, vector);
|
|
727
|
+
}
|
|
728
|
+
return normalized.length;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
// src/internal/memory/index-manager.ts
|
|
732
|
+
var queryVectorCache = new LruEmbeddingCache(2e3);
|
|
733
|
+
var IndexManager = class _IndexManager {
|
|
734
|
+
constructor(cwd, db, embedding) {
|
|
735
|
+
this.cwd = cwd;
|
|
736
|
+
this.db = db;
|
|
737
|
+
this.embedding = embedding;
|
|
738
|
+
}
|
|
739
|
+
cwd;
|
|
740
|
+
db;
|
|
741
|
+
embedding;
|
|
742
|
+
lastSyncMs;
|
|
743
|
+
vectorReady = false;
|
|
744
|
+
static async open(opts) {
|
|
745
|
+
const backend = opts.backend ?? "sqlite-vec";
|
|
746
|
+
assertValidBackend(backend);
|
|
747
|
+
if (backend === "lance") return await openLanceIndex(opts);
|
|
748
|
+
return await _IndexManager.openSqliteInternal(opts);
|
|
749
|
+
}
|
|
750
|
+
/** Internal SQLite-path open. Renamed from previous public `open`. */
|
|
751
|
+
static async openSqliteInternal(opts) {
|
|
752
|
+
const filePath = opts.filePath ?? defaultIndexPath(opts.cwd);
|
|
753
|
+
const db = await openMemoryDb({ filePath });
|
|
754
|
+
const manager = new _IndexManager(opts.cwd, db, opts.embedding);
|
|
755
|
+
if (opts.embedding !== void 0) await manager.initVectorBackend(opts.embedding);
|
|
756
|
+
return manager;
|
|
757
|
+
}
|
|
758
|
+
async initVectorBackend(runtime) {
|
|
759
|
+
await loadSqliteVecExtension(this.db);
|
|
760
|
+
const currentIdentity = {
|
|
761
|
+
providerId: runtime.id,
|
|
762
|
+
model: runtime.model,
|
|
763
|
+
dimension: runtime.dimension
|
|
764
|
+
};
|
|
765
|
+
const persisted = readEmbeddingIdentity(this.db);
|
|
766
|
+
if (persisted !== void 0 && !identityMatches(persisted, currentIdentity)) {
|
|
767
|
+
dropVectorIndex(this.db);
|
|
768
|
+
}
|
|
769
|
+
createVectorIndex(this.db, runtime.dimension);
|
|
770
|
+
writeEmbeddingIdentity(this.db, currentIdentity);
|
|
771
|
+
this.vectorReady = true;
|
|
772
|
+
}
|
|
773
|
+
/** Walk the memory corpus + (re)index changed files. */
|
|
774
|
+
async sync() {
|
|
775
|
+
const files = await collectMarkdownFiles(this.cwd);
|
|
776
|
+
let filesUpdated = 0;
|
|
777
|
+
let chunksWritten = 0;
|
|
778
|
+
const existingByPath = this.loadFilesIndex();
|
|
779
|
+
for (const entry of files) {
|
|
780
|
+
const raw = await readFile(entry.absolutePath, "utf8");
|
|
781
|
+
const hash = sha256(raw);
|
|
782
|
+
const existing = existingByPath.get(entry.absolutePath);
|
|
783
|
+
if (existing !== void 0 && existing.hash === hash) continue;
|
|
784
|
+
const stats = await stat(entry.absolutePath);
|
|
785
|
+
const fileId = this.upsertFile(
|
|
786
|
+
entry.absolutePath,
|
|
787
|
+
entry.relPath,
|
|
788
|
+
hash,
|
|
789
|
+
stats.mtimeMs,
|
|
790
|
+
entry.source
|
|
791
|
+
);
|
|
792
|
+
this.deleteChunksForFile(fileId);
|
|
793
|
+
const chunks = chunkMarkdown(raw);
|
|
794
|
+
for (const chunk of chunks) {
|
|
795
|
+
this.insertChunk(fileId, chunk.startLine, chunk.endLine, chunk.text, chunk.hash);
|
|
796
|
+
}
|
|
797
|
+
filesUpdated += 1;
|
|
798
|
+
chunksWritten += chunks.length;
|
|
799
|
+
}
|
|
800
|
+
let chunksEmbedded = 0;
|
|
801
|
+
if (this.vectorReady && this.embedding !== void 0) {
|
|
802
|
+
chunksEmbedded = await embedMissingChunks({ db: this.db, runtime: this.embedding });
|
|
803
|
+
}
|
|
804
|
+
this.lastSyncMs = Date.now();
|
|
805
|
+
return { filesScanned: files.length, filesUpdated, chunksWritten, chunksEmbedded };
|
|
806
|
+
}
|
|
807
|
+
async search(query, options = {}) {
|
|
808
|
+
if (query.trim().length === 0) return [];
|
|
809
|
+
const { maxResults, minScore } = parseSearchOptions(options);
|
|
810
|
+
const textHits = this.ftsSearch(query, maxResults * 2);
|
|
811
|
+
const vectorHitsById = await this.vectorSearchById(query, maxResults * 2);
|
|
812
|
+
const combined = this.combineHybridScores(textHits, vectorHitsById, options);
|
|
813
|
+
return combined.filter((h) => h.score >= minScore).filter((h) => options.sources === void 0 || options.sources.includes(h.source)).slice(0, maxResults);
|
|
814
|
+
}
|
|
815
|
+
status() {
|
|
816
|
+
const files = this.db.prepare("SELECT COUNT(*) as n FROM files").get() ?? { n: 0 };
|
|
817
|
+
const chunks = this.db.prepare("SELECT COUNT(*) as n FROM chunks").get() ?? { n: 0 };
|
|
818
|
+
const status = {
|
|
819
|
+
backend: this.vectorReady ? "hybrid" : "fts-only",
|
|
820
|
+
filesIndexed: Number(files.n ?? 0),
|
|
821
|
+
chunksIndexed: Number(chunks.n ?? 0)
|
|
822
|
+
};
|
|
823
|
+
if (this.lastSyncMs !== void 0) status.lastSyncMs = this.lastSyncMs;
|
|
824
|
+
return status;
|
|
825
|
+
}
|
|
826
|
+
// ───── search internals ──────────────────────────────────────────────
|
|
827
|
+
ftsSearch(query, limit) {
|
|
828
|
+
const sanitized = sanitizeFts5Query(query);
|
|
829
|
+
if (sanitized.length === 0) return [];
|
|
830
|
+
const stmt = this.db.prepare(
|
|
831
|
+
`SELECT chunks.id as id, files.rel_path as rel_path, files.source as source,
|
|
832
|
+
chunks.start_line as start_line, chunks.end_line as end_line,
|
|
833
|
+
chunks.text as text, bm25(chunks_fts) as bm25_score
|
|
834
|
+
FROM chunks_fts
|
|
835
|
+
JOIN chunks ON chunks_fts.rowid = chunks.id
|
|
836
|
+
JOIN files ON chunks.file_id = files.id
|
|
837
|
+
WHERE chunks_fts MATCH ?
|
|
838
|
+
ORDER BY bm25_score
|
|
839
|
+
LIMIT ?`
|
|
840
|
+
);
|
|
841
|
+
let rows = [];
|
|
842
|
+
try {
|
|
843
|
+
rows = stmt.all(sanitized, limit);
|
|
844
|
+
} catch {
|
|
845
|
+
return this.likeSearchFallback(query, limit);
|
|
846
|
+
}
|
|
847
|
+
return rows.map((row) => {
|
|
848
|
+
const bm25 = Number(row.bm25_score ?? 0);
|
|
849
|
+
const textScore = bm25 < 0 ? 1 / (1 + Math.abs(bm25)) : 1 / (1 + bm25);
|
|
850
|
+
const startLine = Number(row.start_line ?? 0);
|
|
851
|
+
const endLine = Number(row.end_line ?? 0);
|
|
852
|
+
const path = String(row.rel_path);
|
|
853
|
+
return {
|
|
854
|
+
path,
|
|
855
|
+
startLine,
|
|
856
|
+
endLine,
|
|
857
|
+
score: textScore,
|
|
858
|
+
textScore,
|
|
859
|
+
snippet: truncateSnippet(String(row.text ?? "")),
|
|
860
|
+
source: String(row.source),
|
|
861
|
+
citation: `${path}:${startLine}-${endLine}`,
|
|
862
|
+
// sneak the chunk id through for the hybrid join below
|
|
863
|
+
// (cast away later)
|
|
864
|
+
chunkId: Number(row.id)
|
|
865
|
+
};
|
|
866
|
+
});
|
|
867
|
+
}
|
|
868
|
+
/**
|
|
869
|
+
* T4.8 — LIKE-based fallback for CJK and other scripts that FTS5's
|
|
870
|
+
* default tokenizer cannot segment. Slower than FTS5 (full table scan)
|
|
871
|
+
* but correct for any Unicode input. Returns the same shape as
|
|
872
|
+
* `ftsSearch` so callers are unaware of the fallback.
|
|
873
|
+
*/
|
|
874
|
+
likeSearchFallback(query, limit) {
|
|
875
|
+
const pattern = `%${query.replace(/%/g, "\\%").replace(/_/g, "\\_")}%`;
|
|
876
|
+
const stmt = this.db.prepare(
|
|
877
|
+
`SELECT chunks.id as id, files.rel_path as rel_path, files.source as source,
|
|
878
|
+
chunks.start_line as start_line, chunks.end_line as end_line,
|
|
879
|
+
chunks.text as text
|
|
880
|
+
FROM chunks
|
|
881
|
+
JOIN files ON chunks.file_id = files.id
|
|
882
|
+
WHERE chunks.text LIKE ? ESCAPE '\\'
|
|
883
|
+
LIMIT ?`
|
|
884
|
+
);
|
|
885
|
+
const rows = stmt.all(pattern, limit);
|
|
886
|
+
return rows.map((row) => {
|
|
887
|
+
const path = String(row.rel_path ?? "");
|
|
888
|
+
const startLine = Number(row.start_line ?? 0);
|
|
889
|
+
const endLine = Number(row.end_line ?? 0);
|
|
890
|
+
return {
|
|
891
|
+
path,
|
|
892
|
+
startLine,
|
|
893
|
+
endLine,
|
|
894
|
+
score: 0.5,
|
|
895
|
+
// LIKE has no relevance score — use a neutral midpoint
|
|
896
|
+
textScore: 0.5,
|
|
897
|
+
snippet: truncateSnippet(String(row.text ?? "")),
|
|
898
|
+
source: String(row.source),
|
|
899
|
+
citation: `${path}:${startLine}-${endLine}`,
|
|
900
|
+
chunkId: Number(row.id)
|
|
901
|
+
};
|
|
902
|
+
});
|
|
903
|
+
}
|
|
904
|
+
async vectorSearchById(query, limit) {
|
|
905
|
+
if (!this.vectorReady || this.embedding === void 0) return /* @__PURE__ */ new Map();
|
|
906
|
+
const cacheKey = createHash("sha256").update(query).digest("hex");
|
|
907
|
+
const cached = queryVectorCache.get(cacheKey);
|
|
908
|
+
const queryVec = cached ?? (await this.embedding.embed([query]))[0];
|
|
909
|
+
if (queryVec === void 0) return /* @__PURE__ */ new Map();
|
|
910
|
+
if (cached === void 0) queryVectorCache.set(cacheKey, queryVec);
|
|
911
|
+
const rows = vectorSearch(this.db, queryVec, limit);
|
|
912
|
+
const out = /* @__PURE__ */ new Map();
|
|
913
|
+
for (const row of rows) {
|
|
914
|
+
const score = 1 / (1 + Math.max(0, row.distance));
|
|
915
|
+
out.set(row.chunk_id, { vectorScore: score });
|
|
916
|
+
}
|
|
917
|
+
return out;
|
|
918
|
+
}
|
|
919
|
+
combineHybridScores(textHits, vectorHitsById, options) {
|
|
920
|
+
const weights = resolveWeights(options);
|
|
921
|
+
const merged = this.mergeHits(textHits, vectorHitsById);
|
|
922
|
+
const combined = [...merged.values()].map(
|
|
923
|
+
(hit) => blendScores(hit, vectorHitsById.get(hit.chunkId)?.vectorScore ?? 0, weights)
|
|
924
|
+
);
|
|
925
|
+
return combined.sort((a, b) => b.score - a.score);
|
|
926
|
+
}
|
|
927
|
+
mergeHits(textHits, vectorHitsById) {
|
|
928
|
+
const merged = /* @__PURE__ */ new Map();
|
|
929
|
+
for (const hit of textHits) merged.set(hit.chunkId, hit);
|
|
930
|
+
const missingIds = [...vectorHitsById.keys()].filter((id) => !merged.has(id));
|
|
931
|
+
if (missingIds.length > 0) {
|
|
932
|
+
for (const hit of this.fetchChunksByIds(missingIds)) {
|
|
933
|
+
merged.set(hit.chunkId, { ...hit, score: 0, textScore: 0 });
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
return merged;
|
|
937
|
+
}
|
|
938
|
+
fetchChunksByIds(ids) {
|
|
939
|
+
if (ids.length === 0) return [];
|
|
940
|
+
const placeholders = ids.map(() => "?").join(",");
|
|
941
|
+
const rows = this.db.prepare(
|
|
942
|
+
`SELECT chunks.id as id, files.rel_path as rel_path, files.source as source,
|
|
943
|
+
chunks.start_line as start_line, chunks.end_line as end_line,
|
|
944
|
+
chunks.text as text
|
|
945
|
+
FROM chunks JOIN files ON chunks.file_id = files.id
|
|
946
|
+
WHERE chunks.id IN (${placeholders})`
|
|
947
|
+
).all(...ids);
|
|
948
|
+
return rows.map((row) => {
|
|
949
|
+
const startLine = Number(row.start_line ?? 0);
|
|
950
|
+
const endLine = Number(row.end_line ?? 0);
|
|
951
|
+
const path = String(row.rel_path);
|
|
952
|
+
return {
|
|
953
|
+
chunkId: Number(row.id),
|
|
954
|
+
path,
|
|
955
|
+
startLine,
|
|
956
|
+
endLine,
|
|
957
|
+
score: 0,
|
|
958
|
+
textScore: 0,
|
|
959
|
+
snippet: truncateSnippet(String(row.text ?? "")),
|
|
960
|
+
source: String(row.source),
|
|
961
|
+
citation: `${path}:${startLine}-${endLine}`
|
|
962
|
+
};
|
|
963
|
+
});
|
|
964
|
+
}
|
|
965
|
+
// ───── persistence helpers ─────────────────────────────────────────
|
|
966
|
+
loadFilesIndex() {
|
|
967
|
+
const rows = this.db.prepare("SELECT id, path, hash FROM files").all();
|
|
968
|
+
return new Map(rows.map((row) => [row.path, { id: row.id, hash: row.hash }]));
|
|
969
|
+
}
|
|
970
|
+
upsertFile(absPath, relPath, hash, mtimeMs, source = "memory") {
|
|
971
|
+
const stmt = this.db.prepare(
|
|
972
|
+
`INSERT INTO files (path, rel_path, mtime, hash, source) VALUES (?, ?, ?, ?, ?)
|
|
973
|
+
ON CONFLICT(path) DO UPDATE SET hash = excluded.hash, mtime = excluded.mtime, source = excluded.source
|
|
974
|
+
RETURNING id`
|
|
975
|
+
);
|
|
976
|
+
const row = stmt.get(absPath, relPath, Math.floor(mtimeMs), hash, source);
|
|
977
|
+
return row.id;
|
|
978
|
+
}
|
|
979
|
+
deleteChunksForFile(fileId) {
|
|
980
|
+
this.db.prepare("DELETE FROM chunks WHERE file_id = ?").run(fileId);
|
|
981
|
+
}
|
|
982
|
+
insertChunk(fileId, startLine, endLine, text, hash) {
|
|
983
|
+
this.db.prepare(
|
|
984
|
+
"INSERT INTO chunks (file_id, start_line, end_line, text, hash) VALUES (?, ?, ?, ?, ?)"
|
|
985
|
+
).run(fileId, startLine, endLine, text, hash);
|
|
986
|
+
}
|
|
987
|
+
close() {
|
|
988
|
+
this.db.close();
|
|
989
|
+
}
|
|
990
|
+
};
|
|
991
|
+
|
|
992
|
+
export { IndexManager, LanceIndex, appendFact, appendFactToMarkdown, defaultIndexPath, globalEmbeddingCache, lanceStoragePath, legacyMemoryJsonPath, memoryDir, memoryMdPath, openMemoryDb, readFacts, readFactsFromMarkdown, writeSessionSummary };
|
|
993
|
+
//# sourceMappingURL=chunk-G6GO6BXD.js.map
|
|
994
|
+
//# sourceMappingURL=chunk-G6GO6BXD.js.map
|