opensentinel 3.1.1 → 3.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +138 -83
- package/dist/agent-manager-JZ4IM7XI.js +39 -0
- package/dist/agent-processor-DDDHC2SO.js +281 -0
- package/dist/agent-processor-DDDHC2SO.js.map +1 -0
- package/dist/agent-types-2T4PXLFQ.js +12 -0
- package/dist/alerting-LK7VVYTX.js +699 -0
- package/dist/alerting-LK7VVYTX.js.map +1 -0
- package/dist/analysis-agent-JWN2GXYE.js +288 -0
- package/dist/analysis-agent-JWN2GXYE.js.map +1 -0
- package/dist/analyzer-OTWE3ARE.js +22 -0
- package/dist/{archiver-AVNBYCKQ.js → archiver-FPGKRP6P.js} +2 -2
- package/dist/{audit-logger-OBPR7CRO.js → audit-logger-CI4WZQPD.js} +6 -5
- package/dist/{auth-UOX5K2BE.js → auth-PH5IHISW.js} +2 -2
- package/dist/{autonomy-ZXDBDQUJ.js → autonomy-N7W5XPLX.js} +4 -3
- package/dist/autonomy-N7W5XPLX.js.map +1 -0
- package/dist/{aws-s3-Q4LLZZPD.js → aws-s3-QZMURYXB.js} +2 -2
- package/dist/{backup-restore-PZ7CYYB7.js → backup-restore-72OQTZO3.js} +2 -2
- package/dist/{blocks-R3PODY47.js → blocks-YOWOESDD.js} +4 -4
- package/dist/bot-VDHBGUVI.js +47 -0
- package/dist/brain-6QTXN4QP.js +66 -0
- package/dist/{camera-monitor-M5CYKUU4.js → camera-monitor-LHTUWHEL.js} +2 -2
- package/dist/{charts-V7ARZNKF.js → charts-FJ32GQK7.js} +2 -2
- package/dist/{chunk-WRAKK6K6.js → chunk-2I5QHYG6.js} +5 -3
- package/dist/chunk-2I5QHYG6.js.map +1 -0
- package/dist/{chunk-TVEWKIK3.js → chunk-2WTKTG2C.js} +2 -2
- package/dist/chunk-3AWAWRWB.js +143 -0
- package/dist/chunk-3AWAWRWB.js.map +1 -0
- package/dist/{chunk-ZLZKF2PM.js → chunk-4KIHDIXZ.js} +43 -2
- package/dist/chunk-4KIHDIXZ.js.map +1 -0
- package/dist/{chunk-EVE7MIIY.js → chunk-4WH6MFEW.js} +15 -16
- package/dist/chunk-4WH6MFEW.js.map +1 -0
- package/dist/{chunk-I6BDYQIG.js → chunk-56UJS2LA.js} +6 -6
- package/dist/chunk-56UJS2LA.js.map +1 -0
- package/dist/chunk-5BTVJR7R.js +37 -0
- package/dist/chunk-5BTVJR7R.js.map +1 -0
- package/dist/chunk-5JJTLWOR.js +1021 -0
- package/dist/chunk-5JJTLWOR.js.map +1 -0
- package/dist/chunk-66SAOZPU.js +236 -0
- package/dist/chunk-66SAOZPU.js.map +1 -0
- package/dist/chunk-6HGMRR4J.js +113 -0
- package/dist/chunk-6HGMRR4J.js.map +1 -0
- package/dist/chunk-6W6PTJFT.js +181 -0
- package/dist/chunk-6W6PTJFT.js.map +1 -0
- package/dist/chunk-6ZNCY2GI.js +418 -0
- package/dist/chunk-6ZNCY2GI.js.map +1 -0
- package/dist/chunk-7BNFELEK.js +31 -0
- package/dist/chunk-7BNFELEK.js.map +1 -0
- package/dist/chunk-ADTDYJO7.js +265 -0
- package/dist/chunk-ADTDYJO7.js.map +1 -0
- package/dist/{chunk-OCVQGBJK.js → chunk-BBN4VCNK.js} +6 -4
- package/dist/chunk-BBN4VCNK.js.map +1 -0
- package/dist/{chunk-SJSUSJ47.js → chunk-BNZHWAZC.js} +2 -2
- package/dist/chunk-C6PELIHS.js +60 -0
- package/dist/chunk-C6PELIHS.js.map +1 -0
- package/dist/{chunk-MQJ2ECQT.js → chunk-CUPEENUY.js} +3 -3
- package/dist/{chunk-NHMBTUMW.js → chunk-CWT6CAE5.js} +2 -2
- package/dist/{chunk-4GLYY4NN.js → chunk-CZTMGHUC.js} +8 -2
- package/dist/chunk-CZTMGHUC.js.map +1 -0
- package/dist/{chunk-RZ4YESBG.js → chunk-DOYGMNMK.js} +1 -1
- package/dist/chunk-DOYGMNMK.js.map +1 -0
- package/dist/chunk-DTISLIMB.js +89 -0
- package/dist/chunk-DTISLIMB.js.map +1 -0
- package/dist/{chunk-SPPMCAKG.js → chunk-GBVJTRXS.js} +2 -2
- package/dist/chunk-GBVJTRXS.js.map +1 -0
- package/dist/{chunk-AYUKPTSM.js → chunk-GJETKBOY.js} +96 -218
- package/dist/chunk-GJETKBOY.js.map +1 -0
- package/dist/{chunk-BXZ6EA52.js → chunk-GW6V4D43.js} +57 -3
- package/dist/chunk-GW6V4D43.js.map +1 -0
- package/dist/{chunk-6PMVAAA7.js → chunk-HJSEEFO3.js} +3 -3
- package/dist/{chunk-TYAGMJNV.js → chunk-HQZQFEAX.js} +5 -5
- package/dist/{chunk-MXAPLSJ5.js → chunk-J4JW73TT.js} +2 -2
- package/dist/{chunk-VEHFVBLI.js → chunk-JHYYFPKX.js} +2 -2
- package/dist/chunk-LFDXEYYB.js +150 -0
- package/dist/chunk-LFDXEYYB.js.map +1 -0
- package/dist/chunk-MIC5IBQF.js +386 -0
- package/dist/chunk-MIC5IBQF.js.map +1 -0
- package/dist/chunk-ODCFS5WD.js +463 -0
- package/dist/chunk-ODCFS5WD.js.map +1 -0
- package/dist/{chunk-XMCVRVTF.js → chunk-P64EV4YY.js} +1 -1
- package/dist/chunk-P64EV4YY.js.map +1 -0
- package/dist/chunk-PBOCSGNL.js +84 -0
- package/dist/chunk-PBOCSGNL.js.map +1 -0
- package/dist/{chunk-66OJ3WB4.js → chunk-PD3CTDO6.js} +2 -2
- package/dist/chunk-QPY3WRVM.js +647 -0
- package/dist/chunk-QPY3WRVM.js.map +1 -0
- package/dist/chunk-S2EOIVF4.js +3907 -0
- package/dist/chunk-S2EOIVF4.js.map +1 -0
- package/dist/chunk-SDLOMKCW.js +213 -0
- package/dist/chunk-SDLOMKCW.js.map +1 -0
- package/dist/chunk-TKBVW7ZJ.js +162 -0
- package/dist/chunk-TKBVW7ZJ.js.map +1 -0
- package/dist/{chunk-BRBWNV65.js → chunk-U2X2J3FI.js} +3 -3
- package/dist/chunk-U2X2J3FI.js.map +1 -0
- package/dist/{chunk-PLDDJCW6.js → chunk-UP2VWCW5.js} +1 -12
- package/dist/{chunk-SVAPX2XN.js → chunk-V3OKHQUX.js} +9 -7
- package/dist/{chunk-SVAPX2XN.js.map → chunk-V3OKHQUX.js.map} +1 -1
- package/dist/{chunk-4UOE5TUZ.js → chunk-WMDVOWN6.js} +4 -4
- package/dist/chunk-WMFYI7XC.js +564 -0
- package/dist/chunk-WMFYI7XC.js.map +1 -0
- package/dist/chunk-WZAH34TG.js +129 -0
- package/dist/chunk-WZAH34TG.js.map +1 -0
- package/dist/{chunk-H5RQOFO2.js → chunk-X6Q3K3L2.js} +6 -6
- package/dist/chunk-X6Q3K3L2.js.map +1 -0
- package/dist/chunk-XTX7EK43.js +134 -0
- package/dist/chunk-XTX7EK43.js.map +1 -0
- package/dist/chunk-YEDEAX6Y.js +194 -0
- package/dist/chunk-YEDEAX6Y.js.map +1 -0
- package/dist/{chunk-XKYRH4FM.js → chunk-ZIBRVA3Y.js} +70 -30
- package/dist/chunk-ZIBRVA3Y.js.map +1 -0
- package/dist/chunk-ZIYTHUM5.js +457 -0
- package/dist/chunk-ZIYTHUM5.js.map +1 -0
- package/dist/{chunk-766ASQWE.js → chunk-ZMML6T63.js} +2711 -2329
- package/dist/chunk-ZMML6T63.js.map +1 -0
- package/dist/chunk-ZVHG4KF2.js +380 -0
- package/dist/chunk-ZVHG4KF2.js.map +1 -0
- package/dist/chunker-K6WTR62A.js +12 -0
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/{client-ZQSFPMOB.js → client-FOIYPOZQ.js} +5 -6
- package/dist/{clipboard-manager-TEO2GEDN.js → clipboard-manager-4SBNESGZ.js} +2 -2
- package/dist/coding-agent-DESSU3AC.js +233 -0
- package/dist/coding-agent-DESSU3AC.js.map +1 -0
- package/dist/commands/setup.js +2 -2
- package/dist/commands/start.js +3 -3
- package/dist/commands/status.js +2 -2
- package/dist/commands/stop.js +2 -2
- package/dist/commands/utils.js +2 -2
- package/dist/cost-tracker-KZQSTSE2.js +11 -0
- package/dist/{cron-explain-HHQKPD3M.js → cron-explain-UOOOYWZZ.js} +2 -2
- package/dist/{crypto-4AP47IKC.js → crypto-2VG3RJR2.js} +2 -2
- package/dist/{databases-37X4CI2Y.js → databases-XDPMG5AV.js} +4 -4
- package/dist/db-I7MNG6CL.js +83 -0
- package/dist/discord-6UQHCN27.js +81 -0
- package/dist/documents-PFHSK7SZ.js +184 -0
- package/dist/documents-PFHSK7SZ.js.map +1 -0
- package/dist/docx-parser-EXL4TN5E.js +16 -0
- package/dist/{email-K7LO2IPB.js → email-6OIN4SYL.js} +34 -25
- package/dist/email-6OIN4SYL.js.map +1 -0
- package/dist/{enhanced-retrieval-DNLLEM4Z.js → enhanced-retrieval-JWX2HWU4.js} +12 -8
- package/dist/{enhanced-retrieval-DNLLEM4Z.js.map → enhanced-retrieval-JWX2HWU4.js.map} +1 -1
- package/dist/enrichment-pipeline-7FE5R5ZI.js +14 -0
- package/dist/{entity-resolution-Y3IUWEAT.js → entity-resolution-7Z6STVXX.js} +6 -5
- package/dist/env-GN5VHI43.js +12 -0
- package/dist/error-tracker-64DEH3D7.js +32 -0
- package/dist/finnhub-X7ZMQSXF.js +178 -0
- package/dist/finnhub-X7ZMQSXF.js.map +1 -0
- package/dist/fred-TMUF3J2V.js +203 -0
- package/dist/fred-TMUF3J2V.js.map +1 -0
- package/dist/github-DUWSXCNP.js +833 -0
- package/dist/github-DUWSXCNP.js.map +1 -0
- package/dist/{google-workspace-DKWUVNGC.js → google-workspace-TSZPZK5G.js} +2 -2
- package/dist/graph-client-NB475AK5.js +17 -0
- package/dist/{hash-tool-ULQYD7B5.js → hash-tool-ENAB5LWH.js} +2 -2
- package/dist/{heartbeat-monitor-GCISLXI3.js → heartbeat-monitor-KRDYTDBF.js} +2 -2
- package/dist/hooks-N4MIFBVM.js +14 -0
- package/dist/{image-generation-OSU7FP6F.js → image-generation-MDE6AVQO.js} +2 -2
- package/dist/imessage-DSGSGUZS.js +44 -0
- package/dist/inbox-summarizer-F2KAU72V.js +56 -0
- package/dist/{incident-response-C5J7Q6DT.js → incident-response-E3UGMX5G.js} +8 -6
- package/dist/incident-response-E3UGMX5G.js.map +1 -0
- package/dist/{inventory-manager-352OHXWD.js → inventory-manager-C67BSZM6.js} +2 -2
- package/dist/{jira-GSGDBMIG.js → jira-PAGZWUBJ.js} +2 -2
- package/dist/{json-tool-QE2SYHEG.js → json-tool-4FK5RNER.js} +2 -2
- package/dist/{key-rotation-DPHU4ZTB.js → key-rotation-WCC5FOYS.js} +2 -2
- package/dist/knowledge-base-5SMMOGQJ.js +46 -0
- package/dist/lib.d.ts +94 -1
- package/dist/lib.js +83 -66
- package/dist/lib.js.map +1 -1
- package/dist/{mailchimp-KKNF6QJ7.js → mailchimp-ZFYDC44J.js} +2 -2
- package/dist/{matrix-QVHG76I7.js → matrix-WYGEOZL5.js} +30 -21
- package/dist/{matrix-QVHG76I7.js.map → matrix-WYGEOZL5.js.map} +1 -1
- package/dist/{mcp-3JI6W7ZE.js → mcp-DJ2QDA6A.js} +3 -3
- package/dist/metrics-BH3ZLGEV.js +25 -0
- package/dist/{microsoft365-UCBKJHNX.js → microsoft365-6G2IJMWC.js} +2 -2
- package/dist/multi-user-XAEMB244.js +411 -0
- package/dist/multi-user-XAEMB244.js.map +1 -0
- package/dist/oauth-UPJYFOVU.js +34 -0
- package/dist/{ocr-AC7NPX33.js → ocr-UONKTQU7.js} +6 -4
- package/dist/{ollama-BOAMSPLJ.js → ollama-J7CU45WT.js} +2 -2
- package/dist/osint-agent-RL5XPBRQ.js +189 -0
- package/dist/osint-agent-RL5XPBRQ.js.map +1 -0
- package/dist/{pages-MI523RB7.js → pages-XDE7JRCA.js} +5 -5
- package/dist/{pair-JDFTERIK.js → pair-YZJFQUU5.js} +2 -2
- package/dist/{pairing-IFQYCPNS.js → pairing-77N47RAT.js} +2 -2
- package/dist/{pdf-ALQVOEJR.js → pdf-67HGXCFJ.js} +3 -3
- package/dist/pdf-parser-YLMTTYHL.js +14 -0
- package/dist/{presentations-DSV5IHG5.js → presentations-UOET2FVZ.js} +3 -3
- package/dist/presentations-UOET2FVZ.js.map +1 -0
- package/dist/{prometheus-JNT2BD4L.js → prometheus-YETCZO4I.js} +2 -2
- package/dist/prometheus-YETCZO4I.js.map +1 -0
- package/dist/{providers-J4LYPHDR.js → providers-2YQ6E3IF.js} +6 -4
- package/dist/providers-2YQ6E3IF.js.map +1 -0
- package/dist/{qr-code-WIX4PB4U.js → qr-code-6WZJHRKL.js} +2 -2
- package/dist/qr-code-6WZJHRKL.js.map +1 -0
- package/dist/{quickbooks-XB4NII2S.js → quickbooks-N675W7IK.js} +2 -2
- package/dist/{regex-tool-W4ABRKGK.js → regex-tool-6Q63LQ7B.js} +2 -2
- package/dist/regex-tool-6Q63LQ7B.js.map +1 -0
- package/dist/research-agent-WCRSY3UZ.js +168 -0
- package/dist/research-agent-WCRSY3UZ.js.map +1 -0
- package/dist/risk-engine-YKCPT5D5.js +10 -0
- package/dist/risk-engine-YKCPT5D5.js.map +1 -0
- package/dist/scheduler-6PLLAQI7.js +74 -0
- package/dist/scheduler-6PLLAQI7.js.map +1 -0
- package/dist/schema-ETY7L2VA.js +78 -0
- package/dist/schema-ETY7L2VA.js.map +1 -0
- package/dist/{search-BCLBO5E3.js → search-GMLKBHSW.js} +4 -4
- package/dist/search-GMLKBHSW.js.map +1 -0
- package/dist/{sendgrid-RNXCAFKM.js → sendgrid-QGJIVPWV.js} +2 -2
- package/dist/sharepoint-V5P4Q62L.js +30 -0
- package/dist/sharepoint-V5P4Q62L.js.map +1 -0
- package/dist/{shopify-NCXYJB4R.js → shopify-ON2PAU27.js} +2 -2
- package/dist/signal-7D5EPGVL.js +44 -0
- package/dist/signal-7D5EPGVL.js.map +1 -0
- package/dist/slack-KSS6YK5Z.js +86 -0
- package/dist/slack-KSS6YK5Z.js.map +1 -0
- package/dist/{sms-M3JIOTCW.js → sms-CSUCC7HL.js} +4 -4
- package/dist/sms-CSUCC7HL.js.map +1 -0
- package/dist/{src-VYUE6LRA.js → src-GO7GGW7O.js} +190 -52
- package/dist/src-GO7GGW7O.js.map +1 -0
- package/dist/{stocks-XXWBPOCU.js → stocks-4M4HZWZS.js} +2 -2
- package/dist/stocks-4M4HZWZS.js.map +1 -0
- package/dist/text-extractor-OAUBAW5P.js +12 -0
- package/dist/text-extractor-OAUBAW5P.js.map +1 -0
- package/dist/{text-transform-6SGUA5Z4.js → text-transform-HCLCUDFZ.js} +2 -2
- package/dist/text-transform-HCLCUDFZ.js.map +1 -0
- package/dist/token-store-SEWRX6RE.js +20 -0
- package/dist/token-store-SEWRX6RE.js.map +1 -0
- package/dist/tools-PJZ6RI4P.js +47 -0
- package/dist/tools-PJZ6RI4P.js.map +1 -0
- package/dist/{tunnel-IWMXUML4.js → tunnel-XOUVVRAK.js} +4 -2
- package/dist/tunnel-XOUVVRAK.js.map +1 -0
- package/dist/{twilio-53GEW5JT.js → twilio-3L7DUNYQ.js} +2 -2
- package/dist/{unit-converter-ZYXMEZOE.js → unit-converter-LYPAHU64.js} +2 -2
- package/dist/unit-converter-LYPAHU64.js.map +1 -0
- package/dist/whatsapp-DWXK25V2.js +44 -0
- package/dist/whatsapp-DWXK25V2.js.map +1 -0
- package/dist/{word-document-7B6SJMAY.js → word-document-AV3YB4L2.js} +4 -4
- package/dist/word-document-AV3YB4L2.js.map +1 -0
- package/dist/workflow-store-5Y56GUP7.js +373 -0
- package/dist/workflow-store-5Y56GUP7.js.map +1 -0
- package/dist/writing-agent-VDGLNOGO.js +243 -0
- package/dist/writing-agent-VDGLNOGO.js.map +1 -0
- package/dist/{xero-QYO66D45.js → xero-UHAHVYSD.js} +2 -2
- package/dist/{zapier-webhook-TBZ5YF2A.js → zapier-webhook-NIELLTXR.js} +2 -2
- package/drizzle/0002_mushy_master_mold.sql +139 -139
- package/drizzle/0003_overjoyed_rhodey.sql +46 -0
- package/drizzle/meta/0002_snapshot.json +3636 -3636
- package/drizzle/meta/0003_snapshot.json +3946 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +110 -100
- package/dist/autonomy-ZXDBDQUJ.js.map +0 -1
- package/dist/bot-QRARP4UN.js +0 -36
- package/dist/brain-7XLLM3KC.js +0 -56
- package/dist/chunk-4GLYY4NN.js.map +0 -1
- package/dist/chunk-766ASQWE.js.map +0 -1
- package/dist/chunk-AYUKPTSM.js.map +0 -1
- package/dist/chunk-BRBWNV65.js.map +0 -1
- package/dist/chunk-BXZ6EA52.js.map +0 -1
- package/dist/chunk-EVE7MIIY.js.map +0 -1
- package/dist/chunk-H5RQOFO2.js.map +0 -1
- package/dist/chunk-I6BDYQIG.js.map +0 -1
- package/dist/chunk-IZJMVV7O.js +0 -347
- package/dist/chunk-IZJMVV7O.js.map +0 -1
- package/dist/chunk-O7IH7JTI.js +0 -1898
- package/dist/chunk-O7IH7JTI.js.map +0 -1
- package/dist/chunk-OCVQGBJK.js.map +0 -1
- package/dist/chunk-RZ4YESBG.js.map +0 -1
- package/dist/chunk-SPPMCAKG.js.map +0 -1
- package/dist/chunk-VRD5CYRL.js +0 -1568
- package/dist/chunk-VRD5CYRL.js.map +0 -1
- package/dist/chunk-WRAKK6K6.js.map +0 -1
- package/dist/chunk-XKYRH4FM.js.map +0 -1
- package/dist/chunk-XMCVRVTF.js.map +0 -1
- package/dist/chunk-ZLZKF2PM.js.map +0 -1
- package/dist/discord-B3HUPGQ6.js +0 -70
- package/dist/dist-UISMLMFN.js +0 -21847
- package/dist/dist-UISMLMFN.js.map +0 -1
- package/dist/email-K7LO2IPB.js.map +0 -1
- package/dist/enrichment-pipeline-MNHNW65K.js +0 -13
- package/dist/env-IWXUVTCB.js +0 -12
- package/dist/imessage-NGA2XF2V.js +0 -35
- package/dist/inbox-summarizer-NRI4S7IF.js +0 -47
- package/dist/incident-response-C5J7Q6DT.js.map +0 -1
- package/dist/presentations-DSV5IHG5.js.map +0 -1
- package/dist/scheduler-VK4WFERV.js +0 -63
- package/dist/signal-6CGDFYL2.js +0 -35
- package/dist/slack-IZQWIKOH.js +0 -75
- package/dist/src-VYUE6LRA.js.map +0 -1
- package/dist/tools-2RLEI2N6.js +0 -38
- package/dist/tunnel-IWMXUML4.js.map +0 -1
- package/dist/whatsapp-LFX6YKCM.js +0 -35
- package/dist/word-document-7B6SJMAY.js.map +0 -1
- /package/dist/{audit-logger-OBPR7CRO.js.map → agent-manager-JZ4IM7XI.js.map} +0 -0
- /package/dist/{auth-UOX5K2BE.js.map → agent-types-2T4PXLFQ.js.map} +0 -0
- /package/dist/{backup-restore-PZ7CYYB7.js.map → analyzer-OTWE3ARE.js.map} +0 -0
- /package/dist/{archiver-AVNBYCKQ.js.map → archiver-FPGKRP6P.js.map} +0 -0
- /package/dist/{blocks-R3PODY47.js.map → audit-logger-CI4WZQPD.js.map} +0 -0
- /package/dist/{bot-QRARP4UN.js.map → auth-PH5IHISW.js.map} +0 -0
- /package/dist/{aws-s3-Q4LLZZPD.js.map → aws-s3-QZMURYXB.js.map} +0 -0
- /package/dist/{brain-7XLLM3KC.js.map → backup-restore-72OQTZO3.js.map} +0 -0
- /package/dist/{chunk-PLDDJCW6.js.map → blocks-YOWOESDD.js.map} +0 -0
- /package/dist/{client-ZQSFPMOB.js.map → bot-VDHBGUVI.js.map} +0 -0
- /package/dist/{clipboard-manager-TEO2GEDN.js.map → brain-6QTXN4QP.js.map} +0 -0
- /package/dist/{camera-monitor-M5CYKUU4.js.map → camera-monitor-LHTUWHEL.js.map} +0 -0
- /package/dist/{charts-V7ARZNKF.js.map → charts-FJ32GQK7.js.map} +0 -0
- /package/dist/{chunk-TVEWKIK3.js.map → chunk-2WTKTG2C.js.map} +0 -0
- /package/dist/{chunk-SJSUSJ47.js.map → chunk-BNZHWAZC.js.map} +0 -0
- /package/dist/{chunk-MQJ2ECQT.js.map → chunk-CUPEENUY.js.map} +0 -0
- /package/dist/{chunk-NHMBTUMW.js.map → chunk-CWT6CAE5.js.map} +0 -0
- /package/dist/{chunk-6PMVAAA7.js.map → chunk-HJSEEFO3.js.map} +0 -0
- /package/dist/{chunk-TYAGMJNV.js.map → chunk-HQZQFEAX.js.map} +0 -0
- /package/dist/{chunk-MXAPLSJ5.js.map → chunk-J4JW73TT.js.map} +0 -0
- /package/dist/{chunk-VEHFVBLI.js.map → chunk-JHYYFPKX.js.map} +0 -0
- /package/dist/{chunk-66OJ3WB4.js.map → chunk-PD3CTDO6.js.map} +0 -0
- /package/dist/{cron-explain-HHQKPD3M.js.map → chunk-UP2VWCW5.js.map} +0 -0
- /package/dist/{chunk-4UOE5TUZ.js.map → chunk-WMDVOWN6.js.map} +0 -0
- /package/dist/{crypto-4AP47IKC.js.map → chunker-K6WTR62A.js.map} +0 -0
- /package/dist/{databases-37X4CI2Y.js.map → client-FOIYPOZQ.js.map} +0 -0
- /package/dist/{discord-B3HUPGQ6.js.map → clipboard-manager-4SBNESGZ.js.map} +0 -0
- /package/dist/{enrichment-pipeline-MNHNW65K.js.map → cost-tracker-KZQSTSE2.js.map} +0 -0
- /package/dist/{entity-resolution-Y3IUWEAT.js.map → cron-explain-UOOOYWZZ.js.map} +0 -0
- /package/dist/{env-IWXUVTCB.js.map → crypto-2VG3RJR2.js.map} +0 -0
- /package/dist/{hash-tool-ULQYD7B5.js.map → databases-XDPMG5AV.js.map} +0 -0
- /package/dist/{heartbeat-monitor-GCISLXI3.js.map → db-I7MNG6CL.js.map} +0 -0
- /package/dist/{imessage-NGA2XF2V.js.map → discord-6UQHCN27.js.map} +0 -0
- /package/dist/{inbox-summarizer-NRI4S7IF.js.map → docx-parser-EXL4TN5E.js.map} +0 -0
- /package/dist/{inventory-manager-352OHXWD.js.map → enrichment-pipeline-7FE5R5ZI.js.map} +0 -0
- /package/dist/{json-tool-QE2SYHEG.js.map → entity-resolution-7Z6STVXX.js.map} +0 -0
- /package/dist/{key-rotation-DPHU4ZTB.js.map → env-GN5VHI43.js.map} +0 -0
- /package/dist/{mcp-3JI6W7ZE.js.map → error-tracker-64DEH3D7.js.map} +0 -0
- /package/dist/{google-workspace-DKWUVNGC.js.map → google-workspace-TSZPZK5G.js.map} +0 -0
- /package/dist/{ocr-AC7NPX33.js.map → graph-client-NB475AK5.js.map} +0 -0
- /package/dist/{ollama-BOAMSPLJ.js.map → hash-tool-ENAB5LWH.js.map} +0 -0
- /package/dist/{pages-MI523RB7.js.map → heartbeat-monitor-KRDYTDBF.js.map} +0 -0
- /package/dist/{pairing-IFQYCPNS.js.map → hooks-N4MIFBVM.js.map} +0 -0
- /package/dist/{image-generation-OSU7FP6F.js.map → image-generation-MDE6AVQO.js.map} +0 -0
- /package/dist/{pdf-ALQVOEJR.js.map → imessage-DSGSGUZS.js.map} +0 -0
- /package/dist/{prometheus-JNT2BD4L.js.map → inbox-summarizer-F2KAU72V.js.map} +0 -0
- /package/dist/{providers-J4LYPHDR.js.map → inventory-manager-C67BSZM6.js.map} +0 -0
- /package/dist/{jira-GSGDBMIG.js.map → jira-PAGZWUBJ.js.map} +0 -0
- /package/dist/{qr-code-WIX4PB4U.js.map → json-tool-4FK5RNER.js.map} +0 -0
- /package/dist/{regex-tool-W4ABRKGK.js.map → key-rotation-WCC5FOYS.js.map} +0 -0
- /package/dist/{scheduler-VK4WFERV.js.map → knowledge-base-5SMMOGQJ.js.map} +0 -0
- /package/dist/{mailchimp-KKNF6QJ7.js.map → mailchimp-ZFYDC44J.js.map} +0 -0
- /package/dist/{search-BCLBO5E3.js.map → mcp-DJ2QDA6A.js.map} +0 -0
- /package/dist/{signal-6CGDFYL2.js.map → metrics-BH3ZLGEV.js.map} +0 -0
- /package/dist/{microsoft365-UCBKJHNX.js.map → microsoft365-6G2IJMWC.js.map} +0 -0
- /package/dist/{slack-IZQWIKOH.js.map → oauth-UPJYFOVU.js.map} +0 -0
- /package/dist/{sms-M3JIOTCW.js.map → ocr-UONKTQU7.js.map} +0 -0
- /package/dist/{stocks-XXWBPOCU.js.map → ollama-J7CU45WT.js.map} +0 -0
- /package/dist/{text-transform-6SGUA5Z4.js.map → pages-XDE7JRCA.js.map} +0 -0
- /package/dist/{pair-JDFTERIK.js.map → pair-YZJFQUU5.js.map} +0 -0
- /package/dist/{tools-2RLEI2N6.js.map → pairing-77N47RAT.js.map} +0 -0
- /package/dist/{unit-converter-ZYXMEZOE.js.map → pdf-67HGXCFJ.js.map} +0 -0
- /package/dist/{whatsapp-LFX6YKCM.js.map → pdf-parser-YLMTTYHL.js.map} +0 -0
- /package/dist/{quickbooks-XB4NII2S.js.map → quickbooks-N675W7IK.js.map} +0 -0
- /package/dist/{sendgrid-RNXCAFKM.js.map → sendgrid-QGJIVPWV.js.map} +0 -0
- /package/dist/{shopify-NCXYJB4R.js.map → shopify-ON2PAU27.js.map} +0 -0
- /package/dist/{twilio-53GEW5JT.js.map → twilio-3L7DUNYQ.js.map} +0 -0
- /package/dist/{xero-QYO66D45.js.map → xero-UHAHVYSD.js.map} +0 -0
- /package/dist/{zapier-webhook-TBZ5YF2A.js.map → zapier-webhook-NIELLTXR.js.map} +0 -0
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
// src/core/intelligence/risk-engine.ts
|
|
2
|
+
var DEFAULT_CONFIG = {
|
|
3
|
+
maxCostPerRequest: 5,
|
|
4
|
+
maxCostPerHour: 50,
|
|
5
|
+
maxCostPerDay: 200,
|
|
6
|
+
maxToolsPerMinute: 30,
|
|
7
|
+
maxToolsPerHour: 500,
|
|
8
|
+
maxMessagesPerMinute: 60,
|
|
9
|
+
blockedTools: [],
|
|
10
|
+
blockedPatterns: [],
|
|
11
|
+
safeMode: false,
|
|
12
|
+
killSwitch: false,
|
|
13
|
+
customChecks: [],
|
|
14
|
+
maxTradeSize: 100,
|
|
15
|
+
maxDailyTradeSpend: 500,
|
|
16
|
+
maxTradesPerHour: 5
|
|
17
|
+
};
|
|
18
|
+
var costTracker = {
|
|
19
|
+
hourly: /* @__PURE__ */ new Map(),
|
|
20
|
+
daily: /* @__PURE__ */ new Map()
|
|
21
|
+
};
|
|
22
|
+
var rateTracker = /* @__PURE__ */ new Map();
|
|
23
|
+
var tradeSpendTracker = {
|
|
24
|
+
daily: /* @__PURE__ */ new Map(),
|
|
25
|
+
hourlyCount: /* @__PURE__ */ new Map()
|
|
26
|
+
};
|
|
27
|
+
var auditLog = [];
|
|
28
|
+
var RiskEngine = class {
|
|
29
|
+
config;
|
|
30
|
+
checks = [];
|
|
31
|
+
constructor(config = {}) {
|
|
32
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
33
|
+
this.initializeBuiltInChecks();
|
|
34
|
+
this.checks.push(...this.config.customChecks);
|
|
35
|
+
}
|
|
36
|
+
initializeBuiltInChecks() {
|
|
37
|
+
this.checks.push({
|
|
38
|
+
name: "kill_switch",
|
|
39
|
+
description: "Emergency kill switch - blocks all actions",
|
|
40
|
+
severity: "critical",
|
|
41
|
+
check: () => !this.config.killSwitch,
|
|
42
|
+
failMessage: "Kill switch is active. All actions are blocked."
|
|
43
|
+
});
|
|
44
|
+
this.checks.push({
|
|
45
|
+
name: "safe_mode",
|
|
46
|
+
description: "Safe mode restricts to read-only operations",
|
|
47
|
+
severity: "high",
|
|
48
|
+
check: (ctx) => {
|
|
49
|
+
if (!this.config.safeMode) return true;
|
|
50
|
+
const readOnlyActions = [
|
|
51
|
+
"read",
|
|
52
|
+
"search",
|
|
53
|
+
"list",
|
|
54
|
+
"get",
|
|
55
|
+
"query",
|
|
56
|
+
"analyze",
|
|
57
|
+
"view"
|
|
58
|
+
];
|
|
59
|
+
return readOnlyActions.some(
|
|
60
|
+
(a) => ctx.action.toLowerCase().includes(a)
|
|
61
|
+
);
|
|
62
|
+
},
|
|
63
|
+
failMessage: "Safe mode is active. Only read-only operations are allowed."
|
|
64
|
+
});
|
|
65
|
+
this.checks.push({
|
|
66
|
+
name: "blocked_tools",
|
|
67
|
+
description: "Prevents execution of blocked tools",
|
|
68
|
+
severity: "high",
|
|
69
|
+
check: (ctx) => !ctx.toolName || !this.config.blockedTools.includes(ctx.toolName),
|
|
70
|
+
failMessage: "This tool is blocked by the risk policy."
|
|
71
|
+
});
|
|
72
|
+
this.checks.push({
|
|
73
|
+
name: "blocked_patterns",
|
|
74
|
+
description: "Prevents actions matching blocked patterns",
|
|
75
|
+
severity: "high",
|
|
76
|
+
check: (ctx) => {
|
|
77
|
+
const inputStr = JSON.stringify(ctx.input || {});
|
|
78
|
+
return !this.config.blockedPatterns.some(
|
|
79
|
+
(pattern) => new RegExp(pattern, "i").test(inputStr)
|
|
80
|
+
);
|
|
81
|
+
},
|
|
82
|
+
failMessage: "Input matches a blocked pattern."
|
|
83
|
+
});
|
|
84
|
+
this.checks.push({
|
|
85
|
+
name: "cost_per_request",
|
|
86
|
+
description: "Limits cost per individual request",
|
|
87
|
+
severity: "medium",
|
|
88
|
+
check: (ctx) => !ctx.estimatedCost || ctx.estimatedCost <= this.config.maxCostPerRequest,
|
|
89
|
+
failMessage: `Request exceeds maximum cost of $${this.config.maxCostPerRequest}.`
|
|
90
|
+
});
|
|
91
|
+
this.checks.push({
|
|
92
|
+
name: "hourly_cost_limit",
|
|
93
|
+
description: "Limits total cost per hour",
|
|
94
|
+
severity: "high",
|
|
95
|
+
check: (ctx) => {
|
|
96
|
+
const key = ctx.userId || "global";
|
|
97
|
+
const now = Date.now();
|
|
98
|
+
const hourMs = 3600 * 1e3;
|
|
99
|
+
const entry = costTracker.hourly.get(key);
|
|
100
|
+
if (!entry || now - entry.windowStart > hourMs) {
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
return entry.total + (ctx.estimatedCost || 0) <= this.config.maxCostPerHour;
|
|
104
|
+
},
|
|
105
|
+
failMessage: `Hourly cost limit of $${this.config.maxCostPerHour} exceeded.`
|
|
106
|
+
});
|
|
107
|
+
this.checks.push({
|
|
108
|
+
name: "daily_cost_limit",
|
|
109
|
+
description: "Limits total cost per day",
|
|
110
|
+
severity: "high",
|
|
111
|
+
check: (ctx) => {
|
|
112
|
+
const key = ctx.userId || "global";
|
|
113
|
+
const now = Date.now();
|
|
114
|
+
const dayMs = 86400 * 1e3;
|
|
115
|
+
const entry = costTracker.daily.get(key);
|
|
116
|
+
if (!entry || now - entry.windowStart > dayMs) {
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
return entry.total + (ctx.estimatedCost || 0) <= this.config.maxCostPerDay;
|
|
120
|
+
},
|
|
121
|
+
failMessage: `Daily cost limit of $${this.config.maxCostPerDay} exceeded.`
|
|
122
|
+
});
|
|
123
|
+
this.checks.push({
|
|
124
|
+
name: "tool_rate_limit_minute",
|
|
125
|
+
description: "Limits tool executions per minute",
|
|
126
|
+
severity: "medium",
|
|
127
|
+
check: (ctx) => {
|
|
128
|
+
if (!ctx.toolName) return true;
|
|
129
|
+
return this.checkRate(
|
|
130
|
+
`tool:${ctx.userId || "global"}`,
|
|
131
|
+
60 * 1e3,
|
|
132
|
+
this.config.maxToolsPerMinute
|
|
133
|
+
);
|
|
134
|
+
},
|
|
135
|
+
failMessage: `Tool execution rate limit exceeded (${this.config.maxToolsPerMinute}/min).`
|
|
136
|
+
});
|
|
137
|
+
this.checks.push({
|
|
138
|
+
name: "tool_rate_limit_hour",
|
|
139
|
+
description: "Limits tool executions per hour",
|
|
140
|
+
severity: "medium",
|
|
141
|
+
check: (ctx) => {
|
|
142
|
+
if (!ctx.toolName) return true;
|
|
143
|
+
return this.checkRate(
|
|
144
|
+
`tool_hourly:${ctx.userId || "global"}`,
|
|
145
|
+
3600 * 1e3,
|
|
146
|
+
this.config.maxToolsPerHour
|
|
147
|
+
);
|
|
148
|
+
},
|
|
149
|
+
failMessage: `Tool execution hourly limit exceeded (${this.config.maxToolsPerHour}/hr).`
|
|
150
|
+
});
|
|
151
|
+
this.checks.push({
|
|
152
|
+
name: "message_rate_limit",
|
|
153
|
+
description: "Limits messages per minute",
|
|
154
|
+
severity: "medium",
|
|
155
|
+
check: (ctx) => {
|
|
156
|
+
if (ctx.action !== "send_message") return true;
|
|
157
|
+
return this.checkRate(
|
|
158
|
+
`msg:${ctx.userId || "global"}`,
|
|
159
|
+
60 * 1e3,
|
|
160
|
+
this.config.maxMessagesPerMinute
|
|
161
|
+
);
|
|
162
|
+
},
|
|
163
|
+
failMessage: `Message rate limit exceeded (${this.config.maxMessagesPerMinute}/min).`
|
|
164
|
+
});
|
|
165
|
+
this.checks.push({
|
|
166
|
+
name: "command_injection",
|
|
167
|
+
description: "Prevents command injection in tool inputs",
|
|
168
|
+
severity: "critical",
|
|
169
|
+
check: (ctx) => {
|
|
170
|
+
if (!ctx.input) return true;
|
|
171
|
+
const dangerousPatterns = [
|
|
172
|
+
/;\s*(rm|del|format|mkfs|dd)\s/i,
|
|
173
|
+
/\|\s*(bash|sh|cmd|powershell)/i,
|
|
174
|
+
/`[^`]*`/,
|
|
175
|
+
/\$\([^)]*\)/,
|
|
176
|
+
/>\s*\/dev\//i
|
|
177
|
+
];
|
|
178
|
+
const inputStr = JSON.stringify(ctx.input);
|
|
179
|
+
return !dangerousPatterns.some((p) => p.test(inputStr));
|
|
180
|
+
},
|
|
181
|
+
failMessage: "Potential command injection detected in input."
|
|
182
|
+
});
|
|
183
|
+
this.checks.push({
|
|
184
|
+
name: "sensitive_data",
|
|
185
|
+
description: "Prevents leaking sensitive data patterns",
|
|
186
|
+
severity: "high",
|
|
187
|
+
check: (ctx) => {
|
|
188
|
+
if (!ctx.input) return true;
|
|
189
|
+
const sensitivePatterns = [
|
|
190
|
+
/\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b/,
|
|
191
|
+
// credit card
|
|
192
|
+
/\b\d{3}-\d{2}-\d{4}\b/,
|
|
193
|
+
// SSN
|
|
194
|
+
/-----BEGIN\s+(RSA\s+)?PRIVATE\s+KEY-----/
|
|
195
|
+
// private key
|
|
196
|
+
];
|
|
197
|
+
const inputStr = JSON.stringify(ctx.input);
|
|
198
|
+
return !sensitivePatterns.some((p) => p.test(inputStr));
|
|
199
|
+
},
|
|
200
|
+
failMessage: "Sensitive data pattern detected in input."
|
|
201
|
+
});
|
|
202
|
+
this.checks.push({
|
|
203
|
+
name: "trade_size_limit",
|
|
204
|
+
description: "Blocks orders exceeding maximum single trade size",
|
|
205
|
+
severity: "critical",
|
|
206
|
+
check: (ctx) => {
|
|
207
|
+
if (ctx.toolName !== "crypto_exchange") return true;
|
|
208
|
+
const input = ctx.input || {};
|
|
209
|
+
if (input.action !== "place_order") return true;
|
|
210
|
+
const estimatedTotal = input._estimatedTotal || 0;
|
|
211
|
+
if (estimatedTotal <= 0) return true;
|
|
212
|
+
return estimatedTotal <= this.config.maxTradeSize;
|
|
213
|
+
},
|
|
214
|
+
failMessage: `Trade exceeds maximum single order size of $${this.config.maxTradeSize}.`
|
|
215
|
+
});
|
|
216
|
+
this.checks.push({
|
|
217
|
+
name: "daily_trade_spend_limit",
|
|
218
|
+
description: "Blocks when daily trade spending cap exceeded",
|
|
219
|
+
severity: "critical",
|
|
220
|
+
check: (ctx) => {
|
|
221
|
+
if (ctx.toolName !== "crypto_exchange") return true;
|
|
222
|
+
const input = ctx.input || {};
|
|
223
|
+
if (input.action !== "place_order") return true;
|
|
224
|
+
const estimatedTotal = input._estimatedTotal || 0;
|
|
225
|
+
if (estimatedTotal <= 0) return true;
|
|
226
|
+
const key = ctx.userId || "global";
|
|
227
|
+
const now = Date.now();
|
|
228
|
+
const dayMs = 86400 * 1e3;
|
|
229
|
+
const entry = tradeSpendTracker.daily.get(key);
|
|
230
|
+
if (!entry || now - entry.windowStart > dayMs) {
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
return entry.total + estimatedTotal <= this.config.maxDailyTradeSpend;
|
|
234
|
+
},
|
|
235
|
+
failMessage: `Daily trade spend limit of $${this.config.maxDailyTradeSpend} exceeded.`
|
|
236
|
+
});
|
|
237
|
+
this.checks.push({
|
|
238
|
+
name: "trade_rate_limit",
|
|
239
|
+
description: "Blocks when hourly trade count exceeded",
|
|
240
|
+
severity: "high",
|
|
241
|
+
check: (ctx) => {
|
|
242
|
+
if (ctx.toolName !== "crypto_exchange") return true;
|
|
243
|
+
const input = ctx.input || {};
|
|
244
|
+
if (input.action !== "place_order") return true;
|
|
245
|
+
const key = ctx.userId || "global";
|
|
246
|
+
const now = Date.now();
|
|
247
|
+
const hourMs = 3600 * 1e3;
|
|
248
|
+
const entry = tradeSpendTracker.hourlyCount.get(key);
|
|
249
|
+
if (!entry || now - entry.windowStart > hourMs) {
|
|
250
|
+
return true;
|
|
251
|
+
}
|
|
252
|
+
return entry.count < this.config.maxTradesPerHour;
|
|
253
|
+
},
|
|
254
|
+
failMessage: `Trade rate limit exceeded (${this.config.maxTradesPerHour}/hr).`
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
checkRate(key, windowMs, maxCount) {
|
|
258
|
+
const now = Date.now();
|
|
259
|
+
let entry = rateTracker.get(key);
|
|
260
|
+
if (!entry) {
|
|
261
|
+
entry = { timestamps: [] };
|
|
262
|
+
rateTracker.set(key, entry);
|
|
263
|
+
}
|
|
264
|
+
entry.timestamps = entry.timestamps.filter((t) => now - t < windowMs);
|
|
265
|
+
return entry.timestamps.length < maxCount;
|
|
266
|
+
}
|
|
267
|
+
recordRate(key) {
|
|
268
|
+
let entry = rateTracker.get(key);
|
|
269
|
+
if (!entry) {
|
|
270
|
+
entry = { timestamps: [] };
|
|
271
|
+
rateTracker.set(key, entry);
|
|
272
|
+
}
|
|
273
|
+
entry.timestamps.push(Date.now());
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Evaluate all risk checks for an action
|
|
277
|
+
* This is the main entry point - NON-BYPASSABLE
|
|
278
|
+
*/
|
|
279
|
+
async evaluate(context) {
|
|
280
|
+
const results = [];
|
|
281
|
+
let allowed = true;
|
|
282
|
+
for (const check of this.checks) {
|
|
283
|
+
let passed;
|
|
284
|
+
try {
|
|
285
|
+
passed = await check.check(context);
|
|
286
|
+
} catch {
|
|
287
|
+
passed = false;
|
|
288
|
+
}
|
|
289
|
+
results.push({
|
|
290
|
+
name: check.name,
|
|
291
|
+
passed,
|
|
292
|
+
severity: check.severity,
|
|
293
|
+
message: passed ? void 0 : check.failMessage
|
|
294
|
+
});
|
|
295
|
+
if (!passed && (check.severity === "critical" || check.severity === "high")) {
|
|
296
|
+
allowed = false;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
const decision = {
|
|
300
|
+
allowed,
|
|
301
|
+
checks: results,
|
|
302
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
303
|
+
context
|
|
304
|
+
};
|
|
305
|
+
auditLog.push(decision);
|
|
306
|
+
if (auditLog.length > 1e4) {
|
|
307
|
+
auditLog.splice(0, auditLog.length - 5e3);
|
|
308
|
+
}
|
|
309
|
+
if (allowed) {
|
|
310
|
+
if (context.toolName) {
|
|
311
|
+
this.recordRate(`tool:${context.userId || "global"}`);
|
|
312
|
+
this.recordRate(`tool_hourly:${context.userId || "global"}`);
|
|
313
|
+
}
|
|
314
|
+
if (context.action === "send_message") {
|
|
315
|
+
this.recordRate(`msg:${context.userId || "global"}`);
|
|
316
|
+
}
|
|
317
|
+
if (context.estimatedCost) {
|
|
318
|
+
this.recordCost(context.userId || "global", context.estimatedCost);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return decision;
|
|
322
|
+
}
|
|
323
|
+
recordCost(userId, cost) {
|
|
324
|
+
const now = Date.now();
|
|
325
|
+
const hourMs = 3600 * 1e3;
|
|
326
|
+
const dayMs = 86400 * 1e3;
|
|
327
|
+
let hourly = costTracker.hourly.get(userId);
|
|
328
|
+
if (!hourly || now - hourly.windowStart > hourMs) {
|
|
329
|
+
hourly = { total: 0, windowStart: now };
|
|
330
|
+
costTracker.hourly.set(userId, hourly);
|
|
331
|
+
}
|
|
332
|
+
hourly.total += cost;
|
|
333
|
+
let daily = costTracker.daily.get(userId);
|
|
334
|
+
if (!daily || now - daily.windowStart > dayMs) {
|
|
335
|
+
daily = { total: 0, windowStart: now };
|
|
336
|
+
costTracker.daily.set(userId, daily);
|
|
337
|
+
}
|
|
338
|
+
daily.total += cost;
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Add a custom risk check
|
|
342
|
+
*/
|
|
343
|
+
addCheck(check) {
|
|
344
|
+
this.checks.push(check);
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Activate kill switch
|
|
348
|
+
*/
|
|
349
|
+
activateKillSwitch() {
|
|
350
|
+
this.config.killSwitch = true;
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Deactivate kill switch
|
|
354
|
+
*/
|
|
355
|
+
deactivateKillSwitch() {
|
|
356
|
+
this.config.killSwitch = false;
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Enable safe mode
|
|
360
|
+
*/
|
|
361
|
+
enableSafeMode() {
|
|
362
|
+
this.config.safeMode = true;
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Disable safe mode
|
|
366
|
+
*/
|
|
367
|
+
disableSafeMode() {
|
|
368
|
+
this.config.safeMode = false;
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Block a tool
|
|
372
|
+
*/
|
|
373
|
+
blockTool(toolName) {
|
|
374
|
+
if (!this.config.blockedTools.includes(toolName)) {
|
|
375
|
+
this.config.blockedTools.push(toolName);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Unblock a tool
|
|
380
|
+
*/
|
|
381
|
+
unblockTool(toolName) {
|
|
382
|
+
this.config.blockedTools = this.config.blockedTools.filter(
|
|
383
|
+
(t) => t !== toolName
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Get recent audit log
|
|
388
|
+
*/
|
|
389
|
+
getAuditLog(limit = 100) {
|
|
390
|
+
return auditLog.slice(-limit);
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Get current configuration
|
|
394
|
+
*/
|
|
395
|
+
getConfig() {
|
|
396
|
+
return { ...this.config };
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Update configuration
|
|
400
|
+
*/
|
|
401
|
+
updateConfig(updates) {
|
|
402
|
+
Object.assign(this.config, updates);
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Record trade spend after a successful trade execution.
|
|
406
|
+
* Call this after a trade completes to track daily/hourly limits.
|
|
407
|
+
*/
|
|
408
|
+
recordTradeSpend(userId, amountUsd) {
|
|
409
|
+
const now = Date.now();
|
|
410
|
+
const dayMs = 86400 * 1e3;
|
|
411
|
+
const hourMs = 3600 * 1e3;
|
|
412
|
+
let daily = tradeSpendTracker.daily.get(userId);
|
|
413
|
+
if (!daily || now - daily.windowStart > dayMs) {
|
|
414
|
+
daily = { total: 0, windowStart: now };
|
|
415
|
+
tradeSpendTracker.daily.set(userId, daily);
|
|
416
|
+
}
|
|
417
|
+
daily.total += amountUsd;
|
|
418
|
+
let hourly = tradeSpendTracker.hourlyCount.get(userId);
|
|
419
|
+
if (!hourly || now - hourly.windowStart > hourMs) {
|
|
420
|
+
hourly = { count: 0, windowStart: now };
|
|
421
|
+
tradeSpendTracker.hourlyCount.set(userId, hourly);
|
|
422
|
+
}
|
|
423
|
+
hourly.count += 1;
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Register risk engine as a hook on tool:execute to intercept
|
|
427
|
+
* financial tool calls at the hook level.
|
|
428
|
+
*/
|
|
429
|
+
registerAsHook(hookMgr) {
|
|
430
|
+
return hookMgr.register({
|
|
431
|
+
event: "tool:execute",
|
|
432
|
+
phase: "before",
|
|
433
|
+
name: "risk-engine-financial",
|
|
434
|
+
priority: 3,
|
|
435
|
+
// Run before tool sandbox (priority 5)
|
|
436
|
+
handler: async (context) => {
|
|
437
|
+
const toolName = context.data.toolName || "";
|
|
438
|
+
const input = context.data.input || {};
|
|
439
|
+
if (toolName !== "crypto_exchange") return context;
|
|
440
|
+
const decision = await this.evaluate({
|
|
441
|
+
action: "tool_execute",
|
|
442
|
+
userId: context.userId,
|
|
443
|
+
toolName,
|
|
444
|
+
input
|
|
445
|
+
});
|
|
446
|
+
if (!decision.allowed) {
|
|
447
|
+
context.cancelled = true;
|
|
448
|
+
const failedChecks = decision.checks.filter((c) => !c.passed).map((c) => c.message).join("; ");
|
|
449
|
+
context.cancelReason = `[RiskEngine] BLOCKED: ${failedChecks}`;
|
|
450
|
+
console.log(`[RiskEngine] Blocked ${toolName}: ${failedChecks}`);
|
|
451
|
+
}
|
|
452
|
+
return context;
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
};
|
|
457
|
+
var riskEngine = new RiskEngine();
|
|
458
|
+
|
|
459
|
+
export {
|
|
460
|
+
RiskEngine,
|
|
461
|
+
riskEngine
|
|
462
|
+
};
|
|
463
|
+
//# sourceMappingURL=chunk-ODCFS5WD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/intelligence/risk-engine.ts"],"sourcesContent":["/**\r\n * Risk/Constraint Engine\r\n * Ported from PolyMarketAI (Python) to TypeScript\r\n *\r\n * Non-bypassable safety layer with configurable checks:\r\n * - Rate limiting per action type\r\n * - Cost/budget thresholds\r\n * - Content safety checks\r\n * - Tool execution constraints\r\n * - Kill switch and safe mode\r\n * - Audit trail for all decisions\r\n */\r\n\r\nexport interface RiskCheck {\r\n name: string;\r\n description: string;\r\n severity: \"low\" | \"medium\" | \"high\" | \"critical\";\r\n /** Return true if the check passes (action is safe) */\r\n check: (context: RiskContext) => Promise<boolean> | boolean;\r\n /** Message when check fails */\r\n failMessage: string;\r\n}\r\n\r\nexport interface RiskContext {\r\n action: string;\r\n userId?: string;\r\n toolName?: string;\r\n input?: Record<string, unknown>;\r\n estimatedCost?: number;\r\n metadata?: Record<string, unknown>;\r\n}\r\n\r\nexport interface RiskDecision {\r\n allowed: boolean;\r\n checks: Array<{\r\n name: string;\r\n passed: boolean;\r\n severity: string;\r\n message?: string;\r\n }>;\r\n timestamp: Date;\r\n context: RiskContext;\r\n}\r\n\r\nexport interface RiskConfig {\r\n /** Maximum cost per request in USD */\r\n maxCostPerRequest: number;\r\n /** Maximum cost per hour in USD */\r\n maxCostPerHour: number;\r\n /** Maximum cost per day in USD */\r\n maxCostPerDay: number;\r\n /** Maximum tool executions per minute */\r\n maxToolsPerMinute: number;\r\n /** Maximum tool executions per hour */\r\n maxToolsPerHour: number;\r\n /** Maximum messages per minute */\r\n maxMessagesPerMinute: number;\r\n /** Blocked tool names */\r\n blockedTools: string[];\r\n /** Blocked action patterns (regex) */\r\n blockedPatterns: string[];\r\n /** Whether safe mode is active (restricts to read-only operations) */\r\n safeMode: boolean;\r\n /** Kill switch - blocks ALL actions */\r\n killSwitch: boolean;\r\n /** Custom risk checks */\r\n customChecks: RiskCheck[];\r\n /** Maximum single trade size in USD */\r\n maxTradeSize: number;\r\n /** Maximum daily trade spend in USD */\r\n maxDailyTradeSpend: number;\r\n /** Maximum trades per hour */\r\n maxTradesPerHour: number;\r\n}\r\n\r\nconst DEFAULT_CONFIG: RiskConfig = {\r\n maxCostPerRequest: 5.0,\r\n maxCostPerHour: 50.0,\r\n maxCostPerDay: 200.0,\r\n maxToolsPerMinute: 30,\r\n maxToolsPerHour: 500,\r\n maxMessagesPerMinute: 60,\r\n blockedTools: [],\r\n blockedPatterns: [],\r\n safeMode: false,\r\n killSwitch: false,\r\n customChecks: [],\r\n maxTradeSize: 100,\r\n maxDailyTradeSpend: 500,\r\n maxTradesPerHour: 5,\r\n};\r\n\r\n// Tracking state\r\nconst costTracker = {\r\n hourly: new Map<string, { total: number; windowStart: number }>(),\r\n daily: new Map<string, { total: number; windowStart: number }>(),\r\n};\r\n\r\nconst rateTracker = new Map<\r\n string,\r\n { timestamps: number[] }\r\n>();\r\n\r\n// Financial trade spend tracker (daily window)\r\nconst tradeSpendTracker = {\r\n daily: new Map<string, { total: number; windowStart: number }>(),\r\n hourlyCount: new Map<string, { count: number; windowStart: number }>(),\r\n};\r\n\r\nconst auditLog: RiskDecision[] = [];\r\n\r\n/**\r\n * Risk Engine\r\n */\r\nexport class RiskEngine {\r\n private config: RiskConfig;\r\n private checks: RiskCheck[] = [];\r\n\r\n constructor(config: Partial<RiskConfig> = {}) {\r\n this.config = { ...DEFAULT_CONFIG, ...config };\r\n this.initializeBuiltInChecks();\r\n this.checks.push(...this.config.customChecks);\r\n }\r\n\r\n private initializeBuiltInChecks(): void {\r\n // Kill switch check\r\n this.checks.push({\r\n name: \"kill_switch\",\r\n description: \"Emergency kill switch - blocks all actions\",\r\n severity: \"critical\",\r\n check: () => !this.config.killSwitch,\r\n failMessage: \"Kill switch is active. All actions are blocked.\",\r\n });\r\n\r\n // Safe mode check\r\n this.checks.push({\r\n name: \"safe_mode\",\r\n description: \"Safe mode restricts to read-only operations\",\r\n severity: \"high\",\r\n check: (ctx) => {\r\n if (!this.config.safeMode) return true;\r\n const readOnlyActions = [\r\n \"read\",\r\n \"search\",\r\n \"list\",\r\n \"get\",\r\n \"query\",\r\n \"analyze\",\r\n \"view\",\r\n ];\r\n return readOnlyActions.some((a) =>\r\n ctx.action.toLowerCase().includes(a)\r\n );\r\n },\r\n failMessage: \"Safe mode is active. Only read-only operations are allowed.\",\r\n });\r\n\r\n // Blocked tools check\r\n this.checks.push({\r\n name: \"blocked_tools\",\r\n description: \"Prevents execution of blocked tools\",\r\n severity: \"high\",\r\n check: (ctx) =>\r\n !ctx.toolName || !this.config.blockedTools.includes(ctx.toolName),\r\n failMessage: \"This tool is blocked by the risk policy.\",\r\n });\r\n\r\n // Blocked patterns check\r\n this.checks.push({\r\n name: \"blocked_patterns\",\r\n description: \"Prevents actions matching blocked patterns\",\r\n severity: \"high\",\r\n check: (ctx) => {\r\n const inputStr = JSON.stringify(ctx.input || {});\r\n return !this.config.blockedPatterns.some((pattern) =>\r\n new RegExp(pattern, \"i\").test(inputStr)\r\n );\r\n },\r\n failMessage: \"Input matches a blocked pattern.\",\r\n });\r\n\r\n // Cost per request check\r\n this.checks.push({\r\n name: \"cost_per_request\",\r\n description: \"Limits cost per individual request\",\r\n severity: \"medium\",\r\n check: (ctx) =>\r\n !ctx.estimatedCost ||\r\n ctx.estimatedCost <= this.config.maxCostPerRequest,\r\n failMessage: `Request exceeds maximum cost of $${this.config.maxCostPerRequest}.`,\r\n });\r\n\r\n // Hourly cost check\r\n this.checks.push({\r\n name: \"hourly_cost_limit\",\r\n description: \"Limits total cost per hour\",\r\n severity: \"high\",\r\n check: (ctx) => {\r\n const key = ctx.userId || \"global\";\r\n const now = Date.now();\r\n const hourMs = 3600 * 1000;\r\n const entry = costTracker.hourly.get(key);\r\n\r\n if (!entry || now - entry.windowStart > hourMs) {\r\n return true;\r\n }\r\n return entry.total + (ctx.estimatedCost || 0) <= this.config.maxCostPerHour;\r\n },\r\n failMessage: `Hourly cost limit of $${this.config.maxCostPerHour} exceeded.`,\r\n });\r\n\r\n // Daily cost check\r\n this.checks.push({\r\n name: \"daily_cost_limit\",\r\n description: \"Limits total cost per day\",\r\n severity: \"high\",\r\n check: (ctx) => {\r\n const key = ctx.userId || \"global\";\r\n const now = Date.now();\r\n const dayMs = 86400 * 1000;\r\n const entry = costTracker.daily.get(key);\r\n\r\n if (!entry || now - entry.windowStart > dayMs) {\r\n return true;\r\n }\r\n return entry.total + (ctx.estimatedCost || 0) <= this.config.maxCostPerDay;\r\n },\r\n failMessage: `Daily cost limit of $${this.config.maxCostPerDay} exceeded.`,\r\n });\r\n\r\n // Rate limit: tools per minute\r\n this.checks.push({\r\n name: \"tool_rate_limit_minute\",\r\n description: \"Limits tool executions per minute\",\r\n severity: \"medium\",\r\n check: (ctx) => {\r\n if (!ctx.toolName) return true;\r\n return this.checkRate(\r\n `tool:${ctx.userId || \"global\"}`,\r\n 60 * 1000,\r\n this.config.maxToolsPerMinute\r\n );\r\n },\r\n failMessage: `Tool execution rate limit exceeded (${this.config.maxToolsPerMinute}/min).`,\r\n });\r\n\r\n // Rate limit: tools per hour\r\n this.checks.push({\r\n name: \"tool_rate_limit_hour\",\r\n description: \"Limits tool executions per hour\",\r\n severity: \"medium\",\r\n check: (ctx) => {\r\n if (!ctx.toolName) return true;\r\n return this.checkRate(\r\n `tool_hourly:${ctx.userId || \"global\"}`,\r\n 3600 * 1000,\r\n this.config.maxToolsPerHour\r\n );\r\n },\r\n failMessage: `Tool execution hourly limit exceeded (${this.config.maxToolsPerHour}/hr).`,\r\n });\r\n\r\n // Rate limit: messages per minute\r\n this.checks.push({\r\n name: \"message_rate_limit\",\r\n description: \"Limits messages per minute\",\r\n severity: \"medium\",\r\n check: (ctx) => {\r\n if (ctx.action !== \"send_message\") return true;\r\n return this.checkRate(\r\n `msg:${ctx.userId || \"global\"}`,\r\n 60 * 1000,\r\n this.config.maxMessagesPerMinute\r\n );\r\n },\r\n failMessage: `Message rate limit exceeded (${this.config.maxMessagesPerMinute}/min).`,\r\n });\r\n\r\n // Command injection check\r\n this.checks.push({\r\n name: \"command_injection\",\r\n description: \"Prevents command injection in tool inputs\",\r\n severity: \"critical\",\r\n check: (ctx) => {\r\n if (!ctx.input) return true;\r\n const dangerousPatterns = [\r\n /;\\s*(rm|del|format|mkfs|dd)\\s/i,\r\n /\\|\\s*(bash|sh|cmd|powershell)/i,\r\n /`[^`]*`/,\r\n /\\$\\([^)]*\\)/,\r\n />\\s*\\/dev\\//i,\r\n ];\r\n const inputStr = JSON.stringify(ctx.input);\r\n return !dangerousPatterns.some((p) => p.test(inputStr));\r\n },\r\n failMessage: \"Potential command injection detected in input.\",\r\n });\r\n\r\n // Sensitive data check\r\n this.checks.push({\r\n name: \"sensitive_data\",\r\n description: \"Prevents leaking sensitive data patterns\",\r\n severity: \"high\",\r\n check: (ctx) => {\r\n if (!ctx.input) return true;\r\n const sensitivePatterns = [\r\n /\\b\\d{4}[\\s-]?\\d{4}[\\s-]?\\d{4}[\\s-]?\\d{4}\\b/, // credit card\r\n /\\b\\d{3}-\\d{2}-\\d{4}\\b/, // SSN\r\n /-----BEGIN\\s+(RSA\\s+)?PRIVATE\\s+KEY-----/, // private key\r\n ];\r\n const inputStr = JSON.stringify(ctx.input);\r\n return !sensitivePatterns.some((p) => p.test(inputStr));\r\n },\r\n failMessage: \"Sensitive data pattern detected in input.\",\r\n });\r\n\r\n // ── Financial Trade Safeguards ─────────────────────────────────────────\r\n\r\n // Trade size limit\r\n this.checks.push({\r\n name: \"trade_size_limit\",\r\n description: \"Blocks orders exceeding maximum single trade size\",\r\n severity: \"critical\",\r\n check: (ctx) => {\r\n if (ctx.toolName !== \"crypto_exchange\") return true;\r\n const input = ctx.input || {};\r\n if (input.action !== \"place_order\") return true;\r\n const estimatedTotal = (input._estimatedTotal as number) || 0;\r\n if (estimatedTotal <= 0) return true;\r\n return estimatedTotal <= this.config.maxTradeSize;\r\n },\r\n failMessage: `Trade exceeds maximum single order size of $${this.config.maxTradeSize}.`,\r\n });\r\n\r\n // Daily trade spend limit\r\n this.checks.push({\r\n name: \"daily_trade_spend_limit\",\r\n description: \"Blocks when daily trade spending cap exceeded\",\r\n severity: \"critical\",\r\n check: (ctx) => {\r\n if (ctx.toolName !== \"crypto_exchange\") return true;\r\n const input = ctx.input || {};\r\n if (input.action !== \"place_order\") return true;\r\n const estimatedTotal = (input._estimatedTotal as number) || 0;\r\n if (estimatedTotal <= 0) return true;\r\n\r\n const key = ctx.userId || \"global\";\r\n const now = Date.now();\r\n const dayMs = 86400 * 1000;\r\n const entry = tradeSpendTracker.daily.get(key);\r\n\r\n if (!entry || now - entry.windowStart > dayMs) {\r\n return true;\r\n }\r\n return entry.total + estimatedTotal <= this.config.maxDailyTradeSpend;\r\n },\r\n failMessage: `Daily trade spend limit of $${this.config.maxDailyTradeSpend} exceeded.`,\r\n });\r\n\r\n // Trade rate limit (per hour)\r\n this.checks.push({\r\n name: \"trade_rate_limit\",\r\n description: \"Blocks when hourly trade count exceeded\",\r\n severity: \"high\",\r\n check: (ctx) => {\r\n if (ctx.toolName !== \"crypto_exchange\") return true;\r\n const input = ctx.input || {};\r\n if (input.action !== \"place_order\") return true;\r\n\r\n const key = ctx.userId || \"global\";\r\n const now = Date.now();\r\n const hourMs = 3600 * 1000;\r\n const entry = tradeSpendTracker.hourlyCount.get(key);\r\n\r\n if (!entry || now - entry.windowStart > hourMs) {\r\n return true;\r\n }\r\n return entry.count < this.config.maxTradesPerHour;\r\n },\r\n failMessage: `Trade rate limit exceeded (${this.config.maxTradesPerHour}/hr).`,\r\n });\r\n }\r\n\r\n private checkRate(key: string, windowMs: number, maxCount: number): boolean {\r\n const now = Date.now();\r\n let entry = rateTracker.get(key);\r\n\r\n if (!entry) {\r\n entry = { timestamps: [] };\r\n rateTracker.set(key, entry);\r\n }\r\n\r\n // Remove expired timestamps\r\n entry.timestamps = entry.timestamps.filter((t) => now - t < windowMs);\r\n\r\n return entry.timestamps.length < maxCount;\r\n }\r\n\r\n private recordRate(key: string): void {\r\n let entry = rateTracker.get(key);\r\n if (!entry) {\r\n entry = { timestamps: [] };\r\n rateTracker.set(key, entry);\r\n }\r\n entry.timestamps.push(Date.now());\r\n }\r\n\r\n /**\r\n * Evaluate all risk checks for an action\r\n * This is the main entry point - NON-BYPASSABLE\r\n */\r\n async evaluate(context: RiskContext): Promise<RiskDecision> {\r\n const results: RiskDecision[\"checks\"] = [];\r\n let allowed = true;\r\n\r\n for (const check of this.checks) {\r\n let passed: boolean;\r\n try {\r\n passed = await check.check(context);\r\n } catch {\r\n passed = false;\r\n }\r\n\r\n results.push({\r\n name: check.name,\r\n passed,\r\n severity: check.severity,\r\n message: passed ? undefined : check.failMessage,\r\n });\r\n\r\n if (!passed && (check.severity === \"critical\" || check.severity === \"high\")) {\r\n allowed = false;\r\n }\r\n }\r\n\r\n const decision: RiskDecision = {\r\n allowed,\r\n checks: results,\r\n timestamp: new Date(),\r\n context,\r\n };\r\n\r\n // Record in audit log\r\n auditLog.push(decision);\r\n if (auditLog.length > 10000) {\r\n auditLog.splice(0, auditLog.length - 5000);\r\n }\r\n\r\n // Record rate tracking if allowed\r\n if (allowed) {\r\n if (context.toolName) {\r\n this.recordRate(`tool:${context.userId || \"global\"}`);\r\n this.recordRate(`tool_hourly:${context.userId || \"global\"}`);\r\n }\r\n if (context.action === \"send_message\") {\r\n this.recordRate(`msg:${context.userId || \"global\"}`);\r\n }\r\n if (context.estimatedCost) {\r\n this.recordCost(context.userId || \"global\", context.estimatedCost);\r\n }\r\n }\r\n\r\n return decision;\r\n }\r\n\r\n private recordCost(userId: string, cost: number): void {\r\n const now = Date.now();\r\n const hourMs = 3600 * 1000;\r\n const dayMs = 86400 * 1000;\r\n\r\n // Hourly\r\n let hourly = costTracker.hourly.get(userId);\r\n if (!hourly || now - hourly.windowStart > hourMs) {\r\n hourly = { total: 0, windowStart: now };\r\n costTracker.hourly.set(userId, hourly);\r\n }\r\n hourly.total += cost;\r\n\r\n // Daily\r\n let daily = costTracker.daily.get(userId);\r\n if (!daily || now - daily.windowStart > dayMs) {\r\n daily = { total: 0, windowStart: now };\r\n costTracker.daily.set(userId, daily);\r\n }\r\n daily.total += cost;\r\n }\r\n\r\n /**\r\n * Add a custom risk check\r\n */\r\n addCheck(check: RiskCheck): void {\r\n this.checks.push(check);\r\n }\r\n\r\n /**\r\n * Activate kill switch\r\n */\r\n activateKillSwitch(): void {\r\n this.config.killSwitch = true;\r\n }\r\n\r\n /**\r\n * Deactivate kill switch\r\n */\r\n deactivateKillSwitch(): void {\r\n this.config.killSwitch = false;\r\n }\r\n\r\n /**\r\n * Enable safe mode\r\n */\r\n enableSafeMode(): void {\r\n this.config.safeMode = true;\r\n }\r\n\r\n /**\r\n * Disable safe mode\r\n */\r\n disableSafeMode(): void {\r\n this.config.safeMode = false;\r\n }\r\n\r\n /**\r\n * Block a tool\r\n */\r\n blockTool(toolName: string): void {\r\n if (!this.config.blockedTools.includes(toolName)) {\r\n this.config.blockedTools.push(toolName);\r\n }\r\n }\r\n\r\n /**\r\n * Unblock a tool\r\n */\r\n unblockTool(toolName: string): void {\r\n this.config.blockedTools = this.config.blockedTools.filter(\r\n (t) => t !== toolName\r\n );\r\n }\r\n\r\n /**\r\n * Get recent audit log\r\n */\r\n getAuditLog(limit = 100): RiskDecision[] {\r\n return auditLog.slice(-limit);\r\n }\r\n\r\n /**\r\n * Get current configuration\r\n */\r\n getConfig(): RiskConfig {\r\n return { ...this.config };\r\n }\r\n\r\n /**\r\n * Update configuration\r\n */\r\n updateConfig(updates: Partial<RiskConfig>): void {\r\n Object.assign(this.config, updates);\r\n }\r\n\r\n /**\r\n * Record trade spend after a successful trade execution.\r\n * Call this after a trade completes to track daily/hourly limits.\r\n */\r\n recordTradeSpend(userId: string, amountUsd: number): void {\r\n const now = Date.now();\r\n const dayMs = 86400 * 1000;\r\n const hourMs = 3600 * 1000;\r\n\r\n // Daily spend\r\n let daily = tradeSpendTracker.daily.get(userId);\r\n if (!daily || now - daily.windowStart > dayMs) {\r\n daily = { total: 0, windowStart: now };\r\n tradeSpendTracker.daily.set(userId, daily);\r\n }\r\n daily.total += amountUsd;\r\n\r\n // Hourly count\r\n let hourly = tradeSpendTracker.hourlyCount.get(userId);\r\n if (!hourly || now - hourly.windowStart > hourMs) {\r\n hourly = { count: 0, windowStart: now };\r\n tradeSpendTracker.hourlyCount.set(userId, hourly);\r\n }\r\n hourly.count += 1;\r\n }\r\n\r\n /**\r\n * Register risk engine as a hook on tool:execute to intercept\r\n * financial tool calls at the hook level.\r\n */\r\n registerAsHook(hookMgr: {\r\n register: (hook: {\r\n event: \"tool:execute\";\r\n phase: \"before\";\r\n name: string;\r\n priority?: number;\r\n handler: (context: any) => Promise<any>;\r\n }) => string;\r\n }): string {\r\n return hookMgr.register({\r\n event: \"tool:execute\",\r\n phase: \"before\",\r\n name: \"risk-engine-financial\",\r\n priority: 3, // Run before tool sandbox (priority 5)\r\n handler: async (context: any) => {\r\n const toolName = context.data.toolName as string || \"\";\r\n const input = (context.data.input as Record<string, unknown>) || {};\r\n\r\n // Only intercept financial tools\r\n if (toolName !== \"crypto_exchange\") return context;\r\n\r\n const decision = await this.evaluate({\r\n action: \"tool_execute\",\r\n userId: context.userId,\r\n toolName,\r\n input,\r\n });\r\n\r\n if (!decision.allowed) {\r\n context.cancelled = true;\r\n const failedChecks = decision.checks\r\n .filter((c: any) => !c.passed)\r\n .map((c: any) => c.message)\r\n .join(\"; \");\r\n context.cancelReason = `[RiskEngine] BLOCKED: ${failedChecks}`;\r\n console.log(`[RiskEngine] Blocked ${toolName}: ${failedChecks}`);\r\n }\r\n\r\n return context;\r\n },\r\n });\r\n }\r\n}\r\n\r\n/** Singleton risk engine instance */\r\nexport const riskEngine = new RiskEngine();\r\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/utils.ts"],"sourcesContent":["/**\r\n * Shared CLI utilities for OpenSentinel commands.\r\n */\r\n\r\nimport { createInterface } from \"node:readline\";\r\nimport { exec as execCb } from \"node:child_process\";\r\nimport { homedir } from \"node:os\";\r\nimport { join } from \"node:path\";\r\nimport { existsSync, mkdirSync, readFileSync } from \"node:fs\";\r\n\r\n// ── Colors (ANSI escape codes) ───────────────────────────────────────────────\r\n\r\nexport const colors = {\r\n reset: \"\\x1b[0m\",\r\n bold: \"\\x1b[1m\",\r\n dim: \"\\x1b[2m\",\r\n green: \"\\x1b[32m\",\r\n cyan: \"\\x1b[36m\",\r\n yellow: \"\\x1b[33m\",\r\n red: \"\\x1b[31m\",\r\n magenta: \"\\x1b[35m\",\r\n};\r\n\r\n// ── Interactive prompts ──────────────────────────────────────────────────────\r\n\r\nexport async function prompt(question: string): Promise<string> {\r\n const rl = createInterface({ input: process.stdin, output: process.stdout });\r\n return new Promise((resolve) => {\r\n rl.question(question, (answer) => {\r\n rl.close();\r\n resolve(answer.trim());\r\n });\r\n });\r\n}\r\n\r\nexport async function confirm(question: string, defaultYes = true): Promise<boolean> {\r\n const hint = defaultYes ? \"[Y/n]\" : \"[y/N]\";\r\n const answer = await prompt(`${question} ${hint} `);\r\n if (answer === \"\") return defaultYes;\r\n return answer.toLowerCase().startsWith(\"y\");\r\n}\r\n\r\nexport async function promptSecret(question: string): Promise<string> {\r\n const rl = createInterface({ input: process.stdin, output: process.stdout });\r\n // Disable echo for secret input\r\n if (process.stdin.isTTY) {\r\n process.stdin.setRawMode?.(false);\r\n }\r\n return new Promise((resolve) => {\r\n rl.question(question, (answer) => {\r\n rl.close();\r\n resolve(answer.trim());\r\n });\r\n });\r\n}\r\n\r\n// ── Shell execution ──────────────────────────────────────────────────────────\r\n\r\nexport interface ExecResult {\r\n stdout: string;\r\n stderr: string;\r\n exitCode: number;\r\n}\r\n\r\nexport async function exec(cmd: string, opts?: { throws?: boolean; input?: string }): Promise<ExecResult> {\r\n return new Promise((resolve, reject) => {\r\n const child = execCb(cmd, { maxBuffer: 10 * 1024 * 1024 }, (error, stdout, stderr) => {\r\n const exitCode = error?.code ?? 0;\r\n const result = { stdout: stdout.toString(), stderr: stderr.toString(), exitCode: typeof exitCode === \"number\" ? exitCode : 1 };\r\n if (error && opts?.throws !== false) {\r\n reject(Object.assign(error, result));\r\n } else {\r\n resolve(result);\r\n }\r\n });\r\n if (opts?.input) {\r\n child.stdin?.write(opts.input);\r\n child.stdin?.end();\r\n }\r\n });\r\n}\r\n\r\nexport async function which(binary: string): Promise<string | null> {\r\n try {\r\n const result = await exec(`which ${binary}`, { throws: false });\r\n return result.stdout.trim() || null;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n// ── Platform detection ───────────────────────────────────────────────────────\r\n\r\nexport interface Platform {\r\n os: \"linux\" | \"darwin\" | \"other\";\r\n distro: string;\r\n packageManager: \"apt\" | \"brew\" | \"dnf\" | \"pacman\" | \"unknown\";\r\n}\r\n\r\nexport function detectPlatform(): Platform {\r\n const os = process.platform === \"linux\" ? \"linux\"\r\n : process.platform === \"darwin\" ? \"darwin\"\r\n : \"other\" as const;\r\n\r\n let distro = \"unknown\";\r\n let packageManager: Platform[\"packageManager\"] = \"unknown\";\r\n\r\n if (os === \"linux\") {\r\n try {\r\n const osRelease = readFileSync(\"/etc/os-release\", \"utf-8\");\r\n const idMatch = osRelease.match(/^ID=(.+)$/m);\r\n const idLikeMatch = osRelease.match(/^ID_LIKE=(.+)$/m);\r\n distro = idMatch?.[1]?.replace(/\"/g, \"\") || \"unknown\";\r\n const idLike = idLikeMatch?.[1]?.replace(/\"/g, \"\") || \"\";\r\n\r\n if (distro === \"ubuntu\" || distro === \"debian\" || idLike.includes(\"debian\")) {\r\n packageManager = \"apt\";\r\n } else if (distro === \"fedora\" || idLike.includes(\"fedora\") || idLike.includes(\"rhel\")) {\r\n packageManager = \"dnf\";\r\n } else if (distro === \"arch\" || idLike.includes(\"arch\")) {\r\n packageManager = \"pacman\";\r\n }\r\n } catch {}\r\n } else if (os === \"darwin\") {\r\n packageManager = \"brew\";\r\n distro = \"macos\";\r\n }\r\n\r\n return { os, distro, packageManager };\r\n}\r\n\r\n// ── Config directory ─────────────────────────────────────────────────────────\r\n\r\nexport function getConfigDir(): string {\r\n const dir = process.env.OPENSENTINEL_HOME || join(homedir(), \".opensentinel\");\r\n if (!existsSync(dir)) {\r\n mkdirSync(dir, { recursive: true });\r\n }\r\n return dir;\r\n}\r\n\r\nexport function getPackageRoot(): string {\r\n // When running from source: import.meta.dirname is src/commands/\r\n // When installed globally: import.meta.dirname is dist/commands/ or dist/\r\n // Go up to find package.json\r\n let dir = import.meta.dirname || __dirname;\r\n for (let i = 0; i < 5; i++) {\r\n if (existsSync(join(dir, \"package.json\"))) {\r\n return dir;\r\n }\r\n dir = join(dir, \"..\");\r\n }\r\n return process.cwd();\r\n}\r\n\r\nexport function getMigrationsDir(): string {\r\n return join(getPackageRoot(), \"drizzle\");\r\n}\r\n\r\n// ── Port and service checks ──────────────────────────────────────────────────\r\n\r\nexport async function checkPort(port: number): Promise<boolean> {\r\n try {\r\n const result = await exec(`ss -tlnp 2>/dev/null | grep :${port} || netstat -tlnp 2>/dev/null | grep :${port}`, { throws: false });\r\n return result.stdout.trim().length > 0;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\nexport async function checkPostgres(): Promise<{ installed: boolean; running: boolean; port: number }> {\r\n const installed = !!(await which(\"psql\"));\r\n let running = false;\r\n let port = 5432;\r\n\r\n if (installed) {\r\n const result = await exec(\"pg_isready -q 2>/dev/null\", { throws: false });\r\n running = result.exitCode === 0;\r\n }\r\n\r\n // Also check if running on non-standard port\r\n if (!running) {\r\n const port5445 = await checkPort(5445);\r\n if (port5445) {\r\n running = true;\r\n port = 5445;\r\n }\r\n }\r\n\r\n return { installed, running, port };\r\n}\r\n\r\nexport async function checkRedis(): Promise<{ installed: boolean; running: boolean; port: number }> {\r\n const installed = !!(await which(\"redis-cli\"));\r\n let running = false;\r\n let port = 6379;\r\n\r\n if (installed) {\r\n const result = await exec(\"redis-cli ping 2>/dev/null\", { throws: false });\r\n running = result.stdout.trim() === \"PONG\";\r\n }\r\n\r\n // Check alternate ports\r\n if (!running) {\r\n for (const p of [6384, 6380]) {\r\n const result = await exec(`redis-cli -p ${p} ping 2>/dev/null`, { throws: false });\r\n if (result.stdout.trim() === \"PONG\") {\r\n running = true;\r\n port = p;\r\n break;\r\n }\r\n }\r\n }\r\n\r\n return { installed, running, port };\r\n}\r\n\r\n// ── Banner ───────────────────────────────────────────────────────────────────\r\n\r\nexport function printBanner() {\r\n console.log(`\r\n${colors.cyan}${colors.bold}╔══════════════════════════════════════════╗\r\n║ OPENSENTINEL v3.0.0 ║\r\n║ Your Personal AI Assistant ║\r\n╚══════════════════════════════════════════╝${colors.reset}\r\n`);\r\n}\r\n\r\n// ── .env file loading ────────────────────────────────────────────────────────\r\n\r\nexport function loadEnvFile(): string | null {\r\n const candidates = [\r\n process.env.OPENSENTINEL_HOME && join(process.env.OPENSENTINEL_HOME, \".env\"),\r\n join(homedir(), \".opensentinel\", \".env\"),\r\n join(process.cwd(), \".env\"),\r\n ].filter(Boolean) as string[];\r\n\r\n for (const candidate of candidates) {\r\n if (existsSync(candidate)) {\r\n const content = readFileSync(candidate, \"utf-8\");\r\n for (const line of content.split(\"\\n\")) {\r\n const trimmed = line.trim();\r\n if (!trimmed || trimmed.startsWith(\"#\")) continue;\r\n const eqIndex = trimmed.indexOf(\"=\");\r\n if (eqIndex === -1) continue;\r\n const key = trimmed.slice(0, eqIndex).trim();\r\n const value = trimmed.slice(eqIndex + 1).trim();\r\n // Don't override existing env vars\r\n if (!process.env[key]) {\r\n process.env[key] = value;\r\n }\r\n }\r\n return candidate;\r\n }\r\n }\r\n return null;\r\n}\r\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createLogger
|
|
3
|
+
} from "./chunk-7BNFELEK.js";
|
|
4
|
+
|
|
5
|
+
// src/integrations/m365/graph-client.ts
|
|
6
|
+
var log = createLogger("m365:graph");
|
|
7
|
+
var GRAPH_ROOT = "https://graph.microsoft.com/v1.0";
|
|
8
|
+
var GraphError = class extends Error {
|
|
9
|
+
constructor(status, code, message) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.status = status;
|
|
12
|
+
this.code = code;
|
|
13
|
+
this.name = "GraphError";
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
async function graphFetch(accessToken, path, init) {
|
|
17
|
+
const url = path.startsWith("http") ? path : `${GRAPH_ROOT}${path}`;
|
|
18
|
+
const res = await fetch(url, {
|
|
19
|
+
...init,
|
|
20
|
+
headers: {
|
|
21
|
+
Authorization: `Bearer ${accessToken}`,
|
|
22
|
+
"Content-Type": "application/json",
|
|
23
|
+
...init?.headers ?? {}
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
if (!res.ok) {
|
|
27
|
+
let body = null;
|
|
28
|
+
try {
|
|
29
|
+
body = await res.json();
|
|
30
|
+
} catch {
|
|
31
|
+
}
|
|
32
|
+
const code = body?.error?.code || String(res.status);
|
|
33
|
+
const message = body?.error?.message || res.statusText;
|
|
34
|
+
log.warn("graph call failed", { path, status: res.status, code });
|
|
35
|
+
throw new GraphError(res.status, code, message);
|
|
36
|
+
}
|
|
37
|
+
if (res.status === 204) return void 0;
|
|
38
|
+
return await res.json();
|
|
39
|
+
}
|
|
40
|
+
async function getMe(accessToken) {
|
|
41
|
+
return graphFetch(accessToken, "/me");
|
|
42
|
+
}
|
|
43
|
+
async function listMessages(accessToken, opts = {}) {
|
|
44
|
+
const top = Math.max(1, Math.min(opts.top ?? 20, 100));
|
|
45
|
+
const params = new URLSearchParams();
|
|
46
|
+
params.set("$top", String(top));
|
|
47
|
+
if (opts.skip) params.set("$skip", String(opts.skip));
|
|
48
|
+
params.set(
|
|
49
|
+
"$select",
|
|
50
|
+
"id,subject,bodyPreview,from,toRecipients,receivedDateTime,isRead,webLink"
|
|
51
|
+
);
|
|
52
|
+
params.set("$orderby", "receivedDateTime desc");
|
|
53
|
+
if (opts.unreadOnly) params.set("$filter", "isRead eq false");
|
|
54
|
+
if (opts.search) params.set("$search", `"${opts.search.replace(/"/g, "")}"`);
|
|
55
|
+
const base = opts.folder ? `/me/mailFolders/${encodeURIComponent(opts.folder)}/messages` : "/me/messages";
|
|
56
|
+
const resp = await graphFetch(
|
|
57
|
+
accessToken,
|
|
58
|
+
`${base}?${params.toString()}`
|
|
59
|
+
);
|
|
60
|
+
return { value: resp.value, nextLink: resp["@odata.nextLink"] };
|
|
61
|
+
}
|
|
62
|
+
async function getMessage(accessToken, id) {
|
|
63
|
+
const params = new URLSearchParams();
|
|
64
|
+
params.set(
|
|
65
|
+
"$select",
|
|
66
|
+
"id,subject,bodyPreview,from,toRecipients,receivedDateTime,isRead,webLink,body,internetMessageHeaders"
|
|
67
|
+
);
|
|
68
|
+
return graphFetch(
|
|
69
|
+
accessToken,
|
|
70
|
+
`/me/messages/${encodeURIComponent(id)}?${params.toString()}`
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
function stripHtml(html) {
|
|
74
|
+
return html.replace(/<style[\s\S]*?<\/style>/gi, " ").replace(/<script[\s\S]*?<\/script>/gi, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export {
|
|
78
|
+
GraphError,
|
|
79
|
+
getMe,
|
|
80
|
+
listMessages,
|
|
81
|
+
getMessage,
|
|
82
|
+
stripHtml
|
|
83
|
+
};
|
|
84
|
+
//# sourceMappingURL=chunk-PBOCSGNL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/integrations/m365/graph-client.ts"],"sourcesContent":["/**\n * Thin Microsoft Graph client — fetch based, no SDK dep.\n *\n * Only the surface needed by routes lives here. Extend as needed; the one-off\n * helpers match the patterns from docs.microsoft.com/graph/api.\n */\n\nimport { createLogger } from \"../../core/logger\";\n\nconst log = createLogger(\"m365:graph\");\nconst GRAPH_ROOT = \"https://graph.microsoft.com/v1.0\";\n\nexport interface GraphMe {\n id: string;\n userPrincipalName?: string;\n mail?: string;\n displayName?: string;\n givenName?: string;\n surname?: string;\n jobTitle?: string;\n}\n\nexport interface GraphMessageSummary {\n id: string;\n subject: string;\n bodyPreview: string;\n from?: { emailAddress: { name: string; address: string } };\n toRecipients?: Array<{ emailAddress: { name: string; address: string } }>;\n receivedDateTime: string;\n isRead: boolean;\n webLink?: string;\n}\n\nexport interface GraphMessageFull extends GraphMessageSummary {\n body?: { contentType: \"html\" | \"text\"; content: string };\n internetMessageHeaders?: Array<{ name: string; value: string }>;\n}\n\nexport class GraphError extends Error {\n constructor(public status: number, public code: string, message: string) {\n super(message);\n this.name = \"GraphError\";\n }\n}\n\nasync function graphFetch<T>(accessToken: string, path: string, init?: RequestInit): Promise<T> {\n const url = path.startsWith(\"http\") ? path : `${GRAPH_ROOT}${path}`;\n const res = await fetch(url, {\n ...init,\n headers: {\n Authorization: `Bearer ${accessToken}`,\n \"Content-Type\": \"application/json\",\n ...(init?.headers ?? {}),\n },\n });\n\n if (!res.ok) {\n let body: any = null;\n try {\n body = await res.json();\n } catch {\n /* ignore */\n }\n const code = body?.error?.code || String(res.status);\n const message = body?.error?.message || res.statusText;\n log.warn(\"graph call failed\", { path, status: res.status, code });\n throw new GraphError(res.status, code, message);\n }\n\n // 204 No Content\n if (res.status === 204) return undefined as unknown as T;\n return (await res.json()) as T;\n}\n\nexport async function getMe(accessToken: string): Promise<GraphMe> {\n return graphFetch<GraphMe>(accessToken, \"/me\");\n}\n\nexport interface ListMessagesOptions {\n top?: number;\n skip?: number;\n folder?: string; // e.g. \"inbox\", \"sentitems\"\n unreadOnly?: boolean;\n search?: string;\n}\n\nexport async function listMessages(\n accessToken: string,\n opts: ListMessagesOptions = {}\n): Promise<{ value: GraphMessageSummary[]; nextLink?: string }> {\n const top = Math.max(1, Math.min(opts.top ?? 20, 100));\n const params = new URLSearchParams();\n params.set(\"$top\", String(top));\n if (opts.skip) params.set(\"$skip\", String(opts.skip));\n params.set(\n \"$select\",\n \"id,subject,bodyPreview,from,toRecipients,receivedDateTime,isRead,webLink\"\n );\n params.set(\"$orderby\", \"receivedDateTime desc\");\n if (opts.unreadOnly) params.set(\"$filter\", \"isRead eq false\");\n if (opts.search) params.set(\"$search\", `\"${opts.search.replace(/\"/g, \"\")}\"`);\n\n const base = opts.folder\n ? `/me/mailFolders/${encodeURIComponent(opts.folder)}/messages`\n : \"/me/messages\";\n const resp = await graphFetch<{ value: GraphMessageSummary[]; \"@odata.nextLink\"?: string }>(\n accessToken,\n `${base}?${params.toString()}`\n );\n return { value: resp.value, nextLink: resp[\"@odata.nextLink\"] };\n}\n\nexport async function getMessage(accessToken: string, id: string): Promise<GraphMessageFull> {\n const params = new URLSearchParams();\n params.set(\n \"$select\",\n \"id,subject,bodyPreview,from,toRecipients,receivedDateTime,isRead,webLink,body,internetMessageHeaders\"\n );\n return graphFetch<GraphMessageFull>(\n accessToken,\n `/me/messages/${encodeURIComponent(id)}?${params.toString()}`\n );\n}\n\nexport function stripHtml(html: string): string {\n return html\n .replace(/<style[\\s\\S]*?<\\/style>/gi, \" \")\n .replace(/<script[\\s\\S]*?<\\/script>/gi, \" \")\n .replace(/<[^>]+>/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n"],"mappings":";;;;;AASA,IAAM,MAAM,aAAa,YAAY;AACrC,IAAM,aAAa;AA4BZ,IAAM,aAAN,cAAyB,MAAM;AAAA,EACpC,YAAmB,QAAuB,MAAc,SAAiB;AACvE,UAAM,OAAO;AADI;AAAuB;AAExC,SAAK,OAAO;AAAA,EACd;AACF;AAEA,eAAe,WAAc,aAAqB,MAAc,MAAgC;AAC9F,QAAM,MAAM,KAAK,WAAW,MAAM,IAAI,OAAO,GAAG,UAAU,GAAG,IAAI;AACjE,QAAM,MAAM,MAAM,MAAM,KAAK;AAAA,IAC3B,GAAG;AAAA,IACH,SAAS;AAAA,MACP,eAAe,UAAU,WAAW;AAAA,MACpC,gBAAgB;AAAA,MAChB,GAAI,MAAM,WAAW,CAAC;AAAA,IACxB;AAAA,EACF,CAAC;AAED,MAAI,CAAC,IAAI,IAAI;AACX,QAAI,OAAY;AAChB,QAAI;AACF,aAAO,MAAM,IAAI,KAAK;AAAA,IACxB,QAAQ;AAAA,IAER;AACA,UAAM,OAAO,MAAM,OAAO,QAAQ,OAAO,IAAI,MAAM;AACnD,UAAM,UAAU,MAAM,OAAO,WAAW,IAAI;AAC5C,QAAI,KAAK,qBAAqB,EAAE,MAAM,QAAQ,IAAI,QAAQ,KAAK,CAAC;AAChE,UAAM,IAAI,WAAW,IAAI,QAAQ,MAAM,OAAO;AAAA,EAChD;AAGA,MAAI,IAAI,WAAW,IAAK,QAAO;AAC/B,SAAQ,MAAM,IAAI,KAAK;AACzB;AAEA,eAAsB,MAAM,aAAuC;AACjE,SAAO,WAAoB,aAAa,KAAK;AAC/C;AAUA,eAAsB,aACpB,aACA,OAA4B,CAAC,GACiC;AAC9D,QAAM,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,OAAO,IAAI,GAAG,CAAC;AACrD,QAAM,SAAS,IAAI,gBAAgB;AACnC,SAAO,IAAI,QAAQ,OAAO,GAAG,CAAC;AAC9B,MAAI,KAAK,KAAM,QAAO,IAAI,SAAS,OAAO,KAAK,IAAI,CAAC;AACpD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACA,SAAO,IAAI,YAAY,uBAAuB;AAC9C,MAAI,KAAK,WAAY,QAAO,IAAI,WAAW,iBAAiB;AAC5D,MAAI,KAAK,OAAQ,QAAO,IAAI,WAAW,IAAI,KAAK,OAAO,QAAQ,MAAM,EAAE,CAAC,GAAG;AAE3E,QAAM,OAAO,KAAK,SACd,mBAAmB,mBAAmB,KAAK,MAAM,CAAC,cAClD;AACJ,QAAM,OAAO,MAAM;AAAA,IACjB;AAAA,IACA,GAAG,IAAI,IAAI,OAAO,SAAS,CAAC;AAAA,EAC9B;AACA,SAAO,EAAE,OAAO,KAAK,OAAO,UAAU,KAAK,iBAAiB,EAAE;AAChE;AAEA,eAAsB,WAAW,aAAqB,IAAuC;AAC3F,QAAM,SAAS,IAAI,gBAAgB;AACnC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACA,SAAO;AAAA,IACL;AAAA,IACA,gBAAgB,mBAAmB,EAAE,CAAC,IAAI,OAAO,SAAS,CAAC;AAAA,EAC7D;AACF;AAEO,SAAS,UAAU,MAAsB;AAC9C,SAAO,KACJ,QAAQ,6BAA6B,GAAG,EACxC,QAAQ,+BAA+B,GAAG,EAC1C,QAAQ,YAAY,GAAG,EACvB,QAAQ,QAAQ,GAAG,EACnB,KAAK;AACV;","names":[]}
|