@askexenow/exe-os 0.9.127 → 0.9.129
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/active-agent-3FDJYREJ.js +22 -0
- package/dist/active-agent-WC7YK3L5.js +23 -0
- package/dist/agent-context-CDWUZEXY.js +11 -0
- package/dist/agent-loop-G4VUR5ME.js +10 -0
- package/dist/agentic-ontology-2VYNTMNO.js +25 -0
- package/dist/backfill-metadata-OJWOCLSZ.js +601 -0
- package/dist/background-jobs-LGRDXGXC.js +25 -0
- package/dist/bash-Y5PEW5UQ.js +8 -0
- package/dist/behaviors-CSB2YLDT.js +22 -0
- package/dist/bin/age-ontology-load.js +10 -258
- package/dist/bin/agentic-ontology-backfill.js +23 -5296
- package/dist/bin/agentic-reflection-backfill.js +19 -4739
- package/dist/bin/agentic-semantic-label.js +28 -4723
- package/dist/bin/backfill-conversations.js +42 -5543
- package/dist/bin/backfill-responses.js +41 -5542
- package/dist/bin/backfill-vectors.js +43 -4795
- package/dist/bin/bulk-sync-postgres.js +22 -5313
- package/dist/bin/cc-doctor.js +10 -602
- package/dist/bin/cleanup-stale-review-tasks.js +32 -6803
- package/dist/bin/cli.js +169 -38993
- package/dist/bin/exe-agent-config.js +21 -253
- package/dist/bin/exe-agent.js +63 -2429
- package/dist/bin/exe-assign.js +34 -5810
- package/dist/bin/exe-boot.js +180 -12726
- package/dist/bin/exe-call.js +48 -1409
- package/dist/bin/exe-cloud.js +64 -8516
- package/dist/bin/exe-dispatch.js +35 -10818
- package/dist/bin/exe-doctor.js +24 -7537
- package/dist/bin/exe-export-behaviors.js +18 -6122
- package/dist/bin/exe-forget.js +22 -6274
- package/dist/bin/exe-gateway.js +62 -15286
- package/dist/bin/exe-healthcheck.js +9 -602
- package/dist/bin/exe-heartbeat.js +51 -6898
- package/dist/bin/exe-kill.js +30 -5961
- package/dist/bin/exe-launch-agent.js +101 -6788
- package/dist/bin/exe-new-employee.js +42 -3774
- package/dist/bin/exe-pending-messages.js +28 -6833
- package/dist/bin/exe-pending-notifications.js +31 -6869
- package/dist/bin/exe-pending-reviews.js +38 -6910
- package/dist/bin/exe-rename.js +57 -5766
- package/dist/bin/exe-review.js +29 -5948
- package/dist/bin/exe-search.js +22 -7692
- package/dist/bin/exe-session-cleanup.js +52 -11147
- package/dist/bin/exe-settings.js +35 -524
- package/dist/bin/exe-start-codex.js +70 -6641
- package/dist/bin/exe-start-opencode.js +54 -6584
- package/dist/bin/exe-status.js +26 -7081
- package/dist/bin/exe-support.js +10 -546
- package/dist/bin/exe-team.js +18 -5942
- package/dist/bin/git-sweep.js +26 -10909
- package/dist/bin/graph-backfill.js +24 -5979
- package/dist/bin/graph-export.js +31 -6128
- package/dist/bin/graph-layer-benchmark.js +4 -8
- package/dist/bin/install.js +47 -2322
- package/dist/bin/intercom-check.js +25 -11501
- package/dist/bin/list-providers.js +4 -18
- package/dist/bin/postgres-agentic-reflection-backfill.js +14 -357
- package/dist/bin/postgres-agentic-semantic-backfill.js +14 -404
- package/dist/bin/pre-publish.js +4 -298
- package/dist/bin/registry-proxy.js +8 -172
- package/dist/bin/scan-tasks.js +47 -10881
- package/dist/bin/setup.js +6 -9492
- package/dist/bin/shard-migrate.js +30 -5149
- package/dist/bin/stack-update.js +75 -203
- package/dist/bin/update.js +20 -654
- package/dist/capacity-monitor-3GZIHLB4.js +46 -0
- package/dist/catchup-brief-67QDCINS.js +148 -0
- package/dist/chunk-2QD7KBJN.js +664 -0
- package/dist/chunk-2WGSIVI4.js +149 -0
- package/dist/chunk-35TVNLJI.js +57 -0
- package/dist/chunk-3SYV36U5.js +47 -0
- package/dist/chunk-46SQTBQW.js +207 -0
- package/dist/chunk-4CMVLKEI.js +171 -0
- package/dist/chunk-4FLUOZTR.js +116 -0
- package/dist/chunk-4NYQAS33.js +17 -0
- package/dist/chunk-4QNPADWL.js +902 -0
- package/dist/chunk-4Y6QZBEO.js +58 -0
- package/dist/chunk-557C2IGL.js +0 -0
- package/dist/chunk-55S56YDO.js +305 -0
- package/dist/chunk-5BS5ELMC.js +85 -0
- package/dist/chunk-5DHM77JE.js +256 -0
- package/dist/chunk-5QTWQKNF.js +137 -0
- package/dist/chunk-6A7P74QV.js +53 -0
- package/dist/chunk-6BFIFI5F.js +45 -0
- package/dist/chunk-6KFICEAT.js +20 -0
- package/dist/chunk-6LKDJ5WX.js +317 -0
- package/dist/chunk-6M5II4EV.js +148 -0
- package/dist/chunk-6QEFN3DV.js +302 -0
- package/dist/chunk-6WTMJAG3.js +171 -0
- package/dist/chunk-6Y4B3QF6.js +19 -0
- package/dist/chunk-7RK3AYJE.js +163 -0
- package/dist/chunk-7TCP2XTP.js +390 -0
- package/dist/chunk-A2NZP64U.js +2307 -0
- package/dist/chunk-AFYIYM2K.js +322 -0
- package/dist/chunk-AJWFPKQS.js +573 -0
- package/dist/chunk-AVE2B4DQ.js +140 -0
- package/dist/chunk-B4TT2QQA.js +87 -0
- package/dist/chunk-BCMOO4OQ.js +1066 -0
- package/dist/chunk-BU3ID2WT.js +432 -0
- package/dist/chunk-CFIM43JH.js +862 -0
- package/dist/chunk-CURJUF3W.js +66 -0
- package/dist/chunk-DC4ZD76Y.js +288 -0
- package/dist/chunk-DL52JPGF.js +706 -0
- package/dist/chunk-DRSC6ZRA.js +36 -0
- package/dist/chunk-E2Q4Y22A.js +86 -0
- package/dist/chunk-ECGTESAP.js +236 -0
- package/dist/chunk-EHOJUXYG.js +365 -0
- package/dist/chunk-EIT6J37V.js +119 -0
- package/dist/chunk-ELE2C7L4.js +31 -0
- package/dist/chunk-EQSQ4HBW.js +9 -0
- package/dist/chunk-FWFFZGSC.js +94 -0
- package/dist/chunk-GCNWCYJI.js +249 -0
- package/dist/chunk-GGTUUI7J.js +6 -0
- package/dist/chunk-GU56L7OY.js +223 -0
- package/dist/chunk-HF25XPZE.js +83 -0
- package/dist/chunk-HOKOOBDL.js +52 -0
- package/dist/chunk-HP43GLZ6.js +89 -0
- package/dist/chunk-HSRM6PNM.js +682 -0
- package/dist/chunk-HVRTW3OP.js +164 -0
- package/dist/chunk-IHDHL5ML.js +125 -0
- package/dist/chunk-IHF5RXJM.js +168 -0
- package/dist/chunk-IJ73YE73.js +409 -0
- package/dist/chunk-INO4ZD5Y.js +162 -0
- package/dist/chunk-IRQTM7DY.js +475 -0
- package/dist/chunk-JD4FAPYG.js +1208 -0
- package/dist/chunk-JN44LQ53.js +316 -0
- package/dist/chunk-JQ6TLNIV.js +133 -0
- package/dist/chunk-JT76KRZQ.js +35 -0
- package/dist/chunk-K6OEWZTB.js +262 -0
- package/dist/chunk-KCUYRZSX.js +72 -0
- package/dist/chunk-KFQGP6VL.js +33 -0
- package/dist/chunk-KRLOFIPI.js +83 -0
- package/dist/chunk-KVPG5UT6.js +305 -0
- package/dist/chunk-L3TB7CC3.js +170 -0
- package/dist/chunk-L4X5EUHR.js +283 -0
- package/dist/chunk-LAN26C3W.js +655 -0
- package/dist/chunk-LPGBKR4H.js +54 -0
- package/dist/chunk-LVNMOVGD.js +132 -0
- package/dist/chunk-LX5WEEZ7.js +157 -0
- package/dist/chunk-MBH42QNH.js +295 -0
- package/dist/chunk-MFO7MNSD.js +102 -0
- package/dist/chunk-MILTNDZH.js +736 -0
- package/dist/chunk-MJAE4NB7.js +1090 -0
- package/dist/chunk-MLCUPTP7.js +132 -0
- package/dist/chunk-MPURH6JI.js +445 -0
- package/dist/chunk-MVBWW2EO.js +89 -0
- package/dist/chunk-MZIGUUDQ.js +42 -0
- package/dist/chunk-N3DTSVKE.js +157 -0
- package/dist/chunk-N5RRQOAC.js +134 -0
- package/dist/chunk-N7L33TED.js +1664 -0
- package/dist/chunk-NDYSNVI5.js +122 -0
- package/dist/chunk-NEAHEC5G.js +155 -0
- package/dist/chunk-NGVOA6ZQ.js +84 -0
- package/dist/chunk-NHK5KW6Y.js +193 -0
- package/dist/chunk-NMQKGFEP.js +458 -0
- package/dist/chunk-NPT4EHZK.js +352 -0
- package/dist/chunk-NXFJHTED.js +55 -0
- package/dist/chunk-NZLCDI6Y.js +216 -0
- package/dist/chunk-O377P7GM.js +100 -0
- package/dist/chunk-O4VFZRA5.js +33 -0
- package/dist/chunk-O7YD7JYE.js +237 -0
- package/dist/chunk-OFK72LTZ.js +81 -0
- package/dist/chunk-ORCCI2VV.js +140 -0
- package/dist/chunk-OVQR4KMC.js +579 -0
- package/dist/chunk-P3CVUMEH.js +54 -0
- package/dist/chunk-P4HIF72O.js +30 -0
- package/dist/chunk-PEDLSJBL.js +1039 -0
- package/dist/chunk-PFICKZZ5.js +219 -0
- package/dist/chunk-PGW7TIV6.js +142 -0
- package/dist/chunk-PJHHFJAN.js +63 -0
- package/dist/chunk-PP4SNOJ5.js +471 -0
- package/dist/chunk-PRKVT4KN.js +90 -0
- package/dist/chunk-Q2O4VJHH.js +305 -0
- package/dist/chunk-Q36CMZIX.js +38 -0
- package/dist/chunk-Q3V7K4ME.js +149 -0
- package/dist/chunk-QGYPJGHB.js +81 -0
- package/dist/chunk-R23EMFJV.js +198 -0
- package/dist/chunk-R4M6XCMU.js +39 -0
- package/dist/chunk-R4WMF32C.js +81 -0
- package/dist/chunk-RJT7H2KR.js +349 -0
- package/dist/chunk-RJZMRZNV.js +280 -0
- package/dist/chunk-RMFDPCA2.js +72 -0
- package/dist/chunk-RUG3N6P4.js +292 -0
- package/dist/chunk-RWO327FJ.js +84 -0
- package/dist/chunk-SG7EFHQ7.js +108 -0
- package/dist/chunk-SH45SJQW.js +0 -0
- package/dist/chunk-SPKE5ANC.js +42 -0
- package/dist/chunk-SVMFVPBF.js +104 -0
- package/dist/chunk-SVXDCELZ.js +163 -0
- package/dist/chunk-TMEE7AT7.js +72 -0
- package/dist/chunk-TWYEE4FB.js +125 -0
- package/dist/chunk-TYLF4LSW.js +110 -0
- package/dist/chunk-V4TZI6EO.js +60 -0
- package/dist/chunk-VFZTXKQI.js +372 -0
- package/dist/chunk-VQ4K2MLM.js +199 -0
- package/dist/chunk-VU447UAO.js +173 -0
- package/dist/chunk-WMC3TXJF.js +50 -0
- package/dist/chunk-WPOA7XAE.js +84 -0
- package/dist/chunk-WZQ4CPRG.js +64 -0
- package/dist/chunk-X2IMCCM5.js +49 -0
- package/dist/chunk-X2Z5GT3V.js +118 -0
- package/dist/chunk-XEKO37NM.js +43 -0
- package/dist/chunk-XUHFQHGZ.js +505 -0
- package/dist/chunk-YGAAZN3E.js +47 -0
- package/dist/chunk-YKOW7KMK.js +558 -0
- package/dist/chunk-YOQKMB6N.js +145 -0
- package/dist/chunk-YZFZDJWZ.js +107 -0
- package/dist/chunk-ZBY4AUD4.js +10342 -0
- package/dist/chunk-ZOJYPNCM.js +127 -0
- package/dist/chunk-ZS7MGQSD.js +1494 -0
- package/dist/chunk-ZTZQ5A6B.js +191 -0
- package/dist/code-context-index-HXGC4IJL.js +28 -0
- package/dist/content-extractor-UVZXRIPC.js +8 -0
- package/dist/conversation-entity-extractor-HKSNDF4L.js +113 -0
- package/dist/conversation-wiki-populator-NKDAQEZ5.js +105 -0
- package/dist/crdt-sync-T7MHVQCS.js +33 -0
- package/dist/crm-bridge-Q5JBVJ6P.js +19 -0
- package/dist/crm-webhook-OAFTLJYA.js +10 -0
- package/dist/cto-delegation-gate-XWHZCUJH.js +208 -0
- package/dist/daemon-auth-GWUXTUYO.js +15 -0
- package/dist/daemon-orchestration-2C3TVOHO.js +91 -0
- package/dist/daemon-protocol-RLH2XM2K.js +19 -0
- package/dist/db-backup-CH2KG3JY.js +23 -0
- package/dist/devtools-PLJCAU53.js +8 -0
- package/dist/discord-G4BQJ2VX.js +7 -0
- package/dist/email-XMRNMFXR.js +137 -0
- package/dist/entity-boost-IOER4VRR.js +249 -0
- package/dist/exe-drift-2IJFQV43.js +68 -0
- package/dist/exe-export-Y2RFXGNB.js +71 -0
- package/dist/exe-import-LN6PE2YT.js +74 -0
- package/dist/exe-key-DHKBWLIT.js +571 -0
- package/dist/exe-org-F7LZRHFB.js +73 -0
- package/dist/factory-YTD23AW7.js +67 -0
- package/dist/fast-db-init-IIP6EGWT.js +7 -0
- package/dist/file-edit-FJVEO7XZ.js +8 -0
- package/dist/file-read-Q2NH3J35.js +8 -0
- package/dist/file-write-UNSFXNH4.js +8 -0
- package/dist/gateway/index.js +87 -16563
- package/dist/gateway-client-APTYJNCL.js +11 -0
- package/dist/git-staleness-I2BUEDE2.js +111 -0
- package/dist/git-task-sweep-UEOTXRW4.js +35 -0
- package/dist/glob-GRMXLDMB.js +7 -0
- package/dist/global-procedures-MFE5LGRF.js +19 -0
- package/dist/graph-query-657O5JYJ.js +25 -0
- package/dist/graph-rag-ZE5N7C65.js +28 -0
- package/dist/grep-NBV6SKYZ.js +7 -0
- package/dist/hooks/bug-report-worker.js +41 -10823
- package/dist/hooks/codex-stop-task-finalizer.js +38 -9055
- package/dist/hooks/commit-complete.js +32 -10914
- package/dist/hooks/error-recall.js +35 -7955
- package/dist/hooks/exe-heartbeat-hook.js +17 -327
- package/dist/hooks/ingest-worker.js +16 -565
- package/dist/hooks/ingest.js +98 -11436
- package/dist/hooks/instructions-loaded.js +25 -6209
- package/dist/hooks/notification.js +16 -6098
- package/dist/hooks/post-compact.js +34 -7041
- package/dist/hooks/post-tool-combined.js +27 -9751
- package/dist/hooks/pre-compact.js +38 -11130
- package/dist/hooks/pre-tool-use.js +61 -7233
- package/dist/hooks/prompt-submit.js +113 -13358
- package/dist/hooks/session-end.js +57 -11503
- package/dist/hooks/session-start.js +46 -9423
- package/dist/hooks/stop.js +70 -7210
- package/dist/hooks/subagent-stop.js +33 -6897
- package/dist/hooks/summary-worker.js +86 -8629
- package/dist/hooks-KD3N2D7P.js +9 -0
- package/dist/imessage-L7WKA2WD.js +7 -0
- package/dist/index.js +49 -19391
- package/dist/installer-5N24GXFB.js +32 -0
- package/dist/installer-QSD76YRY.js +291 -0
- package/dist/installer-ZPQUKHU5.js +331 -0
- package/dist/intercom-queue-PEEGAJ33.js +19 -0
- package/dist/key-backup-status-57UB74DU.js +41 -0
- package/dist/lib/agent-config.js +19 -224
- package/dist/lib/cloud-sync.js +44 -5398
- package/dist/lib/cloudflare-dns.js +7 -111
- package/dist/lib/config.js +18 -278
- package/dist/lib/consolidation.js +21 -1047
- package/dist/lib/crypto.js +7 -45
- package/dist/lib/database.js +20 -2932
- package/dist/lib/db-daemon-client.js +24 -460
- package/dist/lib/db.js +22 -2932
- package/dist/lib/device-registry.js +20 -2992
- package/dist/lib/embedder.js +14 -822
- package/dist/lib/employee-templates.js +21 -1102
- package/dist/lib/employees.js +30 -497
- package/dist/lib/error-detector.js +9 -149
- package/dist/lib/exe-daemon-client.js +16 -570
- package/dist/lib/exe-daemon.js +509 -18398
- package/dist/lib/file-grep.js +2 -0
- package/dist/lib/hybrid-search.js +18 -7674
- package/dist/lib/identity-templates.js +2 -0
- package/dist/lib/identity.js +13 -309
- package/dist/lib/keychain.js +9 -499
- package/dist/lib/license.js +21 -549
- package/dist/lib/messaging.js +35 -1631
- package/dist/lib/post-tool-memory.js +8 -370
- package/dist/lib/registry-proxy.js +8 -155
- package/dist/lib/reminders.js +11 -231
- package/dist/lib/runtime-table.js +7 -20
- package/dist/lib/schedules.js +16 -4614
- package/dist/lib/session-registry.js +9 -57
- package/dist/lib/session-wrappers.js +3 -127
- package/dist/lib/skill-learning.js +20 -2101
- package/dist/lib/status-brief.js +4 -368
- package/dist/lib/store.js +25 -5593
- package/dist/lib/task-router.js +12 -254
- package/dist/lib/tasks.js +44 -5801
- package/dist/lib/tmux-routing.js +45 -5804
- package/dist/lib/tmux-status.js +16 -248
- package/dist/lib/tmux-transport.js +6 -90
- package/dist/lib/token-spend.js +9 -337
- package/dist/lib/transport.js +8 -134
- package/dist/lib/ws-auth.js +6 -14
- package/dist/lib/ws-client.js +4 -22
- package/dist/license-gate-NXXDOOAQ.js +14 -0
- package/dist/mcp/register-tools.js +90 -32454
- package/dist/mcp/server.js +139 -32625
- package/dist/mcp/tools/complete-reminder.js +10 -237
- package/dist/mcp/tools/create-reminder.js +10 -222
- package/dist/mcp/tools/create-task.js +28 -6730
- package/dist/mcp/tools/deactivate-behavior.js +13 -476
- package/dist/mcp/tools/list-reminders.js +10 -232
- package/dist/mcp/tools/list-tasks.js +28 -1571
- package/dist/mcp/tools/send-message.js +25 -1672
- package/dist/mcp/tools/update-task.js +27 -6123
- package/dist/mcp-diagnostics-OOZ3TDPY.js +200 -0
- package/dist/memory-cards-RIL5BZHK.js +175 -0
- package/dist/memory-queue-JYIJ7TMQ.js +13 -0
- package/dist/memory-queue-client-PE7757HU.js +14 -0
- package/dist/notifications-CJFULBMN.js +42 -0
- package/dist/orchestration-phase-Y2TYNW5H.js +23 -0
- package/dist/orchestrator-RXIPT6PZ.js +29 -0
- package/dist/permission-presets-WI524OSE.js +25 -0
- package/dist/permissions-TYT6YMNZ.js +14 -0
- package/dist/pg-ssl-KFHNJPGO.js +7 -0
- package/dist/plan-limits-5WY5YK6X.js +27 -0
- package/dist/preferences-MW3BYTQ5.js +10 -0
- package/dist/project-name-PL2ZDWNU.js +11 -0
- package/dist/projection-worker-OY4WYZW6.js +661 -0
- package/dist/reranker-LFJ73RRS.js +19 -0
- package/dist/review-gate-E6K7QQE5.js +120 -0
- package/dist/runtime/index.js +82 -13408
- package/dist/self-query-router-IZANO632.js +83 -0
- package/dist/session-events-TQ6S5KQN.js +32 -0
- package/dist/session-kill-telemetry-46YIJWE2.js +30 -0
- package/dist/session-scope-3MYK3YRV.js +34 -0
- package/dist/setup-wizard-ZJ7UCRBP.js +12 -0
- package/dist/shard-manager-RCFZ6RXY.js +29 -0
- package/dist/signal-XN2C7PIG.js +7 -0
- package/dist/slack-Z77TFJCK.js +7 -0
- package/dist/task-enforcement-337DZI3I.js +252 -0
- package/dist/task-scanner-IMIR3T7T.js +11 -0
- package/dist/task-scope-MUU4KXE6.js +32 -0
- package/dist/tasks-crud-PMLK3MM4.js +53 -0
- package/dist/tasks-review-56LVKKNL.js +44 -0
- package/dist/telegram-CRPZO7JT.js +7 -0
- package/dist/telemetry-SPVGPKU7.js +9 -0
- package/dist/tool-capability-index-XNBSDCH3.js +10 -0
- package/dist/tool-gates-LGH6CSY4.js +14 -0
- package/dist/tool-gates-W7SZCYTX.js +13 -0
- package/dist/tool-registry-436LVVLY.js +11 -0
- package/dist/tool-telemetry-L77WNAYT.js +15 -0
- package/dist/tui/App.js +253 -14668
- package/dist/tui-data-SB45REYU.js +161 -0
- package/dist/update-check-LZGZISRJ.js +11 -0
- package/dist/webhook-VVP7KQVC.js +96 -0
- package/dist/whatsapp-J6QNDBGY.js +9 -0
- package/dist/whatsapp-accounts-RTJF3LM6.js +15 -0
- package/dist/wiki-client-EKCIKCVC.js +136 -0
- package/dist/worker-gate-UYNN62GJ.js +19 -0
- package/dist/worktree-4T4BPWPN.js +205 -0
- package/package.json +1 -1
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
import {
|
|
2
|
+
vectorToBlob
|
|
3
|
+
} from "./chunk-HSRM6PNM.js";
|
|
4
|
+
import {
|
|
5
|
+
init_employees,
|
|
6
|
+
isCoordinatorName
|
|
7
|
+
} from "./chunk-RUG3N6P4.js";
|
|
8
|
+
|
|
9
|
+
// src/lib/consolidation.ts
|
|
10
|
+
import { randomUUID } from "crypto";
|
|
11
|
+
init_employees();
|
|
12
|
+
async function selectUnconsolidated(client, limit = 200) {
|
|
13
|
+
const result = await client.execute({
|
|
14
|
+
sql: `SELECT id, agent_id, project_name, tool_name, raw_text, timestamp
|
|
15
|
+
FROM memories
|
|
16
|
+
WHERE consolidated = 0
|
|
17
|
+
AND COALESCE(memory_type, 'raw') != 'procedure'
|
|
18
|
+
ORDER BY timestamp DESC
|
|
19
|
+
LIMIT ?`,
|
|
20
|
+
args: [limit]
|
|
21
|
+
});
|
|
22
|
+
return result.rows.map((row) => ({
|
|
23
|
+
id: row.id,
|
|
24
|
+
agent_id: row.agent_id,
|
|
25
|
+
project_name: row.project_name,
|
|
26
|
+
tool_name: row.tool_name,
|
|
27
|
+
raw_text: row.raw_text,
|
|
28
|
+
timestamp: row.timestamp
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
function groupMemories(memories) {
|
|
32
|
+
const byProject = /* @__PURE__ */ new Map();
|
|
33
|
+
for (const mem of memories) {
|
|
34
|
+
const key = `${mem.agent_id}::${mem.project_name}`;
|
|
35
|
+
const list = byProject.get(key) ?? [];
|
|
36
|
+
list.push(mem);
|
|
37
|
+
byProject.set(key, list);
|
|
38
|
+
}
|
|
39
|
+
const clusters = [];
|
|
40
|
+
for (const [key, projectMemories] of byProject) {
|
|
41
|
+
const [agentId, projectName] = key.split("::");
|
|
42
|
+
const byDay = /* @__PURE__ */ new Map();
|
|
43
|
+
for (const mem of projectMemories) {
|
|
44
|
+
const day = mem.timestamp.slice(0, 10);
|
|
45
|
+
const list = byDay.get(day) ?? [];
|
|
46
|
+
list.push(mem);
|
|
47
|
+
byDay.set(day, list);
|
|
48
|
+
}
|
|
49
|
+
for (const [day, dayMemories] of byDay) {
|
|
50
|
+
if (dayMemories.length <= 15) {
|
|
51
|
+
clusters.push({
|
|
52
|
+
agentId,
|
|
53
|
+
projectName,
|
|
54
|
+
dateRange: day,
|
|
55
|
+
memories: dayMemories
|
|
56
|
+
});
|
|
57
|
+
} else {
|
|
58
|
+
for (let i = 0; i < dayMemories.length; i += 12) {
|
|
59
|
+
const chunk = dayMemories.slice(i, i + 12);
|
|
60
|
+
clusters.push({
|
|
61
|
+
agentId,
|
|
62
|
+
projectName,
|
|
63
|
+
dateRange: day,
|
|
64
|
+
memories: chunk
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return clusters;
|
|
71
|
+
}
|
|
72
|
+
var ROLE_PROMPTS = {
|
|
73
|
+
"COO": `Extract EXACTLY THREE types of insights:
|
|
74
|
+
1. KEY DECISIONS \u2014 choices that were made and why (at most 3)
|
|
75
|
+
2. RECURRING PATTERNS \u2014 actions or approaches that repeated (at most 3)
|
|
76
|
+
3. OPEN QUESTIONS \u2014 things that seem unresolved or risky (at most 2)`,
|
|
77
|
+
"CTO": `Extract EXACTLY THREE types of insights:
|
|
78
|
+
1. ARCHITECTURE DECISIONS \u2014 design choices, tradeoffs, delegation patterns (at most 3)
|
|
79
|
+
2. REVIEW OUTCOMES \u2014 what was approved, rejected, or flagged during code review (at most 3)
|
|
80
|
+
3. TECHNICAL DEBT \u2014 unresolved issues, deferred work, risks identified (at most 2)`,
|
|
81
|
+
"Principal Engineer": `Extract EXACTLY THREE types of insights:
|
|
82
|
+
1. CODE DECISIONS \u2014 implementation choices, patterns used, bugs fixed (at most 3)
|
|
83
|
+
2. FILE CHANGES \u2014 key files modified and why (at most 3)
|
|
84
|
+
3. BLOCKERS \u2014 things that slowed down or prevented progress (at most 2)`,
|
|
85
|
+
"Staff Code Reviewer": `Extract EXACTLY THREE types of insights:
|
|
86
|
+
1. AUDIT FINDINGS \u2014 issues found, severity, fix status (at most 3)
|
|
87
|
+
2. RECURRING ISSUES \u2014 patterns that keep appearing across reviews (at most 3)
|
|
88
|
+
3. QUALITY SIGNALS \u2014 areas of the codebase that are strong or weak (at most 2)`,
|
|
89
|
+
"CMO": `Extract EXACTLY THREE types of insights:
|
|
90
|
+
1. DESIGN DECISIONS \u2014 brand, layout, typography, or content choices made (at most 3)
|
|
91
|
+
2. CONTENT STRATEGY \u2014 messaging, SEO, platform-specific decisions (at most 3)
|
|
92
|
+
3. BRAND ALIGNMENT \u2014 consistency issues or guidelines established (at most 2)`,
|
|
93
|
+
"AI Product Lead": `Extract EXACTLY THREE types of insights:
|
|
94
|
+
1. RESEARCH FINDINGS \u2014 tools, repos, or models evaluated with conclusions (at most 3)
|
|
95
|
+
2. COMPETITIVE GAPS \u2014 features or patterns worth adopting from competitors (at most 3)
|
|
96
|
+
3. BUILD RECOMMENDATIONS \u2014 what to build, skip, or watch (at most 2)`
|
|
97
|
+
};
|
|
98
|
+
var DEFAULT_ROLE_PROMPT = `Extract EXACTLY THREE types of insights:
|
|
99
|
+
1. KEY DECISIONS \u2014 choices that were made and why (at most 3)
|
|
100
|
+
2. RECURRING PATTERNS \u2014 actions or approaches that repeated (at most 3)
|
|
101
|
+
3. OPEN QUESTIONS \u2014 things that seem unresolved or risky (at most 2)`;
|
|
102
|
+
function buildConsolidationPrompt(cluster, agentRole) {
|
|
103
|
+
const snippets = cluster.memories.map((m, i) => {
|
|
104
|
+
const text = m.raw_text.length > 200 ? m.raw_text.slice(0, 200) + "..." : m.raw_text;
|
|
105
|
+
return `${i + 1}. [${m.tool_name}] ${text}`;
|
|
106
|
+
}).join("\n");
|
|
107
|
+
const rolePrompt = agentRole && ROLE_PROMPTS[agentRole] || DEFAULT_ROLE_PROMPT;
|
|
108
|
+
return `You are reviewing a set of work memories from an AI coding agent.
|
|
109
|
+
These are raw tool call records from ${cluster.dateRange}.
|
|
110
|
+
|
|
111
|
+
Agent: ${cluster.agentId} | Project: ${cluster.projectName} | Date: ${cluster.dateRange}
|
|
112
|
+
|
|
113
|
+
MEMORIES:
|
|
114
|
+
${snippets}
|
|
115
|
+
|
|
116
|
+
${rolePrompt}
|
|
117
|
+
|
|
118
|
+
Format each as a single sentence. Be specific \u2014 include file names,
|
|
119
|
+
function names, and concrete details. Skip if no insight for a category.`;
|
|
120
|
+
}
|
|
121
|
+
async function consolidateCluster(cluster, model, agentRole) {
|
|
122
|
+
const Anthropic = (await import("@anthropic-ai/sdk")).default;
|
|
123
|
+
const client = new Anthropic();
|
|
124
|
+
const prompt = buildConsolidationPrompt(cluster, agentRole);
|
|
125
|
+
const response = await client.messages.create({
|
|
126
|
+
model,
|
|
127
|
+
max_tokens: 300,
|
|
128
|
+
messages: [{ role: "user", content: prompt }]
|
|
129
|
+
});
|
|
130
|
+
const textBlock = response.content.find((b) => b.type === "text");
|
|
131
|
+
return textBlock?.text ?? "";
|
|
132
|
+
}
|
|
133
|
+
async function storeConsolidation(client, cluster, synthesisText, embedFn) {
|
|
134
|
+
const consolidatedId = randomUUID();
|
|
135
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
136
|
+
const rawText = `CONSOLIDATION [${cluster.dateRange}, ${cluster.projectName}]:
|
|
137
|
+
|
|
138
|
+
${synthesisText}`;
|
|
139
|
+
let vector = null;
|
|
140
|
+
if (embedFn) {
|
|
141
|
+
try {
|
|
142
|
+
vector = await embedFn(rawText);
|
|
143
|
+
} catch {
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const insertSql = vector ? `INSERT INTO memories
|
|
147
|
+
(id, agent_id, agent_role, session_id, timestamp,
|
|
148
|
+
tool_name, project_name, has_error, raw_text, vector, version, consolidated, importance)
|
|
149
|
+
VALUES (?, ?, 'consolidation', 'daemon-consolidation', ?, 'consolidation', ?, 0, ?, vector32(?), 0, 1, 9)` : `INSERT INTO memories
|
|
150
|
+
(id, agent_id, agent_role, session_id, timestamp,
|
|
151
|
+
tool_name, project_name, has_error, raw_text, vector, version, consolidated, importance)
|
|
152
|
+
VALUES (?, ?, 'consolidation', 'daemon-consolidation', ?, 'consolidation', ?, 0, ?, NULL, 0, 1, 9)`;
|
|
153
|
+
const insertArgs = vector ? [consolidatedId, cluster.agentId, now, cluster.projectName, rawText, vectorToBlob(vector)] : [consolidatedId, cluster.agentId, now, cluster.projectName, rawText];
|
|
154
|
+
await client.execute({ sql: insertSql, args: insertArgs });
|
|
155
|
+
const sourceIds = cluster.memories.map((m) => m.id);
|
|
156
|
+
const linkStmts = sourceIds.map((sourceId) => ({
|
|
157
|
+
sql: `INSERT INTO consolidations (id, consolidated_memory_id, source_memory_id, created_at)
|
|
158
|
+
VALUES (?, ?, ?, ?)`,
|
|
159
|
+
args: [randomUUID(), consolidatedId, sourceId, now]
|
|
160
|
+
}));
|
|
161
|
+
const placeholders = sourceIds.map(() => "?").join(",");
|
|
162
|
+
const markStmt = {
|
|
163
|
+
sql: `UPDATE memories SET consolidated = 1 WHERE id IN (${placeholders})`,
|
|
164
|
+
args: sourceIds
|
|
165
|
+
};
|
|
166
|
+
await client.batch([...linkStmts, markStmt], "write");
|
|
167
|
+
return { consolidatedMemoryId: consolidatedId, sourceIds, rawText };
|
|
168
|
+
}
|
|
169
|
+
var WIKI_FETCH_TIMEOUT_MS = 1e4;
|
|
170
|
+
async function pushToWiki(consolidation, config) {
|
|
171
|
+
if (!config.wikiEnabled || !config.wikiAutoUpdate) {
|
|
172
|
+
return { updated: false };
|
|
173
|
+
}
|
|
174
|
+
const apiUrl = config.wikiUrl || process.env.EXE_WIKI_API_URL;
|
|
175
|
+
const apiKey = config.wikiApiKey || process.env.EXE_WIKI_API_KEY;
|
|
176
|
+
if (!apiUrl || !apiKey) {
|
|
177
|
+
return { updated: false };
|
|
178
|
+
}
|
|
179
|
+
const workspace = config.wikiWorkspaceMapping[consolidation.projectName] ?? consolidation.projectName;
|
|
180
|
+
try {
|
|
181
|
+
const listRes = await fetch(
|
|
182
|
+
`${apiUrl}/v1/workspace/${encodeURIComponent(workspace)}/documents`,
|
|
183
|
+
{
|
|
184
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
185
|
+
signal: AbortSignal.timeout(WIKI_FETCH_TIMEOUT_MS)
|
|
186
|
+
}
|
|
187
|
+
);
|
|
188
|
+
if (!listRes.ok) {
|
|
189
|
+
return { updated: false, error: `Workspace "${workspace}" not accessible (${listRes.status})` };
|
|
190
|
+
}
|
|
191
|
+
const listJson = await listRes.json();
|
|
192
|
+
const docs = listJson.documents ?? listJson.localFiles?.items ?? [];
|
|
193
|
+
const contentLines = consolidation.rawText.split("\n").filter((l) => l.trim() && !l.startsWith("CONSOLIDATION") && !l.match(/^[A-Z\s]+:$/)).join(" ");
|
|
194
|
+
const keywords = contentLines.toLowerCase().replace(/[^a-z0-9\s]/g, "").split(/\s+/).filter((w) => w.length > 3);
|
|
195
|
+
let bestMatch = null;
|
|
196
|
+
for (const doc of docs) {
|
|
197
|
+
if (!doc.id || !doc.title) continue;
|
|
198
|
+
const titleWords = doc.title.toLowerCase().replace(/[^a-z0-9\s]/g, "").split(/\s+/).filter((w) => w.length > 3);
|
|
199
|
+
if (titleWords.length === 0) continue;
|
|
200
|
+
const matchCount = titleWords.filter(
|
|
201
|
+
(tw) => keywords.some((k) => k.includes(tw) || tw.includes(k))
|
|
202
|
+
).length;
|
|
203
|
+
const score = matchCount / titleWords.length;
|
|
204
|
+
if (score > (bestMatch?.score ?? 0)) {
|
|
205
|
+
bestMatch = { id: doc.id, title: doc.title, score };
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
if (bestMatch && bestMatch.score >= config.wikiAutoUpdateThreshold) {
|
|
209
|
+
const updateRes = await fetch(`${apiUrl}/v1/document/raw-text`, {
|
|
210
|
+
method: "POST",
|
|
211
|
+
headers: {
|
|
212
|
+
"Content-Type": "application/json",
|
|
213
|
+
Authorization: `Bearer ${apiKey}`
|
|
214
|
+
},
|
|
215
|
+
body: JSON.stringify({
|
|
216
|
+
textContent: consolidation.rawText,
|
|
217
|
+
metadata: { title: bestMatch.title, appendTo: bestMatch.id },
|
|
218
|
+
workspaceSlugs: [workspace]
|
|
219
|
+
}),
|
|
220
|
+
signal: AbortSignal.timeout(WIKI_FETCH_TIMEOUT_MS)
|
|
221
|
+
});
|
|
222
|
+
if (updateRes.ok) {
|
|
223
|
+
process.stderr.write(
|
|
224
|
+
`[consolidation] Wiki auto-updated: ${workspace}/${bestMatch.title}
|
|
225
|
+
`
|
|
226
|
+
);
|
|
227
|
+
return { updated: true, action: "updated", page: bestMatch.title };
|
|
228
|
+
}
|
|
229
|
+
return { updated: false, error: `Update failed (${updateRes.status})` };
|
|
230
|
+
}
|
|
231
|
+
if (config.wikiAutoUpdateCreateNew) {
|
|
232
|
+
const title = `Consolidated Insights \u2014 ${consolidation.projectName} (${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)})`;
|
|
233
|
+
const createRes = await fetch(`${apiUrl}/v1/document/raw-text`, {
|
|
234
|
+
method: "POST",
|
|
235
|
+
headers: {
|
|
236
|
+
"Content-Type": "application/json",
|
|
237
|
+
Authorization: `Bearer ${apiKey}`
|
|
238
|
+
},
|
|
239
|
+
body: JSON.stringify({
|
|
240
|
+
textContent: consolidation.rawText,
|
|
241
|
+
metadata: { title },
|
|
242
|
+
workspaceSlugs: [workspace]
|
|
243
|
+
}),
|
|
244
|
+
signal: AbortSignal.timeout(WIKI_FETCH_TIMEOUT_MS)
|
|
245
|
+
});
|
|
246
|
+
if (createRes.ok) {
|
|
247
|
+
process.stderr.write(
|
|
248
|
+
`[consolidation] Wiki page created: ${workspace}/${title}
|
|
249
|
+
`
|
|
250
|
+
);
|
|
251
|
+
return { updated: true, action: "created", page: title };
|
|
252
|
+
}
|
|
253
|
+
return { updated: false, error: `Create failed (${createRes.status})` };
|
|
254
|
+
}
|
|
255
|
+
return { updated: false };
|
|
256
|
+
} catch (err) {
|
|
257
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
258
|
+
process.stderr.write(`[consolidation] Wiki push failed: ${msg}
|
|
259
|
+
`);
|
|
260
|
+
return { updated: false, error: msg };
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
async function runConsolidation(client, options) {
|
|
264
|
+
const memories = await selectUnconsolidated(client);
|
|
265
|
+
if (memories.length < 20) {
|
|
266
|
+
return { clustersProcessed: 0, memoriesConsolidated: 0 };
|
|
267
|
+
}
|
|
268
|
+
let roleMap = {};
|
|
269
|
+
try {
|
|
270
|
+
const { loadEmployeesSync } = await import("./lib/employees.js");
|
|
271
|
+
const employees = loadEmployeesSync();
|
|
272
|
+
for (const e of employees) {
|
|
273
|
+
roleMap[e.name] = e.role;
|
|
274
|
+
}
|
|
275
|
+
} catch {
|
|
276
|
+
}
|
|
277
|
+
const clusters = groupMemories(memories);
|
|
278
|
+
let clustersProcessed = 0;
|
|
279
|
+
let memoriesConsolidated = 0;
|
|
280
|
+
for (const cluster of clusters) {
|
|
281
|
+
if (clustersProcessed >= options.maxCalls) break;
|
|
282
|
+
if (cluster.memories.length < 3) continue;
|
|
283
|
+
try {
|
|
284
|
+
const isCoordinator = isCoordinatorName(cluster.agentId);
|
|
285
|
+
const agentRole = roleMap[cluster.agentId];
|
|
286
|
+
const dedupCount = await dedupCluster(client, cluster, options.embedFn);
|
|
287
|
+
memoriesConsolidated += dedupCount;
|
|
288
|
+
const synthesis = await consolidateCluster(cluster, options.model, agentRole);
|
|
289
|
+
if (!synthesis.trim()) {
|
|
290
|
+
if (dedupCount > 0) clustersProcessed++;
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
const result = await storeConsolidation(client, cluster, synthesis, options.embedFn);
|
|
294
|
+
if (isCoordinator && options.wikiConfig) {
|
|
295
|
+
await pushToWiki(
|
|
296
|
+
{ ...result, projectName: cluster.projectName },
|
|
297
|
+
options.wikiConfig
|
|
298
|
+
).catch((err) => {
|
|
299
|
+
process.stderr.write(
|
|
300
|
+
`[consolidation] Wiki push error (non-fatal): ${err instanceof Error ? err.message : String(err)}
|
|
301
|
+
`
|
|
302
|
+
);
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
if (isCoordinator) {
|
|
306
|
+
const sourceIds = result.sourceIds;
|
|
307
|
+
if (sourceIds.length > 0) {
|
|
308
|
+
const placeholders = sourceIds.map(() => "?").join(",");
|
|
309
|
+
await client.execute({
|
|
310
|
+
sql: `UPDATE memories SET status = 'archived' WHERE id IN (${placeholders})`,
|
|
311
|
+
args: sourceIds
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
clustersProcessed++;
|
|
316
|
+
memoriesConsolidated += cluster.memories.length;
|
|
317
|
+
} catch (err) {
|
|
318
|
+
process.stderr.write(
|
|
319
|
+
`[consolidation] Cluster failed (${cluster.projectName}/${cluster.dateRange}): ${err instanceof Error ? err.message : String(err)}
|
|
320
|
+
`
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return { clustersProcessed, memoriesConsolidated };
|
|
325
|
+
}
|
|
326
|
+
async function dedupCluster(client, cluster, embedFn) {
|
|
327
|
+
if (!embedFn || cluster.memories.length < 2) return 0;
|
|
328
|
+
const vectors = [];
|
|
329
|
+
for (const mem of cluster.memories) {
|
|
330
|
+
try {
|
|
331
|
+
const v = await embedFn(mem.raw_text);
|
|
332
|
+
vectors.push({ id: mem.id, vector: v });
|
|
333
|
+
} catch {
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
if (vectors.length < 2) return 0;
|
|
337
|
+
const toArchive = /* @__PURE__ */ new Set();
|
|
338
|
+
for (let i = 0; i < vectors.length; i++) {
|
|
339
|
+
if (toArchive.has(vectors[i].id)) continue;
|
|
340
|
+
for (let j = i + 1; j < vectors.length; j++) {
|
|
341
|
+
if (toArchive.has(vectors[j].id)) continue;
|
|
342
|
+
const sim = cosineSimilarity(vectors[i].vector, vectors[j].vector);
|
|
343
|
+
if (sim > 0.95) {
|
|
344
|
+
toArchive.add(vectors[j].id);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
if (toArchive.size === 0) return 0;
|
|
349
|
+
const ids = [...toArchive];
|
|
350
|
+
const placeholders = ids.map(() => "?").join(",");
|
|
351
|
+
await client.execute({
|
|
352
|
+
sql: `UPDATE memories SET status = 'archived', consolidated = 1 WHERE id IN (${placeholders})`,
|
|
353
|
+
args: ids
|
|
354
|
+
});
|
|
355
|
+
const survivors = vectors.filter((v) => !toArchive.has(v.id)).map((v) => v.id);
|
|
356
|
+
if (survivors.length > 0) {
|
|
357
|
+
const survivorPlaceholders = survivors.map(() => "?").join(",");
|
|
358
|
+
await client.execute({
|
|
359
|
+
sql: `UPDATE memories SET confidence = MIN(1.0, COALESCE(confidence, 0.7) + 0.1) WHERE id IN (${survivorPlaceholders})`,
|
|
360
|
+
args: survivors
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
return ids.length;
|
|
364
|
+
}
|
|
365
|
+
function cosineSimilarity(a, b) {
|
|
366
|
+
let dot = 0, normA = 0, normB = 0;
|
|
367
|
+
for (let i = 0; i < a.length; i++) {
|
|
368
|
+
dot += a[i] * b[i];
|
|
369
|
+
normA += a[i] * a[i];
|
|
370
|
+
normB += b[i] * b[i];
|
|
371
|
+
}
|
|
372
|
+
const denom = Math.sqrt(normA) * Math.sqrt(normB);
|
|
373
|
+
return denom === 0 ? 0 : dot / denom;
|
|
374
|
+
}
|
|
375
|
+
async function isUserIdle(client, idleMinutes = 30) {
|
|
376
|
+
const result = await client.execute({
|
|
377
|
+
sql: `SELECT MAX(timestamp) as last_activity
|
|
378
|
+
FROM memories
|
|
379
|
+
WHERE tool_name != 'consolidation'
|
|
380
|
+
AND timestamp >= datetime('now', '-1 day')`,
|
|
381
|
+
args: []
|
|
382
|
+
});
|
|
383
|
+
const lastActivity = result.rows[0]?.last_activity;
|
|
384
|
+
if (!lastActivity) return true;
|
|
385
|
+
const lastMs = new Date(lastActivity).getTime();
|
|
386
|
+
const now = Date.now();
|
|
387
|
+
return now - lastMs >= idleMinutes * 60 * 1e3;
|
|
388
|
+
}
|
|
389
|
+
async function countUnconsolidated(client) {
|
|
390
|
+
const result = await client.execute({
|
|
391
|
+
sql: `SELECT COUNT(*) as cnt FROM memories
|
|
392
|
+
WHERE consolidated = 0
|
|
393
|
+
AND COALESCE(memory_type, 'raw') != 'procedure'`,
|
|
394
|
+
args: []
|
|
395
|
+
});
|
|
396
|
+
return Number(result.rows[0]?.cnt ?? 0);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
export {
|
|
400
|
+
selectUnconsolidated,
|
|
401
|
+
groupMemories,
|
|
402
|
+
buildConsolidationPrompt,
|
|
403
|
+
consolidateCluster,
|
|
404
|
+
storeConsolidation,
|
|
405
|
+
pushToWiki,
|
|
406
|
+
runConsolidation,
|
|
407
|
+
isUserIdle,
|
|
408
|
+
countUnconsolidated
|
|
409
|
+
};
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getClient,
|
|
3
|
+
init_database
|
|
4
|
+
} from "./chunk-A2NZP64U.js";
|
|
5
|
+
|
|
6
|
+
// src/lib/token-spend.ts
|
|
7
|
+
init_database();
|
|
8
|
+
import { readdir } from "fs/promises";
|
|
9
|
+
import { createReadStream } from "fs";
|
|
10
|
+
import { createInterface } from "readline";
|
|
11
|
+
import path from "path";
|
|
12
|
+
import os from "os";
|
|
13
|
+
var MODEL_PRICING = {
|
|
14
|
+
// Opus 4.5+ ($5/$25 — Anthropic price drop from original Opus 4)
|
|
15
|
+
"claude-opus-4-7": { input: 5 / 1e6, output: 25 / 1e6, cacheRead: 0.5 / 1e6, cacheWrite: 6.25 / 1e6 },
|
|
16
|
+
"claude-opus-4-6": { input: 5 / 1e6, output: 25 / 1e6, cacheRead: 0.5 / 1e6, cacheWrite: 6.25 / 1e6 },
|
|
17
|
+
"claude-opus-4-5": { input: 5 / 1e6, output: 25 / 1e6, cacheRead: 0.5 / 1e6, cacheWrite: 6.25 / 1e6 },
|
|
18
|
+
// Opus 4.0/4.1 (legacy $15/$75)
|
|
19
|
+
"claude-opus-4-1": { input: 15 / 1e6, output: 75 / 1e6, cacheRead: 1.5 / 1e6, cacheWrite: 18.75 / 1e6 },
|
|
20
|
+
"claude-opus-4": { input: 15 / 1e6, output: 75 / 1e6, cacheRead: 1.5 / 1e6, cacheWrite: 18.75 / 1e6 },
|
|
21
|
+
// Sonnet 4.x
|
|
22
|
+
"claude-sonnet-4": { input: 3 / 1e6, output: 15 / 1e6, cacheRead: 0.3 / 1e6, cacheWrite: 3.75 / 1e6 },
|
|
23
|
+
// Sonnet 3.7/3.5
|
|
24
|
+
"claude-3-7-sonnet": { input: 3 / 1e6, output: 15 / 1e6, cacheRead: 0.3 / 1e6, cacheWrite: 3.75 / 1e6 },
|
|
25
|
+
"claude-3-5-sonnet": { input: 3 / 1e6, output: 15 / 1e6, cacheRead: 0.3 / 1e6, cacheWrite: 3.75 / 1e6 },
|
|
26
|
+
// Haiku 4.5
|
|
27
|
+
"claude-haiku-4-5": { input: 1 / 1e6, output: 5 / 1e6, cacheRead: 0.1 / 1e6, cacheWrite: 1.25 / 1e6 },
|
|
28
|
+
// Haiku 3.5
|
|
29
|
+
"claude-3-5-haiku": { input: 0.8 / 1e6, output: 4 / 1e6, cacheRead: 0.08 / 1e6, cacheWrite: 1 / 1e6 },
|
|
30
|
+
// Opus 3
|
|
31
|
+
"claude-3-opus": { input: 15 / 1e6, output: 75 / 1e6, cacheRead: 1.5 / 1e6, cacheWrite: 18.75 / 1e6 },
|
|
32
|
+
// Sonnet 3
|
|
33
|
+
"claude-3-sonnet": { input: 3 / 1e6, output: 15 / 1e6, cacheRead: 0.3 / 1e6, cacheWrite: 3.75 / 1e6 },
|
|
34
|
+
// Haiku 3
|
|
35
|
+
"claude-3-haiku": { input: 0.25 / 1e6, output: 1.25 / 1e6, cacheRead: 0.03 / 1e6, cacheWrite: 0.3 / 1e6 }
|
|
36
|
+
};
|
|
37
|
+
var DEFAULT_PRICING = MODEL_PRICING["claude-sonnet-4"];
|
|
38
|
+
var CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
39
|
+
var _spendCache = /* @__PURE__ */ new Map();
|
|
40
|
+
function getPricing(model) {
|
|
41
|
+
if (MODEL_PRICING[model]) return MODEL_PRICING[model];
|
|
42
|
+
const stripped = model.replace(/-\d{8}$/, "");
|
|
43
|
+
if (MODEL_PRICING[stripped]) return MODEL_PRICING[stripped];
|
|
44
|
+
const sortedKeys = Object.keys(MODEL_PRICING).sort((a, b) => b.length - a.length);
|
|
45
|
+
for (const key of sortedKeys) {
|
|
46
|
+
if (model.includes(key)) return MODEL_PRICING[key];
|
|
47
|
+
}
|
|
48
|
+
return DEFAULT_PRICING;
|
|
49
|
+
}
|
|
50
|
+
async function getAgentSpend(period = "7d") {
|
|
51
|
+
const cached = _spendCache.get(period);
|
|
52
|
+
if (cached && Date.now() < cached.expires) {
|
|
53
|
+
return cached.result;
|
|
54
|
+
}
|
|
55
|
+
const cutoff = periodToCutoff(period);
|
|
56
|
+
const client = getClient();
|
|
57
|
+
const dbResult = await client.execute({
|
|
58
|
+
sql: `SELECT session_uuid, agent_id FROM session_agent_map WHERE started_at >= ?`,
|
|
59
|
+
args: [cutoff]
|
|
60
|
+
});
|
|
61
|
+
if (dbResult.rows.length === 0) return [];
|
|
62
|
+
const sessionAgent = /* @__PURE__ */ new Map();
|
|
63
|
+
for (const row of dbResult.rows) {
|
|
64
|
+
sessionAgent.set(row.session_uuid, row.agent_id);
|
|
65
|
+
}
|
|
66
|
+
const claudeDir = path.join(os.homedir(), ".claude", "projects");
|
|
67
|
+
let projectDirs = [];
|
|
68
|
+
try {
|
|
69
|
+
const entries = await readdir(claudeDir);
|
|
70
|
+
projectDirs = entries.map((e) => path.join(claudeDir, e));
|
|
71
|
+
} catch {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
const agentTotals = /* @__PURE__ */ new Map();
|
|
75
|
+
for (const [sessionUuid, agentId] of sessionAgent) {
|
|
76
|
+
for (const dir of projectDirs) {
|
|
77
|
+
const jsonlPath = path.join(dir, `${sessionUuid}.jsonl`);
|
|
78
|
+
try {
|
|
79
|
+
const usage = await extractSessionUsage(jsonlPath);
|
|
80
|
+
if (usage.input === 0 && usage.output === 0) continue;
|
|
81
|
+
const totals = agentTotals.get(agentId) ?? {
|
|
82
|
+
input: 0,
|
|
83
|
+
output: 0,
|
|
84
|
+
cacheRead: 0,
|
|
85
|
+
cacheCreate: 0,
|
|
86
|
+
costUSD: 0,
|
|
87
|
+
sessions: /* @__PURE__ */ new Set()
|
|
88
|
+
};
|
|
89
|
+
totals.input += usage.input;
|
|
90
|
+
totals.output += usage.output;
|
|
91
|
+
totals.cacheRead += usage.cacheRead;
|
|
92
|
+
totals.cacheCreate += usage.cacheCreate;
|
|
93
|
+
totals.costUSD += usage.costUSD;
|
|
94
|
+
totals.sessions.add(sessionUuid);
|
|
95
|
+
agentTotals.set(agentId, totals);
|
|
96
|
+
break;
|
|
97
|
+
} catch {
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const result = Array.from(agentTotals.entries()).map(([agentId, t]) => ({
|
|
102
|
+
agentId,
|
|
103
|
+
inputTokens: t.input,
|
|
104
|
+
outputTokens: t.output,
|
|
105
|
+
cacheReadTokens: t.cacheRead,
|
|
106
|
+
cacheCreationTokens: t.cacheCreate,
|
|
107
|
+
costUSD: t.costUSD,
|
|
108
|
+
sessions: t.sessions.size,
|
|
109
|
+
period
|
|
110
|
+
})).sort((a, b) => b.costUSD - a.costUSD);
|
|
111
|
+
_spendCache.set(period, { result, expires: Date.now() + CACHE_TTL_MS });
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
async function extractSessionUsage(jsonlPath) {
|
|
115
|
+
let input = 0;
|
|
116
|
+
let output = 0;
|
|
117
|
+
let cacheRead = 0;
|
|
118
|
+
let cacheCreate = 0;
|
|
119
|
+
let costUSD = 0;
|
|
120
|
+
const seenMessageIds = /* @__PURE__ */ new Set();
|
|
121
|
+
const rl = createInterface({
|
|
122
|
+
input: createReadStream(jsonlPath, { encoding: "utf8" }),
|
|
123
|
+
crlfDelay: Infinity
|
|
124
|
+
});
|
|
125
|
+
for await (const line of rl) {
|
|
126
|
+
if (!line.includes('"type":"assistant"')) continue;
|
|
127
|
+
try {
|
|
128
|
+
const record = JSON.parse(line);
|
|
129
|
+
if (record.type !== "assistant") continue;
|
|
130
|
+
const messageId = record.message?.id;
|
|
131
|
+
if (messageId) {
|
|
132
|
+
if (seenMessageIds.has(messageId)) continue;
|
|
133
|
+
seenMessageIds.add(messageId);
|
|
134
|
+
}
|
|
135
|
+
const usage = record.message?.usage;
|
|
136
|
+
if (!usage) continue;
|
|
137
|
+
const model = record.message?.model ?? "";
|
|
138
|
+
const pricing = getPricing(model);
|
|
139
|
+
const inp = usage.input_tokens ?? 0;
|
|
140
|
+
const out = usage.output_tokens ?? 0;
|
|
141
|
+
const cr = usage.cache_read_input_tokens ?? 0;
|
|
142
|
+
const cc = usage.cache_creation_input_tokens ?? 0;
|
|
143
|
+
input += inp;
|
|
144
|
+
output += out;
|
|
145
|
+
cacheRead += cr;
|
|
146
|
+
cacheCreate += cc;
|
|
147
|
+
if (pricing) {
|
|
148
|
+
costUSD += inp * pricing.input + out * pricing.output + cr * pricing.cacheRead + cc * pricing.cacheWrite;
|
|
149
|
+
}
|
|
150
|
+
} catch {
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return { input, output, cacheRead, cacheCreate, costUSD };
|
|
154
|
+
}
|
|
155
|
+
function periodToCutoff(period) {
|
|
156
|
+
const ms = { "24h": 864e5, "7d": 6048e5, "30d": 2592e6 }[period];
|
|
157
|
+
return new Date(Date.now() - ms).toISOString();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export {
|
|
161
|
+
getAgentSpend
|
|
162
|
+
};
|