opensentinel 2.1.1 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (268) hide show
  1. package/README.md +354 -283
  2. package/dist/archiver-AVNBYCKQ.js +15340 -0
  3. package/dist/archiver-AVNBYCKQ.js.map +1 -0
  4. package/dist/audit-logger-OBPR7CRO.js +22 -0
  5. package/dist/auth-UOX5K2BE.js +18 -0
  6. package/dist/autonomy-ZXDBDQUJ.js +86 -0
  7. package/dist/autonomy-ZXDBDQUJ.js.map +1 -0
  8. package/dist/aws-s3-Q4LLZZPD.js +146 -0
  9. package/dist/aws-s3-Q4LLZZPD.js.map +1 -0
  10. package/dist/backup-restore-PZ7CYYB7.js +16 -0
  11. package/dist/blocks-R3PODY47.js +23 -0
  12. package/dist/bot-QRARP4UN.js +36 -0
  13. package/dist/brain-7XLLM3KC.js +56 -0
  14. package/dist/camera-monitor-M5CYKUU4.js +335 -0
  15. package/dist/camera-monitor-M5CYKUU4.js.map +1 -0
  16. package/dist/{charts-MMXM6BWW.js → charts-V7ARZNKF.js} +2 -2
  17. package/dist/chunk-22VGGA7S.js +330 -0
  18. package/dist/chunk-22VGGA7S.js.map +1 -0
  19. package/dist/chunk-35WYTA3C.js +382 -0
  20. package/dist/chunk-35WYTA3C.js.map +1 -0
  21. package/dist/chunk-3E2PSU2C.js +146 -0
  22. package/dist/chunk-3E2PSU2C.js.map +1 -0
  23. package/dist/{chunk-L3F43VPB.js → chunk-4GLYY4NN.js} +2 -2
  24. package/dist/{chunk-L3F43VPB.js.map → chunk-4GLYY4NN.js.map} +1 -1
  25. package/dist/{chunk-L3PDU3XN.js → chunk-4UOE5TUZ.js} +4 -4
  26. package/dist/{chunk-6SNHU3CY.js → chunk-66OJ3WB4.js} +2 -2
  27. package/dist/chunk-6KONMXQ6.js +297 -0
  28. package/dist/chunk-6KONMXQ6.js.map +1 -0
  29. package/dist/chunk-6PMVAAA7.js +196 -0
  30. package/dist/chunk-6PMVAAA7.js.map +1 -0
  31. package/dist/chunk-766ASQWE.js +32620 -0
  32. package/dist/chunk-766ASQWE.js.map +1 -0
  33. package/dist/chunk-7WQO5J2M.js +29 -0
  34. package/dist/chunk-7WQO5J2M.js.map +1 -0
  35. package/dist/chunk-APHSRMBS.js +148 -0
  36. package/dist/chunk-APHSRMBS.js.map +1 -0
  37. package/dist/{chunk-4LVWXUNC.js → chunk-AYUKPTSM.js} +57 -39
  38. package/dist/chunk-AYUKPTSM.js.map +1 -0
  39. package/dist/chunk-BIPYADGB.js +84 -0
  40. package/dist/chunk-BIPYADGB.js.map +1 -0
  41. package/dist/chunk-BRBWNV65.js +457 -0
  42. package/dist/chunk-BRBWNV65.js.map +1 -0
  43. package/dist/chunk-BXZ6EA52.js +382 -0
  44. package/dist/chunk-BXZ6EA52.js.map +1 -0
  45. package/dist/chunk-EVE7MIIY.js +290 -0
  46. package/dist/chunk-EVE7MIIY.js.map +1 -0
  47. package/dist/chunk-F3TTNID2.js +138 -0
  48. package/dist/chunk-F3TTNID2.js.map +1 -0
  49. package/dist/chunk-H5RQOFO2.js +190 -0
  50. package/dist/chunk-H5RQOFO2.js.map +1 -0
  51. package/dist/chunk-HN3F4WSW.js +145 -0
  52. package/dist/chunk-HN3F4WSW.js.map +1 -0
  53. package/dist/{chunk-6DRDKB45.js → chunk-I6BDYQIG.js} +20 -9
  54. package/dist/chunk-I6BDYQIG.js.map +1 -0
  55. package/dist/chunk-IZJMVV7O.js +347 -0
  56. package/dist/chunk-IZJMVV7O.js.map +1 -0
  57. package/dist/chunk-KM22GV7G.js +211 -0
  58. package/dist/chunk-KM22GV7G.js.map +1 -0
  59. package/dist/chunk-MGFBLVR7.js +103 -0
  60. package/dist/chunk-MGFBLVR7.js.map +1 -0
  61. package/dist/chunk-MQJ2ECQT.js +228 -0
  62. package/dist/chunk-MQJ2ECQT.js.map +1 -0
  63. package/dist/{chunk-F6QUZQGI.js → chunk-MXAPLSJ5.js} +2 -2
  64. package/dist/{chunk-GK3E2I7A.js → chunk-NHMBTUMW.js} +2 -2
  65. package/dist/chunk-NPRTSZIF.js +131 -0
  66. package/dist/chunk-NPRTSZIF.js.map +1 -0
  67. package/dist/chunk-O7IH7JTI.js +1898 -0
  68. package/dist/chunk-O7IH7JTI.js.map +1 -0
  69. package/dist/chunk-OCVQGBJK.js +293 -0
  70. package/dist/chunk-OCVQGBJK.js.map +1 -0
  71. package/dist/chunk-P6QINGFL.js +332 -0
  72. package/dist/chunk-P6QINGFL.js.map +1 -0
  73. package/dist/chunk-PHDZKPNE.js +91 -0
  74. package/dist/chunk-PHDZKPNE.js.map +1 -0
  75. package/dist/chunk-PLDDJCW6.js +49 -0
  76. package/dist/chunk-PTGTGXV2.js +164 -0
  77. package/dist/chunk-PTGTGXV2.js.map +1 -0
  78. package/dist/chunk-REMIY4U2.js +171 -0
  79. package/dist/chunk-REMIY4U2.js.map +1 -0
  80. package/dist/chunk-RZ4YESBG.js +141 -0
  81. package/dist/chunk-RZ4YESBG.js.map +1 -0
  82. package/dist/chunk-SAX5MHK4.js +111 -0
  83. package/dist/chunk-SAX5MHK4.js.map +1 -0
  84. package/dist/{chunk-GVJVEWHI.js → chunk-SJSUSJ47.js} +2 -2
  85. package/dist/chunk-SPPMCAKG.js +777 -0
  86. package/dist/chunk-SPPMCAKG.js.map +1 -0
  87. package/dist/chunk-SVAPX2XN.js +2441 -0
  88. package/dist/chunk-SVAPX2XN.js.map +1 -0
  89. package/dist/chunk-TVEWKIK3.js +452 -0
  90. package/dist/chunk-TVEWKIK3.js.map +1 -0
  91. package/dist/{chunk-HH2HBTQM.js → chunk-TYAGMJNV.js} +5 -5
  92. package/dist/{chunk-JXUP2X7V.js → chunk-VEHFVBLI.js} +2 -2
  93. package/dist/chunk-VNX5GMTN.js +128 -0
  94. package/dist/chunk-VNX5GMTN.js.map +1 -0
  95. package/dist/chunk-VRD5CYRL.js +1568 -0
  96. package/dist/chunk-VRD5CYRL.js.map +1 -0
  97. package/dist/chunk-WLUHNG6X.js +122 -0
  98. package/dist/chunk-WLUHNG6X.js.map +1 -0
  99. package/dist/chunk-WRAKK6K6.js +265 -0
  100. package/dist/chunk-WRAKK6K6.js.map +1 -0
  101. package/dist/chunk-XKYRH4FM.js +681 -0
  102. package/dist/chunk-XKYRH4FM.js.map +1 -0
  103. package/dist/{chunk-GUBEEYDW.js → chunk-XMCVRVTF.js} +2 -2
  104. package/dist/{chunk-GUBEEYDW.js.map → chunk-XMCVRVTF.js.map} +1 -1
  105. package/dist/chunk-ZLZKF2PM.js +310 -0
  106. package/dist/chunk-ZLZKF2PM.js.map +1 -0
  107. package/dist/cli.js +5 -1
  108. package/dist/cli.js.map +1 -1
  109. package/dist/client-ZQSFPMOB.js +21 -0
  110. package/dist/clipboard-manager-TEO2GEDN.js +24 -0
  111. package/dist/commands/setup.js +3 -3
  112. package/dist/commands/setup.js.map +1 -1
  113. package/dist/commands/start.js +3 -3
  114. package/dist/commands/status.js +2 -2
  115. package/dist/commands/stop.js +2 -2
  116. package/dist/commands/utils.js +2 -2
  117. package/dist/cron-explain-HHQKPD3M.js +16 -0
  118. package/dist/crypto-4AP47IKC.js +14 -0
  119. package/dist/crypto-4AP47IKC.js.map +1 -0
  120. package/dist/databases-37X4CI2Y.js +21 -0
  121. package/dist/databases-37X4CI2Y.js.map +1 -0
  122. package/dist/discord-B3HUPGQ6.js +70 -0
  123. package/dist/discord-B3HUPGQ6.js.map +1 -0
  124. package/dist/dist-UISMLMFN.js +21847 -0
  125. package/dist/dist-UISMLMFN.js.map +1 -0
  126. package/dist/email-K7LO2IPB.js +268 -0
  127. package/dist/email-K7LO2IPB.js.map +1 -0
  128. package/dist/enhanced-retrieval-DNLLEM4Z.js +753 -0
  129. package/dist/enhanced-retrieval-DNLLEM4Z.js.map +1 -0
  130. package/dist/enrichment-pipeline-MNHNW65K.js +13 -0
  131. package/dist/enrichment-pipeline-MNHNW65K.js.map +1 -0
  132. package/dist/entity-resolution-Y3IUWEAT.js +24 -0
  133. package/dist/entity-resolution-Y3IUWEAT.js.map +1 -0
  134. package/dist/env-IWXUVTCB.js +12 -0
  135. package/dist/env-IWXUVTCB.js.map +1 -0
  136. package/dist/google-workspace-DKWUVNGC.js +169 -0
  137. package/dist/google-workspace-DKWUVNGC.js.map +1 -0
  138. package/dist/hash-tool-ULQYD7B5.js +22 -0
  139. package/dist/hash-tool-ULQYD7B5.js.map +1 -0
  140. package/dist/heartbeat-monitor-GCISLXI3.js +22 -0
  141. package/dist/heartbeat-monitor-GCISLXI3.js.map +1 -0
  142. package/dist/image-generation-OSU7FP6F.js +486 -0
  143. package/dist/image-generation-OSU7FP6F.js.map +1 -0
  144. package/dist/imessage-NGA2XF2V.js +35 -0
  145. package/dist/imessage-NGA2XF2V.js.map +1 -0
  146. package/dist/inbox-summarizer-NRI4S7IF.js +47 -0
  147. package/dist/inbox-summarizer-NRI4S7IF.js.map +1 -0
  148. package/dist/incident-response-C5J7Q6DT.js +244 -0
  149. package/dist/incident-response-C5J7Q6DT.js.map +1 -0
  150. package/dist/inventory-manager-352OHXWD.js +24 -0
  151. package/dist/inventory-manager-352OHXWD.js.map +1 -0
  152. package/dist/jira-GSGDBMIG.js +199 -0
  153. package/dist/jira-GSGDBMIG.js.map +1 -0
  154. package/dist/json-tool-QE2SYHEG.js +26 -0
  155. package/dist/json-tool-QE2SYHEG.js.map +1 -0
  156. package/dist/key-rotation-DPHU4ZTB.js +18 -0
  157. package/dist/key-rotation-DPHU4ZTB.js.map +1 -0
  158. package/dist/lib.d.ts +603 -11
  159. package/dist/lib.js +161 -35
  160. package/dist/lib.js.map +1 -1
  161. package/dist/mailchimp-KKNF6QJ7.js +152 -0
  162. package/dist/mailchimp-KKNF6QJ7.js.map +1 -0
  163. package/dist/matrix-QVHG76I7.js +279 -0
  164. package/dist/matrix-QVHG76I7.js.map +1 -0
  165. package/dist/{mcp-LS7Q3Z5W.js → mcp-3JI6W7ZE.js} +3 -3
  166. package/dist/mcp-3JI6W7ZE.js.map +1 -0
  167. package/dist/microsoft365-UCBKJHNX.js +164 -0
  168. package/dist/microsoft365-UCBKJHNX.js.map +1 -0
  169. package/dist/ocr-AC7NPX33.js +22 -0
  170. package/dist/ocr-AC7NPX33.js.map +1 -0
  171. package/dist/ollama-BOAMSPLJ.js +8 -0
  172. package/dist/ollama-BOAMSPLJ.js.map +1 -0
  173. package/dist/pages-MI523RB7.js +26 -0
  174. package/dist/pages-MI523RB7.js.map +1 -0
  175. package/dist/pair-JDFTERIK.js +24 -0
  176. package/dist/pair-JDFTERIK.js.map +1 -0
  177. package/dist/pairing-IFQYCPNS.js +10 -0
  178. package/dist/pairing-IFQYCPNS.js.map +1 -0
  179. package/dist/pdf-ALQVOEJR.js +17 -0
  180. package/dist/pdf-ALQVOEJR.js.map +1 -0
  181. package/dist/presentations-DSV5IHG5.js +1002 -0
  182. package/dist/presentations-DSV5IHG5.js.map +1 -0
  183. package/dist/prometheus-JNT2BD4L.js +10 -0
  184. package/dist/prometheus-JNT2BD4L.js.map +1 -0
  185. package/dist/providers-J4LYPHDR.js +19 -0
  186. package/dist/providers-J4LYPHDR.js.map +1 -0
  187. package/dist/qr-code-WIX4PB4U.js +16 -0
  188. package/dist/qr-code-WIX4PB4U.js.map +1 -0
  189. package/dist/quickbooks-XB4NII2S.js +190 -0
  190. package/dist/quickbooks-XB4NII2S.js.map +1 -0
  191. package/dist/regex-tool-W4ABRKGK.js +24 -0
  192. package/dist/regex-tool-W4ABRKGK.js.map +1 -0
  193. package/dist/scheduler-VK4WFERV.js +63 -0
  194. package/dist/scheduler-VK4WFERV.js.map +1 -0
  195. package/dist/search-BCLBO5E3.js +25 -0
  196. package/dist/search-BCLBO5E3.js.map +1 -0
  197. package/dist/sendgrid-RNXCAFKM.js +152 -0
  198. package/dist/sendgrid-RNXCAFKM.js.map +1 -0
  199. package/dist/shopify-NCXYJB4R.js +171 -0
  200. package/dist/shopify-NCXYJB4R.js.map +1 -0
  201. package/dist/signal-6CGDFYL2.js +35 -0
  202. package/dist/signal-6CGDFYL2.js.map +1 -0
  203. package/dist/slack-IZQWIKOH.js +75 -0
  204. package/dist/slack-IZQWIKOH.js.map +1 -0
  205. package/dist/sms-M3JIOTCW.js +23 -0
  206. package/dist/sms-M3JIOTCW.js.map +1 -0
  207. package/dist/{src-K7GASHRH.js → src-VYUE6LRA.js} +138 -32
  208. package/dist/src-VYUE6LRA.js.map +1 -0
  209. package/dist/stocks-XXWBPOCU.js +14 -0
  210. package/dist/stocks-XXWBPOCU.js.map +1 -0
  211. package/dist/text-transform-6SGUA5Z4.js +22 -0
  212. package/dist/text-transform-6SGUA5Z4.js.map +1 -0
  213. package/dist/tools-2RLEI2N6.js +38 -0
  214. package/dist/tools-2RLEI2N6.js.map +1 -0
  215. package/dist/tunnel-IWMXUML4.js +301 -0
  216. package/dist/tunnel-IWMXUML4.js.map +1 -0
  217. package/dist/twilio-53GEW5JT.js +139 -0
  218. package/dist/twilio-53GEW5JT.js.map +1 -0
  219. package/dist/unit-converter-ZYXMEZOE.js +14 -0
  220. package/dist/unit-converter-ZYXMEZOE.js.map +1 -0
  221. package/dist/whatsapp-LFX6YKCM.js +35 -0
  222. package/dist/whatsapp-LFX6YKCM.js.map +1 -0
  223. package/dist/word-document-7B6SJMAY.js +902 -0
  224. package/dist/word-document-7B6SJMAY.js.map +1 -0
  225. package/dist/xero-QYO66D45.js +162 -0
  226. package/dist/xero-QYO66D45.js.map +1 -0
  227. package/dist/zapier-webhook-TBZ5YF2A.js +106 -0
  228. package/dist/zapier-webhook-TBZ5YF2A.js.map +1 -0
  229. package/drizzle/0002_mushy_master_mold.sql +140 -0
  230. package/drizzle/meta/0002_snapshot.json +3637 -0
  231. package/drizzle/meta/_journal.json +7 -0
  232. package/package.json +100 -98
  233. package/dist/bot-KJ26BG56.js +0 -15
  234. package/dist/chunk-4LVWXUNC.js.map +0 -1
  235. package/dist/chunk-4TG2IG5K.js +0 -5249
  236. package/dist/chunk-4TG2IG5K.js.map +0 -1
  237. package/dist/chunk-6DRDKB45.js.map +0 -1
  238. package/dist/chunk-CI6Q63MM.js +0 -1613
  239. package/dist/chunk-CI6Q63MM.js.map +0 -1
  240. package/dist/chunk-KHNYJY2Z.js +0 -178
  241. package/dist/chunk-KHNYJY2Z.js.map +0 -1
  242. package/dist/chunk-NSBPE2FW.js +0 -17
  243. package/dist/discord-ZOJFTVTB.js +0 -49
  244. package/dist/imessage-JFRB6EJ7.js +0 -14
  245. package/dist/scheduler-EZ7CZMCS.js +0 -42
  246. package/dist/signal-T3MCSULM.js +0 -14
  247. package/dist/slack-N2M4FHAJ.js +0 -54
  248. package/dist/src-K7GASHRH.js.map +0 -1
  249. package/dist/tools-24GZHYRF.js +0 -16
  250. package/dist/whatsapp-VCRUPAO5.js +0 -14
  251. /package/dist/{bot-KJ26BG56.js.map → audit-logger-OBPR7CRO.js.map} +0 -0
  252. /package/dist/{chunk-NSBPE2FW.js.map → auth-UOX5K2BE.js.map} +0 -0
  253. /package/dist/{discord-ZOJFTVTB.js.map → backup-restore-PZ7CYYB7.js.map} +0 -0
  254. /package/dist/{imessage-JFRB6EJ7.js.map → blocks-R3PODY47.js.map} +0 -0
  255. /package/dist/{mcp-LS7Q3Z5W.js.map → bot-QRARP4UN.js.map} +0 -0
  256. /package/dist/{scheduler-EZ7CZMCS.js.map → brain-7XLLM3KC.js.map} +0 -0
  257. /package/dist/{charts-MMXM6BWW.js.map → charts-V7ARZNKF.js.map} +0 -0
  258. /package/dist/{chunk-L3PDU3XN.js.map → chunk-4UOE5TUZ.js.map} +0 -0
  259. /package/dist/{chunk-6SNHU3CY.js.map → chunk-66OJ3WB4.js.map} +0 -0
  260. /package/dist/{chunk-F6QUZQGI.js.map → chunk-MXAPLSJ5.js.map} +0 -0
  261. /package/dist/{chunk-GK3E2I7A.js.map → chunk-NHMBTUMW.js.map} +0 -0
  262. /package/dist/{signal-T3MCSULM.js.map → chunk-PLDDJCW6.js.map} +0 -0
  263. /package/dist/{chunk-GVJVEWHI.js.map → chunk-SJSUSJ47.js.map} +0 -0
  264. /package/dist/{chunk-HH2HBTQM.js.map → chunk-TYAGMJNV.js.map} +0 -0
  265. /package/dist/{chunk-JXUP2X7V.js.map → chunk-VEHFVBLI.js.map} +0 -0
  266. /package/dist/{slack-N2M4FHAJ.js.map → client-ZQSFPMOB.js.map} +0 -0
  267. /package/dist/{tools-24GZHYRF.js.map → clipboard-manager-TEO2GEDN.js.map} +0 -0
  268. /package/dist/{whatsapp-VCRUPAO5.js.map → cron-explain-HHQKPD3M.js.map} +0 -0
@@ -0,0 +1,777 @@
1
+ import {
2
+ chat
3
+ } from "./chunk-766ASQWE.js";
4
+
5
+ // src/integrations/email/email-parser.ts
6
+ function parseEmail(email) {
7
+ const isReply = email.subject.toLowerCase().startsWith("re:");
8
+ const isForward = email.subject.toLowerCase().startsWith("fwd:") || email.subject.toLowerCase().startsWith("fw:");
9
+ const attachments = email.attachments.map((att) => parseAttachment(att));
10
+ const totalAttachmentSize = attachments.reduce((sum, att) => sum + att.size, 0);
11
+ let importance = "normal";
12
+ const importanceHeader = email.headers.get("importance") || email.headers.get("x-priority");
13
+ if (importanceHeader) {
14
+ const lowerHeader = importanceHeader.toLowerCase();
15
+ if (lowerHeader.includes("high") || lowerHeader === "1" || lowerHeader === "2") {
16
+ importance = "high";
17
+ } else if (lowerHeader.includes("low") || lowerHeader === "5") {
18
+ importance = "low";
19
+ }
20
+ }
21
+ return {
22
+ id: email.id,
23
+ subject: email.subject,
24
+ from: email.from,
25
+ to: email.to,
26
+ cc: email.cc,
27
+ date: email.date,
28
+ body: {
29
+ text: email.text,
30
+ html: email.html,
31
+ snippet: email.snippet || email.text.substring(0, 200).replace(/\s+/g, " ").trim()
32
+ },
33
+ thread: {
34
+ id: email.threadId || email.messageId,
35
+ messageId: email.messageId,
36
+ inReplyTo: email.inReplyTo,
37
+ references: email.references,
38
+ position: email.references.length,
39
+ isReply,
40
+ isForward
41
+ },
42
+ attachments,
43
+ metadata: {
44
+ isRead: email.flags.includes("\\Seen"),
45
+ isFlagged: email.flags.includes("\\Flagged"),
46
+ isSpam: email.labels.includes("Spam") || email.labels.includes("Junk"),
47
+ isDraft: email.flags.includes("\\Draft"),
48
+ labels: email.labels,
49
+ importance,
50
+ hasAttachments: attachments.length > 0,
51
+ attachmentCount: attachments.length,
52
+ totalAttachmentSize
53
+ }
54
+ };
55
+ }
56
+ function parseAttachment(attachment) {
57
+ const extension = attachment.filename.includes(".") ? attachment.filename.split(".").pop()?.toLowerCase() || "" : "";
58
+ return {
59
+ filename: attachment.filename,
60
+ contentType: attachment.contentType,
61
+ size: attachment.size,
62
+ isInline: !!attachment.contentId,
63
+ cid: attachment.contentId,
64
+ content: attachment.content,
65
+ extension,
66
+ category: categorizeAttachment(attachment.contentType, extension)
67
+ };
68
+ }
69
+ function categorizeAttachment(contentType, extension) {
70
+ const lowerContentType = contentType.toLowerCase();
71
+ if (lowerContentType.startsWith("image/")) {
72
+ return "image";
73
+ }
74
+ const docExtensions = ["pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt", "rtf", "odt", "ods", "odp", "csv"];
75
+ const docMimeTypes = [
76
+ "application/pdf",
77
+ "application/msword",
78
+ "application/vnd.openxmlformats",
79
+ "application/vnd.ms-",
80
+ "text/plain",
81
+ "text/csv",
82
+ "application/vnd.oasis.opendocument"
83
+ ];
84
+ if (docExtensions.includes(extension) || docMimeTypes.some((m) => lowerContentType.includes(m))) {
85
+ return "document";
86
+ }
87
+ const archiveExtensions = ["zip", "rar", "7z", "tar", "gz", "bz2"];
88
+ const archiveMimeTypes = ["application/zip", "application/x-rar", "application/x-7z", "application/gzip"];
89
+ if (archiveExtensions.includes(extension) || archiveMimeTypes.some((m) => lowerContentType.includes(m))) {
90
+ return "archive";
91
+ }
92
+ if (lowerContentType.startsWith("audio/") || lowerContentType.startsWith("video/")) {
93
+ return "media";
94
+ }
95
+ return "other";
96
+ }
97
+ function groupIntoThreads(emails) {
98
+ const threadMap = /* @__PURE__ */ new Map();
99
+ for (const email of emails) {
100
+ let threadId = email.threadId || email.messageId;
101
+ if (email.references.length > 0) {
102
+ threadId = email.references[0];
103
+ }
104
+ if (!threadMap.has(threadId)) {
105
+ threadMap.set(threadId, []);
106
+ }
107
+ threadMap.get(threadId).push(email);
108
+ }
109
+ const threads = [];
110
+ for (const [threadId, messages] of threadMap) {
111
+ messages.sort((a, b) => a.date.getTime() - b.date.getTime());
112
+ const participantMap = /* @__PURE__ */ new Map();
113
+ for (const msg of messages) {
114
+ for (const addr of [...msg.from, ...msg.to, ...msg.cc]) {
115
+ if (!participantMap.has(addr.address)) {
116
+ participantMap.set(addr.address, addr);
117
+ }
118
+ }
119
+ }
120
+ const unreadCount = messages.filter((m) => !m.flags.includes("\\Seen")).length;
121
+ let subject = messages[0].subject;
122
+ for (const msg of messages) {
123
+ const cleaned = cleanSubject(msg.subject);
124
+ if (cleaned.length > 0 && !cleaned.toLowerCase().startsWith("re:")) {
125
+ subject = msg.subject;
126
+ break;
127
+ }
128
+ }
129
+ threads.push({
130
+ id: threadId,
131
+ subject: cleanSubject(subject),
132
+ participants: Array.from(participantMap.values()),
133
+ messageCount: messages.length,
134
+ unreadCount,
135
+ lastMessageDate: messages[messages.length - 1].date,
136
+ firstMessageDate: messages[0].date,
137
+ messages: messages.map(parseEmail),
138
+ snippet: messages[messages.length - 1].snippet || messages[messages.length - 1].text.substring(0, 200).replace(/\s+/g, " ").trim()
139
+ });
140
+ }
141
+ threads.sort((a, b) => b.lastMessageDate.getTime() - a.lastMessageDate.getTime());
142
+ return threads;
143
+ }
144
+ function cleanSubject(subject) {
145
+ return subject.replace(/^(Re|Fwd|Fw):\s*/gi, "").replace(/^\[.*?\]\s*/, "").trim();
146
+ }
147
+ function parseEmailBody(text) {
148
+ const lines = text.split("\n");
149
+ const newLines = [];
150
+ const quotedSections = [];
151
+ let currentQuote = null;
152
+ let signature;
153
+ let inSignature = false;
154
+ for (let i = 0; i < lines.length; i++) {
155
+ const line = lines[i];
156
+ if (line.trim() === "--" || line.trim() === "-- ") {
157
+ inSignature = true;
158
+ signature = lines.slice(i + 1).join("\n").trim();
159
+ break;
160
+ }
161
+ const quoteMatch = line.match(/^(>+)\s?/);
162
+ if (quoteMatch) {
163
+ const level = quoteMatch[1].length;
164
+ const content = line.substring(quoteMatch[0].length);
165
+ if (!currentQuote || currentQuote.level !== level) {
166
+ if (currentQuote) {
167
+ quotedSections.push({
168
+ level: currentQuote.level,
169
+ content: currentQuote.lines.join("\n"),
170
+ attribution: currentQuote.attribution
171
+ });
172
+ }
173
+ currentQuote = { level, lines: [content] };
174
+ } else {
175
+ currentQuote.lines.push(content);
176
+ }
177
+ } else if (isAttributionLine(line)) {
178
+ if (currentQuote) {
179
+ currentQuote.attribution = line;
180
+ } else {
181
+ currentQuote = { level: 1, lines: [], attribution: line };
182
+ }
183
+ } else {
184
+ if (currentQuote) {
185
+ quotedSections.push({
186
+ level: currentQuote.level,
187
+ content: currentQuote.lines.join("\n"),
188
+ attribution: currentQuote.attribution
189
+ });
190
+ currentQuote = null;
191
+ }
192
+ newLines.push(line);
193
+ }
194
+ }
195
+ if (currentQuote) {
196
+ quotedSections.push({
197
+ level: currentQuote.level,
198
+ content: currentQuote.lines.join("\n"),
199
+ attribution: currentQuote.attribution
200
+ });
201
+ }
202
+ return {
203
+ newContent: newLines.join("\n").trim(),
204
+ quotedContent: quotedSections,
205
+ signature
206
+ };
207
+ }
208
+ function isAttributionLine(line) {
209
+ const attributionPatterns = [
210
+ /^On .+ wrote:$/i,
211
+ /^On .+, .+ wrote:$/i,
212
+ /^.+ wrote:$/i,
213
+ /^-{3,}\s*Original Message\s*-{3,}$/i,
214
+ /^-{3,}\s*Forwarded message\s*-{3,}$/i,
215
+ /^From:\s*.+$/i,
216
+ /^Sent:\s*.+$/i
217
+ ];
218
+ return attributionPatterns.some((pattern) => pattern.test(line.trim()));
219
+ }
220
+ function extractEmailAddresses(text) {
221
+ const emailRegex = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g;
222
+ const matches = text.match(emailRegex) || [];
223
+ return [...new Set(matches)];
224
+ }
225
+ function extractUrls(text) {
226
+ const urlRegex = /https?:\/\/[^\s<>"\)]+/gi;
227
+ const matches = text.match(urlRegex) || [];
228
+ return [...new Set(matches)];
229
+ }
230
+ function extractPhoneNumbers(text) {
231
+ const phoneRegex = /(?:\+\d{1,3}[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}/g;
232
+ const matches = text.match(phoneRegex) || [];
233
+ return [...new Set(matches)];
234
+ }
235
+ function getEmailSummary(email) {
236
+ const fromAddr = email.from[0];
237
+ const fromDisplay = fromAddr ? fromAddr.name || fromAddr.address : "Unknown";
238
+ const snippet = "body" in email ? email.body.snippet : email.snippet || email.text.substring(0, 100);
239
+ const attachmentCount = "metadata" in email ? email.metadata.attachmentCount : email.attachments.length;
240
+ return {
241
+ from: fromDisplay,
242
+ subject: email.subject,
243
+ snippet,
244
+ date: formatEmailDate(email.date),
245
+ attachmentCount
246
+ };
247
+ }
248
+ function formatEmailDate(date) {
249
+ const now = /* @__PURE__ */ new Date();
250
+ const diff = now.getTime() - date.getTime();
251
+ const days = Math.floor(diff / (1e3 * 60 * 60 * 24));
252
+ if (days === 0) {
253
+ return date.toLocaleTimeString("en-US", {
254
+ hour: "numeric",
255
+ minute: "2-digit",
256
+ hour12: true
257
+ });
258
+ } else if (days === 1) {
259
+ return "Yesterday";
260
+ } else if (days < 7) {
261
+ return date.toLocaleDateString("en-US", { weekday: "short" });
262
+ } else if (date.getFullYear() === now.getFullYear()) {
263
+ return date.toLocaleDateString("en-US", { month: "short", day: "numeric" });
264
+ } else {
265
+ return date.toLocaleDateString("en-US", {
266
+ month: "short",
267
+ day: "numeric",
268
+ year: "numeric"
269
+ });
270
+ }
271
+ }
272
+ function calculateEmailSize(email) {
273
+ let size = 0;
274
+ size += new TextEncoder().encode(email.text).length;
275
+ size += new TextEncoder().encode(email.html).length;
276
+ size += new TextEncoder().encode(email.subject).length;
277
+ size += email.from.reduce((s, a) => s + (a.name?.length || 0) + a.address.length + 10, 0);
278
+ size += email.to.reduce((s, a) => s + (a.name?.length || 0) + a.address.length + 10, 0);
279
+ size += email.attachments.reduce((s, a) => s + a.size, 0);
280
+ return size;
281
+ }
282
+ function matchesFilter(email, filter) {
283
+ const parsed = "metadata" in email ? email : parseEmail(email);
284
+ if (filter.from) {
285
+ const fromMatch = parsed.from.some((addr) => {
286
+ const str = `${addr.name} ${addr.address}`;
287
+ return filter.from instanceof RegExp ? filter.from.test(str) : str.toLowerCase().includes(filter.from.toLowerCase());
288
+ });
289
+ if (!fromMatch) return false;
290
+ }
291
+ if (filter.to) {
292
+ const toMatch = parsed.to.some((addr) => {
293
+ const str = `${addr.name} ${addr.address}`;
294
+ return filter.to instanceof RegExp ? filter.to.test(str) : str.toLowerCase().includes(filter.to.toLowerCase());
295
+ });
296
+ if (!toMatch) return false;
297
+ }
298
+ if (filter.subject) {
299
+ const subjectMatch = filter.subject instanceof RegExp ? filter.subject.test(parsed.subject) : parsed.subject.toLowerCase().includes(filter.subject.toLowerCase());
300
+ if (!subjectMatch) return false;
301
+ }
302
+ if (filter.body) {
303
+ const bodyText = parsed.body.text;
304
+ const bodyMatch = filter.body instanceof RegExp ? filter.body.test(bodyText) : bodyText.toLowerCase().includes(filter.body.toLowerCase());
305
+ if (!bodyMatch) return false;
306
+ }
307
+ if (filter.hasAttachments !== void 0) {
308
+ if (parsed.metadata.hasAttachments !== filter.hasAttachments) return false;
309
+ }
310
+ if (filter.isUnread !== void 0) {
311
+ if (parsed.metadata.isRead === filter.isUnread) return false;
312
+ }
313
+ if (filter.isFlagged !== void 0) {
314
+ if (parsed.metadata.isFlagged !== filter.isFlagged) return false;
315
+ }
316
+ if (filter.dateAfter && parsed.date < filter.dateAfter) return false;
317
+ if (filter.dateBefore && parsed.date > filter.dateBefore) return false;
318
+ return true;
319
+ }
320
+
321
+ // src/integrations/email/inbox-summarizer.ts
322
+ var CATEGORIZATION_PROMPT = `You are an email categorization assistant. Analyze the following email and categorize it.
323
+
324
+ Categories:
325
+ - urgent: Time-sensitive, requires immediate attention
326
+ - action_required: Requires a response or action from the user
327
+ - informational: FYI, newsletters, updates that don't require action
328
+ - meeting: Calendar invites, meeting-related emails
329
+ - financial: Invoices, receipts, financial statements
330
+ - social: Personal emails, social notifications
331
+ - marketing: Promotional emails, newsletters
332
+ - support: Customer support, help desk emails
333
+ - work: Work-related emails that aren't urgent
334
+ - spam: Potential spam or unwanted emails
335
+
336
+ Email:
337
+ From: {{from}}
338
+ Subject: {{subject}}
339
+ Date: {{date}}
340
+ Snippet: {{snippet}}
341
+
342
+ Respond in JSON format:
343
+ {
344
+ "category": "category_name",
345
+ "confidence": 0.0-1.0,
346
+ "reason": "brief explanation"
347
+ }`;
348
+ var ACTION_EXTRACTION_PROMPT = `You are an email assistant that extracts action items. Analyze the following email and identify any actions the recipient needs to take.
349
+
350
+ Email:
351
+ From: {{from}}
352
+ Subject: {{subject}}
353
+ Date: {{date}}
354
+ Body: {{body}}
355
+
356
+ For each action item found, provide:
357
+ - action: A clear, concise description of what needs to be done
358
+ - priority: high (urgent/deadline), medium (important but not urgent), or low (when convenient)
359
+ - dueDate: If a specific date/time is mentioned (ISO format or null)
360
+ - context: Brief context from the email
361
+
362
+ Respond in JSON format:
363
+ {
364
+ "actions": [
365
+ {
366
+ "action": "description",
367
+ "priority": "high|medium|low",
368
+ "dueDate": "ISO date or null",
369
+ "context": "brief context"
370
+ }
371
+ ]
372
+ }
373
+
374
+ If no actions are required, return: { "actions": [] }`;
375
+ var INBOX_SUMMARY_PROMPT = `You are an email assistant providing a daily inbox summary. Based on the following email statistics and categories, provide a brief, helpful summary.
376
+
377
+ Statistics:
378
+ - Total emails: {{totalEmails}}
379
+ - Unread: {{unreadCount}}
380
+ - Important: {{importantCount}}
381
+
382
+ Categories:
383
+ {{categories}}
384
+
385
+ Urgent items:
386
+ {{urgentItems}}
387
+
388
+ Provide a 2-3 sentence summary that:
389
+ 1. Highlights the most important items requiring attention
390
+ 2. Notes any patterns or notable senders
391
+ 3. Suggests prioritization if there are many items
392
+
393
+ Keep it concise and actionable.`;
394
+ var THREAD_SUMMARY_PROMPT = `You are an email assistant that summarizes email threads. Analyze the following email thread and provide a comprehensive summary.
395
+
396
+ Thread: {{subject}}
397
+ Participants: {{participants}}
398
+ Messages: {{messageCount}}
399
+
400
+ Messages (oldest to newest):
401
+ {{messages}}
402
+
403
+ Provide a summary including:
404
+ 1. Brief summary of the entire conversation (2-3 sentences)
405
+ 2. Current status of the discussion
406
+ 3. Key decisions made (if any)
407
+ 4. Open questions that need resolution
408
+ 5. Suggested next steps
409
+
410
+ Respond in JSON format:
411
+ {
412
+ "summary": "conversation summary",
413
+ "currentStatus": "status description",
414
+ "keyDecisions": ["decision 1", "decision 2"],
415
+ "openQuestions": ["question 1", "question 2"],
416
+ "nextSteps": ["step 1", "step 2"]
417
+ }`;
418
+ async function categorizeEmail(email) {
419
+ const parsed = "metadata" in email ? email : parseEmail(email);
420
+ const fromDisplay = parsed.from[0] ? `${parsed.from[0].name || ""} <${parsed.from[0].address}>`.trim() : "Unknown";
421
+ const prompt = CATEGORIZATION_PROMPT.replace("{{from}}", fromDisplay).replace("{{subject}}", parsed.subject).replace("{{date}}", parsed.date.toISOString()).replace("{{snippet}}", parsed.body.snippet);
422
+ try {
423
+ const response = await chat(
424
+ [{ role: "user", content: prompt }],
425
+ "You are a helpful email categorization assistant. Always respond with valid JSON."
426
+ );
427
+ const result = JSON.parse(response.content);
428
+ return {
429
+ category: result.category || "informational",
430
+ confidence: result.confidence || 0.5,
431
+ reason: result.reason || ""
432
+ };
433
+ } catch (err) {
434
+ console.error("Failed to categorize email:", err);
435
+ return {
436
+ category: "informational",
437
+ confidence: 0.5,
438
+ reason: "Failed to categorize"
439
+ };
440
+ }
441
+ }
442
+ async function extractActionItems(email) {
443
+ const parsed = "metadata" in email ? email : parseEmail(email);
444
+ const fromDisplay = parsed.from[0] ? `${parsed.from[0].name || ""} <${parsed.from[0].address}>`.trim() : "Unknown";
445
+ const bodyParts = parseEmailBody(parsed.body.text);
446
+ const relevantBody = bodyParts.newContent || parsed.body.text.substring(0, 2e3);
447
+ const prompt = ACTION_EXTRACTION_PROMPT.replace("{{from}}", fromDisplay).replace("{{subject}}", parsed.subject).replace("{{date}}", parsed.date.toISOString()).replace("{{body}}", relevantBody);
448
+ try {
449
+ const response = await chat(
450
+ [{ role: "user", content: prompt }],
451
+ "You are a helpful email assistant that extracts action items. Always respond with valid JSON."
452
+ );
453
+ const result = JSON.parse(response.content);
454
+ return (result.actions || []).map((action) => ({
455
+ emailId: parsed.id,
456
+ subject: parsed.subject,
457
+ from: fromDisplay,
458
+ action: action.action,
459
+ priority: ["high", "medium", "low"].includes(action.priority) ? action.priority : "medium",
460
+ dueDate: action.dueDate ? new Date(action.dueDate) : void 0,
461
+ context: action.context
462
+ }));
463
+ } catch (err) {
464
+ console.error("Failed to extract action items:", err);
465
+ return [];
466
+ }
467
+ }
468
+ async function summarizeThread(thread) {
469
+ const participants = thread.participants.map((p) => p.name || p.address).slice(0, 10).join(", ");
470
+ const messageContent = thread.messages.slice(-10).map((msg, idx) => {
471
+ const from = msg.from[0]?.name || msg.from[0]?.address || "Unknown";
472
+ const bodyParts = parseEmailBody(msg.body.text);
473
+ const content = (bodyParts.newContent || msg.body.snippet).substring(0, 500);
474
+ return `[${idx + 1}] From: ${from}
475
+ Date: ${msg.date.toISOString()}
476
+ ${content}`;
477
+ }).join("\n\n---\n\n");
478
+ const prompt = THREAD_SUMMARY_PROMPT.replace("{{subject}}", thread.subject).replace("{{participants}}", participants).replace("{{messageCount}}", String(thread.messageCount)).replace("{{messages}}", messageContent);
479
+ try {
480
+ const response = await chat(
481
+ [{ role: "user", content: prompt }],
482
+ "You are a helpful email assistant that summarizes email threads. Always respond with valid JSON."
483
+ );
484
+ const result = JSON.parse(response.content);
485
+ return {
486
+ threadId: thread.id,
487
+ subject: thread.subject,
488
+ participantCount: thread.participants.length,
489
+ messageCount: thread.messageCount,
490
+ summary: result.summary || "No summary available",
491
+ currentStatus: result.currentStatus || "Unknown",
492
+ nextSteps: result.nextSteps || [],
493
+ keyDecisions: result.keyDecisions || [],
494
+ openQuestions: result.openQuestions || []
495
+ };
496
+ } catch (err) {
497
+ console.error("Failed to summarize thread:", err);
498
+ return {
499
+ threadId: thread.id,
500
+ subject: thread.subject,
501
+ participantCount: thread.participants.length,
502
+ messageCount: thread.messageCount,
503
+ summary: "Failed to generate summary",
504
+ currentStatus: "Unknown",
505
+ nextSteps: [],
506
+ keyDecisions: [],
507
+ openQuestions: []
508
+ };
509
+ }
510
+ }
511
+ async function summarizeInbox(emails) {
512
+ const parsedEmails = emails.map(parseEmail);
513
+ const categorizations = await Promise.all(
514
+ parsedEmails.slice(0, 100).map(async (email) => ({
515
+ email,
516
+ categorization: await categorizeEmail(email)
517
+ }))
518
+ );
519
+ const totalEmails = emails.length;
520
+ const unreadCount = parsedEmails.filter((e) => !e.metadata.isRead).length;
521
+ const importantCount = categorizations.filter(
522
+ (c) => c.categorization.category === "urgent" || c.categorization.category === "action_required"
523
+ ).length;
524
+ const categoryMap = /* @__PURE__ */ new Map();
525
+ for (const { email, categorization } of categorizations) {
526
+ const cat = categorization.category;
527
+ if (!categoryMap.has(cat)) {
528
+ categoryMap.set(cat, { emails: [], senders: /* @__PURE__ */ new Set() });
529
+ }
530
+ const entry = categoryMap.get(cat);
531
+ entry.emails.push(email);
532
+ if (email.from[0]) {
533
+ entry.senders.add(email.from[0].name || email.from[0].address);
534
+ }
535
+ }
536
+ const categories = [];
537
+ for (const [name, data] of categoryMap) {
538
+ categories.push({
539
+ name,
540
+ count: data.emails.length,
541
+ unreadCount: data.emails.filter((e) => !e.metadata.isRead).length,
542
+ topSenders: Array.from(data.senders).slice(0, 5),
543
+ description: getCategoryDescription(name)
544
+ });
545
+ }
546
+ categories.sort((a, b) => b.count - a.count);
547
+ const urgentItems = [];
548
+ for (const { email, categorization } of categorizations) {
549
+ if (categorization.category === "urgent") {
550
+ urgentItems.push({
551
+ emailId: email.id,
552
+ subject: email.subject,
553
+ from: email.from[0]?.name || email.from[0]?.address || "Unknown",
554
+ reason: categorization.reason,
555
+ suggestedAction: "Review and respond as soon as possible"
556
+ });
557
+ }
558
+ }
559
+ const actionItems = [];
560
+ const actionRequiredEmails = categorizations.filter((c) => c.categorization.category === "action_required").slice(0, 10);
561
+ for (const { email } of actionRequiredEmails) {
562
+ const items = await extractActionItems(email);
563
+ actionItems.push(...items);
564
+ }
565
+ actionItems.sort((a, b) => {
566
+ const priorityOrder = { high: 0, medium: 1, low: 2 };
567
+ return priorityOrder[a.priority] - priorityOrder[b.priority];
568
+ });
569
+ const categoriesText = categories.map((c) => `- ${c.name}: ${c.count} emails (${c.unreadCount} unread)`).join("\n");
570
+ const urgentText = urgentItems.length > 0 ? urgentItems.map((u) => `- "${u.subject}" from ${u.from}`).join("\n") : "None";
571
+ const summaryPrompt = INBOX_SUMMARY_PROMPT.replace("{{totalEmails}}", String(totalEmails)).replace("{{unreadCount}}", String(unreadCount)).replace("{{importantCount}}", String(importantCount)).replace("{{categories}}", categoriesText).replace("{{urgentItems}}", urgentText);
572
+ let summary = "";
573
+ try {
574
+ const response = await chat(
575
+ [{ role: "user", content: summaryPrompt }],
576
+ "You are a helpful email assistant providing inbox summaries. Be concise and actionable."
577
+ );
578
+ summary = response.content;
579
+ } catch (err) {
580
+ console.error("Failed to generate summary:", err);
581
+ summary = `You have ${totalEmails} emails, ${unreadCount} unread. ${importantCount} require attention.`;
582
+ }
583
+ return {
584
+ totalEmails,
585
+ unreadCount,
586
+ importantCount,
587
+ categories,
588
+ urgentItems,
589
+ actionItems: actionItems.slice(0, 20),
590
+ summary,
591
+ generatedAt: /* @__PURE__ */ new Date()
592
+ };
593
+ }
594
+ async function generateDailyDigest(emails) {
595
+ const summary = await summarizeInbox(emails);
596
+ let digest = `# Daily Email Digest
597
+
598
+ `;
599
+ digest += `*Generated: ${summary.generatedAt.toLocaleString()}*
600
+
601
+ `;
602
+ digest += `## Overview
603
+
604
+ `;
605
+ digest += `${summary.summary}
606
+
607
+ `;
608
+ digest += `- **Total Emails:** ${summary.totalEmails}
609
+ `;
610
+ digest += `- **Unread:** ${summary.unreadCount}
611
+ `;
612
+ digest += `- **Needs Attention:** ${summary.importantCount}
613
+
614
+ `;
615
+ if (summary.urgentItems.length > 0) {
616
+ digest += `## Urgent
617
+
618
+ `;
619
+ for (const item of summary.urgentItems) {
620
+ digest += `- **${item.subject}** from ${item.from}
621
+ `;
622
+ digest += ` *${item.reason}*
623
+
624
+ `;
625
+ }
626
+ }
627
+ if (summary.actionItems.length > 0) {
628
+ digest += `## Action Items
629
+
630
+ `;
631
+ for (const item of summary.actionItems) {
632
+ const priority = item.priority === "high" ? "!!!" : item.priority === "medium" ? "!!" : "!";
633
+ digest += `- [${priority}] **${item.action}**
634
+ `;
635
+ digest += ` From: ${item.from} | ${item.context}
636
+ `;
637
+ if (item.dueDate) {
638
+ digest += ` Due: ${item.dueDate.toLocaleDateString()}
639
+ `;
640
+ }
641
+ digest += "\n";
642
+ }
643
+ }
644
+ digest += `## By Category
645
+
646
+ `;
647
+ for (const cat of summary.categories.slice(0, 8)) {
648
+ digest += `- **${cat.name}:** ${cat.count} emails`;
649
+ if (cat.unreadCount > 0) {
650
+ digest += ` (${cat.unreadCount} unread)`;
651
+ }
652
+ digest += "\n";
653
+ if (cat.topSenders.length > 0) {
654
+ digest += ` Top senders: ${cat.topSenders.slice(0, 3).join(", ")}
655
+ `;
656
+ }
657
+ }
658
+ return digest;
659
+ }
660
+ async function suggestReplies(email) {
661
+ const parsed = "metadata" in email ? email : parseEmail(email);
662
+ const fromDisplay = parsed.from[0] ? `${parsed.from[0].name || ""} <${parsed.from[0].address}>`.trim() : "Unknown";
663
+ const bodyParts = parseEmailBody(parsed.body.text);
664
+ const relevantBody = (bodyParts.newContent || parsed.body.text).substring(0, 1500);
665
+ const prompt = `You are an email assistant suggesting reply options. Based on the following email, suggest 3 brief reply options ranging from formal to casual.
666
+
667
+ Email:
668
+ From: ${fromDisplay}
669
+ Subject: ${parsed.subject}
670
+ Body: ${relevantBody}
671
+
672
+ Provide 3 reply suggestions:
673
+ 1. A brief, professional response
674
+ 2. A friendly but complete response
675
+ 3. A quick, informal response
676
+
677
+ Respond in JSON format:
678
+ {
679
+ "replies": ["reply 1", "reply 2", "reply 3"]
680
+ }`;
681
+ try {
682
+ const response = await chat(
683
+ [{ role: "user", content: prompt }],
684
+ "You are a helpful email assistant. Always respond with valid JSON."
685
+ );
686
+ const result = JSON.parse(response.content);
687
+ return result.replies || [];
688
+ } catch (err) {
689
+ console.error("Failed to suggest replies:", err);
690
+ return [];
691
+ }
692
+ }
693
+ async function analyzeSentiment(email) {
694
+ const parsed = "metadata" in email ? email : parseEmail(email);
695
+ const bodyParts = parseEmailBody(parsed.body.text);
696
+ const relevantBody = (bodyParts.newContent || parsed.body.text).substring(0, 1500);
697
+ const prompt = `Analyze the sentiment and tone of this email:
698
+
699
+ Subject: ${parsed.subject}
700
+ Body: ${relevantBody}
701
+
702
+ Respond in JSON format:
703
+ {
704
+ "sentiment": "positive|negative|neutral",
705
+ "confidence": 0.0-1.0,
706
+ "tone": "brief description of tone (e.g., 'urgent', 'friendly', 'formal', 'frustrated')",
707
+ "keyPhrases": ["phrase1", "phrase2", "phrase3"]
708
+ }`;
709
+ try {
710
+ const response = await chat(
711
+ [{ role: "user", content: prompt }],
712
+ "You are a helpful sentiment analysis assistant. Always respond with valid JSON."
713
+ );
714
+ const result = JSON.parse(response.content);
715
+ return {
716
+ sentiment: result.sentiment || "neutral",
717
+ confidence: result.confidence || 0.5,
718
+ tone: result.tone || "neutral",
719
+ keyPhrases: result.keyPhrases || []
720
+ };
721
+ } catch (err) {
722
+ console.error("Failed to analyze sentiment:", err);
723
+ return {
724
+ sentiment: "neutral",
725
+ confidence: 0.5,
726
+ tone: "neutral",
727
+ keyPhrases: []
728
+ };
729
+ }
730
+ }
731
+ function getCategoryDescription(category) {
732
+ const descriptions = {
733
+ urgent: "Time-sensitive emails requiring immediate attention",
734
+ action_required: "Emails that need your response or action",
735
+ informational: "FYI emails and updates",
736
+ meeting: "Calendar invites and meeting-related emails",
737
+ financial: "Invoices, receipts, and financial communications",
738
+ social: "Personal and social notifications",
739
+ marketing: "Promotional emails and newsletters",
740
+ support: "Customer support and help desk communications",
741
+ work: "Work-related emails",
742
+ spam: "Potentially unwanted emails"
743
+ };
744
+ return descriptions[category] || "Other emails";
745
+ }
746
+ var inbox_summarizer_default = {
747
+ categorizeEmail,
748
+ extractActionItems,
749
+ summarizeThread,
750
+ summarizeInbox,
751
+ generateDailyDigest,
752
+ suggestReplies,
753
+ analyzeSentiment
754
+ };
755
+
756
+ export {
757
+ parseEmail,
758
+ parseAttachment,
759
+ groupIntoThreads,
760
+ cleanSubject,
761
+ parseEmailBody,
762
+ extractEmailAddresses,
763
+ extractUrls,
764
+ extractPhoneNumbers,
765
+ getEmailSummary,
766
+ calculateEmailSize,
767
+ matchesFilter,
768
+ categorizeEmail,
769
+ extractActionItems,
770
+ summarizeThread,
771
+ summarizeInbox,
772
+ generateDailyDigest,
773
+ suggestReplies,
774
+ analyzeSentiment,
775
+ inbox_summarizer_default
776
+ };
777
+ //# sourceMappingURL=chunk-SPPMCAKG.js.map