apple-notes-mcp 2.15.3 → 2.15.4
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/build/index.js +285 -22
- package/package.json +1 -1
package/build/index.js
CHANGED
|
@@ -40498,6 +40498,87 @@ function styleValue(field) {
|
|
|
40498
40498
|
}
|
|
40499
40499
|
return Buffer.from(field.value).toString("hex");
|
|
40500
40500
|
}
|
|
40501
|
+
function storedStyleSignature(data) {
|
|
40502
|
+
return JSON.stringify(
|
|
40503
|
+
decodeWireFields(data).filter((field) => field.fieldNumber !== 1).map((field) => [
|
|
40504
|
+
field.fieldNumber,
|
|
40505
|
+
field.wireType,
|
|
40506
|
+
field.bytes ? styleValue({
|
|
40507
|
+
fieldNumber: field.fieldNumber,
|
|
40508
|
+
wireType: field.wireType,
|
|
40509
|
+
value: field.bytes
|
|
40510
|
+
}) : field.varint.toString()
|
|
40511
|
+
])
|
|
40512
|
+
);
|
|
40513
|
+
}
|
|
40514
|
+
function nativeRunSemantics(data) {
|
|
40515
|
+
const result = {
|
|
40516
|
+
complete: true,
|
|
40517
|
+
unknown: false,
|
|
40518
|
+
structuredParagraph: false,
|
|
40519
|
+
links: false,
|
|
40520
|
+
objects: []
|
|
40521
|
+
};
|
|
40522
|
+
const check2 = (fields, schema) => {
|
|
40523
|
+
const seen = /* @__PURE__ */ new Set();
|
|
40524
|
+
for (const field of fields) {
|
|
40525
|
+
if (!Object.hasOwn(schema, field.fieldNumber)) result.unknown = true;
|
|
40526
|
+
else if (seen.has(field.fieldNumber) || field.wireType !== schema[field.fieldNumber])
|
|
40527
|
+
result.complete = false;
|
|
40528
|
+
seen.add(field.fieldNumber);
|
|
40529
|
+
}
|
|
40530
|
+
};
|
|
40531
|
+
const nested = (field) => {
|
|
40532
|
+
if (field.wireType !== 2 || !field.bytes) {
|
|
40533
|
+
result.complete = false;
|
|
40534
|
+
return [];
|
|
40535
|
+
}
|
|
40536
|
+
return decodeWireFields(field.bytes);
|
|
40537
|
+
};
|
|
40538
|
+
try {
|
|
40539
|
+
const fields = decodeWireFields(data);
|
|
40540
|
+
check2(fields, { 1: 0, 2: 2, 3: 2, 5: 0, 6: 0, 7: 0, 8: 0, 9: 2, 10: 2, 12: 2, 14: 0 });
|
|
40541
|
+
if (fields.filter((f) => f.fieldNumber === 1).length !== 1) result.complete = false;
|
|
40542
|
+
result.links = fields.some((f) => f.fieldNumber === 9);
|
|
40543
|
+
for (const field of fields) {
|
|
40544
|
+
if (field.fieldNumber === 2) {
|
|
40545
|
+
const paragraph = nested(field);
|
|
40546
|
+
check2(paragraph, { 1: 0, 2: 0, 4: 0, 5: 2, 8: 0, 9: 2 });
|
|
40547
|
+
for (const style of paragraph.filter((f) => f.fieldNumber === 1)) {
|
|
40548
|
+
const type = style.varint === void 0 ? void 0 : Number(BigInt.asIntN(64, style.varint));
|
|
40549
|
+
if (type !== void 0 && type >= 100 && type <= 103) result.structuredParagraph = true;
|
|
40550
|
+
else if (type === void 0 || ![-1, 0, 1, 2, 3, 4].includes(type)) result.unknown = true;
|
|
40551
|
+
}
|
|
40552
|
+
for (const uuid2 of paragraph.filter((f) => f.fieldNumber === 9))
|
|
40553
|
+
if (uuid2.bytes?.length !== 16) result.complete = false;
|
|
40554
|
+
for (const todo of paragraph.filter((f) => f.fieldNumber === 5)) {
|
|
40555
|
+
result.structuredParagraph = true;
|
|
40556
|
+
const item = nested(todo);
|
|
40557
|
+
check2(item, { 1: 2, 2: 0 });
|
|
40558
|
+
const id2 = item.filter((f) => f.fieldNumber === 1);
|
|
40559
|
+
if (id2.length !== 1 || id2[0].bytes?.length !== 16) result.complete = false;
|
|
40560
|
+
}
|
|
40561
|
+
} else if (field.fieldNumber === 3) check2(nested(field), { 1: 2, 2: 5, 3: 0 });
|
|
40562
|
+
else if (field.fieldNumber === 10) check2(nested(field), { 1: 5, 2: 5, 3: 5, 4: 5 });
|
|
40563
|
+
else if (field.fieldNumber === 12) {
|
|
40564
|
+
const attachment = nested(field);
|
|
40565
|
+
check2(attachment, { 1: 2, 2: 2 });
|
|
40566
|
+
const ids = attachment.filter((f) => f.fieldNumber === 1), types = attachment.filter((f) => f.fieldNumber === 2);
|
|
40567
|
+
if (ids.length !== 1 || types.length !== 1 || !ids[0].bytes || !types[0].bytes) {
|
|
40568
|
+
result.complete = false;
|
|
40569
|
+
continue;
|
|
40570
|
+
}
|
|
40571
|
+
const utf82 = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
|
|
40572
|
+
const id2 = utf82.decode(ids[0].bytes), type = utf82.decode(types[0].bytes);
|
|
40573
|
+
if (!id2 || !type) result.complete = false;
|
|
40574
|
+
result.objects.push({ id: id2, type });
|
|
40575
|
+
}
|
|
40576
|
+
}
|
|
40577
|
+
} catch {
|
|
40578
|
+
result.complete = false;
|
|
40579
|
+
}
|
|
40580
|
+
return result;
|
|
40581
|
+
}
|
|
40501
40582
|
function parseRichNote(data, nativeTags = [], options = {}) {
|
|
40502
40583
|
const doc = decodeMessage(data);
|
|
40503
40584
|
const wrapper = embeddedMessage(getField(doc, 2));
|
|
@@ -40526,9 +40607,8 @@ function parseRichNote(data, nativeTags = [], options = {}) {
|
|
|
40526
40607
|
highlight: Boolean(varintValue(getField(fields, 14))),
|
|
40527
40608
|
start: position,
|
|
40528
40609
|
length,
|
|
40529
|
-
signature:
|
|
40530
|
-
|
|
40531
|
-
)
|
|
40610
|
+
signature: storedStyleSignature(run.value),
|
|
40611
|
+
nativeSemantics: nativeRunSemantics(run.value)
|
|
40532
40612
|
});
|
|
40533
40613
|
if (/[^\s\ufffc]/u.test(text2.slice(position, position + length))) {
|
|
40534
40614
|
const baseline = varintValue(getField(fields, 8)) ?? 0;
|
|
@@ -40596,7 +40676,7 @@ function parseRichNote(data, nativeTags = [], options = {}) {
|
|
|
40596
40676
|
function readRichNote(id2, options = {}) {
|
|
40597
40677
|
const pk = /^x-coredata:\/\/[0-9a-f-]+\/ICNote\/p([0-9]+)$/i.exec(id2)?.[1];
|
|
40598
40678
|
if (!pk) throw new Error("Invalid exact note ID");
|
|
40599
|
-
const sql = `BEGIN; SELECT hex(ZDATA) FROM ZICNOTEDATA WHERE ZNOTE=${pk}; SELECT json_group_object(ZIDENTIFIER,ZALTTEXT) FROM ZICCLOUDSYNCINGOBJECT WHERE ZNOTE1=${pk} AND ZTYPEUTI1='com.apple.notes.inlinetextattachment.hashtag'; SELECT json_group_array(json_object('id',ZIDENTIFIER,'pk',Z_PK,'type',COALESCE(ZTYPEUTI1,ZTYPEUTI),'mergeable',hex(COALESCE(ZMERGEABLEDATA1,ZMERGEABLEDATA)),'view',ZATTACHMENTVIEWTYPE)) FROM ZICCLOUDSYNCINGOBJECT WHERE ZNOTE1=${pk} OR ZNOTE=${pk}; COMMIT;`;
|
|
40679
|
+
const sql = `BEGIN; SELECT hex(ZDATA) FROM ZICNOTEDATA WHERE ZNOTE=${pk}; SELECT json_group_object(ZIDENTIFIER,ZALTTEXT) FROM ZICCLOUDSYNCINGOBJECT WHERE ZNOTE1=${pk} AND ZTYPEUTI1='com.apple.notes.inlinetextattachment.hashtag'; SELECT json_group_array(json_object('id',ZIDENTIFIER,'pk',Z_PK,'type',COALESCE(ZTYPEUTI1,ZTYPEUTI),'mergeable',hex(COALESCE(ZMERGEABLEDATA1,ZMERGEABLEDATA)),'view',ZATTACHMENTVIEWTYPE,'altText',ZALTTEXT)) FROM ZICCLOUDSYNCINGOBJECT WHERE ZNOTE1=${pk} OR ZNOTE=${pk}; COMMIT;`;
|
|
40600
40680
|
const rows = execFileSync4("/usr/bin/sqlite3", ["-readonly", dbPath, sql], {
|
|
40601
40681
|
encoding: "utf8",
|
|
40602
40682
|
timeout: 5e3,
|
|
@@ -40615,14 +40695,21 @@ function readRichNote(id2, options = {}) {
|
|
|
40615
40695
|
const tagMap = tags;
|
|
40616
40696
|
const objectData = JSON.parse(rows[2] || "[]");
|
|
40617
40697
|
if (!Array.isArray(objectData) || objectData.some(
|
|
40618
|
-
(row) => !row || typeof row.id !== "string" || !Number.isInteger(row.pk) || typeof row.mergeable !== "string" || !/^[0-9a-f]*$/i.test(row.mergeable)
|
|
40698
|
+
(row) => !row || typeof row.id !== "string" || !Number.isInteger(row.pk) || typeof row.mergeable !== "string" || !/^[0-9a-f]*$/i.test(row.mergeable) || row.altText !== void 0 && row.altText !== null && typeof row.altText !== "string"
|
|
40619
40699
|
))
|
|
40620
40700
|
throw new Error("Invalid native object metadata");
|
|
40621
40701
|
rich.objectData = uniqueById(
|
|
40622
40702
|
objectData.filter((row) => rich.nativeObjectIds.includes(row.id)).sort((a, b) => a.id.localeCompare(b.id))
|
|
40623
40703
|
);
|
|
40624
|
-
|
|
40625
|
-
rich.
|
|
40704
|
+
const selectedRows = new Map(rich.objectData.map((row) => [row.id, row]));
|
|
40705
|
+
rich.nativeObjectDataComplete = objectData.every((candidate) => {
|
|
40706
|
+
const row = selectedRows.get(candidate.id);
|
|
40707
|
+
return !row || ["pk", "type", "mergeable", "view", "altText"].every(
|
|
40708
|
+
(key) => candidate[key] === row[key]
|
|
40709
|
+
);
|
|
40710
|
+
});
|
|
40711
|
+
rich.revision = createHash("sha256").update(rich.revision).update(JSON.stringify(rich.objectData)).update(JSON.stringify(rich.nativeObjectDataComplete)).digest("hex");
|
|
40712
|
+
rich.nativeTagObjectIds = /* @__PURE__ */ Object.create(null);
|
|
40626
40713
|
for (const id3 of rich.nativeObjectIds)
|
|
40627
40714
|
if (tagMap[id3]) {
|
|
40628
40715
|
const tag = tagMap[id3].replace(/^#/, "");
|
|
@@ -48649,6 +48736,176 @@ function normalizeNativeTags(tags) {
|
|
|
48649
48736
|
)
|
|
48650
48737
|
];
|
|
48651
48738
|
}
|
|
48739
|
+
var TAG_OBJECT_TYPE = "com.apple.notes.inlinetextattachment.hashtag";
|
|
48740
|
+
function requirePreservationMetadata(rich) {
|
|
48741
|
+
const unavailable = () => {
|
|
48742
|
+
throw new Error("Native object, checklist or formatting preservation metadata is unavailable");
|
|
48743
|
+
};
|
|
48744
|
+
const { objects, objectData, checklistItems, styleRuns, nativeTagObjectIds } = rich;
|
|
48745
|
+
if (!objects || !objectData || !checklistItems || !styleRuns || !nativeTagObjectIds || rich.nativeObjectDataComplete !== true)
|
|
48746
|
+
return unavailable();
|
|
48747
|
+
const ids = new Set(rich.nativeObjectIds);
|
|
48748
|
+
if (ids.size !== rich.nativeObjectIds.length || objects.length !== ids.size || objectData.length !== ids.size || new Set(objects.map((o) => o.id)).size !== ids.size || new Set(objectData.map((o) => o.id)).size !== ids.size || rich.hasNativeObjects !== Boolean(ids.size) || rich.hasChecklist !== Boolean(checklistItems.length))
|
|
48749
|
+
return unavailable();
|
|
48750
|
+
let objectEnd = 0;
|
|
48751
|
+
for (const object3 of objects) {
|
|
48752
|
+
const data = objectData.find((row) => row.id === object3.id);
|
|
48753
|
+
if (!ids.has(object3.id) || !Number.isInteger(object3.start) || !Number.isInteger(object3.length) || object3.start < objectEnd || object3.length < 1 || object3.start + object3.length > rich.text.length || !data || data.type !== object3.type || !Number.isInteger(data.pk) || !/^[0-9a-f]*$/iu.test(data.mergeable) || data.view !== null && !Number.isInteger(data.view) || !Object.hasOwn(data, "altText") || data.altText !== null && typeof data.altText !== "string")
|
|
48754
|
+
return unavailable();
|
|
48755
|
+
objectEnd = object3.start + object3.length;
|
|
48756
|
+
}
|
|
48757
|
+
const mappedIds = /* @__PURE__ */ new Set();
|
|
48758
|
+
if (new Set(rich.nativeTags).size !== rich.nativeTags.length || Object.keys(nativeTagObjectIds).length !== rich.nativeTags.length)
|
|
48759
|
+
return unavailable();
|
|
48760
|
+
for (const [tag, tagIds] of Object.entries(nativeTagObjectIds)) {
|
|
48761
|
+
if (!rich.nativeTags.includes(tag) || !tagIds.length) return unavailable();
|
|
48762
|
+
for (const id2 of tagIds) {
|
|
48763
|
+
if (mappedIds.has(id2) || !objects.some((o) => o.id === id2 && o.type === TAG_OBJECT_TYPE) || objectData.find((o) => o.id === id2)?.altText?.replace(/^#/, "") !== tag)
|
|
48764
|
+
return unavailable();
|
|
48765
|
+
mappedIds.add(id2);
|
|
48766
|
+
}
|
|
48767
|
+
}
|
|
48768
|
+
if (objects.some((o) => o.type === TAG_OBJECT_TYPE && !mappedIds.has(o.id))) return unavailable();
|
|
48769
|
+
if (new Set(checklistItems.map((item) => item.id)).size !== checklistItems.length)
|
|
48770
|
+
return unavailable();
|
|
48771
|
+
for (const item of checklistItems) {
|
|
48772
|
+
const end = item.start + item.text.length;
|
|
48773
|
+
if (!item.id || !Number.isInteger(item.start) || item.start < 0 || end > rich.text.length || rich.text.slice(item.start, end) !== item.text || end < rich.text.length && rich.text[end] !== "\n")
|
|
48774
|
+
return unavailable();
|
|
48775
|
+
}
|
|
48776
|
+
let position = 0;
|
|
48777
|
+
for (const run of styleRuns) {
|
|
48778
|
+
if (run.start !== position || !Number.isInteger(run.length) || run.length < 0 || typeof run.signature !== "string" || run.nativeSemantics?.complete !== true || run.length === 0 && (run.nativeSemantics.unknown || run.nativeSemantics.structuredParagraph || run.nativeSemantics.links || run.nativeSemantics.objects.length > 0))
|
|
48779
|
+
return unavailable();
|
|
48780
|
+
position += run.length;
|
|
48781
|
+
}
|
|
48782
|
+
if (position !== rich.text.length) return unavailable();
|
|
48783
|
+
for (const link of rich.links)
|
|
48784
|
+
if (!Number.isInteger(link.start) || !Number.isInteger(link.length) || link.start < 0 || link.length < 1 || link.start + link.length > rich.text.length || rich.text.slice(link.start, link.start + link.length) !== link.text)
|
|
48785
|
+
return unavailable();
|
|
48786
|
+
}
|
|
48787
|
+
function plainNativeRange(rich, start, length) {
|
|
48788
|
+
return rich.styleRuns.every((run) => {
|
|
48789
|
+
if (run.start >= start + length || run.start + run.length <= start) return true;
|
|
48790
|
+
const metadata = run.nativeSemantics;
|
|
48791
|
+
return metadata.complete && !metadata.unknown && !metadata.structuredParagraph && !metadata.links && !metadata.objects.length;
|
|
48792
|
+
});
|
|
48793
|
+
}
|
|
48794
|
+
function preservedTextSpans(before, after, missing) {
|
|
48795
|
+
const oldIds = new Set(before.nativeObjectIds);
|
|
48796
|
+
const added = after.objects.filter((o) => !oldIds.has(o.id));
|
|
48797
|
+
const tagsById = new Map(
|
|
48798
|
+
Object.entries(after.nativeTagObjectIds).flatMap(
|
|
48799
|
+
([tag, ids]) => ids.map((id2) => [id2, tag])
|
|
48800
|
+
)
|
|
48801
|
+
);
|
|
48802
|
+
if (!added.length || added.some((o) => o.type !== TAG_OBJECT_TYPE || !missing.includes(tagsById.get(o.id))) || missing.some((tag) => !added.some((o) => tagsById.get(o.id) === tag)))
|
|
48803
|
+
return void 0;
|
|
48804
|
+
const spans = [];
|
|
48805
|
+
let oldPosition = 0, newPosition = 0, appended = false;
|
|
48806
|
+
for (const object3 of added) {
|
|
48807
|
+
const prefix = after.text.slice(newPosition, object3.start);
|
|
48808
|
+
const remaining2 = before.text.slice(oldPosition);
|
|
48809
|
+
const length = Math.min(prefix.length, remaining2.length);
|
|
48810
|
+
if (prefix.slice(0, length) !== remaining2.slice(0, length) || prefix.length > length && !/^[ \n]*$/u.test(prefix.slice(length)))
|
|
48811
|
+
return void 0;
|
|
48812
|
+
if (length) spans.push({ before: oldPosition, after: newPosition, length });
|
|
48813
|
+
oldPosition += length;
|
|
48814
|
+
const literal2 = `#${tagsById.get(object3.id)}`;
|
|
48815
|
+
const rendered = after.text.slice(object3.start, object3.start + object3.length);
|
|
48816
|
+
if (rendered !== "\uFFFC" && rendered !== literal2) return void 0;
|
|
48817
|
+
const previous = [...before.text.slice(Math.max(0, oldPosition - 2), oldPosition)].at(-1) || "";
|
|
48818
|
+
const next = String.fromCodePoint(before.text.codePointAt(oldPosition + literal2.length) ?? 0);
|
|
48819
|
+
if (oldPosition === before.text.length) appended = true;
|
|
48820
|
+
else if (before.text.startsWith(literal2, oldPosition) && !/[\p{L}\p{M}\p{N}_#-]/u.test(previous) && !/[\p{L}\p{M}\p{N}_-]/u.test(next) && plainNativeRange(before, oldPosition, literal2.length))
|
|
48821
|
+
oldPosition += literal2.length;
|
|
48822
|
+
else return void 0;
|
|
48823
|
+
newPosition = object3.start + object3.length;
|
|
48824
|
+
}
|
|
48825
|
+
const remaining = before.text.slice(oldPosition);
|
|
48826
|
+
const suffix = after.text.slice(newPosition);
|
|
48827
|
+
if (suffix !== remaining && !(appended && !remaining && /^[ \n]*$/u.test(suffix)))
|
|
48828
|
+
return void 0;
|
|
48829
|
+
if (remaining.length)
|
|
48830
|
+
spans.push({ before: oldPosition, after: newPosition, length: remaining.length });
|
|
48831
|
+
return spans;
|
|
48832
|
+
}
|
|
48833
|
+
function preservesAddedSemantics(before, after, spans) {
|
|
48834
|
+
const oldIds = new Set(before.nativeObjectIds);
|
|
48835
|
+
const added = after.objects.filter((o) => !oldIds.has(o.id));
|
|
48836
|
+
const changed = [];
|
|
48837
|
+
let end = 0;
|
|
48838
|
+
for (const span of spans) {
|
|
48839
|
+
if (end < span.after) changed.push({ start: end, end: span.after });
|
|
48840
|
+
end = span.after + span.length;
|
|
48841
|
+
}
|
|
48842
|
+
if (end < after.text.length) changed.push({ start: end, end: after.text.length });
|
|
48843
|
+
for (const run of after.styleRuns) {
|
|
48844
|
+
if (!changed.some((range) => run.start < range.end && run.start + run.length > range.start))
|
|
48845
|
+
continue;
|
|
48846
|
+
const metadata = run.nativeSemantics;
|
|
48847
|
+
if (!metadata.complete || metadata.unknown || metadata.structuredParagraph || metadata.links)
|
|
48848
|
+
return false;
|
|
48849
|
+
const object3 = added.find((o) => run.start === o.start && run.length === o.length);
|
|
48850
|
+
if (object3) {
|
|
48851
|
+
if (metadata.objects.length !== 1 || metadata.objects[0].id !== object3.id || metadata.objects[0].type !== object3.type)
|
|
48852
|
+
return false;
|
|
48853
|
+
} else if (metadata.objects.length || added.some((o) => run.start < o.start + o.length && run.start + run.length > o.start))
|
|
48854
|
+
return false;
|
|
48855
|
+
}
|
|
48856
|
+
return true;
|
|
48857
|
+
}
|
|
48858
|
+
function preservesNativeContent(before, after, spans) {
|
|
48859
|
+
const rangeStart = (start, length) => {
|
|
48860
|
+
const span = spans.find((s) => start >= s.before && start + length <= s.before + s.length);
|
|
48861
|
+
return span && span.after + start - span.before;
|
|
48862
|
+
};
|
|
48863
|
+
for (const object3 of before.objects) {
|
|
48864
|
+
const actual = after.objects.find((o) => o.id === object3.id);
|
|
48865
|
+
if (!actual || actual.type !== object3.type || actual.length !== object3.length || actual.start !== rangeStart(object3.start, object3.length))
|
|
48866
|
+
return false;
|
|
48867
|
+
}
|
|
48868
|
+
for (const object3 of before.objectData) {
|
|
48869
|
+
const actual = after.objectData.find((o) => o.id === object3.id);
|
|
48870
|
+
if (!actual || actual.pk !== object3.pk || actual.type !== object3.type || actual.mergeable !== object3.mergeable || actual.view !== object3.view || actual.altText !== object3.altText)
|
|
48871
|
+
return false;
|
|
48872
|
+
}
|
|
48873
|
+
for (const tag of before.nativeTags)
|
|
48874
|
+
if (JSON.stringify(before.nativeTagObjectIds[tag]) !== JSON.stringify(after.nativeTagObjectIds[tag]))
|
|
48875
|
+
return false;
|
|
48876
|
+
if (before.checklistItems.length !== after.checklistItems.length) return false;
|
|
48877
|
+
for (const [index, item] of before.checklistItems.entries()) {
|
|
48878
|
+
const actual = after.checklistItems[index];
|
|
48879
|
+
if (actual.id !== item.id || actual.text !== item.text || actual.done !== item.done || actual.start !== rangeStart(item.start, item.text.length))
|
|
48880
|
+
return false;
|
|
48881
|
+
}
|
|
48882
|
+
if (before.links.length !== after.links.length) return false;
|
|
48883
|
+
for (const [index, link] of before.links.entries()) {
|
|
48884
|
+
const actual = after.links[index];
|
|
48885
|
+
if (actual.text !== link.text || actual.url !== link.url || actual.length !== link.length || actual.start !== rangeStart(link.start, link.length))
|
|
48886
|
+
return false;
|
|
48887
|
+
}
|
|
48888
|
+
let oldIndex = 0, newIndex = 0;
|
|
48889
|
+
for (const span of spans) {
|
|
48890
|
+
let offset = 0;
|
|
48891
|
+
while (offset < span.length) {
|
|
48892
|
+
const oldPosition = span.before + offset, newPosition = span.after + offset;
|
|
48893
|
+
while (before.styleRuns[oldIndex].start + before.styleRuns[oldIndex].length <= oldPosition)
|
|
48894
|
+
oldIndex++;
|
|
48895
|
+
while (after.styleRuns[newIndex].start + after.styleRuns[newIndex].length <= newPosition)
|
|
48896
|
+
newIndex++;
|
|
48897
|
+
const oldRun = before.styleRuns[oldIndex], newRun = after.styleRuns[newIndex];
|
|
48898
|
+
if (oldRun.signature !== newRun.signature || oldRun.paragraphStyle !== newRun.paragraphStyle || oldRun.blockQuote !== newRun.blockQuote || oldRun.highlight !== newRun.highlight)
|
|
48899
|
+
return false;
|
|
48900
|
+
offset += Math.min(
|
|
48901
|
+
span.length - offset,
|
|
48902
|
+
oldRun.start + oldRun.length - oldPosition,
|
|
48903
|
+
newRun.start + newRun.length - newPosition
|
|
48904
|
+
);
|
|
48905
|
+
}
|
|
48906
|
+
}
|
|
48907
|
+
return true;
|
|
48908
|
+
}
|
|
48652
48909
|
function addNativeTags(request, deps) {
|
|
48653
48910
|
if (!/^x-coredata:\/\/[0-9a-f-]+\/ICNote\/p\d+$/i.test(request.id))
|
|
48654
48911
|
throw new Error("An exact CoreData note ID is required");
|
|
@@ -48663,32 +48920,37 @@ function addNativeTags(request, deps) {
|
|
|
48663
48920
|
const missing = tags.filter((tag) => !before.rich.nativeTags.includes(tag));
|
|
48664
48921
|
if (!missing.length)
|
|
48665
48922
|
return { nativeTags: before.rich.nativeTags, added: [], contentHash: before.contentHash };
|
|
48923
|
+
requirePreservationMetadata(before.rich);
|
|
48666
48924
|
const candidates = deps.candidates(request.title, request.scopeText);
|
|
48667
48925
|
if (candidates.length !== 1 || candidates[0] !== request.id)
|
|
48668
48926
|
throw new Error(
|
|
48669
48927
|
"Shortcuts selection is ambiguous or points to a different note; nothing was changed"
|
|
48670
48928
|
);
|
|
48671
|
-
|
|
48929
|
+
const current = deps.read(request.id);
|
|
48930
|
+
if (current.contentHash !== request.expectedContentHash)
|
|
48672
48931
|
throw new Error("Note revision changed during preflight; nothing was changed");
|
|
48932
|
+
requirePreservationMetadata(current.rich);
|
|
48673
48933
|
let transportWarning;
|
|
48674
48934
|
try {
|
|
48675
48935
|
deps.run({ title: request.title, scopeText: request.scopeText, tags: missing });
|
|
48676
48936
|
} catch (error2) {
|
|
48677
48937
|
transportWarning = error2 instanceof Error ? error2.message : "Shortcuts completion was uncertain";
|
|
48678
48938
|
}
|
|
48679
|
-
const
|
|
48939
|
+
const verificationFailure = (detail) => new CodedError(
|
|
48940
|
+
(transportWarning ? "Shortcuts did not complete cleanly, and exact-ID tags/text/links/native-content readback was not verified." : "Shortcuts ran, but exact-ID tags/text/links/native-content readback was not verified.") + " Read the note before any retry." + (detail ? ` ${detail}` : "") + (transportWarning ? ` ${transportWarning}` : ""),
|
|
48941
|
+
{ code: "verification_failed", indeterminate: true }
|
|
48942
|
+
);
|
|
48943
|
+
let after;
|
|
48944
|
+
try {
|
|
48945
|
+
after = deps.read(request.id);
|
|
48946
|
+
requirePreservationMetadata(after.rich);
|
|
48947
|
+
} catch (error2) {
|
|
48948
|
+
throw verificationFailure(error2 instanceof Error ? error2.message : String(error2));
|
|
48949
|
+
}
|
|
48680
48950
|
const allTags = [.../* @__PURE__ */ new Set([...before.rich.nativeTags, ...tags])];
|
|
48681
|
-
const
|
|
48682
|
-
|
|
48683
|
-
|
|
48684
|
-
text2 = text2.replace(new RegExp(`#${escaped}(?![\\p{L}\\p{N}_-])`, "gu"), "");
|
|
48685
|
-
}
|
|
48686
|
-
return text2.replace(/[\s\ufffc]/gu, "");
|
|
48687
|
-
};
|
|
48688
|
-
if (after.title !== before.title || allTags.some((tag) => !after.rich.nativeTags.includes(tag)) || textWithoutTags(before.rich.text) !== textWithoutTags(after.rich.text) || linkSignature(before.rich.links) !== linkSignature(after.rich.links) || before.rich.nativeObjectIds.some((id2) => !after.rich.nativeObjectIds.includes(id2)) || before.rich.hasChecklist !== after.rich.hasChecklist) {
|
|
48689
|
-
throw new Error(
|
|
48690
|
-
transportWarning ? `Shortcuts did not complete cleanly, and exact-ID tags/text/links readback was not verified. Read the note before any retry. ${transportWarning}` : "Shortcuts ran, but exact-ID tags/text/links readback was not verified. Read the note before any retry"
|
|
48691
|
-
);
|
|
48951
|
+
const spans = preservedTextSpans(before.rich, after.rich, missing);
|
|
48952
|
+
if (after.title !== before.title || after.rich.nativeTags.length !== allTags.length || allTags.some((tag) => !after.rich.nativeTags.includes(tag)) || before.rich.nativeObjectIds.some((id2) => !after.rich.nativeObjectIds.includes(id2)) || before.rich.hasChecklist !== after.rich.hasChecklist || !spans || !preservesAddedSemantics(before.rich, after.rich, spans) || !preservesNativeContent(before.rich, after.rich, spans)) {
|
|
48953
|
+
throw verificationFailure();
|
|
48692
48954
|
}
|
|
48693
48955
|
return {
|
|
48694
48956
|
nativeTags: after.rich.nativeTags,
|
|
@@ -58520,7 +58782,7 @@ function registerSvgAnalysis(server2) {
|
|
|
58520
58782
|
// src/tools/nativeTagsBridge.ts
|
|
58521
58783
|
var noteId2 = exactIdInput(
|
|
58522
58784
|
"ICNote",
|
|
58523
|
-
/^x-coredata:\/\/[0-9a-
|
|
58785
|
+
/^x-coredata:\/\/[0-9a-fA-F-]+\/ICNote\/p\d+$/i,
|
|
58524
58786
|
NOTE_ID_MESSAGE
|
|
58525
58787
|
);
|
|
58526
58788
|
var revision2 = external_exports.string().regex(/^sha256:[a-f0-9]{64}$/);
|
|
@@ -58554,8 +58816,9 @@ function registerNativeTagsBridge(server2, manager) {
|
|
|
58554
58816
|
if (!body) throw new Error("Note content is unavailable");
|
|
58555
58817
|
const enriched = enrichNoteRead(id2, body);
|
|
58556
58818
|
const rich = readRichNote(id2);
|
|
58557
|
-
if (
|
|
58819
|
+
if (enriched.revision !== rich.revision)
|
|
58558
58820
|
throw new Error("Native metadata changed during read; read the note again");
|
|
58821
|
+
restoreNoteLinks(body, rich);
|
|
58559
58822
|
return {
|
|
58560
58823
|
contentHash: richContentHash(body, enriched),
|
|
58561
58824
|
title: note.title,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "apple-notes-mcp",
|
|
3
|
-
"version": "2.15.
|
|
3
|
+
"version": "2.15.4",
|
|
4
4
|
"description": "MCP server for Apple Notes - read, search, create, edit, organize, and export notes on macOS via Claude and other AI assistants",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "build/index.js",
|