@l22-io/orchard-mcp 0.6.0 → 0.6.1

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/bridge.d.ts CHANGED
@@ -3,13 +3,24 @@ export interface BridgeResponse {
3
3
  data?: unknown;
4
4
  error?: string;
5
5
  }
6
+ export interface BridgeOptions {
7
+ /**
8
+ * Per-call timeout in milliseconds. Defaults to 30_000.
9
+ * Long-running operations (e.g. mail content searches, large file reads)
10
+ * should pass a larger value. When the timeout fires the entire child
11
+ * process group is killed via SIGTERM (then SIGKILL) — this is required
12
+ * for tools that spawn osascript grandchildren, which would otherwise
13
+ * be orphaned and keep Mail.app / Notes.app wedged on Apple Events.
14
+ */
15
+ timeoutMs?: number;
16
+ }
6
17
  /**
7
18
  * Execute an apple-bridge subcommand and return parsed JSON.
8
19
  * Tries direct execution first; falls back to .app bundle mode
9
20
  * (via `open`) when direct execution returns a permission error.
10
21
  */
11
- export declare function callBridge(args: string[]): Promise<BridgeResponse>;
22
+ export declare function callBridge(args: string[], opts?: BridgeOptions): Promise<BridgeResponse>;
12
23
  /**
13
24
  * Convenience: call bridge, check status, return data or throw.
14
25
  */
15
- export declare function bridgeData(args: string[]): Promise<unknown>;
26
+ export declare function bridgeData(args: string[], opts?: BridgeOptions): Promise<unknown>;
package/build/bridge.js CHANGED
@@ -1,11 +1,9 @@
1
- import { execFile, spawn } from "node:child_process";
2
- import { promisify } from "node:util";
1
+ import { spawn } from "node:child_process";
3
2
  import { resolve, dirname } from "node:path";
4
3
  import { fileURLToPath } from "node:url";
5
4
  import { readFile, unlink, access } from "node:fs/promises";
6
5
  import { randomUUID } from "node:crypto";
7
6
  import { tmpdir } from "node:os";
8
- const execFileAsync = promisify(execFile);
9
7
  // Reason: Resolve the Swift binary path relative to this file's location.
10
8
  // In development: swift/.build/release/apple-bridge
11
9
  // In npm package: swift/.build/release/apple-bridge (shipped alongside)
@@ -42,42 +40,143 @@ function getAppBundlePath() {
42
40
  }
43
41
  return resolve(__dirname, "..", "swift", ".build", "AppleBridge.app");
44
42
  }
43
+ const DEFAULT_TIMEOUT_MS = 30_000;
44
+ const SIGKILL_GRACE_MS = 2_000;
45
45
  /**
46
46
  * Execute an apple-bridge subcommand and return parsed JSON.
47
47
  * Tries direct execution first; falls back to .app bundle mode
48
48
  * (via `open`) when direct execution returns a permission error.
49
49
  */
50
- export async function callBridge(args) {
50
+ export async function callBridge(args, opts = {}) {
51
51
  const bin = getBridgePath();
52
- try {
53
- const { stdout, stderr } = await execFileAsync(bin, args, {
54
- timeout: 30_000,
55
- maxBuffer: 10 * 1024 * 1024,
56
- });
57
- if (stderr) {
58
- // Reason: stderr is used for Swift warnings/diagnostics, log but don't fail.
59
- console.error(`[apple-bridge stderr] ${stderr.trim()}`);
52
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
53
+ const direct = await runBridgeProcess(bin, args, timeoutMs);
54
+ if (direct.status === "error" || direct.parsed == null) {
55
+ if (direct.spawnError) {
56
+ return { status: "error", error: direct.spawnError };
57
+ }
58
+ if (direct.timedOut) {
59
+ return {
60
+ status: "error",
61
+ error: `apple-bridge timed out after ${timeoutMs}ms`,
62
+ };
60
63
  }
61
- const parsed = JSON.parse(stdout);
64
+ }
65
+ if (direct.parsed) {
66
+ const parsed = direct.parsed;
62
67
  // If the command returned a permission error, retry via .app bundle
63
68
  if (parsed.status === "error" &&
64
69
  typeof parsed.error === "string" &&
65
70
  parsed.error.includes("access denied")) {
66
- return callBridgeViaApp(args);
71
+ return callBridgeViaApp(args, timeoutMs);
67
72
  }
68
73
  return parsed;
69
74
  }
70
- catch (err) {
71
- const msg = err instanceof Error ? err.message : "Unknown error calling apple-bridge";
72
- return { status: "error", error: msg };
73
- }
75
+ return { status: "error", error: direct.spawnError ?? "apple-bridge returned no output" };
76
+ }
77
+ /**
78
+ * Spawn apple-bridge in its own process group so we can SIGTERM the entire
79
+ * group on timeout. Required because Swift's Foundation.Process does not
80
+ * cascade signals to its child osascript processes — without this, a
81
+ * cancelled/timed-out mail search leaves osascript orphaned and Mail.app
82
+ * locked on Apple Events for as long as the script keeps iterating.
83
+ */
84
+ function runBridgeProcess(bin, args, timeoutMs) {
85
+ return new Promise((resolvePromise) => {
86
+ let child;
87
+ try {
88
+ child = spawn(bin, args, {
89
+ detached: true, // own process group; -pid kills the whole tree
90
+ stdio: ["ignore", "pipe", "pipe"],
91
+ });
92
+ }
93
+ catch (err) {
94
+ const msg = err instanceof Error ? err.message : "Failed to spawn apple-bridge";
95
+ resolvePromise({ status: "error", spawnError: msg });
96
+ return;
97
+ }
98
+ const pid = child.pid;
99
+ if (!pid) {
100
+ resolvePromise({ status: "error", spawnError: "apple-bridge spawn returned no pid" });
101
+ return;
102
+ }
103
+ const chunks = [];
104
+ const errChunks = [];
105
+ let totalBytes = 0;
106
+ const MAX_BYTES = 10 * 1024 * 1024;
107
+ let settled = false;
108
+ let timedOut = false;
109
+ const settle = (result) => {
110
+ if (settled)
111
+ return;
112
+ settled = true;
113
+ clearTimeout(timer);
114
+ clearTimeout(sigkillTimer);
115
+ resolvePromise(result);
116
+ };
117
+ const killGroup = (signal) => {
118
+ try {
119
+ process.kill(-pid, signal);
120
+ }
121
+ catch {
122
+ // Group may already be gone; nothing to do.
123
+ }
124
+ };
125
+ let sigkillTimer = setTimeout(() => { }, 0);
126
+ clearTimeout(sigkillTimer);
127
+ const timer = setTimeout(() => {
128
+ timedOut = true;
129
+ killGroup("SIGTERM");
130
+ sigkillTimer = setTimeout(() => killGroup("SIGKILL"), SIGKILL_GRACE_MS);
131
+ }, timeoutMs);
132
+ child.stdout?.on("data", (d) => {
133
+ totalBytes += d.length;
134
+ if (totalBytes > MAX_BYTES) {
135
+ killGroup("SIGTERM");
136
+ settle({
137
+ status: "error",
138
+ spawnError: `apple-bridge output exceeded ${MAX_BYTES} bytes`,
139
+ });
140
+ return;
141
+ }
142
+ chunks.push(d);
143
+ });
144
+ child.stderr?.on("data", (d) => {
145
+ errChunks.push(d);
146
+ });
147
+ child.on("error", (err) => {
148
+ settle({ status: "error", spawnError: err.message });
149
+ });
150
+ child.on("close", () => {
151
+ const stderr = Buffer.concat(errChunks).toString("utf8").trim();
152
+ if (stderr) {
153
+ console.error(`[apple-bridge stderr] ${stderr}`);
154
+ }
155
+ if (timedOut) {
156
+ settle({ status: "error", timedOut: true });
157
+ return;
158
+ }
159
+ const stdout = Buffer.concat(chunks).toString("utf8");
160
+ try {
161
+ const parsed = JSON.parse(stdout);
162
+ settle({ status: "ok", parsed });
163
+ }
164
+ catch (err) {
165
+ const msg = err instanceof Error ? err.message : "JSON parse failed";
166
+ settle({
167
+ status: "error",
168
+ spawnError: `apple-bridge returned invalid JSON: ${msg}`,
169
+ });
170
+ }
171
+ });
172
+ });
74
173
  }
75
174
  /**
76
175
  * Launch apple-bridge via .app bundle using `open`, with output written to
77
176
  * a temp file. Required on macOS Sequoia where CLI tools cannot obtain
78
177
  * TCC permissions (e.g. Reminders) without an .app bundle context.
79
178
  */
80
- async function callBridgeViaApp(args) {
179
+ async function callBridgeViaApp(args, timeoutMs) {
81
180
  const appPath = getAppBundlePath();
82
181
  const outputFile = resolve(tmpdir(), `apple-bridge-${randomUUID()}.json`);
83
182
  try {
@@ -99,9 +198,9 @@ async function callBridgeViaApp(args) {
99
198
  child.kill();
100
199
  resolvePromise({
101
200
  status: "error",
102
- error: "apple-bridge .app bundle timed out after 30s",
201
+ error: `apple-bridge .app bundle timed out after ${timeoutMs}ms`,
103
202
  });
104
- }, 30_000);
203
+ }, timeoutMs);
105
204
  child.on("close", async () => {
106
205
  clearTimeout(timeout);
107
206
  try {
@@ -130,8 +229,8 @@ async function callBridgeViaApp(args) {
130
229
  /**
131
230
  * Convenience: call bridge, check status, return data or throw.
132
231
  */
133
- export async function bridgeData(args) {
134
- const result = await callBridge(args);
232
+ export async function bridgeData(args, opts) {
233
+ const result = await callBridge(args, opts);
135
234
  if (result.status === "error") {
136
235
  throw new Error(result.error ?? "apple-bridge returned an error");
137
236
  }
@@ -1 +1 @@
1
- {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,11 @@
1
1
  import { z } from "zod";
2
2
  import { bridgeData } from "../bridge.js";
3
+ // Reason: Mail tools that iterate mailboxes via AppleScript can legitimately
4
+ // run for a minute or more on large accounts. The Swift bridge has a 90s
5
+ // osascript watchdog (Mail.swift `defaultAppleScriptTimeout`); the TS timeout
6
+ // must outlive that so the Swift watchdog reports a clean error instead of
7
+ // being cut off mid-execution by the TS-side process-group kill.
8
+ const MAIL_SCAN_TIMEOUT_MS = 120_000;
3
9
  export function registerMailTools(server) {
4
10
  server.tool("mail.list_accounts", "List all Apple Mail accounts with their mailboxes and unread counts. Requires Mail.app to be running.", {}, async () => {
5
11
  const data = await bridgeData(["mail-accounts"]);
@@ -20,12 +26,15 @@ export function registerMailTools(server) {
20
26
  if (limit) {
21
27
  args.push("--limit", String(limit));
22
28
  }
23
- const data = await bridgeData(args);
29
+ const data = await bridgeData(args, { timeoutMs: MAIL_SCAN_TIMEOUT_MS });
24
30
  return {
25
31
  content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
26
32
  };
27
33
  });
28
- server.tool("mail.search", "Search email messages by subject, sender, body, or all fields (default: all). Returns headers only (no body). Body search across all mailboxes may be slow on large accounts.", {
34
+ server.tool("mail.search", "Search email messages by subject, sender, body, or all fields (default: all). Returns headers only (no body). " +
35
+ "SCOPE RULE: body or all-fields search across mailbox='all' AND no specific account is REFUSED — it can lock " +
36
+ "Mail.app for minutes. Narrow the scope: pick a specific account, a specific mailbox, or set searchIn to " +
37
+ "'subject' or 'sender' before using mailbox='all'.", {
29
38
  query: z
30
39
  .string()
31
40
  .describe("Search term to match against message fields (controlled by searchIn)"),
@@ -36,11 +45,11 @@ export function registerMailTools(server) {
36
45
  mailbox: z
37
46
  .string()
38
47
  .optional()
39
- .describe("Mailbox to search in (default: inbox). Use 'all' to search all mailboxes."),
48
+ .describe("Mailbox to search in (default: inbox). Use 'all' to search all mailboxes (requires a specific account when searchIn includes body)."),
40
49
  searchIn: z
41
50
  .enum(["subject", "sender", "body", "all"])
42
51
  .optional()
43
- .describe("Fields to search: subject, sender, body, or all (default: all)"),
52
+ .describe("Fields to search: subject, sender, body, or all (default: all). Use 'subject' or 'sender' when searching across mailbox='all' without an account filter."),
44
53
  limit: z
45
54
  .number()
46
55
  .int()
@@ -71,7 +80,7 @@ export function registerMailTools(server) {
71
80
  if (offset !== undefined) {
72
81
  args.push("--offset", String(offset));
73
82
  }
74
- const data = await bridgeData(args);
83
+ const data = await bridgeData(args, { timeoutMs: MAIL_SCAN_TIMEOUT_MS });
75
84
  return {
76
85
  content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
77
86
  };
@@ -161,7 +170,7 @@ export function registerMailTools(server) {
161
170
  if (offset !== undefined) {
162
171
  args.push("--offset", String(offset));
163
172
  }
164
- const data = await bridgeData(args);
173
+ const data = await bridgeData(args, { timeoutMs: MAIL_SCAN_TIMEOUT_MS });
165
174
  return {
166
175
  content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
167
176
  };
@@ -1 +1 @@
1
- {"version":3,"file":"mail.js","sourceRoot":"","sources":["../../src/tools/mail.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mail.js","sourceRoot":"","sources":["../../src/tools/mail.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,6EAA6E;AAC7E,yEAAyE;AACzE,8EAA8E;AAC9E,2EAA2E;AAC3E,iEAAiE;AACjE,MAAM,oBAAoB,GAAG,OAAO,CAAC;AAErC,MAAM,UAAU,iBAAiB,CAAC,MAAiB;IACjD,MAAM,CAAC,IAAI,CACT,oBAAoB,EACpB,uGAAuG,EACvG,EAAE,EACF,KAAK,IAAI,EAAE;QACT,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC;QACjD,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;SACjE,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,qBAAqB,EACrB,qJAAqJ,EACrJ;QACE,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,GAAG,EAAE;aACL,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,GAAG,CAAC;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,mEAAmE,CACpE;KACJ,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;QAClB,MAAM,IAAI,GAAG,CAAC,aAAa,CAAC,CAAC;QAC7B,IAAI,KAAK,EAAE,CAAC;YACV,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACtC,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,oBAAoB,EAAE,CAAC,CAAC;QACzE,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;SACjE,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,aAAa,EACb,gHAAgH;QAC9G,8GAA8G;QAC9G,0GAA0G;QAC1G,mDAAmD,EACrD;QACE,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,QAAQ,CAAC,sEAAsE,CAAC;QACnF,OAAO,EAAE,CAAC;aACP,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,oCAAoC,CAAC;QACjD,OAAO,EAAE,CAAC;aACP,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,qIAAqI,CAAC;QAClJ,QAAQ,EAAE,CAAC;aACR,IAAI,CAAC,CAAC,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;aAC1C,QAAQ,EAAE;aACV,QAAQ,CAAC,0JAA0J,CAAC;QACvK,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,GAAG,EAAE;aACL,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,GAAG,CAAC;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,+CAA+C,CAAC;QAC5D,MAAM,EAAE,CAAC;aACN,MAAM,EAAE;aACR,GAAG,EAAE;aACL,GAAG,CAAC,CAAC,CAAC;aACN,QAAQ,EAAE;aACV,QAAQ,CACP,uIAAuI,CACxI;KACJ,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE;QAC7D,MAAM,IAAI,GAAG,CAAC,aAAa,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;QAC/C,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAClC,CAAC;QACD,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAClC,CAAC;QACD,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;QACrC,CAAC;QACD,IAAI,KAAK,EAAE,CAAC;YACV,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACtC,CAAC;QACD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;QACxC,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,oBAAoB,EAAE,CAAC,CAAC;QACzE,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;SACjE,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,mBAAmB,EACnB,gOAAgO,EAChO;QACE,SAAS,EAAE,CAAC;aACT,MAAM,EAAE;aACR,QAAQ,CAAC,8DAA8D,CAAC;QAC3E,aAAa,EAAE,CAAC;aACb,MAAM,EAAE;aACR,GAAG,EAAE;aACL,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,SAAS,CAAC;aACd,QAAQ,EAAE;aACV,QAAQ,CAAC,qFAAqF,CAAC;KACnG,EACD,KAAK,EAAE,EAAE,SAAS,EAAE,aAAa,EAAE,EAAE,EAAE;QACrC,MAAM,IAAI,GAAG,CAAC,cAAc,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;QACjD,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;YAChC,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC;QACxD,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;QACpC,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;SACjE,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,mBAAmB,EACnB,2HAA2H,EAC3H;QACE,EAAE,EAAE,CAAC;aACF,MAAM,EAAE;aACR,QAAQ,CAAC,0DAA0D,CAAC;QACvE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,oBAAoB,CAAC;QAClD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iBAAiB,CAAC;QAC5C,EAAE,EAAE,CAAC;aACF,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,mDAAmD,CAAC;QAChE,GAAG,EAAE,CAAC;aACH,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,oDAAoD,CAAC;QACjE,OAAO,EAAE,CAAC;aACP,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,kFAAkF,CACnF;KACJ,EACD,KAAK,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE;QAChD,MAAM,IAAI,GAAG;YACX,mBAAmB;YACnB,MAAM;YACN,EAAE;YACF,WAAW;YACX,OAAO;YACP,QAAQ;YACR,IAAI;SACL,CAAC;QACF,IAAI,EAAE,EAAE,CAAC;YACP,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACxB,CAAC;QACD,IAAI,GAAG,EAAE,CAAC;YACR,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QAC1B,CAAC;QACD,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAClC,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;QACpC,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;SACjE,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,cAAc,EACd,sHAAsH,EACtH;QACE,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,GAAG,EAAE;aACL,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,GAAG,CAAC;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,+CAA+C,CAAC;QAC5D,MAAM,EAAE,CAAC;aACN,MAAM,EAAE;aACR,GAAG,EAAE;aACL,GAAG,CAAC,CAAC,CAAC;aACN,QAAQ,EAAE;aACV,QAAQ,CACP,uIAAuI,CACxI;KACJ,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE;QAC1B,MAAM,IAAI,GAAG,CAAC,cAAc,CAAC,CAAC;QAC9B,IAAI,KAAK,EAAE,CAAC;YACV,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACtC,CAAC;QACD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;QACxC,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,oBAAoB,EAAE,CAAC,CAAC;QACzE,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;SACjE,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,sBAAsB,EACtB,6KAA6K,EAC7K;QACE,SAAS,EAAE,CAAC;aACT,MAAM,EAAE;aACR,QAAQ,CAAC,4DAA4D,CAAC;QACzE,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,GAAG,EAAE;aACL,GAAG,CAAC,CAAC,CAAC;aACN,QAAQ,CAAC,sEAAsE,CAAC;QACnF,IAAI,EAAE,CAAC;aACJ,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,0DAA0D,CAAC;KACxE,EACD,KAAK,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE;QACnC,MAAM,IAAI,GAAG;YACX,sBAAsB;YACtB,MAAM;YACN,SAAS;YACT,SAAS;YACT,MAAM,CAAC,KAAK,CAAC;SACd,CAAC;QACF,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAC5B,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;QACpC,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;SACjE,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@l22-io/orchard-mcp",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "MCP server for Apple Calendar, Mail, Reminders, and Files on macOS using native EventKit",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -20,7 +20,7 @@
20
20
  "scripts": {
21
21
  "build": "npm run build:swift && npm run build:ts",
22
22
  "build:ts": "tsc && chmod 755 build/index.js",
23
- "build:swift": "cd swift && swift build -c release -Xlinker -sectcreate -Xlinker __TEXT -Xlinker __info_plist -Xlinker Sources/AppleBridge/Info.plist",
23
+ "build:swift": "cd swift && swift build -c release -Xlinker -sectcreate -Xlinker __TEXT -Xlinker __info_plist -Xlinker Sources/AppleBridge/Info.plist && mkdir -p .build/AppleBridge.app/Contents/MacOS && cp .build/release/apple-bridge .build/AppleBridge.app/Contents/MacOS/apple-bridge && cp Sources/AppleBridge/Info.plist .build/AppleBridge.app/Contents/Info.plist && codesign --force --sign - .build/AppleBridge.app",
24
24
  "postinstall": "bash scripts/postinstall.sh",
25
25
  "prepublishOnly": "npm run build:ts && bash scripts/prepublish.sh",
26
26
  "dev": "tsc --watch",
@@ -1 +1 @@
1
- 20ea806633df5f1242e3c40daee70a03b1389ef6a03a6356a1751b1680b04433 apple-bridge
1
+ 853d524532c723fcd5c9f0c00a5895e3b384653a6d0b3e39c85e655bb4034602 apple-bridge
@@ -116,6 +116,23 @@ enum MailBridge {
116
116
 
117
117
  /// Search messages by subject, sender, body, or all fields across accounts.
118
118
  static func search(query: String, account: String?, mailbox: String?, limit: Int, searchIn: String, offset: Int?) {
119
+ // Refuse the catastrophic combination: body-content search across every
120
+ // mailbox of every account. AppleScript's `content contains` predicate
121
+ // forces Mail to load message bodies; iterating that across all
122
+ // mailboxes can lock Mail.app on Apple Event processing for many
123
+ // minutes (it cannot service quit / UI events while the script runs).
124
+ // See: orphaned osascript incident (PID 85905, ~11min before kill).
125
+ let searchesContent = (searchIn == "body" || searchIn == "all")
126
+ let allAccounts = (account == nil || account == "all")
127
+ let allMailboxes = (mailbox == "all")
128
+ if searchesContent && allAccounts && allMailboxes {
129
+ JSONOutput.error(
130
+ "Refusing body/all-fields search across every mailbox of every account — this can lock Mail.app for minutes. " +
131
+ "Narrow the scope: pass --account <name>, or pass --mailbox <name>, or pass --search-in subject (or --search-in sender)."
132
+ )
133
+ return
134
+ }
135
+
119
136
  let searchQuery = escapeForAppleScript(query)
120
137
  let effectiveOffset = offset ?? 0
121
138
  let whereClause: String
@@ -620,7 +637,14 @@ enum MailBridge {
620
637
 
621
638
  // MARK: - AppleScript Execution
622
639
 
623
- private static func runAppleScript(_ script: String) -> String? {
640
+ /// Default osascript timeout: long enough for legitimate per-account or
641
+ /// per-mailbox searches on large accounts, short enough that a hung
642
+ /// script returns control to the caller before Mail.app appears frozen
643
+ /// from the user's perspective. The scope guard in `search()` already
644
+ /// rejects the worst combinations; this is belt-and-braces.
645
+ private static let defaultAppleScriptTimeout: TimeInterval = 90
646
+
647
+ private static func runAppleScript(_ script: String, timeoutSeconds: TimeInterval = defaultAppleScriptTimeout) -> String? {
624
648
  let task = Process()
625
649
  task.executableURL = URL(fileURLWithPath: "/usr/bin/osascript")
626
650
  task.arguments = ["-e", script]
@@ -632,7 +656,33 @@ enum MailBridge {
632
656
 
633
657
  do {
634
658
  try task.run()
659
+
660
+ // Watchdog: terminate osascript if it exceeds the timeout. SIGTERM
661
+ // first so the script gets a chance to clean up; SIGKILL after a
662
+ // short grace period if it ignores SIGTERM (Apple Events held by
663
+ // Mail.app can keep an osascript subprocess unresponsive to TERM).
664
+ let pid = task.processIdentifier
665
+ let didTimeOut = TimeoutFlag()
666
+ let watchdog = DispatchWorkItem {
667
+ guard task.isRunning else { return }
668
+ didTimeOut.set()
669
+ task.terminate()
670
+ DispatchQueue.global().asyncAfter(deadline: .now() + 2) {
671
+ if task.isRunning { kill(pid, SIGKILL) }
672
+ }
673
+ }
674
+ DispatchQueue.global().asyncAfter(deadline: .now() + timeoutSeconds, execute: watchdog)
675
+
635
676
  task.waitUntilExit()
677
+ watchdog.cancel()
678
+
679
+ if didTimeOut.value {
680
+ JSONOutput.error(
681
+ "Mail AppleScript exceeded \(Int(timeoutSeconds))s timeout — killed to free Mail.app. " +
682
+ "Narrow the search scope (specific --account or --mailbox) or use --search-in subject."
683
+ )
684
+ return nil
685
+ }
636
686
 
637
687
  if task.terminationStatus != 0 {
638
688
  let errData = errPipe.fileHandleForReading.readDataToEndOfFile()
@@ -658,6 +708,16 @@ enum MailBridge {
658
708
  }
659
709
  }
660
710
 
711
+ /// Tiny actor-like flag so the watchdog closure can signal the main
712
+ /// thread that it fired, without racing with `task.terminationReason`
713
+ /// (which is only set after the kernel reaps the child).
714
+ private final class TimeoutFlag {
715
+ private let lock = NSLock()
716
+ private var fired = false
717
+ func set() { lock.lock(); fired = true; lock.unlock() }
718
+ var value: Bool { lock.lock(); defer { lock.unlock() }; return fired }
719
+ }
720
+
661
721
  private static func escapeForAppleScript(_ str: String) -> String {
662
722
  return str
663
723
  .replacingOccurrences(of: "\\", with: "\\\\")