@l22-io/orchard-mcp 0.3.2 → 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/README.md +11 -8
- package/build/bridge.d.ts +13 -2
- package/build/bridge.js +140 -23
- package/build/bridge.js.map +1 -1
- package/build/index.js +11 -1
- package/build/index.js.map +1 -1
- package/build/tools/contacts.d.ts +2 -0
- package/build/tools/contacts.js +37 -0
- package/build/tools/contacts.js.map +1 -0
- package/build/tools/files.js +4 -1
- package/build/tools/files.js.map +1 -1
- package/build/tools/keynote.d.ts +2 -0
- package/build/tools/keynote.js +198 -0
- package/build/tools/keynote.js.map +1 -0
- package/build/tools/mail.js +69 -13
- package/build/tools/mail.js.map +1 -1
- package/build/tools/notes.d.ts +2 -0
- package/build/tools/notes.js +83 -0
- package/build/tools/notes.js.map +1 -0
- package/build/tools/numbers.d.ts +2 -0
- package/build/tools/numbers.js +167 -0
- package/build/tools/numbers.js.map +1 -0
- package/build/tools/pages.d.ts +2 -0
- package/build/tools/pages.js +143 -0
- package/build/tools/pages.js.map +1 -0
- package/package.json +12 -9
- package/scripts/postinstall.sh +77 -8
- package/swift/.build/AppleBridge.app/Contents/MacOS/apple-bridge +0 -0
- package/swift/.build/AppleBridge.app.sha256 +1 -0
- package/swift/Package.resolved +14 -0
- package/swift/Package.swift +28 -0
- package/swift/Sources/AppleBridge/AppleBridge.swift +846 -0
- package/swift/Sources/AppleBridge/Calendar.swift +221 -0
- package/swift/Sources/AppleBridge/Contacts.swift +225 -0
- package/swift/Sources/AppleBridge/Doctor.swift +252 -0
- package/swift/Sources/AppleBridge/Files.swift +474 -0
- package/swift/Sources/AppleBridge/JSON.swift +57 -0
- package/swift/Sources/AppleBridge/Keynote.swift +599 -0
- package/swift/Sources/AppleBridge/Mail.swift +854 -0
- package/swift/Sources/AppleBridge/Notes.swift +263 -0
- package/swift/Sources/AppleBridge/Numbers.swift +601 -0
- package/swift/Sources/AppleBridge/Pages.swift +467 -0
- package/swift/Sources/AppleBridge/Reminders.swift +347 -0
package/README.md
CHANGED
|
@@ -46,7 +46,10 @@ npm install -g @l22-io/orchard-mcp
|
|
|
46
46
|
orchard-mcp setup
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
If Xcode Command Line Tools are installed (`xcode-select --install`), `postinstall` builds
|
|
50
|
+
`apple-bridge` from source — the strongest install-time guarantee. Otherwise the package
|
|
51
|
+
falls back to the shipped prebuilt universal binary (arm64 + x86_64) and verifies its
|
|
52
|
+
SHA-256 against the manifest published inside the tarball.
|
|
50
53
|
|
|
51
54
|
The setup wizard verifies prerequisites, triggers macOS permission prompts, and generates
|
|
52
55
|
MCP client configuration.
|
|
@@ -102,11 +105,11 @@ Add to your MCP settings:
|
|
|
102
105
|
|
|
103
106
|
### Mail
|
|
104
107
|
|
|
105
|
-
- `mail.list_accounts` -- List all mail accounts with mailboxes and unread counts
|
|
108
|
+
- `mail.list_accounts` -- List all mail accounts with mailboxes (including nested) and unread counts
|
|
106
109
|
- `mail.unread_summary` -- Unread count per account with recent message headers
|
|
107
|
-
- `mail.search` -- Search messages by subject
|
|
108
|
-
- `mail.read_message` -- Get
|
|
109
|
-
- `mail.flagged` -- List flagged messages across all accounts
|
|
110
|
+
- `mail.search` -- Search messages by subject, sender, body, or all fields. Supports cross-mailbox (`mailbox: "all"`) and cross-account (`account: "all"`) search with pagination
|
|
111
|
+
- `mail.read_message` -- Get message content by ID with configurable body truncation (default: 4000 chars)
|
|
112
|
+
- `mail.flagged` -- List flagged messages across all accounts with pagination
|
|
110
113
|
- `mail.create_draft` -- Create a draft email (opens compose window for review)
|
|
111
114
|
- `mail.save_attachment` -- Save an email attachment to disk by message ID and index
|
|
112
115
|
|
|
@@ -162,9 +165,9 @@ apple-bridge reminder-delete Delete a reminder (--id)
|
|
|
162
165
|
apple-bridge reminder-delete-list Delete a reminder list (--id, --force)
|
|
163
166
|
apple-bridge mail-accounts List mail accounts and mailboxes
|
|
164
167
|
apple-bridge mail-unread Unread summary per account (--limit)
|
|
165
|
-
apple-bridge mail-search Search messages (--query, --account, --mailbox, --limit)
|
|
166
|
-
apple-bridge mail-message Full message content (--id)
|
|
167
|
-
apple-bridge mail-flagged Flagged messages (--limit)
|
|
168
|
+
apple-bridge mail-search Search messages (--query, --account, --mailbox, --limit, --search-in, --offset)
|
|
169
|
+
apple-bridge mail-message Full message content (--id, --max-body-length)
|
|
170
|
+
apple-bridge mail-flagged Flagged messages (--limit, --offset)
|
|
168
171
|
apple-bridge mail-create-draft Create a draft email (--to, --subject, --body, --cc, --bcc, --account)
|
|
169
172
|
apple-bridge doctor Check permissions and accessible resources
|
|
170
173
|
```
|
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,18 +1,33 @@
|
|
|
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)
|
|
12
10
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
// Emit a one-time warning when binary path overrides are active: these env
|
|
12
|
+
// vars grant arbitrary executables the TCC permissions granted to apple-bridge.
|
|
13
|
+
let overrideWarned = false;
|
|
14
|
+
function warnOverrideOnce() {
|
|
15
|
+
if (overrideWarned)
|
|
16
|
+
return;
|
|
17
|
+
overrideWarned = true;
|
|
18
|
+
if (process.env.APPLE_BRIDGE_BIN) {
|
|
19
|
+
console.error(`[orchard-mcp] WARNING: APPLE_BRIDGE_BIN override active ("${process.env.APPLE_BRIDGE_BIN}"). ` +
|
|
20
|
+
`This binary inherits all granted TCC permissions — ensure the path is trusted.`);
|
|
21
|
+
}
|
|
22
|
+
if (process.env.APPLE_BRIDGE_APP) {
|
|
23
|
+
console.error(`[orchard-mcp] WARNING: APPLE_BRIDGE_APP override active ("${process.env.APPLE_BRIDGE_APP}"). ` +
|
|
24
|
+
`This .app bundle inherits all granted TCC permissions — ensure the path is trusted.`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
13
27
|
function getBridgePath() {
|
|
14
28
|
// Reason: Allow override via env var for custom installations.
|
|
15
29
|
if (process.env.APPLE_BRIDGE_BIN) {
|
|
30
|
+
warnOverrideOnce();
|
|
16
31
|
return process.env.APPLE_BRIDGE_BIN;
|
|
17
32
|
}
|
|
18
33
|
// Default: use the binary inside the .app bundle (one level up from build/)
|
|
@@ -20,46 +35,148 @@ function getBridgePath() {
|
|
|
20
35
|
}
|
|
21
36
|
function getAppBundlePath() {
|
|
22
37
|
if (process.env.APPLE_BRIDGE_APP) {
|
|
38
|
+
warnOverrideOnce();
|
|
23
39
|
return process.env.APPLE_BRIDGE_APP;
|
|
24
40
|
}
|
|
25
41
|
return resolve(__dirname, "..", "swift", ".build", "AppleBridge.app");
|
|
26
42
|
}
|
|
43
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
44
|
+
const SIGKILL_GRACE_MS = 2_000;
|
|
27
45
|
/**
|
|
28
46
|
* Execute an apple-bridge subcommand and return parsed JSON.
|
|
29
47
|
* Tries direct execution first; falls back to .app bundle mode
|
|
30
48
|
* (via `open`) when direct execution returns a permission error.
|
|
31
49
|
*/
|
|
32
|
-
export async function callBridge(args) {
|
|
50
|
+
export async function callBridge(args, opts = {}) {
|
|
33
51
|
const bin = getBridgePath();
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if (stderr) {
|
|
40
|
-
// Reason: stderr is used for Swift warnings/diagnostics, log but don't fail.
|
|
41
|
-
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 };
|
|
42
57
|
}
|
|
43
|
-
|
|
58
|
+
if (direct.timedOut) {
|
|
59
|
+
return {
|
|
60
|
+
status: "error",
|
|
61
|
+
error: `apple-bridge timed out after ${timeoutMs}ms`,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (direct.parsed) {
|
|
66
|
+
const parsed = direct.parsed;
|
|
44
67
|
// If the command returned a permission error, retry via .app bundle
|
|
45
68
|
if (parsed.status === "error" &&
|
|
46
69
|
typeof parsed.error === "string" &&
|
|
47
70
|
parsed.error.includes("access denied")) {
|
|
48
|
-
return callBridgeViaApp(args);
|
|
71
|
+
return callBridgeViaApp(args, timeoutMs);
|
|
49
72
|
}
|
|
50
73
|
return parsed;
|
|
51
74
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
+
});
|
|
56
173
|
}
|
|
57
174
|
/**
|
|
58
175
|
* Launch apple-bridge via .app bundle using `open`, with output written to
|
|
59
176
|
* a temp file. Required on macOS Sequoia where CLI tools cannot obtain
|
|
60
177
|
* TCC permissions (e.g. Reminders) without an .app bundle context.
|
|
61
178
|
*/
|
|
62
|
-
async function callBridgeViaApp(args) {
|
|
179
|
+
async function callBridgeViaApp(args, timeoutMs) {
|
|
63
180
|
const appPath = getAppBundlePath();
|
|
64
181
|
const outputFile = resolve(tmpdir(), `apple-bridge-${randomUUID()}.json`);
|
|
65
182
|
try {
|
|
@@ -81,9 +198,9 @@ async function callBridgeViaApp(args) {
|
|
|
81
198
|
child.kill();
|
|
82
199
|
resolvePromise({
|
|
83
200
|
status: "error",
|
|
84
|
-
error:
|
|
201
|
+
error: `apple-bridge .app bundle timed out after ${timeoutMs}ms`,
|
|
85
202
|
});
|
|
86
|
-
},
|
|
203
|
+
}, timeoutMs);
|
|
87
204
|
child.on("close", async () => {
|
|
88
205
|
clearTimeout(timeout);
|
|
89
206
|
try {
|
|
@@ -112,8 +229,8 @@ async function callBridgeViaApp(args) {
|
|
|
112
229
|
/**
|
|
113
230
|
* Convenience: call bridge, check status, return data or throw.
|
|
114
231
|
*/
|
|
115
|
-
export async function bridgeData(args) {
|
|
116
|
-
const result = await callBridge(args);
|
|
232
|
+
export async function bridgeData(args, opts) {
|
|
233
|
+
const result = await callBridge(args, opts);
|
|
117
234
|
if (result.status === "error") {
|
|
118
235
|
throw new Error(result.error ?? "apple-bridge returned an error");
|
|
119
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":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,0EAA0E;AAC1E,oDAAoD;AACpD,wEAAwE;AACxE,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE1D,2EAA2E;AAC3E,gFAAgF;AAChF,IAAI,cAAc,GAAG,KAAK,CAAC;AAC3B,SAAS,gBAAgB;IACvB,IAAI,cAAc;QAAE,OAAO;IAC3B,cAAc,GAAG,IAAI,CAAC;IACtB,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QACjC,OAAO,CAAC,KAAK,CACX,6DAA6D,OAAO,CAAC,GAAG,CAAC,gBAAgB,MAAM;YAC/F,gFAAgF,CACjF,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QACjC,OAAO,CAAC,KAAK,CACX,6DAA6D,OAAO,CAAC,GAAG,CAAC,gBAAgB,MAAM;YAC/F,qFAAqF,CACtF,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,aAAa;IACpB,+DAA+D;IAC/D,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QACjC,gBAAgB,EAAE,CAAC;QACnB,OAAO,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IACtC,CAAC;IACD,4EAA4E;IAC5E,OAAO,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,UAAU,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC;AAC7G,CAAC;AAED,SAAS,gBAAgB;IACvB,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QACjC,gBAAgB,EAAE,CAAC;QACnB,OAAO,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IACtC,CAAC;IACD,OAAO,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,iBAAiB,CAAC,CAAC;AACxE,CAAC;AAoBD,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAClC,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAE/B;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,IAAc,EACd,OAAsB,EAAE;IAExB,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;IAC5B,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,kBAAkB,CAAC;IACvD,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,GAAG,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;IAE5D,IAAI,MAAM,CAAC,MAAM,KAAK,OAAO,IAAI,MAAM,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC;QACvD,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;YACtB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC;QACvD,CAAC;QACD,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;YACpB,OAAO;gBACL,MAAM,EAAE,OAAO;gBACf,KAAK,EAAE,gCAAgC,SAAS,IAAI;aACrD,CAAC;QACJ,CAAC;IACH,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAC7B,oEAAoE;QACpE,IACE,MAAM,CAAC,MAAM,KAAK,OAAO;YACzB,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ;YAChC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,eAAe,CAAC,EACtC,CAAC;YACD,OAAO,gBAAgB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QAC3C,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,UAAU,IAAI,iCAAiC,EAAE,CAAC;AAC5F,CAAC;AASD;;;;;;GAMG;AACH,SAAS,gBAAgB,CACvB,GAAW,EACX,IAAc,EACd,SAAiB;IAEjB,OAAO,IAAI,OAAO,CAAC,CAAC,cAAc,EAAE,EAAE;QACpC,IAAI,KAAK,CAAC;QACV,IAAI,CAAC;YACH,KAAK,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE;gBACvB,QAAQ,EAAE,IAAI,EAAE,+CAA+C;gBAC/D,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;aAClC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,8BAA8B,CAAC;YAChF,cAAc,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC;YACrD,OAAO;QACT,CAAC;QAED,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC;QACtB,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,cAAc,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,oCAAoC,EAAE,CAAC,CAAC;YACtF,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,MAAM,SAAS,GAAa,EAAE,CAAC;QAC/B,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,MAAM,SAAS,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;QACnC,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,IAAI,QAAQ,GAAG,KAAK,CAAC;QAErB,MAAM,MAAM,GAAG,CAAC,MAAoB,EAAE,EAAE;YACtC,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,YAAY,CAAC,YAAY,CAAC,CAAC;YAC3B,cAAc,CAAC,MAAM,CAAC,CAAC;QACzB,CAAC,CAAC;QAEF,MAAM,SAAS,GAAG,CAAC,MAAsB,EAAE,EAAE;YAC3C,IAAI,CAAC;gBACH,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YAC7B,CAAC;YAAC,MAAM,CAAC;gBACP,4CAA4C;YAC9C,CAAC;QACH,CAAC,CAAC;QAEF,IAAI,YAAY,GAAmB,UAAU,CAAC,GAAG,EAAE,GAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAC3D,YAAY,CAAC,YAAY,CAAC,CAAC;QAE3B,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,QAAQ,GAAG,IAAI,CAAC;YAChB,SAAS,CAAC,SAAS,CAAC,CAAC;YACrB,YAAY,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,gBAAgB,CAAC,CAAC;QAC1E,CAAC,EAAE,SAAS,CAAC,CAAC;QAEd,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,CAAS,EAAE,EAAE;YACrC,UAAU,IAAI,CAAC,CAAC,MAAM,CAAC;YACvB,IAAI,UAAU,GAAG,SAAS,EAAE,CAAC;gBAC3B,SAAS,CAAC,SAAS,CAAC,CAAC;gBACrB,MAAM,CAAC;oBACL,MAAM,EAAE,OAAO;oBACf,UAAU,EAAE,gCAAgC,SAAS,QAAQ;iBAC9D,CAAC,CAAC;gBACH,OAAO;YACT,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjB,CAAC,CAAC,CAAC;QAEH,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,CAAS,EAAE,EAAE;YACrC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC,CAAC,CAAC;QAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACxB,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QACvD,CAAC,CAAC,CAAC;QAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACrB,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;YAChE,IAAI,MAAM,EAAE,CAAC;gBACX,OAAO,CAAC,KAAK,CAAC,yBAAyB,MAAM,EAAE,CAAC,CAAC;YACnD,CAAC;YACD,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC5C,OAAO;YACT,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YACtD,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAmB,CAAC;gBACpD,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;YACnC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC;gBACrE,MAAM,CAAC;oBACL,MAAM,EAAE,OAAO;oBACf,UAAU,EAAE,uCAAuC,GAAG,EAAE;iBACzD,CAAC,CAAC;YACL,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,gBAAgB,CAC7B,IAAc,EACd,SAAiB;IAEjB,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC;IACnC,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,gBAAgB,UAAU,EAAE,OAAO,CAAC,CAAC;IAE1E,IAAI,CAAC;QACH,4BAA4B;QAC5B,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,MAAM,EAAE,OAAO;YACf,KAAK,EAAE,gCAAgC,OAAO,mEAAmE;SAClH,CAAC;IACJ,CAAC;IAED,OAAO,IAAI,OAAO,CAAC,CAAC,cAAc,EAAE,EAAE;QACpC,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE;YAC1B,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO;YACzB,QAAQ,EAAE,GAAG,IAAI,EAAE,UAAU,EAAE,UAAU;SAC1C,CAAC,CAAC;QAEH,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YAC9B,KAAK,CAAC,IAAI,EAAE,CAAC;YACb,cAAc,CAAC;gBACb,MAAM,EAAE,OAAO;gBACf,KAAK,EAAE,4CAA4C,SAAS,IAAI;aACjE,CAAC,CAAC;QACL,CAAC,EAAE,SAAS,CAAC,CAAC;QAEd,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE;YAC3B,YAAY,CAAC,OAAO,CAAC,CAAC;YACtB,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;gBACjD,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;gBACzC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAmB,CAAC;gBAClD,cAAc,CAAC,MAAM,CAAC,CAAC;YACzB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;gBACzC,MAAM,GAAG,GACP,GAAG,YAAY,KAAK;oBAClB,CAAC,CAAC,GAAG,CAAC,OAAO;oBACb,CAAC,CAAC,mCAAmC,CAAC;gBAC1C,cAAc,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;YAClD,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACxB,YAAY,CAAC,OAAO,CAAC,CAAC;YACtB,cAAc,CAAC;gBACb,MAAM,EAAE,OAAO;gBACf,KAAK,EAAE,iCAAiC,GAAG,CAAC,OAAO,EAAE;aACtD,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,IAAc,EACd,IAAoB;IAEpB,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5C,IAAI,MAAM,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,gCAAgC,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC"}
|
package/build/index.js
CHANGED
|
@@ -12,15 +12,25 @@ import { registerMailTools } from "./tools/mail.js";
|
|
|
12
12
|
import { registerReminderTools } from "./tools/reminders.js";
|
|
13
13
|
import { registerSystemTools } from "./tools/system.js";
|
|
14
14
|
import { registerFileTools } from "./tools/files.js";
|
|
15
|
+
import { registerNumbersTools } from "./tools/numbers.js";
|
|
16
|
+
import { registerPagesTools } from "./tools/pages.js";
|
|
17
|
+
import { registerKeynoteTools } from "./tools/keynote.js";
|
|
18
|
+
import { registerNotesTools } from "./tools/notes.js";
|
|
19
|
+
import { registerContactsTools } from "./tools/contacts.js";
|
|
15
20
|
const server = new McpServer({
|
|
16
21
|
name: "orchard-mcp",
|
|
17
|
-
version: "0.
|
|
22
|
+
version: "0.5.0",
|
|
18
23
|
});
|
|
19
24
|
registerCalendarTools(server);
|
|
20
25
|
registerMailTools(server);
|
|
21
26
|
registerReminderTools(server);
|
|
22
27
|
registerSystemTools(server);
|
|
23
28
|
registerFileTools(server);
|
|
29
|
+
registerNumbersTools(server);
|
|
30
|
+
registerPagesTools(server);
|
|
31
|
+
registerKeynoteTools(server);
|
|
32
|
+
registerNotesTools(server);
|
|
33
|
+
registerContactsTools(server);
|
|
24
34
|
const transport = new StdioServerTransport();
|
|
25
35
|
await server.connect(transport);
|
|
26
36
|
// Reason: stderr only -- stdout is reserved for JSON-RPC in stdio transport.
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,oEAAoE;AACpE,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,OAAO,EAAE,CAAC;IAChC,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;IAChD,MAAM,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAC;IAC3D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,oEAAoE;AACpE,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,OAAO,EAAE,CAAC;IAChC,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;IAChD,MAAM,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAC;IAC3D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,aAAa;IACnB,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,qBAAqB,CAAC,MAAM,CAAC,CAAC;AAC9B,iBAAiB,CAAC,MAAM,CAAC,CAAC;AAC1B,qBAAqB,CAAC,MAAM,CAAC,CAAC;AAC9B,mBAAmB,CAAC,MAAM,CAAC,CAAC;AAC5B,iBAAiB,CAAC,MAAM,CAAC,CAAC;AAC1B,oBAAoB,CAAC,MAAM,CAAC,CAAC;AAC7B,kBAAkB,CAAC,MAAM,CAAC,CAAC;AAC3B,oBAAoB,CAAC,MAAM,CAAC,CAAC;AAC7B,kBAAkB,CAAC,MAAM,CAAC,CAAC;AAC3B,qBAAqB,CAAC,MAAM,CAAC,CAAC;AAE9B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAEhC,6EAA6E;AAC7E,OAAO,CAAC,KAAK,CAAC,mDAAmD,CAAC,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { bridgeData } from "../bridge.js";
|
|
3
|
+
export function registerContactsTools(server) {
|
|
4
|
+
server.tool("contacts.list_groups", "List all contact groups with member counts. Requires Contacts access.", {}, async () => {
|
|
5
|
+
const data = await bridgeData(["contacts-groups"]);
|
|
6
|
+
return {
|
|
7
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
8
|
+
};
|
|
9
|
+
});
|
|
10
|
+
server.tool("contacts.search", "Search contacts by name, email, or phone number. Phone queries (starting with + or a digit) match full numbers via the Contacts framework predicate and partial numbers via a digits-only substring scan — spaces, dashes, and parentheses are ignored in the comparison. Email queries should contain @. Returns summaries; use contacts.read_contact for full details.", {
|
|
11
|
+
query: z.string().describe("Name, email, or phone query"),
|
|
12
|
+
limit: z
|
|
13
|
+
.number()
|
|
14
|
+
.int()
|
|
15
|
+
.min(1)
|
|
16
|
+
.max(200)
|
|
17
|
+
.optional()
|
|
18
|
+
.describe("Max results (default: 20, max: 200)"),
|
|
19
|
+
}, async ({ query, limit }) => {
|
|
20
|
+
const args = ["contacts-search", "--query", query];
|
|
21
|
+
if (limit)
|
|
22
|
+
args.push("--limit", String(limit));
|
|
23
|
+
const data = await bridgeData(args);
|
|
24
|
+
return {
|
|
25
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
server.tool("contacts.read_contact", "Read full details for a contact by ID (from contacts.search). Includes emails, phones, postal addresses, URLs, birthday, and job info. Note: the 'notes' field on contacts requires a restricted Apple entitlement and is not returned.", {
|
|
29
|
+
id: z.string().describe("Contact identifier"),
|
|
30
|
+
}, async ({ id }) => {
|
|
31
|
+
const data = await bridgeData(["contacts-read", "--id", id]);
|
|
32
|
+
return {
|
|
33
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
34
|
+
};
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=contacts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contacts.js","sourceRoot":"","sources":["../../src/tools/contacts.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,UAAU,qBAAqB,CAAC,MAAiB;IACrD,MAAM,CAAC,IAAI,CACT,sBAAsB,EACtB,uEAAuE,EACvE,EAAE,EACF,KAAK,IAAI,EAAE;QACT,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC;QACnD,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,iBAAiB,EACjB,0WAA0W,EAC1W;QACE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,6BAA6B,CAAC;QACzD,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,qCAAqC,CAAC;KACnD,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;QACzB,MAAM,IAAI,GAAG,CAAC,iBAAiB,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;QACnD,IAAI,KAAK;YAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC/C,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,uBAAuB,EACvB,yOAAyO,EACzO;QACE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,oBAAoB,CAAC;KAC9C,EACD,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE;QACf,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,CAAC,eAAe,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;QAC7D,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/build/tools/files.js
CHANGED
|
@@ -12,8 +12,11 @@ export function registerFileTools(server) {
|
|
|
12
12
|
.describe("List recursively (default: false)"),
|
|
13
13
|
depth: z
|
|
14
14
|
.number()
|
|
15
|
+
.int()
|
|
16
|
+
.min(1)
|
|
17
|
+
.max(10)
|
|
15
18
|
.optional()
|
|
16
|
-
.describe("Max recursion depth when recursive (default: 3)"),
|
|
19
|
+
.describe("Max recursion depth when recursive (default: 3, max: 10)"),
|
|
17
20
|
}, async ({ path, recursive, depth }) => {
|
|
18
21
|
const args = ["file-list"];
|
|
19
22
|
if (path)
|
package/build/tools/files.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/tools/files.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,YAAY,EACZ,oGAAoG,EACpG;QACE,IAAI,EAAE,CAAC;aACJ,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,wDAAwD,CAAC;QACrE,SAAS,EAAE,CAAC;aACT,OAAO,EAAE;aACT,QAAQ,EAAE;aACV,QAAQ,CAAC,mCAAmC,CAAC;QAChD,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/tools/files.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { bridgeData } from "../bridge.js";
|
|
3
|
+
export function registerKeynoteTools(server) {
|
|
4
|
+
server.tool("keynote.search", "Search for Keynote presentation files by name.", {
|
|
5
|
+
query: z.string().max(500).describe("Search term to match against file names"),
|
|
6
|
+
limit: z
|
|
7
|
+
.number()
|
|
8
|
+
.int()
|
|
9
|
+
.min(1)
|
|
10
|
+
.max(100)
|
|
11
|
+
.optional()
|
|
12
|
+
.describe("Maximum number of results to return"),
|
|
13
|
+
}, async ({ query, limit }) => {
|
|
14
|
+
const args = ["keynote-search", "--query", query];
|
|
15
|
+
if (limit !== undefined) {
|
|
16
|
+
args.push("--limit", String(limit));
|
|
17
|
+
}
|
|
18
|
+
const data = await bridgeData(args);
|
|
19
|
+
return {
|
|
20
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
21
|
+
};
|
|
22
|
+
});
|
|
23
|
+
server.tool("keynote.read", "Read slide content from a Keynote presentation (title, body, notes, layout, skipped status).", {
|
|
24
|
+
file: z.string().max(1024).describe("Path to the Keynote file"),
|
|
25
|
+
slide: z
|
|
26
|
+
.number()
|
|
27
|
+
.int()
|
|
28
|
+
.min(1)
|
|
29
|
+
.optional()
|
|
30
|
+
.describe("Slide index to read (1-based). Omit to read all slides."),
|
|
31
|
+
}, async ({ file, slide }) => {
|
|
32
|
+
const args = ["keynote-read", "--file", file];
|
|
33
|
+
if (slide !== undefined) {
|
|
34
|
+
args.push("--slide", String(slide));
|
|
35
|
+
}
|
|
36
|
+
const data = await bridgeData(args);
|
|
37
|
+
return {
|
|
38
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
server.tool("keynote.create", "Create a new Keynote presentation. Optionally specify a theme.", {
|
|
42
|
+
file: z.string().max(1024).describe("Path for the new Keynote file"),
|
|
43
|
+
theme: z
|
|
44
|
+
.string()
|
|
45
|
+
.max(10_000)
|
|
46
|
+
.optional()
|
|
47
|
+
.describe("Theme name to use for the presentation"),
|
|
48
|
+
}, async ({ file, theme }) => {
|
|
49
|
+
const args = ["keynote-create", "--file", file];
|
|
50
|
+
if (theme)
|
|
51
|
+
args.push("--theme", theme);
|
|
52
|
+
const data = await bridgeData(args);
|
|
53
|
+
return {
|
|
54
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
server.tool("keynote.add_slide", "Add a new slide to a Keynote presentation with optional layout, title, body, notes, and position.", {
|
|
58
|
+
file: z.string().max(1024).describe("Path to the Keynote file"),
|
|
59
|
+
layout: z
|
|
60
|
+
.string()
|
|
61
|
+
.max(10_000)
|
|
62
|
+
.optional()
|
|
63
|
+
.describe("Slide layout name (from the theme)"),
|
|
64
|
+
title: z.string().max(10_000).optional().describe("Slide title text"),
|
|
65
|
+
body: z.string().max(10_000).optional().describe("Slide body text"),
|
|
66
|
+
notes: z.string().max(10_000).optional().describe("Presenter notes"),
|
|
67
|
+
position: z
|
|
68
|
+
.number()
|
|
69
|
+
.int()
|
|
70
|
+
.min(1)
|
|
71
|
+
.optional()
|
|
72
|
+
.describe("Insert after this slide index (1-based). Omit to add at end."),
|
|
73
|
+
}, async ({ file, layout, title, body, notes, position }) => {
|
|
74
|
+
const args = ["keynote-add-slide", "--file", file];
|
|
75
|
+
if (layout)
|
|
76
|
+
args.push("--layout", layout);
|
|
77
|
+
if (title)
|
|
78
|
+
args.push("--title", title);
|
|
79
|
+
if (body)
|
|
80
|
+
args.push("--body", body);
|
|
81
|
+
if (notes)
|
|
82
|
+
args.push("--notes", notes);
|
|
83
|
+
if (position !== undefined)
|
|
84
|
+
args.push("--position", String(position));
|
|
85
|
+
const data = await bridgeData(args);
|
|
86
|
+
return {
|
|
87
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
88
|
+
};
|
|
89
|
+
});
|
|
90
|
+
server.tool("keynote.edit_slide", "Edit an existing slide's title, body, or presenter notes.", {
|
|
91
|
+
file: z.string().max(1024).describe("Path to the Keynote file"),
|
|
92
|
+
slide: z.number().int().min(1).describe("Slide index to edit (1-based)"),
|
|
93
|
+
title: z.string().max(10_000).optional().describe("New title text"),
|
|
94
|
+
body: z.string().max(10_000).optional().describe("New body text"),
|
|
95
|
+
notes: z.string().max(10_000).optional().describe("New presenter notes"),
|
|
96
|
+
}, async ({ file, slide, title, body, notes }) => {
|
|
97
|
+
const args = [
|
|
98
|
+
"keynote-edit-slide",
|
|
99
|
+
"--file",
|
|
100
|
+
file,
|
|
101
|
+
"--slide",
|
|
102
|
+
String(slide),
|
|
103
|
+
];
|
|
104
|
+
if (title)
|
|
105
|
+
args.push("--title", title);
|
|
106
|
+
if (body)
|
|
107
|
+
args.push("--body", body);
|
|
108
|
+
if (notes)
|
|
109
|
+
args.push("--notes", notes);
|
|
110
|
+
const data = await bridgeData(args);
|
|
111
|
+
return {
|
|
112
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
113
|
+
};
|
|
114
|
+
});
|
|
115
|
+
server.tool("keynote.remove_slide", "Delete a slide from a Keynote presentation.", {
|
|
116
|
+
file: z.string().max(1024).describe("Path to the Keynote file"),
|
|
117
|
+
slide: z.number().int().min(1).describe("Slide index to remove (1-based)"),
|
|
118
|
+
}, async ({ file, slide }) => {
|
|
119
|
+
const data = await bridgeData([
|
|
120
|
+
"keynote-remove-slide",
|
|
121
|
+
"--file",
|
|
122
|
+
file,
|
|
123
|
+
"--slide",
|
|
124
|
+
String(slide),
|
|
125
|
+
]);
|
|
126
|
+
return {
|
|
127
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
128
|
+
};
|
|
129
|
+
});
|
|
130
|
+
server.tool("keynote.reorder_slides", "Move a slide from one position to another in a Keynote presentation.", {
|
|
131
|
+
file: z.string().max(1024).describe("Path to the Keynote file"),
|
|
132
|
+
from: z.number().int().min(1).describe("Current slide index (1-based)"),
|
|
133
|
+
to: z.number().int().min(1).describe("Target slide index (1-based)"),
|
|
134
|
+
}, async ({ file, from, to }) => {
|
|
135
|
+
const data = await bridgeData([
|
|
136
|
+
"keynote-reorder-slides",
|
|
137
|
+
"--file",
|
|
138
|
+
file,
|
|
139
|
+
"--from",
|
|
140
|
+
String(from),
|
|
141
|
+
"--to",
|
|
142
|
+
String(to),
|
|
143
|
+
]);
|
|
144
|
+
return {
|
|
145
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
146
|
+
};
|
|
147
|
+
});
|
|
148
|
+
server.tool("keynote.list_slides", "List all slides in a Keynote presentation with their content and metadata.", {
|
|
149
|
+
file: z.string().max(1024).describe("Path to the Keynote file"),
|
|
150
|
+
}, async ({ file }) => {
|
|
151
|
+
const data = await bridgeData(["keynote-list-slides", "--file", file]);
|
|
152
|
+
return {
|
|
153
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
154
|
+
};
|
|
155
|
+
});
|
|
156
|
+
server.tool("keynote.list_themes", "List all available Keynote themes.", {}, async () => {
|
|
157
|
+
const data = await bridgeData(["keynote-list-themes"]);
|
|
158
|
+
return {
|
|
159
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
160
|
+
};
|
|
161
|
+
});
|
|
162
|
+
server.tool("keynote.export", "Export a Keynote presentation to PDF, PowerPoint, PNG, or JPEG.", {
|
|
163
|
+
file: z.string().max(1024).describe("Path to the Keynote file"),
|
|
164
|
+
format: z
|
|
165
|
+
.enum(["pdf", "pptx", "png", "jpeg"])
|
|
166
|
+
.describe("Export format: pdf, pptx, png, or jpeg"),
|
|
167
|
+
dest: z
|
|
168
|
+
.string()
|
|
169
|
+
.max(1024)
|
|
170
|
+
.optional()
|
|
171
|
+
.describe("Output file or directory path (defaults to same directory as input)"),
|
|
172
|
+
slide: z
|
|
173
|
+
.number()
|
|
174
|
+
.int()
|
|
175
|
+
.min(1)
|
|
176
|
+
.optional()
|
|
177
|
+
.describe("Export only this slide index (1-based, for image formats)"),
|
|
178
|
+
}, async ({ file, format, dest, slide }) => {
|
|
179
|
+
const args = ["keynote-export", "--file", file, "--format", format];
|
|
180
|
+
if (dest)
|
|
181
|
+
args.push("--dest", dest);
|
|
182
|
+
if (slide !== undefined)
|
|
183
|
+
args.push("--slide", String(slide));
|
|
184
|
+
const data = await bridgeData(args);
|
|
185
|
+
return {
|
|
186
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
187
|
+
};
|
|
188
|
+
});
|
|
189
|
+
server.tool("keynote.info", "Get metadata about a Keynote presentation (name, slide count, theme).", {
|
|
190
|
+
file: z.string().max(1024).describe("Path to the Keynote file"),
|
|
191
|
+
}, async ({ file }) => {
|
|
192
|
+
const data = await bridgeData(["keynote-info", "--file", file]);
|
|
193
|
+
return {
|
|
194
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
195
|
+
};
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=keynote.js.map
|