@thenavidm/apple-photos-mcp-cli 1.0.3 → 1.1.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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 Navid Moazzez
3
+ Copyright (c) 2026 NM Media
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -3,17 +3,16 @@
3
3
  # Apple Photos MCP + CLI
4
4
 
5
5
  [![npm](https://img.shields.io/npm/v/@thenavidm/apple-photos-mcp-cli?color=orange&label=npm)](https://www.npmjs.com/package/@thenavidm/apple-photos-mcp-cli)
6
- [![Stars](https://img.shields.io/github/stars/navidmoazzez/apple-photos-mcp-cli?style=flat&logo=github&label=Stars)](https://github.com/navidmoazzez/apple-photos-mcp-cli)
7
- [![License](https://img.shields.io/badge/License-MIT-blue)](./LICENSE)
6
+ [![License](https://img.shields.io/badge/licence-MIT-green)](./LICENSE)
8
7
  [![YouTube](https://img.shields.io/badge/YouTube-@thenavidm-red?logo=youtube&logoColor=white)](https://youtube.com/@thenavidm?sub_confirmation=1)
9
8
  [![X](https://img.shields.io/badge/X-@thenavidm-black?logo=x)](https://x.com/thenavidm)
10
9
  [![LinkedIn](https://img.shields.io/badge/LinkedIn-thenavidm-0A66C2?logo=linkedin&logoColor=white)](https://linkedin.com/in/thenavidm)
11
10
 
12
- Apple Photos MCP server and CLI for Claude Code and AI agents. 13 tools to search, look at, organise and export your own library, entirely on your Mac.
11
+ Apple Photos MCP server and CLI for Claude Code, Codex and AI agents. 13 tools to search, look at, organise and export your own library, entirely on your Mac.
13
12
 
14
13
  Give any AI agent real access to your own Apple Photos library, so it can find, see, organise and export your photos instead of guessing.
15
14
 
16
- Built and maintained by [Navid Moazzez](https://navid.me?utm_source=github&utm_medium=readme&utm_campaign=apple-photos-mcp).
15
+ Built and maintained by [Navid Moazzez](https://navid.me?utm_source=github&utm_medium=referral&utm_campaign=apple-photos-mcp-cli&utm_content=readme).
17
16
 
18
17
  <img src="https://cdn.navid.media/repos/apple-photos-mcp.gif?v=1" alt="Claude Code using the Apple Photos MCP server" width="520">
19
18
 
@@ -52,19 +51,70 @@ Then just ask: _"which receipts do I have from Vietnam?"_
52
51
 
53
52
  ### Which one
54
53
 
55
- | What you are doing | Use |
54
+ | Where you are | What you can reach |
56
55
  |---|---|
57
- | Inside a conversation with an agent | MCP |
58
- | Piping, scripting, cron, CI | CLI |
59
- | A one-off question in a terminal | CLI |
56
+ | An agent that can run shell commands, like Claude Code or Cursor | Both. The CLI is the cheaper one: it costs nothing until you type it |
57
+ | A terminal, a script, cron or CI | The CLI only. There is no MCP client in a shell |
60
58
 
61
59
  They are the same program reading the same tool definitions, so anything one
62
60
  can do, the other can. A test asserts they cannot drift.
63
61
 
62
+ ## Features
63
+
64
+ Every tool is both a command and an MCP tool, with the same name. The command is
65
+ the tool name with dashes.
66
+
67
+ | Capability | CLI command | MCP tool |
68
+ |---|---|---|
69
+ | Search the whole library | `apple-photos-cli search-photos` | `search_photos` |
70
+ | Actually look at photos | `apple-photos-cli look-at-photos` | `look_at_photos` |
71
+ | Full metadata, camera and lens | `apple-photos-cli photo-info` | `photo_info` |
72
+ | Real totals in one call | `apple-photos-cli library-stats` | `library_stats` |
73
+ | What Apple can search for | `apple-photos-cli list-vocabulary` | `list_vocabulary` |
74
+ | Export originals to disk | `apple-photos-cli export-originals` | `export_originals` |
75
+ | Favourite or unfavourite | `apple-photos-cli favorite-photos` | `favorite_photos` |
76
+ | Title and description | `apple-photos-cli set-photo-title` / `set-photo-description` | `set_photo_title` / `set_photo_description` |
77
+ | Keywords and albums | `apple-photos-cli add-keywords` / `add-to-album` | `add_keywords` / `add_to_album` |
78
+ | Move into an archive album | `apple-photos-cli archive-photos` | `archive_photos` |
79
+ | Check the setup | `apple-photos-cli doctor` | `doctor` |
80
+ | Find the right command | `apple-photos-cli which "..."` | not a tool |
81
+
82
+ All 13 with their arguments are in [section 6](#6-tools-).
83
+
84
+ ## Output and exit codes
85
+
86
+ Results on stdout, errors on stderr as JSON, so one parse handles both.
87
+
88
+ | Flag | Result |
89
+ |---|---|
90
+ | none | pretty JSON |
91
+ | `--json` | JSON, always |
92
+ | `--compact` | the same JSON on one line |
93
+ | `--select a,b.c` | keep only these fields |
94
+
95
+ | Code | Means |
96
+ |---|---|
97
+ | `0` | it worked |
98
+ | `2` | it was typed wrong, or a write was refused: a missing flag, a bad value, no `--confirm`, or read only |
99
+ | `3` | a photo or album wasn't found |
100
+ | `4` | macOS refused access: Full Disk Access, or Automation for Photos |
101
+ | `5` | the engine or Photos failed |
102
+ | `10` | the engine could not start: install uv, or set `APPLE_PHOTOS_PYTHON` |
103
+
104
+ ## Which surface, and what each costs
105
+
106
+ An MCP server is charged on every turn; a CLI costs nothing until it is called.
107
+
108
+ The `tools/list` payload for these 13 tools is about **2,800 tokens**, plus the
109
+ server instructions, on every turn of every conversation whether you use it or
110
+ not. The CLI is free until you run something, which is why both exist.
111
+
64
112
  ## Contents
65
113
 
66
114
  | | Section | |
67
115
  |---|---|---|
116
+ | | [Features](#features) | Every tool, both surfaces |
117
+ | | [Output and exit codes](#output-and-exit-codes) | What scripts branch on |
68
118
  | 1 | [What you can ask it](#1-what-you-can-ask-it-) | Real prompts, not features |
69
119
  | 2 | [Quick install](#2-quick-install-) | One command, no credential |
70
120
  | 3 | [Setup](#3-setup-) | One permission, once |
@@ -197,8 +247,8 @@ Apple Photos only exists on macOS, so there is no Windows or Linux path here.
197
247
 
198
248
  **If it already has other servers**, add only the `"apple-photos"` block inside the existing `"mcpServers"` object, and put a comma after the previous server's closing brace. One misplaced comma invalidates the file, and then every server disappears, not just this one.
199
249
 
200
- > **Tip**
201
- > Claude Desktop does not inherit your shell PATH. If `uvx` is not found, run `which uvx` in a terminal and use that absolute path as `"command"`.
250
+ > [!TIP]
251
+ > Claude Desktop does not inherit your shell PATH. If `npx` is not found, run `which npx` in a terminal and use that absolute path as `"command"`.
202
252
 
203
253
  Quit Claude Desktop completely with Cmd+Q and reopen it.
204
254
 
@@ -208,6 +258,8 @@ Quit Claude Desktop completely with Cmd+Q and reopen it.
208
258
  tail -f ~/Library/Logs/Claude/mcp-server-apple-photos.log
209
259
  ```
210
260
 
261
+ There is also a one-click `.mcpb` bundle on the [releases page](https://github.com/thenavidm/apple-photos-mcp-cli/releases), installed through **Settings**, then **Extensions**, then **Install Extension**. It carries the server and the Python engine; uv still fetches the engine's dependencies on first run, because they build pyobjc and only work on macOS.
262
+
211
263
  ### Cursor
212
264
 
213
265
  **Cursor Settings**, then **MCP**, then **Add new global MCP server**. That opens `~/.cursor/mcp.json`. Same JSON shape as Claude Desktop, same `mcpServers` key. Save, then click reload next to the server.
@@ -227,8 +279,8 @@ For one project instead of globally, use `.cursor/mcp.json` in that project.
227
279
  "servers": {
228
280
  "apple-photos": {
229
281
  "type": "stdio",
230
- "command": "uvx",
231
- "args": ["--from", "git+https://github.com/navidmoazzez/apple-photos-mcp-cli", "apple-photos-mcp"]
282
+ "command": "npx",
283
+ "args": ["-y", "@thenavidm/apple-photos-mcp-cli@latest"]
232
284
  }
233
285
  }
234
286
  }
@@ -242,8 +294,8 @@ Reload the window: Cmd+Shift+P, then **Developer: Reload Window**.
242
294
 
243
295
  ```toml
244
296
  [mcp_servers.apple-photos]
245
- command = "uvx"
246
- args = ["--from", "git+https://github.com/navidmoazzez/apple-photos-mcp-cli", "apple-photos-mcp"]
297
+ command = "npx"
298
+ args = ["-y", "@thenavidm/apple-photos-mcp-cli@latest"]
247
299
  ```
248
300
 
249
301
  ### Gemini CLI
@@ -252,7 +304,7 @@ args = ["--from", "git+https://github.com/navidmoazzez/apple-photos-mcp-cli", "a
252
304
 
253
305
  ### Everything else
254
306
 
255
- Any stdio MCP client takes the same two things: the command `uvx`, and the args above.
307
+ Any stdio MCP client takes the same two things: the command `npx`, and the args above.
256
308
 
257
309
  ### claude.ai on the web, with a relay
258
310
 
@@ -393,7 +445,7 @@ Run `doctor` before guessing. It names which of these it is.
393
445
  |---|---|---|
394
446
  | Permission denied reading the library | No Full Disk Access | [Section 3](#3-setup-). Quit the app with Cmd+Q, not just the window. |
395
447
  | Server does not appear in the client | Bad JSON, usually a comma | Paste the config into a JSON validator. One bad comma hides every server. |
396
- | `uvx: command not found` | The app cannot see your shell PATH | Use the absolute path from `which uvx` |
448
+ | `npx: command not found` | The app cannot see your shell PATH | Use the absolute path from `which npx` |
397
449
  | Write tools are missing | `APPLE_PHOTOS_READ_ONLY` is set | Unset it and restart the client |
398
450
  | Reads work, writes fail | Photos automation not approved | Approve the popup, or Privacy & Security, then Automation |
399
451
  | First search takes half a minute | Building the index | One time, about 25 seconds for 37,000 items. Cached afterwards. |
@@ -409,6 +461,20 @@ A standard way to give an AI assistant real access to a tool, so it can act rath
409
461
 
410
462
  </details>
411
463
 
464
+ <details>
465
+ <summary><b>What is the CLI?</b></summary>
466
+
467
+ `apple-photos-cli` is the same program as the MCP server, run as commands. AI agents that run commands, like Claude Code, Codex and OpenCode, use it on their own, and you can type the same commands in a terminal, a script or a cron job. Every tool is a command with dashes, so `search_photos` runs as `apple-photos-cli search-photos`.
468
+
469
+ </details>
470
+
471
+ <details>
472
+ <summary><b>Should I use the MCP server or the CLI?</b></summary>
473
+
474
+ Use the MCP server in an app with no terminal, like Claude Desktop's chat. Use the CLI anywhere commands run: an agent like Claude Code, Codex or OpenCode, a script or a cron job. The MCP server sends its full tool list to the model on every turn, and the CLI costs nothing until it runs.
475
+
476
+ </details>
477
+
412
478
  <details>
413
479
  <summary><b>What is Apple Photos?</b></summary>
414
480
 
@@ -498,17 +564,17 @@ Delete the server from your client's config, or run `claude mcp remove apple-pho
498
564
 
499
565
  ## Questions
500
566
 
501
- Run into a problem or have a question? [Open an issue](https://github.com/navidmoazzez/apple-photos-mcp-cli/issues) and I will help.
567
+ Run into a problem or have a question? [Open an issue](https://github.com/thenavidm/apple-photos-mcp-cli/issues) and I will help.
502
568
 
503
569
  ## About the author
504
570
 
505
- Navid Moazzez is a leading AI business strategist and the host of the AI Creator Summit, watched by 100,000+ creators. He helps creators and founders master AI and build their own AI Operating System (AI OS) to automate their business and life. This Apple Photos MCP server is one piece of that system.
571
+ Navid Moazzez is a leading AI business strategist, and the host of the AI Creator Summit, watched by 100,000+ creators. He helps creators and founders master AI and build their own AI Operating System (AI OS) to automate their business and life. This Apple Photos MCP server is one piece of that system.
506
572
 
507
573
  **Links**
508
574
 
509
- - Personal website: [navid.me](https://navid.me?utm_source=github&utm_medium=readme&utm_campaign=apple-photos-mcp)
510
- - Link in bio: [navid.bio](https://navid.bio?utm_source=github&utm_medium=readme&utm_campaign=apple-photos-mcp)
511
- - Navid Media: [navid.media](https://navid.media?utm_source=github&utm_medium=readme&utm_campaign=apple-photos-mcp)
575
+ - Personal website: [navid.me](https://navid.me?utm_source=github&utm_medium=referral&utm_campaign=apple-photos-mcp-cli&utm_content=readme)
576
+ - Link in bio: [navid.bio](https://navid.bio)
577
+ - Navid Media: [navid.media](https://navid.media)
512
578
  - YouTube: [@thenavidm](https://youtube.com/@thenavidm?sub_confirmation=1) and [@thenavidai](https://youtube.com/@thenavidai?sub_confirmation=1)
513
579
  - X: [@thenavidm](https://x.com/thenavidm)
514
580
  - Instagram: [@thenavidm](https://instagram.com/thenavidm)
@@ -532,4 +598,4 @@ Not affiliated with, endorsed by, or connected to Apple Inc. Apple, macOS, Photo
532
598
 
533
599
  ---
534
600
 
535
- © 2026 [NM Media](https://navid.media?utm_source=github&utm_medium=readme&utm_campaign=apple-photos-mcp). Made with ❤️ by [Navid Moazzez](https://navid.me?utm_source=github&utm_medium=readme&utm_campaign=apple-photos-mcp).
601
+ © 2026 [NM Media](https://navid.media). Made with ❤️ by [Navid Moazzez](https://navid.me?utm_source=github&utm_medium=referral&utm_campaign=apple-photos-mcp-cli&utm_content=readme).
package/SKILL.md CHANGED
@@ -152,6 +152,19 @@ photo_info(refs=[...]) # everything about specific items, including OCR text
152
152
  doctor() # run this first whenever anything misbehaves
153
153
  ```
154
154
 
155
+ ## Exit codes
156
+
157
+ A script branches on the number, not the message:
158
+
159
+ | Code | Means |
160
+ |---|---|
161
+ | 0 | it worked |
162
+ | 2 | typed wrong, or a write was refused: a missing flag, a bad value, no `--confirm`, or read only |
163
+ | 3 | a photo or album was not found |
164
+ | 4 | macOS refused access: Full Disk Access, or Automation for Photos |
165
+ | 5 | the engine or Photos failed |
166
+ | 10 | the engine could not start: install uv, or set `APPLE_PHOTOS_PYTHON` |
167
+
155
168
  ## When something breaks
156
169
 
157
170
  | Symptom | Cause | Fix |
package/lib/bridge.d.ts CHANGED
@@ -14,30 +14,41 @@
14
14
  * HQ connector can import so the hosted surface cannot drift from this one.
15
15
  *
16
16
  * Calls are proxied to the Python MCP server over stdio using the official
17
- * client, rather than a bespoke JSON protocol. That means the Python needs no
18
- * changes at all, and there is exactly one implementation of every tool.
17
+ * client, so the Python needs no changes and there is one implementation of
18
+ * every tool.
19
19
  */
20
20
  import type { Config } from "./config.js";
21
+ /** A content part as the MCP protocol carries it: text, image, or anything later. */
22
+ export type ContentPart = {
23
+ type: string;
24
+ text?: string;
25
+ data?: string;
26
+ mimeType?: string;
27
+ };
21
28
  export type BridgeResult = {
29
+ /** Every part, untouched. Images must survive: look_at_photos returns them. */
30
+ content: ContentPart[];
31
+ /** The text parts joined, for the common case of a JSON payload. */
22
32
  text: string;
23
33
  isError: boolean;
24
34
  };
25
- /**
26
- * One long-lived connection to the Python server.
27
- *
28
- * Spawning per call would pay `uv`'s dependency resolution and a Photos library
29
- * scan every time, which is seconds each. The process is started on first use
30
- * and reused.
31
- */
32
35
  export declare class PythonBridge {
33
36
  private readonly config;
34
37
  private client?;
35
38
  private starting?;
39
+ /** The tail of the engine's stderr, so a failure can say what actually went wrong. */
40
+ private stderrTail;
36
41
  constructor(config: Config);
37
42
  private connect;
38
- /** Call one Python tool and return its text payload. */
39
- call(tool: string, args: Record<string, unknown>): Promise<BridgeResult>;
40
- /** What the Python server says it offers. Used by `doctor` to prove the two agree. */
43
+ /**
44
+ * Call one Python tool and return every content part.
45
+ *
46
+ * `timeoutMs` matters: exporting originals pulls them out of iCloud first and
47
+ * rendering previews is not quick either, so the protocol default of 60s
48
+ * cancels work the engine is still doing.
49
+ */
50
+ call(tool: string, args: Record<string, unknown>, timeoutMs?: number): Promise<BridgeResult>;
51
+ /** What the Python server says it offers, for checking the two lists agree. */
41
52
  listTools(): Promise<string[]>;
42
53
  close(): Promise<void>;
43
54
  }
package/lib/bridge.js CHANGED
@@ -14,23 +14,18 @@
14
14
  * HQ connector can import so the hosted surface cannot drift from this one.
15
15
  *
16
16
  * Calls are proxied to the Python MCP server over stdio using the official
17
- * client, rather than a bespoke JSON protocol. That means the Python needs no
18
- * changes at all, and there is exactly one implementation of every tool.
17
+ * client, so the Python needs no changes and there is one implementation of
18
+ * every tool.
19
19
  */
20
20
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
21
21
  import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
22
22
  import { BridgeError } from "./errors.js";
23
- /**
24
- * One long-lived connection to the Python server.
25
- *
26
- * Spawning per call would pay `uv`'s dependency resolution and a Photos library
27
- * scan every time, which is seconds each. The process is started on first use
28
- * and reused.
29
- */
30
23
  export class PythonBridge {
31
24
  config;
32
25
  client;
33
26
  starting;
27
+ /** The tail of the engine's stderr, so a failure can say what actually went wrong. */
28
+ stderrTail = "";
34
29
  constructor(config) {
35
30
  this.config = config;
36
31
  }
@@ -41,21 +36,38 @@ export class PythonBridge {
41
36
  return this.starting;
42
37
  this.starting = (async () => {
43
38
  const client = new Client({ name: "apple-photos-cli", version: "1.0.0" }, { capabilities: {} });
44
- // `uv run` resolves osxphotos and photoscript on first use and caches
45
- // them, so the reader needs neither a virtualenv nor a pip install.
46
39
  const transport = new StdioClientTransport({
47
40
  command: this.config.pythonCommand,
48
41
  args: this.config.pythonArgs,
49
42
  env: { ...process.env, ...this.config.pythonEnv },
50
43
  stderr: "pipe",
51
44
  });
45
+ // Drain stderr immediately. The SDK pipes it into a PassThrough with a
46
+ // 16KB buffer; with no reader that fills, the OS pipe fills behind it,
47
+ // and the child blocks writing to stderr. osxphotos is chatty on a large
48
+ // library, so this is a real hang, not a theoretical one. Keeping the
49
+ // tail also means a failure can name the actual cause — a missing module,
50
+ // a Full Disk Access denial — instead of a boilerplate "install uv".
51
+ transport.stderr?.on("data", (chunk) => {
52
+ this.stderrTail = (this.stderrTail + chunk.toString()).slice(-4000);
53
+ });
54
+ // A dead client must not stay cached, or one engine crash bricks every
55
+ // later call for the life of the process with "Connection closed".
56
+ const forget = () => {
57
+ if (this.client === client)
58
+ this.client = undefined;
59
+ };
60
+ client.onclose = forget;
61
+ client.onerror = forget;
52
62
  try {
53
- await client.connect(transport);
63
+ // The default is 60s, and a cold `uv` run builds pyobjc, which takes
64
+ // longer than that on a fresh cache. Failing there reported "install
65
+ // uv" at the one moment uv was working correctly.
66
+ await client.connect(transport, { timeout: this.config.startupTimeoutMs });
54
67
  }
55
68
  catch (error) {
56
69
  throw new BridgeError(`Could not start the Photos engine with \`${this.config.pythonCommand} ${this.config.pythonArgs.join(" ")}\`. ` +
57
- `Install uv (https://docs.astral.sh/uv/) or set APPLE_PHOTOS_PYTHON to a Python that has osxphotos and photoscript. ` +
58
- `Underlying error: ${error.message}`);
70
+ `Install uv (https://docs.astral.sh/uv/) or set APPLE_PHOTOS_PYTHON to a Python that has osxphotos and photoscript.`, [error.message, this.stderrTail.trim()].filter(Boolean).join("\n"));
59
71
  }
60
72
  this.client = client;
61
73
  return client;
@@ -67,25 +79,40 @@ export class PythonBridge {
67
79
  this.starting = undefined;
68
80
  }
69
81
  }
70
- /** Call one Python tool and return its text payload. */
71
- async call(tool, args) {
82
+ /**
83
+ * Call one Python tool and return every content part.
84
+ *
85
+ * `timeoutMs` matters: exporting originals pulls them out of iCloud first and
86
+ * rendering previews is not quick either, so the protocol default of 60s
87
+ * cancels work the engine is still doing.
88
+ */
89
+ async call(tool, args, timeoutMs) {
72
90
  const client = await this.connect();
73
- const result = (await client.callTool({ name: tool, arguments: args }));
74
- const text = (result.content ?? [])
91
+ let result;
92
+ try {
93
+ result = (await client.callTool({ name: tool, arguments: args }, undefined, { timeout: timeoutMs ?? this.config.requestTimeoutMs }));
94
+ }
95
+ catch (error) {
96
+ throw new BridgeError(`The Photos engine failed while running ${tool}.`, [error.message, this.stderrTail.trim()].filter(Boolean).join("\n"));
97
+ }
98
+ const content = result.content ?? [];
99
+ const text = content
75
100
  .filter((part) => part.type === "text" && typeof part.text === "string")
76
101
  .map((part) => part.text)
77
102
  .join("\n");
78
- return { text, isError: result.isError === true };
103
+ return { content, text, isError: result.isError === true };
79
104
  }
80
- /** What the Python server says it offers. Used by `doctor` to prove the two agree. */
105
+ /** What the Python server says it offers, for checking the two lists agree. */
81
106
  async listTools() {
82
107
  const client = await this.connect();
83
108
  const { tools } = await client.listTools();
84
109
  return tools.map((tool) => tool.name);
85
110
  }
86
111
  async close() {
87
- await this.client?.close().catch(() => undefined);
112
+ this.starting = undefined;
113
+ const client = this.client;
88
114
  this.client = undefined;
115
+ await client?.close().catch(() => undefined);
89
116
  }
90
117
  }
91
118
  //# sourceMappingURL=bridge.js.map
package/lib/bridge.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../src-ts/bridge.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../src-ts/bridge.ts"],"names":[],"mappings":"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"}
package/lib/cli.d.ts CHANGED
@@ -28,16 +28,7 @@ type Flag = {
28
28
  help: string;
29
29
  };
30
30
  export declare function flagsFor(shape: ZodRawShape): Flag[];
31
- /**
32
- * Midjourney's own parameter spellings, accepted as flags.
33
- *
34
- * The schema names things in full because a tool description is read by a model
35
- * that has never seen a Midjourney prompt. A person at a terminal has, and they
36
- * will type `--ar 16:9`, because that is what the parameter is called
37
- * everywhere Midjourney documents it. Refusing the name the whole ecosystem
38
- * uses, to protect a naming convention nobody outside this repo can see, would
39
- * be the wrong trade.
40
- */
31
+ /** Shorthands for this repo's arguments. Kept small on purpose. */
41
32
  export declare const FLAG_ALIASES: Record<string, string>;
42
33
  /**
43
34
  * Parse argv against a tool's flags.
@@ -67,11 +58,12 @@ export declare function emitError(error: unknown): void;
67
58
  */
68
59
  export declare function binName(): string;
69
60
  /**
70
- * Words people use mapped onto words the tools use.
61
+ * Words people use mapped onto words these tools use.
71
62
  *
72
- * Without this, "make a picture" matches nothing, because every tool says
73
- * "generate" and "image". A lookup that only works when you already know the
74
- * vocabulary is not a lookup.
63
+ * Without this, "save my photos to disk" matches four browsing tools and never
64
+ * export-originals, because nothing in that phrase appears in its name or
65
+ * description. Every target below has to be vocabulary a tool actually
66
+ * contains; a test asserts it.
75
67
  */
76
68
  export declare const SYNONYMS: Record<string, string[]>;
77
69
  /**
@@ -87,6 +79,27 @@ export declare function whichCommand(query: string): {
87
79
  tool: AnyToolSpec;
88
80
  score: number;
89
81
  }[];
82
+ /**
83
+ * The house contract, so a script branches on the number the same way for
84
+ * every one of these CLIs: 0 ok, 2 usage or a refused write, 3 not found,
85
+ * 4 access refused, 5 the engine failed, 10 nothing set up yet.
86
+ */
87
+ export declare const EXIT: {
88
+ readonly ok: 0;
89
+ readonly usage: 2;
90
+ readonly notFound: 3;
91
+ readonly auth: 4;
92
+ readonly api: 5;
93
+ readonly rateLimited: 7;
94
+ readonly config: 10;
95
+ };
96
+ /**
97
+ * There is no account here, so "auth" is macOS refusing access: Full Disk
98
+ * Access for the library, or Automation for Photos itself. The engine reports
99
+ * its failures as text, so its words decide once the class has said what it
100
+ * can.
101
+ */
102
+ export declare function exitCodeFor(error: unknown): number;
90
103
  export declare function isCliCommand(argv: string[]): boolean;
91
104
  export declare function runCli(argv: string[]): Promise<number>;
92
105
  export {};