apple-mail-mcp 2.13.0 → 2.13.2
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 +88 -7
- package/package.json +1 -1
package/build/index.js
CHANGED
|
@@ -79503,6 +79503,35 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
|
|
|
79503
79503
|
end if
|
|
79504
79504
|
set _sLo to _sHi + 1
|
|
79505
79505
|
end repeat
|
|
79506
|
+
-- #179: the loop above is bounded by the count Mail JUST reported,
|
|
79507
|
+
-- and that count can lag the mailbox (#155). Positions past the bound
|
|
79508
|
+
-- are never requested, so \u2014 unlike a slice that failed \u2014 they leave
|
|
79509
|
+
-- no trace in _sMiss, and the record would claim a complete
|
|
79510
|
+
-- observation while every message past the bound looks like it
|
|
79511
|
+
-- disappeared. That is a FABRICATED finding with names attached,
|
|
79512
|
+
-- which is worse than the gap it papers over.
|
|
79513
|
+
--
|
|
79514
|
+
-- Probe exactly ONE position past the bound. One, not a slice: an
|
|
79515
|
+
-- out-of-range RANGE raises as a whole, so an over-requested slice
|
|
79516
|
+
-- could not distinguish "nothing there" from "count was low by more
|
|
79517
|
+
-- than a chunk". If a message is there, the count was low and the
|
|
79518
|
+
-- unread tail is recorded as a hole, which makes this snapshot
|
|
79519
|
+
-- PARTIAL under the existing rules and withholds the halves a
|
|
79520
|
+
-- truncation would poison.
|
|
79521
|
+
try
|
|
79522
|
+
set _sOverId to ((id of message (${countVar} + 1) of ${mbVar}) as string)
|
|
79523
|
+
-- A specifier that CLAMPS rather than raising hands back the LAST
|
|
79524
|
+
-- message instead of failing. That is not evidence of a truncation,
|
|
79525
|
+
-- so only an id this enumeration did not already record counts.
|
|
79526
|
+
set _sSeen to false
|
|
79527
|
+
repeat with _sP in _sPairs
|
|
79528
|
+
if (contents of _sP) starts with (_sOverId & "${SNAP_PAIR}") then set _sSeen to true
|
|
79529
|
+
end repeat
|
|
79530
|
+
if not _sSeen then
|
|
79531
|
+
if _sMiss is not "" then set _sMiss to _sMiss & ","
|
|
79532
|
+
set _sMiss to _sMiss & ((${countVar} + 1) as string) & "-end"
|
|
79533
|
+
end if
|
|
79534
|
+
end try
|
|
79506
79535
|
if _sMiss is not "" then
|
|
79507
79536
|
if (count of _sPairs) is 0 then
|
|
79508
79537
|
set _sStatus to "unavailable"
|
|
@@ -84623,6 +84652,25 @@ function withErrorHandling(handler, errorPrefix) {
|
|
|
84623
84652
|
};
|
|
84624
84653
|
}
|
|
84625
84654
|
|
|
84655
|
+
// src/tools/mailboxListing.ts
|
|
84656
|
+
var LOCAL_STORE_NAMES = ["on my mac", "on my computer", "local", "local folders"];
|
|
84657
|
+
function isLocalStoreName(name) {
|
|
84658
|
+
return LOCAL_STORE_NAMES.includes(name.trim().toLowerCase());
|
|
84659
|
+
}
|
|
84660
|
+
function unlistableStoreError(account, error2, knownAccounts) {
|
|
84661
|
+
const scope = account ? ` for "${account}"` : "";
|
|
84662
|
+
const parts = [`Could not list mailboxes${scope}: ${error2 ?? "Mail declined the request"}`];
|
|
84663
|
+
if (knownAccounts.length > 0) {
|
|
84664
|
+
parts.push(`Accounts on this Mac: ${knownAccounts.join(", ")}.`);
|
|
84665
|
+
}
|
|
84666
|
+
if (account && isLocalStoreName(account)) {
|
|
84667
|
+
parts.push(
|
|
84668
|
+
`"${account}" is Mail's LOCAL store, not an account \u2014 its mailboxes are not children of any account, so they cannot be reached with an \`account\` argument. Enumerating them is not yet supported.`
|
|
84669
|
+
);
|
|
84670
|
+
}
|
|
84671
|
+
return parts.join("\n\n");
|
|
84672
|
+
}
|
|
84673
|
+
|
|
84626
84674
|
// src/tools/batchResults.ts
|
|
84627
84675
|
async function hybridBatchCounts(ids, appleFn, imapFn) {
|
|
84628
84676
|
const distinctIds = [...new Set(ids)];
|
|
@@ -86664,13 +86712,17 @@ ${r.base64}`,
|
|
|
86664
86712
|
registerTool(
|
|
86665
86713
|
"list-mailboxes",
|
|
86666
86714
|
{
|
|
86667
|
-
description: "Use when: discovering the mailbox/folder names (and unread/message counts) available in an account, e.g. before moving messages or searching a specific mailbox.\nReturns: each mailbox's name with its unread (and, for IMAP, total message) count, plus a count.\nDo not use when: you want the messages inside a mailbox (use list-messages or search-messages) or the list of accounts (use list-accounts).",
|
|
86715
|
+
description: "Use when: discovering the mailbox/folder names (and unread/message counts) available in an account, e.g. before moving messages or searching a specific mailbox.\nReturns: each mailbox's name with its unread (and, for IMAP, total message) count, plus a count. A source that could not be read is NAMED \u2014 the result carries `partial: true` + `failedAccounts` and the list is a floor, not the complete set \u2014 and a listing Mail refused outright (e.g. an account that does not exist) returns an ERROR naming the accounts that do exist, never an empty list.\nDo not use when: you want the messages inside a mailbox (use list-messages or search-messages) or the list of accounts (use list-accounts).\nNote: Mail's local \"On My Mac\" mailboxes are not part of any account and are not currently enumerated by this tool.",
|
|
86668
86716
|
inputSchema: {
|
|
86669
86717
|
account: external_exports.string().optional().describe("Account to list mailboxes from")
|
|
86670
86718
|
},
|
|
86671
86719
|
outputSchema: {
|
|
86672
86720
|
mailboxes: external_exports.array(external_exports.object({}).passthrough()).optional(),
|
|
86673
|
-
count: external_exports.number().optional()
|
|
86721
|
+
count: external_exports.number().optional(),
|
|
86722
|
+
// Declared explicitly: the SDK stamps additionalProperties:false on a bare
|
|
86723
|
+
// zod shape, so an undeclared key makes the CLIENT reject the result.
|
|
86724
|
+
partial: external_exports.boolean().optional(),
|
|
86725
|
+
failedAccounts: external_exports.array(external_exports.string()).optional()
|
|
86674
86726
|
}
|
|
86675
86727
|
},
|
|
86676
86728
|
withErrorHandling(async ({ account }) => {
|
|
@@ -86692,6 +86744,7 @@ ${list2}`, structured3);
|
|
|
86692
86744
|
}
|
|
86693
86745
|
const configs = resolveImapConfigs();
|
|
86694
86746
|
const rows = [];
|
|
86747
|
+
const failedAccounts = [];
|
|
86695
86748
|
for (const config2 of configs) {
|
|
86696
86749
|
try {
|
|
86697
86750
|
const boxes = await imapListMailboxes({ config: config2 });
|
|
@@ -86705,11 +86758,18 @@ ${list2}`, structured3);
|
|
|
86705
86758
|
}
|
|
86706
86759
|
} catch (e) {
|
|
86707
86760
|
console.error(`IMAP list-mailboxes failed for "${config2.accountLabel}": ${String(e)}`);
|
|
86761
|
+
failedAccounts.push(config2.accountLabel);
|
|
86708
86762
|
}
|
|
86709
86763
|
}
|
|
86710
86764
|
const { appleScriptOnly } = partitionAccountsForCounts(mailManager.listAccounts(), configs);
|
|
86711
86765
|
for (const acct of appleScriptOnly) {
|
|
86712
|
-
|
|
86766
|
+
const checked = mailManager.listMailboxesChecked(acct.name);
|
|
86767
|
+
if (checked.failed) {
|
|
86768
|
+
console.error(`list-mailboxes failed for "${acct.name}": ${checked.error}`);
|
|
86769
|
+
failedAccounts.push(acct.name);
|
|
86770
|
+
continue;
|
|
86771
|
+
}
|
|
86772
|
+
for (const mb of checked.mailboxes) {
|
|
86713
86773
|
rows.push({
|
|
86714
86774
|
name: `${acct.name}/${mb.name}`,
|
|
86715
86775
|
account: acct.name,
|
|
@@ -86718,13 +86778,34 @@ ${list2}`, structured3);
|
|
|
86718
86778
|
});
|
|
86719
86779
|
}
|
|
86720
86780
|
}
|
|
86721
|
-
const
|
|
86722
|
-
|
|
86781
|
+
const partial2 = failedAccounts.length > 0;
|
|
86782
|
+
const structured2 = {
|
|
86783
|
+
mailboxes: rows,
|
|
86784
|
+
count: rows.length,
|
|
86785
|
+
...partial2 ? { partial: partial2, failedAccounts } : {}
|
|
86786
|
+
};
|
|
86787
|
+
const caveat = partial2 ? `
|
|
86788
|
+
|
|
86789
|
+
PARTIAL \u2014 could not read: ${failedAccounts.join(", ")}. This list is incomplete.` : "";
|
|
86790
|
+
if (rows.length === 0) {
|
|
86791
|
+
return partial2 ? errorResponse(
|
|
86792
|
+
`Could not list mailboxes from any source. Failed: ${failedAccounts.join(", ")}.`
|
|
86793
|
+
) : successResponse("No mailboxes found", structured2);
|
|
86794
|
+
}
|
|
86723
86795
|
const list = rows.map((b) => ` - ${b.name} (${b.unreadCount} unread)`).join("\n");
|
|
86724
86796
|
return successResponse(`Found ${rows.length} mailbox(es):
|
|
86725
|
-
${list}`, structured2);
|
|
86797
|
+
${list}${caveat}`, structured2);
|
|
86798
|
+
}
|
|
86799
|
+
const { mailboxes, failed, error: error2 } = mailManager.listMailboxesChecked(account);
|
|
86800
|
+
if (failed) {
|
|
86801
|
+
return errorResponse(
|
|
86802
|
+
unlistableStoreError(
|
|
86803
|
+
account,
|
|
86804
|
+
error2,
|
|
86805
|
+
mailManager.listAccounts().map((a) => a.name)
|
|
86806
|
+
)
|
|
86807
|
+
);
|
|
86726
86808
|
}
|
|
86727
|
-
const mailboxes = mailManager.listMailboxes(account);
|
|
86728
86809
|
const structured = { mailboxes, count: mailboxes.length };
|
|
86729
86810
|
if (mailboxes.length === 0) {
|
|
86730
86811
|
return successResponse("No mailboxes found", structured);
|
package/package.json
CHANGED