@rubytech/create-maxy-code 0.1.296 → 0.1.298
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/lib/models/dist/index.d.ts +7 -0
- package/payload/platform/lib/models/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/models/dist/index.js +16 -1
- package/payload/platform/lib/models/dist/index.js.map +1 -1
- package/payload/platform/lib/models/src/index.ts +16 -0
- package/payload/platform/plugins/admin/.claude-plugin/plugin.json +5 -1
- package/payload/platform/plugins/admin/lib/mcp-spawn-tee/index.js +159 -0
- package/payload/platform/plugins/admin/lib/mcp-spawn-tee/package.json +3 -0
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +4 -14
- package/payload/platform/plugins/aeo/.claude-plugin/plugin.json +5 -1
- package/payload/platform/plugins/aeo/lib/mcp-spawn-tee/index.js +159 -0
- package/payload/platform/plugins/aeo/lib/mcp-spawn-tee/package.json +3 -0
- package/payload/platform/plugins/browser/.claude-plugin/plugin.json +5 -1
- package/payload/platform/plugins/browser/lib/mcp-spawn-tee/index.js +159 -0
- package/payload/platform/plugins/browser/lib/mcp-spawn-tee/package.json +3 -0
- package/payload/platform/plugins/contacts/.claude-plugin/plugin.json +5 -1
- package/payload/platform/plugins/contacts/lib/mcp-spawn-tee/index.js +159 -0
- package/payload/platform/plugins/contacts/lib/mcp-spawn-tee/package.json +3 -0
- package/payload/platform/plugins/docs/references/admin-ui.md +1 -1
- package/payload/platform/plugins/docs/references/getting-started.md +1 -1
- package/payload/platform/plugins/docs/references/platform.md +1 -11
- package/payload/platform/plugins/email/.claude-plugin/plugin.json +6 -2
- package/payload/platform/plugins/email/PLUGIN.md +14 -2
- package/payload/platform/plugins/email/lib/mcp-spawn-tee/index.js +159 -0
- package/payload/platform/plugins/email/lib/mcp-spawn-tee/package.json +3 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft-edit.test.d.ts +2 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft-edit.test.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft-edit.test.js +71 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft-edit.test.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft-send.test.d.ts +2 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft-send.test.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft-send.test.js +95 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft-send.test.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft.test.d.ts +2 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft.test.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft.test.js +129 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft.test.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/email-setup.test.js +58 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/email-setup.test.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/__tests__/imap-drafts.test.d.ts +2 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/imap-drafts.test.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/imap-drafts.test.js +165 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/imap-drafts.test.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/imap-probe.test.d.ts +2 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/imap-probe.test.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/imap-probe.test.js +69 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/imap-probe.test.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/mail-options.test.d.ts +2 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/mail-options.test.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/mail-options.test.js +46 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/mail-options.test.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/send-raw.test.d.ts +2 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/send-raw.test.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/send-raw.test.js +38 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/send-raw.test.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/setup-probe.test.d.ts +2 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/setup-probe.test.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/setup-probe.test.js +56 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/setup-probe.test.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/smtp-probe.test.d.ts +2 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/smtp-probe.test.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/smtp-probe.test.js +46 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/smtp-probe.test.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/index.js +118 -0
- package/payload/platform/plugins/email/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/compose.d.ts +47 -0
- package/payload/platform/plugins/email/mcp/dist/lib/compose.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/lib/compose.js +75 -0
- package/payload/platform/plugins/email/mcp/dist/lib/compose.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts +53 -3
- package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/imap.js +179 -5
- package/payload/platform/plugins/email/mcp/dist/lib/imap.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/setup-probe.d.ts +42 -0
- package/payload/platform/plugins/email/mcp/dist/lib/setup-probe.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/lib/setup-probe.js +72 -0
- package/payload/platform/plugins/email/mcp/dist/lib/setup-probe.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/lib/smtp.d.ts +34 -6
- package/payload/platform/plugins/email/mcp/dist/lib/smtp.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/smtp.js +62 -20
- package/payload/platform/plugins/email/mcp/dist/lib/smtp.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/scripts/send-transactional.js +1 -2
- package/payload/platform/plugins/email/mcp/dist/scripts/send-transactional.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-draft-edit.d.ts +9 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-draft-edit.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-draft-edit.js +23 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-draft-edit.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-draft-send.d.ts +8 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-draft-send.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-draft-send.js +52 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-draft-send.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-draft.d.ts +7 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-draft.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-draft.js +17 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-draft.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-reply.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-reply.js +1 -8
- package/payload/platform/plugins/email/mcp/dist/tools/email-reply.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-send.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-send.js +2 -8
- package/payload/platform/plugins/email/mcp/dist/tools/email-send.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-setup.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-setup.js +25 -3
- package/payload/platform/plugins/email/mcp/dist/tools/email-setup.js.map +1 -1
- package/payload/platform/plugins/email/references/email-reference.md +15 -0
- package/payload/platform/plugins/email/skills/email-composition/SKILL.md +26 -4
- package/payload/platform/plugins/memory/.claude-plugin/plugin.json +5 -1
- package/payload/platform/plugins/memory/lib/mcp-spawn-tee/index.js +159 -0
- package/payload/platform/plugins/memory/lib/mcp-spawn-tee/package.json +3 -0
- package/payload/platform/plugins/outlook/.claude-plugin/plugin.json +5 -1
- package/payload/platform/plugins/outlook/lib/mcp-spawn-tee/index.js +159 -0
- package/payload/platform/plugins/outlook/lib/mcp-spawn-tee/package.json +3 -0
- package/payload/platform/plugins/replicate/.claude-plugin/plugin.json +5 -1
- package/payload/platform/plugins/replicate/lib/mcp-spawn-tee/index.js +159 -0
- package/payload/platform/plugins/replicate/lib/mcp-spawn-tee/package.json +3 -0
- package/payload/platform/plugins/scheduling/.claude-plugin/plugin.json +5 -1
- package/payload/platform/plugins/scheduling/lib/mcp-spawn-tee/index.js +159 -0
- package/payload/platform/plugins/scheduling/lib/mcp-spawn-tee/package.json +3 -0
- package/payload/platform/plugins/telegram/.claude-plugin/plugin.json +5 -1
- package/payload/platform/plugins/telegram/lib/mcp-spawn-tee/index.js +159 -0
- package/payload/platform/plugins/telegram/lib/mcp-spawn-tee/package.json +3 -0
- package/payload/platform/plugins/url-get/.claude-plugin/plugin.json +5 -1
- package/payload/platform/plugins/url-get/lib/mcp-spawn-tee/index.js +159 -0
- package/payload/platform/plugins/url-get/lib/mcp-spawn-tee/package.json +3 -0
- package/payload/platform/plugins/whatsapp/.claude-plugin/plugin.json +5 -1
- package/payload/platform/plugins/whatsapp/lib/mcp-spawn-tee/index.js +159 -0
- package/payload/platform/plugins/whatsapp/lib/mcp-spawn-tee/package.json +3 -0
- package/payload/platform/plugins/work/.claude-plugin/plugin.json +5 -1
- package/payload/platform/plugins/work/lib/mcp-spawn-tee/index.js +159 -0
- package/payload/platform/plugins/work/lib/mcp-spawn-tee/package.json +3 -0
- package/payload/platform/plugins/workflows/.claude-plugin/plugin.json +5 -1
- package/payload/platform/plugins/workflows/lib/mcp-spawn-tee/index.js +159 -0
- package/payload/platform/plugins/workflows/lib/mcp-spawn-tee/package.json +3 -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 +3 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts +13 -0
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +71 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/jsonl-watch.d.ts +10 -0
- package/payload/platform/services/whatsapp-channel/dist/jsonl-watch.d.ts.map +1 -0
- package/payload/platform/services/whatsapp-channel/dist/jsonl-watch.js +70 -0
- package/payload/platform/services/whatsapp-channel/dist/jsonl-watch.js.map +1 -0
- package/payload/platform/services/whatsapp-channel/dist/server.d.ts +6 -1
- package/payload/platform/services/whatsapp-channel/dist/server.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/server.js +38 -1
- package/payload/platform/services/whatsapp-channel/dist/server.js.map +1 -1
- package/payload/platform/templates/specialists/agents/personal-assistant.md +1 -1
- package/payload/premium-plugins/writer-craft/.claude-plugin/plugin.json +5 -1
- package/payload/premium-plugins/writer-craft/lib/mcp-spawn-tee/index.js +159 -0
- package/payload/premium-plugins/writer-craft/lib/mcp-spawn-tee/package.json +3 -0
- package/payload/server/public/assets/AdminShell-BnhxfX97.js +1 -0
- package/payload/server/public/assets/{Checkbox-DTrIyIFP.js → Checkbox-CVPUf_7I.js} +1 -1
- package/payload/server/public/assets/{Transcript-C3aDVJ-n.js → Transcript-FYmq-mL1.js} +1 -1
- package/payload/server/public/assets/{admin-DVdyV-Q6.js → admin-CF8K3hqE.js} +1 -1
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-DR9W0q1P.js → architectureDiagram-Q4EWVU46-IVt2X8Dk.js} +1 -1
- package/payload/server/public/assets/audio-attachment-mime-DaInZ9sa.js +1 -0
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-C3uwaI7p.js → blockDiagram-DXYQGD6D-CQDngnsc.js} +1 -1
- package/payload/server/public/assets/browser-D_hZgtfv.js +1 -0
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-C8hmUDdd.js → c4Diagram-AHTNJAMY-BjV_YA-L.js} +1 -1
- package/payload/server/public/assets/channel-gFnUr8f4.js +1 -0
- package/payload/server/public/assets/chat-COcrNTJi.js +1 -0
- package/payload/server/public/assets/{chunk-336JU56O-BRCubMCb.js → chunk-336JU56O-B0yBhSVq.js} +2 -2
- package/payload/server/public/assets/{chunk-426QAEUC-BNINkVsL.js → chunk-426QAEUC-BCmWl6vi.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-DSMj_AZh.js → chunk-4TB4RGXK-BImQYhPF.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-6DNGaUkf.js → chunk-5FUZZQ4R-DrDSHQZv.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-DPhkkS4p.js → chunk-5PVQY5BW-CKX_LIok.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-BjWSqn7_.js → chunk-EDXVE4YY-D1zHB217.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-BX1ZnU4A.js → chunk-ENJZ2VHE-SFpdtszU.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-DvYSWH7x.js → chunk-ICPOFSXX-cYdq7RKF.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-7_m3mEOK.js → chunk-OYMX7WX6-B7JLCext.js} +1 -1
- package/payload/server/public/assets/{chunk-U2HBQHQK-Bl1a895I.js → chunk-U2HBQHQK-DWCeFwem.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-WkSpBPYx.js → chunk-X2U36JSP-DGnHsoJ3.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-DpWRmPUo.js → chunk-YZCP3GAM-sg4lGGJV.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-D9Dgmeso.js → chunk-ZZ45TVLE-DtUoGmKE.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-C_wlfUTz.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-Ltv5s3OY.js +1 -0
- package/payload/server/public/assets/clone-D0XoXc_v.js +1 -0
- package/payload/server/public/assets/{dagre-PrVfCcSt.js → dagre-Dfj_jbTe.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-DPq3dcLH.js → dagre-KV5264BT-Bd1VlhUJ.js} +1 -1
- package/payload/server/public/assets/data-DkbQI40a.js +1 -0
- package/payload/server/public/assets/{diagram-5BDNPKRD-DoszElKb.js → diagram-5BDNPKRD-Dqqyk8GE.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-BRuqosix.js → diagram-G4DWMVQ6-Xk3WKR_U.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-CpigG1d_.js → diagram-MMDJMWI5-CAdGL9U7.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-BS0eYiq9.js → diagram-TYMM5635-DY1iYQVY.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-VEQyXCFl.js → erDiagram-SMLLAGMA-BJ5HYKeb.js} +1 -1
- package/payload/server/public/assets/{file-download-C3pBZjt9.js → file-download-BYJN3Kgm.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-2NYMfqHX.js → flowDiagram-DWJPFMVM-B-q6x5Q_.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-AAAa2sqE.js → ganttDiagram-T4ZO3ILL-DbjwY_bG.js} +1 -1
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-d8NUAIz5.js → gitGraphDiagram-UUTBAWPF-C3bLrOmb.js} +1 -1
- package/payload/server/public/assets/{graph-Bx9_2qbJ.js → graph-DmikPM4A.js} +2 -2
- package/payload/server/public/assets/{graph-labels-Cc1nU1_f.js → graph-labels-CtG6ckdG.js} +1 -1
- package/payload/server/public/assets/{graphlib-DUlqr2mr.js → graphlib-BlOjhixq.js} +1 -1
- package/payload/server/public/assets/{infoDiagram-42DDH7IO-D4dh4-0g.js → infoDiagram-42DDH7IO-BpaHbiXO.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-DPTmm2IE.js → ishikawaDiagram-UXIWVN3A-B_DzwK8l.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-B85vjqkE.js → journeyDiagram-VCZTEJTY-COzTF-qc.js} +1 -1
- package/payload/server/public/assets/{jsx-runtime-D3PZpOAF.css → jsx-runtime-BjFkEGXb.css} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-C2Lfb5Xh.js → kanban-definition-6JOO6SKY-C2cOIZU6.js} +1 -1
- package/payload/server/public/assets/{line-CODKFpwO.js → line-Bwa6aUYZ.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-DYdFZnXH.js → mermaid-parser.core-BFAF0BAk.js} +1 -1
- package/payload/server/public/assets/{mermaid.core-Bamjzahu.js → mermaid.core-CMOXmawT.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-CLK90bKJ.js → mindmap-definition-QFDTVHPH-bu0QLO17.js} +1 -1
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-DEsnxhqP.js → pieDiagram-DEJITSTG-DQUe6W2Z.js} +1 -1
- package/payload/server/public/assets/{public-BFMu-jux.js → public-CSEIGhb4.js} +5 -5
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-uIP9V2jZ.js → quadrantDiagram-34T5L4WZ-ChhcwVRA.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-CVS6t5tv.js → requirementDiagram-MS252O5E-DwQXqTA9.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-BIsmtyZA.js → sankeyDiagram-XADWPNL6-zYqdptBM.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-Cu8TfQiW.js → sequenceDiagram-FGHM5R23-x2g84gb4.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-ax4vYGft.js → stateDiagram-FHFEXIEX-CeUrqs2P.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-B27DBP9X.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-3l7ojkMA.js → timeline-definition-GMOUNBTQ-CL-c9XN5.js} +1 -1
- package/payload/server/public/assets/{useSelectionMode-C_EBRd2k.js → useSelectionMode-C1_ky4B6.js} +1 -1
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-C_sv0qMD.js → vennDiagram-DHZGUBPP-By2HBDYr.js} +1 -1
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-C7u4IHMB.js → wardleyDiagram-NUSXRM2D-iahvFvIS.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-A-uLXr1a.js → xychartDiagram-5P7HB3ND-33qqdRhI.js} +1 -1
- package/payload/server/public/browser.html +6 -6
- package/payload/server/public/chat.html +8 -8
- package/payload/server/public/data.html +5 -5
- package/payload/server/public/graph.html +8 -8
- package/payload/server/public/index.html +8 -8
- package/payload/server/public/public.html +6 -6
- package/payload/server/public/whatsapp-wallpaper.webp +0 -0
- package/payload/server/server.js +17 -9
- package/payload/server/public/assets/AdminShell-DDieHnzi.js +0 -1
- package/payload/server/public/assets/audio-attachment-mime-DGEfApkA.js +0 -1
- package/payload/server/public/assets/browser-DrJReVEG.js +0 -1
- package/payload/server/public/assets/channel-drVqp11B.js +0 -1
- package/payload/server/public/assets/chat-rJYaCD6C.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-Dplkw_pj.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-sJXv1Ihp.js +0 -1
- package/payload/server/public/assets/clone-Q_B6oO0c.js +0 -1
- package/payload/server/public/assets/data-CYyR2m_B.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BRv1By5g.js +0 -1
- /package/payload/server/public/assets/{jsx-runtime-5auA0FEj.js → jsx-runtime-UQ0Z6nwN.js} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email-draft-edit.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/email-draft-edit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
const { composeMock, replaceMock } = vi.hoisted(() => ({
|
|
3
|
+
composeMock: vi.fn(async () => ({
|
|
4
|
+
raw: Buffer.from("MIME"),
|
|
5
|
+
resolvedSubject: "Re: Quote",
|
|
6
|
+
threadedParentId: null,
|
|
7
|
+
attachments: [],
|
|
8
|
+
})),
|
|
9
|
+
replaceMock: vi.fn(async () => ({ folder: "Drafts", oldUid: 5, newUid: 99, expunged: true })),
|
|
10
|
+
}));
|
|
11
|
+
vi.mock("../lib/compose.js", () => ({ composeDraft: composeMock }));
|
|
12
|
+
vi.mock("../lib/imap.js", () => ({ replaceDraft: replaceMock }));
|
|
13
|
+
vi.mock("../lib/credentials.js", () => ({
|
|
14
|
+
loadCredentials: vi.fn(async () => ({
|
|
15
|
+
credentials: { config: { email: "a@x.y", agentAddress: "a@x.y" }, password: "pw" },
|
|
16
|
+
})),
|
|
17
|
+
}));
|
|
18
|
+
import { emailDraftEdit } from "../tools/email-draft-edit.js";
|
|
19
|
+
describe("Task 819 — email-draft-edit", () => {
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
vi.clearAllMocks();
|
|
22
|
+
composeMock.mockResolvedValue({
|
|
23
|
+
raw: Buffer.from("MIME"),
|
|
24
|
+
resolvedSubject: "Re: Quote",
|
|
25
|
+
threadedParentId: null,
|
|
26
|
+
attachments: [],
|
|
27
|
+
});
|
|
28
|
+
replaceMock.mockResolvedValue({ folder: "Drafts", oldUid: 5, newUid: 99, expunged: true });
|
|
29
|
+
});
|
|
30
|
+
it("composes the replacement then replaces by UID; names the folder and both UIDs", async () => {
|
|
31
|
+
const text = await emailDraftEdit({
|
|
32
|
+
accountId: "acc-1",
|
|
33
|
+
targetUid: 5,
|
|
34
|
+
to: "c@d.e",
|
|
35
|
+
subject: "Quote",
|
|
36
|
+
body: "Revised body.",
|
|
37
|
+
});
|
|
38
|
+
expect(composeMock).toHaveBeenCalledTimes(1);
|
|
39
|
+
expect(replaceMock).toHaveBeenCalledWith(expect.anything(), "pw", 5, expect.any(Buffer));
|
|
40
|
+
expect(text).toContain("Drafts");
|
|
41
|
+
expect(text).toContain("5");
|
|
42
|
+
expect(text).toContain("99");
|
|
43
|
+
expect(text).toMatch(/unsent/); // a revise never dispatches
|
|
44
|
+
});
|
|
45
|
+
it("names the threaded parent when the revision is a threaded draft", async () => {
|
|
46
|
+
composeMock.mockResolvedValueOnce({
|
|
47
|
+
raw: Buffer.from("MIME"),
|
|
48
|
+
resolvedSubject: "Re: Quote",
|
|
49
|
+
threadedParentId: "<parent@x>",
|
|
50
|
+
attachments: [],
|
|
51
|
+
});
|
|
52
|
+
const text = await emailDraftEdit({
|
|
53
|
+
accountId: "acc-1",
|
|
54
|
+
targetUid: 5,
|
|
55
|
+
to: "c@d.e",
|
|
56
|
+
body: "v2",
|
|
57
|
+
messageId: "<parent@x>",
|
|
58
|
+
});
|
|
59
|
+
expect(text).toContain("threaded reply to <parent@x>");
|
|
60
|
+
});
|
|
61
|
+
it("propagates a parent-not-found compose error and never calls replaceDraft", async () => {
|
|
62
|
+
composeMock.mockRejectedValueOnce(new Error("No email found with Message-ID <gone@x>"));
|
|
63
|
+
await expect(emailDraftEdit({ accountId: "acc-1", targetUid: 5, to: "c@d.e", body: "v2", messageId: "<gone@x>" })).rejects.toThrow(/No email found/);
|
|
64
|
+
expect(replaceMock).not.toHaveBeenCalled();
|
|
65
|
+
});
|
|
66
|
+
it("surfaces a missing-target-UID error from replaceDraft verbatim", async () => {
|
|
67
|
+
replaceMock.mockRejectedValueOnce(new Error("Draft UID 404 not found in Drafts."));
|
|
68
|
+
await expect(emailDraftEdit({ accountId: "acc-1", targetUid: 404, to: "c@d.e", subject: "Q", body: "v2" })).rejects.toThrow(/Draft UID 404 not found/);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
//# sourceMappingURL=email-draft-edit.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email-draft-edit.test.js","sourceRoot":"","sources":["../../src/__tests__/email-draft-edit.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email-draft-send.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/email-draft-send.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
const { fetchMock, sendRawMock, deleteMock } = vi.hoisted(() => ({
|
|
3
|
+
fetchMock: vi.fn(),
|
|
4
|
+
sendRawMock: vi.fn(),
|
|
5
|
+
deleteMock: vi.fn(),
|
|
6
|
+
}));
|
|
7
|
+
vi.mock("../lib/imap.js", () => ({ fetchDraftSource: fetchMock, deleteDraft: deleteMock }));
|
|
8
|
+
vi.mock("../lib/smtp.js", async (importOriginal) => {
|
|
9
|
+
const actual = await importOriginal();
|
|
10
|
+
return { ...actual, sendRaw: sendRawMock };
|
|
11
|
+
});
|
|
12
|
+
vi.mock("../lib/credentials.js", () => ({
|
|
13
|
+
loadCredentials: vi.fn(async () => ({
|
|
14
|
+
credentials: { config: { email: "a@x.y", agentAddress: "a@x.y" }, password: "pw" },
|
|
15
|
+
})),
|
|
16
|
+
}));
|
|
17
|
+
import { emailDraftSend } from "../tools/email-draft-send.js";
|
|
18
|
+
const draft = {
|
|
19
|
+
folder: "Drafts",
|
|
20
|
+
source: Buffer.from("MIME bytes"),
|
|
21
|
+
toAddresses: ["c@d.e"],
|
|
22
|
+
ccAddresses: ["f@g.h"],
|
|
23
|
+
bccAddresses: ["i@j.k"],
|
|
24
|
+
};
|
|
25
|
+
describe("Task 819 — email-draft-send", () => {
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
vi.clearAllMocks();
|
|
28
|
+
fetchMock.mockResolvedValue({ ...draft });
|
|
29
|
+
sendRawMock.mockResolvedValue({ messageId: "<sent@x>" });
|
|
30
|
+
deleteMock.mockResolvedValue({ folder: "Drafts", deleted: true });
|
|
31
|
+
});
|
|
32
|
+
it("sends raw with a To+Cc+Bcc envelope, THEN removes the draft", async () => {
|
|
33
|
+
const text = await emailDraftSend({ accountId: "acc-1", uid: 5 });
|
|
34
|
+
expect(sendRawMock).toHaveBeenCalledWith(expect.anything(), "pw", draft.source, {
|
|
35
|
+
from: "a@x.y",
|
|
36
|
+
to: ["c@d.e", "f@g.h", "i@j.k"],
|
|
37
|
+
});
|
|
38
|
+
expect(deleteMock).toHaveBeenCalledWith(expect.anything(), "pw", 5);
|
|
39
|
+
expect(text).toMatch(/sent to/i);
|
|
40
|
+
expect(text).toContain("<sent@x>");
|
|
41
|
+
expect(text).toContain("removed");
|
|
42
|
+
});
|
|
43
|
+
it("missing draft throws and never sends", async () => {
|
|
44
|
+
fetchMock.mockResolvedValueOnce(null);
|
|
45
|
+
await expect(emailDraftSend({ accountId: "acc-1", uid: 404 })).rejects.toThrow(/No draft with UID 404/);
|
|
46
|
+
expect(sendRawMock).not.toHaveBeenCalled();
|
|
47
|
+
});
|
|
48
|
+
it("a removal failure AFTER a successful send still reports success with a caveat", async () => {
|
|
49
|
+
deleteMock.mockRejectedValueOnce(new Error("Draft UID 5 not found in Drafts."));
|
|
50
|
+
const text = await emailDraftSend({ accountId: "acc-1", uid: 5 });
|
|
51
|
+
expect(sendRawMock).toHaveBeenCalledTimes(1);
|
|
52
|
+
expect(text).toMatch(/sent to/i);
|
|
53
|
+
expect(text).toContain("<sent@x>");
|
|
54
|
+
expect(text).toMatch(/could not be confirmed removed/);
|
|
55
|
+
});
|
|
56
|
+
it("SMTP failure leaves the draft in place (no delete) and surfaces verbatim", async () => {
|
|
57
|
+
sendRawMock.mockRejectedValueOnce(new Error("SMTP 550 rejected"));
|
|
58
|
+
await expect(emailDraftSend({ accountId: "acc-1", uid: 5 })).rejects.toThrow(/SMTP 550/);
|
|
59
|
+
expect(deleteMock).not.toHaveBeenCalled();
|
|
60
|
+
});
|
|
61
|
+
it("a draft with no recipients throws before sending", async () => {
|
|
62
|
+
fetchMock.mockResolvedValueOnce({
|
|
63
|
+
folder: "Drafts",
|
|
64
|
+
source: Buffer.from("x"),
|
|
65
|
+
toAddresses: [],
|
|
66
|
+
ccAddresses: [],
|
|
67
|
+
bccAddresses: [],
|
|
68
|
+
});
|
|
69
|
+
await expect(emailDraftSend({ accountId: "acc-1", uid: 5 })).rejects.toThrow(/no recipients/i);
|
|
70
|
+
expect(sendRawMock).not.toHaveBeenCalled();
|
|
71
|
+
});
|
|
72
|
+
it("de-duplicates an address present in both To and Cc", async () => {
|
|
73
|
+
fetchMock.mockResolvedValueOnce({
|
|
74
|
+
folder: "Drafts",
|
|
75
|
+
source: Buffer.from("x"),
|
|
76
|
+
toAddresses: ["c@d.e"],
|
|
77
|
+
ccAddresses: ["c@d.e"],
|
|
78
|
+
bccAddresses: [],
|
|
79
|
+
});
|
|
80
|
+
await emailDraftSend({ accountId: "acc-1", uid: 5 });
|
|
81
|
+
expect(sendRawMock).toHaveBeenCalledWith(expect.anything(), "pw", expect.any(Buffer), {
|
|
82
|
+
from: "a@x.y",
|
|
83
|
+
to: ["c@d.e"],
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
it("adds the alias diagnostic on SMTP failure when agentAddress differs from the login", async () => {
|
|
87
|
+
const { loadCredentials } = await import("../lib/credentials.js");
|
|
88
|
+
loadCredentials.mockResolvedValueOnce({
|
|
89
|
+
credentials: { config: { email: "login@x.y", agentAddress: "alias@x.y" }, password: "pw" },
|
|
90
|
+
});
|
|
91
|
+
sendRawMock.mockRejectedValueOnce(new Error("SMTP 553"));
|
|
92
|
+
await expect(emailDraftSend({ accountId: "acc-1", uid: 5 })).rejects.toThrow(/sending as alias@x\.y \(authenticated as login@x\.y\)/);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
//# sourceMappingURL=email-draft-send.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email-draft-send.test.js","sourceRoot":"","sources":["../../src/__tests__/email-draft-send.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email-draft.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/email-draft.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
const { appendDraftMock, sendEmailMock, fetchEnvMock } = vi.hoisted(() => ({
|
|
3
|
+
appendDraftMock: vi.fn(async () => ({ folder: "[Gmail]/Drafts", uid: 27675 })),
|
|
4
|
+
sendEmailMock: vi.fn(),
|
|
5
|
+
fetchEnvMock: vi.fn(),
|
|
6
|
+
}));
|
|
7
|
+
vi.mock("../lib/imap.js", () => ({
|
|
8
|
+
appendDraft: appendDraftMock,
|
|
9
|
+
fetchEnvelopeByMessageId: fetchEnvMock,
|
|
10
|
+
}));
|
|
11
|
+
vi.mock("../lib/smtp.js", async (importOriginal) => {
|
|
12
|
+
const actual = await importOriginal();
|
|
13
|
+
// Real buildMailOptions/formatCopyNote (the shared composer under test);
|
|
14
|
+
// sendEmail mocked so any SMTP call on the draft path is a test failure.
|
|
15
|
+
return { ...actual, sendEmail: sendEmailMock };
|
|
16
|
+
});
|
|
17
|
+
vi.mock("../lib/credentials.js", () => ({
|
|
18
|
+
loadCredentials: vi.fn(async () => ({
|
|
19
|
+
credentials: {
|
|
20
|
+
config: { email: "agent@example.com", agentAddress: "agent@example.com" },
|
|
21
|
+
password: "pw",
|
|
22
|
+
},
|
|
23
|
+
})),
|
|
24
|
+
}));
|
|
25
|
+
import { emailDraft } from "../tools/email-draft.js";
|
|
26
|
+
describe("Task 815 — email-draft tool", () => {
|
|
27
|
+
beforeEach(() => {
|
|
28
|
+
vi.clearAllMocks();
|
|
29
|
+
});
|
|
30
|
+
it("composes MIME and appends once to Drafts; never touches SMTP", async () => {
|
|
31
|
+
const text = await emailDraft({
|
|
32
|
+
accountId: "acc-1",
|
|
33
|
+
to: "joel@example.com",
|
|
34
|
+
subject: "Quote follow-up",
|
|
35
|
+
body: "Please review.",
|
|
36
|
+
});
|
|
37
|
+
expect(appendDraftMock).toHaveBeenCalledTimes(1);
|
|
38
|
+
const [, , raw] = appendDraftMock.mock.calls[0];
|
|
39
|
+
const mime = raw.toString();
|
|
40
|
+
expect(mime).toContain("To: joel@example.com");
|
|
41
|
+
expect(mime).toContain("Subject: Quote follow-up");
|
|
42
|
+
expect(mime).toContain("From: agent@example.com");
|
|
43
|
+
expect(mime).toContain("Please review.");
|
|
44
|
+
expect(sendEmailMock).not.toHaveBeenCalled();
|
|
45
|
+
expect(text).toContain("[Gmail]/Drafts");
|
|
46
|
+
expect(text).toContain("27675");
|
|
47
|
+
expect(text).toContain("joel@example.com");
|
|
48
|
+
});
|
|
49
|
+
it("preserves the Bcc header in the draft bytes (keepBcc — the stored draft is the only recipient carrier)", async () => {
|
|
50
|
+
await emailDraft({
|
|
51
|
+
accountId: "acc-1",
|
|
52
|
+
to: "joel@example.com",
|
|
53
|
+
subject: "s",
|
|
54
|
+
body: "b",
|
|
55
|
+
cc: ["copy@example.com"],
|
|
56
|
+
bcc: ["hidden@example.com"],
|
|
57
|
+
});
|
|
58
|
+
const [, , raw] = appendDraftMock.mock.calls[0];
|
|
59
|
+
const mime = raw.toString();
|
|
60
|
+
expect(mime).toMatch(/^Cc: copy@example\.com/m);
|
|
61
|
+
expect(mime).toMatch(/^Bcc: hidden@example\.com/m);
|
|
62
|
+
});
|
|
63
|
+
it("reports when the server did not return an APPENDUID", async () => {
|
|
64
|
+
appendDraftMock.mockResolvedValueOnce({ folder: "Drafts", uid: null });
|
|
65
|
+
const text = await emailDraft({
|
|
66
|
+
accountId: "acc-1",
|
|
67
|
+
to: "joel@example.com",
|
|
68
|
+
subject: "s",
|
|
69
|
+
body: "b",
|
|
70
|
+
});
|
|
71
|
+
expect(text).toContain("Drafts");
|
|
72
|
+
expect(text).toContain("UID not reported");
|
|
73
|
+
});
|
|
74
|
+
it("surfaces the no-Drafts-folder error verbatim", async () => {
|
|
75
|
+
appendDraftMock.mockRejectedValueOnce(new Error("Drafts folder not found for agent@example.com — the server does not advertise a \\Drafts special-use folder, so the draft cannot be stored."));
|
|
76
|
+
await expect(emailDraft({ accountId: "acc-1", to: "j@x.y", subject: "s", body: "b" })).rejects.toThrow(/Drafts folder not found for agent@example\.com/);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
describe("Task 818 — threaded draft via messageId", () => {
|
|
80
|
+
beforeEach(() => {
|
|
81
|
+
vi.clearAllMocks();
|
|
82
|
+
});
|
|
83
|
+
it("threads via messageId: In-Reply-To/References + Re: subject from the parent", async () => {
|
|
84
|
+
fetchEnvMock.mockResolvedValueOnce({
|
|
85
|
+
messageId: "<parent@x>",
|
|
86
|
+
subject: "Quote",
|
|
87
|
+
fromAddress: "client@x.y",
|
|
88
|
+
});
|
|
89
|
+
const text = await emailDraft({
|
|
90
|
+
accountId: "acc-1",
|
|
91
|
+
to: "client@x.y",
|
|
92
|
+
body: "Sounds good.",
|
|
93
|
+
messageId: "<parent@x>",
|
|
94
|
+
});
|
|
95
|
+
expect(fetchEnvMock).toHaveBeenCalledWith(expect.anything(), "pw", "<parent@x>");
|
|
96
|
+
const [, , raw] = appendDraftMock.mock.calls[0];
|
|
97
|
+
const mime = raw.toString();
|
|
98
|
+
expect(mime).toMatch(/^In-Reply-To: <parent@x>/m);
|
|
99
|
+
expect(mime).toMatch(/^References: <parent@x>/m);
|
|
100
|
+
expect(mime).toMatch(/^Subject: Re: Quote/m);
|
|
101
|
+
expect(text).toContain("threaded reply to <parent@x>");
|
|
102
|
+
});
|
|
103
|
+
it("strips an existing Re: on the parent subject (single Re: prefix)", async () => {
|
|
104
|
+
fetchEnvMock.mockResolvedValueOnce({
|
|
105
|
+
messageId: "<p2@x>",
|
|
106
|
+
subject: "Re: Lease terms",
|
|
107
|
+
fromAddress: "client@x.y",
|
|
108
|
+
});
|
|
109
|
+
await emailDraft({ accountId: "acc-1", to: "client@x.y", body: "ok", messageId: "<p2@x>" });
|
|
110
|
+
const [, , raw] = appendDraftMock.mock.calls[0];
|
|
111
|
+
expect(raw.toString()).toMatch(/^Subject: Re: Lease terms/m);
|
|
112
|
+
});
|
|
113
|
+
it("standalone path takes no envelope lookup and stamps no threading headers", async () => {
|
|
114
|
+
await emailDraft({ accountId: "acc-1", to: "client@x.y", subject: "Hello", body: "b" });
|
|
115
|
+
expect(fetchEnvMock).not.toHaveBeenCalled();
|
|
116
|
+
const [, , raw] = appendDraftMock.mock.calls[0];
|
|
117
|
+
expect(raw.toString()).not.toMatch(/^In-Reply-To:/m);
|
|
118
|
+
});
|
|
119
|
+
it("parent not found: throws verbatim and never appends", async () => {
|
|
120
|
+
fetchEnvMock.mockResolvedValueOnce(null);
|
|
121
|
+
await expect(emailDraft({ accountId: "acc-1", to: "client@x.y", body: "b", messageId: "<gone@x>" })).rejects.toThrow(/No email found with Message-ID <gone@x>/);
|
|
122
|
+
expect(appendDraftMock).not.toHaveBeenCalled();
|
|
123
|
+
});
|
|
124
|
+
it("no messageId and no subject: throws before any IMAP work", async () => {
|
|
125
|
+
await expect(emailDraft({ accountId: "acc-1", to: "client@x.y", body: "b" })).rejects.toThrow(/requires a subject/);
|
|
126
|
+
expect(appendDraftMock).not.toHaveBeenCalled();
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
//# sourceMappingURL=email-draft.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email-draft.test.js","sourceRoot":"","sources":["../../src/__tests__/email-draft.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -35,6 +35,19 @@ describe("email-setup short-circuits Microsoft addresses", () => {
|
|
|
35
35
|
expect(smtp.testConnection).not.toHaveBeenCalled();
|
|
36
36
|
expect(resolveMx).not.toHaveBeenCalled();
|
|
37
37
|
});
|
|
38
|
+
it("emits an op=request and op=result outcome=fail lifeline even on the redirect path", async () => {
|
|
39
|
+
const writes = [];
|
|
40
|
+
const spy = vi.spyOn(process.stderr, "write").mockImplementation((s) => { writes.push(String(s)); return true; });
|
|
41
|
+
const result = await emailSetup({
|
|
42
|
+
email: "agent@outlook.com",
|
|
43
|
+
password: "irrelevant",
|
|
44
|
+
accountId: "acct-1",
|
|
45
|
+
});
|
|
46
|
+
spy.mockRestore();
|
|
47
|
+
expect(result.success).toBe(false);
|
|
48
|
+
expect(writes.some((l) => l.includes("[email] setup-probe op=request") && l.includes("domain=outlook.com"))).toBe(true);
|
|
49
|
+
expect(writes.some((l) => l.includes("op=result") && l.includes("outcome=fail"))).toBe(true);
|
|
50
|
+
});
|
|
38
51
|
it("refuses an M365 custom domain detected by MX, even with hosts supplied", async () => {
|
|
39
52
|
resolveMx.mockResolvedValue([
|
|
40
53
|
{ exchange: "contoso-com.mail.protection.outlook.com", priority: 0 },
|
|
@@ -52,4 +65,49 @@ describe("email-setup short-circuits Microsoft addresses", () => {
|
|
|
52
65
|
expect(smtp.testConnection).not.toHaveBeenCalled();
|
|
53
66
|
});
|
|
54
67
|
});
|
|
68
|
+
describe("email-setup probe lifecycle logging", () => {
|
|
69
|
+
beforeEach(() => {
|
|
70
|
+
resolveMx.mockReset();
|
|
71
|
+
imap.testConnection.mockReset();
|
|
72
|
+
imap.getInboxCount.mockReset();
|
|
73
|
+
smtp.testConnection.mockReset();
|
|
74
|
+
});
|
|
75
|
+
it("emits request → probe-imap → probe-smtp → result with one shared token", async () => {
|
|
76
|
+
const writes = [];
|
|
77
|
+
const spy = vi.spyOn(process.stderr, "write").mockImplementation((s) => { writes.push(String(s)); return true; });
|
|
78
|
+
imap.testConnection.mockResolvedValue(null);
|
|
79
|
+
smtp.testConnection.mockResolvedValue(null);
|
|
80
|
+
imap.getInboxCount.mockResolvedValue(7);
|
|
81
|
+
const result = await emailSetup({
|
|
82
|
+
email: "agent@example.org", password: "pw",
|
|
83
|
+
imapHost: "imap.example.org", smtpHost: "smtp.example.org",
|
|
84
|
+
accountId: "acct-1",
|
|
85
|
+
});
|
|
86
|
+
spy.mockRestore();
|
|
87
|
+
expect(result.success).toBe(true);
|
|
88
|
+
const probeLines = writes.filter((l) => l.includes("[email] setup-probe"));
|
|
89
|
+
const token = probeLines[0]?.match(/token=(\S+)/)?.[1];
|
|
90
|
+
expect(token).toBeTruthy();
|
|
91
|
+
expect(probeLines.some((l) => l.includes(`op=request token=${token}`) && l.includes("domain=example.org"))).toBe(true);
|
|
92
|
+
expect(probeLines.some((l) => l.includes(`op=probe-imap token=${token}`) && /ms=\d+/.test(l))).toBe(true);
|
|
93
|
+
expect(probeLines.some((l) => l.includes(`op=probe-smtp token=${token}`) && /ms=\d+/.test(l))).toBe(true);
|
|
94
|
+
expect(probeLines.some((l) => l.includes(`op=result token=${token} outcome=ok`))).toBe(true);
|
|
95
|
+
// The shared token reaches the probe helpers so acquired/released correlate.
|
|
96
|
+
expect(imap.testConnection).toHaveBeenCalledWith(expect.anything(), "pw", token);
|
|
97
|
+
expect(smtp.testConnection).toHaveBeenCalledWith(expect.anything(), "pw", token);
|
|
98
|
+
});
|
|
99
|
+
it("a failed imap probe logs outcome=fail", async () => {
|
|
100
|
+
const writes = [];
|
|
101
|
+
const spy = vi.spyOn(process.stderr, "write").mockImplementation((s) => { writes.push(String(s)); return true; });
|
|
102
|
+
imap.testConnection.mockResolvedValue("IMAP connection failed: nope");
|
|
103
|
+
const result = await emailSetup({
|
|
104
|
+
email: "agent@example.org", password: "pw",
|
|
105
|
+
imapHost: "imap.example.org", smtpHost: "smtp.example.org",
|
|
106
|
+
accountId: "acct-1",
|
|
107
|
+
});
|
|
108
|
+
spy.mockRestore();
|
|
109
|
+
expect(result.success).toBe(false);
|
|
110
|
+
expect(writes.some((l) => l.includes("op=result") && l.includes("outcome=fail"))).toBe(true);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
55
113
|
//# sourceMappingURL=email-setup.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"email-setup.test.js","sourceRoot":"","sources":["../../src/__tests__/email-setup.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAE9D,gFAAgF;AAChF,yEAAyE;AACzE,8EAA8E;AAC9E,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;AACjE,EAAE,CAAC,IAAI,CAAC,mBAAmB,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;AAEpD,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,cAAc,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;AACrF,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,cAAc,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;AAC7D,EAAE,CAAC,IAAI,CAAC,gBAAgB,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;AACtC,EAAE,CAAC,IAAI,CAAC,gBAAgB,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;AACtC,EAAE,CAAC,IAAI,CAAC,uBAAuB,EAAE,GAAG,EAAE,CAAC,CAAC;IACtC,WAAW,EAAE,EAAE,CAAC,EAAE,EAAE;IACpB,aAAa,EAAE,EAAE,CAAC,EAAE,EAAE;IACtB,YAAY,EAAE,EAAE,CAAC,EAAE,EAAE;IACrB,mBAAmB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC;IACpD,kBAAkB,EAAE,EAAE,CAAC,EAAE,EAAE;CAC5B,CAAC,CAAC,CAAC;AAEJ,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,yBAAyB,CAAC,CAAC;AAE/D,QAAQ,CAAC,gDAAgD,EAAE,GAAG,EAAE;IAC9D,UAAU,CAAC,GAAG,EAAE;QACd,SAAS,CAAC,SAAS,EAAE,CAAC;QACtB,IAAI,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC;QAChC,IAAI,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oEAAoE,EAAE,KAAK,IAAI,EAAE;QAClF,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC;YAC9B,KAAK,EAAE,mBAAmB;YAC1B,QAAQ,EAAE,YAAY;YACtB,SAAS,EAAE,QAAQ;SACpB,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,0BAA0B,CAAC,CAAC;QAC3D,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;QAClD,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QACnD,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QACnD,MAAM,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wEAAwE,EAAE,KAAK,IAAI,EAAE;QACtF,SAAS,CAAC,iBAAiB,CAAC;YAC1B,EAAE,QAAQ,EAAE,yCAAyC,EAAE,QAAQ,EAAE,CAAC,EAAE;SACrE,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC;YAC9B,KAAK,EAAE,iBAAiB;YACxB,QAAQ,EAAE,YAAY;YACtB,QAAQ,EAAE,uBAAuB;YACjC,QAAQ,EAAE,oBAAoB;YAC9B,SAAS,EAAE,QAAQ;SACpB,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,0BAA0B,CAAC,CAAC;QAC3D,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QACnD,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IACrD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"email-setup.test.js","sourceRoot":"","sources":["../../src/__tests__/email-setup.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"imap-drafts.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/imap-drafts.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
// Mock the imapflow module so appendDraft's internal createClient() yields our spy client.
|
|
3
|
+
// `order` records the wire sequence of append vs delete so the atomicity contract
|
|
4
|
+
// (append-before-expunge) can be asserted directly.
|
|
5
|
+
const order = [];
|
|
6
|
+
const mockClient = {
|
|
7
|
+
connect: vi.fn(async () => { }),
|
|
8
|
+
list: vi.fn(async () => []),
|
|
9
|
+
mailboxOpen: vi.fn(async () => ({})),
|
|
10
|
+
getMailboxLock: vi.fn(async () => ({ release: vi.fn() })),
|
|
11
|
+
append: vi.fn(async () => {
|
|
12
|
+
order.push("append");
|
|
13
|
+
return { destination: "[Gmail]/Drafts", uid: 27675 };
|
|
14
|
+
}),
|
|
15
|
+
messageDelete: vi.fn(async () => {
|
|
16
|
+
order.push("delete");
|
|
17
|
+
return true;
|
|
18
|
+
}),
|
|
19
|
+
fetchOne: vi.fn(async () => ({ uid: 5 })),
|
|
20
|
+
logout: vi.fn(async () => { }),
|
|
21
|
+
close: vi.fn(() => { }),
|
|
22
|
+
};
|
|
23
|
+
vi.mock("imapflow", () => ({
|
|
24
|
+
// A constructible function — `new ImapFlow(...)` returns the spy client.
|
|
25
|
+
ImapFlow: function ImapFlow() {
|
|
26
|
+
return mockClient;
|
|
27
|
+
},
|
|
28
|
+
}));
|
|
29
|
+
import { appendDraft, resolveFolderName, replaceDraft, fetchDraftSource, deleteDraft, } from "../lib/imap.js";
|
|
30
|
+
const config = {
|
|
31
|
+
email: "agent@example.com",
|
|
32
|
+
imapHost: "imap.example.com",
|
|
33
|
+
imapPort: 993,
|
|
34
|
+
imapSecurity: "tls",
|
|
35
|
+
};
|
|
36
|
+
describe("Task 815 — resolveFolderName drafts branch", () => {
|
|
37
|
+
it("returns the \\Drafts special-use path when advertised", async () => {
|
|
38
|
+
const client = {
|
|
39
|
+
list: async () => [
|
|
40
|
+
{ path: "INBOX" },
|
|
41
|
+
{ path: "[Gmail]/Sent Mail", specialUse: "\\Sent" },
|
|
42
|
+
{ path: "[Gmail]/Drafts", specialUse: "\\Drafts" },
|
|
43
|
+
],
|
|
44
|
+
};
|
|
45
|
+
await expect(resolveFolderName(client, "drafts")).resolves.toBe("[Gmail]/Drafts");
|
|
46
|
+
});
|
|
47
|
+
it("throws a named error when no \\Drafts special-use folder is advertised", async () => {
|
|
48
|
+
const client = { list: async () => [{ path: "INBOX" }] };
|
|
49
|
+
await expect(resolveFolderName(client, "drafts")).rejects.toThrow(/\\Drafts special-use folder/);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
describe("Task 815 — appendDraft", () => {
|
|
53
|
+
beforeEach(() => {
|
|
54
|
+
vi.clearAllMocks();
|
|
55
|
+
});
|
|
56
|
+
it("appends raw bytes to the resolved Drafts folder with the \\Draft flag and returns folder+uid", async () => {
|
|
57
|
+
mockClient.list.mockResolvedValueOnce([
|
|
58
|
+
{ path: "Drafts", specialUse: "\\Drafts" },
|
|
59
|
+
]);
|
|
60
|
+
const raw = Buffer.from("From: a@b.c\r\n\r\nbody");
|
|
61
|
+
const result = await appendDraft(config, "pw", raw);
|
|
62
|
+
expect(mockClient.append).toHaveBeenCalledTimes(1);
|
|
63
|
+
expect(mockClient.append).toHaveBeenCalledWith("Drafts", raw, ["\\Draft"]);
|
|
64
|
+
expect(result).toEqual({ folder: "Drafts", uid: 27675 });
|
|
65
|
+
expect(mockClient.logout).toHaveBeenCalled();
|
|
66
|
+
});
|
|
67
|
+
it("returns uid null when the server reports no APPENDUID (no UIDPLUS)", async () => {
|
|
68
|
+
mockClient.list.mockResolvedValueOnce([
|
|
69
|
+
{ path: "Drafts", specialUse: "\\Drafts" },
|
|
70
|
+
]);
|
|
71
|
+
mockClient.append.mockResolvedValueOnce({ destination: "Drafts" });
|
|
72
|
+
const result = await appendDraft(config, "pw", Buffer.from("x"));
|
|
73
|
+
expect(result).toEqual({ folder: "Drafts", uid: null });
|
|
74
|
+
});
|
|
75
|
+
it("does not re-brand an unrelated list() failure as a missing-Drafts error", async () => {
|
|
76
|
+
mockClient.list.mockRejectedValueOnce(new Error("connection reset by peer"));
|
|
77
|
+
await expect(appendDraft(config, "pw", Buffer.from("x"))).rejects.toThrow(/connection reset by peer/);
|
|
78
|
+
expect(mockClient.append).not.toHaveBeenCalled();
|
|
79
|
+
});
|
|
80
|
+
it("names the mailbox in the no-Drafts error and still logs out", async () => {
|
|
81
|
+
mockClient.list.mockResolvedValueOnce([{ path: "INBOX" }]);
|
|
82
|
+
await expect(appendDraft(config, "pw", Buffer.from("x"))).rejects.toThrow(/agent@example\.com/);
|
|
83
|
+
expect(mockClient.append).not.toHaveBeenCalled();
|
|
84
|
+
expect(mockClient.logout).toHaveBeenCalled();
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
describe("Task 819 — replaceDraft (read-modify-replace)", () => {
|
|
88
|
+
beforeEach(() => {
|
|
89
|
+
order.length = 0;
|
|
90
|
+
vi.clearAllMocks();
|
|
91
|
+
mockClient.list.mockResolvedValue([{ path: "Drafts", specialUse: "\\Drafts" }]);
|
|
92
|
+
mockClient.append.mockImplementation(async () => {
|
|
93
|
+
order.push("append");
|
|
94
|
+
return { destination: "Drafts", uid: 99 };
|
|
95
|
+
});
|
|
96
|
+
mockClient.messageDelete.mockImplementation(async () => {
|
|
97
|
+
order.push("delete");
|
|
98
|
+
return true;
|
|
99
|
+
});
|
|
100
|
+
mockClient.fetchOne.mockResolvedValue({ uid: 5 });
|
|
101
|
+
});
|
|
102
|
+
it("appends the replacement BEFORE expunging the old UID and returns both UIDs", async () => {
|
|
103
|
+
const r = await replaceDraft(config, "pw", 5, Buffer.from("new bytes"));
|
|
104
|
+
expect(order).toEqual(["append", "delete"]);
|
|
105
|
+
expect(mockClient.append).toHaveBeenCalledWith("Drafts", expect.any(Buffer), ["\\Draft"]);
|
|
106
|
+
expect(mockClient.messageDelete).toHaveBeenCalledWith("5", { uid: true });
|
|
107
|
+
expect(r).toEqual({ folder: "Drafts", oldUid: 5, newUid: 99, expunged: true });
|
|
108
|
+
});
|
|
109
|
+
it("throws and NEVER appends when the old UID is absent (no orphan created)", async () => {
|
|
110
|
+
mockClient.fetchOne.mockResolvedValueOnce(false);
|
|
111
|
+
await expect(replaceDraft(config, "pw", 404, Buffer.from("new"))).rejects.toThrow(/Draft UID 404 not found/);
|
|
112
|
+
expect(mockClient.append).not.toHaveBeenCalled();
|
|
113
|
+
expect(mockClient.messageDelete).not.toHaveBeenCalled();
|
|
114
|
+
});
|
|
115
|
+
it("append failure leaves the old UID intact (delete never runs)", async () => {
|
|
116
|
+
mockClient.append.mockRejectedValueOnce(new Error("APPEND failed"));
|
|
117
|
+
await expect(replaceDraft(config, "pw", 5, Buffer.from("new"))).rejects.toThrow(/APPEND failed/);
|
|
118
|
+
expect(mockClient.messageDelete).not.toHaveBeenCalled();
|
|
119
|
+
});
|
|
120
|
+
it("reports expunged:false when the old UID could not be deleted", async () => {
|
|
121
|
+
mockClient.messageDelete.mockResolvedValueOnce(false);
|
|
122
|
+
const r = await replaceDraft(config, "pw", 5, Buffer.from("new"));
|
|
123
|
+
expect(r.expunged).toBe(false);
|
|
124
|
+
expect(r.newUid).toBe(99);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
describe("Task 819 — fetchDraftSource / deleteDraft", () => {
|
|
128
|
+
beforeEach(() => {
|
|
129
|
+
vi.clearAllMocks();
|
|
130
|
+
mockClient.list.mockResolvedValue([{ path: "Drafts", specialUse: "\\Drafts" }]);
|
|
131
|
+
mockClient.messageDelete.mockResolvedValue(true);
|
|
132
|
+
mockClient.fetchOne.mockResolvedValue({
|
|
133
|
+
uid: 5,
|
|
134
|
+
source: Buffer.from("From: a@b.c\r\nTo: c@d.e\r\nCc: f@g.h\r\nBcc: i@j.k\r\n\r\nbody"),
|
|
135
|
+
envelope: {
|
|
136
|
+
to: [{ address: "c@d.e" }],
|
|
137
|
+
cc: [{ address: "f@g.h" }],
|
|
138
|
+
bcc: [{ address: "i@j.k" }],
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
it("fetchDraftSource returns the raw source and envelope recipients (To/Cc/Bcc)", async () => {
|
|
143
|
+
const r = await fetchDraftSource(config, "pw", 5);
|
|
144
|
+
expect(r?.folder).toBe("Drafts");
|
|
145
|
+
expect(r?.source.toString()).toContain("To: c@d.e");
|
|
146
|
+
expect(r?.toAddresses).toEqual(["c@d.e"]);
|
|
147
|
+
expect(r?.ccAddresses).toEqual(["f@g.h"]);
|
|
148
|
+
expect(r?.bccAddresses).toEqual(["i@j.k"]);
|
|
149
|
+
});
|
|
150
|
+
it("fetchDraftSource returns null when the UID is absent", async () => {
|
|
151
|
+
mockClient.fetchOne.mockResolvedValueOnce(false);
|
|
152
|
+
expect(await fetchDraftSource(config, "pw", 404)).toBeNull();
|
|
153
|
+
});
|
|
154
|
+
it("deleteDraft expunges an existing UID", async () => {
|
|
155
|
+
const r = await deleteDraft(config, "pw", 5);
|
|
156
|
+
expect(mockClient.messageDelete).toHaveBeenCalledWith("5", { uid: true });
|
|
157
|
+
expect(r).toEqual({ folder: "Drafts", deleted: true });
|
|
158
|
+
});
|
|
159
|
+
it("deleteDraft throws when the UID is absent", async () => {
|
|
160
|
+
mockClient.fetchOne.mockResolvedValueOnce(false);
|
|
161
|
+
await expect(deleteDraft(config, "pw", 404)).rejects.toThrow(/Draft UID 404 not found/);
|
|
162
|
+
expect(mockClient.messageDelete).not.toHaveBeenCalled();
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
//# sourceMappingURL=imap-drafts.test.js.map
|