apple-notes-mcp 2.8.11 → 2.8.12
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 +62 -42
- 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
|
@@ -42832,7 +42832,7 @@ function runNativeTagsShortcut(input) {
|
|
|
42832
42832
|
});
|
|
42833
42833
|
} catch {
|
|
42834
42834
|
throw new Error(
|
|
42835
|
-
|
|
42835
|
+
`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
42836
|
);
|
|
42837
42837
|
} finally {
|
|
42838
42838
|
rmSync2(directory, { recursive: true, force: true });
|
|
@@ -42930,49 +42930,62 @@ function readBackgroundSnapshot(manager, id2) {
|
|
|
42930
42930
|
checklist: getChecklistItems(id2).items || []
|
|
42931
42931
|
};
|
|
42932
42932
|
}
|
|
42933
|
+
var NATIVE_APPEND_ELEMENTS = [
|
|
42934
|
+
"a",
|
|
42935
|
+
"b",
|
|
42936
|
+
"br",
|
|
42937
|
+
"code",
|
|
42938
|
+
"del",
|
|
42939
|
+
"div",
|
|
42940
|
+
"em",
|
|
42941
|
+
"h1",
|
|
42942
|
+
"h2",
|
|
42943
|
+
"h3",
|
|
42944
|
+
"i",
|
|
42945
|
+
"li",
|
|
42946
|
+
"ol",
|
|
42947
|
+
"p",
|
|
42948
|
+
"s",
|
|
42949
|
+
"span",
|
|
42950
|
+
"strong",
|
|
42951
|
+
"table",
|
|
42952
|
+
"tbody",
|
|
42953
|
+
"td",
|
|
42954
|
+
"th",
|
|
42955
|
+
"thead",
|
|
42956
|
+
"tr",
|
|
42957
|
+
"tt",
|
|
42958
|
+
"u",
|
|
42959
|
+
"ul"
|
|
42960
|
+
];
|
|
42961
|
+
var NATIVE_APPEND_SPAN_STYLE = /^font-size\s*:\s*\d{1,3}(?:\.\d+)?(?:px|pt)\s*;?$/i;
|
|
42962
|
+
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
42963
|
function validateAppendContent(content, format) {
|
|
42934
42964
|
if (!content || content.length > 1024 * 1024 || content.includes("\0"))
|
|
42935
42965
|
throw new Error("Invalid append content (limit 1 MiB)");
|
|
42936
42966
|
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
|
-
]);
|
|
42967
|
+
const allowed = new Set(NATIVE_APPEND_ELEMENTS);
|
|
42962
42968
|
for (const tag of content.matchAll(/<\/?\s*([a-z][a-z0-9]*)\b([^>]*)>/gi)) {
|
|
42963
|
-
|
|
42964
|
-
|
|
42969
|
+
const name = tag[1].toLowerCase();
|
|
42970
|
+
if (!allowed.has(name))
|
|
42971
|
+
throw new Error(`Unsupported HTML element: <${name}>. ${NATIVE_APPEND_HTML_SUBSET}`);
|
|
42965
42972
|
let attrs = tag[2].replace(/\/$/, "").trim();
|
|
42966
|
-
if (
|
|
42973
|
+
if (name === "a")
|
|
42967
42974
|
attrs = attrs.replace(/\bhref\s*=\s*(["'])(.*?)\1/gi, (_s, _q, url) => {
|
|
42968
42975
|
if (!/^(https?:\/\/|notes:\/\/|applenotes:|mailto:)/i.test(url) || Array.from(url).some((c) => c.charCodeAt(0) < 33))
|
|
42969
42976
|
throw new Error("Unsupported link URL");
|
|
42970
42977
|
return "";
|
|
42971
42978
|
});
|
|
42979
|
+
if (name === "span")
|
|
42980
|
+
attrs = attrs.replace(/\bstyle\s*=\s*(["'])(.*?)\1/gi, (_s, _q, style) => {
|
|
42981
|
+
if (!NATIVE_APPEND_SPAN_STYLE.test(style.trim()))
|
|
42982
|
+
throw new Error(
|
|
42983
|
+
`Unsupported <span> style: ${style.trim().slice(0, 80)}. Native append accepts font-size only, as in <span style="font-size: 18px">.`
|
|
42984
|
+
);
|
|
42985
|
+
return "";
|
|
42986
|
+
});
|
|
42972
42987
|
if (attrs.trim())
|
|
42973
|
-
throw new Error(
|
|
42974
|
-
"Unsupported HTML attributes; use semantic formatting and explicit blank paragraphs"
|
|
42975
|
-
);
|
|
42988
|
+
throw new Error(`Unsupported HTML attributes on <${name}>. ${NATIVE_APPEND_HTML_SUBSET}`);
|
|
42976
42989
|
}
|
|
42977
42990
|
if (/<!--|<!|<\?|<[^>]*$/u.test(content)) throw new Error("Unsupported HTML markup");
|
|
42978
42991
|
}
|
|
@@ -42982,7 +42995,9 @@ function validateAppendContent(content, format) {
|
|
|
42982
42995
|
function runBackgroundShortcut(input) {
|
|
42983
42996
|
const status = backgroundStatus();
|
|
42984
42997
|
if (!status.installed)
|
|
42985
|
-
throw new Error(
|
|
42998
|
+
throw new Error(
|
|
42999
|
+
`Install the supplied "${status.shortcut}" Shortcut once; Shortcuts must list it exactly once`
|
|
43000
|
+
);
|
|
42986
43001
|
const directory = mkdtempSync3(join8(tmpdir3(), "apple-notes-background-"));
|
|
42987
43002
|
try {
|
|
42988
43003
|
const file = join8(directory, "request.json");
|
|
@@ -43004,12 +43019,16 @@ function runBackgroundShortcut(input) {
|
|
|
43004
43019
|
}),
|
|
43005
43020
|
{ mode: 384 }
|
|
43006
43021
|
);
|
|
43007
|
-
|
|
43008
|
-
|
|
43009
|
-
|
|
43010
|
-
|
|
43011
|
-
|
|
43012
|
-
|
|
43022
|
+
try {
|
|
43023
|
+
execFileSync7("/usr/bin/shortcuts", ["run", status.identifier, "--input-path", file], {
|
|
43024
|
+
encoding: "utf8",
|
|
43025
|
+
timeout: 6e4,
|
|
43026
|
+
maxBuffer: 1024 * 1024,
|
|
43027
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
43028
|
+
});
|
|
43029
|
+
} catch (error2) {
|
|
43030
|
+
throw Object.assign(error2, { shortcut: status.shortcut });
|
|
43031
|
+
}
|
|
43013
43032
|
} finally {
|
|
43014
43033
|
rmSync3(directory, { recursive: true, force: true });
|
|
43015
43034
|
}
|
|
@@ -43096,7 +43115,8 @@ function mutateBackground(request, operation, data, verify, deps) {
|
|
|
43096
43115
|
} catch (error2) {
|
|
43097
43116
|
transportUncertain = true;
|
|
43098
43117
|
const detail = error2;
|
|
43099
|
-
|
|
43118
|
+
const named = detail?.shortcut ? `the "${detail.shortcut}" Shortcut` : "the background Shortcut";
|
|
43119
|
+
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
43120
|
}
|
|
43101
43121
|
const after = deps.read(request.id);
|
|
43102
43122
|
try {
|
|
@@ -43980,7 +44000,7 @@ function registerNativeOperations(server2, manager) {
|
|
|
43980
44000
|
);
|
|
43981
44001
|
tool(
|
|
43982
44002
|
"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
|
|
44003
|
+
"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
44004
|
{
|
|
43985
44005
|
...common,
|
|
43986
44006
|
content: external_exports.string().min(1).max(1024 * 1024),
|
|
@@ -45022,7 +45042,7 @@ registerTool(
|
|
|
45022
45042
|
registerTool(
|
|
45023
45043
|
"append-to-note",
|
|
45024
45044
|
{
|
|
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.",
|
|
45045
|
+
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
45046
|
inputSchema: {
|
|
45027
45047
|
id: noteIdInput,
|
|
45028
45048
|
expectedContentHash: expectedContentHashInput,
|
package/package.json
CHANGED