apple-mail-mcp 2.20.5 → 2.20.7

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 (2) hide show
  1. package/build/index.js +74 -12
  2. package/package.json +1 -1
package/build/index.js CHANGED
@@ -82735,6 +82735,7 @@ function getByIdScanThreshold() {
82735
82735
  return 5e4;
82736
82736
  }
82737
82737
  var BYID_SCAN_BUDGET_SECONDS = 9;
82738
+ var BYID_PROBE_TIMEOUT_SECONDS = 3;
82738
82739
  var BYID_COVERAGE_MARKER = "COV";
82739
82740
  var SCOPED_MISS_MARKER = "SCOPED";
82740
82741
  function describeUnscopedMiss(id, raw) {
@@ -82761,6 +82762,25 @@ function describeUnscopedMiss(id, raw) {
82761
82762
  );
82762
82763
  return parts.join(" ");
82763
82764
  }
82765
+ var STALLED_PROBE_SUFFIX = ` (size unknown (count probe exceeded ${BYID_PROBE_TIMEOUT_SECONDS}s))`;
82766
+ function extractFreshlyStalledMailboxes(raw) {
82767
+ const covIdx = raw.indexOf(BYID_COVERAGE_MARKER);
82768
+ if (covIdx === -1) return [];
82769
+ const [skippedRaw = ""] = raw.slice(covIdx + BYID_COVERAGE_MARKER.length).split(DIAG_FIELD_SEP);
82770
+ const out = [];
82771
+ for (const entry of skippedRaw.split(DIAG_ITEM_SEP)) {
82772
+ const trimmed = entry.trim();
82773
+ if (!trimmed.endsWith(STALLED_PROBE_SUFFIX)) continue;
82774
+ const withoutSuffix = trimmed.slice(0, -STALLED_PROBE_SUFFIX.length);
82775
+ const sepIdx = withoutSuffix.indexOf(" / ");
82776
+ if (sepIdx === -1) continue;
82777
+ const account = withoutSuffix.slice(0, sepIdx);
82778
+ const path3 = withoutSuffix.slice(sepIdx + 3);
82779
+ const leaf = path3.split("/").pop();
82780
+ if (account && leaf) out.push(`${account}${leaf}`);
82781
+ }
82782
+ return out;
82783
+ }
82764
82784
  var GROUP_SEP = "";
82765
82785
  var FIELD_SEP = "";
82766
82786
  var RECORD_SEP = "";
@@ -83271,6 +83291,24 @@ var AppleMailManager = class {
83271
83291
  * cross-mailbox scan — see `resolveScopedById` (#270).
83272
83292
  */
83273
83293
  idLocationIndex = /* @__PURE__ */ new Map();
83294
+ /**
83295
+ * "Account\x1fLeafMailboxName" pairs whose `count of messages` size-guard
83296
+ * probe has previously exceeded BYID_PROBE_TIMEOUT_SECONDS (#270 follow-up,
83297
+ * @j5pu). The 3s `with timeout of` wrapper only stops the SERVER's script
83298
+ * from waiting — Mail.app handles Apple events one at a time and keeps
83299
+ * running the abandoned count to completion regardless, so re-probing the
83300
+ * same mailbox on the next call doesn't just waste its own 3s, it queues
83301
+ * behind whatever is still draining inside Mail.app. Once a mailbox has
83302
+ * demonstrated this, the unscoped scan skips the probe for it entirely —
83303
+ * no `count of messages` call at all — straight to "size unknown,
83304
+ * previously timed out". Keyed on the leaf mailbox name (not the
83305
+ * container-walked path `mailboxPathFragment` builds for display) so
83306
+ * checking it costs nothing extra per mailbox visited. Remembered for the
83307
+ * life of the process: nothing ever evicts an entry, because there is no
83308
+ * signal that an abandoned Apple event has finished, and a mailbox that
83309
+ * stalled once on a store this large has no reason to get faster.
83310
+ */
83311
+ knownStalledMailboxes = /* @__PURE__ */ new Set();
83274
83312
  /** Error from the most recent numeric message read, if it was refused. */
83275
83313
  lastMessageLookupError;
83276
83314
  /** Cap on the id→location index so a long-lived process can't grow unbounded. */
@@ -84462,10 +84500,10 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
84462
84500
  return null;
84463
84501
  }
84464
84502
  if (result.output.startsWith(LOOKUP_ERROR_MARKER)) {
84465
- this.lastMessageLookupError = describeUnscopedMiss(
84466
- id,
84467
- result.output.slice(LOOKUP_ERROR_MARKER.length)
84468
- );
84503
+ const rawTail = result.output.slice(LOOKUP_ERROR_MARKER.length);
84504
+ for (const key of extractFreshlyStalledMailboxes(rawTail))
84505
+ this.knownStalledMailboxes.add(key);
84506
+ this.lastMessageLookupError = describeUnscopedMiss(id, rawTail);
84469
84507
  return null;
84470
84508
  }
84471
84509
  return result.output;
@@ -84536,18 +84574,42 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
84536
84574
  */
84537
84575
  unscopedByIdScript(id, innerAction, opts = {}) {
84538
84576
  const threshold = getByIdScanThreshold();
84539
- const sizeGuard = (mbVar, acctNameExpr) => threshold > 0 ? `set _mbCount to 0
84540
- try
84541
- set _mbCount to count of messages of ${mbVar}
84542
- end try
84543
- if _mbCount > ${threshold} then
84577
+ const stalledCheck = (mbVar, acctNameExpr) => {
84578
+ if (this.knownStalledMailboxes.size === 0) return void 0;
84579
+ const clauses = Array.from(this.knownStalledMailboxes).map((key) => {
84580
+ const [acct = "", leaf = ""] = key.split("");
84581
+ return `(${acctNameExpr} is "${escapeForAppleScript(acct)}" and (name of ${mbVar}) is "${escapeForAppleScript(leaf)}")`;
84582
+ });
84583
+ return clauses.join(" or ");
84584
+ };
84585
+ const sizeGuard = (mbVar, acctNameExpr) => {
84586
+ if (threshold <= 0) return "";
84587
+ const stalled = stalledCheck(mbVar, acctNameExpr);
84588
+ const skipEntry = (sizeLabelExpr) => `
84544
84589
  set _skipPath to ""
84545
84590
  try
84546
84591
  ${mailboxPathFragment(mbVar, "_skipPath")}
84547
84592
  end try
84548
- set _skipped to _skipped & ${acctNameExpr} & " / " & _skipPath & " (" & (_mbCount as string) & ")${DIAG_ITEM_SEP}"
84549
- set _probe to false
84550
- end if` : "";
84593
+ set _skipped to _skipped & ${acctNameExpr} & " / " & _skipPath & " (" & ${sizeLabelExpr} & ")${DIAG_ITEM_SEP}"
84594
+ set _probe to false`;
84595
+ const probeBlock = `set _mbCount to -1
84596
+ try
84597
+ with timeout of ${BYID_PROBE_TIMEOUT_SECONDS} seconds
84598
+ set _mbCount to count of messages of ${mbVar}
84599
+ end timeout
84600
+ end try
84601
+ if _mbCount < 0 or _mbCount > ${threshold} then
84602
+ set _sizeLabel to "size unknown (count probe exceeded ${BYID_PROBE_TIMEOUT_SECONDS}s)"
84603
+ if _mbCount > -1 then set _sizeLabel to (_mbCount as string)
84604
+ ${skipEntry("_sizeLabel")}
84605
+ end if`;
84606
+ if (!stalled) return probeBlock;
84607
+ return `if ${stalled} then
84608
+ ${skipEntry('"size unknown (previously timed out)"')}
84609
+ else
84610
+ ${probeBlock}
84611
+ end if`;
84612
+ };
84551
84613
  const budgetCheck = `if ((current date) - _startedAt) > ${BYID_SCAN_BUDGET_SECONDS} then
84552
84614
  set _budgetHit to true
84553
84615
  exit repeat
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apple-mail-mcp",
3
- "version": "2.20.5",
3
+ "version": "2.20.7",
4
4
  "description": "MCP server for Apple Mail - read, search, send, and manage emails via Claude and other AI assistants",
5
5
  "type": "module",
6
6
  "main": "build/index.js",