apple-notes-mcp 2.8.35 → 2.8.36
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 +43 -7
- package/build/index.js +677 -194
- package/package.json +1 -1
package/build/index.js
CHANGED
|
@@ -3268,8 +3268,8 @@ var require_utils = __commonJS({
|
|
|
3268
3268
|
}
|
|
3269
3269
|
return ind;
|
|
3270
3270
|
}
|
|
3271
|
-
function removeDotSegments(
|
|
3272
|
-
let input =
|
|
3271
|
+
function removeDotSegments(path8) {
|
|
3272
|
+
let input = path8;
|
|
3273
3273
|
const output = [];
|
|
3274
3274
|
let nextSlash = -1;
|
|
3275
3275
|
let len = 0;
|
|
@@ -3674,8 +3674,8 @@ var require_schemes = __commonJS({
|
|
|
3674
3674
|
}
|
|
3675
3675
|
if (wsComponent.resourceName) {
|
|
3676
3676
|
const queryIndex = wsComponent.resourceName.indexOf("?");
|
|
3677
|
-
const
|
|
3678
|
-
wsComponent.path =
|
|
3677
|
+
const path8 = queryIndex === -1 ? wsComponent.resourceName : wsComponent.resourceName.slice(0, queryIndex);
|
|
3678
|
+
wsComponent.path = path8 && path8 !== "/" ? path8 : void 0;
|
|
3679
3679
|
wsComponent.query = queryIndex === -1 ? void 0 : wsComponent.resourceName.slice(queryIndex + 1);
|
|
3680
3680
|
wsComponent.resourceName = void 0;
|
|
3681
3681
|
}
|
|
@@ -7181,12 +7181,12 @@ var require_dist = __commonJS({
|
|
|
7181
7181
|
throw new Error(`Unknown format "${name}"`);
|
|
7182
7182
|
return f;
|
|
7183
7183
|
};
|
|
7184
|
-
function addFormats(ajv, list,
|
|
7184
|
+
function addFormats(ajv, list, fs8, exportName) {
|
|
7185
7185
|
var _a;
|
|
7186
7186
|
var _b;
|
|
7187
7187
|
(_a = (_b = ajv.opts.code).formats) !== null && _a !== void 0 ? _a : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
|
|
7188
7188
|
for (const f of list)
|
|
7189
|
-
ajv.addFormat(f,
|
|
7189
|
+
ajv.addFormat(f, fs8[f]);
|
|
7190
7190
|
}
|
|
7191
7191
|
module.exports = exports = formatsPlugin;
|
|
7192
7192
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -12238,32 +12238,32 @@ var require_URL = __commonJS({
|
|
|
12238
12238
|
else
|
|
12239
12239
|
return basepath.substring(0, lastslash + 1) + refpath;
|
|
12240
12240
|
}
|
|
12241
|
-
function remove_dot_segments(
|
|
12242
|
-
if (!
|
|
12241
|
+
function remove_dot_segments(path8) {
|
|
12242
|
+
if (!path8) return path8;
|
|
12243
12243
|
var output = "";
|
|
12244
|
-
while (
|
|
12245
|
-
if (
|
|
12246
|
-
|
|
12244
|
+
while (path8.length > 0) {
|
|
12245
|
+
if (path8 === "." || path8 === "..") {
|
|
12246
|
+
path8 = "";
|
|
12247
12247
|
break;
|
|
12248
12248
|
}
|
|
12249
|
-
var twochars =
|
|
12250
|
-
var threechars =
|
|
12251
|
-
var fourchars =
|
|
12249
|
+
var twochars = path8.substring(0, 2);
|
|
12250
|
+
var threechars = path8.substring(0, 3);
|
|
12251
|
+
var fourchars = path8.substring(0, 4);
|
|
12252
12252
|
if (threechars === "../") {
|
|
12253
|
-
|
|
12253
|
+
path8 = path8.substring(3);
|
|
12254
12254
|
} else if (twochars === "./") {
|
|
12255
|
-
|
|
12255
|
+
path8 = path8.substring(2);
|
|
12256
12256
|
} else if (threechars === "/./") {
|
|
12257
|
-
|
|
12258
|
-
} else if (twochars === "/." &&
|
|
12259
|
-
|
|
12260
|
-
} else if (fourchars === "/../" || threechars === "/.." &&
|
|
12261
|
-
|
|
12257
|
+
path8 = "/" + path8.substring(3);
|
|
12258
|
+
} else if (twochars === "/." && path8.length === 2) {
|
|
12259
|
+
path8 = "/";
|
|
12260
|
+
} else if (fourchars === "/../" || threechars === "/.." && path8.length === 3) {
|
|
12261
|
+
path8 = "/" + path8.substring(4);
|
|
12262
12262
|
output = output.replace(/\/?[^\/]*$/, "");
|
|
12263
12263
|
} else {
|
|
12264
|
-
var segment =
|
|
12264
|
+
var segment = path8.match(/(\/?([^\/]*))/)[0];
|
|
12265
12265
|
output += segment;
|
|
12266
|
-
|
|
12266
|
+
path8 = path8.substring(segment.length);
|
|
12267
12267
|
}
|
|
12268
12268
|
}
|
|
12269
12269
|
return output;
|
|
@@ -24465,14 +24465,14 @@ var require_turndown_cjs = __commonJS({
|
|
|
24465
24465
|
} else if (node.nodeType === 1) {
|
|
24466
24466
|
replacement = replacementForNode.call(self, node);
|
|
24467
24467
|
}
|
|
24468
|
-
return
|
|
24468
|
+
return join19(output, replacement);
|
|
24469
24469
|
}, "");
|
|
24470
24470
|
}
|
|
24471
24471
|
function postProcess(output) {
|
|
24472
24472
|
var self = this;
|
|
24473
24473
|
this.rules.forEach(function(rule) {
|
|
24474
24474
|
if (typeof rule.append === "function") {
|
|
24475
|
-
output =
|
|
24475
|
+
output = join19(output, rule.append(self.options));
|
|
24476
24476
|
}
|
|
24477
24477
|
});
|
|
24478
24478
|
return output.replace(/^[\t\r\n]+/, "").replace(/[\t\r\n\s]+$/, "");
|
|
@@ -24484,7 +24484,7 @@ var require_turndown_cjs = __commonJS({
|
|
|
24484
24484
|
if (whitespace.leading || whitespace.trailing) content = content.trim();
|
|
24485
24485
|
return whitespace.leading + rule.replacement(content, node, this.options) + whitespace.trailing;
|
|
24486
24486
|
}
|
|
24487
|
-
function
|
|
24487
|
+
function join19(output, replacement) {
|
|
24488
24488
|
var s1 = trimTrailingNewlines(output);
|
|
24489
24489
|
var s2 = trimLeadingNewlines(replacement);
|
|
24490
24490
|
var nls = Math.max(output.length - s1.length, replacement.length - s2.length);
|
|
@@ -24979,8 +24979,8 @@ function getErrorMap() {
|
|
|
24979
24979
|
|
|
24980
24980
|
// node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
|
|
24981
24981
|
var makeIssue = (params) => {
|
|
24982
|
-
const { data, path:
|
|
24983
|
-
const fullPath = [...
|
|
24982
|
+
const { data, path: path8, errorMaps, issueData } = params;
|
|
24983
|
+
const fullPath = [...path8, ...issueData.path || []];
|
|
24984
24984
|
const fullIssue = {
|
|
24985
24985
|
...issueData,
|
|
24986
24986
|
path: fullPath
|
|
@@ -25096,11 +25096,11 @@ var errorUtil;
|
|
|
25096
25096
|
|
|
25097
25097
|
// node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
|
|
25098
25098
|
var ParseInputLazyPath = class {
|
|
25099
|
-
constructor(parent, value,
|
|
25099
|
+
constructor(parent, value, path8, key) {
|
|
25100
25100
|
this._cachedPath = [];
|
|
25101
25101
|
this.parent = parent;
|
|
25102
25102
|
this.data = value;
|
|
25103
|
-
this._path =
|
|
25103
|
+
this._path = path8;
|
|
25104
25104
|
this._key = key;
|
|
25105
25105
|
}
|
|
25106
25106
|
get path() {
|
|
@@ -28737,10 +28737,10 @@ function assignProp(target, prop, value) {
|
|
|
28737
28737
|
configurable: true
|
|
28738
28738
|
});
|
|
28739
28739
|
}
|
|
28740
|
-
function getElementAtPath(obj,
|
|
28741
|
-
if (!
|
|
28740
|
+
function getElementAtPath(obj, path8) {
|
|
28741
|
+
if (!path8)
|
|
28742
28742
|
return obj;
|
|
28743
|
-
return
|
|
28743
|
+
return path8.reduce((acc, key) => acc?.[key], obj);
|
|
28744
28744
|
}
|
|
28745
28745
|
function promiseAllObject(promisesObj) {
|
|
28746
28746
|
const keys = Object.keys(promisesObj);
|
|
@@ -29060,11 +29060,11 @@ function aborted(x, startIndex = 0) {
|
|
|
29060
29060
|
}
|
|
29061
29061
|
return false;
|
|
29062
29062
|
}
|
|
29063
|
-
function prefixIssues(
|
|
29063
|
+
function prefixIssues(path8, issues) {
|
|
29064
29064
|
return issues.map((iss) => {
|
|
29065
29065
|
var _a;
|
|
29066
29066
|
(_a = iss).path ?? (_a.path = []);
|
|
29067
|
-
iss.path.unshift(
|
|
29067
|
+
iss.path.unshift(path8);
|
|
29068
29068
|
return iss;
|
|
29069
29069
|
});
|
|
29070
29070
|
}
|
|
@@ -32475,11 +32475,11 @@ function normalizeObjectSchema(schema) {
|
|
|
32475
32475
|
}
|
|
32476
32476
|
return void 0;
|
|
32477
32477
|
}
|
|
32478
|
-
function getDotPath(
|
|
32479
|
-
if (
|
|
32478
|
+
function getDotPath(path8) {
|
|
32479
|
+
if (path8.length === 0) {
|
|
32480
32480
|
return "object root";
|
|
32481
32481
|
}
|
|
32482
|
-
return
|
|
32482
|
+
return path8.reduce((acc, seg, index) => {
|
|
32483
32483
|
if (index === 0) {
|
|
32484
32484
|
return String(seg);
|
|
32485
32485
|
}
|
|
@@ -40582,7 +40582,7 @@ var Decoder = class {
|
|
|
40582
40582
|
* positively and negated by the caller.
|
|
40583
40583
|
*/
|
|
40584
40584
|
leaf(key, value, excluded) {
|
|
40585
|
-
const
|
|
40585
|
+
const flag2 = (description, negative) => typeof value === "boolean" ? {
|
|
40586
40586
|
type: key,
|
|
40587
40587
|
value,
|
|
40588
40588
|
...excluded ? { excluded: true } : {},
|
|
@@ -40590,25 +40590,25 @@ var Decoder = class {
|
|
|
40590
40590
|
} : null;
|
|
40591
40591
|
switch (key) {
|
|
40592
40592
|
case "checklist":
|
|
40593
|
-
return
|
|
40593
|
+
return flag2("has a checklist", "has no checklist");
|
|
40594
40594
|
case "checklistInProgress":
|
|
40595
|
-
return
|
|
40595
|
+
return flag2("has an unfinished checklist", "has no unfinished checklist");
|
|
40596
40596
|
case "checklistCompleted":
|
|
40597
|
-
return
|
|
40597
|
+
return flag2("has a completed checklist", "has no completed checklist");
|
|
40598
40598
|
case "attachment":
|
|
40599
|
-
return
|
|
40599
|
+
return flag2("has attachments", "has no attachments");
|
|
40600
40600
|
case "pinned":
|
|
40601
|
-
return
|
|
40601
|
+
return flag2("is pinned", "is not pinned");
|
|
40602
40602
|
case "systemPaper":
|
|
40603
|
-
return
|
|
40603
|
+
return flag2("is a Quick Note", "is not a Quick Note");
|
|
40604
40604
|
case "passwordProtected":
|
|
40605
|
-
return
|
|
40605
|
+
return flag2("is locked", "is not locked");
|
|
40606
40606
|
case "shared":
|
|
40607
|
-
return
|
|
40607
|
+
return flag2("is shared", "is not shared");
|
|
40608
40608
|
case "mention":
|
|
40609
|
-
return
|
|
40609
|
+
return flag2("mentions anyone", "mentions no one");
|
|
40610
40610
|
case "tagged":
|
|
40611
|
-
return
|
|
40611
|
+
return flag2("has any tag", "has no tags");
|
|
40612
40612
|
case "attachmentSection": {
|
|
40613
40613
|
if (typeof value !== "number" || !ATTACHMENT_SECTIONS[value]) return null;
|
|
40614
40614
|
return {
|
|
@@ -40784,7 +40784,7 @@ function buildSmartFolders(output) {
|
|
|
40784
40784
|
if (lines.length < 4) throw new Error("Unexpected smart folder query output");
|
|
40785
40785
|
const [storeUuid, rowsJson, foldersJson, tagsJson] = lines;
|
|
40786
40786
|
if (!/^[0-9A-F-]+$/i.test(storeUuid)) throw new Error("Unexpected Notes store identifier");
|
|
40787
|
-
const coreDataId2 = (
|
|
40787
|
+
const coreDataId2 = (entity3, pk) => `x-coredata://${storeUuid}/${entity3}/p${pk}`;
|
|
40788
40788
|
const rows = JSON.parse(rowsJson);
|
|
40789
40789
|
const folderRows = JSON.parse(foldersJson || "{}");
|
|
40790
40790
|
const tagRows = JSON.parse(tagsJson || "[]");
|
|
@@ -40881,8 +40881,8 @@ function allowedSaveRoots() {
|
|
|
40881
40881
|
"/private/tmp"
|
|
40882
40882
|
];
|
|
40883
40883
|
}
|
|
40884
|
-
function canonicalize(
|
|
40885
|
-
return realpathSync.native(
|
|
40884
|
+
function canonicalize(path8) {
|
|
40885
|
+
return realpathSync.native(path8);
|
|
40886
40886
|
}
|
|
40887
40887
|
function isWithinRoots(candidate, roots) {
|
|
40888
40888
|
return roots.some((root) => {
|
|
@@ -40904,9 +40904,9 @@ function canonicalRoots(roots) {
|
|
|
40904
40904
|
}
|
|
40905
40905
|
return canonical;
|
|
40906
40906
|
}
|
|
40907
|
-
function entryExists(
|
|
40907
|
+
function entryExists(path8) {
|
|
40908
40908
|
try {
|
|
40909
|
-
lstatSync(
|
|
40909
|
+
lstatSync(path8);
|
|
40910
40910
|
return true;
|
|
40911
40911
|
} catch (e) {
|
|
40912
40912
|
const code = e.code;
|
|
@@ -41136,7 +41136,7 @@ function attachmentCoreDataId(noteId3, pk) {
|
|
|
41136
41136
|
}
|
|
41137
41137
|
function buildAttachmentRowsSql(notePk, columns) {
|
|
41138
41138
|
if (!Number.isSafeInteger(notePk) || notePk < 0) throw new Error("Invalid note primary key");
|
|
41139
|
-
const
|
|
41139
|
+
const col3 = (alias, name) => columns.has(name) ? `${alias}.${name}` : "NULL";
|
|
41140
41140
|
const firstOf = (alias, names) => {
|
|
41141
41141
|
const present = names.filter((n) => columns.has(n)).map((n) => `${alias}.${n}`);
|
|
41142
41142
|
if (present.length === 0) return "NULL";
|
|
@@ -41149,19 +41149,19 @@ function buildAttachmentRowsSql(notePk, columns) {
|
|
|
41149
41149
|
].join(", ");
|
|
41150
41150
|
const account = accountCols.length ? `(SELECT acc.ZIDENTIFIER FROM ZICCLOUDSYNCINGOBJECT acc WHERE acc.Z_ENT = (SELECT Z_ENT FROM Z_PRIMARYKEY WHERE Z_NAME = 'ICAccount') AND acc.Z_PK IN (${accountRefs}) LIMIT 1)` : "NULL";
|
|
41151
41151
|
const noteLink = columns.has("ZNOTE") ? "a.ZNOTE" : "NULL";
|
|
41152
|
-
const parent =
|
|
41152
|
+
const parent = col3("a", "ZPARENTATTACHMENT");
|
|
41153
41153
|
const deleted = columns.has("ZMARKEDFORDELETION") ? " AND COALESCE(a.ZMARKEDFORDELETION, 0) = 0" : "";
|
|
41154
41154
|
const fields = [
|
|
41155
41155
|
`'pk', a.Z_PK`,
|
|
41156
41156
|
`'identifier', a.ZIDENTIFIER`,
|
|
41157
|
-
`'uti', ${
|
|
41157
|
+
`'uti', ${col3("a", "ZTYPEUTI")}`,
|
|
41158
41158
|
`'parentPk', ${parent}`,
|
|
41159
|
-
`'filename', ${
|
|
41159
|
+
`'filename', ${col3("a", "ZFILENAME")}`,
|
|
41160
41160
|
`'mediaIdentifier', m.ZIDENTIFIER`,
|
|
41161
|
-
`'mediaFilename', ${
|
|
41161
|
+
`'mediaFilename', ${col3("m", "ZFILENAME")}`,
|
|
41162
41162
|
`'mediaGeneration', ${firstOf("m", ["ZGENERATION1", "ZGENERATION"])}`,
|
|
41163
|
-
`'fallbackImageGeneration', ${
|
|
41164
|
-
`'fallbackPdfGeneration', ${
|
|
41163
|
+
`'fallbackImageGeneration', ${col3("a", "ZFALLBACKIMAGEGENERATION")}`,
|
|
41164
|
+
`'fallbackPdfGeneration', ${col3("a", "ZFALLBACKPDFGENERATION")}`,
|
|
41165
41165
|
`'accountIdentifier', ${account}`
|
|
41166
41166
|
].join(", ");
|
|
41167
41167
|
const mediaJoin = columns.has("ZMEDIA") ? "LEFT JOIN ZICCLOUDSYNCINGOBJECT m ON m.Z_PK = a.ZMEDIA" : "LEFT JOIN ZICCLOUDSYNCINGOBJECT m ON 0";
|
|
@@ -41274,24 +41274,24 @@ function safeComponent(value) {
|
|
|
41274
41274
|
if (value === "." || value === ".." || value.includes("/") || value.includes("\0")) return null;
|
|
41275
41275
|
return value;
|
|
41276
41276
|
}
|
|
41277
|
-
function realInside(
|
|
41277
|
+
function realInside(path8, rootReal) {
|
|
41278
41278
|
try {
|
|
41279
|
-
const real = realpathSync2.native(
|
|
41279
|
+
const real = realpathSync2.native(path8);
|
|
41280
41280
|
return real === rootReal || real.startsWith(rootReal + sep2) ? real : null;
|
|
41281
41281
|
} catch {
|
|
41282
41282
|
return null;
|
|
41283
41283
|
}
|
|
41284
41284
|
}
|
|
41285
|
-
function isRegularFile(
|
|
41285
|
+
function isRegularFile(path8) {
|
|
41286
41286
|
try {
|
|
41287
|
-
return lstatSync2(
|
|
41287
|
+
return lstatSync2(path8).isFile();
|
|
41288
41288
|
} catch {
|
|
41289
41289
|
return false;
|
|
41290
41290
|
}
|
|
41291
41291
|
}
|
|
41292
|
-
function isDirectory(
|
|
41292
|
+
function isDirectory(path8) {
|
|
41293
41293
|
try {
|
|
41294
|
-
return lstatSync2(
|
|
41294
|
+
return lstatSync2(path8).isDirectory();
|
|
41295
41295
|
} catch {
|
|
41296
41296
|
return false;
|
|
41297
41297
|
}
|
|
@@ -41671,10 +41671,10 @@ function readImageInfoFd(fd) {
|
|
|
41671
41671
|
const read = readSync2(fd, buf, 0, buf.length, 0);
|
|
41672
41672
|
return parseImageHeader(buf.subarray(0, read));
|
|
41673
41673
|
}
|
|
41674
|
-
function readImageInfo(
|
|
41674
|
+
function readImageInfo(path8) {
|
|
41675
41675
|
let fd;
|
|
41676
41676
|
try {
|
|
41677
|
-
fd = openSync3(
|
|
41677
|
+
fd = openSync3(path8, constants3.O_RDONLY | constants3.O_NOFOLLOW);
|
|
41678
41678
|
} catch {
|
|
41679
41679
|
return null;
|
|
41680
41680
|
}
|
|
@@ -41686,7 +41686,7 @@ function readImageInfo(path7) {
|
|
|
41686
41686
|
}
|
|
41687
41687
|
function buildDrawingRowsSql(notePk, columns) {
|
|
41688
41688
|
if (!Number.isSafeInteger(notePk) || notePk < 0) throw new Error("Invalid note primary key");
|
|
41689
|
-
const
|
|
41689
|
+
const col3 = (name) => columns.has(name) ? `a.${name}` : "NULL";
|
|
41690
41690
|
const accountCols = [...columns].filter((c) => /^ZACCOUNT\d*$/.test(c)).sort();
|
|
41691
41691
|
const account = accountCols.length ? `(SELECT acc.ZIDENTIFIER FROM ZICCLOUDSYNCINGOBJECT acc WHERE acc.Z_ENT = (SELECT Z_ENT FROM Z_PRIMARYKEY WHERE Z_NAME = 'ICAccount') AND acc.Z_PK IN (${[
|
|
41692
41692
|
...accountCols.map((c) => `a.${c}`),
|
|
@@ -41697,8 +41697,8 @@ function buildDrawingRowsSql(notePk, columns) {
|
|
|
41697
41697
|
`'pk', a.Z_PK`,
|
|
41698
41698
|
`'identifier', a.ZIDENTIFIER`,
|
|
41699
41699
|
`'uti', a.ZTYPEUTI`,
|
|
41700
|
-
`'handwritingSummary', ${
|
|
41701
|
-
`'fallbackImageGeneration', ${
|
|
41700
|
+
`'handwritingSummary', ${col3("ZHANDWRITINGSUMMARY")}`,
|
|
41701
|
+
`'fallbackImageGeneration', ${col3("ZFALLBACKIMAGEGENERATION")}`,
|
|
41702
41702
|
`'accountIdentifier', ${account}`
|
|
41703
41703
|
].join(", ");
|
|
41704
41704
|
return [
|
|
@@ -41774,9 +41774,9 @@ function readDrawingRows(noteId3, dbPath2 = join7(NOTES_CONTAINER_DIR, "NoteStor
|
|
|
41774
41774
|
throw new AttachmentStoreError("Drawing rows could not be parsed", "query_error");
|
|
41775
41775
|
}
|
|
41776
41776
|
}
|
|
41777
|
-
function kindOf(
|
|
41777
|
+
function kindOf(path8) {
|
|
41778
41778
|
try {
|
|
41779
|
-
const st = lstatSync3(
|
|
41779
|
+
const st = lstatSync3(path8);
|
|
41780
41780
|
return st.isFile() ? "file" : st.isDirectory() ? "dir" : null;
|
|
41781
41781
|
} catch {
|
|
41782
41782
|
return null;
|
|
@@ -41842,13 +41842,13 @@ function describeDrawings(rows, containerDir = NOTES_CONTAINER_DIR) {
|
|
|
41842
41842
|
const previewPath = accountDir ? findLargestPreview(accountDir, row.identifier) : null;
|
|
41843
41843
|
const bundle = accountDir && id2 && kind === "paper" ? realInside(join7(accountDir, "Paper", "Bundles", `${id2}.bundle`), accountDir) : null;
|
|
41844
41844
|
let raster = null;
|
|
41845
|
-
for (const [
|
|
41845
|
+
for (const [path8, source] of [
|
|
41846
41846
|
[fallbackImagePath, "fallback"],
|
|
41847
41847
|
[previewPath, "preview"]
|
|
41848
41848
|
]) {
|
|
41849
|
-
const info =
|
|
41850
|
-
if (
|
|
41851
|
-
raster = { path:
|
|
41849
|
+
const info = path8 ? readImageInfo(path8) : null;
|
|
41850
|
+
if (path8 && info) {
|
|
41851
|
+
raster = { path: path8, source, ...info };
|
|
41852
41852
|
break;
|
|
41853
41853
|
}
|
|
41854
41854
|
}
|
|
@@ -41865,10 +41865,10 @@ function describeDrawings(rows, containerDir = NOTES_CONTAINER_DIR) {
|
|
|
41865
41865
|
};
|
|
41866
41866
|
});
|
|
41867
41867
|
}
|
|
41868
|
-
function verifyWrittenImage(fd,
|
|
41868
|
+
function verifyWrittenImage(fd, path8, expected) {
|
|
41869
41869
|
const check2 = readImageInfoFd(fd);
|
|
41870
41870
|
if (!check2 || check2.format !== expected.format || check2.width !== expected.width || check2.height !== expected.height) {
|
|
41871
|
-
unlinkSync2(
|
|
41871
|
+
unlinkSync2(path8);
|
|
41872
41872
|
throw new Error("The exported image failed validation and was removed.");
|
|
41873
41873
|
}
|
|
41874
41874
|
return check2;
|
|
@@ -44772,7 +44772,10 @@ function getNoteMetadata(noteId3) {
|
|
|
44772
44772
|
}
|
|
44773
44773
|
}
|
|
44774
44774
|
|
|
44775
|
-
// src/utils/
|
|
44775
|
+
// src/utils/noteListings.ts
|
|
44776
|
+
import { gunzipSync as gunzipSync6 } from "zlib";
|
|
44777
|
+
|
|
44778
|
+
// src/utils/noteStoreSql.ts
|
|
44776
44779
|
import { execFileSync as execFileSync10 } from "child_process";
|
|
44777
44780
|
import * as fs5 from "fs";
|
|
44778
44781
|
import * as os5 from "os";
|
|
@@ -44781,6 +44784,407 @@ var NOTES_DB_PATH6 = path5.join(
|
|
|
44781
44784
|
os5.homedir(),
|
|
44782
44785
|
"Library/Group Containers/group.com.apple.notes/NoteStore.sqlite"
|
|
44783
44786
|
);
|
|
44787
|
+
var CORE_DATA_EPOCH_MS = Date.UTC(2001, 0, 1);
|
|
44788
|
+
var STORE_FDA_MESSAGE = `Full Disk Access is required to read the Notes database. In System Settings > Privacy & Security > Full Disk Access, grant access to the app that launches this server (Claude Desktop / Terminal / iTerm2), then fully quit and relaunch it. Setup guide: ${FULL_DISK_ACCESS_GUIDE_URL} \u2014 run the doctor tool to verify.`;
|
|
44789
|
+
var NoteStoreError = class extends Error {
|
|
44790
|
+
constructor(message, kind) {
|
|
44791
|
+
super(message);
|
|
44792
|
+
this.kind = kind;
|
|
44793
|
+
this.name = "NoteStoreError";
|
|
44794
|
+
}
|
|
44795
|
+
kind;
|
|
44796
|
+
};
|
|
44797
|
+
function doubleToHex(value) {
|
|
44798
|
+
if (!Number.isFinite(value)) throw new NoteStoreError("Not a finite number", "invalid_input");
|
|
44799
|
+
const buffer = Buffer.alloc(8);
|
|
44800
|
+
buffer.writeDoubleBE(value);
|
|
44801
|
+
return buffer.toString("hex");
|
|
44802
|
+
}
|
|
44803
|
+
function hexToDouble(hex3) {
|
|
44804
|
+
if (!/^[0-9a-f]{16}$/i.test(hex3))
|
|
44805
|
+
throw new NoteStoreError("Invalid double bits", "invalid_input");
|
|
44806
|
+
const value = Buffer.from(hex3, "hex").readDoubleBE();
|
|
44807
|
+
if (!Number.isFinite(value)) throw new NoteStoreError("Invalid double bits", "invalid_input");
|
|
44808
|
+
return value;
|
|
44809
|
+
}
|
|
44810
|
+
function renderValue(value) {
|
|
44811
|
+
if ("int" in value) {
|
|
44812
|
+
if (!Number.isSafeInteger(value.int)) {
|
|
44813
|
+
throw new NoteStoreError("Bound integer out of range", "invalid_input");
|
|
44814
|
+
}
|
|
44815
|
+
return String(value.int);
|
|
44816
|
+
}
|
|
44817
|
+
if ("blob" in value) return `x'${Buffer.from(value.blob).toString("hex")}'`;
|
|
44818
|
+
const double = "double" in value ? value.double : hexToDouble(value.doubleBits);
|
|
44819
|
+
return `ieee754_from_blob(x'${doubleToHex(double)}')`;
|
|
44820
|
+
}
|
|
44821
|
+
function runReadOnlySql(dbPath2, sql, params = {}) {
|
|
44822
|
+
if (!fs5.existsSync(dbPath2)) throw new NoteStoreError(STORE_FDA_MESSAGE, "no_fda");
|
|
44823
|
+
const args = ["-readonly"];
|
|
44824
|
+
const names = Object.keys(params);
|
|
44825
|
+
if (names.length) args.push("-cmd", ".parameter init");
|
|
44826
|
+
for (const name of names) {
|
|
44827
|
+
if (!/^[a-z][a-z0-9_]*$/i.test(name)) {
|
|
44828
|
+
throw new NoteStoreError(`Invalid parameter name ${name}`, "invalid_input");
|
|
44829
|
+
}
|
|
44830
|
+
args.push("-cmd", `.parameter set @${name} ${renderValue(params[name])}`);
|
|
44831
|
+
}
|
|
44832
|
+
args.push(dbPath2, sql);
|
|
44833
|
+
try {
|
|
44834
|
+
return execFileSync10("sqlite3", args, {
|
|
44835
|
+
encoding: "utf8",
|
|
44836
|
+
timeout: 3e4,
|
|
44837
|
+
maxBuffer: 512 * 1024 * 1024,
|
|
44838
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
44839
|
+
});
|
|
44840
|
+
} catch (error2) {
|
|
44841
|
+
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
44842
|
+
if (/authorization denied|unable to open database/i.test(message)) {
|
|
44843
|
+
throw new NoteStoreError(STORE_FDA_MESSAGE, "no_fda");
|
|
44844
|
+
}
|
|
44845
|
+
console.error(`Notes database query failed: ${message}`);
|
|
44846
|
+
throw new NoteStoreError("Failed to query the Notes database.", "query_error");
|
|
44847
|
+
}
|
|
44848
|
+
}
|
|
44849
|
+
function parseJsonLines(output) {
|
|
44850
|
+
const rows = [];
|
|
44851
|
+
for (const line of output.split("\n")) {
|
|
44852
|
+
if (!line.trim()) continue;
|
|
44853
|
+
try {
|
|
44854
|
+
rows.push(JSON.parse(line));
|
|
44855
|
+
} catch {
|
|
44856
|
+
throw new NoteStoreError("Unexpected Notes database response.", "query_error");
|
|
44857
|
+
}
|
|
44858
|
+
}
|
|
44859
|
+
return rows;
|
|
44860
|
+
}
|
|
44861
|
+
function readColumns(dbPath2) {
|
|
44862
|
+
const out = runReadOnlySql(
|
|
44863
|
+
dbPath2,
|
|
44864
|
+
"SELECT json_object('name', name) FROM pragma_table_info('ZICCLOUDSYNCINGOBJECT');"
|
|
44865
|
+
);
|
|
44866
|
+
return new Set(parseJsonLines(out).map((row) => row.name));
|
|
44867
|
+
}
|
|
44868
|
+
function requireColumns(columns, required2, tool) {
|
|
44869
|
+
const missing = required2.filter((column) => !columns.has(column));
|
|
44870
|
+
if (missing.length) {
|
|
44871
|
+
throw new NoteStoreError(
|
|
44872
|
+
`This macOS version's Notes database lacks columns ${tool} needs (${missing.join(", ")}).`,
|
|
44873
|
+
"schema"
|
|
44874
|
+
);
|
|
44875
|
+
}
|
|
44876
|
+
}
|
|
44877
|
+
function col(columns, alias, name, fallback = "NULL") {
|
|
44878
|
+
return columns.has(name) ? `${alias}.${name}` : fallback;
|
|
44879
|
+
}
|
|
44880
|
+
function entity(name) {
|
|
44881
|
+
return `(SELECT Z_ENT FROM Z_PRIMARYKEY WHERE Z_NAME='${name}')`;
|
|
44882
|
+
}
|
|
44883
|
+
function accountRef(columns, alias) {
|
|
44884
|
+
const refs = [...columns].filter((name) => /^ZACCOUNT\d*$/.test(name)).sort().map((name) => `${alias}.${name}`);
|
|
44885
|
+
if (!refs.length) return "NULL";
|
|
44886
|
+
return refs.length === 1 ? refs[0] : `COALESCE(${refs.join(", ")})`;
|
|
44887
|
+
}
|
|
44888
|
+
function trashFolderSql(columns, f) {
|
|
44889
|
+
const parts = [];
|
|
44890
|
+
if (columns.has("ZFOLDERTYPE")) parts.push(`COALESCE(${f}.ZFOLDERTYPE, 0) = 1`);
|
|
44891
|
+
if (columns.has("ZIDENTIFIER")) parts.push(`COALESCE(${f}.ZIDENTIFIER, '') LIKE 'TrashFolder%'`);
|
|
44892
|
+
return parts.length ? `(${parts.join(" OR ")})` : "0";
|
|
44893
|
+
}
|
|
44894
|
+
function notTombstonedSql(columns, alias) {
|
|
44895
|
+
return columns.has("ZMARKEDFORDELETION") ? `COALESCE(${alias}.ZMARKEDFORDELETION, 0) = 0` : "1";
|
|
44896
|
+
}
|
|
44897
|
+
function activeNoteSql(columns, n, f) {
|
|
44898
|
+
return [
|
|
44899
|
+
`${n}.ZFOLDER IS NOT NULL`,
|
|
44900
|
+
`${f}.Z_PK IS NOT NULL`,
|
|
44901
|
+
notTombstonedSql(columns, n),
|
|
44902
|
+
notTombstonedSql(columns, f),
|
|
44903
|
+
`NOT ${trashFolderSql(columns, f)}`
|
|
44904
|
+
].join(" AND ");
|
|
44905
|
+
}
|
|
44906
|
+
function coreDataToIso(seconds) {
|
|
44907
|
+
if (typeof seconds !== "number" || !Number.isFinite(seconds)) return null;
|
|
44908
|
+
const date3 = new Date(CORE_DATA_EPOCH_MS + seconds * 1e3);
|
|
44909
|
+
return Number.isNaN(date3.getTime()) ? null : date3.toISOString();
|
|
44910
|
+
}
|
|
44911
|
+
function noteIdFor(storeUuid, pk) {
|
|
44912
|
+
return `x-coredata://${storeUuid}/ICNote/p${pk}`;
|
|
44913
|
+
}
|
|
44914
|
+
function readStoreContext(dbPath2, columns) {
|
|
44915
|
+
const sql = [
|
|
44916
|
+
"BEGIN;",
|
|
44917
|
+
"SELECT json_object('k', 'meta', 'uuid', (SELECT Z_UUID FROM Z_METADATA LIMIT 1));",
|
|
44918
|
+
`SELECT json_object('k', 'account', 'pk', a.Z_PK, 'name', ${col(columns, "a", "ZNAME")}, 'identifier', ${col(columns, "a", "ZIDENTIFIER")}) FROM ZICCLOUDSYNCINGOBJECT a WHERE a.Z_ENT = ${entity("ICAccount")} AND ${notTombstonedSql(columns, "a")};`,
|
|
44919
|
+
`SELECT json_object('k', 'folder', 'pk', f.Z_PK, 'name', ${col(columns, "f", "ZTITLE2")}, 'identifier', ${col(columns, "f", "ZIDENTIFIER")}, 'parent', ${col(columns, "f", "ZPARENT")}, 'account', ${col(columns, "f", "ZOWNER", accountRef(columns, "f"))}, 'folderType', ${col(columns, "f", "ZFOLDERTYPE")}, 'trash', ${trashFolderSql(columns, "f")}, 'tombstoned', NOT ${notTombstonedSql(columns, "f")}) FROM ZICCLOUDSYNCINGOBJECT f WHERE f.Z_ENT = ${entity("ICFolder")};`,
|
|
44920
|
+
"COMMIT;"
|
|
44921
|
+
].join(" ");
|
|
44922
|
+
const rows = parseJsonLines(runReadOnlySql(dbPath2, sql));
|
|
44923
|
+
const meta = rows.find((row) => row.k === "meta");
|
|
44924
|
+
if (typeof meta?.uuid !== "string" || !meta.uuid) {
|
|
44925
|
+
throw new NoteStoreError("The Notes database has no store identifier.", "schema");
|
|
44926
|
+
}
|
|
44927
|
+
return {
|
|
44928
|
+
uuid: meta.uuid,
|
|
44929
|
+
accounts: rows.filter((row) => row.k === "account").map((row) => ({
|
|
44930
|
+
pk: row.pk,
|
|
44931
|
+
name: typeof row.name === "string" ? row.name : "",
|
|
44932
|
+
identifier: row.identifier ?? null
|
|
44933
|
+
})),
|
|
44934
|
+
folders: rows.filter((row) => row.k === "folder").map((row) => ({
|
|
44935
|
+
pk: row.pk,
|
|
44936
|
+
name: row.name ?? null,
|
|
44937
|
+
identifier: row.identifier ?? null,
|
|
44938
|
+
parent: row.parent ?? null,
|
|
44939
|
+
account: row.account ?? null,
|
|
44940
|
+
folderType: row.folderType ?? null,
|
|
44941
|
+
trash: row.trash ? 1 : 0,
|
|
44942
|
+
tombstoned: row.tombstoned ? 1 : 0
|
|
44943
|
+
}))
|
|
44944
|
+
};
|
|
44945
|
+
}
|
|
44946
|
+
function folderPaths(folders) {
|
|
44947
|
+
const byPk = new Map(folders.map((folder) => [folder.pk, folder]));
|
|
44948
|
+
const paths = /* @__PURE__ */ new Map();
|
|
44949
|
+
for (const folder of folders) {
|
|
44950
|
+
const segments = [];
|
|
44951
|
+
const seen = /* @__PURE__ */ new Set();
|
|
44952
|
+
let current = folder;
|
|
44953
|
+
while (current && !seen.has(current.pk)) {
|
|
44954
|
+
seen.add(current.pk);
|
|
44955
|
+
segments.unshift(escapeFolderName(current.name ?? ""));
|
|
44956
|
+
current = current.parent !== null ? byPk.get(current.parent) : void 0;
|
|
44957
|
+
}
|
|
44958
|
+
paths.set(folder.pk, segments.join("/"));
|
|
44959
|
+
}
|
|
44960
|
+
return paths;
|
|
44961
|
+
}
|
|
44962
|
+
function resolveAccountName(accounts, name) {
|
|
44963
|
+
const wanted = name.trim().toLocaleLowerCase();
|
|
44964
|
+
const exact = accounts.filter((account) => account.name.toLocaleLowerCase() === wanted);
|
|
44965
|
+
if (exact.length === 1) return exact[0];
|
|
44966
|
+
const prefix = accounts.filter((account) => account.name.toLocaleLowerCase().startsWith(wanted));
|
|
44967
|
+
if (exact.length === 0 && prefix.length === 1) return prefix[0];
|
|
44968
|
+
const names = accounts.map((account) => account.name).join(", ");
|
|
44969
|
+
throw new NoteStoreError(
|
|
44970
|
+
exact.length > 1 || prefix.length > 1 ? `Account "${name}" is ambiguous. Accounts: ${names}.` : `No account named "${name}". Accounts: ${names}.`,
|
|
44971
|
+
"invalid_input"
|
|
44972
|
+
);
|
|
44973
|
+
}
|
|
44974
|
+
|
|
44975
|
+
// src/utils/noteListings.ts
|
|
44976
|
+
var SPECIAL_LIMIT = { DEFAULT: 100, MAX: 1e3 };
|
|
44977
|
+
var HASHTAG_UTI = "com.apple.notes.inlinetextattachment.hashtag";
|
|
44978
|
+
var KIND_COLUMN = {
|
|
44979
|
+
pinned: ["ZISPINNED"],
|
|
44980
|
+
"quick-notes": ["ZISSYSTEMPAPER"],
|
|
44981
|
+
"recently-deleted": ["ZFOLDERTYPE", "ZIDENTIFIER"],
|
|
44982
|
+
locked: ["ZISPASSWORDPROTECTED"]
|
|
44983
|
+
};
|
|
44984
|
+
function kindSupported(columns, kind) {
|
|
44985
|
+
return KIND_COLUMN[kind].some((name) => columns.has(name));
|
|
44986
|
+
}
|
|
44987
|
+
var flag = (columns, alias, name) => columns.has(name) ? `COALESCE(${alias}.${name}, 0)` : "0";
|
|
44988
|
+
function kindPredicate(columns, kind) {
|
|
44989
|
+
switch (kind) {
|
|
44990
|
+
case "pinned":
|
|
44991
|
+
return `${flag(columns, "n", "ZISPINNED")} = 1 AND ${activeNoteSql(columns, "n", "f")}`;
|
|
44992
|
+
case "quick-notes":
|
|
44993
|
+
return `${flag(columns, "n", "ZISSYSTEMPAPER")} = 1 AND ${activeNoteSql(columns, "n", "f")}`;
|
|
44994
|
+
case "recently-deleted":
|
|
44995
|
+
return `f.Z_PK IS NOT NULL AND ${trashFolderSql(columns, "f")} AND ${notTombstonedSql(columns, "n")}`;
|
|
44996
|
+
case "locked":
|
|
44997
|
+
return `${flag(columns, "n", "ZISPASSWORDPROTECTED")} = 1`;
|
|
44998
|
+
}
|
|
44999
|
+
}
|
|
45000
|
+
function folderAccountJoins(columns) {
|
|
45001
|
+
const owner = col(columns, "f", "ZOWNER");
|
|
45002
|
+
const account = owner === "NULL" ? accountRef(columns, "n") : `COALESCE(${owner}, ${accountRef(columns, "n")})`;
|
|
45003
|
+
return `LEFT JOIN ZICCLOUDSYNCINGOBJECT f ON f.Z_PK = n.ZFOLDER AND f.Z_ENT = ${entity("ICFolder")} LEFT JOIN ZICCLOUDSYNCINGOBJECT a ON a.Z_PK = ${account} AND a.Z_ENT = ${entity("ICAccount")}`;
|
|
45004
|
+
}
|
|
45005
|
+
function noteFrom(columns) {
|
|
45006
|
+
return `FROM ZICCLOUDSYNCINGOBJECT n ${folderAccountJoins(columns)}`;
|
|
45007
|
+
}
|
|
45008
|
+
var REQUIRED = ["Z_PK", "Z_ENT", "ZFOLDER", "ZTITLE1"];
|
|
45009
|
+
function buildSpecialNotesSql(columns, kind, scoped) {
|
|
45010
|
+
requireColumns(columns, REQUIRED, "list-special-notes");
|
|
45011
|
+
const created = ["ZCREATIONDATE3", "ZCREATIONDATE1", "ZCREATIONDATE"].filter((name) => columns.has(name)).map((name) => `n.${name}`).join(", ") || "NULL";
|
|
45012
|
+
const createdExpr = created.includes(",") ? `COALESCE(${created})` : created;
|
|
45013
|
+
const modified = col(columns, "n", "ZMODIFICATIONDATE1");
|
|
45014
|
+
const locked = flag(columns, "n", "ZISPASSWORDPROTECTED");
|
|
45015
|
+
const where = `WHERE n.Z_ENT = ${entity("ICNote")} AND ${kindPredicate(columns, kind)}` + (scoped ? " AND a.Z_PK = @account" : "");
|
|
45016
|
+
const snippet = `CASE WHEN ${locked} = 1 THEN NULL ELSE ${col(columns, "n", "ZSNIPPET")} END`;
|
|
45017
|
+
const hint = kind === "locked" ? col(columns, "n", "ZPASSWORDHINT") : "NULL";
|
|
45018
|
+
const row = `SELECT json_object('k', 'note', 'pk', n.Z_PK, 'identifier', ${col(columns, "n", "ZIDENTIFIER")}, 'title', n.ZTITLE1, 'folder', f.Z_PK, 'account', a.Z_PK, 'created', ${createdExpr}, 'modified', ${modified}, 'pinned', ${flag(columns, "n", "ZISPINNED")}, 'locked', ${locked}, 'quick', ${flag(columns, "n", "ZISSYSTEMPAPER")}, 'trash', f.Z_PK IS NOT NULL AND ${trashFolderSql(columns, "f")}, 'tombstoned', NOT ${notTombstonedSql(columns, "n")}, 'snippet', ${snippet}, 'hint', ${hint}) ${noteFrom(columns)} ${where} ORDER BY ${modified} DESC, n.Z_PK DESC LIMIT @limit;`;
|
|
45019
|
+
return [
|
|
45020
|
+
"BEGIN;",
|
|
45021
|
+
`SELECT json_object('k', 'total', 'n', COUNT(*)) ${noteFrom(columns)} ${where};`,
|
|
45022
|
+
row,
|
|
45023
|
+
"COMMIT;"
|
|
45024
|
+
].join(" ");
|
|
45025
|
+
}
|
|
45026
|
+
function listSpecialNotes(options) {
|
|
45027
|
+
const dbPath2 = options.dbPath ?? NOTES_DB_PATH6;
|
|
45028
|
+
const limit = Math.min(
|
|
45029
|
+
Math.max(1, Math.trunc(options.limit ?? SPECIAL_LIMIT.DEFAULT)),
|
|
45030
|
+
SPECIAL_LIMIT.MAX
|
|
45031
|
+
);
|
|
45032
|
+
const columns = readColumns(dbPath2);
|
|
45033
|
+
const empty = {
|
|
45034
|
+
kind: options.kind,
|
|
45035
|
+
notes: [],
|
|
45036
|
+
count: 0,
|
|
45037
|
+
total: 0,
|
|
45038
|
+
limit,
|
|
45039
|
+
supported: false
|
|
45040
|
+
};
|
|
45041
|
+
if (!kindSupported(columns, options.kind)) return empty;
|
|
45042
|
+
const context = readStoreContext(dbPath2, columns);
|
|
45043
|
+
const scope2 = options.account ? resolveAccountName(context.accounts, options.account) : void 0;
|
|
45044
|
+
const params = { limit: { int: limit } };
|
|
45045
|
+
if (scope2) params.account = { int: scope2.pk };
|
|
45046
|
+
const rows = parseJsonLines(
|
|
45047
|
+
runReadOnlySql(dbPath2, buildSpecialNotesSql(columns, options.kind, Boolean(scope2)), params)
|
|
45048
|
+
);
|
|
45049
|
+
const paths = folderPaths(context.folders);
|
|
45050
|
+
const accountNames = new Map(context.accounts.map((account) => [account.pk, account.name]));
|
|
45051
|
+
const notes = rows.filter((row) => row.k === "note").map((row) => toSpecialRow(row, context.uuid, paths, accountNames, options.kind));
|
|
45052
|
+
return {
|
|
45053
|
+
kind: options.kind,
|
|
45054
|
+
notes,
|
|
45055
|
+
count: notes.length,
|
|
45056
|
+
total: rows.find((row) => row.k === "total")?.n ?? notes.length,
|
|
45057
|
+
limit,
|
|
45058
|
+
supported: true,
|
|
45059
|
+
...scope2 ? { account: scope2.name } : {}
|
|
45060
|
+
};
|
|
45061
|
+
}
|
|
45062
|
+
function toSpecialRow(row, uuid2, paths, accountNames, kind) {
|
|
45063
|
+
const locked = Boolean(row.locked);
|
|
45064
|
+
const note = {
|
|
45065
|
+
id: noteIdFor(uuid2, row.pk),
|
|
45066
|
+
identifier: row.identifier ?? null,
|
|
45067
|
+
title: row.title ?? null,
|
|
45068
|
+
folder: row.folder !== null ? paths.get(row.folder) ?? null : null,
|
|
45069
|
+
account: row.account !== null ? accountNames.get(row.account) ?? null : null,
|
|
45070
|
+
created: coreDataToIso(row.created),
|
|
45071
|
+
modified: coreDataToIso(row.modified),
|
|
45072
|
+
pinned: Boolean(row.pinned),
|
|
45073
|
+
locked,
|
|
45074
|
+
quickNote: Boolean(row.quick),
|
|
45075
|
+
inRecentlyDeleted: Boolean(row.trash),
|
|
45076
|
+
markedForDeletion: Boolean(row.tombstoned)
|
|
45077
|
+
};
|
|
45078
|
+
if (!locked) note.snippet = row.snippet ?? null;
|
|
45079
|
+
if (kind === "locked" && row.hint) note.passwordHint = row.hint;
|
|
45080
|
+
return note;
|
|
45081
|
+
}
|
|
45082
|
+
var TAG_REQUIRED = ["Z_PK", "Z_ENT", "ZFOLDER", "ZNOTE1", "ZTYPEUTI1", "ZALTTEXT", "ZIDENTIFIER"];
|
|
45083
|
+
function buildTagInventorySql(columns, scoped) {
|
|
45084
|
+
requireColumns(columns, TAG_REQUIRED, "list-native-tags");
|
|
45085
|
+
const accountFilter = scoped ? " AND a.Z_PK = @account" : "";
|
|
45086
|
+
const uses = `FROM ZICCLOUDSYNCINGOBJECT i JOIN ZICCLOUDSYNCINGOBJECT n ON n.Z_PK = i.ZNOTE1 AND n.Z_ENT = ${entity("ICNote")} ${folderAccountJoins(columns)} WHERE i.ZTYPEUTI1 = '${HASHTAG_UTI}' AND ${notTombstonedSql(columns, "i")} AND ${activeNoteSql(columns, "n", "f")}${accountFilter}`;
|
|
45087
|
+
const tagAccount = accountRef(columns, "t");
|
|
45088
|
+
const display = ["ZDISPLAYTEXT", "ZSTANDARDIZEDCONTENT", "ZNAME"].filter((name) => columns.has(name)).map((name) => `t.${name}`);
|
|
45089
|
+
const displayExpr = display.length > 1 ? `COALESCE(${display.join(", ")})` : display[0] || "NULL";
|
|
45090
|
+
return [
|
|
45091
|
+
"BEGIN;",
|
|
45092
|
+
`SELECT json_object('k', 'tag', 'text', ${displayExpr}, 'account', ta.Z_PK) FROM ZICCLOUDSYNCINGOBJECT t LEFT JOIN ZICCLOUDSYNCINGOBJECT ta ON ta.Z_PK = ${tagAccount} AND ta.Z_ENT = ${entity("ICAccount")} WHERE t.Z_ENT = ${entity("ICHashtag")} AND ${notTombstonedSql(columns, "t")}${scoped ? " AND ta.Z_PK = @account" : ""};`,
|
|
45093
|
+
`SELECT json_object('k', 'use', 'note', n.Z_PK, 'object', i.ZIDENTIFIER, 'text', i.ZALTTEXT, 'account', a.Z_PK, 'locked', ${flag(columns, "n", "ZISPASSWORDPROTECTED")}) ${uses};`,
|
|
45094
|
+
`SELECT json_object('k', 'body', 'note', b.Z_PK, 'data', (SELECT hex(d.ZDATA) FROM ZICNOTEDATA d WHERE d.ZNOTE = b.Z_PK ORDER BY d.Z_PK DESC LIMIT 1)) FROM ZICCLOUDSYNCINGOBJECT b WHERE b.Z_PK IN (SELECT n.Z_PK ${uses}) AND ${flag(columns, "b", "ZISPASSWORDPROTECTED")} = 0;`,
|
|
45095
|
+
"COMMIT;"
|
|
45096
|
+
].join(" ");
|
|
45097
|
+
}
|
|
45098
|
+
var bareTag = (text) => text.replace(/^#/, "").trim();
|
|
45099
|
+
function referencedObjects(hex3) {
|
|
45100
|
+
if (!hex3 || !/^[0-9a-f]+$/i.test(hex3)) return null;
|
|
45101
|
+
try {
|
|
45102
|
+
const data = gunzipSync6(Buffer.from(hex3, "hex"), { maxOutputLength: 32 * 1024 * 1024 });
|
|
45103
|
+
const wrapper = embeddedMessage(getField(decodeMessage(data), 2));
|
|
45104
|
+
const body = wrapper && embeddedMessage(getField(wrapper, 3));
|
|
45105
|
+
if (!body) return null;
|
|
45106
|
+
const ids = /* @__PURE__ */ new Set();
|
|
45107
|
+
for (const run of getFields(body, 5)) {
|
|
45108
|
+
const attachment = embeddedMessage(getField(embeddedMessage(run) ?? [], 12));
|
|
45109
|
+
const id2 = attachment && stringValue(getField(attachment, 1));
|
|
45110
|
+
if (id2) ids.add(id2);
|
|
45111
|
+
}
|
|
45112
|
+
return ids;
|
|
45113
|
+
} catch {
|
|
45114
|
+
return null;
|
|
45115
|
+
}
|
|
45116
|
+
}
|
|
45117
|
+
function nativeTagInventory(options = {}) {
|
|
45118
|
+
const dbPath2 = options.dbPath ?? NOTES_DB_PATH6;
|
|
45119
|
+
const columns = readColumns(dbPath2);
|
|
45120
|
+
const context = readStoreContext(dbPath2, columns);
|
|
45121
|
+
const scope2 = options.account ? resolveAccountName(context.accounts, options.account) : void 0;
|
|
45122
|
+
const rows = parseJsonLines(
|
|
45123
|
+
runReadOnlySql(
|
|
45124
|
+
dbPath2,
|
|
45125
|
+
buildTagInventorySql(columns, Boolean(scope2)),
|
|
45126
|
+
scope2 ? { account: { int: scope2.pk } } : {}
|
|
45127
|
+
)
|
|
45128
|
+
);
|
|
45129
|
+
return assembleInventory(rows, context.accounts, scope2);
|
|
45130
|
+
}
|
|
45131
|
+
function assembleInventory(rows, accounts, scope2) {
|
|
45132
|
+
const accountNames = new Map(accounts.map((account) => [account.pk, account.name]));
|
|
45133
|
+
const bodies = /* @__PURE__ */ new Map();
|
|
45134
|
+
for (const row of rows) if (row.k === "body") bodies.set(row.note, referencedObjects(row.data));
|
|
45135
|
+
const groups = /* @__PURE__ */ new Map();
|
|
45136
|
+
const group = (text, weight) => {
|
|
45137
|
+
const key = text.toLocaleLowerCase();
|
|
45138
|
+
let found = groups.get(key);
|
|
45139
|
+
if (!found) groups.set(key, found = { spellings: /* @__PURE__ */ new Map(), notes: /* @__PURE__ */ new Map() });
|
|
45140
|
+
found.spellings.set(text, (found.spellings.get(text) ?? 0) + weight);
|
|
45141
|
+
return found;
|
|
45142
|
+
};
|
|
45143
|
+
const unverified = /* @__PURE__ */ new Set();
|
|
45144
|
+
for (const row of rows) {
|
|
45145
|
+
if (row.k === "tag" && row.text && bareTag(row.text)) group(bareTag(row.text), 0);
|
|
45146
|
+
if (row.k !== "use" || !row.text || !bareTag(row.text)) continue;
|
|
45147
|
+
const referenced = row.locked ? null : bodies.get(row.note) ?? null;
|
|
45148
|
+
if (referenced && !(row.object && referenced.has(row.object))) continue;
|
|
45149
|
+
if (!referenced) unverified.add(row.note);
|
|
45150
|
+
group(bareTag(row.text), 1).notes.set(row.note, row.account);
|
|
45151
|
+
}
|
|
45152
|
+
const inventory = [...groups.values()].map((entry) => {
|
|
45153
|
+
const spellings = [...entry.spellings.entries()].sort(
|
|
45154
|
+
(a, b) => b[1] - a[1] || a[0].localeCompare(b[0])
|
|
45155
|
+
);
|
|
45156
|
+
const perAccount = {};
|
|
45157
|
+
for (const accountPk of entry.notes.values()) {
|
|
45158
|
+
const name = accountPk !== null && accountNames.get(accountPk) || "unknown";
|
|
45159
|
+
perAccount[name] = (perAccount[name] ?? 0) + 1;
|
|
45160
|
+
}
|
|
45161
|
+
const result = {
|
|
45162
|
+
tag: spellings[0][0],
|
|
45163
|
+
noteCount: entry.notes.size,
|
|
45164
|
+
accounts: perAccount
|
|
45165
|
+
};
|
|
45166
|
+
if (spellings.length > 1) result.spellings = spellings.slice(1).map(([text]) => text);
|
|
45167
|
+
return result;
|
|
45168
|
+
});
|
|
45169
|
+
inventory.sort((a, b) => b.noteCount - a.noteCount || a.tag.localeCompare(b.tag));
|
|
45170
|
+
return {
|
|
45171
|
+
inventory,
|
|
45172
|
+
tagCount: inventory.length,
|
|
45173
|
+
complete: unverified.size === 0,
|
|
45174
|
+
unverifiedNotes: unverified.size,
|
|
45175
|
+
...scope2 ? { account: scope2.name } : {}
|
|
45176
|
+
};
|
|
45177
|
+
}
|
|
45178
|
+
|
|
45179
|
+
// src/utils/noteIdentifiers.ts
|
|
45180
|
+
import { execFileSync as execFileSync11 } from "child_process";
|
|
45181
|
+
import * as fs6 from "fs";
|
|
45182
|
+
import * as os6 from "os";
|
|
45183
|
+
import * as path6 from "path";
|
|
45184
|
+
var NOTES_DB_PATH7 = path6.join(
|
|
45185
|
+
os6.homedir(),
|
|
45186
|
+
"Library/Group Containers/group.com.apple.notes/NoteStore.sqlite"
|
|
45187
|
+
);
|
|
44784
45188
|
var UUID_PATTERN = /^[0-9A-Fa-f]{8}(?:-[0-9A-Fa-f]{4}){3}-[0-9A-Fa-f]{12}$/;
|
|
44785
45189
|
var NUMERIC_KEY_PATTERN = /^\d{1,18}$/;
|
|
44786
45190
|
var NOTE_ID_MESSAGE = "A canonical Apple Note ID is required (x-coredata://.../ICNote/p...), or the note's Notes UUID or numeric key";
|
|
@@ -44814,10 +45218,10 @@ function assertAll(values, pattern, label) {
|
|
|
44814
45218
|
if (!pattern.test(value)) throw new Error(`Refusing to query with an invalid ${label}`);
|
|
44815
45219
|
}
|
|
44816
45220
|
}
|
|
44817
|
-
function entityClause(
|
|
44818
|
-
return `(SELECT Z_ENT FROM Z_PRIMARYKEY WHERE Z_NAME = '${
|
|
45221
|
+
function entityClause(entity3) {
|
|
45222
|
+
return `(SELECT Z_ENT FROM Z_PRIMARYKEY WHERE Z_NAME = '${entity3}')`;
|
|
44819
45223
|
}
|
|
44820
|
-
function buildResolveSql(
|
|
45224
|
+
function buildResolveSql(entity3, keys, uuids) {
|
|
44821
45225
|
assertAll(keys, NUMERIC_KEY_PATTERN, "numeric key");
|
|
44822
45226
|
assertAll(uuids, UUID_PATTERN, "UUID");
|
|
44823
45227
|
const matches = [];
|
|
@@ -44834,28 +45238,28 @@ function buildResolveSql(entity2, keys, uuids) {
|
|
|
44834
45238
|
matches.push(`o.ZIDENTIFIER IN (${[...variants].map((v) => `'${v}'`).join(", ")})`);
|
|
44835
45239
|
}
|
|
44836
45240
|
const where = matches.length > 0 ? matches.join(" OR ") : "0";
|
|
44837
|
-
return `SELECT json_object('store', (SELECT Z_UUID FROM Z_METADATA LIMIT 1), 'rows', (SELECT json_group_array(json_object('pk', o.Z_PK, 'identifier', o.ZIDENTIFIER)) FROM ZICCLOUDSYNCINGOBJECT o WHERE o.Z_ENT = ${entityClause(
|
|
45241
|
+
return `SELECT json_object('store', (SELECT Z_UUID FROM Z_METADATA LIMIT 1), 'rows', (SELECT json_group_array(json_object('pk', o.Z_PK, 'identifier', o.ZIDENTIFIER)) FROM ZICCLOUDSYNCINGOBJECT o WHERE o.Z_ENT = ${entityClause(entity3)} AND (${where})));`;
|
|
44838
45242
|
}
|
|
44839
|
-
function buildLookupSql(
|
|
45243
|
+
function buildLookupSql(entity3, keys) {
|
|
44840
45244
|
assertAll(keys, NUMERIC_KEY_PATTERN, "numeric key");
|
|
44841
45245
|
const pks = [...new Set(keys.map(canonicalKey))];
|
|
44842
45246
|
const inList = pks.length > 0 ? pks.join(", ") : "NULL";
|
|
44843
45247
|
let fields = "'pk', o.Z_PK, 'identifier', o.ZIDENTIFIER";
|
|
44844
45248
|
let joins = "";
|
|
44845
|
-
if (
|
|
45249
|
+
if (entity3 === "ICNote") {
|
|
44846
45250
|
fields += ", 'folderIdentifier', f.ZIDENTIFIER, 'accountIdentifier', a.ZIDENTIFIER";
|
|
44847
45251
|
joins = "LEFT JOIN ZICCLOUDSYNCINGOBJECT f ON f.Z_PK = o.ZFOLDER LEFT JOIN ZICCLOUDSYNCINGOBJECT a ON a.Z_PK = f.ZOWNER ";
|
|
44848
|
-
} else if (
|
|
45252
|
+
} else if (entity3 === "ICFolder") {
|
|
44849
45253
|
fields += ", 'parentIdentifier', p.ZIDENTIFIER, 'accountIdentifier', a.ZIDENTIFIER";
|
|
44850
45254
|
joins = "LEFT JOIN ZICCLOUDSYNCINGOBJECT p ON p.Z_PK = o.ZPARENT LEFT JOIN ZICCLOUDSYNCINGOBJECT a ON a.Z_PK = o.ZOWNER ";
|
|
44851
45255
|
}
|
|
44852
|
-
return `SELECT json_object('store', (SELECT Z_UUID FROM Z_METADATA LIMIT 1), 'rows', (SELECT json_group_array(json_object(${fields})) FROM ZICCLOUDSYNCINGOBJECT o ${joins}WHERE o.Z_ENT = ${entityClause(
|
|
45256
|
+
return `SELECT json_object('store', (SELECT Z_UUID FROM Z_METADATA LIMIT 1), 'rows', (SELECT json_group_array(json_object(${fields})) FROM ZICCLOUDSYNCINGOBJECT o ${joins}WHERE o.Z_ENT = ${entityClause(entity3)} AND o.Z_PK IN (${inList})));`;
|
|
44853
45257
|
}
|
|
44854
45258
|
function runJsonQuery(sql, dbPath2) {
|
|
44855
|
-
if (!
|
|
45259
|
+
if (!fs6.existsSync(dbPath2)) throw new IdentifierResolutionError("no_fda", NO_FDA_MESSAGE);
|
|
44856
45260
|
let out;
|
|
44857
45261
|
try {
|
|
44858
|
-
out =
|
|
45262
|
+
out = execFileSync11("sqlite3", ["-readonly", dbPath2, sql], {
|
|
44859
45263
|
encoding: "utf8",
|
|
44860
45264
|
timeout: 5e3,
|
|
44861
45265
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -44872,10 +45276,10 @@ function runJsonQuery(sql, dbPath2) {
|
|
|
44872
45276
|
const rows = typeof parsed.rows === "string" ? JSON.parse(parsed.rows) : parsed.rows;
|
|
44873
45277
|
return { store: parsed.store ?? null, rows: rows ?? [] };
|
|
44874
45278
|
}
|
|
44875
|
-
function coreDataId(store,
|
|
44876
|
-
return `x-coredata://${store}/${
|
|
45279
|
+
function coreDataId(store, entity3, pk) {
|
|
45280
|
+
return `x-coredata://${store}/${entity3}/p${pk}`;
|
|
44877
45281
|
}
|
|
44878
|
-
function resolveIdentifiers(values,
|
|
45282
|
+
function resolveIdentifiers(values, entity3, dbPath2 = NOTES_DB_PATH7) {
|
|
44879
45283
|
const resolved = /* @__PURE__ */ new Map();
|
|
44880
45284
|
const keys = [];
|
|
44881
45285
|
const uuids = [];
|
|
@@ -44887,7 +45291,7 @@ function resolveIdentifiers(values, entity2, dbPath2 = NOTES_DB_PATH6) {
|
|
|
44887
45291
|
}
|
|
44888
45292
|
if (keys.length === 0 && uuids.length === 0) return resolved;
|
|
44889
45293
|
const { store, rows } = runJsonQuery(
|
|
44890
|
-
buildResolveSql(
|
|
45294
|
+
buildResolveSql(entity3, keys, uuids),
|
|
44891
45295
|
dbPath2
|
|
44892
45296
|
);
|
|
44893
45297
|
if (!store) {
|
|
@@ -44900,16 +45304,16 @@ function resolveIdentifiers(values, entity2, dbPath2 = NOTES_DB_PATH6) {
|
|
|
44900
45304
|
const byUuid = new Map(
|
|
44901
45305
|
rows.filter((row) => row.identifier).map((row) => [String(row.identifier).toUpperCase(), row])
|
|
44902
45306
|
);
|
|
44903
|
-
const label = ENTITY_LABEL[
|
|
45307
|
+
const label = ENTITY_LABEL[entity3];
|
|
44904
45308
|
const missing = [];
|
|
44905
45309
|
for (const key of keys) {
|
|
44906
45310
|
const row = byKey.get(canonicalKey(key));
|
|
44907
|
-
if (row) resolved.set(key, coreDataId(store,
|
|
45311
|
+
if (row) resolved.set(key, coreDataId(store, entity3, row.pk));
|
|
44908
45312
|
else missing.push(`numeric key ${key}`);
|
|
44909
45313
|
}
|
|
44910
45314
|
for (const uuid2 of uuids) {
|
|
44911
45315
|
const row = byUuid.get(uuid2.toUpperCase());
|
|
44912
|
-
if (row) resolved.set(uuid2, coreDataId(store,
|
|
45316
|
+
if (row) resolved.set(uuid2, coreDataId(store, entity3, row.pk));
|
|
44913
45317
|
else missing.push(`identifier ${uuid2}`);
|
|
44914
45318
|
}
|
|
44915
45319
|
if (missing.length > 0) {
|
|
@@ -44921,12 +45325,12 @@ function resolveIdentifiers(values, entity2, dbPath2 = NOTES_DB_PATH6) {
|
|
|
44921
45325
|
return resolved;
|
|
44922
45326
|
}
|
|
44923
45327
|
var COREDATA_PARTS = /^x-coredata:\/\/([0-9A-Fa-f-]+)\/(ICNote|ICFolder|ICAccount)\/p(\d{1,18})$/;
|
|
44924
|
-
function lookupStableIdentifiers(ids,
|
|
45328
|
+
function lookupStableIdentifiers(ids, entity3, dbPath2 = NOTES_DB_PATH7) {
|
|
44925
45329
|
const result = /* @__PURE__ */ new Map();
|
|
44926
45330
|
const wanted = /* @__PURE__ */ new Map();
|
|
44927
45331
|
for (const id2 of ids) {
|
|
44928
45332
|
const match = COREDATA_PARTS.exec(id2);
|
|
44929
|
-
if (!match || match[2] !==
|
|
45333
|
+
if (!match || match[2] !== entity3) continue;
|
|
44930
45334
|
const pk = canonicalKey(match[3]);
|
|
44931
45335
|
const list = wanted.get(pk) ?? [];
|
|
44932
45336
|
list.push({ id: id2, store: match[1] });
|
|
@@ -44935,7 +45339,7 @@ function lookupStableIdentifiers(ids, entity2, dbPath2 = NOTES_DB_PATH6) {
|
|
|
44935
45339
|
if (wanted.size === 0) return result;
|
|
44936
45340
|
let query;
|
|
44937
45341
|
try {
|
|
44938
|
-
query = runJsonQuery(buildLookupSql(
|
|
45342
|
+
query = runJsonQuery(buildLookupSql(entity3, [...wanted.keys()]), dbPath2);
|
|
44939
45343
|
} catch {
|
|
44940
45344
|
return result;
|
|
44941
45345
|
}
|
|
@@ -44957,16 +45361,16 @@ function lookupStableIdentifiers(ids, entity2, dbPath2 = NOTES_DB_PATH6) {
|
|
|
44957
45361
|
}
|
|
44958
45362
|
return result;
|
|
44959
45363
|
}
|
|
44960
|
-
function withStableIdentifiers(items,
|
|
45364
|
+
function withStableIdentifiers(items, entity3, dbPath2 = NOTES_DB_PATH7) {
|
|
44961
45365
|
const ids = items.map((item) => item.id).filter((id2) => typeof id2 === "string");
|
|
44962
45366
|
if (ids.length === 0) return items;
|
|
44963
|
-
const found = lookupStableIdentifiers(ids,
|
|
45367
|
+
const found = lookupStableIdentifiers(ids, entity3, dbPath2);
|
|
44964
45368
|
if (found.size === 0) return items;
|
|
44965
45369
|
return items.map(
|
|
44966
45370
|
(item) => item.id && found.has(item.id) ? { ...item, ...found.get(item.id) } : item
|
|
44967
45371
|
);
|
|
44968
45372
|
}
|
|
44969
|
-
var defaultResolver = (values,
|
|
45373
|
+
var defaultResolver = (values, entity3) => resolveIdentifiers(values, entity3);
|
|
44970
45374
|
var DEFAULT_MAX_ID_LENGTH = 2e3;
|
|
44971
45375
|
function acceptAlternateForms(pattern) {
|
|
44972
45376
|
return new RegExp(
|
|
@@ -44974,10 +45378,10 @@ function acceptAlternateForms(pattern) {
|
|
|
44974
45378
|
pattern.flags
|
|
44975
45379
|
);
|
|
44976
45380
|
}
|
|
44977
|
-
function resolveInSchema(values,
|
|
45381
|
+
function resolveInSchema(values, entity3, ctx, resolver) {
|
|
44978
45382
|
if (!values.some(isAlternateIdentifier)) return new Map(values.map((v) => [v, v]));
|
|
44979
45383
|
try {
|
|
44980
|
-
return resolver(values,
|
|
45384
|
+
return resolver(values, entity3);
|
|
44981
45385
|
} catch (error2) {
|
|
44982
45386
|
ctx.addIssue({
|
|
44983
45387
|
code: external_exports.ZodIssueCode.custom,
|
|
@@ -44986,26 +45390,26 @@ function resolveInSchema(values, entity2, ctx, resolver) {
|
|
|
44986
45390
|
return null;
|
|
44987
45391
|
}
|
|
44988
45392
|
}
|
|
44989
|
-
function exactIdInput(
|
|
45393
|
+
function exactIdInput(entity3, pattern, message, options = {}) {
|
|
44990
45394
|
const resolver = options.resolver ?? defaultResolver;
|
|
44991
45395
|
return external_exports.string().max(options.maxLength ?? DEFAULT_MAX_ID_LENGTH).regex(acceptAlternateForms(pattern), message).transform((value, ctx) => {
|
|
44992
|
-
const map = resolveInSchema([value],
|
|
45396
|
+
const map = resolveInSchema([value], entity3, ctx, resolver);
|
|
44993
45397
|
return map ? map.get(value) ?? value : external_exports.NEVER;
|
|
44994
45398
|
});
|
|
44995
45399
|
}
|
|
44996
|
-
function exactIdArrayInput(
|
|
45400
|
+
function exactIdArrayInput(entity3, pattern, message, options = {}) {
|
|
44997
45401
|
const resolver = options.resolver ?? defaultResolver;
|
|
44998
45402
|
const item = external_exports.string().max(options.maxLength ?? DEFAULT_MAX_ID_LENGTH).regex(acceptAlternateForms(pattern), message);
|
|
44999
45403
|
const array2 = options.maxItems === void 0 ? external_exports.array(item) : external_exports.array(item).max(options.maxItems);
|
|
45000
45404
|
return array2.transform((values, ctx) => {
|
|
45001
|
-
const map = resolveInSchema(values,
|
|
45405
|
+
const map = resolveInSchema(values, entity3, ctx, resolver);
|
|
45002
45406
|
return map ? values.map((value) => map.get(value) ?? value) : external_exports.NEVER;
|
|
45003
45407
|
});
|
|
45004
45408
|
}
|
|
45005
|
-
function looseIdTransform(
|
|
45409
|
+
function looseIdTransform(entity3, resolver = defaultResolver) {
|
|
45006
45410
|
return (value, ctx) => {
|
|
45007
45411
|
if (!isAlternateIdentifier(value)) return value;
|
|
45008
|
-
const map = resolveInSchema([value],
|
|
45412
|
+
const map = resolveInSchema([value], entity3, ctx, resolver);
|
|
45009
45413
|
return map ? map.get(value) ?? value : external_exports.NEVER;
|
|
45010
45414
|
};
|
|
45011
45415
|
}
|
|
@@ -45545,18 +45949,18 @@ function positiveTextTerms(node, negated = false) {
|
|
|
45545
45949
|
}
|
|
45546
45950
|
|
|
45547
45951
|
// src/utils/noteQueryStore.ts
|
|
45548
|
-
import { execFileSync as
|
|
45549
|
-
import * as
|
|
45550
|
-
import * as
|
|
45551
|
-
import * as
|
|
45552
|
-
import { gunzipSync as
|
|
45553
|
-
var
|
|
45554
|
-
|
|
45952
|
+
import { execFileSync as execFileSync12 } from "child_process";
|
|
45953
|
+
import * as fs7 from "fs";
|
|
45954
|
+
import * as os7 from "os";
|
|
45955
|
+
import * as path7 from "path";
|
|
45956
|
+
import { gunzipSync as gunzipSync7 } from "zlib";
|
|
45957
|
+
var NOTES_DB_PATH8 = path7.join(
|
|
45958
|
+
os7.homedir(),
|
|
45555
45959
|
"Library/Group Containers/group.com.apple.notes/NoteStore.sqlite"
|
|
45556
45960
|
);
|
|
45557
45961
|
var QUERY_SCAN = { DEFAULT: 500, MAX: 5e3 };
|
|
45558
45962
|
var QUERY_RESULTS = { DEFAULT: 50, MAX: 500 };
|
|
45559
|
-
var
|
|
45963
|
+
var CORE_DATA_EPOCH_MS2 = Date.UTC(2001, 0, 1);
|
|
45560
45964
|
var SNIPPET_BEFORE = 60;
|
|
45561
45965
|
var SNIPPET_LENGTH = 180;
|
|
45562
45966
|
var QUERY_FDA_MESSAGE = `Full Disk Access is required to query notes. In System Settings > Privacy & Security > Full Disk Access, grant access to the app that launches this server (Claude Desktop / Terminal / iTerm2), then fully quit and relaunch it. Setup guide: ${FULL_DISK_ACCESS_GUIDE_URL} \u2014 run the doctor tool to verify.`;
|
|
@@ -45639,10 +46043,10 @@ function countWords(text) {
|
|
|
45639
46043
|
return count;
|
|
45640
46044
|
}
|
|
45641
46045
|
var REQUIRED_COLUMNS3 = ["Z_PK", "Z_ENT", "ZTITLE1", "ZFOLDER", "ZMODIFICATIONDATE1"];
|
|
45642
|
-
function
|
|
46046
|
+
function col2(available, alias, name) {
|
|
45643
46047
|
return available.has(name) ? `${alias}.${name}` : "NULL";
|
|
45644
46048
|
}
|
|
45645
|
-
var
|
|
46049
|
+
var entity2 = (name) => `(SELECT Z_ENT FROM Z_PRIMARYKEY WHERE Z_NAME='${name}')`;
|
|
45646
46050
|
function buildScanSql(available, options) {
|
|
45647
46051
|
const missing = REQUIRED_COLUMNS3.filter((c) => !available.has(c));
|
|
45648
46052
|
if (missing.length) {
|
|
@@ -45660,21 +46064,21 @@ function buildScanSql(available, options) {
|
|
|
45660
46064
|
const bool = (name) => available.has(name) ? `COALESCE(n.${name}, 0)` : "0";
|
|
45661
46065
|
const notNull = (alias, name) => available.has(name) ? `${alias}.${name} IS NOT NULL` : "0";
|
|
45662
46066
|
const tagsExpr = options.withTags && ["ZNOTE1", "ZTYPEUTI1", "ZALTTEXT", "ZIDENTIFIER"].every((c) => available.has(c)) ? `(SELECT json_group_array(json_array(t.ZIDENTIFIER, t.ZALTTEXT)) FROM ZICCLOUDSYNCINGOBJECT t WHERE t.ZNOTE1 = n.Z_PK AND t.ZTYPEUTI1 = 'com.apple.notes.inlinetextattachment.hashtag')` : "NULL";
|
|
45663
|
-
const where = [`n.Z_ENT = ${
|
|
46067
|
+
const where = [`n.Z_ENT = ${entity2("ICNote")}`];
|
|
45664
46068
|
if (!options.includeDeleted) {
|
|
45665
46069
|
where.push("n.ZFOLDER IS NOT NULL");
|
|
45666
46070
|
if (available.has("ZMARKEDFORDELETION")) where.push("COALESCE(n.ZMARKEDFORDELETION, 0) = 0");
|
|
45667
46071
|
if (available.has("ZFOLDERTYPE")) {
|
|
45668
46072
|
where.push(
|
|
45669
|
-
`n.ZFOLDER NOT IN (SELECT Z_PK FROM ZICCLOUDSYNCINGOBJECT WHERE Z_ENT = ${
|
|
46073
|
+
`n.ZFOLDER NOT IN (SELECT Z_PK FROM ZICCLOUDSYNCINGOBJECT WHERE Z_ENT = ${entity2("ICFolder")} AND ZFOLDERTYPE = 1)`
|
|
45670
46074
|
);
|
|
45671
46075
|
}
|
|
45672
46076
|
}
|
|
45673
46077
|
const whereSql = where.join(" AND ");
|
|
45674
|
-
const folderRow = `SELECT json_object('k', 'folder', 'pk', f.Z_PK, 'name', ${
|
|
45675
|
-
const accountRow = `SELECT json_object('k', 'account', 'pk', a.Z_PK, 'name', ${
|
|
46078
|
+
const folderRow = `SELECT json_object('k', 'folder', 'pk', f.Z_PK, 'name', ${col2(available, "f", "ZTITLE2")}, 'parent', ${col2(available, "f", "ZPARENT")}, 'type', ${col2(available, "f", "ZFOLDERTYPE")}, 'owner', ${col2(available, "f", "ZOWNER")}, 'shared', ${notNull("f", "ZSERVERSHAREDATA")}) FROM ZICCLOUDSYNCINGOBJECT f WHERE f.Z_ENT = ${entity2("ICFolder")};`;
|
|
46079
|
+
const accountRow = `SELECT json_object('k', 'account', 'pk', a.Z_PK, 'name', ${col2(available, "a", "ZNAME")}) FROM ZICCLOUDSYNCINGOBJECT a WHERE a.Z_ENT = ${entity2("ICAccount")};`;
|
|
45676
46080
|
const dataExpr = options.withBodies ? "(SELECT hex(d.ZDATA) FROM ZICNOTEDATA d WHERE d.ZNOTE = n.Z_PK ORDER BY d.Z_PK DESC LIMIT 1)" : "NULL";
|
|
45677
|
-
const noteRow = `SELECT json_object('k', 'note', 'pk', n.Z_PK, 'title', n.ZTITLE1, 'folder', n.ZFOLDER, 'created', ${createdExpr}, 'modified', n.ZMODIFICATIONDATE1, 'pinned', ${bool("ZISPINNED")}, 'locked', ${bool("ZISPASSWORDPROTECTED")}, 'shared', ${notNull("n", "ZSERVERSHAREDATA")}, 'snippet', ${
|
|
46081
|
+
const noteRow = `SELECT json_object('k', 'note', 'pk', n.Z_PK, 'title', n.ZTITLE1, 'folder', n.ZFOLDER, 'created', ${createdExpr}, 'modified', n.ZMODIFICATIONDATE1, 'pinned', ${bool("ZISPINNED")}, 'locked', ${bool("ZISPASSWORDPROTECTED")}, 'shared', ${notNull("n", "ZSERVERSHAREDATA")}, 'snippet', ${col2(available, "n", "ZSNIPPET")}, 'data', ${dataExpr}, 'tags', ${tagsExpr}) FROM ZICCLOUDSYNCINGOBJECT n WHERE ${whereSql} ORDER BY n.ZMODIFICATIONDATE1 DESC, n.Z_PK DESC LIMIT ${scan};`;
|
|
45678
46082
|
return [
|
|
45679
46083
|
"BEGIN;",
|
|
45680
46084
|
"SELECT json_object('k', 'meta', 'uuid', (SELECT Z_UUID FROM Z_METADATA LIMIT 1));",
|
|
@@ -45686,7 +46090,7 @@ function buildScanSql(available, options) {
|
|
|
45686
46090
|
].join(" ");
|
|
45687
46091
|
}
|
|
45688
46092
|
function runSqlite6(dbPath2, query) {
|
|
45689
|
-
return
|
|
46093
|
+
return execFileSync12("sqlite3", ["-readonly", dbPath2, query], {
|
|
45690
46094
|
encoding: "utf8",
|
|
45691
46095
|
timeout: 3e4,
|
|
45692
46096
|
maxBuffer: 512 * 1024 * 1024,
|
|
@@ -45713,12 +46117,12 @@ function resolveFolders(rows) {
|
|
|
45713
46117
|
seen.add(pk);
|
|
45714
46118
|
const parent = row.parent !== null ? resolve4(row.parent, seen) : void 0;
|
|
45715
46119
|
const name = row.name ?? "";
|
|
45716
|
-
const
|
|
46120
|
+
const path8 = parent ? `${parent.path}/${escapeSegment(name)}` : escapeSegment(name);
|
|
45717
46121
|
const plainPath = parent ? `${parent.plainPath}/${name}` : name;
|
|
45718
46122
|
const info = {
|
|
45719
|
-
path:
|
|
46123
|
+
path: path8,
|
|
45720
46124
|
plainPath,
|
|
45721
|
-
keys: [...new Set([name, plainPath,
|
|
46125
|
+
keys: [...new Set([name, plainPath, path8].map(normalizeForMatch))],
|
|
45722
46126
|
accountPk: row.owner ?? parent?.accountPk ?? null,
|
|
45723
46127
|
shared: Boolean(row.shared) || Boolean(parent?.shared)
|
|
45724
46128
|
};
|
|
@@ -45728,7 +46132,7 @@ function resolveFolders(rows) {
|
|
|
45728
46132
|
for (const row of rows) resolve4(row.pk, /* @__PURE__ */ new Set());
|
|
45729
46133
|
return resolved;
|
|
45730
46134
|
}
|
|
45731
|
-
var coreDataMs = (seconds) => seconds === null || !Number.isFinite(seconds) ? void 0 :
|
|
46135
|
+
var coreDataMs = (seconds) => seconds === null || !Number.isFinite(seconds) ? void 0 : CORE_DATA_EPOCH_MS2 + seconds * 1e3;
|
|
45732
46136
|
function buildSnippet(text, terms) {
|
|
45733
46137
|
const clean = text.replace(/\ufffc/gu, " ");
|
|
45734
46138
|
const firstBreak = clean.indexOf("\n");
|
|
@@ -45750,8 +46154,8 @@ function queryNotes(expression, options = {}) {
|
|
|
45750
46154
|
const includeDeleted = options.includeDeleted ?? false;
|
|
45751
46155
|
const withBodies = needsContent(ast);
|
|
45752
46156
|
const withTags = needsTags(ast);
|
|
45753
|
-
const dbPath2 = options.dbPath ??
|
|
45754
|
-
if (!
|
|
46157
|
+
const dbPath2 = options.dbPath ?? NOTES_DB_PATH8;
|
|
46158
|
+
if (!fs7.existsSync(dbPath2)) throw new NoteQueryStoreError(QUERY_FDA_MESSAGE, "no_fda");
|
|
45755
46159
|
let output;
|
|
45756
46160
|
try {
|
|
45757
46161
|
const available = presentColumns2(dbPath2);
|
|
@@ -45811,7 +46215,7 @@ function queryNotes(expression, options = {}) {
|
|
|
45811
46215
|
try {
|
|
45812
46216
|
decoded = decodeNoteBody(
|
|
45813
46217
|
new Uint8Array(
|
|
45814
|
-
|
|
46218
|
+
gunzipSync7(Buffer.from(row.data, "hex"), { maxOutputLength: 32 * 1024 * 1024 })
|
|
45815
46219
|
)
|
|
45816
46220
|
);
|
|
45817
46221
|
} catch {
|
|
@@ -45886,10 +46290,10 @@ function queryNotes(expression, options = {}) {
|
|
|
45886
46290
|
import { spawnSync } from "child_process";
|
|
45887
46291
|
|
|
45888
46292
|
// src/services/nativeTags.ts
|
|
45889
|
-
import { execFileSync as
|
|
46293
|
+
import { execFileSync as execFileSync13 } from "node:child_process";
|
|
45890
46294
|
import { mkdtempSync as mkdtempSync2, writeFileSync, rmSync as rmSync2 } from "node:fs";
|
|
45891
46295
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
45892
|
-
import { join as
|
|
46296
|
+
import { join as join14 } from "node:path";
|
|
45893
46297
|
|
|
45894
46298
|
// src/services/shortcutConsent.ts
|
|
45895
46299
|
function shortcutConsentHint(shortcut) {
|
|
@@ -45965,7 +46369,7 @@ function addNativeTags(request, deps) {
|
|
|
45965
46369
|
};
|
|
45966
46370
|
}
|
|
45967
46371
|
function listInstalledShortcuts() {
|
|
45968
|
-
return
|
|
46372
|
+
return execFileSync13("/usr/bin/shortcuts", ["list", "--show-identifiers"], {
|
|
45969
46373
|
encoding: "utf8",
|
|
45970
46374
|
timeout: 15e3,
|
|
45971
46375
|
maxBuffer: 1024 * 1024,
|
|
@@ -45991,11 +46395,11 @@ function runNativeTagsShortcut(input) {
|
|
|
45991
46395
|
const status = nativeTagsStatus();
|
|
45992
46396
|
if (!status.installed)
|
|
45993
46397
|
throw new Error(`Import the supplied ${status.shortcut}.shortcut in Shortcuts first`);
|
|
45994
|
-
const directory = mkdtempSync2(
|
|
46398
|
+
const directory = mkdtempSync2(join14(tmpdir2(), "apple-notes-native-tags-"));
|
|
45995
46399
|
try {
|
|
45996
|
-
const
|
|
45997
|
-
writeFileSync(
|
|
45998
|
-
|
|
46400
|
+
const path8 = join14(directory, "request.json");
|
|
46401
|
+
writeFileSync(path8, JSON.stringify(input), { mode: 384 });
|
|
46402
|
+
execFileSync13("/usr/bin/shortcuts", ["run", status.identifier, "--input-path", path8], {
|
|
45999
46403
|
encoding: "utf8",
|
|
46000
46404
|
timeout: 6e4,
|
|
46001
46405
|
maxBuffer: 1024 * 1024,
|
|
@@ -46014,10 +46418,10 @@ function runNativeTagsShortcut(input) {
|
|
|
46014
46418
|
}
|
|
46015
46419
|
|
|
46016
46420
|
// src/services/backgroundNotes.ts
|
|
46017
|
-
import { execFileSync as
|
|
46421
|
+
import { execFileSync as execFileSync14 } from "node:child_process";
|
|
46018
46422
|
import { mkdtempSync as mkdtempSync3, writeFileSync as writeFileSync2, rmSync as rmSync3 } from "node:fs";
|
|
46019
46423
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
46020
|
-
import { join as
|
|
46424
|
+
import { join as join15 } from "node:path";
|
|
46021
46425
|
|
|
46022
46426
|
// src/utils/appendMarkdown.ts
|
|
46023
46427
|
var escape2 = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
@@ -46342,9 +46746,9 @@ function runBackgroundShortcut(input, status = backgroundStatus()) {
|
|
|
46342
46746
|
throw new Error(
|
|
46343
46747
|
`Install the supplied "${status.shortcut}" Shortcut once; Shortcuts must list it exactly once`
|
|
46344
46748
|
);
|
|
46345
|
-
const directory = mkdtempSync3(
|
|
46749
|
+
const directory = mkdtempSync3(join15(tmpdir3(), "apple-notes-background-"));
|
|
46346
46750
|
try {
|
|
46347
|
-
const file =
|
|
46751
|
+
const file = join15(directory, "request.json");
|
|
46348
46752
|
writeFileSync2(
|
|
46349
46753
|
file,
|
|
46350
46754
|
JSON.stringify({
|
|
@@ -46364,7 +46768,7 @@ function runBackgroundShortcut(input, status = backgroundStatus()) {
|
|
|
46364
46768
|
{ mode: 384 }
|
|
46365
46769
|
);
|
|
46366
46770
|
try {
|
|
46367
|
-
|
|
46771
|
+
execFileSync14("/usr/bin/shortcuts", ["run", status.identifier, "--input-path", file], {
|
|
46368
46772
|
encoding: "utf8",
|
|
46369
46773
|
timeout: callTimeoutMs() ?? 6e4,
|
|
46370
46774
|
maxBuffer: 1024 * 1024,
|
|
@@ -46599,7 +47003,7 @@ function createMarkdownNote(manager, request, run = runBackgroundShortcut) {
|
|
|
46599
47003
|
throw new Error(
|
|
46600
47004
|
`Install the supplied "${status.shortcut}" Shortcut once; Shortcuts must list it exactly once`
|
|
46601
47005
|
);
|
|
46602
|
-
const segments = (
|
|
47006
|
+
const segments = (path8) => JSON.stringify(splitFolderPath(path8).map((part) => part.toLocaleLowerCase()));
|
|
46603
47007
|
if (request.folder) {
|
|
46604
47008
|
const wanted = segments(request.folder);
|
|
46605
47009
|
if (!manager.listAccounts().some(
|
|
@@ -46689,7 +47093,7 @@ ${request.content}`
|
|
|
46689
47093
|
}
|
|
46690
47094
|
|
|
46691
47095
|
// src/services/capabilityMatrix.ts
|
|
46692
|
-
import { execFileSync as
|
|
47096
|
+
import { execFileSync as execFileSync15 } from "node:child_process";
|
|
46693
47097
|
import { release } from "node:os";
|
|
46694
47098
|
var MACOS_SHORTCUTS_CLI = "12.0";
|
|
46695
47099
|
var MACOS_MARKDOWN_IMPORT = "26.0";
|
|
@@ -46896,7 +47300,7 @@ function evaluateFeatures(env, features = FEATURES) {
|
|
|
46896
47300
|
function readMacOSVersion() {
|
|
46897
47301
|
if (process.platform !== "darwin") return null;
|
|
46898
47302
|
try {
|
|
46899
|
-
const out =
|
|
47303
|
+
const out = execFileSync15("/usr/bin/sw_vers", ["-productVersion"], {
|
|
46900
47304
|
encoding: "utf8",
|
|
46901
47305
|
timeout: 3e3,
|
|
46902
47306
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -46929,9 +47333,9 @@ function getCapabilityMatrix(probe = probeCapabilityEnvironment) {
|
|
|
46929
47333
|
return evaluateFeatures(probe());
|
|
46930
47334
|
}
|
|
46931
47335
|
function formatCapabilityMatrix(matrix) {
|
|
46932
|
-
const
|
|
47336
|
+
const os8 = matrix.runtimeOS;
|
|
46933
47337
|
const lines = [
|
|
46934
|
-
`Feature matrix (macOS ${
|
|
47338
|
+
`Feature matrix (macOS ${os8.macOSVersion ?? "unknown"}, Darwin ${os8.darwinRelease}):`
|
|
46935
47339
|
];
|
|
46936
47340
|
for (const [name, status] of Object.entries(matrix.features)) {
|
|
46937
47341
|
lines.push(
|
|
@@ -47049,19 +47453,19 @@ function formatDoctorReport(r) {
|
|
|
47049
47453
|
}
|
|
47050
47454
|
|
|
47051
47455
|
// src/services/fileConfig.ts
|
|
47052
|
-
import { existsSync as
|
|
47053
|
-
import { join as
|
|
47054
|
-
import { homedir as
|
|
47456
|
+
import { existsSync as existsSync10, readFileSync as readFileSync2 } from "fs";
|
|
47457
|
+
import { join as join16 } from "path";
|
|
47458
|
+
import { homedir as homedir13 } from "os";
|
|
47055
47459
|
function fileConfigPath(env = process.env) {
|
|
47056
47460
|
const override = env.APPLE_NOTES_MCP_CONFIG_FILE;
|
|
47057
47461
|
if (override && override.trim()) return override.trim();
|
|
47058
|
-
return
|
|
47462
|
+
return join16(homedir13(), "Library", "Application Support", "apple-notes-mcp", "config.json");
|
|
47059
47463
|
}
|
|
47060
|
-
function loadFileConfig(env = process.env,
|
|
47464
|
+
function loadFileConfig(env = process.env, path8 = fileConfigPath(env)) {
|
|
47061
47465
|
const applied = [];
|
|
47062
47466
|
try {
|
|
47063
|
-
if (!
|
|
47064
|
-
const parsed = JSON.parse(readFileSync2(
|
|
47467
|
+
if (!existsSync10(path8)) return applied;
|
|
47468
|
+
const parsed = JSON.parse(readFileSync2(path8, "utf8"));
|
|
47065
47469
|
if (!parsed || typeof parsed !== "object") return applied;
|
|
47066
47470
|
for (const [k, v] of Object.entries(parsed)) {
|
|
47067
47471
|
if (typeof v !== "string") continue;
|
|
@@ -47071,7 +47475,7 @@ function loadFileConfig(env = process.env, path7 = fileConfigPath(env)) {
|
|
|
47071
47475
|
}
|
|
47072
47476
|
}
|
|
47073
47477
|
} catch (e) {
|
|
47074
|
-
console.error(`Failed to load apple-notes-mcp config file ${
|
|
47478
|
+
console.error(`Failed to load apple-notes-mcp config file ${path8}: ${String(e)}`);
|
|
47075
47479
|
}
|
|
47076
47480
|
return applied;
|
|
47077
47481
|
}
|
|
@@ -47358,11 +47762,11 @@ function createShutdown(stream, exit, timeoutMs = SHUTDOWN_DRAIN_TIMEOUT_MS) {
|
|
|
47358
47762
|
}
|
|
47359
47763
|
|
|
47360
47764
|
// src/utils/noteBlocks.ts
|
|
47361
|
-
import { execFileSync as
|
|
47362
|
-
import { existsSync as
|
|
47363
|
-
import { homedir as
|
|
47364
|
-
import { join as
|
|
47365
|
-
import { gunzipSync as
|
|
47765
|
+
import { execFileSync as execFileSync16 } from "node:child_process";
|
|
47766
|
+
import { existsSync as existsSync11 } from "node:fs";
|
|
47767
|
+
import { homedir as homedir14 } from "node:os";
|
|
47768
|
+
import { join as join17 } from "node:path";
|
|
47769
|
+
import { gunzipSync as gunzipSync8 } from "node:zlib";
|
|
47366
47770
|
var NoteBlocksError = class extends Error {
|
|
47367
47771
|
code;
|
|
47368
47772
|
constructor(code, message) {
|
|
@@ -47650,7 +48054,7 @@ function summarize(blocks, attachments) {
|
|
|
47650
48054
|
function decodeCompressedNoteBlocks(compressed) {
|
|
47651
48055
|
let data;
|
|
47652
48056
|
try {
|
|
47653
|
-
data =
|
|
48057
|
+
data = gunzipSync8(compressed, { maxOutputLength: 32 * 1024 * 1024 });
|
|
47654
48058
|
} catch (error2) {
|
|
47655
48059
|
throw new NoteBlocksError(
|
|
47656
48060
|
"decompress-failed",
|
|
@@ -47704,23 +48108,23 @@ function pageNoteBlocks(doc, { offset = 0, limit = 500, maxBytes = blocksMaxResp
|
|
|
47704
48108
|
undecodedFields: doc.undecodedFields
|
|
47705
48109
|
};
|
|
47706
48110
|
}
|
|
47707
|
-
var
|
|
47708
|
-
|
|
48111
|
+
var NOTES_DB_PATH9 = join17(
|
|
48112
|
+
homedir14(),
|
|
47709
48113
|
"Library/Group Containers/group.com.apple.notes/NoteStore.sqlite"
|
|
47710
48114
|
);
|
|
47711
|
-
function readNoteBlocks(id2, { dbPath: dbPath2 =
|
|
48115
|
+
function readNoteBlocks(id2, { dbPath: dbPath2 = NOTES_DB_PATH9 } = {}) {
|
|
47712
48116
|
const pk = /^x-coredata:\/\/[0-9a-f-]+\/ICNote\/p([0-9]{1,18})$/i.exec(id2)?.[1];
|
|
47713
48117
|
if (!pk)
|
|
47714
48118
|
throw new NoteBlocksError(
|
|
47715
48119
|
"invalid-id",
|
|
47716
48120
|
`Invalid note ID: expected x-coredata://<store>/ICNote/p<number>`
|
|
47717
48121
|
);
|
|
47718
|
-
if (!
|
|
48122
|
+
if (!existsSync11(dbPath2))
|
|
47719
48123
|
throw new NoteBlocksError("no-full-disk-access", "The Notes database is not readable");
|
|
47720
48124
|
const sql = "SELECT json_object('exists', (SELECT count(*) FROM ZICCLOUDSYNCINGOBJECT WHERE Z_PK = @pk AND Z_ENT = (SELECT Z_ENT FROM Z_PRIMARYKEY WHERE Z_NAME = 'ICNote')), 'data', (SELECT hex(ZDATA) FROM ZICNOTEDATA WHERE ZNOTE = @pk), 'encrypted', (SELECT ZCRYPTOINITIALIZATIONVECTOR IS NOT NULL FROM ZICNOTEDATA WHERE ZNOTE = @pk));";
|
|
47721
48125
|
let output;
|
|
47722
48126
|
try {
|
|
47723
|
-
output =
|
|
48127
|
+
output = execFileSync16(
|
|
47724
48128
|
"/usr/bin/sqlite3",
|
|
47725
48129
|
["-readonly", "-cmd", ".parameter init", "-cmd", `.parameter set @pk ${pk}`, dbPath2, sql],
|
|
47726
48130
|
{
|
|
@@ -47881,7 +48285,7 @@ import {
|
|
|
47881
48285
|
writeFileSync as writeFileSync3
|
|
47882
48286
|
} from "node:fs";
|
|
47883
48287
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
47884
|
-
import { basename as basename3, extname as extname3, isAbsolute as isAbsolute3, join as
|
|
48288
|
+
import { basename as basename3, extname as extname3, isAbsolute as isAbsolute3, join as join18 } from "node:path";
|
|
47885
48289
|
var noteId = exactIdInput(
|
|
47886
48290
|
"ICNote",
|
|
47887
48291
|
/^x-coredata:\/\/[0-9a-f-]+\/ICNote\/p\d+$/i,
|
|
@@ -47924,9 +48328,9 @@ function assertExistingContentPreserved(before, after) {
|
|
|
47924
48328
|
throw new Error("Existing native object content or presentation changed");
|
|
47925
48329
|
}
|
|
47926
48330
|
}
|
|
47927
|
-
function localAttachment(
|
|
47928
|
-
if (!isAbsolute3(
|
|
47929
|
-
const descriptor = openSync4(
|
|
48331
|
+
function localAttachment(path8) {
|
|
48332
|
+
if (!isAbsolute3(path8)) throw new Error("An absolute local file path is required");
|
|
48333
|
+
const descriptor = openSync4(path8, constants4.O_RDONLY | constants4.O_NOFOLLOW);
|
|
47930
48334
|
try {
|
|
47931
48335
|
const stat = fstatSync4(descriptor);
|
|
47932
48336
|
if (!stat.isFile() || stat.size === 0 || stat.size > 64 * 1024 * 1024)
|
|
@@ -48048,8 +48452,8 @@ function registerDirectOperations(server2, manager) {
|
|
|
48048
48452
|
}
|
|
48049
48453
|
);
|
|
48050
48454
|
}
|
|
48051
|
-
function attachmentName(
|
|
48052
|
-
const source = basename3(
|
|
48455
|
+
function attachmentName(path8, filename) {
|
|
48456
|
+
const source = basename3(path8);
|
|
48053
48457
|
if (filename === void 0) return source;
|
|
48054
48458
|
if (Buffer.byteLength(filename, "utf8") > 255)
|
|
48055
48459
|
throw new Error("filename must be at most 255 bytes");
|
|
@@ -48064,14 +48468,14 @@ function attachmentName(path7, filename) {
|
|
|
48064
48468
|
return filename;
|
|
48065
48469
|
}
|
|
48066
48470
|
function attachFile(manager, args) {
|
|
48067
|
-
const { id: id2, expectedContentHash, path:
|
|
48068
|
-
const name = attachmentName(
|
|
48471
|
+
const { id: id2, expectedContentHash, path: path8 } = args;
|
|
48472
|
+
const name = attachmentName(path8, args.filename);
|
|
48069
48473
|
const before = readSnapshot(manager, id2);
|
|
48070
48474
|
if (before.hash !== expectedContentHash) throw new Error("Note revision changed");
|
|
48071
|
-
const bytes = localAttachment(
|
|
48475
|
+
const bytes = localAttachment(path8);
|
|
48072
48476
|
const beforeAttachments = manager.listAttachmentsById(id2);
|
|
48073
|
-
const directory = mkdtempSync4(
|
|
48074
|
-
const temporaryFile =
|
|
48477
|
+
const directory = mkdtempSync4(join18(tmpdir4(), "notes-attachment-add-"));
|
|
48478
|
+
const temporaryFile = join18(directory, name);
|
|
48075
48479
|
try {
|
|
48076
48480
|
writeFileSync3(temporaryFile, bytes, { mode: 384 });
|
|
48077
48481
|
if (readSnapshot(manager, id2).hash !== before.hash) throw new Error("Note revision changed");
|
|
@@ -48629,7 +49033,7 @@ function registerNativeOperations(server2, manager) {
|
|
|
48629
49033
|
|
|
48630
49034
|
// src/setupShortcuts.ts
|
|
48631
49035
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
48632
|
-
import { existsSync as
|
|
49036
|
+
import { existsSync as existsSync12 } from "node:fs";
|
|
48633
49037
|
import { release as release2 } from "node:os";
|
|
48634
49038
|
import { dirname as dirname4, resolve as resolve3 } from "node:path";
|
|
48635
49039
|
import { fileURLToPath } from "node:url";
|
|
@@ -48649,16 +49053,16 @@ var shortcutFiles = [
|
|
|
48649
49053
|
];
|
|
48650
49054
|
function setupShortcuts(checkOnly, dependencies = {}) {
|
|
48651
49055
|
const status = dependencies.status || nativeTagsStatus;
|
|
48652
|
-
const exists = dependencies.exists ||
|
|
48653
|
-
const open = dependencies.open || ((
|
|
48654
|
-
const result = spawnSync2("/usr/bin/open", [
|
|
49056
|
+
const exists = dependencies.exists || existsSync12;
|
|
49057
|
+
const open = dependencies.open || ((path8) => {
|
|
49058
|
+
const result = spawnSync2("/usr/bin/open", [path8], { encoding: "utf8" });
|
|
48655
49059
|
return result.status === 0 ? { ok: true } : { ok: false, error: result.stderr || result.error?.message || "open failed" };
|
|
48656
49060
|
});
|
|
48657
49061
|
const baseDirectory = dependencies.baseDirectory || resolve3(dirname4(fileURLToPath(import.meta.url)), "../shortcuts");
|
|
48658
49062
|
const osRelease = (dependencies.osRelease || release2)();
|
|
48659
49063
|
const darwinMajor = Number.parseInt(osRelease.split(".")[0], 10);
|
|
48660
49064
|
const items = shortcutFiles.map(({ name, file, optional: optional2 }) => {
|
|
48661
|
-
const
|
|
49065
|
+
const path8 = resolve3(baseDirectory, file);
|
|
48662
49066
|
let installed = false;
|
|
48663
49067
|
let identifier;
|
|
48664
49068
|
let error2;
|
|
@@ -48674,9 +49078,9 @@ function setupShortcuts(checkOnly, dependencies = {}) {
|
|
|
48674
49078
|
if (!installed && !checkOnly) {
|
|
48675
49079
|
if (optional2 && !(darwinMajor >= MARKDOWN_MIN_DARWIN_MAJOR))
|
|
48676
49080
|
skipped = `requires macOS 26 or later (this Mac reports Darwin ${osRelease})`;
|
|
48677
|
-
else if (!exists(
|
|
49081
|
+
else if (!exists(path8)) error2 = `Packaged Shortcut is missing: ${path8}`;
|
|
48678
49082
|
else {
|
|
48679
|
-
const result = open(
|
|
49083
|
+
const result = open(path8);
|
|
48680
49084
|
opened = result.ok;
|
|
48681
49085
|
if (!result.ok) error2 = result.error || `Could not open ${file}`;
|
|
48682
49086
|
}
|
|
@@ -48685,7 +49089,7 @@ function setupShortcuts(checkOnly, dependencies = {}) {
|
|
|
48685
49089
|
name,
|
|
48686
49090
|
installed,
|
|
48687
49091
|
identifier,
|
|
48688
|
-
file:
|
|
49092
|
+
file: path8,
|
|
48689
49093
|
opened,
|
|
48690
49094
|
...optional2 ? { optional: optional2 } : {},
|
|
48691
49095
|
...skipped ? { skipped } : {},
|
|
@@ -49616,19 +50020,47 @@ registerTool(
|
|
|
49616
50020
|
registerTool(
|
|
49617
50021
|
"list-native-tags",
|
|
49618
50022
|
{
|
|
49619
|
-
description: "Use when: listing actual native Notes tags
|
|
50023
|
+
description: "Use when: listing actual native Notes tags, either in one folder (pass folder) or as an account-wide inventory with note counts (omit folder; account then optionally narrows it, else every account is counted).\nReturns: folder mode maps each tag to exact matching note IDs, plus completeness and per-note errors; inventory mode returns each tag with noteCount and per-account counts, sorted by count.\nDo not use when: searching textual #hashtags in note bodies (search-notes).\nSafety: read-only; requires Full Disk Access and discloses partial reads.",
|
|
49620
50024
|
inputSchema: {
|
|
49621
|
-
account: external_exports.string().min(1).max(MAX.ACCOUNT)
|
|
49622
|
-
|
|
50025
|
+
account: external_exports.string().min(1).max(MAX.ACCOUNT).optional().describe(
|
|
50026
|
+
"Account name (exact or unique prefix). Folder mode: defaults to Notes.app's default account. Inventory mode: omit to count every account."
|
|
50027
|
+
),
|
|
50028
|
+
folder: external_exports.string().min(1).max(MAX.FOLDER).optional().describe("Folder to list tags in. Omit for the account-wide inventory with counts.")
|
|
49623
50029
|
},
|
|
49624
50030
|
outputSchema: {
|
|
49625
50031
|
tags: external_exports.record(external_exports.array(external_exports.string())).optional(),
|
|
49626
50032
|
complete: external_exports.boolean().optional(),
|
|
49627
|
-
errors: external_exports.record(external_exports.string()).optional()
|
|
50033
|
+
errors: external_exports.record(external_exports.string()).optional(),
|
|
50034
|
+
inventory: external_exports.array(
|
|
50035
|
+
external_exports.object({
|
|
50036
|
+
tag: external_exports.string(),
|
|
50037
|
+
noteCount: external_exports.number(),
|
|
50038
|
+
accounts: external_exports.record(external_exports.number()),
|
|
50039
|
+
spellings: external_exports.array(external_exports.string()).optional()
|
|
50040
|
+
}).passthrough()
|
|
50041
|
+
).optional(),
|
|
50042
|
+
tagCount: external_exports.number().optional(),
|
|
50043
|
+
unverifiedNotes: external_exports.number().optional(),
|
|
50044
|
+
account: external_exports.string().optional()
|
|
49628
50045
|
},
|
|
49629
50046
|
annotations: { readOnlyHint: true }
|
|
49630
50047
|
},
|
|
49631
50048
|
withErrorHandling(({ account, folder }) => {
|
|
50049
|
+
if (!folder) {
|
|
50050
|
+
const result = nativeTagInventory({ account });
|
|
50051
|
+
const scope2 = result.account ? ` in ${result.account}` : " across all accounts";
|
|
50052
|
+
const lines = result.inventory.map(
|
|
50053
|
+
(entry) => ` - ${entry.tag}: ${entry.noteCount} note${entry.noteCount === 1 ? "" : "s"}`
|
|
50054
|
+
);
|
|
50055
|
+
const partial2 = result.complete ? "" : `
|
|
50056
|
+
|
|
50057
|
+
${result.unverifiedNotes} note(s) could not be checked against their body (locked or unreadable) and were counted from tag objects alone.`;
|
|
50058
|
+
return successResponse(
|
|
50059
|
+
`${result.tagCount} native tag${result.tagCount === 1 ? "" : "s"}${scope2}` + (lines.length ? `:
|
|
50060
|
+
${lines.join("\n")}` : ".") + partial2,
|
|
50061
|
+
result
|
|
50062
|
+
);
|
|
50063
|
+
}
|
|
49632
50064
|
const tags = {};
|
|
49633
50065
|
const errors = {};
|
|
49634
50066
|
for (const note of notesManager.listNoteRefs(account, folder)) {
|
|
@@ -51150,6 +51582,57 @@ registerTool(
|
|
|
51150
51582
|
return successResponse(summary, metadata);
|
|
51151
51583
|
}, "Error reading note metadata")
|
|
51152
51584
|
);
|
|
51585
|
+
var SPECIAL_KIND_LABEL = {
|
|
51586
|
+
pinned: "pinned notes",
|
|
51587
|
+
"quick-notes": "Quick Notes",
|
|
51588
|
+
"recently-deleted": "notes in Recently Deleted",
|
|
51589
|
+
locked: "password-protected notes"
|
|
51590
|
+
};
|
|
51591
|
+
registerTool(
|
|
51592
|
+
"list-special-notes",
|
|
51593
|
+
{
|
|
51594
|
+
description: "Use when: listing pinned notes, Quick Notes, notes in Recently Deleted, or password-protected (locked) notes \u2014 sets AppleScript cannot enumerate.\nReturns: metadata rows newest first (id, identifier, title, folder path, account, created, modified, and pinned/locked/quickNote/inRecentlyDeleted flags; snippet except for locked notes; passwordHint for kind locked), plus total before limit. supported is false when this macOS version's database cannot answer that kind.\nDo not use when: you need note content (get-note-content) or a folder listing (list-notes).\nNote: reads the NoteStore SQLite database read-only and requires Full Disk Access. Pinned and Quick Notes listings cover notes in folders outside Recently Deleted; the locked listing includes trashed and folderless locked notes, flagged as such. Never reads locked note bodies.",
|
|
51595
|
+
inputSchema: {
|
|
51596
|
+
kind: external_exports.enum(["pinned", "quick-notes", "recently-deleted", "locked"]).describe("Which set of notes to list"),
|
|
51597
|
+
account: external_exports.string().min(1).max(MAX.ACCOUNT).optional().describe("Only this account (exact or unique-prefix name). Omit for every account."),
|
|
51598
|
+
limit: external_exports.number().int().min(1).max(SPECIAL_LIMIT.MAX).optional().describe(`Maximum notes to return (default ${SPECIAL_LIMIT.DEFAULT})`)
|
|
51599
|
+
},
|
|
51600
|
+
outputSchema: {
|
|
51601
|
+
kind: external_exports.string().optional(),
|
|
51602
|
+
notes: external_exports.array(external_exports.object({}).passthrough()).optional(),
|
|
51603
|
+
count: external_exports.number().optional(),
|
|
51604
|
+
total: external_exports.number().optional(),
|
|
51605
|
+
limit: external_exports.number().optional(),
|
|
51606
|
+
supported: external_exports.boolean().optional(),
|
|
51607
|
+
account: external_exports.string().optional()
|
|
51608
|
+
},
|
|
51609
|
+
annotations: { readOnlyHint: true }
|
|
51610
|
+
},
|
|
51611
|
+
withErrorHandling(({ kind, account, limit }) => {
|
|
51612
|
+
const result = listSpecialNotes({ kind, account, limit });
|
|
51613
|
+
const label = SPECIAL_KIND_LABEL[kind];
|
|
51614
|
+
const structured = result;
|
|
51615
|
+
if (!result.supported) {
|
|
51616
|
+
return successResponse(
|
|
51617
|
+
`This macOS version's Notes database does not record ${label}.`,
|
|
51618
|
+
structured
|
|
51619
|
+
);
|
|
51620
|
+
}
|
|
51621
|
+
const scope2 = result.account ? ` in ${result.account}` : "";
|
|
51622
|
+
if (result.count === 0) return successResponse(`No ${label}${scope2}.`, structured);
|
|
51623
|
+
const lines = result.notes.map(
|
|
51624
|
+
(row) => ` - ${row.title ?? "(untitled)"}${row.folder ? ` (${row.folder})` : ""} [id: ${row.id}]`
|
|
51625
|
+
);
|
|
51626
|
+
const more = result.total > result.count ? `
|
|
51627
|
+
|
|
51628
|
+
Showing ${result.count} of ${result.total}; pass a higher limit to see more.` : "";
|
|
51629
|
+
return successResponse(
|
|
51630
|
+
`Found ${result.total} ${label}${scope2}:
|
|
51631
|
+
${lines.join("\n")}${more}`,
|
|
51632
|
+
structured
|
|
51633
|
+
);
|
|
51634
|
+
}, "Error listing notes")
|
|
51635
|
+
);
|
|
51153
51636
|
registerResourcesAndPrompts(server, notesManager);
|
|
51154
51637
|
process.on("uncaughtException", (err) => {
|
|
51155
51638
|
if (err?.code === "EPIPE") process.exit(0);
|