apple-notes-mcp 2.8.39 → 2.8.41
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 +5 -0
- package/build/index.js +62 -26
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -555,6 +555,11 @@ changed after this read. With Full Disk Access, embedded URLs omitted by
|
|
|
555
555
|
AppleScript are restored and returned in `links`. The response also reports
|
|
556
556
|
actual `nativeTags`, `richContentComplete`, and `writable`. Textual `hashtags`
|
|
557
557
|
remain a separate field and are not proof that Notes registered native tags.
|
|
558
|
+
`writable` is also false when the note uses formatting that AppleScript's HTML
|
|
559
|
+
does not carry (superscript, subscript, non-left paragraph alignment, or
|
|
560
|
+
highlight): a full-body `update-note` would silently drop it, so it is refused
|
|
561
|
+
and the `warning` names the formatting. `append-to-note` with `scopeText` still
|
|
562
|
+
works through the native path, which verifies existing formatting.
|
|
558
563
|
|
|
559
564
|
**⚠️ The returned body can be lossy — do not write it back verbatim.** Inline
|
|
560
565
|
base64 images larger than `APPLE_NOTES_MCP_MAX_INLINE_IMAGE_BYTES` (default
|
package/build/index.js
CHANGED
|
@@ -39275,21 +39275,13 @@ var WIRE_TYPE = {
|
|
|
39275
39275
|
};
|
|
39276
39276
|
function decodeVarint(buf, offset) {
|
|
39277
39277
|
let result = 0;
|
|
39278
|
-
let shift = 0;
|
|
39279
|
-
|
|
39280
|
-
while (pos < buf.length) {
|
|
39281
|
-
const byte = buf[pos];
|
|
39278
|
+
for (let pos = offset, shift = 0; pos < buf.length && shift < 28; shift += 7) {
|
|
39279
|
+
const byte = buf[pos++];
|
|
39282
39280
|
result |= (byte & 127) << shift;
|
|
39283
|
-
pos
|
|
39284
|
-
if ((byte & 128) === 0) {
|
|
39285
|
-
return [result, pos];
|
|
39286
|
-
}
|
|
39287
|
-
shift += 7;
|
|
39288
|
-
if (shift > 35) {
|
|
39289
|
-
throw new Error(`Varint too long at offset ${offset}`);
|
|
39290
|
-
}
|
|
39281
|
+
if ((byte & 128) === 0) return [result, pos];
|
|
39291
39282
|
}
|
|
39292
|
-
|
|
39283
|
+
const [value, next] = decodeVarint64(buf, offset);
|
|
39284
|
+
return [Number(BigInt.asIntN(64, value)), next];
|
|
39293
39285
|
}
|
|
39294
39286
|
function decodeMessage(buf, options = {}) {
|
|
39295
39287
|
const fields = [];
|
|
@@ -39306,7 +39298,7 @@ function decodeMessage(buf, options = {}) {
|
|
|
39306
39298
|
} else if (wireType === WIRE_TYPE.LENGTH_DELIMITED) {
|
|
39307
39299
|
let length;
|
|
39308
39300
|
[length, offset] = decodeVarint(buf, offset);
|
|
39309
|
-
if (offset + length > buf.length) {
|
|
39301
|
+
if (length < 0 || offset + length > buf.length) {
|
|
39310
39302
|
break;
|
|
39311
39303
|
}
|
|
39312
39304
|
const value = buf.slice(offset, offset + length);
|
|
@@ -39623,6 +39615,28 @@ import { createHash } from "node:crypto";
|
|
|
39623
39615
|
import { homedir as homedir2 } from "node:os";
|
|
39624
39616
|
import { join as join2 } from "node:path";
|
|
39625
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
|
|
39634
|
+
var HTML_LOSSY_ORDER = [
|
|
39635
|
+
"superscript",
|
|
39636
|
+
"subscript",
|
|
39637
|
+
"alignment",
|
|
39638
|
+
"highlight"
|
|
39639
|
+
];
|
|
39626
39640
|
var dbPath = join2(homedir2(), "Library/Group Containers/group.com.apple.notes/NoteStore.sqlite");
|
|
39627
39641
|
var safeUrl = (url) => /^(?:https?:\/\/|notes:\/\/|applenotes:|mailto:)/i.test(url) && !Array.from(url).some((char) => char.charCodeAt(0) < 32);
|
|
39628
39642
|
var escapeAttribute = (text2) => text2.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<");
|
|
@@ -39643,6 +39657,7 @@ function styleValue(field) {
|
|
|
39643
39657
|
else if (wire === 5) offset += 4;
|
|
39644
39658
|
else if (wire === 2) {
|
|
39645
39659
|
[length, offset] = decodeVarint(data, offset);
|
|
39660
|
+
if (length < 0) return Buffer.from(data).toString("hex");
|
|
39646
39661
|
offset += length;
|
|
39647
39662
|
} else return Buffer.from(data).toString("hex");
|
|
39648
39663
|
if (offset > data.length) return Buffer.from(data).toString("hex");
|
|
@@ -39669,6 +39684,7 @@ function parseRichNote(data, nativeTags = []) {
|
|
|
39669
39684
|
let position = 0;
|
|
39670
39685
|
let hasNativeObjects = false;
|
|
39671
39686
|
let hasChecklist = false;
|
|
39687
|
+
const lossy = /* @__PURE__ */ new Set();
|
|
39672
39688
|
for (const run of getFields(body, 5)) {
|
|
39673
39689
|
const fields = embeddedMessage(run);
|
|
39674
39690
|
if (!fields) throw new Error("Invalid Notes attribute run");
|
|
@@ -39686,6 +39702,13 @@ function parseRichNote(data, nativeTags = []) {
|
|
|
39686
39702
|
fields.filter((f) => f.fieldNumber >= 2 && f.fieldNumber <= 12 || f.fieldNumber === 14).map((f) => [f.fieldNumber, styleValue(f)])
|
|
39687
39703
|
)
|
|
39688
39704
|
});
|
|
39705
|
+
if (/[^\s\ufffc]/u.test(text2.slice(position, position + length))) {
|
|
39706
|
+
const baseline = varintValue(getField(fields, 8)) ?? 0;
|
|
39707
|
+
if (baseline > 0) lossy.add("superscript");
|
|
39708
|
+
if (baseline < 0) lossy.add("subscript");
|
|
39709
|
+
if (paragraph && (varintValue(getField(paragraph, 2)) ?? 0) !== 0) lossy.add("alignment");
|
|
39710
|
+
if (varintValue(getField(fields, 14))) lossy.add("highlight");
|
|
39711
|
+
}
|
|
39689
39712
|
const url = stringValue(getField(fields, 9));
|
|
39690
39713
|
if (url) {
|
|
39691
39714
|
if (!safeUrl(url)) throw new Error("Unsupported link scheme in note");
|
|
@@ -39699,14 +39722,15 @@ function parseRichNote(data, nativeTags = []) {
|
|
|
39699
39722
|
hasNativeObjects ||= Boolean(getField(fields, 12));
|
|
39700
39723
|
const attachment = embeddedMessage(getField(fields, 12));
|
|
39701
39724
|
const attachmentId = attachment && stringValue(getField(attachment, 1));
|
|
39702
|
-
if (attachmentId
|
|
39703
|
-
|
|
39725
|
+
if (attachment && attachmentId && !nativeObjectIds.includes(attachmentId)) {
|
|
39726
|
+
nativeObjectIds.push(attachmentId);
|
|
39704
39727
|
objects.push({
|
|
39705
39728
|
id: attachmentId,
|
|
39706
39729
|
type: stringValue(getField(attachment, 2)) || "unknown",
|
|
39707
39730
|
start: position,
|
|
39708
39731
|
length
|
|
39709
39732
|
});
|
|
39733
|
+
}
|
|
39710
39734
|
hasChecklist ||= Boolean(paragraph && varintValue(getField(paragraph, 1)) === 103);
|
|
39711
39735
|
if (paragraph && varintValue(getField(paragraph, 1)) === 103) {
|
|
39712
39736
|
const checklist = embeddedMessage(getField(paragraph, 5));
|
|
@@ -39737,7 +39761,8 @@ function parseRichNote(data, nativeTags = []) {
|
|
|
39737
39761
|
revision: createHash("sha256").update(data).digest("hex"),
|
|
39738
39762
|
objects,
|
|
39739
39763
|
checklistItems,
|
|
39740
|
-
styleRuns
|
|
39764
|
+
styleRuns,
|
|
39765
|
+
...lossy.size ? { htmlLossyFormatting: HTML_LOSSY_ORDER.filter((f) => lossy.has(f)) } : {}
|
|
39741
39766
|
};
|
|
39742
39767
|
}
|
|
39743
39768
|
function readRichNote(id2) {
|
|
@@ -39763,7 +39788,9 @@ function readRichNote(id2) {
|
|
|
39763
39788
|
(row) => !row || typeof row.id !== "string" || !Number.isInteger(row.pk) || typeof row.mergeable !== "string" || !/^[0-9a-f]*$/i.test(row.mergeable)
|
|
39764
39789
|
))
|
|
39765
39790
|
throw new Error("Invalid native object metadata");
|
|
39766
|
-
rich.objectData =
|
|
39791
|
+
rich.objectData = uniqueById(
|
|
39792
|
+
objectData.filter((row) => rich.nativeObjectIds.includes(row.id)).sort((a, b) => a.id.localeCompare(b.id))
|
|
39793
|
+
);
|
|
39767
39794
|
rich.revision = createHash("sha256").update(rich.revision).update(JSON.stringify(rich.objectData)).digest("hex");
|
|
39768
39795
|
rich.nativeTagObjectIds = {};
|
|
39769
39796
|
for (const id3 of rich.nativeObjectIds)
|
|
@@ -39854,17 +39881,26 @@ function enrichNoteRead(id2, rawBody) {
|
|
|
39854
39881
|
const rich = readRichNote(id2);
|
|
39855
39882
|
metadata = rich;
|
|
39856
39883
|
const content = restoreNoteLinks(rawBody, rich);
|
|
39857
|
-
const
|
|
39884
|
+
const complete = !rich.hasNativeObjects && !rich.hasChecklist;
|
|
39885
|
+
const lossy = rich.htmlLossyFormatting ?? [];
|
|
39886
|
+
const writable = complete && lossy.length === 0;
|
|
39887
|
+
const warnings = [];
|
|
39888
|
+
if (!complete)
|
|
39889
|
+
warnings.push(
|
|
39890
|
+
"Native tags, inline objects or checklists are present. Their state is not writable through AppleScript; full-body edits are blocked to preserve them."
|
|
39891
|
+
);
|
|
39892
|
+
if (lossy.length)
|
|
39893
|
+
warnings.push(
|
|
39894
|
+
`This note uses formatting that Notes' AppleScript HTML does not carry (${lossy.join(", ")}); a full-body edit would silently drop it, so full-body edits are blocked. Edit it in Notes.app, or use append-to-note with scopeText, which appends natively and verifies existing formatting.`
|
|
39895
|
+
);
|
|
39858
39896
|
return {
|
|
39859
39897
|
content,
|
|
39860
39898
|
links: rich.links,
|
|
39861
39899
|
nativeTags: rich.nativeTags,
|
|
39862
|
-
complete
|
|
39900
|
+
complete,
|
|
39863
39901
|
writable,
|
|
39864
39902
|
revision: rich.revision,
|
|
39865
|
-
|
|
39866
|
-
warning: "Native tags, inline objects or checklists are present. Their state is not writable through AppleScript; full-body edits are blocked to preserve them."
|
|
39867
|
-
} : {}
|
|
39903
|
+
...warnings.length ? { warning: warnings.join(" ") } : {}
|
|
39868
39904
|
};
|
|
39869
39905
|
} catch (err) {
|
|
39870
39906
|
const detail = err instanceof Error ? err.message : String(err);
|
|
@@ -43220,7 +43256,7 @@ var AppleNotesManager = class {
|
|
|
43220
43256
|
}
|
|
43221
43257
|
}
|
|
43222
43258
|
}
|
|
43223
|
-
return sharedNotes;
|
|
43259
|
+
return uniqueById(sharedNotes);
|
|
43224
43260
|
}
|
|
43225
43261
|
// ===========================================================================
|
|
43226
43262
|
// Folder Operations
|
|
@@ -44059,7 +44095,7 @@ var AppleNotesManager = class {
|
|
|
44059
44095
|
});
|
|
44060
44096
|
}
|
|
44061
44097
|
}
|
|
44062
|
-
return attachments;
|
|
44098
|
+
return uniqueById(attachments);
|
|
44063
44099
|
}
|
|
44064
44100
|
/**
|
|
44065
44101
|
* Lists attachments for a note by its title.
|
|
@@ -44146,7 +44182,7 @@ var AppleNotesManager = class {
|
|
|
44146
44182
|
});
|
|
44147
44183
|
}
|
|
44148
44184
|
}
|
|
44149
|
-
return attachments;
|
|
44185
|
+
return uniqueById(attachments);
|
|
44150
44186
|
}
|
|
44151
44187
|
/**
|
|
44152
44188
|
* Saves a single attachment of a note (identified by attachment id) to a file
|
package/package.json
CHANGED