@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.
Files changed (238) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/lib/models/dist/index.d.ts +7 -0
  3. package/payload/platform/lib/models/dist/index.d.ts.map +1 -1
  4. package/payload/platform/lib/models/dist/index.js +16 -1
  5. package/payload/platform/lib/models/dist/index.js.map +1 -1
  6. package/payload/platform/lib/models/src/index.ts +16 -0
  7. package/payload/platform/plugins/admin/.claude-plugin/plugin.json +5 -1
  8. package/payload/platform/plugins/admin/lib/mcp-spawn-tee/index.js +159 -0
  9. package/payload/platform/plugins/admin/lib/mcp-spawn-tee/package.json +3 -0
  10. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +4 -14
  11. package/payload/platform/plugins/aeo/.claude-plugin/plugin.json +5 -1
  12. package/payload/platform/plugins/aeo/lib/mcp-spawn-tee/index.js +159 -0
  13. package/payload/platform/plugins/aeo/lib/mcp-spawn-tee/package.json +3 -0
  14. package/payload/platform/plugins/browser/.claude-plugin/plugin.json +5 -1
  15. package/payload/platform/plugins/browser/lib/mcp-spawn-tee/index.js +159 -0
  16. package/payload/platform/plugins/browser/lib/mcp-spawn-tee/package.json +3 -0
  17. package/payload/platform/plugins/contacts/.claude-plugin/plugin.json +5 -1
  18. package/payload/platform/plugins/contacts/lib/mcp-spawn-tee/index.js +159 -0
  19. package/payload/platform/plugins/contacts/lib/mcp-spawn-tee/package.json +3 -0
  20. package/payload/platform/plugins/docs/references/admin-ui.md +1 -1
  21. package/payload/platform/plugins/docs/references/getting-started.md +1 -1
  22. package/payload/platform/plugins/docs/references/platform.md +1 -11
  23. package/payload/platform/plugins/email/.claude-plugin/plugin.json +6 -2
  24. package/payload/platform/plugins/email/PLUGIN.md +14 -2
  25. package/payload/platform/plugins/email/lib/mcp-spawn-tee/index.js +159 -0
  26. package/payload/platform/plugins/email/lib/mcp-spawn-tee/package.json +3 -0
  27. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft-edit.test.d.ts +2 -0
  28. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft-edit.test.d.ts.map +1 -0
  29. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft-edit.test.js +71 -0
  30. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft-edit.test.js.map +1 -0
  31. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft-send.test.d.ts +2 -0
  32. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft-send.test.d.ts.map +1 -0
  33. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft-send.test.js +95 -0
  34. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft-send.test.js.map +1 -0
  35. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft.test.d.ts +2 -0
  36. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft.test.d.ts.map +1 -0
  37. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft.test.js +129 -0
  38. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft.test.js.map +1 -0
  39. package/payload/platform/plugins/email/mcp/dist/__tests__/email-setup.test.js +58 -0
  40. package/payload/platform/plugins/email/mcp/dist/__tests__/email-setup.test.js.map +1 -1
  41. package/payload/platform/plugins/email/mcp/dist/__tests__/imap-drafts.test.d.ts +2 -0
  42. package/payload/platform/plugins/email/mcp/dist/__tests__/imap-drafts.test.d.ts.map +1 -0
  43. package/payload/platform/plugins/email/mcp/dist/__tests__/imap-drafts.test.js +165 -0
  44. package/payload/platform/plugins/email/mcp/dist/__tests__/imap-drafts.test.js.map +1 -0
  45. package/payload/platform/plugins/email/mcp/dist/__tests__/imap-probe.test.d.ts +2 -0
  46. package/payload/platform/plugins/email/mcp/dist/__tests__/imap-probe.test.d.ts.map +1 -0
  47. package/payload/platform/plugins/email/mcp/dist/__tests__/imap-probe.test.js +69 -0
  48. package/payload/platform/plugins/email/mcp/dist/__tests__/imap-probe.test.js.map +1 -0
  49. package/payload/platform/plugins/email/mcp/dist/__tests__/mail-options.test.d.ts +2 -0
  50. package/payload/platform/plugins/email/mcp/dist/__tests__/mail-options.test.d.ts.map +1 -0
  51. package/payload/platform/plugins/email/mcp/dist/__tests__/mail-options.test.js +46 -0
  52. package/payload/platform/plugins/email/mcp/dist/__tests__/mail-options.test.js.map +1 -0
  53. package/payload/platform/plugins/email/mcp/dist/__tests__/send-raw.test.d.ts +2 -0
  54. package/payload/platform/plugins/email/mcp/dist/__tests__/send-raw.test.d.ts.map +1 -0
  55. package/payload/platform/plugins/email/mcp/dist/__tests__/send-raw.test.js +38 -0
  56. package/payload/platform/plugins/email/mcp/dist/__tests__/send-raw.test.js.map +1 -0
  57. package/payload/platform/plugins/email/mcp/dist/__tests__/setup-probe.test.d.ts +2 -0
  58. package/payload/platform/plugins/email/mcp/dist/__tests__/setup-probe.test.d.ts.map +1 -0
  59. package/payload/platform/plugins/email/mcp/dist/__tests__/setup-probe.test.js +56 -0
  60. package/payload/platform/plugins/email/mcp/dist/__tests__/setup-probe.test.js.map +1 -0
  61. package/payload/platform/plugins/email/mcp/dist/__tests__/smtp-probe.test.d.ts +2 -0
  62. package/payload/platform/plugins/email/mcp/dist/__tests__/smtp-probe.test.d.ts.map +1 -0
  63. package/payload/platform/plugins/email/mcp/dist/__tests__/smtp-probe.test.js +46 -0
  64. package/payload/platform/plugins/email/mcp/dist/__tests__/smtp-probe.test.js.map +1 -0
  65. package/payload/platform/plugins/email/mcp/dist/index.js +118 -0
  66. package/payload/platform/plugins/email/mcp/dist/index.js.map +1 -1
  67. package/payload/platform/plugins/email/mcp/dist/lib/compose.d.ts +47 -0
  68. package/payload/platform/plugins/email/mcp/dist/lib/compose.d.ts.map +1 -0
  69. package/payload/platform/plugins/email/mcp/dist/lib/compose.js +75 -0
  70. package/payload/platform/plugins/email/mcp/dist/lib/compose.js.map +1 -0
  71. package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts +53 -3
  72. package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts.map +1 -1
  73. package/payload/platform/plugins/email/mcp/dist/lib/imap.js +179 -5
  74. package/payload/platform/plugins/email/mcp/dist/lib/imap.js.map +1 -1
  75. package/payload/platform/plugins/email/mcp/dist/lib/setup-probe.d.ts +42 -0
  76. package/payload/platform/plugins/email/mcp/dist/lib/setup-probe.d.ts.map +1 -0
  77. package/payload/platform/plugins/email/mcp/dist/lib/setup-probe.js +72 -0
  78. package/payload/platform/plugins/email/mcp/dist/lib/setup-probe.js.map +1 -0
  79. package/payload/platform/plugins/email/mcp/dist/lib/smtp.d.ts +34 -6
  80. package/payload/platform/plugins/email/mcp/dist/lib/smtp.d.ts.map +1 -1
  81. package/payload/platform/plugins/email/mcp/dist/lib/smtp.js +62 -20
  82. package/payload/platform/plugins/email/mcp/dist/lib/smtp.js.map +1 -1
  83. package/payload/platform/plugins/email/mcp/dist/scripts/send-transactional.js +1 -2
  84. package/payload/platform/plugins/email/mcp/dist/scripts/send-transactional.js.map +1 -1
  85. package/payload/platform/plugins/email/mcp/dist/tools/email-draft-edit.d.ts +9 -0
  86. package/payload/platform/plugins/email/mcp/dist/tools/email-draft-edit.d.ts.map +1 -0
  87. package/payload/platform/plugins/email/mcp/dist/tools/email-draft-edit.js +23 -0
  88. package/payload/platform/plugins/email/mcp/dist/tools/email-draft-edit.js.map +1 -0
  89. package/payload/platform/plugins/email/mcp/dist/tools/email-draft-send.d.ts +8 -0
  90. package/payload/platform/plugins/email/mcp/dist/tools/email-draft-send.d.ts.map +1 -0
  91. package/payload/platform/plugins/email/mcp/dist/tools/email-draft-send.js +52 -0
  92. package/payload/platform/plugins/email/mcp/dist/tools/email-draft-send.js.map +1 -0
  93. package/payload/platform/plugins/email/mcp/dist/tools/email-draft.d.ts +7 -0
  94. package/payload/platform/plugins/email/mcp/dist/tools/email-draft.d.ts.map +1 -0
  95. package/payload/platform/plugins/email/mcp/dist/tools/email-draft.js +17 -0
  96. package/payload/platform/plugins/email/mcp/dist/tools/email-draft.js.map +1 -0
  97. package/payload/platform/plugins/email/mcp/dist/tools/email-reply.d.ts.map +1 -1
  98. package/payload/platform/plugins/email/mcp/dist/tools/email-reply.js +1 -8
  99. package/payload/platform/plugins/email/mcp/dist/tools/email-reply.js.map +1 -1
  100. package/payload/platform/plugins/email/mcp/dist/tools/email-send.d.ts.map +1 -1
  101. package/payload/platform/plugins/email/mcp/dist/tools/email-send.js +2 -8
  102. package/payload/platform/plugins/email/mcp/dist/tools/email-send.js.map +1 -1
  103. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.d.ts.map +1 -1
  104. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.js +25 -3
  105. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.js.map +1 -1
  106. package/payload/platform/plugins/email/references/email-reference.md +15 -0
  107. package/payload/platform/plugins/email/skills/email-composition/SKILL.md +26 -4
  108. package/payload/platform/plugins/memory/.claude-plugin/plugin.json +5 -1
  109. package/payload/platform/plugins/memory/lib/mcp-spawn-tee/index.js +159 -0
  110. package/payload/platform/plugins/memory/lib/mcp-spawn-tee/package.json +3 -0
  111. package/payload/platform/plugins/outlook/.claude-plugin/plugin.json +5 -1
  112. package/payload/platform/plugins/outlook/lib/mcp-spawn-tee/index.js +159 -0
  113. package/payload/platform/plugins/outlook/lib/mcp-spawn-tee/package.json +3 -0
  114. package/payload/platform/plugins/replicate/.claude-plugin/plugin.json +5 -1
  115. package/payload/platform/plugins/replicate/lib/mcp-spawn-tee/index.js +159 -0
  116. package/payload/platform/plugins/replicate/lib/mcp-spawn-tee/package.json +3 -0
  117. package/payload/platform/plugins/scheduling/.claude-plugin/plugin.json +5 -1
  118. package/payload/platform/plugins/scheduling/lib/mcp-spawn-tee/index.js +159 -0
  119. package/payload/platform/plugins/scheduling/lib/mcp-spawn-tee/package.json +3 -0
  120. package/payload/platform/plugins/telegram/.claude-plugin/plugin.json +5 -1
  121. package/payload/platform/plugins/telegram/lib/mcp-spawn-tee/index.js +159 -0
  122. package/payload/platform/plugins/telegram/lib/mcp-spawn-tee/package.json +3 -0
  123. package/payload/platform/plugins/url-get/.claude-plugin/plugin.json +5 -1
  124. package/payload/platform/plugins/url-get/lib/mcp-spawn-tee/index.js +159 -0
  125. package/payload/platform/plugins/url-get/lib/mcp-spawn-tee/package.json +3 -0
  126. package/payload/platform/plugins/whatsapp/.claude-plugin/plugin.json +5 -1
  127. package/payload/platform/plugins/whatsapp/lib/mcp-spawn-tee/index.js +159 -0
  128. package/payload/platform/plugins/whatsapp/lib/mcp-spawn-tee/package.json +3 -0
  129. package/payload/platform/plugins/work/.claude-plugin/plugin.json +5 -1
  130. package/payload/platform/plugins/work/lib/mcp-spawn-tee/index.js +159 -0
  131. package/payload/platform/plugins/work/lib/mcp-spawn-tee/package.json +3 -0
  132. package/payload/platform/plugins/workflows/.claude-plugin/plugin.json +5 -1
  133. package/payload/platform/plugins/workflows/lib/mcp-spawn-tee/index.js +159 -0
  134. package/payload/platform/plugins/workflows/lib/mcp-spawn-tee/package.json +3 -0
  135. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
  136. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +3 -0
  137. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
  138. package/payload/platform/services/claude-session-manager/dist/http-server.js +1 -1
  139. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  140. package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts +13 -0
  141. package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
  142. package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +71 -1
  143. package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
  144. package/payload/platform/services/whatsapp-channel/dist/jsonl-watch.d.ts +10 -0
  145. package/payload/platform/services/whatsapp-channel/dist/jsonl-watch.d.ts.map +1 -0
  146. package/payload/platform/services/whatsapp-channel/dist/jsonl-watch.js +70 -0
  147. package/payload/platform/services/whatsapp-channel/dist/jsonl-watch.js.map +1 -0
  148. package/payload/platform/services/whatsapp-channel/dist/server.d.ts +6 -1
  149. package/payload/platform/services/whatsapp-channel/dist/server.d.ts.map +1 -1
  150. package/payload/platform/services/whatsapp-channel/dist/server.js +38 -1
  151. package/payload/platform/services/whatsapp-channel/dist/server.js.map +1 -1
  152. package/payload/platform/templates/specialists/agents/personal-assistant.md +1 -1
  153. package/payload/premium-plugins/writer-craft/.claude-plugin/plugin.json +5 -1
  154. package/payload/premium-plugins/writer-craft/lib/mcp-spawn-tee/index.js +159 -0
  155. package/payload/premium-plugins/writer-craft/lib/mcp-spawn-tee/package.json +3 -0
  156. package/payload/server/public/assets/AdminShell-BnhxfX97.js +1 -0
  157. package/payload/server/public/assets/{Checkbox-DTrIyIFP.js → Checkbox-CVPUf_7I.js} +1 -1
  158. package/payload/server/public/assets/{Transcript-C3aDVJ-n.js → Transcript-FYmq-mL1.js} +1 -1
  159. package/payload/server/public/assets/{admin-DVdyV-Q6.js → admin-CF8K3hqE.js} +1 -1
  160. package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-DR9W0q1P.js → architectureDiagram-Q4EWVU46-IVt2X8Dk.js} +1 -1
  161. package/payload/server/public/assets/audio-attachment-mime-DaInZ9sa.js +1 -0
  162. package/payload/server/public/assets/{blockDiagram-DXYQGD6D-C3uwaI7p.js → blockDiagram-DXYQGD6D-CQDngnsc.js} +1 -1
  163. package/payload/server/public/assets/browser-D_hZgtfv.js +1 -0
  164. package/payload/server/public/assets/{c4Diagram-AHTNJAMY-C8hmUDdd.js → c4Diagram-AHTNJAMY-BjV_YA-L.js} +1 -1
  165. package/payload/server/public/assets/channel-gFnUr8f4.js +1 -0
  166. package/payload/server/public/assets/chat-COcrNTJi.js +1 -0
  167. package/payload/server/public/assets/{chunk-336JU56O-BRCubMCb.js → chunk-336JU56O-B0yBhSVq.js} +2 -2
  168. package/payload/server/public/assets/{chunk-426QAEUC-BNINkVsL.js → chunk-426QAEUC-BCmWl6vi.js} +1 -1
  169. package/payload/server/public/assets/{chunk-4TB4RGXK-DSMj_AZh.js → chunk-4TB4RGXK-BImQYhPF.js} +1 -1
  170. package/payload/server/public/assets/{chunk-5FUZZQ4R-6DNGaUkf.js → chunk-5FUZZQ4R-DrDSHQZv.js} +1 -1
  171. package/payload/server/public/assets/{chunk-5PVQY5BW-DPhkkS4p.js → chunk-5PVQY5BW-CKX_LIok.js} +1 -1
  172. package/payload/server/public/assets/{chunk-EDXVE4YY-BjWSqn7_.js → chunk-EDXVE4YY-D1zHB217.js} +1 -1
  173. package/payload/server/public/assets/{chunk-ENJZ2VHE-BX1ZnU4A.js → chunk-ENJZ2VHE-SFpdtszU.js} +1 -1
  174. package/payload/server/public/assets/{chunk-ICPOFSXX-DvYSWH7x.js → chunk-ICPOFSXX-cYdq7RKF.js} +1 -1
  175. package/payload/server/public/assets/{chunk-OYMX7WX6-7_m3mEOK.js → chunk-OYMX7WX6-B7JLCext.js} +1 -1
  176. package/payload/server/public/assets/{chunk-U2HBQHQK-Bl1a895I.js → chunk-U2HBQHQK-DWCeFwem.js} +1 -1
  177. package/payload/server/public/assets/{chunk-X2U36JSP-WkSpBPYx.js → chunk-X2U36JSP-DGnHsoJ3.js} +1 -1
  178. package/payload/server/public/assets/{chunk-YZCP3GAM-DpWRmPUo.js → chunk-YZCP3GAM-sg4lGGJV.js} +1 -1
  179. package/payload/server/public/assets/{chunk-ZZ45TVLE-D9Dgmeso.js → chunk-ZZ45TVLE-DtUoGmKE.js} +1 -1
  180. package/payload/server/public/assets/classDiagram-6PBFFD2Q-C_wlfUTz.js +1 -0
  181. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-Ltv5s3OY.js +1 -0
  182. package/payload/server/public/assets/clone-D0XoXc_v.js +1 -0
  183. package/payload/server/public/assets/{dagre-PrVfCcSt.js → dagre-Dfj_jbTe.js} +1 -1
  184. package/payload/server/public/assets/{dagre-KV5264BT-DPq3dcLH.js → dagre-KV5264BT-Bd1VlhUJ.js} +1 -1
  185. package/payload/server/public/assets/data-DkbQI40a.js +1 -0
  186. package/payload/server/public/assets/{diagram-5BDNPKRD-DoszElKb.js → diagram-5BDNPKRD-Dqqyk8GE.js} +1 -1
  187. package/payload/server/public/assets/{diagram-G4DWMVQ6-BRuqosix.js → diagram-G4DWMVQ6-Xk3WKR_U.js} +1 -1
  188. package/payload/server/public/assets/{diagram-MMDJMWI5-CpigG1d_.js → diagram-MMDJMWI5-CAdGL9U7.js} +1 -1
  189. package/payload/server/public/assets/{diagram-TYMM5635-BS0eYiq9.js → diagram-TYMM5635-DY1iYQVY.js} +1 -1
  190. package/payload/server/public/assets/{erDiagram-SMLLAGMA-VEQyXCFl.js → erDiagram-SMLLAGMA-BJ5HYKeb.js} +1 -1
  191. package/payload/server/public/assets/{file-download-C3pBZjt9.js → file-download-BYJN3Kgm.js} +1 -1
  192. package/payload/server/public/assets/{flowDiagram-DWJPFMVM-2NYMfqHX.js → flowDiagram-DWJPFMVM-B-q6x5Q_.js} +1 -1
  193. package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-AAAa2sqE.js → ganttDiagram-T4ZO3ILL-DbjwY_bG.js} +1 -1
  194. package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-d8NUAIz5.js → gitGraphDiagram-UUTBAWPF-C3bLrOmb.js} +1 -1
  195. package/payload/server/public/assets/{graph-Bx9_2qbJ.js → graph-DmikPM4A.js} +2 -2
  196. package/payload/server/public/assets/{graph-labels-Cc1nU1_f.js → graph-labels-CtG6ckdG.js} +1 -1
  197. package/payload/server/public/assets/{graphlib-DUlqr2mr.js → graphlib-BlOjhixq.js} +1 -1
  198. package/payload/server/public/assets/{infoDiagram-42DDH7IO-D4dh4-0g.js → infoDiagram-42DDH7IO-BpaHbiXO.js} +1 -1
  199. package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-DPTmm2IE.js → ishikawaDiagram-UXIWVN3A-B_DzwK8l.js} +1 -1
  200. package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-B85vjqkE.js → journeyDiagram-VCZTEJTY-COzTF-qc.js} +1 -1
  201. package/payload/server/public/assets/{jsx-runtime-D3PZpOAF.css → jsx-runtime-BjFkEGXb.css} +1 -1
  202. package/payload/server/public/assets/{kanban-definition-6JOO6SKY-C2Lfb5Xh.js → kanban-definition-6JOO6SKY-C2cOIZU6.js} +1 -1
  203. package/payload/server/public/assets/{line-CODKFpwO.js → line-Bwa6aUYZ.js} +1 -1
  204. package/payload/server/public/assets/{mermaid-parser.core-DYdFZnXH.js → mermaid-parser.core-BFAF0BAk.js} +1 -1
  205. package/payload/server/public/assets/{mermaid.core-Bamjzahu.js → mermaid.core-CMOXmawT.js} +3 -3
  206. package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-CLK90bKJ.js → mindmap-definition-QFDTVHPH-bu0QLO17.js} +1 -1
  207. package/payload/server/public/assets/{pieDiagram-DEJITSTG-DEsnxhqP.js → pieDiagram-DEJITSTG-DQUe6W2Z.js} +1 -1
  208. package/payload/server/public/assets/{public-BFMu-jux.js → public-CSEIGhb4.js} +5 -5
  209. package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-uIP9V2jZ.js → quadrantDiagram-34T5L4WZ-ChhcwVRA.js} +1 -1
  210. package/payload/server/public/assets/{requirementDiagram-MS252O5E-CVS6t5tv.js → requirementDiagram-MS252O5E-DwQXqTA9.js} +1 -1
  211. package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-BIsmtyZA.js → sankeyDiagram-XADWPNL6-zYqdptBM.js} +1 -1
  212. package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-Cu8TfQiW.js → sequenceDiagram-FGHM5R23-x2g84gb4.js} +1 -1
  213. package/payload/server/public/assets/{stateDiagram-FHFEXIEX-ax4vYGft.js → stateDiagram-FHFEXIEX-CeUrqs2P.js} +1 -1
  214. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-B27DBP9X.js +1 -0
  215. package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-3l7ojkMA.js → timeline-definition-GMOUNBTQ-CL-c9XN5.js} +1 -1
  216. package/payload/server/public/assets/{useSelectionMode-C_EBRd2k.js → useSelectionMode-C1_ky4B6.js} +1 -1
  217. package/payload/server/public/assets/{vennDiagram-DHZGUBPP-C_sv0qMD.js → vennDiagram-DHZGUBPP-By2HBDYr.js} +1 -1
  218. package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-C7u4IHMB.js → wardleyDiagram-NUSXRM2D-iahvFvIS.js} +1 -1
  219. package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-A-uLXr1a.js → xychartDiagram-5P7HB3ND-33qqdRhI.js} +1 -1
  220. package/payload/server/public/browser.html +6 -6
  221. package/payload/server/public/chat.html +8 -8
  222. package/payload/server/public/data.html +5 -5
  223. package/payload/server/public/graph.html +8 -8
  224. package/payload/server/public/index.html +8 -8
  225. package/payload/server/public/public.html +6 -6
  226. package/payload/server/public/whatsapp-wallpaper.webp +0 -0
  227. package/payload/server/server.js +17 -9
  228. package/payload/server/public/assets/AdminShell-DDieHnzi.js +0 -1
  229. package/payload/server/public/assets/audio-attachment-mime-DGEfApkA.js +0 -1
  230. package/payload/server/public/assets/browser-DrJReVEG.js +0 -1
  231. package/payload/server/public/assets/channel-drVqp11B.js +0 -1
  232. package/payload/server/public/assets/chat-rJYaCD6C.js +0 -1
  233. package/payload/server/public/assets/classDiagram-6PBFFD2Q-Dplkw_pj.js +0 -1
  234. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-sJXv1Ihp.js +0 -1
  235. package/payload/server/public/assets/clone-Q_B6oO0c.js +0 -1
  236. package/payload/server/public/assets/data-CYyR2m_B.js +0 -1
  237. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BRv1By5g.js +0 -1
  238. /package/payload/server/public/assets/{jsx-runtime-5auA0FEj.js → jsx-runtime-UQ0Z6nwN.js} +0 -0
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=email-draft-edit.test.d.ts.map
@@ -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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=email-draft-send.test.d.ts.map
@@ -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":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9D,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAC/D,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE;IAClB,WAAW,EAAE,EAAE,CAAC,EAAE,EAAE;IACpB,UAAU,EAAE,EAAE,CAAC,EAAE,EAAE;CACpB,CAAC,CAAC,CAAC;AACJ,EAAE,CAAC,IAAI,CAAC,gBAAgB,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,gBAAgB,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC;AAC5F,EAAE,CAAC,IAAI,CAAC,gBAAgB,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE;IACjD,MAAM,MAAM,GAAG,MAAM,cAAc,EAAmC,CAAC;IACvE,OAAO,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;AAC7C,CAAC,CAAC,CAAC;AACH,EAAE,CAAC,IAAI,CAAC,uBAAuB,EAAE,GAAG,EAAE,CAAC,CAAC;IACtC,eAAe,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;QAClC,WAAW,EAAE,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;KACnF,CAAC,CAAC;CACJ,CAAC,CAAC,CAAC;AAEJ,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAE9D,MAAM,KAAK,GAAG;IACZ,MAAM,EAAE,QAAQ;IAChB,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC;IACjC,WAAW,EAAE,CAAC,OAAO,CAAC;IACtB,WAAW,EAAE,CAAC,OAAO,CAAC;IACtB,YAAY,EAAE,CAAC,OAAO,CAAC;CACxB,CAAC;AAEF,QAAQ,CAAC,6BAA6B,EAAE,GAAG,EAAE;IAC3C,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,CAAC,aAAa,EAAE,CAAC;QACnB,SAAS,CAAC,iBAAiB,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;QAC1C,WAAW,CAAC,iBAAiB,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC,CAAC;QACzD,UAAU,CAAC,iBAAiB,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;QAC3E,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QAClE,MAAM,CAAC,WAAW,CAAC,CAAC,oBAAoB,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE;YAC9E,IAAI,EAAE,OAAO;YACb,EAAE,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;SAChC,CAAC,CAAC;QACH,MAAM,CAAC,UAAU,CAAC,CAAC,oBAAoB,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACpE,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QACjC,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QACnC,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;QACpD,SAAS,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC;QACtC,MAAM,MAAM,CAAC,cAAc,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAC5E,uBAAuB,CACxB,CAAC;QACF,MAAM,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+EAA+E,EAAE,KAAK,IAAI,EAAE;QAC7F,UAAU,CAAC,qBAAqB,CAAC,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC,CAAC;QAChF,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QAClE,MAAM,CAAC,WAAW,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;QAC7C,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QACjC,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QACnC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,gCAAgC,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0EAA0E,EAAE,KAAK,IAAI,EAAE;QACxF,WAAW,CAAC,qBAAqB,CAAC,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAC;QAClE,MAAM,MAAM,CAAC,cAAc,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QACzF,MAAM,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,SAAS,CAAC,qBAAqB,CAAC;YAC9B,MAAM,EAAE,QAAQ;YAChB,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;YACxB,WAAW,EAAE,EAAE;YACf,WAAW,EAAE,EAAE;YACf,YAAY,EAAE,EAAE;SACjB,CAAC,CAAC;QACH,MAAM,MAAM,CAAC,cAAc,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QAC/F,MAAM,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QAClE,SAAS,CAAC,qBAAqB,CAAC;YAC9B,MAAM,EAAE,QAAQ;YAChB,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;YACxB,WAAW,EAAE,CAAC,OAAO,CAAC;YACtB,WAAW,EAAE,CAAC,OAAO,CAAC;YACtB,YAAY,EAAE,EAAE;SACjB,CAAC,CAAC;QACH,MAAM,cAAc,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QACrD,MAAM,CAAC,WAAW,CAAC,CAAC,oBAAoB,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;YACpF,IAAI,EAAE,OAAO;YACb,EAAE,EAAE,CAAC,OAAO,CAAC;SACd,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oFAAoF,EAAE,KAAK,IAAI,EAAE;QAClG,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC,uBAAuB,CAAC,CAAC;QACjE,eAAuD,CAAC,qBAAqB,CAAC;YAC7E,WAAW,EAAE,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;SAC3F,CAAC,CAAC;QACH,WAAW,CAAC,qBAAqB,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;QACzD,MAAM,MAAM,CAAC,cAAc,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAC1E,uDAAuD,CACxD,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=email-draft.test.d.ts.map
@@ -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":"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"}
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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=imap-drafts.test.d.ts.map
@@ -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