@askexenow/exe-os 0.9.265 → 0.9.267
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/deploy/compose/.env.example +4 -2
- package/deploy/compose/docker-compose.yml +6 -4
- package/deploy/compose/generate-env.ts +5 -2
- package/dist/active-agent-2XJJZFEW.js +25 -0
- package/dist/active-agent-JZ4PHIAK.js +26 -0
- package/dist/agentic-ontology-J4B525DT.js +25 -0
- package/dist/backfill-metadata-TWEC6BJD.js +597 -0
- package/dist/backfill-metadata-VGZLCJWZ.js +597 -0
- package/dist/backfill-metadata-Y6EABP6Q.js +597 -0
- package/dist/behaviors-BPIVFAGY.js +25 -0
- package/dist/bin/agentic-ontology-backfill.js +5 -5
- package/dist/bin/agentic-reflection-backfill.js +6 -6
- package/dist/bin/agentic-semantic-label.js +5 -5
- package/dist/bin/backfill-conversations.js +4 -4
- package/dist/bin/backfill-responses.js +4 -4
- package/dist/bin/backfill-vectors.js +5 -5
- package/dist/bin/bulk-sync-postgres.js +6 -6
- package/dist/bin/cc-doctor.js +6 -1
- package/dist/bin/cleanup-stale-review-tasks.js +9 -9
- package/dist/bin/cli.js +15 -15
- package/dist/bin/exe-agent-config.js +2 -2
- package/dist/bin/exe-agent.js +4 -4
- package/dist/bin/exe-assign.js +5 -5
- package/dist/bin/exe-boot.js +16 -16
- package/dist/bin/exe-call.js +4 -4
- package/dist/bin/exe-cloud.js +4 -4
- package/dist/bin/exe-dispatch.js +9 -9
- package/dist/bin/exe-doctor.js +1 -1
- package/dist/bin/exe-export-behaviors.js +7 -7
- package/dist/bin/exe-forget.js +6 -6
- package/dist/bin/exe-gateway.js +7 -7
- package/dist/bin/exe-healthcheck.js +6 -1
- package/dist/bin/exe-heartbeat.js +9 -9
- package/dist/bin/exe-kill.js +12 -12
- package/dist/bin/exe-launch-agent.js +16 -16
- package/dist/bin/exe-new-employee.js +6 -6
- package/dist/bin/exe-pending-messages.js +10 -10
- package/dist/bin/exe-pending-notifications.js +9 -9
- package/dist/bin/exe-pending-reviews.js +9 -9
- package/dist/bin/exe-rename.js +4 -4
- package/dist/bin/exe-review.js +11 -11
- package/dist/bin/exe-search.js +5 -5
- package/dist/bin/exe-session-cleanup.js +14 -14
- package/dist/bin/exe-settings.js +4 -4
- package/dist/bin/exe-start-codex.js +11 -11
- package/dist/bin/exe-start-opencode.js +8 -8
- package/dist/bin/exe-status.js +10 -10
- package/dist/bin/exe-team.js +3 -3
- package/dist/bin/git-sweep.js +10 -10
- package/dist/bin/graph-backfill.js +4 -4
- package/dist/bin/graph-export.js +5 -5
- package/dist/bin/import-history.js +7 -7
- package/dist/bin/install.js +6 -6
- package/dist/bin/intercom-check.js +4 -4
- package/dist/bin/mcp-sessions.js +2 -2
- package/dist/bin/orchestration-metrics.js +4 -4
- package/dist/bin/postgres-agentic-reflection-backfill.js +2 -2
- package/dist/bin/postgres-agentic-semantic-backfill.js +1 -1
- package/dist/bin/scan-tasks.js +9 -9
- package/dist/bin/setup.js +1 -1
- package/dist/bin/shard-migrate.js +5 -5
- package/dist/capacity-monitor-3QORC56J.js +49 -0
- package/dist/capacity-monitor-FWRBCZCZ.js +49 -0
- package/dist/capacity-monitor-MTYXZ7Q2.js +49 -0
- package/dist/catchup-brief-242H63OP.js +151 -0
- package/dist/catchup-brief-KNX6L2EN.js +151 -0
- package/dist/catchup-brief-T7W2ARRB.js +151 -0
- package/dist/catchup-brief-VJDLXJHJ.js +151 -0
- package/dist/chunk-2B6FH2QM.js +3951 -0
- package/dist/chunk-2FDYA3GS.js +75 -0
- package/dist/chunk-2V33IVZF.js +1148 -0
- package/dist/chunk-2W5NQOQJ.js +333 -0
- package/dist/chunk-32QR5EHE.js +244 -0
- package/dist/chunk-3DBROKA6.js +382 -0
- package/dist/chunk-3DS2YHAT.js +204 -0
- package/dist/chunk-3GP2QTXT.js +128 -0
- package/dist/chunk-3O2ZD7YV.js +227 -0
- package/dist/chunk-3Q2VWYTA.js +89 -0
- package/dist/chunk-43O2PZH7.js +214 -0
- package/dist/chunk-4AHL6I7X.js +284 -0
- package/dist/chunk-53IGC63J.js +54 -0
- package/dist/chunk-5GBPXJIH.js +50 -0
- package/dist/chunk-5IXN2532.js +58 -0
- package/dist/chunk-5KHVSGHP.js +330 -0
- package/dist/chunk-5SH5TR45.js +731 -0
- package/dist/chunk-5XGMTWKW.js +128 -0
- package/dist/chunk-6AQAILCS.js +13696 -0
- package/dist/chunk-6EIBIA3E.js +13696 -0
- package/dist/chunk-6KGRRZDA.js +81 -0
- package/dist/chunk-72KQJZBH.js +382 -0
- package/dist/chunk-7B2AENJ3.js +1345 -0
- package/dist/chunk-7GKMYFVR.js +551 -0
- package/dist/chunk-7HUGVJHW.js +1021 -0
- package/dist/chunk-7HWBGXDV.js +333 -0
- package/dist/chunk-7ROGPDW6.js +197 -0
- package/dist/chunk-7ZMLNURG.js +513 -0
- package/dist/chunk-A3G4UXNA.js +280 -0
- package/dist/chunk-A4T6U3XZ.js +371 -0
- package/dist/chunk-ADJNRFEK.js +13696 -0
- package/dist/chunk-AVJTW67M.js +513 -0
- package/dist/chunk-B6RC7DAC.js +1090 -0
- package/dist/chunk-BAOJLZVC.js +244 -0
- package/dist/chunk-BCUMPA7J.js +159 -0
- package/dist/chunk-BH2ST7KK.js +183 -0
- package/dist/chunk-C4BIYP5C.js +129 -0
- package/dist/chunk-CBUZG6OC.js +89 -0
- package/dist/chunk-CGQRWCCP.js +81 -0
- package/dist/chunk-CLX4WQHT.js +214 -0
- package/dist/chunk-CM32SM3U.js +127 -0
- package/dist/chunk-D4CQZL46.js +76 -0
- package/dist/chunk-DEBLYXA2.js +56 -0
- package/dist/chunk-E45SYT7G.js +617 -0
- package/dist/chunk-EDNUE5L3.js +38 -0
- package/dist/chunk-EMTXM73F.js +333 -0
- package/dist/chunk-ESNHLTLC.js +1073 -0
- package/dist/chunk-FICUAZEA.js +128 -0
- package/dist/chunk-FP6U5PSY.js +818 -0
- package/dist/chunk-G4WZIPDM.js +1921 -0
- package/dist/chunk-G55UTKFR.js +89 -0
- package/dist/chunk-GIJUXLK5.js +330 -0
- package/dist/chunk-GVSSEGIV.js +348 -0
- package/dist/chunk-GYOOZ725.js +330 -0
- package/dist/chunk-GZ3NZDS5.js +1090 -0
- package/dist/chunk-HCULUL4D.js +447 -0
- package/dist/chunk-HDRQKH7R.js +1051 -0
- package/dist/chunk-HHBN7Y7R.js +197 -0
- package/dist/chunk-IP7YSYZB.js +1073 -0
- package/dist/chunk-IQBXQ7GF.js +1073 -0
- package/dist/chunk-ITF6GEJI.js +2091 -0
- package/dist/chunk-IUY6I2CH.js +1148 -0
- package/dist/chunk-IXHVSWLM.js +58 -0
- package/dist/chunk-IXUGRCIM.js +58 -0
- package/dist/chunk-J3ZFONT4.js +1921 -0
- package/dist/chunk-JEOFG274.js +394 -0
- package/dist/chunk-JH7ISOIJ.js +33 -0
- package/dist/chunk-JVRMAVPN.js +731 -0
- package/dist/chunk-KBYRYSXT.js +3951 -0
- package/dist/chunk-KECNXWD6.js +1051 -0
- package/dist/chunk-KI5HUHVX.js +171 -0
- package/dist/chunk-KIYCHS35.js +128 -0
- package/dist/chunk-KUP3D6G2.js +1345 -0
- package/dist/chunk-KXS5HHDH.js +54 -0
- package/dist/chunk-LNY2DMEX.js +50 -0
- package/dist/chunk-LSI363EB.js +284 -0
- package/dist/chunk-LVZW4WQY.js +221 -0
- package/dist/chunk-LWOCCDSB.js +240 -0
- package/dist/chunk-M4HRKRSE.js +30 -0
- package/dist/chunk-MPG5DR3K.js +244 -0
- package/dist/chunk-NOG2LVBA.js +159 -0
- package/dist/chunk-NP3CYOEY.js +290 -0
- package/dist/chunk-OM5524LQ.js +204 -0
- package/dist/chunk-ONMXLCZ7.js +495 -0
- package/dist/chunk-OVQOKLYA.js +210 -0
- package/dist/chunk-OW26ML36.js +1148 -0
- package/dist/chunk-OZPTYL2D.js +244 -0
- package/dist/chunk-P2DOIWQG.js +260 -0
- package/dist/chunk-P2QTTEYP.js +3951 -0
- package/dist/chunk-P5IKFL7B.js +85 -0
- package/dist/chunk-PD2LUPHD.js +377 -0
- package/dist/chunk-PF5EFIAH.js +818 -0
- package/dist/chunk-PK3NFO76.js +551 -0
- package/dist/chunk-Q4NVLQHH.js +76 -0
- package/dist/chunk-QKMFMJTU.js +171 -0
- package/dist/chunk-R3ERWIOH.js +197 -0
- package/dist/chunk-R3FOMRWJ.js +731 -0
- package/dist/chunk-R77M74QM.js +13696 -0
- package/dist/chunk-RHZ2CRJU.js +3556 -0
- package/dist/chunk-RLR4LVO5.js +1090 -0
- package/dist/chunk-RMDDSWFH.js +495 -0
- package/dist/chunk-RPLEZ74B.js +95 -0
- package/dist/chunk-RXMVPGH2.js +346 -0
- package/dist/chunk-S2ARWNS6.js +135 -0
- package/dist/chunk-SHPIATX7.js +90 -0
- package/dist/chunk-SQUZ3TI2.js +668 -0
- package/dist/chunk-SUGBKORD.js +1148 -0
- package/dist/chunk-T2XD7XL2.js +346 -0
- package/dist/chunk-TAIYLROT.js +127 -0
- package/dist/chunk-TCD4XCBS.js +495 -0
- package/dist/chunk-TEVTA7JX.js +551 -0
- package/dist/chunk-TQVS4W2Y.js +346 -0
- package/dist/chunk-TSBMSHMM.js +163 -0
- package/dist/chunk-U776PBU6.js +488 -0
- package/dist/chunk-UQ27GW5L.js +377 -0
- package/dist/chunk-UQMIBSN4.js +159 -0
- package/dist/chunk-UTVNIAOF.js +284 -0
- package/dist/chunk-VF6VT4MR.js +70 -0
- package/dist/chunk-VZXLYUKS.js +171 -0
- package/dist/chunk-WHATWGUZ.js +447 -0
- package/dist/chunk-WIAHPJDS.js +58 -0
- package/dist/chunk-WM5ELLT4.js +54 -0
- package/dist/chunk-WUUSPOCC.js +1921 -0
- package/dist/chunk-WXHAMPK4.js +81 -0
- package/dist/chunk-WYNZ23XH.js +262 -0
- package/dist/chunk-WZOQLU2Y.js +127 -0
- package/dist/chunk-X24GBZKR.js +157 -0
- package/dist/chunk-X5FRF5MG.js +13696 -0
- package/dist/chunk-XBPLYFBA.js +204 -0
- package/dist/chunk-XDGKFXFW.js +363 -0
- package/dist/chunk-XIT6ONPY.js +630 -0
- package/dist/chunk-XK66XNN3.js +818 -0
- package/dist/chunk-XNRJ5JHU.js +377 -0
- package/dist/chunk-XREWTPZM.js +123 -0
- package/dist/chunk-XURCA5VD.js +297 -0
- package/dist/chunk-Y55VFZJB.js +50 -0
- package/dist/chunk-Y5SXCVET.js +214 -0
- package/dist/chunk-YIH2YMWP.js +76 -0
- package/dist/chunk-YZMCCT73.js +97 -0
- package/dist/chunk-Z4476ZEZ.js +513 -0
- package/dist/chunk-Z7VAUKRU.js +1345 -0
- package/dist/chunk-ZCDGAH7H.js +382 -0
- package/dist/chunk-ZTP3VV23.js +447 -0
- package/dist/co-activation-JOYR73H2.js +72 -0
- package/dist/co-occurrence-G7RRJ3DB.js +74 -0
- package/dist/core-memory-6KK55Z65.js +110 -0
- package/dist/core-memory-DRYQWHJU.js +110 -0
- package/dist/core-memory-QRS6GBXL.js +110 -0
- package/dist/crdt-sync-QWK65Z5A.js +33 -0
- package/dist/crm-webhook-BNUS3USD.js +10 -0
- package/dist/crm-webhook-BSN4TCCY.js +10 -0
- package/dist/crm-webhook-ZTIRFVAH.js +10 -0
- package/dist/cto-delegation-gate-DNZJGBS7.js +206 -0
- package/dist/cto-delegation-gate-IPQBZ3J2.js +206 -0
- package/dist/cto-delegation-gate-YI3LK7VY.js +206 -0
- package/dist/daemon-orchestration-6TIV6MMN.js +135 -0
- package/dist/daemon-orchestration-7LVOHYKA.js +135 -0
- package/dist/daemon-orchestration-SDQNWI3K.js +135 -0
- package/dist/db-backup-5ENHDNZI.js +33 -0
- package/dist/dreaming-5S4SSUIU.js +32 -0
- package/dist/dreaming-PGJOCGAM.js +32 -0
- package/dist/dreaming-UNHHGOU3.js +32 -0
- package/dist/exe-drift-QQJMUQXA.js +68 -0
- package/dist/exe-export-BEZZSQB4.js +73 -0
- package/dist/exe-export-JJJJDQE3.js +73 -0
- package/dist/exe-export-TQGI2VBT.js +73 -0
- package/dist/exe-import-2SR2UP3D.js +76 -0
- package/dist/exe-import-73Q4VLFK.js +76 -0
- package/dist/exe-import-G7VIUGLR.js +76 -0
- package/dist/exe-key-6JHEINOM.js +579 -0
- package/dist/exe-key-JS7OSDJP.js +579 -0
- package/dist/exe-key-RIRPIFK6.js +579 -0
- package/dist/exe-snapshot-DSPO4HHJ.js +164 -0
- package/dist/exe-snapshot-NDMDQJOH.js +164 -0
- package/dist/exe-snapshot-PVCBPMPJ.js +164 -0
- package/dist/fast-db-init-22OBOPTN.js +7 -0
- package/dist/fast-db-init-M6ZYYGAL.js +7 -0
- package/dist/fast-db-init-VLF46DR3.js +7 -0
- package/dist/gateway/index.js +8 -8
- package/dist/git-staleness-4DGYC3RY.js +110 -0
- package/dist/git-task-sweep-CUR7R2ZM.js +40 -0
- package/dist/git-task-sweep-VO2DVEXY.js +40 -0
- package/dist/git-task-sweep-YG3IVGK3.js +40 -0
- package/dist/global-procedures-TYDNKM7V.js +20 -0
- package/dist/graph-auto-extract-I6B5HWTP.js +162 -0
- package/dist/hooks/bug-report-worker.js +11 -11
- package/dist/hooks/codex-stop-task-finalizer.js +11 -11
- package/dist/hooks/commit-complete.js +11 -11
- package/dist/hooks/error-recall.js +6 -6
- package/dist/hooks/exe-heartbeat-hook.js +3 -3
- package/dist/hooks/ingest.js +6 -6
- package/dist/hooks/instructions-loaded.js +4 -4
- package/dist/hooks/manifest.json +19 -19
- package/dist/hooks/notification.js +4 -4
- package/dist/hooks/post-compact.js +10 -10
- package/dist/hooks/post-tool-combined.js +5 -5
- package/dist/hooks/pre-compact.js +11 -11
- package/dist/hooks/pre-tool-use.js +14 -14
- package/dist/hooks/prompt-submit.js +20 -20
- package/dist/hooks/session-end.js +15 -15
- package/dist/hooks/session-start.js +10 -10
- package/dist/hooks/stop.js +14 -14
- package/dist/hooks/subagent-stop.js +10 -10
- package/dist/hooks/summary-worker.js +14 -14
- package/dist/index.js +17 -17
- package/dist/installer-4LP73C3M.js +38 -0
- package/dist/installer-AUVLNS4D.js +296 -0
- package/dist/installer-KCRLQSQH.js +38 -0
- package/dist/installer-KGXYUOIV.js +296 -0
- package/dist/installer-UI6TNJGO.js +342 -0
- package/dist/installer-Z7NPD4PD.js +342 -0
- package/dist/lib/cloud-sync.js +4 -4
- package/dist/lib/consolidation.js +5 -5
- package/dist/lib/database.js +2 -2
- package/dist/lib/db-daemon-client.js +6 -0
- package/dist/lib/db.js +2 -2
- package/dist/lib/employee-templates.js +4 -4
- package/dist/lib/employees.js +2 -2
- package/dist/lib/exe-daemon.js +41 -40
- package/dist/lib/hybrid-search.js +5 -5
- package/dist/lib/identity.js +2 -2
- package/dist/lib/messaging.js +9 -9
- package/dist/lib/reminders.js +3 -3
- package/dist/lib/schedules.js +5 -5
- package/dist/lib/session-registry.js +4 -4
- package/dist/lib/skill-learning.js +4 -4
- package/dist/lib/store.js +4 -4
- package/dist/lib/task-router.js +3 -3
- package/dist/lib/tasks.js +10 -10
- package/dist/lib/tmux-routing.js +8 -8
- package/dist/lib/token-spend.js +3 -3
- package/dist/mcp/register-tools.js +53 -52
- package/dist/mcp/server.js +54 -53
- package/dist/mcp/tools/complete-reminder.js +4 -4
- package/dist/mcp/tools/create-reminder.js +4 -4
- package/dist/mcp/tools/create-task.js +12 -12
- package/dist/mcp/tools/deactivate-behavior.js +5 -5
- package/dist/mcp/tools/list-reminders.js +4 -4
- package/dist/mcp/tools/list-tasks.js +12 -12
- package/dist/mcp/tools/send-message.js +11 -11
- package/dist/mcp/tools/update-task.js +11 -11
- package/dist/mcp-http-config-LN5ITKGS.js +27 -0
- package/dist/mcp-http-config-V43VHNEH.js +27 -0
- package/dist/memory-cards-S36DCEY4.js +174 -0
- package/dist/memory-graph-extractor-66YL4V4B.js +17 -0
- package/dist/memory-poisoning-defense-MXWE6CTY.js +225 -0
- package/dist/memory-reflection-W676LUX5.js +238 -0
- package/dist/notifications-NGKMOBKL.js +45 -0
- package/dist/notifications-OFLXZTDZ.js +45 -0
- package/dist/notifications-XAV4V7T5.js +45 -0
- package/dist/orchestration-events-MJLWJ2H2.js +25 -0
- package/dist/orchestrator-6MKGTKN7.js +33 -0
- package/dist/orchestrator-AIAKV5ST.js +33 -0
- package/dist/orchestrator-VK7D6I36.js +33 -0
- package/dist/pipeline-router-DXH5QVUH.js +13 -0
- package/dist/pipeline-router-EV6C5S33.js +13 -0
- package/dist/pipeline-router-G65CQ5EE.js +13 -0
- package/dist/plan-limits-TQMLKZBG.js +26 -0
- package/dist/project-boot-4XTXHDG4.js +299 -0
- package/dist/projection-worker-NAYVNSI4.js +964 -0
- package/dist/reranker-KHZI7HQK.js +19 -0
- package/dist/reranker-O6QYMIEA.js +19 -0
- package/dist/reranker-UPMS3OX7.js +19 -0
- package/dist/reranker-ZN73HWSB.js +19 -0
- package/dist/review-polling-3UEZSPNT.js +124 -0
- package/dist/review-polling-KBDX3ILL.js +124 -0
- package/dist/review-polling-ZWOO7QQJ.js +124 -0
- package/dist/runtime/index.js +11 -11
- package/dist/session-events-2CHOLA6D.js +36 -0
- package/dist/session-events-HM22KEHN.js +36 -0
- package/dist/session-events-YIUYMJKP.js +36 -0
- package/dist/session-kill-telemetry-LUPVYGZX.js +29 -0
- package/dist/session-scope-EPZZZHHJ.js +86 -0
- package/dist/session-scope-KZ25NMH3.js +86 -0
- package/dist/session-scope-ZGE6GHMS.js +86 -0
- package/dist/setup-wizard-KNWH54HW.js +12 -0
- package/dist/shard-manager-GFKF4AKT.js +30 -0
- package/dist/skill-refinement-A5S4KCS4.js +157 -0
- package/dist/skill-refinement-C4GNWV4F.js +157 -0
- package/dist/skill-refinement-CAUIE4YM.js +157 -0
- package/dist/steward-gate-MZ2DV36N.js +13 -0
- package/dist/task-enforcement-6OMXG6EA.js +333 -0
- package/dist/task-enforcement-D5AP7KJM.js +333 -0
- package/dist/task-enforcement-JFSF6QDD.js +333 -0
- package/dist/task-scope-4HJSCJ7L.js +35 -0
- package/dist/task-scope-7HYE4AS6.js +35 -0
- package/dist/task-scope-MP32TKL3.js +35 -0
- package/dist/tasks-crud-JJL6MMJF.js +77 -0
- package/dist/tasks-crud-KMIPDHBZ.js +77 -0
- package/dist/tasks-crud-NOMD6R4W.js +77 -0
- package/dist/tasks-notify-5D6LF52K.js +38 -0
- package/dist/tasks-notify-J3L2URRG.js +38 -0
- package/dist/tasks-notify-JNGGXFUY.js +38 -0
- package/dist/tasks-review-N6I5UC7G.js +47 -0
- package/dist/tasks-review-USHAMO5N.js +47 -0
- package/dist/tasks-review-WO2Y7F6V.js +47 -0
- package/dist/telemetry-upload-BV2M2NND.js +739 -0
- package/dist/telemetry-upload-O6R7W4CV.js +739 -0
- package/dist/telemetry-upload-Y7QPDJW4.js +739 -0
- package/dist/token-budget-2LUZOFO7.js +84 -0
- package/dist/tool-telemetry-5JT6DPVK.js +17 -0
- package/dist/tui/App.js +16 -16
- package/dist/tui-data-DMAKZMGD.js +258 -0
- package/dist/tui-data-X7NI6ZQ3.js +258 -0
- package/dist/tui-data-Z3KQW37O.js +258 -0
- package/dist/wiki-acl-QHGGWX63.js +111 -0
- package/dist/worker-gate-3AUE4IZX.js +21 -0
- package/dist/worker-gate-4XKUOFWO.js +21 -0
- package/dist/worker-gate-TPZBOXOA.js +21 -0
- package/dist/workflow-engine-F3URLOPA.js +28 -0
- package/dist/workflow-engine-OFOL446Z.js +28 -0
- package/dist/workflow-engine-VNPPUSNL.js +28 -0
- package/dist/worktree-V3NVP7MV.js +26 -0
- package/dist/worktree-sweep-2CADL43Y.js +19 -0
- package/package.json +1 -1
- package/release-notes.json +32 -26
|
@@ -0,0 +1,617 @@
|
|
|
1
|
+
import {
|
|
2
|
+
assertValidDbPath
|
|
3
|
+
} from "./chunk-2I23RPSI.js";
|
|
4
|
+
import {
|
|
5
|
+
EXE_AI_DIR
|
|
6
|
+
} from "./chunk-VXIMSRTO.js";
|
|
7
|
+
|
|
8
|
+
// src/lib/shard-manager.ts
|
|
9
|
+
import path from "path";
|
|
10
|
+
import { existsSync, mkdirSync, readdirSync, renameSync, statSync } from "fs";
|
|
11
|
+
import { createClient } from "@libsql/client";
|
|
12
|
+
var SHARDS_DIR = path.join(EXE_AI_DIR, "shards");
|
|
13
|
+
var SHARD_IDLE_MS = 5 * 60 * 1e3;
|
|
14
|
+
var MAX_OPEN_SHARDS = 10;
|
|
15
|
+
var EVICTION_INTERVAL_MS = 60 * 1e3;
|
|
16
|
+
var _shards = /* @__PURE__ */ new Map();
|
|
17
|
+
var _shardLastAccess = /* @__PURE__ */ new Map();
|
|
18
|
+
var _evictionTimer = null;
|
|
19
|
+
var _encryptionKey = null;
|
|
20
|
+
var _shardingEnabled = false;
|
|
21
|
+
var _keyValidated = false;
|
|
22
|
+
var _keyValidationPromise = null;
|
|
23
|
+
var _validationFailedForKey = null;
|
|
24
|
+
var _validationWarningEmitted = false;
|
|
25
|
+
function initShardManager(encryptionKey) {
|
|
26
|
+
_encryptionKey = encryptionKey;
|
|
27
|
+
_keyValidationPromise = null;
|
|
28
|
+
_keyValidated = false;
|
|
29
|
+
if (!existsSync(SHARDS_DIR)) {
|
|
30
|
+
mkdirSync(SHARDS_DIR, { recursive: true });
|
|
31
|
+
}
|
|
32
|
+
const existingShards = readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db"));
|
|
33
|
+
if (existingShards.length === 0) {
|
|
34
|
+
_keyValidated = true;
|
|
35
|
+
_validationFailedForKey = null;
|
|
36
|
+
}
|
|
37
|
+
if (_validationFailedForKey === encryptionKey && existingShards.length > 0) {
|
|
38
|
+
_keyValidated = true;
|
|
39
|
+
_shardingEnabled = false;
|
|
40
|
+
} else {
|
|
41
|
+
_shardingEnabled = true;
|
|
42
|
+
}
|
|
43
|
+
if (_evictionTimer) clearInterval(_evictionTimer);
|
|
44
|
+
_evictionTimer = setInterval(evictIdleShards, EVICTION_INTERVAL_MS);
|
|
45
|
+
_evictionTimer.unref();
|
|
46
|
+
}
|
|
47
|
+
async function validateEncryptionKey() {
|
|
48
|
+
if (_keyValidated) return _shardingEnabled;
|
|
49
|
+
if (!_encryptionKey) return false;
|
|
50
|
+
const existingShards = readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db"));
|
|
51
|
+
if (existingShards.length === 0) {
|
|
52
|
+
_keyValidated = true;
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
for (const shardFile of existingShards.slice(0, 3)) {
|
|
56
|
+
const dbPath = path.join(SHARDS_DIR, shardFile);
|
|
57
|
+
assertValidDbPath(dbPath, "shard-manager validateEncryptionKey");
|
|
58
|
+
const testClient = createClient({ url: `file:${dbPath}`, encryptionKey: _encryptionKey });
|
|
59
|
+
try {
|
|
60
|
+
await testClient.execute("SELECT COUNT(*) FROM sqlite_schema");
|
|
61
|
+
testClient.close();
|
|
62
|
+
_keyValidated = true;
|
|
63
|
+
_validationFailedForKey = null;
|
|
64
|
+
_validationWarningEmitted = false;
|
|
65
|
+
return true;
|
|
66
|
+
} catch {
|
|
67
|
+
try {
|
|
68
|
+
testClient.close();
|
|
69
|
+
} catch {
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (!_validationWarningEmitted) {
|
|
74
|
+
process.stderr.write(
|
|
75
|
+
`[shard-manager] WARNING: encryption key cannot read any existing shards (${existingShards.length} found). New shard creation disabled to prevent stranded files. Run /exe-doctor to audit.
|
|
76
|
+
`
|
|
77
|
+
);
|
|
78
|
+
_validationWarningEmitted = true;
|
|
79
|
+
}
|
|
80
|
+
_validationFailedForKey = _encryptionKey;
|
|
81
|
+
_keyValidated = true;
|
|
82
|
+
_keyValidationPromise = null;
|
|
83
|
+
_shardingEnabled = false;
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
function isShardingEnabled() {
|
|
87
|
+
return _shardingEnabled;
|
|
88
|
+
}
|
|
89
|
+
function getShardsDir() {
|
|
90
|
+
return SHARDS_DIR;
|
|
91
|
+
}
|
|
92
|
+
function getShardClient(projectName) {
|
|
93
|
+
if (!_encryptionKey) {
|
|
94
|
+
throw new Error("Shard manager not initialized. Call initShardManager() first.");
|
|
95
|
+
}
|
|
96
|
+
const safeName = safeShardName(projectName);
|
|
97
|
+
if (!safeName || safeName === "unknown") {
|
|
98
|
+
throw new Error(`Invalid project name for shard: "${projectName}" (resolved to "${safeName}")`);
|
|
99
|
+
}
|
|
100
|
+
const cached = _shards.get(safeName);
|
|
101
|
+
if (cached) {
|
|
102
|
+
_shardLastAccess.set(safeName, Date.now());
|
|
103
|
+
return cached;
|
|
104
|
+
}
|
|
105
|
+
while (_shards.size >= MAX_OPEN_SHARDS) {
|
|
106
|
+
evictLRU();
|
|
107
|
+
}
|
|
108
|
+
const dbPath = path.join(SHARDS_DIR, `${safeName}.db`);
|
|
109
|
+
assertValidDbPath(dbPath, "shard-manager getShardClient");
|
|
110
|
+
const client = createClient({
|
|
111
|
+
url: `file:${dbPath}`,
|
|
112
|
+
encryptionKey: _encryptionKey
|
|
113
|
+
});
|
|
114
|
+
_shards.set(safeName, client);
|
|
115
|
+
_shardLastAccess.set(safeName, Date.now());
|
|
116
|
+
return client;
|
|
117
|
+
}
|
|
118
|
+
function shardExists(projectName) {
|
|
119
|
+
const safeName = safeShardName(projectName);
|
|
120
|
+
return existsSync(path.join(SHARDS_DIR, `${safeName}.db`));
|
|
121
|
+
}
|
|
122
|
+
function safeShardName(projectName) {
|
|
123
|
+
return projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
124
|
+
}
|
|
125
|
+
function listShards() {
|
|
126
|
+
if (!existsSync(SHARDS_DIR)) return [];
|
|
127
|
+
return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
128
|
+
}
|
|
129
|
+
async function auditShardHealth(options = {}) {
|
|
130
|
+
if (!_encryptionKey) {
|
|
131
|
+
throw new Error("Shard manager not initialized. Call initShardManager() first.");
|
|
132
|
+
}
|
|
133
|
+
const repair = options.repair === true;
|
|
134
|
+
const dryRun = options.dryRun === true;
|
|
135
|
+
const names = listShards();
|
|
136
|
+
const shards = [];
|
|
137
|
+
for (const name of names) {
|
|
138
|
+
const dbPath = path.join(SHARDS_DIR, `${name}.db`);
|
|
139
|
+
const stat = statSync(dbPath);
|
|
140
|
+
const item = {
|
|
141
|
+
name,
|
|
142
|
+
path: dbPath,
|
|
143
|
+
ok: false,
|
|
144
|
+
unreadable: false,
|
|
145
|
+
error: null,
|
|
146
|
+
schemaIssues: [],
|
|
147
|
+
size: stat.size,
|
|
148
|
+
mtime: stat.mtime.toISOString(),
|
|
149
|
+
memoryCount: null
|
|
150
|
+
};
|
|
151
|
+
const client = createClient({
|
|
152
|
+
url: `file:${dbPath}`,
|
|
153
|
+
encryptionKey: _encryptionKey
|
|
154
|
+
});
|
|
155
|
+
try {
|
|
156
|
+
await client.execute("SELECT COUNT(*) as cnt FROM sqlite_schema");
|
|
157
|
+
const hasMemories = await client.execute(
|
|
158
|
+
"SELECT COUNT(*) as cnt FROM sqlite_schema WHERE type = 'table' AND name = 'memories'"
|
|
159
|
+
);
|
|
160
|
+
if (Number(hasMemories.rows[0]?.cnt ?? 0) > 0) {
|
|
161
|
+
const mem = await client.execute("SELECT COUNT(*) as cnt FROM memories");
|
|
162
|
+
item.memoryCount = Number(mem.rows[0]?.cnt ?? 0);
|
|
163
|
+
const columns = await client.execute("PRAGMA table_info(memories)");
|
|
164
|
+
const colNames = new Set(columns.rows.map((r) => String(r.name)));
|
|
165
|
+
for (const required of ["keywords", "content_hash", "memory_type", "status", "session_scope"]) {
|
|
166
|
+
if (!colNames.has(required)) item.schemaIssues.push(`memories missing column ${required}`);
|
|
167
|
+
}
|
|
168
|
+
const fts = await client.execute(
|
|
169
|
+
"SELECT sql FROM sqlite_schema WHERE type='table' AND name='memories_fts'"
|
|
170
|
+
);
|
|
171
|
+
const ftsSql = String(fts.rows[0]?.sql ?? "");
|
|
172
|
+
if (!ftsSql.includes("keywords")) item.schemaIssues.push("memories_fts missing keywords column");
|
|
173
|
+
if (item.schemaIssues.length > 0 && repair && !dryRun) {
|
|
174
|
+
await ensureShardSchema(client);
|
|
175
|
+
item.schemaIssues = [];
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
item.ok = item.schemaIssues.length === 0;
|
|
179
|
+
} catch (err) {
|
|
180
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
181
|
+
item.error = message;
|
|
182
|
+
item.unreadable = /SQLITE_NOTADB|file is not a database/i.test(message);
|
|
183
|
+
if (item.unreadable && repair && !dryRun) {
|
|
184
|
+
client.close();
|
|
185
|
+
_shards.delete(name);
|
|
186
|
+
_shardLastAccess.delete(name);
|
|
187
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
188
|
+
const archivedPath = path.join(SHARDS_DIR, `${name}.db.broken-${stamp}`);
|
|
189
|
+
renameSync(dbPath, archivedPath);
|
|
190
|
+
item.archivedPath = archivedPath;
|
|
191
|
+
}
|
|
192
|
+
} finally {
|
|
193
|
+
try {
|
|
194
|
+
client.close();
|
|
195
|
+
} catch {
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
shards.push(item);
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
total: shards.length,
|
|
202
|
+
ok: shards.filter((s) => s.ok).length,
|
|
203
|
+
unreadable: shards.filter((s) => s.unreadable).length,
|
|
204
|
+
schemaMismatches: shards.filter((s) => s.schemaIssues.length > 0).length,
|
|
205
|
+
archived: shards.filter((s) => Boolean(s.archivedPath)).length,
|
|
206
|
+
shards
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
async function ensureShardSchema(client) {
|
|
210
|
+
await client.execute("PRAGMA journal_mode = WAL");
|
|
211
|
+
await client.execute("PRAGMA busy_timeout = 30000");
|
|
212
|
+
try {
|
|
213
|
+
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
214
|
+
} catch {
|
|
215
|
+
}
|
|
216
|
+
await client.executeMultiple(`
|
|
217
|
+
CREATE TABLE IF NOT EXISTS memories (
|
|
218
|
+
id TEXT PRIMARY KEY,
|
|
219
|
+
agent_id TEXT NOT NULL,
|
|
220
|
+
agent_role TEXT NOT NULL,
|
|
221
|
+
session_id TEXT NOT NULL,
|
|
222
|
+
timestamp TEXT NOT NULL,
|
|
223
|
+
tool_name TEXT NOT NULL,
|
|
224
|
+
project_name TEXT NOT NULL,
|
|
225
|
+
has_error INTEGER NOT NULL DEFAULT 0,
|
|
226
|
+
raw_text TEXT NOT NULL,
|
|
227
|
+
vector F32_BLOB(1024),
|
|
228
|
+
version INTEGER NOT NULL DEFAULT 0
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
CREATE INDEX IF NOT EXISTS idx_memories_agent ON memories(agent_id);
|
|
232
|
+
CREATE INDEX IF NOT EXISTS idx_memories_timestamp ON memories(timestamp);
|
|
233
|
+
CREATE INDEX IF NOT EXISTS idx_memories_agent_project ON memories(agent_id, project_name);
|
|
234
|
+
CREATE INDEX IF NOT EXISTS idx_memories_version ON memories(version);
|
|
235
|
+
`);
|
|
236
|
+
for (const col of [
|
|
237
|
+
"ALTER TABLE memories ADD COLUMN status TEXT DEFAULT 'active'",
|
|
238
|
+
"ALTER TABLE memories ADD COLUMN keywords TEXT DEFAULT ''",
|
|
239
|
+
"ALTER TABLE memories ADD COLUMN founder_id TEXT"
|
|
240
|
+
]) {
|
|
241
|
+
try {
|
|
242
|
+
await client.execute(col);
|
|
243
|
+
} catch {
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
let needsFtsMigration = false;
|
|
247
|
+
try {
|
|
248
|
+
await client.execute("SELECT keywords FROM memories_fts LIMIT 0");
|
|
249
|
+
} catch {
|
|
250
|
+
needsFtsMigration = true;
|
|
251
|
+
}
|
|
252
|
+
if (needsFtsMigration) {
|
|
253
|
+
for (const drop of [
|
|
254
|
+
"DROP TRIGGER IF EXISTS memories_fts_ai",
|
|
255
|
+
"DROP TRIGGER IF EXISTS memories_fts_ad",
|
|
256
|
+
"DROP TRIGGER IF EXISTS memories_fts_au",
|
|
257
|
+
"DROP TRIGGER IF EXISTS memories_fts_soft_delete",
|
|
258
|
+
"DROP TABLE IF EXISTS memories_fts"
|
|
259
|
+
]) {
|
|
260
|
+
try {
|
|
261
|
+
await client.execute(drop);
|
|
262
|
+
} catch {
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
await client.executeMultiple(`
|
|
267
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(
|
|
268
|
+
raw_text,
|
|
269
|
+
keywords,
|
|
270
|
+
content='memories',
|
|
271
|
+
content_rowid='rowid'
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
CREATE TRIGGER IF NOT EXISTS memories_fts_ai AFTER INSERT ON memories BEGIN
|
|
275
|
+
INSERT INTO memories_fts(rowid, raw_text, keywords) VALUES (new.rowid, new.raw_text, COALESCE(new.keywords, ''));
|
|
276
|
+
END;
|
|
277
|
+
|
|
278
|
+
CREATE TRIGGER IF NOT EXISTS memories_fts_ad AFTER DELETE ON memories BEGIN
|
|
279
|
+
INSERT INTO memories_fts(memories_fts, rowid, raw_text, keywords) VALUES('delete', old.rowid, old.raw_text, COALESCE(old.keywords, ''));
|
|
280
|
+
END;
|
|
281
|
+
|
|
282
|
+
CREATE TRIGGER IF NOT EXISTS memories_fts_au AFTER UPDATE ON memories BEGIN
|
|
283
|
+
INSERT INTO memories_fts(memories_fts, rowid, raw_text, keywords) VALUES('delete', old.rowid, old.raw_text, COALESCE(old.keywords, ''));
|
|
284
|
+
INSERT INTO memories_fts(rowid, raw_text, keywords) VALUES (new.rowid, new.raw_text, COALESCE(new.keywords, ''));
|
|
285
|
+
END;
|
|
286
|
+
|
|
287
|
+
CREATE TRIGGER IF NOT EXISTS memories_fts_soft_delete AFTER UPDATE OF status ON memories
|
|
288
|
+
WHEN new.status = 'deleted' AND (old.status IS NULL OR old.status != 'deleted') BEGIN
|
|
289
|
+
INSERT INTO memories_fts(memories_fts, rowid, raw_text, keywords) VALUES('delete', old.rowid, old.raw_text, COALESCE(old.keywords, ''));
|
|
290
|
+
END;
|
|
291
|
+
`);
|
|
292
|
+
for (const col of [
|
|
293
|
+
"ALTER TABLE memories ADD COLUMN task_id TEXT",
|
|
294
|
+
"ALTER TABLE memories ADD COLUMN consolidated INTEGER NOT NULL DEFAULT 0",
|
|
295
|
+
"ALTER TABLE memories ADD COLUMN author_device_id TEXT",
|
|
296
|
+
"ALTER TABLE memories ADD COLUMN scope TEXT NOT NULL DEFAULT 'business'",
|
|
297
|
+
"ALTER TABLE memories ADD COLUMN importance INTEGER DEFAULT 5",
|
|
298
|
+
"ALTER TABLE memories ADD COLUMN status TEXT DEFAULT 'active'",
|
|
299
|
+
"ALTER TABLE memories ADD COLUMN wiki_synced INTEGER DEFAULT 0",
|
|
300
|
+
"ALTER TABLE memories ADD COLUMN graph_extracted INTEGER DEFAULT 0",
|
|
301
|
+
"ALTER TABLE memories ADD COLUMN content_hash TEXT",
|
|
302
|
+
"ALTER TABLE memories ADD COLUMN graph_extracted_hash TEXT",
|
|
303
|
+
"ALTER TABLE memories ADD COLUMN confidence REAL DEFAULT 0.7",
|
|
304
|
+
"ALTER TABLE memories ADD COLUMN last_accessed TEXT",
|
|
305
|
+
// Wiki linkage columns (must match database.ts)
|
|
306
|
+
"ALTER TABLE memories ADD COLUMN workspace_id TEXT",
|
|
307
|
+
"ALTER TABLE memories ADD COLUMN document_id TEXT",
|
|
308
|
+
"ALTER TABLE memories ADD COLUMN user_id TEXT",
|
|
309
|
+
"ALTER TABLE memories ADD COLUMN char_offset INTEGER",
|
|
310
|
+
"ALTER TABLE memories ADD COLUMN page_number INTEGER",
|
|
311
|
+
// Source provenance columns (must match database.ts)
|
|
312
|
+
"ALTER TABLE memories ADD COLUMN source_path TEXT",
|
|
313
|
+
"ALTER TABLE memories ADD COLUMN source_type TEXT DEFAULT 'text'",
|
|
314
|
+
"ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3",
|
|
315
|
+
"ALTER TABLE memories ADD COLUMN supersedes_id TEXT",
|
|
316
|
+
// MS-11: draft staging, MS-6a: memory_type, MS-7: trajectory
|
|
317
|
+
"ALTER TABLE memories ADD COLUMN draft INTEGER DEFAULT 0",
|
|
318
|
+
"ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'",
|
|
319
|
+
"ALTER TABLE memories ADD COLUMN trajectory TEXT",
|
|
320
|
+
// Metadata enrichment columns (must match database.ts)
|
|
321
|
+
"ALTER TABLE memories ADD COLUMN intent TEXT",
|
|
322
|
+
"ALTER TABLE memories ADD COLUMN outcome TEXT",
|
|
323
|
+
"ALTER TABLE memories ADD COLUMN domain TEXT",
|
|
324
|
+
"ALTER TABLE memories ADD COLUMN referenced_entities TEXT",
|
|
325
|
+
"ALTER TABLE memories ADD COLUMN retrieval_count INTEGER DEFAULT 0",
|
|
326
|
+
"ALTER TABLE memories ADD COLUMN chain_position TEXT",
|
|
327
|
+
"ALTER TABLE memories ADD COLUMN review_status TEXT",
|
|
328
|
+
"ALTER TABLE memories ADD COLUMN context_window_pct INTEGER",
|
|
329
|
+
"ALTER TABLE memories ADD COLUMN file_paths TEXT",
|
|
330
|
+
"ALTER TABLE memories ADD COLUMN commit_hash TEXT",
|
|
331
|
+
"ALTER TABLE memories ADD COLUMN duration_ms INTEGER",
|
|
332
|
+
"ALTER TABLE memories ADD COLUMN token_cost REAL",
|
|
333
|
+
"ALTER TABLE memories ADD COLUMN audience TEXT",
|
|
334
|
+
"ALTER TABLE memories ADD COLUMN language_type TEXT",
|
|
335
|
+
"ALTER TABLE memories ADD COLUMN parent_memory_id TEXT",
|
|
336
|
+
"ALTER TABLE memories ADD COLUMN deleted_at TEXT",
|
|
337
|
+
// Temporal validity (must match database.ts)
|
|
338
|
+
"ALTER TABLE memories ADD COLUMN valid_from TEXT",
|
|
339
|
+
"ALTER TABLE memories ADD COLUMN invalid_at TEXT",
|
|
340
|
+
// Multi-agent visibility (must match database.ts)
|
|
341
|
+
"ALTER TABLE memories ADD COLUMN visibility TEXT DEFAULT 'private'",
|
|
342
|
+
// Procedure binding (AFM-3, must match database.ts)
|
|
343
|
+
"ALTER TABLE memories ADD COLUMN procedure_for TEXT",
|
|
344
|
+
// Memory strength scoring — Ebbinghaus decay (must match database.ts)
|
|
345
|
+
"ALTER TABLE memories ADD COLUMN strength REAL DEFAULT 1.0",
|
|
346
|
+
// Source trust level (must match database.ts)
|
|
347
|
+
"ALTER TABLE memories ADD COLUMN source_trust_level TEXT DEFAULT 'unknown'",
|
|
348
|
+
// Poisoning defense (must match database.ts)
|
|
349
|
+
"ALTER TABLE memories ADD COLUMN quarantined INTEGER DEFAULT 0",
|
|
350
|
+
"ALTER TABLE memories ADD COLUMN quarantine_reason TEXT",
|
|
351
|
+
// Multi-modal media (must match database.ts)
|
|
352
|
+
"ALTER TABLE memories ADD COLUMN media_url TEXT",
|
|
353
|
+
"ALTER TABLE memories ADD COLUMN media_type TEXT",
|
|
354
|
+
"ALTER TABLE memories ADD COLUMN media_meta TEXT",
|
|
355
|
+
// Session scope (must match database.ts)
|
|
356
|
+
"ALTER TABLE memories ADD COLUMN session_scope TEXT",
|
|
357
|
+
// Keywords for FTS5 dual-column search (must match database.ts)
|
|
358
|
+
"ALTER TABLE memories ADD COLUMN keywords TEXT DEFAULT ''",
|
|
359
|
+
// Multi-user founder scope (must match database.ts)
|
|
360
|
+
"ALTER TABLE memories ADD COLUMN founder_id TEXT"
|
|
361
|
+
]) {
|
|
362
|
+
try {
|
|
363
|
+
await client.execute(col);
|
|
364
|
+
} catch {
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
for (const idx of [
|
|
368
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)",
|
|
369
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL",
|
|
370
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash ON memories(content_hash, agent_id, project_name, memory_type) WHERE content_hash IS NOT NULL"
|
|
371
|
+
]) {
|
|
372
|
+
try {
|
|
373
|
+
await client.execute(idx);
|
|
374
|
+
} catch {
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
try {
|
|
378
|
+
await client.execute("CREATE INDEX IF NOT EXISTS idx_memories_status ON memories(status)");
|
|
379
|
+
} catch {
|
|
380
|
+
}
|
|
381
|
+
for (const idx of [
|
|
382
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_workspace ON memories(workspace_id)",
|
|
383
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_document ON memories(document_id)",
|
|
384
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_user ON memories(user_id)"
|
|
385
|
+
]) {
|
|
386
|
+
try {
|
|
387
|
+
await client.execute(idx);
|
|
388
|
+
} catch {
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
await client.executeMultiple(`
|
|
392
|
+
CREATE TABLE IF NOT EXISTS entities (
|
|
393
|
+
id TEXT PRIMARY KEY,
|
|
394
|
+
name TEXT NOT NULL,
|
|
395
|
+
type TEXT NOT NULL,
|
|
396
|
+
first_seen TEXT NOT NULL,
|
|
397
|
+
last_seen TEXT NOT NULL,
|
|
398
|
+
properties TEXT DEFAULT '{}',
|
|
399
|
+
UNIQUE(name, type)
|
|
400
|
+
);
|
|
401
|
+
|
|
402
|
+
CREATE TABLE IF NOT EXISTS relationships (
|
|
403
|
+
id TEXT PRIMARY KEY,
|
|
404
|
+
source_entity_id TEXT NOT NULL,
|
|
405
|
+
target_entity_id TEXT NOT NULL,
|
|
406
|
+
type TEXT NOT NULL,
|
|
407
|
+
weight REAL DEFAULT 1.0,
|
|
408
|
+
timestamp TEXT NOT NULL,
|
|
409
|
+
properties TEXT DEFAULT '{}',
|
|
410
|
+
UNIQUE(source_entity_id, target_entity_id, type)
|
|
411
|
+
);
|
|
412
|
+
|
|
413
|
+
CREATE TABLE IF NOT EXISTS entity_memories (
|
|
414
|
+
entity_id TEXT NOT NULL,
|
|
415
|
+
memory_id TEXT NOT NULL,
|
|
416
|
+
PRIMARY KEY (entity_id, memory_id)
|
|
417
|
+
);
|
|
418
|
+
|
|
419
|
+
CREATE TABLE IF NOT EXISTS relationship_memories (
|
|
420
|
+
relationship_id TEXT NOT NULL,
|
|
421
|
+
memory_id TEXT NOT NULL,
|
|
422
|
+
PRIMARY KEY (relationship_id, memory_id)
|
|
423
|
+
);
|
|
424
|
+
|
|
425
|
+
CREATE INDEX IF NOT EXISTS idx_entities_name ON entities(name);
|
|
426
|
+
CREATE INDEX IF NOT EXISTS idx_entities_type ON entities(type);
|
|
427
|
+
CREATE INDEX IF NOT EXISTS idx_relationships_source ON relationships(source_entity_id);
|
|
428
|
+
CREATE INDEX IF NOT EXISTS idx_relationships_target ON relationships(target_entity_id);
|
|
429
|
+
CREATE INDEX IF NOT EXISTS idx_relationships_type ON relationships(type);
|
|
430
|
+
|
|
431
|
+
CREATE TABLE IF NOT EXISTS hyperedges (
|
|
432
|
+
id TEXT PRIMARY KEY,
|
|
433
|
+
label TEXT NOT NULL,
|
|
434
|
+
relation TEXT NOT NULL,
|
|
435
|
+
confidence REAL DEFAULT 1.0,
|
|
436
|
+
timestamp TEXT NOT NULL
|
|
437
|
+
);
|
|
438
|
+
|
|
439
|
+
CREATE TABLE IF NOT EXISTS hyperedge_nodes (
|
|
440
|
+
hyperedge_id TEXT NOT NULL,
|
|
441
|
+
entity_id TEXT NOT NULL,
|
|
442
|
+
PRIMARY KEY (hyperedge_id, entity_id)
|
|
443
|
+
);
|
|
444
|
+
`);
|
|
445
|
+
for (const col of [
|
|
446
|
+
"ALTER TABLE relationships ADD COLUMN confidence REAL DEFAULT 1.0",
|
|
447
|
+
"ALTER TABLE relationships ADD COLUMN confidence_label TEXT DEFAULT 'extracted'",
|
|
448
|
+
// Temporal validity (must match database.ts)
|
|
449
|
+
"ALTER TABLE relationships ADD COLUMN valid_from TEXT",
|
|
450
|
+
"ALTER TABLE relationships ADD COLUMN valid_until TEXT"
|
|
451
|
+
]) {
|
|
452
|
+
try {
|
|
453
|
+
await client.execute(col);
|
|
454
|
+
} catch {
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
try {
|
|
458
|
+
await client.execute("ALTER TABLE entities ADD COLUMN parent_type TEXT");
|
|
459
|
+
} catch {
|
|
460
|
+
}
|
|
461
|
+
for (const idx of [
|
|
462
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_session ON memories(session_id)",
|
|
463
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_project ON memories(project_name)",
|
|
464
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_tool ON memories(tool_name)",
|
|
465
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_content_hash ON memories(content_hash, agent_id)",
|
|
466
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_quarantined ON memories(quarantined) WHERE quarantined = 1",
|
|
467
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_draft ON memories(draft) WHERE draft = 1",
|
|
468
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_type ON memories(memory_type)",
|
|
469
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_agent_scope_project ON memories(agent_id, session_scope, project_name)",
|
|
470
|
+
// UNIQUE dedup index — prevents duplicate memories at DB level
|
|
471
|
+
"CREATE UNIQUE INDEX IF NOT EXISTS idx_memories_unique_scoped_hash ON memories(content_hash, agent_id, project_name, memory_type) WHERE content_hash IS NOT NULL AND COALESCE(status, 'active') != 'deleted'",
|
|
472
|
+
// Entity indexes
|
|
473
|
+
"CREATE INDEX IF NOT EXISTS idx_entities_type_name ON entities(type, name)",
|
|
474
|
+
// Relationship temporal indexes
|
|
475
|
+
"CREATE INDEX IF NOT EXISTS idx_relationships_valid_from ON relationships(valid_from)",
|
|
476
|
+
"CREATE INDEX IF NOT EXISTS idx_relationships_valid_until ON relationships(valid_until)"
|
|
477
|
+
]) {
|
|
478
|
+
try {
|
|
479
|
+
await client.execute(idx);
|
|
480
|
+
} catch {
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
await client.executeMultiple(`
|
|
484
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS entities_fts USING fts5(
|
|
485
|
+
name,
|
|
486
|
+
content='entities',
|
|
487
|
+
content_rowid='rowid'
|
|
488
|
+
);
|
|
489
|
+
|
|
490
|
+
CREATE TRIGGER IF NOT EXISTS entities_fts_ai AFTER INSERT ON entities BEGIN
|
|
491
|
+
INSERT INTO entities_fts(rowid, name) VALUES (new.rowid, new.name);
|
|
492
|
+
END;
|
|
493
|
+
|
|
494
|
+
CREATE TRIGGER IF NOT EXISTS entities_fts_ad AFTER DELETE ON entities BEGIN
|
|
495
|
+
INSERT INTO entities_fts(entities_fts, rowid, name) VALUES('delete', old.rowid, old.name);
|
|
496
|
+
END;
|
|
497
|
+
|
|
498
|
+
CREATE TRIGGER IF NOT EXISTS entities_fts_au AFTER UPDATE ON entities BEGIN
|
|
499
|
+
INSERT INTO entities_fts(entities_fts, rowid, name) VALUES('delete', old.rowid, old.name);
|
|
500
|
+
INSERT INTO entities_fts(rowid, name) VALUES (new.rowid, new.name);
|
|
501
|
+
END;
|
|
502
|
+
`);
|
|
503
|
+
}
|
|
504
|
+
async function getReadyShardClient(projectName) {
|
|
505
|
+
if (!_shardingEnabled && _validationFailedForKey === _encryptionKey) {
|
|
506
|
+
throw new Error(
|
|
507
|
+
`Shard creation blocked: encryption key mismatch with existing shards. Run /exe-doctor to audit.`
|
|
508
|
+
);
|
|
509
|
+
}
|
|
510
|
+
if (!_keyValidated) {
|
|
511
|
+
if (!_keyValidationPromise) {
|
|
512
|
+
_keyValidationPromise = validateEncryptionKey();
|
|
513
|
+
}
|
|
514
|
+
const valid = await _keyValidationPromise;
|
|
515
|
+
if (!valid) {
|
|
516
|
+
throw new Error(
|
|
517
|
+
`Shard creation blocked: encryption key mismatch with existing shards. Run /exe-doctor to audit.`
|
|
518
|
+
);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
if (!_shardingEnabled) {
|
|
522
|
+
throw new Error(
|
|
523
|
+
`Shard creation blocked: encryption key mismatch with existing shards. Run /exe-doctor to audit.`
|
|
524
|
+
);
|
|
525
|
+
}
|
|
526
|
+
const safeName = safeShardName(projectName);
|
|
527
|
+
let client = getShardClient(projectName);
|
|
528
|
+
try {
|
|
529
|
+
await ensureShardSchema(client);
|
|
530
|
+
return client;
|
|
531
|
+
} catch (err) {
|
|
532
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
533
|
+
if (!/SQLITE_NOTADB|file is not a database/i.test(message)) throw err;
|
|
534
|
+
client.close();
|
|
535
|
+
_shards.delete(safeName);
|
|
536
|
+
_shardLastAccess.delete(safeName);
|
|
537
|
+
const dbPath = path.join(SHARDS_DIR, `${safeName}.db`);
|
|
538
|
+
if (existsSync(dbPath)) {
|
|
539
|
+
const stat = statSync(dbPath);
|
|
540
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
541
|
+
const archivedPath = path.join(SHARDS_DIR, `${safeName}.db.broken-${stamp}`);
|
|
542
|
+
renameSync(dbPath, archivedPath);
|
|
543
|
+
process.stderr.write(
|
|
544
|
+
`[shard-manager] Archived unreadable shard ${safeName}: ${archivedPath} (${stat.size} bytes, mtime ${stat.mtime.toISOString()})
|
|
545
|
+
`
|
|
546
|
+
);
|
|
547
|
+
}
|
|
548
|
+
client = getShardClient(projectName);
|
|
549
|
+
await ensureShardSchema(client);
|
|
550
|
+
return client;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
function evictLRU() {
|
|
554
|
+
let oldest = null;
|
|
555
|
+
let oldestTime = Infinity;
|
|
556
|
+
for (const [name, time] of _shardLastAccess) {
|
|
557
|
+
if (time < oldestTime) {
|
|
558
|
+
oldestTime = time;
|
|
559
|
+
oldest = name;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
if (oldest) {
|
|
563
|
+
const client = _shards.get(oldest);
|
|
564
|
+
if (client) {
|
|
565
|
+
client.close();
|
|
566
|
+
}
|
|
567
|
+
_shards.delete(oldest);
|
|
568
|
+
_shardLastAccess.delete(oldest);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
function evictIdleShards() {
|
|
572
|
+
const now = Date.now();
|
|
573
|
+
const toEvict = [];
|
|
574
|
+
for (const [name, lastAccess] of _shardLastAccess) {
|
|
575
|
+
if (now - lastAccess > SHARD_IDLE_MS) {
|
|
576
|
+
toEvict.push(name);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
for (const name of toEvict) {
|
|
580
|
+
const client = _shards.get(name);
|
|
581
|
+
if (client) {
|
|
582
|
+
client.close();
|
|
583
|
+
}
|
|
584
|
+
_shards.delete(name);
|
|
585
|
+
_shardLastAccess.delete(name);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
function getOpenShardCount() {
|
|
589
|
+
return _shards.size;
|
|
590
|
+
}
|
|
591
|
+
function disposeShards() {
|
|
592
|
+
if (_evictionTimer) {
|
|
593
|
+
clearInterval(_evictionTimer);
|
|
594
|
+
_evictionTimer = null;
|
|
595
|
+
}
|
|
596
|
+
for (const [, client] of _shards) {
|
|
597
|
+
client.close();
|
|
598
|
+
}
|
|
599
|
+
_shards.clear();
|
|
600
|
+
_shardLastAccess.clear();
|
|
601
|
+
_shardingEnabled = false;
|
|
602
|
+
_encryptionKey = null;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
export {
|
|
606
|
+
initShardManager,
|
|
607
|
+
isShardingEnabled,
|
|
608
|
+
getShardsDir,
|
|
609
|
+
getShardClient,
|
|
610
|
+
shardExists,
|
|
611
|
+
listShards,
|
|
612
|
+
auditShardHealth,
|
|
613
|
+
ensureShardSchema,
|
|
614
|
+
getReadyShardClient,
|
|
615
|
+
getOpenShardCount,
|
|
616
|
+
disposeShards
|
|
617
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import {
|
|
2
|
+
listReminders
|
|
3
|
+
} from "./chunk-DEBLYXA2.js";
|
|
4
|
+
|
|
5
|
+
// src/mcp/tools/list-reminders.ts
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
function registerListReminders(server) {
|
|
8
|
+
server.registerTool(
|
|
9
|
+
"list_reminders",
|
|
10
|
+
{
|
|
11
|
+
title: "List Reminders",
|
|
12
|
+
description: "List active reminders. Pass include_completed=true to see all.",
|
|
13
|
+
inputSchema: {
|
|
14
|
+
include_completed: z.boolean().optional().default(false).describe("Include completed reminders")
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
async ({ include_completed }) => {
|
|
18
|
+
const reminders = await listReminders(include_completed);
|
|
19
|
+
if (reminders.length === 0) {
|
|
20
|
+
return {
|
|
21
|
+
content: [{ type: "text", text: "No active reminders." }]
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
const lines = reminders.map((r) => {
|
|
25
|
+
const due = r.dueDate ? ` (due: ${r.dueDate})` : "";
|
|
26
|
+
const done = r.completedAt ? " [DONE]" : "";
|
|
27
|
+
return `\u2022 ${r.text}${due}${done} [id: ${r.id.slice(0, 8)}]`;
|
|
28
|
+
});
|
|
29
|
+
return {
|
|
30
|
+
content: [{ type: "text", text: lines.join("\n") }]
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export {
|
|
37
|
+
registerListReminders
|
|
38
|
+
};
|