@jbctechsolutions/mcp-office365 2.5.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 (339) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +667 -0
  3. package/dist/applescript/account-repository.d.ts +30 -0
  4. package/dist/applescript/account-repository.d.ts.map +1 -0
  5. package/dist/applescript/account-repository.js +38 -0
  6. package/dist/applescript/account-repository.js.map +1 -0
  7. package/dist/applescript/account-scripts.d.ts +21 -0
  8. package/dist/applescript/account-scripts.d.ts.map +1 -0
  9. package/dist/applescript/account-scripts.js +180 -0
  10. package/dist/applescript/account-scripts.js.map +1 -0
  11. package/dist/applescript/calendar-manager.d.ts +44 -0
  12. package/dist/applescript/calendar-manager.d.ts.map +1 -0
  13. package/dist/applescript/calendar-manager.js +92 -0
  14. package/dist/applescript/calendar-manager.js.map +1 -0
  15. package/dist/applescript/calendar-writer.d.ts +36 -0
  16. package/dist/applescript/calendar-writer.d.ts.map +1 -0
  17. package/dist/applescript/calendar-writer.js +94 -0
  18. package/dist/applescript/calendar-writer.js.map +1 -0
  19. package/dist/applescript/content-readers.d.ts +114 -0
  20. package/dist/applescript/content-readers.d.ts.map +1 -0
  21. package/dist/applescript/content-readers.js +328 -0
  22. package/dist/applescript/content-readers.js.map +1 -0
  23. package/dist/applescript/executor.d.ts +60 -0
  24. package/dist/applescript/executor.d.ts.map +1 -0
  25. package/dist/applescript/executor.js +173 -0
  26. package/dist/applescript/executor.js.map +1 -0
  27. package/dist/applescript/index.d.ts +20 -0
  28. package/dist/applescript/index.d.ts.map +1 -0
  29. package/dist/applescript/index.js +29 -0
  30. package/dist/applescript/index.js.map +1 -0
  31. package/dist/applescript/mail-sender.d.ts +38 -0
  32. package/dist/applescript/mail-sender.d.ts.map +1 -0
  33. package/dist/applescript/mail-sender.js +67 -0
  34. package/dist/applescript/mail-sender.js.map +1 -0
  35. package/dist/applescript/parser.d.ts +235 -0
  36. package/dist/applescript/parser.d.ts.map +1 -0
  37. package/dist/applescript/parser.js +496 -0
  38. package/dist/applescript/parser.js.map +1 -0
  39. package/dist/applescript/repository.d.ts +64 -0
  40. package/dist/applescript/repository.d.ts.map +1 -0
  41. package/dist/applescript/repository.js +444 -0
  42. package/dist/applescript/repository.js.map +1 -0
  43. package/dist/applescript/scripts.d.ts +265 -0
  44. package/dist/applescript/scripts.d.ts.map +1 -0
  45. package/dist/applescript/scripts.js +1483 -0
  46. package/dist/applescript/scripts.js.map +1 -0
  47. package/dist/approval/hash.d.ts +87 -0
  48. package/dist/approval/hash.d.ts.map +1 -0
  49. package/dist/approval/hash.js +102 -0
  50. package/dist/approval/hash.js.map +1 -0
  51. package/dist/approval/index.d.ts +13 -0
  52. package/dist/approval/index.d.ts.map +1 -0
  53. package/dist/approval/index.js +7 -0
  54. package/dist/approval/index.js.map +1 -0
  55. package/dist/approval/token-manager.d.ts +51 -0
  56. package/dist/approval/token-manager.d.ts.map +1 -0
  57. package/dist/approval/token-manager.js +111 -0
  58. package/dist/approval/token-manager.js.map +1 -0
  59. package/dist/approval/types.d.ts +44 -0
  60. package/dist/approval/types.d.ts.map +1 -0
  61. package/dist/approval/types.js +6 -0
  62. package/dist/approval/types.js.map +1 -0
  63. package/dist/cli.d.ts +30 -0
  64. package/dist/cli.d.ts.map +1 -0
  65. package/dist/cli.js +143 -0
  66. package/dist/cli.js.map +1 -0
  67. package/dist/config.d.ts +27 -0
  68. package/dist/config.d.ts.map +1 -0
  69. package/dist/config.js +42 -0
  70. package/dist/config.js.map +1 -0
  71. package/dist/database/connection.d.ts +77 -0
  72. package/dist/database/connection.d.ts.map +1 -0
  73. package/dist/database/connection.js +130 -0
  74. package/dist/database/connection.js.map +1 -0
  75. package/dist/database/index.d.ts +11 -0
  76. package/dist/database/index.d.ts.map +1 -0
  77. package/dist/database/index.js +11 -0
  78. package/dist/database/index.js.map +1 -0
  79. package/dist/database/queries.d.ts +93 -0
  80. package/dist/database/queries.d.ts.map +1 -0
  81. package/dist/database/queries.js +430 -0
  82. package/dist/database/queries.js.map +1 -0
  83. package/dist/database/repository.d.ts +198 -0
  84. package/dist/database/repository.d.ts.map +1 -0
  85. package/dist/database/repository.js +199 -0
  86. package/dist/database/repository.js.map +1 -0
  87. package/dist/graph/attachments.d.ts +72 -0
  88. package/dist/graph/attachments.d.ts.map +1 -0
  89. package/dist/graph/attachments.js +207 -0
  90. package/dist/graph/attachments.js.map +1 -0
  91. package/dist/graph/auth/config.d.ts +34 -0
  92. package/dist/graph/auth/config.d.ts.map +1 -0
  93. package/dist/graph/auth/config.js +78 -0
  94. package/dist/graph/auth/config.js.map +1 -0
  95. package/dist/graph/auth/device-code-flow.d.ts +55 -0
  96. package/dist/graph/auth/device-code-flow.d.ts.map +1 -0
  97. package/dist/graph/auth/device-code-flow.js +180 -0
  98. package/dist/graph/auth/device-code-flow.js.map +1 -0
  99. package/dist/graph/auth/index.d.ts +13 -0
  100. package/dist/graph/auth/index.d.ts.map +1 -0
  101. package/dist/graph/auth/index.js +13 -0
  102. package/dist/graph/auth/index.js.map +1 -0
  103. package/dist/graph/auth/token-cache.d.ts +41 -0
  104. package/dist/graph/auth/token-cache.d.ts.map +1 -0
  105. package/dist/graph/auth/token-cache.js +105 -0
  106. package/dist/graph/auth/token-cache.js.map +1 -0
  107. package/dist/graph/client/batch.d.ts +38 -0
  108. package/dist/graph/client/batch.d.ts.map +1 -0
  109. package/dist/graph/client/batch.js +33 -0
  110. package/dist/graph/client/batch.js.map +1 -0
  111. package/dist/graph/client/cache.d.ts +64 -0
  112. package/dist/graph/client/cache.d.ts.map +1 -0
  113. package/dist/graph/client/cache.js +108 -0
  114. package/dist/graph/client/cache.js.map +1 -0
  115. package/dist/graph/client/graph-client.d.ts +630 -0
  116. package/dist/graph/client/graph-client.d.ts.map +1 -0
  117. package/dist/graph/client/graph-client.js +1771 -0
  118. package/dist/graph/client/graph-client.js.map +1 -0
  119. package/dist/graph/client/index.d.ts +12 -0
  120. package/dist/graph/client/index.d.ts.map +1 -0
  121. package/dist/graph/client/index.js +12 -0
  122. package/dist/graph/client/index.js.map +1 -0
  123. package/dist/graph/content-readers.d.ts +106 -0
  124. package/dist/graph/content-readers.d.ts.map +1 -0
  125. package/dist/graph/content-readers.js +321 -0
  126. package/dist/graph/content-readers.js.map +1 -0
  127. package/dist/graph/index.d.ts +18 -0
  128. package/dist/graph/index.d.ts.map +1 -0
  129. package/dist/graph/index.js +23 -0
  130. package/dist/graph/index.js.map +1 -0
  131. package/dist/graph/mailbox-adapter.d.ts +30 -0
  132. package/dist/graph/mailbox-adapter.d.ts.map +1 -0
  133. package/dist/graph/mailbox-adapter.js +59 -0
  134. package/dist/graph/mailbox-adapter.js.map +1 -0
  135. package/dist/graph/mappers/contact-mapper.d.ts +14 -0
  136. package/dist/graph/mappers/contact-mapper.d.ts.map +1 -0
  137. package/dist/graph/mappers/contact-mapper.js +20 -0
  138. package/dist/graph/mappers/contact-mapper.js.map +1 -0
  139. package/dist/graph/mappers/email-mapper.d.ts +14 -0
  140. package/dist/graph/mappers/email-mapper.d.ts.map +1 -0
  141. package/dist/graph/mappers/email-mapper.js +44 -0
  142. package/dist/graph/mappers/email-mapper.js.map +1 -0
  143. package/dist/graph/mappers/event-mapper.d.ts +14 -0
  144. package/dist/graph/mappers/event-mapper.d.ts.map +1 -0
  145. package/dist/graph/mappers/event-mapper.js +31 -0
  146. package/dist/graph/mappers/event-mapper.js.map +1 -0
  147. package/dist/graph/mappers/folder-mapper.d.ts +22 -0
  148. package/dist/graph/mappers/folder-mapper.d.ts.map +1 -0
  149. package/dist/graph/mappers/folder-mapper.js +51 -0
  150. package/dist/graph/mappers/folder-mapper.js.map +1 -0
  151. package/dist/graph/mappers/index.d.ts +16 -0
  152. package/dist/graph/mappers/index.d.ts.map +1 -0
  153. package/dist/graph/mappers/index.js +16 -0
  154. package/dist/graph/mappers/index.js.map +1 -0
  155. package/dist/graph/mappers/task-mapper.d.ts +20 -0
  156. package/dist/graph/mappers/task-mapper.d.ts.map +1 -0
  157. package/dist/graph/mappers/task-mapper.js +27 -0
  158. package/dist/graph/mappers/task-mapper.js.map +1 -0
  159. package/dist/graph/mappers/utils.d.ts +97 -0
  160. package/dist/graph/mappers/utils.d.ts.map +1 -0
  161. package/dist/graph/mappers/utils.js +186 -0
  162. package/dist/graph/mappers/utils.js.map +1 -0
  163. package/dist/graph/repository.d.ts +1104 -0
  164. package/dist/graph/repository.d.ts.map +1 -0
  165. package/dist/graph/repository.js +2999 -0
  166. package/dist/graph/repository.js.map +1 -0
  167. package/dist/index.d.ts +21 -0
  168. package/dist/index.d.ts.map +1 -0
  169. package/dist/index.js +6052 -0
  170. package/dist/index.js.map +1 -0
  171. package/dist/parsers/html-stripper.d.ts +41 -0
  172. package/dist/parsers/html-stripper.d.ts.map +1 -0
  173. package/dist/parsers/html-stripper.js +179 -0
  174. package/dist/parsers/html-stripper.js.map +1 -0
  175. package/dist/parsers/index.d.ts +12 -0
  176. package/dist/parsers/index.d.ts.map +1 -0
  177. package/dist/parsers/index.js +12 -0
  178. package/dist/parsers/index.js.map +1 -0
  179. package/dist/parsers/olk15.d.ts +87 -0
  180. package/dist/parsers/olk15.d.ts.map +1 -0
  181. package/dist/parsers/olk15.js +368 -0
  182. package/dist/parsers/olk15.js.map +1 -0
  183. package/dist/signature.d.ts +22 -0
  184. package/dist/signature.d.ts.map +1 -0
  185. package/dist/signature.js +89 -0
  186. package/dist/signature.js.map +1 -0
  187. package/dist/tools/calendar-permissions.d.ts +79 -0
  188. package/dist/tools/calendar-permissions.d.ts.map +1 -0
  189. package/dist/tools/calendar-permissions.js +121 -0
  190. package/dist/tools/calendar-permissions.js.map +1 -0
  191. package/dist/tools/calendar.d.ts +208 -0
  192. package/dist/tools/calendar.d.ts.map +1 -0
  193. package/dist/tools/calendar.js +247 -0
  194. package/dist/tools/calendar.js.map +1 -0
  195. package/dist/tools/categories.d.ts +94 -0
  196. package/dist/tools/categories.d.ts.map +1 -0
  197. package/dist/tools/categories.js +117 -0
  198. package/dist/tools/categories.js.map +1 -0
  199. package/dist/tools/checklist-items.d.ts +89 -0
  200. package/dist/tools/checklist-items.d.ts.map +1 -0
  201. package/dist/tools/checklist-items.js +140 -0
  202. package/dist/tools/checklist-items.js.map +1 -0
  203. package/dist/tools/contacts.d.ts +94 -0
  204. package/dist/tools/contacts.d.ts.map +1 -0
  205. package/dist/tools/contacts.js +134 -0
  206. package/dist/tools/contacts.js.map +1 -0
  207. package/dist/tools/excel.d.ts +96 -0
  208. package/dist/tools/excel.d.ts.map +1 -0
  209. package/dist/tools/excel.js +165 -0
  210. package/dist/tools/excel.js.map +1 -0
  211. package/dist/tools/focused-overrides.d.ts +70 -0
  212. package/dist/tools/focused-overrides.d.ts.map +1 -0
  213. package/dist/tools/focused-overrides.js +117 -0
  214. package/dist/tools/focused-overrides.js.map +1 -0
  215. package/dist/tools/index.d.ts +22 -0
  216. package/dist/tools/index.d.ts.map +1 -0
  217. package/dist/tools/index.js +34 -0
  218. package/dist/tools/index.js.map +1 -0
  219. package/dist/tools/linked-resources.d.ts +74 -0
  220. package/dist/tools/linked-resources.d.ts.map +1 -0
  221. package/dist/tools/linked-resources.js +122 -0
  222. package/dist/tools/linked-resources.js.map +1 -0
  223. package/dist/tools/mail-rules.d.ts +98 -0
  224. package/dist/tools/mail-rules.d.ts.map +1 -0
  225. package/dist/tools/mail-rules.js +169 -0
  226. package/dist/tools/mail-rules.js.map +1 -0
  227. package/dist/tools/mail-send.d.ts +314 -0
  228. package/dist/tools/mail-send.d.ts.map +1 -0
  229. package/dist/tools/mail-send.js +555 -0
  230. package/dist/tools/mail-send.js.map +1 -0
  231. package/dist/tools/mail.d.ts +127 -0
  232. package/dist/tools/mail.d.ts.map +1 -0
  233. package/dist/tools/mail.js +311 -0
  234. package/dist/tools/mail.js.map +1 -0
  235. package/dist/tools/mailbox-organization.d.ts +301 -0
  236. package/dist/tools/mailbox-organization.d.ts.map +1 -0
  237. package/dist/tools/mailbox-organization.js +541 -0
  238. package/dist/tools/mailbox-organization.js.map +1 -0
  239. package/dist/tools/meetings.d.ts +114 -0
  240. package/dist/tools/meetings.d.ts.map +1 -0
  241. package/dist/tools/meetings.js +110 -0
  242. package/dist/tools/meetings.js.map +1 -0
  243. package/dist/tools/notes.d.ts +74 -0
  244. package/dist/tools/notes.d.ts.map +1 -0
  245. package/dist/tools/notes.js +136 -0
  246. package/dist/tools/notes.js.map +1 -0
  247. package/dist/tools/onedrive.d.ts +194 -0
  248. package/dist/tools/onedrive.d.ts.map +1 -0
  249. package/dist/tools/onedrive.js +257 -0
  250. package/dist/tools/onedrive.js.map +1 -0
  251. package/dist/tools/people.d.ts +129 -0
  252. package/dist/tools/people.d.ts.map +1 -0
  253. package/dist/tools/people.js +195 -0
  254. package/dist/tools/people.js.map +1 -0
  255. package/dist/tools/planner-visualization.d.ts +91 -0
  256. package/dist/tools/planner-visualization.d.ts.map +1 -0
  257. package/dist/tools/planner-visualization.js +192 -0
  258. package/dist/tools/planner-visualization.js.map +1 -0
  259. package/dist/tools/planner.d.ts +288 -0
  260. package/dist/tools/planner.d.ts.map +1 -0
  261. package/dist/tools/planner.js +368 -0
  262. package/dist/tools/planner.js.map +1 -0
  263. package/dist/tools/scheduling.d.ts +49 -0
  264. package/dist/tools/scheduling.d.ts.map +1 -0
  265. package/dist/tools/scheduling.js +115 -0
  266. package/dist/tools/scheduling.js.map +1 -0
  267. package/dist/tools/sharepoint.d.ts +115 -0
  268. package/dist/tools/sharepoint.d.ts.map +1 -0
  269. package/dist/tools/sharepoint.js +99 -0
  270. package/dist/tools/sharepoint.js.map +1 -0
  271. package/dist/tools/task-attachments.d.ts +74 -0
  272. package/dist/tools/task-attachments.d.ts.map +1 -0
  273. package/dist/tools/task-attachments.js +122 -0
  274. package/dist/tools/task-attachments.js.map +1 -0
  275. package/dist/tools/tasks.d.ts +74 -0
  276. package/dist/tools/tasks.d.ts.map +1 -0
  277. package/dist/tools/tasks.js +126 -0
  278. package/dist/tools/tasks.js.map +1 -0
  279. package/dist/tools/teams.d.ts +389 -0
  280. package/dist/tools/teams.d.ts.map +1 -0
  281. package/dist/tools/teams.js +546 -0
  282. package/dist/tools/teams.js.map +1 -0
  283. package/dist/types/calendar.d.ts +60 -0
  284. package/dist/types/calendar.d.ts.map +1 -0
  285. package/dist/types/calendar.js +15 -0
  286. package/dist/types/calendar.js.map +1 -0
  287. package/dist/types/contacts.d.ts +96 -0
  288. package/dist/types/contacts.d.ts.map +1 -0
  289. package/dist/types/contacts.js +41 -0
  290. package/dist/types/contacts.js.map +1 -0
  291. package/dist/types/index.d.ts +15 -0
  292. package/dist/types/index.d.ts.map +1 -0
  293. package/dist/types/index.js +16 -0
  294. package/dist/types/index.js.map +1 -0
  295. package/dist/types/mail.d.ts +108 -0
  296. package/dist/types/mail.d.ts.map +1 -0
  297. package/dist/types/mail.js +40 -0
  298. package/dist/types/mail.js.map +1 -0
  299. package/dist/types/notes.d.ts +26 -0
  300. package/dist/types/notes.d.ts.map +1 -0
  301. package/dist/types/notes.js +6 -0
  302. package/dist/types/notes.js.map +1 -0
  303. package/dist/types/tasks.d.ts +31 -0
  304. package/dist/types/tasks.d.ts.map +1 -0
  305. package/dist/types/tasks.js +6 -0
  306. package/dist/types/tasks.js.map +1 -0
  307. package/dist/utils/dates.d.ts +66 -0
  308. package/dist/utils/dates.d.ts.map +1 -0
  309. package/dist/utils/dates.js +94 -0
  310. package/dist/utils/dates.js.map +1 -0
  311. package/dist/utils/errors.d.ts +218 -0
  312. package/dist/utils/errors.d.ts.map +1 -0
  313. package/dist/utils/errors.js +306 -0
  314. package/dist/utils/errors.js.map +1 -0
  315. package/dist/utils/index.d.ts +10 -0
  316. package/dist/utils/index.d.ts.map +1 -0
  317. package/dist/utils/index.js +10 -0
  318. package/dist/utils/index.js.map +1 -0
  319. package/dist/visualization/html.d.ts +26 -0
  320. package/dist/visualization/html.d.ts.map +1 -0
  321. package/dist/visualization/html.js +306 -0
  322. package/dist/visualization/html.js.map +1 -0
  323. package/dist/visualization/markdown.d.ts +25 -0
  324. package/dist/visualization/markdown.d.ts.map +1 -0
  325. package/dist/visualization/markdown.js +186 -0
  326. package/dist/visualization/markdown.js.map +1 -0
  327. package/dist/visualization/mermaid.d.ts +25 -0
  328. package/dist/visualization/mermaid.d.ts.map +1 -0
  329. package/dist/visualization/mermaid.js +158 -0
  330. package/dist/visualization/mermaid.js.map +1 -0
  331. package/dist/visualization/svg.d.ts +25 -0
  332. package/dist/visualization/svg.d.ts.map +1 -0
  333. package/dist/visualization/svg.js +282 -0
  334. package/dist/visualization/svg.js.map +1 -0
  335. package/dist/visualization/types.d.ts +43 -0
  336. package/dist/visualization/types.d.ts.map +1 -0
  337. package/dist/visualization/types.js +34 -0
  338. package/dist/visualization/types.js.map +1 -0
  339. package/package.json +88 -0
@@ -0,0 +1,1483 @@
1
+ /**
2
+ * Copyright (c) 2026 JBC Tech Solutions, LLC
3
+ * Licensed under the MIT License. See LICENSE file in the project root.
4
+ */
5
+ /**
6
+ * AppleScript template strings for Outlook operations.
7
+ *
8
+ * All scripts output data in a delimiter-based format for reliable parsing:
9
+ * - Records are separated by {{RECORD}}
10
+ * - Fields are separated by {{FIELD}}
11
+ * - Field names and values are separated by {{=}}
12
+ *
13
+ * Example output: {{RECORD}}id{{=}}1{{FIELD}}name{{=}}Inbox{{FIELD}}unread{{=}}5{{RECORD}}...
14
+ */
15
+ import { escapeForAppleScript } from './executor.js';
16
+ // =============================================================================
17
+ // Delimiters
18
+ // =============================================================================
19
+ export const DELIMITERS = {
20
+ RECORD: '{{RECORD}}',
21
+ FIELD: '{{FIELD}}',
22
+ EQUALS: '{{=}}',
23
+ NULL: '{{NULL}}',
24
+ };
25
+ // =============================================================================
26
+ // Mail Scripts
27
+ // =============================================================================
28
+ /**
29
+ * Lists all mail folders with their properties.
30
+ */
31
+ export const LIST_MAIL_FOLDERS = `
32
+ tell application "Microsoft Outlook"
33
+ set output to ""
34
+ set allFolders to mail folders
35
+ repeat with f in allFolders
36
+ try
37
+ set fId to id of f
38
+ set fName to name of f
39
+ set uCount to unread count of f
40
+ set output to output & "{{RECORD}}id{{=}}" & fId & "{{FIELD}}name{{=}}" & fName & "{{FIELD}}unreadCount{{=}}" & uCount
41
+ end try
42
+ end repeat
43
+ return output
44
+ end tell
45
+ `;
46
+ /**
47
+ * Gets messages from a specific folder.
48
+ */
49
+ export function listMessages(folderId, limit, offset, unreadOnly) {
50
+ const unreadFilter = unreadOnly ? ' whose is read is false' : '';
51
+ const totalToFetch = limit + offset;
52
+ return `
53
+ tell application "Microsoft Outlook"
54
+ set output to ""
55
+ set targetFolder to mail folder id ${folderId}
56
+ set allMsgs to (messages of targetFolder${unreadFilter})
57
+ set msgCount to count of allMsgs
58
+ set startIdx to ${offset + 1}
59
+ set endIdx to ${totalToFetch}
60
+ if endIdx > msgCount then set endIdx to msgCount
61
+ if startIdx > msgCount then return ""
62
+
63
+ repeat with i from startIdx to endIdx
64
+ try
65
+ set m to item i of allMsgs
66
+ set mId to id of m
67
+ set mSubject to subject of m
68
+ set mSender to ""
69
+ try
70
+ set mSender to address of sender of m
71
+ end try
72
+ set mSenderName to ""
73
+ try
74
+ set mSenderName to name of sender of m
75
+ end try
76
+ set mDate to ""
77
+ try
78
+ set mDate to time received of m as «class isot» as string
79
+ end try
80
+ set mRead to is read of m
81
+ set mPriority to "normal"
82
+ try
83
+ set p to priority of m
84
+ if p is priority high then
85
+ set mPriority to "high"
86
+ else if p is priority low then
87
+ set mPriority to "low"
88
+ end if
89
+ end try
90
+ set mPreview to ""
91
+ try
92
+ set mPreview to text 1 thru 200 of plain text content of m
93
+ on error
94
+ try
95
+ set mPreview to plain text content of m
96
+ end try
97
+ end try
98
+
99
+ set output to output & "{{RECORD}}id{{=}}" & mId & "{{FIELD}}subject{{=}}" & mSubject & "{{FIELD}}senderEmail{{=}}" & mSender & "{{FIELD}}senderName{{=}}" & mSenderName & "{{FIELD}}dateReceived{{=}}" & mDate & "{{FIELD}}isRead{{=}}" & mRead & "{{FIELD}}priority{{=}}" & mPriority & "{{FIELD}}preview{{=}}" & mPreview
100
+ end try
101
+ end repeat
102
+ return output
103
+ end tell
104
+ `;
105
+ }
106
+ /**
107
+ * Maximum number of messages to scan for sender-address matches.
108
+ * Keeps execution within the 30s AppleScript timeout.
109
+ */
110
+ const SENDER_SCAN_LIMIT = 500;
111
+ /**
112
+ * Searches messages by query.
113
+ *
114
+ * Uses a two-phase approach to avoid crashes on emails with unresolvable sender
115
+ * addresses (the AppleScript WHERE clause cannot use try/catch):
116
+ * Phase 1 — subject matches via a safe WHERE clause
117
+ * Phase 2 — sender matches via a loop with try/catch protection
118
+ */
119
+ export function searchMessages(query, folderId, limit) {
120
+ const escapedQuery = escapeForAppleScript(query);
121
+ const folderClause = folderId != null ? `of mail folder id ${folderId}` : '';
122
+ return `
123
+ tell application "Microsoft Outlook"
124
+ set output to ""
125
+ set matchedIds to {}
126
+ set resultCount to 0
127
+ set maxResults to ${limit}
128
+
129
+ -- Phase 1: Subject matches (safe WHERE clause)
130
+ set subjectMatches to (messages ${folderClause} whose subject contains "${escapedQuery}")
131
+ repeat with m in subjectMatches
132
+ if resultCount ≥ maxResults then exit repeat
133
+ try
134
+ set mId to id of m
135
+ set end of matchedIds to mId
136
+ set mSubject to subject of m
137
+ set mSender to ""
138
+ try
139
+ set mSender to address of sender of m
140
+ end try
141
+ set mSenderName to ""
142
+ try
143
+ set mSenderName to name of sender of m
144
+ end try
145
+ set mDate to ""
146
+ try
147
+ set mDate to time received of m as «class isot» as string
148
+ end try
149
+ set mRead to is read of m
150
+ set mPreview to ""
151
+ try
152
+ set mPreview to text 1 thru 200 of plain text content of m
153
+ on error
154
+ try
155
+ set mPreview to plain text content of m
156
+ end try
157
+ end try
158
+ set output to output & "{{RECORD}}id{{=}}" & mId & "{{FIELD}}subject{{=}}" & mSubject & "{{FIELD}}senderEmail{{=}}" & mSender & "{{FIELD}}senderName{{=}}" & mSenderName & "{{FIELD}}dateReceived{{=}}" & mDate & "{{FIELD}}isRead{{=}}" & mRead & "{{FIELD}}preview{{=}}" & mPreview
159
+ set resultCount to resultCount + 1
160
+ end try
161
+ end repeat
162
+
163
+ -- Phase 2: Sender matches (loop with try/catch for safety)
164
+ if resultCount < maxResults then
165
+ set allMsgs to messages ${folderClause}
166
+ set scanLimit to count of allMsgs
167
+ if scanLimit > ${SENDER_SCAN_LIMIT} then set scanLimit to ${SENDER_SCAN_LIMIT}
168
+ repeat with i from 1 to scanLimit
169
+ if resultCount ≥ maxResults then exit repeat
170
+ try
171
+ set m to item i of allMsgs
172
+ set mId to id of m
173
+ if matchedIds does not contain mId then
174
+ set mSender to ""
175
+ try
176
+ set mSender to address of sender of m
177
+ end try
178
+ if mSender contains "${escapedQuery}" then
179
+ set end of matchedIds to mId
180
+ set mSubject to subject of m
181
+ set mSenderName to ""
182
+ try
183
+ set mSenderName to name of sender of m
184
+ end try
185
+ set mDate to ""
186
+ try
187
+ set mDate to time received of m as «class isot» as string
188
+ end try
189
+ set mRead to is read of m
190
+ set mPreview to ""
191
+ try
192
+ set mPreview to text 1 thru 200 of plain text content of m
193
+ on error
194
+ try
195
+ set mPreview to plain text content of m
196
+ end try
197
+ end try
198
+ set output to output & "{{RECORD}}id{{=}}" & mId & "{{FIELD}}subject{{=}}" & mSubject & "{{FIELD}}senderEmail{{=}}" & mSender & "{{FIELD}}senderName{{=}}" & mSenderName & "{{FIELD}}dateReceived{{=}}" & mDate & "{{FIELD}}isRead{{=}}" & mRead & "{{FIELD}}preview{{=}}" & mPreview
199
+ set resultCount to resultCount + 1
200
+ end if
201
+ end if
202
+ end try
203
+ end repeat
204
+ end if
205
+
206
+ return output
207
+ end tell
208
+ `;
209
+ }
210
+ /**
211
+ * Gets a single message by ID with full content.
212
+ */
213
+ export function getMessage(messageId) {
214
+ return `
215
+ tell application "Microsoft Outlook"
216
+ set m to message id ${messageId}
217
+ set mId to id of m
218
+ set mSubject to subject of m
219
+ set mSender to ""
220
+ try
221
+ set mSender to address of sender of m
222
+ end try
223
+ set mSenderName to ""
224
+ try
225
+ set mSenderName to name of sender of m
226
+ end try
227
+ set mDateReceived to ""
228
+ try
229
+ set mDateReceived to time received of m as «class isot» as string
230
+ end try
231
+ set mDateSent to ""
232
+ try
233
+ set mDateSent to time sent of m as «class isot» as string
234
+ end try
235
+ set mRead to is read of m
236
+ set mPriority to "normal"
237
+ try
238
+ set p to priority of m
239
+ if p is priority high then
240
+ set mPriority to "high"
241
+ else if p is priority low then
242
+ set mPriority to "low"
243
+ end if
244
+ end try
245
+ set mHtml to ""
246
+ try
247
+ set mHtml to content of m
248
+ end try
249
+ set mPlain to ""
250
+ try
251
+ set mPlain to plain text content of m
252
+ end try
253
+ set mHasHtml to has html of m
254
+ set mFolderId to ""
255
+ try
256
+ set mFolderId to id of folder of m
257
+ end try
258
+
259
+ -- Get recipients
260
+ set toList to ""
261
+ try
262
+ repeat with r in to recipients of m
263
+ set toList to toList & (address of r) & ","
264
+ end repeat
265
+ end try
266
+ set ccList to ""
267
+ try
268
+ repeat with r in cc recipients of m
269
+ set ccList to ccList & (address of r) & ","
270
+ end repeat
271
+ end try
272
+
273
+ -- Get attachments
274
+ set attachList to ""
275
+ set attachDetailList to ""
276
+ try
277
+ set idx to 1
278
+ repeat with a in attachments of m
279
+ set aName to name of a
280
+ set attachList to attachList & aName & ","
281
+ set aSize to 0
282
+ try
283
+ set aSize to file size of a
284
+ end try
285
+ set aType to ""
286
+ try
287
+ set aType to content type of a
288
+ end try
289
+ set attachDetailList to attachDetailList & idx & "|" & aName & "|" & aSize & "|" & aType & ","
290
+ set idx to idx + 1
291
+ end repeat
292
+ end try
293
+
294
+ return "{{RECORD}}id{{=}}" & mId & "{{FIELD}}subject{{=}}" & mSubject & "{{FIELD}}senderEmail{{=}}" & mSender & "{{FIELD}}senderName{{=}}" & mSenderName & "{{FIELD}}dateReceived{{=}}" & mDateReceived & "{{FIELD}}dateSent{{=}}" & mDateSent & "{{FIELD}}isRead{{=}}" & mRead & "{{FIELD}}priority{{=}}" & mPriority & "{{FIELD}}htmlContent{{=}}" & mHtml & "{{FIELD}}plainContent{{=}}" & mPlain & "{{FIELD}}hasHtml{{=}}" & mHasHtml & "{{FIELD}}folderId{{=}}" & mFolderId & "{{FIELD}}toRecipients{{=}}" & toList & "{{FIELD}}ccRecipients{{=}}" & ccList & "{{FIELD}}attachments{{=}}" & attachList & "{{FIELD}}attachmentDetails{{=}}" & attachDetailList
295
+ end tell
296
+ `;
297
+ }
298
+ /**
299
+ * Gets unread count for a folder.
300
+ */
301
+ export function getUnreadCount(folderId) {
302
+ return `
303
+ tell application "Microsoft Outlook"
304
+ set f to mail folder id ${folderId}
305
+ return unread count of f
306
+ end tell
307
+ `;
308
+ }
309
+ // =============================================================================
310
+ // Attachment Scripts
311
+ // =============================================================================
312
+ /**
313
+ * Lists attachment metadata for a message.
314
+ */
315
+ export function listAttachments(messageId) {
316
+ return `
317
+ tell application "Microsoft Outlook"
318
+ set m to message id ${messageId}
319
+ set output to ""
320
+ set attachList to attachments of m
321
+ set idx to 1
322
+ repeat with a in attachList
323
+ try
324
+ set aName to name of a
325
+ set aSize to 0
326
+ try
327
+ set aSize to file size of a
328
+ end try
329
+ set aType to ""
330
+ try
331
+ set aType to content type of a
332
+ end try
333
+ set output to output & "{{RECORD}}index{{=}}" & idx & "{{FIELD}}name{{=}}" & aName & "{{FIELD}}fileSize{{=}}" & aSize & "{{FIELD}}contentType{{=}}" & aType
334
+ end try
335
+ set idx to idx + 1
336
+ end repeat
337
+ return output
338
+ end tell
339
+ `;
340
+ }
341
+ /**
342
+ * Saves an attachment from a message to a file path.
343
+ * Uses 1-based attachment index.
344
+ */
345
+ export function saveAttachment(messageId, attachmentIndex, savePath) {
346
+ const escapedPath = escapeForAppleScript(savePath);
347
+ return `
348
+ tell application "Microsoft Outlook"
349
+ try
350
+ set m to message id ${messageId}
351
+ set attachList to attachments of m
352
+ set attachCount to count of attachList
353
+ if ${attachmentIndex} > attachCount then
354
+ return "{{RECORD}}success{{=}}false{{FIELD}}error{{=}}Attachment index ${attachmentIndex} out of range (message has " & attachCount & " attachments)"
355
+ end if
356
+ set a to item ${attachmentIndex} of attachList
357
+ set aName to name of a
358
+ set aSize to 0
359
+ try
360
+ set aSize to file size of a
361
+ end try
362
+ save a in POSIX file "${escapedPath}"
363
+ return "{{RECORD}}success{{=}}true{{FIELD}}name{{=}}" & aName & "{{FIELD}}savedTo{{=}}${escapedPath}" & "{{FIELD}}fileSize{{=}}" & aSize
364
+ on error errMsg
365
+ return "{{RECORD}}success{{=}}false{{FIELD}}error{{=}}" & errMsg
366
+ end try
367
+ end tell
368
+ `;
369
+ }
370
+ // =============================================================================
371
+ // Calendar Scripts
372
+ // =============================================================================
373
+ /**
374
+ * Lists all calendars.
375
+ */
376
+ export const LIST_CALENDARS = `
377
+ tell application "Microsoft Outlook"
378
+ set output to ""
379
+ set allCalendars to calendars
380
+ repeat with c in allCalendars
381
+ try
382
+ set cId to id of c
383
+ set cName to name of c
384
+ set output to output & "{{RECORD}}id{{=}}" & cId & "{{FIELD}}name{{=}}" & cName
385
+ end try
386
+ end repeat
387
+ return output
388
+ end tell
389
+ `;
390
+ /**
391
+ * Lists events from a calendar within a date range.
392
+ */
393
+ export function listEvents(calendarId, startDate, endDate, limit) {
394
+ const calendarClause = calendarId != null ? `of calendar id ${calendarId}` : '';
395
+ return `
396
+ tell application "Microsoft Outlook"
397
+ set output to ""
398
+ set allEvents to calendar events ${calendarClause}
399
+ set eventCount to count of allEvents
400
+ set maxEvents to ${limit}
401
+ if eventCount < maxEvents then set maxEvents to eventCount
402
+
403
+ repeat with i from 1 to maxEvents
404
+ try
405
+ set e to item i of allEvents
406
+ set eId to id of e
407
+ set eSubject to subject of e
408
+ set eStart to ""
409
+ try
410
+ set eStart to start time of e as «class isot» as string
411
+ end try
412
+ set eEnd to ""
413
+ try
414
+ set eEnd to end time of e as «class isot» as string
415
+ end try
416
+ set eLocation to ""
417
+ try
418
+ set eLocation to location of e
419
+ end try
420
+ set eAllDay to all day flag of e
421
+ set eRecurring to is recurring of e
422
+
423
+ set output to output & "{{RECORD}}id{{=}}" & eId & "{{FIELD}}subject{{=}}" & eSubject & "{{FIELD}}startTime{{=}}" & eStart & "{{FIELD}}endTime{{=}}" & eEnd & "{{FIELD}}location{{=}}" & eLocation & "{{FIELD}}isAllDay{{=}}" & eAllDay & "{{FIELD}}isRecurring{{=}}" & eRecurring
424
+ end try
425
+ end repeat
426
+ return output
427
+ end tell
428
+ `;
429
+ }
430
+ /**
431
+ * Gets a single event by ID.
432
+ */
433
+ export function getEvent(eventId) {
434
+ return `
435
+ tell application "Microsoft Outlook"
436
+ set e to calendar event id ${eventId}
437
+ set eId to id of e
438
+ set eSubject to subject of e
439
+ set eStart to ""
440
+ try
441
+ set eStart to start time of e as «class isot» as string
442
+ end try
443
+ set eEnd to ""
444
+ try
445
+ set eEnd to end time of e as «class isot» as string
446
+ end try
447
+ set eLocation to ""
448
+ try
449
+ set eLocation to location of e
450
+ end try
451
+ set eContent to ""
452
+ try
453
+ set eContent to content of e
454
+ end try
455
+ set ePlain to ""
456
+ try
457
+ set ePlain to plain text content of e
458
+ end try
459
+ set eAllDay to all day flag of e
460
+ set eRecurring to is recurring of e
461
+ set eOrganizer to ""
462
+ try
463
+ set eOrganizer to organizer of e
464
+ end try
465
+ set eCalId to ""
466
+ try
467
+ set eCalId to id of calendar of e
468
+ end try
469
+
470
+ -- Get attendees
471
+ set attendeeList to ""
472
+ try
473
+ repeat with a in attendees of e
474
+ set aEmail to email address of a
475
+ set aName to name of a
476
+ set attendeeList to attendeeList & aEmail & "|" & aName & ","
477
+ end repeat
478
+ end try
479
+
480
+ return "{{RECORD}}id{{=}}" & eId & "{{FIELD}}subject{{=}}" & eSubject & "{{FIELD}}startTime{{=}}" & eStart & "{{FIELD}}endTime{{=}}" & eEnd & "{{FIELD}}location{{=}}" & eLocation & "{{FIELD}}htmlContent{{=}}" & eContent & "{{FIELD}}plainContent{{=}}" & ePlain & "{{FIELD}}isAllDay{{=}}" & eAllDay & "{{FIELD}}isRecurring{{=}}" & eRecurring & "{{FIELD}}organizer{{=}}" & eOrganizer & "{{FIELD}}calendarId{{=}}" & eCalId & "{{FIELD}}attendees{{=}}" & attendeeList
481
+ end tell
482
+ `;
483
+ }
484
+ /**
485
+ * Searches events by query and/or date range.
486
+ * At least one of query or date range must be provided.
487
+ */
488
+ export function searchEvents(query, startDate, endDate, limit) {
489
+ // Build date variable declarations
490
+ let dateSetup = '';
491
+ if (startDate != null) {
492
+ dateSetup += `
493
+ set theStartDate to current date
494
+ set day of theStartDate to 1
495
+ set year of theStartDate to ${startDate.year}
496
+ set month of theStartDate to ${startDate.month}
497
+ set day of theStartDate to ${startDate.day}
498
+ set hours of theStartDate to ${startDate.hours}
499
+ set minutes of theStartDate to ${startDate.minutes}
500
+ set seconds of theStartDate to 0
501
+ `;
502
+ }
503
+ if (endDate != null) {
504
+ dateSetup += `
505
+ set theEndDate to current date
506
+ set day of theEndDate to 1
507
+ set year of theEndDate to ${endDate.year}
508
+ set month of theEndDate to ${endDate.month}
509
+ set day of theEndDate to ${endDate.day}
510
+ set hours of theEndDate to ${endDate.hours}
511
+ set minutes of theEndDate to ${endDate.minutes}
512
+ set seconds of theEndDate to 0
513
+ `;
514
+ }
515
+ // Build whose clause conditions
516
+ const conditions = [];
517
+ if (query != null) {
518
+ const escapedQuery = escapeForAppleScript(query);
519
+ conditions.push(`subject contains "${escapedQuery}"`);
520
+ }
521
+ if (startDate != null) {
522
+ conditions.push('start time ≥ theStartDate');
523
+ }
524
+ if (endDate != null) {
525
+ conditions.push('end time ≤ theEndDate');
526
+ }
527
+ const whoseClause = conditions.length > 0
528
+ ? ` whose ${conditions.join(' and ')}`
529
+ : '';
530
+ return `
531
+ tell application "Microsoft Outlook"
532
+ set output to ""
533
+ ${dateSetup}
534
+ set searchResults to (calendar events${whoseClause})
535
+ set resultCount to count of searchResults
536
+ set maxResults to ${limit}
537
+ if resultCount < maxResults then set maxResults to resultCount
538
+
539
+ repeat with i from 1 to maxResults
540
+ try
541
+ set e to item i of searchResults
542
+ set eId to id of e
543
+ set eSubject to subject of e
544
+ set eStart to ""
545
+ try
546
+ set eStart to start time of e as «class isot» as string
547
+ end try
548
+ set eEnd to ""
549
+ try
550
+ set eEnd to end time of e as «class isot» as string
551
+ end try
552
+ set eLocation to ""
553
+ try
554
+ set eLocation to location of e
555
+ end try
556
+
557
+ set output to output & "{{RECORD}}id{{=}}" & eId & "{{FIELD}}subject{{=}}" & eSubject & "{{FIELD}}startTime{{=}}" & eStart & "{{FIELD}}endTime{{=}}" & eEnd & "{{FIELD}}location{{=}}" & eLocation
558
+ end try
559
+ end repeat
560
+ return output
561
+ end tell
562
+ `;
563
+ }
564
+ /**
565
+ * Builds AppleScript to set recurrence on a newly created event.
566
+ * Assumes `newEvent` variable is already in scope from createEvent.
567
+ */
568
+ function buildRecurrenceScript(params) {
569
+ const isOrdinalMonthly = params.frequency === 'monthly' && params.weekOfMonth != null;
570
+ const frequencyMap = {
571
+ daily: 'daily recurrence',
572
+ weekly: 'weekly recurrence',
573
+ monthly: isOrdinalMonthly ? 'month nth recurrence' : 'monthly recurrence',
574
+ yearly: 'yearly recurrence',
575
+ };
576
+ const recurrenceType = frequencyMap[params.frequency];
577
+ const capitalize = (s) => s.charAt(0).toUpperCase() + s.slice(1);
578
+ let script = `
579
+ set is recurring of newEvent to true
580
+ set theRecurrence to recurrence of newEvent
581
+ set recurrence type of theRecurrence to ${recurrenceType}
582
+ set occurrence interval of theRecurrence to ${params.interval}`;
583
+ // Weekly: days of week mask
584
+ if (params.frequency === 'weekly' && params.daysOfWeek != null) {
585
+ const daysList = params.daysOfWeek.map(capitalize).join(', ');
586
+ script += `\n set day of week mask of theRecurrence to {${daysList}}`;
587
+ }
588
+ // Monthly by date
589
+ if (params.frequency === 'monthly' && params.dayOfMonth != null && params.weekOfMonth == null) {
590
+ script += `\n set day of month of theRecurrence to ${params.dayOfMonth}`;
591
+ }
592
+ // Monthly ordinal (e.g., 3rd Thursday)
593
+ if (params.frequency === 'monthly' && params.weekOfMonth != null && params.dayOfWeekMonthly != null) {
594
+ const instanceMap = { first: 1, second: 2, third: 3, fourth: 4, last: 5 };
595
+ const instance = instanceMap[params.weekOfMonth] ?? 1;
596
+ script += `\n set day of week mask of theRecurrence to {${capitalize(params.dayOfWeekMonthly)}}`;
597
+ script += `\n set instance of theRecurrence to ${instance}`;
598
+ }
599
+ // End after count
600
+ if (params.endAfterCount != null) {
601
+ script += `\n set occurrences of theRecurrence to ${params.endAfterCount}`;
602
+ }
603
+ // End by date (component-based for locale safety)
604
+ if (params.endDate != null) {
605
+ script += `
606
+ set theEndRecurrenceDate to current date
607
+ set day of theEndRecurrenceDate to 1
608
+ set year of theEndRecurrenceDate to ${params.endDate.year}
609
+ set month of theEndRecurrenceDate to ${params.endDate.month}
610
+ set day of theEndRecurrenceDate to ${params.endDate.day}
611
+ set hours of theEndRecurrenceDate to ${params.endDate.hours}
612
+ set minutes of theEndRecurrenceDate to ${params.endDate.minutes}
613
+ set seconds of theEndRecurrenceDate to 0
614
+ set pattern end date of theRecurrence to theEndRecurrenceDate`;
615
+ }
616
+ return script;
617
+ }
618
+ /**
619
+ * Responds to an event invitation (RSVP).
620
+ */
621
+ export function respondToEvent(params) {
622
+ const { eventId, response, comment } = params;
623
+ // Map response to AppleScript status value
624
+ const statusMap = {
625
+ accept: 'accept',
626
+ decline: 'decline',
627
+ tentative: 'tentative accept',
628
+ };
629
+ const status = statusMap[response];
630
+ // Escape comment if provided
631
+ const commentLine = comment != null
632
+ ? `set comment of myEvent to "${escapeForAppleScript(comment)}"`
633
+ : '';
634
+ return `
635
+ tell application "Microsoft Outlook"
636
+ try
637
+ set myEvent to calendar event id ${eventId}
638
+ set response status of myEvent to ${status}
639
+ ${commentLine}
640
+
641
+ -- Return success
642
+ set output to "{{RECORD}}success{{=}}true{{FIELD}}eventId{{=}}" & ${eventId}
643
+ return output
644
+ on error errMsg
645
+ -- Return failure
646
+ set output to "{{RECORD}}success{{=}}false{{FIELD}}error{{=}}" & errMsg
647
+ return output
648
+ end try
649
+ end tell
650
+ `;
651
+ }
652
+ /**
653
+ * Deletes an event. For recurring events, can delete single instance or entire series.
654
+ */
655
+ export function deleteEvent(params) {
656
+ const { eventId, applyTo } = params;
657
+ const comment = applyTo === 'all_in_series'
658
+ ? '-- Deleting entire series'
659
+ : '-- Deleting single instance';
660
+ return `
661
+ tell application "Microsoft Outlook"
662
+ try
663
+ ${comment}
664
+ set myEvent to calendar event id ${eventId}
665
+ delete myEvent
666
+
667
+ -- Return success
668
+ set output to "{{RECORD}}success{{=}}true{{FIELD}}eventId{{=}}" & ${eventId}
669
+ return output
670
+ on error errMsg
671
+ -- Return failure
672
+ set output to "{{RECORD}}success{{=}}false{{FIELD}}error{{=}}" & errMsg
673
+ return output
674
+ end try
675
+ end tell
676
+ `;
677
+ }
678
+ /**
679
+ * Converts an ISO 8601 date string into individual UTC date components.
680
+ */
681
+ function isoToDateComponents(isoString) {
682
+ const date = new Date(isoString);
683
+ return {
684
+ year: date.getUTCFullYear(),
685
+ month: date.getUTCMonth() + 1,
686
+ day: date.getUTCDate(),
687
+ hours: date.getUTCHours(),
688
+ minutes: date.getUTCMinutes(),
689
+ };
690
+ }
691
+ /**
692
+ * Updates an event. For recurring events, can update single instance or entire series.
693
+ * All update fields are optional - only specified fields will be updated.
694
+ */
695
+ export function updateEvent(params) {
696
+ const { eventId, applyTo, updates } = params;
697
+ const updatedFields = [];
698
+ let updateStatements = '';
699
+ if (updates.title != null) {
700
+ updateStatements += ` set subject of myEvent to "${escapeForAppleScript(updates.title)}"\n`;
701
+ updatedFields.push('title');
702
+ }
703
+ if (updates.location != null) {
704
+ updateStatements += ` set location of myEvent to "${escapeForAppleScript(updates.location)}"\n`;
705
+ updatedFields.push('location');
706
+ }
707
+ if (updates.description != null) {
708
+ updateStatements += ` set content of myEvent to "${escapeForAppleScript(updates.description)}"\n`;
709
+ updatedFields.push('description');
710
+ }
711
+ if (updates.startDate != null) {
712
+ const start = isoToDateComponents(updates.startDate);
713
+ updateStatements += ` set start time of myEvent to date "${start.year}-${start.month}-${start.day} ${start.hours}:${start.minutes}:00"\n`;
714
+ updatedFields.push('startDate');
715
+ }
716
+ if (updates.endDate != null) {
717
+ const end = isoToDateComponents(updates.endDate);
718
+ updateStatements += ` set end time of myEvent to date "${end.year}-${end.month}-${end.day} ${end.hours}:${end.minutes}:00"\n`;
719
+ updatedFields.push('endDate');
720
+ }
721
+ if (updates.isAllDay != null) {
722
+ updateStatements += ` set all day flag of myEvent to ${updates.isAllDay}\n`;
723
+ updatedFields.push('isAllDay');
724
+ }
725
+ const comment = applyTo === 'all_in_series'
726
+ ? '-- Updating entire series'
727
+ : '-- Updating single instance';
728
+ const fieldsOutput = updatedFields.join(',');
729
+ return `
730
+ tell application "Microsoft Outlook"
731
+ try
732
+ ${comment}
733
+ set myEvent to calendar event id ${eventId}
734
+
735
+ ${updateStatements}
736
+ -- Return success
737
+ set output to "{{RECORD}}success{{=}}true{{FIELD}}eventId{{=}}" & ${eventId} & "{{FIELD}}updatedFields{{=}}${fieldsOutput}"
738
+ return output
739
+ on error errMsg
740
+ -- Return failure
741
+ set output to "{{RECORD}}success{{=}}false{{FIELD}}error{{=}}" & errMsg
742
+ return output
743
+ end try
744
+ end tell
745
+ `;
746
+ }
747
+ /**
748
+ * Creates a new calendar event.
749
+ * Uses component-based date construction for locale safety.
750
+ */
751
+ export function createEvent(params) {
752
+ const escapedTitle = escapeForAppleScript(params.title);
753
+ const escapedLocation = params.location != null ? escapeForAppleScript(params.location) : '';
754
+ const escapedDescription = params.description != null ? escapeForAppleScript(params.description) : '';
755
+ // Build properties list
756
+ let properties = `subject:"${escapedTitle}", start time:theStartDate, end time:theEndDate`;
757
+ if (params.location != null) {
758
+ properties += `, location:"${escapedLocation}"`;
759
+ }
760
+ if (params.isAllDay === true) {
761
+ properties += ', all day flag:true';
762
+ }
763
+ // Build the target clause for calendar
764
+ const targetClause = params.calendarId != null
765
+ ? `at calendar id ${params.calendarId} `
766
+ : '';
767
+ return `
768
+ tell application "Microsoft Outlook"
769
+ set theStartDate to current date
770
+ set day of theStartDate to 1
771
+ set year of theStartDate to ${params.startYear}
772
+ set month of theStartDate to ${params.startMonth}
773
+ set day of theStartDate to ${params.startDay}
774
+ set hours of theStartDate to ${params.startHours}
775
+ set minutes of theStartDate to ${params.startMinutes}
776
+ set seconds of theStartDate to 0
777
+
778
+ set theEndDate to current date
779
+ set day of theEndDate to 1
780
+ set year of theEndDate to ${params.endYear}
781
+ set month of theEndDate to ${params.endMonth}
782
+ set day of theEndDate to ${params.endDay}
783
+ set hours of theEndDate to ${params.endHours}
784
+ set minutes of theEndDate to ${params.endMinutes}
785
+ set seconds of theEndDate to 0
786
+
787
+ set newEvent to make new calendar event ${targetClause}with properties {${properties}}
788
+ ${escapedDescription ? `set plain text content of newEvent to "${escapedDescription}"` : ''}${params.recurrence != null ? buildRecurrenceScript(params.recurrence) : ''}
789
+ set eId to id of newEvent
790
+ set eCalId to ""
791
+ try
792
+ set eCalId to id of calendar of newEvent
793
+ end try
794
+ return "{{RECORD}}id{{=}}" & eId & "{{FIELD}}calendarId{{=}}" & eCalId
795
+ end tell
796
+ `;
797
+ }
798
+ // =============================================================================
799
+ // Contact Scripts
800
+ // =============================================================================
801
+ /**
802
+ * Lists all contacts.
803
+ */
804
+ export function listContacts(limit, offset) {
805
+ const totalToFetch = limit + offset;
806
+ return `
807
+ tell application "Microsoft Outlook"
808
+ set output to ""
809
+ set allContacts to contacts
810
+ set contactCount to count of allContacts
811
+ set startIdx to ${offset + 1}
812
+ set endIdx to ${totalToFetch}
813
+ if endIdx > contactCount then set endIdx to contactCount
814
+ if startIdx > contactCount then return ""
815
+
816
+ repeat with i from startIdx to endIdx
817
+ try
818
+ set c to item i of allContacts
819
+ set cId to id of c
820
+ set cDisplay to display name of c
821
+ set cFirst to ""
822
+ try
823
+ set cFirst to first name of c
824
+ end try
825
+ set cLast to ""
826
+ try
827
+ set cLast to last name of c
828
+ end try
829
+ set cCompany to ""
830
+ try
831
+ set cCompany to company of c
832
+ end try
833
+ set cEmail to ""
834
+ try
835
+ set emailAddrs to email addresses of c
836
+ if (count of emailAddrs) > 0 then
837
+ set cEmail to address of item 1 of emailAddrs
838
+ end if
839
+ end try
840
+
841
+ set output to output & "{{RECORD}}id{{=}}" & cId & "{{FIELD}}displayName{{=}}" & cDisplay & "{{FIELD}}firstName{{=}}" & cFirst & "{{FIELD}}lastName{{=}}" & cLast & "{{FIELD}}company{{=}}" & cCompany & "{{FIELD}}email{{=}}" & cEmail
842
+ end try
843
+ end repeat
844
+ return output
845
+ end tell
846
+ `;
847
+ }
848
+ /**
849
+ * Searches contacts by name.
850
+ */
851
+ export function searchContacts(query, limit) {
852
+ const escapedQuery = escapeForAppleScript(query);
853
+ return `
854
+ tell application "Microsoft Outlook"
855
+ set output to ""
856
+ set searchResults to (contacts whose display name contains "${escapedQuery}")
857
+ set resultCount to count of searchResults
858
+ set maxResults to ${limit}
859
+ if resultCount < maxResults then set maxResults to resultCount
860
+
861
+ repeat with i from 1 to maxResults
862
+ try
863
+ set c to item i of searchResults
864
+ set cId to id of c
865
+ set cDisplay to display name of c
866
+ set cFirst to ""
867
+ try
868
+ set cFirst to first name of c
869
+ end try
870
+ set cLast to ""
871
+ try
872
+ set cLast to last name of c
873
+ end try
874
+ set cCompany to ""
875
+ try
876
+ set cCompany to company of c
877
+ end try
878
+ set cEmail to ""
879
+ try
880
+ set emailAddrs to email addresses of c
881
+ if (count of emailAddrs) > 0 then
882
+ set cEmail to address of item 1 of emailAddrs
883
+ end if
884
+ end try
885
+
886
+ set output to output & "{{RECORD}}id{{=}}" & cId & "{{FIELD}}displayName{{=}}" & cDisplay & "{{FIELD}}firstName{{=}}" & cFirst & "{{FIELD}}lastName{{=}}" & cLast & "{{FIELD}}company{{=}}" & cCompany & "{{FIELD}}email{{=}}" & cEmail
887
+ end try
888
+ end repeat
889
+ return output
890
+ end tell
891
+ `;
892
+ }
893
+ /**
894
+ * Gets a single contact by ID with full details.
895
+ */
896
+ export function getContact(contactId) {
897
+ return `
898
+ tell application "Microsoft Outlook"
899
+ set c to contact id ${contactId}
900
+ set cId to id of c
901
+ set cDisplay to display name of c
902
+ set cFirst to ""
903
+ try
904
+ set cFirst to first name of c
905
+ end try
906
+ set cLast to ""
907
+ try
908
+ set cLast to last name of c
909
+ end try
910
+ set cMiddle to ""
911
+ try
912
+ set cMiddle to middle name of c
913
+ end try
914
+ set cNickname to ""
915
+ try
916
+ set cNickname to nickname of c
917
+ end try
918
+ set cCompany to ""
919
+ try
920
+ set cCompany to company of c
921
+ end try
922
+ set cTitle to ""
923
+ try
924
+ set cTitle to job title of c
925
+ end try
926
+ set cDept to ""
927
+ try
928
+ set cDept to department of c
929
+ end try
930
+ set cNotes to ""
931
+ try
932
+ set cNotes to description of c
933
+ end try
934
+
935
+ -- Phones
936
+ set cHomePhone to ""
937
+ try
938
+ set cHomePhone to home phone number of c
939
+ end try
940
+ set cWorkPhone to ""
941
+ try
942
+ set cWorkPhone to business phone number of c
943
+ end try
944
+ set cMobile to ""
945
+ try
946
+ set cMobile to mobile number of c
947
+ end try
948
+
949
+ -- Emails
950
+ set emailList to ""
951
+ try
952
+ repeat with e in email addresses of c
953
+ set emailList to emailList & (address of e) & ","
954
+ end repeat
955
+ end try
956
+
957
+ -- Address
958
+ set cHomeStreet to ""
959
+ try
960
+ set cHomeStreet to home street address of c
961
+ end try
962
+ set cHomeCity to ""
963
+ try
964
+ set cHomeCity to home city of c
965
+ end try
966
+ set cHomeState to ""
967
+ try
968
+ set cHomeState to home state of c
969
+ end try
970
+ set cHomeZip to ""
971
+ try
972
+ set cHomeZip to home zip of c
973
+ end try
974
+ set cHomeCountry to ""
975
+ try
976
+ set cHomeCountry to home country of c
977
+ end try
978
+
979
+ return "{{RECORD}}id{{=}}" & cId & "{{FIELD}}displayName{{=}}" & cDisplay & "{{FIELD}}firstName{{=}}" & cFirst & "{{FIELD}}lastName{{=}}" & cLast & "{{FIELD}}middleName{{=}}" & cMiddle & "{{FIELD}}nickname{{=}}" & cNickname & "{{FIELD}}company{{=}}" & cCompany & "{{FIELD}}jobTitle{{=}}" & cTitle & "{{FIELD}}department{{=}}" & cDept & "{{FIELD}}notes{{=}}" & cNotes & "{{FIELD}}homePhone{{=}}" & cHomePhone & "{{FIELD}}workPhone{{=}}" & cWorkPhone & "{{FIELD}}mobilePhone{{=}}" & cMobile & "{{FIELD}}emails{{=}}" & emailList & "{{FIELD}}homeStreet{{=}}" & cHomeStreet & "{{FIELD}}homeCity{{=}}" & cHomeCity & "{{FIELD}}homeState{{=}}" & cHomeState & "{{FIELD}}homeZip{{=}}" & cHomeZip & "{{FIELD}}homeCountry{{=}}" & cHomeCountry
980
+ end tell
981
+ `;
982
+ }
983
+ // =============================================================================
984
+ // Task Scripts
985
+ // =============================================================================
986
+ /**
987
+ * Lists all tasks.
988
+ */
989
+ export function listTasks(limit, offset, includeCompleted) {
990
+ const totalToFetch = limit + offset;
991
+ const completedFilter = includeCompleted ? '' : ' whose is completed is false';
992
+ return `
993
+ tell application "Microsoft Outlook"
994
+ set output to ""
995
+ set allTasks to (tasks${completedFilter})
996
+ set taskCount to count of allTasks
997
+ set startIdx to ${offset + 1}
998
+ set endIdx to ${totalToFetch}
999
+ if endIdx > taskCount then set endIdx to taskCount
1000
+ if startIdx > taskCount then return ""
1001
+
1002
+ repeat with i from startIdx to endIdx
1003
+ try
1004
+ set t to item i of allTasks
1005
+ set tId to id of t
1006
+ set tName to name of t
1007
+ set tDue to ""
1008
+ try
1009
+ set tDue to due date of t as «class isot» as string
1010
+ end try
1011
+ set tCompleted to is completed of t
1012
+ set tPriority to "normal"
1013
+ try
1014
+ set p to priority of t
1015
+ if p is priority high then
1016
+ set tPriority to "high"
1017
+ else if p is priority low then
1018
+ set tPriority to "low"
1019
+ end if
1020
+ end try
1021
+
1022
+ set output to output & "{{RECORD}}id{{=}}" & tId & "{{FIELD}}name{{=}}" & tName & "{{FIELD}}dueDate{{=}}" & tDue & "{{FIELD}}isCompleted{{=}}" & tCompleted & "{{FIELD}}priority{{=}}" & tPriority
1023
+ end try
1024
+ end repeat
1025
+ return output
1026
+ end tell
1027
+ `;
1028
+ }
1029
+ /**
1030
+ * Searches tasks by name.
1031
+ */
1032
+ export function searchTasks(query, limit) {
1033
+ const escapedQuery = escapeForAppleScript(query);
1034
+ return `
1035
+ tell application "Microsoft Outlook"
1036
+ set output to ""
1037
+ set searchResults to (tasks whose name contains "${escapedQuery}")
1038
+ set resultCount to count of searchResults
1039
+ set maxResults to ${limit}
1040
+ if resultCount < maxResults then set maxResults to resultCount
1041
+
1042
+ repeat with i from 1 to maxResults
1043
+ try
1044
+ set t to item i of searchResults
1045
+ set tId to id of t
1046
+ set tName to name of t
1047
+ set tDue to ""
1048
+ try
1049
+ set tDue to due date of t as «class isot» as string
1050
+ end try
1051
+ set tCompleted to is completed of t
1052
+
1053
+ set output to output & "{{RECORD}}id{{=}}" & tId & "{{FIELD}}name{{=}}" & tName & "{{FIELD}}dueDate{{=}}" & tDue & "{{FIELD}}isCompleted{{=}}" & tCompleted
1054
+ end try
1055
+ end repeat
1056
+ return output
1057
+ end tell
1058
+ `;
1059
+ }
1060
+ /**
1061
+ * Gets a single task by ID.
1062
+ */
1063
+ export function getTask(taskId) {
1064
+ return `
1065
+ tell application "Microsoft Outlook"
1066
+ set t to task id ${taskId}
1067
+ set tId to id of t
1068
+ set tName to name of t
1069
+ set tContent to ""
1070
+ try
1071
+ set tContent to content of t
1072
+ end try
1073
+ set tPlain to ""
1074
+ try
1075
+ set tPlain to plain text content of t
1076
+ end try
1077
+ set tDue to ""
1078
+ try
1079
+ set tDue to due date of t as «class isot» as string
1080
+ end try
1081
+ set tStart to ""
1082
+ try
1083
+ set tStart to start date of t as «class isot» as string
1084
+ end try
1085
+ set tCompletedDate to ""
1086
+ try
1087
+ set tCompletedDate to completed date of t as «class isot» as string
1088
+ end try
1089
+ set tCompleted to is completed of t
1090
+ set tPriority to "normal"
1091
+ try
1092
+ set p to priority of t
1093
+ if p is priority high then
1094
+ set tPriority to "high"
1095
+ else if p is priority low then
1096
+ set tPriority to "low"
1097
+ end if
1098
+ end try
1099
+ set tFolderId to ""
1100
+ try
1101
+ set tFolderId to id of folder of t
1102
+ end try
1103
+
1104
+ return "{{RECORD}}id{{=}}" & tId & "{{FIELD}}name{{=}}" & tName & "{{FIELD}}htmlContent{{=}}" & tContent & "{{FIELD}}plainContent{{=}}" & tPlain & "{{FIELD}}dueDate{{=}}" & tDue & "{{FIELD}}startDate{{=}}" & tStart & "{{FIELD}}completedDate{{=}}" & tCompletedDate & "{{FIELD}}isCompleted{{=}}" & tCompleted & "{{FIELD}}priority{{=}}" & tPriority & "{{FIELD}}folderId{{=}}" & tFolderId
1105
+ end tell
1106
+ `;
1107
+ }
1108
+ // =============================================================================
1109
+ // Note Scripts
1110
+ // =============================================================================
1111
+ /**
1112
+ * Lists all notes.
1113
+ */
1114
+ export function listNotes(limit, offset) {
1115
+ const totalToFetch = limit + offset;
1116
+ return `
1117
+ tell application "Microsoft Outlook"
1118
+ set output to ""
1119
+ set allNotes to notes
1120
+ set noteCount to count of allNotes
1121
+ set startIdx to ${offset + 1}
1122
+ set endIdx to ${totalToFetch}
1123
+ if endIdx > noteCount then set endIdx to noteCount
1124
+ if startIdx > noteCount then return ""
1125
+
1126
+ repeat with i from startIdx to endIdx
1127
+ try
1128
+ set n to item i of allNotes
1129
+ set nId to id of n
1130
+ set nName to name of n
1131
+ set nCreated to ""
1132
+ try
1133
+ set nCreated to creation date of n as «class isot» as string
1134
+ end try
1135
+ set nModified to ""
1136
+ try
1137
+ set nModified to modification date of n as «class isot» as string
1138
+ end try
1139
+ set nPreview to ""
1140
+ try
1141
+ set nPreview to text 1 thru 200 of plain text content of n
1142
+ on error
1143
+ try
1144
+ set nPreview to plain text content of n
1145
+ end try
1146
+ end try
1147
+
1148
+ set output to output & "{{RECORD}}id{{=}}" & nId & "{{FIELD}}name{{=}}" & nName & "{{FIELD}}createdDate{{=}}" & nCreated & "{{FIELD}}modifiedDate{{=}}" & nModified & "{{FIELD}}preview{{=}}" & nPreview
1149
+ end try
1150
+ end repeat
1151
+ return output
1152
+ end tell
1153
+ `;
1154
+ }
1155
+ /**
1156
+ * Searches notes by name.
1157
+ */
1158
+ export function searchNotes(query, limit) {
1159
+ const escapedQuery = escapeForAppleScript(query);
1160
+ return `
1161
+ tell application "Microsoft Outlook"
1162
+ set output to ""
1163
+ set searchResults to (notes whose name contains "${escapedQuery}")
1164
+ set resultCount to count of searchResults
1165
+ set maxResults to ${limit}
1166
+ if resultCount < maxResults then set maxResults to resultCount
1167
+
1168
+ repeat with i from 1 to maxResults
1169
+ try
1170
+ set n to item i of searchResults
1171
+ set nId to id of n
1172
+ set nName to name of n
1173
+ set nCreated to ""
1174
+ try
1175
+ set nCreated to creation date of n as «class isot» as string
1176
+ end try
1177
+ set nPreview to ""
1178
+ try
1179
+ set nPreview to text 1 thru 200 of plain text content of n
1180
+ on error
1181
+ try
1182
+ set nPreview to plain text content of n
1183
+ end try
1184
+ end try
1185
+
1186
+ set output to output & "{{RECORD}}id{{=}}" & nId & "{{FIELD}}name{{=}}" & nName & "{{FIELD}}createdDate{{=}}" & nCreated & "{{FIELD}}preview{{=}}" & nPreview
1187
+ end try
1188
+ end repeat
1189
+ return output
1190
+ end tell
1191
+ `;
1192
+ }
1193
+ /**
1194
+ * Gets a single note by ID.
1195
+ */
1196
+ export function getNote(noteId) {
1197
+ return `
1198
+ tell application "Microsoft Outlook"
1199
+ set n to note id ${noteId}
1200
+ set nId to id of n
1201
+ set nName to name of n
1202
+ set nContent to ""
1203
+ try
1204
+ set nContent to content of n
1205
+ end try
1206
+ set nPlain to ""
1207
+ try
1208
+ set nPlain to plain text content of n
1209
+ end try
1210
+ set nCreated to ""
1211
+ try
1212
+ set nCreated to creation date of n as «class isot» as string
1213
+ end try
1214
+ set nModified to ""
1215
+ try
1216
+ set nModified to modification date of n as «class isot» as string
1217
+ end try
1218
+ set nFolderId to ""
1219
+ try
1220
+ set nFolderId to id of folder of n
1221
+ end try
1222
+
1223
+ return "{{RECORD}}id{{=}}" & nId & "{{FIELD}}name{{=}}" & nName & "{{FIELD}}htmlContent{{=}}" & nContent & "{{FIELD}}plainContent{{=}}" & nPlain & "{{FIELD}}createdDate{{=}}" & nCreated & "{{FIELD}}modifiedDate{{=}}" & nModified & "{{FIELD}}folderId{{=}}" & nFolderId
1224
+ end tell
1225
+ `;
1226
+ }
1227
+ // Write Operation Scripts
1228
+ // =============================================================================
1229
+ /**
1230
+ * Moves a message to a different folder.
1231
+ */
1232
+ export function moveMessage(messageId, destinationFolderId) {
1233
+ return `
1234
+ tell application "Microsoft Outlook"
1235
+ set m to message id ${messageId}
1236
+ set targetFolder to mail folder id ${destinationFolderId}
1237
+ move m to targetFolder
1238
+ return "ok"
1239
+ end tell
1240
+ `;
1241
+ }
1242
+ /**
1243
+ * Moves a message to the Deleted Items folder.
1244
+ */
1245
+ export function deleteMessage(messageId) {
1246
+ return `
1247
+ tell application "Microsoft Outlook"
1248
+ set m to message id ${messageId}
1249
+ set deletedFolder to deleted items
1250
+ move m to deletedFolder
1251
+ return "ok"
1252
+ end tell
1253
+ `;
1254
+ }
1255
+ /**
1256
+ * Moves a message to the Archive folder.
1257
+ * Falls back to an "Archive" named folder if the well-known folder isn't available.
1258
+ */
1259
+ export function archiveMessage(messageId) {
1260
+ return `
1261
+ tell application "Microsoft Outlook"
1262
+ set m to message id ${messageId}
1263
+ try
1264
+ set archiveFolder to mail folder "Archive"
1265
+ move m to archiveFolder
1266
+ on error
1267
+ -- Try finding by name
1268
+ set allFolders to mail folders
1269
+ repeat with f in allFolders
1270
+ if name of f is "Archive" then
1271
+ move m to f
1272
+ return "ok"
1273
+ end if
1274
+ end repeat
1275
+ error "Archive folder not found"
1276
+ end try
1277
+ return "ok"
1278
+ end tell
1279
+ `;
1280
+ }
1281
+ /**
1282
+ * Moves a message to the Junk folder.
1283
+ */
1284
+ export function junkMessage(messageId) {
1285
+ return `
1286
+ tell application "Microsoft Outlook"
1287
+ set m to message id ${messageId}
1288
+ set junkFolder to junk mail
1289
+ move m to junkFolder
1290
+ return "ok"
1291
+ end tell
1292
+ `;
1293
+ }
1294
+ /**
1295
+ * Sets the read status of a message.
1296
+ */
1297
+ export function setMessageReadStatus(messageId, isRead) {
1298
+ return `
1299
+ tell application "Microsoft Outlook"
1300
+ set m to message id ${messageId}
1301
+ set is read of m to ${isRead}
1302
+ return "ok"
1303
+ end tell
1304
+ `;
1305
+ }
1306
+ /**
1307
+ * Sets the flag status of a message.
1308
+ * flagStatus: 0 = none, 1 = flagged, 2 = completed
1309
+ */
1310
+ export function setMessageFlag(messageId, flagStatus) {
1311
+ let flagValue;
1312
+ switch (flagStatus) {
1313
+ case 1:
1314
+ flagValue = 'flag marked';
1315
+ break;
1316
+ case 2:
1317
+ flagValue = 'flag complete';
1318
+ break;
1319
+ default:
1320
+ flagValue = 'flag not flagged';
1321
+ }
1322
+ return `
1323
+ tell application "Microsoft Outlook"
1324
+ set m to message id ${messageId}
1325
+ set todo flag of m to ${flagValue}
1326
+ return "ok"
1327
+ end tell
1328
+ `;
1329
+ }
1330
+ /**
1331
+ * Sets categories on a message.
1332
+ */
1333
+ export function setMessageCategories(messageId, categories) {
1334
+ const categoryList = categories.map(c => `"${escapeForAppleScript(c)}"`).join(', ');
1335
+ return `
1336
+ tell application "Microsoft Outlook"
1337
+ set m to message id ${messageId}
1338
+ set category of m to {${categoryList}}
1339
+ return "ok"
1340
+ end tell
1341
+ `;
1342
+ }
1343
+ /**
1344
+ * Creates a new mail folder.
1345
+ */
1346
+ export function createMailFolder(name, parentFolderId) {
1347
+ const escapedName = escapeForAppleScript(name);
1348
+ if (parentFolderId != null) {
1349
+ return `
1350
+ tell application "Microsoft Outlook"
1351
+ set parentFolder to mail folder id ${parentFolderId}
1352
+ set newFolder to make new mail folder at parentFolder with properties {name:"${escapedName}"}
1353
+ return id of newFolder
1354
+ end tell
1355
+ `;
1356
+ }
1357
+ return `
1358
+ tell application "Microsoft Outlook"
1359
+ set newFolder to make new mail folder with properties {name:"${escapedName}"}
1360
+ return id of newFolder
1361
+ end tell
1362
+ `;
1363
+ }
1364
+ /**
1365
+ * Deletes a mail folder.
1366
+ */
1367
+ export function deleteMailFolder(folderId) {
1368
+ return `
1369
+ tell application "Microsoft Outlook"
1370
+ set f to mail folder id ${folderId}
1371
+ delete f
1372
+ return "ok"
1373
+ end tell
1374
+ `;
1375
+ }
1376
+ /**
1377
+ * Renames a mail folder.
1378
+ */
1379
+ export function renameMailFolder(folderId, newName) {
1380
+ const escapedName = escapeForAppleScript(newName);
1381
+ return `
1382
+ tell application "Microsoft Outlook"
1383
+ set f to mail folder id ${folderId}
1384
+ set name of f to "${escapedName}"
1385
+ return "ok"
1386
+ end tell
1387
+ `;
1388
+ }
1389
+ /**
1390
+ * Moves a mail folder to a new parent.
1391
+ */
1392
+ export function moveMailFolder(folderId, destinationParentId) {
1393
+ return `
1394
+ tell application "Microsoft Outlook"
1395
+ set f to mail folder id ${folderId}
1396
+ set targetParent to mail folder id ${destinationParentId}
1397
+ move f to targetParent
1398
+ return "ok"
1399
+ end tell
1400
+ `;
1401
+ }
1402
+ /**
1403
+ * Deletes all messages in a folder (empties the folder).
1404
+ */
1405
+ export function emptyMailFolder(folderId) {
1406
+ return `
1407
+ tell application "Microsoft Outlook"
1408
+ set targetFolder to mail folder id ${folderId}
1409
+ set msgs to messages of targetFolder
1410
+ set deletedFolder to deleted items
1411
+ repeat with m in msgs
1412
+ try
1413
+ move m to deletedFolder
1414
+ end try
1415
+ end repeat
1416
+ return "ok"
1417
+ end tell
1418
+ `;
1419
+ }
1420
+ /**
1421
+ * Sends an email with optional CC, BCC, attachments, and account selection.
1422
+ */
1423
+ export function sendEmail(params) {
1424
+ const { to, subject, body, bodyType, cc, bcc, replyTo, attachments, inlineImages, accountId } = params;
1425
+ const escapedSubject = escapeForAppleScript(subject);
1426
+ const escapedBody = escapeForAppleScript(body);
1427
+ const toRecipients = to.map(email => ` make new recipient at newMessage with properties {email address:{address:"${email}"}}`).join('\n');
1428
+ const ccRecipients = cc != null && cc.length > 0
1429
+ ? cc.map(email => ` make new recipient at newMessage with properties {email address:{address:"${email}"}, recipient type:recipient cc}`).join('\n')
1430
+ : '';
1431
+ const bccRecipients = bcc != null && bcc.length > 0
1432
+ ? bcc.map(email => ` make new recipient at newMessage with properties {email address:{address:"${email}"}, recipient type:recipient bcc}`).join('\n')
1433
+ : '';
1434
+ const contentProperty = bodyType === 'html'
1435
+ ? `html content:"${escapedBody}"`
1436
+ : `plain text content:"${escapedBody}"`;
1437
+ const replyToStatement = replyTo != null
1438
+ ? ` set reply to of newMessage to "${replyTo}"`
1439
+ : '';
1440
+ const attachmentStatements = attachments != null && attachments.length > 0
1441
+ ? attachments.map(att => ` make new attachment at newMessage with properties {file:(POSIX file "${att.path}")}`).join('\n')
1442
+ : '';
1443
+ const inlineImageStatements = inlineImages != null && inlineImages.length > 0
1444
+ ? inlineImages.map((img, i) => ` set inlineAttach${i} to make new attachment at newMessage with properties {file:(POSIX file "${img.path}")}\n` +
1445
+ ` try\n` +
1446
+ ` set content id of inlineAttach${i} to "${img.contentId}"\n` +
1447
+ ` end try`).join('\n')
1448
+ : '';
1449
+ const accountStatement = accountId != null
1450
+ ? ` set sending account of newMessage to account id ${accountId}`
1451
+ : '';
1452
+ return `
1453
+ tell application "Microsoft Outlook"
1454
+ try
1455
+ set newMessage to make new outgoing message with properties {subject:"${escapedSubject}", ${contentProperty}}
1456
+
1457
+ ${toRecipients}
1458
+ ${ccRecipients}
1459
+ ${bccRecipients}
1460
+ ${replyToStatement}
1461
+ ${accountStatement}
1462
+ ${attachmentStatements}
1463
+ ${inlineImageStatements}
1464
+
1465
+ send newMessage
1466
+
1467
+ -- Get message ID and timestamp
1468
+ set msgId to id of newMessage as string
1469
+ set sentTime to current date
1470
+ set sentISO to sentTime as «class isot» as string
1471
+
1472
+ -- Return success
1473
+ set output to "{{RECORD}}success{{=}}true{{FIELD}}messageId{{=}}" & msgId & "{{FIELD}}sentAt{{=}}" & sentISO
1474
+ return output
1475
+ on error errMsg
1476
+ -- Return failure
1477
+ set output to "{{RECORD}}success{{=}}false{{FIELD}}error{{=}}" & errMsg
1478
+ return output
1479
+ end try
1480
+ end tell
1481
+ `;
1482
+ }
1483
+ //# sourceMappingURL=scripts.js.map