@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,137 @@
|
|
|
1
|
+
import {
|
|
2
|
+
init_employees,
|
|
3
|
+
isCoordinatorRole
|
|
4
|
+
} from "./chunk-RUG3N6P4.js";
|
|
5
|
+
|
|
6
|
+
// src/lib/task-router.ts
|
|
7
|
+
init_employees();
|
|
8
|
+
import { randomUUID } from "crypto";
|
|
9
|
+
var DEFAULT_BLOOM_CONFIG = {
|
|
10
|
+
complexityToTier: {
|
|
11
|
+
routine: "junior",
|
|
12
|
+
standard: "standard",
|
|
13
|
+
complex: "senior",
|
|
14
|
+
critical: "specialist"
|
|
15
|
+
},
|
|
16
|
+
tierRules: {
|
|
17
|
+
junior: {
|
|
18
|
+
eligible: [],
|
|
19
|
+
// resolved dynamically from roster (Principal Engineer role)
|
|
20
|
+
reviewRequired: false,
|
|
21
|
+
manualOnly: false
|
|
22
|
+
},
|
|
23
|
+
standard: {
|
|
24
|
+
eligible: [],
|
|
25
|
+
// resolved dynamically from roster (Principal Engineer role)
|
|
26
|
+
reviewRequired: false,
|
|
27
|
+
manualOnly: false
|
|
28
|
+
},
|
|
29
|
+
senior: {
|
|
30
|
+
eligible: [],
|
|
31
|
+
// any specialist, but review required
|
|
32
|
+
reviewRequired: true,
|
|
33
|
+
manualOnly: false
|
|
34
|
+
},
|
|
35
|
+
specialist: {
|
|
36
|
+
eligible: [],
|
|
37
|
+
reviewRequired: true,
|
|
38
|
+
manualOnly: true
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
function resolveBloomRouting(complexity, config = DEFAULT_BLOOM_CONFIG) {
|
|
43
|
+
const tier = config.complexityToTier[complexity];
|
|
44
|
+
const rule = config.tierRules[tier];
|
|
45
|
+
return {
|
|
46
|
+
tier,
|
|
47
|
+
reviewRequired: rule.reviewRequired,
|
|
48
|
+
manualOnly: rule.manualOnly,
|
|
49
|
+
eligible: rule.eligible
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
async function scoreEmployee(taskVector, agentId, searchFn) {
|
|
53
|
+
const results = await searchFn(taskVector, agentId, { limit: 5 });
|
|
54
|
+
if (results.length === 0) {
|
|
55
|
+
return { agentId, score: 0 };
|
|
56
|
+
}
|
|
57
|
+
const distances = results.map((r) => r["_distance"]).filter((d) => typeof d === "number");
|
|
58
|
+
if (distances.length > 0) {
|
|
59
|
+
const avgDistance = distances.reduce((sum, d) => sum + d, 0) / distances.length;
|
|
60
|
+
return { agentId, score: 1 / (1 + avgDistance) };
|
|
61
|
+
}
|
|
62
|
+
return { agentId, score: results.length / 5 };
|
|
63
|
+
}
|
|
64
|
+
async function routeTask(taskDescription, employees, embedFn, searchFn, options) {
|
|
65
|
+
let specialists = employees.filter((e) => !isCoordinatorRole(e.role));
|
|
66
|
+
if (specialists.length === 0) {
|
|
67
|
+
throw new Error(
|
|
68
|
+
"No specialist employees available. Create one with /exe-new-employee."
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
let bloomRouting;
|
|
72
|
+
if (options?.complexity) {
|
|
73
|
+
bloomRouting = resolveBloomRouting(options.complexity, options.bloomConfig);
|
|
74
|
+
if (bloomRouting.manualOnly) {
|
|
75
|
+
throw new Error(
|
|
76
|
+
`Task complexity "${options.complexity}" requires manual assignment (tier: ${bloomRouting.tier}).`
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
if (bloomRouting.eligible.length > 0) {
|
|
80
|
+
const eligible = new Set(bloomRouting.eligible);
|
|
81
|
+
const filtered = specialists.filter((e) => eligible.has(e.name));
|
|
82
|
+
if (filtered.length > 0) {
|
|
83
|
+
specialists = filtered;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const taskVector = await embedFn(taskDescription);
|
|
88
|
+
const scored = await Promise.all(
|
|
89
|
+
specialists.map(async (emp) => {
|
|
90
|
+
const { score } = await scoreEmployee(taskVector, emp.name, searchFn);
|
|
91
|
+
return { employee: emp, score };
|
|
92
|
+
})
|
|
93
|
+
);
|
|
94
|
+
scored.sort((a, b) => b.score - a.score);
|
|
95
|
+
return { ...scored[0], bloomRouting };
|
|
96
|
+
}
|
|
97
|
+
function createAssignmentMemory(taskDescription, assignedTo, assignedBy) {
|
|
98
|
+
return {
|
|
99
|
+
id: randomUUID(),
|
|
100
|
+
agent_id: assignedTo.name,
|
|
101
|
+
agent_role: assignedTo.role,
|
|
102
|
+
session_id: `assign-${Date.now()}`,
|
|
103
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
104
|
+
tool_name: "assignment",
|
|
105
|
+
project_name: "",
|
|
106
|
+
has_error: false,
|
|
107
|
+
raw_text: `Task assigned by ${assignedBy}: ${taskDescription}`,
|
|
108
|
+
vector: null
|
|
109
|
+
// Will be backfilled
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function formatAssignmentOutput(employee, task, score, mode, bloomRouting) {
|
|
113
|
+
const modeLabel = mode === "auto" ? "auto-routed" : "direct";
|
|
114
|
+
const percent = Math.round(score * 100);
|
|
115
|
+
const lines = [
|
|
116
|
+
`Assigned to ${employee.name} (${employee.role})`,
|
|
117
|
+
`Mode: ${modeLabel}`,
|
|
118
|
+
`Relevance: ${percent}%`,
|
|
119
|
+
`Task: ${task}`
|
|
120
|
+
];
|
|
121
|
+
if (bloomRouting) {
|
|
122
|
+
lines.push(`Complexity tier: ${bloomRouting.tier}`);
|
|
123
|
+
if (bloomRouting.reviewRequired) {
|
|
124
|
+
lines.push(`Review: required`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return lines.join("\n");
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export {
|
|
131
|
+
DEFAULT_BLOOM_CONFIG,
|
|
132
|
+
resolveBloomRouting,
|
|
133
|
+
scoreEmployee,
|
|
134
|
+
routeTask,
|
|
135
|
+
createAssignmentMemory,
|
|
136
|
+
formatAssignmentOutput
|
|
137
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// src/lib/cache-warmth.ts
|
|
2
|
+
import os from "os";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "fs";
|
|
5
|
+
var CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
6
|
+
var CACHE_DIR = path.join(
|
|
7
|
+
process.env.EXE_OS_DIR ?? path.join(os.homedir(), ".exe-os"),
|
|
8
|
+
"session-cache"
|
|
9
|
+
);
|
|
10
|
+
function getStatePath(sessionKey) {
|
|
11
|
+
return path.join(CACHE_DIR, `cache-warmth-${sessionKey}.json`);
|
|
12
|
+
}
|
|
13
|
+
function recordApiCall(sessionKey, agentId, sessionUuid) {
|
|
14
|
+
try {
|
|
15
|
+
mkdirSync(CACHE_DIR, { recursive: true });
|
|
16
|
+
const state = {
|
|
17
|
+
lastApiCallAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
18
|
+
agentId,
|
|
19
|
+
sessionUuid
|
|
20
|
+
};
|
|
21
|
+
writeFileSync(getStatePath(sessionKey), JSON.stringify(state));
|
|
22
|
+
} catch {
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function isCacheCold(sessionKey) {
|
|
26
|
+
const statePath = getStatePath(sessionKey);
|
|
27
|
+
if (!existsSync(statePath)) {
|
|
28
|
+
return { cold: true, idleMs: Number.POSITIVE_INFINITY };
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
const state = JSON.parse(readFileSync(statePath, "utf-8"));
|
|
32
|
+
const lastApiCallAt = new Date(state.lastApiCallAt).getTime();
|
|
33
|
+
if (!Number.isFinite(lastApiCallAt)) {
|
|
34
|
+
return { cold: true, idleMs: Number.POSITIVE_INFINITY };
|
|
35
|
+
}
|
|
36
|
+
const idleMs = Date.now() - lastApiCallAt;
|
|
37
|
+
return { cold: idleMs > CACHE_TTL_MS, idleMs };
|
|
38
|
+
} catch {
|
|
39
|
+
return { cold: true, idleMs: Number.POSITIVE_INFINITY };
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function clearCacheState(sessionKey) {
|
|
43
|
+
try {
|
|
44
|
+
unlinkSync(getStatePath(sessionKey));
|
|
45
|
+
} catch {
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export {
|
|
50
|
+
recordApiCall,
|
|
51
|
+
isCacheCold,
|
|
52
|
+
clearCacheState
|
|
53
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__esm
|
|
3
|
+
} from "./chunk-KFQGP6VL.js";
|
|
4
|
+
|
|
5
|
+
// src/lib/mcp-prefix.ts
|
|
6
|
+
function isExeMcpTool(toolName) {
|
|
7
|
+
if (!toolName) return false;
|
|
8
|
+
return MCP_TOOL_PREFIXES.some((p) => toolName.startsWith(p));
|
|
9
|
+
}
|
|
10
|
+
function stripExeMcpPrefix(toolName) {
|
|
11
|
+
for (const p of MCP_TOOL_PREFIXES) {
|
|
12
|
+
if (toolName.startsWith(p)) return toolName.slice(p.length);
|
|
13
|
+
}
|
|
14
|
+
return toolName;
|
|
15
|
+
}
|
|
16
|
+
function expandDualPrefixTools(shortNames) {
|
|
17
|
+
const out = [];
|
|
18
|
+
for (const name of shortNames) {
|
|
19
|
+
for (const prefix of MCP_TOOL_PREFIXES) {
|
|
20
|
+
out.push(prefix + name);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return out;
|
|
24
|
+
}
|
|
25
|
+
var MCP_PRIMARY_KEY, MCP_LEGACY_KEY, MCP_TOOL_PREFIXES;
|
|
26
|
+
var init_mcp_prefix = __esm({
|
|
27
|
+
"src/lib/mcp-prefix.ts"() {
|
|
28
|
+
"use strict";
|
|
29
|
+
MCP_PRIMARY_KEY = "exe-os";
|
|
30
|
+
MCP_LEGACY_KEY = "exe-mem";
|
|
31
|
+
MCP_TOOL_PREFIXES = [
|
|
32
|
+
`mcp__${MCP_PRIMARY_KEY}__`,
|
|
33
|
+
`mcp__${MCP_LEGACY_KEY}__`
|
|
34
|
+
];
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
export {
|
|
39
|
+
MCP_PRIMARY_KEY,
|
|
40
|
+
MCP_LEGACY_KEY,
|
|
41
|
+
isExeMcpTool,
|
|
42
|
+
stripExeMcpPrefix,
|
|
43
|
+
expandDualPrefixTools,
|
|
44
|
+
init_mcp_prefix
|
|
45
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// src/lib/ws-auth.ts
|
|
2
|
+
import crypto from "crypto";
|
|
3
|
+
var WS_AUTH_HKDF_INFO = "exe-os-ws-auth-v1";
|
|
4
|
+
var ORG_ID_HKDF_INFO = "exe-os-org-id-v1";
|
|
5
|
+
function deriveWsAuthToken(masterKey) {
|
|
6
|
+
return Buffer.from(crypto.hkdfSync("sha256", masterKey, "", WS_AUTH_HKDF_INFO, 32));
|
|
7
|
+
}
|
|
8
|
+
function deriveOrgId(masterKey) {
|
|
9
|
+
const raw = Buffer.from(crypto.hkdfSync("sha256", masterKey, "", ORG_ID_HKDF_INFO, 32));
|
|
10
|
+
return crypto.createHash("sha256").update(raw).digest("hex").slice(0, 32);
|
|
11
|
+
}
|
|
12
|
+
function hashAuthToken(token) {
|
|
13
|
+
return crypto.createHash("sha256").update(token).digest("hex");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export {
|
|
17
|
+
deriveWsAuthToken,
|
|
18
|
+
deriveOrgId,
|
|
19
|
+
hashAuthToken
|
|
20
|
+
};
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
// src/lib/graph-query.ts
|
|
2
|
+
async function getEntityByName(client, name, type) {
|
|
3
|
+
const sql = type ? `SELECT * FROM entities WHERE LOWER(name) = LOWER(?) AND type = ? LIMIT 1` : `SELECT * FROM entities WHERE LOWER(name) = LOWER(?) LIMIT 1`;
|
|
4
|
+
const args = type ? [name, type] : [name];
|
|
5
|
+
const result = await client.execute({ sql, args });
|
|
6
|
+
if (result.rows.length === 0) return null;
|
|
7
|
+
const row = result.rows[0];
|
|
8
|
+
return {
|
|
9
|
+
id: String(row.id),
|
|
10
|
+
name: String(row.name),
|
|
11
|
+
type: String(row.type),
|
|
12
|
+
firstSeen: String(row.first_seen),
|
|
13
|
+
lastSeen: String(row.last_seen),
|
|
14
|
+
properties: JSON.parse(String(row.properties ?? "{}"))
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
async function searchEntities(client, query, limit = 10) {
|
|
18
|
+
const result = await client.execute({
|
|
19
|
+
sql: `SELECT * FROM entities WHERE LOWER(name) LIKE ? ORDER BY last_seen DESC LIMIT ?`,
|
|
20
|
+
args: [`%${query.toLowerCase()}%`, limit]
|
|
21
|
+
});
|
|
22
|
+
return result.rows.map((row) => ({
|
|
23
|
+
id: String(row.id),
|
|
24
|
+
name: String(row.name),
|
|
25
|
+
type: String(row.type),
|
|
26
|
+
firstSeen: String(row.first_seen),
|
|
27
|
+
lastSeen: String(row.last_seen),
|
|
28
|
+
properties: JSON.parse(String(row.properties ?? "{}"))
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
async function getRelationships(client, entityId, options) {
|
|
32
|
+
const direction = options?.direction ?? "both";
|
|
33
|
+
let sql;
|
|
34
|
+
const args = [];
|
|
35
|
+
if (direction === "outgoing") {
|
|
36
|
+
sql = `SELECT r.*, s.name as source_name, t.name as target_name
|
|
37
|
+
FROM relationships r
|
|
38
|
+
JOIN entities s ON r.source_entity_id = s.id
|
|
39
|
+
JOIN entities t ON r.target_entity_id = t.id
|
|
40
|
+
WHERE r.source_entity_id = ?`;
|
|
41
|
+
args.push(entityId);
|
|
42
|
+
} else if (direction === "incoming") {
|
|
43
|
+
sql = `SELECT r.*, s.name as source_name, t.name as target_name
|
|
44
|
+
FROM relationships r
|
|
45
|
+
JOIN entities s ON r.source_entity_id = s.id
|
|
46
|
+
JOIN entities t ON r.target_entity_id = t.id
|
|
47
|
+
WHERE r.target_entity_id = ?`;
|
|
48
|
+
args.push(entityId);
|
|
49
|
+
} else {
|
|
50
|
+
sql = `SELECT r.*, s.name as source_name, t.name as target_name
|
|
51
|
+
FROM relationships r
|
|
52
|
+
JOIN entities s ON r.source_entity_id = s.id
|
|
53
|
+
JOIN entities t ON r.target_entity_id = t.id
|
|
54
|
+
WHERE r.source_entity_id = ? OR r.target_entity_id = ?`;
|
|
55
|
+
args.push(entityId, entityId);
|
|
56
|
+
}
|
|
57
|
+
if (options?.type) {
|
|
58
|
+
sql += ` AND r.type = ?`;
|
|
59
|
+
args.push(options.type);
|
|
60
|
+
}
|
|
61
|
+
sql += ` ORDER BY r.weight DESC, r.timestamp DESC`;
|
|
62
|
+
const result = await client.execute({ sql, args });
|
|
63
|
+
return result.rows.map((row) => ({
|
|
64
|
+
id: String(row.id),
|
|
65
|
+
sourceEntityId: String(row.source_entity_id),
|
|
66
|
+
targetEntityId: String(row.target_entity_id),
|
|
67
|
+
type: String(row.type),
|
|
68
|
+
weight: Number(row.weight),
|
|
69
|
+
timestamp: String(row.timestamp),
|
|
70
|
+
properties: JSON.parse(String(row.properties ?? "{}")),
|
|
71
|
+
confidence: Number(row.confidence ?? 1),
|
|
72
|
+
confidenceLabel: String(row.confidence_label ?? "extracted"),
|
|
73
|
+
sourceName: String(row.source_name),
|
|
74
|
+
targetName: String(row.target_name)
|
|
75
|
+
}));
|
|
76
|
+
}
|
|
77
|
+
async function traverseChain(client, startEntityId, relationshipType, maxDepth = 3) {
|
|
78
|
+
const result = await client.execute({
|
|
79
|
+
sql: `WITH RECURSIVE chain(entity_id, depth, rel_type) AS (
|
|
80
|
+
SELECT ?, 0, ''
|
|
81
|
+
UNION ALL
|
|
82
|
+
SELECT r.target_entity_id, c.depth + 1, r.type
|
|
83
|
+
FROM chain c
|
|
84
|
+
JOIN relationships r ON r.source_entity_id = c.entity_id
|
|
85
|
+
WHERE r.type = ? AND c.depth < ?
|
|
86
|
+
)
|
|
87
|
+
SELECT DISTINCT e.*, chain.depth, chain.rel_type
|
|
88
|
+
FROM chain
|
|
89
|
+
JOIN entities e ON e.id = chain.entity_id
|
|
90
|
+
ORDER BY chain.depth ASC`,
|
|
91
|
+
args: [startEntityId, relationshipType, maxDepth]
|
|
92
|
+
});
|
|
93
|
+
return result.rows.map((row) => ({
|
|
94
|
+
entity: {
|
|
95
|
+
id: String(row.id),
|
|
96
|
+
name: String(row.name),
|
|
97
|
+
type: String(row.type),
|
|
98
|
+
firstSeen: String(row.first_seen),
|
|
99
|
+
lastSeen: String(row.last_seen),
|
|
100
|
+
properties: JSON.parse(String(row.properties ?? "{}"))
|
|
101
|
+
},
|
|
102
|
+
depth: Number(row.depth),
|
|
103
|
+
relationship: String(row.rel_type)
|
|
104
|
+
}));
|
|
105
|
+
}
|
|
106
|
+
async function getEntityNeighbors(client, entityId, maxHops = 2) {
|
|
107
|
+
const result = await client.execute({
|
|
108
|
+
sql: `WITH RECURSIVE neighborhood(entity_id, depth, rel_type, rel_confidence) AS (
|
|
109
|
+
SELECT ?, 0, '', 1.0
|
|
110
|
+
UNION ALL
|
|
111
|
+
SELECT CASE
|
|
112
|
+
WHEN r.source_entity_id = n.entity_id THEN r.target_entity_id
|
|
113
|
+
ELSE r.source_entity_id
|
|
114
|
+
END, n.depth + 1, r.type, COALESCE(r.confidence, 1.0)
|
|
115
|
+
FROM neighborhood n
|
|
116
|
+
JOIN relationships r ON r.source_entity_id = n.entity_id
|
|
117
|
+
OR r.target_entity_id = n.entity_id
|
|
118
|
+
WHERE n.depth < ?
|
|
119
|
+
)
|
|
120
|
+
SELECT DISTINCT e.*, MIN(neighborhood.depth) as depth,
|
|
121
|
+
neighborhood.rel_type, neighborhood.rel_confidence
|
|
122
|
+
FROM neighborhood
|
|
123
|
+
JOIN entities e ON e.id = neighborhood.entity_id
|
|
124
|
+
GROUP BY e.id
|
|
125
|
+
ORDER BY depth ASC, e.last_seen DESC
|
|
126
|
+
LIMIT 50`,
|
|
127
|
+
args: [entityId, maxHops]
|
|
128
|
+
});
|
|
129
|
+
return result.rows.map((row) => ({
|
|
130
|
+
entity: {
|
|
131
|
+
id: String(row.id),
|
|
132
|
+
name: String(row.name),
|
|
133
|
+
type: String(row.type),
|
|
134
|
+
firstSeen: String(row.first_seen),
|
|
135
|
+
lastSeen: String(row.last_seen),
|
|
136
|
+
properties: JSON.parse(String(row.properties ?? "{}"))
|
|
137
|
+
},
|
|
138
|
+
depth: Number(row.depth),
|
|
139
|
+
relType: String(row.rel_type ?? ""),
|
|
140
|
+
relConfidence: Number(row.rel_confidence ?? 1)
|
|
141
|
+
}));
|
|
142
|
+
}
|
|
143
|
+
async function getGraphStats(client) {
|
|
144
|
+
const entityCount = await client.execute("SELECT COUNT(*) as cnt FROM entities");
|
|
145
|
+
const relCount = await client.execute("SELECT COUNT(*) as cnt FROM relationships");
|
|
146
|
+
const typeResult = await client.execute(
|
|
147
|
+
"SELECT type, COUNT(*) as cnt FROM entities GROUP BY type ORDER BY cnt DESC"
|
|
148
|
+
);
|
|
149
|
+
const types = {};
|
|
150
|
+
for (const row of typeResult.rows) {
|
|
151
|
+
types[String(row.type)] = Number(row.cnt);
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
entities: Number(entityCount.rows[0]?.cnt ?? 0),
|
|
155
|
+
relationships: Number(relCount.rows[0]?.cnt ?? 0),
|
|
156
|
+
types
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
async function getEntityTimeline(client, entityId, since) {
|
|
160
|
+
const args = [entityId, entityId];
|
|
161
|
+
let sinceClause = "";
|
|
162
|
+
if (since) {
|
|
163
|
+
sinceClause = " AND r.timestamp >= ?";
|
|
164
|
+
args.push(since.toISOString());
|
|
165
|
+
}
|
|
166
|
+
const result = await client.execute({
|
|
167
|
+
sql: `SELECT r.*, s.name as source_name, t.name as target_name
|
|
168
|
+
FROM relationships r
|
|
169
|
+
JOIN entities s ON r.source_entity_id = s.id
|
|
170
|
+
JOIN entities t ON r.target_entity_id = t.id
|
|
171
|
+
WHERE (r.source_entity_id = ? OR r.target_entity_id = ?)${sinceClause}
|
|
172
|
+
ORDER BY r.timestamp DESC`,
|
|
173
|
+
args
|
|
174
|
+
});
|
|
175
|
+
return result.rows.map((row) => ({
|
|
176
|
+
relationship: {
|
|
177
|
+
id: String(row.id),
|
|
178
|
+
sourceEntityId: String(row.source_entity_id),
|
|
179
|
+
targetEntityId: String(row.target_entity_id),
|
|
180
|
+
type: String(row.type),
|
|
181
|
+
weight: Number(row.weight),
|
|
182
|
+
timestamp: String(row.timestamp),
|
|
183
|
+
properties: JSON.parse(String(row.properties ?? "{}")),
|
|
184
|
+
sourceName: String(row.source_name),
|
|
185
|
+
targetName: String(row.target_name)
|
|
186
|
+
},
|
|
187
|
+
timestamp: String(row.timestamp)
|
|
188
|
+
}));
|
|
189
|
+
}
|
|
190
|
+
async function getRelationshipFrequency(client, entityId, options) {
|
|
191
|
+
const granularity = options?.granularity ?? "day";
|
|
192
|
+
const args = [entityId, entityId];
|
|
193
|
+
let typeClause = "";
|
|
194
|
+
if (options?.type) {
|
|
195
|
+
typeClause = " AND r.type = ?";
|
|
196
|
+
args.push(options.type);
|
|
197
|
+
}
|
|
198
|
+
let bucketExpr;
|
|
199
|
+
switch (granularity) {
|
|
200
|
+
case "week":
|
|
201
|
+
bucketExpr = `strftime('%Y', r.timestamp) || '-W' || strftime('%W', r.timestamp)`;
|
|
202
|
+
break;
|
|
203
|
+
case "month":
|
|
204
|
+
bucketExpr = `strftime('%Y-%m', r.timestamp)`;
|
|
205
|
+
break;
|
|
206
|
+
default:
|
|
207
|
+
bucketExpr = `strftime('%Y-%m-%d', r.timestamp)`;
|
|
208
|
+
}
|
|
209
|
+
const result = await client.execute({
|
|
210
|
+
sql: `SELECT ${bucketExpr} as bucket, COUNT(*) as cnt, r.type as rel_type
|
|
211
|
+
FROM relationships r
|
|
212
|
+
WHERE (r.source_entity_id = ? OR r.target_entity_id = ?)${typeClause}
|
|
213
|
+
GROUP BY bucket${options?.type ? "" : ", r.type"}
|
|
214
|
+
ORDER BY bucket DESC`,
|
|
215
|
+
args
|
|
216
|
+
});
|
|
217
|
+
return result.rows.map((row) => ({
|
|
218
|
+
bucket: String(row.bucket),
|
|
219
|
+
count: Number(row.cnt),
|
|
220
|
+
relationshipType: options?.type ? options.type : String(row.rel_type)
|
|
221
|
+
}));
|
|
222
|
+
}
|
|
223
|
+
async function getConversationPartners(client, contactEntityId, since) {
|
|
224
|
+
const args = [contactEntityId, contactEntityId];
|
|
225
|
+
let sinceClause = "";
|
|
226
|
+
if (since) {
|
|
227
|
+
sinceClause = " AND r.timestamp >= ?";
|
|
228
|
+
args.push(since.toISOString());
|
|
229
|
+
}
|
|
230
|
+
const result = await client.execute({
|
|
231
|
+
sql: `SELECT
|
|
232
|
+
CASE
|
|
233
|
+
WHEN r.source_entity_id = ? THEN r.target_entity_id
|
|
234
|
+
ELSE r.source_entity_id
|
|
235
|
+
END as partner_id,
|
|
236
|
+
COUNT(*) as interaction_count,
|
|
237
|
+
MAX(r.timestamp) as last_interaction
|
|
238
|
+
FROM relationships r
|
|
239
|
+
WHERE (r.source_entity_id = ? OR r.target_entity_id = ?)${sinceClause}
|
|
240
|
+
GROUP BY partner_id
|
|
241
|
+
ORDER BY interaction_count DESC`,
|
|
242
|
+
args: [contactEntityId, ...args]
|
|
243
|
+
});
|
|
244
|
+
const partners = [];
|
|
245
|
+
for (const row of result.rows) {
|
|
246
|
+
const partnerId = String(row.partner_id);
|
|
247
|
+
const entityResult = await client.execute({
|
|
248
|
+
sql: "SELECT * FROM entities WHERE id = ?",
|
|
249
|
+
args: [partnerId]
|
|
250
|
+
});
|
|
251
|
+
if (entityResult.rows.length === 0) continue;
|
|
252
|
+
const e = entityResult.rows[0];
|
|
253
|
+
partners.push({
|
|
254
|
+
agentEntity: {
|
|
255
|
+
id: String(e.id),
|
|
256
|
+
name: String(e.name),
|
|
257
|
+
type: String(e.type),
|
|
258
|
+
firstSeen: String(e.first_seen),
|
|
259
|
+
lastSeen: String(e.last_seen),
|
|
260
|
+
properties: JSON.parse(String(e.properties ?? "{}"))
|
|
261
|
+
},
|
|
262
|
+
interactionCount: Number(row.interaction_count),
|
|
263
|
+
lastInteraction: String(row.last_interaction)
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
return partners;
|
|
267
|
+
}
|
|
268
|
+
async function getHotEntities(client, since, limit = 10) {
|
|
269
|
+
const sinceISO = since.toISOString();
|
|
270
|
+
const result = await client.execute({
|
|
271
|
+
sql: `SELECT entity_id, COUNT(*) as rel_count
|
|
272
|
+
FROM (
|
|
273
|
+
SELECT source_entity_id as entity_id FROM relationships WHERE timestamp >= ?
|
|
274
|
+
UNION ALL
|
|
275
|
+
SELECT target_entity_id as entity_id FROM relationships WHERE timestamp >= ?
|
|
276
|
+
)
|
|
277
|
+
GROUP BY entity_id
|
|
278
|
+
ORDER BY rel_count DESC
|
|
279
|
+
LIMIT ?`,
|
|
280
|
+
args: [sinceISO, sinceISO, limit]
|
|
281
|
+
});
|
|
282
|
+
const hotEntities = [];
|
|
283
|
+
for (const row of result.rows) {
|
|
284
|
+
const eid = String(row.entity_id);
|
|
285
|
+
const entityResult = await client.execute({
|
|
286
|
+
sql: "SELECT * FROM entities WHERE id = ?",
|
|
287
|
+
args: [eid]
|
|
288
|
+
});
|
|
289
|
+
if (entityResult.rows.length === 0) continue;
|
|
290
|
+
const e = entityResult.rows[0];
|
|
291
|
+
hotEntities.push({
|
|
292
|
+
entity: {
|
|
293
|
+
id: String(e.id),
|
|
294
|
+
name: String(e.name),
|
|
295
|
+
type: String(e.type),
|
|
296
|
+
firstSeen: String(e.first_seen),
|
|
297
|
+
lastSeen: String(e.last_seen),
|
|
298
|
+
properties: JSON.parse(String(e.properties ?? "{}"))
|
|
299
|
+
},
|
|
300
|
+
newRelationships: Number(row.rel_count)
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
return hotEntities;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
export {
|
|
307
|
+
getEntityByName,
|
|
308
|
+
searchEntities,
|
|
309
|
+
getRelationships,
|
|
310
|
+
traverseChain,
|
|
311
|
+
getEntityNeighbors,
|
|
312
|
+
getGraphStats,
|
|
313
|
+
getEntityTimeline,
|
|
314
|
+
getRelationshipFrequency,
|
|
315
|
+
getConversationPartners,
|
|
316
|
+
getHotEntities
|
|
317
|
+
};
|