@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 +13 -2
- package/build/bridge.js +122 -23
- package/build/bridge.js.map +1 -1
- package/build/tools/mail.js +15 -6
- package/build/tools/mail.js.map +1 -1
- package/package.json +2 -2
- package/swift/.build/AppleBridge.app/Contents/MacOS/apple-bridge +0 -0
- package/swift/.build/AppleBridge.app.sha256 +1 -1
- package/swift/Sources/AppleBridge/Mail.swift +61 -1
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 {
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
-
|
|
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
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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:
|
|
201
|
+
error: `apple-bridge .app bundle timed out after ${timeoutMs}ms`,
|
|
103
202
|
});
|
|
104
|
-
},
|
|
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
|
}
|
package/build/bridge.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bridge.js","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"bridge.js","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"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"}
|
package/build/tools/mail.js
CHANGED
|
@@ -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).
|
|
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
|
};
|
package/build/tools/mail.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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,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,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"mail.js","sourceRoot":"","sources":["../../src/tools/mail.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@l22-io/orchard-mcp",
|
|
3
|
-
"version": "0.6.
|
|
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",
|
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
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
|
-
|
|
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: "\\\\")
|