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.
Files changed (3) hide show
  1. package/README.md +43 -7
  2. package/build/index.js +677 -194
  3. 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(path7) {
3272
- let input = path7;
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 path7 = queryIndex === -1 ? wsComponent.resourceName : wsComponent.resourceName.slice(0, queryIndex);
3678
- wsComponent.path = path7 && path7 !== "/" ? path7 : void 0;
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, fs7, exportName) {
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, fs7[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(path7) {
12242
- if (!path7) return path7;
12241
+ function remove_dot_segments(path8) {
12242
+ if (!path8) return path8;
12243
12243
  var output = "";
12244
- while (path7.length > 0) {
12245
- if (path7 === "." || path7 === "..") {
12246
- path7 = "";
12244
+ while (path8.length > 0) {
12245
+ if (path8 === "." || path8 === "..") {
12246
+ path8 = "";
12247
12247
  break;
12248
12248
  }
12249
- var twochars = path7.substring(0, 2);
12250
- var threechars = path7.substring(0, 3);
12251
- var fourchars = path7.substring(0, 4);
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
- path7 = path7.substring(3);
12253
+ path8 = path8.substring(3);
12254
12254
  } else if (twochars === "./") {
12255
- path7 = path7.substring(2);
12255
+ path8 = path8.substring(2);
12256
12256
  } else if (threechars === "/./") {
12257
- path7 = "/" + path7.substring(3);
12258
- } else if (twochars === "/." && path7.length === 2) {
12259
- path7 = "/";
12260
- } else if (fourchars === "/../" || threechars === "/.." && path7.length === 3) {
12261
- path7 = "/" + path7.substring(4);
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 = path7.match(/(\/?([^\/]*))/)[0];
12264
+ var segment = path8.match(/(\/?([^\/]*))/)[0];
12265
12265
  output += segment;
12266
- path7 = path7.substring(segment.length);
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 join18(output, replacement);
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 = join18(output, rule.append(self.options));
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 join18(output, replacement) {
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: path7, errorMaps, issueData } = params;
24983
- const fullPath = [...path7, ...issueData.path || []];
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, path7, key) {
25099
+ constructor(parent, value, path8, key) {
25100
25100
  this._cachedPath = [];
25101
25101
  this.parent = parent;
25102
25102
  this.data = value;
25103
- this._path = path7;
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, path7) {
28741
- if (!path7)
28740
+ function getElementAtPath(obj, path8) {
28741
+ if (!path8)
28742
28742
  return obj;
28743
- return path7.reduce((acc, key) => acc?.[key], obj);
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(path7, issues) {
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(path7);
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(path7) {
32479
- if (path7.length === 0) {
32478
+ function getDotPath(path8) {
32479
+ if (path8.length === 0) {
32480
32480
  return "object root";
32481
32481
  }
32482
- return path7.reduce((acc, seg, index) => {
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 flag = (description, negative) => typeof value === "boolean" ? {
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 flag("has a checklist", "has no checklist");
40593
+ return flag2("has a checklist", "has no checklist");
40594
40594
  case "checklistInProgress":
40595
- return flag("has an unfinished checklist", "has no unfinished checklist");
40595
+ return flag2("has an unfinished checklist", "has no unfinished checklist");
40596
40596
  case "checklistCompleted":
40597
- return flag("has a completed checklist", "has no completed checklist");
40597
+ return flag2("has a completed checklist", "has no completed checklist");
40598
40598
  case "attachment":
40599
- return flag("has attachments", "has no attachments");
40599
+ return flag2("has attachments", "has no attachments");
40600
40600
  case "pinned":
40601
- return flag("is pinned", "is not pinned");
40601
+ return flag2("is pinned", "is not pinned");
40602
40602
  case "systemPaper":
40603
- return flag("is a Quick Note", "is not a Quick Note");
40603
+ return flag2("is a Quick Note", "is not a Quick Note");
40604
40604
  case "passwordProtected":
40605
- return flag("is locked", "is not locked");
40605
+ return flag2("is locked", "is not locked");
40606
40606
  case "shared":
40607
- return flag("is shared", "is not shared");
40607
+ return flag2("is shared", "is not shared");
40608
40608
  case "mention":
40609
- return flag("mentions anyone", "mentions no one");
40609
+ return flag2("mentions anyone", "mentions no one");
40610
40610
  case "tagged":
40611
- return flag("has any tag", "has no tags");
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 = (entity2, pk) => `x-coredata://${storeUuid}/${entity2}/p${pk}`;
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(path7) {
40885
- return realpathSync.native(path7);
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(path7) {
40907
+ function entryExists(path8) {
40908
40908
  try {
40909
- lstatSync(path7);
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 col2 = (alias, name) => columns.has(name) ? `${alias}.${name}` : "NULL";
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 = col2("a", "ZPARENTATTACHMENT");
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', ${col2("a", "ZTYPEUTI")}`,
41157
+ `'uti', ${col3("a", "ZTYPEUTI")}`,
41158
41158
  `'parentPk', ${parent}`,
41159
- `'filename', ${col2("a", "ZFILENAME")}`,
41159
+ `'filename', ${col3("a", "ZFILENAME")}`,
41160
41160
  `'mediaIdentifier', m.ZIDENTIFIER`,
41161
- `'mediaFilename', ${col2("m", "ZFILENAME")}`,
41161
+ `'mediaFilename', ${col3("m", "ZFILENAME")}`,
41162
41162
  `'mediaGeneration', ${firstOf("m", ["ZGENERATION1", "ZGENERATION"])}`,
41163
- `'fallbackImageGeneration', ${col2("a", "ZFALLBACKIMAGEGENERATION")}`,
41164
- `'fallbackPdfGeneration', ${col2("a", "ZFALLBACKPDFGENERATION")}`,
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(path7, rootReal) {
41277
+ function realInside(path8, rootReal) {
41278
41278
  try {
41279
- const real = realpathSync2.native(path7);
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(path7) {
41285
+ function isRegularFile(path8) {
41286
41286
  try {
41287
- return lstatSync2(path7).isFile();
41287
+ return lstatSync2(path8).isFile();
41288
41288
  } catch {
41289
41289
  return false;
41290
41290
  }
41291
41291
  }
41292
- function isDirectory(path7) {
41292
+ function isDirectory(path8) {
41293
41293
  try {
41294
- return lstatSync2(path7).isDirectory();
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(path7) {
41674
+ function readImageInfo(path8) {
41675
41675
  let fd;
41676
41676
  try {
41677
- fd = openSync3(path7, constants3.O_RDONLY | constants3.O_NOFOLLOW);
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 col2 = (name) => columns.has(name) ? `a.${name}` : "NULL";
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', ${col2("ZHANDWRITINGSUMMARY")}`,
41701
- `'fallbackImageGeneration', ${col2("ZFALLBACKIMAGEGENERATION")}`,
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(path7) {
41777
+ function kindOf(path8) {
41778
41778
  try {
41779
- const st = lstatSync3(path7);
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 [path7, source] of [
41845
+ for (const [path8, source] of [
41846
41846
  [fallbackImagePath, "fallback"],
41847
41847
  [previewPath, "preview"]
41848
41848
  ]) {
41849
- const info = path7 ? readImageInfo(path7) : null;
41850
- if (path7 && info) {
41851
- raster = { path: path7, source, ...info };
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, path7, expected) {
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(path7);
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/noteIdentifiers.ts
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(entity2) {
44818
- return `(SELECT Z_ENT FROM Z_PRIMARYKEY WHERE Z_NAME = '${entity2}')`;
45221
+ function entityClause(entity3) {
45222
+ return `(SELECT Z_ENT FROM Z_PRIMARYKEY WHERE Z_NAME = '${entity3}')`;
44819
45223
  }
44820
- function buildResolveSql(entity2, keys, uuids) {
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(entity2)} AND (${where})));`;
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(entity2, keys) {
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 (entity2 === "ICNote") {
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 (entity2 === "ICFolder") {
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(entity2)} AND o.Z_PK IN (${inList})));`;
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 (!fs5.existsSync(dbPath2)) throw new IdentifierResolutionError("no_fda", NO_FDA_MESSAGE);
45259
+ if (!fs6.existsSync(dbPath2)) throw new IdentifierResolutionError("no_fda", NO_FDA_MESSAGE);
44856
45260
  let out;
44857
45261
  try {
44858
- out = execFileSync10("sqlite3", ["-readonly", dbPath2, sql], {
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, entity2, pk) {
44876
- return `x-coredata://${store}/${entity2}/p${pk}`;
45279
+ function coreDataId(store, entity3, pk) {
45280
+ return `x-coredata://${store}/${entity3}/p${pk}`;
44877
45281
  }
44878
- function resolveIdentifiers(values, entity2, dbPath2 = NOTES_DB_PATH6) {
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(entity2, keys, uuids),
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[entity2];
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, entity2, row.pk));
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, entity2, row.pk));
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, entity2, dbPath2 = NOTES_DB_PATH6) {
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] !== entity2) continue;
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(entity2, [...wanted.keys()]), dbPath2);
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, entity2, dbPath2 = NOTES_DB_PATH6) {
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, entity2, dbPath2);
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, entity2) => resolveIdentifiers(values, entity2);
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, entity2, ctx, resolver) {
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, entity2);
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(entity2, pattern, message, options = {}) {
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], entity2, ctx, resolver);
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(entity2, pattern, message, options = {}) {
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, entity2, ctx, resolver);
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(entity2, resolver = defaultResolver) {
45409
+ function looseIdTransform(entity3, resolver = defaultResolver) {
45006
45410
  return (value, ctx) => {
45007
45411
  if (!isAlternateIdentifier(value)) return value;
45008
- const map = resolveInSchema([value], entity2, ctx, resolver);
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 execFileSync11 } from "child_process";
45549
- import * as fs6 from "fs";
45550
- import * as os6 from "os";
45551
- import * as path6 from "path";
45552
- import { gunzipSync as gunzipSync6 } from "zlib";
45553
- var NOTES_DB_PATH7 = path6.join(
45554
- os6.homedir(),
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 CORE_DATA_EPOCH_MS = Date.UTC(2001, 0, 1);
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 col(available, alias, name) {
46046
+ function col2(available, alias, name) {
45643
46047
  return available.has(name) ? `${alias}.${name}` : "NULL";
45644
46048
  }
45645
- var entity = (name) => `(SELECT Z_ENT FROM Z_PRIMARYKEY WHERE Z_NAME='${name}')`;
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 = ${entity("ICNote")}`];
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 = ${entity("ICFolder")} AND ZFOLDERTYPE = 1)`
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', ${col(available, "f", "ZTITLE2")}, 'parent', ${col(available, "f", "ZPARENT")}, 'type', ${col(available, "f", "ZFOLDERTYPE")}, 'owner', ${col(available, "f", "ZOWNER")}, 'shared', ${notNull("f", "ZSERVERSHAREDATA")}) FROM ZICCLOUDSYNCINGOBJECT f WHERE f.Z_ENT = ${entity("ICFolder")};`;
45675
- const accountRow = `SELECT json_object('k', 'account', 'pk', a.Z_PK, 'name', ${col(available, "a", "ZNAME")}) FROM ZICCLOUDSYNCINGOBJECT a WHERE a.Z_ENT = ${entity("ICAccount")};`;
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', ${col(available, "n", "ZSNIPPET")}, 'data', ${dataExpr}, 'tags', ${tagsExpr}) FROM ZICCLOUDSYNCINGOBJECT n WHERE ${whereSql} ORDER BY n.ZMODIFICATIONDATE1 DESC, n.Z_PK DESC LIMIT ${scan};`;
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 execFileSync11("sqlite3", ["-readonly", dbPath2, query], {
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 path7 = parent ? `${parent.path}/${escapeSegment(name)}` : escapeSegment(name);
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: path7,
46123
+ path: path8,
45720
46124
  plainPath,
45721
- keys: [...new Set([name, plainPath, path7].map(normalizeForMatch))],
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 : CORE_DATA_EPOCH_MS + seconds * 1e3;
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 ?? NOTES_DB_PATH7;
45754
- if (!fs6.existsSync(dbPath2)) throw new NoteQueryStoreError(QUERY_FDA_MESSAGE, "no_fda");
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
- gunzipSync6(Buffer.from(row.data, "hex"), { maxOutputLength: 32 * 1024 * 1024 })
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 execFileSync12 } from "node:child_process";
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 join13 } from "node:path";
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 execFileSync12("/usr/bin/shortcuts", ["list", "--show-identifiers"], {
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(join13(tmpdir2(), "apple-notes-native-tags-"));
46398
+ const directory = mkdtempSync2(join14(tmpdir2(), "apple-notes-native-tags-"));
45995
46399
  try {
45996
- const path7 = join13(directory, "request.json");
45997
- writeFileSync(path7, JSON.stringify(input), { mode: 384 });
45998
- execFileSync12("/usr/bin/shortcuts", ["run", status.identifier, "--input-path", path7], {
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 execFileSync13 } from "node:child_process";
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 join14 } from "node:path";
46424
+ import { join as join15 } from "node:path";
46021
46425
 
46022
46426
  // src/utils/appendMarkdown.ts
46023
46427
  var escape2 = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
@@ -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(join14(tmpdir3(), "apple-notes-background-"));
46749
+ const directory = mkdtempSync3(join15(tmpdir3(), "apple-notes-background-"));
46346
46750
  try {
46347
- const file = join14(directory, "request.json");
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
- execFileSync13("/usr/bin/shortcuts", ["run", status.identifier, "--input-path", file], {
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 = (path7) => JSON.stringify(splitFolderPath(path7).map((part) => part.toLocaleLowerCase()));
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 execFileSync14 } from "node:child_process";
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 = execFileSync14("/usr/bin/sw_vers", ["-productVersion"], {
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 os7 = matrix.runtimeOS;
47336
+ const os8 = matrix.runtimeOS;
46933
47337
  const lines = [
46934
- `Feature matrix (macOS ${os7.macOSVersion ?? "unknown"}, Darwin ${os7.darwinRelease}):`
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 existsSync9, readFileSync as readFileSync2 } from "fs";
47053
- import { join as join15 } from "path";
47054
- import { homedir as homedir12 } from "os";
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 join15(homedir12(), "Library", "Application Support", "apple-notes-mcp", "config.json");
47462
+ return join16(homedir13(), "Library", "Application Support", "apple-notes-mcp", "config.json");
47059
47463
  }
47060
- function loadFileConfig(env = process.env, path7 = fileConfigPath(env)) {
47464
+ function loadFileConfig(env = process.env, path8 = fileConfigPath(env)) {
47061
47465
  const applied = [];
47062
47466
  try {
47063
- if (!existsSync9(path7)) return applied;
47064
- const parsed = JSON.parse(readFileSync2(path7, "utf8"));
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 ${path7}: ${String(e)}`);
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 execFileSync15 } from "node:child_process";
47362
- import { existsSync as existsSync10 } from "node:fs";
47363
- import { homedir as homedir13 } from "node:os";
47364
- import { join as join16 } from "node:path";
47365
- import { gunzipSync as gunzipSync7 } from "node:zlib";
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 = gunzipSync7(compressed, { maxOutputLength: 32 * 1024 * 1024 });
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 NOTES_DB_PATH8 = join16(
47708
- homedir13(),
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 = NOTES_DB_PATH8 } = {}) {
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 (!existsSync10(dbPath2))
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 = execFileSync15(
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 join17 } from "node:path";
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(path7) {
47928
- if (!isAbsolute3(path7)) throw new Error("An absolute local file path is required");
47929
- const descriptor = openSync4(path7, constants4.O_RDONLY | constants4.O_NOFOLLOW);
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(path7, filename) {
48052
- const source = basename3(path7);
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: path7 } = args;
48068
- const name = attachmentName(path7, args.filename);
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(path7);
48475
+ const bytes = localAttachment(path8);
48072
48476
  const beforeAttachments = manager.listAttachmentsById(id2);
48073
- const directory = mkdtempSync4(join17(tmpdir4(), "notes-attachment-add-"));
48074
- const temporaryFile = join17(directory, name);
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 existsSync11 } from "node:fs";
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 || existsSync11;
48653
- const open = dependencies.open || ((path7) => {
48654
- const result = spawnSync2("/usr/bin/open", [path7], { encoding: "utf8" });
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 path7 = resolve3(baseDirectory, file);
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(path7)) error2 = `Packaged Shortcut is missing: ${path7}`;
49081
+ else if (!exists(path8)) error2 = `Packaged Shortcut is missing: ${path8}`;
48678
49082
  else {
48679
- const result = open(path7);
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: path7,
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 used in one explicit account and folder.\nReturns: each native tag mapped to exact matching note IDs, plus completeness and per-note errors.\nDo not use when: searching textual #hashtags in note bodies (search-notes).\nSafety: read-only; requires Full Disk Access and discloses partial reads.",
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
- folder: external_exports.string().min(1).max(MAX.FOLDER)
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);