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 @@
1
+ {"version":3,"sources":["../src/integrations/email/email-parser.ts","../src/integrations/email/inbox-summarizer.ts"],"sourcesContent":["import type { EmailMessage, EmailAttachment, EmailAddress } from \"./imap-client\";\n\nexport interface ParsedEmail {\n id: string;\n subject: string;\n from: EmailAddress[];\n to: EmailAddress[];\n cc: EmailAddress[];\n date: Date;\n body: {\n text: string;\n html: string;\n snippet: string;\n };\n thread: ThreadInfo;\n attachments: ParsedAttachment[];\n metadata: EmailMetadata;\n}\n\nexport interface ThreadInfo {\n id: string;\n messageId: string;\n inReplyTo?: string;\n references: string[];\n position: number;\n isReply: boolean;\n isForward: boolean;\n}\n\nexport interface ParsedAttachment {\n filename: string;\n contentType: string;\n size: number;\n isInline: boolean;\n cid?: string;\n content?: Buffer;\n extension: string;\n category: \"image\" | \"document\" | \"archive\" | \"media\" | \"other\";\n}\n\nexport interface EmailMetadata {\n isRead: boolean;\n isFlagged: boolean;\n isSpam: boolean;\n isDraft: boolean;\n labels: string[];\n importance: \"high\" | \"normal\" | \"low\";\n hasAttachments: boolean;\n attachmentCount: number;\n totalAttachmentSize: number;\n}\n\nexport interface EmailThread {\n id: string;\n subject: string;\n participants: EmailAddress[];\n messageCount: number;\n unreadCount: number;\n lastMessageDate: Date;\n firstMessageDate: Date;\n messages: ParsedEmail[];\n snippet: string;\n}\n\nexport interface QuotedSection {\n level: number;\n content: string;\n attribution?: string;\n}\n\nexport interface EmailBodyParts {\n newContent: string;\n quotedContent: QuotedSection[];\n signature?: string;\n}\n\n/**\n * Parse an email message into a more structured format\n */\nexport function parseEmail(email: EmailMessage): ParsedEmail {\n const isReply = email.subject.toLowerCase().startsWith(\"re:\");\n const isForward = email.subject.toLowerCase().startsWith(\"fwd:\") ||\n email.subject.toLowerCase().startsWith(\"fw:\");\n\n // Calculate attachment metadata\n const attachments = email.attachments.map(att => parseAttachment(att));\n const totalAttachmentSize = attachments.reduce((sum, att) => sum + att.size, 0);\n\n // Determine importance from headers or flags\n let importance: \"high\" | \"normal\" | \"low\" = \"normal\";\n const importanceHeader = email.headers.get(\"importance\") ||\n email.headers.get(\"x-priority\");\n if (importanceHeader) {\n const lowerHeader = importanceHeader.toLowerCase();\n if (lowerHeader.includes(\"high\") || lowerHeader === \"1\" || lowerHeader === \"2\") {\n importance = \"high\";\n } else if (lowerHeader.includes(\"low\") || lowerHeader === \"5\") {\n importance = \"low\";\n }\n }\n\n return {\n id: email.id,\n subject: email.subject,\n from: email.from,\n to: email.to,\n cc: email.cc,\n date: email.date,\n body: {\n text: email.text,\n html: email.html,\n snippet: email.snippet || email.text.substring(0, 200).replace(/\\s+/g, \" \").trim(),\n },\n thread: {\n id: email.threadId || email.messageId,\n messageId: email.messageId,\n inReplyTo: email.inReplyTo,\n references: email.references,\n position: email.references.length,\n isReply,\n isForward,\n },\n attachments,\n metadata: {\n isRead: email.flags.includes(\"\\\\Seen\"),\n isFlagged: email.flags.includes(\"\\\\Flagged\"),\n isSpam: email.labels.includes(\"Spam\") || email.labels.includes(\"Junk\"),\n isDraft: email.flags.includes(\"\\\\Draft\"),\n labels: email.labels,\n importance,\n hasAttachments: attachments.length > 0,\n attachmentCount: attachments.length,\n totalAttachmentSize,\n },\n };\n}\n\n/**\n * Parse an attachment into structured format\n */\nexport function parseAttachment(attachment: EmailAttachment): ParsedAttachment {\n const extension = attachment.filename.includes(\".\")\n ? attachment.filename.split(\".\").pop()?.toLowerCase() || \"\"\n : \"\";\n\n return {\n filename: attachment.filename,\n contentType: attachment.contentType,\n size: attachment.size,\n isInline: !!attachment.contentId,\n cid: attachment.contentId,\n content: attachment.content,\n extension,\n category: categorizeAttachment(attachment.contentType, extension),\n };\n}\n\n/**\n * Categorize an attachment by its type\n */\nfunction categorizeAttachment(\n contentType: string,\n extension: string\n): \"image\" | \"document\" | \"archive\" | \"media\" | \"other\" {\n const lowerContentType = contentType.toLowerCase();\n\n // Images\n if (lowerContentType.startsWith(\"image/\")) {\n return \"image\";\n }\n\n // Documents\n const docExtensions = [\"pdf\", \"doc\", \"docx\", \"xls\", \"xlsx\", \"ppt\", \"pptx\", \"txt\", \"rtf\", \"odt\", \"ods\", \"odp\", \"csv\"];\n const docMimeTypes = [\n \"application/pdf\",\n \"application/msword\",\n \"application/vnd.openxmlformats\",\n \"application/vnd.ms-\",\n \"text/plain\",\n \"text/csv\",\n \"application/vnd.oasis.opendocument\",\n ];\n if (docExtensions.includes(extension) || docMimeTypes.some(m => lowerContentType.includes(m))) {\n return \"document\";\n }\n\n // Archives\n const archiveExtensions = [\"zip\", \"rar\", \"7z\", \"tar\", \"gz\", \"bz2\"];\n const archiveMimeTypes = [\"application/zip\", \"application/x-rar\", \"application/x-7z\", \"application/gzip\"];\n if (archiveExtensions.includes(extension) || archiveMimeTypes.some(m => lowerContentType.includes(m))) {\n return \"archive\";\n }\n\n // Media (audio/video)\n if (lowerContentType.startsWith(\"audio/\") || lowerContentType.startsWith(\"video/\")) {\n return \"media\";\n }\n\n return \"other\";\n}\n\n/**\n * Group emails into threads\n */\nexport function groupIntoThreads(emails: EmailMessage[]): EmailThread[] {\n const threadMap = new Map<string, EmailMessage[]>();\n\n // Group by thread ID (using references chain or Message-ID)\n for (const email of emails) {\n // Find the root message ID for this thread\n let threadId = email.threadId || email.messageId;\n\n if (email.references.length > 0) {\n // Use the first reference as the thread root\n threadId = email.references[0];\n }\n\n if (!threadMap.has(threadId)) {\n threadMap.set(threadId, []);\n }\n threadMap.get(threadId)!.push(email);\n }\n\n // Convert to EmailThread objects\n const threads: EmailThread[] = [];\n\n for (const [threadId, messages] of threadMap) {\n // Sort messages by date (oldest first)\n messages.sort((a, b) => a.date.getTime() - b.date.getTime());\n\n // Collect all participants\n const participantMap = new Map<string, EmailAddress>();\n for (const msg of messages) {\n for (const addr of [...msg.from, ...msg.to, ...msg.cc]) {\n if (!participantMap.has(addr.address)) {\n participantMap.set(addr.address, addr);\n }\n }\n }\n\n // Count unread\n const unreadCount = messages.filter(m => !m.flags.includes(\"\\\\Seen\")).length;\n\n // Get the subject (use the original, non-reply subject if possible)\n let subject = messages[0].subject;\n for (const msg of messages) {\n const cleaned = cleanSubject(msg.subject);\n if (cleaned.length > 0 && !cleaned.toLowerCase().startsWith(\"re:\")) {\n subject = msg.subject;\n break;\n }\n }\n\n threads.push({\n id: threadId,\n subject: cleanSubject(subject),\n participants: Array.from(participantMap.values()),\n messageCount: messages.length,\n unreadCount,\n lastMessageDate: messages[messages.length - 1].date,\n firstMessageDate: messages[0].date,\n messages: messages.map(parseEmail),\n snippet: messages[messages.length - 1].snippet ||\n messages[messages.length - 1].text.substring(0, 200).replace(/\\s+/g, \" \").trim(),\n });\n }\n\n // Sort threads by last message date (newest first)\n threads.sort((a, b) => b.lastMessageDate.getTime() - a.lastMessageDate.getTime());\n\n return threads;\n}\n\n/**\n * Clean a subject line (remove Re:, Fwd:, etc.)\n */\nexport function cleanSubject(subject: string): string {\n return subject\n .replace(/^(Re|Fwd|Fw):\\s*/gi, \"\")\n .replace(/^\\[.*?\\]\\s*/, \"\") // Remove list prefixes like [ListName]\n .trim();\n}\n\n/**\n * Parse email body to separate new content from quoted sections\n */\nexport function parseEmailBody(text: string): EmailBodyParts {\n const lines = text.split(\"\\n\");\n const newLines: string[] = [];\n const quotedSections: QuotedSection[] = [];\n let currentQuote: { level: number; lines: string[]; attribution?: string } | null = null;\n let signature: string | undefined;\n let inSignature = false;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n\n // Check for signature delimiter\n if (line.trim() === \"--\" || line.trim() === \"-- \") {\n inSignature = true;\n signature = lines.slice(i + 1).join(\"\\n\").trim();\n break;\n }\n\n // Check for quote markers\n const quoteMatch = line.match(/^(>+)\\s?/);\n\n if (quoteMatch) {\n const level = quoteMatch[1].length;\n const content = line.substring(quoteMatch[0].length);\n\n if (!currentQuote || currentQuote.level !== level) {\n // Save previous quote section\n if (currentQuote) {\n quotedSections.push({\n level: currentQuote.level,\n content: currentQuote.lines.join(\"\\n\"),\n attribution: currentQuote.attribution,\n });\n }\n currentQuote = { level, lines: [content] };\n } else {\n currentQuote.lines.push(content);\n }\n } else if (isAttributionLine(line)) {\n // This is an attribution line like \"On Date, Person wrote:\"\n if (currentQuote) {\n currentQuote.attribution = line;\n } else {\n // Start of a new quoted section\n currentQuote = { level: 1, lines: [], attribution: line };\n }\n } else {\n // Regular line\n if (currentQuote) {\n quotedSections.push({\n level: currentQuote.level,\n content: currentQuote.lines.join(\"\\n\"),\n attribution: currentQuote.attribution,\n });\n currentQuote = null;\n }\n newLines.push(line);\n }\n }\n\n // Don't forget the last quote section\n if (currentQuote) {\n quotedSections.push({\n level: currentQuote.level,\n content: currentQuote.lines.join(\"\\n\"),\n attribution: currentQuote.attribution,\n });\n }\n\n return {\n newContent: newLines.join(\"\\n\").trim(),\n quotedContent: quotedSections,\n signature,\n };\n}\n\n/**\n * Check if a line is an email attribution (e.g., \"On Jan 1, Person wrote:\")\n */\nfunction isAttributionLine(line: string): boolean {\n const attributionPatterns = [\n /^On .+ wrote:$/i,\n /^On .+, .+ wrote:$/i,\n /^.+ wrote:$/i,\n /^-{3,}\\s*Original Message\\s*-{3,}$/i,\n /^-{3,}\\s*Forwarded message\\s*-{3,}$/i,\n /^From:\\s*.+$/i,\n /^Sent:\\s*.+$/i,\n ];\n\n return attributionPatterns.some(pattern => pattern.test(line.trim()));\n}\n\n/**\n * Extract email addresses from a text string\n */\nexport function extractEmailAddresses(text: string): string[] {\n const emailRegex = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}/g;\n const matches = text.match(emailRegex) || [];\n return [...new Set(matches)];\n}\n\n/**\n * Extract URLs from email text\n */\nexport function extractUrls(text: string): string[] {\n const urlRegex = /https?:\\/\\/[^\\s<>\"\\)]+/gi;\n const matches = text.match(urlRegex) || [];\n return [...new Set(matches)];\n}\n\n/**\n * Extract phone numbers from email text\n */\nexport function extractPhoneNumbers(text: string): string[] {\n const phoneRegex = /(?:\\+\\d{1,3}[-.\\s]?)?\\(?\\d{3}\\)?[-.\\s]?\\d{3}[-.\\s]?\\d{4}/g;\n const matches = text.match(phoneRegex) || [];\n return [...new Set(matches)];\n}\n\n/**\n * Get a summary of an email suitable for display\n */\nexport function getEmailSummary(email: EmailMessage | ParsedEmail): {\n from: string;\n subject: string;\n snippet: string;\n date: string;\n attachmentCount: number;\n} {\n const fromAddr = email.from[0];\n const fromDisplay = fromAddr\n ? fromAddr.name || fromAddr.address\n : \"Unknown\";\n\n const snippet = \"body\" in email\n ? email.body.snippet\n : email.snippet || email.text.substring(0, 100);\n\n const attachmentCount = \"metadata\" in email\n ? email.metadata.attachmentCount\n : email.attachments.length;\n\n return {\n from: fromDisplay,\n subject: email.subject,\n snippet,\n date: formatEmailDate(email.date),\n attachmentCount,\n };\n}\n\n/**\n * Format a date for email display\n */\nfunction formatEmailDate(date: Date): string {\n const now = new Date();\n const diff = now.getTime() - date.getTime();\n const days = Math.floor(diff / (1000 * 60 * 60 * 24));\n\n if (days === 0) {\n // Today - show time\n return date.toLocaleTimeString(\"en-US\", {\n hour: \"numeric\",\n minute: \"2-digit\",\n hour12: true,\n });\n } else if (days === 1) {\n return \"Yesterday\";\n } else if (days < 7) {\n // This week - show day name\n return date.toLocaleDateString(\"en-US\", { weekday: \"short\" });\n } else if (date.getFullYear() === now.getFullYear()) {\n // This year - show month and day\n return date.toLocaleDateString(\"en-US\", { month: \"short\", day: \"numeric\" });\n } else {\n // Older - show full date\n return date.toLocaleDateString(\"en-US\", {\n month: \"short\",\n day: \"numeric\",\n year: \"numeric\",\n });\n }\n}\n\n/**\n * Calculate the size of an email in bytes\n */\nexport function calculateEmailSize(email: EmailMessage): number {\n let size = 0;\n\n // Text content\n size += new TextEncoder().encode(email.text).length;\n size += new TextEncoder().encode(email.html).length;\n\n // Headers (estimate)\n size += new TextEncoder().encode(email.subject).length;\n size += email.from.reduce((s, a) => s + (a.name?.length || 0) + a.address.length + 10, 0);\n size += email.to.reduce((s, a) => s + (a.name?.length || 0) + a.address.length + 10, 0);\n\n // Attachments\n size += email.attachments.reduce((s, a) => s + a.size, 0);\n\n return size;\n}\n\n/**\n * Check if an email matches a filter\n */\nexport function matchesFilter(\n email: EmailMessage | ParsedEmail,\n filter: {\n from?: string | RegExp;\n to?: string | RegExp;\n subject?: string | RegExp;\n body?: string | RegExp;\n hasAttachments?: boolean;\n isUnread?: boolean;\n isFlagged?: boolean;\n dateAfter?: Date;\n dateBefore?: Date;\n }\n): boolean {\n const parsed = \"metadata\" in email ? email : parseEmail(email);\n\n // Check from\n if (filter.from) {\n const fromMatch = parsed.from.some(addr => {\n const str = `${addr.name} ${addr.address}`;\n return filter.from instanceof RegExp\n ? filter.from.test(str)\n : str.toLowerCase().includes(filter.from.toLowerCase());\n });\n if (!fromMatch) return false;\n }\n\n // Check to\n if (filter.to) {\n const toMatch = parsed.to.some(addr => {\n const str = `${addr.name} ${addr.address}`;\n return filter.to instanceof RegExp\n ? filter.to.test(str)\n : str.toLowerCase().includes(filter.to.toLowerCase());\n });\n if (!toMatch) return false;\n }\n\n // Check subject\n if (filter.subject) {\n const subjectMatch = filter.subject instanceof RegExp\n ? filter.subject.test(parsed.subject)\n : parsed.subject.toLowerCase().includes(filter.subject.toLowerCase());\n if (!subjectMatch) return false;\n }\n\n // Check body\n if (filter.body) {\n const bodyText = parsed.body.text;\n const bodyMatch = filter.body instanceof RegExp\n ? filter.body.test(bodyText)\n : bodyText.toLowerCase().includes(filter.body.toLowerCase());\n if (!bodyMatch) return false;\n }\n\n // Check attachments\n if (filter.hasAttachments !== undefined) {\n if (parsed.metadata.hasAttachments !== filter.hasAttachments) return false;\n }\n\n // Check read status\n if (filter.isUnread !== undefined) {\n if (parsed.metadata.isRead === filter.isUnread) return false;\n }\n\n // Check flagged status\n if (filter.isFlagged !== undefined) {\n if (parsed.metadata.isFlagged !== filter.isFlagged) return false;\n }\n\n // Check date range\n if (filter.dateAfter && parsed.date < filter.dateAfter) return false;\n if (filter.dateBefore && parsed.date > filter.dateBefore) return false;\n\n return true;\n}\n\nexport default {\n parseEmail,\n parseAttachment,\n groupIntoThreads,\n cleanSubject,\n parseEmailBody,\n extractEmailAddresses,\n extractUrls,\n extractPhoneNumbers,\n getEmailSummary,\n calculateEmailSize,\n matchesFilter,\n};\n","import { chat } from \"../../core/brain\";\nimport type { EmailMessage } from \"./imap-client\";\nimport { parseEmail, groupIntoThreads, cleanSubject, parseEmailBody } from \"./email-parser\";\nimport type { ParsedEmail, EmailThread } from \"./email-parser\";\n\nexport interface InboxSummary {\n totalEmails: number;\n unreadCount: number;\n importantCount: number;\n categories: CategorySummary[];\n urgentItems: UrgentItem[];\n actionItems: ActionItem[];\n summary: string;\n generatedAt: Date;\n}\n\nexport interface CategorySummary {\n name: string;\n count: number;\n unreadCount: number;\n topSenders: string[];\n description: string;\n}\n\nexport interface UrgentItem {\n emailId: string;\n subject: string;\n from: string;\n reason: string;\n suggestedAction: string;\n}\n\nexport interface ActionItem {\n emailId: string;\n subject: string;\n from: string;\n action: string;\n priority: \"high\" | \"medium\" | \"low\";\n dueDate?: Date;\n context: string;\n}\n\nexport interface EmailCategorization {\n category: string;\n confidence: number;\n reason: string;\n}\n\nexport interface ThreadSummary {\n threadId: string;\n subject: string;\n participantCount: number;\n messageCount: number;\n summary: string;\n currentStatus: string;\n nextSteps: string[];\n keyDecisions: string[];\n openQuestions: string[];\n}\n\nconst CATEGORIZATION_PROMPT = `You are an email categorization assistant. Analyze the following email and categorize it.\n\nCategories:\n- urgent: Time-sensitive, requires immediate attention\n- action_required: Requires a response or action from the user\n- informational: FYI, newsletters, updates that don't require action\n- meeting: Calendar invites, meeting-related emails\n- financial: Invoices, receipts, financial statements\n- social: Personal emails, social notifications\n- marketing: Promotional emails, newsletters\n- support: Customer support, help desk emails\n- work: Work-related emails that aren't urgent\n- spam: Potential spam or unwanted emails\n\nEmail:\nFrom: {{from}}\nSubject: {{subject}}\nDate: {{date}}\nSnippet: {{snippet}}\n\nRespond in JSON format:\n{\n \"category\": \"category_name\",\n \"confidence\": 0.0-1.0,\n \"reason\": \"brief explanation\"\n}`;\n\nconst ACTION_EXTRACTION_PROMPT = `You are an email assistant that extracts action items. Analyze the following email and identify any actions the recipient needs to take.\n\nEmail:\nFrom: {{from}}\nSubject: {{subject}}\nDate: {{date}}\nBody: {{body}}\n\nFor each action item found, provide:\n- action: A clear, concise description of what needs to be done\n- priority: high (urgent/deadline), medium (important but not urgent), or low (when convenient)\n- dueDate: If a specific date/time is mentioned (ISO format or null)\n- context: Brief context from the email\n\nRespond in JSON format:\n{\n \"actions\": [\n {\n \"action\": \"description\",\n \"priority\": \"high|medium|low\",\n \"dueDate\": \"ISO date or null\",\n \"context\": \"brief context\"\n }\n ]\n}\n\nIf no actions are required, return: { \"actions\": [] }`;\n\nconst INBOX_SUMMARY_PROMPT = `You are an email assistant providing a daily inbox summary. Based on the following email statistics and categories, provide a brief, helpful summary.\n\nStatistics:\n- Total emails: {{totalEmails}}\n- Unread: {{unreadCount}}\n- Important: {{importantCount}}\n\nCategories:\n{{categories}}\n\nUrgent items:\n{{urgentItems}}\n\nProvide a 2-3 sentence summary that:\n1. Highlights the most important items requiring attention\n2. Notes any patterns or notable senders\n3. Suggests prioritization if there are many items\n\nKeep it concise and actionable.`;\n\nconst THREAD_SUMMARY_PROMPT = `You are an email assistant that summarizes email threads. Analyze the following email thread and provide a comprehensive summary.\n\nThread: {{subject}}\nParticipants: {{participants}}\nMessages: {{messageCount}}\n\nMessages (oldest to newest):\n{{messages}}\n\nProvide a summary including:\n1. Brief summary of the entire conversation (2-3 sentences)\n2. Current status of the discussion\n3. Key decisions made (if any)\n4. Open questions that need resolution\n5. Suggested next steps\n\nRespond in JSON format:\n{\n \"summary\": \"conversation summary\",\n \"currentStatus\": \"status description\",\n \"keyDecisions\": [\"decision 1\", \"decision 2\"],\n \"openQuestions\": [\"question 1\", \"question 2\"],\n \"nextSteps\": [\"step 1\", \"step 2\"]\n}`;\n\n/**\n * Categorize a single email using AI\n */\nexport async function categorizeEmail(email: EmailMessage | ParsedEmail): Promise<EmailCategorization> {\n const parsed = \"metadata\" in email ? email : parseEmail(email);\n\n const fromDisplay = parsed.from[0]\n ? `${parsed.from[0].name || \"\"} <${parsed.from[0].address}>`.trim()\n : \"Unknown\";\n\n const prompt = CATEGORIZATION_PROMPT\n .replace(\"{{from}}\", fromDisplay)\n .replace(\"{{subject}}\", parsed.subject)\n .replace(\"{{date}}\", parsed.date.toISOString())\n .replace(\"{{snippet}}\", parsed.body.snippet);\n\n try {\n const response = await chat(\n [{ role: \"user\", content: prompt }],\n \"You are a helpful email categorization assistant. Always respond with valid JSON.\"\n );\n\n const result = JSON.parse(response.content);\n return {\n category: result.category || \"informational\",\n confidence: result.confidence || 0.5,\n reason: result.reason || \"\",\n };\n } catch (err) {\n console.error(\"Failed to categorize email:\", err);\n return {\n category: \"informational\",\n confidence: 0.5,\n reason: \"Failed to categorize\",\n };\n }\n}\n\n/**\n * Extract action items from an email using AI\n */\nexport async function extractActionItems(email: EmailMessage | ParsedEmail): Promise<ActionItem[]> {\n const parsed = \"metadata\" in email ? email : parseEmail(email);\n\n const fromDisplay = parsed.from[0]\n ? `${parsed.from[0].name || \"\"} <${parsed.from[0].address}>`.trim()\n : \"Unknown\";\n\n // Parse the email body to get just the new content (not quoted parts)\n const bodyParts = parseEmailBody(parsed.body.text);\n const relevantBody = bodyParts.newContent || parsed.body.text.substring(0, 2000);\n\n const prompt = ACTION_EXTRACTION_PROMPT\n .replace(\"{{from}}\", fromDisplay)\n .replace(\"{{subject}}\", parsed.subject)\n .replace(\"{{date}}\", parsed.date.toISOString())\n .replace(\"{{body}}\", relevantBody);\n\n try {\n const response = await chat(\n [{ role: \"user\", content: prompt }],\n \"You are a helpful email assistant that extracts action items. Always respond with valid JSON.\"\n );\n\n const result = JSON.parse(response.content);\n\n return (result.actions || []).map((action: {\n action: string;\n priority: string;\n dueDate?: string | null;\n context: string;\n }) => ({\n emailId: parsed.id,\n subject: parsed.subject,\n from: fromDisplay,\n action: action.action,\n priority: ([\"high\", \"medium\", \"low\"].includes(action.priority) ? action.priority : \"medium\") as \"high\" | \"medium\" | \"low\",\n dueDate: action.dueDate ? new Date(action.dueDate) : undefined,\n context: action.context,\n }));\n } catch (err) {\n console.error(\"Failed to extract action items:\", err);\n return [];\n }\n}\n\n/**\n * Summarize an email thread using AI\n */\nexport async function summarizeThread(thread: EmailThread): Promise<ThreadSummary> {\n const participants = thread.participants\n .map(p => p.name || p.address)\n .slice(0, 10)\n .join(\", \");\n\n // Build message content (limited to avoid token limits)\n const messageContent = thread.messages\n .slice(-10) // Last 10 messages\n .map((msg, idx) => {\n const from = msg.from[0]?.name || msg.from[0]?.address || \"Unknown\";\n const bodyParts = parseEmailBody(msg.body.text);\n const content = (bodyParts.newContent || msg.body.snippet).substring(0, 500);\n return `[${idx + 1}] From: ${from}\\nDate: ${msg.date.toISOString()}\\n${content}`;\n })\n .join(\"\\n\\n---\\n\\n\");\n\n const prompt = THREAD_SUMMARY_PROMPT\n .replace(\"{{subject}}\", thread.subject)\n .replace(\"{{participants}}\", participants)\n .replace(\"{{messageCount}}\", String(thread.messageCount))\n .replace(\"{{messages}}\", messageContent);\n\n try {\n const response = await chat(\n [{ role: \"user\", content: prompt }],\n \"You are a helpful email assistant that summarizes email threads. Always respond with valid JSON.\"\n );\n\n const result = JSON.parse(response.content);\n\n return {\n threadId: thread.id,\n subject: thread.subject,\n participantCount: thread.participants.length,\n messageCount: thread.messageCount,\n summary: result.summary || \"No summary available\",\n currentStatus: result.currentStatus || \"Unknown\",\n nextSteps: result.nextSteps || [],\n keyDecisions: result.keyDecisions || [],\n openQuestions: result.openQuestions || [],\n };\n } catch (err) {\n console.error(\"Failed to summarize thread:\", err);\n return {\n threadId: thread.id,\n subject: thread.subject,\n participantCount: thread.participants.length,\n messageCount: thread.messageCount,\n summary: \"Failed to generate summary\",\n currentStatus: \"Unknown\",\n nextSteps: [],\n keyDecisions: [],\n openQuestions: [],\n };\n }\n}\n\n/**\n * Generate a comprehensive inbox summary\n */\nexport async function summarizeInbox(emails: EmailMessage[]): Promise<InboxSummary> {\n // Parse and categorize all emails\n const parsedEmails = emails.map(parseEmail);\n const categorizations = await Promise.all(\n parsedEmails.slice(0, 100).map(async email => ({\n email,\n categorization: await categorizeEmail(email),\n }))\n );\n\n // Count statistics\n const totalEmails = emails.length;\n const unreadCount = parsedEmails.filter(e => !e.metadata.isRead).length;\n const importantCount = categorizations.filter(\n c => c.categorization.category === \"urgent\" || c.categorization.category === \"action_required\"\n ).length;\n\n // Group by category\n const categoryMap = new Map<string, { emails: ParsedEmail[]; senders: Set<string> }>();\n\n for (const { email, categorization } of categorizations) {\n const cat = categorization.category;\n if (!categoryMap.has(cat)) {\n categoryMap.set(cat, { emails: [], senders: new Set() });\n }\n const entry = categoryMap.get(cat)!;\n entry.emails.push(email);\n if (email.from[0]) {\n entry.senders.add(email.from[0].name || email.from[0].address);\n }\n }\n\n const categories: CategorySummary[] = [];\n for (const [name, data] of categoryMap) {\n categories.push({\n name,\n count: data.emails.length,\n unreadCount: data.emails.filter(e => !e.metadata.isRead).length,\n topSenders: Array.from(data.senders).slice(0, 5),\n description: getCategoryDescription(name),\n });\n }\n\n // Sort categories by count\n categories.sort((a, b) => b.count - a.count);\n\n // Identify urgent items\n const urgentItems: UrgentItem[] = [];\n for (const { email, categorization } of categorizations) {\n if (categorization.category === \"urgent\") {\n urgentItems.push({\n emailId: email.id,\n subject: email.subject,\n from: email.from[0]?.name || email.from[0]?.address || \"Unknown\",\n reason: categorization.reason,\n suggestedAction: \"Review and respond as soon as possible\",\n });\n }\n }\n\n // Extract action items from action_required emails\n const actionItems: ActionItem[] = [];\n const actionRequiredEmails = categorizations\n .filter(c => c.categorization.category === \"action_required\")\n .slice(0, 10);\n\n for (const { email } of actionRequiredEmails) {\n const items = await extractActionItems(email);\n actionItems.push(...items);\n }\n\n // Sort action items by priority\n actionItems.sort((a, b) => {\n const priorityOrder = { high: 0, medium: 1, low: 2 };\n return priorityOrder[a.priority] - priorityOrder[b.priority];\n });\n\n // Generate summary text\n const categoriesText = categories\n .map(c => `- ${c.name}: ${c.count} emails (${c.unreadCount} unread)`)\n .join(\"\\n\");\n\n const urgentText = urgentItems.length > 0\n ? urgentItems.map(u => `- \"${u.subject}\" from ${u.from}`).join(\"\\n\")\n : \"None\";\n\n const summaryPrompt = INBOX_SUMMARY_PROMPT\n .replace(\"{{totalEmails}}\", String(totalEmails))\n .replace(\"{{unreadCount}}\", String(unreadCount))\n .replace(\"{{importantCount}}\", String(importantCount))\n .replace(\"{{categories}}\", categoriesText)\n .replace(\"{{urgentItems}}\", urgentText);\n\n let summary = \"\";\n try {\n const response = await chat(\n [{ role: \"user\", content: summaryPrompt }],\n \"You are a helpful email assistant providing inbox summaries. Be concise and actionable.\"\n );\n summary = response.content;\n } catch (err) {\n console.error(\"Failed to generate summary:\", err);\n summary = `You have ${totalEmails} emails, ${unreadCount} unread. ${importantCount} require attention.`;\n }\n\n return {\n totalEmails,\n unreadCount,\n importantCount,\n categories,\n urgentItems,\n actionItems: actionItems.slice(0, 20),\n summary,\n generatedAt: new Date(),\n };\n}\n\n/**\n * Generate a daily digest summary\n */\nexport async function generateDailyDigest(emails: EmailMessage[]): Promise<string> {\n const summary = await summarizeInbox(emails);\n\n let digest = `# Daily Email Digest\\n\\n`;\n digest += `*Generated: ${summary.generatedAt.toLocaleString()}*\\n\\n`;\n\n // Overview\n digest += `## Overview\\n\\n`;\n digest += `${summary.summary}\\n\\n`;\n digest += `- **Total Emails:** ${summary.totalEmails}\\n`;\n digest += `- **Unread:** ${summary.unreadCount}\\n`;\n digest += `- **Needs Attention:** ${summary.importantCount}\\n\\n`;\n\n // Urgent items\n if (summary.urgentItems.length > 0) {\n digest += `## Urgent\\n\\n`;\n for (const item of summary.urgentItems) {\n digest += `- **${item.subject}** from ${item.from}\\n`;\n digest += ` *${item.reason}*\\n\\n`;\n }\n }\n\n // Action items\n if (summary.actionItems.length > 0) {\n digest += `## Action Items\\n\\n`;\n for (const item of summary.actionItems) {\n const priority = item.priority === \"high\" ? \"!!!\" : item.priority === \"medium\" ? \"!!\" : \"!\";\n digest += `- [${priority}] **${item.action}**\\n`;\n digest += ` From: ${item.from} | ${item.context}\\n`;\n if (item.dueDate) {\n digest += ` Due: ${item.dueDate.toLocaleDateString()}\\n`;\n }\n digest += \"\\n\";\n }\n }\n\n // Categories breakdown\n digest += `## By Category\\n\\n`;\n for (const cat of summary.categories.slice(0, 8)) {\n digest += `- **${cat.name}:** ${cat.count} emails`;\n if (cat.unreadCount > 0) {\n digest += ` (${cat.unreadCount} unread)`;\n }\n digest += \"\\n\";\n if (cat.topSenders.length > 0) {\n digest += ` Top senders: ${cat.topSenders.slice(0, 3).join(\", \")}\\n`;\n }\n }\n\n return digest;\n}\n\n/**\n * Smart reply suggestions for an email\n */\nexport async function suggestReplies(email: EmailMessage | ParsedEmail): Promise<string[]> {\n const parsed = \"metadata\" in email ? email : parseEmail(email);\n\n const fromDisplay = parsed.from[0]\n ? `${parsed.from[0].name || \"\"} <${parsed.from[0].address}>`.trim()\n : \"Unknown\";\n\n const bodyParts = parseEmailBody(parsed.body.text);\n const relevantBody = (bodyParts.newContent || parsed.body.text).substring(0, 1500);\n\n const prompt = `You are an email assistant suggesting reply options. Based on the following email, suggest 3 brief reply options ranging from formal to casual.\n\nEmail:\nFrom: ${fromDisplay}\nSubject: ${parsed.subject}\nBody: ${relevantBody}\n\nProvide 3 reply suggestions:\n1. A brief, professional response\n2. A friendly but complete response\n3. A quick, informal response\n\nRespond in JSON format:\n{\n \"replies\": [\"reply 1\", \"reply 2\", \"reply 3\"]\n}`;\n\n try {\n const response = await chat(\n [{ role: \"user\", content: prompt }],\n \"You are a helpful email assistant. Always respond with valid JSON.\"\n );\n\n const result = JSON.parse(response.content);\n return result.replies || [];\n } catch (err) {\n console.error(\"Failed to suggest replies:\", err);\n return [];\n }\n}\n\n/**\n * Analyze email sentiment\n */\nexport async function analyzeSentiment(email: EmailMessage | ParsedEmail): Promise<{\n sentiment: \"positive\" | \"negative\" | \"neutral\";\n confidence: number;\n tone: string;\n keyPhrases: string[];\n}> {\n const parsed = \"metadata\" in email ? email : parseEmail(email);\n\n const bodyParts = parseEmailBody(parsed.body.text);\n const relevantBody = (bodyParts.newContent || parsed.body.text).substring(0, 1500);\n\n const prompt = `Analyze the sentiment and tone of this email:\n\nSubject: ${parsed.subject}\nBody: ${relevantBody}\n\nRespond in JSON format:\n{\n \"sentiment\": \"positive|negative|neutral\",\n \"confidence\": 0.0-1.0,\n \"tone\": \"brief description of tone (e.g., 'urgent', 'friendly', 'formal', 'frustrated')\",\n \"keyPhrases\": [\"phrase1\", \"phrase2\", \"phrase3\"]\n}`;\n\n try {\n const response = await chat(\n [{ role: \"user\", content: prompt }],\n \"You are a helpful sentiment analysis assistant. Always respond with valid JSON.\"\n );\n\n const result = JSON.parse(response.content);\n return {\n sentiment: result.sentiment || \"neutral\",\n confidence: result.confidence || 0.5,\n tone: result.tone || \"neutral\",\n keyPhrases: result.keyPhrases || [],\n };\n } catch (err) {\n console.error(\"Failed to analyze sentiment:\", err);\n return {\n sentiment: \"neutral\",\n confidence: 0.5,\n tone: \"neutral\",\n keyPhrases: [],\n };\n }\n}\n\n/**\n * Get description for a category\n */\nfunction getCategoryDescription(category: string): string {\n const descriptions: Record<string, string> = {\n urgent: \"Time-sensitive emails requiring immediate attention\",\n action_required: \"Emails that need your response or action\",\n informational: \"FYI emails and updates\",\n meeting: \"Calendar invites and meeting-related emails\",\n financial: \"Invoices, receipts, and financial communications\",\n social: \"Personal and social notifications\",\n marketing: \"Promotional emails and newsletters\",\n support: \"Customer support and help desk communications\",\n work: \"Work-related emails\",\n spam: \"Potentially unwanted emails\",\n };\n return descriptions[category] || \"Other emails\";\n}\n\nexport default {\n categorizeEmail,\n extractActionItems,\n summarizeThread,\n summarizeInbox,\n generateDailyDigest,\n suggestReplies,\n analyzeSentiment,\n};\n"],"mappings":";;;;;AA+EO,SAAS,WAAW,OAAkC;AAC3D,QAAM,UAAU,MAAM,QAAQ,YAAY,EAAE,WAAW,KAAK;AAC5D,QAAM,YAAY,MAAM,QAAQ,YAAY,EAAE,WAAW,MAAM,KAC7C,MAAM,QAAQ,YAAY,EAAE,WAAW,KAAK;AAG9D,QAAM,cAAc,MAAM,YAAY,IAAI,SAAO,gBAAgB,GAAG,CAAC;AACrE,QAAM,sBAAsB,YAAY,OAAO,CAAC,KAAK,QAAQ,MAAM,IAAI,MAAM,CAAC;AAG9E,MAAI,aAAwC;AAC5C,QAAM,mBAAmB,MAAM,QAAQ,IAAI,YAAY,KAC9B,MAAM,QAAQ,IAAI,YAAY;AACvD,MAAI,kBAAkB;AACpB,UAAM,cAAc,iBAAiB,YAAY;AACjD,QAAI,YAAY,SAAS,MAAM,KAAK,gBAAgB,OAAO,gBAAgB,KAAK;AAC9E,mBAAa;AAAA,IACf,WAAW,YAAY,SAAS,KAAK,KAAK,gBAAgB,KAAK;AAC7D,mBAAa;AAAA,IACf;AAAA,EACF;AAEA,SAAO;AAAA,IACL,IAAI,MAAM;AAAA,IACV,SAAS,MAAM;AAAA,IACf,MAAM,MAAM;AAAA,IACZ,IAAI,MAAM;AAAA,IACV,IAAI,MAAM;AAAA,IACV,MAAM,MAAM;AAAA,IACZ,MAAM;AAAA,MACJ,MAAM,MAAM;AAAA,MACZ,MAAM,MAAM;AAAA,MACZ,SAAS,MAAM,WAAW,MAAM,KAAK,UAAU,GAAG,GAAG,EAAE,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAAA,IACnF;AAAA,IACA,QAAQ;AAAA,MACN,IAAI,MAAM,YAAY,MAAM;AAAA,MAC5B,WAAW,MAAM;AAAA,MACjB,WAAW,MAAM;AAAA,MACjB,YAAY,MAAM;AAAA,MAClB,UAAU,MAAM,WAAW;AAAA,MAC3B;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,IACA,UAAU;AAAA,MACR,QAAQ,MAAM,MAAM,SAAS,QAAQ;AAAA,MACrC,WAAW,MAAM,MAAM,SAAS,WAAW;AAAA,MAC3C,QAAQ,MAAM,OAAO,SAAS,MAAM,KAAK,MAAM,OAAO,SAAS,MAAM;AAAA,MACrE,SAAS,MAAM,MAAM,SAAS,SAAS;AAAA,MACvC,QAAQ,MAAM;AAAA,MACd;AAAA,MACA,gBAAgB,YAAY,SAAS;AAAA,MACrC,iBAAiB,YAAY;AAAA,MAC7B;AAAA,IACF;AAAA,EACF;AACF;AAKO,SAAS,gBAAgB,YAA+C;AAC7E,QAAM,YAAY,WAAW,SAAS,SAAS,GAAG,IAC9C,WAAW,SAAS,MAAM,GAAG,EAAE,IAAI,GAAG,YAAY,KAAK,KACvD;AAEJ,SAAO;AAAA,IACL,UAAU,WAAW;AAAA,IACrB,aAAa,WAAW;AAAA,IACxB,MAAM,WAAW;AAAA,IACjB,UAAU,CAAC,CAAC,WAAW;AAAA,IACvB,KAAK,WAAW;AAAA,IAChB,SAAS,WAAW;AAAA,IACpB;AAAA,IACA,UAAU,qBAAqB,WAAW,aAAa,SAAS;AAAA,EAClE;AACF;AAKA,SAAS,qBACP,aACA,WACsD;AACtD,QAAM,mBAAmB,YAAY,YAAY;AAGjD,MAAI,iBAAiB,WAAW,QAAQ,GAAG;AACzC,WAAO;AAAA,EACT;AAGA,QAAM,gBAAgB,CAAC,OAAO,OAAO,QAAQ,OAAO,QAAQ,OAAO,QAAQ,OAAO,OAAO,OAAO,OAAO,OAAO,KAAK;AACnH,QAAM,eAAe;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,MAAI,cAAc,SAAS,SAAS,KAAK,aAAa,KAAK,OAAK,iBAAiB,SAAS,CAAC,CAAC,GAAG;AAC7F,WAAO;AAAA,EACT;AAGA,QAAM,oBAAoB,CAAC,OAAO,OAAO,MAAM,OAAO,MAAM,KAAK;AACjE,QAAM,mBAAmB,CAAC,mBAAmB,qBAAqB,oBAAoB,kBAAkB;AACxG,MAAI,kBAAkB,SAAS,SAAS,KAAK,iBAAiB,KAAK,OAAK,iBAAiB,SAAS,CAAC,CAAC,GAAG;AACrG,WAAO;AAAA,EACT;AAGA,MAAI,iBAAiB,WAAW,QAAQ,KAAK,iBAAiB,WAAW,QAAQ,GAAG;AAClF,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAKO,SAAS,iBAAiB,QAAuC;AACtE,QAAM,YAAY,oBAAI,IAA4B;AAGlD,aAAW,SAAS,QAAQ;AAE1B,QAAI,WAAW,MAAM,YAAY,MAAM;AAEvC,QAAI,MAAM,WAAW,SAAS,GAAG;AAE/B,iBAAW,MAAM,WAAW,CAAC;AAAA,IAC/B;AAEA,QAAI,CAAC,UAAU,IAAI,QAAQ,GAAG;AAC5B,gBAAU,IAAI,UAAU,CAAC,CAAC;AAAA,IAC5B;AACA,cAAU,IAAI,QAAQ,EAAG,KAAK,KAAK;AAAA,EACrC;AAGA,QAAM,UAAyB,CAAC;AAEhC,aAAW,CAAC,UAAU,QAAQ,KAAK,WAAW;AAE5C,aAAS,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,QAAQ,IAAI,EAAE,KAAK,QAAQ,CAAC;AAG3D,UAAM,iBAAiB,oBAAI,IAA0B;AACrD,eAAW,OAAO,UAAU;AAC1B,iBAAW,QAAQ,CAAC,GAAG,IAAI,MAAM,GAAG,IAAI,IAAI,GAAG,IAAI,EAAE,GAAG;AACtD,YAAI,CAAC,eAAe,IAAI,KAAK,OAAO,GAAG;AACrC,yBAAe,IAAI,KAAK,SAAS,IAAI;AAAA,QACvC;AAAA,MACF;AAAA,IACF;AAGA,UAAM,cAAc,SAAS,OAAO,OAAK,CAAC,EAAE,MAAM,SAAS,QAAQ,CAAC,EAAE;AAGtE,QAAI,UAAU,SAAS,CAAC,EAAE;AAC1B,eAAW,OAAO,UAAU;AAC1B,YAAM,UAAU,aAAa,IAAI,OAAO;AACxC,UAAI,QAAQ,SAAS,KAAK,CAAC,QAAQ,YAAY,EAAE,WAAW,KAAK,GAAG;AAClE,kBAAU,IAAI;AACd;AAAA,MACF;AAAA,IACF;AAEA,YAAQ,KAAK;AAAA,MACX,IAAI;AAAA,MACJ,SAAS,aAAa,OAAO;AAAA,MAC7B,cAAc,MAAM,KAAK,eAAe,OAAO,CAAC;AAAA,MAChD,cAAc,SAAS;AAAA,MACvB;AAAA,MACA,iBAAiB,SAAS,SAAS,SAAS,CAAC,EAAE;AAAA,MAC/C,kBAAkB,SAAS,CAAC,EAAE;AAAA,MAC9B,UAAU,SAAS,IAAI,UAAU;AAAA,MACjC,SAAS,SAAS,SAAS,SAAS,CAAC,EAAE,WAC9B,SAAS,SAAS,SAAS,CAAC,EAAE,KAAK,UAAU,GAAG,GAAG,EAAE,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAAA,IAC1F,CAAC;AAAA,EACH;AAGA,UAAQ,KAAK,CAAC,GAAG,MAAM,EAAE,gBAAgB,QAAQ,IAAI,EAAE,gBAAgB,QAAQ,CAAC;AAEhF,SAAO;AACT;AAKO,SAAS,aAAa,SAAyB;AACpD,SAAO,QACJ,QAAQ,sBAAsB,EAAE,EAChC,QAAQ,eAAe,EAAE,EACzB,KAAK;AACV;AAKO,SAAS,eAAe,MAA8B;AAC3D,QAAM,QAAQ,KAAK,MAAM,IAAI;AAC7B,QAAM,WAAqB,CAAC;AAC5B,QAAM,iBAAkC,CAAC;AACzC,MAAI,eAAgF;AACpF,MAAI;AACJ,MAAI,cAAc;AAElB,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,OAAO,MAAM,CAAC;AAGpB,QAAI,KAAK,KAAK,MAAM,QAAQ,KAAK,KAAK,MAAM,OAAO;AACjD,oBAAc;AACd,kBAAY,MAAM,MAAM,IAAI,CAAC,EAAE,KAAK,IAAI,EAAE,KAAK;AAC/C;AAAA,IACF;AAGA,UAAM,aAAa,KAAK,MAAM,UAAU;AAExC,QAAI,YAAY;AACd,YAAM,QAAQ,WAAW,CAAC,EAAE;AAC5B,YAAM,UAAU,KAAK,UAAU,WAAW,CAAC,EAAE,MAAM;AAEnD,UAAI,CAAC,gBAAgB,aAAa,UAAU,OAAO;AAEjD,YAAI,cAAc;AAChB,yBAAe,KAAK;AAAA,YAClB,OAAO,aAAa;AAAA,YACpB,SAAS,aAAa,MAAM,KAAK,IAAI;AAAA,YACrC,aAAa,aAAa;AAAA,UAC5B,CAAC;AAAA,QACH;AACA,uBAAe,EAAE,OAAO,OAAO,CAAC,OAAO,EAAE;AAAA,MAC3C,OAAO;AACL,qBAAa,MAAM,KAAK,OAAO;AAAA,MACjC;AAAA,IACF,WAAW,kBAAkB,IAAI,GAAG;AAElC,UAAI,cAAc;AAChB,qBAAa,cAAc;AAAA,MAC7B,OAAO;AAEL,uBAAe,EAAE,OAAO,GAAG,OAAO,CAAC,GAAG,aAAa,KAAK;AAAA,MAC1D;AAAA,IACF,OAAO;AAEL,UAAI,cAAc;AAChB,uBAAe,KAAK;AAAA,UAClB,OAAO,aAAa;AAAA,UACpB,SAAS,aAAa,MAAM,KAAK,IAAI;AAAA,UACrC,aAAa,aAAa;AAAA,QAC5B,CAAC;AACD,uBAAe;AAAA,MACjB;AACA,eAAS,KAAK,IAAI;AAAA,IACpB;AAAA,EACF;AAGA,MAAI,cAAc;AAChB,mBAAe,KAAK;AAAA,MAClB,OAAO,aAAa;AAAA,MACpB,SAAS,aAAa,MAAM,KAAK,IAAI;AAAA,MACrC,aAAa,aAAa;AAAA,IAC5B,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,YAAY,SAAS,KAAK,IAAI,EAAE,KAAK;AAAA,IACrC,eAAe;AAAA,IACf;AAAA,EACF;AACF;AAKA,SAAS,kBAAkB,MAAuB;AAChD,QAAM,sBAAsB;AAAA,IAC1B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,SAAO,oBAAoB,KAAK,aAAW,QAAQ,KAAK,KAAK,KAAK,CAAC,CAAC;AACtE;AAKO,SAAS,sBAAsB,MAAwB;AAC5D,QAAM,aAAa;AACnB,QAAM,UAAU,KAAK,MAAM,UAAU,KAAK,CAAC;AAC3C,SAAO,CAAC,GAAG,IAAI,IAAI,OAAO,CAAC;AAC7B;AAKO,SAAS,YAAY,MAAwB;AAClD,QAAM,WAAW;AACjB,QAAM,UAAU,KAAK,MAAM,QAAQ,KAAK,CAAC;AACzC,SAAO,CAAC,GAAG,IAAI,IAAI,OAAO,CAAC;AAC7B;AAKO,SAAS,oBAAoB,MAAwB;AAC1D,QAAM,aAAa;AACnB,QAAM,UAAU,KAAK,MAAM,UAAU,KAAK,CAAC;AAC3C,SAAO,CAAC,GAAG,IAAI,IAAI,OAAO,CAAC;AAC7B;AAKO,SAAS,gBAAgB,OAM9B;AACA,QAAM,WAAW,MAAM,KAAK,CAAC;AAC7B,QAAM,cAAc,WAChB,SAAS,QAAQ,SAAS,UAC1B;AAEJ,QAAM,UAAU,UAAU,QACtB,MAAM,KAAK,UACX,MAAM,WAAW,MAAM,KAAK,UAAU,GAAG,GAAG;AAEhD,QAAM,kBAAkB,cAAc,QAClC,MAAM,SAAS,kBACf,MAAM,YAAY;AAEtB,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS,MAAM;AAAA,IACf;AAAA,IACA,MAAM,gBAAgB,MAAM,IAAI;AAAA,IAChC;AAAA,EACF;AACF;AAKA,SAAS,gBAAgB,MAAoB;AAC3C,QAAM,MAAM,oBAAI,KAAK;AACrB,QAAM,OAAO,IAAI,QAAQ,IAAI,KAAK,QAAQ;AAC1C,QAAM,OAAO,KAAK,MAAM,QAAQ,MAAO,KAAK,KAAK,GAAG;AAEpD,MAAI,SAAS,GAAG;AAEd,WAAO,KAAK,mBAAmB,SAAS;AAAA,MACtC,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,QAAQ;AAAA,IACV,CAAC;AAAA,EACH,WAAW,SAAS,GAAG;AACrB,WAAO;AAAA,EACT,WAAW,OAAO,GAAG;AAEnB,WAAO,KAAK,mBAAmB,SAAS,EAAE,SAAS,QAAQ,CAAC;AAAA,EAC9D,WAAW,KAAK,YAAY,MAAM,IAAI,YAAY,GAAG;AAEnD,WAAO,KAAK,mBAAmB,SAAS,EAAE,OAAO,SAAS,KAAK,UAAU,CAAC;AAAA,EAC5E,OAAO;AAEL,WAAO,KAAK,mBAAmB,SAAS;AAAA,MACtC,OAAO;AAAA,MACP,KAAK;AAAA,MACL,MAAM;AAAA,IACR,CAAC;AAAA,EACH;AACF;AAKO,SAAS,mBAAmB,OAA6B;AAC9D,MAAI,OAAO;AAGX,UAAQ,IAAI,YAAY,EAAE,OAAO,MAAM,IAAI,EAAE;AAC7C,UAAQ,IAAI,YAAY,EAAE,OAAO,MAAM,IAAI,EAAE;AAG7C,UAAQ,IAAI,YAAY,EAAE,OAAO,MAAM,OAAO,EAAE;AAChD,UAAQ,MAAM,KAAK,OAAO,CAAC,GAAG,MAAM,KAAK,EAAE,MAAM,UAAU,KAAK,EAAE,QAAQ,SAAS,IAAI,CAAC;AACxF,UAAQ,MAAM,GAAG,OAAO,CAAC,GAAG,MAAM,KAAK,EAAE,MAAM,UAAU,KAAK,EAAE,QAAQ,SAAS,IAAI,CAAC;AAGtF,UAAQ,MAAM,YAAY,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,MAAM,CAAC;AAExD,SAAO;AACT;AAKO,SAAS,cACd,OACA,QAWS;AACT,QAAM,SAAS,cAAc,QAAQ,QAAQ,WAAW,KAAK;AAG7D,MAAI,OAAO,MAAM;AACf,UAAM,YAAY,OAAO,KAAK,KAAK,UAAQ;AACzC,YAAM,MAAM,GAAG,KAAK,IAAI,IAAI,KAAK,OAAO;AACxC,aAAO,OAAO,gBAAgB,SAC1B,OAAO,KAAK,KAAK,GAAG,IACpB,IAAI,YAAY,EAAE,SAAS,OAAO,KAAK,YAAY,CAAC;AAAA,IAC1D,CAAC;AACD,QAAI,CAAC,UAAW,QAAO;AAAA,EACzB;AAGA,MAAI,OAAO,IAAI;AACb,UAAM,UAAU,OAAO,GAAG,KAAK,UAAQ;AACrC,YAAM,MAAM,GAAG,KAAK,IAAI,IAAI,KAAK,OAAO;AACxC,aAAO,OAAO,cAAc,SACxB,OAAO,GAAG,KAAK,GAAG,IAClB,IAAI,YAAY,EAAE,SAAS,OAAO,GAAG,YAAY,CAAC;AAAA,IACxD,CAAC;AACD,QAAI,CAAC,QAAS,QAAO;AAAA,EACvB;AAGA,MAAI,OAAO,SAAS;AAClB,UAAM,eAAe,OAAO,mBAAmB,SAC3C,OAAO,QAAQ,KAAK,OAAO,OAAO,IAClC,OAAO,QAAQ,YAAY,EAAE,SAAS,OAAO,QAAQ,YAAY,CAAC;AACtE,QAAI,CAAC,aAAc,QAAO;AAAA,EAC5B;AAGA,MAAI,OAAO,MAAM;AACf,UAAM,WAAW,OAAO,KAAK;AAC7B,UAAM,YAAY,OAAO,gBAAgB,SACrC,OAAO,KAAK,KAAK,QAAQ,IACzB,SAAS,YAAY,EAAE,SAAS,OAAO,KAAK,YAAY,CAAC;AAC7D,QAAI,CAAC,UAAW,QAAO;AAAA,EACzB;AAGA,MAAI,OAAO,mBAAmB,QAAW;AACvC,QAAI,OAAO,SAAS,mBAAmB,OAAO,eAAgB,QAAO;AAAA,EACvE;AAGA,MAAI,OAAO,aAAa,QAAW;AACjC,QAAI,OAAO,SAAS,WAAW,OAAO,SAAU,QAAO;AAAA,EACzD;AAGA,MAAI,OAAO,cAAc,QAAW;AAClC,QAAI,OAAO,SAAS,cAAc,OAAO,UAAW,QAAO;AAAA,EAC7D;AAGA,MAAI,OAAO,aAAa,OAAO,OAAO,OAAO,UAAW,QAAO;AAC/D,MAAI,OAAO,cAAc,OAAO,OAAO,OAAO,WAAY,QAAO;AAEjE,SAAO;AACT;;;AC9fA,IAAM,wBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2B9B,IAAM,2BAA2B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4BjC,IAAM,uBAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoB7B,IAAM,wBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4B9B,eAAsB,gBAAgB,OAAiE;AACrG,QAAM,SAAS,cAAc,QAAQ,QAAQ,WAAW,KAAK;AAE7D,QAAM,cAAc,OAAO,KAAK,CAAC,IAC7B,GAAG,OAAO,KAAK,CAAC,EAAE,QAAQ,EAAE,KAAK,OAAO,KAAK,CAAC,EAAE,OAAO,IAAI,KAAK,IAChE;AAEJ,QAAM,SAAS,sBACZ,QAAQ,YAAY,WAAW,EAC/B,QAAQ,eAAe,OAAO,OAAO,EACrC,QAAQ,YAAY,OAAO,KAAK,YAAY,CAAC,EAC7C,QAAQ,eAAe,OAAO,KAAK,OAAO;AAE7C,MAAI;AACF,UAAM,WAAW,MAAM;AAAA,MACrB,CAAC,EAAE,MAAM,QAAQ,SAAS,OAAO,CAAC;AAAA,MAClC;AAAA,IACF;AAEA,UAAM,SAAS,KAAK,MAAM,SAAS,OAAO;AAC1C,WAAO;AAAA,MACL,UAAU,OAAO,YAAY;AAAA,MAC7B,YAAY,OAAO,cAAc;AAAA,MACjC,QAAQ,OAAO,UAAU;AAAA,IAC3B;AAAA,EACF,SAAS,KAAK;AACZ,YAAQ,MAAM,+BAA+B,GAAG;AAChD,WAAO;AAAA,MACL,UAAU;AAAA,MACV,YAAY;AAAA,MACZ,QAAQ;AAAA,IACV;AAAA,EACF;AACF;AAKA,eAAsB,mBAAmB,OAA0D;AACjG,QAAM,SAAS,cAAc,QAAQ,QAAQ,WAAW,KAAK;AAE7D,QAAM,cAAc,OAAO,KAAK,CAAC,IAC7B,GAAG,OAAO,KAAK,CAAC,EAAE,QAAQ,EAAE,KAAK,OAAO,KAAK,CAAC,EAAE,OAAO,IAAI,KAAK,IAChE;AAGJ,QAAM,YAAY,eAAe,OAAO,KAAK,IAAI;AACjD,QAAM,eAAe,UAAU,cAAc,OAAO,KAAK,KAAK,UAAU,GAAG,GAAI;AAE/E,QAAM,SAAS,yBACZ,QAAQ,YAAY,WAAW,EAC/B,QAAQ,eAAe,OAAO,OAAO,EACrC,QAAQ,YAAY,OAAO,KAAK,YAAY,CAAC,EAC7C,QAAQ,YAAY,YAAY;AAEnC,MAAI;AACF,UAAM,WAAW,MAAM;AAAA,MACrB,CAAC,EAAE,MAAM,QAAQ,SAAS,OAAO,CAAC;AAAA,MAClC;AAAA,IACF;AAEA,UAAM,SAAS,KAAK,MAAM,SAAS,OAAO;AAE1C,YAAQ,OAAO,WAAW,CAAC,GAAG,IAAI,CAAC,YAK5B;AAAA,MACL,SAAS,OAAO;AAAA,MAChB,SAAS,OAAO;AAAA,MAChB,MAAM;AAAA,MACN,QAAQ,OAAO;AAAA,MACf,UAAW,CAAC,QAAQ,UAAU,KAAK,EAAE,SAAS,OAAO,QAAQ,IAAI,OAAO,WAAW;AAAA,MACnF,SAAS,OAAO,UAAU,IAAI,KAAK,OAAO,OAAO,IAAI;AAAA,MACrD,SAAS,OAAO;AAAA,IAClB,EAAE;AAAA,EACJ,SAAS,KAAK;AACZ,YAAQ,MAAM,mCAAmC,GAAG;AACpD,WAAO,CAAC;AAAA,EACV;AACF;AAKA,eAAsB,gBAAgB,QAA6C;AACjF,QAAM,eAAe,OAAO,aACzB,IAAI,OAAK,EAAE,QAAQ,EAAE,OAAO,EAC5B,MAAM,GAAG,EAAE,EACX,KAAK,IAAI;AAGZ,QAAM,iBAAiB,OAAO,SAC3B,MAAM,GAAG,EACT,IAAI,CAAC,KAAK,QAAQ;AACjB,UAAM,OAAO,IAAI,KAAK,CAAC,GAAG,QAAQ,IAAI,KAAK,CAAC,GAAG,WAAW;AAC1D,UAAM,YAAY,eAAe,IAAI,KAAK,IAAI;AAC9C,UAAM,WAAW,UAAU,cAAc,IAAI,KAAK,SAAS,UAAU,GAAG,GAAG;AAC3E,WAAO,IAAI,MAAM,CAAC,WAAW,IAAI;AAAA,QAAW,IAAI,KAAK,YAAY,CAAC;AAAA,EAAK,OAAO;AAAA,EAChF,CAAC,EACA,KAAK,aAAa;AAErB,QAAM,SAAS,sBACZ,QAAQ,eAAe,OAAO,OAAO,EACrC,QAAQ,oBAAoB,YAAY,EACxC,QAAQ,oBAAoB,OAAO,OAAO,YAAY,CAAC,EACvD,QAAQ,gBAAgB,cAAc;AAEzC,MAAI;AACF,UAAM,WAAW,MAAM;AAAA,MACrB,CAAC,EAAE,MAAM,QAAQ,SAAS,OAAO,CAAC;AAAA,MAClC;AAAA,IACF;AAEA,UAAM,SAAS,KAAK,MAAM,SAAS,OAAO;AAE1C,WAAO;AAAA,MACL,UAAU,OAAO;AAAA,MACjB,SAAS,OAAO;AAAA,MAChB,kBAAkB,OAAO,aAAa;AAAA,MACtC,cAAc,OAAO;AAAA,MACrB,SAAS,OAAO,WAAW;AAAA,MAC3B,eAAe,OAAO,iBAAiB;AAAA,MACvC,WAAW,OAAO,aAAa,CAAC;AAAA,MAChC,cAAc,OAAO,gBAAgB,CAAC;AAAA,MACtC,eAAe,OAAO,iBAAiB,CAAC;AAAA,IAC1C;AAAA,EACF,SAAS,KAAK;AACZ,YAAQ,MAAM,+BAA+B,GAAG;AAChD,WAAO;AAAA,MACL,UAAU,OAAO;AAAA,MACjB,SAAS,OAAO;AAAA,MAChB,kBAAkB,OAAO,aAAa;AAAA,MACtC,cAAc,OAAO;AAAA,MACrB,SAAS;AAAA,MACT,eAAe;AAAA,MACf,WAAW,CAAC;AAAA,MACZ,cAAc,CAAC;AAAA,MACf,eAAe,CAAC;AAAA,IAClB;AAAA,EACF;AACF;AAKA,eAAsB,eAAe,QAA+C;AAElF,QAAM,eAAe,OAAO,IAAI,UAAU;AAC1C,QAAM,kBAAkB,MAAM,QAAQ;AAAA,IACpC,aAAa,MAAM,GAAG,GAAG,EAAE,IAAI,OAAM,WAAU;AAAA,MAC7C;AAAA,MACA,gBAAgB,MAAM,gBAAgB,KAAK;AAAA,IAC7C,EAAE;AAAA,EACJ;AAGA,QAAM,cAAc,OAAO;AAC3B,QAAM,cAAc,aAAa,OAAO,OAAK,CAAC,EAAE,SAAS,MAAM,EAAE;AACjE,QAAM,iBAAiB,gBAAgB;AAAA,IACrC,OAAK,EAAE,eAAe,aAAa,YAAY,EAAE,eAAe,aAAa;AAAA,EAC/E,EAAE;AAGF,QAAM,cAAc,oBAAI,IAA6D;AAErF,aAAW,EAAE,OAAO,eAAe,KAAK,iBAAiB;AACvD,UAAM,MAAM,eAAe;AAC3B,QAAI,CAAC,YAAY,IAAI,GAAG,GAAG;AACzB,kBAAY,IAAI,KAAK,EAAE,QAAQ,CAAC,GAAG,SAAS,oBAAI,IAAI,EAAE,CAAC;AAAA,IACzD;AACA,UAAM,QAAQ,YAAY,IAAI,GAAG;AACjC,UAAM,OAAO,KAAK,KAAK;AACvB,QAAI,MAAM,KAAK,CAAC,GAAG;AACjB,YAAM,QAAQ,IAAI,MAAM,KAAK,CAAC,EAAE,QAAQ,MAAM,KAAK,CAAC,EAAE,OAAO;AAAA,IAC/D;AAAA,EACF;AAEA,QAAM,aAAgC,CAAC;AACvC,aAAW,CAAC,MAAM,IAAI,KAAK,aAAa;AACtC,eAAW,KAAK;AAAA,MACd;AAAA,MACA,OAAO,KAAK,OAAO;AAAA,MACnB,aAAa,KAAK,OAAO,OAAO,OAAK,CAAC,EAAE,SAAS,MAAM,EAAE;AAAA,MACzD,YAAY,MAAM,KAAK,KAAK,OAAO,EAAE,MAAM,GAAG,CAAC;AAAA,MAC/C,aAAa,uBAAuB,IAAI;AAAA,IAC1C,CAAC;AAAA,EACH;AAGA,aAAW,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAG3C,QAAM,cAA4B,CAAC;AACnC,aAAW,EAAE,OAAO,eAAe,KAAK,iBAAiB;AACvD,QAAI,eAAe,aAAa,UAAU;AACxC,kBAAY,KAAK;AAAA,QACf,SAAS,MAAM;AAAA,QACf,SAAS,MAAM;AAAA,QACf,MAAM,MAAM,KAAK,CAAC,GAAG,QAAQ,MAAM,KAAK,CAAC,GAAG,WAAW;AAAA,QACvD,QAAQ,eAAe;AAAA,QACvB,iBAAiB;AAAA,MACnB,CAAC;AAAA,IACH;AAAA,EACF;AAGA,QAAM,cAA4B,CAAC;AACnC,QAAM,uBAAuB,gBAC1B,OAAO,OAAK,EAAE,eAAe,aAAa,iBAAiB,EAC3D,MAAM,GAAG,EAAE;AAEd,aAAW,EAAE,MAAM,KAAK,sBAAsB;AAC5C,UAAM,QAAQ,MAAM,mBAAmB,KAAK;AAC5C,gBAAY,KAAK,GAAG,KAAK;AAAA,EAC3B;AAGA,cAAY,KAAK,CAAC,GAAG,MAAM;AACzB,UAAM,gBAAgB,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,EAAE;AACnD,WAAO,cAAc,EAAE,QAAQ,IAAI,cAAc,EAAE,QAAQ;AAAA,EAC7D,CAAC;AAGD,QAAM,iBAAiB,WACpB,IAAI,OAAK,KAAK,EAAE,IAAI,KAAK,EAAE,KAAK,YAAY,EAAE,WAAW,UAAU,EACnE,KAAK,IAAI;AAEZ,QAAM,aAAa,YAAY,SAAS,IACpC,YAAY,IAAI,OAAK,MAAM,EAAE,OAAO,UAAU,EAAE,IAAI,EAAE,EAAE,KAAK,IAAI,IACjE;AAEJ,QAAM,gBAAgB,qBACnB,QAAQ,mBAAmB,OAAO,WAAW,CAAC,EAC9C,QAAQ,mBAAmB,OAAO,WAAW,CAAC,EAC9C,QAAQ,sBAAsB,OAAO,cAAc,CAAC,EACpD,QAAQ,kBAAkB,cAAc,EACxC,QAAQ,mBAAmB,UAAU;AAExC,MAAI,UAAU;AACd,MAAI;AACF,UAAM,WAAW,MAAM;AAAA,MACrB,CAAC,EAAE,MAAM,QAAQ,SAAS,cAAc,CAAC;AAAA,MACzC;AAAA,IACF;AACA,cAAU,SAAS;AAAA,EACrB,SAAS,KAAK;AACZ,YAAQ,MAAM,+BAA+B,GAAG;AAChD,cAAU,YAAY,WAAW,YAAY,WAAW,YAAY,cAAc;AAAA,EACpF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,YAAY,MAAM,GAAG,EAAE;AAAA,IACpC;AAAA,IACA,aAAa,oBAAI,KAAK;AAAA,EACxB;AACF;AAKA,eAAsB,oBAAoB,QAAyC;AACjF,QAAM,UAAU,MAAM,eAAe,MAAM;AAE3C,MAAI,SAAS;AAAA;AAAA;AACb,YAAU,eAAe,QAAQ,YAAY,eAAe,CAAC;AAAA;AAAA;AAG7D,YAAU;AAAA;AAAA;AACV,YAAU,GAAG,QAAQ,OAAO;AAAA;AAAA;AAC5B,YAAU,uBAAuB,QAAQ,WAAW;AAAA;AACpD,YAAU,iBAAiB,QAAQ,WAAW;AAAA;AAC9C,YAAU,0BAA0B,QAAQ,cAAc;AAAA;AAAA;AAG1D,MAAI,QAAQ,YAAY,SAAS,GAAG;AAClC,cAAU;AAAA;AAAA;AACV,eAAW,QAAQ,QAAQ,aAAa;AACtC,gBAAU,OAAO,KAAK,OAAO,WAAW,KAAK,IAAI;AAAA;AACjD,gBAAU,MAAM,KAAK,MAAM;AAAA;AAAA;AAAA,IAC7B;AAAA,EACF;AAGA,MAAI,QAAQ,YAAY,SAAS,GAAG;AAClC,cAAU;AAAA;AAAA;AACV,eAAW,QAAQ,QAAQ,aAAa;AACtC,YAAM,WAAW,KAAK,aAAa,SAAS,QAAQ,KAAK,aAAa,WAAW,OAAO;AACxF,gBAAU,MAAM,QAAQ,OAAO,KAAK,MAAM;AAAA;AAC1C,gBAAU,WAAW,KAAK,IAAI,MAAM,KAAK,OAAO;AAAA;AAChD,UAAI,KAAK,SAAS;AAChB,kBAAU,UAAU,KAAK,QAAQ,mBAAmB,CAAC;AAAA;AAAA,MACvD;AACA,gBAAU;AAAA,IACZ;AAAA,EACF;AAGA,YAAU;AAAA;AAAA;AACV,aAAW,OAAO,QAAQ,WAAW,MAAM,GAAG,CAAC,GAAG;AAChD,cAAU,OAAO,IAAI,IAAI,OAAO,IAAI,KAAK;AACzC,QAAI,IAAI,cAAc,GAAG;AACvB,gBAAU,KAAK,IAAI,WAAW;AAAA,IAChC;AACA,cAAU;AACV,QAAI,IAAI,WAAW,SAAS,GAAG;AAC7B,gBAAU,kBAAkB,IAAI,WAAW,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA;AAAA,IACnE;AAAA,EACF;AAEA,SAAO;AACT;AAKA,eAAsB,eAAe,OAAsD;AACzF,QAAM,SAAS,cAAc,QAAQ,QAAQ,WAAW,KAAK;AAE7D,QAAM,cAAc,OAAO,KAAK,CAAC,IAC7B,GAAG,OAAO,KAAK,CAAC,EAAE,QAAQ,EAAE,KAAK,OAAO,KAAK,CAAC,EAAE,OAAO,IAAI,KAAK,IAChE;AAEJ,QAAM,YAAY,eAAe,OAAO,KAAK,IAAI;AACjD,QAAM,gBAAgB,UAAU,cAAc,OAAO,KAAK,MAAM,UAAU,GAAG,IAAI;AAEjF,QAAM,SAAS;AAAA;AAAA;AAAA,QAGT,WAAW;AAAA,WACR,OAAO,OAAO;AAAA,QACjB,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYlB,MAAI;AACF,UAAM,WAAW,MAAM;AAAA,MACrB,CAAC,EAAE,MAAM,QAAQ,SAAS,OAAO,CAAC;AAAA,MAClC;AAAA,IACF;AAEA,UAAM,SAAS,KAAK,MAAM,SAAS,OAAO;AAC1C,WAAO,OAAO,WAAW,CAAC;AAAA,EAC5B,SAAS,KAAK;AACZ,YAAQ,MAAM,8BAA8B,GAAG;AAC/C,WAAO,CAAC;AAAA,EACV;AACF;AAKA,eAAsB,iBAAiB,OAKpC;AACD,QAAM,SAAS,cAAc,QAAQ,QAAQ,WAAW,KAAK;AAE7D,QAAM,YAAY,eAAe,OAAO,KAAK,IAAI;AACjD,QAAM,gBAAgB,UAAU,cAAc,OAAO,KAAK,MAAM,UAAU,GAAG,IAAI;AAEjF,QAAM,SAAS;AAAA;AAAA,WAEN,OAAO,OAAO;AAAA,QACjB,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUlB,MAAI;AACF,UAAM,WAAW,MAAM;AAAA,MACrB,CAAC,EAAE,MAAM,QAAQ,SAAS,OAAO,CAAC;AAAA,MAClC;AAAA,IACF;AAEA,UAAM,SAAS,KAAK,MAAM,SAAS,OAAO;AAC1C,WAAO;AAAA,MACL,WAAW,OAAO,aAAa;AAAA,MAC/B,YAAY,OAAO,cAAc;AAAA,MACjC,MAAM,OAAO,QAAQ;AAAA,MACrB,YAAY,OAAO,cAAc,CAAC;AAAA,IACpC;AAAA,EACF,SAAS,KAAK;AACZ,YAAQ,MAAM,gCAAgC,GAAG;AACjD,WAAO;AAAA,MACL,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,IACf;AAAA,EACF;AACF;AAKA,SAAS,uBAAuB,UAA0B;AACxD,QAAM,eAAuC;AAAA,IAC3C,QAAQ;AAAA,IACR,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,SAAS;AAAA,IACT,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,SAAS;AAAA,IACT,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AACA,SAAO,aAAa,QAAQ,KAAK;AACnC;AAEA,IAAO,2BAAQ;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;","names":[]}