apple-mail-mcp 2.1.5 → 2.2.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.
- package/README.md +5 -2
- package/build/index.js +159 -53
- package/build/services/imapClient.d.ts +14 -2
- package/build/services/imapClient.d.ts.map +1 -1
- package/build/services/imapClient.js +34 -5
- package/build/services/messageRouter.d.ts +8 -0
- package/build/services/messageRouter.d.ts.map +1 -1
- package/build/services/messageRouter.js +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -62,11 +62,14 @@ codex plugin marketplace add sweetrb/apple-mail-mcp
|
|
|
62
62
|
codex plugin add apple-mail@apple-mail-mcp
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
-
The Codex package registers the same `apple-mail` MCP server through `npx -y
|
|
65
|
+
The Codex package registers the same `apple-mail` MCP server through `npx -y apple-mail-mcp` and includes the Apple Mail skill guidance.
|
|
66
66
|
|
|
67
67
|
### Other Hosts (Hermes, Antigravity)
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
Configuration for two more hosts is included — each registers the same `apple-mail` MCP server (`npx -y apple-mail-mcp`):
|
|
70
|
+
|
|
71
|
+
- **[Hermes Agent](https://hermes-agent.nousresearch.com/)** (NousResearch) — Hermes has no plugin/marketplace drop-in. Add the server with `hermes mcp add apple-mail --command npx --args -y apple-mail-mcp`, or merge [`.hermes-plugin/config.yaml`](.hermes-plugin/config.yaml) into `~/.hermes/config.yaml`. Details: [`.hermes-plugin/README.md`](.hermes-plugin/README.md).
|
|
72
|
+
- **[Antigravity](https://antigravity.google/)** (Google) — add the server entry from [`.antigravity-plugin/mcp_config.json`](.antigravity-plugin/mcp_config.json) to `~/.gemini/config/mcp_config.json` (or via Antigravity's MCP settings).
|
|
70
73
|
|
|
71
74
|
### Manual Installation
|
|
72
75
|
|
package/build/index.js
CHANGED
|
@@ -153,7 +153,7 @@ server.tool("search-messages", "Use when: finding messages by query/sender/subje
|
|
|
153
153
|
// IMAP backend (issue #43): server-side search when this account is
|
|
154
154
|
// explicitly configured for IMAP; otherwise fall through to AppleScript.
|
|
155
155
|
if (isImapAccount(account)) {
|
|
156
|
-
|
|
156
|
+
const r = await imapSearchMessages({
|
|
157
157
|
query,
|
|
158
158
|
mailbox,
|
|
159
159
|
account,
|
|
@@ -164,7 +164,12 @@ server.tool("search-messages", "Use when: finding messages by query/sender/subje
|
|
|
164
164
|
subject,
|
|
165
165
|
isRead,
|
|
166
166
|
isFlagged,
|
|
167
|
-
})
|
|
167
|
+
});
|
|
168
|
+
return successResponse(r.text, {
|
|
169
|
+
messages: r.messages,
|
|
170
|
+
count: r.count,
|
|
171
|
+
partial: r.partial,
|
|
172
|
+
});
|
|
168
173
|
}
|
|
169
174
|
const { messages, diagnostics } = mailManager.searchMessagesWithDiagnostics(query, mailbox, account, limit, dateFrom, dateTo, from, subject, isRead, isFlagged);
|
|
170
175
|
const coverageBlock = partialCoverageBlock(diagnostics);
|
|
@@ -197,6 +202,19 @@ server.tool("get-message", "Use when: reading the full body of one message whose
|
|
|
197
202
|
}, withErrorHandling(({ id, preferHtml }) => routeMessage(id, {
|
|
198
203
|
// IMAP id (imap:…) → fetch via IMAP (#43 Phase 3); else AppleScript.
|
|
199
204
|
imap: () => imapGetMessage(id, preferHtml === true),
|
|
205
|
+
// IMAP path: parse subject/body out of the returned source so the
|
|
206
|
+
// structuredContent matches the AppleScript branch's shape.
|
|
207
|
+
structuredFromResult: (r) => {
|
|
208
|
+
if (!r.info)
|
|
209
|
+
return undefined;
|
|
210
|
+
const sep = r.info.indexOf("\n\n");
|
|
211
|
+
return {
|
|
212
|
+
id,
|
|
213
|
+
subject: subjectFromGetMessage(r.info),
|
|
214
|
+
body: sep >= 0 ? r.info.slice(sep + 2) : r.info,
|
|
215
|
+
isHtml: preferHtml === true,
|
|
216
|
+
};
|
|
217
|
+
},
|
|
200
218
|
apple: () => {
|
|
201
219
|
// Only fetch/parse the raw source when HTML is actually requested (#32).
|
|
202
220
|
const content = mailManager.getMessageContent(id, preferHtml === true);
|
|
@@ -249,8 +267,13 @@ server.tool("get-thread", "Use when: you have one message id and want the whole
|
|
|
249
267
|
const base = normalizeSubject(seedSubject);
|
|
250
268
|
// IMAP backend: server-side subject search.
|
|
251
269
|
if (isImapAccount(account)) {
|
|
252
|
-
const
|
|
253
|
-
return successResponse(`Thread "${base}":\n${text}`, {
|
|
270
|
+
const r = await imapSearchMessages({ subject: base, mailbox, account, limit });
|
|
271
|
+
return successResponse(`Thread "${base}":\n${r.text}`, {
|
|
272
|
+
subject: base,
|
|
273
|
+
messages: r.messages,
|
|
274
|
+
count: r.count,
|
|
275
|
+
partial: r.partial,
|
|
276
|
+
});
|
|
254
277
|
}
|
|
255
278
|
const { messages, diagnostics } = mailManager.searchMessagesWithDiagnostics(undefined, mailbox, account, limit, undefined, undefined, undefined, base);
|
|
256
279
|
// Oldest-first is the natural reading order for a conversation.
|
|
@@ -287,7 +310,12 @@ server.tool("list-messages", "Use when: browsing a mailbox's recent messages (op
|
|
|
287
310
|
// IMAP backend (issue #43): server-side listing when this account is
|
|
288
311
|
// explicitly configured for IMAP; otherwise fall through to AppleScript.
|
|
289
312
|
if (isImapAccount(account)) {
|
|
290
|
-
|
|
313
|
+
const r = await imapListMessages({ mailbox, account, limit, offset, from, unreadOnly });
|
|
314
|
+
return successResponse(r.text, {
|
|
315
|
+
messages: r.messages,
|
|
316
|
+
count: r.count,
|
|
317
|
+
partial: r.partial,
|
|
318
|
+
});
|
|
291
319
|
}
|
|
292
320
|
const { messages, diagnostics } = mailManager.listMessagesWithDiagnostics(mailbox, account, limit, from, offset);
|
|
293
321
|
const coverageBlock = partialCoverageBlock(diagnostics);
|
|
@@ -327,18 +355,29 @@ server.tool("send-email", "Use when: the user has explicitly confirmed they want
|
|
|
327
355
|
"Mail.app <blockquote> wrapping (issue #12); requires APPLE_MAIL_MCP_SMTP_* env config."),
|
|
328
356
|
}, withErrorHandling(async ({ to, subject, body, cc, bcc, account, attachments, transport }) => {
|
|
329
357
|
const attachInfo = attachments?.length ? ` with ${attachments.length} attachment(s)` : "";
|
|
358
|
+
const attachmentCount = attachments?.length ?? 0;
|
|
330
359
|
if (transport === "smtp") {
|
|
331
360
|
const result = await sendViaSmtp({ to, subject, body, cc, bcc, from: account, attachments });
|
|
332
361
|
if (!result.success) {
|
|
333
362
|
return errorResponse(result.error ?? "Failed to send email via SMTP.");
|
|
334
363
|
}
|
|
335
|
-
return successResponse(`Email sent via SMTP to ${to.join(", ")}${attachInfo}
|
|
364
|
+
return successResponse(`Email sent via SMTP to ${to.join(", ")}${attachInfo}`, {
|
|
365
|
+
ok: true,
|
|
366
|
+
recipients: to,
|
|
367
|
+
attachmentCount,
|
|
368
|
+
transport: "smtp",
|
|
369
|
+
});
|
|
336
370
|
}
|
|
337
371
|
const success = mailManager.sendEmail(to, subject, body, cc, bcc, account, attachments);
|
|
338
372
|
if (!success) {
|
|
339
373
|
return errorResponse("Failed to send email. Check Mail.app configuration.");
|
|
340
374
|
}
|
|
341
|
-
return successResponse(`Email sent to ${to.join(", ")}${attachInfo}
|
|
375
|
+
return successResponse(`Email sent to ${to.join(", ")}${attachInfo}`, {
|
|
376
|
+
ok: true,
|
|
377
|
+
recipients: to,
|
|
378
|
+
attachmentCount,
|
|
379
|
+
transport: "applescript",
|
|
380
|
+
});
|
|
342
381
|
}, "Error sending email"));
|
|
343
382
|
// --- send-serial-email ---
|
|
344
383
|
server.tool("send-serial-email", "Use when: the user has confirmed a mail-merge — sending individually personalized copies to many recipients (max 100), with {{Key}} placeholders in subject/body replaced per-recipient from each recipient's variables. Recipients do not see each other.\nReturns: a per-recipient sent/failed report with counts.\nDo not use when: sending one message to a shared recipient list (use send-email) or saving for review (use create-draft).\nSafety: this SENDS many real emails immediately and they cannot be unsent — require explicit user confirmation of the recipient list, the subject/body template, and the placeholder substitutions before calling.", {
|
|
@@ -374,14 +413,20 @@ server.tool("send-serial-email", "Use when: the user has confirmed a mail-merge
|
|
|
374
413
|
const details = results
|
|
375
414
|
.map((r) => ` - ${r.email}: ${r.success ? "sent" : `FAILED (${r.error})`}`)
|
|
376
415
|
.join("\n");
|
|
416
|
+
const structured = {
|
|
417
|
+
ok: failCount === 0,
|
|
418
|
+
sent: successCount,
|
|
419
|
+
failed: failCount,
|
|
420
|
+
results: results.map((r) => ({ email: r.email, success: r.success, error: r.error })),
|
|
421
|
+
};
|
|
377
422
|
if (failCount === 0) {
|
|
378
|
-
return successResponse(`Successfully sent ${successCount} email(s):\n${details}
|
|
423
|
+
return successResponse(`Successfully sent ${successCount} email(s):\n${details}`, structured);
|
|
379
424
|
}
|
|
380
425
|
else if (successCount === 0) {
|
|
381
426
|
return errorResponse(`Failed to send all ${failCount} email(s):\n${details}`);
|
|
382
427
|
}
|
|
383
428
|
else {
|
|
384
|
-
return successResponse(`Sent ${successCount} of ${results.length} email(s), ${failCount} failed:\n${details}
|
|
429
|
+
return successResponse(`Sent ${successCount} of ${results.length} email(s), ${failCount} failed:\n${details}`, structured);
|
|
385
430
|
}
|
|
386
431
|
}, "Error sending serial emails"));
|
|
387
432
|
// --- create-draft ---
|
|
@@ -398,8 +443,13 @@ server.tool("create-draft", "Use when: composing an email the user should review
|
|
|
398
443
|
if (!success) {
|
|
399
444
|
return errorResponse("Failed to create draft. Check Mail.app configuration.");
|
|
400
445
|
}
|
|
401
|
-
const
|
|
402
|
-
|
|
446
|
+
const attachmentCount = attachments?.length ?? 0;
|
|
447
|
+
const attachInfo = attachmentCount ? ` with ${attachmentCount} attachment(s)` : "";
|
|
448
|
+
return successResponse(`Draft created for ${to.join(", ")}${attachInfo}`, {
|
|
449
|
+
ok: true,
|
|
450
|
+
recipients: to,
|
|
451
|
+
attachmentCount,
|
|
452
|
+
});
|
|
403
453
|
}, "Error creating draft"));
|
|
404
454
|
// --- reply-to-message ---
|
|
405
455
|
server.tool("reply-to-message", "Use when: replying to an existing message by id, preserving its threading headers. Set replyAll for all recipients; set send=false to save as a draft instead of sending.\nReturns: a confirmation that the reply was sent or saved as a draft.\nDo not use when: composing a brand-new message (use send-email / create-draft) or forwarding to new recipients (use forward-message).\nSafety: with the default send=true this SENDS real email immediately and cannot be unsent — require explicit user confirmation of the recipients and body, or pass send=false to let the user review.", {
|
|
@@ -412,7 +462,11 @@ server.tool("reply-to-message", "Use when: replying to an existing message by id
|
|
|
412
462
|
if (!success) {
|
|
413
463
|
return errorResponse(`Failed to reply to message "${id}"`);
|
|
414
464
|
}
|
|
415
|
-
return successResponse(send ? "Reply sent" : "Reply saved as draft"
|
|
465
|
+
return successResponse(send ? "Reply sent" : "Reply saved as draft", {
|
|
466
|
+
ok: true,
|
|
467
|
+
sent: send,
|
|
468
|
+
id,
|
|
469
|
+
});
|
|
416
470
|
}, "Error replying to message"));
|
|
417
471
|
// --- forward-message ---
|
|
418
472
|
server.tool("forward-message", "Use when: forwarding an existing message (by id) to new recipients (to is an array), with an optional body to prepend. Set send=false to save as a draft.\nReturns: a confirmation that the message was forwarded or saved as a draft.\nDo not use when: replying to the sender/recipients (use reply-to-message) or composing a new message (use send-email / create-draft).\nSafety: with the default send=true this SENDS real email immediately and cannot be unsent — require explicit user confirmation of the recipients and any prepended body, or pass send=false to let the user review.", {
|
|
@@ -425,7 +479,7 @@ server.tool("forward-message", "Use when: forwarding an existing message (by id)
|
|
|
425
479
|
if (!success) {
|
|
426
480
|
return errorResponse(`Failed to forward message "${id}"`);
|
|
427
481
|
}
|
|
428
|
-
return successResponse(send ? `Message forwarded to ${to.join(", ")}` : "Forward saved as draft");
|
|
482
|
+
return successResponse(send ? `Message forwarded to ${to.join(", ")}` : "Forward saved as draft", { ok: true, sent: send, recipients: to, id });
|
|
429
483
|
}, "Error forwarding message"));
|
|
430
484
|
// --- mark-as-read ---
|
|
431
485
|
server.tool("mark-as-read", "Use when: marking a single message (by id) as read.\nReturns: a confirmation that the message was marked read.\nDo not use when: marking several at once (use batch-mark-as-read) or marking unread (use mark-as-unread). Get the id from search-messages or list-messages first.", {
|
|
@@ -433,10 +487,11 @@ server.tool("mark-as-read", "Use when: marking a single message (by id) as read.
|
|
|
433
487
|
}, withErrorHandling(({ id }) => routeMessage(id, {
|
|
434
488
|
imap: () => imapMarkRead(id),
|
|
435
489
|
apple: () => mailManager.markAsRead(id)
|
|
436
|
-
? successResponse("Message marked as read")
|
|
490
|
+
? successResponse("Message marked as read", { ok: true, id })
|
|
437
491
|
: errorResponse(`Failed to mark message "${id}" as read`),
|
|
438
492
|
ok: "Message marked as read",
|
|
439
493
|
fail: `Failed to mark message "${id}" as read`,
|
|
494
|
+
structured: { ok: true, id },
|
|
440
495
|
}), "Error marking message as read"));
|
|
441
496
|
// --- mark-as-unread ---
|
|
442
497
|
server.tool("mark-as-unread", "Use when: marking a single message (by id) as unread.\nReturns: a confirmation that the message was marked unread.\nDo not use when: marking several at once (use batch-mark-as-unread) or marking read (use mark-as-read). Get the id from search-messages or list-messages first.", {
|
|
@@ -444,10 +499,11 @@ server.tool("mark-as-unread", "Use when: marking a single message (by id) as unr
|
|
|
444
499
|
}, withErrorHandling(({ id }) => routeMessage(id, {
|
|
445
500
|
imap: () => imapMarkUnread(id),
|
|
446
501
|
apple: () => mailManager.markAsUnread(id)
|
|
447
|
-
? successResponse("Message marked as unread")
|
|
502
|
+
? successResponse("Message marked as unread", { ok: true, id })
|
|
448
503
|
: errorResponse(`Failed to mark message "${id}" as unread`),
|
|
449
504
|
ok: "Message marked as unread",
|
|
450
505
|
fail: `Failed to mark message "${id}" as unread`,
|
|
506
|
+
structured: { ok: true, id },
|
|
451
507
|
}), "Error marking message as unread"));
|
|
452
508
|
// --- flag-message ---
|
|
453
509
|
server.tool("flag-message", "Use when: flagging a single message (by id).\nReturns: a confirmation that the message was flagged.\nDo not use when: flagging several at once (use batch-flag-messages) or removing a flag (use unflag-message). Get the id from search-messages or list-messages first.", {
|
|
@@ -455,10 +511,11 @@ server.tool("flag-message", "Use when: flagging a single message (by id).\nRetur
|
|
|
455
511
|
}, withErrorHandling(({ id }) => routeMessage(id, {
|
|
456
512
|
imap: () => imapFlagMessage(id),
|
|
457
513
|
apple: () => mailManager.flagMessage(id)
|
|
458
|
-
? successResponse("Message flagged")
|
|
514
|
+
? successResponse("Message flagged", { ok: true, id })
|
|
459
515
|
: errorResponse(`Failed to flag message "${id}"`),
|
|
460
516
|
ok: "Message flagged",
|
|
461
517
|
fail: `Failed to flag message "${id}"`,
|
|
518
|
+
structured: { ok: true, id },
|
|
462
519
|
}), "Error flagging message"));
|
|
463
520
|
// --- unflag-message ---
|
|
464
521
|
server.tool("unflag-message", "Use when: removing the flag from a single message (by id).\nReturns: a confirmation that the message was unflagged.\nDo not use when: unflagging several at once (use batch-unflag-messages) or adding a flag (use flag-message). Get the id from search-messages or list-messages first.", {
|
|
@@ -466,10 +523,11 @@ server.tool("unflag-message", "Use when: removing the flag from a single message
|
|
|
466
523
|
}, withErrorHandling(({ id }) => routeMessage(id, {
|
|
467
524
|
imap: () => imapUnflagMessage(id),
|
|
468
525
|
apple: () => mailManager.unflagMessage(id)
|
|
469
|
-
? successResponse("Message unflagged")
|
|
526
|
+
? successResponse("Message unflagged", { ok: true, id })
|
|
470
527
|
: errorResponse(`Failed to unflag message "${id}"`),
|
|
471
528
|
ok: "Message unflagged",
|
|
472
529
|
fail: `Failed to unflag message "${id}"`,
|
|
530
|
+
structured: { ok: true, id },
|
|
473
531
|
}), "Error unflagging message"));
|
|
474
532
|
// --- delete-message ---
|
|
475
533
|
server.tool("delete-message", "Use when: deleting a single message by id (moves it to Trash).\nReturns: a confirmation that the message was deleted.\nDo not use when: deleting several at once (use batch-delete-messages) or just filing it away (use move-message).\nSafety: destructive — require explicit user confirmation, and search-messages/list-messages first to confirm you have the right id before deleting.", {
|
|
@@ -479,11 +537,12 @@ server.tool("delete-message", "Use when: deleting a single message by id (moves
|
|
|
479
537
|
apple: () => {
|
|
480
538
|
const { success, error } = mailManager.deleteMessage(id);
|
|
481
539
|
return success
|
|
482
|
-
? successResponse("Message deleted")
|
|
540
|
+
? successResponse("Message deleted", { ok: true, id })
|
|
483
541
|
: errorResponse(error || `Failed to delete message "${id}"`);
|
|
484
542
|
},
|
|
485
543
|
ok: "Message deleted",
|
|
486
544
|
fail: `Failed to delete message "${id}"`,
|
|
545
|
+
structured: { ok: true, id },
|
|
487
546
|
}), "Error deleting message"));
|
|
488
547
|
// --- move-message ---
|
|
489
548
|
server.tool("move-message", "Use when: moving a single message (by id) into another mailbox/folder, e.g. archiving or filing.\nReturns: a confirmation naming the destination mailbox.\nDo not use when: moving several at once (use batch-move-messages) or deleting (use delete-message). Use list-mailboxes to confirm the destination name exists.\nSafety: moves a real message between folders — confirm the destination mailbox, and search-messages/list-messages first to confirm the id.", {
|
|
@@ -495,25 +554,27 @@ server.tool("move-message", "Use when: moving a single message (by id) into anot
|
|
|
495
554
|
apple: () => {
|
|
496
555
|
const { success, error } = mailManager.moveMessage(id, mailbox, account);
|
|
497
556
|
return success
|
|
498
|
-
? successResponse(`Message moved to "${mailbox}"
|
|
557
|
+
? successResponse(`Message moved to "${mailbox}"`, { ok: true, id, mailbox })
|
|
499
558
|
: errorResponse(error || `Failed to move message to "${mailbox}"`);
|
|
500
559
|
},
|
|
501
560
|
ok: `Message moved to "${mailbox}"`,
|
|
502
561
|
fail: `Failed to move message to "${mailbox}"`,
|
|
562
|
+
structured: { ok: true, id, mailbox },
|
|
503
563
|
}), "Error moving message"));
|
|
504
564
|
// --- batch-delete-messages ---
|
|
505
565
|
server.tool("batch-delete-messages", "Use when: deleting multiple messages in one call (1–100 ids; moves them to Trash).\nReturns: counts of how many were deleted and how many failed.\nDo not use when: deleting just one (use delete-message) or filing messages away (use batch-move-messages).\nSafety: destructive and applies to many messages at once — require explicit user confirmation, and search-messages/list-messages first to confirm every id is correct before deleting.", {
|
|
506
566
|
ids: BATCH_IDS_SCHEMA,
|
|
507
567
|
}, withErrorHandling(async ({ ids }) => {
|
|
508
568
|
const { success: successCount, fail: failCount } = await hybridBatchCounts(ids, (n) => mailManager.batchDeleteMessages(n), (im) => imapBatchDelete(im));
|
|
569
|
+
const structured = { ok: failCount === 0, success: successCount, failed: failCount };
|
|
509
570
|
if (failCount === 0) {
|
|
510
|
-
return successResponse(`Successfully deleted ${successCount} message(s)
|
|
571
|
+
return successResponse(`Successfully deleted ${successCount} message(s)`, structured);
|
|
511
572
|
}
|
|
512
573
|
else if (successCount === 0) {
|
|
513
574
|
return errorResponse(`Failed to delete all ${failCount} message(s)`);
|
|
514
575
|
}
|
|
515
576
|
else {
|
|
516
|
-
return successResponse(`Deleted ${successCount} message(s), ${failCount} failed
|
|
577
|
+
return successResponse(`Deleted ${successCount} message(s), ${failCount} failed`, structured);
|
|
517
578
|
}
|
|
518
579
|
}, "Error batch deleting messages"));
|
|
519
580
|
// --- batch-move-messages ---
|
|
@@ -523,14 +584,15 @@ server.tool("batch-move-messages", "Use when: moving multiple messages (1–100
|
|
|
523
584
|
account: z.string().optional().describe("Account containing the destination mailbox"),
|
|
524
585
|
}, withErrorHandling(async ({ ids, mailbox, account }) => {
|
|
525
586
|
const { success: successCount, fail: failCount } = await hybridBatchCounts(ids, (n) => mailManager.batchMoveMessages(n, mailbox, account), (im) => imapBatchMove(im, mailbox, { account }));
|
|
587
|
+
const structured = { ok: failCount === 0, success: successCount, failed: failCount, mailbox };
|
|
526
588
|
if (failCount === 0) {
|
|
527
|
-
return successResponse(`Successfully moved ${successCount} message(s) to "${mailbox}"
|
|
589
|
+
return successResponse(`Successfully moved ${successCount} message(s) to "${mailbox}"`, structured);
|
|
528
590
|
}
|
|
529
591
|
else if (successCount === 0) {
|
|
530
592
|
return errorResponse(`Failed to move all ${failCount} message(s)`);
|
|
531
593
|
}
|
|
532
594
|
else {
|
|
533
|
-
return successResponse(`Moved ${successCount} message(s) to "${mailbox}", ${failCount} failed
|
|
595
|
+
return successResponse(`Moved ${successCount} message(s) to "${mailbox}", ${failCount} failed`, structured);
|
|
534
596
|
}
|
|
535
597
|
}, "Error batch moving messages"));
|
|
536
598
|
// --- batch-mark-as-read ---
|
|
@@ -538,14 +600,15 @@ server.tool("batch-mark-as-read", "Use when: marking multiple messages (1–100
|
|
|
538
600
|
ids: BATCH_IDS_SCHEMA,
|
|
539
601
|
}, withErrorHandling(async ({ ids }) => {
|
|
540
602
|
const { success: successCount, fail: failCount } = await hybridBatchCounts(ids, (n) => mailManager.batchMarkAsRead(n), (im) => imapBatchMarkRead(im));
|
|
603
|
+
const structured = { ok: failCount === 0, success: successCount, failed: failCount };
|
|
541
604
|
if (failCount === 0) {
|
|
542
|
-
return successResponse(`Successfully marked ${successCount} message(s) as read
|
|
605
|
+
return successResponse(`Successfully marked ${successCount} message(s) as read`, structured);
|
|
543
606
|
}
|
|
544
607
|
else if (successCount === 0) {
|
|
545
608
|
return errorResponse(`Failed to mark all ${failCount} message(s) as read`);
|
|
546
609
|
}
|
|
547
610
|
else {
|
|
548
|
-
return successResponse(`Marked ${successCount} message(s) as read, ${failCount} failed
|
|
611
|
+
return successResponse(`Marked ${successCount} message(s) as read, ${failCount} failed`, structured);
|
|
549
612
|
}
|
|
550
613
|
}, "Error batch marking messages as read"));
|
|
551
614
|
// --- batch-mark-as-unread ---
|
|
@@ -553,14 +616,15 @@ server.tool("batch-mark-as-unread", "Use when: marking multiple messages (1–10
|
|
|
553
616
|
ids: BATCH_IDS_SCHEMA,
|
|
554
617
|
}, withErrorHandling(async ({ ids }) => {
|
|
555
618
|
const { success: successCount, fail: failCount } = await hybridBatchCounts(ids, (n) => mailManager.batchMarkAsUnread(n), (im) => imapBatchMarkUnread(im));
|
|
619
|
+
const structured = { ok: failCount === 0, success: successCount, failed: failCount };
|
|
556
620
|
if (failCount === 0) {
|
|
557
|
-
return successResponse(`Successfully marked ${successCount} message(s) as unread
|
|
621
|
+
return successResponse(`Successfully marked ${successCount} message(s) as unread`, structured);
|
|
558
622
|
}
|
|
559
623
|
else if (successCount === 0) {
|
|
560
624
|
return errorResponse(`Failed to mark all ${failCount} message(s) as unread`);
|
|
561
625
|
}
|
|
562
626
|
else {
|
|
563
|
-
return successResponse(`Marked ${successCount} message(s) as unread, ${failCount} failed
|
|
627
|
+
return successResponse(`Marked ${successCount} message(s) as unread, ${failCount} failed`, structured);
|
|
564
628
|
}
|
|
565
629
|
}, "Error batch marking messages as unread"));
|
|
566
630
|
// --- batch-flag-messages ---
|
|
@@ -568,14 +632,15 @@ server.tool("batch-flag-messages", "Use when: flagging multiple messages (1–10
|
|
|
568
632
|
ids: BATCH_IDS_SCHEMA,
|
|
569
633
|
}, withErrorHandling(async ({ ids }) => {
|
|
570
634
|
const { success: successCount, fail: failCount } = await hybridBatchCounts(ids, (n) => mailManager.batchFlagMessages(n), (im) => imapBatchFlag(im));
|
|
635
|
+
const structured = { ok: failCount === 0, success: successCount, failed: failCount };
|
|
571
636
|
if (failCount === 0) {
|
|
572
|
-
return successResponse(`Successfully flagged ${successCount} message(s)
|
|
637
|
+
return successResponse(`Successfully flagged ${successCount} message(s)`, structured);
|
|
573
638
|
}
|
|
574
639
|
else if (successCount === 0) {
|
|
575
640
|
return errorResponse(`Failed to flag all ${failCount} message(s)`);
|
|
576
641
|
}
|
|
577
642
|
else {
|
|
578
|
-
return successResponse(`Flagged ${successCount} message(s), ${failCount} failed
|
|
643
|
+
return successResponse(`Flagged ${successCount} message(s), ${failCount} failed`, structured);
|
|
579
644
|
}
|
|
580
645
|
}, "Error batch flagging messages"));
|
|
581
646
|
// --- batch-unflag-messages ---
|
|
@@ -583,14 +648,15 @@ server.tool("batch-unflag-messages", "Use when: removing flags from multiple mes
|
|
|
583
648
|
ids: BATCH_IDS_SCHEMA,
|
|
584
649
|
}, withErrorHandling(async ({ ids }) => {
|
|
585
650
|
const { success: successCount, fail: failCount } = await hybridBatchCounts(ids, (n) => mailManager.batchUnflagMessages(n), (im) => imapBatchUnflag(im));
|
|
651
|
+
const structured = { ok: failCount === 0, success: successCount, failed: failCount };
|
|
586
652
|
if (failCount === 0) {
|
|
587
|
-
return successResponse(`Successfully unflagged ${successCount} message(s)
|
|
653
|
+
return successResponse(`Successfully unflagged ${successCount} message(s)`, structured);
|
|
588
654
|
}
|
|
589
655
|
else if (successCount === 0) {
|
|
590
656
|
return errorResponse(`Failed to unflag all ${failCount} message(s)`);
|
|
591
657
|
}
|
|
592
658
|
else {
|
|
593
|
-
return successResponse(`Unflagged ${successCount} message(s), ${failCount} failed
|
|
659
|
+
return successResponse(`Unflagged ${successCount} message(s), ${failCount} failed`, structured);
|
|
594
660
|
}
|
|
595
661
|
}, "Error batch unflagging messages"));
|
|
596
662
|
// --- list-attachments ---
|
|
@@ -640,14 +706,23 @@ server.tool("save-attachment", "Use when: writing one of a message's attachments
|
|
|
640
706
|
if (!r.success || !r.base64) {
|
|
641
707
|
return errorResponse(r.error || `Failed to fetch attachment "${attachmentName}"`);
|
|
642
708
|
}
|
|
643
|
-
|
|
644
|
-
|
|
709
|
+
const savedPath = joinPath(resolvedDir, attachmentName);
|
|
710
|
+
writeFileSync(savedPath, Buffer.from(r.base64, "base64"));
|
|
711
|
+
return successResponse(`Attachment "${attachmentName}" saved to ${savePath}`, {
|
|
712
|
+
ok: true,
|
|
713
|
+
attachmentName,
|
|
714
|
+
savedPath,
|
|
715
|
+
});
|
|
645
716
|
}
|
|
646
717
|
const success = mailManager.saveAttachment(id, attachmentName, savePath);
|
|
647
718
|
if (!success) {
|
|
648
719
|
return errorResponse(`Failed to save attachment "${attachmentName}"`);
|
|
649
720
|
}
|
|
650
|
-
return successResponse(`Attachment "${attachmentName}" saved to ${savePath}
|
|
721
|
+
return successResponse(`Attachment "${attachmentName}" saved to ${savePath}`, {
|
|
722
|
+
ok: true,
|
|
723
|
+
attachmentName,
|
|
724
|
+
savedPath: joinPath(savePath, attachmentName),
|
|
725
|
+
});
|
|
651
726
|
}, "Error saving attachment"));
|
|
652
727
|
// --- fetch-attachment ---
|
|
653
728
|
server.tool("fetch-attachment", "Use when: retrieving an attachment's raw bytes inline as base64 (by message id and attachmentName), e.g. to process its contents without touching disk.\nReturns: the attachment's bytes base64-encoded, with its size and (for IMAP) MIME type.\nDo not use when: you don't know the attachment name (use list-attachments first) or you just want it saved to disk (use save-attachment).", {
|
|
@@ -730,13 +805,13 @@ server.tool("create-mailbox", "Use when: creating a new mailbox/folder in an acc
|
|
|
730
805
|
const r = await imapCreateMailbox(name, { account });
|
|
731
806
|
if (!r.success)
|
|
732
807
|
return errorResponse(r.error || `Failed to create mailbox "${name}"`);
|
|
733
|
-
return successResponse(r.info || `Mailbox "${name}" created
|
|
808
|
+
return successResponse(r.info || `Mailbox "${name}" created`, { ok: true, name });
|
|
734
809
|
}
|
|
735
810
|
const success = mailManager.createMailbox(name, account);
|
|
736
811
|
if (!success) {
|
|
737
812
|
return errorResponse(`Failed to create mailbox "${name}"`);
|
|
738
813
|
}
|
|
739
|
-
return successResponse(`Mailbox "${name}" created
|
|
814
|
+
return successResponse(`Mailbox "${name}" created`, { ok: true, name });
|
|
740
815
|
}, "Error creating mailbox"));
|
|
741
816
|
// --- delete-mailbox ---
|
|
742
817
|
server.tool("delete-mailbox", "Use when: deleting a mailbox/folder from an account.\nReturns: a confirmation that the mailbox was deleted.\nDo not use when: renaming it (use rename-mailbox) or deleting messages within it (use delete-message / batch-delete-messages).\nSafety: destructive — deleting a mailbox removes the folder and any messages it contains. Require explicit user confirmation and use list-mailboxes first to confirm the exact name.", {
|
|
@@ -747,13 +822,13 @@ server.tool("delete-mailbox", "Use when: deleting a mailbox/folder from an accou
|
|
|
747
822
|
const r = await imapDeleteMailbox(name, { account });
|
|
748
823
|
if (!r.success)
|
|
749
824
|
return errorResponse(r.error || `Failed to delete mailbox "${name}"`);
|
|
750
|
-
return successResponse(r.info || `Mailbox "${name}" deleted
|
|
825
|
+
return successResponse(r.info || `Mailbox "${name}" deleted`, { ok: true, name });
|
|
751
826
|
}
|
|
752
827
|
const { success, error } = mailManager.deleteMailbox(name, account);
|
|
753
828
|
if (!success) {
|
|
754
829
|
return errorResponse(error || `Failed to delete mailbox "${name}"`);
|
|
755
830
|
}
|
|
756
|
-
return successResponse(`Mailbox "${name}" deleted
|
|
831
|
+
return successResponse(`Mailbox "${name}" deleted`, { ok: true, name });
|
|
757
832
|
}, "Error deleting mailbox"));
|
|
758
833
|
// --- rename-mailbox ---
|
|
759
834
|
server.tool("rename-mailbox", "Use when: renaming an existing mailbox/folder from oldName to newName within an account.\nReturns: a confirmation naming the old and new mailbox names.\nDo not use when: creating a new folder (use create-mailbox) or deleting one (use delete-mailbox). Use list-mailboxes to confirm the current name.\nSafety: renames a real folder in the mail account — confirm oldName matches exactly (case-sensitive) before calling.", {
|
|
@@ -766,13 +841,21 @@ server.tool("rename-mailbox", "Use when: renaming an existing mailbox/folder fro
|
|
|
766
841
|
if (!r.success) {
|
|
767
842
|
return errorResponse(r.error || `Failed to rename mailbox "${oldName}" to "${newName}"`);
|
|
768
843
|
}
|
|
769
|
-
return successResponse(r.info || `Mailbox renamed from "${oldName}" to "${newName}"
|
|
844
|
+
return successResponse(r.info || `Mailbox renamed from "${oldName}" to "${newName}"`, {
|
|
845
|
+
ok: true,
|
|
846
|
+
oldName,
|
|
847
|
+
newName,
|
|
848
|
+
});
|
|
770
849
|
}
|
|
771
850
|
const { success, error } = mailManager.renameMailbox(oldName, newName, account);
|
|
772
851
|
if (!success) {
|
|
773
852
|
return errorResponse(error || `Failed to rename mailbox "${oldName}" to "${newName}"`);
|
|
774
853
|
}
|
|
775
|
-
return successResponse(`Mailbox renamed from "${oldName}" to "${newName}"
|
|
854
|
+
return successResponse(`Mailbox renamed from "${oldName}" to "${newName}"`, {
|
|
855
|
+
ok: true,
|
|
856
|
+
oldName,
|
|
857
|
+
newName,
|
|
858
|
+
});
|
|
776
859
|
}, "Error renaming mailbox"));
|
|
777
860
|
// =============================================================================
|
|
778
861
|
// Account Tools
|
|
@@ -793,13 +876,17 @@ server.tool("list-accounts", "Use when: discovering the configured Mail accounts
|
|
|
793
876
|
// --- list-rules ---
|
|
794
877
|
server.tool("list-rules", "Use when: discovering the Mail rules that exist and whether each is enabled or disabled, e.g. before enabling/disabling/deleting one.\nReturns: each rule's name and enabled/disabled state.\nDo not use when: you want to change a rule (use enable-rule / disable-rule / create-rule / delete-rule).", {}, withErrorHandling(() => {
|
|
795
878
|
const rules = mailManager.listRules();
|
|
879
|
+
const structured = {
|
|
880
|
+
rules: rules.map((r) => ({ name: r.name, enabled: r.enabled })),
|
|
881
|
+
count: rules.length,
|
|
882
|
+
};
|
|
796
883
|
if (rules.length === 0) {
|
|
797
|
-
return successResponse("No mail rules found");
|
|
884
|
+
return successResponse("No mail rules found", structured);
|
|
798
885
|
}
|
|
799
886
|
const ruleList = rules
|
|
800
887
|
.map((r) => ` - ${r.name} [${r.enabled ? "enabled" : "disabled"}]`)
|
|
801
888
|
.join("\n");
|
|
802
|
-
return successResponse(`Found ${rules.length} rule(s):\n${ruleList}
|
|
889
|
+
return successResponse(`Found ${rules.length} rule(s):\n${ruleList}`, structured);
|
|
803
890
|
}, "Error listing rules"));
|
|
804
891
|
// --- enable-rule ---
|
|
805
892
|
server.tool("enable-rule", "Use when: turning on an existing Mail rule by name.\nReturns: a confirmation that the rule was enabled.\nDo not use when: turning a rule off (use disable-rule), creating one (use create-rule), or deleting one (use delete-rule). Use list-rules to confirm the exact rule name.", {
|
|
@@ -809,7 +896,7 @@ server.tool("enable-rule", "Use when: turning on an existing Mail rule by name.\
|
|
|
809
896
|
if (!success) {
|
|
810
897
|
return errorResponse(`Failed to enable rule "${name}"`);
|
|
811
898
|
}
|
|
812
|
-
return successResponse(`Rule "${name}" enabled
|
|
899
|
+
return successResponse(`Rule "${name}" enabled`, { ok: true, name, enabled: true });
|
|
813
900
|
}, "Error enabling rule"));
|
|
814
901
|
// --- disable-rule ---
|
|
815
902
|
server.tool("disable-rule", "Use when: turning off an existing Mail rule by name (without deleting it).\nReturns: a confirmation that the rule was disabled.\nDo not use when: turning a rule on (use enable-rule), creating one (use create-rule), or removing it permanently (use delete-rule). Use list-rules to confirm the exact rule name.", {
|
|
@@ -819,7 +906,7 @@ server.tool("disable-rule", "Use when: turning off an existing Mail rule by name
|
|
|
819
906
|
if (!success) {
|
|
820
907
|
return errorResponse(`Failed to disable rule "${name}"`);
|
|
821
908
|
}
|
|
822
|
-
return successResponse(`Rule "${name}" disabled
|
|
909
|
+
return successResponse(`Rule "${name}" disabled`, { ok: true, name, enabled: false });
|
|
823
910
|
}, "Error disabling rule"));
|
|
824
911
|
// --- create-rule ---
|
|
825
912
|
server.tool("create-rule", "Use when: creating a new Mail rule with one or more conditions (field/operator/value) and at least one action (markRead, markFlagged, delete, or moveTo). Set matchAll to require all conditions vs. any.\nReturns: a confirmation naming the rule and its condition count.\nDo not use when: toggling an existing rule (use enable-rule / disable-rule) or removing one (use delete-rule). Use list-rules to avoid duplicating an existing rule.\nSafety: creates a rule that automatically acts on real mail (including delete/move actions) on an ongoing basis — confirm the conditions and actions with the user before calling.", {
|
|
@@ -869,8 +956,12 @@ server.tool("search-contacts", "Use when: looking up a person in Contacts.app by
|
|
|
869
956
|
query: z.string().min(1, "Search query is required"),
|
|
870
957
|
}, withErrorHandling(({ query }) => {
|
|
871
958
|
const contacts = mailManager.searchContacts(query);
|
|
959
|
+
const structured = {
|
|
960
|
+
contacts: contacts.map((c) => ({ name: c.name, emails: c.emails })),
|
|
961
|
+
count: contacts.length,
|
|
962
|
+
};
|
|
872
963
|
if (contacts.length === 0) {
|
|
873
|
-
return successResponse("No contacts found");
|
|
964
|
+
return successResponse("No contacts found", structured);
|
|
874
965
|
}
|
|
875
966
|
const contactList = contacts
|
|
876
967
|
.map((c) => {
|
|
@@ -878,7 +969,7 @@ server.tool("search-contacts", "Use when: looking up a person in Contacts.app by
|
|
|
878
969
|
return ` - ${c.name} (${emails})`;
|
|
879
970
|
})
|
|
880
971
|
.join("\n");
|
|
881
|
-
return successResponse(`Found ${contacts.length} contact(s):\n${contactList}
|
|
972
|
+
return successResponse(`Found ${contacts.length} contact(s):\n${contactList}`, structured);
|
|
882
973
|
}, "Error searching contacts"));
|
|
883
974
|
// =============================================================================
|
|
884
975
|
// Email Template Tools
|
|
@@ -893,18 +984,26 @@ server.tool("save-template", "Use when: creating a reusable email template (name
|
|
|
893
984
|
id: z.string().optional().describe("Template ID (for updating existing template)"),
|
|
894
985
|
}, withErrorHandling(({ name, subject, body, to, cc, id }) => {
|
|
895
986
|
const template = mailManager.saveTemplate(name, subject, body, to, cc, id);
|
|
896
|
-
return successResponse(`Template "${template.name}" saved with ID: ${template.id}
|
|
987
|
+
return successResponse(`Template "${template.name}" saved with ID: ${template.id}`, {
|
|
988
|
+
ok: true,
|
|
989
|
+
id: template.id,
|
|
990
|
+
name: template.name,
|
|
991
|
+
});
|
|
897
992
|
}, "Error saving template"));
|
|
898
993
|
// --- list-templates ---
|
|
899
994
|
server.tool("list-templates", "Use when: discovering the saved email templates and their ids, e.g. before using or editing one.\nReturns: each template's id, name, and subject.\nDo not use when: you want a single template's full body (use get-template) or want to apply one (use use-template).", {}, withErrorHandling(() => {
|
|
900
995
|
const templates = mailManager.listTemplates();
|
|
996
|
+
const structured = {
|
|
997
|
+
templates: templates.map((t) => ({ id: t.id, name: t.name, subject: t.subject })),
|
|
998
|
+
count: templates.length,
|
|
999
|
+
};
|
|
901
1000
|
if (templates.length === 0) {
|
|
902
|
-
return successResponse("No templates saved");
|
|
1001
|
+
return successResponse("No templates saved", structured);
|
|
903
1002
|
}
|
|
904
1003
|
const templateList = templates
|
|
905
1004
|
.map((t) => ` - [${t.id}] ${t.name} — "${t.subject}"`)
|
|
906
1005
|
.join("\n");
|
|
907
|
-
return successResponse(`Found ${templates.length} template(s):\n${templateList}
|
|
1006
|
+
return successResponse(`Found ${templates.length} template(s):\n${templateList}`, structured);
|
|
908
1007
|
}, "Error listing templates"));
|
|
909
1008
|
// --- get-template ---
|
|
910
1009
|
server.tool("get-template", "Use when: reading the full contents of one saved template by id — its name, subject, default to/cc, and body.\nReturns: the template's name, subject, default recipients, and body text.\nDo not use when: you don't have the id (use list-templates first) or want to apply the template into a draft (use use-template).", {
|
|
@@ -923,7 +1022,14 @@ server.tool("get-template", "Use when: reading the full contents of one saved te
|
|
|
923
1022
|
]
|
|
924
1023
|
.filter(Boolean)
|
|
925
1024
|
.join("\n");
|
|
926
|
-
return successResponse(lines
|
|
1025
|
+
return successResponse(lines, {
|
|
1026
|
+
id: template.id,
|
|
1027
|
+
name: template.name,
|
|
1028
|
+
subject: template.subject,
|
|
1029
|
+
to: template.to ?? [],
|
|
1030
|
+
cc: template.cc ?? [],
|
|
1031
|
+
body: template.body,
|
|
1032
|
+
});
|
|
927
1033
|
}, "Error getting template"));
|
|
928
1034
|
// --- delete-template ---
|
|
929
1035
|
server.tool("delete-template", "Use when: permanently removing a saved email template by id.\nReturns: a confirmation that the template was deleted.\nDo not use when: you only want to view it (use get-template) or update it (use save-template with the existing id).\nSafety: destructive — removes the template from the on-disk store permanently. Require explicit user confirmation and use list-templates first to confirm the id.", {
|
|
@@ -933,7 +1039,7 @@ server.tool("delete-template", "Use when: permanently removing a saved email tem
|
|
|
933
1039
|
if (!success) {
|
|
934
1040
|
return errorResponse(`Template "${id}" not found`);
|
|
935
1041
|
}
|
|
936
|
-
return successResponse(`Template "${id}" deleted
|
|
1042
|
+
return successResponse(`Template "${id}" deleted`, { ok: true, id });
|
|
937
1043
|
}, "Error deleting template"));
|
|
938
1044
|
// --- use-template ---
|
|
939
1045
|
server.tool("use-template", "Use when: composing a new draft from a saved template (by id), optionally overriding the recipients, subject, or body. Creates a draft in Mail.app for the user to review and send.\nReturns: a confirmation that a draft was created from the template.\nDo not use when: you want to inspect the template without composing (use get-template) or send immediately without a draft (use send-email).", {
|
|
@@ -947,7 +1053,7 @@ server.tool("use-template", "Use when: composing a new draft from a saved templa
|
|
|
947
1053
|
if (!success) {
|
|
948
1054
|
return errorResponse(`Failed to use template "${id}". Template not found or no recipients.`);
|
|
949
1055
|
}
|
|
950
|
-
return successResponse(`Draft created from template "${id}"
|
|
1056
|
+
return successResponse(`Draft created from template "${id}"`, { ok: true, id });
|
|
951
1057
|
}, "Error using template"));
|
|
952
1058
|
// =============================================================================
|
|
953
1059
|
// Diagnostics Tools
|
|
@@ -963,7 +1069,7 @@ server.tool("health-check", "Use when: doing a quick check that Mail.app is reac
|
|
|
963
1069
|
return ` ${icon} ${c.name}: ${c.message}`;
|
|
964
1070
|
})
|
|
965
1071
|
.join("\n");
|
|
966
|
-
return successResponse(`${statusIcon} ${statusText}\n\n${checkLines}
|
|
1072
|
+
return successResponse(`${statusIcon} ${statusText}\n\n${checkLines}`, { ...result });
|
|
967
1073
|
}, "Error running health check"));
|
|
968
1074
|
// --- doctor ---
|
|
969
1075
|
server.tool("doctor", "Use when: troubleshooting setup problems — diagnoses Mail.app automation permissions, account state, and the IMAP/SMTP backends with actionable remediation messages.\nReturns: a detailed diagnostic report (formatted text plus structured checks).\nDo not use when: you just want a quick up/down status (use health-check) or message counts (use get-mail-stats).", {}, withErrorHandling(async () => {
|
|
@@ -155,8 +155,20 @@ export declare function resolveImapConfigs(env?: NodeJS.ProcessEnv): ImapConfig[
|
|
|
155
155
|
export declare function resolveImapConfig(env?: NodeJS.ProcessEnv, account?: string): ImapConfig;
|
|
156
156
|
/** Map common (Gmail) mailbox names to their IMAP paths. */
|
|
157
157
|
export declare function resolveMailboxPath(mailbox: string | undefined, mode: "search" | "list"): string;
|
|
158
|
-
|
|
159
|
-
|
|
158
|
+
/**
|
|
159
|
+
* Result of an IMAP search/list: the human text identical to before, plus the
|
|
160
|
+
* structured payload (messages + count) so callers can pass it straight to
|
|
161
|
+
* `successResponse(text, structured)` and emit `structuredContent` on the IMAP
|
|
162
|
+
* path the same way the AppleScript path does.
|
|
163
|
+
*/
|
|
164
|
+
export interface ImapListResult {
|
|
165
|
+
text: string;
|
|
166
|
+
messages: Record<string, unknown>[];
|
|
167
|
+
count: number;
|
|
168
|
+
partial: boolean;
|
|
169
|
+
}
|
|
170
|
+
export declare function imapSearchMessages(args: ImapSearchArgs, deps?: ImapDeps): Promise<ImapListResult>;
|
|
171
|
+
export declare function imapListMessages(args: ImapSearchArgs, deps?: ImapDeps): Promise<ImapListResult>;
|
|
160
172
|
/** Unread count via IMAP STATUS (UNSEEN). No mailbox → sum across all mailboxes. */
|
|
161
173
|
export declare function imapUnreadCount(mailbox: string | undefined, deps?: ImapDeps): Promise<number>;
|
|
162
174
|
export interface ImapMailboxInfo {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"imapClient.d.ts","sourceRoot":"","sources":["../../src/services/imapClient.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"imapClient.d.ts","sourceRoot":"","sources":["../../src/services/imapClient.ts"],"names":[],"mappings":"AA4BA,eAAO,MAAM,QAAQ;;;;;;;;;CAWX,CAAC;AAEX,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,UAAU,WAAW;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AACD,UAAU,YAAY;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,WAAW,EAAE,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AACD,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qBAAqB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/C,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,iBAAiB,EAAE,CAAC;CAClC;AACD,UAAU,WAAW;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,KAAK,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,iBAAiB,CAAC;IAClC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC3B;AACD,UAAU,YAAY;IACpB,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACnD,OAAO,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;CACpC;AACD,UAAU,WAAW;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AACD,UAAU,kBAAkB;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AACD,KAAK,QAAQ,GAAG;IAAE,GAAG,EAAE,OAAO,CAAA;CAAE,CAAC;AACjC,MAAM,WAAW,cAAc;IAC7B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACnD,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE;QAAE,GAAG,EAAE,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC;IACvF,KAAK,CACH,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,IAAI,EAAE;QAAE,GAAG,EAAE,IAAI,CAAA;KAAE,GAClB,aAAa,CAAC,WAAW,CAAC,CAAC;IAC9B,QAAQ,CACN,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,IAAI,EAAE;QAAE,GAAG,EAAE,IAAI,CAAA;KAAE,GAClB,OAAO,CAAC,WAAW,GAAG,KAAK,CAAC,CAAC;IAChC,IAAI,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC;IACtC,MAAM,CACJ,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GAChE,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClF,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,GAAG,EAAE,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAClF,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACzE,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACzF,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvD,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACpF,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACvF,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACpF,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACjE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB;AASD,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAK/E;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAS9F;AAED,MAAM,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE,UAAU,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;AAEvE;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AA6FD,+EAA+E;AAC/E,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,OAAO,CAGT;AAED,6EAA6E;AAC7E,wBAAgB,qBAAqB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,EAAE,CAEpF;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,UAAU,EAAE,CAUrF;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,OAAO,CAAC,EAAE,MAAM,GACf,UAAU,CAiBZ;AAcD,4DAA4D;AAC5D,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,MAAM,CAc/F;AAsDD;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CAClB;AA2DD,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,cAAc,EACpB,IAAI,GAAE,QAAa,GAClB,OAAO,CAAC,cAAc,CAAC,CAEzB;AAED,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,cAAc,EACpB,IAAI,GAAE,QAAa,GAClB,OAAO,CAAC,cAAc,CAAC,CAEzB;AAUD,oFAAoF;AACpF,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,GAAE,QAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAqBjG;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,oFAAoF;AACpF,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,QAAa,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAqBjF;AAED,MAAM,WAAW,SAAS;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACpE,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9D;AAED,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,IAAI,GAAE,QAAa,GAAG,OAAO,CAAC,SAAS,CAAC,CA2CrE;AAYD,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AA6ED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,IAAI,GAAE,QAAa,GAClB,OAAO,CAAC;IAAE,UAAU,EAAE,OAAO,CAAC;IAAC,EAAE,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAwBhG;AAED,4EAA4E;AAC5E,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI,CAE7D;AACD,yDAAyD;AACzD,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAEjD;AAmED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,QAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAW1F;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,QAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAmB1F;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,QAAa,GAClB,OAAO,CAAC,YAAY,CAAC,CAmBvB;AA0BD,2EAA2E;AAC3E,wBAAsB,cAAc,CAClC,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,OAAO,EACnB,IAAI,GAAE,QAAa,GAClB,OAAO,CAAC,YAAY,CAAC,CAwBvB;AA0BD,eAAO,MAAM,YAAY,GAAI,IAAI,MAAM,EAAE,SAAS,KAAG,OAAO,CAAC,YAAY,CACvC,CAAC;AACnC,eAAO,MAAM,cAAc,GAAI,IAAI,MAAM,EAAE,SAAS,KAAG,OAAO,CAAC,YAAY,CACxC,CAAC;AACpC,eAAO,MAAM,eAAe,GAAI,IAAI,MAAM,EAAE,SAAS,KAAG,OAAO,CAAC,YAAY,CACvC,CAAC;AACtC,eAAO,MAAM,iBAAiB,GAAI,IAAI,MAAM,EAAE,SAAS,KAAG,OAAO,CAAC,YAAY,CACxC,CAAC;AAEvC,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,MAAM,EACV,WAAW,EAAE,MAAM,EACnB,IAAI,GAAE,QAAa,GAClB,OAAO,CAAC,YAAY,CAAC,CAmBvB;AAED,wBAAsB,qBAAqB,CACzC,EAAE,EAAE,MAAM,EACV,IAAI,GAAE,QAAa,GAClB,OAAO,CAAC,YAAY,CAAC,CAgBvB;AAkBD,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AA2BD,8EAA8E;AAC9E,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,MAAM,EACV,IAAI,GAAE,QAAa,GAClB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAoBnF;AAED,2EAA2E;AAC3E,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,MAAM,EACV,cAAc,EAAE,MAAM,EACtB,IAAI,GAAE,QAAa,GAClB,OAAO,CAAC;IACT,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC,CA8BD;AAUD,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AA0CD,eAAO,MAAM,iBAAiB,GAAI,KAAK,MAAM,EAAE,EAAE,OAAM,QAAa,KAAG,OAAO,CAAC,eAAe,CAG1F,CAAC;AACL,eAAO,MAAM,mBAAmB,GAAI,KAAK,MAAM,EAAE,EAAE,OAAM,QAAa,KAAG,OAAO,CAAC,eAAe,CAG5F,CAAC;AACL,eAAO,MAAM,aAAa,GAAI,KAAK,MAAM,EAAE,EAAE,OAAM,QAAa,KAAG,OAAO,CAAC,eAAe,CAGtF,CAAC;AACL,eAAO,MAAM,eAAe,GAAI,KAAK,MAAM,EAAE,EAAE,OAAM,QAAa,KAAG,OAAO,CAAC,eAAe,CAGxF,CAAC;AACL,eAAO,MAAM,eAAe,GAAI,KAAK,MAAM,EAAE,EAAE,OAAM,QAAa,KAAG,OAAO,CAAC,eAAe,CAGxF,CAAC;AACL,wBAAgB,aAAa,CAC3B,GAAG,EAAE,MAAM,EAAE,EACb,WAAW,EAAE,MAAM,EACnB,IAAI,GAAE,QAAa,GAClB,OAAO,CAAC,eAAe,CAAC,CAK1B;AAYD,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;CACjB;AACD,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,iBAAiB,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/E;AAWD,wBAAsB,UAAU,CAC9B,EAAE,EAAE,MAAM,EACV,IAAI,GAAE,QAAa,EACnB,KAAK,SAAK,GACT,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAmElC"}
|
|
@@ -254,6 +254,25 @@ function formatRow(m, account, path) {
|
|
|
254
254
|
// can route this row back to IMAP (Phase 3).
|
|
255
255
|
return ` - ID: ${encodeImapId(account, path, m.uid)} | ${date} | ${subject} (from: ${from}) [${read}]`;
|
|
256
256
|
}
|
|
257
|
+
/**
|
|
258
|
+
* JSON-friendly summary of an IMAP message for `structuredContent`, mirroring the
|
|
259
|
+
* AppleScript path's `messageSummary` shape so the search/list/thread tools emit
|
|
260
|
+
* the same structured payload regardless of backend (A1).
|
|
261
|
+
*/
|
|
262
|
+
function structuredRow(m, account, path) {
|
|
263
|
+
const env = m.envelope ?? {};
|
|
264
|
+
return {
|
|
265
|
+
id: encodeImapId(account, path, m.uid),
|
|
266
|
+
subject: env.subject || "(no subject)",
|
|
267
|
+
sender: senderName(env.from),
|
|
268
|
+
dateReceived: env.date ? new Date(env.date).toISOString() : "",
|
|
269
|
+
isRead: m.flags?.has("\\Seen") ?? false,
|
|
270
|
+
isFlagged: m.flags?.has("\\Flagged") ?? false,
|
|
271
|
+
mailbox: path,
|
|
272
|
+
account,
|
|
273
|
+
hasAttachments: false,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
257
276
|
async function run(args, listMode, deps) {
|
|
258
277
|
// Reads are idempotent → safe to retry once if a pooled connection is dead.
|
|
259
278
|
// Route to the account named in the search args (C2 multi-account).
|
|
@@ -264,7 +283,12 @@ async function run(args, listMode, deps) {
|
|
|
264
283
|
const found = await client.search(buildCriteria(args, listMode), { uid: true });
|
|
265
284
|
const uids = Array.isArray(found) ? found : [];
|
|
266
285
|
if (uids.length === 0) {
|
|
267
|
-
return
|
|
286
|
+
return {
|
|
287
|
+
text: `No messages found via IMAP in "${path}" (account ${cfg.accountLabel}).`,
|
|
288
|
+
messages: [],
|
|
289
|
+
count: 0,
|
|
290
|
+
partial: false,
|
|
291
|
+
};
|
|
268
292
|
}
|
|
269
293
|
const limit = args.limit ?? 50;
|
|
270
294
|
const offset = args.offset ?? 0;
|
|
@@ -275,13 +299,18 @@ async function run(args, listMode, deps) {
|
|
|
275
299
|
.slice(offset, offset + limit);
|
|
276
300
|
const byUid = new Map();
|
|
277
301
|
for await (const msg of client.fetch(newest.join(","), { envelope: true, flags: true }, { uid: true })) {
|
|
278
|
-
byUid.set(msg.uid,
|
|
302
|
+
byUid.set(msg.uid, msg);
|
|
279
303
|
}
|
|
280
|
-
const
|
|
304
|
+
const ordered = newest
|
|
305
|
+
.map((u) => byUid.get(u))
|
|
306
|
+
.filter((m) => m !== undefined);
|
|
307
|
+
const rows = ordered.map((m) => formatRow(m, cfg.accountLabel, path));
|
|
308
|
+
const messages = ordered.map((m) => structuredRow(m, cfg.accountLabel, path));
|
|
281
309
|
const verb = listMode ? "listed" : "matched";
|
|
282
|
-
|
|
310
|
+
const text = `Found ${rows.length} message(s) via IMAP (server-side, account ${cfg.accountLabel}, mailbox "${path}"; ${uids.length} total ${verb}):\n` +
|
|
283
311
|
rows.join("\n") +
|
|
284
|
-
`\n\nNote: these IMAP IDs (imap:…) work with get-message and the message mutations (mark/flag/move/delete-message), which route back to IMAP
|
|
312
|
+
`\n\nNote: these IMAP IDs (imap:…) work with get-message and the message mutations (mark/flag/move/delete-message), which route back to IMAP.`;
|
|
313
|
+
return { text, messages, count: messages.length, partial: false };
|
|
285
314
|
}
|
|
286
315
|
finally {
|
|
287
316
|
lock.release();
|
|
@@ -12,5 +12,13 @@ export declare function routeMessage(id: string, opts: {
|
|
|
12
12
|
apple: () => ToolResponse | Promise<ToolResponse>;
|
|
13
13
|
ok: string;
|
|
14
14
|
fail: string;
|
|
15
|
+
/** Optional ack payload attached as `structuredContent` on the IMAP success
|
|
16
|
+
* path, so a caller can verify the mutation programmatically regardless of
|
|
17
|
+
* backend (A1). The AppleScript path supplies its own via `apple`. */
|
|
18
|
+
structured?: Record<string, unknown>;
|
|
19
|
+
/** Derive `structuredContent` from the IMAP result on success (e.g. parse
|
|
20
|
+
* subject/body from `info`). Takes precedence over `structured`; return
|
|
21
|
+
* undefined to attach none. */
|
|
22
|
+
structuredFromResult?: (r: ImapOpResult) => Record<string, unknown> | undefined;
|
|
15
23
|
}): Promise<ToolResponse>;
|
|
16
24
|
//# sourceMappingURL=messageRouter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messageRouter.d.ts","sourceRoot":"","sources":["../../src/services/messageRouter.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAkC,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvF,oEAAoE;AACpE,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAE5C;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAChC,EAAE,EAAE,MAAM,EACV,IAAI,EAAE;IACJ,IAAI,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,CAAC;IAClC,KAAK,EAAE,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAClD,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"messageRouter.d.ts","sourceRoot":"","sources":["../../src/services/messageRouter.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAkC,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvF,oEAAoE;AACpE,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAE5C;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAChC,EAAE,EAAE,MAAM,EACV,IAAI,EAAE;IACJ,IAAI,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,CAAC;IAClC,KAAK,EAAE,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAClD,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb;;2EAEuE;IACvE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC;;oCAEgC;IAChC,oBAAoB,CAAC,EAAE,CAAC,CAAC,EAAE,YAAY,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;CACjF,GACA,OAAO,CAAC,YAAY,CAAC,CAWvB"}
|
|
@@ -23,7 +23,9 @@ export function isImapId(id) {
|
|
|
23
23
|
export async function routeMessage(id, opts) {
|
|
24
24
|
if (decodeImapId(id)) {
|
|
25
25
|
const r = await opts.imap();
|
|
26
|
-
return r.success
|
|
26
|
+
return r.success
|
|
27
|
+
? successResponse(r.info ?? opts.ok, opts.structuredFromResult ? opts.structuredFromResult(r) : opts.structured)
|
|
28
|
+
: errorResponse(r.error ?? opts.fail);
|
|
27
29
|
}
|
|
28
30
|
return opts.apple();
|
|
29
31
|
}
|
package/package.json
CHANGED