apple-mail-mcp 2.10.28 → 2.10.29
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 +13 -3
- package/build/cli.js +123 -34
- package/build/index.js +271 -189
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -311,7 +311,7 @@ Send a new email immediately.
|
|
|
311
311
|
| `cc` | string[] | No | CC recipients |
|
|
312
312
|
| `bcc` | string[] | No | BCC recipients |
|
|
313
313
|
| `account` | string | No | Mail.app account label, or an email-form SMTP From override. An SMTP override must match `APPLE_MAIL_MCP_SMTP_USER`, `APPLE_MAIL_MCP_SMTP_FROM`, or an address in `APPLE_MAIL_MCP_SMTP_ALLOWED_FROM` |
|
|
314
|
-
| `attachments` | (string \| {filename, contentBase64})[] | No | Up to 20 attachments: absolute file paths (e.g., `"/Users/me/report.pdf"`) and/or inline `{filename, contentBase64}` objects up to 25 MiB decoded each |
|
|
314
|
+
| `attachments` | (string \| {filename, contentBase64})[] | No | Up to 20 attachments: absolute file paths inside the configured read roots (e.g., `"/Users/me/Documents/report.pdf"`) and/or inline `{filename, contentBase64}` objects up to 25 MiB decoded each |
|
|
315
315
|
| `transport` | `"applescript"` \| `"smtp"` | No | Send transport. If omitted, **SMTP is used automatically when configured** (otherwise AppleScript). Pass `"smtp"` to require clean MIME, or `"applescript"` to force the Mail.app path — see [SMTP transport](#smtp-transport) |
|
|
316
316
|
|
|
317
317
|
**Example:**
|
|
@@ -665,7 +665,7 @@ Save an email to Drafts without sending.
|
|
|
665
665
|
| `cc` | string[] | No | CC recipients |
|
|
666
666
|
| `bcc` | string[] | No | BCC recipients |
|
|
667
667
|
| `account` | string | No | Account for draft |
|
|
668
|
-
| `attachments` | (string \| {filename, contentBase64})[] | No | Up to 20 attachments: absolute file paths and/or inline `{filename, contentBase64}` objects up to 25 MiB decoded each |
|
|
668
|
+
| `attachments` | (string \| {filename, contentBase64})[] | No | Up to 20 attachments: absolute file paths inside the configured read roots and/or inline `{filename, contentBase64}` objects up to 25 MiB decoded each |
|
|
669
669
|
|
|
670
670
|
**Returns:** Confirmation that draft was created.
|
|
671
671
|
|
|
@@ -1604,6 +1604,16 @@ The entrypoint is written as:
|
|
|
1604
1604
|
- **Permission required** - macOS will prompt for automation permission on first use.
|
|
1605
1605
|
- **No credential storage** - The server doesn't store any passwords or authentication tokens.
|
|
1606
1606
|
- **Email safety** - Use `create-draft` to review emails before sending.
|
|
1607
|
+
- **Attachment read boundary** - Outbound file attachments may come from
|
|
1608
|
+
ordinary files under the home directory, `/Volumes`, or temporary directories
|
|
1609
|
+
by default. Hidden files and known credential/configuration locations
|
|
1610
|
+
(including `.ssh`, `.aws`, `.config/gh`, Keychains, and
|
|
1611
|
+
application `config.json` files) are denied. Set
|
|
1612
|
+
`APPLE_MAIL_MCP_ATTACHMENT_READ_ROOTS` to a colon-separated list of explicit
|
|
1613
|
+
absolute additional roots when a deliberate other location is required.
|
|
1614
|
+
Paths are canonicalized before use, so symlink escapes are rejected. `/tmp`
|
|
1615
|
+
is world-writable and is a convenience root, not a user-content trust
|
|
1616
|
+
boundary. Inline base64 attachments are unaffected.
|
|
1607
1617
|
|
|
1608
1618
|
---
|
|
1609
1619
|
|
|
@@ -1613,7 +1623,7 @@ The entrypoint is written as:
|
|
|
1613
1623
|
|------------|--------|
|
|
1614
1624
|
| macOS only | Apple Mail and AppleScript are macOS-specific |
|
|
1615
1625
|
| MCP `send-email` is plain-text | The `send-email` tool sends plain text (reading HTML content is supported). To send HTML, use the bundled `apple-mail-send` CLI with `--html-body-file` (sends `multipart/alternative` via SMTP) |
|
|
1616
|
-
|
|
|
1626
|
+
| Attachment read path restrictions | Outbound file attachments must use full absolute paths inside the default home-directory, `/Volumes`, or temporary roots, except hidden files and protected credential/configuration locations. Set `APPLE_MAIL_MCP_ATTACHMENT_READ_ROOTS` to add an explicit absolute root for another deliberate location; symlink escapes are rejected. |
|
|
1617
1627
|
| Smart mailboxes need Mail quit | Smart mailboxes are supported (see [Smart Mailbox Operations](#smart-mailbox-operations-intelligente-postfächer)), but `create-`/`delete-smart-mailbox` edit `SyncedSmartMailboxes.plist` directly — a running Mail may not show a new one until relaunched, and can overwrite plist edits it didn't make. Quit Mail first. Reading them needs Full Disk Access for the Node runtime |
|
|
1618
1628
|
| Very large mailboxes not searchable *via AppleScript* | Apple Mail's AppleScript bridge times out on mailboxes with tens of thousands of messages, so unscoped `search-messages` skips mailboxes above `APPLE_MAIL_MAX_SEARCH_MAILBOX` (default 5000) and reports them as a partial result. Scope with `mailbox` + a date window — or configure the [IMAP backend](#imap-backend--opt-in), which searches these server-side in well under a second. ([#24](https://github.com/sweetrb/apple-mail-mcp/issues/24)) |
|
|
1619
1629
|
| Can't delete/rename server-side mailboxes or mutate drafts *via AppleScript* | Mail.app's AppleScript bridge can only `delete`/`rename` **local "On My Mac"** mailboxes and cannot delete/move drafts — it throws `AppleEvent handler failed` for IMAP/Gmail/Workspace/iCloud/Exchange mailboxes (the GUI can do it). Without IMAP configured, `delete-mailbox`/`rename-mailbox`/`delete-message`/`move-message` return a clear "do it in Mail.app directly" error instead of a generic failure. With the [IMAP backend](#imap-backend--opt-in) configured for the account, these operations run via IMAP and succeed. ([#42](https://github.com/sweetrb/apple-mail-mcp/issues/42)) |
|
package/build/cli.js
CHANGED
|
@@ -48,7 +48,7 @@ var require_punycode = __commonJS({
|
|
|
48
48
|
var damp = 700;
|
|
49
49
|
var initialBias = 72;
|
|
50
50
|
var initialN = 128;
|
|
51
|
-
var
|
|
51
|
+
var delimiter2 = "-";
|
|
52
52
|
var regexPunycode = /^xn--/;
|
|
53
53
|
var regexNonASCII = /[^\0-\x7F]/;
|
|
54
54
|
var regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g;
|
|
@@ -139,7 +139,7 @@ var require_punycode = __commonJS({
|
|
|
139
139
|
let i = 0;
|
|
140
140
|
let n = initialN;
|
|
141
141
|
let bias = initialBias;
|
|
142
|
-
let basic = input.lastIndexOf(
|
|
142
|
+
let basic = input.lastIndexOf(delimiter2);
|
|
143
143
|
if (basic < 0) {
|
|
144
144
|
basic = 0;
|
|
145
145
|
}
|
|
@@ -199,7 +199,7 @@ var require_punycode = __commonJS({
|
|
|
199
199
|
const basicLength = output.length;
|
|
200
200
|
let handledCPCount = basicLength;
|
|
201
201
|
if (basicLength) {
|
|
202
|
-
output.push(
|
|
202
|
+
output.push(delimiter2);
|
|
203
203
|
}
|
|
204
204
|
while (handledCPCount < inputLength) {
|
|
205
205
|
let m = maxInt;
|
|
@@ -954,7 +954,7 @@ var require_shared = __commonJS({
|
|
|
954
954
|
}
|
|
955
955
|
return Object.keys(ifaces).map((key) => ifaces[key]).reduce((acc, val) => acc.concat(val), []).filter((i) => !i.internal || allowInternal).some((i) => i.family === "IPv" + family || i.family === family);
|
|
956
956
|
};
|
|
957
|
-
var
|
|
957
|
+
var resolve2 = (family, hostname, options, callback) => {
|
|
958
958
|
options = options || {};
|
|
959
959
|
if (!isFamilySupported(family, options.allowInternalNetworkInterfaces)) {
|
|
960
960
|
return callback(null, []);
|
|
@@ -1041,13 +1041,13 @@ var require_shared = __commonJS({
|
|
|
1041
1041
|
let ipv6Addresses = [];
|
|
1042
1042
|
let ipv4Error = null;
|
|
1043
1043
|
let ipv6Error = null;
|
|
1044
|
-
|
|
1044
|
+
resolve2(4, options.host, options, (err, addresses) => {
|
|
1045
1045
|
if (err) {
|
|
1046
1046
|
ipv4Error = err;
|
|
1047
1047
|
} else {
|
|
1048
1048
|
ipv4Addresses = addresses || [];
|
|
1049
1049
|
}
|
|
1050
|
-
|
|
1050
|
+
resolve2(6, options.host, options, (err2, addresses2) => {
|
|
1051
1051
|
if (err2) {
|
|
1052
1052
|
ipv6Error = err2;
|
|
1053
1053
|
} else {
|
|
@@ -1236,13 +1236,13 @@ var require_shared = __commonJS({
|
|
|
1236
1236
|
});
|
|
1237
1237
|
return response;
|
|
1238
1238
|
};
|
|
1239
|
-
module.exports.callbackPromise = (
|
|
1239
|
+
module.exports.callbackPromise = (resolve3, reject) => function() {
|
|
1240
1240
|
const args = Array.from(arguments);
|
|
1241
1241
|
const err = args.shift();
|
|
1242
1242
|
if (err) {
|
|
1243
1243
|
reject(err);
|
|
1244
1244
|
} else {
|
|
1245
|
-
|
|
1245
|
+
resolve3(...args);
|
|
1246
1246
|
}
|
|
1247
1247
|
};
|
|
1248
1248
|
module.exports.parseDataURI = (uri) => {
|
|
@@ -1309,8 +1309,8 @@ var require_shared = __commonJS({
|
|
|
1309
1309
|
options = options || {};
|
|
1310
1310
|
let promise;
|
|
1311
1311
|
if (!callback) {
|
|
1312
|
-
promise = new Promise((
|
|
1313
|
-
callback = module.exports.callbackPromise(
|
|
1312
|
+
promise = new Promise((resolve3, reject) => {
|
|
1313
|
+
callback = module.exports.callbackPromise(resolve3, reject);
|
|
1314
1314
|
});
|
|
1315
1315
|
}
|
|
1316
1316
|
resolveContentValue(data, key, options, callback);
|
|
@@ -4981,8 +4981,8 @@ var require_mime_node = __commonJS({
|
|
|
4981
4981
|
build(callback) {
|
|
4982
4982
|
let promise;
|
|
4983
4983
|
if (!callback) {
|
|
4984
|
-
promise = new Promise((
|
|
4985
|
-
callback = shared.callbackPromise(
|
|
4984
|
+
promise = new Promise((resolve2, reject) => {
|
|
4985
|
+
callback = shared.callbackPromise(resolve2, reject);
|
|
4986
4986
|
});
|
|
4987
4987
|
}
|
|
4988
4988
|
const stream = this.createReadStream();
|
|
@@ -7211,8 +7211,8 @@ var require_mailer = __commonJS({
|
|
|
7211
7211
|
sendMail(data, callback = null) {
|
|
7212
7212
|
let promise;
|
|
7213
7213
|
if (!callback) {
|
|
7214
|
-
promise = new Promise((
|
|
7215
|
-
callback = shared.callbackPromise(
|
|
7214
|
+
promise = new Promise((resolve2, reject) => {
|
|
7215
|
+
callback = shared.callbackPromise(resolve2, reject);
|
|
7216
7216
|
});
|
|
7217
7217
|
}
|
|
7218
7218
|
if (typeof this.getSocket === "function") {
|
|
@@ -7920,7 +7920,7 @@ var require_smtp_connection = __commonJS({
|
|
|
7920
7920
|
const handler = this.customAuth.get(this._authMethod);
|
|
7921
7921
|
let lastResponse;
|
|
7922
7922
|
let returned = false;
|
|
7923
|
-
const
|
|
7923
|
+
const resolve2 = () => {
|
|
7924
7924
|
if (returned) {
|
|
7925
7925
|
return;
|
|
7926
7926
|
}
|
|
@@ -7954,8 +7954,8 @@ var require_smtp_connection = __commonJS({
|
|
|
7954
7954
|
sendCommand: (cmd, done) => {
|
|
7955
7955
|
let promise;
|
|
7956
7956
|
if (!done) {
|
|
7957
|
-
promise = new Promise((
|
|
7958
|
-
done = shared.callbackPromise(
|
|
7957
|
+
promise = new Promise((resolve3, reject2) => {
|
|
7958
|
+
done = shared.callbackPromise(resolve3, reject2);
|
|
7959
7959
|
});
|
|
7960
7960
|
}
|
|
7961
7961
|
this._responseActions.push((str) => {
|
|
@@ -7980,11 +7980,11 @@ var require_smtp_connection = __commonJS({
|
|
|
7980
7980
|
setImmediate(() => this._sendCommand(cmd));
|
|
7981
7981
|
return promise;
|
|
7982
7982
|
},
|
|
7983
|
-
resolve,
|
|
7983
|
+
resolve: resolve2,
|
|
7984
7984
|
reject
|
|
7985
7985
|
});
|
|
7986
7986
|
if (handlerResponse && typeof handlerResponse.catch === "function") {
|
|
7987
|
-
handlerResponse.then(
|
|
7987
|
+
handlerResponse.then(resolve2).catch(reject);
|
|
7988
7988
|
}
|
|
7989
7989
|
return;
|
|
7990
7990
|
}
|
|
@@ -10695,8 +10695,8 @@ var require_smtp_pool = __commonJS({
|
|
|
10695
10695
|
verify(callback) {
|
|
10696
10696
|
let promise;
|
|
10697
10697
|
if (!callback) {
|
|
10698
|
-
promise = new Promise((
|
|
10699
|
-
callback = shared.callbackPromise(
|
|
10698
|
+
promise = new Promise((resolve2, reject) => {
|
|
10699
|
+
callback = shared.callbackPromise(resolve2, reject);
|
|
10700
10700
|
});
|
|
10701
10701
|
}
|
|
10702
10702
|
const auth = new PoolResource(this).auth;
|
|
@@ -11043,8 +11043,8 @@ var require_smtp_transport = __commonJS({
|
|
|
11043
11043
|
verify(callback) {
|
|
11044
11044
|
let promise;
|
|
11045
11045
|
if (!callback) {
|
|
11046
|
-
promise = new Promise((
|
|
11047
|
-
callback = shared.callbackPromise(
|
|
11046
|
+
promise = new Promise((resolve2, reject) => {
|
|
11047
|
+
callback = shared.callbackPromise(resolve2, reject);
|
|
11048
11048
|
});
|
|
11049
11049
|
}
|
|
11050
11050
|
this.getSocket(this.options, (err, socketOptions) => {
|
|
@@ -11697,8 +11697,8 @@ var require_ses_transport = __commonJS({
|
|
|
11697
11697
|
verify(callback) {
|
|
11698
11698
|
let promise;
|
|
11699
11699
|
if (!callback) {
|
|
11700
|
-
promise = new Promise((
|
|
11701
|
-
callback = shared.callbackPromise(
|
|
11700
|
+
promise = new Promise((resolve2, reject) => {
|
|
11701
|
+
callback = shared.callbackPromise(resolve2, reject);
|
|
11702
11702
|
});
|
|
11703
11703
|
}
|
|
11704
11704
|
const cb = (err) => {
|
|
@@ -11799,8 +11799,8 @@ var require_nodemailer = __commonJS({
|
|
|
11799
11799
|
apiUrl = false;
|
|
11800
11800
|
}
|
|
11801
11801
|
if (!callback) {
|
|
11802
|
-
promise = new Promise((
|
|
11803
|
-
callback = shared.callbackPromise(
|
|
11802
|
+
promise = new Promise((resolve2, reject) => {
|
|
11803
|
+
callback = shared.callbackPromise(resolve2, reject);
|
|
11804
11804
|
});
|
|
11805
11805
|
}
|
|
11806
11806
|
if (ETHEREAL_CACHE && testAccount) {
|
|
@@ -11877,15 +11877,13 @@ var require_nodemailer = __commonJS({
|
|
|
11877
11877
|
});
|
|
11878
11878
|
|
|
11879
11879
|
// src/cli.ts
|
|
11880
|
-
import { readFileSync, realpathSync } from "fs";
|
|
11880
|
+
import { readFileSync, realpathSync as realpathSync2 } from "fs";
|
|
11881
11881
|
import { fileURLToPath } from "url";
|
|
11882
11882
|
import { parseArgs } from "util";
|
|
11883
11883
|
|
|
11884
11884
|
// src/services/smtpMailer.ts
|
|
11885
11885
|
var import_nodemailer = __toESM(require_nodemailer(), 1);
|
|
11886
11886
|
import { execFileSync } from "child_process";
|
|
11887
|
-
import { isAbsolute } from "path";
|
|
11888
|
-
import { existsSync } from "fs";
|
|
11889
11887
|
|
|
11890
11888
|
// src/utils/attachmentLimits.ts
|
|
11891
11889
|
var MAX_INLINE_ATTACHMENT_BYTES = 25 * 1024 * 1024;
|
|
@@ -11910,6 +11908,99 @@ function decodeInlineAttachment(contentBase64) {
|
|
|
11910
11908
|
return content;
|
|
11911
11909
|
}
|
|
11912
11910
|
|
|
11911
|
+
// src/utils/attachmentReadPolicy.ts
|
|
11912
|
+
import { realpathSync, statSync } from "fs";
|
|
11913
|
+
import { homedir, tmpdir } from "os";
|
|
11914
|
+
import { delimiter, isAbsolute, join, resolve, sep } from "path";
|
|
11915
|
+
var ATTACHMENT_READ_ROOTS_ENV = "APPLE_MAIL_MCP_ATTACHMENT_READ_ROOTS";
|
|
11916
|
+
var DEFAULT_ATTACHMENT_READ_ROOTS = [homedir(), "/Volumes", tmpdir(), "/tmp", "/private/tmp"];
|
|
11917
|
+
var SENSITIVE_HOME_ROOTS = [
|
|
11918
|
+
join(homedir(), ".ssh"),
|
|
11919
|
+
join(homedir(), ".aws"),
|
|
11920
|
+
join(homedir(), ".config", "gh"),
|
|
11921
|
+
join(homedir(), "Library", "Keychains")
|
|
11922
|
+
];
|
|
11923
|
+
function canonicalize(path) {
|
|
11924
|
+
return realpathSync.native(path);
|
|
11925
|
+
}
|
|
11926
|
+
function sensitiveRoots() {
|
|
11927
|
+
return SENSITIVE_HOME_ROOTS.map((root) => {
|
|
11928
|
+
try {
|
|
11929
|
+
return canonicalize(root);
|
|
11930
|
+
} catch {
|
|
11931
|
+
return root;
|
|
11932
|
+
}
|
|
11933
|
+
});
|
|
11934
|
+
}
|
|
11935
|
+
function isWithinRoot(candidate, root) {
|
|
11936
|
+
return candidate === root || candidate.startsWith(root + sep);
|
|
11937
|
+
}
|
|
11938
|
+
function hasHiddenPathSegment(candidate) {
|
|
11939
|
+
return candidate.split(sep).some((segment) => segment.startsWith(".") && segment.length > 1);
|
|
11940
|
+
}
|
|
11941
|
+
function isProtectedPath(candidate) {
|
|
11942
|
+
if (hasHiddenPathSegment(candidate)) return true;
|
|
11943
|
+
if (sensitiveRoots().some((root) => isWithinRoot(candidate, root))) return true;
|
|
11944
|
+
let home;
|
|
11945
|
+
try {
|
|
11946
|
+
home = canonicalize(homedir());
|
|
11947
|
+
} catch {
|
|
11948
|
+
home = resolve(homedir());
|
|
11949
|
+
}
|
|
11950
|
+
if (!isWithinRoot(candidate, home)) return false;
|
|
11951
|
+
const relative = candidate.slice(home.length).split(sep).filter(Boolean);
|
|
11952
|
+
return relative.length >= 4 && relative[0].toLowerCase() === "library" && relative[1].toLowerCase() === "application support" && relative.at(-1)?.toLowerCase() === "config.json";
|
|
11953
|
+
}
|
|
11954
|
+
function configuredRoots(env) {
|
|
11955
|
+
const raw = env[ATTACHMENT_READ_ROOTS_ENV];
|
|
11956
|
+
const extraRoots = raw === void 0 ? [] : raw.split(delimiter).map((root) => root.trim()).filter(Boolean);
|
|
11957
|
+
const requested = [...DEFAULT_ATTACHMENT_READ_ROOTS, ...extraRoots];
|
|
11958
|
+
for (const root of requested) {
|
|
11959
|
+
if (!isAbsolute(root)) {
|
|
11960
|
+
throw new Error(`${ATTACHMENT_READ_ROOTS_ENV} entries must be absolute paths.`);
|
|
11961
|
+
}
|
|
11962
|
+
}
|
|
11963
|
+
const resolved = [];
|
|
11964
|
+
for (const root of requested) {
|
|
11965
|
+
try {
|
|
11966
|
+
const canonical = canonicalize(resolve(root));
|
|
11967
|
+
if (!resolved.includes(canonical)) resolved.push(canonical);
|
|
11968
|
+
} catch {
|
|
11969
|
+
}
|
|
11970
|
+
}
|
|
11971
|
+
return resolved;
|
|
11972
|
+
}
|
|
11973
|
+
function resolveAttachmentReadPath(filePath, env = process.env) {
|
|
11974
|
+
if (!isAbsolute(filePath)) {
|
|
11975
|
+
throw new Error(`Attachment path must be absolute: "${filePath}"`);
|
|
11976
|
+
}
|
|
11977
|
+
let canonical;
|
|
11978
|
+
try {
|
|
11979
|
+
canonical = canonicalize(filePath);
|
|
11980
|
+
} catch {
|
|
11981
|
+
throw new Error(`Attachment file not found: "${filePath}"`);
|
|
11982
|
+
}
|
|
11983
|
+
try {
|
|
11984
|
+
if (!statSync(canonical).isFile()) {
|
|
11985
|
+
throw new Error(`Attachment path is not a regular file: "${filePath}"`);
|
|
11986
|
+
}
|
|
11987
|
+
} catch (error) {
|
|
11988
|
+
if (error instanceof Error && error.message.includes("not a regular file")) throw error;
|
|
11989
|
+
throw new Error(`Attachment file not found: "${filePath}"`);
|
|
11990
|
+
}
|
|
11991
|
+
if (isProtectedPath(canonical)) {
|
|
11992
|
+
throw new Error(
|
|
11993
|
+
`Attachment path is in a protected location: "${filePath}". Hidden files and credential/configuration locations cannot be sent as attachments.`
|
|
11994
|
+
);
|
|
11995
|
+
}
|
|
11996
|
+
if (!configuredRoots(env).some((root) => isWithinRoot(canonical, root))) {
|
|
11997
|
+
throw new Error(
|
|
11998
|
+
`Attachment path is outside the allowed read roots: "${filePath}". Use an ordinary home-directory, /Volumes, or temporary path, or configure ${ATTACHMENT_READ_ROOTS_ENV} for an additional explicit root.`
|
|
11999
|
+
);
|
|
12000
|
+
}
|
|
12001
|
+
return canonical;
|
|
12002
|
+
}
|
|
12003
|
+
|
|
11913
12004
|
// src/utils/docsUrls.ts
|
|
11914
12005
|
var SETUP_GUIDE_URL = "https://github.com/sweetrb/apple-mail-mcp/blob/main/docs/IMAP-SETUP.md";
|
|
11915
12006
|
var SETUP_HINT = `Setup guide: ${SETUP_GUIDE_URL} \u2014 run the "doctor" tool to check your setup.`;
|
|
@@ -11986,9 +12077,7 @@ function buildAttachments(attachments) {
|
|
|
11986
12077
|
if (!attachments || attachments.length === 0) return void 0;
|
|
11987
12078
|
return attachments.map((a) => {
|
|
11988
12079
|
if (typeof a === "string") {
|
|
11989
|
-
|
|
11990
|
-
if (!existsSync(a)) throw new Error(`Attachment file not found: "${a}"`);
|
|
11991
|
-
return { path: a };
|
|
12080
|
+
return { path: resolveAttachmentReadPath(a) };
|
|
11992
12081
|
}
|
|
11993
12082
|
if (!a.filename || !a.contentBase64) {
|
|
11994
12083
|
throw new Error("Inline attachment requires both filename and contentBase64.");
|
|
@@ -12171,7 +12260,7 @@ async function runCli(argv, deps = {}) {
|
|
|
12171
12260
|
function isInvokedDirectly() {
|
|
12172
12261
|
if (typeof process === "undefined" || !process.argv?.[1]) return false;
|
|
12173
12262
|
try {
|
|
12174
|
-
return
|
|
12263
|
+
return realpathSync2(process.argv[1]) === fileURLToPath(import.meta.url);
|
|
12175
12264
|
} catch {
|
|
12176
12265
|
return false;
|
|
12177
12266
|
}
|