@mgcrea/mcp-apple-messages 1.16.0 → 1.18.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/dist/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { A as MESSAGES_SURFACE, V as BUILD_INFO, a as loadConfig, r as createServer } from "./server-CIacos3P.js";
2
+ import { A as MESSAGES_SURFACE, V as BUILD_INFO, a as loadConfig, r as createServer } from "./server-BdWRSEL0.js";
3
3
  import { runStdioServer } from "@mgcrea/mcp-apple-core";
4
4
  //#region src/cli.ts
5
5
  const LOG_PREFIX = "apple-messages-mcp";
package/dist/index.d.ts CHANGED
@@ -132,6 +132,15 @@ type RangeQuery = {
132
132
  fromApple?: number | undefined;
133
133
  toApple?: number | undefined;
134
134
  includeReactions?: boolean | undefined;
135
+ /**
136
+ * Narrow to one direction in SQL.
137
+ *
138
+ * `find_codes` wants received messages only, and used to get there by
139
+ * fetching `limit` rows and discarding the sent ones AFTERWARDS — so a busy
140
+ * few minutes of the user's own replies could push the code being looked for
141
+ * off the end of a page that was never about it.
142
+ */
143
+ direction?: "sent" | "received" | undefined;
135
144
  limit: number;
136
145
  };
137
146
  /**
@@ -148,7 +157,17 @@ declare const COUNT_GROUP_FIELDS: readonly ["day", "month", "chat", "handle", "d
148
157
  type CountGroupField = (typeof COUNT_GROUP_FIELDS)[number];
149
158
  type CountQuery = {
150
159
  chatGuid?: string | undefined;
151
- /** Substring of a handle — a phone number or an email address. */
160
+ /**
161
+ * Exact store handles to count, already resolved by the client.
162
+ *
163
+ * Preferred over `handle` below. The client resolves what the caller typed
164
+ * through the same last-nine-digits rule `send_message` uses, so
165
+ * "06 12 34 56 78" and "+33612345678" reach the same rows — which the
166
+ * substring match could not do, while `send_message`'s own description
167
+ * promises exactly that.
168
+ */
169
+ handles?: string[] | undefined;
170
+ /** Substring of a handle. Only used when nothing resolved — see `handles`. */
152
171
  handle?: string | undefined;
153
172
  direction?: "sent" | "received" | undefined;
154
173
  fromApple?: number | undefined;
@@ -433,6 +452,7 @@ declare class AppleMessagesClient {
433
452
  fromApple?: number | undefined;
434
453
  toApple?: number | undefined;
435
454
  includeReactions?: boolean | undefined;
455
+ direction?: "sent" | "received" | undefined;
436
456
  limit?: number | undefined;
437
457
  }): RenderedMessage[];
438
458
  searchMessages(query: string, limit?: number): RenderedMessage[];
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/build-info.ts","../src/config.ts","../src/client/locate.ts","../src/client/store.ts","../src/client/messages.ts","../src/client/dates.ts","../src/client/errors.ts","../src/client/ref.ts","../src/client/typedstream.ts","../src/client/jxa/core.ts","../src/client/jxa/write.ts","../src/server.ts","../src/tools/index.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/build-info.ts","../src/config.ts","../src/client/locate.ts","../src/client/store.ts","../src/client/messages.ts","../src/client/dates.ts","../src/client/errors.ts","../src/client/ref.ts","../src/client/typedstream.ts","../src/client/jxa/core.ts","../src/client/jxa/write.ts","../src/server.ts","../src/tools/index.ts"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import { A as MESSAGES_SURFACE, B as toAppleSeconds, C as locateStore, D as ChatNotFoundError, E as AppleMessagesError, F as SendTargetNotFoundError, I as CORE_DATA_EPOCH_OFFSET, L as appleSecondsSql, M as MessagesUnavailableError, N as SchemaDriftError, O as IndexUnavailableError, P as SendFailedError, R as fromAppleSeconds, S as defaultStorePath, T as PRELUDE, V as BUILD_INFO, _ as decodeMessageRef, a as loadConfig, b as ATTACHMENTS_RELATIVE, c as introspect, d as decodeAttributedBody, f as outline, g as decodeChatRef, h as MESSAGE_REF_VERSION, i as registerTools, j as MessageNotFoundError, k as MESSAGES_BUNDLE_ID, l as openStore, m as InvalidMessageRefError, n as SERVER_VERSION, o as AppleMessagesClient, p as CHAT_REF_VERSION, r as createServer, s as MessagesStore, t as SERVER_NAME, u as reactionLabel, v as encodeChatRef, w as SEND_MESSAGE, x as STORE_RELATIVE, y as encodeMessageRef, z as renderInstant } from "./server-CIacos3P.js";
1
+ import { A as MESSAGES_SURFACE, B as toAppleSeconds, C as locateStore, D as ChatNotFoundError, E as AppleMessagesError, F as SendTargetNotFoundError, I as CORE_DATA_EPOCH_OFFSET, L as appleSecondsSql, M as MessagesUnavailableError, N as SchemaDriftError, O as IndexUnavailableError, P as SendFailedError, R as fromAppleSeconds, S as defaultStorePath, T as PRELUDE, V as BUILD_INFO, _ as decodeMessageRef, a as loadConfig, b as ATTACHMENTS_RELATIVE, c as introspect, d as decodeAttributedBody, f as outline, g as decodeChatRef, h as MESSAGE_REF_VERSION, i as registerTools, j as MessageNotFoundError, k as MESSAGES_BUNDLE_ID, l as openStore, m as InvalidMessageRefError, n as SERVER_VERSION, o as AppleMessagesClient, p as CHAT_REF_VERSION, r as createServer, s as MessagesStore, t as SERVER_NAME, u as reactionLabel, v as encodeChatRef, w as SEND_MESSAGE, x as STORE_RELATIVE, y as encodeMessageRef, z as renderInstant } from "./server-BdWRSEL0.js";
2
2
  export { ATTACHMENTS_RELATIVE, AppleMessagesClient, AppleMessagesError, BUILD_INFO, CHAT_REF_VERSION, CORE_DATA_EPOCH_OFFSET, ChatNotFoundError, IndexUnavailableError, InvalidMessageRefError, MESSAGES_BUNDLE_ID, MESSAGES_SURFACE, MESSAGE_REF_VERSION, MessageNotFoundError, MessagesStore, MessagesUnavailableError, PRELUDE, SEND_MESSAGE, SERVER_NAME, SERVER_VERSION, STORE_RELATIVE, SchemaDriftError, SendFailedError, SendTargetNotFoundError, appleSecondsSql, createServer, decodeAttributedBody, decodeChatRef, decodeMessageRef, defaultStorePath, encodeChatRef, encodeMessageRef, fromAppleSeconds, introspect, loadConfig, locateStore, openStore, outline, reactionLabel, registerTools, renderInstant, toAppleSeconds };
@@ -1,4 +1,4 @@
1
- import { AppleAutomationError, AppleAutomationError as AppleMessagesError, BaseConfigSchema, CORE_DATA_EPOCH_OFFSET, IndexUnavailableError, IndexUnavailableError as IndexUnavailableError$1, PreconditionError, SchemaDriftError, SchemaDriftError as SchemaDriftError$1, columnsOf, confirmArg, createOsascriptRunner, describeAggregation, describeStore, escapeLike, extractCode, fail, fingerprintSchema, groupByArg, limitArg, ok, openReadOnly, parseBool, parseConfig, parseIntOpt, promptArg, readPackageIdentity, registerSurfaceResources, registerWorkflowPrompt, requiredPromptArg, resolveLimit, trimmed, withBusyRetry, withLazyTools, wrap, wrapResult } from "@mgcrea/mcp-apple-core";
1
+ import { AppleAutomationError, AppleAutomationError as AppleMessagesError, BaseConfigSchema, CORE_DATA_EPOCH_OFFSET, IndexUnavailableError, IndexUnavailableError as IndexUnavailableError$1, PreconditionError, SchemaDriftError, SchemaDriftError as SchemaDriftError$1, columnsOf, confirmArg, createOsascriptRunner, describeAggregation, describeStore, escapeLike, extractCode, fail, fingerprintSchema, groupByArg, limitArg, ok, openReadOnly, parseBool, parseBound, parseConfig, parseIntOpt, promptArg, readPackageIdentity, registerSurfaceResources, registerWorkflowPrompt, requiredPromptArg, resolveLimit, trimmed, withBusyRetry, withLazyTools, wrap, wrapResult } from "@mgcrea/mcp-apple-core";
2
2
  import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
3
3
  import { homedir } from "node:os";
4
4
  import { basename, isAbsolute, join, resolve, sep } from "node:path";
@@ -13,8 +13,8 @@ const pkg = readPackageIdentity(new URL("../package.json", import.meta.url), {
13
13
  const BUILD_INFO = {
14
14
  name: pkg.name,
15
15
  version: pkg.version,
16
- gitCommit: "d70b8e4",
17
- gitCommitDate: "2026-09-06T12:13:21+02:00"
16
+ gitCommit: "657cbf0",
17
+ gitCommitDate: "2026-09-07T21:40:45+02:00"
18
18
  };
19
19
  //#endregion
20
20
  //#region src/client/dates.ts
@@ -1055,6 +1055,10 @@ var MessagesStore = class {
1055
1055
  params.push(q.toApple);
1056
1056
  }
1057
1057
  if (!q.includeReactions && m.has("associated_message_type")) where.push(`(m."associated_message_type" IS NULL OR m."associated_message_type" = 0)`);
1058
+ if (q.direction && m.has("is_from_me")) {
1059
+ where.push(`m."is_from_me" = ?`);
1060
+ params.push(q.direction === "sent" ? 1 : 0);
1061
+ }
1058
1062
  const sql = `
1059
1063
  SELECT ${this.#messageColumns()}
1060
1064
  FROM "message" m
@@ -1082,26 +1086,29 @@ var MessagesStore = class {
1082
1086
  const needle = `%${escapeLike(query)}%`;
1083
1087
  const reactionFilter = !includeReactions && m.has("associated_message_type") ? `AND (m."associated_message_type" IS NULL OR m."associated_message_type" = 0)` : "";
1084
1088
  const cap = Math.max(1, Math.trunc(limit));
1085
- const results = this.db.prepare(`SELECT ${this.#messageColumns()}
1089
+ const column = this.db.prepare(`SELECT ${this.#messageColumns()}
1086
1090
  FROM "message" m
1087
1091
  ${this.#joins()}
1088
1092
  WHERE m."text" LIKE ? ESCAPE '\\' ${reactionFilter}
1089
1093
  ORDER BY m."date" DESC
1090
1094
  LIMIT ${cap}`).all(needle).map((r) => this.#toRow(r));
1091
- if (results.length >= cap || !m.has("attributedBody")) return results;
1095
+ if (!m.has("attributedBody")) return column.slice(0, cap);
1096
+ const floor = column.length >= cap ? column.at(-1)?.sentAt ?? null : null;
1092
1097
  const blobOnly = this.db.prepare(`SELECT ${this.#messageColumns()}
1093
1098
  FROM "message" m
1094
1099
  ${this.#joins()}
1095
1100
  WHERE (m."text" IS NULL OR m."text" = '')
1096
1101
  AND m."attributedBody" IS NOT NULL ${reactionFilter}
1097
- ORDER BY m."date" DESC`).all();
1102
+ ${floor === null ? "" : `AND ${appleSecondsSql("m.\"date\"")} >= ?`}
1103
+ ORDER BY m."date" DESC`).all(...floor === null ? [] : [floor]);
1098
1104
  const lowered = query.toLowerCase();
1105
+ const decoded = [];
1099
1106
  for (const raw of blobOnly) {
1100
- if (results.length >= cap) break;
1101
1107
  const row = this.#toRow(raw);
1102
- if (row.text && row.text.toLowerCase().includes(lowered)) results.push(row);
1108
+ if (row.text && row.text.toLowerCase().includes(lowered)) decoded.push(row);
1103
1109
  }
1104
- return results.slice(0, cap);
1110
+ if (decoded.length === 0) return column.slice(0, cap);
1111
+ return [...column, ...decoded].toSorted((a, b) => (b.sentAt ?? -Infinity) - (a.sentAt ?? -Infinity)).slice(0, cap);
1105
1112
  }
1106
1113
  byGuid(guid) {
1107
1114
  const rows = this.db.prepare(`SELECT ${this.#messageColumns()}
@@ -1368,7 +1375,7 @@ var MessagesStore = class {
1368
1375
  */
1369
1376
  #countFrom(q, field) {
1370
1377
  const parts = [];
1371
- if (q.handle || field === "handle") parts.push(`LEFT JOIN "handle" h ON h."ROWID" = m."handle_id"`);
1378
+ if (q.handle || q.handles?.length || field === "handle") parts.push(`LEFT JOIN "handle" h ON h."ROWID" = m."handle_id"`);
1372
1379
  if (q.chatGuid || field === "chat") parts.push(`LEFT JOIN "chat_message_join" cmj ON cmj."message_id" = m."ROWID"`, `LEFT JOIN "chat" c ON c."ROWID" = cmj."chat_id"`);
1373
1380
  return parts.join("\n ");
1374
1381
  }
@@ -1384,7 +1391,10 @@ var MessagesStore = class {
1384
1391
  where.push(`c."guid" = ?`);
1385
1392
  params.push(q.chatGuid);
1386
1393
  }
1387
- if (q.handle) {
1394
+ if (q.handles?.length) {
1395
+ where.push(`h."id" IN (${q.handles.map(() => "?").join(",")})`);
1396
+ params.push(...q.handles);
1397
+ } else if (q.handle) {
1388
1398
  where.push(`h."id" LIKE ? ESCAPE '\\'`);
1389
1399
  params.push(`%${escapeLike(q.handle)}%`);
1390
1400
  }
@@ -1648,6 +1658,7 @@ var AppleMessagesClient = class {
1648
1658
  ...opts.fromApple === void 0 ? {} : { fromApple: opts.fromApple },
1649
1659
  ...opts.toApple === void 0 ? {} : { toApple: opts.toApple },
1650
1660
  ...opts.includeReactions === void 0 ? {} : { includeReactions: opts.includeReactions },
1661
+ ...opts.direction === void 0 ? {} : { direction: opts.direction },
1651
1662
  limit: resolveLimit(opts.limit, this.#config.maxResults)
1652
1663
  }));
1653
1664
  }
@@ -1780,8 +1791,11 @@ var AppleMessagesClient = class {
1780
1791
  * `searchMessages`, which has the decode pass that makes it complete.
1781
1792
  */
1782
1793
  countMessages(q, groupBy) {
1783
- const result = this.#require().countMessages({
1794
+ const store = this.#require();
1795
+ const resolved = q.handle ? this.#handlesLike(q.handle) : [];
1796
+ const result = store.countMessages({
1784
1797
  ...q,
1798
+ ...resolved.length ? { handles: resolved } : {},
1785
1799
  limit: resolveLimit(q.limit, this.#config.maxResults)
1786
1800
  }, groupBy);
1787
1801
  if (!("groups" in result)) return renderCount(result);
@@ -1816,7 +1830,7 @@ var AppleMessagesClient = class {
1816
1830
  return {
1817
1831
  guid,
1818
1832
  chat,
1819
- handle: chat?.participants[0] ?? null
1833
+ handle: chat && !chat.isGroup ? chat.participants[0] ?? null : null
1820
1834
  };
1821
1835
  }
1822
1836
  const to = input.to?.trim();
@@ -1830,15 +1844,7 @@ var AppleMessagesClient = class {
1830
1844
  chat: null,
1831
1845
  handle: to
1832
1846
  };
1833
- const kind = handleKind(to);
1834
- const wantedSuffix = kind === "phone" ? suffixKey(to) : null;
1835
- const wantedEmail = kind === "email" ? emailKey(to) : null;
1836
- const candidates = store.handles().filter((h) => {
1837
- if (h === to) return true;
1838
- if (wantedEmail) return emailKey(h) === wantedEmail;
1839
- if (wantedSuffix) return suffixKey(h) === wantedSuffix;
1840
- return false;
1841
- });
1847
+ const candidates = this.#handlesLike(to);
1842
1848
  if (!candidates.length) return {
1843
1849
  guid: null,
1844
1850
  chat: null,
@@ -1852,6 +1858,30 @@ var AppleMessagesClient = class {
1852
1858
  };
1853
1859
  }
1854
1860
  /**
1861
+ * Every handle in the store that names the same correspondent.
1862
+ *
1863
+ * The last-nine-digits rule `packages/contacts` measured, so
1864
+ * "06 12 34 56 78", "+33 6 12 34 56 78" and "+33612345678" all reach the same
1865
+ * rows. Used by the send lane to pick a chat, and by `count_messages`, which
1866
+ * used a substring LIKE instead — so counting by a locally-spelled number
1867
+ * answered zero while `send_message` to that same string worked. One
1868
+ * surface, two ideas of what a handle is.
1869
+ */
1870
+ #handlesLike(handle) {
1871
+ const store = this.store();
1872
+ if (!store) return [];
1873
+ const wanted = handle.trim();
1874
+ const kind = handleKind(wanted);
1875
+ const wantedSuffix = kind === "phone" ? suffixKey(wanted) : null;
1876
+ const wantedEmail = kind === "email" ? emailKey(wanted) : null;
1877
+ return store.handles().filter((h) => {
1878
+ if (h === wanted) return true;
1879
+ if (wantedEmail) return emailKey(h) === wantedEmail;
1880
+ if (wantedSuffix) return suffixKey(h) === wantedSuffix;
1881
+ return false;
1882
+ });
1883
+ }
1884
+ /**
1855
1885
  * Find the row Messages wrote, or say plainly that it was not found.
1856
1886
  *
1857
1887
  * `docs/messages.md` left this as an open question — "whether a send should
@@ -1885,7 +1915,7 @@ var AppleMessagesClient = class {
1885
1915
  const store = this.store();
1886
1916
  if (!store) return null;
1887
1917
  const rows = store.sentSince([guid], since, 10);
1888
- const hit = (text === null ? void 0 : rows.find((r) => r.text !== null && r.text === text)) ?? rows[0];
1918
+ const hit = text === null ? rows[0] : rows.find((r) => r.text === text);
1889
1919
  if (hit) return this.#render([hit])[0] ?? null;
1890
1920
  if (Date.now() >= deadline) return null;
1891
1921
  await new Promise((resolve) => setTimeout(resolve, 250));
@@ -2280,8 +2310,18 @@ the blob-storage change described in the guide, not the end of the conversation
2280
2310
  //#region src/tools/util.ts
2281
2311
  const chatRefArg = z.string().optional().describe("An opaque chat ref from apple_messages_list_chats (looks like \"mc1:<guid>\"). Do not construct one by hand.");
2282
2312
  const messageRefArg = z.string().min(1).describe("An opaque message ref from a list or search result (looks like \"m1:<guid>\"). Do not construct one by hand.");
2283
- const fromArg = z.string().optional().describe("Start of the window, ISO-8601 — \"2026-08-01\" or \"2026-08-01T09:00\".");
2284
- const toArg = z.string().optional().describe("End of the window, ISO-8601. Defaults to 30 days after `from`, or to now when `from` is omitted too.");
2313
+ const fromArg = z.string().optional().describe("Start of the window — \"2026-08-01\" (a whole day, local), \"2026-08-01T09:00\", or a relative form like \"-7d\", \"yesterday\" or \"last monday\".");
2314
+ const toArg = z.string().optional().describe("End of the window, same forms as `from`. A bare day includes ALL of that day. Defaults to 30 days after `from`, or to now when `from` is omitted too.");
2315
+ /**
2316
+ * One bound, through the grammar every surface shares.
2317
+ *
2318
+ * This replaced two copies of a local `new Date(raw)`, which had the bug that
2319
+ * grammar exists to prevent: `new Date("2026-08-01")` is UTC midnight while
2320
+ * `new Date("2026-08-01T00:00")` is LOCAL midnight, so the two spellings the
2321
+ * descriptions above treat as equivalent bounded a query hours apart — and the
2322
+ * day and month buckets these windows feed are local calendar dates.
2323
+ */
2324
+ const bound = (raw, field, edge) => raw === void 0 ? void 0 : parseBound(field, raw, edge);
2285
2325
  const includeReactionsArg = z.boolean().optional().describe("Include tapbacks as if they were messages. Off by default, and you almost never want it on: a tapback renders as `Liked \"see you at 8\"`, which nobody typed. Use apple_messages_get_message to see the reactions on a specific message instead.");
2286
2326
  //#endregion
2287
2327
  //#region src/tools/diagnostics.ts
@@ -2462,6 +2502,8 @@ CHECK \`ageSeconds\` BEFORE USING A CODE. An expired code is still in the store
2462
2502
 
2463
2503
  \`confidence\` says how the match was made and is not decoration. "high" means the code was bound to a domain (\`@site.com #123456\`) or sat directly against a word like "verification code" — safe to use. "medium" means the keyword was further away, or two candidates tied. "low" means there was no keyword at all and only the sender being a shortcode suggested it. On anything below high, read the message with apple_messages_get_message and confirm against the body before using the digits.
2464
2504
 
2505
+ \`service\` is a trust signal, not a detail. iMessage is authenticated against an Apple ID; SMS and RCS sender IDs are not, and can be forged. \`confidence\` measures how cleanly the code was EXTRACTED from the text — it says nothing about who sent it, so a spoofed SMS naming a domain scores "high" exactly like a real one. Most genuine codes do arrive by SMS, so this is not a reason to discard them; it is a reason not to treat a code as proof of anything. If a code arrives that the user did not just ask for, say which service delivered it instead of offering the digits.
2506
+
2465
2507
  A \`matched\` value ending in \`-ambiguous\` means the message held more than one plausible code and this tool did not guess — confirm which one is wanted.
2466
2508
 
2467
2509
  Returning nothing is the normal result when no code has arrived. It does NOT mean the code was missed, and it is not a reason to re-run with a longer window: if a code was sent it is in the store within seconds. Prefer asking the user to trigger a new one.`,
@@ -2479,9 +2521,11 @@ Returning nothing is the normal result when no code has arrived. It does NOT mea
2479
2521
  const since = /* @__PURE__ */ new Date(Date.now() - minutes * 6e4);
2480
2522
  const { fromApple } = client.window(since);
2481
2523
  const needle = service?.trim().toLowerCase();
2524
+ const scan = needle ? client.config.maxResults : limit;
2482
2525
  const codes = client.listMessages({
2483
2526
  ...fromApple === void 0 ? {} : { fromApple },
2484
- limit
2527
+ direction: "received",
2528
+ limit: scan
2485
2529
  }).filter((m) => !m.fromMe).filter((m) => {
2486
2530
  if (!needle) return true;
2487
2531
  return `${m.from.name ?? ""} ${m.from.handle ?? ""} ${m.text ?? ""}`.toLowerCase().includes(needle);
@@ -2495,12 +2539,13 @@ Returning nothing is the normal result when no code has arrived. It does NOT mea
2495
2539
  matched: match.matched,
2496
2540
  ...match.boundTo ? { boundTo: match.boundTo } : {},
2497
2541
  from: m.from,
2542
+ service: m.service,
2498
2543
  sentAt: m.sentAt,
2499
2544
  ageSeconds: Number.isNaN(sentAtMs) ? null : Math.max(0, Math.round((Date.now() - sentAtMs) / 1e3)),
2500
2545
  ref: m.ref,
2501
2546
  chat: m.chat
2502
2547
  }];
2503
- });
2548
+ }).slice(0, limit);
2504
2549
  return {
2505
2550
  windowMinutes: minutes,
2506
2551
  searchedSince: since.toISOString(),
@@ -2511,13 +2556,6 @@ Returning nothing is the normal result when no code has arrived. It does NOT mea
2511
2556
  };
2512
2557
  //#endregion
2513
2558
  //#region src/tools/counts.ts
2514
- /** ISO-8601 in, or a clear refusal. Same grammar as `list_messages`. */
2515
- const parseBound$1 = (raw, field) => {
2516
- if (raw === void 0) return void 0;
2517
- const d = new Date(raw);
2518
- if (Number.isNaN(d.getTime())) throw new Error(`Could not read ${field} from ${JSON.stringify(raw)}. Use ISO-8601: "2026-08-01" or "2026-08-01T09:00".`);
2519
- return d;
2520
- };
2521
2559
  /**
2522
2560
  * The cheap-answer lane on this surface: counts, and counts per group.
2523
2561
  *
@@ -2539,7 +2577,7 @@ const registerCountTools = (server, client) => {
2539
2577
  description: "Count messages without reading them. Answers 'how many', 'how many did I send', 'who do I message most' and 'which month was busiest' as arithmetic the store does, rather than a page of conversations you tally by hand. Every result splits `sent` and `received`.\n\n`groupBy` counts per day, month, chat, handle or direction, over EVERY match rather than the first `limit` of them — `limit` caps how many groups come back. Grouping by handle is the one to reach for when a person has several conversations, since apple_messages_list_chats already gives you per-CHAT totals.\n\nCounts metadata only: there is no text filter here, because message bodies from 2026 onward live in an archived blob that SQL cannot see, and a count that quietly skipped them would look exactly like a correct one. Use apple_messages_search_messages for anything about what was said. Tapbacks are excluded unless you ask for them.",
2540
2578
  inputSchema: {
2541
2579
  chatRef: chatRefArg,
2542
- handle: z.string().optional().describe("Only messages with this correspondent — a phone number or email, matched as a substring. Spans every chat they appear in, which is the difference from chatRef."),
2580
+ handle: z.string().optional().describe("Only messages with this correspondent — a phone number or email. Spellings of the same number match each other, so \"06 12 34 56 78\" and \"+33612345678\" are the same person, exactly as they are for send_message. A fragment that resolves to nobody falls back to a substring match. Spans every chat they appear in, which is the difference from chatRef."),
2543
2581
  direction: z.enum(["sent", "received"]).optional().describe("Only what you sent, or only what you received. Omit for both."),
2544
2582
  from: fromArg,
2545
2583
  to: z.string().optional().describe("End of the window, ISO-8601, exclusive. Omit to count up to now."),
@@ -2549,7 +2587,7 @@ const registerCountTools = (server, client) => {
2549
2587
  },
2550
2588
  annotations: { readOnlyHint: true }
2551
2589
  }, async ({ chatRef, handle, direction, from, to, includeReactions, groupBy, limit }) => wrap(async () => {
2552
- const window = client.window(parseBound$1(from, "from"), parseBound$1(to, "to"));
2590
+ const window = client.window(bound(from, "from", "start"), bound(to, "to", "end"));
2553
2591
  const result = client.countMessages({
2554
2592
  ...chatRef ? { chatGuid: decodeChatRef(chatRef) } : {},
2555
2593
  ...handle === void 0 ? {} : { handle },
@@ -2567,13 +2605,6 @@ const registerCountTools = (server, client) => {
2567
2605
  };
2568
2606
  //#endregion
2569
2607
  //#region src/tools/messages.ts
2570
- /** ISO-8601 in, or a clear refusal. No relative grammar on this surface yet. */
2571
- const parseBound = (raw, field) => {
2572
- if (raw === void 0) return void 0;
2573
- const d = new Date(raw);
2574
- if (Number.isNaN(d.getTime())) throw new Error(`Could not read ${field} from ${JSON.stringify(raw)}. Use ISO-8601: "2026-08-01" or "2026-08-01T09:00".`);
2575
- return d;
2576
- };
2577
2608
  /**
2578
2609
  * Close a range that named only a start.
2579
2610
  *
@@ -2603,8 +2634,8 @@ const registerMessageTools = (server, client) => {
2603
2634
  },
2604
2635
  annotations: { readOnlyHint: true }
2605
2636
  }, async ({ chatRef, from, to, includeReactions, limit }) => wrap(async () => {
2606
- const fromDate = parseBound(from, "from");
2607
- const window = client.window(fromDate, closeRange(fromDate, parseBound(to, "to"), client.config.defaultRangeDays));
2637
+ const fromDate = bound(from, "from", "start");
2638
+ const window = client.window(fromDate, closeRange(fromDate, bound(to, "to", "end"), client.config.defaultRangeDays));
2608
2639
  return client.listMessages({
2609
2640
  ...chatRef ? { chatRef: decodeChatRef(chatRef) } : {},
2610
2641
  ...window,
@@ -2713,4 +2744,4 @@ const createServer = (opts) => {
2713
2744
  //#endregion
2714
2745
  export { MESSAGES_SURFACE as A, toAppleSeconds as B, locateStore as C, ChatNotFoundError as D, AppleMessagesError as E, SendTargetNotFoundError as F, CORE_DATA_EPOCH_OFFSET as I, appleSecondsSql as L, MessagesUnavailableError as M, SchemaDriftError$1 as N, IndexUnavailableError$1 as O, SendFailedError as P, fromAppleSeconds as R, defaultStorePath as S, PRELUDE as T, BUILD_INFO as V, decodeMessageRef as _, loadConfig$1 as a, ATTACHMENTS_RELATIVE as b, introspect as c, decodeAttributedBody as d, outline as f, decodeChatRef as g, MESSAGE_REF_VERSION as h, registerTools as i, MessageNotFoundError as j, MESSAGES_BUNDLE_ID as k, openStore as l, InvalidMessageRefError as m, SERVER_VERSION as n, AppleMessagesClient as o, CHAT_REF_VERSION as p, createServer as r, MessagesStore as s, SERVER_NAME as t, reactionLabel as u, encodeChatRef as v, SEND_MESSAGE as w, STORE_RELATIVE as x, encodeMessageRef as y, renderInstant as z };
2715
2746
 
2716
- //# sourceMappingURL=server-CIacos3P.js.map
2747
+ //# sourceMappingURL=server-BdWRSEL0.js.map