apple-notes-mcp 2.8.26 → 2.8.28
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 +73 -1
- package/build/index.js +1184 -206
- 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(path7) {
|
|
3272
|
+
let input = path7;
|
|
3273
3273
|
const output = [];
|
|
3274
3274
|
let nextSlash = -1;
|
|
3275
3275
|
let len = 0;
|
|
@@ -3358,9 +3358,9 @@ var require_utils = __commonJS({
|
|
|
3358
3358
|
let output = "";
|
|
3359
3359
|
for (let i = 0; i < input.length; i++) {
|
|
3360
3360
|
if (input[i] === "%" && i + 2 < input.length) {
|
|
3361
|
-
const
|
|
3362
|
-
if (isHexPair(
|
|
3363
|
-
const normalizedHex =
|
|
3361
|
+
const hex3 = input.slice(i + 1, i + 3);
|
|
3362
|
+
if (isHexPair(hex3)) {
|
|
3363
|
+
const normalizedHex = hex3.toUpperCase();
|
|
3364
3364
|
const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
|
|
3365
3365
|
if (decodeUnreserved && isUnreserved(decoded)) {
|
|
3366
3366
|
output += decoded;
|
|
@@ -3380,9 +3380,9 @@ var require_utils = __commonJS({
|
|
|
3380
3380
|
for (let i = 0; i < input.length; i++) {
|
|
3381
3381
|
const ch = input[i];
|
|
3382
3382
|
if (ch === "%" && i + 2 < input.length) {
|
|
3383
|
-
const
|
|
3384
|
-
if (isHexPair(
|
|
3385
|
-
const normalizedHex =
|
|
3383
|
+
const hex3 = input.slice(i + 1, i + 3);
|
|
3384
|
+
if (isHexPair(hex3)) {
|
|
3385
|
+
const normalizedHex = hex3.toUpperCase();
|
|
3386
3386
|
const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
|
|
3387
3387
|
if (decoded !== "." && isUnreserved(decoded)) {
|
|
3388
3388
|
output += decoded;
|
|
@@ -3422,9 +3422,9 @@ var require_utils = __commonJS({
|
|
|
3422
3422
|
for (let i = 0; i < input.length; i++) {
|
|
3423
3423
|
const ch = input[i];
|
|
3424
3424
|
if (ch === "%" && i + 2 < input.length) {
|
|
3425
|
-
const
|
|
3426
|
-
if (isHexPair(
|
|
3427
|
-
output += "%" +
|
|
3425
|
+
const hex3 = input.slice(i + 1, i + 3);
|
|
3426
|
+
if (isHexPair(hex3)) {
|
|
3427
|
+
output += "%" + hex3.toUpperCase();
|
|
3428
3428
|
i += 2;
|
|
3429
3429
|
continue;
|
|
3430
3430
|
}
|
|
@@ -3460,9 +3460,9 @@ var require_utils = __commonJS({
|
|
|
3460
3460
|
for (let i = 0; i < input.length; i++) {
|
|
3461
3461
|
const ch = input[i];
|
|
3462
3462
|
if (ch === "%" && i + 2 < input.length) {
|
|
3463
|
-
const
|
|
3464
|
-
if (isHexPair(
|
|
3465
|
-
output += "%" +
|
|
3463
|
+
const hex3 = input.slice(i + 1, i + 3);
|
|
3464
|
+
if (isHexPair(hex3)) {
|
|
3465
|
+
output += "%" + hex3.toUpperCase();
|
|
3466
3466
|
i += 2;
|
|
3467
3467
|
continue;
|
|
3468
3468
|
}
|
|
@@ -3507,9 +3507,9 @@ var require_utils = __commonJS({
|
|
|
3507
3507
|
for (let i = 0; i < input.length; i++) {
|
|
3508
3508
|
const ch = input[i];
|
|
3509
3509
|
if (ch === "%" && i + 2 < input.length) {
|
|
3510
|
-
const
|
|
3511
|
-
if (isHexPair(
|
|
3512
|
-
const normalizedHex =
|
|
3510
|
+
const hex3 = input.slice(i + 1, i + 3);
|
|
3511
|
+
if (isHexPair(hex3)) {
|
|
3512
|
+
const normalizedHex = hex3.toUpperCase();
|
|
3513
3513
|
const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
|
|
3514
3514
|
if (isUnreserved(decoded)) {
|
|
3515
3515
|
output += decoded;
|
|
@@ -3547,9 +3547,9 @@ var require_utils = __commonJS({
|
|
|
3547
3547
|
let output = "";
|
|
3548
3548
|
for (let i = 0; i < input.length; i++) {
|
|
3549
3549
|
if (input[i] === "%" && i + 2 < input.length) {
|
|
3550
|
-
const
|
|
3551
|
-
if (isHexPair(
|
|
3552
|
-
output += "%" +
|
|
3550
|
+
const hex3 = input.slice(i + 1, i + 3);
|
|
3551
|
+
if (isHexPair(hex3)) {
|
|
3552
|
+
output += "%" + hex3.toUpperCase();
|
|
3553
3553
|
i += 2;
|
|
3554
3554
|
continue;
|
|
3555
3555
|
}
|
|
@@ -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 path7 = queryIndex === -1 ? wsComponent.resourceName : wsComponent.resourceName.slice(0, queryIndex);
|
|
3678
|
+
wsComponent.path = path7 && path7 !== "/" ? path7 : 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, fs7, 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, fs7[f]);
|
|
7190
7190
|
}
|
|
7191
7191
|
module.exports = exports = formatsPlugin;
|
|
7192
7192
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -8768,25 +8768,25 @@ var require_ContainerNode = __commonJS({
|
|
|
8768
8768
|
return this._firstChild;
|
|
8769
8769
|
} },
|
|
8770
8770
|
lastChild: { get: function() {
|
|
8771
|
-
var kids = this._childNodes,
|
|
8771
|
+
var kids = this._childNodes, first2;
|
|
8772
8772
|
if (kids) {
|
|
8773
8773
|
return kids.length === 0 ? null : kids[kids.length - 1];
|
|
8774
8774
|
}
|
|
8775
|
-
|
|
8776
|
-
if (
|
|
8775
|
+
first2 = this._firstChild;
|
|
8776
|
+
if (first2 === null) {
|
|
8777
8777
|
return null;
|
|
8778
8778
|
}
|
|
8779
|
-
return
|
|
8779
|
+
return first2._previousSibling;
|
|
8780
8780
|
} },
|
|
8781
8781
|
_ensureChildNodes: { value: function() {
|
|
8782
8782
|
if (this._childNodes) {
|
|
8783
8783
|
return;
|
|
8784
8784
|
}
|
|
8785
|
-
var
|
|
8786
|
-
if (
|
|
8785
|
+
var first2 = this._firstChild, kid = first2, childNodes = this._childNodes = new NodeList();
|
|
8786
|
+
if (first2) do {
|
|
8787
8787
|
childNodes.push(kid);
|
|
8788
8788
|
kid = kid._nextSibling;
|
|
8789
|
-
} while (kid !==
|
|
8789
|
+
} while (kid !== first2);
|
|
8790
8790
|
this._firstChild = null;
|
|
8791
8791
|
} },
|
|
8792
8792
|
// Remove all of this node's children. This is a minor
|
|
@@ -10257,22 +10257,22 @@ var require_Element = __commonJS({
|
|
|
10257
10257
|
}
|
|
10258
10258
|
},
|
|
10259
10259
|
_insertAdjacent: { value: function _insertAdjacent(position, node) {
|
|
10260
|
-
var
|
|
10260
|
+
var first2 = false;
|
|
10261
10261
|
switch (position) {
|
|
10262
10262
|
case "beforebegin":
|
|
10263
|
-
|
|
10263
|
+
first2 = true;
|
|
10264
10264
|
/* falls through */
|
|
10265
10265
|
case "afterend":
|
|
10266
10266
|
var parent = this.parentNode;
|
|
10267
10267
|
if (parent === null) {
|
|
10268
10268
|
return null;
|
|
10269
10269
|
}
|
|
10270
|
-
return parent.insertBefore(node,
|
|
10270
|
+
return parent.insertBefore(node, first2 ? this : this.nextSibling);
|
|
10271
10271
|
case "afterbegin":
|
|
10272
|
-
|
|
10272
|
+
first2 = true;
|
|
10273
10273
|
/* falls through */
|
|
10274
10274
|
case "beforeend":
|
|
10275
|
-
return this.insertBefore(node,
|
|
10275
|
+
return this.insertBefore(node, first2 ? this.firstChild : null);
|
|
10276
10276
|
default:
|
|
10277
10277
|
return utils.SyntaxError();
|
|
10278
10278
|
}
|
|
@@ -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(path7) {
|
|
12242
|
+
if (!path7) return path7;
|
|
12243
12243
|
var output = "";
|
|
12244
|
-
while (
|
|
12245
|
-
if (
|
|
12246
|
-
|
|
12244
|
+
while (path7.length > 0) {
|
|
12245
|
+
if (path7 === "." || path7 === "..") {
|
|
12246
|
+
path7 = "";
|
|
12247
12247
|
break;
|
|
12248
12248
|
}
|
|
12249
|
-
var twochars =
|
|
12250
|
-
var threechars =
|
|
12251
|
-
var fourchars =
|
|
12249
|
+
var twochars = path7.substring(0, 2);
|
|
12250
|
+
var threechars = path7.substring(0, 3);
|
|
12251
|
+
var fourchars = path7.substring(0, 4);
|
|
12252
12252
|
if (threechars === "../") {
|
|
12253
|
-
|
|
12253
|
+
path7 = path7.substring(3);
|
|
12254
12254
|
} else if (twochars === "./") {
|
|
12255
|
-
|
|
12255
|
+
path7 = path7.substring(2);
|
|
12256
12256
|
} else if (threechars === "/./") {
|
|
12257
|
-
|
|
12258
|
-
} else if (twochars === "/." &&
|
|
12259
|
-
|
|
12260
|
-
} else if (fourchars === "/../" || threechars === "/.." &&
|
|
12261
|
-
|
|
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);
|
|
12262
12262
|
output = output.replace(/\/?[^\/]*$/, "");
|
|
12263
12263
|
} else {
|
|
12264
|
-
var segment =
|
|
12264
|
+
var segment = path7.match(/(\/?([^\/]*))/)[0];
|
|
12265
12265
|
output += segment;
|
|
12266
|
-
|
|
12266
|
+
path7 = path7.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 join15(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 = join15(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 join15(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);
|
|
@@ -24675,9 +24675,9 @@ var util;
|
|
|
24675
24675
|
})(util || (util = {}));
|
|
24676
24676
|
var objectUtil;
|
|
24677
24677
|
(function(objectUtil2) {
|
|
24678
|
-
objectUtil2.mergeShapes = (
|
|
24678
|
+
objectUtil2.mergeShapes = (first2, second) => {
|
|
24679
24679
|
return {
|
|
24680
|
-
...
|
|
24680
|
+
...first2,
|
|
24681
24681
|
...second
|
|
24682
24682
|
// second overwrites first
|
|
24683
24683
|
};
|
|
@@ -24777,8 +24777,8 @@ var ZodError = class _ZodError extends Error {
|
|
|
24777
24777
|
constructor(issues) {
|
|
24778
24778
|
super();
|
|
24779
24779
|
this.issues = [];
|
|
24780
|
-
this.addIssue = (
|
|
24781
|
-
this.issues = [...this.issues,
|
|
24780
|
+
this.addIssue = (sub3) => {
|
|
24781
|
+
this.issues = [...this.issues, sub3];
|
|
24782
24782
|
};
|
|
24783
24783
|
this.addIssues = (subs = []) => {
|
|
24784
24784
|
this.issues = [...this.issues, ...subs];
|
|
@@ -24845,13 +24845,13 @@ var ZodError = class _ZodError extends Error {
|
|
|
24845
24845
|
flatten(mapper = (issue2) => issue2.message) {
|
|
24846
24846
|
const fieldErrors = {};
|
|
24847
24847
|
const formErrors = [];
|
|
24848
|
-
for (const
|
|
24849
|
-
if (
|
|
24850
|
-
const firstEl =
|
|
24848
|
+
for (const sub3 of this.issues) {
|
|
24849
|
+
if (sub3.path.length > 0) {
|
|
24850
|
+
const firstEl = sub3.path[0];
|
|
24851
24851
|
fieldErrors[firstEl] = fieldErrors[firstEl] || [];
|
|
24852
|
-
fieldErrors[firstEl].push(mapper(
|
|
24852
|
+
fieldErrors[firstEl].push(mapper(sub3));
|
|
24853
24853
|
} else {
|
|
24854
|
-
formErrors.push(mapper(
|
|
24854
|
+
formErrors.push(mapper(sub3));
|
|
24855
24855
|
}
|
|
24856
24856
|
}
|
|
24857
24857
|
return { formErrors, fieldErrors };
|
|
@@ -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: path7, errorMaps, issueData } = params;
|
|
24983
|
+
const fullPath = [...path7, ...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, path7, key) {
|
|
25100
25100
|
this._cachedPath = [];
|
|
25101
25101
|
this.parent = parent;
|
|
25102
25102
|
this.data = value;
|
|
25103
|
-
this._path =
|
|
25103
|
+
this._path = path7;
|
|
25104
25104
|
this._key = key;
|
|
25105
25105
|
}
|
|
25106
25106
|
get path() {
|
|
@@ -27599,10 +27599,10 @@ var ZodRecord = class _ZodRecord extends ZodType {
|
|
|
27599
27599
|
get element() {
|
|
27600
27600
|
return this._def.valueType;
|
|
27601
27601
|
}
|
|
27602
|
-
static create(
|
|
27602
|
+
static create(first2, second, third) {
|
|
27603
27603
|
if (second instanceof ZodType) {
|
|
27604
27604
|
return new _ZodRecord({
|
|
27605
|
-
keyType:
|
|
27605
|
+
keyType: first2,
|
|
27606
27606
|
valueType: second,
|
|
27607
27607
|
typeName: ZodFirstPartyTypeKind.ZodRecord,
|
|
27608
27608
|
...processCreateParams(third)
|
|
@@ -27610,7 +27610,7 @@ var ZodRecord = class _ZodRecord extends ZodType {
|
|
|
27610
27610
|
}
|
|
27611
27611
|
return new _ZodRecord({
|
|
27612
27612
|
keyType: ZodString.create(),
|
|
27613
|
-
valueType:
|
|
27613
|
+
valueType: first2,
|
|
27614
27614
|
typeName: ZodFirstPartyTypeKind.ZodRecord,
|
|
27615
27615
|
...processCreateParams(second)
|
|
27616
27616
|
});
|
|
@@ -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, path7) {
|
|
28741
|
+
if (!path7)
|
|
28742
28742
|
return obj;
|
|
28743
|
-
return
|
|
28743
|
+
return path7.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(path7, 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(path7);
|
|
29068
29068
|
return iss;
|
|
29069
29069
|
});
|
|
29070
29070
|
}
|
|
@@ -29150,12 +29150,12 @@ var $ZodRealError = $constructor("$ZodError", initializer, { Parent: Error });
|
|
|
29150
29150
|
function flattenError(error2, mapper = (issue2) => issue2.message) {
|
|
29151
29151
|
const fieldErrors = {};
|
|
29152
29152
|
const formErrors = [];
|
|
29153
|
-
for (const
|
|
29154
|
-
if (
|
|
29155
|
-
fieldErrors[
|
|
29156
|
-
fieldErrors[
|
|
29153
|
+
for (const sub3 of error2.issues) {
|
|
29154
|
+
if (sub3.path.length > 0) {
|
|
29155
|
+
fieldErrors[sub3.path[0]] = fieldErrors[sub3.path[0]] || [];
|
|
29156
|
+
fieldErrors[sub3.path[0]].push(mapper(sub3));
|
|
29157
29157
|
} else {
|
|
29158
|
-
formErrors.push(mapper(
|
|
29158
|
+
formErrors.push(mapper(sub3));
|
|
29159
29159
|
}
|
|
29160
29160
|
}
|
|
29161
29161
|
return { formErrors, fieldErrors };
|
|
@@ -32475,11 +32475,11 @@ function normalizeObjectSchema(schema) {
|
|
|
32475
32475
|
}
|
|
32476
32476
|
return void 0;
|
|
32477
32477
|
}
|
|
32478
|
-
function getDotPath(
|
|
32479
|
-
if (
|
|
32478
|
+
function getDotPath(path7) {
|
|
32479
|
+
if (path7.length === 0) {
|
|
32480
32480
|
return "object root";
|
|
32481
32481
|
}
|
|
32482
|
-
return
|
|
32482
|
+
return path7.reduce((acc, seg, index) => {
|
|
32483
32483
|
if (index === 0) {
|
|
32484
32484
|
return String(seg);
|
|
32485
32485
|
}
|
|
@@ -39330,6 +39330,68 @@ function embeddedMessage(field) {
|
|
|
39330
39330
|
if (!bytes) return void 0;
|
|
39331
39331
|
return decodeMessage(bytes);
|
|
39332
39332
|
}
|
|
39333
|
+
var ProtobufDecodeError = class extends Error {
|
|
39334
|
+
constructor(message) {
|
|
39335
|
+
super(message);
|
|
39336
|
+
this.name = "ProtobufDecodeError";
|
|
39337
|
+
}
|
|
39338
|
+
};
|
|
39339
|
+
function decodeVarint64(buf, offset) {
|
|
39340
|
+
let result = 0n;
|
|
39341
|
+
let shift = 0n;
|
|
39342
|
+
let pos = offset;
|
|
39343
|
+
while (pos < buf.length) {
|
|
39344
|
+
const byte = buf[pos++];
|
|
39345
|
+
result |= BigInt(byte & 127) << shift;
|
|
39346
|
+
if ((byte & 128) === 0) return [BigInt.asUintN(64, result), pos];
|
|
39347
|
+
shift += 7n;
|
|
39348
|
+
if (shift >= 70n) throw new ProtobufDecodeError(`Varint too long at offset ${offset}`);
|
|
39349
|
+
}
|
|
39350
|
+
throw new ProtobufDecodeError(`Unexpected end of buffer reading varint at offset ${offset}`);
|
|
39351
|
+
}
|
|
39352
|
+
function decodeWireFields(buf) {
|
|
39353
|
+
const fields = [];
|
|
39354
|
+
let offset = 0;
|
|
39355
|
+
while (offset < buf.length) {
|
|
39356
|
+
const [tag, afterTag] = decodeVarint64(buf, offset);
|
|
39357
|
+
offset = afterTag;
|
|
39358
|
+
const fieldNumber = Number(tag >> 3n);
|
|
39359
|
+
const wireType = Number(tag & 7n);
|
|
39360
|
+
if (fieldNumber === 0 || fieldNumber > 536870911)
|
|
39361
|
+
throw new ProtobufDecodeError("Invalid field number");
|
|
39362
|
+
if (wireType === 0) {
|
|
39363
|
+
const [value, next] = decodeVarint64(buf, offset);
|
|
39364
|
+
offset = next;
|
|
39365
|
+
fields.push({ fieldNumber, wireType, varint: value });
|
|
39366
|
+
continue;
|
|
39367
|
+
}
|
|
39368
|
+
let length;
|
|
39369
|
+
if (wireType === 1) length = 8;
|
|
39370
|
+
else if (wireType === 5) length = 4;
|
|
39371
|
+
else if (wireType === 2) {
|
|
39372
|
+
const [value, next] = decodeVarint64(buf, offset);
|
|
39373
|
+
if (value > BigInt(buf.length)) throw new ProtobufDecodeError("Truncated field");
|
|
39374
|
+
length = Number(value);
|
|
39375
|
+
offset = next;
|
|
39376
|
+
} else throw new ProtobufDecodeError(`Unsupported wire type ${wireType}`);
|
|
39377
|
+
if (offset + length > buf.length) throw new ProtobufDecodeError("Truncated field");
|
|
39378
|
+
fields.push({
|
|
39379
|
+
fieldNumber,
|
|
39380
|
+
wireType,
|
|
39381
|
+
bytes: buf.subarray(offset, offset + length)
|
|
39382
|
+
});
|
|
39383
|
+
offset += length;
|
|
39384
|
+
}
|
|
39385
|
+
return fields;
|
|
39386
|
+
}
|
|
39387
|
+
function signedVarint(value) {
|
|
39388
|
+
return Number(BigInt.asIntN(64, value));
|
|
39389
|
+
}
|
|
39390
|
+
function fixed32Float(field) {
|
|
39391
|
+
if (!field || field.wireType !== 5 || !field.bytes || field.bytes.length !== 4) return void 0;
|
|
39392
|
+
const bytes = field.bytes;
|
|
39393
|
+
return new DataView(bytes.buffer, bytes.byteOffset, 4).getFloat32(0, true);
|
|
39394
|
+
}
|
|
39333
39395
|
|
|
39334
39396
|
// src/utils/checklistRuns.ts
|
|
39335
39397
|
function checklistRunLineStart(text, position, length) {
|
|
@@ -39373,9 +39435,9 @@ function queryNoteData(noteId3) {
|
|
|
39373
39435
|
timeout: 5e3,
|
|
39374
39436
|
stdio: ["pipe", "pipe", "pipe"]
|
|
39375
39437
|
});
|
|
39376
|
-
const
|
|
39377
|
-
if (!
|
|
39378
|
-
return { hex:
|
|
39438
|
+
const hex3 = result.trim();
|
|
39439
|
+
if (!hex3) return { hex: null };
|
|
39440
|
+
return { hex: hex3 };
|
|
39379
39441
|
} catch (error2) {
|
|
39380
39442
|
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
39381
39443
|
console.error(`Failed to query NoteStore database: ${message}`);
|
|
@@ -39385,10 +39447,10 @@ function queryNoteData(noteId3) {
|
|
|
39385
39447
|
return { hex: null };
|
|
39386
39448
|
}
|
|
39387
39449
|
}
|
|
39388
|
-
function hexToBytes(
|
|
39389
|
-
const bytes = new Uint8Array(
|
|
39390
|
-
for (let i = 0; i <
|
|
39391
|
-
bytes[i / 2] = parseInt(
|
|
39450
|
+
function hexToBytes(hex3) {
|
|
39451
|
+
const bytes = new Uint8Array(hex3.length / 2);
|
|
39452
|
+
for (let i = 0; i < hex3.length; i += 2) {
|
|
39453
|
+
bytes[i / 2] = parseInt(hex3.substring(i, i + 2), 16);
|
|
39392
39454
|
}
|
|
39393
39455
|
return bytes;
|
|
39394
39456
|
}
|
|
@@ -39839,9 +39901,392 @@ function assertLinkedWrite(rich, content, format, allowLinkChanges = false) {
|
|
|
39839
39901
|
}
|
|
39840
39902
|
}
|
|
39841
39903
|
|
|
39904
|
+
// src/utils/smartFolders.ts
|
|
39905
|
+
import { execFileSync as execFileSync4 } from "child_process";
|
|
39906
|
+
import * as fs2 from "fs";
|
|
39907
|
+
import * as os2 from "os";
|
|
39908
|
+
import * as path2 from "path";
|
|
39909
|
+
var NOTES_DB_PATH2 = path2.join(
|
|
39910
|
+
os2.homedir(),
|
|
39911
|
+
"Library/Group Containers/group.com.apple.notes/NoteStore.sqlite"
|
|
39912
|
+
);
|
|
39913
|
+
var FDA_MESSAGE = `Full Disk Access is required to read smart folders. 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.`;
|
|
39914
|
+
var COCOA_EPOCH_OFFSET = 978307200;
|
|
39915
|
+
var MAX_DEPTH = 32;
|
|
39916
|
+
var RELATIVE_RANGES = {
|
|
39917
|
+
0: "today",
|
|
39918
|
+
1: "yesterday",
|
|
39919
|
+
2: "in the last 7 days",
|
|
39920
|
+
3: "in the last 30 days",
|
|
39921
|
+
4: "in the last 3 months",
|
|
39922
|
+
5: "in the last 12 months"
|
|
39923
|
+
};
|
|
39924
|
+
var CUSTOM_UNITS = {
|
|
39925
|
+
0: "hours",
|
|
39926
|
+
1: "days",
|
|
39927
|
+
2: "weeks",
|
|
39928
|
+
3: "months",
|
|
39929
|
+
4: "years"
|
|
39930
|
+
};
|
|
39931
|
+
var ATTACHMENT_SECTIONS = {
|
|
39932
|
+
1: "Photos & Videos",
|
|
39933
|
+
2: "Drawings",
|
|
39934
|
+
3: "Maps",
|
|
39935
|
+
4: "Websites",
|
|
39936
|
+
5: "Audio",
|
|
39937
|
+
6: "Documents",
|
|
39938
|
+
7: "Scans"
|
|
39939
|
+
};
|
|
39940
|
+
var isClause = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
39941
|
+
var isDeletedWrapper = (value) => isClause(value) && Object.keys(value).length === 1 && typeof value.deleted === "boolean";
|
|
39942
|
+
function cocoaDate(value) {
|
|
39943
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return null;
|
|
39944
|
+
const date3 = new Date((value + COCOA_EPOCH_OFFSET) * 1e3);
|
|
39945
|
+
return Number.isNaN(date3.getTime()) ? null : date3.toISOString();
|
|
39946
|
+
}
|
|
39947
|
+
var Decoder = class {
|
|
39948
|
+
constructor(context) {
|
|
39949
|
+
this.context = context;
|
|
39950
|
+
}
|
|
39951
|
+
context;
|
|
39952
|
+
fullyDecoded = true;
|
|
39953
|
+
unknown(key, value, excluded) {
|
|
39954
|
+
this.fullyDecoded = false;
|
|
39955
|
+
return {
|
|
39956
|
+
type: "unknown",
|
|
39957
|
+
...key === null ? {} : { key },
|
|
39958
|
+
value,
|
|
39959
|
+
...excluded ? { excluded: true } : {},
|
|
39960
|
+
description: "Unrecognized clause (see value)"
|
|
39961
|
+
};
|
|
39962
|
+
}
|
|
39963
|
+
/** Decode a list of sibling clauses, dropping inner `deleted` wrappers. */
|
|
39964
|
+
list(clauses, excluded, depth) {
|
|
39965
|
+
if (!Array.isArray(clauses)) return [this.clause(clauses, excluded, depth)];
|
|
39966
|
+
return clauses.filter((clause) => !isDeletedWrapper(clause)).map((clause) => this.clause(clause, excluded, depth));
|
|
39967
|
+
}
|
|
39968
|
+
group(match, clauses, excluded, depth) {
|
|
39969
|
+
const items = Array.isArray(clauses) ? clauses.filter((clause) => !isDeletedWrapper(clause)) : [clauses];
|
|
39970
|
+
if (items.length === 1) return this.clause(items[0], excluded, depth + 1);
|
|
39971
|
+
const filters = this.list(items, false, depth + 1);
|
|
39972
|
+
const joiner = match === "all" ? "all of" : "any of";
|
|
39973
|
+
return {
|
|
39974
|
+
type: "group",
|
|
39975
|
+
match,
|
|
39976
|
+
...excluded ? { excluded: true } : {},
|
|
39977
|
+
filters,
|
|
39978
|
+
description: `${excluded ? "not " : ""}${joiner}: ${filters.map((f) => f.description).join("; ")}`
|
|
39979
|
+
};
|
|
39980
|
+
}
|
|
39981
|
+
/** Mark a positively described leaf as an Exclude rule. */
|
|
39982
|
+
negate(filter) {
|
|
39983
|
+
const text = filter.description;
|
|
39984
|
+
const negated = text.startsWith("has ") ? text.replace(/^has /, "does not have ") : text.startsWith("is ") ? text.replace(/^is /, "is not ") : text.startsWith("mentions ") ? text.replace(/^mentions /, "does not mention ") : `not ${text}`;
|
|
39985
|
+
return { ...filter, excluded: true, description: negated };
|
|
39986
|
+
}
|
|
39987
|
+
clause(clause, excluded, depth) {
|
|
39988
|
+
if (depth > MAX_DEPTH || !isClause(clause)) return this.unknown(null, clause, excluded);
|
|
39989
|
+
const keys = Object.keys(clause);
|
|
39990
|
+
if (keys.length !== 1) {
|
|
39991
|
+
return this.group(
|
|
39992
|
+
"all",
|
|
39993
|
+
keys.map((key2) => ({ [key2]: clause[key2] })),
|
|
39994
|
+
excluded,
|
|
39995
|
+
depth
|
|
39996
|
+
);
|
|
39997
|
+
}
|
|
39998
|
+
const [key] = keys;
|
|
39999
|
+
const value = clause[key];
|
|
40000
|
+
if (key === "and" || key === "or") {
|
|
40001
|
+
if (!Array.isArray(value)) return this.unknown(key, value, excluded);
|
|
40002
|
+
return this.group(key === "and" ? "all" : "any", value, excluded, depth);
|
|
40003
|
+
}
|
|
40004
|
+
if (key === "not") return this.clause(value, !excluded, depth + 1);
|
|
40005
|
+
const leaf = this.leaf(key, value, excluded);
|
|
40006
|
+
if (!leaf) return this.unknown(key, value, excluded);
|
|
40007
|
+
return excluded && !leaf.excluded ? this.negate(leaf) : leaf;
|
|
40008
|
+
}
|
|
40009
|
+
/**
|
|
40010
|
+
* Decode one leaf clause. Boolean flags describe their own negation (an
|
|
40011
|
+
* excluded `pinned: true` reads "is not pinned"); other leaves are described
|
|
40012
|
+
* positively and negated by the caller.
|
|
40013
|
+
*/
|
|
40014
|
+
leaf(key, value, excluded) {
|
|
40015
|
+
const flag = (description, negative) => typeof value === "boolean" ? {
|
|
40016
|
+
type: key,
|
|
40017
|
+
value,
|
|
40018
|
+
...excluded ? { excluded: true } : {},
|
|
40019
|
+
description: value !== excluded ? description : negative
|
|
40020
|
+
} : null;
|
|
40021
|
+
switch (key) {
|
|
40022
|
+
case "checklist":
|
|
40023
|
+
return flag("has a checklist", "has no checklist");
|
|
40024
|
+
case "checklistInProgress":
|
|
40025
|
+
return flag("has an unfinished checklist", "has no unfinished checklist");
|
|
40026
|
+
case "checklistCompleted":
|
|
40027
|
+
return flag("has a completed checklist", "has no completed checklist");
|
|
40028
|
+
case "attachment":
|
|
40029
|
+
return flag("has attachments", "has no attachments");
|
|
40030
|
+
case "pinned":
|
|
40031
|
+
return flag("is pinned", "is not pinned");
|
|
40032
|
+
case "systemPaper":
|
|
40033
|
+
return flag("is a Quick Note", "is not a Quick Note");
|
|
40034
|
+
case "passwordProtected":
|
|
40035
|
+
return flag("is locked", "is not locked");
|
|
40036
|
+
case "shared":
|
|
40037
|
+
return flag("is shared", "is not shared");
|
|
40038
|
+
case "mention":
|
|
40039
|
+
return flag("mentions anyone", "mentions no one");
|
|
40040
|
+
case "tagged":
|
|
40041
|
+
return flag("has any tag", "has no tags");
|
|
40042
|
+
case "attachmentSection": {
|
|
40043
|
+
if (typeof value !== "number" || !ATTACHMENT_SECTIONS[value]) return null;
|
|
40044
|
+
return {
|
|
40045
|
+
type: key,
|
|
40046
|
+
value,
|
|
40047
|
+
name: ATTACHMENT_SECTIONS[value],
|
|
40048
|
+
description: `has ${ATTACHMENT_SECTIONS[value]} attachments`
|
|
40049
|
+
};
|
|
40050
|
+
}
|
|
40051
|
+
case "tag": {
|
|
40052
|
+
if (typeof value !== "string") return null;
|
|
40053
|
+
const names = this.context.tags?.[value] ?? [];
|
|
40054
|
+
const name = names.length === 1 ? names[0] : void 0;
|
|
40055
|
+
return {
|
|
40056
|
+
type: key,
|
|
40057
|
+
value,
|
|
40058
|
+
...name ? { name } : {},
|
|
40059
|
+
description: `has tag #${name ?? value}`
|
|
40060
|
+
};
|
|
40061
|
+
}
|
|
40062
|
+
case "folder": {
|
|
40063
|
+
if (typeof value !== "string") return null;
|
|
40064
|
+
const folder = this.context.folders?.[value];
|
|
40065
|
+
return {
|
|
40066
|
+
type: key,
|
|
40067
|
+
value,
|
|
40068
|
+
...folder ? { folderId: folder.id } : {},
|
|
40069
|
+
...folder?.title ? { name: folder.title } : {},
|
|
40070
|
+
description: folder?.title ? `is in folder "${folder.title}"` : `is in folder ${value}${folder ? "" : " (not found)"}`
|
|
40071
|
+
};
|
|
40072
|
+
}
|
|
40073
|
+
case "sharedParticipant":
|
|
40074
|
+
case "mentionParticipant":
|
|
40075
|
+
return typeof value === "string" ? {
|
|
40076
|
+
type: key,
|
|
40077
|
+
value,
|
|
40078
|
+
description: key === "sharedParticipant" ? `is shared with participant ${value}` : `mentions participant ${value}`
|
|
40079
|
+
} : null;
|
|
40080
|
+
case "creationDateRelativeRange":
|
|
40081
|
+
case "modificationDateRelativeRange": {
|
|
40082
|
+
if (!isClause(value) || typeof value.type !== "number") return null;
|
|
40083
|
+
const verb = key.startsWith("creation") ? "created" : "edited";
|
|
40084
|
+
if (value.type === 6) {
|
|
40085
|
+
const amount = value.customAmount;
|
|
40086
|
+
const unit = typeof value.customUnit === "number" ? CUSTOM_UNITS[value.customUnit] : null;
|
|
40087
|
+
if (typeof amount !== "number" || !unit) return null;
|
|
40088
|
+
return {
|
|
40089
|
+
type: key,
|
|
40090
|
+
value,
|
|
40091
|
+
description: `${verb} in the last ${amount} ${unit}`
|
|
40092
|
+
};
|
|
40093
|
+
}
|
|
40094
|
+
const range = RELATIVE_RANGES[value.type];
|
|
40095
|
+
return range ? { type: key, value, description: `${verb} ${range}` } : null;
|
|
40096
|
+
}
|
|
40097
|
+
case "creationDateRange":
|
|
40098
|
+
case "modificationDateRange": {
|
|
40099
|
+
if (!isClause(value)) return null;
|
|
40100
|
+
const from = cocoaDate(value.fromDate);
|
|
40101
|
+
const to = cocoaDate(value.toDate);
|
|
40102
|
+
if (!from || !to) return null;
|
|
40103
|
+
const verb = key.startsWith("creation") ? "created" : "edited";
|
|
40104
|
+
return {
|
|
40105
|
+
type: key,
|
|
40106
|
+
value,
|
|
40107
|
+
from,
|
|
40108
|
+
to,
|
|
40109
|
+
description: `${verb} between ${from} and ${to}`
|
|
40110
|
+
};
|
|
40111
|
+
}
|
|
40112
|
+
default:
|
|
40113
|
+
return null;
|
|
40114
|
+
}
|
|
40115
|
+
}
|
|
40116
|
+
};
|
|
40117
|
+
function decodeSmartFolderQuery(raw, context = {}) {
|
|
40118
|
+
if (raw === null || raw.trim() === "") {
|
|
40119
|
+
return { match: null, filters: [], query: null, fullyDecoded: false };
|
|
40120
|
+
}
|
|
40121
|
+
let parsed;
|
|
40122
|
+
try {
|
|
40123
|
+
parsed = JSON.parse(raw);
|
|
40124
|
+
} catch {
|
|
40125
|
+
return { match: null, filters: [], query: raw, fullyDecoded: false };
|
|
40126
|
+
}
|
|
40127
|
+
const decoder = new Decoder(context);
|
|
40128
|
+
const type = isClause(parsed) ? parsed.type : void 0;
|
|
40129
|
+
if (!isClause(type)) {
|
|
40130
|
+
return {
|
|
40131
|
+
match: null,
|
|
40132
|
+
filters: [decoder.unknown(null, parsed, false)],
|
|
40133
|
+
query: parsed,
|
|
40134
|
+
fullyDecoded: false
|
|
40135
|
+
};
|
|
40136
|
+
}
|
|
40137
|
+
let includesRecentlyDeleted;
|
|
40138
|
+
let inner = [type];
|
|
40139
|
+
if (Object.keys(type).length === 1 && Array.isArray(type.and)) {
|
|
40140
|
+
const wrapper = type.and.find(isDeletedWrapper);
|
|
40141
|
+
if (wrapper) {
|
|
40142
|
+
includesRecentlyDeleted = wrapper.deleted;
|
|
40143
|
+
inner = type.and.filter((clause) => !isDeletedWrapper(clause));
|
|
40144
|
+
}
|
|
40145
|
+
}
|
|
40146
|
+
const query = inner.length === 1 ? inner[0] : { and: inner };
|
|
40147
|
+
let match = "all";
|
|
40148
|
+
let filters;
|
|
40149
|
+
const only = inner.length === 1 && isClause(inner[0]) ? inner[0] : void 0;
|
|
40150
|
+
const onlyKey = only && Object.keys(only).length === 1 ? Object.keys(only)[0] : void 0;
|
|
40151
|
+
if (only && onlyKey === "and" && Array.isArray(only.and)) {
|
|
40152
|
+
filters = decoder.list(only.and, false, 1);
|
|
40153
|
+
} else if (only && onlyKey === "or" && Array.isArray(only.or)) {
|
|
40154
|
+
match = "any";
|
|
40155
|
+
filters = decoder.list(only.or, false, 1);
|
|
40156
|
+
} else if (only && onlyKey === "not" && isClause(only.not) && Object.keys(only.not).length === 1 && Array.isArray(only.not.or)) {
|
|
40157
|
+
match = "none";
|
|
40158
|
+
filters = decoder.list(only.not.or, false, 1);
|
|
40159
|
+
} else {
|
|
40160
|
+
filters = decoder.list(inner, false, 1);
|
|
40161
|
+
}
|
|
40162
|
+
return {
|
|
40163
|
+
match,
|
|
40164
|
+
filters,
|
|
40165
|
+
query,
|
|
40166
|
+
...includesRecentlyDeleted === void 0 ? {} : { includesRecentlyDeleted },
|
|
40167
|
+
fullyDecoded: decoder.fullyDecoded
|
|
40168
|
+
};
|
|
40169
|
+
}
|
|
40170
|
+
var SMART_FOLDERS_SQL = `BEGIN;
|
|
40171
|
+
SELECT Z_UUID FROM Z_METADATA;
|
|
40172
|
+
SELECT json_group_array(json_object(
|
|
40173
|
+
'pk', f.Z_PK,
|
|
40174
|
+
'identifier', f.ZIDENTIFIER,
|
|
40175
|
+
'title', f.ZTITLE2,
|
|
40176
|
+
'folderType', f.ZFOLDERTYPE,
|
|
40177
|
+
'query', f.ZSMARTFOLDERQUERYJSON,
|
|
40178
|
+
'parentPk', p.Z_PK,
|
|
40179
|
+
'parentIdentifier', p.ZIDENTIFIER,
|
|
40180
|
+
'parentTitle', p.ZTITLE2,
|
|
40181
|
+
'accountPk', a.Z_PK,
|
|
40182
|
+
'accountIdentifier', a.ZIDENTIFIER,
|
|
40183
|
+
'accountName', a.ZNAME))
|
|
40184
|
+
FROM ZICCLOUDSYNCINGOBJECT f
|
|
40185
|
+
LEFT JOIN ZICCLOUDSYNCINGOBJECT p ON p.Z_PK = f.ZPARENT
|
|
40186
|
+
LEFT JOIN ZICCLOUDSYNCINGOBJECT a ON a.Z_PK = f.ZOWNER
|
|
40187
|
+
WHERE f.Z_ENT = (SELECT Z_ENT FROM Z_PRIMARYKEY WHERE Z_NAME = 'ICFolder')
|
|
40188
|
+
AND (f.ZFOLDERTYPE = 2 OR f.ZSMARTFOLDERQUERYJSON IS NOT NULL)
|
|
40189
|
+
AND COALESCE(f.ZMARKEDFORDELETION, 0) = 0;
|
|
40190
|
+
SELECT json_group_object(ZIDENTIFIER, json_object('pk', Z_PK, 'title', ZTITLE2))
|
|
40191
|
+
FROM ZICCLOUDSYNCINGOBJECT
|
|
40192
|
+
WHERE Z_ENT = (SELECT Z_ENT FROM Z_PRIMARYKEY WHERE Z_NAME = 'ICFolder')
|
|
40193
|
+
AND ZIDENTIFIER IS NOT NULL;
|
|
40194
|
+
SELECT json_group_array(json_object('standardized', ZSTANDARDIZEDCONTENT, 'display', ZDISPLAYTEXT))
|
|
40195
|
+
FROM ZICCLOUDSYNCINGOBJECT
|
|
40196
|
+
WHERE Z_ENT = (SELECT Z_ENT FROM Z_PRIMARYKEY WHERE Z_NAME = 'ICHashtag')
|
|
40197
|
+
AND ZSTANDARDIZEDCONTENT IS NOT NULL
|
|
40198
|
+
AND COALESCE(ZMARKEDFORDELETION, 0) = 0;
|
|
40199
|
+
COMMIT;`;
|
|
40200
|
+
var REQUIRED_COLUMNS = [
|
|
40201
|
+
"ZIDENTIFIER",
|
|
40202
|
+
"ZTITLE2",
|
|
40203
|
+
"ZFOLDERTYPE",
|
|
40204
|
+
"ZSMARTFOLDERQUERYJSON",
|
|
40205
|
+
"ZPARENT",
|
|
40206
|
+
"ZOWNER",
|
|
40207
|
+
"ZNAME",
|
|
40208
|
+
"ZMARKEDFORDELETION",
|
|
40209
|
+
"ZSTANDARDIZEDCONTENT",
|
|
40210
|
+
"ZDISPLAYTEXT"
|
|
40211
|
+
];
|
|
40212
|
+
function buildSmartFolders(output) {
|
|
40213
|
+
const lines = output.trim().split("\n");
|
|
40214
|
+
if (lines.length < 4) throw new Error("Unexpected smart folder query output");
|
|
40215
|
+
const [storeUuid, rowsJson, foldersJson, tagsJson] = lines;
|
|
40216
|
+
if (!/^[0-9A-F-]+$/i.test(storeUuid)) throw new Error("Unexpected Notes store identifier");
|
|
40217
|
+
const coreDataId2 = (entity2, pk) => `x-coredata://${storeUuid}/${entity2}/p${pk}`;
|
|
40218
|
+
const rows = JSON.parse(rowsJson);
|
|
40219
|
+
const folderRows = JSON.parse(foldersJson || "{}");
|
|
40220
|
+
const tagRows = JSON.parse(tagsJson || "[]");
|
|
40221
|
+
const folders = {};
|
|
40222
|
+
for (const [identifier, row] of Object.entries(folderRows)) {
|
|
40223
|
+
folders[identifier] = { id: coreDataId2("ICFolder", row.pk), title: row.title };
|
|
40224
|
+
}
|
|
40225
|
+
const tags = {};
|
|
40226
|
+
for (const tag of tagRows) {
|
|
40227
|
+
if (!tag.display) continue;
|
|
40228
|
+
const names = tags[tag.standardized] ||= [];
|
|
40229
|
+
if (!names.includes(tag.display)) names.push(tag.display);
|
|
40230
|
+
}
|
|
40231
|
+
return rows.map((row) => {
|
|
40232
|
+
const decoded = decodeSmartFolderQuery(row.query, { folders, tags });
|
|
40233
|
+
return {
|
|
40234
|
+
id: coreDataId2("ICFolder", row.pk),
|
|
40235
|
+
identifier: row.identifier,
|
|
40236
|
+
name: row.title,
|
|
40237
|
+
account: row.accountName,
|
|
40238
|
+
accountId: row.accountPk === null ? null : coreDataId2("ICAccount", row.accountPk),
|
|
40239
|
+
accountIdentifier: row.accountIdentifier,
|
|
40240
|
+
parent: row.parentTitle,
|
|
40241
|
+
parentId: row.parentPk === null ? null : coreDataId2("ICFolder", row.parentPk),
|
|
40242
|
+
parentIdentifier: row.parentIdentifier,
|
|
40243
|
+
match: decoded.match,
|
|
40244
|
+
filters: decoded.filters,
|
|
40245
|
+
...decoded.includesRecentlyDeleted === void 0 ? {} : { includesRecentlyDeleted: decoded.includesRecentlyDeleted },
|
|
40246
|
+
fullyDecoded: decoded.fullyDecoded,
|
|
40247
|
+
query: decoded.query,
|
|
40248
|
+
rawQuery: row.query
|
|
40249
|
+
};
|
|
40250
|
+
}).sort(
|
|
40251
|
+
(a, b) => (a.account ?? "").localeCompare(b.account ?? "") || (a.name ?? "").localeCompare(b.name ?? "") || a.id.localeCompare(b.id)
|
|
40252
|
+
);
|
|
40253
|
+
}
|
|
40254
|
+
function runSqlite(dbPath2, sql) {
|
|
40255
|
+
return execFileSync4("sqlite3", ["-readonly", dbPath2, sql], {
|
|
40256
|
+
encoding: "utf8",
|
|
40257
|
+
timeout: 5e3,
|
|
40258
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
40259
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
40260
|
+
});
|
|
40261
|
+
}
|
|
40262
|
+
function readSmartFolders(dbPath2 = NOTES_DB_PATH2) {
|
|
40263
|
+
if (!fs2.existsSync(dbPath2)) return { folders: null, error: "no_fda", message: FDA_MESSAGE };
|
|
40264
|
+
try {
|
|
40265
|
+
const columns = new Set(
|
|
40266
|
+
runSqlite(dbPath2, "SELECT name FROM pragma_table_info('ZICCLOUDSYNCINGOBJECT');").trim().split("\n")
|
|
40267
|
+
);
|
|
40268
|
+
const missing = REQUIRED_COLUMNS.filter((column) => !columns.has(column));
|
|
40269
|
+
if (missing.length) {
|
|
40270
|
+
return {
|
|
40271
|
+
folders: null,
|
|
40272
|
+
error: "unsupported_schema",
|
|
40273
|
+
message: `This Notes database does not have the columns smart folders need (${missing.join(", ")}).`
|
|
40274
|
+
};
|
|
40275
|
+
}
|
|
40276
|
+
return { folders: buildSmartFolders(runSqlite(dbPath2, SMART_FOLDERS_SQL)) };
|
|
40277
|
+
} catch (error2) {
|
|
40278
|
+
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
40279
|
+
if (message.includes("authorization denied") || message.includes("unable to open database")) {
|
|
40280
|
+
return { folders: null, error: "no_fda", message: FDA_MESSAGE };
|
|
40281
|
+
}
|
|
40282
|
+
console.error(`Failed to read smart folders: ${message}`);
|
|
40283
|
+
return { folders: null, error: "query_error", message: "Failed to read smart folders." };
|
|
40284
|
+
}
|
|
40285
|
+
}
|
|
40286
|
+
|
|
39842
40287
|
// src/utils/attachmentFs.ts
|
|
39843
40288
|
import {
|
|
39844
|
-
existsSync as
|
|
40289
|
+
existsSync as existsSync3,
|
|
39845
40290
|
lstatSync,
|
|
39846
40291
|
mkdirSync,
|
|
39847
40292
|
mkdtempSync,
|
|
@@ -39850,11 +40295,11 @@ import {
|
|
|
39850
40295
|
rmSync,
|
|
39851
40296
|
statSync
|
|
39852
40297
|
} from "fs";
|
|
39853
|
-
import { dirname, isAbsolute, join as
|
|
39854
|
-
import { homedir as
|
|
40298
|
+
import { dirname, isAbsolute, join as join4, relative, resolve, sep } from "path";
|
|
40299
|
+
import { homedir as homedir4, tmpdir } from "os";
|
|
39855
40300
|
function allowedSaveRoots() {
|
|
39856
40301
|
return [
|
|
39857
|
-
resolve(
|
|
40302
|
+
resolve(homedir4()),
|
|
39858
40303
|
resolve(tmpdir()),
|
|
39859
40304
|
"/Volumes",
|
|
39860
40305
|
"/private/var/folders",
|
|
@@ -39862,8 +40307,8 @@ function allowedSaveRoots() {
|
|
|
39862
40307
|
"/private/tmp"
|
|
39863
40308
|
];
|
|
39864
40309
|
}
|
|
39865
|
-
function canonicalize(
|
|
39866
|
-
return realpathSync.native(
|
|
40310
|
+
function canonicalize(path7) {
|
|
40311
|
+
return realpathSync.native(path7);
|
|
39867
40312
|
}
|
|
39868
40313
|
function isWithinRoots(candidate, roots) {
|
|
39869
40314
|
return roots.some((root) => {
|
|
@@ -39885,9 +40330,9 @@ function canonicalRoots(roots) {
|
|
|
39885
40330
|
}
|
|
39886
40331
|
return canonical;
|
|
39887
40332
|
}
|
|
39888
|
-
function entryExists(
|
|
40333
|
+
function entryExists(path7) {
|
|
39889
40334
|
try {
|
|
39890
|
-
lstatSync(
|
|
40335
|
+
lstatSync(path7);
|
|
39891
40336
|
return true;
|
|
39892
40337
|
} catch (e) {
|
|
39893
40338
|
const code = e.code;
|
|
@@ -39928,7 +40373,7 @@ function assertSafeSavePath(p, roots = allowedSaveRoots()) {
|
|
|
39928
40373
|
if (suffix.split(sep).includes("..")) {
|
|
39929
40374
|
throw new Error(`Refusing to write outside allowed locations (home, temp, /Volumes): "${abs}"`);
|
|
39930
40375
|
}
|
|
39931
|
-
const canonicalDest = suffix ?
|
|
40376
|
+
const canonicalDest = suffix ? join4(canonicalAncestor, suffix) : canonicalAncestor;
|
|
39932
40377
|
const allowed = canonicalRoots(roots);
|
|
39933
40378
|
if (!isWithinRoots(canonicalAncestor, allowed) || !isWithinRoots(canonicalDest, allowed)) {
|
|
39934
40379
|
throw new Error(
|
|
@@ -39970,16 +40415,16 @@ function makeTempDir() {
|
|
|
39970
40415
|
}
|
|
39971
40416
|
function cleanupTempDir(dir) {
|
|
39972
40417
|
try {
|
|
39973
|
-
if (
|
|
40418
|
+
if (existsSync3(dir)) rmSync(dir, { recursive: true, force: true });
|
|
39974
40419
|
} catch {
|
|
39975
40420
|
}
|
|
39976
40421
|
}
|
|
39977
40422
|
|
|
39978
40423
|
// src/services/appleNotesManager.ts
|
|
39979
40424
|
var import_turndown = __toESM(require_turndown_cjs(), 1);
|
|
39980
|
-
import { existsSync as
|
|
39981
|
-
import { homedir as
|
|
39982
|
-
import { join as
|
|
40425
|
+
import { existsSync as existsSync4 } from "fs";
|
|
40426
|
+
import { homedir as homedir5 } from "os";
|
|
40427
|
+
import { join as join5 } from "path";
|
|
39983
40428
|
var FIELD_SEP = "";
|
|
39984
40429
|
var RECORD_SEP = "";
|
|
39985
40430
|
var AS_FIELD_SEP = "(character id 31)";
|
|
@@ -40207,8 +40652,8 @@ function getNoteLinkFromDB(coreDataId2) {
|
|
|
40207
40652
|
const match = coreDataId2.match(/\/p(\d+)$/);
|
|
40208
40653
|
if (!match) return null;
|
|
40209
40654
|
const pk = parseInt(match[1], 10);
|
|
40210
|
-
const dbPath2 =
|
|
40211
|
-
if (!
|
|
40655
|
+
const dbPath2 = join5(homedir5(), "Library/Group Containers/group.com.apple.notes/NoteStore.sqlite");
|
|
40656
|
+
if (!existsSync4(dbPath2)) return null;
|
|
40212
40657
|
try {
|
|
40213
40658
|
const { DatabaseSync } = __require("node:sqlite");
|
|
40214
40659
|
const db = new DatabaseSync(dbPath2, { readOnly: true });
|
|
@@ -40849,6 +41294,58 @@ var AppleNotesManager = class {
|
|
|
40849
41294
|
return resultList as text
|
|
40850
41295
|
`;
|
|
40851
41296
|
}
|
|
41297
|
+
/**
|
|
41298
|
+
* Lists every smart folder with its decoded query, read-only.
|
|
41299
|
+
*
|
|
41300
|
+
* Folder metadata and queries come from the NoteStore database (Full Disk
|
|
41301
|
+
* Access). With `includeMatchingNotes`, Notes.app itself is asked which notes
|
|
41302
|
+
* each smart folder currently shows, so membership reflects Notes' own
|
|
41303
|
+
* evaluation of the query rather than a reimplementation of it.
|
|
41304
|
+
*
|
|
41305
|
+
* @param options.includeMatchingNotes - Also list the notes each folder shows
|
|
41306
|
+
* @param options.limit - Maximum matching notes per folder (default 50)
|
|
41307
|
+
* @throws Error when the database cannot be read (message says why)
|
|
41308
|
+
*/
|
|
41309
|
+
listSmartFolders(options = {}) {
|
|
41310
|
+
const result = readSmartFolders();
|
|
41311
|
+
if (!result.folders) throw new Error(result.message || "Failed to read smart folders.");
|
|
41312
|
+
if (!options.includeMatchingNotes) return result.folders;
|
|
41313
|
+
const limit = options.limit ?? 50;
|
|
41314
|
+
return result.folders.map((folder) => {
|
|
41315
|
+
try {
|
|
41316
|
+
const { total, notes } = this.listSmartFolderNoteRefs(folder.id, limit);
|
|
41317
|
+
return { ...folder, matchingNoteCount: total, matchingNotes: notes };
|
|
41318
|
+
} catch (error2) {
|
|
41319
|
+
return {
|
|
41320
|
+
...folder,
|
|
41321
|
+
matchingNotesError: error2 instanceof Error ? error2.message : String(error2)
|
|
41322
|
+
};
|
|
41323
|
+
}
|
|
41324
|
+
});
|
|
41325
|
+
}
|
|
41326
|
+
/**
|
|
41327
|
+
* Asks Notes.app for the notes one smart folder currently shows.
|
|
41328
|
+
*
|
|
41329
|
+
* @returns The folder's total note count and up to `limit` (title, id) pairs
|
|
41330
|
+
*/
|
|
41331
|
+
listSmartFolderNoteRefs(folderId2, limit) {
|
|
41332
|
+
if (!/^x-coredata:\/\/[0-9a-f-]+\/ICFolder\/p\d+$/i.test(folderId2))
|
|
41333
|
+
throw new Error("An exact folder ID is required");
|
|
41334
|
+
const safeLimit = Math.max(1, Math.floor(limit));
|
|
41335
|
+
const script = buildAppLevelScript(
|
|
41336
|
+
this.buildBulkListCommand({ folderRef: `folder id "${folderId2}"`, sliceLimit: safeLimit })
|
|
41337
|
+
);
|
|
41338
|
+
const result = executeAppleScript(script);
|
|
41339
|
+
if (!result.success) {
|
|
41340
|
+
throw new Error(`Failed to list smart folder notes: ${result.error ?? "unknown error"}`);
|
|
41341
|
+
}
|
|
41342
|
+
const sepIdx = result.output.indexOf(RECORD_SEP);
|
|
41343
|
+
const header = sepIdx === -1 ? result.output : result.output.slice(0, sepIdx);
|
|
41344
|
+
const total = Number.parseInt(header.trim(), 10);
|
|
41345
|
+
if (Number.isNaN(total)) throw new Error("Unexpected smart folder listing output");
|
|
41346
|
+
const records = sepIdx === -1 ? "" : result.output.slice(sepIdx + 1);
|
|
41347
|
+
return { total, notes: this.parseBulkListOutput(records, safeLimit) };
|
|
41348
|
+
}
|
|
40852
41349
|
/**
|
|
40853
41350
|
* Parses bulk listing output into deduplicated (title, id) pairs.
|
|
40854
41351
|
*
|
|
@@ -42009,7 +42506,7 @@ var AppleNotesManager = class {
|
|
|
42009
42506
|
if (parts[0] !== "OK") {
|
|
42010
42507
|
return { success: false, error: parts[1]?.trim() || "attachment not found" };
|
|
42011
42508
|
}
|
|
42012
|
-
if (!
|
|
42509
|
+
if (!existsSync4(abs) || fileSize(abs) === 0) {
|
|
42013
42510
|
return { success: false, error: `Notes reported success but no file was written to ${abs}` };
|
|
42014
42511
|
}
|
|
42015
42512
|
return {
|
|
@@ -42452,15 +42949,15 @@ var AppleNotesManager = class {
|
|
|
42452
42949
|
};
|
|
42453
42950
|
|
|
42454
42951
|
// src/utils/syncDetection.ts
|
|
42455
|
-
import { execFileSync as
|
|
42456
|
-
import * as
|
|
42457
|
-
import * as
|
|
42458
|
-
import * as
|
|
42459
|
-
var
|
|
42460
|
-
|
|
42952
|
+
import { execFileSync as execFileSync5 } from "child_process";
|
|
42953
|
+
import * as fs3 from "fs";
|
|
42954
|
+
import * as path3 from "path";
|
|
42955
|
+
import * as os3 from "os";
|
|
42956
|
+
var NOTES_DB_PATH3 = path3.join(
|
|
42957
|
+
os3.homedir(),
|
|
42461
42958
|
"Library/Group Containers/group.com.apple.notes/NoteStore.sqlite"
|
|
42462
42959
|
);
|
|
42463
|
-
var WAL_PATH = `${
|
|
42960
|
+
var WAL_PATH = `${NOTES_DB_PATH3}-wal`;
|
|
42464
42961
|
var RECENT_ACTIVITY_THRESHOLD_SECONDS = 5;
|
|
42465
42962
|
var SYNC_STATUS_CACHE_TTL_MS = 2e3;
|
|
42466
42963
|
var cachedSyncStatus = null;
|
|
@@ -42476,14 +42973,14 @@ function getSyncStatus(useCache = true) {
|
|
|
42476
42973
|
recentActivity: false
|
|
42477
42974
|
};
|
|
42478
42975
|
try {
|
|
42479
|
-
if (!
|
|
42976
|
+
if (!fs3.existsSync(NOTES_DB_PATH3)) {
|
|
42480
42977
|
status.error = "Notes database not found";
|
|
42481
42978
|
cachedSyncStatus = status;
|
|
42482
42979
|
cacheTimestamp = Date.now();
|
|
42483
42980
|
return status;
|
|
42484
42981
|
}
|
|
42485
|
-
if (
|
|
42486
|
-
const walStats =
|
|
42982
|
+
if (fs3.existsSync(WAL_PATH)) {
|
|
42983
|
+
const walStats = fs3.statSync(WAL_PATH);
|
|
42487
42984
|
const secondsAgo = (Date.now() - walStats.mtimeMs) / 1e3;
|
|
42488
42985
|
status.secondsSinceLastChange = Math.round(secondsAgo);
|
|
42489
42986
|
status.recentActivity = secondsAgo < RECENT_ACTIVITY_THRESHOLD_SECONDS;
|
|
@@ -42497,9 +42994,9 @@ function getSyncStatus(useCache = true) {
|
|
|
42497
42994
|
WHERE object.ZCLOUDSTATE = state.Z_PK
|
|
42498
42995
|
);
|
|
42499
42996
|
`;
|
|
42500
|
-
const result =
|
|
42997
|
+
const result = execFileSync5(
|
|
42501
42998
|
"sqlite3",
|
|
42502
|
-
["-readonly",
|
|
42999
|
+
["-readonly", NOTES_DB_PATH3, query.replace(/\n/g, " ")],
|
|
42503
43000
|
{
|
|
42504
43001
|
encoding: "utf8",
|
|
42505
43002
|
timeout: 5e3,
|
|
@@ -42556,15 +43053,15 @@ function withSyncAwarenessSync(operation, fn) {
|
|
|
42556
43053
|
}
|
|
42557
43054
|
|
|
42558
43055
|
// src/utils/noteMetadata.ts
|
|
42559
|
-
import { execFileSync as
|
|
42560
|
-
import * as
|
|
42561
|
-
import * as
|
|
42562
|
-
import * as
|
|
42563
|
-
var
|
|
42564
|
-
|
|
43056
|
+
import { execFileSync as execFileSync6 } from "child_process";
|
|
43057
|
+
import * as fs4 from "fs";
|
|
43058
|
+
import * as path4 from "path";
|
|
43059
|
+
import * as os4 from "os";
|
|
43060
|
+
var NOTES_DB_PATH4 = path4.join(
|
|
43061
|
+
os4.homedir(),
|
|
42565
43062
|
"Library/Group Containers/group.com.apple.notes/NoteStore.sqlite"
|
|
42566
43063
|
);
|
|
42567
|
-
var
|
|
43064
|
+
var FDA_MESSAGE2 = `Full Disk Access is required to read note metadata. 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.`;
|
|
42568
43065
|
var COLUMN_MAP = [
|
|
42569
43066
|
{ key: "pinned", column: "ZISPINNED", type: "bool" },
|
|
42570
43067
|
{ key: "hasChecklist", column: "ZHASCHECKLIST", type: "bool" },
|
|
@@ -42576,15 +43073,15 @@ var COLUMN_MAP = [
|
|
|
42576
43073
|
{ key: "widgetSnippet", column: "ZWIDGETSNIPPET", type: "text" },
|
|
42577
43074
|
{ key: "smartFolderQuery", column: "ZSMARTFOLDERQUERYJSON", type: "text" }
|
|
42578
43075
|
];
|
|
42579
|
-
function
|
|
42580
|
-
return
|
|
43076
|
+
function runSqlite2(query) {
|
|
43077
|
+
return execFileSync6("sqlite3", ["-readonly", NOTES_DB_PATH4, query], {
|
|
42581
43078
|
encoding: "utf8",
|
|
42582
43079
|
timeout: 5e3,
|
|
42583
43080
|
stdio: ["pipe", "pipe", "pipe"]
|
|
42584
43081
|
}).trim();
|
|
42585
43082
|
}
|
|
42586
43083
|
function presentColumns() {
|
|
42587
|
-
const out =
|
|
43084
|
+
const out = runSqlite2("PRAGMA table_info(ZICCLOUDSYNCINGOBJECT);");
|
|
42588
43085
|
const cols = /* @__PURE__ */ new Set();
|
|
42589
43086
|
for (const line of out.split("\n")) {
|
|
42590
43087
|
const name = line.split("|")[1];
|
|
@@ -42602,8 +43099,8 @@ function getNoteMetadata(noteId3) {
|
|
|
42602
43099
|
};
|
|
42603
43100
|
}
|
|
42604
43101
|
const pk = pkMatch[1];
|
|
42605
|
-
if (!
|
|
42606
|
-
return { metadata: null, error: "no_fda", message:
|
|
43102
|
+
if (!fs4.existsSync(NOTES_DB_PATH4)) {
|
|
43103
|
+
return { metadata: null, error: "no_fda", message: FDA_MESSAGE2 };
|
|
42607
43104
|
}
|
|
42608
43105
|
try {
|
|
42609
43106
|
const available = presentColumns();
|
|
@@ -42612,7 +43109,7 @@ function getNoteMetadata(noteId3) {
|
|
|
42612
43109
|
return { metadata: {} };
|
|
42613
43110
|
}
|
|
42614
43111
|
const pairs = selected.map((c) => `'${c.key}', ${c.column}`).join(", ");
|
|
42615
|
-
const row =
|
|
43112
|
+
const row = runSqlite2(
|
|
42616
43113
|
`SELECT json_object(${pairs}) FROM ZICCLOUDSYNCINGOBJECT WHERE Z_PK = ${pk};`
|
|
42617
43114
|
);
|
|
42618
43115
|
if (!row) {
|
|
@@ -42637,7 +43134,7 @@ function getNoteMetadata(noteId3) {
|
|
|
42637
43134
|
} catch (error2) {
|
|
42638
43135
|
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
42639
43136
|
if (message.includes("authorization denied") || message.includes("unable to open database")) {
|
|
42640
|
-
return { metadata: null, error: "no_fda", message:
|
|
43137
|
+
return { metadata: null, error: "no_fda", message: FDA_MESSAGE2 };
|
|
42641
43138
|
}
|
|
42642
43139
|
console.error(`Failed to read note metadata: ${message}`);
|
|
42643
43140
|
return { metadata: null, error: "query_error", message: "Failed to read note metadata." };
|
|
@@ -42645,12 +43142,12 @@ function getNoteMetadata(noteId3) {
|
|
|
42645
43142
|
}
|
|
42646
43143
|
|
|
42647
43144
|
// src/utils/noteIdentifiers.ts
|
|
42648
|
-
import { execFileSync as
|
|
42649
|
-
import * as
|
|
42650
|
-
import * as
|
|
42651
|
-
import * as
|
|
42652
|
-
var
|
|
42653
|
-
|
|
43145
|
+
import { execFileSync as execFileSync7 } from "child_process";
|
|
43146
|
+
import * as fs5 from "fs";
|
|
43147
|
+
import * as os5 from "os";
|
|
43148
|
+
import * as path5 from "path";
|
|
43149
|
+
var NOTES_DB_PATH5 = path5.join(
|
|
43150
|
+
os5.homedir(),
|
|
42654
43151
|
"Library/Group Containers/group.com.apple.notes/NoteStore.sqlite"
|
|
42655
43152
|
);
|
|
42656
43153
|
var UUID_PATTERN = /^[0-9A-Fa-f]{8}(?:-[0-9A-Fa-f]{4}){3}-[0-9A-Fa-f]{12}$/;
|
|
@@ -42724,10 +43221,10 @@ function buildLookupSql(entity2, keys) {
|
|
|
42724
43221
|
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})));`;
|
|
42725
43222
|
}
|
|
42726
43223
|
function runJsonQuery(sql, dbPath2) {
|
|
42727
|
-
if (!
|
|
43224
|
+
if (!fs5.existsSync(dbPath2)) throw new IdentifierResolutionError("no_fda", NO_FDA_MESSAGE);
|
|
42728
43225
|
let out;
|
|
42729
43226
|
try {
|
|
42730
|
-
out =
|
|
43227
|
+
out = execFileSync7("sqlite3", ["-readonly", dbPath2, sql], {
|
|
42731
43228
|
encoding: "utf8",
|
|
42732
43229
|
timeout: 5e3,
|
|
42733
43230
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -42747,7 +43244,7 @@ function runJsonQuery(sql, dbPath2) {
|
|
|
42747
43244
|
function coreDataId(store, entity2, pk) {
|
|
42748
43245
|
return `x-coredata://${store}/${entity2}/p${pk}`;
|
|
42749
43246
|
}
|
|
42750
|
-
function resolveIdentifiers(values, entity2, dbPath2 =
|
|
43247
|
+
function resolveIdentifiers(values, entity2, dbPath2 = NOTES_DB_PATH5) {
|
|
42751
43248
|
const resolved = /* @__PURE__ */ new Map();
|
|
42752
43249
|
const keys = [];
|
|
42753
43250
|
const uuids = [];
|
|
@@ -42793,7 +43290,7 @@ function resolveIdentifiers(values, entity2, dbPath2 = NOTES_DB_PATH4) {
|
|
|
42793
43290
|
return resolved;
|
|
42794
43291
|
}
|
|
42795
43292
|
var COREDATA_PARTS = /^x-coredata:\/\/([0-9A-Fa-f-]+)\/(ICNote|ICFolder|ICAccount)\/p(\d{1,18})$/;
|
|
42796
|
-
function lookupStableIdentifiers(ids, entity2, dbPath2 =
|
|
43293
|
+
function lookupStableIdentifiers(ids, entity2, dbPath2 = NOTES_DB_PATH5) {
|
|
42797
43294
|
const result = /* @__PURE__ */ new Map();
|
|
42798
43295
|
const wanted = /* @__PURE__ */ new Map();
|
|
42799
43296
|
for (const id2 of ids) {
|
|
@@ -42829,7 +43326,7 @@ function lookupStableIdentifiers(ids, entity2, dbPath2 = NOTES_DB_PATH4) {
|
|
|
42829
43326
|
}
|
|
42830
43327
|
return result;
|
|
42831
43328
|
}
|
|
42832
|
-
function withStableIdentifiers(items, entity2, dbPath2 =
|
|
43329
|
+
function withStableIdentifiers(items, entity2, dbPath2 = NOTES_DB_PATH5) {
|
|
42833
43330
|
const ids = items.map((item) => item.id).filter((id2) => typeof id2 === "string");
|
|
42834
43331
|
if (ids.length === 0) return items;
|
|
42835
43332
|
const found = lookupStableIdentifiers(ids, entity2, dbPath2);
|
|
@@ -42926,7 +43423,7 @@ function decodeHtmlEntities(text) {
|
|
|
42926
43423
|
}
|
|
42927
43424
|
return String.fromCodePoint(codePoint);
|
|
42928
43425
|
};
|
|
42929
|
-
return text.replace(/&#x([0-9a-f]+);?/gi, (match,
|
|
43426
|
+
return text.replace(/&#x([0-9a-f]+);?/gi, (match, hex3) => decodeCodePoint(match, hex3, 16)).replace(/&#([0-9]+);?/g, (match, decimal) => decodeCodePoint(match, decimal, 10)).replace(/ (?:;|(?![0-9a-z]))/gi, " ").replace(/"(?:;|(?![0-9a-z]))/gi, '"').replace(/&apos(?:;|(?![0-9a-z]))/gi, "'").replace(/<(?:;|(?![0-9a-z]))/gi, "<").replace(/>(?:;|(?![0-9a-z]))/gi, ">").replace(/&(?:;|(?![0-9a-z]))/gi, "&");
|
|
42930
43427
|
}
|
|
42931
43428
|
function firstVisibleHtmlLine(html) {
|
|
42932
43429
|
let text = html;
|
|
@@ -43417,13 +43914,13 @@ function positiveTextTerms(node, negated = false) {
|
|
|
43417
43914
|
}
|
|
43418
43915
|
|
|
43419
43916
|
// src/utils/noteQueryStore.ts
|
|
43420
|
-
import { execFileSync as
|
|
43421
|
-
import * as
|
|
43422
|
-
import * as
|
|
43423
|
-
import * as
|
|
43917
|
+
import { execFileSync as execFileSync8 } from "child_process";
|
|
43918
|
+
import * as fs6 from "fs";
|
|
43919
|
+
import * as os6 from "os";
|
|
43920
|
+
import * as path6 from "path";
|
|
43424
43921
|
import { gunzipSync as gunzipSync3 } from "zlib";
|
|
43425
|
-
var
|
|
43426
|
-
|
|
43922
|
+
var NOTES_DB_PATH6 = path6.join(
|
|
43923
|
+
os6.homedir(),
|
|
43427
43924
|
"Library/Group Containers/group.com.apple.notes/NoteStore.sqlite"
|
|
43428
43925
|
);
|
|
43429
43926
|
var QUERY_SCAN = { DEFAULT: 500, MAX: 5e3 };
|
|
@@ -43510,13 +44007,13 @@ function countWords(text) {
|
|
|
43510
44007
|
}
|
|
43511
44008
|
return count;
|
|
43512
44009
|
}
|
|
43513
|
-
var
|
|
44010
|
+
var REQUIRED_COLUMNS2 = ["Z_PK", "Z_ENT", "ZTITLE1", "ZFOLDER", "ZMODIFICATIONDATE1"];
|
|
43514
44011
|
function col(available, alias, name) {
|
|
43515
44012
|
return available.has(name) ? `${alias}.${name}` : "NULL";
|
|
43516
44013
|
}
|
|
43517
44014
|
var entity = (name) => `(SELECT Z_ENT FROM Z_PRIMARYKEY WHERE Z_NAME='${name}')`;
|
|
43518
44015
|
function buildScanSql(available, options) {
|
|
43519
|
-
const missing =
|
|
44016
|
+
const missing = REQUIRED_COLUMNS2.filter((c) => !available.has(c));
|
|
43520
44017
|
if (missing.length) {
|
|
43521
44018
|
throw new NoteQueryStoreError(
|
|
43522
44019
|
`This macOS version's Notes database lacks columns query-notes needs (${missing.join(", ")}).`,
|
|
@@ -43557,8 +44054,8 @@ function buildScanSql(available, options) {
|
|
|
43557
44054
|
"COMMIT;"
|
|
43558
44055
|
].join(" ");
|
|
43559
44056
|
}
|
|
43560
|
-
function
|
|
43561
|
-
return
|
|
44057
|
+
function runSqlite3(dbPath2, query) {
|
|
44058
|
+
return execFileSync8("sqlite3", ["-readonly", dbPath2, query], {
|
|
43562
44059
|
encoding: "utf8",
|
|
43563
44060
|
timeout: 3e4,
|
|
43564
44061
|
maxBuffer: 512 * 1024 * 1024,
|
|
@@ -43567,7 +44064,7 @@ function runSqlite2(dbPath2, query) {
|
|
|
43567
44064
|
}
|
|
43568
44065
|
function presentColumns2(dbPath2) {
|
|
43569
44066
|
const cols = /* @__PURE__ */ new Set();
|
|
43570
|
-
for (const line of
|
|
44067
|
+
for (const line of runSqlite3(dbPath2, "PRAGMA table_info(ZICCLOUDSYNCINGOBJECT);").split("\n")) {
|
|
43571
44068
|
const name = line.split("|")[1];
|
|
43572
44069
|
if (name) cols.add(name);
|
|
43573
44070
|
}
|
|
@@ -43585,12 +44082,12 @@ function resolveFolders(rows) {
|
|
|
43585
44082
|
seen.add(pk);
|
|
43586
44083
|
const parent = row.parent !== null ? resolve3(row.parent, seen) : void 0;
|
|
43587
44084
|
const name = row.name ?? "";
|
|
43588
|
-
const
|
|
44085
|
+
const path7 = parent ? `${parent.path}/${escapeSegment(name)}` : escapeSegment(name);
|
|
43589
44086
|
const plainPath = parent ? `${parent.plainPath}/${name}` : name;
|
|
43590
44087
|
const info = {
|
|
43591
|
-
path:
|
|
44088
|
+
path: path7,
|
|
43592
44089
|
plainPath,
|
|
43593
|
-
keys: [...new Set([name, plainPath,
|
|
44090
|
+
keys: [...new Set([name, plainPath, path7].map(normalizeForMatch))],
|
|
43594
44091
|
accountPk: row.owner ?? parent?.accountPk ?? null,
|
|
43595
44092
|
shared: Boolean(row.shared) || Boolean(parent?.shared)
|
|
43596
44093
|
};
|
|
@@ -43622,12 +44119,12 @@ function queryNotes(expression, options = {}) {
|
|
|
43622
44119
|
const includeDeleted = options.includeDeleted ?? false;
|
|
43623
44120
|
const withBodies = needsContent(ast);
|
|
43624
44121
|
const withTags = needsTags(ast);
|
|
43625
|
-
const dbPath2 = options.dbPath ??
|
|
43626
|
-
if (!
|
|
44122
|
+
const dbPath2 = options.dbPath ?? NOTES_DB_PATH6;
|
|
44123
|
+
if (!fs6.existsSync(dbPath2)) throw new NoteQueryStoreError(QUERY_FDA_MESSAGE, "no_fda");
|
|
43627
44124
|
let output;
|
|
43628
44125
|
try {
|
|
43629
44126
|
const available = presentColumns2(dbPath2);
|
|
43630
|
-
output =
|
|
44127
|
+
output = runSqlite3(
|
|
43631
44128
|
dbPath2,
|
|
43632
44129
|
buildScanSql(available, { scanLimit, includeDeleted, withBodies, withTags })
|
|
43633
44130
|
);
|
|
@@ -43758,10 +44255,10 @@ function queryNotes(expression, options = {}) {
|
|
|
43758
44255
|
import { spawnSync } from "child_process";
|
|
43759
44256
|
|
|
43760
44257
|
// src/services/nativeTags.ts
|
|
43761
|
-
import { execFileSync as
|
|
44258
|
+
import { execFileSync as execFileSync9 } from "node:child_process";
|
|
43762
44259
|
import { mkdtempSync as mkdtempSync2, writeFileSync, rmSync as rmSync2 } from "node:fs";
|
|
43763
44260
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
43764
|
-
import { join as
|
|
44261
|
+
import { join as join10 } from "node:path";
|
|
43765
44262
|
|
|
43766
44263
|
// src/services/shortcutConsent.ts
|
|
43767
44264
|
function shortcutConsentHint(shortcut) {
|
|
@@ -43837,7 +44334,7 @@ function addNativeTags(request, deps) {
|
|
|
43837
44334
|
};
|
|
43838
44335
|
}
|
|
43839
44336
|
function listInstalledShortcuts() {
|
|
43840
|
-
return
|
|
44337
|
+
return execFileSync9("/usr/bin/shortcuts", ["list", "--show-identifiers"], {
|
|
43841
44338
|
encoding: "utf8",
|
|
43842
44339
|
timeout: 15e3,
|
|
43843
44340
|
maxBuffer: 1024 * 1024,
|
|
@@ -43863,11 +44360,11 @@ function runNativeTagsShortcut(input) {
|
|
|
43863
44360
|
const status = nativeTagsStatus();
|
|
43864
44361
|
if (!status.installed)
|
|
43865
44362
|
throw new Error(`Import the supplied ${status.shortcut}.shortcut in Shortcuts first`);
|
|
43866
|
-
const directory = mkdtempSync2(
|
|
44363
|
+
const directory = mkdtempSync2(join10(tmpdir2(), "apple-notes-native-tags-"));
|
|
43867
44364
|
try {
|
|
43868
|
-
const
|
|
43869
|
-
writeFileSync(
|
|
43870
|
-
|
|
44365
|
+
const path7 = join10(directory, "request.json");
|
|
44366
|
+
writeFileSync(path7, JSON.stringify(input), { mode: 384 });
|
|
44367
|
+
execFileSync9("/usr/bin/shortcuts", ["run", status.identifier, "--input-path", path7], {
|
|
43871
44368
|
encoding: "utf8",
|
|
43872
44369
|
timeout: 6e4,
|
|
43873
44370
|
maxBuffer: 1024 * 1024,
|
|
@@ -43886,10 +44383,10 @@ function runNativeTagsShortcut(input) {
|
|
|
43886
44383
|
}
|
|
43887
44384
|
|
|
43888
44385
|
// src/services/backgroundNotes.ts
|
|
43889
|
-
import { execFileSync as
|
|
44386
|
+
import { execFileSync as execFileSync10 } from "node:child_process";
|
|
43890
44387
|
import { mkdtempSync as mkdtempSync3, writeFileSync as writeFileSync2, rmSync as rmSync3 } from "node:fs";
|
|
43891
44388
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
43892
|
-
import { join as
|
|
44389
|
+
import { join as join11 } from "node:path";
|
|
43893
44390
|
|
|
43894
44391
|
// src/utils/appendMarkdown.ts
|
|
43895
44392
|
var escape2 = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
@@ -43954,10 +44451,10 @@ var LEGACY_ENTITIES = {
|
|
|
43954
44451
|
function comparableVisibleText(html) {
|
|
43955
44452
|
return html.replace(/<br\s*\/?\s*>/gi, " ").replace(/<[^>]*>/g, (tag) => INLINE_TAG.test(tag) ? "" : " ").replace(
|
|
43956
44453
|
/&(?:(nbsp|quot|lt|gt|amp);?|apos;|#(\d+);|#x([0-9a-f]+);)/gi,
|
|
43957
|
-
(_match, legacy, dec,
|
|
44454
|
+
(_match, legacy, dec, hex3) => {
|
|
43958
44455
|
if (legacy) return LEGACY_ENTITIES[legacy.toLowerCase()];
|
|
43959
44456
|
if (dec) return String.fromCodePoint(Number(dec));
|
|
43960
|
-
if (
|
|
44457
|
+
if (hex3) return String.fromCodePoint(Number.parseInt(hex3, 16));
|
|
43961
44458
|
return "'";
|
|
43962
44459
|
}
|
|
43963
44460
|
).replace(/\s+/g, " ").trim();
|
|
@@ -44078,9 +44575,9 @@ function runBackgroundShortcut(input, status = backgroundStatus()) {
|
|
|
44078
44575
|
throw new Error(
|
|
44079
44576
|
`Install the supplied "${status.shortcut}" Shortcut once; Shortcuts must list it exactly once`
|
|
44080
44577
|
);
|
|
44081
|
-
const directory = mkdtempSync3(
|
|
44578
|
+
const directory = mkdtempSync3(join11(tmpdir3(), "apple-notes-background-"));
|
|
44082
44579
|
try {
|
|
44083
|
-
const file =
|
|
44580
|
+
const file = join11(directory, "request.json");
|
|
44084
44581
|
writeFileSync2(
|
|
44085
44582
|
file,
|
|
44086
44583
|
JSON.stringify({
|
|
@@ -44100,7 +44597,7 @@ function runBackgroundShortcut(input, status = backgroundStatus()) {
|
|
|
44100
44597
|
{ mode: 384 }
|
|
44101
44598
|
);
|
|
44102
44599
|
try {
|
|
44103
|
-
|
|
44600
|
+
execFileSync10("/usr/bin/shortcuts", ["run", status.identifier, "--input-path", file], {
|
|
44104
44601
|
encoding: "utf8",
|
|
44105
44602
|
timeout: 6e4,
|
|
44106
44603
|
maxBuffer: 1024 * 1024,
|
|
@@ -44303,7 +44800,7 @@ function createMarkdownNote(manager, request, run = runBackgroundShortcut) {
|
|
|
44303
44800
|
throw new Error(
|
|
44304
44801
|
`Install the supplied "${status.shortcut}" Shortcut once; Shortcuts must list it exactly once`
|
|
44305
44802
|
);
|
|
44306
|
-
const segments = (
|
|
44803
|
+
const segments = (path7) => JSON.stringify(splitFolderPath(path7).map((part) => part.toLocaleLowerCase()));
|
|
44307
44804
|
if (request.folder) {
|
|
44308
44805
|
const wanted = segments(request.folder);
|
|
44309
44806
|
if (!manager.listAccounts().some(
|
|
@@ -44392,7 +44889,7 @@ ${request.content}`
|
|
|
44392
44889
|
}
|
|
44393
44890
|
|
|
44394
44891
|
// src/services/capabilityMatrix.ts
|
|
44395
|
-
import { execFileSync as
|
|
44892
|
+
import { execFileSync as execFileSync11 } from "node:child_process";
|
|
44396
44893
|
import { release } from "node:os";
|
|
44397
44894
|
var MACOS_SHORTCUTS_CLI = "12.0";
|
|
44398
44895
|
var MACOS_MARKDOWN_IMPORT = "26.0";
|
|
@@ -44599,7 +45096,7 @@ function evaluateFeatures(env, features = FEATURES) {
|
|
|
44599
45096
|
function readMacOSVersion() {
|
|
44600
45097
|
if (process.platform !== "darwin") return null;
|
|
44601
45098
|
try {
|
|
44602
|
-
const out =
|
|
45099
|
+
const out = execFileSync11("/usr/bin/sw_vers", ["-productVersion"], {
|
|
44603
45100
|
encoding: "utf8",
|
|
44604
45101
|
timeout: 3e3,
|
|
44605
45102
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -44632,9 +45129,9 @@ function getCapabilityMatrix(probe = probeCapabilityEnvironment) {
|
|
|
44632
45129
|
return evaluateFeatures(probe());
|
|
44633
45130
|
}
|
|
44634
45131
|
function formatCapabilityMatrix(matrix) {
|
|
44635
|
-
const
|
|
45132
|
+
const os7 = matrix.runtimeOS;
|
|
44636
45133
|
const lines = [
|
|
44637
|
-
`Feature matrix (macOS ${
|
|
45134
|
+
`Feature matrix (macOS ${os7.macOSVersion ?? "unknown"}, Darwin ${os7.darwinRelease}):`
|
|
44638
45135
|
];
|
|
44639
45136
|
for (const [name, status] of Object.entries(matrix.features)) {
|
|
44640
45137
|
lines.push(
|
|
@@ -44752,19 +45249,19 @@ function formatDoctorReport(r) {
|
|
|
44752
45249
|
}
|
|
44753
45250
|
|
|
44754
45251
|
// src/services/fileConfig.ts
|
|
44755
|
-
import { existsSync as
|
|
44756
|
-
import { join as
|
|
44757
|
-
import { homedir as
|
|
45252
|
+
import { existsSync as existsSync9, readFileSync as readFileSync2 } from "fs";
|
|
45253
|
+
import { join as join12 } from "path";
|
|
45254
|
+
import { homedir as homedir10 } from "os";
|
|
44758
45255
|
function fileConfigPath(env = process.env) {
|
|
44759
45256
|
const override = env.APPLE_NOTES_MCP_CONFIG_FILE;
|
|
44760
45257
|
if (override && override.trim()) return override.trim();
|
|
44761
|
-
return
|
|
45258
|
+
return join12(homedir10(), "Library", "Application Support", "apple-notes-mcp", "config.json");
|
|
44762
45259
|
}
|
|
44763
|
-
function loadFileConfig(env = process.env,
|
|
45260
|
+
function loadFileConfig(env = process.env, path7 = fileConfigPath(env)) {
|
|
44764
45261
|
const applied = [];
|
|
44765
45262
|
try {
|
|
44766
|
-
if (!
|
|
44767
|
-
const parsed = JSON.parse(readFileSync2(
|
|
45263
|
+
if (!existsSync9(path7)) return applied;
|
|
45264
|
+
const parsed = JSON.parse(readFileSync2(path7, "utf8"));
|
|
44768
45265
|
if (!parsed || typeof parsed !== "object") return applied;
|
|
44769
45266
|
for (const [k, v] of Object.entries(parsed)) {
|
|
44770
45267
|
if (typeof v !== "string") continue;
|
|
@@ -44774,7 +45271,7 @@ function loadFileConfig(env = process.env, path6 = fileConfigPath(env)) {
|
|
|
44774
45271
|
}
|
|
44775
45272
|
}
|
|
44776
45273
|
} catch (e) {
|
|
44777
|
-
console.error(`Failed to load apple-notes-mcp config file ${
|
|
45274
|
+
console.error(`Failed to load apple-notes-mcp config file ${path7}: ${String(e)}`);
|
|
44778
45275
|
}
|
|
44779
45276
|
return applied;
|
|
44780
45277
|
}
|
|
@@ -45157,6 +45654,402 @@ function parseNoteTable(compressed) {
|
|
|
45157
45654
|
return { rows: values, rowIds: rows.ids, columnIds: columns.ids };
|
|
45158
45655
|
}
|
|
45159
45656
|
|
|
45657
|
+
// src/utils/noteBlocks.ts
|
|
45658
|
+
import { execFileSync as execFileSync12 } from "node:child_process";
|
|
45659
|
+
import { existsSync as existsSync10 } from "node:fs";
|
|
45660
|
+
import { homedir as homedir11 } from "node:os";
|
|
45661
|
+
import { join as join13 } from "node:path";
|
|
45662
|
+
import { gunzipSync as gunzipSync5 } from "node:zlib";
|
|
45663
|
+
var NoteBlocksError = class extends Error {
|
|
45664
|
+
code;
|
|
45665
|
+
constructor(code, message) {
|
|
45666
|
+
super(message);
|
|
45667
|
+
this.name = "NoteBlocksError";
|
|
45668
|
+
this.code = code;
|
|
45669
|
+
}
|
|
45670
|
+
};
|
|
45671
|
+
var STYLE_NAMES = {
|
|
45672
|
+
0: "title",
|
|
45673
|
+
1: "heading",
|
|
45674
|
+
2: "subheading",
|
|
45675
|
+
4: "monospaced",
|
|
45676
|
+
100: "bulleted",
|
|
45677
|
+
101: "dashed",
|
|
45678
|
+
102: "numbered",
|
|
45679
|
+
103: "checklist"
|
|
45680
|
+
};
|
|
45681
|
+
var ALIGNMENTS = {
|
|
45682
|
+
0: "left",
|
|
45683
|
+
1: "center",
|
|
45684
|
+
2: "right",
|
|
45685
|
+
3: "justify"
|
|
45686
|
+
};
|
|
45687
|
+
var HIGHLIGHTS = {
|
|
45688
|
+
1: "purple",
|
|
45689
|
+
2: "pink",
|
|
45690
|
+
3: "orange",
|
|
45691
|
+
4: "mint",
|
|
45692
|
+
5: "blue"
|
|
45693
|
+
};
|
|
45694
|
+
var KNOWN_RUN_FIELDS = /* @__PURE__ */ new Set([1, 2, 3, 5, 6, 7, 8, 9, 10, 12, 14]);
|
|
45695
|
+
var KNOWN_PARAGRAPH_FIELDS = /* @__PURE__ */ new Set([1, 2, 4, 5, 8, 9]);
|
|
45696
|
+
var isSafeLink = (url) => /^(?:https?:\/\/|notes:\/\/|applenotes:|mailto:)/i.test(url) && !Array.from(url).some((char) => char.charCodeAt(0) < 32);
|
|
45697
|
+
var utf8 = new TextDecoder();
|
|
45698
|
+
var first = (fields, n) => fields.find((f) => f.fieldNumber === n);
|
|
45699
|
+
var varintOf = (fields, n) => {
|
|
45700
|
+
const f = first(fields, n);
|
|
45701
|
+
return f?.wireType === 0 && f.varint !== void 0 ? signedVarint(f.varint) : void 0;
|
|
45702
|
+
};
|
|
45703
|
+
var bytesOf = (fields, n) => {
|
|
45704
|
+
const f = first(fields, n);
|
|
45705
|
+
return f?.wireType === 2 ? f.bytes : void 0;
|
|
45706
|
+
};
|
|
45707
|
+
var stringOf = (fields, n) => {
|
|
45708
|
+
const b = bytesOf(fields, n);
|
|
45709
|
+
return b ? utf8.decode(b) : void 0;
|
|
45710
|
+
};
|
|
45711
|
+
var sub2 = (fields, n) => {
|
|
45712
|
+
const b = bytesOf(fields, n);
|
|
45713
|
+
return b ? decodeWireFields(b) : void 0;
|
|
45714
|
+
};
|
|
45715
|
+
var hex2 = (bytes) => Buffer.from(bytes).toString("hex");
|
|
45716
|
+
var uuidString = (bytes) => {
|
|
45717
|
+
const h = hex2(bytes).toUpperCase();
|
|
45718
|
+
return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20)}`;
|
|
45719
|
+
};
|
|
45720
|
+
var channel = (value) => Math.max(0, Math.min(255, Math.round((Number.isFinite(value) ? value : 0) * 255))).toString(16).toUpperCase().padStart(2, "0");
|
|
45721
|
+
function colorOf(fields) {
|
|
45722
|
+
const [r, g, b, a] = [1, 2, 3, 4].map((n) => fixed32Float(first(fields, n)));
|
|
45723
|
+
if (r === void 0 && g === void 0 && b === void 0) return void 0;
|
|
45724
|
+
const rgb = `#${channel(r)}${channel(g)}${channel(b)}`;
|
|
45725
|
+
return a === void 0 || a >= 0.999 ? rgb : `${rgb}${channel(a)}`;
|
|
45726
|
+
}
|
|
45727
|
+
var DEFAULT_PARAGRAPH = {
|
|
45728
|
+
styleType: null,
|
|
45729
|
+
alignmentValue: 0,
|
|
45730
|
+
indent: 0,
|
|
45731
|
+
blockQuote: false
|
|
45732
|
+
};
|
|
45733
|
+
function decodeParagraph(fields, tally) {
|
|
45734
|
+
if (!fields) return DEFAULT_PARAGRAPH;
|
|
45735
|
+
for (const n of new Set(fields.map((f) => f.fieldNumber)))
|
|
45736
|
+
if (!KNOWN_PARAGRAPH_FIELDS.has(n)) tally.set(n, (tally.get(n) || 0) + 1);
|
|
45737
|
+
const attrs = {
|
|
45738
|
+
styleType: varintOf(fields, 1) ?? null,
|
|
45739
|
+
alignmentValue: varintOf(fields, 2) ?? 0,
|
|
45740
|
+
indent: Math.max(0, varintOf(fields, 4) ?? 0),
|
|
45741
|
+
blockQuote: (varintOf(fields, 8) ?? 0) !== 0
|
|
45742
|
+
};
|
|
45743
|
+
if (attrs.styleType === -1) attrs.styleType = null;
|
|
45744
|
+
const checklist = sub2(fields, 5);
|
|
45745
|
+
const checklistId = checklist && bytesOf(checklist, 1);
|
|
45746
|
+
if (attrs.styleType === 103 && checklistId)
|
|
45747
|
+
attrs.checklist = { id: hex2(checklistId), done: varintOf(checklist, 2) === 1 };
|
|
45748
|
+
const uuid2 = bytesOf(fields, 9);
|
|
45749
|
+
if (uuid2?.length === 16) attrs.paragraphUuid = uuidString(uuid2);
|
|
45750
|
+
return attrs;
|
|
45751
|
+
}
|
|
45752
|
+
function decodeInline(fields) {
|
|
45753
|
+
const inline = {};
|
|
45754
|
+
const font = sub2(fields, 3);
|
|
45755
|
+
const hints = font ? varintOf(font, 3) ?? 0 : 0;
|
|
45756
|
+
const weight = varintOf(fields, 5) ?? 0;
|
|
45757
|
+
if (weight === 1 || weight === 3 || hints & 1) inline.bold = true;
|
|
45758
|
+
if (weight === 2 || weight === 3 || hints & 2) inline.italic = true;
|
|
45759
|
+
if (varintOf(fields, 6)) inline.underline = true;
|
|
45760
|
+
if (varintOf(fields, 7)) inline.strikethrough = true;
|
|
45761
|
+
const baseline = varintOf(fields, 8) ?? 0;
|
|
45762
|
+
if (baseline > 0) inline.superscript = true;
|
|
45763
|
+
if (baseline < 0) inline.subscript = true;
|
|
45764
|
+
const color = sub2(fields, 10);
|
|
45765
|
+
const colorValue = color && colorOf(color);
|
|
45766
|
+
if (colorValue) inline.color = colorValue;
|
|
45767
|
+
const emphasis = varintOf(fields, 14);
|
|
45768
|
+
if (emphasis !== void 0 && emphasis !== 0) {
|
|
45769
|
+
inline.highlight = HIGHLIGHTS[emphasis] ?? "unknown";
|
|
45770
|
+
if (inline.highlight === "unknown") inline.highlightValue = emphasis;
|
|
45771
|
+
}
|
|
45772
|
+
const link = stringOf(fields, 9);
|
|
45773
|
+
if (link) {
|
|
45774
|
+
inline.link = link;
|
|
45775
|
+
inline.linkSafe = isSafeLink(link);
|
|
45776
|
+
}
|
|
45777
|
+
if (font) {
|
|
45778
|
+
const name = stringOf(font, 1);
|
|
45779
|
+
const size = fixed32Float(first(font, 2));
|
|
45780
|
+
if (name || size !== void 0)
|
|
45781
|
+
inline.font = {
|
|
45782
|
+
...name ? { name } : {},
|
|
45783
|
+
...size !== void 0 && Number.isFinite(size) ? { size } : {}
|
|
45784
|
+
};
|
|
45785
|
+
}
|
|
45786
|
+
const attachment = sub2(fields, 12);
|
|
45787
|
+
const attachmentId = attachment && stringOf(attachment, 1);
|
|
45788
|
+
if (attachmentId)
|
|
45789
|
+
inline.attachment = { id: attachmentId, uti: stringOf(attachment, 2) || "unknown" };
|
|
45790
|
+
return inline;
|
|
45791
|
+
}
|
|
45792
|
+
function wrap(error2) {
|
|
45793
|
+
if (error2 instanceof NoteBlocksError) throw error2;
|
|
45794
|
+
if (error2 instanceof ProtobufDecodeError)
|
|
45795
|
+
throw new NoteBlocksError("malformed-protobuf", error2.message);
|
|
45796
|
+
throw error2;
|
|
45797
|
+
}
|
|
45798
|
+
function decodeNoteBlocks(data) {
|
|
45799
|
+
let note;
|
|
45800
|
+
try {
|
|
45801
|
+
const document = sub2(decodeWireFields(data), 2);
|
|
45802
|
+
note = document && sub2(document, 3);
|
|
45803
|
+
} catch (error2) {
|
|
45804
|
+
wrap(error2);
|
|
45805
|
+
}
|
|
45806
|
+
const textBytes = note && bytesOf(note, 2);
|
|
45807
|
+
if (!note || !textBytes)
|
|
45808
|
+
throw new NoteBlocksError("unsupported-structure", "Unsupported Notes document structure");
|
|
45809
|
+
const text = utf8.decode(textBytes);
|
|
45810
|
+
const runTally = /* @__PURE__ */ new Map();
|
|
45811
|
+
const paragraphTally = /* @__PURE__ */ new Map();
|
|
45812
|
+
const runs = [];
|
|
45813
|
+
let position = 0;
|
|
45814
|
+
try {
|
|
45815
|
+
for (const field of note.filter((f) => f.fieldNumber === 5)) {
|
|
45816
|
+
if (field.wireType !== 2 || !field.bytes)
|
|
45817
|
+
throw new NoteBlocksError("invalid-runs", "Invalid Notes attribute run");
|
|
45818
|
+
const fields = decodeWireFields(field.bytes);
|
|
45819
|
+
const length = varintOf(fields, 1);
|
|
45820
|
+
if (length === void 0 || length < 0 || position + length > text.length)
|
|
45821
|
+
throw new NoteBlocksError("invalid-runs", "Invalid Notes run length");
|
|
45822
|
+
for (const n of new Set(fields.map((f) => f.fieldNumber)))
|
|
45823
|
+
if (!KNOWN_RUN_FIELDS.has(n)) runTally.set(n, (runTally.get(n) || 0) + 1);
|
|
45824
|
+
runs.push({
|
|
45825
|
+
start: position,
|
|
45826
|
+
length,
|
|
45827
|
+
paragraph: decodeParagraph(sub2(fields, 2), paragraphTally),
|
|
45828
|
+
inline: decodeInline(fields)
|
|
45829
|
+
});
|
|
45830
|
+
position += length;
|
|
45831
|
+
}
|
|
45832
|
+
} catch (error2) {
|
|
45833
|
+
wrap(error2);
|
|
45834
|
+
}
|
|
45835
|
+
if (position !== text.length)
|
|
45836
|
+
throw new NoteBlocksError("invalid-runs", "Incomplete Notes attribute runs");
|
|
45837
|
+
const blocks = [];
|
|
45838
|
+
const attachments = [];
|
|
45839
|
+
let runIndex = 0;
|
|
45840
|
+
let paragraphStart = 0;
|
|
45841
|
+
while (paragraphStart < text.length) {
|
|
45842
|
+
const newline = text.indexOf("\n", paragraphStart);
|
|
45843
|
+
const end = newline === -1 ? text.length : newline;
|
|
45844
|
+
while (runIndex < runs.length - 1 && runs[runIndex].start + runs[runIndex].length <= paragraphStart)
|
|
45845
|
+
runIndex++;
|
|
45846
|
+
const attrs = runs[runIndex]?.paragraph ?? DEFAULT_PARAGRAPH;
|
|
45847
|
+
const style = attrs.styleType === null ? "body" : STYLE_NAMES[attrs.styleType] ?? "unknown";
|
|
45848
|
+
const alignment = ALIGNMENTS[attrs.alignmentValue] ?? "unknown";
|
|
45849
|
+
const block = {
|
|
45850
|
+
index: blocks.length,
|
|
45851
|
+
start: paragraphStart,
|
|
45852
|
+
length: end - paragraphStart,
|
|
45853
|
+
text: text.slice(paragraphStart, end),
|
|
45854
|
+
style,
|
|
45855
|
+
styleType: attrs.styleType,
|
|
45856
|
+
indent: attrs.indent,
|
|
45857
|
+
alignment,
|
|
45858
|
+
...alignment === "unknown" ? { alignmentValue: attrs.alignmentValue } : {},
|
|
45859
|
+
blockQuote: attrs.blockQuote,
|
|
45860
|
+
...attrs.checklist ? { checklist: attrs.checklist } : {},
|
|
45861
|
+
...attrs.paragraphUuid ? { paragraphUuid: attrs.paragraphUuid } : {},
|
|
45862
|
+
runs: [],
|
|
45863
|
+
attachments: []
|
|
45864
|
+
};
|
|
45865
|
+
for (let i = runIndex; i < runs.length && runs[i].start < end; i++) {
|
|
45866
|
+
const run = runs[i];
|
|
45867
|
+
const start = Math.max(run.start, paragraphStart);
|
|
45868
|
+
const stop = Math.min(run.start + run.length, end);
|
|
45869
|
+
if (stop <= start) continue;
|
|
45870
|
+
block.runs.push({
|
|
45871
|
+
start,
|
|
45872
|
+
length: stop - start,
|
|
45873
|
+
text: text.slice(start, stop),
|
|
45874
|
+
...run.inline
|
|
45875
|
+
});
|
|
45876
|
+
if (run.inline.attachment)
|
|
45877
|
+
for (let at = text.indexOf("\uFFFC", start); at !== -1 && at < stop; at = text.indexOf("\uFFFC", at + 1)) {
|
|
45878
|
+
const marker = { ...run.inline.attachment, start: at, blockIndex: block.index };
|
|
45879
|
+
block.attachments.push(marker);
|
|
45880
|
+
attachments.push(marker);
|
|
45881
|
+
}
|
|
45882
|
+
}
|
|
45883
|
+
blocks.push(block);
|
|
45884
|
+
paragraphStart = end + 1;
|
|
45885
|
+
}
|
|
45886
|
+
return {
|
|
45887
|
+
text,
|
|
45888
|
+
textLength: text.length,
|
|
45889
|
+
blocks,
|
|
45890
|
+
attachments,
|
|
45891
|
+
undecodedFields: {
|
|
45892
|
+
attributeRun: Object.fromEntries([...runTally].sort((a, b) => a[0] - b[0])),
|
|
45893
|
+
paragraphStyle: Object.fromEntries([...paragraphTally].sort((a, b) => a[0] - b[0]))
|
|
45894
|
+
},
|
|
45895
|
+
summary: summarize(blocks, attachments)
|
|
45896
|
+
};
|
|
45897
|
+
}
|
|
45898
|
+
function summarize(blocks, attachments) {
|
|
45899
|
+
const summary = {
|
|
45900
|
+
blocks: blocks.length,
|
|
45901
|
+
styles: {},
|
|
45902
|
+
alignments: {},
|
|
45903
|
+
blockQuotes: 0,
|
|
45904
|
+
indented: 0,
|
|
45905
|
+
checklist: { total: 0, done: 0 },
|
|
45906
|
+
inline: {
|
|
45907
|
+
bold: 0,
|
|
45908
|
+
italic: 0,
|
|
45909
|
+
underline: 0,
|
|
45910
|
+
strikethrough: 0,
|
|
45911
|
+
superscript: 0,
|
|
45912
|
+
subscript: 0,
|
|
45913
|
+
color: 0,
|
|
45914
|
+
highlight: 0,
|
|
45915
|
+
link: 0,
|
|
45916
|
+
unsafeLink: 0
|
|
45917
|
+
},
|
|
45918
|
+
attachments: attachments.length
|
|
45919
|
+
};
|
|
45920
|
+
for (const block of blocks) {
|
|
45921
|
+
summary.styles[block.style] = (summary.styles[block.style] || 0) + 1;
|
|
45922
|
+
summary.alignments[block.alignment] = (summary.alignments[block.alignment] || 0) + 1;
|
|
45923
|
+
if (block.blockQuote) summary.blockQuotes++;
|
|
45924
|
+
if (block.indent > 0) summary.indented++;
|
|
45925
|
+
if (block.checklist) {
|
|
45926
|
+
summary.checklist.total++;
|
|
45927
|
+
if (block.checklist.done) summary.checklist.done++;
|
|
45928
|
+
}
|
|
45929
|
+
for (const run of block.runs) {
|
|
45930
|
+
for (const key of [
|
|
45931
|
+
"bold",
|
|
45932
|
+
"italic",
|
|
45933
|
+
"underline",
|
|
45934
|
+
"strikethrough",
|
|
45935
|
+
"superscript",
|
|
45936
|
+
"subscript",
|
|
45937
|
+
"color",
|
|
45938
|
+
"highlight",
|
|
45939
|
+
"link"
|
|
45940
|
+
])
|
|
45941
|
+
if (run[key]) summary.inline[key]++;
|
|
45942
|
+
if (run.link && !run.linkSafe) summary.inline.unsafeLink++;
|
|
45943
|
+
}
|
|
45944
|
+
}
|
|
45945
|
+
return summary;
|
|
45946
|
+
}
|
|
45947
|
+
function decodeCompressedNoteBlocks(compressed) {
|
|
45948
|
+
let data;
|
|
45949
|
+
try {
|
|
45950
|
+
data = gunzipSync5(compressed, { maxOutputLength: 32 * 1024 * 1024 });
|
|
45951
|
+
} catch (error2) {
|
|
45952
|
+
throw new NoteBlocksError(
|
|
45953
|
+
"decompress-failed",
|
|
45954
|
+
`Failed to decompress note data: ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
45955
|
+
);
|
|
45956
|
+
}
|
|
45957
|
+
return decodeNoteBlocks(data);
|
|
45958
|
+
}
|
|
45959
|
+
var DEFAULT_BLOCKS_MAX_BYTES = 4 * 1024 * 1024;
|
|
45960
|
+
function blocksMaxResponseBytes(env = process.env) {
|
|
45961
|
+
const raw = env.APPLE_NOTES_MCP_BLOCKS_MAX_BYTES;
|
|
45962
|
+
if (raw !== void 0) {
|
|
45963
|
+
const n = Number(raw);
|
|
45964
|
+
if (Number.isFinite(n) && n > 0) return Math.floor(n);
|
|
45965
|
+
}
|
|
45966
|
+
return DEFAULT_BLOCKS_MAX_BYTES;
|
|
45967
|
+
}
|
|
45968
|
+
function pageNoteBlocks(doc, { offset = 0, limit = 500, maxBytes = blocksMaxResponseBytes() } = {}) {
|
|
45969
|
+
const total = doc.blocks.length;
|
|
45970
|
+
const start = Math.min(Math.max(0, offset), total);
|
|
45971
|
+
const blocks = [];
|
|
45972
|
+
let bytes = 0;
|
|
45973
|
+
for (let i = start; i < total && blocks.length < limit; i++) {
|
|
45974
|
+
let block = doc.blocks[i];
|
|
45975
|
+
let size = Buffer.byteLength(JSON.stringify(block));
|
|
45976
|
+
if (bytes + size > maxBytes) {
|
|
45977
|
+
if (blocks.length) break;
|
|
45978
|
+
block = {
|
|
45979
|
+
...block,
|
|
45980
|
+
text: "",
|
|
45981
|
+
textOmitted: true,
|
|
45982
|
+
runs: block.runs.map((run) => ({ ...run, text: "" }))
|
|
45983
|
+
};
|
|
45984
|
+
size = Buffer.byteLength(JSON.stringify(block));
|
|
45985
|
+
}
|
|
45986
|
+
blocks.push(block);
|
|
45987
|
+
bytes += size;
|
|
45988
|
+
}
|
|
45989
|
+
const next = start + blocks.length;
|
|
45990
|
+
return {
|
|
45991
|
+
textLength: doc.textLength,
|
|
45992
|
+
blocks,
|
|
45993
|
+
page: {
|
|
45994
|
+
offset: start,
|
|
45995
|
+
returned: blocks.length,
|
|
45996
|
+
total,
|
|
45997
|
+
hasMore: next < total,
|
|
45998
|
+
...next < total ? { nextOffset: next } : {}
|
|
45999
|
+
},
|
|
46000
|
+
summary: doc.summary,
|
|
46001
|
+
undecodedFields: doc.undecodedFields
|
|
46002
|
+
};
|
|
46003
|
+
}
|
|
46004
|
+
var NOTES_DB_PATH7 = join13(
|
|
46005
|
+
homedir11(),
|
|
46006
|
+
"Library/Group Containers/group.com.apple.notes/NoteStore.sqlite"
|
|
46007
|
+
);
|
|
46008
|
+
function readNoteBlocks(id2, { dbPath: dbPath2 = NOTES_DB_PATH7 } = {}) {
|
|
46009
|
+
const pk = /^x-coredata:\/\/[0-9a-f-]+\/ICNote\/p([0-9]{1,18})$/i.exec(id2)?.[1];
|
|
46010
|
+
if (!pk)
|
|
46011
|
+
throw new NoteBlocksError(
|
|
46012
|
+
"invalid-id",
|
|
46013
|
+
`Invalid note ID: expected x-coredata://<store>/ICNote/p<number>`
|
|
46014
|
+
);
|
|
46015
|
+
if (!existsSync10(dbPath2))
|
|
46016
|
+
throw new NoteBlocksError("no-full-disk-access", "The Notes database is not readable");
|
|
46017
|
+
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));";
|
|
46018
|
+
let output;
|
|
46019
|
+
try {
|
|
46020
|
+
output = execFileSync12(
|
|
46021
|
+
"/usr/bin/sqlite3",
|
|
46022
|
+
["-readonly", "-cmd", ".parameter init", "-cmd", `.parameter set @pk ${pk}`, dbPath2, sql],
|
|
46023
|
+
{
|
|
46024
|
+
encoding: "utf8",
|
|
46025
|
+
timeout: 5e3,
|
|
46026
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
46027
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
46028
|
+
}
|
|
46029
|
+
).trim();
|
|
46030
|
+
} catch (error2) {
|
|
46031
|
+
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
46032
|
+
if (/authorization denied|unable to open database/i.test(message))
|
|
46033
|
+
throw new NoteBlocksError("no-full-disk-access", "The Notes database is not readable");
|
|
46034
|
+
throw new NoteBlocksError("query-failed", "Failed to query the Notes database");
|
|
46035
|
+
}
|
|
46036
|
+
let row;
|
|
46037
|
+
try {
|
|
46038
|
+
row = JSON.parse(output);
|
|
46039
|
+
} catch {
|
|
46040
|
+
throw new NoteBlocksError("query-failed", "Unexpected Notes database response");
|
|
46041
|
+
}
|
|
46042
|
+
if (!row.exists) throw new NoteBlocksError("not-found", `No note found for ID "${id2}"`);
|
|
46043
|
+
if (row.encrypted)
|
|
46044
|
+
throw new NoteBlocksError(
|
|
46045
|
+
"encrypted",
|
|
46046
|
+
"This note is password-protected; its body is encrypted and cannot be decoded"
|
|
46047
|
+
);
|
|
46048
|
+
if (!row.data || !/^[0-9a-f]+$/i.test(row.data))
|
|
46049
|
+
throw new NoteBlocksError("no-body", "No body data is stored for this note");
|
|
46050
|
+
return decodeCompressedNoteBlocks(Buffer.from(row.data, "hex"));
|
|
46051
|
+
}
|
|
46052
|
+
|
|
45160
46053
|
// src/utils/linkInsert.ts
|
|
45161
46054
|
var MAX_LINK_URL_LENGTH = 4096;
|
|
45162
46055
|
var MAX_LINK_LABEL_LENGTH = 2e3;
|
|
@@ -45285,7 +46178,7 @@ import {
|
|
|
45285
46178
|
writeFileSync as writeFileSync3
|
|
45286
46179
|
} from "node:fs";
|
|
45287
46180
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
45288
|
-
import { basename, isAbsolute as isAbsolute2, join as
|
|
46181
|
+
import { basename, isAbsolute as isAbsolute2, join as join14 } from "node:path";
|
|
45289
46182
|
var noteId = exactIdInput(
|
|
45290
46183
|
"ICNote",
|
|
45291
46184
|
/^x-coredata:\/\/[0-9a-f-]+\/ICNote\/p\d+$/i,
|
|
@@ -45328,9 +46221,9 @@ function assertExistingContentPreserved(before, after) {
|
|
|
45328
46221
|
throw new Error("Existing native object content or presentation changed");
|
|
45329
46222
|
}
|
|
45330
46223
|
}
|
|
45331
|
-
function localAttachment(
|
|
45332
|
-
if (!isAbsolute2(
|
|
45333
|
-
const descriptor = openSync(
|
|
46224
|
+
function localAttachment(path7) {
|
|
46225
|
+
if (!isAbsolute2(path7)) throw new Error("An absolute local file path is required");
|
|
46226
|
+
const descriptor = openSync(path7, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
45334
46227
|
try {
|
|
45335
46228
|
const stat = fstatSync(descriptor);
|
|
45336
46229
|
if (!stat.isFile() || stat.size === 0 || stat.size > 64 * 1024 * 1024)
|
|
@@ -45394,13 +46287,13 @@ function registerDirectOperations(server2, manager) {
|
|
|
45394
46287
|
"add-attachment",
|
|
45395
46288
|
"Use when: adding one local file to an exact note without replacing its body.\nReturns: the new attachment id, byte count, and post-write content hash after exact byte verification.\nDo not use when: reading or exporting an existing attachment.\nSafety: requires a fresh rich revision, copies at most 64 MiB through a private temporary file, never retries insertion, and verifies existing content plus fetched bytes.",
|
|
45396
46289
|
{ id: noteId, expectedContentHash: revision, path: external_exports.string().min(1).max(4096) },
|
|
45397
|
-
({ id: id2, expectedContentHash, path:
|
|
46290
|
+
({ id: id2, expectedContentHash, path: path7 }) => {
|
|
45398
46291
|
const before = readSnapshot(manager, id2);
|
|
45399
46292
|
if (before.hash !== expectedContentHash) throw new Error("Note revision changed");
|
|
45400
|
-
const bytes = localAttachment(
|
|
46293
|
+
const bytes = localAttachment(path7);
|
|
45401
46294
|
const beforeAttachments = manager.listAttachmentsById(id2);
|
|
45402
|
-
const directory = mkdtempSync4(
|
|
45403
|
-
const temporaryFile =
|
|
46295
|
+
const directory = mkdtempSync4(join14(tmpdir4(), "notes-attachment-add-"));
|
|
46296
|
+
const temporaryFile = join14(directory, basename(path7));
|
|
45404
46297
|
try {
|
|
45405
46298
|
writeFileSync3(temporaryFile, bytes, { mode: 384 });
|
|
45406
46299
|
if (readSnapshot(manager, id2).hash !== before.hash)
|
|
@@ -45946,7 +46839,7 @@ function registerNativeOperations(server2, manager) {
|
|
|
45946
46839
|
|
|
45947
46840
|
// src/setupShortcuts.ts
|
|
45948
46841
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
45949
|
-
import { existsSync as
|
|
46842
|
+
import { existsSync as existsSync11 } from "node:fs";
|
|
45950
46843
|
import { release as release2 } from "node:os";
|
|
45951
46844
|
import { dirname as dirname2, resolve as resolve2 } from "node:path";
|
|
45952
46845
|
import { fileURLToPath } from "node:url";
|
|
@@ -45966,16 +46859,16 @@ var shortcutFiles = [
|
|
|
45966
46859
|
];
|
|
45967
46860
|
function setupShortcuts(checkOnly, dependencies = {}) {
|
|
45968
46861
|
const status = dependencies.status || nativeTagsStatus;
|
|
45969
|
-
const exists = dependencies.exists ||
|
|
45970
|
-
const open = dependencies.open || ((
|
|
45971
|
-
const result = spawnSync2("/usr/bin/open", [
|
|
46862
|
+
const exists = dependencies.exists || existsSync11;
|
|
46863
|
+
const open = dependencies.open || ((path7) => {
|
|
46864
|
+
const result = spawnSync2("/usr/bin/open", [path7], { encoding: "utf8" });
|
|
45972
46865
|
return result.status === 0 ? { ok: true } : { ok: false, error: result.stderr || result.error?.message || "open failed" };
|
|
45973
46866
|
});
|
|
45974
46867
|
const baseDirectory = dependencies.baseDirectory || resolve2(dirname2(fileURLToPath(import.meta.url)), "../shortcuts");
|
|
45975
46868
|
const osRelease = (dependencies.osRelease || release2)();
|
|
45976
46869
|
const darwinMajor = Number.parseInt(osRelease.split(".")[0], 10);
|
|
45977
46870
|
const items = shortcutFiles.map(({ name, file, optional: optional2 }) => {
|
|
45978
|
-
const
|
|
46871
|
+
const path7 = resolve2(baseDirectory, file);
|
|
45979
46872
|
let installed = false;
|
|
45980
46873
|
let identifier;
|
|
45981
46874
|
let error2;
|
|
@@ -45991,9 +46884,9 @@ function setupShortcuts(checkOnly, dependencies = {}) {
|
|
|
45991
46884
|
if (!installed && !checkOnly) {
|
|
45992
46885
|
if (optional2 && !(darwinMajor >= MARKDOWN_MIN_DARWIN_MAJOR))
|
|
45993
46886
|
skipped = `requires macOS 26 or later (this Mac reports Darwin ${osRelease})`;
|
|
45994
|
-
else if (!exists(
|
|
46887
|
+
else if (!exists(path7)) error2 = `Packaged Shortcut is missing: ${path7}`;
|
|
45995
46888
|
else {
|
|
45996
|
-
const result = open(
|
|
46889
|
+
const result = open(path7);
|
|
45997
46890
|
opened = result.ok;
|
|
45998
46891
|
if (!result.ok) error2 = result.error || `Could not open ${file}`;
|
|
45999
46892
|
}
|
|
@@ -46002,7 +46895,7 @@ function setupShortcuts(checkOnly, dependencies = {}) {
|
|
|
46002
46895
|
name,
|
|
46003
46896
|
installed,
|
|
46004
46897
|
identifier,
|
|
46005
|
-
file:
|
|
46898
|
+
file: path7,
|
|
46006
46899
|
opened,
|
|
46007
46900
|
...optional2 ? { optional: optional2 } : {},
|
|
46008
46901
|
...skipped ? { skipped } : {},
|
|
@@ -46782,6 +47675,42 @@ registerTool(
|
|
|
46782
47675
|
});
|
|
46783
47676
|
}, "Error reading native objects")
|
|
46784
47677
|
);
|
|
47678
|
+
registerTool(
|
|
47679
|
+
"get-note-blocks",
|
|
47680
|
+
{
|
|
47681
|
+
description: "Use when: you need a note's structure, not just its text: paragraph styles (title, heading, subheading, body, monospaced, bulleted/dashed/numbered list, checklist with done state), indent, alignment, block quote, inline formatting (bold, italic, underline, strikethrough, superscript, subscript, color, highlight, links) and attachment positions, by exact id.\nReturns: one page of blocks in body order (default 500, stopped early under APPLE_NOTES_MCP_BLOCKS_MAX_BYTES, default 4 MB), whole-note summary counts, undecodedFields, and page info; while page.hasMore is true, call again with offset set to page.nextOffset. Offsets and lengths count UTF-16 code units.\nDo not use when: you want the editable HTML body (get-note-content) or Markdown (get-note-markdown).\nSafety: read-only; decodes the NoteStore database directly and requires Full Disk Access. Password-protected notes are refused. Link URLs are returned as stored; linkSafe is false for schemes other than http(s), notes, applenotes and mailto.",
|
|
47682
|
+
inputSchema: {
|
|
47683
|
+
id: noteIdInput,
|
|
47684
|
+
offset: external_exports.number().int().min(0).optional().describe("Index of the first block to return (default 0); use page.nextOffset"),
|
|
47685
|
+
limit: external_exports.number().int().min(1).max(5e3).optional().describe("Maximum blocks to return (default 500, max 5000)")
|
|
47686
|
+
},
|
|
47687
|
+
outputSchema: {
|
|
47688
|
+
id: external_exports.string().optional(),
|
|
47689
|
+
textLength: external_exports.number().optional(),
|
|
47690
|
+
blocks: external_exports.array(external_exports.record(external_exports.unknown())).optional(),
|
|
47691
|
+
page: external_exports.record(external_exports.unknown()).optional(),
|
|
47692
|
+
summary: external_exports.record(external_exports.unknown()).optional(),
|
|
47693
|
+
undecodedFields: external_exports.record(external_exports.unknown()).optional()
|
|
47694
|
+
},
|
|
47695
|
+
annotations: { readOnlyHint: true }
|
|
47696
|
+
},
|
|
47697
|
+
withErrorHandling(({ id: id2, offset, limit }) => {
|
|
47698
|
+
let page;
|
|
47699
|
+
try {
|
|
47700
|
+
page = pageNoteBlocks(readNoteBlocks(id2), { offset, limit });
|
|
47701
|
+
} catch (error2) {
|
|
47702
|
+
if (!(error2 instanceof NoteBlocksError)) throw error2;
|
|
47703
|
+
const hint = error2.code === "no-full-disk-access" ? ` Grant Full Disk Access to the app that launches this server: ${FULL_DISK_ACCESS_GUIDE_URL}` : "";
|
|
47704
|
+
return errorResponse(`Error reading note blocks [${error2.code}]: ${error2.message}${hint}`);
|
|
47705
|
+
}
|
|
47706
|
+
const { summary } = page;
|
|
47707
|
+
const styles = Object.entries(summary.styles).map(([style, count]) => `${style} ${count}`).join(", ");
|
|
47708
|
+
return successResponse(
|
|
47709
|
+
`Decoded ${summary.blocks} blocks (${styles || "none"}); returned ${page.page.returned} from offset ${page.page.offset}` + (page.page.hasMore ? `; more available at offset ${page.page.nextOffset}` : "") + ".",
|
|
47710
|
+
{ id: id2, ...page }
|
|
47711
|
+
);
|
|
47712
|
+
}, "Error reading note blocks")
|
|
47713
|
+
);
|
|
46785
47714
|
registerTool(
|
|
46786
47715
|
"list-native-tags",
|
|
46787
47716
|
{
|
|
@@ -47346,6 +48275,55 @@ ${folderList}${syncNote}`,
|
|
|
47346
48275
|
);
|
|
47347
48276
|
}, "Error listing folders")
|
|
47348
48277
|
);
|
|
48278
|
+
registerTool(
|
|
48279
|
+
"list-smart-folders",
|
|
48280
|
+
{
|
|
48281
|
+
description: `Use when: listing Smart Folders and the rules that define them.
|
|
48282
|
+
Returns: each smart folder's name, ids, account, and parent, its rules decoded as match ("all"/"any"/"none") plus filters (each with a readable description), the stored query with the outer deleted wrapper removed, and the raw stored query JSON. With includeMatchingNotes, also the notes Notes.app currently shows in each folder.
|
|
48283
|
+
Do not use when: listing ordinary folders (list-folders) or searching notes (search-notes).
|
|
48284
|
+
Safety: read-only; reads the NoteStore database and requires Full Disk Access. includeMatchingNotes asks Notes.app (Automation permission) for each folder's current contents rather than re-evaluating the rules. Unrecognized rules are kept as "unknown" filters and set fullyDecoded false.`,
|
|
48285
|
+
inputSchema: {
|
|
48286
|
+
includeMatchingNotes: external_exports.boolean().optional().describe(
|
|
48287
|
+
"Also list the notes Notes.app currently shows in each smart folder (default false)"
|
|
48288
|
+
),
|
|
48289
|
+
limit: external_exports.number().int().min(1).max(500).optional().describe("Maximum matching notes returned per folder (default 50; count is always total)")
|
|
48290
|
+
},
|
|
48291
|
+
outputSchema: {
|
|
48292
|
+
smartFolders: external_exports.array(external_exports.object({}).passthrough()).optional(),
|
|
48293
|
+
count: external_exports.number().optional(),
|
|
48294
|
+
fullyDecoded: external_exports.boolean().optional()
|
|
48295
|
+
},
|
|
48296
|
+
annotations: { readOnlyHint: true }
|
|
48297
|
+
},
|
|
48298
|
+
withErrorHandling(({ includeMatchingNotes = false, limit }) => {
|
|
48299
|
+
const folders = notesManager.listSmartFolders({ includeMatchingNotes, limit });
|
|
48300
|
+
const fullyDecoded = folders.every((folder) => folder.fullyDecoded);
|
|
48301
|
+
if (folders.length === 0) {
|
|
48302
|
+
return successResponse("No smart folders found.", {
|
|
48303
|
+
smartFolders: [],
|
|
48304
|
+
count: 0,
|
|
48305
|
+
fullyDecoded
|
|
48306
|
+
});
|
|
48307
|
+
}
|
|
48308
|
+
const lines = folders.map((folder) => {
|
|
48309
|
+
const joiner = folder.match === "any" ? " OR " : " AND ";
|
|
48310
|
+
const rules = folder.filters.map((filter) => filter.description).join(joiner);
|
|
48311
|
+
const prefix = folder.match === "none" ? "none of: " : "";
|
|
48312
|
+
const where = [folder.account, folder.parent].filter(Boolean).join(" / ");
|
|
48313
|
+
const matches = folder.matchingNoteCount !== void 0 ? ` [${folder.matchingNoteCount} note(s)]` : folder.matchingNotesError ? ` [notes unavailable: ${folder.matchingNotesError}]` : "";
|
|
48314
|
+
return ` - ${folder.name ?? "(untitled)"}${where ? ` (${where})` : ""}: ${prefix}${rules || "(no rules)"}${matches}`;
|
|
48315
|
+
});
|
|
48316
|
+
return successResponse(
|
|
48317
|
+
`Found ${folders.length} smart folder(s):
|
|
48318
|
+
${lines.join("\n")}${fullyDecoded ? "" : '\n\nSome rules were not recognized; see filters of type "unknown".'}`,
|
|
48319
|
+
{
|
|
48320
|
+
smartFolders: folders,
|
|
48321
|
+
count: folders.length,
|
|
48322
|
+
fullyDecoded
|
|
48323
|
+
}
|
|
48324
|
+
);
|
|
48325
|
+
}, "Error listing smart folders")
|
|
48326
|
+
);
|
|
47349
48327
|
registerTool(
|
|
47350
48328
|
"create-folder",
|
|
47351
48329
|
{
|