apple-notes-mcp 2.9.25 → 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 +17 -12
- package/build/index.js +500 -197
- 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] || "[]");
|
|
@@ -41474,8 +41480,11 @@ function privateContentReason(p, roots) {
|
|
|
41474
41480
|
return isWithinRoots(p, cloudDocuments) ? null : "~/Library";
|
|
41475
41481
|
}
|
|
41476
41482
|
var CLOUD_DOCUMENT_DIRS = ["Mobile Documents", "CloudStorage"];
|
|
41477
|
-
function
|
|
41478
|
-
const
|
|
41483
|
+
function readAllowedFile(p, maxBytes, options = {}) {
|
|
41484
|
+
const roots = options.roots ?? allowedSaveRoots();
|
|
41485
|
+
const allowPrivate = options.allowPrivate ?? process.env[ALLOW_PRIVATE_CONTENT_ENV] === "1";
|
|
41486
|
+
const label = options.label ?? "Content file";
|
|
41487
|
+
const abs = assertReadableInRoots(p, roots, label);
|
|
41479
41488
|
const assertNotPrivate = (candidate, candidateRoots) => {
|
|
41480
41489
|
if (allowPrivate) return;
|
|
41481
41490
|
const reason = privateContentReason(candidate, candidateRoots);
|
|
@@ -41496,12 +41505,12 @@ function readAllowedTextFile(p, maxBytes, roots = allowedSaveRoots(), allowPriva
|
|
|
41496
41505
|
}
|
|
41497
41506
|
try {
|
|
41498
41507
|
const stat = fstatSync(descriptor);
|
|
41499
|
-
if (!stat.isFile()) throw new Error(
|
|
41508
|
+
if (!stat.isFile()) throw new Error(`${label} is not a regular file: "${abs}"`);
|
|
41500
41509
|
let after;
|
|
41501
41510
|
try {
|
|
41502
41511
|
after = canonicalize(abs);
|
|
41503
41512
|
} catch {
|
|
41504
|
-
throw new Error(
|
|
41513
|
+
throw new Error(`${label} changed while it was being opened; try again: "${abs}"`);
|
|
41505
41514
|
}
|
|
41506
41515
|
if (!isWithinRoots(after, canonicalRoots(roots)))
|
|
41507
41516
|
throw new Error(
|
|
@@ -41510,22 +41519,26 @@ function readAllowedTextFile(p, maxBytes, roots = allowedSaveRoots(), allowPriva
|
|
|
41510
41519
|
assertNotPrivate(after, canonicalRoots(roots));
|
|
41511
41520
|
const named = statSync(after);
|
|
41512
41521
|
if (named.dev !== stat.dev || named.ino !== stat.ino)
|
|
41513
|
-
throw new Error(
|
|
41514
|
-
if (stat.size === 0) throw new Error(
|
|
41522
|
+
throw new Error(`${label} changed while it was being opened; try again: "${abs}"`);
|
|
41523
|
+
if (stat.size === 0) throw new Error(`${label} is empty: "${abs}"`);
|
|
41515
41524
|
if (stat.size > maxBytes)
|
|
41516
|
-
throw new Error(
|
|
41525
|
+
throw new Error(`${label} is ${stat.size} bytes, over the ${maxBytes}-byte limit.`);
|
|
41517
41526
|
const bytes = readFileSync(descriptor);
|
|
41518
41527
|
if (bytes.length !== stat.size)
|
|
41519
|
-
throw new Error(
|
|
41520
|
-
|
|
41521
|
-
return new TextDecoder("utf-8", { fatal: true }).decode(bytes).replace(/^\uFEFF/, "");
|
|
41522
|
-
} catch {
|
|
41523
|
-
throw new Error(`Content file is not valid UTF-8 text: "${abs}"`);
|
|
41524
|
-
}
|
|
41528
|
+
throw new Error(`${label} changed while it was being read; try again`);
|
|
41529
|
+
return bytes;
|
|
41525
41530
|
} finally {
|
|
41526
41531
|
closeSync(descriptor);
|
|
41527
41532
|
}
|
|
41528
41533
|
}
|
|
41534
|
+
function readAllowedTextFile(p, maxBytes, roots = allowedSaveRoots(), allowPrivate = process.env[ALLOW_PRIVATE_CONTENT_ENV] === "1") {
|
|
41535
|
+
const bytes = readAllowedFile(p, maxBytes, { roots, allowPrivate });
|
|
41536
|
+
try {
|
|
41537
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(bytes).replace(/^\uFEFF/, "");
|
|
41538
|
+
} catch {
|
|
41539
|
+
throw new Error(`Content file is not valid UTF-8 text: "${resolve(p)}"`);
|
|
41540
|
+
}
|
|
41541
|
+
}
|
|
41529
41542
|
function cleanupTempDir(dir) {
|
|
41530
41543
|
try {
|
|
41531
41544
|
if (existsSync5(dir)) rmSync(dir, { recursive: true, force: true });
|
|
@@ -41653,6 +41666,7 @@ function buildAttachmentRowsSql(notePk, columns) {
|
|
|
41653
41666
|
`'identifier', a.ZIDENTIFIER`,
|
|
41654
41667
|
`'uti', ${col3("a", "ZTYPEUTI")}`,
|
|
41655
41668
|
`'parentPk', ${parent}`,
|
|
41669
|
+
`'parentDeleted', ${parent !== "NULL" && columns.has("ZMARKEDFORDELETION") ? `(SELECT COALESCE(p.ZMARKEDFORDELETION, 0) FROM ZICCLOUDSYNCINGOBJECT p WHERE p.Z_PK = ${parent})` : "0"}`,
|
|
41656
41670
|
`'filename', ${col3("a", "ZFILENAME")}`,
|
|
41657
41671
|
`'mediaIdentifier', m.ZIDENTIFIER`,
|
|
41658
41672
|
`'mediaFilename', ${col3("m", "ZFILENAME")}`,
|
|
@@ -41711,6 +41725,7 @@ function parseAttachmentRows(json2) {
|
|
|
41711
41725
|
identifier,
|
|
41712
41726
|
uti: toStringOrNull(r.uti),
|
|
41713
41727
|
parentPk: toIntOrNull(r.parentPk),
|
|
41728
|
+
...toIntOrNull(r.parentDeleted) ? { parentDeleted: true } : {},
|
|
41714
41729
|
filename: toStringOrNull(r.filename),
|
|
41715
41730
|
mediaIdentifier: toStringOrNull(r.mediaIdentifier),
|
|
41716
41731
|
mediaFilename: toStringOrNull(r.mediaFilename),
|
|
@@ -41828,7 +41843,7 @@ function generationDirs(base, accountDir) {
|
|
|
41828
41843
|
const entries2 = boundedEntries(base, MAX_GENERATION_DIRS) ?? [];
|
|
41829
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)));
|
|
41830
41845
|
}
|
|
41831
|
-
function fallbackFiles(accountDir, rootName, identifier, generation, names) {
|
|
41846
|
+
function fallbackFiles(accountDir, rootName, identifier, generation, names, onStale) {
|
|
41832
41847
|
const base = join8(accountDir, rootName, identifier);
|
|
41833
41848
|
const found = [];
|
|
41834
41849
|
const add = (candidate) => {
|
|
@@ -41837,12 +41852,14 @@ function fallbackFiles(accountDir, rootName, identifier, generation, names) {
|
|
|
41837
41852
|
};
|
|
41838
41853
|
const gen = safeComponent(generation);
|
|
41839
41854
|
if (gen) for (const name of names) add(join8(base, gen, name));
|
|
41855
|
+
const recorded = found.length;
|
|
41840
41856
|
if (isDirectory(base)) {
|
|
41841
41857
|
for (const dir of generationDirs(base, accountDir))
|
|
41842
41858
|
for (const name of names) add(join8(dir, name));
|
|
41843
41859
|
for (const name of names) add(join8(base, name));
|
|
41844
41860
|
}
|
|
41845
41861
|
for (const name of names) add(join8(accountDir, rootName, `${identifier}${extname(name)}`));
|
|
41862
|
+
if (gen && recorded === 0 && found.length > 0) onStale?.();
|
|
41846
41863
|
return found;
|
|
41847
41864
|
}
|
|
41848
41865
|
function previewPixelArea(name) {
|
|
@@ -41888,7 +41905,7 @@ function previewPaths(accountDir, identifier, entries2) {
|
|
|
41888
41905
|
}
|
|
41889
41906
|
return files;
|
|
41890
41907
|
}
|
|
41891
|
-
function assetPathsFor(accountDir, row) {
|
|
41908
|
+
function assetPathsFor(accountDir, row, onStale) {
|
|
41892
41909
|
const found = [];
|
|
41893
41910
|
const add = (candidate) => {
|
|
41894
41911
|
const real = realInside(candidate, accountDir);
|
|
@@ -41905,18 +41922,28 @@ function assetPathsFor(accountDir, row) {
|
|
|
41905
41922
|
if (!id2) return found;
|
|
41906
41923
|
const ownName = safeComponent(row.filename);
|
|
41907
41924
|
if (ownName) add(join8(accountDir, "Media", id2, ownName));
|
|
41908
|
-
for (const file of fallbackFiles(
|
|
41909
|
-
|
|
41910
|
-
"
|
|
41911
|
-
|
|
41925
|
+
for (const file of fallbackFiles(
|
|
41926
|
+
accountDir,
|
|
41927
|
+
"FallbackImages",
|
|
41928
|
+
id2,
|
|
41929
|
+
row.fallbackImageGeneration,
|
|
41930
|
+
["FallbackImage.png", "FallbackImage.jpg"],
|
|
41931
|
+
onStale
|
|
41932
|
+
))
|
|
41912
41933
|
add(file);
|
|
41913
|
-
for (const file of fallbackFiles(
|
|
41914
|
-
|
|
41915
|
-
|
|
41934
|
+
for (const file of fallbackFiles(
|
|
41935
|
+
accountDir,
|
|
41936
|
+
"FallbackPDFs",
|
|
41937
|
+
id2,
|
|
41938
|
+
row.fallbackPdfGeneration,
|
|
41939
|
+
["FallbackPDF.pdf"],
|
|
41940
|
+
onStale
|
|
41941
|
+
))
|
|
41916
41942
|
add(file);
|
|
41917
41943
|
return found;
|
|
41918
41944
|
}
|
|
41919
|
-
function assembleAttachmentAssets(
|
|
41945
|
+
function assembleAttachmentAssets(allRows, bodyOrder, containerDir = NOTES_CONTAINER_DIR) {
|
|
41946
|
+
const rows = allRows.filter((r) => !r.parentDeleted);
|
|
41920
41947
|
const byPk = new Map(rows.map((r) => [r.pk, r]));
|
|
41921
41948
|
const roots = rows.filter((r) => r.parentPk === null || !byPk.has(r.parentPk));
|
|
41922
41949
|
const bodyIndex = /* @__PURE__ */ new Map();
|
|
@@ -41939,10 +41966,11 @@ function assembleAttachmentAssets(rows, bodyOrder, containerDir = NOTES_CONTAINE
|
|
|
41939
41966
|
const accountDir = accountDirFor(row.accountIdentifier ?? parent?.accountIdentifier ?? null);
|
|
41940
41967
|
let assetPaths = [];
|
|
41941
41968
|
let previews = [];
|
|
41969
|
+
let fallbackStale = false;
|
|
41942
41970
|
if (accountDir) {
|
|
41943
41971
|
if (!previewEntries.has(accountDir))
|
|
41944
41972
|
previewEntries.set(accountDir, listPreviewEntries(accountDir));
|
|
41945
|
-
assetPaths = assetPathsFor(accountDir, row);
|
|
41973
|
+
assetPaths = assetPathsFor(accountDir, row, () => fallbackStale = true);
|
|
41946
41974
|
previews = previewPaths(accountDir, row.identifier, previewEntries.get(accountDir));
|
|
41947
41975
|
}
|
|
41948
41976
|
const previewPath = previews[0] ?? null;
|
|
@@ -41955,6 +41983,7 @@ function assembleAttachmentAssets(rows, bodyOrder, containerDir = NOTES_CONTAINE
|
|
|
41955
41983
|
filename: row.filename ?? row.mediaFilename,
|
|
41956
41984
|
bodyIndex: parent ? null : indexOf(row),
|
|
41957
41985
|
assetPaths,
|
|
41986
|
+
...fallbackStale ? { fallbackStale: true } : {},
|
|
41958
41987
|
previewPath,
|
|
41959
41988
|
paths: previewPath ? [...assetPaths, previewPath] : [...assetPaths]
|
|
41960
41989
|
};
|
|
@@ -42040,6 +42069,11 @@ function copyFileExclusive(src, dest) {
|
|
|
42040
42069
|
function exportFileName(record2, source, kind) {
|
|
42041
42070
|
const ext = extname(source);
|
|
42042
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
|
+
}
|
|
42043
42077
|
if (kind === "preview") {
|
|
42044
42078
|
const stored2 = safeComponent(record2.filename ? basename(record2.filename) : null);
|
|
42045
42079
|
const stem = stored2 ? basename(stored2, extname(stored2)) : id2;
|
|
@@ -42068,7 +42102,7 @@ function prepareExportDir(exportDir, containerDir = NOTES_CONTAINER_DIR) {
|
|
|
42068
42102
|
}
|
|
42069
42103
|
return abs;
|
|
42070
42104
|
}
|
|
42071
|
-
function exportOneAttachment(record2, dir, source) {
|
|
42105
|
+
function exportOneAttachment(record2, dir, source, inBody) {
|
|
42072
42106
|
const base = {
|
|
42073
42107
|
pk: record2.pk,
|
|
42074
42108
|
identifier: record2.identifier,
|
|
@@ -42076,7 +42110,8 @@ function exportOneAttachment(record2, dir, source) {
|
|
|
42076
42110
|
kind: record2.kind,
|
|
42077
42111
|
parentIdentifier: record2.parentIdentifier,
|
|
42078
42112
|
exportedTo: null,
|
|
42079
|
-
exportedKind: null
|
|
42113
|
+
exportedKind: null,
|
|
42114
|
+
...inBody === false ? { inBody: false } : {}
|
|
42080
42115
|
};
|
|
42081
42116
|
if (!source) return base;
|
|
42082
42117
|
const name = exportFileName(record2, source.path, source.kind);
|
|
@@ -42087,7 +42122,12 @@ function exportOneAttachment(record2, dir, source) {
|
|
|
42087
42122
|
throw new Error(`Refusing to write outside the export directory: "${dest}"`);
|
|
42088
42123
|
assertSafeSavePath(dest);
|
|
42089
42124
|
copyFileExclusive(source.path, dest);
|
|
42090
|
-
return {
|
|
42125
|
+
return {
|
|
42126
|
+
...base,
|
|
42127
|
+
exportedTo: dest,
|
|
42128
|
+
exportedKind: source.kind,
|
|
42129
|
+
...source.kind === "fallback" && record2.fallbackStale ? { stale: true } : {}
|
|
42130
|
+
};
|
|
42091
42131
|
} catch (error2) {
|
|
42092
42132
|
if (error2.code === "EEXIST") continue;
|
|
42093
42133
|
return { ...base, error: error2 instanceof Error ? error2.message : String(error2) };
|
|
@@ -42095,20 +42135,31 @@ function exportOneAttachment(record2, dir, source) {
|
|
|
42095
42135
|
}
|
|
42096
42136
|
return { ...base, error: "Too many name collisions in the export directory" };
|
|
42097
42137
|
}
|
|
42138
|
+
function isFallbackRendering(path10) {
|
|
42139
|
+
return /[\\/]Fallback(?:Images|PDFs)[\\/]/.test(path10);
|
|
42140
|
+
}
|
|
42098
42141
|
function exportSource(record2) {
|
|
42099
|
-
|
|
42142
|
+
const asset = record2.assetPaths[0];
|
|
42143
|
+
if (asset) return { path: asset, kind: isFallbackRendering(asset) ? "fallback" : "asset" };
|
|
42100
42144
|
if (record2.previewPath) return { path: record2.previewPath, kind: "preview" };
|
|
42101
42145
|
return null;
|
|
42102
42146
|
}
|
|
42103
42147
|
function exportAttachmentAssets(assets, exportDir, options = {}) {
|
|
42104
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
|
+
};
|
|
42105
42156
|
if (options.firstImageOnly) {
|
|
42106
42157
|
const first2 = selectFirstImage(assets);
|
|
42107
42158
|
if (!first2) return { exportDir: dir, results: [], firstImage: null };
|
|
42108
42159
|
const record2 = assets.attachments.find((a) => a.pk === first2.pk);
|
|
42109
42160
|
return {
|
|
42110
42161
|
exportDir: dir,
|
|
42111
|
-
results: [exportOneAttachment(record2, dir, exportSource(record2))],
|
|
42162
|
+
results: [exportOneAttachment(record2, dir, exportSource(record2), inBody(record2))],
|
|
42112
42163
|
firstImage: first2
|
|
42113
42164
|
};
|
|
42114
42165
|
}
|
|
@@ -42122,7 +42173,7 @@ function exportAttachmentAssets(assets, exportDir, options = {}) {
|
|
|
42122
42173
|
} else if (!exportSource(record2) && assets.attachments.some((c) => c.parentIdentifier === record2.identifier)) {
|
|
42123
42174
|
continue;
|
|
42124
42175
|
}
|
|
42125
|
-
results.push(exportOneAttachment(record2, dir, exportSource(record2)));
|
|
42176
|
+
results.push(exportOneAttachment(record2, dir, exportSource(record2), inBody(record2)));
|
|
42126
42177
|
}
|
|
42127
42178
|
return { exportDir: dir, results };
|
|
42128
42179
|
}
|
|
@@ -42291,7 +42342,17 @@ function entries(dir, limit) {
|
|
|
42291
42342
|
}
|
|
42292
42343
|
}
|
|
42293
42344
|
var byGenerationDesc = (a, b) => generationRank(basename2(b)) - generationRank(basename2(a));
|
|
42294
|
-
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) {
|
|
42295
42356
|
const id2 = safeComponent(identifier);
|
|
42296
42357
|
if (!id2) return null;
|
|
42297
42358
|
const base = join9(accountDir, "FallbackImages", id2);
|
|
@@ -42338,7 +42399,8 @@ function describeDrawings(rows, containerDir = NOTES_CONTAINER_DIR) {
|
|
|
42338
42399
|
const accountDir = resolveAccountDir(containerDir, row.accountIdentifier);
|
|
42339
42400
|
const kind = row.uti === "com.apple.paper" ? "paper" : "drawing";
|
|
42340
42401
|
const id2 = safeComponent(row.identifier);
|
|
42341
|
-
const
|
|
42402
|
+
const fallback = accountDir ? locateFallbackImage(accountDir, row.identifier, row.fallbackImageGeneration) : { path: null, stale: false };
|
|
42403
|
+
const fallbackImagePath = fallback.path;
|
|
42342
42404
|
const previewPath = accountDir ? findLargestPreview(accountDir, row.identifier) : null;
|
|
42343
42405
|
const bundle = accountDir && id2 && kind === "paper" ? realInside(join9(accountDir, "Paper", "Bundles", `${id2}.bundle`), accountDir) : null;
|
|
42344
42406
|
let raster = null;
|
|
@@ -42360,6 +42422,7 @@ function describeDrawings(rows, containerDir = NOTES_CONTAINER_DIR) {
|
|
|
42360
42422
|
handwritingSummary: row.handwritingSummary,
|
|
42361
42423
|
bundlePresent: bundle !== null && kindOf(bundle) === "dir",
|
|
42362
42424
|
fallbackImagePath,
|
|
42425
|
+
fallbackImageStale: fallback.stale,
|
|
42363
42426
|
previewPath,
|
|
42364
42427
|
raster
|
|
42365
42428
|
};
|
|
@@ -42500,18 +42563,25 @@ function idList(ids) {
|
|
|
42500
42563
|
function buildScopeGuardScript(noteVar, guard, destinationVar) {
|
|
42501
42564
|
if (!hasScopeGuard(guard)) return "";
|
|
42502
42565
|
validateScopeGuard(guard);
|
|
42503
|
-
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))];
|
|
42504
42569
|
let script = `
|
|
42505
42570
|
set scopeFolder to container of ${noteVar}
|
|
42506
42571
|
if class of scopeFolder is not folder then return "${SCOPE_MARKER}:the note is not in a folder"`;
|
|
42507
|
-
if (
|
|
42572
|
+
if (forbidden.length > 0)
|
|
42508
42573
|
script += `
|
|
42509
|
-
|
|
42510
|
-
|
|
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)
|
|
42511
42581
|
script += chainScript("scopeChain", "scopeFolder");
|
|
42512
|
-
if (
|
|
42582
|
+
if (ifAncestorFolderId)
|
|
42513
42583
|
script += `
|
|
42514
|
-
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"`;
|
|
42515
42585
|
if (forbidden.length > 0) {
|
|
42516
42586
|
script += `
|
|
42517
42587
|
repeat with forbiddenId in ${idList(forbidden)}
|
|
@@ -43428,7 +43498,7 @@ var AppleNotesManager = class {
|
|
|
43428
43498
|
* @throws Error when the note's rich data cannot be read (e.g. no Full Disk Access)
|
|
43429
43499
|
*/
|
|
43430
43500
|
getNoteTablesById(id2) {
|
|
43431
|
-
return collectNoteTables(readRichNote(id2), id2);
|
|
43501
|
+
return collectNoteTables(readRichNote(id2, { skipUnsafeLinks: true }), id2);
|
|
43432
43502
|
}
|
|
43433
43503
|
/**
|
|
43434
43504
|
* Retrieves detailed metadata for a note by title.
|
|
@@ -43561,6 +43631,7 @@ var AppleNotesManager = class {
|
|
|
43561
43631
|
return `
|
|
43562
43632
|
if not (exists note id "${safeGuardId}") then ${inactive("missing")}
|
|
43563
43633
|
set ${ref} to note id "${safeGuardId}"
|
|
43634
|
+
if (id of ${ref}) is (id of noteRef) then ${inactive("the note being deleted")}
|
|
43564
43635
|
if password protected of ${ref} then ${inactive("locked")}
|
|
43565
43636
|
set ${folderVar} to missing value
|
|
43566
43637
|
try
|
|
@@ -46321,7 +46392,7 @@ var HIGHLIGHTS = {
|
|
|
46321
46392
|
var KNOWN_RUN_FIELDS = /* @__PURE__ */ new Set([1, 2, 3, 5, 6, 7, 8, 9, 10, 12, 14]);
|
|
46322
46393
|
var KNOWN_PARAGRAPH_FIELDS = /* @__PURE__ */ new Set([1, 2, 4, 5, 8, 9]);
|
|
46323
46394
|
var isSafeLink = (url) => /^(?:https?:\/\/|notes:\/\/|applenotes:|mailto:)/i.test(url) && !Array.from(url).some((char) => char.charCodeAt(0) < 32);
|
|
46324
|
-
var utf8 = new TextDecoder();
|
|
46395
|
+
var utf8 = new TextDecoder("utf-8", { ignoreBOM: true });
|
|
46325
46396
|
var first = (fields, n) => fields.find((f) => f.fieldNumber === n);
|
|
46326
46397
|
var varintOf = (fields, n) => {
|
|
46327
46398
|
const f = first(fields, n);
|
|
@@ -46470,7 +46541,8 @@ function decodeNoteBlocks(data) {
|
|
|
46470
46541
|
const end = newline === -1 ? text2.length : newline;
|
|
46471
46542
|
while (runIndex < runs.length - 1 && runs[runIndex].start + runs[runIndex].length <= paragraphStart)
|
|
46472
46543
|
runIndex++;
|
|
46473
|
-
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;
|
|
46474
46546
|
const style = attrs.styleType === null ? "body" : STYLE_NAMES[attrs.styleType] ?? "unknown";
|
|
46475
46547
|
const alignment = ALIGNMENTS[attrs.alignmentValue] ?? "unknown";
|
|
46476
46548
|
const block = {
|
|
@@ -46677,6 +46749,25 @@ function readNoteBlocks(id2, { dbPath: dbPath2 = NOTES_DB_PATH9 } = {}) {
|
|
|
46677
46749
|
return decodeCompressedNoteBlocks(Buffer.from(row.data, "hex"));
|
|
46678
46750
|
}
|
|
46679
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
|
+
|
|
46680
46771
|
// src/utils/noteRecentList.ts
|
|
46681
46772
|
var RECENT_LIMIT = { DEFAULT: 50, MAX: 1e3 };
|
|
46682
46773
|
var CHECKPOINT_PREFIX = "cdts1:";
|
|
@@ -46731,9 +46822,7 @@ function parseSince(input) {
|
|
|
46731
46822
|
}
|
|
46732
46823
|
function textStats(text2) {
|
|
46733
46824
|
const visible2 = text2.replace(OBJECT_REPLACEMENT, "");
|
|
46734
|
-
|
|
46735
|
-
for (const token of visible2.split(/\s+/u)) if (/[\p{L}\p{N}]/u.test(token)) wordCount2++;
|
|
46736
|
-
return { wordCount: wordCount2, charCount: [...visible2].length };
|
|
46825
|
+
return { wordCount: countWords(visible2), charCount: [...visible2].length };
|
|
46737
46826
|
}
|
|
46738
46827
|
function previewText(text2) {
|
|
46739
46828
|
const flat = text2.replace(OBJECT_REPLACEMENT, " ").replace(/\s+/gu, " ").trim();
|
|
@@ -47355,6 +47444,10 @@ var Parser = class {
|
|
|
47355
47444
|
function parseNoteQuery(input) {
|
|
47356
47445
|
return new Parser(tokenize(input), input.length).parse();
|
|
47357
47446
|
}
|
|
47447
|
+
function noteBodyText(text2) {
|
|
47448
|
+
const firstBreak = text2.indexOf("\n");
|
|
47449
|
+
return firstBreak === -1 ? "" : text2.slice(firstBreak + 1);
|
|
47450
|
+
}
|
|
47358
47451
|
function normalizeForMatch(text2) {
|
|
47359
47452
|
return text2.normalize("NFC").replace(/[\ufffc\u00a0]/gu, " ").toLowerCase();
|
|
47360
47453
|
}
|
|
@@ -47429,20 +47522,36 @@ function cheapFirst(children) {
|
|
|
47429
47522
|
}
|
|
47430
47523
|
return ordered;
|
|
47431
47524
|
}
|
|
47432
|
-
function
|
|
47525
|
+
function evaluateNoteQueryTruth(node, note) {
|
|
47433
47526
|
switch (node.type) {
|
|
47434
|
-
case "and":
|
|
47435
|
-
|
|
47436
|
-
|
|
47437
|
-
|
|
47438
|
-
|
|
47439
|
-
|
|
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
|
+
}
|
|
47440
47549
|
case "text": {
|
|
47441
47550
|
const needle = normalizeForMatch(node.value);
|
|
47442
47551
|
if (node.field === "title") return note.titleLower.includes(needle);
|
|
47443
47552
|
if (node.field === "any" && note.titleLower.includes(needle)) return true;
|
|
47444
47553
|
const content = note.content();
|
|
47445
|
-
if (!content) return
|
|
47554
|
+
if (!content) return null;
|
|
47446
47555
|
return (node.field === "body" ? content.bodyLower : content.textLower).includes(needle);
|
|
47447
47556
|
}
|
|
47448
47557
|
case "folder":
|
|
@@ -47455,21 +47564,27 @@ function evaluateNoteQuery(node, note) {
|
|
|
47455
47564
|
return compareDate(node.field === "created" ? note.created : note.modified, node);
|
|
47456
47565
|
case "tag": {
|
|
47457
47566
|
const content = note.content();
|
|
47458
|
-
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;
|
|
47459
47572
|
}
|
|
47460
|
-
case "has":
|
|
47461
|
-
return Boolean(note.content()?.facets.has(node.facet));
|
|
47462
47573
|
case "checklist": {
|
|
47463
47574
|
const content = note.content();
|
|
47464
|
-
if (!content
|
|
47575
|
+
if (!content) return null;
|
|
47576
|
+
if (content.checklist.total === 0) return false;
|
|
47465
47577
|
return node.state === "open" ? content.checklist.open > 0 : content.checklist.open === 0;
|
|
47466
47578
|
}
|
|
47467
47579
|
case "words": {
|
|
47468
47580
|
const content = note.content();
|
|
47469
|
-
return content ? compare(content.words, node.op, node.value) :
|
|
47581
|
+
return content ? compare(content.words, node.op, node.value) : null;
|
|
47470
47582
|
}
|
|
47471
47583
|
}
|
|
47472
47584
|
}
|
|
47585
|
+
function evaluateNoteQuery(node, note) {
|
|
47586
|
+
return evaluateNoteQueryTruth(node, note) === true;
|
|
47587
|
+
}
|
|
47473
47588
|
function positiveTextPredicates(node, negated = false) {
|
|
47474
47589
|
switch (node.type) {
|
|
47475
47590
|
case "and":
|
|
@@ -47492,7 +47607,7 @@ function matchLocations(predicates, title, text2) {
|
|
|
47492
47607
|
const firstBreak = text2 === null ? -1 : text2.indexOf("\n");
|
|
47493
47608
|
const titleLower = normalizeForMatch(title);
|
|
47494
47609
|
const firstLineLower = text2 === null ? "" : normalizeForMatch(firstBreak === -1 ? text2 : text2.slice(0, firstBreak));
|
|
47495
|
-
const bodyLower = text2 === null
|
|
47610
|
+
const bodyLower = text2 === null ? "" : normalizeForMatch(noteBodyText(text2));
|
|
47496
47611
|
let inTitle = false;
|
|
47497
47612
|
let inBody = false;
|
|
47498
47613
|
for (const predicate of predicates) {
|
|
@@ -47604,13 +47719,6 @@ function decodeBodyHex(hex3) {
|
|
|
47604
47719
|
return null;
|
|
47605
47720
|
}
|
|
47606
47721
|
}
|
|
47607
|
-
function countWords(text2) {
|
|
47608
|
-
let count = 0;
|
|
47609
|
-
for (const word of text2.replace(/\ufffc/gu, " ").split(/\s+/u)) {
|
|
47610
|
-
if (/[\p{L}\p{N}]/u.test(word)) count++;
|
|
47611
|
-
}
|
|
47612
|
-
return count;
|
|
47613
|
-
}
|
|
47614
47722
|
var REQUIRED_COLUMNS3 = ["Z_PK", "Z_ENT", "ZTITLE1", "ZFOLDER", "ZMODIFICATIONDATE1"];
|
|
47615
47723
|
function col2(available, alias, name) {
|
|
47616
47724
|
return available.has(name) ? `${alias}.${name}` : "NULL";
|
|
@@ -47855,7 +47963,6 @@ function runNoteQuery(ast, options = {}) {
|
|
|
47855
47963
|
const body2 = decode2();
|
|
47856
47964
|
if (!body2) return content = null;
|
|
47857
47965
|
const text2 = body2.text;
|
|
47858
|
-
const firstBreak = text2.indexOf("\n");
|
|
47859
47966
|
const tags = /* @__PURE__ */ new Set();
|
|
47860
47967
|
for (const [id2, alt] of row.tags ?? []) {
|
|
47861
47968
|
if (id2 && alt && body2.objectIds.has(id2))
|
|
@@ -47865,7 +47972,7 @@ function runNoteQuery(ast, options = {}) {
|
|
|
47865
47972
|
if (tags.size) facets.add("tag");
|
|
47866
47973
|
content = {
|
|
47867
47974
|
textLower: normalizeForMatch(text2),
|
|
47868
|
-
bodyLower: normalizeForMatch(
|
|
47975
|
+
bodyLower: normalizeForMatch(noteBodyText(text2)),
|
|
47869
47976
|
words: countWords(text2),
|
|
47870
47977
|
facets,
|
|
47871
47978
|
checklist: body2.checklist,
|
|
@@ -48358,13 +48465,16 @@ var LEGACY_ENTITIES = {
|
|
|
48358
48465
|
gt: ">",
|
|
48359
48466
|
amp: "&"
|
|
48360
48467
|
};
|
|
48468
|
+
function codePointText(value) {
|
|
48469
|
+
return Number.isSafeInteger(value) && value <= 1114111 ? String.fromCodePoint(value) : "\uFFFD";
|
|
48470
|
+
}
|
|
48361
48471
|
function comparableVisibleText(html) {
|
|
48362
48472
|
return html.replace(/<br\s*\/?\s*>/gi, " ").replace(/<[^>]*>/g, (tag) => INLINE_TAG.test(tag) ? "" : " ").replace(
|
|
48363
48473
|
/&(?:(nbsp|quot|lt|gt|amp);?|apos;|#(\d+);|#x([0-9a-f]+);)/gi,
|
|
48364
48474
|
(_match, legacy, dec, hex3) => {
|
|
48365
48475
|
if (legacy) return LEGACY_ENTITIES[legacy.toLowerCase()];
|
|
48366
|
-
if (dec) return
|
|
48367
|
-
if (hex3) return
|
|
48476
|
+
if (dec) return codePointText(Number(dec));
|
|
48477
|
+
if (hex3) return codePointText(Number.parseInt(hex3, 16));
|
|
48368
48478
|
return "'";
|
|
48369
48479
|
}
|
|
48370
48480
|
).replace(/\s+/g, " ").trim();
|
|
@@ -48789,15 +48899,26 @@ function createMarkdownNote(manager, request, run = runBackgroundShortcut) {
|
|
|
48789
48899
|
const segments = (path10) => JSON.stringify(splitFolderPath(path10).map((part) => part.toLocaleLowerCase()));
|
|
48790
48900
|
if (request.folder) {
|
|
48791
48901
|
const wanted = segments(request.folder);
|
|
48792
|
-
const accounts = manager.listAccounts().filter(
|
|
48793
|
-
|
|
48794
|
-
|
|
48795
|
-
)
|
|
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)
|
|
48796
48906
|
throw new Error(
|
|
48797
48907
|
`Folder "${request.folder}" does not exist; create it with create-folder first. Nothing was created`
|
|
48798
48908
|
);
|
|
48799
|
-
|
|
48800
|
-
|
|
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;
|
|
48801
48922
|
}
|
|
48802
48923
|
const defaultFolderNotes = () => new Map(
|
|
48803
48924
|
manager.listAccounts().flatMap(
|
|
@@ -49494,7 +49615,63 @@ function withJsonSchema2020_12(transport2) {
|
|
|
49494
49615
|
|
|
49495
49616
|
// src/utils/shutdown.ts
|
|
49496
49617
|
var SHUTDOWN_DRAIN_TIMEOUT_MS = 2e3;
|
|
49497
|
-
|
|
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) {
|
|
49498
49675
|
let shuttingDown = false;
|
|
49499
49676
|
let exited = false;
|
|
49500
49677
|
const exitOnce = () => {
|
|
@@ -49511,8 +49688,11 @@ function createShutdown(stream, exit, timeoutMs = SHUTDOWN_DRAIN_TIMEOUT_MS) {
|
|
|
49511
49688
|
return () => {
|
|
49512
49689
|
if (shuttingDown) return;
|
|
49513
49690
|
shuttingDown = true;
|
|
49514
|
-
|
|
49515
|
-
|
|
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
|
+
);
|
|
49516
49696
|
};
|
|
49517
49697
|
}
|
|
49518
49698
|
|
|
@@ -49860,7 +50040,7 @@ function lastViewedOf(raw, columnPresent = true, now = Date.now()) {
|
|
|
49860
50040
|
return { lastViewed: new Date(ms).toISOString(), lastViewedStatus: "viewed" };
|
|
49861
50041
|
}
|
|
49862
50042
|
var visible = (text2) => text2.replace(/\ufffc/g, "");
|
|
49863
|
-
var wordCount = (text2) =>
|
|
50043
|
+
var wordCount = (text2) => countWords(text2);
|
|
49864
50044
|
var charCount = (text2) => Array.from(visible(text2)).length;
|
|
49865
50045
|
function noteStructureSql(columns) {
|
|
49866
50046
|
const c = (alias, name) => col(columns, alias, name);
|
|
@@ -50148,7 +50328,7 @@ function inventorySql(columns) {
|
|
|
50148
50328
|
ORDER BY d.ZNOTE LIMIT ${BODY_BATCH};`
|
|
50149
50329
|
};
|
|
50150
50330
|
}
|
|
50151
|
-
function decodeBodies(dbPath2, sql, params) {
|
|
50331
|
+
function decodeBodies(dbPath2, sql, params, notes) {
|
|
50152
50332
|
const docs = /* @__PURE__ */ new Map();
|
|
50153
50333
|
let after = 0;
|
|
50154
50334
|
for (; ; ) {
|
|
@@ -50157,7 +50337,7 @@ function decodeBodies(dbPath2, sql, params) {
|
|
|
50157
50337
|
);
|
|
50158
50338
|
for (const row of rows) {
|
|
50159
50339
|
after = Math.max(after, row.note);
|
|
50160
|
-
if (row.encrypted || !row.data) continue;
|
|
50340
|
+
if (row.encrypted || !row.data || !notes.has(row.note)) continue;
|
|
50161
50341
|
try {
|
|
50162
50342
|
docs.set(row.note, decodeCompressedNoteBlocks(Buffer.from(row.data, "hex")));
|
|
50163
50343
|
} catch {
|
|
@@ -50205,7 +50385,7 @@ function listNoteLinks(options = {}) {
|
|
|
50205
50385
|
if (options.id && !notes.length)
|
|
50206
50386
|
throw new NoteStoreError(`No note found for ID "${options.id}".`, "invalid_input");
|
|
50207
50387
|
const includeInline = options.includeInline ?? Boolean(options.id);
|
|
50208
|
-
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();
|
|
50209
50389
|
const noteById = new Map(notes.map((note) => [note.pk, note]));
|
|
50210
50390
|
const accountById = new Map(context.accounts.map((account) => [account.pk, account]));
|
|
50211
50391
|
const folderById = new Map(context.folders.map((folder) => [folder.pk, folder]));
|
|
@@ -50520,7 +50700,14 @@ var AssetLocator = class {
|
|
|
50520
50700
|
["FallbackImage.png", "FallbackImage.jpg"]
|
|
50521
50701
|
);
|
|
50522
50702
|
if (fallback)
|
|
50523
|
-
return {
|
|
50703
|
+
return {
|
|
50704
|
+
primary: {
|
|
50705
|
+
path: fallback.path,
|
|
50706
|
+
name: `${source.kind}.png`,
|
|
50707
|
+
role: "fallback",
|
|
50708
|
+
...fallback.stale ? { stale: true } : {}
|
|
50709
|
+
}
|
|
50710
|
+
};
|
|
50524
50711
|
return preview ? { primary: preview } : {};
|
|
50525
50712
|
}
|
|
50526
50713
|
case "scan": {
|
|
@@ -50528,7 +50715,14 @@ var AssetLocator = class {
|
|
|
50528
50715
|
"FallbackPDF.pdf"
|
|
50529
50716
|
]);
|
|
50530
50717
|
return {
|
|
50531
|
-
...pdf ? {
|
|
50718
|
+
...pdf ? {
|
|
50719
|
+
primary: {
|
|
50720
|
+
path: pdf.path,
|
|
50721
|
+
name: "scan.pdf",
|
|
50722
|
+
role: "fallback",
|
|
50723
|
+
...pdf.stale ? { stale: true } : {}
|
|
50724
|
+
}
|
|
50725
|
+
} : {},
|
|
50532
50726
|
...preview ? { preview } : {}
|
|
50533
50727
|
};
|
|
50534
50728
|
}
|
|
@@ -50557,7 +50751,11 @@ var AssetLocator = class {
|
|
|
50557
50751
|
}
|
|
50558
50752
|
return void 0;
|
|
50559
50753
|
}
|
|
50560
|
-
/**
|
|
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
|
+
*/
|
|
50561
50759
|
fallback(account, dir, id2, generation, names) {
|
|
50562
50760
|
const base = join19(account, dir, id2);
|
|
50563
50761
|
const gen = safeComponent2(generation);
|
|
@@ -50569,7 +50767,7 @@ var AssetLocator = class {
|
|
|
50569
50767
|
for (const g of generations)
|
|
50570
50768
|
for (const name of names) {
|
|
50571
50769
|
const path10 = confine(g ? join19(base, g, name) : join19(base, name), account);
|
|
50572
|
-
if (path10 && isFile(path10)) return path10;
|
|
50770
|
+
if (path10 && isFile(path10)) return { path: path10, stale: Boolean(gen) && g !== gen };
|
|
50573
50771
|
}
|
|
50574
50772
|
return void 0;
|
|
50575
50773
|
}
|
|
@@ -50726,6 +50924,9 @@ function readHead(fd) {
|
|
|
50726
50924
|
const n = readSync3(fd, head, 0, 16, 0);
|
|
50727
50925
|
return head.subarray(0, n);
|
|
50728
50926
|
}
|
|
50927
|
+
function directoryFailure(dir, error2) {
|
|
50928
|
+
return `Could not create the assets directory ${dir}: ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
50929
|
+
}
|
|
50729
50930
|
var SidecarWriter = class {
|
|
50730
50931
|
constructor(dir, linkBase) {
|
|
50731
50932
|
this.dir = dir;
|
|
@@ -50736,9 +50937,16 @@ var SidecarWriter = class {
|
|
|
50736
50937
|
placed = /* @__PURE__ */ new Map();
|
|
50737
50938
|
created = false;
|
|
50738
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;
|
|
50739
50946
|
place(asset) {
|
|
50740
50947
|
const done = this.placed.get(asset.path);
|
|
50741
50948
|
if (done) return done;
|
|
50949
|
+
if (this.directoryError) return { error: this.directoryError };
|
|
50742
50950
|
let source;
|
|
50743
50951
|
try {
|
|
50744
50952
|
source = openSource(asset.path);
|
|
@@ -50748,8 +50956,13 @@ var SidecarWriter = class {
|
|
|
50748
50956
|
try {
|
|
50749
50957
|
const mime = sniffMime(readHead(source.fd), asset.name);
|
|
50750
50958
|
if (!this.created) {
|
|
50751
|
-
|
|
50752
|
-
|
|
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
|
+
}
|
|
50753
50966
|
this.created = true;
|
|
50754
50967
|
}
|
|
50755
50968
|
const name = safeAssetName(asset.name, mime);
|
|
@@ -50902,7 +51115,10 @@ function titleBlockIndex(note) {
|
|
|
50902
51115
|
return first2.text.trim() === note.title.trim() && first2.style !== "monospaced" ? first2.index : -1;
|
|
50903
51116
|
}
|
|
50904
51117
|
function place(ctx, asset) {
|
|
50905
|
-
|
|
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;
|
|
50906
51122
|
}
|
|
50907
51123
|
function planAttachment(attachment, ctx) {
|
|
50908
51124
|
ctx.stats.attachments++;
|
|
@@ -51068,6 +51284,7 @@ function inlinePlanHtml(plan) {
|
|
|
51068
51284
|
}
|
|
51069
51285
|
}
|
|
51070
51286
|
function blockPlanHtml(plan) {
|
|
51287
|
+
if (!isHtmlBlockPlan(plan)) return `<p>${inlinePlanHtml(plan)}</p>`;
|
|
51071
51288
|
switch (plan.type) {
|
|
51072
51289
|
case "table":
|
|
51073
51290
|
return tableHtml(plan.rows);
|
|
@@ -51935,7 +52152,7 @@ function child(path10, key) {
|
|
|
51935
52152
|
if (key.length > MAX_QUOTED_TOKEN) key = `${key.slice(0, MAX_QUOTED_TOKEN - 3)}...`;
|
|
51936
52153
|
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key) ? `${path10}.${key}` : `${path10}[${JSON.stringify(key)}]`;
|
|
51937
52154
|
}
|
|
51938
|
-
var
|
|
52155
|
+
var isObject3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
51939
52156
|
var describe = (value) => value === null ? "null" : Array.isArray(value) ? "an array" : `a ${typeof value}`;
|
|
51940
52157
|
var describeVersion = (value) => typeof value === "number" && Number.isFinite(value) ? String(value) : describe(value);
|
|
51941
52158
|
var listed = (values) => values.map((v) => JSON.stringify(v)).join(", ");
|
|
@@ -52016,7 +52233,7 @@ var RULE_FIELDS = {
|
|
|
52016
52233
|
omit: []
|
|
52017
52234
|
};
|
|
52018
52235
|
function validateRule(c, rule, path10) {
|
|
52019
|
-
if (!
|
|
52236
|
+
if (!isObject3(rule)) {
|
|
52020
52237
|
c.add(path10, `must be an object, not ${describe(rule)}`);
|
|
52021
52238
|
return;
|
|
52022
52239
|
}
|
|
@@ -52063,7 +52280,7 @@ function validateInlineOrder(c, value, path10) {
|
|
|
52063
52280
|
if (missing.length) c.add(path10, `must list every inline format; missing ${listed(missing)}`);
|
|
52064
52281
|
}
|
|
52065
52282
|
function validateOptions(c, value, path10) {
|
|
52066
|
-
if (!
|
|
52283
|
+
if (!isObject3(value)) {
|
|
52067
52284
|
c.add(path10, `must be an object, not ${describe(value)}`);
|
|
52068
52285
|
return;
|
|
52069
52286
|
}
|
|
@@ -52084,7 +52301,7 @@ function validateOptions(c, value, path10) {
|
|
|
52084
52301
|
}
|
|
52085
52302
|
function templateErrors(input) {
|
|
52086
52303
|
const c = new Collector();
|
|
52087
|
-
if (!
|
|
52304
|
+
if (!isObject3(input)) {
|
|
52088
52305
|
c.add("$", `a template must be a JSON object, not ${describe(input)}`);
|
|
52089
52306
|
return c.errors;
|
|
52090
52307
|
}
|
|
@@ -52119,7 +52336,7 @@ function templateErrors(input) {
|
|
|
52119
52336
|
c.oneOf(value, path10, BUILTIN_TEMPLATE_NAMES);
|
|
52120
52337
|
break;
|
|
52121
52338
|
case "assets":
|
|
52122
|
-
if (!
|
|
52339
|
+
if (!isObject3(value)) {
|
|
52123
52340
|
c.add(path10, `must be an object, not ${describe(value)}`);
|
|
52124
52341
|
break;
|
|
52125
52342
|
}
|
|
@@ -52135,7 +52352,7 @@ function templateErrors(input) {
|
|
|
52135
52352
|
validateInlineOrder(c, value, path10);
|
|
52136
52353
|
break;
|
|
52137
52354
|
case "rules":
|
|
52138
|
-
if (!
|
|
52355
|
+
if (!isObject3(value)) {
|
|
52139
52356
|
c.add(path10, `must be an object keyed by rule id, not ${describe(value)}`);
|
|
52140
52357
|
break;
|
|
52141
52358
|
}
|
|
@@ -52765,16 +52982,26 @@ var HashedSidecarWriter = class {
|
|
|
52765
52982
|
/** Absolute paths of files written or reused. */
|
|
52766
52983
|
files = [];
|
|
52767
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. */
|
|
52768
52988
|
prepare() {
|
|
52769
|
-
if (this.ready) return;
|
|
52770
|
-
|
|
52771
|
-
|
|
52772
|
-
|
|
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
|
+
}
|
|
52773
52998
|
this.ready = true;
|
|
52999
|
+
return void 0;
|
|
52774
53000
|
}
|
|
52775
53001
|
place(asset) {
|
|
52776
53002
|
const done = this.placed.get(asset.path);
|
|
52777
53003
|
if (done) return done;
|
|
53004
|
+
if (this.directoryError) return { error: this.directoryError };
|
|
52778
53005
|
let source;
|
|
52779
53006
|
try {
|
|
52780
53007
|
source = openRegular(asset.path);
|
|
@@ -52784,7 +53011,8 @@ var HashedSidecarWriter = class {
|
|
|
52784
53011
|
try {
|
|
52785
53012
|
const { hash, head } = digest(source);
|
|
52786
53013
|
const mime = sniffMime(head, asset.name);
|
|
52787
|
-
this.prepare();
|
|
53014
|
+
const directoryError = this.prepare();
|
|
53015
|
+
if (directoryError) return { error: directoryError };
|
|
52788
53016
|
const name = safeAssetName(asset.name, mime);
|
|
52789
53017
|
const ext = extname4(name);
|
|
52790
53018
|
const target = join21(
|
|
@@ -53014,10 +53242,11 @@ function validPath(path10, what) {
|
|
|
53014
53242
|
function selectNotes(request, deps) {
|
|
53015
53243
|
if (!!request.id === !!request.folder)
|
|
53016
53244
|
throw new NotesExportError("invalid-request", "Provide exactly one of 'id' or 'folder'.");
|
|
53017
|
-
if (request.id) return [request.id];
|
|
53245
|
+
if (request.id) return { ids: [request.id], truncated: false };
|
|
53018
53246
|
const limit = Math.min(request.limit ?? DEFAULT_FOLDER_EXPORT_LIMIT, MAX_FOLDER_EXPORT_LIMIT);
|
|
53019
53247
|
try {
|
|
53020
|
-
|
|
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 };
|
|
53021
53250
|
} catch (error2) {
|
|
53022
53251
|
throw new NotesExportError(
|
|
53023
53252
|
"folder-unavailable",
|
|
@@ -53049,9 +53278,13 @@ function openOutput(output) {
|
|
|
53049
53278
|
throw error2;
|
|
53050
53279
|
}
|
|
53051
53280
|
}
|
|
53052
|
-
function renderInto(fd, render) {
|
|
53281
|
+
function renderInto(fd, render, writers = []) {
|
|
53053
53282
|
try {
|
|
53054
|
-
|
|
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;
|
|
53055
53288
|
} catch (error2) {
|
|
53056
53289
|
if (fd !== void 0) writeAllAndClose(fd, "");
|
|
53057
53290
|
throw error2;
|
|
@@ -53068,10 +53301,15 @@ function exportNotesMarkdown(request, deps) {
|
|
|
53068
53301
|
"invalid-request",
|
|
53069
53302
|
`assetsDir has no effect: template "${chosen.info.name}" sets assets.mode to "${chosen.template.assets.mode}".`
|
|
53070
53303
|
);
|
|
53071
|
-
const ids = selectNotes(request, deps);
|
|
53304
|
+
const { ids, truncated } = selectNotes(request, deps);
|
|
53072
53305
|
const { notes, skipped } = loadNotes(ids, !!request.id, deps.readNote);
|
|
53073
|
-
if (chosen)
|
|
53074
|
-
|
|
53306
|
+
if (chosen) {
|
|
53307
|
+
const receipt2 = exportWithTemplate(request, deps, chosen, notes, skipped, {
|
|
53308
|
+
output,
|
|
53309
|
+
assetsDir
|
|
53310
|
+
});
|
|
53311
|
+
return truncated ? { ...receipt2, truncated } : receipt2;
|
|
53312
|
+
}
|
|
53075
53313
|
const fd = output ? openOutput(output) : void 0;
|
|
53076
53314
|
const writer = assetsDir ? new SidecarWriter(assetsDir, output ? dirname6(output) : void 0) : void 0;
|
|
53077
53315
|
const ctx = {
|
|
@@ -53080,12 +53318,14 @@ function exportNotesMarkdown(request, deps) {
|
|
|
53080
53318
|
};
|
|
53081
53319
|
const markdown = renderInto(
|
|
53082
53320
|
fd,
|
|
53083
|
-
() => renderNotesMarkdown(notes, ctx, { wrap: request.wrap ?? 0 })
|
|
53321
|
+
() => renderNotesMarkdown(notes, ctx, { wrap: request.wrap ?? 0 }),
|
|
53322
|
+
writer ? [writer] : []
|
|
53084
53323
|
);
|
|
53085
53324
|
const bytes = Buffer.byteLength(markdown);
|
|
53086
53325
|
const receipt = {
|
|
53087
53326
|
format: "markdown",
|
|
53088
53327
|
count: notes.length,
|
|
53328
|
+
...truncated ? { truncated } : {},
|
|
53089
53329
|
bytes,
|
|
53090
53330
|
stats: ctx.stats,
|
|
53091
53331
|
skipped,
|
|
@@ -53121,7 +53361,7 @@ function exportNotesHtml(request, deps) {
|
|
|
53121
53361
|
const assetsDir = embed ? void 0 : validPath(request.assetsDir ?? defaultSidecarDir(output), "assetsDir");
|
|
53122
53362
|
if (assetsDir === output)
|
|
53123
53363
|
throw new NotesExportError("invalid-path", "outputPath and assetsDir must differ.");
|
|
53124
|
-
const ids = selectNotes(request, deps);
|
|
53364
|
+
const { ids, truncated } = selectNotes(request, deps);
|
|
53125
53365
|
const { notes, skipped } = loadNotes(ids, !!request.id, deps.readNote);
|
|
53126
53366
|
const fd = openOutput(output);
|
|
53127
53367
|
const writer = assetsDir ? new SidecarWriter(assetsDir, dirname6(output)) : new DataUrlWriter();
|
|
@@ -53131,11 +53371,16 @@ function exportNotesHtml(request, deps) {
|
|
|
53131
53371
|
locator: deps.locator ?? new AssetLocator()
|
|
53132
53372
|
};
|
|
53133
53373
|
const title = request.id ? notes[0]?.title || "Note" : request.folder;
|
|
53134
|
-
const html = renderInto(
|
|
53374
|
+
const html = renderInto(
|
|
53375
|
+
fd,
|
|
53376
|
+
() => renderNotesHtml(notes, ctx, { title }),
|
|
53377
|
+
writer instanceof SidecarWriter ? [writer] : []
|
|
53378
|
+
);
|
|
53135
53379
|
const bytes = writeAllAndClose(fd, html);
|
|
53136
53380
|
return {
|
|
53137
53381
|
format: "html",
|
|
53138
53382
|
count: notes.length,
|
|
53383
|
+
...truncated ? { truncated } : {},
|
|
53139
53384
|
bytes,
|
|
53140
53385
|
output,
|
|
53141
53386
|
stats: ctx.stats,
|
|
@@ -53217,7 +53462,7 @@ function exportWithTemplate(request, deps, chosen, notes, skipped, { output, ass
|
|
|
53217
53462
|
});
|
|
53218
53463
|
warnings = result.warnings;
|
|
53219
53464
|
return result.markdown;
|
|
53220
|
-
});
|
|
53465
|
+
}, [...writers.values()]);
|
|
53221
53466
|
const bytes = Buffer.byteLength(markdown);
|
|
53222
53467
|
const used = [...writers.values()].filter((writer) => writer.count > 0);
|
|
53223
53468
|
const files = used.flatMap((writer) => writer.files);
|
|
@@ -53258,7 +53503,6 @@ import {
|
|
|
53258
53503
|
fstatSync as fstatSync7,
|
|
53259
53504
|
mkdtempSync as mkdtempSync6,
|
|
53260
53505
|
openSync as openSync7,
|
|
53261
|
-
readFileSync as readFileSync4,
|
|
53262
53506
|
readSync as readSync5,
|
|
53263
53507
|
rmSync as rmSync6,
|
|
53264
53508
|
writeFileSync as writeFileSync5
|
|
@@ -53284,12 +53528,12 @@ import { basename as basename5, extname as extname6, join as join23 } from "node
|
|
|
53284
53528
|
var PASTEBOARD_NAME_ENV = "APPLE_NOTES_MCP_PASTEBOARD_NAME";
|
|
53285
53529
|
var MAX_PASTEBOARD_BYTES = 64 * 1024 * 1024;
|
|
53286
53530
|
var PASTEBOARD_DATA_TYPES = [
|
|
53531
|
+
{ type: "com.adobe.pdf", ext: "pdf", label: "document" },
|
|
53287
53532
|
{ type: "public.png", ext: "png", label: "image" },
|
|
53288
53533
|
{ type: "public.jpeg", ext: "jpg", label: "image" },
|
|
53289
53534
|
{ type: "public.heic", ext: "heic", label: "image" },
|
|
53290
53535
|
{ type: "com.compuserve.gif", ext: "gif", label: "image" },
|
|
53291
|
-
{ type: "public.tiff", ext: "tiff", label: "image" }
|
|
53292
|
-
{ type: "com.adobe.pdf", ext: "pdf", label: "document" }
|
|
53536
|
+
{ type: "public.tiff", ext: "tiff", label: "image" }
|
|
53293
53537
|
];
|
|
53294
53538
|
var PASTEBOARD_ACCESS_BEHAVIORS = {
|
|
53295
53539
|
0: "default",
|
|
@@ -53316,15 +53560,26 @@ function run(argv) {
|
|
|
53316
53560
|
var items = pb.pasteboardItems;
|
|
53317
53561
|
var itemCount = items && !items.isNil() ? Number(items.count) : 0;
|
|
53318
53562
|
var fileUrls = [];
|
|
53563
|
+
var dataItems = 0;
|
|
53319
53564
|
for (var k = 0; k < itemCount; k++) {
|
|
53320
53565
|
var item = items.objectAtIndex(k);
|
|
53321
53566
|
var itemTypes = ObjC.deepUnwrap(item.types) || [];
|
|
53322
|
-
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
|
+
}
|
|
53323
53576
|
var value = ObjC.unwrap(item.stringForType("public.file-url"));
|
|
53324
53577
|
if (value) fileUrls.push(value);
|
|
53325
53578
|
}
|
|
53326
53579
|
if (fileUrls.length > 1)
|
|
53327
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 });
|
|
53328
53583
|
if (fileUrls.length === 1) {
|
|
53329
53584
|
var url = $.NSURL.URLWithString(fileUrls[0]);
|
|
53330
53585
|
if (url && !url.isNil() && url.isFileURL) {
|
|
@@ -53355,6 +53610,7 @@ var ENVELOPE_CODES = {
|
|
|
53355
53610
|
pasteboard_changed: "operation_failed",
|
|
53356
53611
|
unsupported_content: "validation_error",
|
|
53357
53612
|
multiple_files: "validation_error",
|
|
53613
|
+
multiple_items: "validation_error",
|
|
53358
53614
|
too_large: "validation_error",
|
|
53359
53615
|
write_failed: "operation_failed",
|
|
53360
53616
|
file_unreadable: "validation_error"
|
|
@@ -53381,6 +53637,7 @@ var MESSAGES = {
|
|
|
53381
53637
|
pasteboard_changed: "The pasteboard changed while it was being read. Try again.",
|
|
53382
53638
|
unsupported_content: `The pasteboard holds no supported content: copy ${SUPPORTED}. Text belongs in append-to-note, not in an attachment.`,
|
|
53383
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.",
|
|
53384
53641
|
too_large: "The pasteboard contents exceed the 64 MiB attachment limit.",
|
|
53385
53642
|
write_failed: "Could not write the pasteboard contents to a temporary file.",
|
|
53386
53643
|
file_unreadable: "The copied file could not be read as a regular file of at most 64 MiB."
|
|
@@ -53392,13 +53649,10 @@ function replyError(code, reply) {
|
|
|
53392
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;
|
|
53393
53650
|
return new PasteboardError(code, message, { accessBehavior });
|
|
53394
53651
|
}
|
|
53395
|
-
if (code === "multiple_files") {
|
|
53652
|
+
if (code === "multiple_files" || code === "multiple_items") {
|
|
53396
53653
|
const count = typeof reply.count === "number" ? reply.count : void 0;
|
|
53397
|
-
|
|
53398
|
-
|
|
53399
|
-
count ? `The pasteboard holds ${count} copied files. Copy exactly one file, or attach each file with add-attachment.` : MESSAGES[code],
|
|
53400
|
-
count ? { count } : {}
|
|
53401
|
-
);
|
|
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 } : {});
|
|
53402
53656
|
}
|
|
53403
53657
|
if (code === "unsupported_content" && Array.isArray(reply.types)) {
|
|
53404
53658
|
const types = reply.types.filter((t) => typeof t === "string").slice(0, 20);
|
|
@@ -53538,17 +53792,14 @@ function assertExistingContentPreserved(before, after) {
|
|
|
53538
53792
|
}
|
|
53539
53793
|
function localAttachment(path10) {
|
|
53540
53794
|
if (!isAbsolute4(path10)) throw new Error("An absolute local file path is required");
|
|
53541
|
-
const descriptor = openSync7(path10, constants7.O_RDONLY | constants7.O_NOFOLLOW);
|
|
53542
53795
|
try {
|
|
53543
|
-
|
|
53544
|
-
|
|
53545
|
-
|
|
53546
|
-
|
|
53547
|
-
|
|
53548
|
-
|
|
53549
|
-
|
|
53550
|
-
} finally {
|
|
53551
|
-
closeSync7(descriptor);
|
|
53796
|
+
return readAllowedFile(path10, MAX_ADD_ATTACHMENT_BYTES, { label: "Attachment" });
|
|
53797
|
+
} catch (error2) {
|
|
53798
|
+
throw new CodedError(error2 instanceof Error ? error2.message : String(error2), {
|
|
53799
|
+
code: "validation_error",
|
|
53800
|
+
committed: false,
|
|
53801
|
+
indeterminate: false
|
|
53802
|
+
});
|
|
53552
53803
|
}
|
|
53553
53804
|
}
|
|
53554
53805
|
var MAX_ADD_ATTACHMENT_BYTES = 64 * 1024 * 1024;
|
|
@@ -53614,7 +53865,10 @@ function registerDirectOperations(server2, manager) {
|
|
|
53614
53865
|
{
|
|
53615
53866
|
id: folderId,
|
|
53616
53867
|
expectedName: external_exports.string().max(1e3),
|
|
53617
|
-
|
|
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,
|
|
53618
53872
|
newName: external_exports.string().min(1).max(1e3)
|
|
53619
53873
|
},
|
|
53620
53874
|
(args) => ({
|
|
@@ -53623,20 +53877,22 @@ function registerDirectOperations(server2, manager) {
|
|
|
53623
53877
|
})
|
|
53624
53878
|
);
|
|
53625
53879
|
const attachmentInput = {
|
|
53626
|
-
path: external_exports.string().min(1).max(4096).describe(
|
|
53880
|
+
path: external_exports.string().min(1).max(4096).describe(
|
|
53881
|
+
"Absolute path of the local regular file to attach, in home, temp or /Volumes; hidden paths and ~/Library (except iCloud Drive and CloudStorage) are refused"
|
|
53882
|
+
),
|
|
53627
53883
|
filename: external_exports.string().min(1).max(255).optional().describe(
|
|
53628
53884
|
"Name the attachment gets in Notes instead of the source file's name. One path component with the source file's extension; no slash, colon, or control characters, and no leading dot."
|
|
53629
53885
|
)
|
|
53630
53886
|
};
|
|
53631
53887
|
tool(
|
|
53632
53888
|
"add-attachment",
|
|
53633
|
-
"Use when: adding one local file to an exact note without replacing its body.\nReturns: the new attachment id, byte count, attachment name, and post-write content hash after exact byte verification.\nDo not use when: reading or exporting an existing attachment.\nSafety: requires a fresh rich revision, copies at most 64 MiB through a private temporary file, never retries insertion, and verifies existing content plus fetched bytes. On macOS 27 Notes' AppleScript does not list PDF attachments; with Full Disk Access the new attachment is verified through the read-only NoteStore database instead (verifiedBy: database), otherwise the outcome is reported as uncertain.",
|
|
53889
|
+
"Use when: adding one local file to an exact note without replacing its body.\nReturns: the new attachment id, byte count, attachment name, and post-write content hash after exact byte verification.\nDo not use when: reading or exporting an existing attachment.\nSafety: reads only a regular file in home, temp or /Volumes, refusing hidden paths (~/.ssh, .env) and ~/Library outside iCloud Drive and CloudStorage unless the server sets APPLE_NOTES_MCP_ALLOW_PRIVATE_CONTENT_PATHS=1; requires a fresh rich revision, copies at most 64 MiB through a private temporary file, never retries insertion, and verifies existing content plus fetched bytes. On macOS 27 Notes' AppleScript does not list PDF attachments; with Full Disk Access the new attachment is verified through the read-only NoteStore database instead (verifiedBy: database), otherwise the outcome is reported as uncertain.",
|
|
53634
53890
|
{ id: noteId, expectedContentHash: revision, ...attachmentInput },
|
|
53635
53891
|
(args) => attachFile(manager, args)
|
|
53636
53892
|
);
|
|
53637
53893
|
tool(
|
|
53638
53894
|
"create-note-with-attachment",
|
|
53639
|
-
"Use when: creating a new note that holds one local file, in one call.\nReturns: the new note id plus the add-attachment result (attachment id, bytes, name, content hash).\nDo not use when: the note already exists (add-attachment).\nSafety: checks the file and filename before creating anything, creates the note through Notes.app like create-note, then attaches with the same byte verification as add-attachment. If the attachment step fails before the file is inserted, the error names the new note's id; attach to it with add-attachment instead of creating another note. If insertion started but could not be verified, the outcome is uncertain: read the note with list-attachments before attaching again.",
|
|
53895
|
+
"Use when: creating a new note that holds one local file, in one call.\nReturns: the new note id plus the add-attachment result (attachment id, bytes, name, content hash).\nDo not use when: the note already exists (add-attachment).\nSafety: checks the file and filename before creating anything, with the same read scope as add-attachment (home, temp or /Volumes; no hidden paths or ~/Library outside iCloud Drive and CloudStorage), creates the note through Notes.app like create-note, then attaches with the same byte verification as add-attachment. If the attachment step fails before the file is inserted, the error names the new note's id; attach to it with add-attachment instead of creating another note. If insertion started but could not be verified, the outcome is uncertain: read the note with list-attachments before attaching again.",
|
|
53640
53896
|
{
|
|
53641
53897
|
title: external_exports.string().min(1).max(2e3).refine((s) => !/[\r\n\0]/u.test(s), "One-line title"),
|
|
53642
53898
|
content: external_exports.string().min(1).max(1024 * 1024).optional().describe("Optional plain-text body placed above the attachment"),
|
|
@@ -54015,7 +54271,9 @@ function readFolderStoreFacts(pk, dbPath2 = NOTE_STORE_PATH) {
|
|
|
54015
54271
|
|
|
54016
54272
|
// src/tools/folderDelete.ts
|
|
54017
54273
|
var folderIdSchema = external_exports.string().max(2e3).transform(looseIdTransform("ICFolder"));
|
|
54018
|
-
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
|
+
);
|
|
54019
54277
|
var revisionSchema = external_exports.string().regex(/^sha256:[a-f0-9]{64}$/);
|
|
54020
54278
|
var defaultDeps = {
|
|
54021
54279
|
readStore: (pk) => readFolderStoreFacts(pk),
|
|
@@ -57408,7 +57666,7 @@ import {
|
|
|
57408
57666
|
existsSync as existsSync14,
|
|
57409
57667
|
mkdirSync as mkdirSync8,
|
|
57410
57668
|
mkdtempSync as mkdtempSync7,
|
|
57411
|
-
readFileSync as
|
|
57669
|
+
readFileSync as readFileSync4,
|
|
57412
57670
|
renameSync as renameSync2,
|
|
57413
57671
|
rmSync as rmSync7,
|
|
57414
57672
|
writeFileSync as writeFileSync6
|
|
@@ -57445,7 +57703,7 @@ function packageRoot(fromDir = dirname8(fileURLToPath2(import.meta.url))) {
|
|
|
57445
57703
|
const candidate = join27(dir, "package.json");
|
|
57446
57704
|
if (existsSync14(candidate)) {
|
|
57447
57705
|
try {
|
|
57448
|
-
if (JSON.parse(
|
|
57706
|
+
if (JSON.parse(readFileSync4(candidate, "utf8")).name === "apple-notes-mcp")
|
|
57449
57707
|
return dir;
|
|
57450
57708
|
} catch {
|
|
57451
57709
|
}
|
|
@@ -57461,7 +57719,7 @@ function defaultPublicHelperDeps(overrides = {}) {
|
|
|
57461
57719
|
platform: process.platform,
|
|
57462
57720
|
sourcePath: join27(packageRoot(), PUBLIC_HELPER_SOURCE),
|
|
57463
57721
|
exists: existsSync14,
|
|
57464
|
-
readFile: (path10) =>
|
|
57722
|
+
readFile: (path10) => readFileSync4(path10),
|
|
57465
57723
|
spawn: spawnSync3,
|
|
57466
57724
|
spawnAsync: spawn,
|
|
57467
57725
|
...overrides
|
|
@@ -58000,14 +58258,17 @@ var strokeSchema = external_exports.object({
|
|
|
58000
58258
|
force: external_exports.number()
|
|
58001
58259
|
})
|
|
58002
58260
|
).optional(),
|
|
58003
|
-
transformApplied: external_exports.boolean().optional()
|
|
58261
|
+
transformApplied: external_exports.boolean().optional(),
|
|
58262
|
+
masked: external_exports.boolean().optional(),
|
|
58263
|
+
pointsTruncated: external_exports.boolean().optional()
|
|
58004
58264
|
}).strip();
|
|
58005
58265
|
var decodedDrawingSchema = external_exports.object({
|
|
58006
58266
|
status: external_exports.literal("ok"),
|
|
58007
58267
|
strokeCount: external_exports.number().int(),
|
|
58008
58268
|
strokes: external_exports.array(strokeSchema),
|
|
58009
58269
|
truncated: external_exports.boolean(),
|
|
58010
|
-
bounds
|
|
58270
|
+
bounds,
|
|
58271
|
+
hiddenStrokeCount: external_exports.number().int().optional()
|
|
58011
58272
|
});
|
|
58012
58273
|
function decodeRow(row, format, includePoints, deps) {
|
|
58013
58274
|
const base = {
|
|
@@ -58040,7 +58301,8 @@ function decodeRow(row, format, includePoints, deps) {
|
|
|
58040
58301
|
status: "ok",
|
|
58041
58302
|
strokeCount: decoded.strokeCount,
|
|
58042
58303
|
bounds: decoded.bounds,
|
|
58043
|
-
truncated: decoded.truncated
|
|
58304
|
+
truncated: decoded.truncated,
|
|
58305
|
+
...decoded.hiddenStrokeCount ? { hiddenStrokeCount: decoded.hiddenStrokeCount } : {}
|
|
58044
58306
|
};
|
|
58045
58307
|
if (format !== "json") result.svg = drawingToSvg(strokes, decoded.bounds);
|
|
58046
58308
|
if (format !== "svg")
|
|
@@ -58065,6 +58327,28 @@ function getNoteDrawings(noteId3, options = {}) {
|
|
|
58065
58327
|
drawings
|
|
58066
58328
|
};
|
|
58067
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
|
+
}
|
|
58068
58352
|
function formatNoteDrawings(result) {
|
|
58069
58353
|
if (result.drawingCount === 0) return `No classic PencilKit drawings in note ${result.id}.`;
|
|
58070
58354
|
const lines = [
|
|
@@ -58072,7 +58356,7 @@ function formatNoteDrawings(result) {
|
|
|
58072
58356
|
];
|
|
58073
58357
|
for (const d of result.drawings)
|
|
58074
58358
|
lines.push(
|
|
58075
|
-
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}`
|
|
58076
58360
|
);
|
|
58077
58361
|
return lines.join("\n");
|
|
58078
58362
|
}
|
|
@@ -58172,9 +58456,6 @@ function readAudioAssets(noteId3, options = {}) {
|
|
|
58172
58456
|
};
|
|
58173
58457
|
});
|
|
58174
58458
|
}
|
|
58175
|
-
function countWords2(text2) {
|
|
58176
|
-
return text2.split(/\s+/u).filter((w) => /[\p{L}\p{N}]/u.test(w)).length;
|
|
58177
|
-
}
|
|
58178
58459
|
|
|
58179
58460
|
// src/services/noteTranscription.ts
|
|
58180
58461
|
var DEFAULT_TRANSCRIPTION_LOCALE = "en-US";
|
|
@@ -58189,6 +58470,7 @@ var BUDGET_MARGIN_MS = 1e4;
|
|
|
58189
58470
|
var MIN_TAKE_SECONDS = 5;
|
|
58190
58471
|
var CALL_WIDE_CODES = /* @__PURE__ */ new Set([
|
|
58191
58472
|
"permission_required",
|
|
58473
|
+
"permission_not_requested",
|
|
58192
58474
|
"asset_unavailable",
|
|
58193
58475
|
"unsupported_locale",
|
|
58194
58476
|
"speech_unavailable"
|
|
@@ -58267,7 +58549,7 @@ async function transcribeTake(take, ctx) {
|
|
|
58267
58549
|
status: complete ? "ok" : text2 ? "partial" : "indeterminate",
|
|
58268
58550
|
...complete ? {} : { code: "incomplete", message: stopReason ?? "stopped early" },
|
|
58269
58551
|
...durationSeconds !== void 0 ? { durationSeconds } : {},
|
|
58270
|
-
wordCount:
|
|
58552
|
+
wordCount: countWords(text2),
|
|
58271
58553
|
...engine ? { engine } : {}
|
|
58272
58554
|
},
|
|
58273
58555
|
text: text2
|
|
@@ -58294,7 +58576,7 @@ async function transcribeRecording(asset, includeText, ctx) {
|
|
|
58294
58576
|
status,
|
|
58295
58577
|
...status !== "ok" && firstProblem?.code ? { code: firstProblem.code, message: firstProblem.message } : {},
|
|
58296
58578
|
...asset.durationSeconds !== null ? { durationSeconds: Math.round(asset.durationSeconds) } : {},
|
|
58297
|
-
wordCount:
|
|
58579
|
+
wordCount: countWords(transcript),
|
|
58298
58580
|
...includeText ? { transcript } : {},
|
|
58299
58581
|
takes: outcomes.map((o) => o.take)
|
|
58300
58582
|
};
|
|
@@ -58349,24 +58631,29 @@ async function transcribeNoteAudio(noteId3, options = {}) {
|
|
|
58349
58631
|
}
|
|
58350
58632
|
function fitTranscriptions(result, maxBytes, measure = (r) => Buffer.byteLength(JSON.stringify(r))) {
|
|
58351
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
|
+
});
|
|
58352
58644
|
let next = result;
|
|
58353
58645
|
for (let share = 0.5; measure(next) > maxBytes && share > 1e-4; share /= 2) {
|
|
58354
|
-
next =
|
|
58355
|
-
...result,
|
|
58356
|
-
recordings: result.recordings.map(
|
|
58357
|
-
(r) => r.transcript ? {
|
|
58358
|
-
...r,
|
|
58359
|
-
transcript: r.transcript.slice(0, Math.floor(r.transcript.length * share)),
|
|
58360
|
-
transcriptTruncated: true
|
|
58361
|
-
} : r
|
|
58362
|
-
)
|
|
58363
|
-
};
|
|
58646
|
+
next = shorten(share);
|
|
58364
58647
|
}
|
|
58648
|
+
if (measure(next) > maxBytes) next = { ...shorten(0), responseOversized: true };
|
|
58365
58649
|
return next;
|
|
58366
58650
|
}
|
|
58367
58651
|
function formatTranscription(result) {
|
|
58368
58652
|
if (result.recordingCount === 0) return `No audio attachments in note ${result.id}.`;
|
|
58369
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
|
+
] : [],
|
|
58370
58657
|
`${result.recordingCount} audio attachment${result.recordingCount === 1 ? "" : "s"} in note ${result.id} (${result.status}, locale ${result.locale}):`
|
|
58371
58658
|
];
|
|
58372
58659
|
result.recordings.forEach((r, i) => {
|
|
@@ -58401,7 +58688,7 @@ import { join as join30 } from "node:path";
|
|
|
58401
58688
|
// src/services/privateHelper.ts
|
|
58402
58689
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
58403
58690
|
import { createHash as createHash7 } from "node:crypto";
|
|
58404
|
-
import { existsSync as existsSync15, readFileSync as
|
|
58691
|
+
import { existsSync as existsSync15, readFileSync as readFileSync5 } from "node:fs";
|
|
58405
58692
|
import { homedir as homedir21 } from "node:os";
|
|
58406
58693
|
import { dirname as dirname9, join as join29, resolve as resolve8 } from "node:path";
|
|
58407
58694
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
@@ -58434,7 +58721,7 @@ function packageRoot2(fromDir = dirname9(fileURLToPath3(import.meta.url))) {
|
|
|
58434
58721
|
const candidate = join29(dir, "package.json");
|
|
58435
58722
|
if (existsSync15(candidate)) {
|
|
58436
58723
|
try {
|
|
58437
|
-
const pkg = JSON.parse(
|
|
58724
|
+
const pkg = JSON.parse(readFileSync5(candidate, "utf8"));
|
|
58438
58725
|
if (pkg.name === "apple-notes-mcp") return dir;
|
|
58439
58726
|
} catch {
|
|
58440
58727
|
}
|
|
@@ -58450,7 +58737,7 @@ function defaultDeps2(overrides = {}) {
|
|
|
58450
58737
|
platform: process.platform,
|
|
58451
58738
|
sourcePath: join29(packageRoot2(), HELPER_SOURCE_RELATIVE),
|
|
58452
58739
|
exists: existsSync15,
|
|
58453
|
-
readFile: (path10) =>
|
|
58740
|
+
readFile: (path10) => readFileSync5(path10),
|
|
58454
58741
|
spawn: spawnSync4,
|
|
58455
58742
|
...overrides
|
|
58456
58743
|
};
|
|
@@ -59238,10 +59525,11 @@ function prepareDeleteGuards(args) {
|
|
|
59238
59525
|
if (guardNoteId === void 0 !== (expectedGuardContentHash === void 0)) {
|
|
59239
59526
|
return { error: "Pass guardNoteId and expectedGuardContentHash together." };
|
|
59240
59527
|
}
|
|
59241
|
-
|
|
59528
|
+
const same = (a, b) => a !== void 0 && b !== void 0 && canonicalCoreDataId(a) === canonicalCoreDataId(b);
|
|
59529
|
+
if (same(guardNoteId, id2) || same(requireActiveNoteId, id2)) {
|
|
59242
59530
|
return { error: "A guard note must be a different note from the one being deleted." };
|
|
59243
59531
|
}
|
|
59244
|
-
if (guardNoteId
|
|
59532
|
+
if (same(guardNoteId, requireActiveNoteId)) {
|
|
59245
59533
|
return { error: "requireActiveNoteId repeats guardNoteId; pass only guardNoteId." };
|
|
59246
59534
|
}
|
|
59247
59535
|
const prepared = { guards: [], labels: [] };
|
|
@@ -59588,7 +59876,7 @@ ${noteList}${truncationNote}${scanNote}${wordCountNote}${syncNote}`,
|
|
|
59588
59876
|
registerTool(
|
|
59589
59877
|
"query-notes",
|
|
59590
59878
|
{
|
|
59591
|
-
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.',
|
|
59592
59880
|
inputSchema: {
|
|
59593
59881
|
query: external_exports.string().min(1, "A query expression is required").max(MAX.QUERY).describe(
|
|
59594
59882
|
'Boolean query expression, e.g. `folder:"Work Projects" has:checklist -checklist:done`'
|
|
@@ -59641,7 +59929,7 @@ registerTool(
|
|
|
59641
59929
|
}
|
|
59642
59930
|
if (result.unreadable > 0) {
|
|
59643
59931
|
notes.push(
|
|
59644
|
-
`\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.`
|
|
59645
59933
|
);
|
|
59646
59934
|
}
|
|
59647
59935
|
const footer = notes.length ? `
|
|
@@ -60044,7 +60332,7 @@ registerTool(
|
|
|
60044
60332
|
if (!note) return notFoundResponse(`Note with ID "${id2}" not found`);
|
|
60045
60333
|
const body = notesManager.getNoteContentById(id2);
|
|
60046
60334
|
if (!body) return errorResponse(`Failed to read content of note "${note.title}"`);
|
|
60047
|
-
const rich = readRichNote(id2);
|
|
60335
|
+
const rich = readRichNote(id2, { skipUnsafeLinks: true });
|
|
60048
60336
|
const tables = (rich.objectData || []).filter((object3) => object3.type?.includes("table")).map((object3) => {
|
|
60049
60337
|
try {
|
|
60050
60338
|
return {
|
|
@@ -61654,6 +61942,7 @@ registerTool(
|
|
|
61654
61942
|
height: external_exports.number().optional(),
|
|
61655
61943
|
bytes: external_exports.number().optional(),
|
|
61656
61944
|
source: external_exports.enum(["fallback", "preview"]).optional(),
|
|
61945
|
+
stale: external_exports.boolean().optional(),
|
|
61657
61946
|
attachmentId: external_exports.string().optional(),
|
|
61658
61947
|
identifier: external_exports.string().optional(),
|
|
61659
61948
|
kind: external_exports.enum(["paper", "drawing"]).optional(),
|
|
@@ -61662,8 +61951,9 @@ registerTool(
|
|
|
61662
61951
|
},
|
|
61663
61952
|
withErrorHandling(({ noteId: noteId3, savePath, attachmentId }) => {
|
|
61664
61953
|
const r = notesManager.exportPaperImageById(noteId3, savePath, attachmentId);
|
|
61954
|
+
const stale = r.source === "fallback" && r.drawing.fallbackImageStale;
|
|
61665
61955
|
return successResponse(
|
|
61666
|
-
`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." : ""),
|
|
61667
61957
|
{
|
|
61668
61958
|
savedPath: r.savedPath,
|
|
61669
61959
|
format: r.format,
|
|
@@ -61671,6 +61961,7 @@ registerTool(
|
|
|
61671
61961
|
height: r.height,
|
|
61672
61962
|
bytes: r.bytes,
|
|
61673
61963
|
source: r.source,
|
|
61964
|
+
...stale ? { stale } : {},
|
|
61674
61965
|
attachmentId: attachmentCoreDataId(noteId3, r.drawing.pk),
|
|
61675
61966
|
identifier: r.drawing.identifier,
|
|
61676
61967
|
kind: r.drawing.kind,
|
|
@@ -61683,7 +61974,7 @@ registerTool(
|
|
|
61683
61974
|
"export-attachments",
|
|
61684
61975
|
{
|
|
61685
61976
|
description: `Use when: copying every file attachment of one note (or only its lead visual) into a directory on disk.
|
|
61686
|
-
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.
|
|
61687
61978
|
Do not use when: exporting one attachment to an exact path (save-attachment) or reading bytes inline (fetch-attachment).
|
|
61688
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.`,
|
|
61689
61980
|
inputSchema: {
|
|
@@ -61695,6 +61986,7 @@ Safety: writes files; exportDir must be absolute and under the home directory, a
|
|
|
61695
61986
|
exportDir: external_exports.string().optional(),
|
|
61696
61987
|
exported: external_exports.number().optional(),
|
|
61697
61988
|
previews: external_exports.number().optional(),
|
|
61989
|
+
fallbacks: external_exports.number().optional(),
|
|
61698
61990
|
skipped: external_exports.number().optional(),
|
|
61699
61991
|
failed: external_exports.number().optional(),
|
|
61700
61992
|
results: external_exports.array(external_exports.object({}).passthrough()).optional(),
|
|
@@ -61709,12 +62001,14 @@ Safety: writes files; exportDir must be absolute and under the home directory, a
|
|
|
61709
62001
|
}));
|
|
61710
62002
|
const exported = results.filter((x) => x.exportedKind !== null).length;
|
|
61711
62003
|
const previews = results.filter((x) => x.exportedKind === "preview").length;
|
|
62004
|
+
const fallbacks = results.filter((x) => x.exportedKind === "fallback").length;
|
|
61712
62005
|
const failed = results.filter((x) => x.error).length;
|
|
61713
62006
|
const skipped = results.length - exported - failed;
|
|
61714
62007
|
const structured = {
|
|
61715
62008
|
exportDir: r.exportDir,
|
|
61716
62009
|
exported,
|
|
61717
62010
|
previews,
|
|
62011
|
+
fallbacks,
|
|
61718
62012
|
skipped,
|
|
61719
62013
|
failed,
|
|
61720
62014
|
results
|
|
@@ -61728,7 +62022,7 @@ Safety: writes files; exportDir must be absolute and under the home directory, a
|
|
|
61728
62022
|
);
|
|
61729
62023
|
}
|
|
61730
62024
|
}
|
|
61731
|
-
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).`;
|
|
61732
62026
|
if (exported === 0 && failed > 0) {
|
|
61733
62027
|
const error2 = errorResponse(summary, new CodedError(summary, { code: "operation_failed" }));
|
|
61734
62028
|
return { ...error2, structuredContent: { ...structured, ...error2.structuredContent } };
|
|
@@ -61909,7 +62203,8 @@ var exportStatsSchema = external_exports.object({
|
|
|
61909
62203
|
unavailable: external_exports.number(),
|
|
61910
62204
|
tables: external_exports.number(),
|
|
61911
62205
|
unreadableTables: external_exports.number(),
|
|
61912
|
-
unreferenced: external_exports.number()
|
|
62206
|
+
unreferenced: external_exports.number(),
|
|
62207
|
+
staleRenderings: external_exports.number().optional()
|
|
61913
62208
|
});
|
|
61914
62209
|
registerTool(
|
|
61915
62210
|
"export-notes-markdown",
|
|
@@ -61935,6 +62230,7 @@ registerTool(
|
|
|
61935
62230
|
outputSchema: {
|
|
61936
62231
|
format: external_exports.string().optional(),
|
|
61937
62232
|
count: external_exports.number().optional(),
|
|
62233
|
+
truncated: external_exports.boolean().optional(),
|
|
61938
62234
|
bytes: external_exports.number().optional(),
|
|
61939
62235
|
markdown: external_exports.string().optional(),
|
|
61940
62236
|
output: external_exports.string().optional(),
|
|
@@ -61973,7 +62269,7 @@ registerTool(
|
|
|
61973
62269
|
);
|
|
61974
62270
|
}
|
|
61975
62271
|
const warned = receipt.warnings?.length ? `; ${receipt.warnings.length + (receipt.warningsOmitted ?? 0)} warning(s)` : "";
|
|
61976
|
-
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" : "");
|
|
61977
62273
|
if (receipt.output)
|
|
61978
62274
|
return successResponse(
|
|
61979
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}.`,
|
|
@@ -62004,6 +62300,7 @@ registerTool(
|
|
|
62004
62300
|
outputSchema: {
|
|
62005
62301
|
format: external_exports.string().optional(),
|
|
62006
62302
|
count: external_exports.number().optional(),
|
|
62303
|
+
truncated: external_exports.boolean().optional(),
|
|
62007
62304
|
bytes: external_exports.number().optional(),
|
|
62008
62305
|
output: external_exports.string().optional(),
|
|
62009
62306
|
assets: external_exports.object({ dir: external_exports.string(), files: external_exports.number() }).optional(),
|
|
@@ -62026,7 +62323,7 @@ registerTool(
|
|
|
62026
62323
|
return errorResponse(`Error exporting HTML [${error2.code}]: ${error2.message}${hint}`, error2);
|
|
62027
62324
|
}
|
|
62028
62325
|
const assets = receipt.assets ? `; copied ${receipt.assets.files} asset file(s) to ${receipt.assets.dir}` : `; embedded ${receipt.embedded ?? 0} asset(s)`;
|
|
62029
|
-
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" : "");
|
|
62030
62327
|
return successResponse(
|
|
62031
62328
|
`Wrote ${receipt.count} note(s) as HTML (${receipt.bytes} bytes) to ${receipt.output}${assets}${skipped}.`,
|
|
62032
62329
|
{ ...receipt }
|
|
@@ -62209,27 +62506,32 @@ registerTool(
|
|
|
62209
62506
|
drawingCount: external_exports.number().optional(),
|
|
62210
62507
|
status: external_exports.string().optional(),
|
|
62211
62508
|
drawings: external_exports.array(external_exports.object({}).passthrough()).optional(),
|
|
62212
|
-
pointsOmitted: external_exports.boolean().optional()
|
|
62509
|
+
pointsOmitted: external_exports.boolean().optional(),
|
|
62510
|
+
svgOmitted: external_exports.boolean().optional()
|
|
62213
62511
|
}
|
|
62214
62512
|
},
|
|
62215
62513
|
withErrorHandling(({ id: id2, format, includePoints }) => {
|
|
62216
|
-
|
|
62217
|
-
|
|
62218
|
-
|
|
62219
|
-
|
|
62220
|
-
|
|
62221
|
-
|
|
62222
|
-
|
|
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)." : "");
|
|
62223
62524
|
return successResponse(text2, {
|
|
62224
62525
|
...result,
|
|
62225
|
-
...pointsOmitted ? { pointsOmitted } : {}
|
|
62526
|
+
...pointsOmitted ? { pointsOmitted } : {},
|
|
62527
|
+
...svgOmitted ? { svgOmitted } : {}
|
|
62226
62528
|
});
|
|
62227
62529
|
}, "Error reading drawings")
|
|
62228
62530
|
);
|
|
62229
62531
|
registerTool(
|
|
62230
62532
|
"transcribe-note-audio",
|
|
62231
62533
|
{
|
|
62232
|
-
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.",
|
|
62233
62535
|
inputSchema: {
|
|
62234
62536
|
id: noteIdInput,
|
|
62235
62537
|
locale: external_exports.string().max(35).optional().describe('BCP-47 language of the speech, e.g. "en-US" (default), "it-IT", "fr-FR"'),
|
|
@@ -62247,11 +62549,13 @@ registerTool(
|
|
|
62247
62549
|
locale: external_exports.string().optional(),
|
|
62248
62550
|
status: external_exports.string().optional(),
|
|
62249
62551
|
recordingCount: external_exports.number().optional(),
|
|
62250
|
-
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()
|
|
62251
62554
|
}
|
|
62252
62555
|
},
|
|
62253
62556
|
withAsyncErrorHandling(async (params, signal) => {
|
|
62254
62557
|
const { id: id2, locale, attachmentId, includeText, downloadAssets, maxSeconds } = params;
|
|
62558
|
+
const toResponse = (r) => successResponse(formatTranscription(r), r);
|
|
62255
62559
|
const result = fitTranscriptions(
|
|
62256
62560
|
await transcribeNoteAudio(id2, {
|
|
62257
62561
|
locale,
|
|
@@ -62261,12 +62565,10 @@ registerTool(
|
|
|
62261
62565
|
maxSeconds,
|
|
62262
62566
|
signal
|
|
62263
62567
|
}),
|
|
62264
|
-
exportMaxResponseBytes()
|
|
62265
|
-
|
|
62266
|
-
return successResponse(
|
|
62267
|
-
formatTranscription(result),
|
|
62268
|
-
result
|
|
62568
|
+
exportMaxResponseBytes(),
|
|
62569
|
+
(r) => Buffer.byteLength(JSON.stringify(toResponse(r)))
|
|
62269
62570
|
);
|
|
62571
|
+
return toResponse(result);
|
|
62270
62572
|
}, "Error transcribing audio")
|
|
62271
62573
|
);
|
|
62272
62574
|
registerTool(
|
|
@@ -62381,13 +62683,14 @@ process.on("uncaughtException", (err) => {
|
|
|
62381
62683
|
process.on("unhandledRejection", (reason) => {
|
|
62382
62684
|
console.error("[unhandledRejection]", reason);
|
|
62383
62685
|
});
|
|
62384
|
-
var
|
|
62686
|
+
var inFlight = new InFlightRequests();
|
|
62687
|
+
var shutdown = createShutdown(process.stdout, () => process.exit(0), void 0, inFlight);
|
|
62385
62688
|
for (const sig of ["SIGINT", "SIGTERM"]) {
|
|
62386
62689
|
process.on(sig, shutdown);
|
|
62387
62690
|
}
|
|
62388
62691
|
process.stdin.on("end", shutdown);
|
|
62389
62692
|
process.stdin.on("close", shutdown);
|
|
62390
|
-
var transport = withJsonSchema2020_12(new StdioServerTransport());
|
|
62693
|
+
var transport = trackRequests(withJsonSchema2020_12(new StdioServerTransport()), inFlight);
|
|
62391
62694
|
await server.connect(transport);
|
|
62392
62695
|
/*! Bundled license information:
|
|
62393
62696
|
|