apple-notes-mcp 2.8.39 → 2.8.40

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 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
- let pos = offset;
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
- throw new Error(`Unexpected end of buffer reading varint at offset ${offset}`);
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,12 @@ 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
+ var HTML_LOSSY_ORDER = [
39619
+ "superscript",
39620
+ "subscript",
39621
+ "alignment",
39622
+ "highlight"
39623
+ ];
39626
39624
  var dbPath = join2(homedir2(), "Library/Group Containers/group.com.apple.notes/NoteStore.sqlite");
39627
39625
  var safeUrl = (url) => /^(?:https?:\/\/|notes:\/\/|applenotes:|mailto:)/i.test(url) && !Array.from(url).some((char) => char.charCodeAt(0) < 32);
39628
39626
  var escapeAttribute = (text2) => text2.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;");
@@ -39643,6 +39641,7 @@ function styleValue(field) {
39643
39641
  else if (wire === 5) offset += 4;
39644
39642
  else if (wire === 2) {
39645
39643
  [length, offset] = decodeVarint(data, offset);
39644
+ if (length < 0) return Buffer.from(data).toString("hex");
39646
39645
  offset += length;
39647
39646
  } else return Buffer.from(data).toString("hex");
39648
39647
  if (offset > data.length) return Buffer.from(data).toString("hex");
@@ -39669,6 +39668,7 @@ function parseRichNote(data, nativeTags = []) {
39669
39668
  let position = 0;
39670
39669
  let hasNativeObjects = false;
39671
39670
  let hasChecklist = false;
39671
+ const lossy = /* @__PURE__ */ new Set();
39672
39672
  for (const run of getFields(body, 5)) {
39673
39673
  const fields = embeddedMessage(run);
39674
39674
  if (!fields) throw new Error("Invalid Notes attribute run");
@@ -39686,6 +39686,13 @@ function parseRichNote(data, nativeTags = []) {
39686
39686
  fields.filter((f) => f.fieldNumber >= 2 && f.fieldNumber <= 12 || f.fieldNumber === 14).map((f) => [f.fieldNumber, styleValue(f)])
39687
39687
  )
39688
39688
  });
39689
+ if (/[^\s\ufffc]/u.test(text2.slice(position, position + length))) {
39690
+ const baseline = varintValue(getField(fields, 8)) ?? 0;
39691
+ if (baseline > 0) lossy.add("superscript");
39692
+ if (baseline < 0) lossy.add("subscript");
39693
+ if (paragraph && (varintValue(getField(paragraph, 2)) ?? 0) !== 0) lossy.add("alignment");
39694
+ if (varintValue(getField(fields, 14))) lossy.add("highlight");
39695
+ }
39689
39696
  const url = stringValue(getField(fields, 9));
39690
39697
  if (url) {
39691
39698
  if (!safeUrl(url)) throw new Error("Unsupported link scheme in note");
@@ -39737,7 +39744,8 @@ function parseRichNote(data, nativeTags = []) {
39737
39744
  revision: createHash("sha256").update(data).digest("hex"),
39738
39745
  objects,
39739
39746
  checklistItems,
39740
- styleRuns
39747
+ styleRuns,
39748
+ ...lossy.size ? { htmlLossyFormatting: HTML_LOSSY_ORDER.filter((f) => lossy.has(f)) } : {}
39741
39749
  };
39742
39750
  }
39743
39751
  function readRichNote(id2) {
@@ -39854,17 +39862,26 @@ function enrichNoteRead(id2, rawBody) {
39854
39862
  const rich = readRichNote(id2);
39855
39863
  metadata = rich;
39856
39864
  const content = restoreNoteLinks(rawBody, rich);
39857
- const writable = !rich.hasNativeObjects && !rich.hasChecklist;
39865
+ const complete = !rich.hasNativeObjects && !rich.hasChecklist;
39866
+ const lossy = rich.htmlLossyFormatting ?? [];
39867
+ const writable = complete && lossy.length === 0;
39868
+ const warnings = [];
39869
+ if (!complete)
39870
+ warnings.push(
39871
+ "Native tags, inline objects or checklists are present. Their state is not writable through AppleScript; full-body edits are blocked to preserve them."
39872
+ );
39873
+ if (lossy.length)
39874
+ warnings.push(
39875
+ `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.`
39876
+ );
39858
39877
  return {
39859
39878
  content,
39860
39879
  links: rich.links,
39861
39880
  nativeTags: rich.nativeTags,
39862
- complete: writable,
39881
+ complete,
39863
39882
  writable,
39864
39883
  revision: rich.revision,
39865
- ...!writable ? {
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
- } : {}
39884
+ ...warnings.length ? { warning: warnings.join(" ") } : {}
39868
39885
  };
39869
39886
  } catch (err) {
39870
39887
  const detail = err instanceof Error ? err.message : String(err);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apple-notes-mcp",
3
- "version": "2.8.39",
3
+ "version": "2.8.40",
4
4
  "description": "MCP server for Apple Notes - create, search, update, and manage notes via Claude and other AI assistants",
5
5
  "type": "module",
6
6
  "main": "build/index.js",