apple-notes-mcp 2.5.8 → 2.5.10
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 +1 -0
- package/build/index.js +118 -46
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -943,6 +943,7 @@ All configuration is optional — the server works out of the box. Override beha
|
|
|
943
943
|
|----------|---------|-------------|
|
|
944
944
|
| `APPLE_NOTES_MCP_MAX_BUFFER` | `67108864` (64 MB) | Max bytes captured from a single AppleScript invocation. Raise it if a very large export/list is truncated; lower it to cap memory. |
|
|
945
945
|
| `APPLE_NOTES_MCP_MAX_ATTACHMENT_BYTES` | `26214400` (25 MB) | Max size of an attachment that [`fetch-attachment`](#fetch-attachment) will base64-encode inline. Larger attachments are rejected with an error pointing at [`save-attachment`](#save-attachment) (which streams to disk and has no such limit). Raise it to fetch bigger attachments inline; lower it to cap memory. |
|
|
946
|
+
| `APPLE_NOTES_MCP_MAX_INLINE_IMAGE_BYTES` | `262144` (256 KB) | Per-image cap on the base64 payload kept inline in a [`get-note-content`](#get-note-content) response. Inline images over the cap are replaced with placeholders (with a warning appended) so an image-heavy note cannot exceed the MCP client's message limit and drop the connection; export the real files with [`save-attachment`](#save-attachment) or [`fetch-attachment`](#fetch-attachment). Raise it to keep bigger images inline. |
|
|
946
947
|
| `APPLE_NOTES_MCP_CONFIG_FILE` | `~/Library/Application Support/apple-notes-mcp/config.json` | Path to the JSON config file (see below). |
|
|
947
948
|
| `APPLE_NOTES_MCP_TIMEOUT_MS` | `30000` (30 s) | Per-call AppleScript timeout. Raise it if full-library operations (large searches, exports) time out on a big Notes library. Per-call `timeoutMs` options still win. |
|
|
948
949
|
| `APPLE_NOTES_MCP_MAX_RETRIES` | `2` | Total attempts for an AppleScript call that fails with a **transient** error (Notes.app busy / not responding / lost connection / timeout). `2` means one retry; set `1` to fail fast with no retries. Non-transient errors (e.g. "note not found") never retry. |
|
package/build/index.js
CHANGED
|
@@ -38656,7 +38656,7 @@ var StdioServerTransport = class {
|
|
|
38656
38656
|
};
|
|
38657
38657
|
|
|
38658
38658
|
// src/utils/applescript.ts
|
|
38659
|
-
import {
|
|
38659
|
+
import { execFileSync } from "child_process";
|
|
38660
38660
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
38661
38661
|
var DEFAULT_MAX_BUFFER_BYTES = 64 * 1024 * 1024;
|
|
38662
38662
|
function envPositiveNumber(name) {
|
|
@@ -38693,13 +38693,10 @@ function debugLog(message, data) {
|
|
|
38693
38693
|
console.error(`[DEBUG ${timestamp}] ${message}`);
|
|
38694
38694
|
}
|
|
38695
38695
|
}
|
|
38696
|
-
function escapeForShell(script) {
|
|
38697
|
-
return script.replace(/'/g, "'\\''");
|
|
38698
|
-
}
|
|
38699
38696
|
function isTimeoutError(error2) {
|
|
38700
38697
|
if (error2 instanceof Error) {
|
|
38701
38698
|
const execError = error2;
|
|
38702
|
-
return execError.killed === true || execError.signal === "SIGTERM";
|
|
38699
|
+
return execError.code === "ETIMEDOUT" || execError.killed === true || execError.signal === "SIGKILL" || execError.signal === "SIGTERM";
|
|
38703
38700
|
}
|
|
38704
38701
|
return false;
|
|
38705
38702
|
}
|
|
@@ -38714,13 +38711,7 @@ function isRetryableError(errorMessage) {
|
|
|
38714
38711
|
return RETRYABLE_ERROR_PATTERNS.some((pattern) => pattern.test(errorMessage));
|
|
38715
38712
|
}
|
|
38716
38713
|
function sleep(ms) {
|
|
38717
|
-
|
|
38718
|
-
const result = spawnSync("sleep", [seconds.toString()], { stdio: "ignore" });
|
|
38719
|
-
if (result.error) {
|
|
38720
|
-
const end = Date.now() + ms;
|
|
38721
|
-
while (Date.now() < end) {
|
|
38722
|
-
}
|
|
38723
|
-
}
|
|
38714
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
38724
38715
|
}
|
|
38725
38716
|
var ERROR_MAPPINGS = [
|
|
38726
38717
|
// Permission errors
|
|
@@ -38812,8 +38803,7 @@ function executeAppleScript(script, options = {}) {
|
|
|
38812
38803
|
error: "Cannot execute empty AppleScript"
|
|
38813
38804
|
};
|
|
38814
38805
|
}
|
|
38815
|
-
const preparedScript =
|
|
38816
|
-
const command = `osascript -e '${preparedScript}'`;
|
|
38806
|
+
const preparedScript = wrapWithTimeout(script.trim(), timeoutMs);
|
|
38817
38807
|
debugLog("Executing AppleScript", {
|
|
38818
38808
|
scriptPreview: script.trim().substring(0, 200) + (script.length > 200 ? "..." : ""),
|
|
38819
38809
|
timeout: timeoutMs,
|
|
@@ -38824,7 +38814,8 @@ function executeAppleScript(script, options = {}) {
|
|
|
38824
38814
|
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
38825
38815
|
const attemptStart = Date.now();
|
|
38826
38816
|
try {
|
|
38827
|
-
const output =
|
|
38817
|
+
const output = execFileSync("osascript", ["-"], {
|
|
38818
|
+
input: preparedScript,
|
|
38828
38819
|
encoding: "utf8",
|
|
38829
38820
|
timeout: timeoutMs,
|
|
38830
38821
|
// SIGKILL (not the default SIGTERM): a wedged osascript blocked on an
|
|
@@ -38833,9 +38824,7 @@ function executeAppleScript(script, options = {}) {
|
|
|
38833
38824
|
killSignal: "SIGKILL",
|
|
38834
38825
|
// Raise the output cap above Node's 1 MB default so large exports /
|
|
38835
38826
|
// long notes aren't truncated into an ENOBUFS failure. (#16)
|
|
38836
|
-
maxBuffer: getMaxBuffer()
|
|
38837
|
-
// Capture stderr separately to get error details
|
|
38838
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
38827
|
+
maxBuffer: getMaxBuffer()
|
|
38839
38828
|
});
|
|
38840
38829
|
const duration3 = Date.now() - attemptStart;
|
|
38841
38830
|
debugLog("AppleScript succeeded", {
|
|
@@ -38901,7 +38890,7 @@ function executeAppleScript(script, options = {}) {
|
|
|
38901
38890
|
}
|
|
38902
38891
|
|
|
38903
38892
|
// src/utils/checklistParser.ts
|
|
38904
|
-
import { execFileSync } from "child_process";
|
|
38893
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
38905
38894
|
import * as zlib from "zlib";
|
|
38906
38895
|
import * as fs from "fs";
|
|
38907
38896
|
import * as path from "path";
|
|
@@ -38995,7 +38984,7 @@ var NOTES_DB_PATH = path.join(
|
|
|
38995
38984
|
function hasFullDiskAccess() {
|
|
38996
38985
|
try {
|
|
38997
38986
|
if (!fs.existsSync(NOTES_DB_PATH)) return false;
|
|
38998
|
-
|
|
38987
|
+
execFileSync2("sqlite3", ["-readonly", NOTES_DB_PATH, "SELECT 1;"], {
|
|
38999
38988
|
encoding: "utf8",
|
|
39000
38989
|
timeout: 3e3,
|
|
39001
38990
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -39014,7 +39003,7 @@ function queryNoteData(noteId) {
|
|
|
39014
39003
|
const pk = pkMatch[1];
|
|
39015
39004
|
const query = `SELECT hex(nd.ZDATA) FROM ZICNOTEDATA nd JOIN ZICCLOUDSYNCINGOBJECT n ON nd.ZNOTE = n.Z_PK WHERE n.Z_PK = ${pk};`;
|
|
39016
39005
|
try {
|
|
39017
|
-
const result =
|
|
39006
|
+
const result = execFileSync2("sqlite3", ["-readonly", NOTES_DB_PATH, query], {
|
|
39018
39007
|
encoding: "utf8",
|
|
39019
39008
|
timeout: 5e3,
|
|
39020
39009
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -39140,11 +39129,21 @@ function getChecklistItems(noteId) {
|
|
|
39140
39129
|
}
|
|
39141
39130
|
|
|
39142
39131
|
// src/utils/attachmentFs.ts
|
|
39143
|
-
import { existsSync as existsSync2, mkdtempSync, readFileSync, rmSync, statSync } from "fs";
|
|
39144
|
-
import { isAbsolute, resolve, sep } from "path";
|
|
39132
|
+
import { existsSync as existsSync2, mkdirSync, mkdtempSync, readFileSync, rmSync, statSync } from "fs";
|
|
39133
|
+
import { dirname, isAbsolute, resolve, sep } from "path";
|
|
39145
39134
|
import { homedir as homedir2, tmpdir } from "os";
|
|
39146
39135
|
function allowedSaveRoots() {
|
|
39147
|
-
return [
|
|
39136
|
+
return [
|
|
39137
|
+
resolve(homedir2()),
|
|
39138
|
+
resolve(tmpdir()),
|
|
39139
|
+
"/Volumes",
|
|
39140
|
+
"/private/var/folders",
|
|
39141
|
+
"/tmp",
|
|
39142
|
+
"/private/tmp"
|
|
39143
|
+
];
|
|
39144
|
+
}
|
|
39145
|
+
function ensureParentDir(abs) {
|
|
39146
|
+
mkdirSync(dirname(abs), { recursive: true });
|
|
39148
39147
|
}
|
|
39149
39148
|
function assertSafeSavePath(p, roots = allowedSaveRoots()) {
|
|
39150
39149
|
if (!p || !p.trim()) throw new Error("A destination path is required.");
|
|
@@ -39282,6 +39281,10 @@ function buildAppleScriptDateVar(date3, varName = "thresholdDate") {
|
|
|
39282
39281
|
function asDatePartsExpr(v) {
|
|
39283
39282
|
return `((year of ${v}) as text) & "-" & ((month of ${v}) as integer as text) & "-" & ((day of ${v}) as text) & "-" & ((hours of ${v}) as text) & "-" & ((minutes of ${v}) as text) & "-" & ((seconds of ${v}) as text)`;
|
|
39284
39283
|
}
|
|
39284
|
+
function normalizeAppleScriptText(field) {
|
|
39285
|
+
const trimmed = field?.trim();
|
|
39286
|
+
return trimmed && trimmed !== "missing value" ? trimmed : void 0;
|
|
39287
|
+
}
|
|
39285
39288
|
function parseNotePropertiesOutput(output) {
|
|
39286
39289
|
const parts = output.split(FIELD_SEP);
|
|
39287
39290
|
if (parts.length < 6) {
|
|
@@ -40471,7 +40474,7 @@ var AppleNotesManager = class {
|
|
|
40471
40474
|
end if
|
|
40472
40475
|
end repeat
|
|
40473
40476
|
if theAttachment is missing value then
|
|
40474
|
-
return "ERR${AS_FIELD_SEP}attachment not found"
|
|
40477
|
+
return "ERR" & ${AS_FIELD_SEP} & "attachment not found"
|
|
40475
40478
|
end if
|
|
40476
40479
|
show theAttachment${separatelyClause}
|
|
40477
40480
|
return "OK"
|
|
@@ -40737,8 +40740,8 @@ var AppleNotesManager = class {
|
|
|
40737
40740
|
set end of attachmentList to attachId & ${AS_FIELD_SEP} & attachName & ${AS_FIELD_SEP} & attachContentId & ${AS_FIELD_SEP} & attachUrl & ${AS_FIELD_SEP} & createdParts & ${AS_FIELD_SEP} & modifiedParts & ${AS_FIELD_SEP} & sharedFlag
|
|
40738
40741
|
end repeat
|
|
40739
40742
|
set output to ""
|
|
40740
|
-
repeat with
|
|
40741
|
-
set output to output &
|
|
40743
|
+
repeat with recordItem in attachmentList
|
|
40744
|
+
set output to output & recordItem & ${AS_RECORD_SEP}
|
|
40742
40745
|
end repeat
|
|
40743
40746
|
return output
|
|
40744
40747
|
end tell
|
|
@@ -40760,7 +40763,7 @@ var AppleNotesManager = class {
|
|
|
40760
40763
|
name: parts[1].trim(),
|
|
40761
40764
|
contentType: parts[2].trim(),
|
|
40762
40765
|
contentId: parts[2].trim() || void 0,
|
|
40763
|
-
url: parts[3]
|
|
40766
|
+
url: normalizeAppleScriptText(parts[3]),
|
|
40764
40767
|
created: parts[4] ? parseAppleScriptDate(parts[4].trim()) : void 0,
|
|
40765
40768
|
modified: parts[5] ? parseAppleScriptDate(parts[5].trim()) : void 0,
|
|
40766
40769
|
shared: parts[6] ? parts[6].trim().toLowerCase() === "true" : void 0
|
|
@@ -40801,8 +40804,8 @@ var AppleNotesManager = class {
|
|
|
40801
40804
|
set end of attachmentList to attachId & ${AS_FIELD_SEP} & attachName & ${AS_FIELD_SEP} & attachContentId & ${AS_FIELD_SEP} & attachUrl & ${AS_FIELD_SEP} & createdParts & ${AS_FIELD_SEP} & modifiedParts & ${AS_FIELD_SEP} & sharedFlag
|
|
40802
40805
|
end repeat
|
|
40803
40806
|
set output to ""
|
|
40804
|
-
repeat with
|
|
40805
|
-
set output to output &
|
|
40807
|
+
repeat with recordItem in attachmentList
|
|
40808
|
+
set output to output & recordItem & ${AS_RECORD_SEP}
|
|
40806
40809
|
end repeat
|
|
40807
40810
|
return output
|
|
40808
40811
|
end tell
|
|
@@ -40825,7 +40828,7 @@ var AppleNotesManager = class {
|
|
|
40825
40828
|
name: parts[1].trim(),
|
|
40826
40829
|
contentType: parts[2].trim(),
|
|
40827
40830
|
contentId: parts[2].trim() || void 0,
|
|
40828
|
-
url: parts[3]
|
|
40831
|
+
url: normalizeAppleScriptText(parts[3]),
|
|
40829
40832
|
created: parts[4] ? parseAppleScriptDate(parts[4].trim()) : void 0,
|
|
40830
40833
|
modified: parts[5] ? parseAppleScriptDate(parts[5].trim()) : void 0,
|
|
40831
40834
|
shared: parts[6] ? parts[6].trim().toLowerCase() === "true" : void 0
|
|
@@ -40847,6 +40850,7 @@ var AppleNotesManager = class {
|
|
|
40847
40850
|
let abs;
|
|
40848
40851
|
try {
|
|
40849
40852
|
abs = assertSafeSavePath(savePath);
|
|
40853
|
+
ensureParentDir(abs);
|
|
40850
40854
|
} catch (e) {
|
|
40851
40855
|
return { success: false, error: e instanceof Error ? e.message : String(e) };
|
|
40852
40856
|
}
|
|
@@ -40864,10 +40868,18 @@ var AppleNotesManager = class {
|
|
|
40864
40868
|
end if
|
|
40865
40869
|
end repeat
|
|
40866
40870
|
if theAttachment is missing value then
|
|
40867
|
-
return "ERR${AS_FIELD_SEP}attachment not found"
|
|
40871
|
+
return "ERR" & ${AS_FIELD_SEP} & "attachment not found"
|
|
40868
40872
|
end if
|
|
40869
|
-
|
|
40870
|
-
|
|
40873
|
+
set attachUrl to ""
|
|
40874
|
+
try
|
|
40875
|
+
set attachUrl to URL of theAttachment as text
|
|
40876
|
+
end try
|
|
40877
|
+
try
|
|
40878
|
+
save theAttachment in (POSIX file "${safePath}")
|
|
40879
|
+
on error errMsg
|
|
40880
|
+
return "ERRSAVE" & ${AS_FIELD_SEP} & errMsg & ${AS_FIELD_SEP} & attachUrl
|
|
40881
|
+
end try
|
|
40882
|
+
return "OK" & ${AS_FIELD_SEP} & (name of theAttachment) & ${AS_FIELD_SEP} & (content identifier of theAttachment)
|
|
40871
40883
|
end tell
|
|
40872
40884
|
`;
|
|
40873
40885
|
const result = executeAppleScript(script);
|
|
@@ -40875,6 +40887,16 @@ var AppleNotesManager = class {
|
|
|
40875
40887
|
return { success: false, error: result.error ?? "unknown error" };
|
|
40876
40888
|
}
|
|
40877
40889
|
const parts = (result.output ?? "").trim().split(FIELD_SEP);
|
|
40890
|
+
if (parts[0] === "ERRSAVE") {
|
|
40891
|
+
const saveErr = (parts[1]?.trim() || "unknown error").replace(/\.$/, "");
|
|
40892
|
+
const rawUrl = parts[2]?.trim();
|
|
40893
|
+
const attachUrl = rawUrl && rawUrl !== "missing value" ? rawUrl : void 0;
|
|
40894
|
+
const linkHint = attachUrl ? ` This attachment appears to be a link preview (URL: ${attachUrl}) rather than a file, and link previews have no file payload to save.` : "";
|
|
40895
|
+
return {
|
|
40896
|
+
success: false,
|
|
40897
|
+
error: `Notes could not save this attachment: ${saveErr}.${linkHint}`
|
|
40898
|
+
};
|
|
40899
|
+
}
|
|
40878
40900
|
if (parts[0] !== "OK") {
|
|
40879
40901
|
return { success: false, error: parts[1]?.trim() || "attachment not found" };
|
|
40880
40902
|
}
|
|
@@ -41333,7 +41355,7 @@ var AppleNotesManager = class {
|
|
|
41333
41355
|
};
|
|
41334
41356
|
|
|
41335
41357
|
// src/utils/syncDetection.ts
|
|
41336
|
-
import { execFileSync as
|
|
41358
|
+
import { execFileSync as execFileSync3 } from "child_process";
|
|
41337
41359
|
import * as fs2 from "fs";
|
|
41338
41360
|
import * as path2 from "path";
|
|
41339
41361
|
import * as os2 from "os";
|
|
@@ -41374,7 +41396,7 @@ function getSyncStatus(useCache = true) {
|
|
|
41374
41396
|
WHERE ZCURRENTLOCALVERSION > ZLATESTVERSIONSYNCEDTOCLOUD
|
|
41375
41397
|
AND ZLATESTVERSIONSYNCEDTOCLOUD IS NOT NULL;
|
|
41376
41398
|
`;
|
|
41377
|
-
const result =
|
|
41399
|
+
const result = execFileSync3(
|
|
41378
41400
|
"sqlite3",
|
|
41379
41401
|
["-readonly", NOTES_DB_PATH2, query.replace(/\n/g, " ")],
|
|
41380
41402
|
{
|
|
@@ -41433,7 +41455,7 @@ function withSyncAwarenessSync(operation, fn) {
|
|
|
41433
41455
|
}
|
|
41434
41456
|
|
|
41435
41457
|
// src/utils/noteMetadata.ts
|
|
41436
|
-
import { execFileSync as
|
|
41458
|
+
import { execFileSync as execFileSync4 } from "child_process";
|
|
41437
41459
|
import * as fs3 from "fs";
|
|
41438
41460
|
import * as path3 from "path";
|
|
41439
41461
|
import * as os3 from "os";
|
|
@@ -41454,7 +41476,7 @@ var COLUMN_MAP = [
|
|
|
41454
41476
|
{ key: "smartFolderQuery", column: "ZSMARTFOLDERQUERYJSON", type: "text" }
|
|
41455
41477
|
];
|
|
41456
41478
|
function runSqlite(query) {
|
|
41457
|
-
return
|
|
41479
|
+
return execFileSync4("sqlite3", ["-readonly", NOTES_DB_PATH3, query], {
|
|
41458
41480
|
encoding: "utf8",
|
|
41459
41481
|
timeout: 5e3,
|
|
41460
41482
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -41552,8 +41574,48 @@ function parseHashtags(body) {
|
|
|
41552
41574
|
return result;
|
|
41553
41575
|
}
|
|
41554
41576
|
|
|
41577
|
+
// src/utils/inlineImages.ts
|
|
41578
|
+
var DEFAULT_MAX_INLINE_IMAGE_BYTES = 256 * 1024;
|
|
41579
|
+
function maxInlineImageBytes(env = process.env) {
|
|
41580
|
+
const raw = env.APPLE_NOTES_MCP_MAX_INLINE_IMAGE_BYTES;
|
|
41581
|
+
if (raw !== void 0) {
|
|
41582
|
+
const n = Number(raw);
|
|
41583
|
+
if (Number.isFinite(n) && n > 0) return n;
|
|
41584
|
+
}
|
|
41585
|
+
return DEFAULT_MAX_INLINE_IMAGE_BYTES;
|
|
41586
|
+
}
|
|
41587
|
+
function formatBytes(bytes) {
|
|
41588
|
+
if (bytes >= 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
41589
|
+
if (bytes >= 1024) return `${Math.round(bytes / 1024)} KB`;
|
|
41590
|
+
return `${bytes} B`;
|
|
41591
|
+
}
|
|
41592
|
+
var INLINE_IMG_RE = /<img\b[^>]*\bsrc\s*=\s*(["'])data:([^;'"]+);base64,([^"']*)\1[^>]*\/?>/gi;
|
|
41593
|
+
function stripLargeInlineImages(html, maxBytes = maxInlineImageBytes()) {
|
|
41594
|
+
let strippedCount = 0;
|
|
41595
|
+
let strippedBytes = 0;
|
|
41596
|
+
const result = html.replace(INLINE_IMG_RE, (tag, _quote, mediaType, b64) => {
|
|
41597
|
+
if (b64.length <= maxBytes) return tag;
|
|
41598
|
+
const decodedBytes = Math.floor(b64.length * 3 / 4);
|
|
41599
|
+
strippedCount += 1;
|
|
41600
|
+
strippedBytes += decodedBytes;
|
|
41601
|
+
return `<div>[inline image omitted: ${mediaType}, ~${formatBytes(
|
|
41602
|
+
decodedBytes
|
|
41603
|
+
)}; use list-attachments and save-attachment or fetch-attachment to export it]</div>`;
|
|
41604
|
+
});
|
|
41605
|
+
return { html: result, strippedCount, strippedBytes };
|
|
41606
|
+
}
|
|
41607
|
+
function strippedImagesWarning(stripped) {
|
|
41608
|
+
if (stripped.strippedCount === 0) return null;
|
|
41609
|
+
const plural = stripped.strippedCount === 1 ? "image" : "images";
|
|
41610
|
+
return `
|
|
41611
|
+
|
|
41612
|
+
\u26A0\uFE0F ${stripped.strippedCount} inline ${plural} (~${formatBytes(
|
|
41613
|
+
stripped.strippedBytes
|
|
41614
|
+
)} decoded) exceeded the per-image inline cap and ${stripped.strippedCount === 1 ? "was" : "were"} replaced with placeholders so the response stays within MCP message limits. The images are still in the note: use list-attachments with save-attachment or fetch-attachment to export them, or raise APPLE_NOTES_MCP_MAX_INLINE_IMAGE_BYTES.`;
|
|
41615
|
+
}
|
|
41616
|
+
|
|
41555
41617
|
// src/tools/doctor.ts
|
|
41556
|
-
import { spawnSync
|
|
41618
|
+
import { spawnSync } from "child_process";
|
|
41557
41619
|
function runDoctor(manager) {
|
|
41558
41620
|
const checks = [];
|
|
41559
41621
|
const hc = manager.healthCheck();
|
|
@@ -41591,7 +41653,7 @@ function runDoctor(manager) {
|
|
|
41591
41653
|
function checkNodeRuntimeSignature() {
|
|
41592
41654
|
const name = "Node runtime signature";
|
|
41593
41655
|
try {
|
|
41594
|
-
const r =
|
|
41656
|
+
const r = spawnSync("codesign", ["-dvvv", process.execPath], { encoding: "utf8" });
|
|
41595
41657
|
const out = `${r.stdout ?? ""}${r.stderr ?? ""}`;
|
|
41596
41658
|
if (r.error || !out.trim()) {
|
|
41597
41659
|
return {
|
|
@@ -41911,12 +41973,19 @@ server.registerTool(
|
|
|
41911
41973
|
`Note "${note2.title}" is password-protected and cannot be read. Unlock it in Notes.app first.`
|
|
41912
41974
|
);
|
|
41913
41975
|
}
|
|
41914
|
-
const
|
|
41915
|
-
if (!
|
|
41976
|
+
const rawContent2 = notesManager.getNoteContentById(id);
|
|
41977
|
+
if (!rawContent2) {
|
|
41916
41978
|
return errorResponse(`Failed to read content of note "${note2.title}"`);
|
|
41917
41979
|
}
|
|
41980
|
+
const stripped2 = stripLargeInlineImages(rawContent2);
|
|
41981
|
+
const content2 = stripped2.html;
|
|
41918
41982
|
const hashtags2 = parseHashtags(content2);
|
|
41919
|
-
|
|
41983
|
+
const warning2 = strippedImagesWarning(stripped2);
|
|
41984
|
+
return successResponse(warning2 ? content2 + warning2 : content2, {
|
|
41985
|
+
title: note2.title,
|
|
41986
|
+
content: content2,
|
|
41987
|
+
hashtags: hashtags2
|
|
41988
|
+
});
|
|
41920
41989
|
}
|
|
41921
41990
|
if (!title) {
|
|
41922
41991
|
return errorResponse("Either 'id' or 'title' is required");
|
|
@@ -41930,12 +41999,15 @@ server.registerTool(
|
|
|
41930
41999
|
`Note "${title}" is password-protected and cannot be read. Unlock it in Notes.app first.`
|
|
41931
42000
|
);
|
|
41932
42001
|
}
|
|
41933
|
-
const
|
|
41934
|
-
if (!
|
|
42002
|
+
const rawContent = notesManager.getNoteContent(title, account);
|
|
42003
|
+
if (!rawContent) {
|
|
41935
42004
|
return errorResponse(`Failed to read content of note "${title}"`);
|
|
41936
42005
|
}
|
|
42006
|
+
const stripped = stripLargeInlineImages(rawContent);
|
|
42007
|
+
const content = stripped.html;
|
|
41937
42008
|
const hashtags = parseHashtags(content);
|
|
41938
|
-
|
|
42009
|
+
const warning = strippedImagesWarning(stripped);
|
|
42010
|
+
return successResponse(warning ? content + warning : content, { title, content, hashtags });
|
|
41939
42011
|
}, "Error retrieving note content")
|
|
41940
42012
|
);
|
|
41941
42013
|
server.registerTool(
|
package/package.json
CHANGED