@askexenow/exe-os 0.9.280 → 0.9.281
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.customer.example +1 -1
- package/deploy/compose/.env.default +2 -1
- package/deploy/compose/.env.example +1 -1
- package/deploy/compose/docker-compose.yml +74 -13
- package/deploy/compose/erp-nginx/nginx.conf +52 -0
- package/deploy/compose/generate-env.ts +1 -1
- package/deploy/compose/init-db.sql +13 -2
- package/deploy/stack-manifests/v0.9.json +11 -31
- package/dist/active-agent-6ZBHGHXF.js +26 -0
- package/dist/active-agent-E23SCYER.js +27 -0
- package/dist/active-agent-KMZT44S4.js +26 -0
- package/dist/active-agent-LFFTVROM.js +27 -0
- package/dist/agentic-ontology-PCZB5HV5.js +25 -0
- package/dist/agentic-ontology-PGGJN2ES.js +25 -0
- package/dist/assets/tmux.conf +2 -0
- package/dist/backfill-metadata-KQ4FEVUR.js +599 -0
- package/dist/backfill-metadata-Y3YWCHKJ.js +599 -0
- package/dist/behaviors-H4DZECKL.js +39 -0
- package/dist/behaviors-WIUTIJF6.js +39 -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 +7 -7
- package/dist/bin/cc-doctor.js +4 -4
- package/dist/bin/cleanup-stale-review-tasks.js +10 -10
- 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 +17 -17
- package/dist/bin/exe-call.js +4 -4
- package/dist/bin/exe-cloud.js +5 -5
- package/dist/bin/exe-dispatch.js +10 -10
- 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 +4 -4
- package/dist/bin/exe-heartbeat.js +10 -10
- package/dist/bin/exe-kill.js +13 -13
- package/dist/bin/exe-launch-agent.js +17 -17
- package/dist/bin/exe-new-employee.js +7 -7
- package/dist/bin/exe-pending-messages.js +11 -11
- package/dist/bin/exe-pending-notifications.js +10 -10
- package/dist/bin/exe-pending-reviews.js +10 -10
- package/dist/bin/exe-rename.js +4 -4
- package/dist/bin/exe-review.js +12 -12
- package/dist/bin/exe-search.js +5 -5
- package/dist/bin/exe-session-cleanup.js +15 -15
- package/dist/bin/exe-settings.js +5 -5
- package/dist/bin/exe-start-codex.js +11 -11
- package/dist/bin/exe-start-opencode.js +8 -8
- package/dist/bin/exe-status.js +11 -11
- package/dist/bin/exe-support.js +2 -2
- package/dist/bin/exe-team.js +3 -3
- package/dist/bin/exe-watchdog.js +17 -2
- package/dist/bin/git-sweep.js +11 -11
- 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 +8 -7
- 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 +10 -10
- package/dist/bin/setup.js +1 -1
- package/dist/bin/shard-migrate.js +4 -4
- package/dist/bin/stack-update.js +3 -3
- package/dist/bin/vps-health-gate.js +1 -1
- package/dist/capability-cards-F22XWGLB.js +88 -0
- package/dist/capability-cards-KCKITXXZ.js +88 -0
- package/dist/capacity-monitor-CHXGKVEO.js +50 -0
- package/dist/capacity-monitor-L3M5KB6T.js +50 -0
- package/dist/catchup-brief-BVZANLRZ.js +154 -0
- package/dist/catchup-brief-LDUGMC7S.js +154 -0
- package/dist/catchup-brief-NZDLL7SA.js +154 -0
- package/dist/catchup-brief-OOIXVGBA.js +154 -0
- package/dist/catchup-brief-UPXHDYTB.js +154 -0
- package/dist/chunk-2BI3FQKL.js +1876 -0
- package/dist/chunk-2CJUQGHH.js +362 -0
- package/dist/chunk-2EVYBMBJ.js +128 -0
- package/dist/chunk-2NQOZOXG.js +2113 -0
- package/dist/chunk-2QK5E3LB.js +128 -0
- package/dist/chunk-2VTCG4ZU.js +1352 -0
- package/dist/chunk-2YGI36DV.js +1119 -0
- package/dist/chunk-32BQN2QN.js +185 -0
- package/dist/chunk-33JMO4UV.js +157 -0
- package/dist/chunk-3DZAYLXY.js +377 -0
- package/dist/chunk-3MGBE7GR.js +76 -0
- package/dist/chunk-3MTV4FJL.js +271 -0
- package/dist/chunk-3NN7VQ27.js +1352 -0
- package/dist/chunk-4533HNOG.js +70 -0
- package/dist/chunk-456UW3MT.js +731 -0
- package/dist/chunk-4AU56XV2.js +58 -0
- package/dist/chunk-4MRP6EBR.js +280 -0
- package/dist/chunk-4MRWW52U.js +14219 -0
- package/dist/chunk-4WWECNAY.js +50 -0
- package/dist/chunk-4ZJDDR6L.js +171 -0
- package/dist/chunk-522EOPM6.js +382 -0
- package/dist/chunk-52UDAVZE.js +3208 -0
- package/dist/chunk-5FAMUB4X.js +204 -0
- package/dist/chunk-5PGZJQUI.js +58 -0
- package/dist/chunk-67TZJXNZ.js +262 -0
- package/dist/chunk-6FEZ7GN2.js +123 -0
- package/dist/chunk-6MOGND7S.js +14219 -0
- package/dist/chunk-6TRSVY7L.js +181 -0
- package/dist/chunk-6WCS7ZNK.js +85 -0
- package/dist/chunk-6WRYDREW.js +539 -0
- package/dist/chunk-72UA2FB3.js +181 -0
- package/dist/chunk-77DMFEOL.js +30 -0
- package/dist/chunk-7COXVQ5W.js +214 -0
- package/dist/chunk-7HLWBYH7.js +60 -0
- package/dist/chunk-ALSTZCWT.js +204 -0
- package/dist/chunk-ARUTDXZX.js +280 -0
- package/dist/chunk-AU47B4QY.js +129 -0
- package/dist/chunk-AXOREWVL.js +836 -0
- package/dist/chunk-B5MNC54V.js +127 -0
- package/dist/chunk-B74VSMKX.js +1350 -0
- package/dist/chunk-BHWLH44J.js +362 -0
- package/dist/chunk-BUPZ3HD2.js +85 -0
- package/dist/chunk-BWVLMA53.js +2113 -0
- package/dist/chunk-C5WLBKMJ.js +50 -0
- package/dist/chunk-C62T6R2A.js +97 -0
- package/dist/chunk-CV5KBAIK.js +33 -0
- package/dist/chunk-DAYSDWXA.js +1068 -0
- package/dist/chunk-DI4URIUB.js +227 -0
- package/dist/chunk-DNTCYFJ6.js +76 -0
- package/dist/chunk-DPDRRS7T.js +103 -0
- package/dist/chunk-DT3EV6CW.js +103 -0
- package/dist/chunk-DX45HDWY.js +1076 -0
- package/dist/chunk-E72BD6MG.js +284 -0
- package/dist/chunk-EAPUSVKS.js +375 -0
- package/dist/chunk-EFUANRRT.js +85 -0
- package/dist/chunk-EG2SCT5R.js +1352 -0
- package/dist/chunk-EJD2JU77.js +58 -0
- package/dist/chunk-EMXYUAVP.js +81 -0
- package/dist/chunk-ENM2TAAM.js +14219 -0
- package/dist/chunk-EPDRTPVP.js +1876 -0
- package/dist/chunk-EW6XDHID.js +221 -0
- package/dist/chunk-EYEGSAWZ.js +1094 -0
- package/dist/chunk-F6L33PAQ.js +231 -0
- package/dist/chunk-FC2SCTVE.js +38 -0
- package/dist/chunk-FSRKIZGZ.js +630 -0
- package/dist/chunk-FTG7I5CB.js +81 -0
- package/dist/chunk-GVFRLWX7.js +30 -0
- package/dist/chunk-H3XMZOWW.js +1119 -0
- package/dist/chunk-HAKXE6LN.js +123 -0
- package/dist/chunk-HLP3ZDTW.js +448 -0
- package/dist/chunk-HOYWKQAA.js +510 -0
- package/dist/chunk-HWDD64IW.js +712 -0
- package/dist/chunk-HWMCULHY.js +127 -0
- package/dist/chunk-HZZHRZPK.js +210 -0
- package/dist/chunk-ICRWTYNW.js +103 -0
- package/dist/chunk-J5MWPC33.js +167 -0
- package/dist/chunk-JBXANNNB.js +70 -0
- package/dist/chunk-JPBMIYWF.js +1352 -0
- package/dist/chunk-JY6EXBFI.js +373 -0
- package/dist/chunk-JZLIBXI7.js +14219 -0
- package/dist/chunk-JZPTKXJ6.js +668 -0
- package/dist/chunk-KEYMA4ZP.js +510 -0
- package/dist/chunk-KHGNN6GL.js +2078 -0
- package/dist/chunk-KVLB2PD6.js +97 -0
- package/dist/chunk-L3YBRBKL.js +1076 -0
- package/dist/chunk-L7VZ32NA.js +89 -0
- package/dist/chunk-LEHLADW4.js +221 -0
- package/dist/chunk-LPD4HILQ.js +262 -0
- package/dist/chunk-LSJ3ADDI.js +51 -0
- package/dist/chunk-LUMS2MAS.js +58 -0
- package/dist/chunk-LV4SEC6C.js +394 -0
- package/dist/chunk-LXXBEI4A.js +284 -0
- package/dist/chunk-M4NPCAIH.js +456 -0
- package/dist/chunk-MFJ62LQ5.js +157 -0
- package/dist/chunk-MGEZNKOD.js +836 -0
- package/dist/chunk-MJ7X5IBW.js +227 -0
- package/dist/chunk-MLGRWCY4.js +54 -0
- package/dist/chunk-MQZX57IY.js +348 -0
- package/dist/chunk-MY7MFF6J.js +103 -0
- package/dist/chunk-MYA2X5OY.js +185 -0
- package/dist/chunk-MYEABW5Z.js +630 -0
- package/dist/chunk-MZ2TDCAL.js +402 -0
- package/dist/chunk-NF3FRB7Z.js +271 -0
- package/dist/chunk-NXYIFEPV.js +539 -0
- package/dist/chunk-O2GVE5B5.js +58 -0
- package/dist/chunk-O5GUCDR2.js +456 -0
- package/dist/chunk-OBZNRECA.js +128 -0
- package/dist/chunk-OMZ2RLJG.js +214 -0
- package/dist/chunk-ORDHJRWN.js +299 -0
- package/dist/chunk-OSPIJMCD.js +210 -0
- package/dist/chunk-OUGWEH4J.js +240 -0
- package/dist/chunk-OV5MJQGC.js +1876 -0
- package/dist/chunk-PC635OAG.js +4318 -0
- package/dist/chunk-PH46R4J6.js +348 -0
- package/dist/chunk-PJP2EP7P.js +394 -0
- package/dist/chunk-PODFWH3V.js +333 -0
- package/dist/chunk-PPWH3SHR.js +1068 -0
- package/dist/chunk-PWPJK7KB.js +4318 -0
- package/dist/chunk-PXONZVG4.js +377 -0
- package/dist/chunk-QAOGJRZD.js +369 -0
- package/dist/chunk-QC3LAEI7.js +197 -0
- package/dist/chunk-QDWQDUWI.js +668 -0
- package/dist/chunk-QKJFD6BH.js +1350 -0
- package/dist/chunk-QNYVJGFM.js +345 -0
- package/dist/chunk-QQF3XGQ5.js +14219 -0
- package/dist/chunk-QRPFQNI3.js +150 -0
- package/dist/chunk-QSSU5XWD.js +731 -0
- package/dist/chunk-QXZAGVAV.js +2078 -0
- package/dist/chunk-RA54MW64.js +244 -0
- package/dist/chunk-RF7PUWXI.js +197 -0
- package/dist/chunk-S3INDYSO.js +244 -0
- package/dist/chunk-SLQVTHH5.js +369 -0
- package/dist/chunk-SY2B74KL.js +345 -0
- package/dist/chunk-T6QPXXXW.js +712 -0
- package/dist/chunk-TO5M5YCT.js +41 -0
- package/dist/chunk-TQ4VXUAF.js +129 -0
- package/dist/chunk-UAB7RQC4.js +41 -0
- package/dist/chunk-UMEIBDYW.js +97 -0
- package/dist/chunk-UXW5TB7Y.js +240 -0
- package/dist/chunk-VB2N5WOX.js +150 -0
- package/dist/chunk-VLZEMRG3.js +167 -0
- package/dist/chunk-VM3V6VK7.js +230 -0
- package/dist/chunk-VMCGKBHB.js +1352 -0
- package/dist/chunk-VNIYZAR5.js +128 -0
- package/dist/chunk-VYV4KOD2.js +85 -0
- package/dist/chunk-W4SRJBAT.js +171 -0
- package/dist/chunk-W5W3LZ3Q.js +54 -0
- package/dist/chunk-WDNZEOM3.js +38 -0
- package/dist/chunk-WUKEXVOR.js +3208 -0
- package/dist/chunk-X3Z35Q6L.js +373 -0
- package/dist/chunk-X4VOU6BQ.js +382 -0
- package/dist/chunk-X6EEVSVG.js +290 -0
- package/dist/chunk-XFHGWGNB.js +1094 -0
- package/dist/chunk-XKOLRWYA.js +33 -0
- package/dist/chunk-XMMIL3UD.js +402 -0
- package/dist/chunk-XWILC6VA.js +290 -0
- package/dist/chunk-Y4OQCX4C.js +97 -0
- package/dist/chunk-Y67VYYOA.js +231 -0
- package/dist/chunk-YGQCQTQH.js +230 -0
- package/dist/chunk-YGWFBN5A.js +299 -0
- package/dist/chunk-YMKUXZIG.js +379 -0
- package/dist/chunk-YOMLMT7E.js +230 -0
- package/dist/chunk-YPESIZOB.js +14219 -0
- package/dist/chunk-Z2CGCIU2.js +89 -0
- package/dist/chunk-ZLAWNHQR.js +448 -0
- package/dist/chunk-ZME5UQSN.js +333 -0
- package/dist/co-activation-NUEQYXE5.js +73 -0
- package/dist/co-activation-ZG5HLBCZ.js +73 -0
- package/dist/co-occurrence-7S5KWQB2.js +94 -0
- package/dist/co-occurrence-X5SWDXT2.js +94 -0
- package/dist/core-memory-GOPBRGGZ.js +110 -0
- package/dist/core-memory-XLCU6L5M.js +110 -0
- package/dist/crdt-sync-EPKHPGRZ.js +33 -0
- package/dist/crdt-sync-UIQJ5U7T.js +33 -0
- package/dist/crm-webhook-MKN23JNU.js +10 -0
- package/dist/crm-webhook-SM63BPXO.js +10 -0
- package/dist/cto-delegation-gate-PQY5TOVZ.js +279 -0
- package/dist/cto-delegation-gate-V5VVUR3G.js +279 -0
- package/dist/daemon-orchestration-C7AAS67Q.js +138 -0
- package/dist/daemon-orchestration-OBCAJB2H.js +138 -0
- package/dist/db-backup-F7VP4QRH.js +33 -0
- package/dist/db-backup-KVYC57W7.js +33 -0
- package/dist/doc-graph-extractor-H2ETEINP.js +132 -0
- package/dist/doc-graph-extractor-PCUZEYCH.js +132 -0
- package/dist/dreaming-4OZXSLE3.js +33 -0
- package/dist/dreaming-Z2RYEYNT.js +33 -0
- package/dist/exe-drift-GEWNIK7A.js +69 -0
- package/dist/exe-drift-XCGH7AFO.js +69 -0
- package/dist/exe-export-7DKAU5IP.js +75 -0
- package/dist/exe-export-BCHH6OE6.js +75 -0
- package/dist/exe-import-PDRIZVYF.js +78 -0
- package/dist/exe-import-ZCKUDFKL.js +78 -0
- package/dist/exe-key-FUWLLI3U.js +580 -0
- package/dist/exe-key-RKKNVUMP.js +580 -0
- package/dist/exe-snapshot-G4I5FQMK.js +337 -0
- package/dist/exe-snapshot-GWU7QTZK.js +337 -0
- package/dist/fast-db-init-6QG6YQNT.js +7 -0
- package/dist/fast-db-init-X2QDQUA4.js +7 -0
- package/dist/founder-context-TOMNUBGJ.js +96 -0
- package/dist/founder-context-UU3V6MAS.js +96 -0
- package/dist/gateway/index.js +8 -8
- package/dist/git-staleness-FEPFMZKF.js +111 -0
- package/dist/git-staleness-HYVYLCW3.js +111 -0
- package/dist/git-task-sweep-IRV52JIM.js +41 -0
- package/dist/git-task-sweep-T6BSM3GS.js +41 -0
- package/dist/global-procedures-3AURRMKO.js +21 -0
- package/dist/global-procedures-JPCYBZYC.js +21 -0
- package/dist/graph-auto-extract-OC3AOSMW.js +182 -0
- package/dist/graph-auto-extract-PVDYEJBY.js +182 -0
- package/dist/hooks/bug-report-worker.js +12 -12
- package/dist/hooks/codex-stop-task-finalizer.js +12 -12
- package/dist/hooks/commit-complete.js +12 -12
- 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 +11 -11
- package/dist/hooks/post-tool-combined.js +5 -5
- package/dist/hooks/pre-compact.js +12 -12
- package/dist/hooks/pre-tool-use.js +15 -15
- package/dist/hooks/prompt-submit.js +22 -22
- package/dist/hooks/session-end.js +16 -16
- package/dist/hooks/session-start.js +10 -10
- package/dist/hooks/stop.js +15 -15
- package/dist/hooks/subagent-stop.js +11 -11
- package/dist/hooks/summary-worker.js +15 -15
- package/dist/index.js +18 -18
- package/dist/installer-72XXLBRP.js +39 -0
- package/dist/installer-HDXG2BZN.js +343 -0
- package/dist/installer-JALMKPCS.js +297 -0
- package/dist/installer-Q46SNNLU.js +39 -0
- package/dist/installer-W7PIPRCX.js +343 -0
- package/dist/installer-Z7WQEOS7.js +297 -0
- package/dist/lib/cloud-sync.js +5 -5
- package/dist/lib/consolidation.js +5 -5
- package/dist/lib/database.js +2 -2
- 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 +45 -41
- package/dist/lib/hybrid-search.js +5 -5
- package/dist/lib/identity.js +2 -2
- package/dist/lib/license.js +1 -1
- package/dist/lib/messaging.js +10 -10
- 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 +6 -6
- package/dist/lib/store.js +4 -4
- package/dist/lib/task-router.js +3 -3
- package/dist/lib/tasks.js +11 -11
- package/dist/lib/tmux-routing.js +9 -9
- package/dist/lib/token-spend.js +3 -3
- package/dist/license-gate-7JZCHOAG.js +14 -0
- package/dist/license-gate-OP4SKL4P.js +14 -0
- package/dist/mcp/register-tools.js +58 -58
- package/dist/mcp/server.js +59 -59
- 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 +13 -13
- package/dist/mcp/tools/deactivate-behavior.js +7 -7
- package/dist/mcp/tools/list-reminders.js +4 -4
- package/dist/mcp/tools/list-tasks.js +13 -13
- package/dist/mcp/tools/send-message.js +12 -12
- package/dist/mcp/tools/update-task.js +12 -12
- package/dist/mcp-health-VULNT722.js +17 -0
- package/dist/mcp-health-WDOB6XUB.js +19 -0
- package/dist/mcp-http-config-2OZ7N74D.js +28 -0
- package/dist/mcp-http-config-4VXA5K73.js +28 -0
- package/dist/memory-cards-2K6QRZU6.js +179 -0
- package/dist/memory-cards-KSJF5OH2.js +179 -0
- package/dist/memory-graph-extractor-IJD5HWYT.js +21 -0
- package/dist/memory-graph-extractor-O4GAXOK5.js +21 -0
- package/dist/memory-poisoning-defense-2JRPWT5V.js +223 -0
- package/dist/memory-poisoning-defense-DH4A25NU.js +223 -0
- package/dist/memory-reflection-ISY2BBDB.js +243 -0
- package/dist/memory-reflection-Z5AQRR6H.js +243 -0
- package/dist/notifications-2VSWK2UJ.js +46 -0
- package/dist/notifications-4S253VQM.js +46 -0
- package/dist/oauth-server-D7D4574D.js +437 -0
- package/dist/oauth-server-MACN54SJ.js +437 -0
- package/dist/orchestration-events-BGP5RYQI.js +26 -0
- package/dist/orchestration-events-MDXUEVRZ.js +26 -0
- package/dist/orchestrator-DHK7RSSH.js +34 -0
- package/dist/orchestrator-R75WHQVA.js +34 -0
- package/dist/pipeline-router-4WUKQQEC.js +14 -0
- package/dist/pipeline-router-GWB2XK2Q.js +14 -0
- package/dist/plan-limits-NNJRAESF.js +27 -0
- package/dist/plan-limits-YTQW4UR4.js +27 -0
- package/dist/project-boot-46GZJTEX.js +299 -0
- package/dist/project-boot-PPHBBGIF.js +299 -0
- package/dist/projection-worker-UPAWXI7P.js +1034 -0
- package/dist/projection-worker-ZIKDYBW5.js +1034 -0
- package/dist/reranker-5ZBP2RRN.js +19 -0
- package/dist/reranker-E2MQIMJL.js +19 -0
- package/dist/reranker-GLSDJT3V.js +19 -0
- package/dist/reranker-LBBXWNOD.js +19 -0
- package/dist/reranker-XZ2EF4OH.js +19 -0
- package/dist/retrieval-health-JYRKPSII.js +7 -0
- package/dist/retrieval-health-OUV25J6S.js +7 -0
- package/dist/retrieval-health-U73JUAZL.js +7 -0
- package/dist/retrieval-health-WSZ7TYFF.js +7 -0
- package/dist/review-polling-62JV55ZT.js +125 -0
- package/dist/review-polling-CJXLWFWK.js +125 -0
- package/dist/runtime/index.js +12 -12
- package/dist/session-events-2ADD54VI.js +37 -0
- package/dist/session-events-QIJVBSKS.js +37 -0
- package/dist/session-kill-telemetry-HS6HD2YE.js +30 -0
- package/dist/session-kill-telemetry-MRT5FVSM.js +30 -0
- package/dist/session-scope-7ICYPC33.js +87 -0
- package/dist/session-scope-KMXD6EE6.js +87 -0
- package/dist/setup-wizard-B6GIT7YC.js +12 -0
- package/dist/setup-wizard-JUIJ4UZO.js +12 -0
- package/dist/skill-refinement-HIOX4VMC.js +158 -0
- package/dist/skill-refinement-T7JXRYUW.js +158 -0
- package/dist/stack-update-5KE6BZKQ.js +74 -0
- package/dist/stack-update-OP2RHP7N.js +74 -0
- package/dist/stack-update-VGCWDJEE.js +74 -0
- package/dist/steward-gate-L22WE3SY.js +14 -0
- package/dist/steward-gate-YKD2LUWN.js +14 -0
- package/dist/task-enforcement-5AOKXTY4.js +439 -0
- package/dist/task-enforcement-VO3YEGIO.js +439 -0
- package/dist/task-scope-YV2WPKRD.js +36 -0
- package/dist/task-scope-ZSXDZBRE.js +36 -0
- package/dist/tasks-crud-C6KADACT.js +78 -0
- package/dist/tasks-crud-NV6JEWGL.js +78 -0
- package/dist/tasks-notify-E22HSN6O.js +39 -0
- package/dist/tasks-notify-RPSEQ4WV.js +39 -0
- package/dist/tasks-review-V4ZLXOAZ.js +48 -0
- package/dist/tasks-review-ZVRI73JE.js +48 -0
- package/dist/telemetry-upload-LXUH7SKI.js +740 -0
- package/dist/telemetry-upload-TCDAZTUQ.js +740 -0
- package/dist/token-budget-OFBEZJTA.js +85 -0
- package/dist/token-budget-WAN57V6S.js +85 -0
- package/dist/tool-telemetry-UA3N32PK.js +17 -0
- package/dist/tool-telemetry-XXZJ35RR.js +17 -0
- package/dist/tui/App.js +17 -17
- package/dist/tui-data-46QLCJUE.js +259 -0
- package/dist/tui-data-ZDB7BLP2.js +259 -0
- package/dist/wiki-acl-HHSIBPF3.js +111 -0
- package/dist/wiki-acl-O65GZ2ZF.js +111 -0
- package/dist/worker-gate-27I4GAEZ.js +21 -0
- package/dist/worker-gate-DXU4HEPY.js +21 -0
- package/dist/workflow-engine-63EOEJ5Q.js +28 -0
- package/dist/workflow-engine-C6F2RMPN.js +28 -0
- package/dist/worktree-SFKKOMFD.js +27 -0
- package/dist/worktree-SVCE3S7X.js +27 -0
- package/dist/worktree-sweep-S3JHJTVP.js +20 -0
- package/dist/worktree-sweep-U3TIQ7WL.js +20 -0
- package/package.json +1 -1
- package/release-notes.json +88 -26
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
// src/automation/trigger-engine.ts
|
|
2
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
3
|
+
import { randomUUID } from "crypto";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import os from "os";
|
|
6
|
+
var TRIGGERS_PATH = path.join(os.homedir(), ".exe-os", "triggers.json");
|
|
7
|
+
var GRAPH_API_VERSION = "v21.0";
|
|
8
|
+
var MAX_PARAM_LENGTH = 2e3;
|
|
9
|
+
var MAX_TRIGGER_DEPTH = 3;
|
|
10
|
+
var _currentTriggerDepth = 0;
|
|
11
|
+
var OUTBOUND_RATE_LIMIT_PER_HOUR = 100;
|
|
12
|
+
var _outboundWindows = /* @__PURE__ */ new Map();
|
|
13
|
+
function checkOutboundRateLimit(channel) {
|
|
14
|
+
const now = Date.now();
|
|
15
|
+
const cutoff = now - 36e5;
|
|
16
|
+
if (!_outboundWindows.has(channel)) _outboundWindows.set(channel, []);
|
|
17
|
+
const window = _outboundWindows.get(channel);
|
|
18
|
+
while (window.length > 0 && window[0] < cutoff) window.shift();
|
|
19
|
+
if (window.length >= OUTBOUND_RATE_LIMIT_PER_HOUR) return false;
|
|
20
|
+
window.push(now);
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
function sanitizeParam(value, maxLen = MAX_PARAM_LENGTH) {
|
|
24
|
+
const cleaned = value.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
|
|
25
|
+
return cleaned.length > maxLen ? cleaned.slice(0, maxLen) : cleaned;
|
|
26
|
+
}
|
|
27
|
+
function sanitizeExternalPayload(text) {
|
|
28
|
+
let sanitized = text;
|
|
29
|
+
sanitized = sanitized.replace(/^(system|SYSTEM|System)\s*:/gm, "[filtered]:");
|
|
30
|
+
sanitized = sanitized.replace(/<\/?system[^>]*>/gi, "[filtered]");
|
|
31
|
+
sanitized = sanitized.replace(/ignore\s+(all\s+)?previous\s+(instructions|prompts|rules)/gi, "[filtered]");
|
|
32
|
+
sanitized = sanitized.replace(/you\s+are\s+now\s+/gi, "[filtered] ");
|
|
33
|
+
return sanitized;
|
|
34
|
+
}
|
|
35
|
+
function substituteTemplate(template, record, sanitizeExternal = false) {
|
|
36
|
+
return template.replace(
|
|
37
|
+
/\{\{(\w+(?:\.\w+)*)\}\}/g,
|
|
38
|
+
(_match, dotPath) => {
|
|
39
|
+
const segments = dotPath.split(".");
|
|
40
|
+
if (segments[0] === "record") segments.shift();
|
|
41
|
+
let current = record;
|
|
42
|
+
for (const seg of segments) {
|
|
43
|
+
if (current == null || typeof current !== "object") return "";
|
|
44
|
+
current = current[seg];
|
|
45
|
+
}
|
|
46
|
+
if (current == null) return "";
|
|
47
|
+
const value = String(current);
|
|
48
|
+
return sanitizeExternal ? sanitizeExternalPayload(value) : value;
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
function resolveFieldValue(record, field) {
|
|
53
|
+
let current = record;
|
|
54
|
+
for (const segment of field.split(".")) {
|
|
55
|
+
if (current == null || typeof current !== "object") return void 0;
|
|
56
|
+
current = current[segment];
|
|
57
|
+
}
|
|
58
|
+
return current;
|
|
59
|
+
}
|
|
60
|
+
function evaluateCondition(condition, record) {
|
|
61
|
+
const fieldValue = resolveFieldValue(record, condition.field);
|
|
62
|
+
const target = condition.value;
|
|
63
|
+
switch (condition.op) {
|
|
64
|
+
case "eq":
|
|
65
|
+
return String(fieldValue) === String(target);
|
|
66
|
+
case "neq":
|
|
67
|
+
return String(fieldValue) !== String(target);
|
|
68
|
+
case "gt":
|
|
69
|
+
return Number(fieldValue) > Number(target);
|
|
70
|
+
case "lt":
|
|
71
|
+
return Number(fieldValue) < Number(target);
|
|
72
|
+
case "gte":
|
|
73
|
+
return Number(fieldValue) >= Number(target);
|
|
74
|
+
case "lte":
|
|
75
|
+
return Number(fieldValue) <= Number(target);
|
|
76
|
+
case "contains":
|
|
77
|
+
return String(fieldValue).toLowerCase().includes(String(target).toLowerCase());
|
|
78
|
+
case "not_contains":
|
|
79
|
+
return !String(fieldValue).toLowerCase().includes(String(target).toLowerCase());
|
|
80
|
+
default:
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function evaluateConditions(conditions, record) {
|
|
85
|
+
if (conditions.length === 0) return true;
|
|
86
|
+
return conditions.every((c) => evaluateCondition(c, record));
|
|
87
|
+
}
|
|
88
|
+
function loadTriggers(project) {
|
|
89
|
+
if (!existsSync(TRIGGERS_PATH)) return [];
|
|
90
|
+
try {
|
|
91
|
+
const raw = readFileSync(TRIGGERS_PATH, "utf-8");
|
|
92
|
+
const all = JSON.parse(raw);
|
|
93
|
+
if (!Array.isArray(all)) return [];
|
|
94
|
+
if (project) {
|
|
95
|
+
return all.filter((t) => !t.project || t.project === project);
|
|
96
|
+
}
|
|
97
|
+
return all;
|
|
98
|
+
} catch {
|
|
99
|
+
return [];
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
function saveTriggers(triggers) {
|
|
103
|
+
const dir = path.dirname(TRIGGERS_PATH);
|
|
104
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
105
|
+
writeFileSync(TRIGGERS_PATH, JSON.stringify(triggers, null, 2), "utf-8");
|
|
106
|
+
}
|
|
107
|
+
function createNewTrigger(input) {
|
|
108
|
+
const triggers = loadTriggers();
|
|
109
|
+
const trigger = {
|
|
110
|
+
id: randomUUID().slice(0, 8),
|
|
111
|
+
...input
|
|
112
|
+
};
|
|
113
|
+
triggers.push(trigger);
|
|
114
|
+
saveTriggers(triggers);
|
|
115
|
+
return trigger;
|
|
116
|
+
}
|
|
117
|
+
async function executeSendWhatsapp(params) {
|
|
118
|
+
if (!checkOutboundRateLimit("whatsapp")) {
|
|
119
|
+
throw new Error(`Outbound rate limit exceeded for WhatsApp (max ${OUTBOUND_RATE_LIMIT_PER_HOUR}/hour)`);
|
|
120
|
+
}
|
|
121
|
+
const { getAccountByName, getDefaultAccount } = await import("./whatsapp-accounts-BWRZUY23.js");
|
|
122
|
+
const account = params.account ? getAccountByName(params.account) : getDefaultAccount();
|
|
123
|
+
if (!account) {
|
|
124
|
+
throw new Error(
|
|
125
|
+
`No WhatsApp account found${params.account ? ` (${params.account})` : ""}`
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
const to = params.to ?? params.recipient;
|
|
129
|
+
const message = params.message ?? params.text;
|
|
130
|
+
if (!to || !message)
|
|
131
|
+
throw new Error("send_whatsapp requires 'to' and 'message' params");
|
|
132
|
+
const url = `https://graph.facebook.com/${GRAPH_API_VERSION}/${account.phoneNumberId}/messages`;
|
|
133
|
+
const res = await fetch(url, {
|
|
134
|
+
method: "POST",
|
|
135
|
+
headers: {
|
|
136
|
+
"Content-Type": "application/json",
|
|
137
|
+
Authorization: `Bearer ${account.accessToken}`
|
|
138
|
+
},
|
|
139
|
+
body: JSON.stringify({
|
|
140
|
+
messaging_product: "whatsapp",
|
|
141
|
+
to,
|
|
142
|
+
type: "text",
|
|
143
|
+
text: { body: message }
|
|
144
|
+
}),
|
|
145
|
+
signal: AbortSignal.timeout(3e4)
|
|
146
|
+
});
|
|
147
|
+
if (!res.ok) {
|
|
148
|
+
const errBody = await res.text();
|
|
149
|
+
throw new Error(`WhatsApp send failed (${res.status}): ${errBody}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
async function executeSendMessage(params) {
|
|
153
|
+
const { sendMessage } = await import("./lib/messaging.js");
|
|
154
|
+
const { getCoordinatorName } = await import("./lib/employees.js");
|
|
155
|
+
const rawTo = params.to ?? params.recipient;
|
|
156
|
+
const to = rawTo === "coordinator" ? getCoordinatorName() : rawTo;
|
|
157
|
+
const content = params.message ?? params.content ?? params.text;
|
|
158
|
+
if (!to || !content)
|
|
159
|
+
throw new Error("send_message requires 'to' and 'message' params");
|
|
160
|
+
await sendMessage({
|
|
161
|
+
fromAgent: params.from ?? "trigger-engine",
|
|
162
|
+
targetAgent: to,
|
|
163
|
+
content,
|
|
164
|
+
priority: params.priority ?? "normal"
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
async function executeCreateTask(params) {
|
|
168
|
+
const { createTask } = await import("./lib/tasks.js");
|
|
169
|
+
const { getCoordinatorName } = await import("./lib/employees.js");
|
|
170
|
+
const rawAssignedTo = params.assigned_to;
|
|
171
|
+
await createTask({
|
|
172
|
+
title: params.title ?? "Triggered task",
|
|
173
|
+
assignedTo: !rawAssignedTo || rawAssignedTo === "coordinator" ? getCoordinatorName() : rawAssignedTo,
|
|
174
|
+
assignedBy: "trigger-engine",
|
|
175
|
+
projectName: params.project ?? "exe-os",
|
|
176
|
+
priority: params.priority ?? "p1",
|
|
177
|
+
context: params.context ?? params.description ?? "",
|
|
178
|
+
baseDir: process.cwd()
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
async function executeUpdateWiki(params) {
|
|
182
|
+
const apiUrl = process.env.EXE_WIKI_API_URL;
|
|
183
|
+
const apiKey = process.env.EXE_WIKI_API_KEY;
|
|
184
|
+
if (!apiUrl || !apiKey) {
|
|
185
|
+
throw new Error("Wiki not configured: EXE_WIKI_API_URL / EXE_WIKI_API_KEY not set");
|
|
186
|
+
}
|
|
187
|
+
const workspace = params.workspace;
|
|
188
|
+
const content = params.content ?? params.text;
|
|
189
|
+
const mode = params.mode ?? "append";
|
|
190
|
+
const section = params.section;
|
|
191
|
+
if (!workspace || !content) {
|
|
192
|
+
throw new Error("update_wiki requires 'workspace' and 'content' params");
|
|
193
|
+
}
|
|
194
|
+
const documentId = params.document_id;
|
|
195
|
+
if (documentId && mode === "append") {
|
|
196
|
+
const readRes = await fetch(`${apiUrl}/v1/document/${documentId}`, {
|
|
197
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
198
|
+
signal: AbortSignal.timeout(15e3)
|
|
199
|
+
});
|
|
200
|
+
if (!readRes.ok) {
|
|
201
|
+
throw new Error(`Wiki read failed (${readRes.status})`);
|
|
202
|
+
}
|
|
203
|
+
const doc = await readRes.json();
|
|
204
|
+
const existingContent = String(doc.content ?? "");
|
|
205
|
+
const title = String(doc.title ?? "Untitled");
|
|
206
|
+
await fetch(`${apiUrl}/v1/document/${documentId}`, {
|
|
207
|
+
method: "DELETE",
|
|
208
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
209
|
+
signal: AbortSignal.timeout(15e3)
|
|
210
|
+
}).catch((err) => {
|
|
211
|
+
process.stderr.write(`[trigger-engine] wiki purge failed: ${err instanceof Error ? err.message : String(err)}
|
|
212
|
+
`);
|
|
213
|
+
});
|
|
214
|
+
const uploadRes = await fetch(`${apiUrl}/v1/document/raw-text`, {
|
|
215
|
+
method: "POST",
|
|
216
|
+
headers: {
|
|
217
|
+
"Content-Type": "application/json",
|
|
218
|
+
Authorization: `Bearer ${apiKey}`
|
|
219
|
+
},
|
|
220
|
+
body: JSON.stringify({
|
|
221
|
+
textContent: section ? existingContent + `
|
|
222
|
+
|
|
223
|
+
## ${section}
|
|
224
|
+
${content}` : existingContent + "\n\n" + content,
|
|
225
|
+
metadata: { title },
|
|
226
|
+
workspaceSlugs: [workspace]
|
|
227
|
+
}),
|
|
228
|
+
signal: AbortSignal.timeout(15e3)
|
|
229
|
+
});
|
|
230
|
+
if (!uploadRes.ok) throw new Error(`Wiki upload failed (${uploadRes.status})`);
|
|
231
|
+
} else {
|
|
232
|
+
const title = params.title ?? "Auto-generated";
|
|
233
|
+
const res = 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: content,
|
|
241
|
+
metadata: { title },
|
|
242
|
+
workspaceSlugs: [workspace]
|
|
243
|
+
}),
|
|
244
|
+
signal: AbortSignal.timeout(15e3)
|
|
245
|
+
});
|
|
246
|
+
if (!res.ok) throw new Error(`Wiki create failed (${res.status})`);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
async function routeToApproval(action, resolvedParams, triggerName) {
|
|
250
|
+
const { createTask } = await import("./lib/tasks.js");
|
|
251
|
+
const { getCoordinatorName } = await import("./lib/employees.js");
|
|
252
|
+
const actionSummary = action.type === "send_whatsapp" ? `Send WhatsApp to ${resolvedParams.to ?? resolvedParams.recipient ?? "unknown"}: "${(resolvedParams.message ?? resolvedParams.text ?? "").slice(0, 100)}"` : `${action.type}: ${JSON.stringify(resolvedParams).slice(0, 200)}`;
|
|
253
|
+
await createTask({
|
|
254
|
+
title: `[Approval Required] ${triggerName}: ${action.type}`,
|
|
255
|
+
assignedTo: getCoordinatorName(),
|
|
256
|
+
assignedBy: "trigger-engine",
|
|
257
|
+
projectName: resolvedParams.project ?? "exe-os",
|
|
258
|
+
priority: "p1",
|
|
259
|
+
context: `Trigger "${triggerName}" wants to execute this action but requires approval.
|
|
260
|
+
|
|
261
|
+
**Action:** ${action.type}
|
|
262
|
+
**Summary:** ${actionSummary}
|
|
263
|
+
**Full params:** ${JSON.stringify(resolvedParams, null, 2)}
|
|
264
|
+
|
|
265
|
+
To approve, manually run the action via MCP tools.`,
|
|
266
|
+
baseDir: process.cwd()
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
async function executeAction(action, record, executor, triggerName) {
|
|
270
|
+
if (executor) {
|
|
271
|
+
return executor(action, record);
|
|
272
|
+
}
|
|
273
|
+
const resolvedParams = {};
|
|
274
|
+
for (const [key, val] of Object.entries(action.params)) {
|
|
275
|
+
resolvedParams[key] = sanitizeParam(substituteTemplate(val, record));
|
|
276
|
+
}
|
|
277
|
+
if (action.requires_approval) {
|
|
278
|
+
try {
|
|
279
|
+
await routeToApproval(action, resolvedParams, triggerName ?? "Unknown trigger");
|
|
280
|
+
return { success: true };
|
|
281
|
+
} catch (err) {
|
|
282
|
+
return {
|
|
283
|
+
success: false,
|
|
284
|
+
error: `Approval routing failed: ${err instanceof Error ? err.message : String(err)}`
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
try {
|
|
289
|
+
switch (action.type) {
|
|
290
|
+
case "send_whatsapp":
|
|
291
|
+
await executeSendWhatsapp(resolvedParams);
|
|
292
|
+
break;
|
|
293
|
+
case "send_message":
|
|
294
|
+
await executeSendMessage(resolvedParams);
|
|
295
|
+
break;
|
|
296
|
+
case "create_task":
|
|
297
|
+
await executeCreateTask(resolvedParams);
|
|
298
|
+
break;
|
|
299
|
+
case "update_wiki":
|
|
300
|
+
await executeUpdateWiki(resolvedParams);
|
|
301
|
+
break;
|
|
302
|
+
case "asana": {
|
|
303
|
+
const { loadAsanaConfig, executeAsanaOperation } = await import("./asana-MRQ2OQMJ.js");
|
|
304
|
+
const asanaConfig = loadAsanaConfig();
|
|
305
|
+
if (!asanaConfig) throw new Error("Asana not configured: set ASANA_API_TOKEN env var");
|
|
306
|
+
const operation = resolvedParams.operation ?? resolvedParams._operation;
|
|
307
|
+
if (!operation) throw new Error("asana action requires 'operation' param");
|
|
308
|
+
await executeAsanaOperation(asanaConfig, operation, resolvedParams);
|
|
309
|
+
break;
|
|
310
|
+
}
|
|
311
|
+
case "mcp_tool":
|
|
312
|
+
console.log(
|
|
313
|
+
`[trigger-engine] mcp_tool action: ${JSON.stringify(resolvedParams)}`
|
|
314
|
+
);
|
|
315
|
+
break;
|
|
316
|
+
}
|
|
317
|
+
return { success: true };
|
|
318
|
+
} catch (err) {
|
|
319
|
+
return {
|
|
320
|
+
success: false,
|
|
321
|
+
error: err instanceof Error ? err.message : String(err)
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
async function processCRMEvent(event, executor, triggersOverride) {
|
|
326
|
+
if (_currentTriggerDepth >= MAX_TRIGGER_DEPTH) {
|
|
327
|
+
console.error(
|
|
328
|
+
`[trigger-engine] Recursion limit (${MAX_TRIGGER_DEPTH}) reached \u2014 skipping event ${event.objectType}.${event.eventType}`
|
|
329
|
+
);
|
|
330
|
+
return [];
|
|
331
|
+
}
|
|
332
|
+
_currentTriggerDepth++;
|
|
333
|
+
try {
|
|
334
|
+
return await _processCRMEventInner(event, executor, triggersOverride);
|
|
335
|
+
} finally {
|
|
336
|
+
_currentTriggerDepth--;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
async function _processCRMEventInner(event, executor, triggersOverride) {
|
|
340
|
+
const eventString = `${event.objectType}.${event.eventType}`;
|
|
341
|
+
const triggers = triggersOverride ?? loadTriggers();
|
|
342
|
+
const logs = [];
|
|
343
|
+
for (const trigger of triggers) {
|
|
344
|
+
if (!trigger.enabled) continue;
|
|
345
|
+
if (trigger.event !== eventString && trigger.event !== "*") continue;
|
|
346
|
+
if (!evaluateConditions(trigger.conditions, event.record)) continue;
|
|
347
|
+
const actionResults = [];
|
|
348
|
+
for (const action of trigger.actions) {
|
|
349
|
+
const result = await executeAction(action, event.record, executor, trigger.name);
|
|
350
|
+
actionResults.push({
|
|
351
|
+
type: action.type,
|
|
352
|
+
success: result.success,
|
|
353
|
+
error: result.error
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
const log = {
|
|
357
|
+
triggerId: trigger.id,
|
|
358
|
+
triggerName: trigger.name,
|
|
359
|
+
event: eventString,
|
|
360
|
+
firedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
361
|
+
actionsExecuted: actionResults
|
|
362
|
+
};
|
|
363
|
+
logs.push(log);
|
|
364
|
+
console.log(
|
|
365
|
+
`[trigger-engine] Fired "${trigger.name}" on ${eventString}: ${actionResults.filter((a) => a.success).length}/${actionResults.length} actions succeeded`
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
return logs;
|
|
369
|
+
}
|
|
370
|
+
function isScheduledTrigger(trigger) {
|
|
371
|
+
return "schedule" in trigger && "query" in trigger;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
export {
|
|
375
|
+
sanitizeParam,
|
|
376
|
+
substituteTemplate,
|
|
377
|
+
loadTriggers,
|
|
378
|
+
createNewTrigger,
|
|
379
|
+
executeAction,
|
|
380
|
+
processCRMEvent,
|
|
381
|
+
isScheduledTrigger
|
|
382
|
+
};
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import {
|
|
2
|
+
storeBehavior
|
|
3
|
+
} from "./chunk-3MTV4FJL.js";
|
|
4
|
+
import {
|
|
5
|
+
getClient
|
|
6
|
+
} from "./chunk-WUKEXVOR.js";
|
|
7
|
+
import {
|
|
8
|
+
loadConfig
|
|
9
|
+
} from "./chunk-T3B5RK4H.js";
|
|
10
|
+
|
|
11
|
+
// src/lib/skill-learning.ts
|
|
12
|
+
import crypto from "crypto";
|
|
13
|
+
var DEFAULT_SKILL_THRESHOLD = 3;
|
|
14
|
+
async function extractTrajectory(taskId, agentId) {
|
|
15
|
+
const client = getClient();
|
|
16
|
+
const result = await client.execute({
|
|
17
|
+
sql: `SELECT tool_name, raw_text
|
|
18
|
+
FROM memories
|
|
19
|
+
WHERE task_id = ? AND agent_id = ?
|
|
20
|
+
ORDER BY timestamp ASC`,
|
|
21
|
+
args: [taskId, agentId]
|
|
22
|
+
});
|
|
23
|
+
if (result.rows.length === 0) return [];
|
|
24
|
+
const rawTools = result.rows.map((r) => {
|
|
25
|
+
const toolName = String(r.tool_name);
|
|
26
|
+
if (toolName === "Bash") {
|
|
27
|
+
const text = String(r.raw_text);
|
|
28
|
+
const cmdMatch = text.match(/(?:command|Command).*?[:\s]+"?(\w+)/);
|
|
29
|
+
return cmdMatch ? `Bash:${cmdMatch[1]}` : "Bash";
|
|
30
|
+
}
|
|
31
|
+
return toolName;
|
|
32
|
+
});
|
|
33
|
+
const signature = [];
|
|
34
|
+
for (const tool of rawTools) {
|
|
35
|
+
if (signature.length === 0 || signature[signature.length - 1] !== tool) {
|
|
36
|
+
signature.push(tool);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return signature;
|
|
40
|
+
}
|
|
41
|
+
function hashSignature(signature) {
|
|
42
|
+
return crypto.createHash("sha256").update(signature.join("|")).digest("hex").slice(0, 16);
|
|
43
|
+
}
|
|
44
|
+
async function storeTrajectory(opts) {
|
|
45
|
+
const client = getClient();
|
|
46
|
+
const id = crypto.randomUUID();
|
|
47
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
48
|
+
const signatureHash = hashSignature(opts.signature);
|
|
49
|
+
await client.execute({
|
|
50
|
+
sql: `INSERT INTO trajectories (id, task_id, agent_id, project_name, task_title, signature, signature_hash, tool_count, created_at)
|
|
51
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
52
|
+
args: [
|
|
53
|
+
id,
|
|
54
|
+
opts.taskId,
|
|
55
|
+
opts.agentId,
|
|
56
|
+
opts.projectName,
|
|
57
|
+
opts.taskTitle,
|
|
58
|
+
JSON.stringify(opts.signature),
|
|
59
|
+
signatureHash,
|
|
60
|
+
opts.signature.length,
|
|
61
|
+
now
|
|
62
|
+
]
|
|
63
|
+
});
|
|
64
|
+
return id;
|
|
65
|
+
}
|
|
66
|
+
async function findSimilarTrajectories(signature, threshold = DEFAULT_SKILL_THRESHOLD) {
|
|
67
|
+
const client = getClient();
|
|
68
|
+
const hash = hashSignature(signature);
|
|
69
|
+
const result = await client.execute({
|
|
70
|
+
sql: `SELECT id, task_id, agent_id, project_name, task_title, signature, signature_hash, tool_count, skill_id, created_at
|
|
71
|
+
FROM trajectories
|
|
72
|
+
WHERE signature_hash = ?
|
|
73
|
+
ORDER BY created_at DESC
|
|
74
|
+
LIMIT 20`,
|
|
75
|
+
args: [hash]
|
|
76
|
+
});
|
|
77
|
+
const mapRow = (r) => ({
|
|
78
|
+
id: String(r.id),
|
|
79
|
+
taskId: String(r.task_id),
|
|
80
|
+
agentId: String(r.agent_id),
|
|
81
|
+
projectName: String(r.project_name),
|
|
82
|
+
taskTitle: String(r.task_title),
|
|
83
|
+
signature: JSON.parse(String(r.signature)),
|
|
84
|
+
signatureHash: String(r.signature_hash),
|
|
85
|
+
toolCount: Number(r.tool_count),
|
|
86
|
+
skillId: r.skill_id ? String(r.skill_id) : null,
|
|
87
|
+
createdAt: String(r.created_at)
|
|
88
|
+
});
|
|
89
|
+
const matches = result.rows.map(mapRow);
|
|
90
|
+
if (matches.length >= threshold) return matches;
|
|
91
|
+
const nearResult = await client.execute({
|
|
92
|
+
sql: `SELECT id, task_id, agent_id, project_name, task_title, signature, signature_hash, tool_count, skill_id, created_at
|
|
93
|
+
FROM trajectories
|
|
94
|
+
WHERE tool_count BETWEEN ? AND ?
|
|
95
|
+
AND signature_hash != ?
|
|
96
|
+
ORDER BY created_at DESC
|
|
97
|
+
LIMIT 50`,
|
|
98
|
+
args: [
|
|
99
|
+
Math.max(1, signature.length - 3),
|
|
100
|
+
signature.length + 3,
|
|
101
|
+
hash
|
|
102
|
+
]
|
|
103
|
+
});
|
|
104
|
+
for (const r of nearResult.rows) {
|
|
105
|
+
const candidateSig = JSON.parse(String(r.signature));
|
|
106
|
+
if (editDistance(signature, candidateSig) <= 2) {
|
|
107
|
+
matches.push(mapRow(r));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return matches;
|
|
111
|
+
}
|
|
112
|
+
async function captureTrajectory(opts) {
|
|
113
|
+
const signature = await extractTrajectory(opts.taskId, opts.agentId);
|
|
114
|
+
if (signature.length < 3) {
|
|
115
|
+
return { trajectoryId: "", similarCount: 0, similar: [] };
|
|
116
|
+
}
|
|
117
|
+
const trajectoryId = await storeTrajectory({
|
|
118
|
+
taskId: opts.taskId,
|
|
119
|
+
agentId: opts.agentId,
|
|
120
|
+
projectName: opts.projectName,
|
|
121
|
+
taskTitle: opts.taskTitle,
|
|
122
|
+
signature
|
|
123
|
+
});
|
|
124
|
+
const similar = await findSimilarTrajectories(
|
|
125
|
+
signature,
|
|
126
|
+
opts.skillThreshold ?? DEFAULT_SKILL_THRESHOLD
|
|
127
|
+
);
|
|
128
|
+
return { trajectoryId, similarCount: similar.length, similar };
|
|
129
|
+
}
|
|
130
|
+
function buildExtractionPrompt(trajectories) {
|
|
131
|
+
const items = trajectories.map((t, i) => {
|
|
132
|
+
const sig = t.signature.join(" \u2192 ");
|
|
133
|
+
return `Task ${i + 1}: "${t.taskTitle}" (${t.agentId}, ${t.projectName}) \u2014 ${t.toolCount} tool calls
|
|
134
|
+
Signature: ${sig}`;
|
|
135
|
+
}).join("\n\n");
|
|
136
|
+
return `You are analyzing ${trajectories.length} completed tasks that followed similar procedures:
|
|
137
|
+
|
|
138
|
+
${items}
|
|
139
|
+
|
|
140
|
+
Extract the reusable procedure. Format your response EXACTLY like this:
|
|
141
|
+
|
|
142
|
+
SKILL: {name \u2014 short, descriptive}
|
|
143
|
+
TRIGGER: {when to use this \u2014 one sentence}
|
|
144
|
+
STEPS:
|
|
145
|
+
1. ...
|
|
146
|
+
2. ...
|
|
147
|
+
PITFALLS: {common mistakes to avoid}
|
|
148
|
+
|
|
149
|
+
Be specific and actionable. Include tool names, file patterns, and concrete commands where applicable.`;
|
|
150
|
+
}
|
|
151
|
+
async function extractSkill(trajectories, model) {
|
|
152
|
+
if (trajectories.length === 0) return null;
|
|
153
|
+
const config = await loadConfig();
|
|
154
|
+
const skillModel = model ?? config.skillModel;
|
|
155
|
+
const Anthropic = (await import("@anthropic-ai/sdk")).default;
|
|
156
|
+
const client = new Anthropic();
|
|
157
|
+
const prompt = buildExtractionPrompt(trajectories);
|
|
158
|
+
const response = await client.messages.create({
|
|
159
|
+
model: skillModel,
|
|
160
|
+
max_tokens: 500,
|
|
161
|
+
messages: [{ role: "user", content: prompt }]
|
|
162
|
+
});
|
|
163
|
+
const textBlock = response.content.find((b) => b.type === "text");
|
|
164
|
+
const skillText = textBlock?.text;
|
|
165
|
+
if (!skillText) return null;
|
|
166
|
+
const agentId = trajectories[0].agentId;
|
|
167
|
+
const projectName = trajectories[0].projectName;
|
|
168
|
+
const skillId = await storeBehavior({
|
|
169
|
+
agentId,
|
|
170
|
+
content: skillText,
|
|
171
|
+
domain: "skill",
|
|
172
|
+
projectName
|
|
173
|
+
});
|
|
174
|
+
const dbClient = getClient();
|
|
175
|
+
for (const t of trajectories) {
|
|
176
|
+
await dbClient.execute({
|
|
177
|
+
sql: "UPDATE trajectories SET skill_id = ? WHERE id = ?",
|
|
178
|
+
args: [skillId, t.id]
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
process.stderr.write(
|
|
182
|
+
`[skill-learning] Skill extracted from ${trajectories.length} trajectories \u2192 behavior ${skillId}
|
|
183
|
+
`
|
|
184
|
+
);
|
|
185
|
+
return skillId;
|
|
186
|
+
}
|
|
187
|
+
async function captureAndLearn(opts) {
|
|
188
|
+
try {
|
|
189
|
+
const config = await loadConfig();
|
|
190
|
+
if (!config.skillLearning) return;
|
|
191
|
+
const { trajectoryId, similarCount, similar } = await captureTrajectory({
|
|
192
|
+
...opts,
|
|
193
|
+
skillThreshold: config.skillThreshold
|
|
194
|
+
});
|
|
195
|
+
if (!trajectoryId) return;
|
|
196
|
+
if (similarCount >= config.skillThreshold) {
|
|
197
|
+
const unprocessed = similar.filter((t) => !t.skillId);
|
|
198
|
+
if (unprocessed.length >= config.skillThreshold) {
|
|
199
|
+
extractSkill(unprocessed, config.skillModel).catch((err) => {
|
|
200
|
+
process.stderr.write(
|
|
201
|
+
`[skill-learning] Extraction failed: ${err instanceof Error ? err.message : String(err)}
|
|
202
|
+
`
|
|
203
|
+
);
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
} catch (err) {
|
|
208
|
+
process.stderr.write(
|
|
209
|
+
`[skill-learning] captureAndLearn failed: ${err instanceof Error ? err.message : String(err)}
|
|
210
|
+
`
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
async function sweepTrajectories(threshold, model) {
|
|
215
|
+
const config = await loadConfig();
|
|
216
|
+
if (!config.skillLearning) return { clustersProcessed: 0, skillsExtracted: 0 };
|
|
217
|
+
const t = threshold ?? config.skillThreshold;
|
|
218
|
+
const client = getClient();
|
|
219
|
+
const result = await client.execute({
|
|
220
|
+
sql: `SELECT signature_hash, COUNT(*) as cnt
|
|
221
|
+
FROM trajectories
|
|
222
|
+
WHERE skill_id IS NULL
|
|
223
|
+
GROUP BY signature_hash
|
|
224
|
+
HAVING cnt >= ?
|
|
225
|
+
ORDER BY cnt DESC
|
|
226
|
+
LIMIT 10`,
|
|
227
|
+
args: [t]
|
|
228
|
+
});
|
|
229
|
+
let clustersProcessed = 0;
|
|
230
|
+
let skillsExtracted = 0;
|
|
231
|
+
for (const row of result.rows) {
|
|
232
|
+
const hash = String(row.signature_hash);
|
|
233
|
+
const trajResult = await client.execute({
|
|
234
|
+
sql: `SELECT id, task_id, agent_id, project_name, task_title, signature, signature_hash, tool_count, created_at
|
|
235
|
+
FROM trajectories
|
|
236
|
+
WHERE signature_hash = ? AND skill_id IS NULL
|
|
237
|
+
ORDER BY created_at DESC
|
|
238
|
+
LIMIT 10`,
|
|
239
|
+
args: [hash]
|
|
240
|
+
});
|
|
241
|
+
const trajectories = trajResult.rows.map((r) => ({
|
|
242
|
+
id: String(r.id),
|
|
243
|
+
taskId: String(r.task_id),
|
|
244
|
+
agentId: String(r.agent_id),
|
|
245
|
+
projectName: String(r.project_name),
|
|
246
|
+
taskTitle: String(r.task_title),
|
|
247
|
+
signature: JSON.parse(String(r.signature)),
|
|
248
|
+
signatureHash: String(r.signature_hash),
|
|
249
|
+
toolCount: Number(r.tool_count),
|
|
250
|
+
skillId: null,
|
|
251
|
+
createdAt: String(r.created_at)
|
|
252
|
+
}));
|
|
253
|
+
if (trajectories.length >= t) {
|
|
254
|
+
clustersProcessed++;
|
|
255
|
+
const skillId = await extractSkill(trajectories, model ?? config.skillModel);
|
|
256
|
+
if (skillId) skillsExtracted++;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return { clustersProcessed, skillsExtracted };
|
|
260
|
+
}
|
|
261
|
+
function editDistance(a, b) {
|
|
262
|
+
const m = a.length;
|
|
263
|
+
const n = b.length;
|
|
264
|
+
const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
|
|
265
|
+
for (let i = 0; i <= m; i++) dp[i][0] = i;
|
|
266
|
+
for (let j = 0; j <= n; j++) dp[0][j] = j;
|
|
267
|
+
for (let i = 1; i <= m; i++) {
|
|
268
|
+
for (let j = 1; j <= n; j++) {
|
|
269
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
270
|
+
dp[i][j] = Math.min(
|
|
271
|
+
dp[i - 1][j] + 1,
|
|
272
|
+
dp[i][j - 1] + 1,
|
|
273
|
+
dp[i - 1][j - 1] + cost
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return dp[m][n];
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export {
|
|
281
|
+
extractTrajectory,
|
|
282
|
+
hashSignature,
|
|
283
|
+
storeTrajectory,
|
|
284
|
+
findSimilarTrajectories,
|
|
285
|
+
captureTrajectory,
|
|
286
|
+
extractSkill,
|
|
287
|
+
captureAndLearn,
|
|
288
|
+
sweepTrajectories,
|
|
289
|
+
editDistance
|
|
290
|
+
};
|