opensentinel 3.1.1 → 3.6.1
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 +126 -83
- package/dist/agent-manager-7N7REQZQ.js +39 -0
- package/dist/agent-processor-I23VWQY3.js +280 -0
- package/dist/agent-processor-I23VWQY3.js.map +1 -0
- package/dist/agent-types-2T4PXLFQ.js +12 -0
- package/dist/alerting-4I37GG4U.js +699 -0
- package/dist/alerting-4I37GG4U.js.map +1 -0
- package/dist/analysis-agent-JWN2GXYE.js +288 -0
- package/dist/analysis-agent-JWN2GXYE.js.map +1 -0
- package/dist/{archiver-AVNBYCKQ.js → archiver-XLRIIXPY.js} +86 -17
- package/dist/archiver-XLRIIXPY.js.map +1 -0
- package/dist/{audit-logger-OBPR7CRO.js → audit-logger-AU3TMWKI.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-MU2TJQ3Y.js +46 -0
- package/dist/brain-SLA474EU.js +65 -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-6PMVAAA7.js → chunk-2RGPWU77.js} +3 -3
- package/dist/{chunk-TVEWKIK3.js → chunk-2WTKTG2C.js} +2 -2
- package/dist/{chunk-MXAPLSJ5.js → chunk-45YXODSB.js} +2 -2
- package/dist/{chunk-SJSUSJ47.js → chunk-4YJRBMMA.js} +2 -2
- package/dist/chunk-643M3AP5.js +564 -0
- package/dist/chunk-643M3AP5.js.map +1 -0
- package/dist/{chunk-766ASQWE.js → chunk-6JY4HNUH.js} +2413 -2368
- package/dist/chunk-6JY4HNUH.js.map +1 -0
- package/dist/chunk-6LTLIYAQ.js +194 -0
- package/dist/chunk-6LTLIYAQ.js.map +1 -0
- package/dist/chunk-6UZPE35A.js +724 -0
- package/dist/chunk-6UZPE35A.js.map +1 -0
- package/dist/chunk-6W6PTJFT.js +181 -0
- package/dist/chunk-6W6PTJFT.js.map +1 -0
- package/dist/chunk-7MZN73J2.js +162 -0
- package/dist/chunk-7MZN73J2.js.map +1 -0
- package/dist/{chunk-SVAPX2XN.js → chunk-A24GPVLY.js} +9 -7
- package/dist/{chunk-SVAPX2XN.js.map → chunk-A24GPVLY.js.map} +1 -1
- package/dist/chunk-AD6YEH6U.js +3408 -0
- package/dist/chunk-AD6YEH6U.js.map +1 -0
- package/dist/chunk-ADTDYJO7.js +265 -0
- package/dist/chunk-ADTDYJO7.js.map +1 -0
- package/dist/{chunk-WRAKK6K6.js → chunk-AR34B6XR.js} +5 -3
- package/dist/{chunk-WRAKK6K6.js.map → chunk-AR34B6XR.js.map} +1 -1
- package/dist/chunk-BMOUYXLX.js +418 -0
- package/dist/chunk-BMOUYXLX.js.map +1 -0
- 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-RZ4YESBG.js → chunk-DOYGMNMK.js} +1 -1
- package/dist/chunk-DOYGMNMK.js.map +1 -0
- package/dist/chunk-FFV2SXFD.js +380 -0
- package/dist/chunk-FFV2SXFD.js.map +1 -0
- package/dist/{chunk-EVE7MIIY.js → chunk-GUKKW7JI.js} +15 -16
- package/dist/chunk-GUKKW7JI.js.map +1 -0
- package/dist/{chunk-66OJ3WB4.js → chunk-H3BOLSTS.js} +2 -2
- package/dist/chunk-HKOPRRDJ.js +1021 -0
- package/dist/chunk-HKOPRRDJ.js.map +1 -0
- package/dist/{chunk-BXZ6EA52.js → chunk-HTF2GIQC.js} +57 -3
- package/dist/chunk-HTF2GIQC.js.map +1 -0
- package/dist/{chunk-TYAGMJNV.js → chunk-JOA5A3G3.js} +5 -5
- package/dist/{chunk-OCVQGBJK.js → chunk-KABG5PG3.js} +6 -4
- package/dist/{chunk-OCVQGBJK.js.map → chunk-KABG5PG3.js.map} +1 -1
- package/dist/{chunk-VEHFVBLI.js → chunk-KT7NLIXP.js} +2 -2
- package/dist/chunk-LFDXEYYB.js +150 -0
- package/dist/chunk-LFDXEYYB.js.map +1 -0
- package/dist/{chunk-I6BDYQIG.js → chunk-M7YLQHFP.js} +6 -6
- package/dist/chunk-M7YLQHFP.js.map +1 -0
- package/dist/{chunk-AYUKPTSM.js → chunk-MFK34XSY.js} +96 -218
- package/dist/chunk-MFK34XSY.js.map +1 -0
- package/dist/chunk-MIC5IBQF.js +386 -0
- package/dist/chunk-MIC5IBQF.js.map +1 -0
- package/dist/{chunk-4UOE5TUZ.js → chunk-NMSHVO5O.js} +4 -4
- package/dist/{chunk-XKYRH4FM.js → chunk-NYVBXUGD.js} +13 -32
- package/dist/chunk-NYVBXUGD.js.map +1 -0
- package/dist/chunk-ODCFS5WD.js +463 -0
- package/dist/chunk-ODCFS5WD.js.map +1 -0
- package/dist/{chunk-ZLZKF2PM.js → chunk-PUNIMPMY.js} +32 -2
- package/dist/chunk-PUNIMPMY.js.map +1 -0
- package/dist/chunk-S4NJJS5C.js +37 -0
- package/dist/chunk-S4NJJS5C.js.map +1 -0
- package/dist/{chunk-NHMBTUMW.js → chunk-TAAZB5KN.js} +2 -2
- 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-4GLYY4NN.js → chunk-UWUIJTT4.js} +8 -2
- package/dist/chunk-UWUIJTT4.js.map +1 -0
- package/dist/{chunk-SPPMCAKG.js → chunk-VKMFUIVA.js} +2 -2
- package/dist/chunk-VKMFUIVA.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-ZIYTHUM5.js +457 -0
- package/dist/chunk-ZIYTHUM5.js.map +1 -0
- package/dist/chunker-K6WTR62A.js +12 -0
- package/dist/cli.js +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 +1 -1
- package/dist/commands/start.js +2 -2
- package/dist/commands/status.js +1 -1
- package/dist/commands/stop.js +1 -1
- package/dist/commands/utils.js +1 -1
- package/dist/cost-tracker-EMOIOYH7.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-LRIOKQBO.js +77 -0
- package/dist/discord-NKR3X4AV.js +80 -0
- package/dist/documents-EYIYLZK2.js +184 -0
- package/dist/documents-EYIYLZK2.js.map +1 -0
- package/dist/docx-parser-EXL4TN5E.js +16 -0
- package/dist/{email-K7LO2IPB.js → email-EAQNULVD.js} +33 -25
- package/dist/{email-K7LO2IPB.js.map → email-EAQNULVD.js.map} +1 -1
- package/dist/{enhanced-retrieval-DNLLEM4Z.js → enhanced-retrieval-OGHT6TS5.js} +11 -8
- package/dist/{enhanced-retrieval-DNLLEM4Z.js.map → enhanced-retrieval-OGHT6TS5.js.map} +1 -1
- package/dist/enrichment-pipeline-CMUVBDC7.js +14 -0
- package/dist/{entity-resolution-Y3IUWEAT.js → entity-resolution-4X4JU43O.js} +6 -5
- package/dist/env-CHOFICED.js +12 -0
- package/dist/error-tracker-SVQSDQDW.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-KGNILDWJ.js +833 -0
- package/dist/github-KGNILDWJ.js.map +1 -0
- package/dist/{google-workspace-DKWUVNGC.js → google-workspace-TSZPZK5G.js} +2 -2
- 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-V2XNDDHT.js +43 -0
- package/dist/inbox-summarizer-DKKRYXDR.js +55 -0
- package/dist/{incident-response-C5J7Q6DT.js → incident-response-ZTIKUWEO.js} +8 -6
- package/dist/{incident-response-C5J7Q6DT.js.map → incident-response-ZTIKUWEO.js.map} +1 -1
- 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-J7PJ7MZ3.js +46 -0
- package/dist/lib.d.ts +73 -1
- package/dist/lib.js +86 -76
- package/dist/lib.js.map +1 -1
- package/dist/{mailchimp-KKNF6QJ7.js → mailchimp-ZFYDC44J.js} +2 -2
- package/dist/{matrix-QVHG76I7.js → matrix-XHTR53VQ.js} +29 -21
- package/dist/{matrix-QVHG76I7.js.map → matrix-XHTR53VQ.js.map} +1 -1
- package/dist/{mcp-3JI6W7ZE.js → mcp-3C2TN67D.js} +3 -3
- package/dist/metrics-VJDWQWU7.js +25 -0
- package/dist/{microsoft365-UCBKJHNX.js → microsoft365-6G2IJMWC.js} +2 -2
- package/dist/multi-user-S56GUD6L.js +411 -0
- package/dist/multi-user-S56GUD6L.js.map +1 -0
- package/dist/{ocr-AC7NPX33.js → ocr-LGUIPKVZ.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-HXTAMGHT.js} +3 -3
- package/dist/presentations-HXTAMGHT.js.map +1 -0
- package/dist/{prometheus-JNT2BD4L.js → prometheus-YETCZO4I.js} +2 -2
- package/dist/{providers-J4LYPHDR.js → providers-H6YIC3MG.js} +6 -4
- package/dist/{qr-code-WIX4PB4U.js → qr-code-6WZJHRKL.js} +2 -2
- 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-CA5UNHZV.js +73 -0
- package/dist/scheduler-CA5UNHZV.js.map +1 -0
- package/dist/schema-ALJ67YVG.js +72 -0
- package/dist/schema-ALJ67YVG.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/{shopify-NCXYJB4R.js → shopify-ON2PAU27.js} +2 -2
- package/dist/signal-X7IQJGRQ.js +43 -0
- package/dist/signal-X7IQJGRQ.js.map +1 -0
- package/dist/slack-P2LFUJUQ.js +85 -0
- package/dist/slack-P2LFUJUQ.js.map +1 -0
- package/dist/{sms-M3JIOTCW.js → sms-4VME2HUL.js} +4 -4
- package/dist/sms-4VME2HUL.js.map +1 -0
- package/dist/{src-VYUE6LRA.js → src-S5KX4YEV.js} +179 -48
- package/dist/src-S5KX4YEV.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/tools-FGPN522P.js +46 -0
- package/dist/tools-FGPN522P.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-KRPQ4YUX.js +43 -0
- package/dist/whatsapp-KRPQ4YUX.js.map +1 -0
- package/dist/{word-document-7B6SJMAY.js → word-document-D6N2C47N.js} +4 -4
- package/dist/word-document-D6N2C47N.js.map +1 -0
- package/dist/workflow-store-ZYAYE5P6.js +373 -0
- package/dist/workflow-store-ZYAYE5P6.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/package.json +11 -1
- package/dist/archiver-AVNBYCKQ.js.map +0 -1
- 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-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-XKYRH4FM.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/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/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-7N7REQZQ.js.map} +0 -0
- /package/dist/{auth-UOX5K2BE.js.map → agent-types-2T4PXLFQ.js.map} +0 -0
- /package/dist/{backup-restore-PZ7CYYB7.js.map → audit-logger-AU3TMWKI.js.map} +0 -0
- /package/dist/{blocks-R3PODY47.js.map → auth-PH5IHISW.js.map} +0 -0
- /package/dist/{aws-s3-Q4LLZZPD.js.map → aws-s3-QZMURYXB.js.map} +0 -0
- /package/dist/{bot-QRARP4UN.js.map → backup-restore-72OQTZO3.js.map} +0 -0
- /package/dist/{brain-7XLLM3KC.js.map → blocks-YOWOESDD.js.map} +0 -0
- /package/dist/{chunk-PLDDJCW6.js.map → bot-MU2TJQ3Y.js.map} +0 -0
- /package/dist/{client-ZQSFPMOB.js.map → brain-SLA474EU.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-6PMVAAA7.js.map → chunk-2RGPWU77.js.map} +0 -0
- /package/dist/{chunk-TVEWKIK3.js.map → chunk-2WTKTG2C.js.map} +0 -0
- /package/dist/{chunk-MXAPLSJ5.js.map → chunk-45YXODSB.js.map} +0 -0
- /package/dist/{chunk-SJSUSJ47.js.map → chunk-4YJRBMMA.js.map} +0 -0
- /package/dist/{chunk-MQJ2ECQT.js.map → chunk-CUPEENUY.js.map} +0 -0
- /package/dist/{chunk-66OJ3WB4.js.map → chunk-H3BOLSTS.js.map} +0 -0
- /package/dist/{chunk-TYAGMJNV.js.map → chunk-JOA5A3G3.js.map} +0 -0
- /package/dist/{chunk-VEHFVBLI.js.map → chunk-KT7NLIXP.js.map} +0 -0
- /package/dist/{chunk-4UOE5TUZ.js.map → chunk-NMSHVO5O.js.map} +0 -0
- /package/dist/{chunk-NHMBTUMW.js.map → chunk-TAAZB5KN.js.map} +0 -0
- /package/dist/{clipboard-manager-TEO2GEDN.js.map → chunk-UP2VWCW5.js.map} +0 -0
- /package/dist/{cron-explain-HHQKPD3M.js.map → chunker-K6WTR62A.js.map} +0 -0
- /package/dist/{crypto-4AP47IKC.js.map → client-FOIYPOZQ.js.map} +0 -0
- /package/dist/{databases-37X4CI2Y.js.map → clipboard-manager-4SBNESGZ.js.map} +0 -0
- /package/dist/{discord-B3HUPGQ6.js.map → cost-tracker-EMOIOYH7.js.map} +0 -0
- /package/dist/{enrichment-pipeline-MNHNW65K.js.map → cron-explain-UOOOYWZZ.js.map} +0 -0
- /package/dist/{entity-resolution-Y3IUWEAT.js.map → crypto-2VG3RJR2.js.map} +0 -0
- /package/dist/{env-IWXUVTCB.js.map → databases-XDPMG5AV.js.map} +0 -0
- /package/dist/{hash-tool-ULQYD7B5.js.map → db-LRIOKQBO.js.map} +0 -0
- /package/dist/{heartbeat-monitor-GCISLXI3.js.map → discord-NKR3X4AV.js.map} +0 -0
- /package/dist/{imessage-NGA2XF2V.js.map → docx-parser-EXL4TN5E.js.map} +0 -0
- /package/dist/{inbox-summarizer-NRI4S7IF.js.map → enrichment-pipeline-CMUVBDC7.js.map} +0 -0
- /package/dist/{inventory-manager-352OHXWD.js.map → entity-resolution-4X4JU43O.js.map} +0 -0
- /package/dist/{json-tool-QE2SYHEG.js.map → env-CHOFICED.js.map} +0 -0
- /package/dist/{key-rotation-DPHU4ZTB.js.map → error-tracker-SVQSDQDW.js.map} +0 -0
- /package/dist/{google-workspace-DKWUVNGC.js.map → google-workspace-TSZPZK5G.js.map} +0 -0
- /package/dist/{mcp-3JI6W7ZE.js.map → hash-tool-ENAB5LWH.js.map} +0 -0
- /package/dist/{ocr-AC7NPX33.js.map → heartbeat-monitor-KRDYTDBF.js.map} +0 -0
- /package/dist/{ollama-BOAMSPLJ.js.map → hooks-N4MIFBVM.js.map} +0 -0
- /package/dist/{image-generation-OSU7FP6F.js.map → image-generation-MDE6AVQO.js.map} +0 -0
- /package/dist/{pages-MI523RB7.js.map → imessage-V2XNDDHT.js.map} +0 -0
- /package/dist/{pairing-IFQYCPNS.js.map → inbox-summarizer-DKKRYXDR.js.map} +0 -0
- /package/dist/{pdf-ALQVOEJR.js.map → inventory-manager-C67BSZM6.js.map} +0 -0
- /package/dist/{jira-GSGDBMIG.js.map → jira-PAGZWUBJ.js.map} +0 -0
- /package/dist/{prometheus-JNT2BD4L.js.map → json-tool-4FK5RNER.js.map} +0 -0
- /package/dist/{providers-J4LYPHDR.js.map → key-rotation-WCC5FOYS.js.map} +0 -0
- /package/dist/{qr-code-WIX4PB4U.js.map → knowledge-base-J7PJ7MZ3.js.map} +0 -0
- /package/dist/{mailchimp-KKNF6QJ7.js.map → mailchimp-ZFYDC44J.js.map} +0 -0
- /package/dist/{regex-tool-W4ABRKGK.js.map → mcp-3C2TN67D.js.map} +0 -0
- /package/dist/{scheduler-VK4WFERV.js.map → metrics-VJDWQWU7.js.map} +0 -0
- /package/dist/{microsoft365-UCBKJHNX.js.map → microsoft365-6G2IJMWC.js.map} +0 -0
- /package/dist/{search-BCLBO5E3.js.map → ocr-LGUIPKVZ.js.map} +0 -0
- /package/dist/{signal-6CGDFYL2.js.map → ollama-J7CU45WT.js.map} +0 -0
- /package/dist/{slack-IZQWIKOH.js.map → pages-XDE7JRCA.js.map} +0 -0
- /package/dist/{pair-JDFTERIK.js.map → pair-YZJFQUU5.js.map} +0 -0
- /package/dist/{sms-M3JIOTCW.js.map → pairing-77N47RAT.js.map} +0 -0
- /package/dist/{stocks-XXWBPOCU.js.map → pdf-67HGXCFJ.js.map} +0 -0
- /package/dist/{text-transform-6SGUA5Z4.js.map → pdf-parser-YLMTTYHL.js.map} +0 -0
- /package/dist/{tools-2RLEI2N6.js.map → prometheus-YETCZO4I.js.map} +0 -0
- /package/dist/{unit-converter-ZYXMEZOE.js.map → providers-H6YIC3MG.js.map} +0 -0
- /package/dist/{whatsapp-LFX6YKCM.js.map → qr-code-6WZJHRKL.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 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/integrations/email/email-parser.ts","../src/integrations/email/inbox-summarizer.ts"],"sourcesContent":["import type { EmailMessage, EmailAttachment, EmailAddress } from \"./imap-client\";\r\n\r\nexport interface ParsedEmail {\r\n id: string;\r\n subject: string;\r\n from: EmailAddress[];\r\n to: EmailAddress[];\r\n cc: EmailAddress[];\r\n date: Date;\r\n body: {\r\n text: string;\r\n html: string;\r\n snippet: string;\r\n };\r\n thread: ThreadInfo;\r\n attachments: ParsedAttachment[];\r\n metadata: EmailMetadata;\r\n}\r\n\r\nexport interface ThreadInfo {\r\n id: string;\r\n messageId: string;\r\n inReplyTo?: string;\r\n references: string[];\r\n position: number;\r\n isReply: boolean;\r\n isForward: boolean;\r\n}\r\n\r\nexport interface ParsedAttachment {\r\n filename: string;\r\n contentType: string;\r\n size: number;\r\n isInline: boolean;\r\n cid?: string;\r\n content?: Buffer;\r\n extension: string;\r\n category: \"image\" | \"document\" | \"archive\" | \"media\" | \"other\";\r\n}\r\n\r\nexport interface EmailMetadata {\r\n isRead: boolean;\r\n isFlagged: boolean;\r\n isSpam: boolean;\r\n isDraft: boolean;\r\n labels: string[];\r\n importance: \"high\" | \"normal\" | \"low\";\r\n hasAttachments: boolean;\r\n attachmentCount: number;\r\n totalAttachmentSize: number;\r\n}\r\n\r\nexport interface EmailThread {\r\n id: string;\r\n subject: string;\r\n participants: EmailAddress[];\r\n messageCount: number;\r\n unreadCount: number;\r\n lastMessageDate: Date;\r\n firstMessageDate: Date;\r\n messages: ParsedEmail[];\r\n snippet: string;\r\n}\r\n\r\nexport interface QuotedSection {\r\n level: number;\r\n content: string;\r\n attribution?: string;\r\n}\r\n\r\nexport interface EmailBodyParts {\r\n newContent: string;\r\n quotedContent: QuotedSection[];\r\n signature?: string;\r\n}\r\n\r\n/**\r\n * Parse an email message into a more structured format\r\n */\r\nexport function parseEmail(email: EmailMessage): ParsedEmail {\r\n const isReply = email.subject.toLowerCase().startsWith(\"re:\");\r\n const isForward = email.subject.toLowerCase().startsWith(\"fwd:\") ||\r\n email.subject.toLowerCase().startsWith(\"fw:\");\r\n\r\n // Calculate attachment metadata\r\n const attachments = email.attachments.map(att => parseAttachment(att));\r\n const totalAttachmentSize = attachments.reduce((sum, att) => sum + att.size, 0);\r\n\r\n // Determine importance from headers or flags\r\n let importance: \"high\" | \"normal\" | \"low\" = \"normal\";\r\n const importanceHeader = email.headers.get(\"importance\") ||\r\n email.headers.get(\"x-priority\");\r\n if (importanceHeader) {\r\n const lowerHeader = importanceHeader.toLowerCase();\r\n if (lowerHeader.includes(\"high\") || lowerHeader === \"1\" || lowerHeader === \"2\") {\r\n importance = \"high\";\r\n } else if (lowerHeader.includes(\"low\") || lowerHeader === \"5\") {\r\n importance = \"low\";\r\n }\r\n }\r\n\r\n return {\r\n id: email.id,\r\n subject: email.subject,\r\n from: email.from,\r\n to: email.to,\r\n cc: email.cc,\r\n date: email.date,\r\n body: {\r\n text: email.text,\r\n html: email.html,\r\n snippet: email.snippet || email.text.substring(0, 200).replace(/\\s+/g, \" \").trim(),\r\n },\r\n thread: {\r\n id: email.threadId || email.messageId,\r\n messageId: email.messageId,\r\n inReplyTo: email.inReplyTo,\r\n references: email.references,\r\n position: email.references.length,\r\n isReply,\r\n isForward,\r\n },\r\n attachments,\r\n metadata: {\r\n isRead: email.flags.includes(\"\\\\Seen\"),\r\n isFlagged: email.flags.includes(\"\\\\Flagged\"),\r\n isSpam: email.labels.includes(\"Spam\") || email.labels.includes(\"Junk\"),\r\n isDraft: email.flags.includes(\"\\\\Draft\"),\r\n labels: email.labels,\r\n importance,\r\n hasAttachments: attachments.length > 0,\r\n attachmentCount: attachments.length,\r\n totalAttachmentSize,\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Parse an attachment into structured format\r\n */\r\nexport function parseAttachment(attachment: EmailAttachment): ParsedAttachment {\r\n const extension = attachment.filename.includes(\".\")\r\n ? attachment.filename.split(\".\").pop()?.toLowerCase() || \"\"\r\n : \"\";\r\n\r\n return {\r\n filename: attachment.filename,\r\n contentType: attachment.contentType,\r\n size: attachment.size,\r\n isInline: !!attachment.contentId,\r\n cid: attachment.contentId,\r\n content: attachment.content,\r\n extension,\r\n category: categorizeAttachment(attachment.contentType, extension),\r\n };\r\n}\r\n\r\n/**\r\n * Categorize an attachment by its type\r\n */\r\nfunction categorizeAttachment(\r\n contentType: string,\r\n extension: string\r\n): \"image\" | \"document\" | \"archive\" | \"media\" | \"other\" {\r\n const lowerContentType = contentType.toLowerCase();\r\n\r\n // Images\r\n if (lowerContentType.startsWith(\"image/\")) {\r\n return \"image\";\r\n }\r\n\r\n // Documents\r\n const docExtensions = [\"pdf\", \"doc\", \"docx\", \"xls\", \"xlsx\", \"ppt\", \"pptx\", \"txt\", \"rtf\", \"odt\", \"ods\", \"odp\", \"csv\"];\r\n const docMimeTypes = [\r\n \"application/pdf\",\r\n \"application/msword\",\r\n \"application/vnd.openxmlformats\",\r\n \"application/vnd.ms-\",\r\n \"text/plain\",\r\n \"text/csv\",\r\n \"application/vnd.oasis.opendocument\",\r\n ];\r\n if (docExtensions.includes(extension) || docMimeTypes.some(m => lowerContentType.includes(m))) {\r\n return \"document\";\r\n }\r\n\r\n // Archives\r\n const archiveExtensions = [\"zip\", \"rar\", \"7z\", \"tar\", \"gz\", \"bz2\"];\r\n const archiveMimeTypes = [\"application/zip\", \"application/x-rar\", \"application/x-7z\", \"application/gzip\"];\r\n if (archiveExtensions.includes(extension) || archiveMimeTypes.some(m => lowerContentType.includes(m))) {\r\n return \"archive\";\r\n }\r\n\r\n // Media (audio/video)\r\n if (lowerContentType.startsWith(\"audio/\") || lowerContentType.startsWith(\"video/\")) {\r\n return \"media\";\r\n }\r\n\r\n return \"other\";\r\n}\r\n\r\n/**\r\n * Group emails into threads\r\n */\r\nexport function groupIntoThreads(emails: EmailMessage[]): EmailThread[] {\r\n const threadMap = new Map<string, EmailMessage[]>();\r\n\r\n // Group by thread ID (using references chain or Message-ID)\r\n for (const email of emails) {\r\n // Find the root message ID for this thread\r\n let threadId = email.threadId || email.messageId;\r\n\r\n if (email.references.length > 0) {\r\n // Use the first reference as the thread root\r\n threadId = email.references[0];\r\n }\r\n\r\n if (!threadMap.has(threadId)) {\r\n threadMap.set(threadId, []);\r\n }\r\n threadMap.get(threadId)!.push(email);\r\n }\r\n\r\n // Convert to EmailThread objects\r\n const threads: EmailThread[] = [];\r\n\r\n for (const [threadId, messages] of threadMap) {\r\n // Sort messages by date (oldest first)\r\n messages.sort((a, b) => a.date.getTime() - b.date.getTime());\r\n\r\n // Collect all participants\r\n const participantMap = new Map<string, EmailAddress>();\r\n for (const msg of messages) {\r\n for (const addr of [...msg.from, ...msg.to, ...msg.cc]) {\r\n if (!participantMap.has(addr.address)) {\r\n participantMap.set(addr.address, addr);\r\n }\r\n }\r\n }\r\n\r\n // Count unread\r\n const unreadCount = messages.filter(m => !m.flags.includes(\"\\\\Seen\")).length;\r\n\r\n // Get the subject (use the original, non-reply subject if possible)\r\n let subject = messages[0].subject;\r\n for (const msg of messages) {\r\n const cleaned = cleanSubject(msg.subject);\r\n if (cleaned.length > 0 && !cleaned.toLowerCase().startsWith(\"re:\")) {\r\n subject = msg.subject;\r\n break;\r\n }\r\n }\r\n\r\n threads.push({\r\n id: threadId,\r\n subject: cleanSubject(subject),\r\n participants: Array.from(participantMap.values()),\r\n messageCount: messages.length,\r\n unreadCount,\r\n lastMessageDate: messages[messages.length - 1].date,\r\n firstMessageDate: messages[0].date,\r\n messages: messages.map(parseEmail),\r\n snippet: messages[messages.length - 1].snippet ||\r\n messages[messages.length - 1].text.substring(0, 200).replace(/\\s+/g, \" \").trim(),\r\n });\r\n }\r\n\r\n // Sort threads by last message date (newest first)\r\n threads.sort((a, b) => b.lastMessageDate.getTime() - a.lastMessageDate.getTime());\r\n\r\n return threads;\r\n}\r\n\r\n/**\r\n * Clean a subject line (remove Re:, Fwd:, etc.)\r\n */\r\nexport function cleanSubject(subject: string): string {\r\n return subject\r\n .replace(/^(Re|Fwd|Fw):\\s*/gi, \"\")\r\n .replace(/^\\[.*?\\]\\s*/, \"\") // Remove list prefixes like [ListName]\r\n .trim();\r\n}\r\n\r\n/**\r\n * Parse email body to separate new content from quoted sections\r\n */\r\nexport function parseEmailBody(text: string): EmailBodyParts {\r\n const lines = text.split(\"\\n\");\r\n const newLines: string[] = [];\r\n const quotedSections: QuotedSection[] = [];\r\n let currentQuote: { level: number; lines: string[]; attribution?: string } | null = null;\r\n let signature: string | undefined;\r\n let inSignature = false;\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n const line = lines[i];\r\n\r\n // Check for signature delimiter\r\n if (line.trim() === \"--\" || line.trim() === \"-- \") {\r\n inSignature = true;\r\n signature = lines.slice(i + 1).join(\"\\n\").trim();\r\n break;\r\n }\r\n\r\n // Check for quote markers\r\n const quoteMatch = line.match(/^(>+)\\s?/);\r\n\r\n if (quoteMatch) {\r\n const level = quoteMatch[1].length;\r\n const content = line.substring(quoteMatch[0].length);\r\n\r\n if (!currentQuote || currentQuote.level !== level) {\r\n // Save previous quote section\r\n if (currentQuote) {\r\n quotedSections.push({\r\n level: currentQuote.level,\r\n content: currentQuote.lines.join(\"\\n\"),\r\n attribution: currentQuote.attribution,\r\n });\r\n }\r\n currentQuote = { level, lines: [content] };\r\n } else {\r\n currentQuote.lines.push(content);\r\n }\r\n } else if (isAttributionLine(line)) {\r\n // This is an attribution line like \"On Date, Person wrote:\"\r\n if (currentQuote) {\r\n currentQuote.attribution = line;\r\n } else {\r\n // Start of a new quoted section\r\n currentQuote = { level: 1, lines: [], attribution: line };\r\n }\r\n } else {\r\n // Regular line\r\n if (currentQuote) {\r\n quotedSections.push({\r\n level: currentQuote.level,\r\n content: currentQuote.lines.join(\"\\n\"),\r\n attribution: currentQuote.attribution,\r\n });\r\n currentQuote = null;\r\n }\r\n newLines.push(line);\r\n }\r\n }\r\n\r\n // Don't forget the last quote section\r\n if (currentQuote) {\r\n quotedSections.push({\r\n level: currentQuote.level,\r\n content: currentQuote.lines.join(\"\\n\"),\r\n attribution: currentQuote.attribution,\r\n });\r\n }\r\n\r\n return {\r\n newContent: newLines.join(\"\\n\").trim(),\r\n quotedContent: quotedSections,\r\n signature,\r\n };\r\n}\r\n\r\n/**\r\n * Check if a line is an email attribution (e.g., \"On Jan 1, Person wrote:\")\r\n */\r\nfunction isAttributionLine(line: string): boolean {\r\n const attributionPatterns = [\r\n /^On .+ wrote:$/i,\r\n /^On .+, .+ wrote:$/i,\r\n /^.+ wrote:$/i,\r\n /^-{3,}\\s*Original Message\\s*-{3,}$/i,\r\n /^-{3,}\\s*Forwarded message\\s*-{3,}$/i,\r\n /^From:\\s*.+$/i,\r\n /^Sent:\\s*.+$/i,\r\n ];\r\n\r\n return attributionPatterns.some(pattern => pattern.test(line.trim()));\r\n}\r\n\r\n/**\r\n * Extract email addresses from a text string\r\n */\r\nexport function extractEmailAddresses(text: string): string[] {\r\n const emailRegex = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}/g;\r\n const matches = text.match(emailRegex) || [];\r\n return [...new Set(matches)];\r\n}\r\n\r\n/**\r\n * Extract URLs from email text\r\n */\r\nexport function extractUrls(text: string): string[] {\r\n const urlRegex = /https?:\\/\\/[^\\s<>\"\\)]+/gi;\r\n const matches = text.match(urlRegex) || [];\r\n return [...new Set(matches)];\r\n}\r\n\r\n/**\r\n * Extract phone numbers from email text\r\n */\r\nexport function extractPhoneNumbers(text: string): string[] {\r\n const phoneRegex = /(?:\\+\\d{1,3}[-.\\s]?)?\\(?\\d{3}\\)?[-.\\s]?\\d{3}[-.\\s]?\\d{4}/g;\r\n const matches = text.match(phoneRegex) || [];\r\n return [...new Set(matches)];\r\n}\r\n\r\n/**\r\n * Get a summary of an email suitable for display\r\n */\r\nexport function getEmailSummary(email: EmailMessage | ParsedEmail): {\r\n from: string;\r\n subject: string;\r\n snippet: string;\r\n date: string;\r\n attachmentCount: number;\r\n} {\r\n const fromAddr = email.from[0];\r\n const fromDisplay = fromAddr\r\n ? fromAddr.name || fromAddr.address\r\n : \"Unknown\";\r\n\r\n const snippet = \"body\" in email\r\n ? email.body.snippet\r\n : email.snippet || email.text.substring(0, 100);\r\n\r\n const attachmentCount = \"metadata\" in email\r\n ? email.metadata.attachmentCount\r\n : email.attachments.length;\r\n\r\n return {\r\n from: fromDisplay,\r\n subject: email.subject,\r\n snippet,\r\n date: formatEmailDate(email.date),\r\n attachmentCount,\r\n };\r\n}\r\n\r\n/**\r\n * Format a date for email display\r\n */\r\nfunction formatEmailDate(date: Date): string {\r\n const now = new Date();\r\n const diff = now.getTime() - date.getTime();\r\n const days = Math.floor(diff / (1000 * 60 * 60 * 24));\r\n\r\n if (days === 0) {\r\n // Today - show time\r\n return date.toLocaleTimeString(\"en-US\", {\r\n hour: \"numeric\",\r\n minute: \"2-digit\",\r\n hour12: true,\r\n });\r\n } else if (days === 1) {\r\n return \"Yesterday\";\r\n } else if (days < 7) {\r\n // This week - show day name\r\n return date.toLocaleDateString(\"en-US\", { weekday: \"short\" });\r\n } else if (date.getFullYear() === now.getFullYear()) {\r\n // This year - show month and day\r\n return date.toLocaleDateString(\"en-US\", { month: \"short\", day: \"numeric\" });\r\n } else {\r\n // Older - show full date\r\n return date.toLocaleDateString(\"en-US\", {\r\n month: \"short\",\r\n day: \"numeric\",\r\n year: \"numeric\",\r\n });\r\n }\r\n}\r\n\r\n/**\r\n * Calculate the size of an email in bytes\r\n */\r\nexport function calculateEmailSize(email: EmailMessage): number {\r\n let size = 0;\r\n\r\n // Text content\r\n size += new TextEncoder().encode(email.text).length;\r\n size += new TextEncoder().encode(email.html).length;\r\n\r\n // Headers (estimate)\r\n size += new TextEncoder().encode(email.subject).length;\r\n size += email.from.reduce((s, a) => s + (a.name?.length || 0) + a.address.length + 10, 0);\r\n size += email.to.reduce((s, a) => s + (a.name?.length || 0) + a.address.length + 10, 0);\r\n\r\n // Attachments\r\n size += email.attachments.reduce((s, a) => s + a.size, 0);\r\n\r\n return size;\r\n}\r\n\r\n/**\r\n * Check if an email matches a filter\r\n */\r\nexport function matchesFilter(\r\n email: EmailMessage | ParsedEmail,\r\n filter: {\r\n from?: string | RegExp;\r\n to?: string | RegExp;\r\n subject?: string | RegExp;\r\n body?: string | RegExp;\r\n hasAttachments?: boolean;\r\n isUnread?: boolean;\r\n isFlagged?: boolean;\r\n dateAfter?: Date;\r\n dateBefore?: Date;\r\n }\r\n): boolean {\r\n const parsed = \"metadata\" in email ? email : parseEmail(email);\r\n\r\n // Check from\r\n if (filter.from) {\r\n const fromMatch = parsed.from.some(addr => {\r\n const str = `${addr.name} ${addr.address}`;\r\n return filter.from instanceof RegExp\r\n ? filter.from.test(str)\r\n : str.toLowerCase().includes(filter.from!.toLowerCase());\r\n });\r\n if (!fromMatch) return false;\r\n }\r\n\r\n // Check to\r\n if (filter.to) {\r\n const toMatch = parsed.to.some(addr => {\r\n const str = `${addr.name} ${addr.address}`;\r\n return filter.to instanceof RegExp\r\n ? filter.to.test(str)\r\n : str.toLowerCase().includes(filter.to!.toLowerCase());\r\n });\r\n if (!toMatch) return false;\r\n }\r\n\r\n // Check subject\r\n if (filter.subject) {\r\n const subjectMatch = filter.subject instanceof RegExp\r\n ? filter.subject.test(parsed.subject)\r\n : parsed.subject.toLowerCase().includes(filter.subject.toLowerCase());\r\n if (!subjectMatch) return false;\r\n }\r\n\r\n // Check body\r\n if (filter.body) {\r\n const bodyText = parsed.body.text;\r\n const bodyMatch = filter.body instanceof RegExp\r\n ? filter.body.test(bodyText)\r\n : bodyText.toLowerCase().includes(filter.body.toLowerCase());\r\n if (!bodyMatch) return false;\r\n }\r\n\r\n // Check attachments\r\n if (filter.hasAttachments !== undefined) {\r\n if (parsed.metadata.hasAttachments !== filter.hasAttachments) return false;\r\n }\r\n\r\n // Check read status\r\n if (filter.isUnread !== undefined) {\r\n if (parsed.metadata.isRead === filter.isUnread) return false;\r\n }\r\n\r\n // Check flagged status\r\n if (filter.isFlagged !== undefined) {\r\n if (parsed.metadata.isFlagged !== filter.isFlagged) return false;\r\n }\r\n\r\n // Check date range\r\n if (filter.dateAfter && parsed.date < filter.dateAfter) return false;\r\n if (filter.dateBefore && parsed.date > filter.dateBefore) return false;\r\n\r\n return true;\r\n}\r\n\r\nexport default {\r\n parseEmail,\r\n parseAttachment,\r\n groupIntoThreads,\r\n cleanSubject,\r\n parseEmailBody,\r\n extractEmailAddresses,\r\n extractUrls,\r\n extractPhoneNumbers,\r\n getEmailSummary,\r\n calculateEmailSize,\r\n matchesFilter,\r\n};\r\n","import { chat } from \"../../core/brain\";\nimport type { EmailMessage } from \"./imap-client\";\nimport { parseEmail, groupIntoThreads, cleanSubject, parseEmailBody } from \"./email-parser\";\nimport type { ParsedEmail, EmailThread } from \"./email-parser\";\n\nexport interface InboxSummary {\n totalEmails: number;\n unreadCount: number;\n importantCount: number;\n categories: CategorySummary[];\n urgentItems: UrgentItem[];\n actionItems: ActionItem[];\n summary: string;\n generatedAt: Date;\n}\n\nexport interface CategorySummary {\n name: string;\n count: number;\n unreadCount: number;\n topSenders: string[];\n description: string;\n}\n\nexport interface UrgentItem {\n emailId: string;\n subject: string;\n from: string;\n reason: string;\n suggestedAction: string;\n}\n\nexport interface ActionItem {\n emailId: string;\n subject: string;\n from: string;\n action: string;\n priority: \"high\" | \"medium\" | \"low\";\n dueDate?: Date;\n context: string;\n}\n\nexport interface EmailCategorization {\n category: string;\n confidence: number;\n reason: string;\n}\n\nexport interface ThreadSummary {\n threadId: string;\n subject: string;\n participantCount: number;\n messageCount: number;\n summary: string;\n currentStatus: string;\n nextSteps: string[];\n keyDecisions: string[];\n openQuestions: string[];\n}\n\nconst CATEGORIZATION_PROMPT = `You are an email categorization assistant. Analyze the following email and categorize it.\n\nCategories:\n- urgent: Time-sensitive, requires immediate attention\n- action_required: Requires a response or action from the user\n- informational: FYI, newsletters, updates that don't require action\n- meeting: Calendar invites, meeting-related emails\n- financial: Invoices, receipts, financial statements\n- social: Personal emails, social notifications\n- marketing: Promotional emails, newsletters\n- support: Customer support, help desk emails\n- work: Work-related emails that aren't urgent\n- spam: Potential spam or unwanted emails\n\nEmail:\nFrom: {{from}}\nSubject: {{subject}}\nDate: {{date}}\nSnippet: {{snippet}}\n\nRespond in JSON format:\n{\n \"category\": \"category_name\",\n \"confidence\": 0.0-1.0,\n \"reason\": \"brief explanation\"\n}`;\n\nconst ACTION_EXTRACTION_PROMPT = `You are an email assistant that extracts action items. Analyze the following email and identify any actions the recipient needs to take.\n\nEmail:\nFrom: {{from}}\nSubject: {{subject}}\nDate: {{date}}\nBody: {{body}}\n\nFor each action item found, provide:\n- action: A clear, concise description of what needs to be done\n- priority: high (urgent/deadline), medium (important but not urgent), or low (when convenient)\n- dueDate: If a specific date/time is mentioned (ISO format or null)\n- context: Brief context from the email\n\nRespond in JSON format:\n{\n \"actions\": [\n {\n \"action\": \"description\",\n \"priority\": \"high|medium|low\",\n \"dueDate\": \"ISO date or null\",\n \"context\": \"brief context\"\n }\n ]\n}\n\nIf no actions are required, return: { \"actions\": [] }`;\n\nconst INBOX_SUMMARY_PROMPT = `You are an email assistant providing a daily inbox summary. Based on the following email statistics and categories, provide a brief, helpful summary.\n\nStatistics:\n- Total emails: {{totalEmails}}\n- Unread: {{unreadCount}}\n- Important: {{importantCount}}\n\nCategories:\n{{categories}}\n\nUrgent items:\n{{urgentItems}}\n\nProvide a 2-3 sentence summary that:\n1. Highlights the most important items requiring attention\n2. Notes any patterns or notable senders\n3. Suggests prioritization if there are many items\n\nKeep it concise and actionable.`;\n\nconst THREAD_SUMMARY_PROMPT = `You are an email assistant that summarizes email threads. Analyze the following email thread and provide a comprehensive summary.\n\nThread: {{subject}}\nParticipants: {{participants}}\nMessages: {{messageCount}}\n\nMessages (oldest to newest):\n{{messages}}\n\nProvide a summary including:\n1. Brief summary of the entire conversation (2-3 sentences)\n2. Current status of the discussion\n3. Key decisions made (if any)\n4. Open questions that need resolution\n5. Suggested next steps\n\nRespond in JSON format:\n{\n \"summary\": \"conversation summary\",\n \"currentStatus\": \"status description\",\n \"keyDecisions\": [\"decision 1\", \"decision 2\"],\n \"openQuestions\": [\"question 1\", \"question 2\"],\n \"nextSteps\": [\"step 1\", \"step 2\"]\n}`;\n\n/**\n * Categorize a single email using AI\n */\nexport async function categorizeEmail(email: EmailMessage | ParsedEmail): Promise<EmailCategorization> {\n const parsed = \"metadata\" in email ? email : parseEmail(email);\n\n const fromDisplay = parsed.from[0]\n ? `${parsed.from[0].name || \"\"} <${parsed.from[0].address}>`.trim()\n : \"Unknown\";\n\n const prompt = CATEGORIZATION_PROMPT\n .replace(\"{{from}}\", fromDisplay)\n .replace(\"{{subject}}\", parsed.subject)\n .replace(\"{{date}}\", parsed.date.toISOString())\n .replace(\"{{snippet}}\", parsed.body.snippet);\n\n try {\n const response = await chat(\n [{ role: \"user\", content: prompt }],\n \"You are a helpful email categorization assistant. Always respond with valid JSON.\"\n );\n\n const result = JSON.parse(response.content);\n return {\n category: result.category || \"informational\",\n confidence: result.confidence || 0.5,\n reason: result.reason || \"\",\n };\n } catch (err) {\n console.error(\"Failed to categorize email:\", err);\n return {\n category: \"informational\",\n confidence: 0.5,\n reason: \"Failed to categorize\",\n };\n }\n}\n\n/**\n * Extract action items from an email using AI\n */\nexport async function extractActionItems(email: EmailMessage | ParsedEmail): Promise<ActionItem[]> {\n const parsed = \"metadata\" in email ? email : parseEmail(email);\n\n const fromDisplay = parsed.from[0]\n ? `${parsed.from[0].name || \"\"} <${parsed.from[0].address}>`.trim()\n : \"Unknown\";\n\n // Parse the email body to get just the new content (not quoted parts)\n const bodyParts = parseEmailBody(parsed.body.text);\n const relevantBody = bodyParts.newContent || parsed.body.text.substring(0, 2000);\n\n const prompt = ACTION_EXTRACTION_PROMPT\n .replace(\"{{from}}\", fromDisplay)\n .replace(\"{{subject}}\", parsed.subject)\n .replace(\"{{date}}\", parsed.date.toISOString())\n .replace(\"{{body}}\", relevantBody);\n\n try {\n const response = await chat(\n [{ role: \"user\", content: prompt }],\n \"You are a helpful email assistant that extracts action items. Always respond with valid JSON.\"\n );\n\n const result = JSON.parse(response.content);\n\n return (result.actions || []).map((action: {\n action: string;\n priority: string;\n dueDate?: string | null;\n context: string;\n }) => ({\n emailId: parsed.id,\n subject: parsed.subject,\n from: fromDisplay,\n action: action.action,\n priority: ([\"high\", \"medium\", \"low\"].includes(action.priority) ? action.priority : \"medium\") as \"high\" | \"medium\" | \"low\",\n dueDate: action.dueDate ? new Date(action.dueDate) : undefined,\n context: action.context,\n }));\n } catch (err) {\n console.error(\"Failed to extract action items:\", err);\n return [];\n }\n}\n\n/**\n * Summarize an email thread using AI\n */\nexport async function summarizeThread(thread: EmailThread): Promise<ThreadSummary> {\n const participants = thread.participants\n .map(p => p.name || p.address)\n .slice(0, 10)\n .join(\", \");\n\n // Build message content (limited to avoid token limits)\n const messageContent = thread.messages\n .slice(-10) // Last 10 messages\n .map((msg, idx) => {\n const from = msg.from[0]?.name || msg.from[0]?.address || \"Unknown\";\n const bodyParts = parseEmailBody(msg.body.text);\n const content = (bodyParts.newContent || msg.body.snippet).substring(0, 500);\n return `[${idx + 1}] From: ${from}\\nDate: ${msg.date.toISOString()}\\n${content}`;\n })\n .join(\"\\n\\n---\\n\\n\");\n\n const prompt = THREAD_SUMMARY_PROMPT\n .replace(\"{{subject}}\", thread.subject)\n .replace(\"{{participants}}\", participants)\n .replace(\"{{messageCount}}\", String(thread.messageCount))\n .replace(\"{{messages}}\", messageContent);\n\n try {\n const response = await chat(\n [{ role: \"user\", content: prompt }],\n \"You are a helpful email assistant that summarizes email threads. Always respond with valid JSON.\"\n );\n\n const result = JSON.parse(response.content);\n\n return {\n threadId: thread.id,\n subject: thread.subject,\n participantCount: thread.participants.length,\n messageCount: thread.messageCount,\n summary: result.summary || \"No summary available\",\n currentStatus: result.currentStatus || \"Unknown\",\n nextSteps: result.nextSteps || [],\n keyDecisions: result.keyDecisions || [],\n openQuestions: result.openQuestions || [],\n };\n } catch (err) {\n console.error(\"Failed to summarize thread:\", err);\n return {\n threadId: thread.id,\n subject: thread.subject,\n participantCount: thread.participants.length,\n messageCount: thread.messageCount,\n summary: \"Failed to generate summary\",\n currentStatus: \"Unknown\",\n nextSteps: [],\n keyDecisions: [],\n openQuestions: [],\n };\n }\n}\n\n/**\n * Generate a comprehensive inbox summary\n */\nexport async function summarizeInbox(emails: EmailMessage[]): Promise<InboxSummary> {\n // Parse and categorize all emails\n const parsedEmails = emails.map(parseEmail);\n const categorizations = await Promise.all(\n parsedEmails.slice(0, 100).map(async email => ({\n email,\n categorization: await categorizeEmail(email),\n }))\n );\n\n // Count statistics\n const totalEmails = emails.length;\n const unreadCount = parsedEmails.filter(e => !e.metadata.isRead).length;\n const importantCount = categorizations.filter(\n c => c.categorization.category === \"urgent\" || c.categorization.category === \"action_required\"\n ).length;\n\n // Group by category\n const categoryMap = new Map<string, { emails: ParsedEmail[]; senders: Set<string> }>();\n\n for (const { email, categorization } of categorizations) {\n const cat = categorization.category;\n if (!categoryMap.has(cat)) {\n categoryMap.set(cat, { emails: [], senders: new Set() });\n }\n const entry = categoryMap.get(cat)!;\n entry.emails.push(email);\n if (email.from[0]) {\n entry.senders.add(email.from[0].name || email.from[0].address);\n }\n }\n\n const categories: CategorySummary[] = [];\n for (const [name, data] of categoryMap) {\n categories.push({\n name,\n count: data.emails.length,\n unreadCount: data.emails.filter(e => !e.metadata.isRead).length,\n topSenders: Array.from(data.senders).slice(0, 5),\n description: getCategoryDescription(name),\n });\n }\n\n // Sort categories by count\n categories.sort((a, b) => b.count - a.count);\n\n // Identify urgent items\n const urgentItems: UrgentItem[] = [];\n for (const { email, categorization } of categorizations) {\n if (categorization.category === \"urgent\") {\n urgentItems.push({\n emailId: email.id,\n subject: email.subject,\n from: email.from[0]?.name || email.from[0]?.address || \"Unknown\",\n reason: categorization.reason,\n suggestedAction: \"Review and respond as soon as possible\",\n });\n }\n }\n\n // Extract action items from action_required emails\n const actionItems: ActionItem[] = [];\n const actionRequiredEmails = categorizations\n .filter(c => c.categorization.category === \"action_required\")\n .slice(0, 10);\n\n for (const { email } of actionRequiredEmails) {\n const items = await extractActionItems(email);\n actionItems.push(...items);\n }\n\n // Sort action items by priority\n actionItems.sort((a, b) => {\n const priorityOrder = { high: 0, medium: 1, low: 2 };\n return priorityOrder[a.priority] - priorityOrder[b.priority];\n });\n\n // Generate summary text\n const categoriesText = categories\n .map(c => `- ${c.name}: ${c.count} emails (${c.unreadCount} unread)`)\n .join(\"\\n\");\n\n const urgentText = urgentItems.length > 0\n ? urgentItems.map(u => `- \"${u.subject}\" from ${u.from}`).join(\"\\n\")\n : \"None\";\n\n const summaryPrompt = INBOX_SUMMARY_PROMPT\n .replace(\"{{totalEmails}}\", String(totalEmails))\n .replace(\"{{unreadCount}}\", String(unreadCount))\n .replace(\"{{importantCount}}\", String(importantCount))\n .replace(\"{{categories}}\", categoriesText)\n .replace(\"{{urgentItems}}\", urgentText);\n\n let summary = \"\";\n try {\n const response = await chat(\n [{ role: \"user\", content: summaryPrompt }],\n \"You are a helpful email assistant providing inbox summaries. Be concise and actionable.\"\n );\n summary = response.content;\n } catch (err) {\n console.error(\"Failed to generate summary:\", err);\n summary = `You have ${totalEmails} emails, ${unreadCount} unread. ${importantCount} require attention.`;\n }\n\n return {\n totalEmails,\n unreadCount,\n importantCount,\n categories,\n urgentItems,\n actionItems: actionItems.slice(0, 20),\n summary,\n generatedAt: new Date(),\n };\n}\n\n/**\n * Generate a daily digest summary\n */\nexport async function generateDailyDigest(emails: EmailMessage[]): Promise<string> {\n const summary = await summarizeInbox(emails);\n\n let digest = `# Daily Email Digest\\n\\n`;\n digest += `*Generated: ${summary.generatedAt.toLocaleString()}*\\n\\n`;\n\n // Overview\n digest += `## Overview\\n\\n`;\n digest += `${summary.summary}\\n\\n`;\n digest += `- **Total Emails:** ${summary.totalEmails}\\n`;\n digest += `- **Unread:** ${summary.unreadCount}\\n`;\n digest += `- **Needs Attention:** ${summary.importantCount}\\n\\n`;\n\n // Urgent items\n if (summary.urgentItems.length > 0) {\n digest += `## Urgent\\n\\n`;\n for (const item of summary.urgentItems) {\n digest += `- **${item.subject}** from ${item.from}\\n`;\n digest += ` *${item.reason}*\\n\\n`;\n }\n }\n\n // Action items\n if (summary.actionItems.length > 0) {\n digest += `## Action Items\\n\\n`;\n for (const item of summary.actionItems) {\n const priority = item.priority === \"high\" ? \"!!!\" : item.priority === \"medium\" ? \"!!\" : \"!\";\n digest += `- [${priority}] **${item.action}**\\n`;\n digest += ` From: ${item.from} | ${item.context}\\n`;\n if (item.dueDate) {\n digest += ` Due: ${item.dueDate.toLocaleDateString()}\\n`;\n }\n digest += \"\\n\";\n }\n }\n\n // Categories breakdown\n digest += `## By Category\\n\\n`;\n for (const cat of summary.categories.slice(0, 8)) {\n digest += `- **${cat.name}:** ${cat.count} emails`;\n if (cat.unreadCount > 0) {\n digest += ` (${cat.unreadCount} unread)`;\n }\n digest += \"\\n\";\n if (cat.topSenders.length > 0) {\n digest += ` Top senders: ${cat.topSenders.slice(0, 3).join(\", \")}\\n`;\n }\n }\n\n return digest;\n}\n\n/**\n * Smart reply suggestions for an email\n */\nexport async function suggestReplies(email: EmailMessage | ParsedEmail): Promise<string[]> {\n const parsed = \"metadata\" in email ? email : parseEmail(email);\n\n const fromDisplay = parsed.from[0]\n ? `${parsed.from[0].name || \"\"} <${parsed.from[0].address}>`.trim()\n : \"Unknown\";\n\n const bodyParts = parseEmailBody(parsed.body.text);\n const relevantBody = (bodyParts.newContent || parsed.body.text).substring(0, 1500);\n\n const prompt = `You are an email assistant suggesting reply options. Based on the following email, suggest 3 brief reply options ranging from formal to casual.\n\nEmail:\nFrom: ${fromDisplay}\nSubject: ${parsed.subject}\nBody: ${relevantBody}\n\nProvide 3 reply suggestions:\n1. A brief, professional response\n2. A friendly but complete response\n3. A quick, informal response\n\nRespond in JSON format:\n{\n \"replies\": [\"reply 1\", \"reply 2\", \"reply 3\"]\n}`;\n\n try {\n const response = await chat(\n [{ role: \"user\", content: prompt }],\n \"You are a helpful email assistant. Always respond with valid JSON.\"\n );\n\n const result = JSON.parse(response.content);\n return result.replies || [];\n } catch (err) {\n console.error(\"Failed to suggest replies:\", err);\n return [];\n }\n}\n\n/**\n * Analyze email sentiment\n */\nexport async function analyzeSentiment(email: EmailMessage | ParsedEmail): Promise<{\n sentiment: \"positive\" | \"negative\" | \"neutral\";\n confidence: number;\n tone: string;\n keyPhrases: string[];\n}> {\n const parsed = \"metadata\" in email ? email : parseEmail(email);\n\n const bodyParts = parseEmailBody(parsed.body.text);\n const relevantBody = (bodyParts.newContent || parsed.body.text).substring(0, 1500);\n\n const prompt = `Analyze the sentiment and tone of this email:\n\nSubject: ${parsed.subject}\nBody: ${relevantBody}\n\nRespond in JSON format:\n{\n \"sentiment\": \"positive|negative|neutral\",\n \"confidence\": 0.0-1.0,\n \"tone\": \"brief description of tone (e.g., 'urgent', 'friendly', 'formal', 'frustrated')\",\n \"keyPhrases\": [\"phrase1\", \"phrase2\", \"phrase3\"]\n}`;\n\n try {\n const response = await chat(\n [{ role: \"user\", content: prompt }],\n \"You are a helpful sentiment analysis assistant. Always respond with valid JSON.\"\n );\n\n const result = JSON.parse(response.content);\n return {\n sentiment: result.sentiment || \"neutral\",\n confidence: result.confidence || 0.5,\n tone: result.tone || \"neutral\",\n keyPhrases: result.keyPhrases || [],\n };\n } catch (err) {\n console.error(\"Failed to analyze sentiment:\", err);\n return {\n sentiment: \"neutral\",\n confidence: 0.5,\n tone: \"neutral\",\n keyPhrases: [],\n };\n }\n}\n\n/**\n * Get description for a category\n */\nfunction getCategoryDescription(category: string): string {\n const descriptions: Record<string, string> = {\n urgent: \"Time-sensitive emails requiring immediate attention\",\n action_required: \"Emails that need your response or action\",\n informational: \"FYI emails and updates\",\n meeting: \"Calendar invites and meeting-related emails\",\n financial: \"Invoices, receipts, and financial communications\",\n social: \"Personal and social notifications\",\n marketing: \"Promotional emails and newsletters\",\n support: \"Customer support and help desk communications\",\n work: \"Work-related emails\",\n spam: \"Potentially unwanted emails\",\n };\n return descriptions[category] || \"Other emails\";\n}\n\nexport default {\n categorizeEmail,\n extractActionItems,\n summarizeThread,\n summarizeInbox,\n generateDailyDigest,\n suggestReplies,\n analyzeSentiment,\n};\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// src/core/ml/linear-regression.ts
|
|
2
|
+
var LinearRegression = class _LinearRegression {
|
|
3
|
+
slope = 0;
|
|
4
|
+
intercept = 0;
|
|
5
|
+
rSquared = 0;
|
|
6
|
+
standardError = 0;
|
|
7
|
+
n = 0;
|
|
8
|
+
meanX = 0;
|
|
9
|
+
sumXXDeviation = 0;
|
|
10
|
+
trained = false;
|
|
11
|
+
/**
|
|
12
|
+
* Fit the model to data.
|
|
13
|
+
* @param x Independent variable values
|
|
14
|
+
* @param y Dependent variable values
|
|
15
|
+
*/
|
|
16
|
+
fit(x, y) {
|
|
17
|
+
if (x.length !== y.length || x.length < 2) {
|
|
18
|
+
return { slope: 0, intercept: 0, rSquared: 0, standardError: 0, n: 0 };
|
|
19
|
+
}
|
|
20
|
+
this.n = x.length;
|
|
21
|
+
this.meanX = x.reduce((s, v) => s + v, 0) / this.n;
|
|
22
|
+
const meanY = y.reduce((s, v) => s + v, 0) / this.n;
|
|
23
|
+
let sumXYDeviation = 0;
|
|
24
|
+
this.sumXXDeviation = 0;
|
|
25
|
+
for (let i = 0; i < this.n; i++) {
|
|
26
|
+
const dx = x[i] - this.meanX;
|
|
27
|
+
const dy = y[i] - meanY;
|
|
28
|
+
sumXYDeviation += dx * dy;
|
|
29
|
+
this.sumXXDeviation += dx * dx;
|
|
30
|
+
}
|
|
31
|
+
this.slope = this.sumXXDeviation > 0 ? sumXYDeviation / this.sumXXDeviation : 0;
|
|
32
|
+
this.intercept = meanY - this.slope * this.meanX;
|
|
33
|
+
let ssRes = 0;
|
|
34
|
+
let ssTot = 0;
|
|
35
|
+
for (let i = 0; i < this.n; i++) {
|
|
36
|
+
const predicted = this.slope * x[i] + this.intercept;
|
|
37
|
+
ssRes += (y[i] - predicted) ** 2;
|
|
38
|
+
ssTot += (y[i] - meanY) ** 2;
|
|
39
|
+
}
|
|
40
|
+
this.rSquared = ssTot > 0 ? 1 - ssRes / ssTot : 0;
|
|
41
|
+
this.standardError = this.n > 2 ? Math.sqrt(ssRes / (this.n - 2)) : 0;
|
|
42
|
+
this.trained = true;
|
|
43
|
+
return {
|
|
44
|
+
slope: this.slope,
|
|
45
|
+
intercept: this.intercept,
|
|
46
|
+
rSquared: this.rSquared,
|
|
47
|
+
standardError: this.standardError,
|
|
48
|
+
n: this.n
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Predict y for a given x, with confidence interval.
|
|
53
|
+
*/
|
|
54
|
+
predict(x) {
|
|
55
|
+
if (!this.trained) return { value: 0, lower95: 0, upper95: 0 };
|
|
56
|
+
const value = this.slope * x + this.intercept;
|
|
57
|
+
const t = 1.96;
|
|
58
|
+
const dx = x - this.meanX;
|
|
59
|
+
const predictionSE = this.standardError * Math.sqrt(
|
|
60
|
+
1 + 1 / this.n + (this.sumXXDeviation > 0 ? dx * dx / this.sumXXDeviation : 0)
|
|
61
|
+
);
|
|
62
|
+
return {
|
|
63
|
+
value,
|
|
64
|
+
lower95: value - t * predictionSE,
|
|
65
|
+
upper95: value + t * predictionSE
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Predict multiple values.
|
|
70
|
+
*/
|
|
71
|
+
predictBatch(xValues) {
|
|
72
|
+
return xValues.map((x) => this.predict(x));
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Forecast future values for a time series.
|
|
76
|
+
* @param historicalY Array of historical values (assumes x = 0, 1, 2, ...)
|
|
77
|
+
* @param stepsAhead How many steps to forecast
|
|
78
|
+
*/
|
|
79
|
+
static forecast(historicalY, stepsAhead) {
|
|
80
|
+
const x = historicalY.map((_, i) => i);
|
|
81
|
+
const model = new _LinearRegression();
|
|
82
|
+
model.fit(x, historicalY);
|
|
83
|
+
const predictions = [];
|
|
84
|
+
for (let i = 0; i < stepsAhead; i++) {
|
|
85
|
+
predictions.push(model.predict(historicalY.length + i));
|
|
86
|
+
}
|
|
87
|
+
return predictions;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Detect trend direction and strength.
|
|
91
|
+
*/
|
|
92
|
+
static detectTrend(values) {
|
|
93
|
+
if (values.length < 2) return { direction: "flat", strength: 0, slopePerUnit: 0 };
|
|
94
|
+
const x = values.map((_, i) => i);
|
|
95
|
+
const model = new _LinearRegression();
|
|
96
|
+
const result = model.fit(x, values);
|
|
97
|
+
const avgValue = values.reduce((s, v) => s + v, 0) / values.length;
|
|
98
|
+
const normalizedSlope = avgValue !== 0 ? result.slope / avgValue : 0;
|
|
99
|
+
let direction;
|
|
100
|
+
if (Math.abs(normalizedSlope) < 0.01) {
|
|
101
|
+
direction = "flat";
|
|
102
|
+
} else {
|
|
103
|
+
direction = normalizedSlope > 0 ? "up" : "down";
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
direction,
|
|
107
|
+
strength: result.rSquared,
|
|
108
|
+
slopePerUnit: result.slope
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
getResult() {
|
|
112
|
+
if (!this.trained) return null;
|
|
113
|
+
return {
|
|
114
|
+
slope: this.slope,
|
|
115
|
+
intercept: this.intercept,
|
|
116
|
+
rSquared: this.rSquared,
|
|
117
|
+
standardError: this.standardError,
|
|
118
|
+
n: this.n
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
isReady() {
|
|
122
|
+
return this.trained;
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export {
|
|
127
|
+
LinearRegression
|
|
128
|
+
};
|
|
129
|
+
//# sourceMappingURL=chunk-WZAH34TG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/ml/linear-regression.ts"],"sourcesContent":["/**\r\n * Linear Regression — Prediction & Forecasting (Algorithm #1)\r\n *\r\n * Pure TypeScript implementation. No external dependencies.\r\n *\r\n * How it works:\r\n * - Ordinary Least Squares (OLS) for single variable\r\n * - Fits y = mx + b to minimize sum of squared errors\r\n * - Supports confidence intervals and R² scoring\r\n *\r\n * Used in: cost-tracker.ts (cost forecasting),\r\n * pattern-analyzer.ts (trend detection)\r\n */\r\n\r\nexport interface RegressionResult {\r\n /** Slope (m in y = mx + b) */\r\n slope: number;\r\n /** Intercept (b in y = mx + b) */\r\n intercept: number;\r\n /** R² score (0–1, higher = better fit) */\r\n rSquared: number;\r\n /** Standard error of the estimate */\r\n standardError: number;\r\n /** Number of data points used */\r\n n: number;\r\n}\r\n\r\nexport interface Prediction {\r\n /** Predicted value */\r\n value: number;\r\n /** Lower bound of 95% confidence interval */\r\n lower95: number;\r\n /** Upper bound of 95% confidence interval */\r\n upper95: number;\r\n}\r\n\r\nexport class LinearRegression {\r\n private slope = 0;\r\n private intercept = 0;\r\n private rSquared = 0;\r\n private standardError = 0;\r\n private n = 0;\r\n private meanX = 0;\r\n private sumXXDeviation = 0;\r\n private trained = false;\r\n\r\n /**\r\n * Fit the model to data.\r\n * @param x Independent variable values\r\n * @param y Dependent variable values\r\n */\r\n fit(x: number[], y: number[]): RegressionResult {\r\n if (x.length !== y.length || x.length < 2) {\r\n return { slope: 0, intercept: 0, rSquared: 0, standardError: 0, n: 0 };\r\n }\r\n\r\n this.n = x.length;\r\n\r\n // Compute means\r\n this.meanX = x.reduce((s, v) => s + v, 0) / this.n;\r\n const meanY = y.reduce((s, v) => s + v, 0) / this.n;\r\n\r\n // Compute slope and intercept using OLS\r\n let sumXYDeviation = 0;\r\n this.sumXXDeviation = 0;\r\n\r\n for (let i = 0; i < this.n; i++) {\r\n const dx = x[i] - this.meanX;\r\n const dy = y[i] - meanY;\r\n sumXYDeviation += dx * dy;\r\n this.sumXXDeviation += dx * dx;\r\n }\r\n\r\n this.slope = this.sumXXDeviation > 0 ? sumXYDeviation / this.sumXXDeviation : 0;\r\n this.intercept = meanY - this.slope * this.meanX;\r\n\r\n // Compute R² and standard error\r\n let ssRes = 0;\r\n let ssTot = 0;\r\n for (let i = 0; i < this.n; i++) {\r\n const predicted = this.slope * x[i] + this.intercept;\r\n ssRes += (y[i] - predicted) ** 2;\r\n ssTot += (y[i] - meanY) ** 2;\r\n }\r\n\r\n this.rSquared = ssTot > 0 ? 1 - ssRes / ssTot : 0;\r\n this.standardError = this.n > 2 ? Math.sqrt(ssRes / (this.n - 2)) : 0;\r\n this.trained = true;\r\n\r\n return {\r\n slope: this.slope,\r\n intercept: this.intercept,\r\n rSquared: this.rSquared,\r\n standardError: this.standardError,\r\n n: this.n,\r\n };\r\n }\r\n\r\n /**\r\n * Predict y for a given x, with confidence interval.\r\n */\r\n predict(x: number): Prediction {\r\n if (!this.trained) return { value: 0, lower95: 0, upper95: 0 };\r\n\r\n const value = this.slope * x + this.intercept;\r\n\r\n // 95% prediction interval (t ≈ 1.96 for large n)\r\n const t = 1.96;\r\n const dx = x - this.meanX;\r\n const predictionSE = this.standardError * Math.sqrt(\r\n 1 + 1 / this.n + (this.sumXXDeviation > 0 ? (dx * dx) / this.sumXXDeviation : 0)\r\n );\r\n\r\n return {\r\n value,\r\n lower95: value - t * predictionSE,\r\n upper95: value + t * predictionSE,\r\n };\r\n }\r\n\r\n /**\r\n * Predict multiple values.\r\n */\r\n predictBatch(xValues: number[]): Prediction[] {\r\n return xValues.map((x) => this.predict(x));\r\n }\r\n\r\n /**\r\n * Forecast future values for a time series.\r\n * @param historicalY Array of historical values (assumes x = 0, 1, 2, ...)\r\n * @param stepsAhead How many steps to forecast\r\n */\r\n static forecast(historicalY: number[], stepsAhead: number): Prediction[] {\r\n const x = historicalY.map((_, i) => i);\r\n const model = new LinearRegression();\r\n model.fit(x, historicalY);\r\n\r\n const predictions: Prediction[] = [];\r\n for (let i = 0; i < stepsAhead; i++) {\r\n predictions.push(model.predict(historicalY.length + i));\r\n }\r\n return predictions;\r\n }\r\n\r\n /**\r\n * Detect trend direction and strength.\r\n */\r\n static detectTrend(values: number[]): {\r\n direction: \"up\" | \"down\" | \"flat\";\r\n strength: number;\r\n slopePerUnit: number;\r\n } {\r\n if (values.length < 2) return { direction: \"flat\", strength: 0, slopePerUnit: 0 };\r\n\r\n const x = values.map((_, i) => i);\r\n const model = new LinearRegression();\r\n const result = model.fit(x, values);\r\n\r\n const avgValue = values.reduce((s, v) => s + v, 0) / values.length;\r\n const normalizedSlope = avgValue !== 0 ? result.slope / avgValue : 0;\r\n\r\n let direction: \"up\" | \"down\" | \"flat\";\r\n if (Math.abs(normalizedSlope) < 0.01) {\r\n direction = \"flat\";\r\n } else {\r\n direction = normalizedSlope > 0 ? \"up\" : \"down\";\r\n }\r\n\r\n return {\r\n direction,\r\n strength: result.rSquared,\r\n slopePerUnit: result.slope,\r\n };\r\n }\r\n\r\n getResult(): RegressionResult | null {\r\n if (!this.trained) return null;\r\n return {\r\n slope: this.slope,\r\n intercept: this.intercept,\r\n rSquared: this.rSquared,\r\n standardError: this.standardError,\r\n n: this.n,\r\n };\r\n }\r\n\r\n isReady(): boolean {\r\n return this.trained;\r\n }\r\n}\r\n"],"mappings":";AAoCO,IAAM,mBAAN,MAAM,kBAAiB;AAAA,EACpB,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,gBAAgB;AAAA,EAChB,IAAI;AAAA,EACJ,QAAQ;AAAA,EACR,iBAAiB;AAAA,EACjB,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOlB,IAAI,GAAa,GAA+B;AAC9C,QAAI,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,GAAG;AACzC,aAAO,EAAE,OAAO,GAAG,WAAW,GAAG,UAAU,GAAG,eAAe,GAAG,GAAG,EAAE;AAAA,IACvE;AAEA,SAAK,IAAI,EAAE;AAGX,SAAK,QAAQ,EAAE,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC,IAAI,KAAK;AACjD,UAAM,QAAQ,EAAE,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC,IAAI,KAAK;AAGlD,QAAI,iBAAiB;AACrB,SAAK,iBAAiB;AAEtB,aAAS,IAAI,GAAG,IAAI,KAAK,GAAG,KAAK;AAC/B,YAAM,KAAK,EAAE,CAAC,IAAI,KAAK;AACvB,YAAM,KAAK,EAAE,CAAC,IAAI;AAClB,wBAAkB,KAAK;AACvB,WAAK,kBAAkB,KAAK;AAAA,IAC9B;AAEA,SAAK,QAAQ,KAAK,iBAAiB,IAAI,iBAAiB,KAAK,iBAAiB;AAC9E,SAAK,YAAY,QAAQ,KAAK,QAAQ,KAAK;AAG3C,QAAI,QAAQ;AACZ,QAAI,QAAQ;AACZ,aAAS,IAAI,GAAG,IAAI,KAAK,GAAG,KAAK;AAC/B,YAAM,YAAY,KAAK,QAAQ,EAAE,CAAC,IAAI,KAAK;AAC3C,gBAAU,EAAE,CAAC,IAAI,cAAc;AAC/B,gBAAU,EAAE,CAAC,IAAI,UAAU;AAAA,IAC7B;AAEA,SAAK,WAAW,QAAQ,IAAI,IAAI,QAAQ,QAAQ;AAChD,SAAK,gBAAgB,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,KAAK,IAAI,EAAE,IAAI;AACpE,SAAK,UAAU;AAEf,WAAO;AAAA,MACL,OAAO,KAAK;AAAA,MACZ,WAAW,KAAK;AAAA,MAChB,UAAU,KAAK;AAAA,MACf,eAAe,KAAK;AAAA,MACpB,GAAG,KAAK;AAAA,IACV;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ,GAAuB;AAC7B,QAAI,CAAC,KAAK,QAAS,QAAO,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,EAAE;AAE7D,UAAM,QAAQ,KAAK,QAAQ,IAAI,KAAK;AAGpC,UAAM,IAAI;AACV,UAAM,KAAK,IAAI,KAAK;AACpB,UAAM,eAAe,KAAK,gBAAgB,KAAK;AAAA,MAC7C,IAAI,IAAI,KAAK,KAAK,KAAK,iBAAiB,IAAK,KAAK,KAAM,KAAK,iBAAiB;AAAA,IAChF;AAEA,WAAO;AAAA,MACL;AAAA,MACA,SAAS,QAAQ,IAAI;AAAA,MACrB,SAAS,QAAQ,IAAI;AAAA,IACvB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,SAAiC;AAC5C,WAAO,QAAQ,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OAAO,SAAS,aAAuB,YAAkC;AACvE,UAAM,IAAI,YAAY,IAAI,CAAC,GAAG,MAAM,CAAC;AACrC,UAAM,QAAQ,IAAI,kBAAiB;AACnC,UAAM,IAAI,GAAG,WAAW;AAExB,UAAM,cAA4B,CAAC;AACnC,aAAS,IAAI,GAAG,IAAI,YAAY,KAAK;AACnC,kBAAY,KAAK,MAAM,QAAQ,YAAY,SAAS,CAAC,CAAC;AAAA,IACxD;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,YAAY,QAIjB;AACA,QAAI,OAAO,SAAS,EAAG,QAAO,EAAE,WAAW,QAAQ,UAAU,GAAG,cAAc,EAAE;AAEhF,UAAM,IAAI,OAAO,IAAI,CAAC,GAAG,MAAM,CAAC;AAChC,UAAM,QAAQ,IAAI,kBAAiB;AACnC,UAAM,SAAS,MAAM,IAAI,GAAG,MAAM;AAElC,UAAM,WAAW,OAAO,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC,IAAI,OAAO;AAC5D,UAAM,kBAAkB,aAAa,IAAI,OAAO,QAAQ,WAAW;AAEnE,QAAI;AACJ,QAAI,KAAK,IAAI,eAAe,IAAI,MAAM;AACpC,kBAAY;AAAA,IACd,OAAO;AACL,kBAAY,kBAAkB,IAAI,OAAO;AAAA,IAC3C;AAEA,WAAO;AAAA,MACL;AAAA,MACA,UAAU,OAAO;AAAA,MACjB,cAAc,OAAO;AAAA,IACvB;AAAA,EACF;AAAA,EAEA,YAAqC;AACnC,QAAI,CAAC,KAAK,QAAS,QAAO;AAC1B,WAAO;AAAA,MACL,OAAO,KAAK;AAAA,MACZ,WAAW,KAAK;AAAA,MAChB,UAAU,KAAK;AAAA,MACf,eAAe,KAAK;AAAA,MACpB,GAAG,KAAK;AAAA,IACV;AAAA,EACF;AAAA,EAEA,UAAmB;AACjB,WAAO,KAAK;AAAA,EACd;AACF;","names":[]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getNotionClient,
|
|
3
3
|
init_client
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-C6PELIHS.js";
|
|
5
5
|
|
|
6
6
|
// src/integrations/notion/search.ts
|
|
7
7
|
init_client();
|
|
@@ -30,8 +30,8 @@ function pageToSearchResult(page) {
|
|
|
30
30
|
createdTime: page.created_time,
|
|
31
31
|
lastEditedTime: page.last_edited_time,
|
|
32
32
|
archived: page.archived,
|
|
33
|
-
icon: page.icon?.type === "emoji" ? page.icon.emoji : page.icon?.type === "external" ? page.icon.external
|
|
34
|
-
cover: page.cover?.type === "external" ? page.cover.external
|
|
33
|
+
icon: page.icon?.type === "emoji" ? page.icon.emoji : page.icon?.type === "external" ? page.icon.external?.url : void 0,
|
|
34
|
+
cover: page.cover?.type === "external" ? page.cover.external?.url : page.cover?.type === "file" ? page.cover.file?.url : void 0,
|
|
35
35
|
parent
|
|
36
36
|
};
|
|
37
37
|
}
|
|
@@ -51,8 +51,8 @@ function databaseToSearchResult(database) {
|
|
|
51
51
|
createdTime: database.created_time,
|
|
52
52
|
lastEditedTime: database.last_edited_time,
|
|
53
53
|
isInline: database.is_inline,
|
|
54
|
-
icon: database.icon?.type === "emoji" ? database.icon.emoji : database.icon?.type === "external" ? database.icon.external
|
|
55
|
-
cover: database.cover?.type === "external" ? database.cover.external
|
|
54
|
+
icon: database.icon?.type === "emoji" ? database.icon.emoji : database.icon?.type === "external" ? database.icon.external?.url : void 0,
|
|
55
|
+
cover: database.cover?.type === "external" ? database.cover.external?.url : database.cover?.type === "file" ? database.cover.file?.url : void 0,
|
|
56
56
|
parent
|
|
57
57
|
};
|
|
58
58
|
}
|
|
@@ -187,4 +187,4 @@ export {
|
|
|
187
187
|
getRecentlyEditedDatabases,
|
|
188
188
|
fullTextSearch
|
|
189
189
|
};
|
|
190
|
-
//# sourceMappingURL=chunk-
|
|
190
|
+
//# sourceMappingURL=chunk-X6Q3K3L2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/integrations/notion/search.ts"],"sourcesContent":["import { getNotionClient } from \"./client\";\r\n\r\n/**\r\n * Search functionality for Notion workspace\r\n * Supports searching across pages and databases\r\n */\r\n\r\n// Type definitions for API responses\r\ninterface PageObjectResponse {\r\n object: \"page\";\r\n id: string;\r\n url: string;\r\n created_time: string;\r\n last_edited_time: string;\r\n archived: boolean;\r\n icon?: { type: string; emoji?: string; external?: { url: string } };\r\n cover?: { type: string; external?: { url: string }; file?: { url: string } };\r\n parent: { type: string; page_id?: string; database_id?: string };\r\n properties: Record<string, any>;\r\n}\r\n\r\ninterface DatabaseObjectResponse {\r\n object: \"database\";\r\n id: string;\r\n url: string;\r\n title: Array<{ plain_text: string }>;\r\n description: Array<{ plain_text: string }>;\r\n created_time: string;\r\n last_edited_time: string;\r\n is_inline: boolean;\r\n icon?: { type: string; emoji?: string; external?: { url: string } };\r\n cover?: { type: string; external?: { url: string }; file?: { url: string } };\r\n parent: { type: string; page_id?: string };\r\n}\r\n\r\ninterface SearchParams {\r\n query?: string;\r\n filter?: any;\r\n sort?: any;\r\n start_cursor?: string;\r\n page_size?: number;\r\n}\r\n\r\nexport type SearchObjectType = \"page\" | \"database\";\r\n\r\nexport interface SearchOptions {\r\n query?: string;\r\n filter?: {\r\n value: SearchObjectType;\r\n property: \"object\";\r\n };\r\n sort?: {\r\n direction: \"ascending\" | \"descending\";\r\n timestamp: \"last_edited_time\";\r\n };\r\n startCursor?: string;\r\n pageSize?: number;\r\n}\r\n\r\nexport interface SearchResultPage {\r\n type: \"page\";\r\n id: string;\r\n url: string;\r\n title: string;\r\n createdTime: string;\r\n lastEditedTime: string;\r\n archived: boolean;\r\n icon?: string;\r\n cover?: string;\r\n parent: {\r\n type: \"page\" | \"database\" | \"workspace\";\r\n id?: string;\r\n };\r\n}\r\n\r\nexport interface SearchResultDatabase {\r\n type: \"database\";\r\n id: string;\r\n url: string;\r\n title: string;\r\n description: string;\r\n createdTime: string;\r\n lastEditedTime: string;\r\n isInline: boolean;\r\n icon?: string;\r\n cover?: string;\r\n parent: {\r\n type: \"page\" | \"workspace\";\r\n id?: string;\r\n };\r\n}\r\n\r\nexport type SearchResult = SearchResultPage | SearchResultDatabase;\r\n\r\nexport interface SearchResponse {\r\n results: SearchResult[];\r\n hasMore: boolean;\r\n nextCursor: string | null;\r\n}\r\n\r\n/**\r\n * Extract title from page properties\r\n */\r\nfunction extractPageTitle(properties: Record<string, any>): string {\r\n for (const value of Object.values(properties)) {\r\n if (value?.type === \"title\" && Array.isArray(value.title)) {\r\n return value.title.map((t: any) => t.plain_text || \"\").join(\"\");\r\n }\r\n }\r\n return \"Untitled\";\r\n}\r\n\r\n/**\r\n * Convert page response to search result\r\n */\r\nfunction pageToSearchResult(page: PageObjectResponse): SearchResultPage {\r\n let parent: SearchResultPage[\"parent\"];\r\n\r\n if (page.parent.type === \"page_id\") {\r\n parent = { type: \"page\", id: page.parent.page_id };\r\n } else if (page.parent.type === \"database_id\") {\r\n parent = { type: \"database\", id: page.parent.database_id };\r\n } else {\r\n parent = { type: \"workspace\" };\r\n }\r\n\r\n return {\r\n type: \"page\",\r\n id: page.id,\r\n url: page.url,\r\n title: extractPageTitle(page.properties),\r\n createdTime: page.created_time,\r\n lastEditedTime: page.last_edited_time,\r\n archived: page.archived,\r\n icon:\r\n page.icon?.type === \"emoji\"\r\n ? page.icon.emoji\r\n : page.icon?.type === \"external\"\r\n ? page.icon.external?.url\r\n : undefined,\r\n cover:\r\n page.cover?.type === \"external\"\r\n ? page.cover.external?.url\r\n : page.cover?.type === \"file\"\r\n ? page.cover.file?.url\r\n : undefined,\r\n parent,\r\n };\r\n}\r\n\r\n/**\r\n * Convert database response to search result\r\n */\r\nfunction databaseToSearchResult(\r\n database: DatabaseObjectResponse\r\n): SearchResultDatabase {\r\n let parent: SearchResultDatabase[\"parent\"];\r\n\r\n if (database.parent.type === \"page_id\") {\r\n parent = { type: \"page\", id: database.parent.page_id };\r\n } else {\r\n parent = { type: \"workspace\" };\r\n }\r\n\r\n return {\r\n type: \"database\",\r\n id: database.id,\r\n url: database.url,\r\n title: database.title.map((t) => t.plain_text).join(\"\"),\r\n description: database.description.map((t) => t.plain_text).join(\"\"),\r\n createdTime: database.created_time,\r\n lastEditedTime: database.last_edited_time,\r\n isInline: database.is_inline,\r\n icon:\r\n database.icon?.type === \"emoji\"\r\n ? database.icon.emoji\r\n : database.icon?.type === \"external\"\r\n ? database.icon.external?.url\r\n : undefined,\r\n cover:\r\n database.cover?.type === \"external\"\r\n ? database.cover.external?.url\r\n : database.cover?.type === \"file\"\r\n ? database.cover.file?.url\r\n : undefined,\r\n parent,\r\n };\r\n}\r\n\r\n/**\r\n * Search across the entire Notion workspace\r\n */\r\nexport async function search(options: SearchOptions = {}): Promise<SearchResponse> {\r\n const notion = getNotionClient();\r\n\r\n const params: SearchParams = {};\r\n\r\n if (options.query) {\r\n params.query = options.query;\r\n }\r\n\r\n if (options.filter) {\r\n // Map 'database' to 'data_source' for newer SDK versions\r\n const filterValue = options.filter.value === \"database\" ? \"data_source\" : options.filter.value;\r\n params.filter = { value: filterValue, property: options.filter.property };\r\n }\r\n\r\n if (options.sort) {\r\n params.sort = options.sort;\r\n }\r\n\r\n if (options.startCursor) {\r\n params.start_cursor = options.startCursor;\r\n }\r\n\r\n if (options.pageSize) {\r\n params.page_size = options.pageSize;\r\n }\r\n\r\n const response = await notion.search(params as any);\r\n\r\n const results: SearchResult[] = response.results.map((item: any) => {\r\n if (item.object === \"page\") {\r\n return pageToSearchResult(item as PageObjectResponse);\r\n } else {\r\n return databaseToSearchResult(item as DatabaseObjectResponse);\r\n }\r\n });\r\n\r\n return {\r\n results,\r\n hasMore: response.has_more,\r\n nextCursor: response.next_cursor,\r\n };\r\n}\r\n\r\n/**\r\n * Search for pages only\r\n */\r\nexport async function searchPages(\r\n query?: string,\r\n options: Omit<SearchOptions, \"filter\"> = {}\r\n): Promise<SearchResultPage[]> {\r\n const response = await search({\r\n ...options,\r\n query,\r\n filter: { value: \"page\", property: \"object\" },\r\n });\r\n\r\n return response.results.filter(\r\n (r): r is SearchResultPage => r.type === \"page\"\r\n );\r\n}\r\n\r\n/**\r\n * Search for databases only\r\n */\r\nexport async function searchDatabases(\r\n query?: string,\r\n options: Omit<SearchOptions, \"filter\"> = {}\r\n): Promise<SearchResultDatabase[]> {\r\n const response = await search({\r\n ...options,\r\n query,\r\n filter: { value: \"database\", property: \"object\" },\r\n });\r\n\r\n return response.results.filter(\r\n (r): r is SearchResultDatabase => r.type === \"database\"\r\n );\r\n}\r\n\r\n/**\r\n * Search all results (handles pagination)\r\n */\r\nexport async function searchAll(\r\n query?: string,\r\n options: Omit<SearchOptions, \"startCursor\" | \"pageSize\"> = {}\r\n): Promise<SearchResult[]> {\r\n const allResults: SearchResult[] = [];\r\n let cursor: string | undefined;\r\n\r\n do {\r\n const response = await search({\r\n ...options,\r\n query,\r\n startCursor: cursor,\r\n pageSize: 100,\r\n });\r\n allResults.push(...response.results);\r\n cursor = response.nextCursor ?? undefined;\r\n } while (cursor);\r\n\r\n return allResults;\r\n}\r\n\r\n/**\r\n * Find a page by title\r\n */\r\nexport async function findPageByTitle(\r\n title: string,\r\n exactMatch: boolean = false\r\n): Promise<SearchResultPage | null> {\r\n const pages = await searchPages(title);\r\n\r\n if (exactMatch) {\r\n return pages.find((p) => p.title === title) || null;\r\n }\r\n\r\n return pages[0] || null;\r\n}\r\n\r\n/**\r\n * Find a database by title\r\n */\r\nexport async function findDatabaseByTitle(\r\n title: string,\r\n exactMatch: boolean = false\r\n): Promise<SearchResultDatabase | null> {\r\n const databases = await searchDatabases(title);\r\n\r\n if (exactMatch) {\r\n return databases.find((d) => d.title === title) || null;\r\n }\r\n\r\n return databases[0] || null;\r\n}\r\n\r\n/**\r\n * Get recently edited pages\r\n */\r\nexport async function getRecentlyEditedPages(\r\n limit: number = 10\r\n): Promise<SearchResultPage[]> {\r\n const response = await search({\r\n filter: { value: \"page\", property: \"object\" },\r\n sort: { direction: \"descending\", timestamp: \"last_edited_time\" },\r\n pageSize: limit,\r\n });\r\n\r\n return response.results.filter(\r\n (r): r is SearchResultPage => r.type === \"page\"\r\n );\r\n}\r\n\r\n/**\r\n * Get recently edited databases\r\n */\r\nexport async function getRecentlyEditedDatabases(\r\n limit: number = 10\r\n): Promise<SearchResultDatabase[]> {\r\n const response = await search({\r\n filter: { value: \"database\", property: \"object\" },\r\n sort: { direction: \"descending\", timestamp: \"last_edited_time\" },\r\n pageSize: limit,\r\n });\r\n\r\n return response.results.filter(\r\n (r): r is SearchResultDatabase => r.type === \"database\"\r\n );\r\n}\r\n\r\n/**\r\n * Full text search in workspace\r\n * Returns pages and databases matching the query\r\n */\r\nexport async function fullTextSearch(\r\n query: string,\r\n options: {\r\n objectType?: SearchObjectType;\r\n limit?: number;\r\n sortByRelevance?: boolean;\r\n } = {}\r\n): Promise<SearchResult[]> {\r\n const searchOptions: SearchOptions = {\r\n query,\r\n pageSize: options.limit ?? 20,\r\n };\r\n\r\n if (options.objectType) {\r\n searchOptions.filter = { value: options.objectType, property: \"object\" };\r\n }\r\n\r\n if (!options.sortByRelevance) {\r\n searchOptions.sort = {\r\n direction: \"descending\",\r\n timestamp: \"last_edited_time\",\r\n };\r\n }\r\n\r\n const response = await search(searchOptions);\r\n return response.results;\r\n}\r\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__require
|
|
3
|
+
} from "./chunk-UP2VWCW5.js";
|
|
4
|
+
|
|
5
|
+
// src/integrations/documents/pdf-parser.ts
|
|
6
|
+
import * as fs from "fs/promises";
|
|
7
|
+
import * as path from "path";
|
|
8
|
+
var pdf = __require("pdf-parse");
|
|
9
|
+
async function parsePDF(input, options = {}) {
|
|
10
|
+
let buffer;
|
|
11
|
+
if (typeof input === "string") {
|
|
12
|
+
const absolutePath = path.isAbsolute(input) ? input : path.resolve(input);
|
|
13
|
+
buffer = await fs.readFile(absolutePath);
|
|
14
|
+
} else {
|
|
15
|
+
buffer = input;
|
|
16
|
+
}
|
|
17
|
+
const pageTexts = [];
|
|
18
|
+
let currentPage = 0;
|
|
19
|
+
const parseOptions = {
|
|
20
|
+
// Custom page renderer to capture individual page text
|
|
21
|
+
pagerender: (pageData) => {
|
|
22
|
+
return pageData.getTextContent().then((textContent) => {
|
|
23
|
+
currentPage++;
|
|
24
|
+
if (options.pageRange) {
|
|
25
|
+
const [start, end] = options.pageRange;
|
|
26
|
+
if (currentPage < start || currentPage > end) {
|
|
27
|
+
return "";
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (options.maxPages && currentPage > options.maxPages) {
|
|
31
|
+
return "";
|
|
32
|
+
}
|
|
33
|
+
const pageText = textContent.items.map((item) => {
|
|
34
|
+
if (item.str) {
|
|
35
|
+
return item.str;
|
|
36
|
+
}
|
|
37
|
+
return "";
|
|
38
|
+
}).join("");
|
|
39
|
+
pageTexts.push(pageText);
|
|
40
|
+
return pageText;
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
if (options.maxPages) {
|
|
45
|
+
parseOptions.max = options.maxPages;
|
|
46
|
+
}
|
|
47
|
+
const result = await pdf(buffer, parseOptions);
|
|
48
|
+
const metadata = {};
|
|
49
|
+
if (result.info) {
|
|
50
|
+
metadata.title = result.info.Title || void 0;
|
|
51
|
+
metadata.author = result.info.Author || void 0;
|
|
52
|
+
metadata.subject = result.info.Subject || void 0;
|
|
53
|
+
metadata.creator = result.info.Creator || void 0;
|
|
54
|
+
metadata.producer = result.info.Producer || void 0;
|
|
55
|
+
if (result.info.CreationDate) {
|
|
56
|
+
metadata.creationDate = parsePDFDate(result.info.CreationDate);
|
|
57
|
+
}
|
|
58
|
+
if (result.info.ModDate) {
|
|
59
|
+
metadata.modificationDate = parsePDFDate(result.info.ModDate);
|
|
60
|
+
}
|
|
61
|
+
if (result.info.Keywords) {
|
|
62
|
+
metadata.keywords = result.info.Keywords.split(/[,;]/).map(
|
|
63
|
+
(k) => k.trim()
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
text: result.text,
|
|
69
|
+
metadata,
|
|
70
|
+
pageCount: result.numpages,
|
|
71
|
+
pages: pageTexts.length > 0 ? pageTexts : [result.text]
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function parsePDFDate(dateStr) {
|
|
75
|
+
if (!dateStr) return void 0;
|
|
76
|
+
const cleanDate = dateStr.replace(/^D:/, "");
|
|
77
|
+
const match = cleanDate.match(
|
|
78
|
+
/^(\d{4})(\d{2})?(\d{2})?(\d{2})?(\d{2})?(\d{2})?([+-Z])?(\d{2})?'?(\d{2})?'?$/
|
|
79
|
+
);
|
|
80
|
+
if (!match) {
|
|
81
|
+
const parsed = new Date(dateStr);
|
|
82
|
+
return isNaN(parsed.getTime()) ? void 0 : parsed;
|
|
83
|
+
}
|
|
84
|
+
const year = parseInt(match[1], 10);
|
|
85
|
+
const month = parseInt(match[2] || "01", 10) - 1;
|
|
86
|
+
const day = parseInt(match[3] || "01", 10);
|
|
87
|
+
const hour = parseInt(match[4] || "00", 10);
|
|
88
|
+
const minute = parseInt(match[5] || "00", 10);
|
|
89
|
+
const second = parseInt(match[6] || "00", 10);
|
|
90
|
+
const date = new Date(year, month, day, hour, minute, second);
|
|
91
|
+
if (match[7] && match[7] !== "Z" && match[8] && match[9]) {
|
|
92
|
+
const tzSign = match[7] === "+" ? -1 : 1;
|
|
93
|
+
const tzHours = parseInt(match[8], 10);
|
|
94
|
+
const tzMinutes = parseInt(match[9], 10);
|
|
95
|
+
date.setMinutes(date.getMinutes() + tzSign * (tzHours * 60 + tzMinutes));
|
|
96
|
+
}
|
|
97
|
+
return date;
|
|
98
|
+
}
|
|
99
|
+
async function extractPDFPages(input, startPage, endPage) {
|
|
100
|
+
const result = await parsePDF(input, {
|
|
101
|
+
pageRange: [startPage, endPage]
|
|
102
|
+
});
|
|
103
|
+
return result.pages;
|
|
104
|
+
}
|
|
105
|
+
async function getPDFMetadata(input) {
|
|
106
|
+
const result = await parsePDF(input, { maxPages: 1 });
|
|
107
|
+
return {
|
|
108
|
+
metadata: result.metadata,
|
|
109
|
+
pageCount: result.pageCount
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
async function isValidPDF(input) {
|
|
113
|
+
try {
|
|
114
|
+
let buffer;
|
|
115
|
+
if (typeof input === "string") {
|
|
116
|
+
const absolutePath = path.isAbsolute(input) ? input : path.resolve(input);
|
|
117
|
+
buffer = await fs.readFile(absolutePath);
|
|
118
|
+
} else {
|
|
119
|
+
buffer = input;
|
|
120
|
+
}
|
|
121
|
+
const header = buffer.slice(0, 5).toString("ascii");
|
|
122
|
+
return header === "%PDF-";
|
|
123
|
+
} catch {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export {
|
|
129
|
+
parsePDF,
|
|
130
|
+
extractPDFPages,
|
|
131
|
+
getPDFMetadata,
|
|
132
|
+
isValidPDF
|
|
133
|
+
};
|
|
134
|
+
//# sourceMappingURL=chunk-XTX7EK43.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/integrations/documents/pdf-parser.ts"],"sourcesContent":["/**\n * PDF Parser for OpenSentinel Document Ingestion\n *\n * Extracts text content from PDF files using pdf-parse.\n */\n\n// pdf-parse doesn't have proper ESM exports, use require\nconst pdf = require(\"pdf-parse\");\nimport * as fs from \"fs/promises\";\nimport * as path from \"path\";\n\nexport interface PDFParseResult {\n text: string;\n metadata: PDFMetadata;\n pageCount: number;\n pages: string[];\n}\n\nexport interface PDFMetadata {\n title?: string;\n author?: string;\n subject?: string;\n creator?: string;\n producer?: string;\n creationDate?: Date;\n modificationDate?: Date;\n keywords?: string[];\n}\n\nexport interface PDFParseOptions {\n /** Maximum number of pages to parse (0 = all) */\n maxPages?: number;\n /** Page range to parse (e.g., [1, 5] for pages 1-5) */\n pageRange?: [number, number];\n}\n\n/**\n * Parse a PDF file and extract its text content\n */\nexport async function parsePDF(\n input: string | Buffer,\n options: PDFParseOptions = {}\n): Promise<PDFParseResult> {\n let buffer: Buffer;\n\n if (typeof input === \"string\") {\n // Input is a file path\n const absolutePath = path.isAbsolute(input) ? input : path.resolve(input);\n buffer = await fs.readFile(absolutePath);\n } else {\n buffer = input;\n }\n\n const pageTexts: string[] = [];\n let currentPage = 0;\n\n const parseOptions: any = {\n // Custom page renderer to capture individual page text\n pagerender: (pageData: any) => {\n return pageData.getTextContent().then((textContent: any) => {\n currentPage++;\n\n // Apply page range filter\n if (options.pageRange) {\n const [start, end] = options.pageRange;\n if (currentPage < start || currentPage > end) {\n return \"\";\n }\n }\n\n // Apply max pages filter\n if (options.maxPages && currentPage > options.maxPages) {\n return \"\";\n }\n\n // Extract text from page\n const pageText = textContent.items\n .map((item: any) => {\n if (item.str) {\n return item.str;\n }\n return \"\";\n })\n .join(\"\");\n\n pageTexts.push(pageText);\n return pageText;\n });\n },\n };\n\n // Apply max pages limit\n if (options.maxPages) {\n parseOptions.max = options.maxPages;\n }\n\n const result = await pdf(buffer, parseOptions);\n\n // Extract metadata\n const metadata: PDFMetadata = {};\n\n if (result.info) {\n metadata.title = result.info.Title || undefined;\n metadata.author = result.info.Author || undefined;\n metadata.subject = result.info.Subject || undefined;\n metadata.creator = result.info.Creator || undefined;\n metadata.producer = result.info.Producer || undefined;\n\n if (result.info.CreationDate) {\n metadata.creationDate = parsePDFDate(result.info.CreationDate);\n }\n if (result.info.ModDate) {\n metadata.modificationDate = parsePDFDate(result.info.ModDate);\n }\n if (result.info.Keywords) {\n metadata.keywords = result.info.Keywords.split(/[,;]/).map((k: string) =>\n k.trim()\n );\n }\n }\n\n return {\n text: result.text,\n metadata,\n pageCount: result.numpages,\n pages: pageTexts.length > 0 ? pageTexts : [result.text],\n };\n}\n\n/**\n * Parse PDF date string to Date object\n * PDF dates are in format: D:YYYYMMDDHHmmSS+HH'mm'\n */\nfunction parsePDFDate(dateStr: string): Date | undefined {\n if (!dateStr) return undefined;\n\n // Remove 'D:' prefix if present\n const cleanDate = dateStr.replace(/^D:/, \"\");\n\n // Extract components using regex\n const match = cleanDate.match(\n /^(\\d{4})(\\d{2})?(\\d{2})?(\\d{2})?(\\d{2})?(\\d{2})?([+-Z])?(\\d{2})?'?(\\d{2})?'?$/\n );\n\n if (!match) {\n // Try parsing as ISO date\n const parsed = new Date(dateStr);\n return isNaN(parsed.getTime()) ? undefined : parsed;\n }\n\n const year = parseInt(match[1], 10);\n const month = parseInt(match[2] || \"01\", 10) - 1;\n const day = parseInt(match[3] || \"01\", 10);\n const hour = parseInt(match[4] || \"00\", 10);\n const minute = parseInt(match[5] || \"00\", 10);\n const second = parseInt(match[6] || \"00\", 10);\n\n const date = new Date(year, month, day, hour, minute, second);\n\n // Handle timezone offset\n if (match[7] && match[7] !== \"Z\" && match[8] && match[9]) {\n const tzSign = match[7] === \"+\" ? -1 : 1;\n const tzHours = parseInt(match[8], 10);\n const tzMinutes = parseInt(match[9], 10);\n date.setMinutes(date.getMinutes() + tzSign * (tzHours * 60 + tzMinutes));\n }\n\n return date;\n}\n\n/**\n * Extract text from specific pages of a PDF\n */\nexport async function extractPDFPages(\n input: string | Buffer,\n startPage: number,\n endPage: number\n): Promise<string[]> {\n const result = await parsePDF(input, {\n pageRange: [startPage, endPage],\n });\n return result.pages;\n}\n\n/**\n * Get PDF metadata without extracting full text\n */\nexport async function getPDFMetadata(\n input: string | Buffer\n): Promise<{ metadata: PDFMetadata; pageCount: number }> {\n const result = await parsePDF(input, { maxPages: 1 });\n return {\n metadata: result.metadata,\n pageCount: result.pageCount,\n };\n}\n\n/**\n * Check if a file is a valid PDF\n */\nexport async function isValidPDF(input: string | Buffer): Promise<boolean> {\n try {\n let buffer: Buffer;\n\n if (typeof input === \"string\") {\n const absolutePath = path.isAbsolute(input) ? input : path.resolve(input);\n buffer = await fs.readFile(absolutePath);\n } else {\n buffer = input;\n }\n\n // Check PDF magic number\n const header = buffer.slice(0, 5).toString(\"ascii\");\n return header === \"%PDF-\";\n } catch {\n return false;\n }\n}\n"],"mappings":";;;;;AAQA,YAAY,QAAQ;AACpB,YAAY,UAAU;AAFtB,IAAM,MAAM,UAAQ,WAAW;AAgC/B,eAAsB,SACpB,OACA,UAA2B,CAAC,GACH;AACzB,MAAI;AAEJ,MAAI,OAAO,UAAU,UAAU;AAE7B,UAAM,eAAoB,gBAAW,KAAK,IAAI,QAAa,aAAQ,KAAK;AACxE,aAAS,MAAS,YAAS,YAAY;AAAA,EACzC,OAAO;AACL,aAAS;AAAA,EACX;AAEA,QAAM,YAAsB,CAAC;AAC7B,MAAI,cAAc;AAElB,QAAM,eAAoB;AAAA;AAAA,IAExB,YAAY,CAAC,aAAkB;AAC7B,aAAO,SAAS,eAAe,EAAE,KAAK,CAAC,gBAAqB;AAC1D;AAGA,YAAI,QAAQ,WAAW;AACrB,gBAAM,CAAC,OAAO,GAAG,IAAI,QAAQ;AAC7B,cAAI,cAAc,SAAS,cAAc,KAAK;AAC5C,mBAAO;AAAA,UACT;AAAA,QACF;AAGA,YAAI,QAAQ,YAAY,cAAc,QAAQ,UAAU;AACtD,iBAAO;AAAA,QACT;AAGA,cAAM,WAAW,YAAY,MAC1B,IAAI,CAAC,SAAc;AAClB,cAAI,KAAK,KAAK;AACZ,mBAAO,KAAK;AAAA,UACd;AACA,iBAAO;AAAA,QACT,CAAC,EACA,KAAK,EAAE;AAEV,kBAAU,KAAK,QAAQ;AACvB,eAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,EACF;AAGA,MAAI,QAAQ,UAAU;AACpB,iBAAa,MAAM,QAAQ;AAAA,EAC7B;AAEA,QAAM,SAAS,MAAM,IAAI,QAAQ,YAAY;AAG7C,QAAM,WAAwB,CAAC;AAE/B,MAAI,OAAO,MAAM;AACf,aAAS,QAAQ,OAAO,KAAK,SAAS;AACtC,aAAS,SAAS,OAAO,KAAK,UAAU;AACxC,aAAS,UAAU,OAAO,KAAK,WAAW;AAC1C,aAAS,UAAU,OAAO,KAAK,WAAW;AAC1C,aAAS,WAAW,OAAO,KAAK,YAAY;AAE5C,QAAI,OAAO,KAAK,cAAc;AAC5B,eAAS,eAAe,aAAa,OAAO,KAAK,YAAY;AAAA,IAC/D;AACA,QAAI,OAAO,KAAK,SAAS;AACvB,eAAS,mBAAmB,aAAa,OAAO,KAAK,OAAO;AAAA,IAC9D;AACA,QAAI,OAAO,KAAK,UAAU;AACxB,eAAS,WAAW,OAAO,KAAK,SAAS,MAAM,MAAM,EAAE;AAAA,QAAI,CAAC,MAC1D,EAAE,KAAK;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM,OAAO;AAAA,IACb;AAAA,IACA,WAAW,OAAO;AAAA,IAClB,OAAO,UAAU,SAAS,IAAI,YAAY,CAAC,OAAO,IAAI;AAAA,EACxD;AACF;AAMA,SAAS,aAAa,SAAmC;AACvD,MAAI,CAAC,QAAS,QAAO;AAGrB,QAAM,YAAY,QAAQ,QAAQ,OAAO,EAAE;AAG3C,QAAM,QAAQ,UAAU;AAAA,IACtB;AAAA,EACF;AAEA,MAAI,CAAC,OAAO;AAEV,UAAM,SAAS,IAAI,KAAK,OAAO;AAC/B,WAAO,MAAM,OAAO,QAAQ,CAAC,IAAI,SAAY;AAAA,EAC/C;AAEA,QAAM,OAAO,SAAS,MAAM,CAAC,GAAG,EAAE;AAClC,QAAM,QAAQ,SAAS,MAAM,CAAC,KAAK,MAAM,EAAE,IAAI;AAC/C,QAAM,MAAM,SAAS,MAAM,CAAC,KAAK,MAAM,EAAE;AACzC,QAAM,OAAO,SAAS,MAAM,CAAC,KAAK,MAAM,EAAE;AAC1C,QAAM,SAAS,SAAS,MAAM,CAAC,KAAK,MAAM,EAAE;AAC5C,QAAM,SAAS,SAAS,MAAM,CAAC,KAAK,MAAM,EAAE;AAE5C,QAAM,OAAO,IAAI,KAAK,MAAM,OAAO,KAAK,MAAM,QAAQ,MAAM;AAG5D,MAAI,MAAM,CAAC,KAAK,MAAM,CAAC,MAAM,OAAO,MAAM,CAAC,KAAK,MAAM,CAAC,GAAG;AACxD,UAAM,SAAS,MAAM,CAAC,MAAM,MAAM,KAAK;AACvC,UAAM,UAAU,SAAS,MAAM,CAAC,GAAG,EAAE;AACrC,UAAM,YAAY,SAAS,MAAM,CAAC,GAAG,EAAE;AACvC,SAAK,WAAW,KAAK,WAAW,IAAI,UAAU,UAAU,KAAK,UAAU;AAAA,EACzE;AAEA,SAAO;AACT;AAKA,eAAsB,gBACpB,OACA,WACA,SACmB;AACnB,QAAM,SAAS,MAAM,SAAS,OAAO;AAAA,IACnC,WAAW,CAAC,WAAW,OAAO;AAAA,EAChC,CAAC;AACD,SAAO,OAAO;AAChB;AAKA,eAAsB,eACpB,OACuD;AACvD,QAAM,SAAS,MAAM,SAAS,OAAO,EAAE,UAAU,EAAE,CAAC;AACpD,SAAO;AAAA,IACL,UAAU,OAAO;AAAA,IACjB,WAAW,OAAO;AAAA,EACpB;AACF;AAKA,eAAsB,WAAW,OAA0C;AACzE,MAAI;AACF,QAAI;AAEJ,QAAI,OAAO,UAAU,UAAU;AAC7B,YAAM,eAAoB,gBAAW,KAAK,IAAI,QAAa,aAAQ,KAAK;AACxE,eAAS,MAAS,YAAS,YAAY;AAAA,IACzC,OAAO;AACL,eAAS;AAAA,IACX;AAGA,UAAM,SAAS,OAAO,MAAM,GAAG,CAAC,EAAE,SAAS,OAAO;AAClD,WAAO,WAAW;AAAA,EACpB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}
|