@diskd-ai/email-mcp 0.3.0

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 (295) hide show
  1. package/LICENSE +155 -0
  2. package/README.md +820 -0
  3. package/dist/cli/account-commands.d.ts +10 -0
  4. package/dist/cli/account-commands.d.ts.map +1 -0
  5. package/dist/cli/account-commands.js +703 -0
  6. package/dist/cli/account-commands.js.map +1 -0
  7. package/dist/cli/config-commands.d.ts +9 -0
  8. package/dist/cli/config-commands.d.ts.map +1 -0
  9. package/dist/cli/config-commands.js +156 -0
  10. package/dist/cli/config-commands.js.map +1 -0
  11. package/dist/cli/guard.d.ts +11 -0
  12. package/dist/cli/guard.d.ts.map +1 -0
  13. package/dist/cli/guard.js +18 -0
  14. package/dist/cli/guard.js.map +1 -0
  15. package/dist/cli/install-commands.d.ts +12 -0
  16. package/dist/cli/install-commands.d.ts.map +1 -0
  17. package/dist/cli/install-commands.js +320 -0
  18. package/dist/cli/install-commands.js.map +1 -0
  19. package/dist/cli/notify.d.ts +8 -0
  20. package/dist/cli/notify.d.ts.map +1 -0
  21. package/dist/cli/notify.js +143 -0
  22. package/dist/cli/notify.js.map +1 -0
  23. package/dist/cli/providers.d.ts +13 -0
  24. package/dist/cli/providers.d.ts.map +1 -0
  25. package/dist/cli/providers.js +180 -0
  26. package/dist/cli/providers.js.map +1 -0
  27. package/dist/cli/scheduler.d.ts +8 -0
  28. package/dist/cli/scheduler.d.ts.map +1 -0
  29. package/dist/cli/scheduler.js +268 -0
  30. package/dist/cli/scheduler.js.map +1 -0
  31. package/dist/cli/setup.d.ts +12 -0
  32. package/dist/cli/setup.d.ts.map +1 -0
  33. package/dist/cli/setup.js +15 -0
  34. package/dist/cli/setup.js.map +1 -0
  35. package/dist/cli/test.d.ts +7 -0
  36. package/dist/cli/test.d.ts.map +1 -0
  37. package/dist/cli/test.js +67 -0
  38. package/dist/cli/test.js.map +1 -0
  39. package/dist/config/loader.d.ts +34 -0
  40. package/dist/config/loader.d.ts.map +1 -0
  41. package/dist/config/loader.js +339 -0
  42. package/dist/config/loader.js.map +1 -0
  43. package/dist/config/schema.d.ts +351 -0
  44. package/dist/config/schema.d.ts.map +1 -0
  45. package/dist/config/schema.js +165 -0
  46. package/dist/config/schema.js.map +1 -0
  47. package/dist/config/xdg.d.ts +27 -0
  48. package/dist/config/xdg.d.ts.map +1 -0
  49. package/dist/config/xdg.js +30 -0
  50. package/dist/config/xdg.js.map +1 -0
  51. package/dist/connections/manager.d.ts +42 -0
  52. package/dist/connections/manager.d.ts.map +1 -0
  53. package/dist/connections/manager.js +266 -0
  54. package/dist/connections/manager.js.map +1 -0
  55. package/dist/connections/types.d.ts +13 -0
  56. package/dist/connections/types.d.ts.map +1 -0
  57. package/dist/connections/types.js +2 -0
  58. package/dist/connections/types.js.map +1 -0
  59. package/dist/logging.d.ts +46 -0
  60. package/dist/logging.d.ts.map +1 -0
  61. package/dist/logging.js +63 -0
  62. package/dist/logging.js.map +1 -0
  63. package/dist/main.d.ts +13 -0
  64. package/dist/main.d.ts.map +1 -0
  65. package/dist/main.js +206 -0
  66. package/dist/main.js.map +1 -0
  67. package/dist/prompts/actions.prompt.d.ts +9 -0
  68. package/dist/prompts/actions.prompt.d.ts.map +1 -0
  69. package/dist/prompts/actions.prompt.js +64 -0
  70. package/dist/prompts/actions.prompt.js.map +1 -0
  71. package/dist/prompts/calendar.prompt.d.ts +9 -0
  72. package/dist/prompts/calendar.prompt.d.ts.map +1 -0
  73. package/dist/prompts/calendar.prompt.js +55 -0
  74. package/dist/prompts/calendar.prompt.js.map +1 -0
  75. package/dist/prompts/cleanup.prompt.d.ts +9 -0
  76. package/dist/prompts/cleanup.prompt.d.ts.map +1 -0
  77. package/dist/prompts/cleanup.prompt.js +78 -0
  78. package/dist/prompts/cleanup.prompt.js.map +1 -0
  79. package/dist/prompts/compose.prompt.d.ts +8 -0
  80. package/dist/prompts/compose.prompt.d.ts.map +1 -0
  81. package/dist/prompts/compose.prompt.js +116 -0
  82. package/dist/prompts/compose.prompt.js.map +1 -0
  83. package/dist/prompts/register.d.ts +8 -0
  84. package/dist/prompts/register.d.ts.map +1 -0
  85. package/dist/prompts/register.js +20 -0
  86. package/dist/prompts/register.js.map +1 -0
  87. package/dist/prompts/thread.prompt.d.ts +9 -0
  88. package/dist/prompts/thread.prompt.d.ts.map +1 -0
  89. package/dist/prompts/thread.prompt.js +58 -0
  90. package/dist/prompts/thread.prompt.js.map +1 -0
  91. package/dist/prompts/triage.prompt.d.ts +9 -0
  92. package/dist/prompts/triage.prompt.d.ts.map +1 -0
  93. package/dist/prompts/triage.prompt.js +64 -0
  94. package/dist/prompts/triage.prompt.js.map +1 -0
  95. package/dist/resources/accounts.resource.d.ts +9 -0
  96. package/dist/resources/accounts.resource.d.ts.map +1 -0
  97. package/dist/resources/accounts.resource.js +26 -0
  98. package/dist/resources/accounts.resource.js.map +1 -0
  99. package/dist/resources/mailboxes.resource.d.ts +10 -0
  100. package/dist/resources/mailboxes.resource.d.ts.map +1 -0
  101. package/dist/resources/mailboxes.resource.js +33 -0
  102. package/dist/resources/mailboxes.resource.js.map +1 -0
  103. package/dist/resources/register.d.ts +12 -0
  104. package/dist/resources/register.d.ts.map +1 -0
  105. package/dist/resources/register.js +20 -0
  106. package/dist/resources/register.js.map +1 -0
  107. package/dist/resources/scheduled.resource.d.ts +9 -0
  108. package/dist/resources/scheduled.resource.d.ts.map +1 -0
  109. package/dist/resources/scheduled.resource.js +31 -0
  110. package/dist/resources/scheduled.resource.js.map +1 -0
  111. package/dist/resources/stats.resource.d.ts +10 -0
  112. package/dist/resources/stats.resource.d.ts.map +1 -0
  113. package/dist/resources/stats.resource.js +45 -0
  114. package/dist/resources/stats.resource.js.map +1 -0
  115. package/dist/resources/templates.resource.d.ts +9 -0
  116. package/dist/resources/templates.resource.d.ts.map +1 -0
  117. package/dist/resources/templates.resource.js +34 -0
  118. package/dist/resources/templates.resource.js.map +1 -0
  119. package/dist/resources/unread.resource.d.ts +11 -0
  120. package/dist/resources/unread.resource.d.ts.map +1 -0
  121. package/dist/resources/unread.resource.js +46 -0
  122. package/dist/resources/unread.resource.js.map +1 -0
  123. package/dist/safety/audit.d.ts +17 -0
  124. package/dist/safety/audit.d.ts.map +1 -0
  125. package/dist/safety/audit.js +50 -0
  126. package/dist/safety/audit.js.map +1 -0
  127. package/dist/safety/rate-limiter.d.ts +22 -0
  128. package/dist/safety/rate-limiter.d.ts.map +1 -0
  129. package/dist/safety/rate-limiter.js +52 -0
  130. package/dist/safety/rate-limiter.js.map +1 -0
  131. package/dist/safety/validation.d.ts +44 -0
  132. package/dist/safety/validation.d.ts.map +1 -0
  133. package/dist/safety/validation.js +113 -0
  134. package/dist/safety/validation.js.map +1 -0
  135. package/dist/server.d.ts +10 -0
  136. package/dist/server.d.ts.map +1 -0
  137. package/dist/server.js +25 -0
  138. package/dist/server.js.map +1 -0
  139. package/dist/services/calendar.service.d.ts +22 -0
  140. package/dist/services/calendar.service.d.ts.map +1 -0
  141. package/dist/services/calendar.service.js +115 -0
  142. package/dist/services/calendar.service.js.map +1 -0
  143. package/dist/services/event-bus.d.ts +28 -0
  144. package/dist/services/event-bus.d.ts.map +1 -0
  145. package/dist/services/event-bus.js +16 -0
  146. package/dist/services/event-bus.js.map +1 -0
  147. package/dist/services/hooks.service.d.ts +77 -0
  148. package/dist/services/hooks.service.d.ts.map +1 -0
  149. package/dist/services/hooks.service.js +498 -0
  150. package/dist/services/hooks.service.js.map +1 -0
  151. package/dist/services/imap.service.d.ts +133 -0
  152. package/dist/services/imap.service.d.ts.map +1 -0
  153. package/dist/services/imap.service.js +1393 -0
  154. package/dist/services/imap.service.js.map +1 -0
  155. package/dist/services/label-strategy.d.ts +20 -0
  156. package/dist/services/label-strategy.d.ts.map +1 -0
  157. package/dist/services/label-strategy.js +237 -0
  158. package/dist/services/label-strategy.js.map +1 -0
  159. package/dist/services/local-calendar.service.d.ts +126 -0
  160. package/dist/services/local-calendar.service.d.ts.map +1 -0
  161. package/dist/services/local-calendar.service.js +428 -0
  162. package/dist/services/local-calendar.service.js.map +1 -0
  163. package/dist/services/notifier.service.d.ts +69 -0
  164. package/dist/services/notifier.service.d.ts.map +1 -0
  165. package/dist/services/notifier.service.js +319 -0
  166. package/dist/services/notifier.service.js.map +1 -0
  167. package/dist/services/oauth.service.d.ts +47 -0
  168. package/dist/services/oauth.service.d.ts.map +1 -0
  169. package/dist/services/oauth.service.js +140 -0
  170. package/dist/services/oauth.service.js.map +1 -0
  171. package/dist/services/presets.d.ts +36 -0
  172. package/dist/services/presets.d.ts.map +1 -0
  173. package/dist/services/presets.js +173 -0
  174. package/dist/services/presets.js.map +1 -0
  175. package/dist/services/reminders.service.d.ts +63 -0
  176. package/dist/services/reminders.service.d.ts.map +1 -0
  177. package/dist/services/reminders.service.js +281 -0
  178. package/dist/services/reminders.service.js.map +1 -0
  179. package/dist/services/scheduler.service.d.ts +42 -0
  180. package/dist/services/scheduler.service.d.ts.map +1 -0
  181. package/dist/services/scheduler.service.js +260 -0
  182. package/dist/services/scheduler.service.js.map +1 -0
  183. package/dist/services/smtp.service.d.ts +40 -0
  184. package/dist/services/smtp.service.d.ts.map +1 -0
  185. package/dist/services/smtp.service.js +151 -0
  186. package/dist/services/smtp.service.js.map +1 -0
  187. package/dist/services/template.service.d.ts +33 -0
  188. package/dist/services/template.service.d.ts.map +1 -0
  189. package/dist/services/template.service.js +123 -0
  190. package/dist/services/template.service.js.map +1 -0
  191. package/dist/services/watcher.service.d.ts +36 -0
  192. package/dist/services/watcher.service.d.ts.map +1 -0
  193. package/dist/services/watcher.service.js +241 -0
  194. package/dist/services/watcher.service.js.map +1 -0
  195. package/dist/tools/accounts.tool.d.ts +7 -0
  196. package/dist/tools/accounts.tool.d.ts.map +1 -0
  197. package/dist/tools/accounts.tool.js +29 -0
  198. package/dist/tools/accounts.tool.js.map +1 -0
  199. package/dist/tools/analytics.tool.d.ts +9 -0
  200. package/dist/tools/analytics.tool.d.ts.map +1 -0
  201. package/dist/tools/analytics.tool.js +27 -0
  202. package/dist/tools/analytics.tool.js.map +1 -0
  203. package/dist/tools/attachments.tool.d.ts +7 -0
  204. package/dist/tools/attachments.tool.d.ts.map +1 -0
  205. package/dist/tools/attachments.tool.js +45 -0
  206. package/dist/tools/attachments.tool.js.map +1 -0
  207. package/dist/tools/bulk.tool.d.ts +7 -0
  208. package/dist/tools/bulk.tool.d.ts.map +1 -0
  209. package/dist/tools/bulk.tool.js +75 -0
  210. package/dist/tools/bulk.tool.js.map +1 -0
  211. package/dist/tools/calendar.tool.d.ts +19 -0
  212. package/dist/tools/calendar.tool.d.ts.map +1 -0
  213. package/dist/tools/calendar.tool.js +538 -0
  214. package/dist/tools/calendar.tool.js.map +1 -0
  215. package/dist/tools/contacts.tool.d.ts +7 -0
  216. package/dist/tools/contacts.tool.d.ts.map +1 -0
  217. package/dist/tools/contacts.tool.js +44 -0
  218. package/dist/tools/contacts.tool.js.map +1 -0
  219. package/dist/tools/drafts.tool.d.ts +8 -0
  220. package/dist/tools/drafts.tool.d.ts.map +1 -0
  221. package/dist/tools/drafts.tool.js +92 -0
  222. package/dist/tools/drafts.tool.js.map +1 -0
  223. package/dist/tools/emails.tool.d.ts +7 -0
  224. package/dist/tools/emails.tool.d.ts.map +1 -0
  225. package/dist/tools/emails.tool.js +400 -0
  226. package/dist/tools/emails.tool.js.map +1 -0
  227. package/dist/tools/folders.tool.d.ts +7 -0
  228. package/dist/tools/folders.tool.d.ts.map +1 -0
  229. package/dist/tools/folders.tool.js +111 -0
  230. package/dist/tools/folders.tool.js.map +1 -0
  231. package/dist/tools/health.tool.d.ts +10 -0
  232. package/dist/tools/health.tool.d.ts.map +1 -0
  233. package/dist/tools/health.tool.js +78 -0
  234. package/dist/tools/health.tool.js.map +1 -0
  235. package/dist/tools/label.tool.d.ts +11 -0
  236. package/dist/tools/label.tool.d.ts.map +1 -0
  237. package/dist/tools/label.tool.js +165 -0
  238. package/dist/tools/label.tool.js.map +1 -0
  239. package/dist/tools/locate.tool.d.ts +11 -0
  240. package/dist/tools/locate.tool.d.ts.map +1 -0
  241. package/dist/tools/locate.tool.js +59 -0
  242. package/dist/tools/locate.tool.js.map +1 -0
  243. package/dist/tools/mailboxes.tool.d.ts +7 -0
  244. package/dist/tools/mailboxes.tool.d.ts.map +1 -0
  245. package/dist/tools/mailboxes.tool.js +38 -0
  246. package/dist/tools/mailboxes.tool.js.map +1 -0
  247. package/dist/tools/manage.tool.d.ts +7 -0
  248. package/dist/tools/manage.tool.d.ts.map +1 -0
  249. package/dist/tools/manage.tool.js +125 -0
  250. package/dist/tools/manage.tool.js.map +1 -0
  251. package/dist/tools/register.d.ts +20 -0
  252. package/dist/tools/register.d.ts.map +1 -0
  253. package/dist/tools/register.js +53 -0
  254. package/dist/tools/register.js.map +1 -0
  255. package/dist/tools/scheduler.tool.d.ts +9 -0
  256. package/dist/tools/scheduler.tool.d.ts.map +1 -0
  257. package/dist/tools/scheduler.tool.js +104 -0
  258. package/dist/tools/scheduler.tool.js.map +1 -0
  259. package/dist/tools/send.tool.d.ts +7 -0
  260. package/dist/tools/send.tool.d.ts.map +1 -0
  261. package/dist/tools/send.tool.js +123 -0
  262. package/dist/tools/send.tool.js.map +1 -0
  263. package/dist/tools/templates.tool.d.ts +12 -0
  264. package/dist/tools/templates.tool.d.ts.map +1 -0
  265. package/dist/tools/templates.tool.js +140 -0
  266. package/dist/tools/templates.tool.js.map +1 -0
  267. package/dist/tools/thread.tool.d.ts +10 -0
  268. package/dist/tools/thread.tool.d.ts.map +1 -0
  269. package/dist/tools/thread.tool.js +146 -0
  270. package/dist/tools/thread.tool.js.map +1 -0
  271. package/dist/tools/watcher.tool.d.ts +9 -0
  272. package/dist/tools/watcher.tool.d.ts.map +1 -0
  273. package/dist/tools/watcher.tool.js +282 -0
  274. package/dist/tools/watcher.tool.js.map +1 -0
  275. package/dist/types/index.d.ts +271 -0
  276. package/dist/types/index.d.ts.map +1 -0
  277. package/dist/types/index.js +5 -0
  278. package/dist/types/index.js.map +1 -0
  279. package/dist/utils/calendar-notes.d.ts +31 -0
  280. package/dist/utils/calendar-notes.d.ts.map +1 -0
  281. package/dist/utils/calendar-notes.js +99 -0
  282. package/dist/utils/calendar-notes.js.map +1 -0
  283. package/dist/utils/calendar-state.d.ts +27 -0
  284. package/dist/utils/calendar-state.d.ts.map +1 -0
  285. package/dist/utils/calendar-state.js +85 -0
  286. package/dist/utils/calendar-state.js.map +1 -0
  287. package/dist/utils/conference-details.d.ts +12 -0
  288. package/dist/utils/conference-details.d.ts.map +1 -0
  289. package/dist/utils/conference-details.js +71 -0
  290. package/dist/utils/conference-details.js.map +1 -0
  291. package/dist/utils/meeting-url.d.ts +10 -0
  292. package/dist/utils/meeting-url.d.ts.map +1 -0
  293. package/dist/utils/meeting-url.js +30 -0
  294. package/dist/utils/meeting-url.js.map +1 -0
  295. package/package.json +108 -0
@@ -0,0 +1,428 @@
1
+ /**
2
+ * Local calendar integration service.
3
+ *
4
+ * macOS: uses `osascript` (AppleScript) for calendar operations
5
+ * - Triggers the native OS permission dialog automatically on first use
6
+ * - Shows a native confirmation dialog before adding any event
7
+ *
8
+ * Linux: generates a temporary .ics file and opens it with `xdg-open`
9
+ * - Universal — works with GNOME Calendar, KDE Organizer, Thunderbird, etc.
10
+ * - No confirmation dialog (xdg-open hands off to the desktop app)
11
+ */
12
+ import { execFile as execFileCb } from 'node:child_process';
13
+ import { writeFile } from 'node:fs/promises';
14
+ import { tmpdir } from 'node:os';
15
+ import { join } from 'node:path';
16
+ import { promisify } from 'node:util';
17
+ const execFile = promisify(execFileCb);
18
+ /** @internal Exported for testing. */
19
+ export function escapeAS(s) {
20
+ return s
21
+ .replace(/\\/g, '\\\\')
22
+ .replace(/"/g, '\\"')
23
+ .replace(/\r\n/g, '\\n')
24
+ .replace(/\n/g, '\\n')
25
+ .replace(/\r/g, '\\r')
26
+ .replace(/\t/g, '\\t');
27
+ }
28
+ /**
29
+ * Emit AppleScript lines that set an existing date variable to a specific
30
+ * point in time by assigning each component (year, month, day, hours, minutes,
31
+ * seconds) individually.
32
+ *
33
+ * Uses the JS Date's **local-time** getters so the resulting AppleScript date
34
+ * matches the system timezone — the same timezone Calendar.app operates in.
35
+ *
36
+ * This replaces the previous approach of converting to Unix epoch via
37
+ * `date -j … '+%s'` and coercing `(number) as date`, which fails on macOS
38
+ * because AppleScript cannot coerce large integers to dates (error -1700).
39
+ *
40
+ * @internal Exported for testing.
41
+ */
42
+ export function dateToAppleScriptLines(varName, d) {
43
+ return [
44
+ `set ${varName} to current date`,
45
+ `set year of ${varName} to ${d.getFullYear()}`,
46
+ `set month of ${varName} to ${d.getMonth() + 1}`,
47
+ `set day of ${varName} to ${d.getDate()}`,
48
+ `set hours of ${varName} to ${d.getHours()}`,
49
+ `set minutes of ${varName} to ${d.getMinutes()}`,
50
+ `set seconds of ${varName} to ${d.getSeconds()}`,
51
+ ];
52
+ }
53
+ function buildAppleScript(opts) {
54
+ const { event, calendarName, alarmMinutes, attachCount, attendeeCount, confirm } = opts;
55
+ const title = escapeAS(event.title);
56
+ const location = escapeAS(event.location ?? '');
57
+ const notes = escapeAS(event.notes ?? '');
58
+ const url = escapeAS(event.url ?? '');
59
+ const urlLabel = escapeAS(event.urlLabel ?? event.conferenceProvider ?? '');
60
+ const dialIn = escapeAS(event.dialIn ?? '');
61
+ const meetingId = escapeAS(event.meetingId ?? '');
62
+ const passcode = escapeAS(event.passcode ?? '');
63
+ const calName = escapeAS(calendarName);
64
+ const lines = [
65
+ `set eventTitle to "${title}"`,
66
+ '',
67
+ ...dateToAppleScriptLines('eventStart', event.start),
68
+ '',
69
+ ...dateToAppleScriptLines('eventEnd', event.end),
70
+ '',
71
+ ];
72
+ if (confirm) {
73
+ const dialogLines = [`\uD83D\uDCC5 ${title}`];
74
+ dialogLines.push('\uD83D\uDD50 " & (eventStart as text) & " \u2013 " & (eventEnd as text) & "');
75
+ if (location) {
76
+ dialogLines.push(`\uD83D\uDCCD ${location}`);
77
+ }
78
+ if (url) {
79
+ const domain = url.replace(/^https?:\/\//, '').split('/')[0];
80
+ dialogLines.push(`\uD83C\uDFA5 ${urlLabel || domain}`);
81
+ }
82
+ if (dialIn) {
83
+ dialogLines.push(`\uD83D\uDCDE ${dialIn}`);
84
+ }
85
+ if (meetingId) {
86
+ const pin = passcode ? ` \u00B7 PIN: ${passcode}` : '';
87
+ dialogLines.push(`\uD83D\uDD11 ID: ${meetingId}${pin}`);
88
+ }
89
+ if (attendeeCount > 0) {
90
+ dialogLines.push(`\uD83D\uDC65 ${attendeeCount} attendee${attendeeCount > 1 ? 's' : ''}`);
91
+ }
92
+ if (attachCount > 0) {
93
+ dialogLines.push(`\uD83D\uDCCE ${attachCount} attachment${attachCount > 1 ? 's' : ''} saved locally`);
94
+ }
95
+ dialogLines.push(`\uD83D\uDCC6 ${calName || 'Default Calendar'} \u00B7 \u23F0 ${alarmMinutes} min before`);
96
+ lines.push(`set dialogText to "${escapeAS(dialogLines[0])}"`);
97
+ dialogLines.slice(1).forEach((dl) => {
98
+ lines.push(`set dialogText to dialogText & return & "${escapeAS(dl)}"`);
99
+ });
100
+ lines.push('try', ' display dialog dialogText with title "email-mcp \u2014 Add Calendar Event?" buttons {"Cancel", "Add to Calendar"} default button "Add to Calendar" cancel button "Cancel" giving up after 60', ' set dlgResult to button returned of result', ' if dlgResult is not "Add to Calendar" then', ' return "{\\"status\\":\\"timed_out\\"}"', ' end if', 'on error', ' return "{\\"status\\":\\"cancelled\\"}"', 'end try', '');
101
+ }
102
+ lines.push('tell application "Calendar"');
103
+ if (calName) {
104
+ lines.push(' try', ` set theCal to first calendar whose name is "${calName}"`, ' on error', ' set theCal to first calendar', ' end try');
105
+ }
106
+ else {
107
+ lines.push(' set theCal to first calendar');
108
+ }
109
+ lines.push(' set eventProps to {summary:eventTitle, start date:eventStart, end date:eventEnd}');
110
+ if (location) {
111
+ lines.push(` set eventProps to eventProps & {location:"${location}"}`);
112
+ }
113
+ if (notes) {
114
+ lines.push(` set eventProps to eventProps & {description:"${notes}"}`);
115
+ }
116
+ if (url) {
117
+ lines.push(` set eventProps to eventProps & {url:"${url}"}`);
118
+ }
119
+ lines.push(' set theEvent to make new event at end of events of theCal with properties eventProps');
120
+ if (alarmMinutes > 0) {
121
+ lines.push(' try', ` make new display alarm at end of display alarms of theEvent with properties {trigger interval:-${alarmMinutes * 60}}`, ' end try');
122
+ }
123
+ lines.push(' set eventId to uid of theEvent', ' set finalCalName to name of theCal', 'end tell', '', 'return "{\\"status\\":\\"added\\",\\"eventId\\":\\"" & eventId & "\\",\\"calendarName\\":\\"" & finalCalName & "\\"}"');
124
+ return lines.join('\n');
125
+ }
126
+ function toICSDate(d) {
127
+ return `${d.toISOString().replace(/[-:]/g, '').split('.')[0]}Z`;
128
+ }
129
+ function escapeICS(s) {
130
+ return s.replace(/\\/g, '\\\\').replace(/;/g, '\\;').replace(/,/g, '\\,').replace(/\n/g, '\\n');
131
+ }
132
+ function buildICS(event) {
133
+ const uid = `email-mcp-${Date.now()}@local`;
134
+ const lines = [
135
+ 'BEGIN:VCALENDAR',
136
+ 'VERSION:2.0',
137
+ 'PRODID:-//email-mcp//email-mcp//EN',
138
+ 'CALSCALE:GREGORIAN',
139
+ 'METHOD:PUBLISH',
140
+ 'BEGIN:VEVENT',
141
+ `UID:${uid}`,
142
+ `DTSTAMP:${toICSDate(new Date())}`,
143
+ `DTSTART:${toICSDate(event.start)}`,
144
+ `DTEND:${toICSDate(event.end)}`,
145
+ `SUMMARY:${escapeICS(event.title)}`,
146
+ ];
147
+ if (event.location)
148
+ lines.push(`LOCATION:${escapeICS(event.location)}`);
149
+ if (event.notes)
150
+ lines.push(`DESCRIPTION:${escapeICS(event.notes)}`);
151
+ if (event.url)
152
+ lines.push(`URL:${event.url}`);
153
+ if (event.alarmMinutes) {
154
+ lines.push('BEGIN:VALARM', `TRIGGER:-PT${event.alarmMinutes}M`, 'ACTION:DISPLAY', `DESCRIPTION:${escapeICS(event.title)}`, 'END:VALARM');
155
+ }
156
+ lines.push('END:VEVENT', 'END:VCALENDAR');
157
+ return `${lines.join('\r\n')}\r\n`;
158
+ }
159
+ function statusMessage(status, title, calName) {
160
+ switch (status) {
161
+ case 'added':
162
+ return `\u2705 Event added: "${title}" \u2192 ${calName ?? 'calendar'}.`;
163
+ case 'duplicate':
164
+ return `\u26A0\uFE0F Event already exists in ${calName ?? 'calendar'}: "${title}". Skipped.`;
165
+ case 'cancelled':
166
+ return '\uD83D\uDEAB Cancelled \u2014 event was not added to the calendar.';
167
+ case 'timed_out':
168
+ return '\u23F1\uFE0F Dialog timed out after 60 s \u2014 event was not added. Try again.';
169
+ case 'no_display':
170
+ return '\u26A0\uFE0F No display available. Run check_calendar_permissions for setup instructions.';
171
+ default:
172
+ return `Unknown status: ${status}`;
173
+ }
174
+ }
175
+ async function checkPermissionsMacOS() {
176
+ const script = 'tell application "Calendar" to return count of calendars';
177
+ try {
178
+ const { stdout } = await execFile('osascript', ['-e', script], {
179
+ timeout: 10_000,
180
+ });
181
+ const count = parseInt(stdout.trim(), 10);
182
+ if (count >= 0)
183
+ return { granted: true, platform: 'darwin', instructions: [] };
184
+ }
185
+ catch {
186
+ // fall through to denied
187
+ }
188
+ return {
189
+ granted: false,
190
+ platform: 'darwin',
191
+ instructions: [
192
+ 'Calendar access was denied or unavailable.',
193
+ '1. Open System Settings (Apple menu \u2192 System Settings)',
194
+ '2. Go to Privacy & Security \u2192 Calendars',
195
+ '3. Enable access for Terminal (or your terminal emulator, e.g. iTerm2)',
196
+ '4. Quit and restart the terminal, then try again.',
197
+ ],
198
+ };
199
+ }
200
+ async function listCalendarsMacOS() {
201
+ const script = 'tell application "Calendar" to return name of every calendar';
202
+ try {
203
+ const { stdout } = await execFile('osascript', ['-e', script], {
204
+ timeout: 10_000,
205
+ });
206
+ const raw = stdout.trim();
207
+ if (!raw)
208
+ return [];
209
+ return raw.split(', ').map((name) => ({ id: name, name }));
210
+ }
211
+ catch {
212
+ return [];
213
+ }
214
+ }
215
+ async function findExistingEventMacOS(title, _start, _icsUid) {
216
+ const searchTitle = escapeAS(title);
217
+ const script = `
218
+ set searchTitle to "${searchTitle}"
219
+ tell application "Calendar"
220
+ repeat with c in calendars
221
+ try
222
+ set evList to (every event of c whose summary is searchTitle)
223
+ if (count of evList) > 0 then
224
+ set theEvent to item 1 of evList
225
+ set eventId to uid of theEvent
226
+ set calName to name of c
227
+ return "{\\"found\\":true,\\"eventId\\":\\"" & eventId & "\\",\\"calendarName\\":\\"" & calName & "\\"}"
228
+ end if
229
+ end try
230
+ end repeat
231
+ end tell
232
+ return "{\\"found\\":false}"
233
+ `;
234
+ try {
235
+ const { stdout } = await execFile('osascript', ['-e', script], {
236
+ timeout: 10_000,
237
+ });
238
+ return JSON.parse(stdout.trim());
239
+ }
240
+ catch {
241
+ return { found: false };
242
+ }
243
+ }
244
+ async function addEventMacOS(event, calendarName, confirm) {
245
+ const alarmMinutes = event.alarmMinutes ?? 15;
246
+ const attachCount = (event.savedAttachments?.length ?? 0) + (event.pendingAttachments?.length ?? 0);
247
+ const attendeeCount = event.attendeeCount ?? 0;
248
+ const script = buildAppleScript({
249
+ event,
250
+ calendarName: calendarName ?? '',
251
+ alarmMinutes,
252
+ attachCount,
253
+ attendeeCount,
254
+ confirm,
255
+ });
256
+ try {
257
+ const { stdout } = await execFile('osascript', ['-e', script], {
258
+ timeout: 90_000,
259
+ });
260
+ const result = JSON.parse(stdout.trim());
261
+ return {
262
+ status: result.status,
263
+ eventId: result.eventId,
264
+ calendarName: result.calendarName,
265
+ message: statusMessage(result.status, event.title, result.calendarName),
266
+ };
267
+ }
268
+ catch (err) {
269
+ const msg = err instanceof Error ? err.message : String(err);
270
+ if (/user canceled|(-128)/i.test(msg)) {
271
+ return { status: 'cancelled', message: 'Cancelled by user.' };
272
+ }
273
+ if (/not authorized|access/i.test(msg)) {
274
+ return {
275
+ status: 'no_display',
276
+ message: 'Calendar access denied. Run check_calendar_permissions for setup instructions.',
277
+ };
278
+ }
279
+ return { status: 'no_display', message: `Could not add event: ${msg}` };
280
+ }
281
+ }
282
+ async function addEventLinux(event, _calendarName) {
283
+ const tmpFile = join(tmpdir(), `email-mcp-event-${Date.now()}.ics`);
284
+ const ics = buildICS(event);
285
+ await writeFile(tmpFile, ics, 'utf8');
286
+ try {
287
+ await execFile('xdg-open', [tmpFile], { timeout: 10_000 });
288
+ return {
289
+ status: 'added',
290
+ message: `Calendar file opened: ${event.title}. Confirm import in your calendar application.`,
291
+ };
292
+ }
293
+ catch (err) {
294
+ const msg = err instanceof Error ? err.message : String(err);
295
+ return {
296
+ status: 'no_display',
297
+ message: `Could not open calendar app (xdg-open failed): ${msg}`,
298
+ };
299
+ }
300
+ }
301
+ async function listEventsMacOS(opts) {
302
+ const limit = opts.limit ?? 20;
303
+ const titleFilter = opts.title ? escapeAS(opts.title) : '';
304
+ const calFilter = opts.calendarName ? escapeAS(opts.calendarName) : '';
305
+ // Default range: today ± 30 days
306
+ const now = new Date();
307
+ const defaultFrom = new Date(now);
308
+ defaultFrom.setDate(defaultFrom.getDate() - 7);
309
+ const defaultTo = new Date(now);
310
+ defaultTo.setDate(defaultTo.getDate() + 30);
311
+ const fromDate = opts.from ? new Date(opts.from) : defaultFrom;
312
+ const toDate = opts.to ? new Date(opts.to) : defaultTo;
313
+ const script = `
314
+ set fromDate to current date
315
+ ${dateToAppleScriptLines('fromDate', fromDate).slice(1).join('\n')}
316
+
317
+ set toDate to current date
318
+ ${dateToAppleScriptLines('toDate', toDate).slice(1).join('\n')}
319
+
320
+ set jsonResult to "["
321
+ set resultCount to 0
322
+ set maxResults to ${limit}
323
+ set titleFilter to "${titleFilter}"
324
+ set calFilter to "${calFilter}"
325
+
326
+ tell application "Calendar"
327
+ repeat with c in calendars
328
+ if resultCount ≥ maxResults then exit repeat
329
+ set calName to name of c
330
+ if calFilter is "" or calName is calFilter then
331
+ try
332
+ set evList to (every event of c whose start date ≥ fromDate and start date ≤ toDate)
333
+ repeat with ev in evList
334
+ if resultCount ≥ maxResults then exit repeat
335
+ set evTitle to summary of ev
336
+ set matchesTitle to true
337
+ if titleFilter is not "" then
338
+ considering case
339
+ if evTitle does not contain titleFilter then set matchesTitle to false
340
+ end considering
341
+ ignoring case
342
+ if not matchesTitle then
343
+ if evTitle contains titleFilter then set matchesTitle to true
344
+ end if
345
+ end ignoring
346
+ end if
347
+ if matchesTitle then
348
+ set evId to uid of ev
349
+ set evStart to start date of ev
350
+ set evEnd to end date of ev
351
+ set evLoc to ""
352
+ try
353
+ set evLoc to location of ev
354
+ end try
355
+ if evLoc is missing value then set evLoc to ""
356
+ if resultCount > 0 then set jsonResult to jsonResult & ","
357
+ set jsonResult to jsonResult & "{\\"id\\":\\"" & evId & "\\",\\"title\\":\\"" & evTitle & "\\",\\"start\\":\\"" & (evStart as text) & "\\",\\"end\\":\\"" & (evEnd as text) & "\\",\\"location\\":\\"" & evLoc & "\\",\\"calendar\\":\\"" & calName & "\\"}"
358
+ set resultCount to resultCount + 1
359
+ end if
360
+ end repeat
361
+ end try
362
+ end if
363
+ end repeat
364
+ end tell
365
+
366
+ set jsonResult to jsonResult & "]"
367
+ return jsonResult
368
+ `;
369
+ try {
370
+ const { stdout } = await execFile('osascript', ['-e', script], { timeout: 15_000 });
371
+ return JSON.parse(stdout.trim());
372
+ }
373
+ catch {
374
+ return [];
375
+ }
376
+ }
377
+ // ---------------------------------------------------------------------------
378
+ // Service
379
+ // ---------------------------------------------------------------------------
380
+ export default class LocalCalendarService {
381
+ platform = process.platform;
382
+ async checkPermissions() {
383
+ if (this.platform === 'darwin')
384
+ return checkPermissionsMacOS();
385
+ return { granted: true, platform: 'linux', instructions: [] };
386
+ }
387
+ async listCalendars() {
388
+ if (this.platform !== 'darwin') {
389
+ return [{ id: 'default', name: 'Default Calendar' }];
390
+ }
391
+ return listCalendarsMacOS();
392
+ }
393
+ /** Check all calendars for an existing event matching by ICS UID or title+startDate. */
394
+ async findExistingEvent(title, start, icsUid) {
395
+ if (this.platform !== 'darwin')
396
+ return { found: false };
397
+ return findExistingEventMacOS(title, start, icsUid);
398
+ }
399
+ async addEvent(event, calendarName, opts = {}) {
400
+ const confirm = opts.confirm !== false;
401
+ // Duplicate detection (macOS only, can opt out)
402
+ if (this.platform === 'darwin' && opts.skipDuplicateCheck !== true) {
403
+ const existing = await findExistingEventMacOS(event.title, event.start, event.icsUid);
404
+ if (existing.found) {
405
+ return {
406
+ status: 'duplicate',
407
+ eventId: existing.eventId,
408
+ calendarName: existing.calendarName,
409
+ message: statusMessage('duplicate', event.title, existing.calendarName),
410
+ duplicate: existing.found
411
+ ? { eventId: existing.eventId ?? '', calendarName: existing.calendarName ?? '' }
412
+ : undefined,
413
+ };
414
+ }
415
+ }
416
+ if (this.platform === 'darwin') {
417
+ return addEventMacOS(event, calendarName, confirm);
418
+ }
419
+ return addEventLinux(event, calendarName);
420
+ }
421
+ /** List calendar events matching the given filters. */
422
+ async listEvents(opts = {}) {
423
+ if (this.platform !== 'darwin')
424
+ return [];
425
+ return listEventsMacOS(opts);
426
+ }
427
+ }
428
+ //# sourceMappingURL=local-calendar.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-calendar.service.js","sourceRoot":"","sources":["../../src/services/local-calendar.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * NotifierService — multi-channel notification dispatcher.
3
+ *
4
+ * Routes email alerts to the appropriate channels based on urgency:
5
+ * - Desktop notifications (native OS commands — zero npm deps)
6
+ * - Sound alerts (via OS notification sound)
7
+ * - MCP log level escalation (urgent→alert, high→warning, …)
8
+ * - Webhook dispatch (HTTP POST to Slack/Discord/ntfy.sh/etc.)
9
+ *
10
+ * All channels are opt-in and disabled by default.
11
+ */
12
+ import type { AlertsConfig } from '../types/index.js';
13
+ export type UrgencyLevel = 'urgent' | 'high' | 'normal' | 'low';
14
+ export interface AlertPayload {
15
+ account: string;
16
+ sender: {
17
+ name?: string;
18
+ address: string;
19
+ };
20
+ subject: string;
21
+ priority: UrgencyLevel;
22
+ labels?: string[];
23
+ ruleName?: string;
24
+ uid?: string;
25
+ folder?: string;
26
+ hasAttachments?: boolean;
27
+ }
28
+ export interface PlatformDiagnostics {
29
+ platform: string;
30
+ supported: boolean;
31
+ desktopTool: {
32
+ name: string;
33
+ available: boolean;
34
+ };
35
+ soundTool: {
36
+ name: string;
37
+ available: boolean;
38
+ };
39
+ issues: string[];
40
+ setupInstructions: string[];
41
+ }
42
+ export default class NotifierService {
43
+ private config;
44
+ private desktopCount;
45
+ private desktopResetTimer;
46
+ private static readonly MAX_DESKTOP_PER_MIN;
47
+ constructor(config: AlertsConfig);
48
+ stop(): void;
49
+ /** Returns the current alerts configuration. */
50
+ getConfig(): AlertsConfig;
51
+ /** Updates alert configuration at runtime (partial merge). */
52
+ updateConfig(partial: Partial<AlertsConfig>): AlertsConfig;
53
+ static checkPlatformSupport(): Promise<PlatformDiagnostics>;
54
+ /** Test if a command-line tool exists on the system. */
55
+ private static commandExists;
56
+ /** Send a test notification to verify platform setup. */
57
+ sendTestNotification(withSound?: boolean): Promise<{
58
+ success: boolean;
59
+ message: string;
60
+ }>;
61
+ alert(payload: AlertPayload, forceDesktop?: boolean): Promise<void>;
62
+ private sendDesktopNotification;
63
+ private static execDarwin;
64
+ private static execLinux;
65
+ private static execWindows;
66
+ private static execCommand;
67
+ private sendWebhook;
68
+ }
69
+ //# sourceMappingURL=notifier.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notifier.service.d.ts","sourceRoot":"","sources":["../../src/services/notifier.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAMtD,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEhE,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,YAAY,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;IAClD,SAAS,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;IAChD,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B;AAoCD,MAAM,CAAC,OAAO,OAAO,eAAe;IAClC,OAAO,CAAC,MAAM,CAAe;IAE7B,OAAO,CAAC,YAAY,CAAK;IAEzB,OAAO,CAAC,iBAAiB,CAA+C;IAExE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAK;gBAEpC,MAAM,EAAE,YAAY;IAShC,IAAI,IAAI,IAAI;IAOZ,gDAAgD;IAChD,SAAS,IAAI,YAAY;IAIzB,8DAA8D;IAC9D,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY;WAS7C,oBAAoB,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAkGjE,wDAAwD;mBACnC,aAAa;IASlC,yDAAyD;IACnD,oBAAoB,CAAC,SAAS,UAAQ,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IA6CvF,KAAK,CAAC,OAAO,EAAE,YAAY,EAAE,YAAY,UAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;YA2BzD,uBAAuB;mBA2BhB,UAAU;mBAMV,SAAS;mBAcT,WAAW;mBAUX,WAAW;YAalB,WAAW;CAiD1B"}