apple-notes-mcp 2.8.40 → 2.8.42
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 +1 -1
- package/build/index.js +41 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1602,7 +1602,7 @@ Saves a note attachment to disk.
|
|
|
1602
1602
|
|-----------|------|----------|-------------|
|
|
1603
1603
|
| `noteId` | string | Yes | CoreData note ID (from `search-notes`/`list-notes`) |
|
|
1604
1604
|
| `attachmentId` | string | Yes | Attachment ID (from `list-attachments`) |
|
|
1605
|
-
| `savePath` | string | Yes | Absolute destination file path. Must be under your home directory, a temp directory, or `/Volumes` |
|
|
1605
|
+
| `savePath` | string | Yes | Absolute destination file path. Must be under your home directory, a temp directory, or `/Volumes`, and never inside the Notes data folder (`~/Library/Group Containers/group.com.apple.notes`), however it is reached (symlink or different letter case) |
|
|
1606
1606
|
|
|
1607
1607
|
**Returns:** Confirmation with the saved path, name, and content type (also in `structuredContent`).
|
|
1608
1608
|
|
package/build/index.js
CHANGED
|
@@ -39615,6 +39615,22 @@ import { createHash } from "node:crypto";
|
|
|
39615
39615
|
import { homedir as homedir2 } from "node:os";
|
|
39616
39616
|
import { join as join2 } from "node:path";
|
|
39617
39617
|
import { gunzipSync as gunzipSync2 } from "node:zlib";
|
|
39618
|
+
|
|
39619
|
+
// src/utils/uniqueById.ts
|
|
39620
|
+
function uniqueById(items) {
|
|
39621
|
+
const seen = /* @__PURE__ */ new Set();
|
|
39622
|
+
const result = [];
|
|
39623
|
+
for (const item of items) {
|
|
39624
|
+
if (item.id) {
|
|
39625
|
+
if (seen.has(item.id)) continue;
|
|
39626
|
+
seen.add(item.id);
|
|
39627
|
+
}
|
|
39628
|
+
result.push(item);
|
|
39629
|
+
}
|
|
39630
|
+
return result;
|
|
39631
|
+
}
|
|
39632
|
+
|
|
39633
|
+
// src/utils/noteRichText.ts
|
|
39618
39634
|
var HTML_LOSSY_ORDER = [
|
|
39619
39635
|
"superscript",
|
|
39620
39636
|
"subscript",
|
|
@@ -39706,14 +39722,15 @@ function parseRichNote(data, nativeTags = []) {
|
|
|
39706
39722
|
hasNativeObjects ||= Boolean(getField(fields, 12));
|
|
39707
39723
|
const attachment = embeddedMessage(getField(fields, 12));
|
|
39708
39724
|
const attachmentId = attachment && stringValue(getField(attachment, 1));
|
|
39709
|
-
if (attachmentId
|
|
39710
|
-
|
|
39725
|
+
if (attachment && attachmentId && !nativeObjectIds.includes(attachmentId)) {
|
|
39726
|
+
nativeObjectIds.push(attachmentId);
|
|
39711
39727
|
objects.push({
|
|
39712
39728
|
id: attachmentId,
|
|
39713
39729
|
type: stringValue(getField(attachment, 2)) || "unknown",
|
|
39714
39730
|
start: position,
|
|
39715
39731
|
length
|
|
39716
39732
|
});
|
|
39733
|
+
}
|
|
39717
39734
|
hasChecklist ||= Boolean(paragraph && varintValue(getField(paragraph, 1)) === 103);
|
|
39718
39735
|
if (paragraph && varintValue(getField(paragraph, 1)) === 103) {
|
|
39719
39736
|
const checklist = embeddedMessage(getField(paragraph, 5));
|
|
@@ -39771,7 +39788,9 @@ function readRichNote(id2) {
|
|
|
39771
39788
|
(row) => !row || typeof row.id !== "string" || !Number.isInteger(row.pk) || typeof row.mergeable !== "string" || !/^[0-9a-f]*$/i.test(row.mergeable)
|
|
39772
39789
|
))
|
|
39773
39790
|
throw new Error("Invalid native object metadata");
|
|
39774
|
-
rich.objectData =
|
|
39791
|
+
rich.objectData = uniqueById(
|
|
39792
|
+
objectData.filter((row) => rich.nativeObjectIds.includes(row.id)).sort((a, b) => a.id.localeCompare(b.id))
|
|
39793
|
+
);
|
|
39775
39794
|
rich.revision = createHash("sha256").update(rich.revision).update(JSON.stringify(rich.objectData)).digest("hex");
|
|
39776
39795
|
rich.nativeTagObjectIds = {};
|
|
39777
39796
|
for (const id3 of rich.nativeObjectIds)
|
|
@@ -40942,6 +40961,9 @@ function allowedSaveRoots() {
|
|
|
40942
40961
|
"/private/tmp"
|
|
40943
40962
|
];
|
|
40944
40963
|
}
|
|
40964
|
+
function deniedSaveRoots() {
|
|
40965
|
+
return [join6(homedir6(), "Library/Group Containers/group.com.apple.notes")];
|
|
40966
|
+
}
|
|
40945
40967
|
function canonicalize(path9) {
|
|
40946
40968
|
return realpathSync.native(path9);
|
|
40947
40969
|
}
|
|
@@ -40983,11 +41005,11 @@ function deepestExistingAncestor(abs) {
|
|
|
40983
41005
|
current = parent;
|
|
40984
41006
|
}
|
|
40985
41007
|
}
|
|
40986
|
-
function ensureParentDir(abs, roots = allowedSaveRoots()) {
|
|
40987
|
-
assertSafeSavePath(abs, roots);
|
|
41008
|
+
function ensureParentDir(abs, roots = allowedSaveRoots(), denied = deniedSaveRoots()) {
|
|
41009
|
+
assertSafeSavePath(abs, roots, denied);
|
|
40988
41010
|
mkdirSync(dirname(abs), { recursive: true });
|
|
40989
41011
|
}
|
|
40990
|
-
function assertSafeSavePath(p, roots = allowedSaveRoots()) {
|
|
41012
|
+
function assertSafeSavePath(p, roots = allowedSaveRoots(), denied = deniedSaveRoots()) {
|
|
40991
41013
|
if (!p || !p.trim()) throw new Error("A destination path is required.");
|
|
40992
41014
|
if (!isAbsolute(p)) throw new Error(`Destination path must be absolute: "${p}"`);
|
|
40993
41015
|
const abs = resolve(p);
|
|
@@ -41015,6 +41037,12 @@ function assertSafeSavePath(p, roots = allowedSaveRoots()) {
|
|
|
41015
41037
|
`Refusing to write outside allowed locations (home, temp, /Volumes): "${abs}" resolves to "${canonicalDest}" through a symbolic link.`
|
|
41016
41038
|
);
|
|
41017
41039
|
}
|
|
41040
|
+
const deniedForms = [
|
|
41041
|
+
.../* @__PURE__ */ new Set([...denied.map((d) => resolve(d)), ...canonicalRoots(denied)])
|
|
41042
|
+
].map((d) => d.toLowerCase());
|
|
41043
|
+
if ([abs, canonicalDest].some((form) => isWithinRoots(form.toLowerCase(), deniedForms))) {
|
|
41044
|
+
throw new Error(`Refusing to write inside the Notes library container: "${abs}"`);
|
|
41045
|
+
}
|
|
41018
41046
|
return abs;
|
|
41019
41047
|
}
|
|
41020
41048
|
var DEFAULT_MAX_ATTACHMENT_BYTES = 25 * 1024 * 1024;
|
|
@@ -43237,7 +43265,7 @@ var AppleNotesManager = class {
|
|
|
43237
43265
|
}
|
|
43238
43266
|
}
|
|
43239
43267
|
}
|
|
43240
|
-
return sharedNotes;
|
|
43268
|
+
return uniqueById(sharedNotes);
|
|
43241
43269
|
}
|
|
43242
43270
|
// ===========================================================================
|
|
43243
43271
|
// Folder Operations
|
|
@@ -44076,7 +44104,7 @@ var AppleNotesManager = class {
|
|
|
44076
44104
|
});
|
|
44077
44105
|
}
|
|
44078
44106
|
}
|
|
44079
|
-
return attachments;
|
|
44107
|
+
return uniqueById(attachments);
|
|
44080
44108
|
}
|
|
44081
44109
|
/**
|
|
44082
44110
|
* Lists attachments for a note by its title.
|
|
@@ -44163,7 +44191,7 @@ var AppleNotesManager = class {
|
|
|
44163
44191
|
});
|
|
44164
44192
|
}
|
|
44165
44193
|
}
|
|
44166
|
-
return attachments;
|
|
44194
|
+
return uniqueById(attachments);
|
|
44167
44195
|
}
|
|
44168
44196
|
/**
|
|
44169
44197
|
* Saves a single attachment of a note (identified by attachment id) to a file
|
|
@@ -52745,13 +52773,15 @@ registerTool(
|
|
|
52745
52773
|
registerTool(
|
|
52746
52774
|
"save-attachment",
|
|
52747
52775
|
{
|
|
52748
|
-
description: "Use when: writing one note attachment to a file on disk.\nReturns: the saved path.\nDo not use when: you want the bytes in-memory as base64 (fetch-attachment).\nSafety: writes a file; savePath must be absolute and under the home directory, a temp dir, or /Volumes. Get the ids from list-attachments first.",
|
|
52776
|
+
description: "Use when: writing one note attachment to a file on disk.\nReturns: the saved path.\nDo not use when: you want the bytes in-memory as base64 (fetch-attachment).\nSafety: writes a file; savePath must be absolute and under the home directory, a temp dir, or /Volumes, and not inside the Notes data folder. Get the ids from list-attachments first.",
|
|
52749
52777
|
inputSchema: {
|
|
52750
52778
|
noteId: looseNoteId(external_exports.string().min(1, "noteId is required")).describe(
|
|
52751
52779
|
`Note id (from search/list): ${NOTE_ID_FORMS}`
|
|
52752
52780
|
),
|
|
52753
52781
|
attachmentId: external_exports.string().min(1, "attachmentId is required").max(MAX.ATTACHMENT_ID).describe("Attachment id (from list-attachments)"),
|
|
52754
|
-
savePath: external_exports.string().min(1, "savePath is required").max(MAX.SAVE_PATH).describe(
|
|
52782
|
+
savePath: external_exports.string().min(1, "savePath is required").max(MAX.SAVE_PATH).describe(
|
|
52783
|
+
"Absolute destination file path (must be under home, temp, or /Volumes; never inside the Notes data folder)"
|
|
52784
|
+
)
|
|
52755
52785
|
},
|
|
52756
52786
|
outputSchema: {
|
|
52757
52787
|
savedPath: external_exports.string().optional(),
|
package/package.json
CHANGED