@redpop/apple-mail-actions-mcp 0.0.0-placeholder.0 → 0.3.2

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Martin Alker
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,5 +1,229 @@
1
- # @redpop/apple-mail-actions-mcp
1
+ # apple-mail-actions-mcp
2
2
 
3
- Placeholder. This version contains no code and reserves the package name so that trusted
4
- publishing can be set up. Install a later version once it is released:
5
- https://github.com/redpop/apple-mail-mcp
3
+ An [MCP](https://modelcontextprotocol.io) server with one tool, `move_messages`. It moves
4
+ messages to another mailbox of the same account in Apple Mail. It is the companion of
5
+ [`@redpop/apple-mail-mcp`](../../README.md), the read-only server. That package stays read-only;
6
+ all moving code lives here.
7
+
8
+ **macOS only.** Status: not published yet. The install commands below apply from the first
9
+ release; until then, build it from source.
10
+
11
+ ## What it does
12
+
13
+ Claude looks at your mailbox with the read server, proposes a folder for some messages, and
14
+ you confirm. Then Claude calls `move_messages` with message ids and target mailbox ids. The
15
+ package only moves messages. It does not send, draft, delete, flag, create folders, read mail
16
+ or move between accounts.
17
+
18
+ ```
19
+ "Which of these invoices belong in the Accounting folder? Move the ones you are sure about."
20
+ ```
21
+
22
+ The server asks Claude to show the proposal first, with the choices move all, move some,
23
+ adjust first or move none. That is a request in the server instructions, not a lock. The lock
24
+ is that the tool is not marked read-only, so your client asks before each call, but only in a
25
+ mode that asks.
26
+
27
+ **Do not choose "Always allow" for this tool.** It turns that confirmation off, and a
28
+ malicious mail could then make the model move messages without you seeing it.
29
+
30
+ **Use a mode that asks.** In Claude Desktop and Cowork, the Auto mode does not ask: an
31
+ automated check blocks only actions it flags as risky, otherwise Claude moves without asking,
32
+ even though the tool is set to "Needs approval". Choose Manual for conversations that may move
33
+ mail. In a test on 2026-11-11, Auto moved a message right after a "yes" in the chat, with no
34
+ prompt; Manual asked. In Claude Code, modes that approve tools on their own, such as auto mode
35
+ or skipping permissions, have the same effect.
36
+
37
+ ## What you need beside it
38
+
39
+ This package needs the read server beside it. The read server lists mailboxes and finds
40
+ messages; this server only takes the ids it returns. Install `@redpop/apple-mail-mcp` first
41
+ and give it Full Disk Access as its README describes.
42
+
43
+ Two settings must match across both servers, because neither server sees the other's
44
+ configuration:
45
+
46
+ - `APPLE_MAIL_ACCOUNTS` is required here. If it is empty, every call fails with
47
+ `CONFIG_INVALID`; moving is never enabled for all accounts. Use the same list in the read
48
+ server.
49
+ - Set `APPLE_MAIL_EXCLUDE_MAILBOXES` in both servers. A mailbox hidden in the read server but
50
+ not here would still be a possible target.
51
+
52
+ Junk and trash are not visible by default, in either server.
53
+
54
+ ## What it moves, and what it refuses
55
+
56
+ Targets are all visible mailboxes except trash, junk, drafts, sent and "all mail". Sources
57
+ must be visible under the same rules, so junk and trash are not sources by default. Further
58
+ targets can be forbidden with `APPLE_MAIL_MOVE_EXCLUDE_TARGETS`.
59
+
60
+ Each message gets one status. `moved` means the index of Mail shows it in the target and no
61
+ longer in the source. `moved_unverified` means the move was requested but the index did not
62
+ confirm it within 10 seconds. Both describe the local state in Mail, not the mail server.
63
+ `failed` and the `skipped_*` statuses say why a message did not move; nothing was changed for
64
+ those.
65
+
66
+ Message ids are valid for the current index only. After Mail rebuilds a mailbox, or after a
67
+ `skipped_not_found` status, search again and use the new ids.
68
+
69
+ Messages are skipped, never moved, in these cases:
70
+
71
+ - The message looks like a security mail (verification code, password reset, sign-in link).
72
+ The check looks at the subject only; the message text is not read. `APPLE_MAIL_SHOW_SECURITY_MAILS` does not lift it.
73
+ - The message was moved in the last 5 minutes. Rapid back and forth can create a copy on the
74
+ mail server, so each moved message is locked for 5 minutes, across processes. Moves you make
75
+ yourself in Mail are not known to the lock.
76
+ - The message is visible in several mailboxes and `sourceMailboxId` does not pick one.
77
+ - The message has no Message-ID header in Mail's index. On macOS 15 Mail does not store it, so
78
+ the tool cannot move anything there. `doctor` says so.
79
+ - The source and target are the same, or in different accounts.
80
+ - The account is not supported. Only mailbox.org has been tested. Other IMAP providers are
81
+ untested: they run without a refusal, so limit `APPLE_MAIL_ACCOUNTS` to accounts you
82
+ are willing to try. Gmail, Exchange and local folders are refused.
83
+ - A folder name differs from another folder of the account only in case, or contains control
84
+ characters.
85
+
86
+ Moves run one after another, never in parallel, and are never retried: a failed move may have
87
+ arrived halfway.
88
+
89
+ A folder that never held a message is not in Mail's index, so it does not appear in
90
+ `list_mailboxes` and cannot be a target. Put one message in it by hand first.
91
+
92
+ Subfolders and INBOX have had one manual test: on 2026-11-04, on macOS 27 with one IMAP
93
+ account at mailbox.org, one test mail was moved to a subfolder and back, and one test mail to
94
+ INBOX and back, 60 seconds apart, with no copy in the webmail. These were single test mails,
95
+ not a series.
96
+
97
+ ## Requirements
98
+
99
+ - macOS 26 or later to move mail. The server starts on macOS 15, but Mail there does not store
100
+ the Message-ID header, so every move is refused with `skipped_no_message_id`; the server
101
+ never moves a message it cannot identify by its Message-ID. Verified with a real mailbox
102
+ only on macOS 27 with Mail 16 and one mailbox.org account.
103
+ - Node.js 22.16 or newer in the 22 line, or 24 and newer.
104
+ - The read server `@redpop/apple-mail-mcp` at the same version, with Full Disk Access.
105
+ - Mail must be running. The server never starts it; without it the call fails with
106
+ `MAIL_NOT_RUNNING`.
107
+
108
+ ## Install
109
+
110
+ **Claude Code, as a plugin:**
111
+
112
+ ```
113
+ /plugin install apple-mail-actions-mcp --marketplace redpop/apple-mail-mcp
114
+ npx -y @redpop/apple-mail-actions-mcp setup
115
+ ```
116
+
117
+ **Claude Code without the plugin:**
118
+
119
+ ```bash
120
+ claude mcp add apple-mail-actions \
121
+ -e APPLE_MAIL_ACCOUNTS=work@example.com \
122
+ -e APPLE_MAIL_EXCLUDE_MAILBOXES=Archive \
123
+ -- npx -y @redpop/apple-mail-actions-mcp
124
+ npx -y @redpop/apple-mail-actions-mcp setup
125
+ ```
126
+
127
+ **Claude Desktop and Cowork:** the release will carry an `.mcpb` bundle with the same settings
128
+ page. Claude Desktop does not switch it on after the install, because the accounts setting is
129
+ required; enter the accounts, save, and switch it on under Settings > Extensions. The plugin does not work in Cowork, which starts a plugin's local server inside its Linux
130
+ virtual machine, away from Mail, or in the desktop chat, which ignores such servers.
131
+
132
+ `setup` first runs the setup of the read server (Full Disk Access for its helper), then asks
133
+ macOS for the Automation permission of "Mail MCP Actions" to control Mail. Mail must be
134
+ running for the dialog to appear. The permission goes to that small app alone, not to Claude,
135
+ your terminal or Node. It can be switched off under System Settings > Privacy & Security >
136
+ Automation.
137
+
138
+ ## Configuration
139
+
140
+ Set these in the environment of the server. They cannot be changed through tool parameters.
141
+ An invalid value does not stop the server; every call then fails with `CONFIG_INVALID` naming
142
+ the setting. The server reads them once, at startup: restart the client after a change.
143
+
144
+ | Variable | Default | Meaning |
145
+ |---|---|---|
146
+ | `APPLE_MAIL_ACCOUNTS` | required | Comma-separated allowlist of accounts, by UUID, address or name. Empty is an error, not "all accounts". |
147
+ | `APPLE_MAIL_INCLUDE_JUNK` | `false` | Treat mailboxes with the junk role as visible. Same meaning as in the read server. |
148
+ | `APPLE_MAIL_INCLUDE_TRASH` | `false` | Treat mailboxes with the trash role as visible. Same meaning as in the read server. |
149
+ | `APPLE_MAIL_EXCLUDE_MAILBOXES` | empty | Comma-separated mailboxes to hide, by name or by path with `/`. Set it in both servers. |
150
+ | `APPLE_MAIL_MAX_MOVES` | `25` | Upper bound for the number of messages in one call (1 to 100). |
151
+ | `APPLE_MAIL_MOVE_EXCLUDE_TARGETS` | empty | Comma-separated mailboxes that are never a target, by name or by path with `/`. |
152
+ | `APPLE_MAIL_ACTIONS_PATH` | not set | Development only: path to a Dev or Ad hoc build of the Actions app. A bundle with the release bundle id is refused. |
153
+
154
+ The settings of the read server that do not appear here, for example body search, do not affect
155
+ this package.
156
+
157
+ ## Install from source
158
+
159
+ You need the Xcode Command Line Tools and an Apple Development certificate for a build that
160
+ keeps its permission across rebuilds.
161
+
162
+ ```bash
163
+ git clone https://github.com/redpop/apple-mail-mcp.git
164
+ cd apple-mail-mcp
165
+ npm ci
166
+ npm run build && npm run build:helper
167
+ npm run build --workspace packages/actions && npm run build:helper --workspace packages/actions
168
+ ```
169
+
170
+ Then follow the README of the read server for its helper, and grant Automation with
171
+ `node packages/actions/dist/index.js setup`, with `APPLE_MAIL_ACTIONS_PATH` and
172
+ `APPLE_MAIL_HELPER_PATH` pointing at the Dev bundles in each `bin/` directory. Never sign
173
+ these builds with a Developer ID.
174
+
175
+ Put these variables in front of the command instead of exporting them. An exported
176
+ `APPLE_MAIL_*` variable stays in the shell, and every MCP server that a client started from
177
+ that shell inherits it: an exported `APPLE_MAIL_ACCOUNTS` also limits the read server to those
178
+ accounts. If you exported them, run `unset` on them before you start the client.
179
+
180
+ ## Diagnostics
181
+
182
+ ```bash
183
+ npx -y @redpop/apple-mail-actions-mcp doctor
184
+ ```
185
+
186
+ `doctor` runs the checks of the read server, then checks the Actions app and its signature,
187
+ the Automation permission, whether Mail is running, whether the Message-ID column exists and
188
+ which accounts are supported. Without `--verbose` it names no accounts or addresses. Exit code
189
+ 1 means at least one check failed.
190
+
191
+ ## Privacy Policy
192
+
193
+ This policy covers the server and the Actions app, as published on npm and in the GitHub
194
+ releases. It adds to the policy of the read server.
195
+
196
+ ### What is collected
197
+
198
+ Nothing is collected by the author or by any service. The server has no telemetry, and neither
199
+ the server nor the app opens a network connection. The app never sees mail content. It receives
200
+ a message number, a Message-ID and the names of an account and two mailboxes, and returns a
201
+ status.
202
+
203
+ ### How it is used and stored
204
+
205
+ When your AI client calls `move_messages`, the app asks Mail to move the messages you named. The
206
+ server writes one file, `move-locks.json`, under
207
+ `~/Library/Application Support/apple-mail-mcp/`, directory 0700, file 0600. It holds the
208
+ internal message numbers of recently moved messages and the time their lock ends. No names or
209
+ subjects.
210
+
211
+ ### Sharing with third parties
212
+
213
+ Nothing is shared. Mail itself synchronizes the move with your mail server, as it does for a move
214
+ you make by hand. The statuses of a call go back to your AI client.
215
+
216
+ ### Retention
217
+
218
+ Entries leave the lock file after 5 minutes at the next move. Delete the file at any time. The
219
+ server never deletes or changes anything under `~/Library/Mail` itself; the moves are Mail's.
220
+
221
+ ### Contact
222
+
223
+ Questions about this policy: open an issue at
224
+ <https://github.com/redpop/apple-mail-mcp/issues>. Security problems: report them privately as
225
+ [`SECURITY.md`](./SECURITY.md#reporting-a-vulnerability) describes.
226
+
227
+ ## License
228
+
229
+ MIT, see [`LICENSE`](./LICENSE).
package/SECURITY.md ADDED
@@ -0,0 +1,87 @@
1
+ # Security
2
+
3
+ This covers `@redpop/apple-mail-actions-mcp`. The threat model of the read server, including
4
+ prompt injection and what a mailbox holds, is in the
5
+ [root `SECURITY.md`](../../SECURITY.md) and applies here too.
6
+
7
+ ## What the package can do
8
+
9
+ One tool, `move_messages`, moves messages between mailboxes of one account. The signed app
10
+ "Mail MCP Actions" does the move by asking Mail through Apple Events. It has the Automation
11
+ permission for Mail and no Full Disk Access. It has a fixed set of commands (`hello`,
12
+ `permission`, `request-permission`, `move`) and no command to list, read or delete mail.
13
+ It never sees mail content: it gets a message number, a Message-ID and names, and returns a
14
+ status or an error number. It holds no credentials and opens no network connection.
15
+
16
+ What limits the server:
17
+
18
+ - **Settings come from the environment, never from tool parameters.** The account list, the
19
+ limit per call and the forbidden targets cannot be widened by the model, so an injected mail
20
+ cannot widen them.
21
+ - **Accounts are an allowlist.** An empty `APPLE_MAIL_ACCOUNTS` makes every call fail.
22
+ - **Targets exclude trash, junk, drafts, sent and "all mail".** Sources must be visible under
23
+ the policy of the read server's rules.
24
+ - **Nothing is deleted or sent.** The worst a move does is put a message in the wrong
25
+ folder; moving it back works with the same tool once the 5-minute lock has ended.
26
+ - **The message is checked before the move.** The app finds the message by number and compares
27
+ its Message-ID with the one the server read from the index. It moves only if both agree.
28
+ - **No raw scripts.** Account and folder names are never put into script text unchecked.
29
+ - **Moves are locked for 5 minutes, one at a time, never retried.**
30
+ - **The client asks, in a mode that asks.** `move_messages` is not marked read-only, so a client
31
+ asks before each call. If you set "Always allow" for the tool, that is gone; do not. A mode
32
+ that approves tools on its own removes it too: in Claude Desktop and Cowork, Auto moves without
33
+ asking when its automated check does not flag the action, even for a tool set to "Needs
34
+ approval" (tested 2026-11-11). Use Manual there, and no auto-approving mode in Claude Code.
35
+
36
+ ## Residual risks
37
+
38
+ ### Any local process can run the app
39
+
40
+ Any program running as your macOS user can start the Actions app and send it `move`
41
+ commands directly, as long as the Automation permission exists. The server's policy lives in
42
+ Node, not in the app. Such a program could move any message it can identify, in any account
43
+ that Mail holds, into any folder, trash included. The damage is limited to moving:
44
+ the app cannot read, send, delete or flag mail, and a moved message can be moved back. If your
45
+ threat model includes hostile programs under your account, this package does not defend
46
+ against them. The permission can be switched off in System Settings > Privacy & Security >
47
+ Automation.
48
+
49
+ Mail's own permission model is the reason for the shape: the grant attaches to the app because
50
+ it re-launches itself as its own responsible process. The permission does not go to Claude,
51
+ your terminal or Node.
52
+
53
+ ### Any local process can switch the grant off
54
+
55
+ As with the read helper, a program of your user can build an ad-hoc bundle with the release
56
+ bundle id and run it. macOS then turns the grant off. The server is blind until you switch it
57
+ on again. Local builds use their own bundle ids. The server starts a bundle with the release id
58
+ only if its signature verifies against the project's Developer ID requirement, and starts a Dev
59
+ or Ad hoc bundle only when `APPLE_MAIL_ACTIONS_PATH` points at it; it refuses any other bundle id.
60
+
61
+ ### The security-mail check looks at the subject only
62
+
63
+ Messages that look like security mails are never moved. The check is the same heuristic as in
64
+ the read server, applied to the subject only. The message text is not read, and the sender address does not change the result. It does not load the body: the body
65
+ check also flags ordinary mail with a word like "code" and would block normal moves, and it
66
+ could not judge mail that was never downloaded. So a security mail with a harmless subject
67
+ can be moved, to a folder you allow. Moving does not read it or send it anywhere. The check
68
+ is a safety net, not a guarantee.
69
+
70
+ ### Status means the local state, not the server
71
+
72
+ A status describes the local state in Mail, not the server. `moved` says that the index of Mail shows the message in the target and not in the source. Mail
73
+ then synchronizes with the server. If that fails, or if Mail creates a copy on the server
74
+ (rapid back and forth can), the status does not know. Check in the webmail if it matters.
75
+
76
+ ### Untested providers
77
+
78
+ Only mailbox.org has been tested. Other IMAP providers run without a refusal and may behave
79
+ differently, for example by keeping a copy. Limit `APPLE_MAIL_ACCOUNTS` to accounts you are
80
+ willing to try.
81
+
82
+ ## Reporting a vulnerability
83
+
84
+ Please report security problems privately through GitHub Security Advisories:
85
+ <https://github.com/redpop/apple-mail-mcp/security/advisories/new>. Do not open a public issue
86
+ for them. Include the macOS version, the output of `doctor` and steps to reproduce. Please do
87
+ not attach real mail.
@@ -0,0 +1,28 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>CFBundleIdentifier</key>
6
+ <string>io.github.redpop.apple-mail-mcp.mail-actions</string>
7
+ <key>CFBundleName</key>
8
+ <string>Mail MCP Actions</string>
9
+ <key>CFBundleDisplayName</key>
10
+ <string>Mail MCP Actions</string>
11
+ <key>CFBundleExecutable</key>
12
+ <string>mail-actions</string>
13
+ <key>CFBundleIconFile</key>
14
+ <string>AppIcon</string>
15
+ <key>CFBundlePackageType</key>
16
+ <string>APPL</string>
17
+ <key>CFBundleShortVersionString</key>
18
+ <string>0.3.2</string>
19
+ <key>CFBundleVersion</key>
20
+ <string>0.3.2</string>
21
+ <key>LSMinimumSystemVersion</key>
22
+ <string>15.0</string>
23
+ <key>NSAppleEventsUsageDescription</key>
24
+ <string>Moves messages between folders in Apple Mail when you confirm it.</string>
25
+ <key>LSUIElement</key>
26
+ <true/>
27
+ </dict>
28
+ </plist>
@@ -0,0 +1,128 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>files</key>
6
+ <dict>
7
+ <key>Resources/AppIcon.icns</key>
8
+ <data>
9
+ E9KEMJn1uUwhssgjN+4uU5ZYdpA=
10
+ </data>
11
+ </dict>
12
+ <key>files2</key>
13
+ <dict>
14
+ <key>Resources/AppIcon.icns</key>
15
+ <dict>
16
+ <key>hash2</key>
17
+ <data>
18
+ GT2ygd05uo0+IBsX1vwkfZQ0HNjYcREuoPCNFAL6mNY=
19
+ </data>
20
+ </dict>
21
+ </dict>
22
+ <key>rules</key>
23
+ <dict>
24
+ <key>^Resources/</key>
25
+ <true/>
26
+ <key>^Resources/.*\.lproj/</key>
27
+ <dict>
28
+ <key>optional</key>
29
+ <true/>
30
+ <key>weight</key>
31
+ <real>1000</real>
32
+ </dict>
33
+ <key>^Resources/.*\.lproj/locversion.plist$</key>
34
+ <dict>
35
+ <key>omit</key>
36
+ <true/>
37
+ <key>weight</key>
38
+ <real>1100</real>
39
+ </dict>
40
+ <key>^Resources/Base\.lproj/</key>
41
+ <dict>
42
+ <key>weight</key>
43
+ <real>1010</real>
44
+ </dict>
45
+ <key>^version.plist$</key>
46
+ <true/>
47
+ </dict>
48
+ <key>rules2</key>
49
+ <dict>
50
+ <key>.*\.dSYM($|/)</key>
51
+ <dict>
52
+ <key>weight</key>
53
+ <real>11</real>
54
+ </dict>
55
+ <key>^(.*/)?\.DS_Store$</key>
56
+ <dict>
57
+ <key>omit</key>
58
+ <true/>
59
+ <key>weight</key>
60
+ <real>2000</real>
61
+ </dict>
62
+ <key>^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/</key>
63
+ <dict>
64
+ <key>nested</key>
65
+ <true/>
66
+ <key>weight</key>
67
+ <real>10</real>
68
+ </dict>
69
+ <key>^.*</key>
70
+ <true/>
71
+ <key>^Info\.plist$</key>
72
+ <dict>
73
+ <key>omit</key>
74
+ <true/>
75
+ <key>weight</key>
76
+ <real>20</real>
77
+ </dict>
78
+ <key>^PkgInfo$</key>
79
+ <dict>
80
+ <key>omit</key>
81
+ <true/>
82
+ <key>weight</key>
83
+ <real>20</real>
84
+ </dict>
85
+ <key>^Resources/</key>
86
+ <dict>
87
+ <key>weight</key>
88
+ <real>20</real>
89
+ </dict>
90
+ <key>^Resources/.*\.lproj/</key>
91
+ <dict>
92
+ <key>optional</key>
93
+ <true/>
94
+ <key>weight</key>
95
+ <real>1000</real>
96
+ </dict>
97
+ <key>^Resources/.*\.lproj/locversion.plist$</key>
98
+ <dict>
99
+ <key>omit</key>
100
+ <true/>
101
+ <key>weight</key>
102
+ <real>1100</real>
103
+ </dict>
104
+ <key>^Resources/Base\.lproj/</key>
105
+ <dict>
106
+ <key>weight</key>
107
+ <real>1010</real>
108
+ </dict>
109
+ <key>^[^/]+$</key>
110
+ <dict>
111
+ <key>nested</key>
112
+ <true/>
113
+ <key>weight</key>
114
+ <real>10</real>
115
+ </dict>
116
+ <key>^embedded\.provisionprofile$</key>
117
+ <dict>
118
+ <key>weight</key>
119
+ <real>20</real>
120
+ </dict>
121
+ <key>^version\.plist$</key>
122
+ <dict>
123
+ <key>weight</key>
124
+ <real>20</real>
125
+ </dict>
126
+ </dict>
127
+ </dict>
128
+ </plist>
package/dist/bundle.js ADDED
@@ -0,0 +1,85 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import { existsSync } from 'node:fs';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { readBundleId, TEAM_ID } from '@redpop/apple-mail-mcp/dist/signing.js';
5
+ import { createStdioRunner } from '@redpop/apple-mail-mcp/dist/stdioRunner.js';
6
+ import { ActionsError } from './errors.js';
7
+ // Die IDs stehen auch in packages/actions/swift/build.sh; tests/signing.test.ts prueft, dass sie passen.
8
+ export const RELEASE_BUNDLE_ID = 'io.github.redpop.apple-mail-mcp.mail-actions';
9
+ export const DEV_BUNDLE_ID = RELEASE_BUNDLE_ID + '.dev';
10
+ export const ADHOC_BUNDLE_ID = RELEASE_BUNDLE_ID + '.adhoc';
11
+ export const RELEASE_REQUIREMENT = `identifier "${RELEASE_BUNDLE_ID}" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] exists and certificate leaf[subject.OU] = "${TEAM_ID}"`;
12
+ /** Mehr als die 2 Minuten, nach denen ein Apple Event selbst aufgibt: Sonst gaelte ein noch laufender Zug als tot. */
13
+ export const ACTIONS_TIMEOUTS = { firstRequestMs: 130_000, requestMs: 130_000 };
14
+ const defaultExec = (file, args) => execFileSync(file, args, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] });
15
+ /** Wo das Bundle im ausgelieferten Paket liegt (gleich fuer src/ und dist/). */
16
+ export function packagedActionsBundle() {
17
+ return fileURLToPath(new URL('../bin/Mail MCP Actions.app', import.meta.url));
18
+ }
19
+ export function resolveActionsBundle(config) {
20
+ return config.actionsPath ?? packagedActionsBundle();
21
+ }
22
+ export function actionsExecutable(bundle) {
23
+ return `${bundle}/Contents/MacOS/mail-actions`;
24
+ }
25
+ /**
26
+ * Signaturgatter vor dem ersten Start, nach dem Muster von checkBundle im Lesepaket. Der Override erlaubt nur
27
+ * Dev- und Ad-hoc-Bundles: Eine Release-ID per Override waere ein fremder Build mit der Freigabe des Nutzers.
28
+ */
29
+ export function checkActionsBundle(bundle, opts) {
30
+ const exec = opts.exec ?? defaultExec;
31
+ if (!(opts.exists ?? existsSync)(bundle))
32
+ throw new ActionsError('ACTIONS_BUNDLE_MISSING');
33
+ let id;
34
+ try {
35
+ id = readBundleId(bundle, exec);
36
+ }
37
+ catch {
38
+ throw new ActionsError('ACTIONS_SIGNATURE_INVALID');
39
+ }
40
+ if (id === RELEASE_BUNDLE_ID) {
41
+ if (opts.override)
42
+ throw new ActionsError('ACTIONS_SIGNATURE_INVALID');
43
+ try {
44
+ exec('/usr/bin/codesign', ['--verify', '--strict', '--deep', `-R=${RELEASE_REQUIREMENT}`, bundle]);
45
+ }
46
+ catch {
47
+ throw new ActionsError('ACTIONS_SIGNATURE_INVALID');
48
+ }
49
+ return;
50
+ }
51
+ if (opts.override && (id === DEV_BUNDLE_ID || id === ADHOC_BUNDLE_ID))
52
+ return;
53
+ throw new ActionsError('ACTIONS_SIGNATURE_INVALID');
54
+ }
55
+ /**
56
+ * Ein Runner pro Serverprozess; das Gatter laeuft einmal vor dem ersten Start, auch ein Fehlschlag bleibt
57
+ * bis zum Prozessende stehen (wie createHelperRunner).
58
+ */
59
+ export function createActionsRunner(config, deps = {}) {
60
+ const bundlePath = resolveActionsBundle(config);
61
+ const options = { debug: config.debug === true };
62
+ const inner = (deps.makeRunner ?? ((exe, opts) => createStdioRunner(exe, ACTIONS_TIMEOUTS, opts)))(actionsExecutable(bundlePath), options);
63
+ const check = deps.check ?? checkActionsBundle;
64
+ let gate;
65
+ return {
66
+ bundlePath,
67
+ run(command, payload) {
68
+ if (gate === undefined) {
69
+ try {
70
+ check(bundlePath, { override: config.actionsPath !== null });
71
+ gate = true;
72
+ }
73
+ catch (e) {
74
+ gate = e;
75
+ }
76
+ }
77
+ if (gate !== true)
78
+ return Promise.reject(gate);
79
+ return inner.run(command, payload);
80
+ },
81
+ stop: () => inner.stop(),
82
+ helperVersion: () => inner.helperVersion(),
83
+ };
84
+ }
85
+ //# sourceMappingURL=bundle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundle.js","sourceRoot":"","sources":["../src/bundle.ts"],"names":[],"mappings":"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"}