apple-mail-mcp 2.12.0 → 2.13.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/README.md +29 -3
- package/build/index.js +65 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1430,9 +1430,35 @@ Three more honesty rules:
|
|
|
1430
1430
|
than list positions — and `expected` stays comparable with the mailbox instead
|
|
1431
1431
|
of double-counting a duplicate into a false `over`.
|
|
1432
1432
|
|
|
1433
|
-
`imap:` ids are not reconciled
|
|
1434
|
-
one mailbox, so the mis-targeting class this exists for cannot
|
|
1435
|
-
batch of only `imap:` ids returns no `countDelta` rather than a
|
|
1433
|
+
`imap:` ids are not reconciled by `countDelta`. An IMAP UID names exactly one
|
|
1434
|
+
message in exactly one mailbox, so the mis-targeting class this exists for cannot
|
|
1435
|
+
occur there; a batch of only `imap:` ids returns no `countDelta` rather than a
|
|
1436
|
+
fabricated one.
|
|
1437
|
+
|
|
1438
|
+
They carry their own post-condition check instead. `delete-message` and
|
|
1439
|
+
`move-message` on an `imap:` id return a **`verification`** object in
|
|
1440
|
+
`structuredContent`:
|
|
1441
|
+
|
|
1442
|
+
```json
|
|
1443
|
+
{
|
|
1444
|
+
"verification": {
|
|
1445
|
+
"verdict": "verified",
|
|
1446
|
+
"how": "COPYUID: UID 5 arrived in \"Archive\" as UID 91"
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
```
|
|
1450
|
+
|
|
1451
|
+
| `verdict` | Meaning |
|
|
1452
|
+
|---|---|
|
|
1453
|
+
| `verified` | The effect was **observed** — either the server's UIDPLUS `COPYUID` named the message's new UID in the destination, or the UID is no longer in the source mailbox. |
|
|
1454
|
+
| `unverified` | The server **accepted** the command and nothing could confirm the effect. Populates `why`. |
|
|
1455
|
+
|
|
1456
|
+
`unverified` is **not a failure** and must not be rendered as one — it means
|
|
1457
|
+
"accepted, no observation either way". It is reported rather than hidden because
|
|
1458
|
+
an absent verification must never read as a successful one, the same rule the
|
|
1459
|
+
collateral diff follows. A message that is still in the source mailbox after an
|
|
1460
|
+
accepted move is reported `unverified` rather than failed, because a Gmail label
|
|
1461
|
+
store can legitimately keep a message visible in an all-mail view after a move.
|
|
1436
1462
|
|
|
1437
1463
|
### `APPLE_MAIL_MCP_AUDIT_LOG` — opt-in forensic log
|
|
1438
1464
|
|
package/build/index.js
CHANGED
|
@@ -83842,6 +83842,27 @@ function assertMutated(result, what) {
|
|
|
83842
83842
|
if (!result) throw new Error(`${what}: server rejected the command (IMAP NO/BAD)`);
|
|
83843
83843
|
return result;
|
|
83844
83844
|
}
|
|
83845
|
+
async function verifyMoved(client, moved, uid, srcPath, destPath) {
|
|
83846
|
+
const newUid = moved.uidMap?.get(uid);
|
|
83847
|
+
if (newUid !== void 0) {
|
|
83848
|
+
return {
|
|
83849
|
+
verdict: "verified",
|
|
83850
|
+
how: `COPYUID: UID ${uid} arrived in "${destPath}" as UID ${newUid}`
|
|
83851
|
+
};
|
|
83852
|
+
}
|
|
83853
|
+
try {
|
|
83854
|
+
const stillThere = await client.fetchOne(String(uid), { uid: true }, { uid: true });
|
|
83855
|
+
if (!stillThere) {
|
|
83856
|
+
return { verdict: "verified", how: `UID ${uid} is no longer present in "${srcPath}"` };
|
|
83857
|
+
}
|
|
83858
|
+
return {
|
|
83859
|
+
verdict: "unverified",
|
|
83860
|
+
why: `the server accepted the MOVE, but UID ${uid} is still present in "${srcPath}" and this server does not advertise UIDPLUS, so arrival in "${destPath}" could not be confirmed. A Gmail label store can legitimately keep a message in an all-mail view after a move, so this is not reported as a failure`
|
|
83861
|
+
};
|
|
83862
|
+
} catch (e) {
|
|
83863
|
+
return { verdict: "unverified", why: `the post-move check could not run: ${errText(e)}` };
|
|
83864
|
+
}
|
|
83865
|
+
}
|
|
83845
83866
|
var poolConnect = defaultConnect;
|
|
83846
83867
|
var pools = /* @__PURE__ */ new Map();
|
|
83847
83868
|
function poolKey(cfg) {
|
|
@@ -84180,11 +84201,16 @@ async function imapMoveMessageById(id, destMailbox, deps = {}) {
|
|
|
84180
84201
|
const destPath = dest.kind === "found" ? dest.path : resolveMailboxPath(destMailbox, "list");
|
|
84181
84202
|
const lock = await client.getMailboxLock(ref.path);
|
|
84182
84203
|
try {
|
|
84183
|
-
assertMutated(
|
|
84204
|
+
const moved = assertMutated(
|
|
84184
84205
|
await client.messageMove([ref.uid], destPath, { uid: true }),
|
|
84185
84206
|
`IMAP move of UID ${ref.uid} to "${destPath}"`
|
|
84186
84207
|
);
|
|
84187
|
-
|
|
84208
|
+
const verification = await verifyMoved(client, moved, ref.uid, ref.path, destPath);
|
|
84209
|
+
return {
|
|
84210
|
+
success: true,
|
|
84211
|
+
info: verification.verdict === "verified" ? `Moved UID ${ref.uid} to "${destPath}" via IMAP (verified: ${verification.how}).` : `Moved UID ${ref.uid} to "${destPath}" via IMAP \u2014 UNVERIFIED: ${verification.why}.`,
|
|
84212
|
+
verification
|
|
84213
|
+
};
|
|
84188
84214
|
} catch (e) {
|
|
84189
84215
|
return {
|
|
84190
84216
|
success: false,
|
|
@@ -84226,21 +84252,38 @@ async function trashUids(client, uids, srcPath) {
|
|
|
84226
84252
|
);
|
|
84227
84253
|
return { dest, expunged: true };
|
|
84228
84254
|
}
|
|
84229
|
-
assertMutated(
|
|
84255
|
+
const moved = assertMutated(
|
|
84230
84256
|
await client.messageMove(uids, dest, { uid: true }),
|
|
84231
84257
|
`IMAP move of ${uids.length} message(s) from "${srcPath}" to "${dest}"`
|
|
84232
84258
|
);
|
|
84233
|
-
return { dest, expunged: false };
|
|
84259
|
+
return { dest, expunged: false, moved };
|
|
84260
|
+
}
|
|
84261
|
+
async function verifyExpunged(client, uid, path) {
|
|
84262
|
+
try {
|
|
84263
|
+
const stillThere = await client.fetchOne(String(uid), { uid: true }, { uid: true });
|
|
84264
|
+
if (!stillThere) {
|
|
84265
|
+
return { verdict: "verified", how: `UID ${uid} is no longer present in "${path}"` };
|
|
84266
|
+
}
|
|
84267
|
+
return {
|
|
84268
|
+
verdict: "unverified",
|
|
84269
|
+
why: `the server accepted the EXPUNGE but UID ${uid} is still present in "${path}"`
|
|
84270
|
+
};
|
|
84271
|
+
} catch (e) {
|
|
84272
|
+
return { verdict: "unverified", why: `the post-delete check could not run: ${errText(e)}` };
|
|
84273
|
+
}
|
|
84234
84274
|
}
|
|
84235
84275
|
async function imapDeleteMessageById(id, deps = {}) {
|
|
84236
84276
|
const ref = decodeImapId(id);
|
|
84237
84277
|
if (!ref) return { success: false, error: `Not an IMAP message id: "${id}".` };
|
|
84238
84278
|
return withMailbox(ref.path, depsForMessageRef(ref, deps), async (client) => {
|
|
84239
84279
|
try {
|
|
84240
|
-
const { dest, expunged } = await trashUids(client, [ref.uid], ref.path);
|
|
84280
|
+
const { dest, expunged, moved } = await trashUids(client, [ref.uid], ref.path);
|
|
84281
|
+
const verification = expunged || !moved ? await verifyExpunged(client, ref.uid, ref.path) : await verifyMoved(client, moved, ref.uid, ref.path, dest);
|
|
84282
|
+
const what = expunged ? `Permanently deleted UID ${ref.uid} from Trash ("${ref.path}") via IMAP` : `Moved UID ${ref.uid} to Trash ("${dest}") via IMAP`;
|
|
84241
84283
|
return {
|
|
84242
84284
|
success: true,
|
|
84243
|
-
info:
|
|
84285
|
+
info: verification.verdict === "verified" ? `${what} (verified: ${verification.how}).` : `${what} \u2014 UNVERIFIED: ${verification.why}.`,
|
|
84286
|
+
verification
|
|
84244
84287
|
};
|
|
84245
84288
|
} catch (e) {
|
|
84246
84289
|
return { success: false, error: `IMAP delete failed for UID ${ref.uid}: ${errText(e)}` };
|
|
@@ -84820,10 +84863,12 @@ function formatMergedRows(rows, showReadState = true) {
|
|
|
84820
84863
|
async function routeMessage(id, opts) {
|
|
84821
84864
|
if (decodeImapId(id)) {
|
|
84822
84865
|
const r = await opts.imap();
|
|
84823
|
-
|
|
84866
|
+
if (!r.success) return errorResponse(r.error ?? opts.fail);
|
|
84867
|
+
const structured = opts.structuredFromResult ? opts.structuredFromResult(r) : opts.structured;
|
|
84868
|
+
return successResponse(
|
|
84824
84869
|
r.info ?? opts.ok,
|
|
84825
|
-
|
|
84826
|
-
)
|
|
84870
|
+
r.verification && structured ? { ...structured, verification: r.verification } : structured
|
|
84871
|
+
);
|
|
84827
84872
|
}
|
|
84828
84873
|
return opts.apple();
|
|
84829
84874
|
}
|
|
@@ -85387,6 +85432,13 @@ var COUNT_DELTA_OUTPUT_SCHEMA = external_exports.array(
|
|
|
85387
85432
|
note: external_exports.string().optional()
|
|
85388
85433
|
})
|
|
85389
85434
|
).optional();
|
|
85435
|
+
var VERIFICATION_OUTPUT_SCHEMA = external_exports.object({
|
|
85436
|
+
verdict: external_exports.enum(["verified", "unverified"]),
|
|
85437
|
+
/** Present on `verified`: what was observed. */
|
|
85438
|
+
how: external_exports.string().optional(),
|
|
85439
|
+
/** Present on `unverified`: why no observation was possible. */
|
|
85440
|
+
why: external_exports.string().optional()
|
|
85441
|
+
}).optional();
|
|
85390
85442
|
var CHECK_ITEM_SCHEMA = external_exports.object({}).passthrough();
|
|
85391
85443
|
var require2 = createRequire(import.meta.url);
|
|
85392
85444
|
var { version: version2 } = require2("../package.json");
|
|
@@ -86239,7 +86291,8 @@ registerTool(
|
|
|
86239
86291
|
outputSchema: {
|
|
86240
86292
|
ok: external_exports.boolean().optional(),
|
|
86241
86293
|
id: external_exports.string().optional(),
|
|
86242
|
-
countDelta: COUNT_DELTA_OUTPUT_SCHEMA
|
|
86294
|
+
countDelta: COUNT_DELTA_OUTPUT_SCHEMA,
|
|
86295
|
+
verification: VERIFICATION_OUTPUT_SCHEMA
|
|
86243
86296
|
}
|
|
86244
86297
|
},
|
|
86245
86298
|
withErrorHandling(
|
|
@@ -86279,7 +86332,8 @@ registerTool(
|
|
|
86279
86332
|
ok: external_exports.boolean().optional(),
|
|
86280
86333
|
id: external_exports.string().optional(),
|
|
86281
86334
|
mailbox: external_exports.string().optional(),
|
|
86282
|
-
countDelta: COUNT_DELTA_OUTPUT_SCHEMA
|
|
86335
|
+
countDelta: COUNT_DELTA_OUTPUT_SCHEMA,
|
|
86336
|
+
verification: VERIFICATION_OUTPUT_SCHEMA
|
|
86283
86337
|
}
|
|
86284
86338
|
},
|
|
86285
86339
|
withErrorHandling(
|
package/package.json
CHANGED