@rubytech/create-maxy-code 0.1.496 → 0.1.498
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/package.json +1 -1
- package/payload/platform/docs/superpowers/plans/2026-07-24-task-1942-subaccount-switcher-brand-head.md +327 -0
- package/payload/platform/docs/superpowers/specs/2026-07-24-task-1942-subaccount-switcher-brand-head-design.md +35 -0
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +72 -12
- package/payload/platform/plugins/docs/references/admin-ui.md +50 -10
- package/payload/platform/plugins/docs/references/outlook-guide.md +5 -1
- package/payload/platform/plugins/docs/references/sweep-guide.md +16 -0
- package/payload/platform/plugins/memory/PLUGIN.md +2 -0
- package/payload/platform/plugins/memory/mcp/dist/index.js +2 -2
- package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/scripts/__tests__/dream-cycle-sweep-decision.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/scripts/__tests__/dream-cycle-sweep-decision.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/scripts/__tests__/dream-cycle-sweep-decision.test.js +84 -0
- package/payload/platform/plugins/memory/mcp/dist/scripts/__tests__/dream-cycle-sweep-decision.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/scripts/dream-cycle-sweep-decision.d.ts +54 -0
- package/payload/platform/plugins/memory/mcp/dist/scripts/dream-cycle-sweep-decision.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/scripts/dream-cycle-sweep-decision.js +58 -0
- package/payload/platform/plugins/memory/mcp/dist/scripts/dream-cycle-sweep-decision.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/scripts/dream-cycle-sweep.d.ts +30 -0
- package/payload/platform/plugins/memory/mcp/dist/scripts/dream-cycle-sweep.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/scripts/dream-cycle-sweep.js +204 -0
- package/payload/platform/plugins/memory/mcp/dist/scripts/dream-cycle-sweep.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights.test.js +30 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.d.ts +4 -2
- package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.js +38 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/vitest.config.ts +2 -0
- package/payload/platform/plugins/memory/skills/conversation-archive-enrich/SKILL.md +10 -4
- package/payload/platform/plugins/outlook/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/outlook/PLUGIN.md +6 -2
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/dispatch-grouping.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/dispatch-grouping.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/dispatch-grouping.test.js +54 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/dispatch-grouping.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/fetch-body-fromname.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/fetch-body-fromname.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/fetch-body-fromname.test.js +19 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/fetch-body-fromname.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-ingest-decisions.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-ingest-decisions.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-ingest-decisions.test.js +20 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-ingest-decisions.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/index.js +21 -0
- package/payload/platform/plugins/outlook/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/lib/conversation-archive-dispatch.d.ts +40 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/conversation-archive-dispatch.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/conversation-archive-dispatch.js +143 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/conversation-archive-dispatch.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/neo4j.d.ts +5 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/neo4j.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/neo4j.js +44 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/neo4j.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-fetch-body.d.ts +14 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-fetch-body.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-fetch-body.js +13 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-fetch-body.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-ingest.d.ts +27 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-ingest.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-ingest.js +69 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-ingest.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/package.json +1 -0
- package/payload/platform/plugins/outlook/references/graph-surfaces.md +10 -1
- package/payload/platform/plugins/outlook/skills/outlook/SKILL.md +4 -0
- package/payload/platform/plugins/outlook/skills/outlook-mail-ingest/SKILL.md +85 -0
- package/payload/platform/plugins/sweep/PLUGIN.md +5 -1
- package/payload/platform/plugins/sweep/skills/email-graph-sweep/SKILL.md +165 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +1 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/templates/specialists/agents/personal-assistant.md +1 -1
- package/payload/server/package.json +2 -1
- package/payload/server/public/activity.html +6 -6
- package/payload/server/public/assets/{AdminLoginScreens-CFF28MGy.js → AdminLoginScreens-Ce5aBBWF.js} +1 -1
- package/payload/server/public/assets/AdminShell-BFVVkWFC.js +2 -0
- package/payload/server/public/assets/{activity-CElZcdjR.js → activity-CKUYOLd2.js} +1 -1
- package/payload/server/public/assets/admin-BWb8me-E.js +1 -0
- package/payload/server/public/assets/{arc-CFMJyMm-.js → arc-CpWWSum8.js} +1 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-D-AX2VuA.js +1 -0
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-CiSSgdL8.js → architectureDiagram-Q4EWVU46-D2EzaII0.js} +1 -1
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-_sXtIW5c.js → blockDiagram-DXYQGD6D-8kDpaNSZ.js} +1 -1
- package/payload/server/public/assets/{bot-Q-JmeVT3.js → bot-DESMpxSQ.js} +1 -1
- package/payload/server/public/assets/{browser-BrfPJMYF.js → browser-CpLq_DIo.js} +1 -1
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-Bh7OAMXs.js → c4Diagram-AHTNJAMY-CbwmZpK3.js} +1 -1
- package/payload/server/public/assets/calendar-ClOwyuz-.js +1 -0
- package/payload/server/public/assets/channel-DZ5sh6YQ.js +1 -0
- package/payload/server/public/assets/chat-qtOiJX-Y.js +1 -0
- package/payload/server/public/assets/chevron-left-BzIg4in6.js +1 -0
- package/payload/server/public/assets/chevron-right-BcFSa9C3.js +1 -0
- package/payload/server/public/assets/{chunk-2KRD3SAO-D4fktAwW.js → chunk-2KRD3SAO-PFheZ9mw.js} +1 -1
- package/payload/server/public/assets/{chunk-336JU56O-CcQoKH2G.js → chunk-336JU56O-CCFOp5VK.js} +2 -2
- package/payload/server/public/assets/chunk-426QAEUC-CcjBLp4a.js +1 -0
- package/payload/server/public/assets/{chunk-4BX2VUAB-C13Wz3zS.js → chunk-4BX2VUAB-Hz4JWOf2.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-BL48D7gN.js → chunk-4TB4RGXK-4xeV0s85.js} +1 -1
- package/payload/server/public/assets/{chunk-55IACEB6-TmOKdy8a.js → chunk-55IACEB6-4QKgBpoh.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-DZ_jSF6N.js → chunk-5FUZZQ4R-ms3K6Z5z.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-De4G1vfV.js → chunk-5PVQY5BW-CIC4GIGi.js} +1 -1
- package/payload/server/public/assets/{chunk-67CJDMHE-Cif9Uu5C.js → chunk-67CJDMHE-B-XrWVmV.js} +1 -1
- package/payload/server/public/assets/{chunk-7N4EOEYR-WjTHCXnd.js → chunk-7N4EOEYR-C7ECOUYQ.js} +1 -1
- package/payload/server/public/assets/{chunk-AA7GKIK3-CwCfdQmb.js → chunk-AA7GKIK3-DOZ6Fxwk.js} +1 -1
- package/payload/server/public/assets/{chunk-BSJP7CBP-9A67yXwT.js → chunk-BSJP7CBP-4cJ_b0c6.js} +1 -1
- package/payload/server/public/assets/{chunk-CIAEETIT-DPMiWSBi.js → chunk-CIAEETIT--mhZipWM.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-C2f_Qvx-.js → chunk-EDXVE4YY-jZpVwob_.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-B-Q9EbSQ.js → chunk-ENJZ2VHE-Nn-p-xIA.js} +1 -1
- package/payload/server/public/assets/{chunk-FMBD7UC4-Bmt_ZRlV.js → chunk-FMBD7UC4-DyNpcKOS.js} +1 -1
- package/payload/server/public/assets/{chunk-FOC6F5B3-DfGJGxpX.js → chunk-FOC6F5B3-C0P8q1uz.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-Wyym1Q8K.js → chunk-ICPOFSXX-CdXQ5SfI.js} +2 -2
- package/payload/server/public/assets/{chunk-K5T4RW27-DMpoaqw2.js → chunk-K5T4RW27-BVZJKKsT.js} +1 -1
- package/payload/server/public/assets/{chunk-KGLVRYIC-DYUFgri2.js → chunk-KGLVRYIC-QlVWTe0V.js} +1 -1
- package/payload/server/public/assets/{chunk-LIHQZDEY-x3LmeKmx.js → chunk-LIHQZDEY-CpGVZutP.js} +1 -1
- package/payload/server/public/assets/{chunk-ORNJ4GCN-BeuNAWkW.js → chunk-ORNJ4GCN-WVcS6fUC.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-BUWVAfQA.js → chunk-OYMX7WX6-B7hiSTed.js} +1 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-B2WjDYBE.js +1 -0
- package/payload/server/public/assets/{chunk-U2HBQHQK-DKS5adQo.js → chunk-U2HBQHQK-DJPnZxGy.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-CT_UM4IN.js → chunk-X2U36JSP-DilBs1Yc.js} +1 -1
- package/payload/server/public/assets/{chunk-XPW4576I-ByFnN4JO.js → chunk-XPW4576I-B5-uyrJ0.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-DCetC20J.js → chunk-YZCP3GAM-BNO4z0Mv.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-Bh1QIv8N.js → chunk-ZZ45TVLE-BzHMQpip.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-CT3jNrze.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DJRsjAkC.js +1 -0
- package/payload/server/public/assets/clock-Dr3NGtjR.js +1 -0
- package/payload/server/public/assets/clone-FcEDnoMT.js +1 -0
- package/payload/server/public/assets/{cose-bilkent-S5V4N54A-DgLEaApT.js → cose-bilkent-S5V4N54A-3DWYmn1o.js} +1 -1
- package/payload/server/public/assets/{dagre-unhMIyVo.js → dagre-Cpy31xJW.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-BfkUPrEV.js → dagre-KV5264BT-C8fyxHFd.js} +1 -1
- package/payload/server/public/assets/data-BjqC4hyM.js +1 -0
- package/payload/server/public/assets/{diagram-5BDNPKRD-BjjwcTD9.js → diagram-5BDNPKRD-ycyhnLvr.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-BbgWtVSS.js → diagram-G4DWMVQ6-BkeYicIt.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-DyAnkWGy.js → diagram-MMDJMWI5-BcGZU-Q3.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-SAMMoLxq.js → diagram-TYMM5635-DuBDCFb_.js} +1 -1
- package/payload/server/public/assets/{dist-C9D_xz81.js → dist-BYc_arNy.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-Cvo-5-fD.js → erDiagram-SMLLAGMA-DmkeOzvp.js} +1 -1
- package/payload/server/public/assets/{flatten-BXzaHgtL.js → flatten-QjnJ1Gcl.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-y3o2Ycld.js → flowDiagram-DWJPFMVM-CkE-pjuB.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-BEm_CQaK.js → ganttDiagram-T4ZO3ILL-Cjiy3kvE.js} +1 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-D1uhnP9U.js +1 -0
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-CqmOxS7F.js → gitGraphDiagram-UUTBAWPF-CsI4lKZm.js} +1 -1
- package/payload/server/public/assets/{graph-BLO4nVi3.js → graph-B7niLM97.js} +3 -3
- package/payload/server/public/assets/{graph-labels-ibEi7ggo.js → graph-labels-DykmXYHA.js} +1 -1
- package/payload/server/public/assets/{graphlib-_HfbQcBf.js → graphlib-BkXxC6D5.js} +1 -1
- package/payload/server/public/assets/info-OMHHGYJF-oNm27GAV.js +1 -0
- package/payload/server/public/assets/infoDiagram-42DDH7IO-LxTftqyS.js +2 -0
- package/payload/server/public/assets/{isEmpty-uB1dEu_Z.js → isEmpty-BavJI9Cn.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-C_d0vcZC.js → ishikawaDiagram-UXIWVN3A-D8lZtjRc.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-DsjRBqlW.js → journeyDiagram-VCZTEJTY-kLE7SiR_.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-BwtK6LS-.js → kanban-definition-6JOO6SKY-ove6JuD3.js} +1 -1
- package/payload/server/public/assets/{line-szBCFOLJ.js → line-CZMSoxM6.js} +1 -1
- package/payload/server/public/assets/{linear-X3O7lwK3.js → linear-Be8IK9hK.js} +1 -1
- package/payload/server/public/assets/{maximize-2-CezchDEF.js → maximize-2-BbzPm7o8.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-BavvMAhU.js → mermaid-parser.core-BBADqbnp.js} +2 -2
- package/payload/server/public/assets/{mermaid.core-Br2F9Hdm.js → mermaid.core-mH3N7K0I.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-4qlwXoJ-.js → mindmap-definition-QFDTVHPH-BjwwwWil.js} +1 -1
- package/payload/server/public/assets/{operator-B-3vkwO8.js → operator-icJwMkZF.js} +1 -1
- package/payload/server/public/assets/{ordinal-CZY9laxg.js → ordinal-BHeIKG-K.js} +1 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-eQNVGiK3.js +1 -0
- package/payload/server/public/assets/page-DUgrGrJp.js +1 -0
- package/payload/server/public/assets/{page-BL1ko2_-.js → page-iG57nKOg.js} +4 -4
- package/payload/server/public/assets/{pdf-render-H884L3EI.js → pdf-render-fJz4vym9.js} +1 -1
- package/payload/server/public/assets/pie-ZZUOXDRM-E1u-48rt.js +1 -0
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-BbXryIg0.js → pieDiagram-DEJITSTG-D-lXWWta.js} +1 -1
- package/payload/server/public/assets/{public-DxfSLhNp.js → public-CkOumzpf.js} +1 -1
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-BHLjcvh3.js → quadrantDiagram-34T5L4WZ-13QyG_AO.js} +1 -1
- package/payload/server/public/assets/radar-PYXPWWZC-Cn2cGN90.js +1 -0
- package/payload/server/public/assets/{reduce-BGQzAenn.js → reduce-Fm685to3.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-BXaVO0lk.js → requirementDiagram-MS252O5E-Bx45Bgn4.js} +1 -1
- package/payload/server/public/assets/{rotate-ccw-CWvGAut4.js → rotate-ccw-L42fL8ey.js} +1 -1
- package/payload/server/public/assets/routines-JOV6xdYh.js +1 -0
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-CmN1s17Q.js → sankeyDiagram-XADWPNL6-Cj-Gq25v.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-DC08e5NY.js → sequenceDiagram-FGHM5R23-B8RDRq93.js} +1 -1
- package/payload/server/public/assets/{src-BTKk8KAG.js → src-D3VYuW_Z.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-DnoQMuOW.js → stateDiagram-FHFEXIEX-DoyFF1Kl.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-Bml-X4-H.js +1 -0
- package/payload/server/public/assets/{tasks-DlXIN3v3.js → tasks-GNtvZL8F.js} +1 -1
- package/payload/server/public/assets/{time-entry-format-VzHwljTv.js → time-entry-format-BreNpFLJ.js} +1 -1
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-eTn3uRaH.js → timeline-definition-GMOUNBTQ-Df4RQXm6.js} +1 -1
- package/payload/server/public/assets/treeView-SZITEDCU-CimabhXy.js +1 -0
- package/payload/server/public/assets/treemap-W4RFUUIX-Cg264rpM.js +1 -0
- package/payload/server/public/assets/{triangle-alert-C5BpoPlq.js → triangle-alert-DumCWC08.js} +1 -1
- package/payload/server/public/assets/{useCopyFeedback-h1qT8mpZ.js → useCopyFeedback-DHCtz8qX.js} +1 -1
- package/payload/server/public/assets/{useSubAccountSwitcher-DDStL7Nt.js → useSubAccountSwitcher-Bc7XHr0L.js} +2 -2
- package/payload/server/public/assets/useSubAccountSwitcher-DPHQJO7E.css +1 -0
- package/payload/server/public/assets/{useVoiceRecorder-kqMitFlk.js → useVoiceRecorder-Cu6zvuFx.js} +2 -2
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-DNx6o_ZQ.js → vennDiagram-DHZGUBPP-D2o5og9l.js} +1 -1
- package/payload/server/public/assets/wardley-RL74JXVD-tbgfCg0E.js +1 -0
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-BZOchqF3.js → wardleyDiagram-NUSXRM2D-BDueObbS.js} +1 -1
- package/payload/server/public/assets/wrench-iWkROE1V.js +1 -0
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-ZBEGH6ZI.js → xychartDiagram-5P7HB3ND-BTYs4Fgh.js} +1 -1
- package/payload/server/public/browser.html +5 -5
- package/payload/server/public/calendar.html +8 -7
- package/payload/server/public/chat.html +15 -15
- package/payload/server/public/data.html +12 -12
- package/payload/server/public/graph.html +10 -11
- package/payload/server/public/index.html +16 -17
- package/payload/server/public/operator.html +16 -16
- package/payload/server/public/public.html +15 -15
- package/payload/server/public/routines.html +20 -0
- package/payload/server/public/tasks.html +7 -7
- package/payload/server/server.js +417 -203
- package/payload/server/public/assets/AdminShell-ClIT8c0K.js +0 -2
- package/payload/server/public/assets/admin-BHiA9_Ks.js +0 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-Cypt5qHL.js +0 -1
- package/payload/server/public/assets/calendar-D45S_aal.js +0 -1
- package/payload/server/public/assets/channel-BMyXE4zc.js +0 -1
- package/payload/server/public/assets/chat-gy8scQov.js +0 -1
- package/payload/server/public/assets/chevron-down-CdxvexgY.js +0 -1
- package/payload/server/public/assets/chevron-left-D5LLz6ke.js +0 -1
- package/payload/server/public/assets/chevron-right-DzPmwDew.js +0 -1
- package/payload/server/public/assets/chunk-426QAEUC-Xu6JKP4d.js +0 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-7_kS3RBy.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-DJqbNcuC.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-CGglqfQA.js +0 -1
- package/payload/server/public/assets/clone-BiTMTzp_.js +0 -1
- package/payload/server/public/assets/data-CUsNHUpu.js +0 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-C_-XjxLd.js +0 -1
- package/payload/server/public/assets/info-OMHHGYJF-BH8yDCfL.js +0 -1
- package/payload/server/public/assets/infoDiagram-42DDH7IO-DyDXyJ6U.js +0 -2
- package/payload/server/public/assets/packet-4T2RLAQJ-Bajcns4r.js +0 -1
- package/payload/server/public/assets/page-BbxoY4QI.js +0 -1
- package/payload/server/public/assets/pie-ZZUOXDRM-D7hjM5w1.js +0 -1
- package/payload/server/public/assets/radar-PYXPWWZC-B46d5x7a.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-CrstH34p.js +0 -1
- package/payload/server/public/assets/treeView-SZITEDCU-3XQh5xQ1.js +0 -1
- package/payload/server/public/assets/treemap-W4RFUUIX-DwR-_l5z.js +0 -1
- package/payload/server/public/assets/useSubAccountSwitcher-DnfX9Uxe.css +0 -1
- package/payload/server/public/assets/wardley-RL74JXVD-DZp9oCGv.js +0 -1
- /package/payload/server/public/assets/{_baseFor-CMWvz0uA.js → _baseFor-Bvwvhrz4.js} +0 -0
- /package/payload/server/public/assets/{array-Cny_NT6T.js → array-D3d-WgFW.js} +0 -0
- /package/payload/server/public/assets/{chunk-TPjIAO9U.js → chunk-fQC6bEKA.js} +0 -0
- /package/payload/server/public/assets/{cytoscape.esm-De0CCmB2.js → cytoscape.esm-Cun-OM6a.js} +0 -0
- /package/payload/server/public/assets/{defaultLocale-BahRht8U.js → defaultLocale-CisKV5Ew.js} +0 -0
- /package/payload/server/public/assets/{init-DoIvjoJ_.js → init-D9ZOVaZ3.js} +0 -0
- /package/payload/server/public/assets/{katex-Bfn1OZEl.js → katex-C-3ZDK8o.js} +0 -0
- /package/payload/server/public/assets/{path-CTezU8L5.js → path-BMOgQSLM.js} +0 -0
- /package/payload/server/public/assets/{preload-helper-D_sPnjeL.js → preload-helper-DL2DwvxV.js} +0 -0
- /package/payload/server/public/assets/{rough.esm-BJo4pvXu.js → rough.esm-BrTFrov0.js} +0 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join, resolve } from "node:path";
|
|
5
|
+
import { randomUUID } from "node:crypto";
|
|
6
|
+
import { getSession } from "./neo4j.js";
|
|
7
|
+
function ingestBashPath() {
|
|
8
|
+
const platformRoot = process.env.PLATFORM_ROOT ?? resolve(import.meta.dirname, "../../../..");
|
|
9
|
+
return resolve(platformRoot, "plugins/memory/bin/conversation-archive-ingest.sh");
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Group messages into threads by Graph conversationId. A message with no
|
|
13
|
+
* conversationId falls back to its own messageId key, so it stands alone
|
|
14
|
+
* rather than colliding with other conversation-less messages.
|
|
15
|
+
*/
|
|
16
|
+
export function groupByThread(messages) {
|
|
17
|
+
const groups = new Map();
|
|
18
|
+
for (const m of messages) {
|
|
19
|
+
const rootKey = m.conversationId && m.conversationId.length > 0
|
|
20
|
+
? `conv:${m.conversationId}`
|
|
21
|
+
: `msg:${m.messageId}`;
|
|
22
|
+
let g = groups.get(rootKey);
|
|
23
|
+
if (!g) {
|
|
24
|
+
g = { rootKey, messages: [], addresses: [] };
|
|
25
|
+
groups.set(rootKey, g);
|
|
26
|
+
}
|
|
27
|
+
g.messages.push(m);
|
|
28
|
+
}
|
|
29
|
+
for (const g of groups.values()) {
|
|
30
|
+
g.messages.sort((a, b) => a.receivedDateTime.localeCompare(b.receivedDateTime));
|
|
31
|
+
const addrs = new Set();
|
|
32
|
+
for (const m of g.messages) {
|
|
33
|
+
if (m.fromAddress)
|
|
34
|
+
addrs.add(m.fromAddress.trim().toLowerCase());
|
|
35
|
+
for (const a of m.toAddresses)
|
|
36
|
+
addrs.add(a.trim().toLowerCase());
|
|
37
|
+
for (const a of m.ccAddresses)
|
|
38
|
+
addrs.add(a.trim().toLowerCase());
|
|
39
|
+
}
|
|
40
|
+
g.addresses = [...addrs].filter((a) => a.length > 0).sort();
|
|
41
|
+
}
|
|
42
|
+
return [...groups.values()];
|
|
43
|
+
}
|
|
44
|
+
/** Thread JSON shape consumed by the `email` normaliser: [{from:{name,email},date,bodyText}]. */
|
|
45
|
+
export function buildThreadJson(thread) {
|
|
46
|
+
return thread.messages.map((m) => ({
|
|
47
|
+
from: { name: m.fromName ?? null, email: m.fromAddress },
|
|
48
|
+
date: m.receivedDateTime,
|
|
49
|
+
bodyText: m.bodyText,
|
|
50
|
+
}));
|
|
51
|
+
}
|
|
52
|
+
async function resolveAddresses(addresses, accountId) {
|
|
53
|
+
const map = new Map();
|
|
54
|
+
if (addresses.length === 0)
|
|
55
|
+
return map;
|
|
56
|
+
const session = getSession();
|
|
57
|
+
try {
|
|
58
|
+
const r = await session.run(`UNWIND $addresses AS addr
|
|
59
|
+
OPTIONAL MATCH (p) WHERE (p:Person OR p:AdminUser)
|
|
60
|
+
AND p.accountId = $accountId
|
|
61
|
+
AND toLower(p.email) = addr
|
|
62
|
+
WITH addr, p
|
|
63
|
+
WHERE p IS NOT NULL
|
|
64
|
+
RETURN addr, elementId(p) AS eid`, { addresses, accountId });
|
|
65
|
+
for (const rec of r.records) {
|
|
66
|
+
map.set(rec.get("addr"), rec.get("eid"));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
finally {
|
|
70
|
+
await session.close();
|
|
71
|
+
}
|
|
72
|
+
return map;
|
|
73
|
+
}
|
|
74
|
+
export async function dispatchOutlookMessagesToConversationArchive(messages) {
|
|
75
|
+
if (messages.length === 0) {
|
|
76
|
+
return { threadsDispatched: 0, threadsSkipped: 0, unresolvedAddresses: [] };
|
|
77
|
+
}
|
|
78
|
+
const accountId = messages[0].accountId;
|
|
79
|
+
const threads = groupByThread(messages);
|
|
80
|
+
const distinct = new Set();
|
|
81
|
+
for (const t of threads)
|
|
82
|
+
for (const a of t.addresses)
|
|
83
|
+
distinct.add(a);
|
|
84
|
+
const resolved = await resolveAddresses([...distinct], accountId);
|
|
85
|
+
let threadsDispatched = 0;
|
|
86
|
+
let threadsSkipped = 0;
|
|
87
|
+
const unresolved = new Set();
|
|
88
|
+
for (const thread of threads) {
|
|
89
|
+
const ids = [];
|
|
90
|
+
let ok = true;
|
|
91
|
+
for (const addr of thread.addresses) {
|
|
92
|
+
const eid = resolved.get(addr);
|
|
93
|
+
if (!eid) {
|
|
94
|
+
unresolved.add(addr);
|
|
95
|
+
ok = false;
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
ids.push(eid);
|
|
99
|
+
}
|
|
100
|
+
if (!ok) {
|
|
101
|
+
threadsSkipped += 1;
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
const tmpDir = mkdtempSync(join(tmpdir(), "outlook-thread-"));
|
|
105
|
+
const jsonPath = join(tmpDir, `thread-${thread.rootKey.replace(/[^a-z0-9-]+/gi, "_")}.json`);
|
|
106
|
+
try {
|
|
107
|
+
writeFileSync(jsonPath, JSON.stringify(buildThreadJson(thread)));
|
|
108
|
+
const exit = spawnSync("bash", [
|
|
109
|
+
ingestBashPath(),
|
|
110
|
+
jsonPath,
|
|
111
|
+
"--source",
|
|
112
|
+
"email",
|
|
113
|
+
"--participant-person-ids",
|
|
114
|
+
ids.join(","),
|
|
115
|
+
"--scope",
|
|
116
|
+
"admin",
|
|
117
|
+
"--session-id",
|
|
118
|
+
`outlook-${randomUUID()}`,
|
|
119
|
+
], { stdio: ["ignore", "pipe", "inherit"] });
|
|
120
|
+
if (exit.status === 0) {
|
|
121
|
+
threadsDispatched += 1;
|
|
122
|
+
console.error(`[outlook-mcp] mail-ingest op=thread-dispatched root=${thread.rootKey} messages=${thread.messages.length} participants=${ids.length}`);
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
threadsSkipped += 1;
|
|
126
|
+
// status is null when spawnSync itself failed to launch (bad path,
|
|
127
|
+
// ENOENT); surface exit.error so a launch failure is not reported as a
|
|
128
|
+
// silent skip with no cause. Dropping the error body would blind the
|
|
129
|
+
// operator to why every thread skipped.
|
|
130
|
+
console.error(`[outlook-mcp] mail-ingest op=thread-failed root=${thread.rootKey} status=${exit.status} err=${exit.error?.message ?? "none"}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
finally {
|
|
134
|
+
rmSync(tmpDir, { recursive: true, force: true });
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
threadsDispatched,
|
|
139
|
+
threadsSkipped,
|
|
140
|
+
unresolvedAddresses: [...unresolved].sort(),
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=conversation-archive-dispatch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversation-archive-dispatch.js","sourceRoot":"","sources":["../../src/lib/conversation-archive-dispatch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAwCxC,SAAS,cAAc;IACrB,MAAM,YAAY,GAChB,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;IAC3E,OAAO,OAAO,CAAC,YAAY,EAAE,mDAAmD,CAAC,CAAC;AACpF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,QAA8B;IAC1D,MAAM,MAAM,GAAG,IAAI,GAAG,EAAuB,CAAC;IAC9C,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,OAAO,GACX,CAAC,CAAC,cAAc,IAAI,CAAC,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC;YAC7C,CAAC,CAAC,QAAQ,CAAC,CAAC,cAAc,EAAE;YAC5B,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC;QAC3B,IAAI,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC5B,IAAI,CAAC,CAAC,EAAE,CAAC;YACP,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;YAC7C,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QACzB,CAAC;QACD,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACrB,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;QAChC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC,aAAa,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC;QAChF,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;QAChC,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;YAC3B,IAAI,CAAC,CAAC,WAAW;gBAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;YACjE,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,WAAW;gBAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;YACjE,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,WAAW;gBAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;QACnE,CAAC;QACD,CAAC,CAAC,SAAS,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9D,CAAC;IAED,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;AAC9B,CAAC;AAED,iGAAiG;AACjG,MAAM,UAAU,eAAe,CAAC,MAAmB;IACjD,OAAO,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACjC,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,QAAQ,IAAI,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,WAAW,EAAE;QACxD,IAAI,EAAE,CAAC,CAAC,gBAAgB;QACxB,QAAQ,EAAE,CAAC,CAAC,QAAQ;KACrB,CAAC,CAAC,CAAC;AACN,CAAC;AAED,KAAK,UAAU,gBAAgB,CAC7B,SAAmB,EACnB,SAAiB;IAEjB,MAAM,GAAG,GAAG,IAAI,GAAG,EAAkB,CAAC;IACtC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,GAAG,CAAC;IACvC,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CACzB;;;;;;wCAMkC,EAClC,EAAE,SAAS,EAAE,SAAS,EAAE,CACzB,CAAC;QACF,KAAK,MAAM,GAAG,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;YAC5B,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAW,EAAE,GAAG,CAAC,GAAG,CAAC,KAAK,CAAW,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,4CAA4C,CAChE,QAA8B;IAE9B,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,EAAE,iBAAiB,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,mBAAmB,EAAE,EAAE,EAAE,CAAC;IAC9E,CAAC;IAED,MAAM,SAAS,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACxC,MAAM,OAAO,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IAExC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,KAAK,MAAM,CAAC,IAAI,OAAO;QAAE,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS;YAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACtE,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,CAAC,GAAG,QAAQ,CAAC,EAAE,SAAS,CAAC,CAAC;IAElE,IAAI,iBAAiB,GAAG,CAAC,CAAC;IAC1B,IAAI,cAAc,GAAG,CAAC,CAAC;IACvB,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;IAErC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,GAAG,GAAa,EAAE,CAAC;QACzB,IAAI,EAAE,GAAG,IAAI,CAAC;QACd,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YACpC,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC/B,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBACrB,EAAE,GAAG,KAAK,CAAC;gBACX,SAAS;YACX,CAAC;YACD,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAChB,CAAC;QACD,IAAI,CAAC,EAAE,EAAE,CAAC;YACR,cAAc,IAAI,CAAC,CAAC;YACpB,SAAS;QACX,CAAC;QAED,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,iBAAiB,CAAC,CAAC,CAAC;QAC9D,MAAM,QAAQ,GAAG,IAAI,CACnB,MAAM,EACN,UAAU,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,eAAe,EAAE,GAAG,CAAC,OAAO,CAC9D,CAAC;QACF,IAAI,CAAC;YACH,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YACjE,MAAM,IAAI,GAAG,SAAS,CACpB,MAAM,EACN;gBACE,cAAc,EAAE;gBAChB,QAAQ;gBACR,UAAU;gBACV,OAAO;gBACP,0BAA0B;gBAC1B,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC;gBACb,SAAS;gBACT,OAAO;gBACP,cAAc;gBACd,WAAW,UAAU,EAAE,EAAE;aAC1B,EACD,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,CACzC,CAAC;YACF,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACtB,iBAAiB,IAAI,CAAC,CAAC;gBACvB,OAAO,CAAC,KAAK,CACX,uDAAuD,MAAM,CAAC,OAAO,aAAa,MAAM,CAAC,QAAQ,CAAC,MAAM,iBAAiB,GAAG,CAAC,MAAM,EAAE,CACtI,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,cAAc,IAAI,CAAC,CAAC;gBACpB,mEAAmE;gBACnE,uEAAuE;gBACvE,qEAAqE;gBACrE,wCAAwC;gBACxC,OAAO,CAAC,KAAK,CACX,mDAAmD,MAAM,CAAC,OAAO,WAAW,IAAI,CAAC,MAAM,QAAQ,IAAI,CAAC,KAAK,EAAE,OAAO,IAAI,MAAM,EAAE,CAC/H,CAAC;YACJ,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,MAAM,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;IAED,OAAO;QACL,iBAAiB;QACjB,cAAc;QACd,mBAAmB,EAAE,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,EAAE;KAC5C,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"neo4j.d.ts","sourceRoot":"","sources":["../../src/lib/neo4j.ts"],"names":[],"mappings":"AAAA,OAAc,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AA8BtD,wBAAgB,SAAS,IAAI,MAAM,CAclC;AAED,wBAAgB,UAAU,IAAI,OAAO,CAEpC;AAED,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAKjD"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import neo4j from "neo4j-driver";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
// Minimal Neo4j accessor for the outlook plugin (Task 1656 — the plugin's
|
|
5
|
+
// first Neo4j coupling). Mirrors plugins/email/mcp/src/lib/neo4j.ts: the URI
|
|
6
|
+
// must be explicit (a silent bolt://localhost:7687 default was the vector for
|
|
7
|
+
// orphan data across installs), and module init never touches the network —
|
|
8
|
+
// the guard lives inside getDriver, so importing this file throws nothing even
|
|
9
|
+
// when the plugin-system spawn enumerates with empty env.
|
|
10
|
+
let driver = null;
|
|
11
|
+
function readPassword() {
|
|
12
|
+
if (process.env.NEO4J_PASSWORD)
|
|
13
|
+
return process.env.NEO4J_PASSWORD;
|
|
14
|
+
const passwordFile = resolve(process.env.PLATFORM_ROOT ?? resolve(import.meta.dirname, "../../../.."), "config/.neo4j-password");
|
|
15
|
+
try {
|
|
16
|
+
return readFileSync(passwordFile, "utf-8").trim();
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
throw new Error(`Neo4j password not found. Expected at ${passwordFile} or in NEO4J_PASSWORD env var.`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export function getDriver() {
|
|
23
|
+
if (!driver) {
|
|
24
|
+
const uri = process.env.NEO4J_URI;
|
|
25
|
+
if (!uri) {
|
|
26
|
+
throw new Error("[outlook] NEO4J_URI unset — refusing to default to bolt://localhost:7687");
|
|
27
|
+
}
|
|
28
|
+
const user = process.env.NEO4J_USER ?? "neo4j";
|
|
29
|
+
const password = readPassword();
|
|
30
|
+
console.error(`[outlook] resolved neo4j_uri=${uri}`);
|
|
31
|
+
driver = neo4j.driver(uri, neo4j.auth.basic(user, password));
|
|
32
|
+
}
|
|
33
|
+
return driver;
|
|
34
|
+
}
|
|
35
|
+
export function getSession() {
|
|
36
|
+
return getDriver().session();
|
|
37
|
+
}
|
|
38
|
+
export async function closeDriver() {
|
|
39
|
+
if (driver) {
|
|
40
|
+
await driver.close();
|
|
41
|
+
driver = null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=neo4j.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"neo4j.js","sourceRoot":"","sources":["../../src/lib/neo4j.ts"],"names":[],"mappings":"AAAA,OAAO,KAA0B,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,0EAA0E;AAC1E,6EAA6E;AAC7E,8EAA8E;AAC9E,4EAA4E;AAC5E,+EAA+E;AAC/E,0DAA0D;AAE1D,IAAI,MAAM,GAAkB,IAAI,CAAC;AAEjC,SAAS,YAAY;IACnB,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAElE,MAAM,YAAY,GAAG,OAAO,CAC1B,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,EACxE,wBAAwB,CACzB,CAAC;IAEF,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CACb,yCAAyC,YAAY,gCAAgC,CACtF,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;QAClC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CACb,0EAA0E,CAC3E,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,OAAO,CAAC;QAC/C,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;QAChC,OAAO,CAAC,KAAK,CAAC,gCAAgC,GAAG,EAAE,CAAC,CAAC;QACrD,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,SAAS,EAAE,CAAC,OAAO,EAAE,CAAC;AAC/B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACrB,MAAM,GAAG,IAAI,CAAC;IAChB,CAAC;AACH,CAAC"}
|
|
@@ -3,6 +3,7 @@ export interface FetchBodyResult {
|
|
|
3
3
|
id: string;
|
|
4
4
|
subject: string | null;
|
|
5
5
|
from: string | null;
|
|
6
|
+
fromName: string | null;
|
|
6
7
|
to: string[];
|
|
7
8
|
cc: string[];
|
|
8
9
|
receivedDateTime: string;
|
|
@@ -12,6 +13,19 @@ export interface FetchBodyResult {
|
|
|
12
13
|
contentType: "html" | "text";
|
|
13
14
|
body: string;
|
|
14
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Map Graph's `from.emailAddress` to the archive's { from, fromName } pair.
|
|
18
|
+
* Exported so the mapping is unit-testable without a live Graph call.
|
|
19
|
+
*/
|
|
20
|
+
export declare function mapRawFrom(from?: {
|
|
21
|
+
emailAddress?: {
|
|
22
|
+
address?: string;
|
|
23
|
+
name?: string;
|
|
24
|
+
};
|
|
25
|
+
} | null): {
|
|
26
|
+
from: string | null;
|
|
27
|
+
fromName: string | null;
|
|
28
|
+
};
|
|
15
29
|
/**
|
|
16
30
|
* Read the COMPLETE body of one message by id. Graph's bodyPreview (returned by
|
|
17
31
|
* outlook-mail-list/-search) is capped near 255 chars; this requests the full
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mail-fetch-body.d.ts","sourceRoot":"","sources":["../../src/tools/mail-fetch-body.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAMhE,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,EAAE,EAAE,MAAM,EAAE,CAAC;IACb,EAAE,EAAE,MAAM,EAAE,CAAC;IACb,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,MAAM,EAAE,OAAO,CAAC;IAChB,cAAc,EAAE,OAAO,CAAC;IACxB,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC;CACd;AAkBD;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,iBAAiB,EACzB,IAAI,EAAE;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,GAC1B,OAAO,CAAC,eAAe,CAAC,
|
|
1
|
+
{"version":3,"file":"mail-fetch-body.d.ts","sourceRoot":"","sources":["../../src/tools/mail-fetch-body.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAMhE,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,EAAE,EAAE,MAAM,EAAE,CAAC;IACb,EAAE,EAAE,MAAM,EAAE,CAAC;IACb,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,MAAM,EAAE,OAAO,CAAC;IAChB,cAAc,EAAE,OAAO,CAAC;IACxB,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC;CACd;AAkBD;;;GAGG;AACH,wBAAgB,UAAU,CACxB,IAAI,CAAC,EAAE;IAAE,YAAY,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAAG,IAAI,GACnE;IAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAKlD;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,iBAAiB,EACzB,IAAI,EAAE;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,GAC1B,OAAO,CAAC,eAAe,CAAC,CAqC1B"}
|
|
@@ -3,6 +3,16 @@ import { htmlToText } from "../lib/html-to-text.js";
|
|
|
3
3
|
import { log } from "../lib/log.js";
|
|
4
4
|
import { addrs } from "../lib/recipients.js";
|
|
5
5
|
const SELECT = "id,subject,from,toRecipients,ccRecipients,receivedDateTime,conversationId,isRead,hasAttachments,body";
|
|
6
|
+
/**
|
|
7
|
+
* Map Graph's `from.emailAddress` to the archive's { from, fromName } pair.
|
|
8
|
+
* Exported so the mapping is unit-testable without a live Graph call.
|
|
9
|
+
*/
|
|
10
|
+
export function mapRawFrom(from) {
|
|
11
|
+
return {
|
|
12
|
+
from: from?.emailAddress?.address ?? null,
|
|
13
|
+
fromName: from?.emailAddress?.name ?? null,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
6
16
|
/**
|
|
7
17
|
* Read the COMPLETE body of one message by id. Graph's bodyPreview (returned by
|
|
8
18
|
* outlook-mail-list/-search) is capped near 255 chars; this requests the full
|
|
@@ -24,10 +34,12 @@ export async function runMailFetchBody(config, args) {
|
|
|
24
34
|
bytes: body.length,
|
|
25
35
|
contentType,
|
|
26
36
|
});
|
|
37
|
+
const fromMapped = mapRawFrom(msg.from);
|
|
27
38
|
return {
|
|
28
39
|
id: msg.id,
|
|
29
40
|
subject: msg.subject ?? null,
|
|
30
|
-
from:
|
|
41
|
+
from: fromMapped.from,
|
|
42
|
+
fromName: fromMapped.fromName,
|
|
31
43
|
to: addrs(msg.toRecipients),
|
|
32
44
|
cc: addrs(msg.ccRecipients),
|
|
33
45
|
receivedDateTime: msg.receivedDateTime,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mail-fetch-body.js","sourceRoot":"","sources":["../../src/tools/mail-fetch-body.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACpC,OAAO,EAAE,KAAK,EAAqB,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"mail-fetch-body.js","sourceRoot":"","sources":["../../src/tools/mail-fetch-body.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACpC,OAAO,EAAE,KAAK,EAAqB,MAAM,sBAAsB,CAAC;AA8BhE,MAAM,MAAM,GACV,sGAAsG,CAAC;AAEzG;;;GAGG;AACH,MAAM,UAAU,UAAU,CACxB,IAAoE;IAEpE,OAAO;QACL,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,IAAI,IAAI;QACzC,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,IAAI,IAAI;KAC3C,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAAyB,EACzB,IAA2B;IAE3B,MAAM,IAAI,GAAG,gBAAgB,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;IAClE,MAAM,GAAG,GAAG,MAAM,SAAS,CACzB,MAAM,EACN,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAe,EAC7E,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,EAAE,IAAI,EAAE,CAC1C,CAAC;IAEF,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,WAAW,IAAI,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;IAChE,MAAM,WAAW,GAAoB,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;IAC1E,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,EAAE,OAAO,IAAI,EAAE,CAAC;IACpC,MAAM,IAAI,GAAG,WAAW,KAAK,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IAE5D,GAAG,CAAC;QACF,KAAK,EAAE,iBAAiB;QACxB,EAAE,EAAE,YAAY;QAChB,OAAO,EAAE,MAAM,CAAC,SAAS;QACzB,EAAE,EAAE,IAAI,CAAC,SAAS;QAClB,KAAK,EAAE,IAAI,CAAC,MAAM;QAClB,WAAW;KACZ,CAAC,CAAC;IAEH,MAAM,UAAU,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACxC,OAAO;QACL,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,IAAI;QAC5B,IAAI,EAAE,UAAU,CAAC,IAAI;QACrB,QAAQ,EAAE,UAAU,CAAC,QAAQ;QAC7B,EAAE,EAAE,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC;QAC3B,EAAE,EAAE,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC;QAC3B,gBAAgB,EAAE,GAAG,CAAC,gBAAgB;QACtC,cAAc,EAAE,GAAG,CAAC,cAAc,IAAI,IAAI;QAC1C,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,KAAK;QAC3B,cAAc,EAAE,GAAG,CAAC,cAAc,IAAI,KAAK;QAC3C,WAAW;QACX,IAAI;KACL,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { GraphClientConfig } from "../lib/graph-client.js";
|
|
2
|
+
export interface IngestDecision {
|
|
3
|
+
messageId: string;
|
|
4
|
+
disposition: "ingest" | "discard";
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Split decisions into ingest ids + a discard count. Refuses an empty array
|
|
8
|
+
* (nothing to do) or a duplicate messageId (ambiguous disposition) so the
|
|
9
|
+
* operator re-issues a clean set rather than a silent partial ingest. Unlike
|
|
10
|
+
* email-ingest there is no staged batch or high-water mark to guard: the ids
|
|
11
|
+
* are explicit and the per-message decision holds over exactly this call.
|
|
12
|
+
*/
|
|
13
|
+
export declare function validateDecisions(decisions: IngestDecision[]): {
|
|
14
|
+
toIngest: string[];
|
|
15
|
+
discarded: number;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Write operator-reviewed messages into the business graph. For each `ingest`
|
|
19
|
+
* decision the full body + envelope is fetched, threads are grouped by
|
|
20
|
+
* conversationId, participants are resolved closed-set against Neo4j, and each
|
|
21
|
+
* resolvable thread is dispatched through the shared conversation-archive
|
|
22
|
+
* script. Unresolved-address threads are skipped and reported.
|
|
23
|
+
*/
|
|
24
|
+
export declare function runMailIngest(config: GraphClientConfig, params: {
|
|
25
|
+
decisions: IngestDecision[];
|
|
26
|
+
}): Promise<string>;
|
|
27
|
+
//# sourceMappingURL=mail-ingest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mail-ingest.d.ts","sourceRoot":"","sources":["../../src/tools/mail-ingest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAOhE,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,QAAQ,GAAG,SAAS,CAAC;CACnC;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,cAAc,EAAE,GAC1B;IAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAsB3C;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,iBAAiB,EACzB,MAAM,EAAE;IAAE,SAAS,EAAE,cAAc,EAAE,CAAA;CAAE,GACtC,OAAO,CAAC,MAAM,CAAC,CAwCjB"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { runMailFetchBody } from "./mail-fetch-body.js";
|
|
2
|
+
import { dispatchOutlookMessagesToConversationArchive, } from "../lib/conversation-archive-dispatch.js";
|
|
3
|
+
/**
|
|
4
|
+
* Split decisions into ingest ids + a discard count. Refuses an empty array
|
|
5
|
+
* (nothing to do) or a duplicate messageId (ambiguous disposition) so the
|
|
6
|
+
* operator re-issues a clean set rather than a silent partial ingest. Unlike
|
|
7
|
+
* email-ingest there is no staged batch or high-water mark to guard: the ids
|
|
8
|
+
* are explicit and the per-message decision holds over exactly this call.
|
|
9
|
+
*/
|
|
10
|
+
export function validateDecisions(decisions) {
|
|
11
|
+
if (decisions.length === 0) {
|
|
12
|
+
throw new Error("Refusing to ingest — no decisions passed. List messages with outlook-mail-list or outlook-mail-search first, then pass a disposition for each.");
|
|
13
|
+
}
|
|
14
|
+
const seen = new Set();
|
|
15
|
+
const toIngest = [];
|
|
16
|
+
let discarded = 0;
|
|
17
|
+
for (const d of decisions) {
|
|
18
|
+
const id = d.messageId.trim();
|
|
19
|
+
if (!id)
|
|
20
|
+
throw new Error(`Decision had a blank messageId: ${JSON.stringify(d)}`);
|
|
21
|
+
if (seen.has(id)) {
|
|
22
|
+
throw new Error(`Refusing to ingest — duplicate messageId "${id}". Pass one disposition per message.`);
|
|
23
|
+
}
|
|
24
|
+
seen.add(id);
|
|
25
|
+
if (d.disposition === "ingest")
|
|
26
|
+
toIngest.push(id);
|
|
27
|
+
else
|
|
28
|
+
discarded++;
|
|
29
|
+
}
|
|
30
|
+
return { toIngest, discarded };
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Write operator-reviewed messages into the business graph. For each `ingest`
|
|
34
|
+
* decision the full body + envelope is fetched, threads are grouped by
|
|
35
|
+
* conversationId, participants are resolved closed-set against Neo4j, and each
|
|
36
|
+
* resolvable thread is dispatched through the shared conversation-archive
|
|
37
|
+
* script. Unresolved-address threads are skipped and reported.
|
|
38
|
+
*/
|
|
39
|
+
export async function runMailIngest(config, params) {
|
|
40
|
+
const { toIngest, discarded } = validateDecisions(params.decisions);
|
|
41
|
+
const messages = [];
|
|
42
|
+
for (const messageId of toIngest) {
|
|
43
|
+
const body = await runMailFetchBody(config, { messageId });
|
|
44
|
+
messages.push({
|
|
45
|
+
messageId: body.id,
|
|
46
|
+
conversationId: body.conversationId,
|
|
47
|
+
fromAddress: body.from,
|
|
48
|
+
fromName: body.fromName,
|
|
49
|
+
toAddresses: body.to,
|
|
50
|
+
ccAddresses: body.cc,
|
|
51
|
+
subject: body.subject,
|
|
52
|
+
bodyText: body.body,
|
|
53
|
+
receivedDateTime: body.receivedDateTime,
|
|
54
|
+
accountId: config.accountId,
|
|
55
|
+
});
|
|
56
|
+
console.error(`[outlook-mcp] mail-ingest op=ingest id=${body.id} conversationId=${body.conversationId ?? "none"} disposition=ingest`);
|
|
57
|
+
}
|
|
58
|
+
const { threadsDispatched, threadsSkipped, unresolvedAddresses } = await dispatchOutlookMessagesToConversationArchive(messages);
|
|
59
|
+
console.error(`[outlook-mcp] mail-ingest op=summary ingested=${toIngest.length} discarded=${discarded} threadsDispatched=${threadsDispatched} threadsSkipped=${threadsSkipped} unresolved=${unresolvedAddresses.length}`);
|
|
60
|
+
const lines = [
|
|
61
|
+
`Ingested ${toIngest.length} message(s); discarded ${discarded}.`,
|
|
62
|
+
`Graph: ${threadsDispatched} thread(s) dispatched to conversation-archive, ${threadsSkipped} skipped.`,
|
|
63
|
+
];
|
|
64
|
+
if (unresolvedAddresses.length > 0) {
|
|
65
|
+
lines.push(`Unresolved sender/recipient addresses (no :Person or :AdminUser carries these emails — add them to the graph and re-run outlook-mail-ingest to land their threads): ${unresolvedAddresses.join(", ")}`);
|
|
66
|
+
}
|
|
67
|
+
return lines.join("\n");
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=mail-ingest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mail-ingest.js","sourceRoot":"","sources":["../../src/tools/mail-ingest.ts"],"names":[],"mappings":"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"}
|
|
@@ -76,7 +76,8 @@ Reads the COMPLETE body (not `bodyPreview`). `body.contentType` is `html` or `te
|
|
|
76
76
|
{
|
|
77
77
|
id: string;
|
|
78
78
|
subject: string | null;
|
|
79
|
-
from: string | null;
|
|
79
|
+
from: string | null; // from.emailAddress.address
|
|
80
|
+
fromName: string | null; // from.emailAddress.name (additive) — the sender display name outlook-mail-ingest carries into the archive
|
|
80
81
|
to: string[]; // toRecipients[].emailAddress.address
|
|
81
82
|
cc: string[];
|
|
82
83
|
receivedDateTime: string;
|
|
@@ -124,6 +125,14 @@ Recoverable — moves to Deleted Items, never hard-deletes or expunges. An id al
|
|
|
124
125
|
|
|
125
126
|
**Returned shape:** `{ moved: string[]; notMoved: string[] }`.
|
|
126
127
|
|
|
128
|
+
## outlook-mail-ingest
|
|
129
|
+
|
|
130
|
+
**No direct Graph mutation.** Per approved message it calls `runMailFetchBody`'s `GET /me/messages/{id}?$select=…,body` to read the full body + envelope (including `conversationId` and the additive `fromName`). The graph write is delegated: threads are grouped by `conversationId`, participants resolve closed-set against Neo4j (`UNWIND $addresses … WHERE (p:Person OR p:AdminUser) AND p.accountId=$accountId AND toLower(p.email)=addr`), and each resolvable thread is written by spawning `plugins/memory/bin/conversation-archive-ingest.sh <thread.json> --source email --participant-person-ids <elementIds> --scope admin --session-id outlook-<uuid>`. The thread JSON is `[{from:{name,email}, date, bodyText}]`, the shape the shared `email` normaliser consumes. An unresolved From/To/Cc address skips its whole thread; no `:Person` is auto-created. This is the plugin's only Neo4j coupling (`neo4j-driver`, `lib/neo4j.ts`).
|
|
131
|
+
|
|
132
|
+
**Input:** `{ decisions: [{ messageId, disposition: "ingest" | "discard" }], mailbox? }`. Refuses an empty array and a duplicate messageId.
|
|
133
|
+
|
|
134
|
+
**Returned shape:** a plain-text summary — ingested/discarded counts, threads dispatched/skipped, and any unresolved addresses.
|
|
135
|
+
|
|
127
136
|
## outlook-mail-otp-extract
|
|
128
137
|
|
|
129
138
|
**Endpoints:** `GET /me/mailFolders/Inbox/messages?$top=15&$orderby=receivedDateTime DESC&$select=id,subject,from,receivedDateTime` to list candidates, then `outlook-mail-fetch-body`'s `GET /me/messages/{id}?$select=…,body` per sender-matched candidate. Scans immediately, then polls every 5 s until a code is found or `timeout` seconds (default 60) elapse. `extractOtpFromText` is shared verbatim with the `email` plugin.
|
|
@@ -60,6 +60,10 @@ The revoke path below is scoped to one specific, visible failure. It is not a ge
|
|
|
60
60
|
- `outlook-mail-reply messageId=<id> body=<text>` — reply in-thread. Threads natively (the original conversation is preserved). `replyAll=true` replies to the sender and every original recipient; `cc`/`bcc` add recipients; `attachments` is an array of file paths inside the account directory (up to 25 MB per file). The body is plain text, prepended above the quoted original. Needs `Mail.ReadWrite` + `Mail.Send`.
|
|
61
61
|
- `outlook-mail-delete ids=[<id>...]` — move messages to Deleted Items. RECOVERABLE: it never hard-deletes or expunges, so recovery is possible from the mailbox's Deleted Items. Pass the ids from a prior list/search. An id already gone is reported not-moved without failing the rest. Needs `Mail.ReadWrite`.
|
|
62
62
|
|
|
63
|
+
## Ingesting mail into memory
|
|
64
|
+
|
|
65
|
+
Writing operator-reviewed messages into the business graph is the `outlook-mail-ingest` skill (its own SKILL.md), which drives the list, summarise, ask, ingest loop over `outlook-mail-ingest`.
|
|
66
|
+
|
|
63
67
|
## One-time codes (OTP)
|
|
64
68
|
|
|
65
69
|
- `outlook-mail-otp-extract sender=<domain>` — poll the inbox for a verification code from a sender (e.g. `cloudflare.com`). Optional `subjectPattern` (regex) and `timeout` (seconds, default 60). Reads full bodies to extract the code. Used during service authentication.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: outlook-mail-ingest
|
|
3
|
+
description: "Operator-initiated Outlook mail ingestion. Activate when the operator asks to check, triage, or pull Outlook mail into memory ('check my Outlook', 'ingest these Outlook messages', 'pull that thread into the graph'). Drives a list, summarise, ask, ingest loop using the outlook-mail-list / outlook-mail-search and outlook-mail-ingest tools. Human-in-the-loop: nothing enters the graph without an explicit operator decision per message."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Outlook mail ingestion
|
|
7
|
+
|
|
8
|
+
Invoked from `specialists:personal-assistant`.
|
|
9
|
+
|
|
10
|
+
Operator-initiated, human-in-the-loop ingestion of an Outlook mailbox into the business graph. Reviewed messages become `:ConversationArchive {source:'email'}` threads. A message enters the graph only when the operator says so, and only the ones they pick. There is no background poll, no automatic classifier, no silent writes.
|
|
11
|
+
|
|
12
|
+
This is the Microsoft Graph analogue of the IMAP `email-ingest` skill. It differs in one structural way: Outlook reads are stateless Graph calls, so there is no staged batch and no high-water mark. You list with the ordinary read tools and pass the exact message ids you want to `outlook-mail-ingest`.
|
|
13
|
+
|
|
14
|
+
## When to activate
|
|
15
|
+
|
|
16
|
+
Activate when the operator wants to bring Outlook mail into the agent's memory. Typical phrasings:
|
|
17
|
+
|
|
18
|
+
- "Check my Outlook."
|
|
19
|
+
- "Ingest these Outlook messages."
|
|
20
|
+
- "Pull that Outlook thread into the graph."
|
|
21
|
+
|
|
22
|
+
Do not activate for:
|
|
23
|
+
|
|
24
|
+
- Reading or searching mail already in the mailbox or the graph. Those are `outlook-mail-list`, `outlook-mail-search`, `outlook-mail-fetch-body`.
|
|
25
|
+
- Drafting or sending. Those are `outlook-draft`, `outlook-mail-reply`, `outlook-mail-send`.
|
|
26
|
+
- Setup, status, or OTP extraction. Those are direct tool calls.
|
|
27
|
+
|
|
28
|
+
## Flow
|
|
29
|
+
|
|
30
|
+
### 1. List
|
|
31
|
+
|
|
32
|
+
Call `outlook-mail-list` (or `outlook-mail-search` for a sender or subject filter). Both return a preview per message with its id, sender, subject, and `receivedDateTime`. They write nothing to the graph.
|
|
33
|
+
|
|
34
|
+
An account can hold more than one mailbox. When it does, every operational tool refuses unless it names one, and the refusal lists the connected mailboxes. That refusal means "say which mailbox", not "there is no mail". Resolve it with `outlook-mailbox-list`, then pass `mailbox` and carry on.
|
|
35
|
+
|
|
36
|
+
Reads page beyond the newest window. When a response carries a `nextCursor`, older messages remain behind it; pass the cursor back to page on. Absence of a `nextCursor` is the only thing that means you saw everything in range.
|
|
37
|
+
|
|
38
|
+
### 2. Summarise
|
|
39
|
+
|
|
40
|
+
Present the listed messages to the operator as a numbered or per-id summary. For each, surface the sender, the subject, and a one-line gist from the preview. Where a message is obviously one or the other, suggest a disposition ("newsletter, looks like discard"; "thread reply from a known correspondent, looks like ingest"). The suggestion is a hint, never an action; the operator decides.
|
|
41
|
+
|
|
42
|
+
There is no screener. If a message looks like phishing, say so in plain English so the operator can discard it by eye.
|
|
43
|
+
|
|
44
|
+
### 3. Ask
|
|
45
|
+
|
|
46
|
+
Ask the operator to confirm a disposition for every message you intend to ingest. Either a blanket call ("ingest all", "discard the rest") that you turn into the per-message map, or an explicit per-message choice ("ingest 1, 2, 4; discard 3"). If the operator answers ambiguously ("the work ones"), restate the messages you think they mean and confirm before proceeding. Never guess.
|
|
47
|
+
|
|
48
|
+
### 4. Ingest
|
|
49
|
+
|
|
50
|
+
Call `outlook-mail-ingest` with a `decisions` array: one `{ messageId, disposition }` per message, `disposition` being `ingest` or `discard`. The tool refuses an empty array and refuses a duplicate messageId, so pass a clean set with one disposition per id.
|
|
51
|
+
|
|
52
|
+
For each `ingest` message the tool fetches the full body and envelope, groups messages into threads by Graph `conversationId`, and resolves every From/To/Cc address closed-set against the graph. An address that does not already resolve to a `:Person` or `:AdminUser` for this account causes its whole thread to skip; the tool returns the unresolved addresses. It never creates a `:Person`.
|
|
53
|
+
|
|
54
|
+
On success the tool returns a one-line summary: how many were ingested, how many discarded, how many threads dispatched or skipped, and any unresolved addresses.
|
|
55
|
+
|
|
56
|
+
### 5. Confirm
|
|
57
|
+
|
|
58
|
+
Echo the tool's summary back to the operator in one sentence. If any thread was skipped for an unresolved address, tell the operator which address, and that adding that person to the graph and re-running will land the thread. If they want to draft a reply to anything just ingested, hand off to the Outlook compose tools.
|
|
59
|
+
|
|
60
|
+
## Edge cases
|
|
61
|
+
|
|
62
|
+
| Situation | Behaviour |
|
|
63
|
+
|-----------|-----------|
|
|
64
|
+
| The list returns zero messages | Tell the operator and stop. Do not call `outlook-mail-ingest`. |
|
|
65
|
+
| An address on a thread does not resolve | The thread is skipped and the address is returned. Surface it; the operator adds the person to the graph, then re-runs for that message. |
|
|
66
|
+
| Operator wants to ingest some now and review the rest later | Fine. Ids are explicit, so ingest exactly the ones decided now and list the rest again later. There is no high-water mark to advance and nothing is silently dropped. |
|
|
67
|
+
| Operator abandons mid-flow | Do not call `outlook-mail-ingest`. Nothing was staged and nothing changes. |
|
|
68
|
+
| A tool errors (Graph down, auth failure) | Surface the error verbatim. Do not retry silently. |
|
|
69
|
+
|
|
70
|
+
## Out of scope
|
|
71
|
+
|
|
72
|
+
- Automatic re-screening or classification. The operator is the screener.
|
|
73
|
+
- Scheduled or recurring ingestion. The operator initiates every cycle.
|
|
74
|
+
- Attachment ingest. This skill lands text threads only.
|
|
75
|
+
- Other channels. WhatsApp, IMAP email, and the public web have their own ingestion paths.
|
|
76
|
+
|
|
77
|
+
## Observability
|
|
78
|
+
|
|
79
|
+
Each ingest emits tagged lines the operator can grep:
|
|
80
|
+
|
|
81
|
+
- `[outlook-mcp] mail-ingest op=ingest id=<id> conversationId=<id> disposition=ingest` per approved message.
|
|
82
|
+
- `[outlook-mcp] mail-ingest op=thread-dispatched root=<key> messages=<n> participants=<n>` per landed thread.
|
|
83
|
+
- `[outlook-mcp] mail-ingest op=summary ingested=<n> discarded=<m> threadsDispatched=<n> threadsSkipped=<n> unresolved=<n>` once per call.
|
|
84
|
+
|
|
85
|
+
A complete cycle is greppable as the `[outlook-mcp] mail-ingest` lines for one session. A `threadsSkipped` above zero with an `unresolved` count is the closed-set resolution refusing an unknown participant, not a failure.
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sweep
|
|
3
3
|
description: "Catch-up composition. On a catch me up / what did I miss / morning sync / sweep turn, reads every connected surface (inbox, calendar, contacts, and the site captures published sites write to Cloudflare D1), compares against the graph, and proposes graph writes for the operator to approve. Composes work, scheduling, contacts, and memory; adds no tools of its own and never sends."
|
|
4
|
+
skills:
|
|
5
|
+
- skills/sweep-workflow/SKILL.md
|
|
6
|
+
- skills/email-graph-sweep/SKILL.md
|
|
4
7
|
metadata: {"platform":{"always":false,"embed":["admin"],"pluginKey":"sweep","optional":true,"recommended":true}}
|
|
5
8
|
---
|
|
6
9
|
|
|
@@ -10,6 +13,7 @@ Sweep is a catch-up composition. When the operator asks to be caught up, it read
|
|
|
10
13
|
|
|
11
14
|
This plugin adds no tools. It composes plugins that already ship: `work` for a new to-do, `scheduling` for a calendar event, `contacts` for a person or organisation, and `memory` for a standalone fact. Each of those plugins writes through its own schema-enforcing tool.
|
|
12
15
|
|
|
13
|
-
##
|
|
16
|
+
## Skills
|
|
14
17
|
|
|
15
18
|
- `sweep-workflow` — the read-dedupe-propose-approve-delegate workflow. Triggers on "catch me up", "what did I miss", "morning sync", and "sweep".
|
|
19
|
+
- `email-graph-sweep` — enable or disable a recurring, per-account routine that turns new inbound mail into deduped graph entities and reports over a persistent channel on every fire. Gated on a mailbox connector and a registered persistent-channel destination; it writes where `sweep-workflow` only proposes, and it is opt-in, never auto-provisioned. Triggers on "set up an automatic email sweep", "turn my email into the graph automatically", and the disable equivalents.
|