apple-mail-mcp 1.6.3 → 1.6.4
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/build/index.js
CHANGED
|
@@ -85,6 +85,28 @@ function errorResponse(message) {
|
|
|
85
85
|
isError: true,
|
|
86
86
|
};
|
|
87
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* Render a partial-coverage warning from search/list diagnostics, so a caller
|
|
90
|
+
* never mistakes an incomplete scan for a confirmed "no matches" (#24/#29).
|
|
91
|
+
* Returns "" when coverage was complete.
|
|
92
|
+
*/
|
|
93
|
+
function partialCoverageBlock(diagnostics) {
|
|
94
|
+
const notes = [];
|
|
95
|
+
if (diagnostics.timedOutAccounts.length > 0) {
|
|
96
|
+
notes.push(`timed out (no results) for account(s): ${diagnostics.timedOutAccounts.join(", ")}`);
|
|
97
|
+
}
|
|
98
|
+
if (diagnostics.skippedLargeMailboxes.length > 0) {
|
|
99
|
+
notes.push(`skipped mailbox(es) too large to scan via AppleScript: ${diagnostics.skippedLargeMailboxes.join(", ")} — scope with \`mailbox\` (+ a \`dateFrom\`/\`dateTo\` window for search) to reach them`);
|
|
100
|
+
}
|
|
101
|
+
if (diagnostics.notSearchedMailboxes.length > 0) {
|
|
102
|
+
notes.push(`could not finish scanning mailbox(es): ${diagnostics.notSearchedMailboxes.join(", ")}`);
|
|
103
|
+
}
|
|
104
|
+
if (notes.length === 0)
|
|
105
|
+
return "";
|
|
106
|
+
return `\n\n⚠️ Partial results — this is NOT a confirmed "no such mail":\n${notes
|
|
107
|
+
.map((n) => ` - ${n}`)
|
|
108
|
+
.join("\n")}`;
|
|
109
|
+
}
|
|
88
110
|
/**
|
|
89
111
|
* Serial execution gate for AppleScript-backed tool calls (issue #11).
|
|
90
112
|
*
|
|
@@ -137,24 +159,7 @@ server.tool("search-messages", {
|
|
|
137
159
|
limit: z.number().optional().describe("Maximum number of results (default: 50)"),
|
|
138
160
|
}, withErrorHandling(({ query, mailbox, account, limit = 50, dateFrom, dateTo, from, subject, isRead, isFlagged, }) => {
|
|
139
161
|
const { messages, diagnostics } = mailManager.searchMessagesWithDiagnostics(query, mailbox, account, limit, dateFrom, dateTo, from, subject, isRead, isFlagged);
|
|
140
|
-
|
|
141
|
-
// caller never mistakes an incomplete search for a confirmed "no matches"
|
|
142
|
-
// (issue #24).
|
|
143
|
-
const coverageNotes = [];
|
|
144
|
-
if (diagnostics.timedOutAccounts.length > 0) {
|
|
145
|
-
coverageNotes.push(`timed out (no results) for account(s): ${diagnostics.timedOutAccounts.join(", ")}`);
|
|
146
|
-
}
|
|
147
|
-
if (diagnostics.skippedLargeMailboxes.length > 0) {
|
|
148
|
-
coverageNotes.push(`skipped mailbox(es) too large to search via AppleScript: ${diagnostics.skippedLargeMailboxes.join(", ")} — scope the search with \`mailbox\` + a \`dateFrom\`/\`dateTo\` window to target them`);
|
|
149
|
-
}
|
|
150
|
-
if (diagnostics.notSearchedMailboxes.length > 0) {
|
|
151
|
-
coverageNotes.push(`could not finish searching mailbox(es): ${diagnostics.notSearchedMailboxes.join(", ")}`);
|
|
152
|
-
}
|
|
153
|
-
const coverageBlock = coverageNotes.length > 0
|
|
154
|
-
? `\n\n⚠️ Partial results — this is NOT a confirmed "no such mail":\n${coverageNotes
|
|
155
|
-
.map((n) => ` - ${n}`)
|
|
156
|
-
.join("\n")}`
|
|
157
|
-
: "";
|
|
162
|
+
const coverageBlock = partialCoverageBlock(diagnostics);
|
|
158
163
|
if (messages.length === 0) {
|
|
159
164
|
const base = diagnostics.partial
|
|
160
165
|
? "No messages found in the portions that were searched."
|
|
@@ -192,14 +197,18 @@ server.tool("list-messages", {
|
|
|
192
197
|
from: z.string().optional().describe("Filter by sender email address or name"),
|
|
193
198
|
unreadOnly: z.boolean().optional().describe("Only show unread messages"),
|
|
194
199
|
}, withErrorHandling(({ mailbox, account, limit = 50, offset = 0, from }) => {
|
|
195
|
-
const messages = mailManager.
|
|
200
|
+
const { messages, diagnostics } = mailManager.listMessagesWithDiagnostics(mailbox, account, limit, from, offset);
|
|
201
|
+
const coverageBlock = partialCoverageBlock(diagnostics);
|
|
196
202
|
if (messages.length === 0) {
|
|
197
|
-
|
|
203
|
+
const base = diagnostics.partial
|
|
204
|
+
? "No messages found in the portions that were listed."
|
|
205
|
+
: "No messages found";
|
|
206
|
+
return successResponse(`${base}${coverageBlock}`);
|
|
198
207
|
}
|
|
199
208
|
const messageList = messages
|
|
200
209
|
.map((m) => ` - ID: ${m.id} | ${m.dateReceived.toLocaleDateString()} | ${m.subject} (from: ${m.sender})`)
|
|
201
210
|
.join("\n");
|
|
202
|
-
return successResponse(`Found ${messages.length} message(s):\n${messageList}`);
|
|
211
|
+
return successResponse(`Found ${messages.length} message(s):\n${messageList}${coverageBlock}`);
|
|
203
212
|
}, "Error listing messages"));
|
|
204
213
|
// --- send-email ---
|
|
205
214
|
server.tool("send-email", {
|
|
@@ -203,6 +203,19 @@ export declare class AppleMailManager {
|
|
|
203
203
|
* @returns Array of messages
|
|
204
204
|
*/
|
|
205
205
|
listMessages(mailbox?: string, account?: string, limit?: number, from?: string, offset?: number): Message[];
|
|
206
|
+
/**
|
|
207
|
+
* List messages, returning matches plus coverage diagnostics.
|
|
208
|
+
*
|
|
209
|
+
* Like `searchMessages`, the unscoped (all-mailboxes) path used to iterate
|
|
210
|
+
* `messages of mb` over every mailbox with a swallowing per-mailbox `try`,
|
|
211
|
+
* so a large IMAP/Gmail mailbox timed out and the method returned `[]` — a
|
|
212
|
+
* false "No messages found." This applies the same #24 discipline: skip
|
|
213
|
+
* mailboxes above the scan threshold (reported), enforce a per-account
|
|
214
|
+
* wall-clock budget, capture per-mailbox timeouts, and surface all of it as a
|
|
215
|
+
* partial result. (by-id lookups don't need this — `whose id is` is indexed
|
|
216
|
+
* and returns instantly even on a 44k-message mailbox.)
|
|
217
|
+
*/
|
|
218
|
+
listMessagesWithDiagnostics(mailbox?: string, account?: string, limit?: number, from?: string, offset?: number): SearchResult;
|
|
206
219
|
/**
|
|
207
220
|
* Parse message list output from AppleScript.
|
|
208
221
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"appleMailManager.d.ts","sourceRoot":"","sources":["../../src/services/appleMailManager.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"appleMailManager.d.ts","sourceRoot":"","sources":["../../src/services/appleMailManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -790,107 +790,172 @@ export class AppleMailManager {
|
|
|
790
790
|
* @returns Array of messages
|
|
791
791
|
*/
|
|
792
792
|
listMessages(mailbox, account, limit = 50, from, offset = 0) {
|
|
793
|
-
|
|
793
|
+
return this.listMessagesWithDiagnostics(mailbox, account, limit, from, offset).messages;
|
|
794
|
+
}
|
|
795
|
+
/**
|
|
796
|
+
* List messages, returning matches plus coverage diagnostics.
|
|
797
|
+
*
|
|
798
|
+
* Like `searchMessages`, the unscoped (all-mailboxes) path used to iterate
|
|
799
|
+
* `messages of mb` over every mailbox with a swallowing per-mailbox `try`,
|
|
800
|
+
* so a large IMAP/Gmail mailbox timed out and the method returned `[]` — a
|
|
801
|
+
* false "No messages found." This applies the same #24 discipline: skip
|
|
802
|
+
* mailboxes above the scan threshold (reported), enforce a per-account
|
|
803
|
+
* wall-clock budget, capture per-mailbox timeouts, and surface all of it as a
|
|
804
|
+
* partial result. (by-id lookups don't need this — `whose id is` is indexed
|
|
805
|
+
* and returns instantly even on a 44k-message mailbox.)
|
|
806
|
+
*/
|
|
807
|
+
listMessagesWithDiagnostics(mailbox, account, limit = 50, from, offset = 0) {
|
|
808
|
+
// If no account specified, list across all accounts and merge diagnostics.
|
|
794
809
|
if (!account) {
|
|
795
810
|
const accounts = this.listAccounts();
|
|
796
811
|
const allMessages = [];
|
|
812
|
+
const diagnostics = {
|
|
813
|
+
partial: false,
|
|
814
|
+
timedOutAccounts: [],
|
|
815
|
+
skippedLargeMailboxes: [],
|
|
816
|
+
notSearchedMailboxes: [],
|
|
817
|
+
};
|
|
797
818
|
for (const acct of accounts) {
|
|
798
819
|
if (allMessages.length >= limit)
|
|
799
820
|
break;
|
|
800
821
|
const remaining = limit - allMessages.length;
|
|
801
|
-
const
|
|
802
|
-
allMessages.push(...
|
|
822
|
+
const res = this.listMessagesWithDiagnostics(mailbox, acct.name, remaining, from, offset);
|
|
823
|
+
allMessages.push(...res.messages);
|
|
824
|
+
mergeSearchDiagnostics(diagnostics, res.diagnostics);
|
|
803
825
|
}
|
|
804
|
-
return allMessages.slice(0, limit);
|
|
826
|
+
return { messages: allMessages.slice(0, limit), diagnostics };
|
|
805
827
|
}
|
|
806
828
|
const targetAccount = this.resolveAccount(account);
|
|
807
829
|
const safeFrom = from ? escapeForAppleScript(from) : "";
|
|
808
830
|
const fromFilter = from ? `whose sender contains "${safeFrom}"` : "";
|
|
831
|
+
const scanThreshold = getMailboxScanThreshold();
|
|
809
832
|
let listCommand;
|
|
810
833
|
if (mailbox) {
|
|
811
|
-
// List from a specific mailbox
|
|
834
|
+
// List from a specific mailbox. Caller-scoped, so no count-guard skip, but
|
|
835
|
+
// wrap the scan so a timeout is reported as partial, not a false empty.
|
|
812
836
|
const targetMailbox = this.resolveMailbox(mailbox, targetAccount);
|
|
813
837
|
listCommand = `
|
|
814
838
|
set outputText to ""
|
|
839
|
+
set _timedOut to false
|
|
840
|
+
set _notSearched to ""
|
|
815
841
|
set theMailbox to mailbox "${escapeForAppleScript(targetMailbox)}"
|
|
816
842
|
set msgCount to 0
|
|
817
843
|
set skipped to 0
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
844
|
+
try
|
|
845
|
+
repeat with msg in messages of theMailbox ${fromFilter}
|
|
846
|
+
if msgCount >= ${limit} then exit repeat
|
|
847
|
+
try
|
|
848
|
+
if skipped < ${offset} then
|
|
849
|
+
set skipped to skipped + 1
|
|
850
|
+
else
|
|
851
|
+
set msgId to id of msg as string
|
|
852
|
+
set msgSubject to subject of msg
|
|
853
|
+
set msgSender to sender of msg
|
|
854
|
+
set d to date received of msg
|
|
855
|
+
set msgDate to ${AS_DATE_TO_STRING}
|
|
856
|
+
set msgRead to read status of msg as string
|
|
857
|
+
set msgFlagged to flagged status of msg as string
|
|
858
|
+
set msgHasAtt to "false"
|
|
859
|
+
try
|
|
860
|
+
if (count of mail attachments of msg) > 0 then set msgHasAtt to "true"
|
|
861
|
+
end try
|
|
862
|
+
if msgCount > 0 then set outputText to outputText & "|||ITEM|||"
|
|
863
|
+
set outputText to outputText & msgId & "|||" & msgSubject & "|||" & msgSender & "|||" & msgDate & "|||" & msgRead & "|||" & msgFlagged & "|||" & msgHasAtt
|
|
864
|
+
set msgCount to msgCount + 1
|
|
865
|
+
end if
|
|
866
|
+
end try
|
|
867
|
+
end repeat
|
|
868
|
+
on error _errMsg number _errNum
|
|
869
|
+
set _timedOut to true
|
|
870
|
+
set _notSearched to "${escapeForAppleScript(targetMailbox)}|||M|||"
|
|
871
|
+
end try
|
|
872
|
+
return outputText & "${DIAG_MARKER}timedOut=" & (_timedOut as string) & "|||F|||skipped=|||F|||notSearched=" & _notSearched
|
|
842
873
|
`;
|
|
843
874
|
}
|
|
844
875
|
else {
|
|
845
|
-
// List from ALL mailboxes —
|
|
876
|
+
// List from ALL mailboxes — skip mailboxes over the scan threshold, enforce
|
|
877
|
+
// the per-account budget, capture per-mailbox timeouts; dedup by message ID.
|
|
878
|
+
const scanGuard = scanThreshold > 0 ? `mbCount > ${scanThreshold}` : "false";
|
|
846
879
|
listCommand = `
|
|
847
880
|
set outputText to ""
|
|
848
881
|
set msgCount to 0
|
|
849
882
|
set skipped to 0
|
|
850
883
|
set seenIds to {}
|
|
884
|
+
set _timedOut to false
|
|
885
|
+
set _skipped to ""
|
|
886
|
+
set _notSearched to ""
|
|
887
|
+
set _startedAt to current date
|
|
851
888
|
repeat with mb in mailboxes
|
|
852
889
|
if msgCount >= ${limit} then exit repeat
|
|
890
|
+
set mbName to ""
|
|
853
891
|
try
|
|
854
|
-
|
|
855
|
-
|
|
892
|
+
set mbName to name of mb
|
|
893
|
+
end try
|
|
894
|
+
if ((current date) - _startedAt) > ${SEARCH_ACCOUNT_BUDGET_SECONDS} then
|
|
895
|
+
set _timedOut to true
|
|
896
|
+
set _notSearched to _notSearched & mbName & "|||M|||"
|
|
897
|
+
else
|
|
898
|
+
set mbCount to 0
|
|
899
|
+
try
|
|
900
|
+
set mbCount to count of messages of mb
|
|
901
|
+
end try
|
|
902
|
+
if (${scanGuard}) then
|
|
903
|
+
set _timedOut to true
|
|
904
|
+
set _skipped to _skipped & mbName & " (" & (mbCount as string) & ")|||M|||"
|
|
905
|
+
else
|
|
856
906
|
try
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
907
|
+
repeat with msg in messages of mb ${fromFilter}
|
|
908
|
+
if msgCount >= ${limit} then exit repeat
|
|
909
|
+
try
|
|
910
|
+
set msgId to id of msg as string
|
|
911
|
+
if seenIds does not contain msgId then
|
|
912
|
+
set end of seenIds to msgId
|
|
913
|
+
if skipped < ${offset} then
|
|
914
|
+
set skipped to skipped + 1
|
|
915
|
+
else
|
|
916
|
+
set msgSubject to subject of msg
|
|
917
|
+
set msgSender to sender of msg
|
|
918
|
+
set d to date received of msg
|
|
919
|
+
set msgDate to ${AS_DATE_TO_STRING}
|
|
920
|
+
set msgRead to read status of msg as string
|
|
921
|
+
set msgFlagged to flagged status of msg as string
|
|
922
|
+
set msgHasAtt to "false"
|
|
923
|
+
try
|
|
924
|
+
if (count of mail attachments of msg) > 0 then set msgHasAtt to "true"
|
|
925
|
+
end try
|
|
926
|
+
if msgCount > 0 then set outputText to outputText & "|||ITEM|||"
|
|
927
|
+
set outputText to outputText & msgId & "|||" & msgSubject & "|||" & msgSender & "|||" & msgDate & "|||" & msgRead & "|||" & msgFlagged & "|||" & mbName & "|||" & msgHasAtt
|
|
928
|
+
set msgCount to msgCount + 1
|
|
929
|
+
end if
|
|
930
|
+
end if
|
|
931
|
+
end try
|
|
932
|
+
end repeat
|
|
933
|
+
on error _errMsg number _errNum
|
|
934
|
+
set _timedOut to true
|
|
935
|
+
set _notSearched to _notSearched & mbName & "|||M|||"
|
|
878
936
|
end try
|
|
879
|
-
end
|
|
880
|
-
end
|
|
937
|
+
end if
|
|
938
|
+
end if
|
|
881
939
|
end repeat
|
|
882
|
-
return outputText
|
|
940
|
+
return outputText & "${DIAG_MARKER}timedOut=" & (_timedOut as string) & "|||F|||skipped=" & _skipped & "|||F|||notSearched=" & _notSearched
|
|
883
941
|
`;
|
|
884
942
|
}
|
|
885
943
|
const script = buildAccountScopedScript(targetAccount, listCommand);
|
|
886
|
-
const result = executeAppleScript(script, { timeoutMs:
|
|
944
|
+
const result = executeAppleScript(script, { timeoutMs: SEARCH_ACCOUNT_TIMEOUT_MS });
|
|
887
945
|
if (!result.success) {
|
|
888
|
-
|
|
889
|
-
|
|
946
|
+
// Whole-account failure — surface as a timeout, not a false empty (#24/#29).
|
|
947
|
+
console.error(`Failed to list messages in "${targetAccount}": ${result.error}`);
|
|
948
|
+
return {
|
|
949
|
+
messages: [],
|
|
950
|
+
diagnostics: {
|
|
951
|
+
partial: true,
|
|
952
|
+
timedOutAccounts: [targetAccount],
|
|
953
|
+
skippedLargeMailboxes: [],
|
|
954
|
+
notSearchedMailboxes: [],
|
|
955
|
+
},
|
|
956
|
+
};
|
|
890
957
|
}
|
|
891
|
-
|
|
892
|
-
return [];
|
|
893
|
-
return this.parseMessageList(result.output, mailbox || "INBOX", targetAccount);
|
|
958
|
+
return this.parseSearchResult(result.output, mailbox || "INBOX", targetAccount);
|
|
894
959
|
}
|
|
895
960
|
/**
|
|
896
961
|
* Parse message list output from AppleScript.
|