apple-notes-mcp 2.8.11 → 2.8.13
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 +21 -3
- package/build/index.js +66 -45
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -565,8 +565,22 @@ visible text after saving, not byte-identical rich formatting. Warns when the
|
|
|
565
565
|
note is shared with collaborators.
|
|
566
566
|
|
|
567
567
|
**Safety:** The append is rejected if the note changed since it was read, rich
|
|
568
|
-
metadata is unavailable, or the note contains attachments
|
|
569
|
-
|
|
568
|
+
metadata is unavailable, or the note contains attachments. Existing link
|
|
569
|
+
destinations are verified after saving.
|
|
570
|
+
|
|
571
|
+
**Notes containing native objects** (a table, a checklist, native tags) cannot be
|
|
572
|
+
spliced, so they are routed to the native end-append bridge — see
|
|
573
|
+
[`append-native`](#append-native). That path additionally requires `scopeText`,
|
|
574
|
+
keeps the default blank-line `separator` and `position: "after"`, and accepts a
|
|
575
|
+
fixed HTML subset rather than anything Notes.app can render:
|
|
576
|
+
|
|
577
|
+
| | Native append |
|
|
578
|
+
|---|---|
|
|
579
|
+
| Elements | `<a>` `<b>` `<br>` `<code>` `<del>` `<div>` `<em>` `<h1>` `<h2>` `<h3>` `<i>` `<li>` `<ol>` `<p>` `<s>` `<span>` `<strong>` `<table>` `<tbody>` `<td>` `<th>` `<thead>` `<tr>` `<tt>` `<u>` `<ul>` |
|
|
580
|
+
| Attributes | `href` on `<a>` (`https:`, `http:`, `notes:`, `applenotes:`, `mailto:` only) and a `font-size` style on `<span>`, e.g. `<span style="font-size: 18px">` — the form Notes itself stores a heading as |
|
|
581
|
+
| Refused | every other element and attribute, by name, naming the accepted subset; `<table>` here (use [`create-table`](#create-table)); comments, doctype and processing instructions |
|
|
582
|
+
|
|
583
|
+
Ordinary notes take the guarded HTML path and are not restricted to that subset.
|
|
570
584
|
|
|
571
585
|
---
|
|
572
586
|
|
|
@@ -1050,7 +1064,11 @@ Appends bounded plaintext, semantic HTML, or Markdown while preserving existing
|
|
|
1050
1064
|
native objects. The regular `append-to-note` tool routes protected notes here
|
|
1051
1065
|
when `scopeText` is supplied. Use a distinctive phrase of plain words without
|
|
1052
1066
|
punctuation, hashtags, or paths because Notes search may not resolve them
|
|
1053
|
-
literally.
|
|
1067
|
+
literally. `format: "html"` accepts the fixed subset tabulated under
|
|
1068
|
+
[`append-to-note`](#append-to-note); content outside it is refused by name, with
|
|
1069
|
+
the accepted subset in the error. A transport failure names the Shortcut it was
|
|
1070
|
+
waiting on, so a missing or unapproved bridge is identified rather than guessed
|
|
1071
|
+
at.
|
|
1054
1072
|
|
|
1055
1073
|
#### `create-checklist-item`
|
|
1056
1074
|
|
package/build/index.js
CHANGED
|
@@ -39708,7 +39708,7 @@ function visibleCharacters(html) {
|
|
|
39708
39708
|
token++;
|
|
39709
39709
|
if (part[0].startsWith("<")) continue;
|
|
39710
39710
|
for (const item of part[0].matchAll(
|
|
39711
|
-
/&(?:#[0-9]+;?|#x[0-9a-f]+;?|(?:amp|lt|gt|quot|
|
|
39711
|
+
/&(?:#[0-9]+;?|#x[0-9a-f]+;?|(?:amp|lt|gt|quot|nbsp);?|apos;)|[\s\S]/gi
|
|
39712
39712
|
)) {
|
|
39713
39713
|
const value = decodeEntity(item[0]);
|
|
39714
39714
|
for (let i = 0; i < value.length; i++) {
|
|
@@ -39770,7 +39770,8 @@ function enrichNoteRead(id2, rawBody) {
|
|
|
39770
39770
|
warning: "Native tags, inline objects or checklists are present. Their state is not writable through AppleScript; full-body edits are blocked to preserve them."
|
|
39771
39771
|
} : {}
|
|
39772
39772
|
};
|
|
39773
|
-
} catch {
|
|
39773
|
+
} catch (err) {
|
|
39774
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
39774
39775
|
return {
|
|
39775
39776
|
content: rawBody,
|
|
39776
39777
|
links: metadata?.links ?? [],
|
|
@@ -39778,7 +39779,7 @@ function enrichNoteRead(id2, rawBody) {
|
|
|
39778
39779
|
complete: false,
|
|
39779
39780
|
writable: false,
|
|
39780
39781
|
revision: metadata?.revision ?? "unavailable",
|
|
39781
|
-
warning:
|
|
39782
|
+
warning: `Rich Notes metadata could not be read or matched. Links/native tags may be missing from this view. Full-body edits are blocked; check Full Disk Access and retry after sync. (${detail})`
|
|
39782
39783
|
};
|
|
39783
39784
|
}
|
|
39784
39785
|
}
|
|
@@ -42832,7 +42833,7 @@ function runNativeTagsShortcut(input) {
|
|
|
42832
42833
|
});
|
|
42833
42834
|
} catch {
|
|
42834
42835
|
throw new Error(
|
|
42835
|
-
|
|
42836
|
+
`Native tag operation did not complete cleanly; the "${status.shortcut}" Shortcut may be waiting for macOS permission. Do not retry automatically; read the exact note and check that Shortcut in Shortcuts.app`
|
|
42836
42837
|
);
|
|
42837
42838
|
} finally {
|
|
42838
42839
|
rmSync2(directory, { recursive: true, force: true });
|
|
@@ -42930,49 +42931,62 @@ function readBackgroundSnapshot(manager, id2) {
|
|
|
42930
42931
|
checklist: getChecklistItems(id2).items || []
|
|
42931
42932
|
};
|
|
42932
42933
|
}
|
|
42934
|
+
var NATIVE_APPEND_ELEMENTS = [
|
|
42935
|
+
"a",
|
|
42936
|
+
"b",
|
|
42937
|
+
"br",
|
|
42938
|
+
"code",
|
|
42939
|
+
"del",
|
|
42940
|
+
"div",
|
|
42941
|
+
"em",
|
|
42942
|
+
"h1",
|
|
42943
|
+
"h2",
|
|
42944
|
+
"h3",
|
|
42945
|
+
"i",
|
|
42946
|
+
"li",
|
|
42947
|
+
"ol",
|
|
42948
|
+
"p",
|
|
42949
|
+
"s",
|
|
42950
|
+
"span",
|
|
42951
|
+
"strong",
|
|
42952
|
+
"table",
|
|
42953
|
+
"tbody",
|
|
42954
|
+
"td",
|
|
42955
|
+
"th",
|
|
42956
|
+
"thead",
|
|
42957
|
+
"tr",
|
|
42958
|
+
"tt",
|
|
42959
|
+
"u",
|
|
42960
|
+
"ul"
|
|
42961
|
+
];
|
|
42962
|
+
var NATIVE_APPEND_SPAN_STYLE = /^font-size\s*:\s*\d{1,3}(?:\.\d+)?(?:px|pt)\s*;?$/i;
|
|
42963
|
+
var NATIVE_APPEND_HTML_SUBSET = `Native append accepts ${NATIVE_APPEND_ELEMENTS.map((e) => `<${e}>`).join(" ")}, with href on <a> and a font-size style on <span> as the only attributes; everything else needs update-note.`;
|
|
42933
42964
|
function validateAppendContent(content, format) {
|
|
42934
42965
|
if (!content || content.length > 1024 * 1024 || content.includes("\0"))
|
|
42935
42966
|
throw new Error("Invalid append content (limit 1 MiB)");
|
|
42936
42967
|
if (format === "html") {
|
|
42937
|
-
const allowed =
|
|
42938
|
-
"div",
|
|
42939
|
-
"p",
|
|
42940
|
-
"br",
|
|
42941
|
-
"b",
|
|
42942
|
-
"strong",
|
|
42943
|
-
"i",
|
|
42944
|
-
"em",
|
|
42945
|
-
"u",
|
|
42946
|
-
"s",
|
|
42947
|
-
"del",
|
|
42948
|
-
"h1",
|
|
42949
|
-
"h2",
|
|
42950
|
-
"h3",
|
|
42951
|
-
"ul",
|
|
42952
|
-
"ol",
|
|
42953
|
-
"li",
|
|
42954
|
-
"a",
|
|
42955
|
-
"table",
|
|
42956
|
-
"thead",
|
|
42957
|
-
"tbody",
|
|
42958
|
-
"tr",
|
|
42959
|
-
"td",
|
|
42960
|
-
"th"
|
|
42961
|
-
]);
|
|
42968
|
+
const allowed = new Set(NATIVE_APPEND_ELEMENTS);
|
|
42962
42969
|
for (const tag of content.matchAll(/<\/?\s*([a-z][a-z0-9]*)\b([^>]*)>/gi)) {
|
|
42963
|
-
|
|
42964
|
-
|
|
42970
|
+
const name = tag[1].toLowerCase();
|
|
42971
|
+
if (!allowed.has(name))
|
|
42972
|
+
throw new Error(`Unsupported HTML element: <${name}>. ${NATIVE_APPEND_HTML_SUBSET}`);
|
|
42965
42973
|
let attrs = tag[2].replace(/\/$/, "").trim();
|
|
42966
|
-
if (
|
|
42974
|
+
if (name === "a")
|
|
42967
42975
|
attrs = attrs.replace(/\bhref\s*=\s*(["'])(.*?)\1/gi, (_s, _q, url) => {
|
|
42968
42976
|
if (!/^(https?:\/\/|notes:\/\/|applenotes:|mailto:)/i.test(url) || Array.from(url).some((c) => c.charCodeAt(0) < 33))
|
|
42969
42977
|
throw new Error("Unsupported link URL");
|
|
42970
42978
|
return "";
|
|
42971
42979
|
});
|
|
42980
|
+
if (name === "span")
|
|
42981
|
+
attrs = attrs.replace(/\bstyle\s*=\s*(["'])(.*?)\1/gi, (_s, _q, style) => {
|
|
42982
|
+
if (!NATIVE_APPEND_SPAN_STYLE.test(style.trim()))
|
|
42983
|
+
throw new Error(
|
|
42984
|
+
`Unsupported <span> style: ${style.trim().slice(0, 80)}. Native append accepts font-size only, as in <span style="font-size: 18px">.`
|
|
42985
|
+
);
|
|
42986
|
+
return "";
|
|
42987
|
+
});
|
|
42972
42988
|
if (attrs.trim())
|
|
42973
|
-
throw new Error(
|
|
42974
|
-
"Unsupported HTML attributes; use semantic formatting and explicit blank paragraphs"
|
|
42975
|
-
);
|
|
42989
|
+
throw new Error(`Unsupported HTML attributes on <${name}>. ${NATIVE_APPEND_HTML_SUBSET}`);
|
|
42976
42990
|
}
|
|
42977
42991
|
if (/<!--|<!|<\?|<[^>]*$/u.test(content)) throw new Error("Unsupported HTML markup");
|
|
42978
42992
|
}
|
|
@@ -42982,7 +42996,9 @@ function validateAppendContent(content, format) {
|
|
|
42982
42996
|
function runBackgroundShortcut(input) {
|
|
42983
42997
|
const status = backgroundStatus();
|
|
42984
42998
|
if (!status.installed)
|
|
42985
|
-
throw new Error(
|
|
42999
|
+
throw new Error(
|
|
43000
|
+
`Install the supplied "${status.shortcut}" Shortcut once; Shortcuts must list it exactly once`
|
|
43001
|
+
);
|
|
42986
43002
|
const directory = mkdtempSync3(join8(tmpdir3(), "apple-notes-background-"));
|
|
42987
43003
|
try {
|
|
42988
43004
|
const file = join8(directory, "request.json");
|
|
@@ -43004,12 +43020,16 @@ function runBackgroundShortcut(input) {
|
|
|
43004
43020
|
}),
|
|
43005
43021
|
{ mode: 384 }
|
|
43006
43022
|
);
|
|
43007
|
-
|
|
43008
|
-
|
|
43009
|
-
|
|
43010
|
-
|
|
43011
|
-
|
|
43012
|
-
|
|
43023
|
+
try {
|
|
43024
|
+
execFileSync7("/usr/bin/shortcuts", ["run", status.identifier, "--input-path", file], {
|
|
43025
|
+
encoding: "utf8",
|
|
43026
|
+
timeout: 6e4,
|
|
43027
|
+
maxBuffer: 1024 * 1024,
|
|
43028
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
43029
|
+
});
|
|
43030
|
+
} catch (error2) {
|
|
43031
|
+
throw Object.assign(error2, { shortcut: status.shortcut });
|
|
43032
|
+
}
|
|
43013
43033
|
} finally {
|
|
43014
43034
|
rmSync3(directory, { recursive: true, force: true });
|
|
43015
43035
|
}
|
|
@@ -43096,7 +43116,8 @@ function mutateBackground(request, operation, data, verify, deps) {
|
|
|
43096
43116
|
} catch (error2) {
|
|
43097
43117
|
transportUncertain = true;
|
|
43098
43118
|
const detail = error2;
|
|
43099
|
-
|
|
43119
|
+
const named = detail?.shortcut ? `the "${detail.shortcut}" Shortcut` : "the background Shortcut";
|
|
43120
|
+
transportMessage = detail?.code === "ETIMEDOUT" ? `Shortcuts timed out waiting for ${named}; check for an interactive parameter or permission request` : `${named} failed: ${String(detail?.stderr || detail?.message || "no output").trim().slice(0, 400)}`;
|
|
43100
43121
|
}
|
|
43101
43122
|
const after = deps.read(request.id);
|
|
43102
43123
|
try {
|
|
@@ -43980,7 +44001,7 @@ function registerNativeOperations(server2, manager) {
|
|
|
43980
44001
|
);
|
|
43981
44002
|
tool(
|
|
43982
44003
|
"append-native",
|
|
43983
|
-
"Use when: appending formatted content to a native-object note without replacing its body.\nReturns: exact-ID preservation and appended-content readback.\nDo not use when: the existing note can be safely handled by append-to-note or the scope phrase is ambiguous.\nSafety: requires a fresh revision and unique existing scope phrase of plain words; avoid punctuation, hashtags, and paths because Notes search may not resolve them literally. Supports bounded plaintext, semantic HTML, and Markdown without external fetching or automatic retries
|
|
44004
|
+
"Use when: appending formatted content to a native-object note without replacing its body.\nReturns: exact-ID preservation and appended-content readback.\nDo not use when: the existing note can be safely handled by append-to-note or the scope phrase is ambiguous.\nSafety: requires a fresh revision and unique existing scope phrase of plain words; avoid punctuation, hashtags, and paths because Notes search may not resolve them literally. Supports bounded plaintext, semantic HTML, and Markdown without external fetching or automatic retries.\nHTML subset: " + NATIVE_APPEND_HTML_SUBSET,
|
|
43984
44005
|
{
|
|
43985
44006
|
...common,
|
|
43986
44007
|
content: external_exports.string().min(1).max(1024 * 1024),
|
|
@@ -45022,7 +45043,7 @@ registerTool(
|
|
|
45022
45043
|
registerTool(
|
|
45023
45044
|
"append-to-note",
|
|
45024
45045
|
{
|
|
45025
|
-
description: "Use when: adding content to one exact note after reading it by id.\nReturns: exact id, new content hash, and visible-text readback verification.\nDo not use when: you only have a title or the note changed since the read.\nSafety: protected native-object notes use native end-append with scopeText; ordinary notes retain guarded HTML editing. Notes.app normalizes HTML, so rich formatting is not claimed as byte-identical.",
|
|
45046
|
+
description: "Use when: adding content to one exact note after reading it by id.\nReturns: exact id, new content hash, and visible-text readback verification.\nDo not use when: you only have a title or the note changed since the read.\nSafety: protected native-object notes use native end-append with scopeText; ordinary notes retain guarded HTML editing. Notes.app normalizes HTML, so rich formatting is not claimed as byte-identical.\nNative-append HTML subset (protected notes only; ordinary notes accept any HTML Notes.app renders): " + NATIVE_APPEND_HTML_SUBSET + " Native append also requires scopeText, the default blank-line separator and position 'after'.",
|
|
45026
45047
|
inputSchema: {
|
|
45027
45048
|
id: noteIdInput,
|
|
45028
45049
|
expectedContentHash: expectedContentHashInput,
|
package/package.json
CHANGED