apple-notes-mcp 2.9.26 → 2.9.27
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 +14 -9
- package/build/index.js +462 -164
- package/native/public-helper/apple-notes-public-helper.swift +130 -52
- package/package.json +1 -1
package/build/index.js
CHANGED
|
@@ -30351,7 +30351,7 @@ var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => {
|
|
|
30351
30351
|
return (payload, ctx) => fn(shape, payload, ctx);
|
|
30352
30352
|
};
|
|
30353
30353
|
let fastpass;
|
|
30354
|
-
const
|
|
30354
|
+
const isObject4 = isObject;
|
|
30355
30355
|
const jit = !globalConfig.jitless;
|
|
30356
30356
|
const allowsEval2 = allowsEval;
|
|
30357
30357
|
const fastEnabled = jit && allowsEval2.value;
|
|
@@ -30360,7 +30360,7 @@ var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => {
|
|
|
30360
30360
|
inst._zod.parse = (payload, ctx) => {
|
|
30361
30361
|
value ?? (value = _normalized.value);
|
|
30362
30362
|
const input = payload.value;
|
|
30363
|
-
if (!
|
|
30363
|
+
if (!isObject4(input)) {
|
|
30364
30364
|
payload.issues.push({
|
|
30365
30365
|
expected: "object",
|
|
30366
30366
|
code: "invalid_type",
|
|
@@ -39361,7 +39361,7 @@ function bytesValue(field) {
|
|
|
39361
39361
|
function stringValue(field) {
|
|
39362
39362
|
const bytes = bytesValue(field);
|
|
39363
39363
|
if (!bytes) return void 0;
|
|
39364
|
-
return new TextDecoder().decode(bytes);
|
|
39364
|
+
return new TextDecoder("utf-8", { ignoreBOM: true }).decode(bytes);
|
|
39365
39365
|
}
|
|
39366
39366
|
function embeddedMessage(field) {
|
|
39367
39367
|
const bytes = bytesValue(field);
|
|
@@ -39641,6 +39641,10 @@ function identifierFailureIn(message) {
|
|
|
39641
39641
|
function canonicalKey(value) {
|
|
39642
39642
|
return BigInt(value).toString();
|
|
39643
39643
|
}
|
|
39644
|
+
function canonicalCoreDataId(id2) {
|
|
39645
|
+
const match = /^x-coredata:\/\/([0-9A-Fa-f-]+)\/(IC[A-Za-z]+)\/p(\d+)$/.exec(id2);
|
|
39646
|
+
return match ? `x-coredata://${match[1].toUpperCase()}/${match[2]}/p${canonicalKey(match[3])}` : id2;
|
|
39647
|
+
}
|
|
39644
39648
|
function assertAll(values, pattern2, label) {
|
|
39645
39649
|
for (const value of values) {
|
|
39646
39650
|
if (!pattern2.test(value)) throw new Error(`Refusing to query with an invalid ${label}`);
|
|
@@ -40034,7 +40038,7 @@ function styleValue(field) {
|
|
|
40034
40038
|
}
|
|
40035
40039
|
return Buffer.from(field.value).toString("hex");
|
|
40036
40040
|
}
|
|
40037
|
-
function parseRichNote(data, nativeTags = []) {
|
|
40041
|
+
function parseRichNote(data, nativeTags = [], options = {}) {
|
|
40038
40042
|
const doc = decodeMessage(data);
|
|
40039
40043
|
const wrapper = embeddedMessage(getField(doc, 2));
|
|
40040
40044
|
const body = wrapper && embeddedMessage(getField(wrapper, 3));
|
|
@@ -40074,7 +40078,7 @@ function parseRichNote(data, nativeTags = []) {
|
|
|
40074
40078
|
if (varintValue(getField(fields, 14))) lossy.add("highlight");
|
|
40075
40079
|
}
|
|
40076
40080
|
const url = stringValue(getField(fields, 9));
|
|
40077
|
-
if (url) {
|
|
40081
|
+
if (url && !(options.skipUnsafeLinks && !safeUrl(url))) {
|
|
40078
40082
|
if (!safeUrl(url)) throw new Error("Unsupported link scheme in note");
|
|
40079
40083
|
const previous = links.at(-1);
|
|
40080
40084
|
if (previous?.url === url && previous.start + previous.length === position) {
|
|
@@ -40129,7 +40133,7 @@ function parseRichNote(data, nativeTags = []) {
|
|
|
40129
40133
|
...lossy.size ? { htmlLossyFormatting: HTML_LOSSY_ORDER.filter((f) => lossy.has(f)) } : {}
|
|
40130
40134
|
};
|
|
40131
40135
|
}
|
|
40132
|
-
function readRichNote(id2) {
|
|
40136
|
+
function readRichNote(id2, options = {}) {
|
|
40133
40137
|
const pk = /^x-coredata:\/\/[0-9a-f-]+\/ICNote\/p([0-9]+)$/i.exec(id2)?.[1];
|
|
40134
40138
|
if (!pk) throw new Error("Invalid exact note ID");
|
|
40135
40139
|
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;`;
|
|
@@ -40144,7 +40148,9 @@ function readRichNote(id2) {
|
|
|
40144
40148
|
if (!tags || Array.isArray(tags) || typeof tags !== "object" || Object.values(tags).some((tag) => typeof tag !== "string"))
|
|
40145
40149
|
throw new Error("Invalid native tags");
|
|
40146
40150
|
const rich = parseRichNote(
|
|
40147
|
-
gunzipSync2(Buffer.from(rows[0], "hex"), { maxOutputLength: 32 * 1024 * 1024 })
|
|
40151
|
+
gunzipSync2(Buffer.from(rows[0], "hex"), { maxOutputLength: 32 * 1024 * 1024 }),
|
|
40152
|
+
[],
|
|
40153
|
+
options
|
|
40148
40154
|
);
|
|
40149
40155
|
const tagMap = tags;
|
|
40150
40156
|
const objectData = JSON.parse(rows[2] || "[]");
|
|
@@ -41660,6 +41666,7 @@ function buildAttachmentRowsSql(notePk, columns) {
|
|
|
41660
41666
|
`'identifier', a.ZIDENTIFIER`,
|
|
41661
41667
|
`'uti', ${col3("a", "ZTYPEUTI")}`,
|
|
41662
41668
|
`'parentPk', ${parent}`,
|
|
41669
|
+
`'parentDeleted', ${parent !== "NULL" && columns.has("ZMARKEDFORDELETION") ? `(SELECT COALESCE(p.ZMARKEDFORDELETION, 0) FROM ZICCLOUDSYNCINGOBJECT p WHERE p.Z_PK = ${parent})` : "0"}`,
|
|
41663
41670
|
`'filename', ${col3("a", "ZFILENAME")}`,
|
|
41664
41671
|
`'mediaIdentifier', m.ZIDENTIFIER`,
|
|
41665
41672
|
`'mediaFilename', ${col3("m", "ZFILENAME")}`,
|
|
@@ -41718,6 +41725,7 @@ function parseAttachmentRows(json2) {
|
|
|
41718
41725
|
identifier,
|
|
41719
41726
|
uti: toStringOrNull(r.uti),
|
|
41720
41727
|
parentPk: toIntOrNull(r.parentPk),
|
|
41728
|
+
...toIntOrNull(r.parentDeleted) ? { parentDeleted: true } : {},
|
|
41721
41729
|
filename: toStringOrNull(r.filename),
|
|
41722
41730
|
mediaIdentifier: toStringOrNull(r.mediaIdentifier),
|
|
41723
41731
|
mediaFilename: toStringOrNull(r.mediaFilename),
|
|
@@ -41835,7 +41843,7 @@ function generationDirs(base, accountDir) {
|
|
|
41835
41843
|
const entries2 = boundedEntries(base, MAX_GENERATION_DIRS) ?? [];
|
|
41836
41844
|
return entries2.map((e) => realInside(join8(base, e), accountDir)).filter((p) => p !== null && isDirectory(p)).sort((a, b) => generationRank(basename(b)) - generationRank(basename(a)));
|
|
41837
41845
|
}
|
|
41838
|
-
function fallbackFiles(accountDir, rootName, identifier, generation, names) {
|
|
41846
|
+
function fallbackFiles(accountDir, rootName, identifier, generation, names, onStale) {
|
|
41839
41847
|
const base = join8(accountDir, rootName, identifier);
|
|
41840
41848
|
const found = [];
|
|
41841
41849
|
const add = (candidate) => {
|
|
@@ -41844,12 +41852,14 @@ function fallbackFiles(accountDir, rootName, identifier, generation, names) {
|
|
|
41844
41852
|
};
|
|
41845
41853
|
const gen = safeComponent(generation);
|
|
41846
41854
|
if (gen) for (const name of names) add(join8(base, gen, name));
|
|
41855
|
+
const recorded = found.length;
|
|
41847
41856
|
if (isDirectory(base)) {
|
|
41848
41857
|
for (const dir of generationDirs(base, accountDir))
|
|
41849
41858
|
for (const name of names) add(join8(dir, name));
|
|
41850
41859
|
for (const name of names) add(join8(base, name));
|
|
41851
41860
|
}
|
|
41852
41861
|
for (const name of names) add(join8(accountDir, rootName, `${identifier}${extname(name)}`));
|
|
41862
|
+
if (gen && recorded === 0 && found.length > 0) onStale?.();
|
|
41853
41863
|
return found;
|
|
41854
41864
|
}
|
|
41855
41865
|
function previewPixelArea(name) {
|
|
@@ -41895,7 +41905,7 @@ function previewPaths(accountDir, identifier, entries2) {
|
|
|
41895
41905
|
}
|
|
41896
41906
|
return files;
|
|
41897
41907
|
}
|
|
41898
|
-
function assetPathsFor(accountDir, row) {
|
|
41908
|
+
function assetPathsFor(accountDir, row, onStale) {
|
|
41899
41909
|
const found = [];
|
|
41900
41910
|
const add = (candidate) => {
|
|
41901
41911
|
const real = realInside(candidate, accountDir);
|
|
@@ -41912,18 +41922,28 @@ function assetPathsFor(accountDir, row) {
|
|
|
41912
41922
|
if (!id2) return found;
|
|
41913
41923
|
const ownName = safeComponent(row.filename);
|
|
41914
41924
|
if (ownName) add(join8(accountDir, "Media", id2, ownName));
|
|
41915
|
-
for (const file of fallbackFiles(
|
|
41916
|
-
|
|
41917
|
-
"
|
|
41918
|
-
|
|
41925
|
+
for (const file of fallbackFiles(
|
|
41926
|
+
accountDir,
|
|
41927
|
+
"FallbackImages",
|
|
41928
|
+
id2,
|
|
41929
|
+
row.fallbackImageGeneration,
|
|
41930
|
+
["FallbackImage.png", "FallbackImage.jpg"],
|
|
41931
|
+
onStale
|
|
41932
|
+
))
|
|
41919
41933
|
add(file);
|
|
41920
|
-
for (const file of fallbackFiles(
|
|
41921
|
-
|
|
41922
|
-
|
|
41934
|
+
for (const file of fallbackFiles(
|
|
41935
|
+
accountDir,
|
|
41936
|
+
"FallbackPDFs",
|
|
41937
|
+
id2,
|
|
41938
|
+
row.fallbackPdfGeneration,
|
|
41939
|
+
["FallbackPDF.pdf"],
|
|
41940
|
+
onStale
|
|
41941
|
+
))
|
|
41923
41942
|
add(file);
|
|
41924
41943
|
return found;
|
|
41925
41944
|
}
|
|
41926
|
-
function assembleAttachmentAssets(
|
|
41945
|
+
function assembleAttachmentAssets(allRows, bodyOrder, containerDir = NOTES_CONTAINER_DIR) {
|
|
41946
|
+
const rows = allRows.filter((r) => !r.parentDeleted);
|
|
41927
41947
|
const byPk = new Map(rows.map((r) => [r.pk, r]));
|
|
41928
41948
|
const roots = rows.filter((r) => r.parentPk === null || !byPk.has(r.parentPk));
|
|
41929
41949
|
const bodyIndex = /* @__PURE__ */ new Map();
|
|
@@ -41946,10 +41966,11 @@ function assembleAttachmentAssets(rows, bodyOrder, containerDir = NOTES_CONTAINE
|
|
|
41946
41966
|
const accountDir = accountDirFor(row.accountIdentifier ?? parent?.accountIdentifier ?? null);
|
|
41947
41967
|
let assetPaths = [];
|
|
41948
41968
|
let previews = [];
|
|
41969
|
+
let fallbackStale = false;
|
|
41949
41970
|
if (accountDir) {
|
|
41950
41971
|
if (!previewEntries.has(accountDir))
|
|
41951
41972
|
previewEntries.set(accountDir, listPreviewEntries(accountDir));
|
|
41952
|
-
assetPaths = assetPathsFor(accountDir, row);
|
|
41973
|
+
assetPaths = assetPathsFor(accountDir, row, () => fallbackStale = true);
|
|
41953
41974
|
previews = previewPaths(accountDir, row.identifier, previewEntries.get(accountDir));
|
|
41954
41975
|
}
|
|
41955
41976
|
const previewPath = previews[0] ?? null;
|
|
@@ -41962,6 +41983,7 @@ function assembleAttachmentAssets(rows, bodyOrder, containerDir = NOTES_CONTAINE
|
|
|
41962
41983
|
filename: row.filename ?? row.mediaFilename,
|
|
41963
41984
|
bodyIndex: parent ? null : indexOf(row),
|
|
41964
41985
|
assetPaths,
|
|
41986
|
+
...fallbackStale ? { fallbackStale: true } : {},
|
|
41965
41987
|
previewPath,
|
|
41966
41988
|
paths: previewPath ? [...assetPaths, previewPath] : [...assetPaths]
|
|
41967
41989
|
};
|
|
@@ -42047,6 +42069,11 @@ function copyFileExclusive(src, dest) {
|
|
|
42047
42069
|
function exportFileName(record2, source, kind) {
|
|
42048
42070
|
const ext = extname(source);
|
|
42049
42071
|
const id2 = safeComponent(record2.identifier) ?? "attachment";
|
|
42072
|
+
if (kind === "fallback") {
|
|
42073
|
+
const stored2 = safeComponent(record2.filename ? basename(record2.filename) : null);
|
|
42074
|
+
const stem = stored2 && !GENERIC_FILE_NAMES.has(stored2.toLowerCase()) ? basename(stored2, extname(stored2)) : id2;
|
|
42075
|
+
return `${safeComponent(stem) ?? id2}${ext}`;
|
|
42076
|
+
}
|
|
42050
42077
|
if (kind === "preview") {
|
|
42051
42078
|
const stored2 = safeComponent(record2.filename ? basename(record2.filename) : null);
|
|
42052
42079
|
const stem = stored2 ? basename(stored2, extname(stored2)) : id2;
|
|
@@ -42075,7 +42102,7 @@ function prepareExportDir(exportDir, containerDir = NOTES_CONTAINER_DIR) {
|
|
|
42075
42102
|
}
|
|
42076
42103
|
return abs;
|
|
42077
42104
|
}
|
|
42078
|
-
function exportOneAttachment(record2, dir, source) {
|
|
42105
|
+
function exportOneAttachment(record2, dir, source, inBody) {
|
|
42079
42106
|
const base = {
|
|
42080
42107
|
pk: record2.pk,
|
|
42081
42108
|
identifier: record2.identifier,
|
|
@@ -42083,7 +42110,8 @@ function exportOneAttachment(record2, dir, source) {
|
|
|
42083
42110
|
kind: record2.kind,
|
|
42084
42111
|
parentIdentifier: record2.parentIdentifier,
|
|
42085
42112
|
exportedTo: null,
|
|
42086
|
-
exportedKind: null
|
|
42113
|
+
exportedKind: null,
|
|
42114
|
+
...inBody === false ? { inBody: false } : {}
|
|
42087
42115
|
};
|
|
42088
42116
|
if (!source) return base;
|
|
42089
42117
|
const name = exportFileName(record2, source.path, source.kind);
|
|
@@ -42094,7 +42122,12 @@ function exportOneAttachment(record2, dir, source) {
|
|
|
42094
42122
|
throw new Error(`Refusing to write outside the export directory: "${dest}"`);
|
|
42095
42123
|
assertSafeSavePath(dest);
|
|
42096
42124
|
copyFileExclusive(source.path, dest);
|
|
42097
|
-
return {
|
|
42125
|
+
return {
|
|
42126
|
+
...base,
|
|
42127
|
+
exportedTo: dest,
|
|
42128
|
+
exportedKind: source.kind,
|
|
42129
|
+
...source.kind === "fallback" && record2.fallbackStale ? { stale: true } : {}
|
|
42130
|
+
};
|
|
42098
42131
|
} catch (error2) {
|
|
42099
42132
|
if (error2.code === "EEXIST") continue;
|
|
42100
42133
|
return { ...base, error: error2 instanceof Error ? error2.message : String(error2) };
|
|
@@ -42102,20 +42135,31 @@ function exportOneAttachment(record2, dir, source) {
|
|
|
42102
42135
|
}
|
|
42103
42136
|
return { ...base, error: "Too many name collisions in the export directory" };
|
|
42104
42137
|
}
|
|
42138
|
+
function isFallbackRendering(path10) {
|
|
42139
|
+
return /[\\/]Fallback(?:Images|PDFs)[\\/]/.test(path10);
|
|
42140
|
+
}
|
|
42105
42141
|
function exportSource(record2) {
|
|
42106
|
-
|
|
42142
|
+
const asset = record2.assetPaths[0];
|
|
42143
|
+
if (asset) return { path: asset, kind: isFallbackRendering(asset) ? "fallback" : "asset" };
|
|
42107
42144
|
if (record2.previewPath) return { path: record2.previewPath, kind: "preview" };
|
|
42108
42145
|
return null;
|
|
42109
42146
|
}
|
|
42110
42147
|
function exportAttachmentAssets(assets, exportDir, options = {}) {
|
|
42111
42148
|
const dir = prepareExportDir(exportDir, options.containerDir);
|
|
42149
|
+
const inBody = (record2) => {
|
|
42150
|
+
if (assets.orderSource !== "body") return void 0;
|
|
42151
|
+
const root = record2.parentIdentifier === null ? record2 : assets.attachments.find(
|
|
42152
|
+
(a) => a.parentIdentifier === null && a.identifier === record2.parentIdentifier
|
|
42153
|
+
);
|
|
42154
|
+
return root ? root.bodyIndex !== null : void 0;
|
|
42155
|
+
};
|
|
42112
42156
|
if (options.firstImageOnly) {
|
|
42113
42157
|
const first2 = selectFirstImage(assets);
|
|
42114
42158
|
if (!first2) return { exportDir: dir, results: [], firstImage: null };
|
|
42115
42159
|
const record2 = assets.attachments.find((a) => a.pk === first2.pk);
|
|
42116
42160
|
return {
|
|
42117
42161
|
exportDir: dir,
|
|
42118
|
-
results: [exportOneAttachment(record2, dir, exportSource(record2))],
|
|
42162
|
+
results: [exportOneAttachment(record2, dir, exportSource(record2), inBody(record2))],
|
|
42119
42163
|
firstImage: first2
|
|
42120
42164
|
};
|
|
42121
42165
|
}
|
|
@@ -42129,7 +42173,7 @@ function exportAttachmentAssets(assets, exportDir, options = {}) {
|
|
|
42129
42173
|
} else if (!exportSource(record2) && assets.attachments.some((c) => c.parentIdentifier === record2.identifier)) {
|
|
42130
42174
|
continue;
|
|
42131
42175
|
}
|
|
42132
|
-
results.push(exportOneAttachment(record2, dir, exportSource(record2)));
|
|
42176
|
+
results.push(exportOneAttachment(record2, dir, exportSource(record2), inBody(record2)));
|
|
42133
42177
|
}
|
|
42134
42178
|
return { exportDir: dir, results };
|
|
42135
42179
|
}
|
|
@@ -42298,7 +42342,17 @@ function entries(dir, limit) {
|
|
|
42298
42342
|
}
|
|
42299
42343
|
}
|
|
42300
42344
|
var byGenerationDesc = (a, b) => generationRank(basename2(b)) - generationRank(basename2(a));
|
|
42301
|
-
function
|
|
42345
|
+
function locateFallbackImage(accountDir, identifier, generation) {
|
|
42346
|
+
const gen = safeComponent(generation);
|
|
42347
|
+
const path10 = searchFallbackImage(accountDir, identifier, generation);
|
|
42348
|
+
if (!path10 || !gen) return { path: path10, stale: false };
|
|
42349
|
+
const id2 = safeComponent(identifier);
|
|
42350
|
+
const recorded = ["FallbackImage.png", "FallbackImage.jpg"].map(
|
|
42351
|
+
(n) => id2 ? realInside(join9(accountDir, "FallbackImages", id2, gen, n), accountDir) : null
|
|
42352
|
+
).filter((p) => p !== null);
|
|
42353
|
+
return { path: path10, stale: !recorded.includes(path10) };
|
|
42354
|
+
}
|
|
42355
|
+
function searchFallbackImage(accountDir, identifier, generation) {
|
|
42302
42356
|
const id2 = safeComponent(identifier);
|
|
42303
42357
|
if (!id2) return null;
|
|
42304
42358
|
const base = join9(accountDir, "FallbackImages", id2);
|
|
@@ -42345,7 +42399,8 @@ function describeDrawings(rows, containerDir = NOTES_CONTAINER_DIR) {
|
|
|
42345
42399
|
const accountDir = resolveAccountDir(containerDir, row.accountIdentifier);
|
|
42346
42400
|
const kind = row.uti === "com.apple.paper" ? "paper" : "drawing";
|
|
42347
42401
|
const id2 = safeComponent(row.identifier);
|
|
42348
|
-
const
|
|
42402
|
+
const fallback = accountDir ? locateFallbackImage(accountDir, row.identifier, row.fallbackImageGeneration) : { path: null, stale: false };
|
|
42403
|
+
const fallbackImagePath = fallback.path;
|
|
42349
42404
|
const previewPath = accountDir ? findLargestPreview(accountDir, row.identifier) : null;
|
|
42350
42405
|
const bundle = accountDir && id2 && kind === "paper" ? realInside(join9(accountDir, "Paper", "Bundles", `${id2}.bundle`), accountDir) : null;
|
|
42351
42406
|
let raster = null;
|
|
@@ -42367,6 +42422,7 @@ function describeDrawings(rows, containerDir = NOTES_CONTAINER_DIR) {
|
|
|
42367
42422
|
handwritingSummary: row.handwritingSummary,
|
|
42368
42423
|
bundlePresent: bundle !== null && kindOf(bundle) === "dir",
|
|
42369
42424
|
fallbackImagePath,
|
|
42425
|
+
fallbackImageStale: fallback.stale,
|
|
42370
42426
|
previewPath,
|
|
42371
42427
|
raster
|
|
42372
42428
|
};
|
|
@@ -42507,18 +42563,25 @@ function idList(ids) {
|
|
|
42507
42563
|
function buildScopeGuardScript(noteVar, guard, destinationVar) {
|
|
42508
42564
|
if (!hasScopeGuard(guard)) return "";
|
|
42509
42565
|
validateScopeGuard(guard);
|
|
42510
|
-
const
|
|
42566
|
+
const ifFolderId = guard.ifFolderId && canonicalCoreDataId(guard.ifFolderId);
|
|
42567
|
+
const ifAncestorFolderId = guard.ifAncestorFolderId && canonicalCoreDataId(guard.ifAncestorFolderId);
|
|
42568
|
+
const forbidden = [...new Set((guard.forbiddenAncestorFolderIds ?? []).map(canonicalCoreDataId))];
|
|
42511
42569
|
let script = `
|
|
42512
42570
|
set scopeFolder to container of ${noteVar}
|
|
42513
42571
|
if class of scopeFolder is not folder then return "${SCOPE_MARKER}:the note is not in a folder"`;
|
|
42514
|
-
if (
|
|
42572
|
+
if (forbidden.length > 0)
|
|
42515
42573
|
script += `
|
|
42516
|
-
|
|
42517
|
-
|
|
42574
|
+
repeat with forbiddenId in ${idList(forbidden)}
|
|
42575
|
+
if not (exists folder id (contents of forbiddenId)) then return "${SCOPE_MARKER}:a forbidden folder id does not match any folder"
|
|
42576
|
+
end repeat`;
|
|
42577
|
+
if (ifFolderId)
|
|
42578
|
+
script += `
|
|
42579
|
+
if (id of scopeFolder) is not "${ifFolderId}" then return "${SCOPE_MARKER}:the note is not in the expected folder"`;
|
|
42580
|
+
if (ifAncestorFolderId || forbidden.length > 0)
|
|
42518
42581
|
script += chainScript("scopeChain", "scopeFolder");
|
|
42519
|
-
if (
|
|
42582
|
+
if (ifAncestorFolderId)
|
|
42520
42583
|
script += `
|
|
42521
|
-
if scopeChain does not contain "${
|
|
42584
|
+
if scopeChain does not contain "${ifAncestorFolderId}" then return "${SCOPE_MARKER}:the note is not inside the expected ancestor folder"`;
|
|
42522
42585
|
if (forbidden.length > 0) {
|
|
42523
42586
|
script += `
|
|
42524
42587
|
repeat with forbiddenId in ${idList(forbidden)}
|
|
@@ -43435,7 +43498,7 @@ var AppleNotesManager = class {
|
|
|
43435
43498
|
* @throws Error when the note's rich data cannot be read (e.g. no Full Disk Access)
|
|
43436
43499
|
*/
|
|
43437
43500
|
getNoteTablesById(id2) {
|
|
43438
|
-
return collectNoteTables(readRichNote(id2), id2);
|
|
43501
|
+
return collectNoteTables(readRichNote(id2, { skipUnsafeLinks: true }), id2);
|
|
43439
43502
|
}
|
|
43440
43503
|
/**
|
|
43441
43504
|
* Retrieves detailed metadata for a note by title.
|
|
@@ -43568,6 +43631,7 @@ var AppleNotesManager = class {
|
|
|
43568
43631
|
return `
|
|
43569
43632
|
if not (exists note id "${safeGuardId}") then ${inactive("missing")}
|
|
43570
43633
|
set ${ref} to note id "${safeGuardId}"
|
|
43634
|
+
if (id of ${ref}) is (id of noteRef) then ${inactive("the note being deleted")}
|
|
43571
43635
|
if password protected of ${ref} then ${inactive("locked")}
|
|
43572
43636
|
set ${folderVar} to missing value
|
|
43573
43637
|
try
|
|
@@ -46328,7 +46392,7 @@ var HIGHLIGHTS = {
|
|
|
46328
46392
|
var KNOWN_RUN_FIELDS = /* @__PURE__ */ new Set([1, 2, 3, 5, 6, 7, 8, 9, 10, 12, 14]);
|
|
46329
46393
|
var KNOWN_PARAGRAPH_FIELDS = /* @__PURE__ */ new Set([1, 2, 4, 5, 8, 9]);
|
|
46330
46394
|
var isSafeLink = (url) => /^(?:https?:\/\/|notes:\/\/|applenotes:|mailto:)/i.test(url) && !Array.from(url).some((char) => char.charCodeAt(0) < 32);
|
|
46331
|
-
var utf8 = new TextDecoder();
|
|
46395
|
+
var utf8 = new TextDecoder("utf-8", { ignoreBOM: true });
|
|
46332
46396
|
var first = (fields, n) => fields.find((f) => f.fieldNumber === n);
|
|
46333
46397
|
var varintOf = (fields, n) => {
|
|
46334
46398
|
const f = first(fields, n);
|
|
@@ -46477,7 +46541,8 @@ function decodeNoteBlocks(data) {
|
|
|
46477
46541
|
const end = newline === -1 ? text2.length : newline;
|
|
46478
46542
|
while (runIndex < runs.length - 1 && runs[runIndex].start + runs[runIndex].length <= paragraphStart)
|
|
46479
46543
|
runIndex++;
|
|
46480
|
-
const
|
|
46544
|
+
const covering = runs[runIndex];
|
|
46545
|
+
const attrs = !covering ? DEFAULT_PARAGRAPH : covering.paragraph.styleType === 103 && checklistRunLineStart(text2, covering.start, covering.length) > paragraphStart ? DEFAULT_PARAGRAPH : covering.paragraph;
|
|
46481
46546
|
const style = attrs.styleType === null ? "body" : STYLE_NAMES[attrs.styleType] ?? "unknown";
|
|
46482
46547
|
const alignment = ALIGNMENTS[attrs.alignmentValue] ?? "unknown";
|
|
46483
46548
|
const block = {
|
|
@@ -46684,6 +46749,25 @@ function readNoteBlocks(id2, { dbPath: dbPath2 = NOTES_DB_PATH9 } = {}) {
|
|
|
46684
46749
|
return decodeCompressedNoteBlocks(Buffer.from(row.data, "hex"));
|
|
46685
46750
|
}
|
|
46686
46751
|
|
|
46752
|
+
// src/utils/wordCount.ts
|
|
46753
|
+
var UNSPACED_SCRIPT = /[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Thai}\p{Script=Lao}\p{Script=Khmer}\p{Script=Myanmar}]/u;
|
|
46754
|
+
var segmenter;
|
|
46755
|
+
function countWords(text2) {
|
|
46756
|
+
let count = 0;
|
|
46757
|
+
for (const run of text2.replace(//gu, " ").split(/\s+/u)) {
|
|
46758
|
+
if (!/[\p{L}\p{N}]/u.test(run)) continue;
|
|
46759
|
+
if (!UNSPACED_SCRIPT.test(run)) {
|
|
46760
|
+
count++;
|
|
46761
|
+
continue;
|
|
46762
|
+
}
|
|
46763
|
+
segmenter ??= new Intl.Segmenter(void 0, { granularity: "word" });
|
|
46764
|
+
let words = 0;
|
|
46765
|
+
for (const segment of segmenter.segment(run)) if (segment.isWordLike) words++;
|
|
46766
|
+
count += Math.max(1, words);
|
|
46767
|
+
}
|
|
46768
|
+
return count;
|
|
46769
|
+
}
|
|
46770
|
+
|
|
46687
46771
|
// src/utils/noteRecentList.ts
|
|
46688
46772
|
var RECENT_LIMIT = { DEFAULT: 50, MAX: 1e3 };
|
|
46689
46773
|
var CHECKPOINT_PREFIX = "cdts1:";
|
|
@@ -46738,9 +46822,7 @@ function parseSince(input) {
|
|
|
46738
46822
|
}
|
|
46739
46823
|
function textStats(text2) {
|
|
46740
46824
|
const visible2 = text2.replace(OBJECT_REPLACEMENT, "");
|
|
46741
|
-
|
|
46742
|
-
for (const token of visible2.split(/\s+/u)) if (/[\p{L}\p{N}]/u.test(token)) wordCount2++;
|
|
46743
|
-
return { wordCount: wordCount2, charCount: [...visible2].length };
|
|
46825
|
+
return { wordCount: countWords(visible2), charCount: [...visible2].length };
|
|
46744
46826
|
}
|
|
46745
46827
|
function previewText(text2) {
|
|
46746
46828
|
const flat = text2.replace(OBJECT_REPLACEMENT, " ").replace(/\s+/gu, " ").trim();
|
|
@@ -47362,6 +47444,10 @@ var Parser = class {
|
|
|
47362
47444
|
function parseNoteQuery(input) {
|
|
47363
47445
|
return new Parser(tokenize(input), input.length).parse();
|
|
47364
47446
|
}
|
|
47447
|
+
function noteBodyText(text2) {
|
|
47448
|
+
const firstBreak = text2.indexOf("\n");
|
|
47449
|
+
return firstBreak === -1 ? "" : text2.slice(firstBreak + 1);
|
|
47450
|
+
}
|
|
47365
47451
|
function normalizeForMatch(text2) {
|
|
47366
47452
|
return text2.normalize("NFC").replace(/[\ufffc\u00a0]/gu, " ").toLowerCase();
|
|
47367
47453
|
}
|
|
@@ -47436,20 +47522,36 @@ function cheapFirst(children) {
|
|
|
47436
47522
|
}
|
|
47437
47523
|
return ordered;
|
|
47438
47524
|
}
|
|
47439
|
-
function
|
|
47525
|
+
function evaluateNoteQueryTruth(node, note) {
|
|
47440
47526
|
switch (node.type) {
|
|
47441
|
-
case "and":
|
|
47442
|
-
|
|
47443
|
-
|
|
47444
|
-
|
|
47445
|
-
|
|
47446
|
-
|
|
47527
|
+
case "and": {
|
|
47528
|
+
let unknown2 = false;
|
|
47529
|
+
for (const child2 of cheapFirst(node.children)) {
|
|
47530
|
+
const value = evaluateNoteQueryTruth(child2, note);
|
|
47531
|
+
if (value === false) return false;
|
|
47532
|
+
if (value === null) unknown2 = true;
|
|
47533
|
+
}
|
|
47534
|
+
return unknown2 ? null : true;
|
|
47535
|
+
}
|
|
47536
|
+
case "or": {
|
|
47537
|
+
let unknown2 = false;
|
|
47538
|
+
for (const child2 of cheapFirst(node.children)) {
|
|
47539
|
+
const value = evaluateNoteQueryTruth(child2, note);
|
|
47540
|
+
if (value === true) return true;
|
|
47541
|
+
if (value === null) unknown2 = true;
|
|
47542
|
+
}
|
|
47543
|
+
return unknown2 ? null : false;
|
|
47544
|
+
}
|
|
47545
|
+
case "not": {
|
|
47546
|
+
const value = evaluateNoteQueryTruth(node.child, note);
|
|
47547
|
+
return value === null ? null : !value;
|
|
47548
|
+
}
|
|
47447
47549
|
case "text": {
|
|
47448
47550
|
const needle = normalizeForMatch(node.value);
|
|
47449
47551
|
if (node.field === "title") return note.titleLower.includes(needle);
|
|
47450
47552
|
if (node.field === "any" && note.titleLower.includes(needle)) return true;
|
|
47451
47553
|
const content = note.content();
|
|
47452
|
-
if (!content) return
|
|
47554
|
+
if (!content) return null;
|
|
47453
47555
|
return (node.field === "body" ? content.bodyLower : content.textLower).includes(needle);
|
|
47454
47556
|
}
|
|
47455
47557
|
case "folder":
|
|
@@ -47462,21 +47564,27 @@ function evaluateNoteQuery(node, note) {
|
|
|
47462
47564
|
return compareDate(node.field === "created" ? note.created : note.modified, node);
|
|
47463
47565
|
case "tag": {
|
|
47464
47566
|
const content = note.content();
|
|
47465
|
-
return
|
|
47567
|
+
return content ? content.tags.includes(normalizeForMatch(node.value)) : null;
|
|
47568
|
+
}
|
|
47569
|
+
case "has": {
|
|
47570
|
+
const content = note.content();
|
|
47571
|
+
return content ? content.facets.has(node.facet) : null;
|
|
47466
47572
|
}
|
|
47467
|
-
case "has":
|
|
47468
|
-
return Boolean(note.content()?.facets.has(node.facet));
|
|
47469
47573
|
case "checklist": {
|
|
47470
47574
|
const content = note.content();
|
|
47471
|
-
if (!content
|
|
47575
|
+
if (!content) return null;
|
|
47576
|
+
if (content.checklist.total === 0) return false;
|
|
47472
47577
|
return node.state === "open" ? content.checklist.open > 0 : content.checklist.open === 0;
|
|
47473
47578
|
}
|
|
47474
47579
|
case "words": {
|
|
47475
47580
|
const content = note.content();
|
|
47476
|
-
return content ? compare(content.words, node.op, node.value) :
|
|
47581
|
+
return content ? compare(content.words, node.op, node.value) : null;
|
|
47477
47582
|
}
|
|
47478
47583
|
}
|
|
47479
47584
|
}
|
|
47585
|
+
function evaluateNoteQuery(node, note) {
|
|
47586
|
+
return evaluateNoteQueryTruth(node, note) === true;
|
|
47587
|
+
}
|
|
47480
47588
|
function positiveTextPredicates(node, negated = false) {
|
|
47481
47589
|
switch (node.type) {
|
|
47482
47590
|
case "and":
|
|
@@ -47499,7 +47607,7 @@ function matchLocations(predicates, title, text2) {
|
|
|
47499
47607
|
const firstBreak = text2 === null ? -1 : text2.indexOf("\n");
|
|
47500
47608
|
const titleLower = normalizeForMatch(title);
|
|
47501
47609
|
const firstLineLower = text2 === null ? "" : normalizeForMatch(firstBreak === -1 ? text2 : text2.slice(0, firstBreak));
|
|
47502
|
-
const bodyLower = text2 === null
|
|
47610
|
+
const bodyLower = text2 === null ? "" : normalizeForMatch(noteBodyText(text2));
|
|
47503
47611
|
let inTitle = false;
|
|
47504
47612
|
let inBody = false;
|
|
47505
47613
|
for (const predicate of predicates) {
|
|
@@ -47611,13 +47719,6 @@ function decodeBodyHex(hex3) {
|
|
|
47611
47719
|
return null;
|
|
47612
47720
|
}
|
|
47613
47721
|
}
|
|
47614
|
-
function countWords(text2) {
|
|
47615
|
-
let count = 0;
|
|
47616
|
-
for (const word of text2.replace(/\ufffc/gu, " ").split(/\s+/u)) {
|
|
47617
|
-
if (/[\p{L}\p{N}]/u.test(word)) count++;
|
|
47618
|
-
}
|
|
47619
|
-
return count;
|
|
47620
|
-
}
|
|
47621
47722
|
var REQUIRED_COLUMNS3 = ["Z_PK", "Z_ENT", "ZTITLE1", "ZFOLDER", "ZMODIFICATIONDATE1"];
|
|
47622
47723
|
function col2(available, alias, name) {
|
|
47623
47724
|
return available.has(name) ? `${alias}.${name}` : "NULL";
|
|
@@ -47862,7 +47963,6 @@ function runNoteQuery(ast, options = {}) {
|
|
|
47862
47963
|
const body2 = decode2();
|
|
47863
47964
|
if (!body2) return content = null;
|
|
47864
47965
|
const text2 = body2.text;
|
|
47865
|
-
const firstBreak = text2.indexOf("\n");
|
|
47866
47966
|
const tags = /* @__PURE__ */ new Set();
|
|
47867
47967
|
for (const [id2, alt] of row.tags ?? []) {
|
|
47868
47968
|
if (id2 && alt && body2.objectIds.has(id2))
|
|
@@ -47872,7 +47972,7 @@ function runNoteQuery(ast, options = {}) {
|
|
|
47872
47972
|
if (tags.size) facets.add("tag");
|
|
47873
47973
|
content = {
|
|
47874
47974
|
textLower: normalizeForMatch(text2),
|
|
47875
|
-
bodyLower: normalizeForMatch(
|
|
47975
|
+
bodyLower: normalizeForMatch(noteBodyText(text2)),
|
|
47876
47976
|
words: countWords(text2),
|
|
47877
47977
|
facets,
|
|
47878
47978
|
checklist: body2.checklist,
|
|
@@ -48365,13 +48465,16 @@ var LEGACY_ENTITIES = {
|
|
|
48365
48465
|
gt: ">",
|
|
48366
48466
|
amp: "&"
|
|
48367
48467
|
};
|
|
48468
|
+
function codePointText(value) {
|
|
48469
|
+
return Number.isSafeInteger(value) && value <= 1114111 ? String.fromCodePoint(value) : "\uFFFD";
|
|
48470
|
+
}
|
|
48368
48471
|
function comparableVisibleText(html) {
|
|
48369
48472
|
return html.replace(/<br\s*\/?\s*>/gi, " ").replace(/<[^>]*>/g, (tag) => INLINE_TAG.test(tag) ? "" : " ").replace(
|
|
48370
48473
|
/&(?:(nbsp|quot|lt|gt|amp);?|apos;|#(\d+);|#x([0-9a-f]+);)/gi,
|
|
48371
48474
|
(_match, legacy, dec, hex3) => {
|
|
48372
48475
|
if (legacy) return LEGACY_ENTITIES[legacy.toLowerCase()];
|
|
48373
|
-
if (dec) return
|
|
48374
|
-
if (hex3) return
|
|
48476
|
+
if (dec) return codePointText(Number(dec));
|
|
48477
|
+
if (hex3) return codePointText(Number.parseInt(hex3, 16));
|
|
48375
48478
|
return "'";
|
|
48376
48479
|
}
|
|
48377
48480
|
).replace(/\s+/g, " ").trim();
|
|
@@ -48796,15 +48899,26 @@ function createMarkdownNote(manager, request, run = runBackgroundShortcut) {
|
|
|
48796
48899
|
const segments = (path10) => JSON.stringify(splitFolderPath(path10).map((part) => part.toLocaleLowerCase()));
|
|
48797
48900
|
if (request.folder) {
|
|
48798
48901
|
const wanted = segments(request.folder);
|
|
48799
|
-
const accounts = manager.listAccounts().filter(
|
|
48800
|
-
|
|
48801
|
-
|
|
48802
|
-
)
|
|
48902
|
+
const accounts = manager.listAccounts().filter(
|
|
48903
|
+
(account) => account.defaultFolder && manager.listFolders(account.name).some((folder) => segments(folder.name) === wanted)
|
|
48904
|
+
);
|
|
48905
|
+
if (!accounts.length)
|
|
48803
48906
|
throw new Error(
|
|
48804
48907
|
`Folder "${request.folder}" does not exist; create it with create-folder first. Nothing was created`
|
|
48805
48908
|
);
|
|
48806
|
-
|
|
48807
|
-
|
|
48909
|
+
let smartRefusal;
|
|
48910
|
+
const ordinary = accounts.filter((account) => {
|
|
48911
|
+
try {
|
|
48912
|
+
manager.assertNotSmartFolderDestination(request.folder, account.name);
|
|
48913
|
+
return true;
|
|
48914
|
+
} catch (error2) {
|
|
48915
|
+
if (!(error2 instanceof CodedError && error2.envelope.reason === "smart_folder_destination"))
|
|
48916
|
+
throw error2;
|
|
48917
|
+
smartRefusal ??= error2;
|
|
48918
|
+
return false;
|
|
48919
|
+
}
|
|
48920
|
+
});
|
|
48921
|
+
if (!ordinary.length) throw smartRefusal;
|
|
48808
48922
|
}
|
|
48809
48923
|
const defaultFolderNotes = () => new Map(
|
|
48810
48924
|
manager.listAccounts().flatMap(
|
|
@@ -49501,7 +49615,63 @@ function withJsonSchema2020_12(transport2) {
|
|
|
49501
49615
|
|
|
49502
49616
|
// src/utils/shutdown.ts
|
|
49503
49617
|
var SHUTDOWN_DRAIN_TIMEOUT_MS = 2e3;
|
|
49504
|
-
|
|
49618
|
+
var SHUTDOWN_IN_FLIGHT_TIMEOUT_MS = 3e4;
|
|
49619
|
+
var InFlightRequests = class {
|
|
49620
|
+
open = /* @__PURE__ */ new Set();
|
|
49621
|
+
waiters = [];
|
|
49622
|
+
get count() {
|
|
49623
|
+
return this.open.size;
|
|
49624
|
+
}
|
|
49625
|
+
received(id2) {
|
|
49626
|
+
this.open.add(id2);
|
|
49627
|
+
}
|
|
49628
|
+
/** A response was sent, or the client cancelled the request (no response follows). */
|
|
49629
|
+
settled(id2) {
|
|
49630
|
+
if (!this.open.delete(id2) || this.open.size > 0) return;
|
|
49631
|
+
const waiters = this.waiters;
|
|
49632
|
+
this.waiters = [];
|
|
49633
|
+
for (const waiter of waiters) waiter();
|
|
49634
|
+
}
|
|
49635
|
+
onIdle(listener) {
|
|
49636
|
+
if (this.open.size === 0) listener();
|
|
49637
|
+
else this.waiters.push(listener);
|
|
49638
|
+
}
|
|
49639
|
+
};
|
|
49640
|
+
var isObject2 = (value) => typeof value === "object" && value !== null;
|
|
49641
|
+
var isId = (value) => typeof value === "string" || typeof value === "number";
|
|
49642
|
+
function trackRequests(transport2, requests) {
|
|
49643
|
+
if (typeof transport2.send !== "function") return transport2;
|
|
49644
|
+
let handler;
|
|
49645
|
+
Object.defineProperty(transport2, "onmessage", {
|
|
49646
|
+
configurable: true,
|
|
49647
|
+
enumerable: true,
|
|
49648
|
+
get: () => handler,
|
|
49649
|
+
set: (next) => {
|
|
49650
|
+
handler = next ? (message, extra) => {
|
|
49651
|
+
const m = message;
|
|
49652
|
+
if (typeof m.method === "string") {
|
|
49653
|
+
if (isId(m.id)) requests.received(m.id);
|
|
49654
|
+
else if (m.method === "notifications/cancelled" && isObject2(m.params)) {
|
|
49655
|
+
const id2 = m.params.requestId;
|
|
49656
|
+
if (isId(id2)) requests.settled(id2);
|
|
49657
|
+
}
|
|
49658
|
+
}
|
|
49659
|
+
next(message, extra);
|
|
49660
|
+
} : next;
|
|
49661
|
+
}
|
|
49662
|
+
});
|
|
49663
|
+
const send = transport2.send.bind(transport2);
|
|
49664
|
+
transport2.send = async (message, options) => {
|
|
49665
|
+
try {
|
|
49666
|
+
return await send(message, options);
|
|
49667
|
+
} finally {
|
|
49668
|
+
const m = message;
|
|
49669
|
+
if (typeof m.method !== "string" && isId(m.id)) requests.settled(m.id);
|
|
49670
|
+
}
|
|
49671
|
+
};
|
|
49672
|
+
return transport2;
|
|
49673
|
+
}
|
|
49674
|
+
function createShutdown(stream, exit, timeoutMs = SHUTDOWN_DRAIN_TIMEOUT_MS, pending, inFlightTimeoutMs = SHUTDOWN_IN_FLIGHT_TIMEOUT_MS) {
|
|
49505
49675
|
let shuttingDown = false;
|
|
49506
49676
|
let exited = false;
|
|
49507
49677
|
const exitOnce = () => {
|
|
@@ -49518,8 +49688,11 @@ function createShutdown(stream, exit, timeoutMs = SHUTDOWN_DRAIN_TIMEOUT_MS) {
|
|
|
49518
49688
|
return () => {
|
|
49519
49689
|
if (shuttingDown) return;
|
|
49520
49690
|
shuttingDown = true;
|
|
49521
|
-
|
|
49522
|
-
|
|
49691
|
+
const busy = (pending?.count ?? 0) > 0;
|
|
49692
|
+
timer = setTimeout(exitOnce, busy ? Math.max(timeoutMs, inFlightTimeoutMs) : timeoutMs);
|
|
49693
|
+
setImmediate(
|
|
49694
|
+
() => pending ? pending.onIdle(() => setImmediate(exitWhenDrained)) : exitWhenDrained()
|
|
49695
|
+
);
|
|
49523
49696
|
};
|
|
49524
49697
|
}
|
|
49525
49698
|
|
|
@@ -49867,7 +50040,7 @@ function lastViewedOf(raw, columnPresent = true, now = Date.now()) {
|
|
|
49867
50040
|
return { lastViewed: new Date(ms).toISOString(), lastViewedStatus: "viewed" };
|
|
49868
50041
|
}
|
|
49869
50042
|
var visible = (text2) => text2.replace(/\ufffc/g, "");
|
|
49870
|
-
var wordCount = (text2) =>
|
|
50043
|
+
var wordCount = (text2) => countWords(text2);
|
|
49871
50044
|
var charCount = (text2) => Array.from(visible(text2)).length;
|
|
49872
50045
|
function noteStructureSql(columns) {
|
|
49873
50046
|
const c = (alias, name) => col(columns, alias, name);
|
|
@@ -50155,7 +50328,7 @@ function inventorySql(columns) {
|
|
|
50155
50328
|
ORDER BY d.ZNOTE LIMIT ${BODY_BATCH};`
|
|
50156
50329
|
};
|
|
50157
50330
|
}
|
|
50158
|
-
function decodeBodies(dbPath2, sql, params) {
|
|
50331
|
+
function decodeBodies(dbPath2, sql, params, notes) {
|
|
50159
50332
|
const docs = /* @__PURE__ */ new Map();
|
|
50160
50333
|
let after = 0;
|
|
50161
50334
|
for (; ; ) {
|
|
@@ -50164,7 +50337,7 @@ function decodeBodies(dbPath2, sql, params) {
|
|
|
50164
50337
|
);
|
|
50165
50338
|
for (const row of rows) {
|
|
50166
50339
|
after = Math.max(after, row.note);
|
|
50167
|
-
if (row.encrypted || !row.data) continue;
|
|
50340
|
+
if (row.encrypted || !row.data || !notes.has(row.note)) continue;
|
|
50168
50341
|
try {
|
|
50169
50342
|
docs.set(row.note, decodeCompressedNoteBlocks(Buffer.from(row.data, "hex")));
|
|
50170
50343
|
} catch {
|
|
@@ -50212,7 +50385,7 @@ function listNoteLinks(options = {}) {
|
|
|
50212
50385
|
if (options.id && !notes.length)
|
|
50213
50386
|
throw new NoteStoreError(`No note found for ID "${options.id}".`, "invalid_input");
|
|
50214
50387
|
const includeInline = options.includeInline ?? Boolean(options.id);
|
|
50215
|
-
const docs = includeInline ? decodeBodies(dbPath2, sql.bodies, params) : /* @__PURE__ */ new Map();
|
|
50388
|
+
const docs = includeInline ? decodeBodies(dbPath2, sql.bodies, params, new Set(notes.map((note) => note.pk))) : /* @__PURE__ */ new Map();
|
|
50216
50389
|
const noteById = new Map(notes.map((note) => [note.pk, note]));
|
|
50217
50390
|
const accountById = new Map(context.accounts.map((account) => [account.pk, account]));
|
|
50218
50391
|
const folderById = new Map(context.folders.map((folder) => [folder.pk, folder]));
|
|
@@ -50527,7 +50700,14 @@ var AssetLocator = class {
|
|
|
50527
50700
|
["FallbackImage.png", "FallbackImage.jpg"]
|
|
50528
50701
|
);
|
|
50529
50702
|
if (fallback)
|
|
50530
|
-
return {
|
|
50703
|
+
return {
|
|
50704
|
+
primary: {
|
|
50705
|
+
path: fallback.path,
|
|
50706
|
+
name: `${source.kind}.png`,
|
|
50707
|
+
role: "fallback",
|
|
50708
|
+
...fallback.stale ? { stale: true } : {}
|
|
50709
|
+
}
|
|
50710
|
+
};
|
|
50531
50711
|
return preview ? { primary: preview } : {};
|
|
50532
50712
|
}
|
|
50533
50713
|
case "scan": {
|
|
@@ -50535,7 +50715,14 @@ var AssetLocator = class {
|
|
|
50535
50715
|
"FallbackPDF.pdf"
|
|
50536
50716
|
]);
|
|
50537
50717
|
return {
|
|
50538
|
-
...pdf ? {
|
|
50718
|
+
...pdf ? {
|
|
50719
|
+
primary: {
|
|
50720
|
+
path: pdf.path,
|
|
50721
|
+
name: "scan.pdf",
|
|
50722
|
+
role: "fallback",
|
|
50723
|
+
...pdf.stale ? { stale: true } : {}
|
|
50724
|
+
}
|
|
50725
|
+
} : {},
|
|
50539
50726
|
...preview ? { preview } : {}
|
|
50540
50727
|
};
|
|
50541
50728
|
}
|
|
@@ -50564,7 +50751,11 @@ var AssetLocator = class {
|
|
|
50564
50751
|
}
|
|
50565
50752
|
return void 0;
|
|
50566
50753
|
}
|
|
50567
|
-
/**
|
|
50754
|
+
/**
|
|
50755
|
+
* <dir>/<id>/<generation>/<name>, <dir>/<id>/<name>, then any generation.
|
|
50756
|
+
* `stale` is set when a generation was recorded but the file came from
|
|
50757
|
+
* somewhere else.
|
|
50758
|
+
*/
|
|
50568
50759
|
fallback(account, dir, id2, generation, names) {
|
|
50569
50760
|
const base = join19(account, dir, id2);
|
|
50570
50761
|
const gen = safeComponent2(generation);
|
|
@@ -50576,7 +50767,7 @@ var AssetLocator = class {
|
|
|
50576
50767
|
for (const g of generations)
|
|
50577
50768
|
for (const name of names) {
|
|
50578
50769
|
const path10 = confine(g ? join19(base, g, name) : join19(base, name), account);
|
|
50579
|
-
if (path10 && isFile(path10)) return path10;
|
|
50770
|
+
if (path10 && isFile(path10)) return { path: path10, stale: Boolean(gen) && g !== gen };
|
|
50580
50771
|
}
|
|
50581
50772
|
return void 0;
|
|
50582
50773
|
}
|
|
@@ -50733,6 +50924,9 @@ function readHead(fd) {
|
|
|
50733
50924
|
const n = readSync3(fd, head, 0, 16, 0);
|
|
50734
50925
|
return head.subarray(0, n);
|
|
50735
50926
|
}
|
|
50927
|
+
function directoryFailure(dir, error2) {
|
|
50928
|
+
return `Could not create the assets directory ${dir}: ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
50929
|
+
}
|
|
50736
50930
|
var SidecarWriter = class {
|
|
50737
50931
|
constructor(dir, linkBase) {
|
|
50738
50932
|
this.dir = dir;
|
|
@@ -50743,9 +50937,16 @@ var SidecarWriter = class {
|
|
|
50743
50937
|
placed = /* @__PURE__ */ new Map();
|
|
50744
50938
|
created = false;
|
|
50745
50939
|
count = 0;
|
|
50940
|
+
/**
|
|
50941
|
+
* Set when the directory could not be created. Every later asset fails the
|
|
50942
|
+
* same way without another attempt; the export checks this and fails
|
|
50943
|
+
* instead of reporting each asset as unavailable.
|
|
50944
|
+
*/
|
|
50945
|
+
directoryError;
|
|
50746
50946
|
place(asset) {
|
|
50747
50947
|
const done = this.placed.get(asset.path);
|
|
50748
50948
|
if (done) return done;
|
|
50949
|
+
if (this.directoryError) return { error: this.directoryError };
|
|
50749
50950
|
let source;
|
|
50750
50951
|
try {
|
|
50751
50952
|
source = openSource(asset.path);
|
|
@@ -50755,8 +50956,13 @@ var SidecarWriter = class {
|
|
|
50755
50956
|
try {
|
|
50756
50957
|
const mime = sniffMime(readHead(source.fd), asset.name);
|
|
50757
50958
|
if (!this.created) {
|
|
50758
|
-
|
|
50759
|
-
|
|
50959
|
+
try {
|
|
50960
|
+
assertExportPath(this.dir);
|
|
50961
|
+
mkdirSync4(this.dir, { recursive: true });
|
|
50962
|
+
} catch (error2) {
|
|
50963
|
+
this.directoryError = directoryFailure(this.dir, error2);
|
|
50964
|
+
return { error: this.directoryError };
|
|
50965
|
+
}
|
|
50760
50966
|
this.created = true;
|
|
50761
50967
|
}
|
|
50762
50968
|
const name = safeAssetName(asset.name, mime);
|
|
@@ -50909,7 +51115,10 @@ function titleBlockIndex(note) {
|
|
|
50909
51115
|
return first2.text.trim() === note.title.trim() && first2.style !== "monospaced" ? first2.index : -1;
|
|
50910
51116
|
}
|
|
50911
51117
|
function place(ctx, asset) {
|
|
50912
|
-
|
|
51118
|
+
const placed = asset && ctx.writer ? ctx.writer.place(asset) : void 0;
|
|
51119
|
+
if (asset?.stale && placed && "url" in placed)
|
|
51120
|
+
ctx.stats.staleRenderings = (ctx.stats.staleRenderings ?? 0) + 1;
|
|
51121
|
+
return placed;
|
|
50913
51122
|
}
|
|
50914
51123
|
function planAttachment(attachment, ctx) {
|
|
50915
51124
|
ctx.stats.attachments++;
|
|
@@ -51075,6 +51284,7 @@ function inlinePlanHtml(plan) {
|
|
|
51075
51284
|
}
|
|
51076
51285
|
}
|
|
51077
51286
|
function blockPlanHtml(plan) {
|
|
51287
|
+
if (!isHtmlBlockPlan(plan)) return `<p>${inlinePlanHtml(plan)}</p>`;
|
|
51078
51288
|
switch (plan.type) {
|
|
51079
51289
|
case "table":
|
|
51080
51290
|
return tableHtml(plan.rows);
|
|
@@ -51942,7 +52152,7 @@ function child(path10, key) {
|
|
|
51942
52152
|
if (key.length > MAX_QUOTED_TOKEN) key = `${key.slice(0, MAX_QUOTED_TOKEN - 3)}...`;
|
|
51943
52153
|
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key) ? `${path10}.${key}` : `${path10}[${JSON.stringify(key)}]`;
|
|
51944
52154
|
}
|
|
51945
|
-
var
|
|
52155
|
+
var isObject3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
51946
52156
|
var describe = (value) => value === null ? "null" : Array.isArray(value) ? "an array" : `a ${typeof value}`;
|
|
51947
52157
|
var describeVersion = (value) => typeof value === "number" && Number.isFinite(value) ? String(value) : describe(value);
|
|
51948
52158
|
var listed = (values) => values.map((v) => JSON.stringify(v)).join(", ");
|
|
@@ -52023,7 +52233,7 @@ var RULE_FIELDS = {
|
|
|
52023
52233
|
omit: []
|
|
52024
52234
|
};
|
|
52025
52235
|
function validateRule(c, rule, path10) {
|
|
52026
|
-
if (!
|
|
52236
|
+
if (!isObject3(rule)) {
|
|
52027
52237
|
c.add(path10, `must be an object, not ${describe(rule)}`);
|
|
52028
52238
|
return;
|
|
52029
52239
|
}
|
|
@@ -52070,7 +52280,7 @@ function validateInlineOrder(c, value, path10) {
|
|
|
52070
52280
|
if (missing.length) c.add(path10, `must list every inline format; missing ${listed(missing)}`);
|
|
52071
52281
|
}
|
|
52072
52282
|
function validateOptions(c, value, path10) {
|
|
52073
|
-
if (!
|
|
52283
|
+
if (!isObject3(value)) {
|
|
52074
52284
|
c.add(path10, `must be an object, not ${describe(value)}`);
|
|
52075
52285
|
return;
|
|
52076
52286
|
}
|
|
@@ -52091,7 +52301,7 @@ function validateOptions(c, value, path10) {
|
|
|
52091
52301
|
}
|
|
52092
52302
|
function templateErrors(input) {
|
|
52093
52303
|
const c = new Collector();
|
|
52094
|
-
if (!
|
|
52304
|
+
if (!isObject3(input)) {
|
|
52095
52305
|
c.add("$", `a template must be a JSON object, not ${describe(input)}`);
|
|
52096
52306
|
return c.errors;
|
|
52097
52307
|
}
|
|
@@ -52126,7 +52336,7 @@ function templateErrors(input) {
|
|
|
52126
52336
|
c.oneOf(value, path10, BUILTIN_TEMPLATE_NAMES);
|
|
52127
52337
|
break;
|
|
52128
52338
|
case "assets":
|
|
52129
|
-
if (!
|
|
52339
|
+
if (!isObject3(value)) {
|
|
52130
52340
|
c.add(path10, `must be an object, not ${describe(value)}`);
|
|
52131
52341
|
break;
|
|
52132
52342
|
}
|
|
@@ -52142,7 +52352,7 @@ function templateErrors(input) {
|
|
|
52142
52352
|
validateInlineOrder(c, value, path10);
|
|
52143
52353
|
break;
|
|
52144
52354
|
case "rules":
|
|
52145
|
-
if (!
|
|
52355
|
+
if (!isObject3(value)) {
|
|
52146
52356
|
c.add(path10, `must be an object keyed by rule id, not ${describe(value)}`);
|
|
52147
52357
|
break;
|
|
52148
52358
|
}
|
|
@@ -52772,16 +52982,26 @@ var HashedSidecarWriter = class {
|
|
|
52772
52982
|
/** Absolute paths of files written or reused. */
|
|
52773
52983
|
files = [];
|
|
52774
52984
|
count = 0;
|
|
52985
|
+
/** Set when the directory could not be created; see SidecarWriter.directoryError. */
|
|
52986
|
+
directoryError;
|
|
52987
|
+
/** Creates the directory once; returns an error message when it cannot. */
|
|
52775
52988
|
prepare() {
|
|
52776
|
-
if (this.ready) return;
|
|
52777
|
-
|
|
52778
|
-
|
|
52779
|
-
|
|
52989
|
+
if (this.ready) return void 0;
|
|
52990
|
+
try {
|
|
52991
|
+
assertExportPath(this.dir);
|
|
52992
|
+
mkdirSync5(this.dir, { recursive: true });
|
|
52993
|
+
if (!lstatSync4(this.dir).isDirectory())
|
|
52994
|
+
throw new Error("assets directory is not a directory");
|
|
52995
|
+
} catch (error2) {
|
|
52996
|
+
return this.directoryError = directoryFailure(this.dir, error2);
|
|
52997
|
+
}
|
|
52780
52998
|
this.ready = true;
|
|
52999
|
+
return void 0;
|
|
52781
53000
|
}
|
|
52782
53001
|
place(asset) {
|
|
52783
53002
|
const done = this.placed.get(asset.path);
|
|
52784
53003
|
if (done) return done;
|
|
53004
|
+
if (this.directoryError) return { error: this.directoryError };
|
|
52785
53005
|
let source;
|
|
52786
53006
|
try {
|
|
52787
53007
|
source = openRegular(asset.path);
|
|
@@ -52791,7 +53011,8 @@ var HashedSidecarWriter = class {
|
|
|
52791
53011
|
try {
|
|
52792
53012
|
const { hash, head } = digest(source);
|
|
52793
53013
|
const mime = sniffMime(head, asset.name);
|
|
52794
|
-
this.prepare();
|
|
53014
|
+
const directoryError = this.prepare();
|
|
53015
|
+
if (directoryError) return { error: directoryError };
|
|
52795
53016
|
const name = safeAssetName(asset.name, mime);
|
|
52796
53017
|
const ext = extname4(name);
|
|
52797
53018
|
const target = join21(
|
|
@@ -53021,10 +53242,11 @@ function validPath(path10, what) {
|
|
|
53021
53242
|
function selectNotes(request, deps) {
|
|
53022
53243
|
if (!!request.id === !!request.folder)
|
|
53023
53244
|
throw new NotesExportError("invalid-request", "Provide exactly one of 'id' or 'folder'.");
|
|
53024
|
-
if (request.id) return [request.id];
|
|
53245
|
+
if (request.id) return { ids: [request.id], truncated: false };
|
|
53025
53246
|
const limit = Math.min(request.limit ?? DEFAULT_FOLDER_EXPORT_LIMIT, MAX_FOLDER_EXPORT_LIMIT);
|
|
53026
53247
|
try {
|
|
53027
|
-
|
|
53248
|
+
const ids = deps.listNoteRefs(request.account, request.folder, void 0, limit + 1).map((ref) => ref.id);
|
|
53249
|
+
return { ids: ids.slice(0, limit), truncated: ids.length > limit };
|
|
53028
53250
|
} catch (error2) {
|
|
53029
53251
|
throw new NotesExportError(
|
|
53030
53252
|
"folder-unavailable",
|
|
@@ -53056,9 +53278,13 @@ function openOutput(output) {
|
|
|
53056
53278
|
throw error2;
|
|
53057
53279
|
}
|
|
53058
53280
|
}
|
|
53059
|
-
function renderInto(fd, render) {
|
|
53281
|
+
function renderInto(fd, render, writers = []) {
|
|
53060
53282
|
try {
|
|
53061
|
-
|
|
53283
|
+
const document = render();
|
|
53284
|
+
const directoryError = writers.find((writer) => writer.directoryError)?.directoryError;
|
|
53285
|
+
if (directoryError)
|
|
53286
|
+
throw new NotesExportError("invalid-path", `${directoryError}. Nothing was exported.`);
|
|
53287
|
+
return document;
|
|
53062
53288
|
} catch (error2) {
|
|
53063
53289
|
if (fd !== void 0) writeAllAndClose(fd, "");
|
|
53064
53290
|
throw error2;
|
|
@@ -53075,10 +53301,15 @@ function exportNotesMarkdown(request, deps) {
|
|
|
53075
53301
|
"invalid-request",
|
|
53076
53302
|
`assetsDir has no effect: template "${chosen.info.name}" sets assets.mode to "${chosen.template.assets.mode}".`
|
|
53077
53303
|
);
|
|
53078
|
-
const ids = selectNotes(request, deps);
|
|
53304
|
+
const { ids, truncated } = selectNotes(request, deps);
|
|
53079
53305
|
const { notes, skipped } = loadNotes(ids, !!request.id, deps.readNote);
|
|
53080
|
-
if (chosen)
|
|
53081
|
-
|
|
53306
|
+
if (chosen) {
|
|
53307
|
+
const receipt2 = exportWithTemplate(request, deps, chosen, notes, skipped, {
|
|
53308
|
+
output,
|
|
53309
|
+
assetsDir
|
|
53310
|
+
});
|
|
53311
|
+
return truncated ? { ...receipt2, truncated } : receipt2;
|
|
53312
|
+
}
|
|
53082
53313
|
const fd = output ? openOutput(output) : void 0;
|
|
53083
53314
|
const writer = assetsDir ? new SidecarWriter(assetsDir, output ? dirname6(output) : void 0) : void 0;
|
|
53084
53315
|
const ctx = {
|
|
@@ -53087,12 +53318,14 @@ function exportNotesMarkdown(request, deps) {
|
|
|
53087
53318
|
};
|
|
53088
53319
|
const markdown = renderInto(
|
|
53089
53320
|
fd,
|
|
53090
|
-
() => renderNotesMarkdown(notes, ctx, { wrap: request.wrap ?? 0 })
|
|
53321
|
+
() => renderNotesMarkdown(notes, ctx, { wrap: request.wrap ?? 0 }),
|
|
53322
|
+
writer ? [writer] : []
|
|
53091
53323
|
);
|
|
53092
53324
|
const bytes = Buffer.byteLength(markdown);
|
|
53093
53325
|
const receipt = {
|
|
53094
53326
|
format: "markdown",
|
|
53095
53327
|
count: notes.length,
|
|
53328
|
+
...truncated ? { truncated } : {},
|
|
53096
53329
|
bytes,
|
|
53097
53330
|
stats: ctx.stats,
|
|
53098
53331
|
skipped,
|
|
@@ -53128,7 +53361,7 @@ function exportNotesHtml(request, deps) {
|
|
|
53128
53361
|
const assetsDir = embed ? void 0 : validPath(request.assetsDir ?? defaultSidecarDir(output), "assetsDir");
|
|
53129
53362
|
if (assetsDir === output)
|
|
53130
53363
|
throw new NotesExportError("invalid-path", "outputPath and assetsDir must differ.");
|
|
53131
|
-
const ids = selectNotes(request, deps);
|
|
53364
|
+
const { ids, truncated } = selectNotes(request, deps);
|
|
53132
53365
|
const { notes, skipped } = loadNotes(ids, !!request.id, deps.readNote);
|
|
53133
53366
|
const fd = openOutput(output);
|
|
53134
53367
|
const writer = assetsDir ? new SidecarWriter(assetsDir, dirname6(output)) : new DataUrlWriter();
|
|
@@ -53138,11 +53371,16 @@ function exportNotesHtml(request, deps) {
|
|
|
53138
53371
|
locator: deps.locator ?? new AssetLocator()
|
|
53139
53372
|
};
|
|
53140
53373
|
const title = request.id ? notes[0]?.title || "Note" : request.folder;
|
|
53141
|
-
const html = renderInto(
|
|
53374
|
+
const html = renderInto(
|
|
53375
|
+
fd,
|
|
53376
|
+
() => renderNotesHtml(notes, ctx, { title }),
|
|
53377
|
+
writer instanceof SidecarWriter ? [writer] : []
|
|
53378
|
+
);
|
|
53142
53379
|
const bytes = writeAllAndClose(fd, html);
|
|
53143
53380
|
return {
|
|
53144
53381
|
format: "html",
|
|
53145
53382
|
count: notes.length,
|
|
53383
|
+
...truncated ? { truncated } : {},
|
|
53146
53384
|
bytes,
|
|
53147
53385
|
output,
|
|
53148
53386
|
stats: ctx.stats,
|
|
@@ -53224,7 +53462,7 @@ function exportWithTemplate(request, deps, chosen, notes, skipped, { output, ass
|
|
|
53224
53462
|
});
|
|
53225
53463
|
warnings = result.warnings;
|
|
53226
53464
|
return result.markdown;
|
|
53227
|
-
});
|
|
53465
|
+
}, [...writers.values()]);
|
|
53228
53466
|
const bytes = Buffer.byteLength(markdown);
|
|
53229
53467
|
const used = [...writers.values()].filter((writer) => writer.count > 0);
|
|
53230
53468
|
const files = used.flatMap((writer) => writer.files);
|
|
@@ -53290,12 +53528,12 @@ import { basename as basename5, extname as extname6, join as join23 } from "node
|
|
|
53290
53528
|
var PASTEBOARD_NAME_ENV = "APPLE_NOTES_MCP_PASTEBOARD_NAME";
|
|
53291
53529
|
var MAX_PASTEBOARD_BYTES = 64 * 1024 * 1024;
|
|
53292
53530
|
var PASTEBOARD_DATA_TYPES = [
|
|
53531
|
+
{ type: "com.adobe.pdf", ext: "pdf", label: "document" },
|
|
53293
53532
|
{ type: "public.png", ext: "png", label: "image" },
|
|
53294
53533
|
{ type: "public.jpeg", ext: "jpg", label: "image" },
|
|
53295
53534
|
{ type: "public.heic", ext: "heic", label: "image" },
|
|
53296
53535
|
{ type: "com.compuserve.gif", ext: "gif", label: "image" },
|
|
53297
|
-
{ type: "public.tiff", ext: "tiff", label: "image" }
|
|
53298
|
-
{ type: "com.adobe.pdf", ext: "pdf", label: "document" }
|
|
53536
|
+
{ type: "public.tiff", ext: "tiff", label: "image" }
|
|
53299
53537
|
];
|
|
53300
53538
|
var PASTEBOARD_ACCESS_BEHAVIORS = {
|
|
53301
53539
|
0: "default",
|
|
@@ -53322,15 +53560,26 @@ function run(argv) {
|
|
|
53322
53560
|
var items = pb.pasteboardItems;
|
|
53323
53561
|
var itemCount = items && !items.isNil() ? Number(items.count) : 0;
|
|
53324
53562
|
var fileUrls = [];
|
|
53563
|
+
var dataItems = 0;
|
|
53325
53564
|
for (var k = 0; k < itemCount; k++) {
|
|
53326
53565
|
var item = items.objectAtIndex(k);
|
|
53327
53566
|
var itemTypes = ObjC.deepUnwrap(item.types) || [];
|
|
53328
|
-
if (itemTypes.indexOf("public.file-url") < 0)
|
|
53567
|
+
if (itemTypes.indexOf("public.file-url") < 0) {
|
|
53568
|
+
for (var j = 0; j < prefs.length; j++) {
|
|
53569
|
+
if (itemTypes.indexOf(prefs[j][0]) >= 0) {
|
|
53570
|
+
dataItems++;
|
|
53571
|
+
break;
|
|
53572
|
+
}
|
|
53573
|
+
}
|
|
53574
|
+
continue;
|
|
53575
|
+
}
|
|
53329
53576
|
var value = ObjC.unwrap(item.stringForType("public.file-url"));
|
|
53330
53577
|
if (value) fileUrls.push(value);
|
|
53331
53578
|
}
|
|
53332
53579
|
if (fileUrls.length > 1)
|
|
53333
53580
|
return JSON.stringify({ status: "error", code: "multiple_files", count: fileUrls.length });
|
|
53581
|
+
if (fileUrls.length === 0 && dataItems > 1)
|
|
53582
|
+
return JSON.stringify({ status: "error", code: "multiple_items", count: dataItems });
|
|
53334
53583
|
if (fileUrls.length === 1) {
|
|
53335
53584
|
var url = $.NSURL.URLWithString(fileUrls[0]);
|
|
53336
53585
|
if (url && !url.isNil() && url.isFileURL) {
|
|
@@ -53361,6 +53610,7 @@ var ENVELOPE_CODES = {
|
|
|
53361
53610
|
pasteboard_changed: "operation_failed",
|
|
53362
53611
|
unsupported_content: "validation_error",
|
|
53363
53612
|
multiple_files: "validation_error",
|
|
53613
|
+
multiple_items: "validation_error",
|
|
53364
53614
|
too_large: "validation_error",
|
|
53365
53615
|
write_failed: "operation_failed",
|
|
53366
53616
|
file_unreadable: "validation_error"
|
|
@@ -53387,6 +53637,7 @@ var MESSAGES = {
|
|
|
53387
53637
|
pasteboard_changed: "The pasteboard changed while it was being read. Try again.",
|
|
53388
53638
|
unsupported_content: `The pasteboard holds no supported content: copy ${SUPPORTED}. Text belongs in append-to-note, not in an attachment.`,
|
|
53389
53639
|
multiple_files: "The pasteboard holds more than one copied file. Copy exactly one file, or attach each file with add-attachment.",
|
|
53640
|
+
multiple_items: "The pasteboard holds more than one image or PDF. Copy exactly one, or save each and attach it with add-attachment.",
|
|
53390
53641
|
too_large: "The pasteboard contents exceed the 64 MiB attachment limit.",
|
|
53391
53642
|
write_failed: "Could not write the pasteboard contents to a temporary file.",
|
|
53392
53643
|
file_unreadable: "The copied file could not be read as a regular file of at most 64 MiB."
|
|
@@ -53398,13 +53649,10 @@ function replyError(code, reply) {
|
|
|
53398
53649
|
const message = accessBehavior === "alwaysDeny" ? "macOS is set to deny pasteboard access to the app that runs this server, so nothing was read. Change it to allow in System Settings, then try again." : MESSAGES.pasteboard_access_denied;
|
|
53399
53650
|
return new PasteboardError(code, message, { accessBehavior });
|
|
53400
53651
|
}
|
|
53401
|
-
if (code === "multiple_files") {
|
|
53652
|
+
if (code === "multiple_files" || code === "multiple_items") {
|
|
53402
53653
|
const count = typeof reply.count === "number" ? reply.count : void 0;
|
|
53403
|
-
|
|
53404
|
-
|
|
53405
|
-
count ? `The pasteboard holds ${count} copied files. Copy exactly one file, or attach each file with add-attachment.` : MESSAGES[code],
|
|
53406
|
-
count ? { count } : {}
|
|
53407
|
-
);
|
|
53654
|
+
const counted = code === "multiple_files" ? `The pasteboard holds ${count} copied files. Copy exactly one file, or attach each file with add-attachment.` : `The pasteboard holds ${count} images or PDFs. Copy exactly one, or save each and attach it with add-attachment.`;
|
|
53655
|
+
return new PasteboardError(code, count ? counted : MESSAGES[code], count ? { count } : {});
|
|
53408
53656
|
}
|
|
53409
53657
|
if (code === "unsupported_content" && Array.isArray(reply.types)) {
|
|
53410
53658
|
const types = reply.types.filter((t) => typeof t === "string").slice(0, 20);
|
|
@@ -53617,7 +53865,10 @@ function registerDirectOperations(server2, manager) {
|
|
|
53617
53865
|
{
|
|
53618
53866
|
id: folderId,
|
|
53619
53867
|
expectedName: external_exports.string().max(1e3),
|
|
53620
|
-
|
|
53868
|
+
// Same forms as id, so list-folders' parentIdentifier (a folder UUID)
|
|
53869
|
+
// works; a top-level folder's parent is its account, passed as the
|
|
53870
|
+
// account's x-coredata id.
|
|
53871
|
+
expectedParentId: folderId,
|
|
53621
53872
|
newName: external_exports.string().min(1).max(1e3)
|
|
53622
53873
|
},
|
|
53623
53874
|
(args) => ({
|
|
@@ -54020,7 +54271,9 @@ function readFolderStoreFacts(pk, dbPath2 = NOTE_STORE_PATH) {
|
|
|
54020
54271
|
|
|
54021
54272
|
// src/tools/folderDelete.ts
|
|
54022
54273
|
var folderIdSchema = external_exports.string().max(2e3).transform(looseIdTransform("ICFolder"));
|
|
54023
|
-
var accountIdSchema = external_exports.string().max(2e3).
|
|
54274
|
+
var accountIdSchema = external_exports.string().max(2e3).transform(looseIdTransform("ICAccount")).pipe(
|
|
54275
|
+
external_exports.string().regex(/^x-coredata:\/\/[0-9a-f-]+\/ICAccount\/p\d+$/i, "An exact account ID is required")
|
|
54276
|
+
);
|
|
54024
54277
|
var revisionSchema = external_exports.string().regex(/^sha256:[a-f0-9]{64}$/);
|
|
54025
54278
|
var defaultDeps = {
|
|
54026
54279
|
readStore: (pk) => readFolderStoreFacts(pk),
|
|
@@ -58005,14 +58258,17 @@ var strokeSchema = external_exports.object({
|
|
|
58005
58258
|
force: external_exports.number()
|
|
58006
58259
|
})
|
|
58007
58260
|
).optional(),
|
|
58008
|
-
transformApplied: external_exports.boolean().optional()
|
|
58261
|
+
transformApplied: external_exports.boolean().optional(),
|
|
58262
|
+
masked: external_exports.boolean().optional(),
|
|
58263
|
+
pointsTruncated: external_exports.boolean().optional()
|
|
58009
58264
|
}).strip();
|
|
58010
58265
|
var decodedDrawingSchema = external_exports.object({
|
|
58011
58266
|
status: external_exports.literal("ok"),
|
|
58012
58267
|
strokeCount: external_exports.number().int(),
|
|
58013
58268
|
strokes: external_exports.array(strokeSchema),
|
|
58014
58269
|
truncated: external_exports.boolean(),
|
|
58015
|
-
bounds
|
|
58270
|
+
bounds,
|
|
58271
|
+
hiddenStrokeCount: external_exports.number().int().optional()
|
|
58016
58272
|
});
|
|
58017
58273
|
function decodeRow(row, format, includePoints, deps) {
|
|
58018
58274
|
const base = {
|
|
@@ -58045,7 +58301,8 @@ function decodeRow(row, format, includePoints, deps) {
|
|
|
58045
58301
|
status: "ok",
|
|
58046
58302
|
strokeCount: decoded.strokeCount,
|
|
58047
58303
|
bounds: decoded.bounds,
|
|
58048
|
-
truncated: decoded.truncated
|
|
58304
|
+
truncated: decoded.truncated,
|
|
58305
|
+
...decoded.hiddenStrokeCount ? { hiddenStrokeCount: decoded.hiddenStrokeCount } : {}
|
|
58049
58306
|
};
|
|
58050
58307
|
if (format !== "json") result.svg = drawingToSvg(strokes, decoded.bounds);
|
|
58051
58308
|
if (format !== "svg")
|
|
@@ -58070,6 +58327,28 @@ function getNoteDrawings(noteId3, options = {}) {
|
|
|
58070
58327
|
drawings
|
|
58071
58328
|
};
|
|
58072
58329
|
}
|
|
58330
|
+
function fitNoteDrawings(result, maxBytes, measure = (r) => Buffer.byteLength(JSON.stringify(r))) {
|
|
58331
|
+
let next = result;
|
|
58332
|
+
let pointsOmitted = false;
|
|
58333
|
+
let svgOmitted = false;
|
|
58334
|
+
if (measure(next) > maxBytes && next.drawings.some((d) => d.strokes?.some((s) => s.points))) {
|
|
58335
|
+
next = {
|
|
58336
|
+
...next,
|
|
58337
|
+
drawings: next.drawings.map(
|
|
58338
|
+
(d) => d.strokes ? { ...d, strokes: d.strokes.map(({ points: _points, ...rest }) => rest) } : d
|
|
58339
|
+
)
|
|
58340
|
+
};
|
|
58341
|
+
pointsOmitted = true;
|
|
58342
|
+
}
|
|
58343
|
+
if (measure(next) > maxBytes && next.drawings.some((d) => d.svg !== void 0)) {
|
|
58344
|
+
next = {
|
|
58345
|
+
...next,
|
|
58346
|
+
drawings: next.drawings.map(({ svg: _svg, ...rest }) => rest)
|
|
58347
|
+
};
|
|
58348
|
+
svgOmitted = true;
|
|
58349
|
+
}
|
|
58350
|
+
return { result: next, pointsOmitted, svgOmitted, oversized: measure(next) > maxBytes };
|
|
58351
|
+
}
|
|
58073
58352
|
function formatNoteDrawings(result) {
|
|
58074
58353
|
if (result.drawingCount === 0) return `No classic PencilKit drawings in note ${result.id}.`;
|
|
58075
58354
|
const lines = [
|
|
@@ -58077,7 +58356,7 @@ function formatNoteDrawings(result) {
|
|
|
58077
58356
|
];
|
|
58078
58357
|
for (const d of result.drawings)
|
|
58079
58358
|
lines.push(
|
|
58080
|
-
d.status === "ok" ? `- ${d.attachmentId}: ${d.strokeCount} stroke${d.strokeCount === 1 ? "" : "s"}${d.truncated ? " (truncated)" : ""}` : `- ${d.attachmentId}: error ${d.code}: ${d.message}`
|
|
58359
|
+
d.status === "ok" ? `- ${d.attachmentId}: ${d.strokeCount} stroke${d.strokeCount === 1 ? "" : "s"}${d.hiddenStrokeCount ? ` (${d.hiddenStrokeCount} fully erased)` : ""}${d.truncated ? " (truncated)" : ""}` : `- ${d.attachmentId}: error ${d.code}: ${d.message}`
|
|
58081
58360
|
);
|
|
58082
58361
|
return lines.join("\n");
|
|
58083
58362
|
}
|
|
@@ -58177,9 +58456,6 @@ function readAudioAssets(noteId3, options = {}) {
|
|
|
58177
58456
|
};
|
|
58178
58457
|
});
|
|
58179
58458
|
}
|
|
58180
|
-
function countWords2(text2) {
|
|
58181
|
-
return text2.split(/\s+/u).filter((w) => /[\p{L}\p{N}]/u.test(w)).length;
|
|
58182
|
-
}
|
|
58183
58459
|
|
|
58184
58460
|
// src/services/noteTranscription.ts
|
|
58185
58461
|
var DEFAULT_TRANSCRIPTION_LOCALE = "en-US";
|
|
@@ -58194,6 +58470,7 @@ var BUDGET_MARGIN_MS = 1e4;
|
|
|
58194
58470
|
var MIN_TAKE_SECONDS = 5;
|
|
58195
58471
|
var CALL_WIDE_CODES = /* @__PURE__ */ new Set([
|
|
58196
58472
|
"permission_required",
|
|
58473
|
+
"permission_not_requested",
|
|
58197
58474
|
"asset_unavailable",
|
|
58198
58475
|
"unsupported_locale",
|
|
58199
58476
|
"speech_unavailable"
|
|
@@ -58272,7 +58549,7 @@ async function transcribeTake(take, ctx) {
|
|
|
58272
58549
|
status: complete ? "ok" : text2 ? "partial" : "indeterminate",
|
|
58273
58550
|
...complete ? {} : { code: "incomplete", message: stopReason ?? "stopped early" },
|
|
58274
58551
|
...durationSeconds !== void 0 ? { durationSeconds } : {},
|
|
58275
|
-
wordCount:
|
|
58552
|
+
wordCount: countWords(text2),
|
|
58276
58553
|
...engine ? { engine } : {}
|
|
58277
58554
|
},
|
|
58278
58555
|
text: text2
|
|
@@ -58299,7 +58576,7 @@ async function transcribeRecording(asset, includeText, ctx) {
|
|
|
58299
58576
|
status,
|
|
58300
58577
|
...status !== "ok" && firstProblem?.code ? { code: firstProblem.code, message: firstProblem.message } : {},
|
|
58301
58578
|
...asset.durationSeconds !== null ? { durationSeconds: Math.round(asset.durationSeconds) } : {},
|
|
58302
|
-
wordCount:
|
|
58579
|
+
wordCount: countWords(transcript),
|
|
58303
58580
|
...includeText ? { transcript } : {},
|
|
58304
58581
|
takes: outcomes.map((o) => o.take)
|
|
58305
58582
|
};
|
|
@@ -58354,24 +58631,29 @@ async function transcribeNoteAudio(noteId3, options = {}) {
|
|
|
58354
58631
|
}
|
|
58355
58632
|
function fitTranscriptions(result, maxBytes, measure = (r) => Buffer.byteLength(JSON.stringify(r))) {
|
|
58356
58633
|
if (measure(result) <= maxBytes) return result;
|
|
58634
|
+
const shorten = (share) => ({
|
|
58635
|
+
...result,
|
|
58636
|
+
recordings: result.recordings.map(
|
|
58637
|
+
(r) => r.transcript ? {
|
|
58638
|
+
...r,
|
|
58639
|
+
transcript: r.transcript.slice(0, Math.floor(r.transcript.length * share)),
|
|
58640
|
+
transcriptTruncated: true
|
|
58641
|
+
} : r
|
|
58642
|
+
)
|
|
58643
|
+
});
|
|
58357
58644
|
let next = result;
|
|
58358
58645
|
for (let share = 0.5; measure(next) > maxBytes && share > 1e-4; share /= 2) {
|
|
58359
|
-
next =
|
|
58360
|
-
...result,
|
|
58361
|
-
recordings: result.recordings.map(
|
|
58362
|
-
(r) => r.transcript ? {
|
|
58363
|
-
...r,
|
|
58364
|
-
transcript: r.transcript.slice(0, Math.floor(r.transcript.length * share)),
|
|
58365
|
-
transcriptTruncated: true
|
|
58366
|
-
} : r
|
|
58367
|
-
)
|
|
58368
|
-
};
|
|
58646
|
+
next = shorten(share);
|
|
58369
58647
|
}
|
|
58648
|
+
if (measure(next) > maxBytes) next = { ...shorten(0), responseOversized: true };
|
|
58370
58649
|
return next;
|
|
58371
58650
|
}
|
|
58372
58651
|
function formatTranscription(result) {
|
|
58373
58652
|
if (result.recordingCount === 0) return `No audio attachments in note ${result.id}.`;
|
|
58374
58653
|
const lines = [
|
|
58654
|
+
...result.responseOversized ? [
|
|
58655
|
+
"The transcripts were dropped: even without them the response exceeds APPLE_NOTES_MCP_EXPORT_MAX_BYTES. Transcribe one recording at a time with attachmentId."
|
|
58656
|
+
] : [],
|
|
58375
58657
|
`${result.recordingCount} audio attachment${result.recordingCount === 1 ? "" : "s"} in note ${result.id} (${result.status}, locale ${result.locale}):`
|
|
58376
58658
|
];
|
|
58377
58659
|
result.recordings.forEach((r, i) => {
|
|
@@ -59243,10 +59525,11 @@ function prepareDeleteGuards(args) {
|
|
|
59243
59525
|
if (guardNoteId === void 0 !== (expectedGuardContentHash === void 0)) {
|
|
59244
59526
|
return { error: "Pass guardNoteId and expectedGuardContentHash together." };
|
|
59245
59527
|
}
|
|
59246
|
-
|
|
59528
|
+
const same = (a, b) => a !== void 0 && b !== void 0 && canonicalCoreDataId(a) === canonicalCoreDataId(b);
|
|
59529
|
+
if (same(guardNoteId, id2) || same(requireActiveNoteId, id2)) {
|
|
59247
59530
|
return { error: "A guard note must be a different note from the one being deleted." };
|
|
59248
59531
|
}
|
|
59249
|
-
if (guardNoteId
|
|
59532
|
+
if (same(guardNoteId, requireActiveNoteId)) {
|
|
59250
59533
|
return { error: "requireActiveNoteId repeats guardNoteId; pass only guardNoteId." };
|
|
59251
59534
|
}
|
|
59252
59535
|
const prepared = { guards: [], labels: [] };
|
|
@@ -59593,7 +59876,7 @@ ${noteList}${truncationNote}${scanNote}${wordCountNote}${syncNote}`,
|
|
|
59593
59876
|
registerTool(
|
|
59594
59877
|
"query-notes",
|
|
59595
59878
|
{
|
|
59596
|
-
description: 'Use when: finding notes with a boolean expression over text and metadata \u2014 e.g. `folder:Work has:checklist -checklist:done`, `(title:invoice OR tag:finance) modified:>=2026-07-01`, `pinned words:>250`. Reads the Notes database directly, so it is fast and can match title OR body in one call.\nSyntax: bare words and "quoted phrases" match title or body (case-insensitive substring); fields title:, body:, text:, folder:, account:, tag: (values may be quoted, e.g. folder:"Work Projects"); facets has:link|attachment|checklist|drawing|image|video|audio|pdf|table|scan|tag; checklist:open|done; flags pinned, locked, shared (or is:pinned); words:>250 and created:/modified: with =, >, >=, <, <= and YYYY-MM-DD local dates. AND is implicit; OR, NOT, leading -, and parentheses are supported; operators are case-insensitive and a quoted "and" searches the literal word.\nReturns: matching notes (most recently modified first) with id, title, folder, account, modified date, snippet, and matchedIn (where the positive text terms occur: title, body, or both; absent when the body is unreadable or the query has no text term), plus scan/match counts; includeWordCount adds wordCount. Ids work with get-note-content and every other id-based tool.\nDo not use when: Full Disk Access is unavailable (use search-notes). Scans the most recent scanLimit notes (default 500); raise it for older notes.\nSafety: read-only; never writes the database. Excludes Recently Deleted and folderless notes unless includeDeleted is true. Locked notes match on title and metadata only; body predicates never match them.',
|
|
59879
|
+
description: 'Use when: finding notes with a boolean expression over text and metadata \u2014 e.g. `folder:Work has:checklist -checklist:done`, `(title:invoice OR tag:finance) modified:>=2026-07-01`, `pinned words:>250`. Reads the Notes database directly, so it is fast and can match title OR body in one call.\nSyntax: bare words and "quoted phrases" match title or body (case-insensitive substring); fields title:, body:, text:, folder:, account:, tag: (values may be quoted, e.g. folder:"Work Projects"); facets has:link|attachment|checklist|drawing|image|video|audio|pdf|table|scan|tag; checklist:open|done; flags pinned, locked, shared (or is:pinned); words:>250 and created:/modified: with =, >, >=, <, <= and YYYY-MM-DD local dates. AND is implicit; OR, NOT, leading -, and parentheses are supported; operators are case-insensitive and a quoted "and" searches the literal word.\nReturns: matching notes (most recently modified first) with id, title, folder, account, modified date, snippet, and matchedIn (where the positive text terms occur: title, body, or both; absent when the body is unreadable or the query has no text term), plus scan/match counts; includeWordCount adds wordCount. Ids work with get-note-content and every other id-based tool.\nDo not use when: Full Disk Access is unavailable (use search-notes). Scans the most recent scanLimit notes (default 500); raise it for older notes.\nSafety: read-only; never writes the database. Excludes Recently Deleted and folderless notes unless includeDeleted is true. Locked notes match on title and metadata only; body predicates (including negated ones such as -body:x) never match them.',
|
|
59597
59880
|
inputSchema: {
|
|
59598
59881
|
query: external_exports.string().min(1, "A query expression is required").max(MAX.QUERY).describe(
|
|
59599
59882
|
'Boolean query expression, e.g. `folder:"Work Projects" has:checklist -checklist:done`'
|
|
@@ -59646,7 +59929,7 @@ registerTool(
|
|
|
59646
59929
|
}
|
|
59647
59930
|
if (result.unreadable > 0) {
|
|
59648
59931
|
notes.push(
|
|
59649
|
-
`\u26A0\uFE0F ${result.unreadable} note bodies could not be decoded, so body predicates did not match them.`
|
|
59932
|
+
`\u26A0\uFE0F ${result.unreadable} note bodies could not be decoded, so body predicates (including negated ones) did not match them.`
|
|
59650
59933
|
);
|
|
59651
59934
|
}
|
|
59652
59935
|
const footer = notes.length ? `
|
|
@@ -60049,7 +60332,7 @@ registerTool(
|
|
|
60049
60332
|
if (!note) return notFoundResponse(`Note with ID "${id2}" not found`);
|
|
60050
60333
|
const body = notesManager.getNoteContentById(id2);
|
|
60051
60334
|
if (!body) return errorResponse(`Failed to read content of note "${note.title}"`);
|
|
60052
|
-
const rich = readRichNote(id2);
|
|
60335
|
+
const rich = readRichNote(id2, { skipUnsafeLinks: true });
|
|
60053
60336
|
const tables = (rich.objectData || []).filter((object3) => object3.type?.includes("table")).map((object3) => {
|
|
60054
60337
|
try {
|
|
60055
60338
|
return {
|
|
@@ -61659,6 +61942,7 @@ registerTool(
|
|
|
61659
61942
|
height: external_exports.number().optional(),
|
|
61660
61943
|
bytes: external_exports.number().optional(),
|
|
61661
61944
|
source: external_exports.enum(["fallback", "preview"]).optional(),
|
|
61945
|
+
stale: external_exports.boolean().optional(),
|
|
61662
61946
|
attachmentId: external_exports.string().optional(),
|
|
61663
61947
|
identifier: external_exports.string().optional(),
|
|
61664
61948
|
kind: external_exports.enum(["paper", "drawing"]).optional(),
|
|
@@ -61667,8 +61951,9 @@ registerTool(
|
|
|
61667
61951
|
},
|
|
61668
61952
|
withErrorHandling(({ noteId: noteId3, savePath, attachmentId }) => {
|
|
61669
61953
|
const r = notesManager.exportPaperImageById(noteId3, savePath, attachmentId);
|
|
61954
|
+
const stale = r.source === "fallback" && r.drawing.fallbackImageStale;
|
|
61670
61955
|
return successResponse(
|
|
61671
|
-
`Saved ${r.format.toUpperCase()} ${r.width}x${r.height} (${r.bytes} bytes, ${r.source === "fallback" ? "Notes' full rendering" : "largest preview"}) to ${r.savedPath}
|
|
61956
|
+
`Saved ${r.format.toUpperCase()} ${r.width}x${r.height} (${r.bytes} bytes, ${r.source === "fallback" ? "Notes' full rendering" : "largest preview"}) to ${r.savedPath}` + (stale ? ". This is an older rendering: the one Notes recorded is not on disk, so it may not show the latest strokes." : ""),
|
|
61672
61957
|
{
|
|
61673
61958
|
savedPath: r.savedPath,
|
|
61674
61959
|
format: r.format,
|
|
@@ -61676,6 +61961,7 @@ registerTool(
|
|
|
61676
61961
|
height: r.height,
|
|
61677
61962
|
bytes: r.bytes,
|
|
61678
61963
|
source: r.source,
|
|
61964
|
+
...stale ? { stale } : {},
|
|
61679
61965
|
attachmentId: attachmentCoreDataId(noteId3, r.drawing.pk),
|
|
61680
61966
|
identifier: r.drawing.identifier,
|
|
61681
61967
|
kind: r.drawing.kind,
|
|
@@ -61688,7 +61974,7 @@ registerTool(
|
|
|
61688
61974
|
"export-attachments",
|
|
61689
61975
|
{
|
|
61690
61976
|
description: `Use when: copying every file attachment of one note (or only its lead visual) into a directory on disk.
|
|
61691
|
-
Returns: per attachment its id, kind, exportedTo, and exportedKind: "asset" for the real file, "preview" when the asset never downloaded and only Notes' rendered thumbnail was available, or null when nothing was on disk.
|
|
61977
|
+
Returns: per attachment its id, kind, exportedTo, and exportedKind: "asset" for the real file, "fallback" for Notes' own full rendering of it (a drawing's PNG or a scan's PDF, named with that format's extension), "preview" when the asset never downloaded and only Notes' rendered thumbnail was available, or null when nothing was on disk; inBody: false marks an attachment no longer shown in the note body.
|
|
61692
61978
|
Do not use when: exporting one attachment to an exact path (save-attachment) or reading bytes inline (fetch-attachment).
|
|
61693
61979
|
Safety: writes files; exportDir must be absolute and under the home directory, a temp dir, or /Volumes, and not inside the Notes data folder. Existing files are never replaced: name collisions get -2, -3, ... suffixes. Reads NoteStore and the Notes data folder read-only; requires Full Disk Access. Notes.app is not opened.`,
|
|
61694
61980
|
inputSchema: {
|
|
@@ -61700,6 +61986,7 @@ Safety: writes files; exportDir must be absolute and under the home directory, a
|
|
|
61700
61986
|
exportDir: external_exports.string().optional(),
|
|
61701
61987
|
exported: external_exports.number().optional(),
|
|
61702
61988
|
previews: external_exports.number().optional(),
|
|
61989
|
+
fallbacks: external_exports.number().optional(),
|
|
61703
61990
|
skipped: external_exports.number().optional(),
|
|
61704
61991
|
failed: external_exports.number().optional(),
|
|
61705
61992
|
results: external_exports.array(external_exports.object({}).passthrough()).optional(),
|
|
@@ -61714,12 +62001,14 @@ Safety: writes files; exportDir must be absolute and under the home directory, a
|
|
|
61714
62001
|
}));
|
|
61715
62002
|
const exported = results.filter((x) => x.exportedKind !== null).length;
|
|
61716
62003
|
const previews = results.filter((x) => x.exportedKind === "preview").length;
|
|
62004
|
+
const fallbacks = results.filter((x) => x.exportedKind === "fallback").length;
|
|
61717
62005
|
const failed = results.filter((x) => x.error).length;
|
|
61718
62006
|
const skipped = results.length - exported - failed;
|
|
61719
62007
|
const structured = {
|
|
61720
62008
|
exportDir: r.exportDir,
|
|
61721
62009
|
exported,
|
|
61722
62010
|
previews,
|
|
62011
|
+
fallbacks,
|
|
61723
62012
|
skipped,
|
|
61724
62013
|
failed,
|
|
61725
62014
|
results
|
|
@@ -61733,7 +62022,7 @@ Safety: writes files; exportDir must be absolute and under the home directory, a
|
|
|
61733
62022
|
);
|
|
61734
62023
|
}
|
|
61735
62024
|
}
|
|
61736
|
-
const summary = `Exported ${exported} file(s) to ${r.exportDir} (${previews} preview-only, ${skipped} with nothing on disk, ${failed} failed).`;
|
|
62025
|
+
const summary = `Exported ${exported} file(s) to ${r.exportDir} (${previews} preview-only, ${fallbacks} Notes rendering(s), ${skipped} with nothing on disk, ${failed} failed).`;
|
|
61737
62026
|
if (exported === 0 && failed > 0) {
|
|
61738
62027
|
const error2 = errorResponse(summary, new CodedError(summary, { code: "operation_failed" }));
|
|
61739
62028
|
return { ...error2, structuredContent: { ...structured, ...error2.structuredContent } };
|
|
@@ -61914,7 +62203,8 @@ var exportStatsSchema = external_exports.object({
|
|
|
61914
62203
|
unavailable: external_exports.number(),
|
|
61915
62204
|
tables: external_exports.number(),
|
|
61916
62205
|
unreadableTables: external_exports.number(),
|
|
61917
|
-
unreferenced: external_exports.number()
|
|
62206
|
+
unreferenced: external_exports.number(),
|
|
62207
|
+
staleRenderings: external_exports.number().optional()
|
|
61918
62208
|
});
|
|
61919
62209
|
registerTool(
|
|
61920
62210
|
"export-notes-markdown",
|
|
@@ -61940,6 +62230,7 @@ registerTool(
|
|
|
61940
62230
|
outputSchema: {
|
|
61941
62231
|
format: external_exports.string().optional(),
|
|
61942
62232
|
count: external_exports.number().optional(),
|
|
62233
|
+
truncated: external_exports.boolean().optional(),
|
|
61943
62234
|
bytes: external_exports.number().optional(),
|
|
61944
62235
|
markdown: external_exports.string().optional(),
|
|
61945
62236
|
output: external_exports.string().optional(),
|
|
@@ -61978,7 +62269,7 @@ registerTool(
|
|
|
61978
62269
|
);
|
|
61979
62270
|
}
|
|
61980
62271
|
const warned = receipt.warnings?.length ? `; ${receipt.warnings.length + (receipt.warningsOmitted ?? 0)} warning(s)` : "";
|
|
61981
|
-
const skipped = (receipt.skipped.length ? `; skipped ${receipt.skipped.length}` : "") + warned;
|
|
62272
|
+
const skipped = (receipt.skipped.length ? `; skipped ${receipt.skipped.length}` : "") + warned + (receipt.truncated ? "; the folder has more notes than limit, pass a higher limit" : "");
|
|
61982
62273
|
if (receipt.output)
|
|
61983
62274
|
return successResponse(
|
|
61984
62275
|
`Wrote ${receipt.count} note(s) as Markdown (${receipt.bytes} bytes) to ${receipt.output}` + (receipt.assets ? `; copied ${receipt.assets.files} asset file(s) to ${receipt.assets.dir}` : "") + `${skipped}.`,
|
|
@@ -62009,6 +62300,7 @@ registerTool(
|
|
|
62009
62300
|
outputSchema: {
|
|
62010
62301
|
format: external_exports.string().optional(),
|
|
62011
62302
|
count: external_exports.number().optional(),
|
|
62303
|
+
truncated: external_exports.boolean().optional(),
|
|
62012
62304
|
bytes: external_exports.number().optional(),
|
|
62013
62305
|
output: external_exports.string().optional(),
|
|
62014
62306
|
assets: external_exports.object({ dir: external_exports.string(), files: external_exports.number() }).optional(),
|
|
@@ -62031,7 +62323,7 @@ registerTool(
|
|
|
62031
62323
|
return errorResponse(`Error exporting HTML [${error2.code}]: ${error2.message}${hint}`, error2);
|
|
62032
62324
|
}
|
|
62033
62325
|
const assets = receipt.assets ? `; copied ${receipt.assets.files} asset file(s) to ${receipt.assets.dir}` : `; embedded ${receipt.embedded ?? 0} asset(s)`;
|
|
62034
|
-
const skipped = receipt.skipped.length ? `; skipped ${receipt.skipped.length}` : "";
|
|
62326
|
+
const skipped = (receipt.skipped.length ? `; skipped ${receipt.skipped.length}` : "") + (receipt.truncated ? "; the folder has more notes than limit, pass a higher limit" : "");
|
|
62035
62327
|
return successResponse(
|
|
62036
62328
|
`Wrote ${receipt.count} note(s) as HTML (${receipt.bytes} bytes) to ${receipt.output}${assets}${skipped}.`,
|
|
62037
62329
|
{ ...receipt }
|
|
@@ -62214,27 +62506,32 @@ registerTool(
|
|
|
62214
62506
|
drawingCount: external_exports.number().optional(),
|
|
62215
62507
|
status: external_exports.string().optional(),
|
|
62216
62508
|
drawings: external_exports.array(external_exports.object({}).passthrough()).optional(),
|
|
62217
|
-
pointsOmitted: external_exports.boolean().optional()
|
|
62509
|
+
pointsOmitted: external_exports.boolean().optional(),
|
|
62510
|
+
svgOmitted: external_exports.boolean().optional()
|
|
62218
62511
|
}
|
|
62219
62512
|
},
|
|
62220
62513
|
withErrorHandling(({ id: id2, format, includePoints }) => {
|
|
62221
|
-
|
|
62222
|
-
|
|
62223
|
-
|
|
62224
|
-
|
|
62225
|
-
|
|
62226
|
-
|
|
62227
|
-
|
|
62514
|
+
const limit = exportMaxResponseBytes();
|
|
62515
|
+
const { result, pointsOmitted, svgOmitted, oversized } = fitNoteDrawings(
|
|
62516
|
+
getNoteDrawings(id2, { format, includePoints }),
|
|
62517
|
+
limit
|
|
62518
|
+
);
|
|
62519
|
+
if (oversized)
|
|
62520
|
+
return errorResponse(
|
|
62521
|
+
`The drawings in note "${id2}" are too large to return even without stroke points and SVG (limit ${limit} bytes, APPLE_NOTES_MCP_EXPORT_MAX_BYTES).`
|
|
62522
|
+
);
|
|
62523
|
+
const text2 = formatNoteDrawings(result) + (pointsOmitted ? "\nStroke points were omitted to stay under the response size limit (APPLE_NOTES_MCP_EXPORT_MAX_BYTES)." : "") + (svgOmitted ? "\nSVG documents were omitted to stay under the response size limit (APPLE_NOTES_MCP_EXPORT_MAX_BYTES)." : "");
|
|
62228
62524
|
return successResponse(text2, {
|
|
62229
62525
|
...result,
|
|
62230
|
-
...pointsOmitted ? { pointsOmitted } : {}
|
|
62526
|
+
...pointsOmitted ? { pointsOmitted } : {},
|
|
62527
|
+
...svgOmitted ? { svgOmitted } : {}
|
|
62231
62528
|
});
|
|
62232
62529
|
}, "Error reading drawings")
|
|
62233
62530
|
);
|
|
62234
62531
|
registerTool(
|
|
62235
62532
|
"transcribe-note-audio",
|
|
62236
62533
|
{
|
|
62237
|
-
description: "Use when: you need the words spoken in a note's voice recordings or audio attachments, transcribed now on this Mac, by note id.\nReturns: per audio attachment a status (ok / partial / error / indeterminate), duration, word count, per-take results, and the transcript; overall status ok / partial / error / indeterminate / none.\nDo not use when: you only need the audio file (save-attachment) or a note has no audio.\nNote: read-only; recognition runs entirely on-device (never sent to a server). Needs Full Disk Access and the public native helper built once with `apple-notes-mcp setup --public-helper`. Long recordings take time: pass attachmentId to transcribe one at a time. An indeterminate result means the helper timed out; retrying may succeed. Never prompts: code permission_required means the user must allow the host app under System Settings > Privacy & Security > Speech Recognition. asset_unavailable can mean the language's speech model is not installed; pass downloadAssets: true only if the user agrees to the download.",
|
|
62534
|
+
description: "Use when: you need the words spoken in a note's voice recordings or audio attachments, transcribed now on this Mac, by note id.\nReturns: per audio attachment a status (ok / partial / error / indeterminate), duration, word count, per-take results, and the transcript; overall status ok / partial / error / indeterminate / none.\nDo not use when: you only need the audio file (save-attachment) or a note has no audio.\nNote: read-only; recognition runs entirely on-device (never sent to a server). Needs Full Disk Access and the public native helper built once with `apple-notes-mcp setup --public-helper`. Long recordings take time: pass attachmentId to transcribe one at a time. An indeterminate result means the helper timed out; retrying may succeed. Never prompts: code permission_required means the user must allow the host app under System Settings > Privacy & Security > Speech Recognition; permission_not_requested (before macOS 26) means the host app has never asked for that access, so it is not listed there yet. asset_unavailable can mean the language's speech model is not installed; pass downloadAssets: true only if the user agrees to the download.",
|
|
62238
62535
|
inputSchema: {
|
|
62239
62536
|
id: noteIdInput,
|
|
62240
62537
|
locale: external_exports.string().max(35).optional().describe('BCP-47 language of the speech, e.g. "en-US" (default), "it-IT", "fr-FR"'),
|
|
@@ -62252,11 +62549,13 @@ registerTool(
|
|
|
62252
62549
|
locale: external_exports.string().optional(),
|
|
62253
62550
|
status: external_exports.string().optional(),
|
|
62254
62551
|
recordingCount: external_exports.number().optional(),
|
|
62255
|
-
recordings: external_exports.array(external_exports.object({}).passthrough()).optional()
|
|
62552
|
+
recordings: external_exports.array(external_exports.object({}).passthrough()).optional(),
|
|
62553
|
+
responseOversized: external_exports.boolean().optional()
|
|
62256
62554
|
}
|
|
62257
62555
|
},
|
|
62258
62556
|
withAsyncErrorHandling(async (params, signal) => {
|
|
62259
62557
|
const { id: id2, locale, attachmentId, includeText, downloadAssets, maxSeconds } = params;
|
|
62558
|
+
const toResponse = (r) => successResponse(formatTranscription(r), r);
|
|
62260
62559
|
const result = fitTranscriptions(
|
|
62261
62560
|
await transcribeNoteAudio(id2, {
|
|
62262
62561
|
locale,
|
|
@@ -62266,12 +62565,10 @@ registerTool(
|
|
|
62266
62565
|
maxSeconds,
|
|
62267
62566
|
signal
|
|
62268
62567
|
}),
|
|
62269
|
-
exportMaxResponseBytes()
|
|
62270
|
-
|
|
62271
|
-
return successResponse(
|
|
62272
|
-
formatTranscription(result),
|
|
62273
|
-
result
|
|
62568
|
+
exportMaxResponseBytes(),
|
|
62569
|
+
(r) => Buffer.byteLength(JSON.stringify(toResponse(r)))
|
|
62274
62570
|
);
|
|
62571
|
+
return toResponse(result);
|
|
62275
62572
|
}, "Error transcribing audio")
|
|
62276
62573
|
);
|
|
62277
62574
|
registerTool(
|
|
@@ -62386,13 +62683,14 @@ process.on("uncaughtException", (err) => {
|
|
|
62386
62683
|
process.on("unhandledRejection", (reason) => {
|
|
62387
62684
|
console.error("[unhandledRejection]", reason);
|
|
62388
62685
|
});
|
|
62389
|
-
var
|
|
62686
|
+
var inFlight = new InFlightRequests();
|
|
62687
|
+
var shutdown = createShutdown(process.stdout, () => process.exit(0), void 0, inFlight);
|
|
62390
62688
|
for (const sig of ["SIGINT", "SIGTERM"]) {
|
|
62391
62689
|
process.on(sig, shutdown);
|
|
62392
62690
|
}
|
|
62393
62691
|
process.stdin.on("end", shutdown);
|
|
62394
62692
|
process.stdin.on("close", shutdown);
|
|
62395
|
-
var transport = withJsonSchema2020_12(new StdioServerTransport());
|
|
62693
|
+
var transport = trackRequests(withJsonSchema2020_12(new StdioServerTransport()), inFlight);
|
|
62396
62694
|
await server.connect(transport);
|
|
62397
62695
|
/*! Bundled license information:
|
|
62398
62696
|
|