apple-notes-mcp 2.8.35 → 2.8.37
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 +93 -8
- package/build/index.js +2012 -420
- package/package.json +1 -1
package/build/index.js
CHANGED
|
@@ -417,11 +417,11 @@ var require_codegen = __commonJS({
|
|
|
417
417
|
const rhs = this.rhs === void 0 ? "" : ` = ${this.rhs}`;
|
|
418
418
|
return `${varKind} ${this.name}${rhs};` + _n;
|
|
419
419
|
}
|
|
420
|
-
optimizeNames(names,
|
|
420
|
+
optimizeNames(names, constants6) {
|
|
421
421
|
if (!names[this.name.str])
|
|
422
422
|
return;
|
|
423
423
|
if (this.rhs)
|
|
424
|
-
this.rhs = optimizeExpr(this.rhs, names,
|
|
424
|
+
this.rhs = optimizeExpr(this.rhs, names, constants6);
|
|
425
425
|
return this;
|
|
426
426
|
}
|
|
427
427
|
get names() {
|
|
@@ -438,10 +438,10 @@ var require_codegen = __commonJS({
|
|
|
438
438
|
render({ _n }) {
|
|
439
439
|
return `${this.lhs} = ${this.rhs};` + _n;
|
|
440
440
|
}
|
|
441
|
-
optimizeNames(names,
|
|
441
|
+
optimizeNames(names, constants6) {
|
|
442
442
|
if (this.lhs instanceof code_1.Name && !names[this.lhs.str] && !this.sideEffects)
|
|
443
443
|
return;
|
|
444
|
-
this.rhs = optimizeExpr(this.rhs, names,
|
|
444
|
+
this.rhs = optimizeExpr(this.rhs, names, constants6);
|
|
445
445
|
return this;
|
|
446
446
|
}
|
|
447
447
|
get names() {
|
|
@@ -502,8 +502,8 @@ var require_codegen = __commonJS({
|
|
|
502
502
|
optimizeNodes() {
|
|
503
503
|
return `${this.code}` ? this : void 0;
|
|
504
504
|
}
|
|
505
|
-
optimizeNames(names,
|
|
506
|
-
this.code = optimizeExpr(this.code, names,
|
|
505
|
+
optimizeNames(names, constants6) {
|
|
506
|
+
this.code = optimizeExpr(this.code, names, constants6);
|
|
507
507
|
return this;
|
|
508
508
|
}
|
|
509
509
|
get names() {
|
|
@@ -532,12 +532,12 @@ var require_codegen = __commonJS({
|
|
|
532
532
|
}
|
|
533
533
|
return nodes.length > 0 ? this : void 0;
|
|
534
534
|
}
|
|
535
|
-
optimizeNames(names,
|
|
535
|
+
optimizeNames(names, constants6) {
|
|
536
536
|
const { nodes } = this;
|
|
537
537
|
let i = nodes.length;
|
|
538
538
|
while (i--) {
|
|
539
539
|
const n = nodes[i];
|
|
540
|
-
if (n.optimizeNames(names,
|
|
540
|
+
if (n.optimizeNames(names, constants6))
|
|
541
541
|
continue;
|
|
542
542
|
subtractNames(names, n.names);
|
|
543
543
|
nodes.splice(i, 1);
|
|
@@ -590,12 +590,12 @@ var require_codegen = __commonJS({
|
|
|
590
590
|
return void 0;
|
|
591
591
|
return this;
|
|
592
592
|
}
|
|
593
|
-
optimizeNames(names,
|
|
593
|
+
optimizeNames(names, constants6) {
|
|
594
594
|
var _a;
|
|
595
|
-
this.else = (_a = this.else) === null || _a === void 0 ? void 0 : _a.optimizeNames(names,
|
|
596
|
-
if (!(super.optimizeNames(names,
|
|
595
|
+
this.else = (_a = this.else) === null || _a === void 0 ? void 0 : _a.optimizeNames(names, constants6);
|
|
596
|
+
if (!(super.optimizeNames(names, constants6) || this.else))
|
|
597
597
|
return;
|
|
598
|
-
this.condition = optimizeExpr(this.condition, names,
|
|
598
|
+
this.condition = optimizeExpr(this.condition, names, constants6);
|
|
599
599
|
return this;
|
|
600
600
|
}
|
|
601
601
|
get names() {
|
|
@@ -618,10 +618,10 @@ var require_codegen = __commonJS({
|
|
|
618
618
|
render(opts) {
|
|
619
619
|
return `for(${this.iteration})` + super.render(opts);
|
|
620
620
|
}
|
|
621
|
-
optimizeNames(names,
|
|
622
|
-
if (!super.optimizeNames(names,
|
|
621
|
+
optimizeNames(names, constants6) {
|
|
622
|
+
if (!super.optimizeNames(names, constants6))
|
|
623
623
|
return;
|
|
624
|
-
this.iteration = optimizeExpr(this.iteration, names,
|
|
624
|
+
this.iteration = optimizeExpr(this.iteration, names, constants6);
|
|
625
625
|
return this;
|
|
626
626
|
}
|
|
627
627
|
get names() {
|
|
@@ -657,10 +657,10 @@ var require_codegen = __commonJS({
|
|
|
657
657
|
render(opts) {
|
|
658
658
|
return `for(${this.varKind} ${this.name} ${this.loop} ${this.iterable})` + super.render(opts);
|
|
659
659
|
}
|
|
660
|
-
optimizeNames(names,
|
|
661
|
-
if (!super.optimizeNames(names,
|
|
660
|
+
optimizeNames(names, constants6) {
|
|
661
|
+
if (!super.optimizeNames(names, constants6))
|
|
662
662
|
return;
|
|
663
|
-
this.iterable = optimizeExpr(this.iterable, names,
|
|
663
|
+
this.iterable = optimizeExpr(this.iterable, names, constants6);
|
|
664
664
|
return this;
|
|
665
665
|
}
|
|
666
666
|
get names() {
|
|
@@ -702,11 +702,11 @@ var require_codegen = __commonJS({
|
|
|
702
702
|
(_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNodes();
|
|
703
703
|
return this;
|
|
704
704
|
}
|
|
705
|
-
optimizeNames(names,
|
|
705
|
+
optimizeNames(names, constants6) {
|
|
706
706
|
var _a, _b;
|
|
707
|
-
super.optimizeNames(names,
|
|
708
|
-
(_a = this.catch) === null || _a === void 0 ? void 0 : _a.optimizeNames(names,
|
|
709
|
-
(_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNames(names,
|
|
707
|
+
super.optimizeNames(names, constants6);
|
|
708
|
+
(_a = this.catch) === null || _a === void 0 ? void 0 : _a.optimizeNames(names, constants6);
|
|
709
|
+
(_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNames(names, constants6);
|
|
710
710
|
return this;
|
|
711
711
|
}
|
|
712
712
|
get names() {
|
|
@@ -1007,7 +1007,7 @@ var require_codegen = __commonJS({
|
|
|
1007
1007
|
function addExprNames(names, from) {
|
|
1008
1008
|
return from instanceof code_1._CodeOrName ? addNames(names, from.names) : names;
|
|
1009
1009
|
}
|
|
1010
|
-
function optimizeExpr(expr, names,
|
|
1010
|
+
function optimizeExpr(expr, names, constants6) {
|
|
1011
1011
|
if (expr instanceof code_1.Name)
|
|
1012
1012
|
return replaceName(expr);
|
|
1013
1013
|
if (!canOptimize(expr))
|
|
@@ -1022,14 +1022,14 @@ var require_codegen = __commonJS({
|
|
|
1022
1022
|
return items;
|
|
1023
1023
|
}, []));
|
|
1024
1024
|
function replaceName(n) {
|
|
1025
|
-
const c =
|
|
1025
|
+
const c = constants6[n.str];
|
|
1026
1026
|
if (c === void 0 || names[n.str] !== 1)
|
|
1027
1027
|
return n;
|
|
1028
1028
|
delete names[n.str];
|
|
1029
1029
|
return c;
|
|
1030
1030
|
}
|
|
1031
1031
|
function canOptimize(e) {
|
|
1032
|
-
return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 &&
|
|
1032
|
+
return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 && constants6[c.str] !== void 0);
|
|
1033
1033
|
}
|
|
1034
1034
|
}
|
|
1035
1035
|
function subtractNames(names, from) {
|
|
@@ -2991,7 +2991,7 @@ var require_compile = __commonJS({
|
|
|
2991
2991
|
const schOrFunc = root.refs[ref];
|
|
2992
2992
|
if (schOrFunc)
|
|
2993
2993
|
return schOrFunc;
|
|
2994
|
-
let _sch =
|
|
2994
|
+
let _sch = resolve5.call(this, root, ref);
|
|
2995
2995
|
if (_sch === void 0) {
|
|
2996
2996
|
const schema = (_a = root.localRefs) === null || _a === void 0 ? void 0 : _a[ref];
|
|
2997
2997
|
const { schemaId } = this.opts;
|
|
@@ -3018,7 +3018,7 @@ var require_compile = __commonJS({
|
|
|
3018
3018
|
function sameSchemaEnv(s1, s2) {
|
|
3019
3019
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
3020
3020
|
}
|
|
3021
|
-
function
|
|
3021
|
+
function resolve5(root, ref) {
|
|
3022
3022
|
let sch;
|
|
3023
3023
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
3024
3024
|
ref = sch;
|
|
@@ -3268,8 +3268,8 @@ var require_utils = __commonJS({
|
|
|
3268
3268
|
}
|
|
3269
3269
|
return ind;
|
|
3270
3270
|
}
|
|
3271
|
-
function removeDotSegments(
|
|
3272
|
-
let input =
|
|
3271
|
+
function removeDotSegments(path8) {
|
|
3272
|
+
let input = path8;
|
|
3273
3273
|
const output = [];
|
|
3274
3274
|
let nextSlash = -1;
|
|
3275
3275
|
let len = 0;
|
|
@@ -3674,8 +3674,8 @@ var require_schemes = __commonJS({
|
|
|
3674
3674
|
}
|
|
3675
3675
|
if (wsComponent.resourceName) {
|
|
3676
3676
|
const queryIndex = wsComponent.resourceName.indexOf("?");
|
|
3677
|
-
const
|
|
3678
|
-
wsComponent.path =
|
|
3677
|
+
const path8 = queryIndex === -1 ? wsComponent.resourceName : wsComponent.resourceName.slice(0, queryIndex);
|
|
3678
|
+
wsComponent.path = path8 && path8 !== "/" ? path8 : void 0;
|
|
3679
3679
|
wsComponent.query = queryIndex === -1 ? void 0 : wsComponent.resourceName.slice(queryIndex + 1);
|
|
3680
3680
|
wsComponent.resourceName = void 0;
|
|
3681
3681
|
}
|
|
@@ -3843,7 +3843,7 @@ var require_fast_uri = __commonJS({
|
|
|
3843
3843
|
}
|
|
3844
3844
|
return uri;
|
|
3845
3845
|
}
|
|
3846
|
-
function
|
|
3846
|
+
function resolve5(baseURI, relativeURI, options) {
|
|
3847
3847
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
3848
3848
|
const {
|
|
3849
3849
|
parsed: baseParsed,
|
|
@@ -3876,49 +3876,49 @@ var require_fast_uri = __commonJS({
|
|
|
3876
3876
|
schemelessOptions.skipEscape = true;
|
|
3877
3877
|
return serialize(resolved, schemelessOptions);
|
|
3878
3878
|
}
|
|
3879
|
-
function resolveComponent(base,
|
|
3879
|
+
function resolveComponent(base, relative4, options, skipNormalization) {
|
|
3880
3880
|
const target = {};
|
|
3881
3881
|
if (!skipNormalization) {
|
|
3882
3882
|
base = parse3(serialize(base, options), options);
|
|
3883
|
-
|
|
3883
|
+
relative4 = parse3(serialize(relative4, options), options);
|
|
3884
3884
|
}
|
|
3885
3885
|
options = options || {};
|
|
3886
|
-
if (!options.tolerant &&
|
|
3887
|
-
target.scheme =
|
|
3888
|
-
target.userinfo =
|
|
3889
|
-
target.host =
|
|
3890
|
-
target.port =
|
|
3891
|
-
target.path = removeDotSegments(
|
|
3892
|
-
target.query =
|
|
3886
|
+
if (!options.tolerant && relative4.scheme) {
|
|
3887
|
+
target.scheme = relative4.scheme;
|
|
3888
|
+
target.userinfo = relative4.userinfo;
|
|
3889
|
+
target.host = relative4.host;
|
|
3890
|
+
target.port = relative4.port;
|
|
3891
|
+
target.path = removeDotSegments(relative4.path || "");
|
|
3892
|
+
target.query = relative4.query;
|
|
3893
3893
|
} else {
|
|
3894
|
-
if (
|
|
3895
|
-
target.userinfo =
|
|
3896
|
-
target.host =
|
|
3897
|
-
target.port =
|
|
3898
|
-
target.path = removeDotSegments(
|
|
3899
|
-
target.query =
|
|
3894
|
+
if (relative4.userinfo !== void 0 || relative4.host !== void 0 || relative4.port !== void 0) {
|
|
3895
|
+
target.userinfo = relative4.userinfo;
|
|
3896
|
+
target.host = relative4.host;
|
|
3897
|
+
target.port = relative4.port;
|
|
3898
|
+
target.path = removeDotSegments(relative4.path || "");
|
|
3899
|
+
target.query = relative4.query;
|
|
3900
3900
|
} else {
|
|
3901
|
-
if (!
|
|
3901
|
+
if (!relative4.path) {
|
|
3902
3902
|
target.path = base.path;
|
|
3903
|
-
if (
|
|
3904
|
-
target.query =
|
|
3903
|
+
if (relative4.query !== void 0) {
|
|
3904
|
+
target.query = relative4.query;
|
|
3905
3905
|
} else {
|
|
3906
3906
|
target.query = base.query;
|
|
3907
3907
|
}
|
|
3908
3908
|
} else {
|
|
3909
|
-
if (
|
|
3910
|
-
target.path = removeDotSegments(
|
|
3909
|
+
if (relative4.path[0] === "/") {
|
|
3910
|
+
target.path = removeDotSegments(relative4.path);
|
|
3911
3911
|
} else {
|
|
3912
3912
|
if ((base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0) && !base.path) {
|
|
3913
|
-
target.path = "/" +
|
|
3913
|
+
target.path = "/" + relative4.path;
|
|
3914
3914
|
} else if (!base.path) {
|
|
3915
|
-
target.path =
|
|
3915
|
+
target.path = relative4.path;
|
|
3916
3916
|
} else {
|
|
3917
|
-
target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) +
|
|
3917
|
+
target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative4.path;
|
|
3918
3918
|
}
|
|
3919
3919
|
target.path = removeDotSegments(target.path);
|
|
3920
3920
|
}
|
|
3921
|
-
target.query =
|
|
3921
|
+
target.query = relative4.query;
|
|
3922
3922
|
}
|
|
3923
3923
|
target.userinfo = base.userinfo;
|
|
3924
3924
|
target.host = base.host;
|
|
@@ -3926,7 +3926,7 @@ var require_fast_uri = __commonJS({
|
|
|
3926
3926
|
}
|
|
3927
3927
|
target.scheme = base.scheme;
|
|
3928
3928
|
}
|
|
3929
|
-
target.fragment =
|
|
3929
|
+
target.fragment = relative4.fragment;
|
|
3930
3930
|
return target;
|
|
3931
3931
|
}
|
|
3932
3932
|
function equal(uriA, uriB, options) {
|
|
@@ -4205,7 +4205,7 @@ var require_fast_uri = __commonJS({
|
|
|
4205
4205
|
var fastUri = {
|
|
4206
4206
|
SCHEMES,
|
|
4207
4207
|
normalize,
|
|
4208
|
-
resolve:
|
|
4208
|
+
resolve: resolve5,
|
|
4209
4209
|
resolveComponent,
|
|
4210
4210
|
equal,
|
|
4211
4211
|
serialize,
|
|
@@ -4620,7 +4620,7 @@ var require_core = __commonJS({
|
|
|
4620
4620
|
errorsText(errors = this.errors, { separator = ", ", dataVar = "data" } = {}) {
|
|
4621
4621
|
if (!errors || errors.length === 0)
|
|
4622
4622
|
return "No errors";
|
|
4623
|
-
return errors.map((e) => `${dataVar}${e.instancePath} ${e.message}`).reduce((
|
|
4623
|
+
return errors.map((e) => `${dataVar}${e.instancePath} ${e.message}`).reduce((text2, msg) => text2 + separator + msg);
|
|
4624
4624
|
}
|
|
4625
4625
|
$dataMetaSchema(metaSchema, keywordsJsonPointers) {
|
|
4626
4626
|
const rules = this.RULES.all;
|
|
@@ -7181,12 +7181,12 @@ var require_dist = __commonJS({
|
|
|
7181
7181
|
throw new Error(`Unknown format "${name}"`);
|
|
7182
7182
|
return f;
|
|
7183
7183
|
};
|
|
7184
|
-
function addFormats(ajv, list,
|
|
7184
|
+
function addFormats(ajv, list, fs8, exportName) {
|
|
7185
7185
|
var _a;
|
|
7186
7186
|
var _b;
|
|
7187
7187
|
(_a = (_b = ajv.opts.code).formats) !== null && _a !== void 0 ? _a : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
|
|
7188
7188
|
for (const f of list)
|
|
7189
|
-
ajv.addFormat(f,
|
|
7189
|
+
ajv.addFormat(f, fs8[f]);
|
|
7190
7190
|
}
|
|
7191
7191
|
module.exports = exports = formatsPlugin;
|
|
7192
7192
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -7422,7 +7422,7 @@ var require_DOMException = __commonJS({
|
|
|
7422
7422
|
"INVALID_NODE_TYPE_ERR (24): the supplied node is invalid or has an invalid ancestor for this operation",
|
|
7423
7423
|
"DATA_CLONE_ERR (25): the object can not be cloned."
|
|
7424
7424
|
];
|
|
7425
|
-
var
|
|
7425
|
+
var constants6 = {
|
|
7426
7426
|
INDEX_SIZE_ERR,
|
|
7427
7427
|
DOMSTRING_SIZE_ERR: 2,
|
|
7428
7428
|
// historical
|
|
@@ -7461,8 +7461,8 @@ var require_DOMException = __commonJS({
|
|
|
7461
7461
|
this.name = names[code];
|
|
7462
7462
|
}
|
|
7463
7463
|
DOMException.prototype.__proto__ = Error.prototype;
|
|
7464
|
-
for (c in
|
|
7465
|
-
v = { value:
|
|
7464
|
+
for (c in constants6) {
|
|
7465
|
+
v = { value: constants6[c] };
|
|
7466
7466
|
Object.defineProperty(DOMException, c, v);
|
|
7467
7467
|
Object.defineProperty(DOMException.prototype, c, v);
|
|
7468
7468
|
}
|
|
@@ -9621,8 +9621,8 @@ var require_select = __commonJS({
|
|
|
9621
9621
|
// Non-standard, for compatibility purposes.
|
|
9622
9622
|
":contains": function(param) {
|
|
9623
9623
|
return function(el) {
|
|
9624
|
-
var
|
|
9625
|
-
return
|
|
9624
|
+
var text2 = el.innerText || el.textContent || el.value || "";
|
|
9625
|
+
return text2.indexOf(param) !== -1;
|
|
9626
9626
|
};
|
|
9627
9627
|
},
|
|
9628
9628
|
":has": function(param) {
|
|
@@ -10289,9 +10289,9 @@ var require_Element = __commonJS({
|
|
|
10289
10289
|
position = utils.toASCIILowerCase(String(position));
|
|
10290
10290
|
this._insertAdjacent(position, textNode);
|
|
10291
10291
|
} },
|
|
10292
|
-
insertAdjacentHTML: { value: function insertAdjacentHTML(position,
|
|
10292
|
+
insertAdjacentHTML: { value: function insertAdjacentHTML(position, text2) {
|
|
10293
10293
|
position = utils.toASCIILowerCase(String(position));
|
|
10294
|
-
|
|
10294
|
+
text2 = String(text2);
|
|
10295
10295
|
var context;
|
|
10296
10296
|
switch (position) {
|
|
10297
10297
|
case "beforebegin":
|
|
@@ -10315,7 +10315,7 @@ var require_Element = __commonJS({
|
|
|
10315
10315
|
this.ownerDocument._address,
|
|
10316
10316
|
context
|
|
10317
10317
|
);
|
|
10318
|
-
parser.parse(
|
|
10318
|
+
parser.parse(text2, true);
|
|
10319
10319
|
this._insertAdjacent(position, parser._asDocumentFragment());
|
|
10320
10320
|
} },
|
|
10321
10321
|
children: { get: function() {
|
|
@@ -12184,9 +12184,9 @@ var require_URL = __commonJS({
|
|
|
12184
12184
|
},
|
|
12185
12185
|
// See: http://tools.ietf.org/html/rfc3986#section-5.2
|
|
12186
12186
|
// and https://url.spec.whatwg.org/#constructors
|
|
12187
|
-
resolve: function(
|
|
12187
|
+
resolve: function(relative4) {
|
|
12188
12188
|
var base = this;
|
|
12189
|
-
var r = new URL2(
|
|
12189
|
+
var r = new URL2(relative4);
|
|
12190
12190
|
var t = new URL2();
|
|
12191
12191
|
if (r.scheme !== void 0) {
|
|
12192
12192
|
t.scheme = r.scheme;
|
|
@@ -12238,32 +12238,32 @@ var require_URL = __commonJS({
|
|
|
12238
12238
|
else
|
|
12239
12239
|
return basepath.substring(0, lastslash + 1) + refpath;
|
|
12240
12240
|
}
|
|
12241
|
-
function remove_dot_segments(
|
|
12242
|
-
if (!
|
|
12241
|
+
function remove_dot_segments(path8) {
|
|
12242
|
+
if (!path8) return path8;
|
|
12243
12243
|
var output = "";
|
|
12244
|
-
while (
|
|
12245
|
-
if (
|
|
12246
|
-
|
|
12244
|
+
while (path8.length > 0) {
|
|
12245
|
+
if (path8 === "." || path8 === "..") {
|
|
12246
|
+
path8 = "";
|
|
12247
12247
|
break;
|
|
12248
12248
|
}
|
|
12249
|
-
var twochars =
|
|
12250
|
-
var threechars =
|
|
12251
|
-
var fourchars =
|
|
12249
|
+
var twochars = path8.substring(0, 2);
|
|
12250
|
+
var threechars = path8.substring(0, 3);
|
|
12251
|
+
var fourchars = path8.substring(0, 4);
|
|
12252
12252
|
if (threechars === "../") {
|
|
12253
|
-
|
|
12253
|
+
path8 = path8.substring(3);
|
|
12254
12254
|
} else if (twochars === "./") {
|
|
12255
|
-
|
|
12255
|
+
path8 = path8.substring(2);
|
|
12256
12256
|
} else if (threechars === "/./") {
|
|
12257
|
-
|
|
12258
|
-
} else if (twochars === "/." &&
|
|
12259
|
-
|
|
12260
|
-
} else if (fourchars === "/../" || threechars === "/.." &&
|
|
12261
|
-
|
|
12257
|
+
path8 = "/" + path8.substring(3);
|
|
12258
|
+
} else if (twochars === "/." && path8.length === 2) {
|
|
12259
|
+
path8 = "/";
|
|
12260
|
+
} else if (fourchars === "/../" || threechars === "/.." && path8.length === 3) {
|
|
12261
|
+
path8 = "/" + path8.substring(4);
|
|
12262
12262
|
output = output.replace(/\/?[^\/]*$/, "");
|
|
12263
12263
|
} else {
|
|
12264
|
-
var segment =
|
|
12264
|
+
var segment = path8.match(/(\/?([^\/]*))/)[0];
|
|
12265
12265
|
output += segment;
|
|
12266
|
-
|
|
12266
|
+
path8 = path8.substring(segment.length);
|
|
12267
12267
|
}
|
|
12268
12268
|
}
|
|
12269
12269
|
return output;
|
|
@@ -12434,9 +12434,9 @@ var require_CSSStyleDeclaration = __commonJS({
|
|
|
12434
12434
|
// Note that the styles don't get parsed until they're actually needed
|
|
12435
12435
|
_parsed: { get: function() {
|
|
12436
12436
|
if (!this._parsedStyles || this.cssText !== this._lastParsedText) {
|
|
12437
|
-
var
|
|
12438
|
-
this._parsedStyles = parseStyles(
|
|
12439
|
-
this._lastParsedText =
|
|
12437
|
+
var text2 = this.cssText;
|
|
12438
|
+
this._parsedStyles = parseStyles(text2);
|
|
12439
|
+
this._lastParsedText = text2;
|
|
12440
12440
|
delete this._names;
|
|
12441
12441
|
}
|
|
12442
12442
|
return this._parsedStyles;
|
|
@@ -23907,7 +23907,7 @@ var require_turndown_cjs = __commonJS({
|
|
|
23907
23907
|
});
|
|
23908
23908
|
}
|
|
23909
23909
|
var markdownEscapes = [[/\\/g, "\\\\"], [/\*/g, "\\*"], [/^-/g, "\\-"], [/^\+ /g, "\\+ "], [/^(=+)/g, "\\$1"], [/^(#{1,6}) /g, "\\$1 "], [/`/g, "\\`"], [/^~~~/g, "\\~~~"], [/\[/g, "\\["], [/\]/g, "\\]"], [/^>/g, "\\>"], [/_/g, "\\_"], [/^(\d+)\. /g, "$1\\. "]];
|
|
23910
|
-
function
|
|
23910
|
+
function escapeMarkdown2(string3) {
|
|
23911
23911
|
return markdownEscapes.reduce(function(accumulator, escape3) {
|
|
23912
23912
|
return accumulator.replace(escape3[0], escape3[1]);
|
|
23913
23913
|
}, string3);
|
|
@@ -24087,7 +24087,7 @@ var require_turndown_cjs = __commonJS({
|
|
|
24087
24087
|
rules.image = {
|
|
24088
24088
|
filter: "img",
|
|
24089
24089
|
replacement: function(content, node) {
|
|
24090
|
-
var alt =
|
|
24090
|
+
var alt = escapeMarkdown2(cleanAttribute(node.getAttribute("alt")));
|
|
24091
24091
|
var src = escapeLinkDestination(node.getAttribute("src") || "");
|
|
24092
24092
|
var title = cleanAttribute(node.getAttribute("title"));
|
|
24093
24093
|
var titlePart = title ? ' "' + escapeLinkTitle(title) + '"' : "";
|
|
@@ -24181,15 +24181,15 @@ var require_turndown_cjs = __commonJS({
|
|
|
24181
24181
|
var node = next(prev, element, isPre);
|
|
24182
24182
|
while (node !== element) {
|
|
24183
24183
|
if (node.nodeType === 3 || node.nodeType === 4) {
|
|
24184
|
-
var
|
|
24185
|
-
if ((!prevText || / $/.test(prevText.data)) && !keepLeadingWs &&
|
|
24186
|
-
|
|
24184
|
+
var text2 = node.data.replace(/[ \r\n\t]+/g, " ");
|
|
24185
|
+
if ((!prevText || / $/.test(prevText.data)) && !keepLeadingWs && text2[0] === " ") {
|
|
24186
|
+
text2 = text2.substr(1);
|
|
24187
24187
|
}
|
|
24188
|
-
if (!
|
|
24188
|
+
if (!text2) {
|
|
24189
24189
|
node = remove(node);
|
|
24190
24190
|
continue;
|
|
24191
24191
|
}
|
|
24192
|
-
node.data =
|
|
24192
|
+
node.data = text2;
|
|
24193
24193
|
prevText = node;
|
|
24194
24194
|
} else if (node.nodeType === 1) {
|
|
24195
24195
|
if (isBlock2(node) || node.nodeName === "BR") {
|
|
@@ -24452,7 +24452,7 @@ var require_turndown_cjs = __commonJS({
|
|
|
24452
24452
|
* @type String
|
|
24453
24453
|
*/
|
|
24454
24454
|
escape: function(string3) {
|
|
24455
|
-
return
|
|
24455
|
+
return escapeMarkdown2(string3);
|
|
24456
24456
|
}
|
|
24457
24457
|
};
|
|
24458
24458
|
function process3(parentNode) {
|
|
@@ -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 join21(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 = join21(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 join21(output, replacement) {
|
|
24488
24488
|
var s1 = trimTrailingNewlines(output);
|
|
24489
24489
|
var s2 = trimLeadingNewlines(replacement);
|
|
24490
24490
|
var nls = Math.max(output.length - s1.length, replacement.length - s2.length);
|
|
@@ -24979,8 +24979,8 @@ function getErrorMap() {
|
|
|
24979
24979
|
|
|
24980
24980
|
// node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
|
|
24981
24981
|
var makeIssue = (params) => {
|
|
24982
|
-
const { data, path:
|
|
24983
|
-
const fullPath = [...
|
|
24982
|
+
const { data, path: path8, errorMaps, issueData } = params;
|
|
24983
|
+
const fullPath = [...path8, ...issueData.path || []];
|
|
24984
24984
|
const fullIssue = {
|
|
24985
24985
|
...issueData,
|
|
24986
24986
|
path: fullPath
|
|
@@ -25096,11 +25096,11 @@ var errorUtil;
|
|
|
25096
25096
|
|
|
25097
25097
|
// node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
|
|
25098
25098
|
var ParseInputLazyPath = class {
|
|
25099
|
-
constructor(parent, value,
|
|
25099
|
+
constructor(parent, value, path8, key) {
|
|
25100
25100
|
this._cachedPath = [];
|
|
25101
25101
|
this.parent = parent;
|
|
25102
25102
|
this.data = value;
|
|
25103
|
-
this._path =
|
|
25103
|
+
this._path = path8;
|
|
25104
25104
|
this._key = key;
|
|
25105
25105
|
}
|
|
25106
25106
|
get path() {
|
|
@@ -28737,10 +28737,10 @@ function assignProp(target, prop, value) {
|
|
|
28737
28737
|
configurable: true
|
|
28738
28738
|
});
|
|
28739
28739
|
}
|
|
28740
|
-
function getElementAtPath(obj,
|
|
28741
|
-
if (!
|
|
28740
|
+
function getElementAtPath(obj, path8) {
|
|
28741
|
+
if (!path8)
|
|
28742
28742
|
return obj;
|
|
28743
|
-
return
|
|
28743
|
+
return path8.reduce((acc, key) => acc?.[key], obj);
|
|
28744
28744
|
}
|
|
28745
28745
|
function promiseAllObject(promisesObj) {
|
|
28746
28746
|
const keys = Object.keys(promisesObj);
|
|
@@ -29060,11 +29060,11 @@ function aborted(x, startIndex = 0) {
|
|
|
29060
29060
|
}
|
|
29061
29061
|
return false;
|
|
29062
29062
|
}
|
|
29063
|
-
function prefixIssues(
|
|
29063
|
+
function prefixIssues(path8, issues) {
|
|
29064
29064
|
return issues.map((iss) => {
|
|
29065
29065
|
var _a;
|
|
29066
29066
|
(_a = iss).path ?? (_a.path = []);
|
|
29067
|
-
iss.path.unshift(
|
|
29067
|
+
iss.path.unshift(path8);
|
|
29068
29068
|
return iss;
|
|
29069
29069
|
});
|
|
29070
29070
|
}
|
|
@@ -32475,11 +32475,11 @@ function normalizeObjectSchema(schema) {
|
|
|
32475
32475
|
}
|
|
32476
32476
|
return void 0;
|
|
32477
32477
|
}
|
|
32478
|
-
function getDotPath(
|
|
32479
|
-
if (
|
|
32478
|
+
function getDotPath(path8) {
|
|
32479
|
+
if (path8.length === 0) {
|
|
32480
32480
|
return "object root";
|
|
32481
32481
|
}
|
|
32482
|
-
return
|
|
32482
|
+
return path8.reduce((acc, seg, index) => {
|
|
32483
32483
|
if (index === 0) {
|
|
32484
32484
|
return String(seg);
|
|
32485
32485
|
}
|
|
@@ -36608,7 +36608,7 @@ var Protocol = class {
|
|
|
36608
36608
|
return;
|
|
36609
36609
|
}
|
|
36610
36610
|
const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
|
|
36611
|
-
await new Promise((
|
|
36611
|
+
await new Promise((resolve5) => setTimeout(resolve5, pollInterval));
|
|
36612
36612
|
options?.signal?.throwIfAborted();
|
|
36613
36613
|
}
|
|
36614
36614
|
} catch (error2) {
|
|
@@ -36625,7 +36625,7 @@ var Protocol = class {
|
|
|
36625
36625
|
*/
|
|
36626
36626
|
request(request, resultSchema, options) {
|
|
36627
36627
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
36628
|
-
return new Promise((
|
|
36628
|
+
return new Promise((resolve5, reject) => {
|
|
36629
36629
|
const earlyReject = (error2) => {
|
|
36630
36630
|
reject(error2);
|
|
36631
36631
|
};
|
|
@@ -36703,7 +36703,7 @@ var Protocol = class {
|
|
|
36703
36703
|
if (!parseResult.success) {
|
|
36704
36704
|
reject(parseResult.error);
|
|
36705
36705
|
} else {
|
|
36706
|
-
|
|
36706
|
+
resolve5(parseResult.data);
|
|
36707
36707
|
}
|
|
36708
36708
|
} catch (error2) {
|
|
36709
36709
|
reject(error2);
|
|
@@ -36964,12 +36964,12 @@ var Protocol = class {
|
|
|
36964
36964
|
}
|
|
36965
36965
|
} catch {
|
|
36966
36966
|
}
|
|
36967
|
-
return new Promise((
|
|
36967
|
+
return new Promise((resolve5, reject) => {
|
|
36968
36968
|
if (signal.aborted) {
|
|
36969
36969
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
36970
36970
|
return;
|
|
36971
36971
|
}
|
|
36972
|
-
const timeoutId = setTimeout(
|
|
36972
|
+
const timeoutId = setTimeout(resolve5, interval);
|
|
36973
36973
|
signal.addEventListener("abort", () => {
|
|
36974
36974
|
clearTimeout(timeoutId);
|
|
36975
36975
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -38282,7 +38282,7 @@ var McpServer = class {
|
|
|
38282
38282
|
let task = createTaskResult.task;
|
|
38283
38283
|
const pollInterval = task.pollInterval ?? 5e3;
|
|
38284
38284
|
while (task.status !== "completed" && task.status !== "failed" && task.status !== "cancelled") {
|
|
38285
|
-
await new Promise((
|
|
38285
|
+
await new Promise((resolve5) => setTimeout(resolve5, pollInterval));
|
|
38286
38286
|
const updatedTask = await extra.taskStore.getTask(taskId);
|
|
38287
38287
|
if (!updatedTask) {
|
|
38288
38288
|
throw new McpError(ErrorCode.InternalError, `Task ${taskId} not found during polling`);
|
|
@@ -38970,12 +38970,12 @@ var StdioServerTransport = class {
|
|
|
38970
38970
|
this.onclose?.();
|
|
38971
38971
|
}
|
|
38972
38972
|
send(message) {
|
|
38973
|
-
return new Promise((
|
|
38973
|
+
return new Promise((resolve5) => {
|
|
38974
38974
|
const json2 = serializeMessage(message);
|
|
38975
38975
|
if (this._stdout.write(json2)) {
|
|
38976
|
-
|
|
38976
|
+
resolve5();
|
|
38977
38977
|
} else {
|
|
38978
|
-
this._stdout.once("drain",
|
|
38978
|
+
this._stdout.once("drain", resolve5);
|
|
38979
38979
|
}
|
|
38980
38980
|
});
|
|
38981
38981
|
}
|
|
@@ -39418,12 +39418,12 @@ function fixed32Float(field) {
|
|
|
39418
39418
|
}
|
|
39419
39419
|
|
|
39420
39420
|
// src/utils/checklistRuns.ts
|
|
39421
|
-
function checklistRunLineStart(
|
|
39421
|
+
function checklistRunLineStart(text2, position, length) {
|
|
39422
39422
|
const end = position + length;
|
|
39423
39423
|
let anchor = position;
|
|
39424
|
-
while (anchor < end &&
|
|
39424
|
+
while (anchor < end && text2[anchor] === "\n") anchor++;
|
|
39425
39425
|
if (anchor === end) anchor = position;
|
|
39426
|
-
return anchor === 0 ? 0 :
|
|
39426
|
+
return anchor === 0 ? 0 : text2.lastIndexOf("\n", anchor - 1) + 1;
|
|
39427
39427
|
}
|
|
39428
39428
|
|
|
39429
39429
|
// src/utils/checklistParser.ts
|
|
@@ -39625,8 +39625,8 @@ import { join as join2 } from "node:path";
|
|
|
39625
39625
|
import { gunzipSync as gunzipSync2 } from "node:zlib";
|
|
39626
39626
|
var dbPath = join2(homedir2(), "Library/Group Containers/group.com.apple.notes/NoteStore.sqlite");
|
|
39627
39627
|
var safeUrl = (url) => /^(?:https?:\/\/|notes:\/\/|applenotes:|mailto:)/i.test(url) && !Array.from(url).some((char) => char.charCodeAt(0) < 32);
|
|
39628
|
-
var escapeAttribute = (
|
|
39629
|
-
var normalized = (
|
|
39628
|
+
var escapeAttribute = (text2) => text2.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<");
|
|
39629
|
+
var normalized = (text2) => text2.replace(/[\s\ufffc]/gu, "");
|
|
39630
39630
|
function styleValue(field) {
|
|
39631
39631
|
if (!(field.value instanceof Uint8Array)) return field.value;
|
|
39632
39632
|
if (field.fieldNumber === 2) {
|
|
@@ -39659,8 +39659,8 @@ function parseRichNote(data, nativeTags = []) {
|
|
|
39659
39659
|
const doc = decodeMessage(data);
|
|
39660
39660
|
const wrapper = embeddedMessage(getField(doc, 2));
|
|
39661
39661
|
const body = wrapper && embeddedMessage(getField(wrapper, 3));
|
|
39662
|
-
const
|
|
39663
|
-
if (!body ||
|
|
39662
|
+
const text2 = body && stringValue(getField(body, 2));
|
|
39663
|
+
if (!body || text2 === void 0) throw new Error("Unsupported Notes document structure");
|
|
39664
39664
|
const links = [];
|
|
39665
39665
|
const nativeObjectIds = [];
|
|
39666
39666
|
const objects = [];
|
|
@@ -39673,7 +39673,7 @@ function parseRichNote(data, nativeTags = []) {
|
|
|
39673
39673
|
const fields = embeddedMessage(run);
|
|
39674
39674
|
if (!fields) throw new Error("Invalid Notes attribute run");
|
|
39675
39675
|
const length = varintValue(getField(fields, 1));
|
|
39676
|
-
if (length === void 0 || length < 0 || position + length >
|
|
39676
|
+
if (length === void 0 || length < 0 || position + length > text2.length)
|
|
39677
39677
|
throw new Error("Invalid Notes run length");
|
|
39678
39678
|
const paragraph = embeddedMessage(getField(fields, 2));
|
|
39679
39679
|
styleRuns.push({
|
|
@@ -39692,9 +39692,9 @@ function parseRichNote(data, nativeTags = []) {
|
|
|
39692
39692
|
const previous = links.at(-1);
|
|
39693
39693
|
if (previous?.url === url && previous.start + previous.length === position) {
|
|
39694
39694
|
previous.length += length;
|
|
39695
|
-
previous.text +=
|
|
39695
|
+
previous.text += text2.slice(position, position + length);
|
|
39696
39696
|
} else
|
|
39697
|
-
links.push({ start: position, length, text:
|
|
39697
|
+
links.push({ start: position, length, text: text2.slice(position, position + length), url });
|
|
39698
39698
|
}
|
|
39699
39699
|
hasNativeObjects ||= Boolean(getField(fields, 12));
|
|
39700
39700
|
const attachment = embeddedMessage(getField(fields, 12));
|
|
@@ -39712,23 +39712,23 @@ function parseRichNote(data, nativeTags = []) {
|
|
|
39712
39712
|
const checklist = embeddedMessage(getField(paragraph, 5));
|
|
39713
39713
|
const rawId = checklist && getField(checklist, 1)?.value;
|
|
39714
39714
|
const itemId = rawId instanceof Uint8Array ? Buffer.from(rawId).toString("hex") : "";
|
|
39715
|
-
const start = checklistRunLineStart(
|
|
39715
|
+
const start = checklistRunLineStart(text2, position, length);
|
|
39716
39716
|
if (itemId && !checklistItems.some((item) => item.id === itemId))
|
|
39717
39717
|
checklistItems.push({
|
|
39718
39718
|
id: itemId,
|
|
39719
39719
|
start,
|
|
39720
|
-
text:
|
|
39720
|
+
text: text2.slice(
|
|
39721
39721
|
start,
|
|
39722
|
-
|
|
39722
|
+
text2.indexOf("\n", start) === -1 ? text2.length : text2.indexOf("\n", start)
|
|
39723
39723
|
),
|
|
39724
39724
|
done: checklist ? varintValue(getField(checklist, 2)) === 1 : false
|
|
39725
39725
|
});
|
|
39726
39726
|
}
|
|
39727
39727
|
position += length;
|
|
39728
39728
|
}
|
|
39729
|
-
if (position !==
|
|
39729
|
+
if (position !== text2.length) throw new Error("Incomplete Notes attribute runs");
|
|
39730
39730
|
return {
|
|
39731
|
-
text,
|
|
39731
|
+
text: text2,
|
|
39732
39732
|
links,
|
|
39733
39733
|
nativeTags: hasNativeObjects ? nativeTags : [],
|
|
39734
39734
|
nativeObjectIds,
|
|
@@ -40014,8 +40014,8 @@ function parseAudioRecording(data) {
|
|
|
40014
40014
|
const registerNoteText = (id2) => {
|
|
40015
40015
|
const target = registerTarget(id2);
|
|
40016
40016
|
const note = target && sub(target, 10);
|
|
40017
|
-
const
|
|
40018
|
-
return
|
|
40017
|
+
const text2 = note && stringValue(getField(note, 2));
|
|
40018
|
+
return text2?.replace(/\n+$/u, "") || void 0;
|
|
40019
40019
|
};
|
|
40020
40020
|
const recordings = entries2.map((e) => customMap(e)).filter((m) => m?.type === "com.apple.notes.ICTTAudioRecording");
|
|
40021
40021
|
if (recordings.length !== 1) throw new Error("Expected exactly one audio recording object");
|
|
@@ -40054,13 +40054,13 @@ function parseAudioRecording(data) {
|
|
|
40054
40054
|
const segment = customMap(entry(segmentIndex));
|
|
40055
40055
|
if (segment?.type !== "com.apple.notes.ICTTTranscriptSegment")
|
|
40056
40056
|
throw new Error("Unexpected segment type");
|
|
40057
|
-
const
|
|
40058
|
-
if (typeof
|
|
40057
|
+
const text2 = registerPrimitive(segment.values.get("text"));
|
|
40058
|
+
if (typeof text2 !== "string") throw new Error("Segment without text");
|
|
40059
40059
|
const start = registerPrimitive(segment.values.get("timestamp"));
|
|
40060
40060
|
const duration3 = registerPrimitive(segment.values.get("duration"));
|
|
40061
40061
|
const speaker = registerPrimitive(segment.values.get("speaker"));
|
|
40062
40062
|
segments.push({
|
|
40063
|
-
text,
|
|
40063
|
+
text: text2,
|
|
40064
40064
|
...typeof start === "number" ? { start } : {},
|
|
40065
40065
|
...typeof duration3 === "number" ? { duration: duration3 } : {},
|
|
40066
40066
|
...typeof speaker === "string" && speaker ? { speaker } : {}
|
|
@@ -40080,10 +40080,10 @@ function parseAudioRecording(data) {
|
|
|
40080
40080
|
}
|
|
40081
40081
|
function joinSegments(segments) {
|
|
40082
40082
|
let out = "";
|
|
40083
|
-
for (const { text } of segments) {
|
|
40084
|
-
if (!
|
|
40085
|
-
const glue = !out || /\s$/u.test(out) || /^\s/u.test(
|
|
40086
|
-
out += glue +
|
|
40083
|
+
for (const { text: text2 } of segments) {
|
|
40084
|
+
if (!text2) continue;
|
|
40085
|
+
const glue = !out || /\s$/u.test(out) || /^\s/u.test(text2) || /^[.,!?;:%)\]}…'’]/u.test(text2) ? "" : " ";
|
|
40086
|
+
out += glue + text2;
|
|
40087
40087
|
}
|
|
40088
40088
|
return out.trim();
|
|
40089
40089
|
}
|
|
@@ -40217,14 +40217,14 @@ function describeRow(row, store, options, maxSegments) {
|
|
|
40217
40217
|
const all = recording.fragments.flatMap(
|
|
40218
40218
|
(fragment, i) => fragment.segments.map((s) => multi ? { ...s, fragment: i } : s)
|
|
40219
40219
|
);
|
|
40220
|
-
const
|
|
40220
|
+
const text2 = recording.fragments.map((f) => joinSegments(f.segments)).filter(Boolean).join("\n\n");
|
|
40221
40221
|
const speakers = [...new Set(all.flatMap((s) => s.speaker ? [s.speaker] : []))];
|
|
40222
40222
|
return {
|
|
40223
40223
|
...base,
|
|
40224
40224
|
status: all.length ? "ok" : "none",
|
|
40225
40225
|
fragmentCount: recording.fragments.length,
|
|
40226
40226
|
wordCount: all.length,
|
|
40227
|
-
...
|
|
40227
|
+
...text2 ? { text: text2 } : {},
|
|
40228
40228
|
...speakers.length ? { speakers } : {},
|
|
40229
40229
|
...recording.summary ? { summary: recording.summary } : {},
|
|
40230
40230
|
...recording.topLineSummary ? { topLineSummary: recording.topLineSummary } : {},
|
|
@@ -40378,18 +40378,18 @@ function decodeTable(compressed, strict) {
|
|
|
40378
40378
|
const ri = rows.map.get(uuidIndex(num(sub2(row, 1), 6)));
|
|
40379
40379
|
if (ri === void 0 || ci === void 0) continue;
|
|
40380
40380
|
const note = sub2(entry(num(sub2(row, 2), 6)), 10);
|
|
40381
|
-
const
|
|
40382
|
-
if (
|
|
40381
|
+
const text2 = stringValue(getField(note, 2));
|
|
40382
|
+
if (text2 === void 0 || text2.includes("\uFFFC")) {
|
|
40383
40383
|
if (strict) throw new Error("Embedded or unsupported table cell");
|
|
40384
40384
|
values[ri][ci] = null;
|
|
40385
40385
|
incomplete.push({
|
|
40386
40386
|
ri,
|
|
40387
40387
|
ci,
|
|
40388
|
-
reason:
|
|
40388
|
+
reason: text2 === void 0 ? "Cell text is missing" : "Cell contains an embedded object"
|
|
40389
40389
|
});
|
|
40390
40390
|
continue;
|
|
40391
40391
|
}
|
|
40392
|
-
values[ri][ci] =
|
|
40392
|
+
values[ri][ci] = text2.replace(/\n$/u, "");
|
|
40393
40393
|
}
|
|
40394
40394
|
}
|
|
40395
40395
|
const rtl = entries2.some((e) => {
|
|
@@ -40409,8 +40409,8 @@ function decodeTable(compressed, strict) {
|
|
|
40409
40409
|
|
|
40410
40410
|
// src/utils/tableMarkdown.ts
|
|
40411
40411
|
var UNDECODED_CELL_MARKER = "[undecoded cell]";
|
|
40412
|
-
function escapeMarkdownTableCell(
|
|
40413
|
-
return
|
|
40412
|
+
function escapeMarkdownTableCell(text2) {
|
|
40413
|
+
return text2.replace(/\\/g, "\\\\").replace(/\|/g, "\\|").replace(/\r\n|[\r\n\u2028\u2029]/g, "<br>");
|
|
40414
40414
|
}
|
|
40415
40415
|
function renderMarkdownTable(rows) {
|
|
40416
40416
|
const width = rows.reduce((max, row) => Math.max(max, row.length), 0);
|
|
@@ -40550,8 +40550,8 @@ var Decoder = class {
|
|
|
40550
40550
|
}
|
|
40551
40551
|
/** Mark a positively described leaf as an Exclude rule. */
|
|
40552
40552
|
negate(filter) {
|
|
40553
|
-
const
|
|
40554
|
-
const negated =
|
|
40553
|
+
const text2 = filter.description;
|
|
40554
|
+
const negated = text2.startsWith("has ") ? text2.replace(/^has /, "does not have ") : text2.startsWith("is ") ? text2.replace(/^is /, "is not ") : text2.startsWith("mentions ") ? text2.replace(/^mentions /, "does not mention ") : `not ${text2}`;
|
|
40555
40555
|
return { ...filter, excluded: true, description: negated };
|
|
40556
40556
|
}
|
|
40557
40557
|
clause(clause, excluded, depth) {
|
|
@@ -40582,7 +40582,7 @@ var Decoder = class {
|
|
|
40582
40582
|
* positively and negated by the caller.
|
|
40583
40583
|
*/
|
|
40584
40584
|
leaf(key, value, excluded) {
|
|
40585
|
-
const
|
|
40585
|
+
const flag2 = (description, negative) => typeof value === "boolean" ? {
|
|
40586
40586
|
type: key,
|
|
40587
40587
|
value,
|
|
40588
40588
|
...excluded ? { excluded: true } : {},
|
|
@@ -40590,25 +40590,25 @@ var Decoder = class {
|
|
|
40590
40590
|
} : null;
|
|
40591
40591
|
switch (key) {
|
|
40592
40592
|
case "checklist":
|
|
40593
|
-
return
|
|
40593
|
+
return flag2("has a checklist", "has no checklist");
|
|
40594
40594
|
case "checklistInProgress":
|
|
40595
|
-
return
|
|
40595
|
+
return flag2("has an unfinished checklist", "has no unfinished checklist");
|
|
40596
40596
|
case "checklistCompleted":
|
|
40597
|
-
return
|
|
40597
|
+
return flag2("has a completed checklist", "has no completed checklist");
|
|
40598
40598
|
case "attachment":
|
|
40599
|
-
return
|
|
40599
|
+
return flag2("has attachments", "has no attachments");
|
|
40600
40600
|
case "pinned":
|
|
40601
|
-
return
|
|
40601
|
+
return flag2("is pinned", "is not pinned");
|
|
40602
40602
|
case "systemPaper":
|
|
40603
|
-
return
|
|
40603
|
+
return flag2("is a Quick Note", "is not a Quick Note");
|
|
40604
40604
|
case "passwordProtected":
|
|
40605
|
-
return
|
|
40605
|
+
return flag2("is locked", "is not locked");
|
|
40606
40606
|
case "shared":
|
|
40607
|
-
return
|
|
40607
|
+
return flag2("is shared", "is not shared");
|
|
40608
40608
|
case "mention":
|
|
40609
|
-
return
|
|
40609
|
+
return flag2("mentions anyone", "mentions no one");
|
|
40610
40610
|
case "tagged":
|
|
40611
|
-
return
|
|
40611
|
+
return flag2("has any tag", "has no tags");
|
|
40612
40612
|
case "attachmentSection": {
|
|
40613
40613
|
if (typeof value !== "number" || !ATTACHMENT_SECTIONS[value]) return null;
|
|
40614
40614
|
return {
|
|
@@ -40784,7 +40784,7 @@ function buildSmartFolders(output) {
|
|
|
40784
40784
|
if (lines.length < 4) throw new Error("Unexpected smart folder query output");
|
|
40785
40785
|
const [storeUuid, rowsJson, foldersJson, tagsJson] = lines;
|
|
40786
40786
|
if (!/^[0-9A-F-]+$/i.test(storeUuid)) throw new Error("Unexpected Notes store identifier");
|
|
40787
|
-
const coreDataId2 = (
|
|
40787
|
+
const coreDataId2 = (entity3, pk) => `x-coredata://${storeUuid}/${entity3}/p${pk}`;
|
|
40788
40788
|
const rows = JSON.parse(rowsJson);
|
|
40789
40789
|
const folderRows = JSON.parse(foldersJson || "{}");
|
|
40790
40790
|
const tagRows = JSON.parse(tagsJson || "[]");
|
|
@@ -40881,8 +40881,8 @@ function allowedSaveRoots() {
|
|
|
40881
40881
|
"/private/tmp"
|
|
40882
40882
|
];
|
|
40883
40883
|
}
|
|
40884
|
-
function canonicalize(
|
|
40885
|
-
return realpathSync.native(
|
|
40884
|
+
function canonicalize(path8) {
|
|
40885
|
+
return realpathSync.native(path8);
|
|
40886
40886
|
}
|
|
40887
40887
|
function isWithinRoots(candidate, roots) {
|
|
40888
40888
|
return roots.some((root) => {
|
|
@@ -40904,9 +40904,9 @@ function canonicalRoots(roots) {
|
|
|
40904
40904
|
}
|
|
40905
40905
|
return canonical;
|
|
40906
40906
|
}
|
|
40907
|
-
function entryExists(
|
|
40907
|
+
function entryExists(path8) {
|
|
40908
40908
|
try {
|
|
40909
|
-
lstatSync(
|
|
40909
|
+
lstatSync(path8);
|
|
40910
40910
|
return true;
|
|
40911
40911
|
} catch (e) {
|
|
40912
40912
|
const code = e.code;
|
|
@@ -41136,7 +41136,7 @@ function attachmentCoreDataId(noteId3, pk) {
|
|
|
41136
41136
|
}
|
|
41137
41137
|
function buildAttachmentRowsSql(notePk, columns) {
|
|
41138
41138
|
if (!Number.isSafeInteger(notePk) || notePk < 0) throw new Error("Invalid note primary key");
|
|
41139
|
-
const
|
|
41139
|
+
const col3 = (alias, name) => columns.has(name) ? `${alias}.${name}` : "NULL";
|
|
41140
41140
|
const firstOf = (alias, names) => {
|
|
41141
41141
|
const present = names.filter((n) => columns.has(n)).map((n) => `${alias}.${n}`);
|
|
41142
41142
|
if (present.length === 0) return "NULL";
|
|
@@ -41149,19 +41149,19 @@ function buildAttachmentRowsSql(notePk, columns) {
|
|
|
41149
41149
|
].join(", ");
|
|
41150
41150
|
const account = accountCols.length ? `(SELECT acc.ZIDENTIFIER FROM ZICCLOUDSYNCINGOBJECT acc WHERE acc.Z_ENT = (SELECT Z_ENT FROM Z_PRIMARYKEY WHERE Z_NAME = 'ICAccount') AND acc.Z_PK IN (${accountRefs}) LIMIT 1)` : "NULL";
|
|
41151
41151
|
const noteLink = columns.has("ZNOTE") ? "a.ZNOTE" : "NULL";
|
|
41152
|
-
const parent =
|
|
41152
|
+
const parent = col3("a", "ZPARENTATTACHMENT");
|
|
41153
41153
|
const deleted = columns.has("ZMARKEDFORDELETION") ? " AND COALESCE(a.ZMARKEDFORDELETION, 0) = 0" : "";
|
|
41154
41154
|
const fields = [
|
|
41155
41155
|
`'pk', a.Z_PK`,
|
|
41156
41156
|
`'identifier', a.ZIDENTIFIER`,
|
|
41157
|
-
`'uti', ${
|
|
41157
|
+
`'uti', ${col3("a", "ZTYPEUTI")}`,
|
|
41158
41158
|
`'parentPk', ${parent}`,
|
|
41159
|
-
`'filename', ${
|
|
41159
|
+
`'filename', ${col3("a", "ZFILENAME")}`,
|
|
41160
41160
|
`'mediaIdentifier', m.ZIDENTIFIER`,
|
|
41161
|
-
`'mediaFilename', ${
|
|
41161
|
+
`'mediaFilename', ${col3("m", "ZFILENAME")}`,
|
|
41162
41162
|
`'mediaGeneration', ${firstOf("m", ["ZGENERATION1", "ZGENERATION"])}`,
|
|
41163
|
-
`'fallbackImageGeneration', ${
|
|
41164
|
-
`'fallbackPdfGeneration', ${
|
|
41163
|
+
`'fallbackImageGeneration', ${col3("a", "ZFALLBACKIMAGEGENERATION")}`,
|
|
41164
|
+
`'fallbackPdfGeneration', ${col3("a", "ZFALLBACKPDFGENERATION")}`,
|
|
41165
41165
|
`'accountIdentifier', ${account}`
|
|
41166
41166
|
].join(", ");
|
|
41167
41167
|
const mediaJoin = columns.has("ZMEDIA") ? "LEFT JOIN ZICCLOUDSYNCINGOBJECT m ON m.Z_PK = a.ZMEDIA" : "LEFT JOIN ZICCLOUDSYNCINGOBJECT m ON 0";
|
|
@@ -41274,24 +41274,24 @@ function safeComponent(value) {
|
|
|
41274
41274
|
if (value === "." || value === ".." || value.includes("/") || value.includes("\0")) return null;
|
|
41275
41275
|
return value;
|
|
41276
41276
|
}
|
|
41277
|
-
function realInside(
|
|
41277
|
+
function realInside(path8, rootReal) {
|
|
41278
41278
|
try {
|
|
41279
|
-
const real = realpathSync2.native(
|
|
41279
|
+
const real = realpathSync2.native(path8);
|
|
41280
41280
|
return real === rootReal || real.startsWith(rootReal + sep2) ? real : null;
|
|
41281
41281
|
} catch {
|
|
41282
41282
|
return null;
|
|
41283
41283
|
}
|
|
41284
41284
|
}
|
|
41285
|
-
function isRegularFile(
|
|
41285
|
+
function isRegularFile(path8) {
|
|
41286
41286
|
try {
|
|
41287
|
-
return lstatSync2(
|
|
41287
|
+
return lstatSync2(path8).isFile();
|
|
41288
41288
|
} catch {
|
|
41289
41289
|
return false;
|
|
41290
41290
|
}
|
|
41291
41291
|
}
|
|
41292
|
-
function isDirectory(
|
|
41292
|
+
function isDirectory(path8) {
|
|
41293
41293
|
try {
|
|
41294
|
-
return lstatSync2(
|
|
41294
|
+
return lstatSync2(path8).isDirectory();
|
|
41295
41295
|
} catch {
|
|
41296
41296
|
return false;
|
|
41297
41297
|
}
|
|
@@ -41671,10 +41671,10 @@ function readImageInfoFd(fd) {
|
|
|
41671
41671
|
const read = readSync2(fd, buf, 0, buf.length, 0);
|
|
41672
41672
|
return parseImageHeader(buf.subarray(0, read));
|
|
41673
41673
|
}
|
|
41674
|
-
function readImageInfo(
|
|
41674
|
+
function readImageInfo(path8) {
|
|
41675
41675
|
let fd;
|
|
41676
41676
|
try {
|
|
41677
|
-
fd = openSync3(
|
|
41677
|
+
fd = openSync3(path8, constants3.O_RDONLY | constants3.O_NOFOLLOW);
|
|
41678
41678
|
} catch {
|
|
41679
41679
|
return null;
|
|
41680
41680
|
}
|
|
@@ -41686,7 +41686,7 @@ function readImageInfo(path7) {
|
|
|
41686
41686
|
}
|
|
41687
41687
|
function buildDrawingRowsSql(notePk, columns) {
|
|
41688
41688
|
if (!Number.isSafeInteger(notePk) || notePk < 0) throw new Error("Invalid note primary key");
|
|
41689
|
-
const
|
|
41689
|
+
const col3 = (name) => columns.has(name) ? `a.${name}` : "NULL";
|
|
41690
41690
|
const accountCols = [...columns].filter((c) => /^ZACCOUNT\d*$/.test(c)).sort();
|
|
41691
41691
|
const account = accountCols.length ? `(SELECT acc.ZIDENTIFIER FROM ZICCLOUDSYNCINGOBJECT acc WHERE acc.Z_ENT = (SELECT Z_ENT FROM Z_PRIMARYKEY WHERE Z_NAME = 'ICAccount') AND acc.Z_PK IN (${[
|
|
41692
41692
|
...accountCols.map((c) => `a.${c}`),
|
|
@@ -41697,8 +41697,8 @@ function buildDrawingRowsSql(notePk, columns) {
|
|
|
41697
41697
|
`'pk', a.Z_PK`,
|
|
41698
41698
|
`'identifier', a.ZIDENTIFIER`,
|
|
41699
41699
|
`'uti', a.ZTYPEUTI`,
|
|
41700
|
-
`'handwritingSummary', ${
|
|
41701
|
-
`'fallbackImageGeneration', ${
|
|
41700
|
+
`'handwritingSummary', ${col3("ZHANDWRITINGSUMMARY")}`,
|
|
41701
|
+
`'fallbackImageGeneration', ${col3("ZFALLBACKIMAGEGENERATION")}`,
|
|
41702
41702
|
`'accountIdentifier', ${account}`
|
|
41703
41703
|
].join(", ");
|
|
41704
41704
|
return [
|
|
@@ -41774,9 +41774,9 @@ function readDrawingRows(noteId3, dbPath2 = join7(NOTES_CONTAINER_DIR, "NoteStor
|
|
|
41774
41774
|
throw new AttachmentStoreError("Drawing rows could not be parsed", "query_error");
|
|
41775
41775
|
}
|
|
41776
41776
|
}
|
|
41777
|
-
function kindOf(
|
|
41777
|
+
function kindOf(path8) {
|
|
41778
41778
|
try {
|
|
41779
|
-
const st = lstatSync3(
|
|
41779
|
+
const st = lstatSync3(path8);
|
|
41780
41780
|
return st.isFile() ? "file" : st.isDirectory() ? "dir" : null;
|
|
41781
41781
|
} catch {
|
|
41782
41782
|
return null;
|
|
@@ -41842,13 +41842,13 @@ function describeDrawings(rows, containerDir = NOTES_CONTAINER_DIR) {
|
|
|
41842
41842
|
const previewPath = accountDir ? findLargestPreview(accountDir, row.identifier) : null;
|
|
41843
41843
|
const bundle = accountDir && id2 && kind === "paper" ? realInside(join7(accountDir, "Paper", "Bundles", `${id2}.bundle`), accountDir) : null;
|
|
41844
41844
|
let raster = null;
|
|
41845
|
-
for (const [
|
|
41845
|
+
for (const [path8, source] of [
|
|
41846
41846
|
[fallbackImagePath, "fallback"],
|
|
41847
41847
|
[previewPath, "preview"]
|
|
41848
41848
|
]) {
|
|
41849
|
-
const info =
|
|
41850
|
-
if (
|
|
41851
|
-
raster = { path:
|
|
41849
|
+
const info = path8 ? readImageInfo(path8) : null;
|
|
41850
|
+
if (path8 && info) {
|
|
41851
|
+
raster = { path: path8, source, ...info };
|
|
41852
41852
|
break;
|
|
41853
41853
|
}
|
|
41854
41854
|
}
|
|
@@ -41865,10 +41865,10 @@ function describeDrawings(rows, containerDir = NOTES_CONTAINER_DIR) {
|
|
|
41865
41865
|
};
|
|
41866
41866
|
});
|
|
41867
41867
|
}
|
|
41868
|
-
function verifyWrittenImage(fd,
|
|
41868
|
+
function verifyWrittenImage(fd, path8, expected) {
|
|
41869
41869
|
const check2 = readImageInfoFd(fd);
|
|
41870
41870
|
if (!check2 || check2.format !== expected.format || check2.width !== expected.width || check2.height !== expected.height) {
|
|
41871
|
-
unlinkSync2(
|
|
41871
|
+
unlinkSync2(path8);
|
|
41872
41872
|
throw new Error("The exported image failed validation and was removed.");
|
|
41873
41873
|
}
|
|
41874
41874
|
return check2;
|
|
@@ -42003,11 +42003,11 @@ function fitExportNoteToBudget(note, maxBytes) {
|
|
|
42003
42003
|
function executeMutationAppleScript(script) {
|
|
42004
42004
|
return executeAppleScript(script, { maxRetries: 1 });
|
|
42005
42005
|
}
|
|
42006
|
-
function escapeForAppleScript(
|
|
42007
|
-
if (!
|
|
42006
|
+
function escapeForAppleScript(text2) {
|
|
42007
|
+
if (!text2) {
|
|
42008
42008
|
return "";
|
|
42009
42009
|
}
|
|
42010
|
-
let escaped =
|
|
42010
|
+
let escaped = text2.replace(/&/g, "&");
|
|
42011
42011
|
escaped = escaped.replace(/\\/g, "\");
|
|
42012
42012
|
escaped = escaped.replace(/"/g, '\\"');
|
|
42013
42013
|
escaped = escaped.replace(/\n/g, "<br>");
|
|
@@ -42020,9 +42020,9 @@ function escapeHtmlForAppleScript(htmlContent) {
|
|
|
42020
42020
|
}
|
|
42021
42021
|
return htmlContent.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
42022
42022
|
}
|
|
42023
|
-
function escapePlainStringForAppleScript(
|
|
42024
|
-
if (!
|
|
42025
|
-
return
|
|
42023
|
+
function escapePlainStringForAppleScript(text2) {
|
|
42024
|
+
if (!text2) return "";
|
|
42025
|
+
return text2.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
42026
42026
|
}
|
|
42027
42027
|
var MAX_TITLE_LENGTH = 2e3;
|
|
42028
42028
|
var MAX_CONTENT_LENGTH = 5 * 1024 * 1024;
|
|
@@ -44319,13 +44319,13 @@ var AppleNotesManager = class {
|
|
|
44319
44319
|
* Simple HTML to plaintext conversion for export.
|
|
44320
44320
|
*/
|
|
44321
44321
|
htmlToPlaintext(html) {
|
|
44322
|
-
let
|
|
44322
|
+
let text2 = html.replace(/<br\s*\/?>/gi, "\n").replace(/<\/div>/gi, "\n").replace(/<\/p>/gi, "\n");
|
|
44323
44323
|
let prev;
|
|
44324
44324
|
do {
|
|
44325
|
-
prev =
|
|
44326
|
-
|
|
44327
|
-
} while (
|
|
44328
|
-
return
|
|
44325
|
+
prev = text2;
|
|
44326
|
+
text2 = text2.replace(/<[^>]*>/g, "");
|
|
44327
|
+
} while (text2 !== prev);
|
|
44328
|
+
return text2.replace(/ /g, " ").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/\/g, "\\").replace(/&/g, "&").replace(/\n{3,}/g, "\n\n").trim();
|
|
44329
44329
|
}
|
|
44330
44330
|
/**
|
|
44331
44331
|
* Exports notes as a JSON structure for backup/migration, one page at a time.
|
|
@@ -44501,11 +44501,11 @@ var AppleNotesManager = class {
|
|
|
44501
44501
|
const enriched = lines.map((line) => {
|
|
44502
44502
|
const listMatch = line.match(/^(\s*[-*])\s+(.+)$/);
|
|
44503
44503
|
if (!listMatch) return line;
|
|
44504
|
-
const [, prefix,
|
|
44505
|
-
const done = checklistMap.get(
|
|
44504
|
+
const [, prefix, text2] = listMatch;
|
|
44505
|
+
const done = checklistMap.get(text2.trim());
|
|
44506
44506
|
if (done === void 0) return line;
|
|
44507
|
-
checklistMap.delete(
|
|
44508
|
-
return `${prefix} ${done ? "[x]" : "[ ]"} ${
|
|
44507
|
+
checklistMap.delete(text2.trim());
|
|
44508
|
+
return `${prefix} ${done ? "[x]" : "[ ]"} ${text2}`;
|
|
44509
44509
|
});
|
|
44510
44510
|
return enriched.join("\n");
|
|
44511
44511
|
}
|
|
@@ -44772,7 +44772,10 @@ function getNoteMetadata(noteId3) {
|
|
|
44772
44772
|
}
|
|
44773
44773
|
}
|
|
44774
44774
|
|
|
44775
|
-
// src/utils/
|
|
44775
|
+
// src/utils/noteListings.ts
|
|
44776
|
+
import { gunzipSync as gunzipSync6 } from "zlib";
|
|
44777
|
+
|
|
44778
|
+
// src/utils/noteStoreSql.ts
|
|
44776
44779
|
import { execFileSync as execFileSync10 } from "child_process";
|
|
44777
44780
|
import * as fs5 from "fs";
|
|
44778
44781
|
import * as os5 from "os";
|
|
@@ -44781,6 +44784,407 @@ var NOTES_DB_PATH6 = path5.join(
|
|
|
44781
44784
|
os5.homedir(),
|
|
44782
44785
|
"Library/Group Containers/group.com.apple.notes/NoteStore.sqlite"
|
|
44783
44786
|
);
|
|
44787
|
+
var CORE_DATA_EPOCH_MS = Date.UTC(2001, 0, 1);
|
|
44788
|
+
var STORE_FDA_MESSAGE = `Full Disk Access is required to read the Notes database. In System Settings > Privacy & Security > Full Disk Access, grant access to the app that launches this server (Claude Desktop / Terminal / iTerm2), then fully quit and relaunch it. Setup guide: ${FULL_DISK_ACCESS_GUIDE_URL} \u2014 run the doctor tool to verify.`;
|
|
44789
|
+
var NoteStoreError = class extends Error {
|
|
44790
|
+
constructor(message, kind) {
|
|
44791
|
+
super(message);
|
|
44792
|
+
this.kind = kind;
|
|
44793
|
+
this.name = "NoteStoreError";
|
|
44794
|
+
}
|
|
44795
|
+
kind;
|
|
44796
|
+
};
|
|
44797
|
+
function doubleToHex(value) {
|
|
44798
|
+
if (!Number.isFinite(value)) throw new NoteStoreError("Not a finite number", "invalid_input");
|
|
44799
|
+
const buffer = Buffer.alloc(8);
|
|
44800
|
+
buffer.writeDoubleBE(value);
|
|
44801
|
+
return buffer.toString("hex");
|
|
44802
|
+
}
|
|
44803
|
+
function hexToDouble(hex3) {
|
|
44804
|
+
if (!/^[0-9a-f]{16}$/i.test(hex3))
|
|
44805
|
+
throw new NoteStoreError("Invalid double bits", "invalid_input");
|
|
44806
|
+
const value = Buffer.from(hex3, "hex").readDoubleBE();
|
|
44807
|
+
if (!Number.isFinite(value)) throw new NoteStoreError("Invalid double bits", "invalid_input");
|
|
44808
|
+
return value;
|
|
44809
|
+
}
|
|
44810
|
+
function renderValue(value) {
|
|
44811
|
+
if ("int" in value) {
|
|
44812
|
+
if (!Number.isSafeInteger(value.int)) {
|
|
44813
|
+
throw new NoteStoreError("Bound integer out of range", "invalid_input");
|
|
44814
|
+
}
|
|
44815
|
+
return String(value.int);
|
|
44816
|
+
}
|
|
44817
|
+
if ("blob" in value) return `x'${Buffer.from(value.blob).toString("hex")}'`;
|
|
44818
|
+
const double = "double" in value ? value.double : hexToDouble(value.doubleBits);
|
|
44819
|
+
return `ieee754_from_blob(x'${doubleToHex(double)}')`;
|
|
44820
|
+
}
|
|
44821
|
+
function runReadOnlySql(dbPath2, sql, params = {}) {
|
|
44822
|
+
if (!fs5.existsSync(dbPath2)) throw new NoteStoreError(STORE_FDA_MESSAGE, "no_fda");
|
|
44823
|
+
const args = ["-readonly"];
|
|
44824
|
+
const names = Object.keys(params);
|
|
44825
|
+
if (names.length) args.push("-cmd", ".parameter init");
|
|
44826
|
+
for (const name of names) {
|
|
44827
|
+
if (!/^[a-z][a-z0-9_]*$/i.test(name)) {
|
|
44828
|
+
throw new NoteStoreError(`Invalid parameter name ${name}`, "invalid_input");
|
|
44829
|
+
}
|
|
44830
|
+
args.push("-cmd", `.parameter set @${name} ${renderValue(params[name])}`);
|
|
44831
|
+
}
|
|
44832
|
+
args.push(dbPath2, sql);
|
|
44833
|
+
try {
|
|
44834
|
+
return execFileSync10("sqlite3", args, {
|
|
44835
|
+
encoding: "utf8",
|
|
44836
|
+
timeout: 3e4,
|
|
44837
|
+
maxBuffer: 512 * 1024 * 1024,
|
|
44838
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
44839
|
+
});
|
|
44840
|
+
} catch (error2) {
|
|
44841
|
+
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
44842
|
+
if (/authorization denied|unable to open database/i.test(message)) {
|
|
44843
|
+
throw new NoteStoreError(STORE_FDA_MESSAGE, "no_fda");
|
|
44844
|
+
}
|
|
44845
|
+
console.error(`Notes database query failed: ${message}`);
|
|
44846
|
+
throw new NoteStoreError("Failed to query the Notes database.", "query_error");
|
|
44847
|
+
}
|
|
44848
|
+
}
|
|
44849
|
+
function parseJsonLines(output) {
|
|
44850
|
+
const rows = [];
|
|
44851
|
+
for (const line of output.split("\n")) {
|
|
44852
|
+
if (!line.trim()) continue;
|
|
44853
|
+
try {
|
|
44854
|
+
rows.push(JSON.parse(line));
|
|
44855
|
+
} catch {
|
|
44856
|
+
throw new NoteStoreError("Unexpected Notes database response.", "query_error");
|
|
44857
|
+
}
|
|
44858
|
+
}
|
|
44859
|
+
return rows;
|
|
44860
|
+
}
|
|
44861
|
+
function readColumns(dbPath2) {
|
|
44862
|
+
const out = runReadOnlySql(
|
|
44863
|
+
dbPath2,
|
|
44864
|
+
"SELECT json_object('name', name) FROM pragma_table_info('ZICCLOUDSYNCINGOBJECT');"
|
|
44865
|
+
);
|
|
44866
|
+
return new Set(parseJsonLines(out).map((row) => row.name));
|
|
44867
|
+
}
|
|
44868
|
+
function requireColumns(columns, required2, tool) {
|
|
44869
|
+
const missing = required2.filter((column) => !columns.has(column));
|
|
44870
|
+
if (missing.length) {
|
|
44871
|
+
throw new NoteStoreError(
|
|
44872
|
+
`This macOS version's Notes database lacks columns ${tool} needs (${missing.join(", ")}).`,
|
|
44873
|
+
"schema"
|
|
44874
|
+
);
|
|
44875
|
+
}
|
|
44876
|
+
}
|
|
44877
|
+
function col(columns, alias, name, fallback = "NULL") {
|
|
44878
|
+
return columns.has(name) ? `${alias}.${name}` : fallback;
|
|
44879
|
+
}
|
|
44880
|
+
function entity(name) {
|
|
44881
|
+
return `(SELECT Z_ENT FROM Z_PRIMARYKEY WHERE Z_NAME='${name}')`;
|
|
44882
|
+
}
|
|
44883
|
+
function accountRef(columns, alias) {
|
|
44884
|
+
const refs = [...columns].filter((name) => /^ZACCOUNT\d*$/.test(name)).sort().map((name) => `${alias}.${name}`);
|
|
44885
|
+
if (!refs.length) return "NULL";
|
|
44886
|
+
return refs.length === 1 ? refs[0] : `COALESCE(${refs.join(", ")})`;
|
|
44887
|
+
}
|
|
44888
|
+
function trashFolderSql(columns, f) {
|
|
44889
|
+
const parts = [];
|
|
44890
|
+
if (columns.has("ZFOLDERTYPE")) parts.push(`COALESCE(${f}.ZFOLDERTYPE, 0) = 1`);
|
|
44891
|
+
if (columns.has("ZIDENTIFIER")) parts.push(`COALESCE(${f}.ZIDENTIFIER, '') LIKE 'TrashFolder%'`);
|
|
44892
|
+
return parts.length ? `(${parts.join(" OR ")})` : "0";
|
|
44893
|
+
}
|
|
44894
|
+
function notTombstonedSql(columns, alias) {
|
|
44895
|
+
return columns.has("ZMARKEDFORDELETION") ? `COALESCE(${alias}.ZMARKEDFORDELETION, 0) = 0` : "1";
|
|
44896
|
+
}
|
|
44897
|
+
function activeNoteSql(columns, n, f) {
|
|
44898
|
+
return [
|
|
44899
|
+
`${n}.ZFOLDER IS NOT NULL`,
|
|
44900
|
+
`${f}.Z_PK IS NOT NULL`,
|
|
44901
|
+
notTombstonedSql(columns, n),
|
|
44902
|
+
notTombstonedSql(columns, f),
|
|
44903
|
+
`NOT ${trashFolderSql(columns, f)}`
|
|
44904
|
+
].join(" AND ");
|
|
44905
|
+
}
|
|
44906
|
+
function coreDataToIso(seconds) {
|
|
44907
|
+
if (typeof seconds !== "number" || !Number.isFinite(seconds)) return null;
|
|
44908
|
+
const date3 = new Date(CORE_DATA_EPOCH_MS + seconds * 1e3);
|
|
44909
|
+
return Number.isNaN(date3.getTime()) ? null : date3.toISOString();
|
|
44910
|
+
}
|
|
44911
|
+
function noteIdFor(storeUuid, pk) {
|
|
44912
|
+
return `x-coredata://${storeUuid}/ICNote/p${pk}`;
|
|
44913
|
+
}
|
|
44914
|
+
function readStoreContext(dbPath2, columns) {
|
|
44915
|
+
const sql = [
|
|
44916
|
+
"BEGIN;",
|
|
44917
|
+
"SELECT json_object('k', 'meta', 'uuid', (SELECT Z_UUID FROM Z_METADATA LIMIT 1));",
|
|
44918
|
+
`SELECT json_object('k', 'account', 'pk', a.Z_PK, 'name', ${col(columns, "a", "ZNAME")}, 'identifier', ${col(columns, "a", "ZIDENTIFIER")}) FROM ZICCLOUDSYNCINGOBJECT a WHERE a.Z_ENT = ${entity("ICAccount")} AND ${notTombstonedSql(columns, "a")};`,
|
|
44919
|
+
`SELECT json_object('k', 'folder', 'pk', f.Z_PK, 'name', ${col(columns, "f", "ZTITLE2")}, 'identifier', ${col(columns, "f", "ZIDENTIFIER")}, 'parent', ${col(columns, "f", "ZPARENT")}, 'account', ${col(columns, "f", "ZOWNER", accountRef(columns, "f"))}, 'folderType', ${col(columns, "f", "ZFOLDERTYPE")}, 'trash', ${trashFolderSql(columns, "f")}, 'tombstoned', NOT ${notTombstonedSql(columns, "f")}) FROM ZICCLOUDSYNCINGOBJECT f WHERE f.Z_ENT = ${entity("ICFolder")};`,
|
|
44920
|
+
"COMMIT;"
|
|
44921
|
+
].join(" ");
|
|
44922
|
+
const rows = parseJsonLines(runReadOnlySql(dbPath2, sql));
|
|
44923
|
+
const meta = rows.find((row) => row.k === "meta");
|
|
44924
|
+
if (typeof meta?.uuid !== "string" || !meta.uuid) {
|
|
44925
|
+
throw new NoteStoreError("The Notes database has no store identifier.", "schema");
|
|
44926
|
+
}
|
|
44927
|
+
return {
|
|
44928
|
+
uuid: meta.uuid,
|
|
44929
|
+
accounts: rows.filter((row) => row.k === "account").map((row) => ({
|
|
44930
|
+
pk: row.pk,
|
|
44931
|
+
name: typeof row.name === "string" ? row.name : "",
|
|
44932
|
+
identifier: row.identifier ?? null
|
|
44933
|
+
})),
|
|
44934
|
+
folders: rows.filter((row) => row.k === "folder").map((row) => ({
|
|
44935
|
+
pk: row.pk,
|
|
44936
|
+
name: row.name ?? null,
|
|
44937
|
+
identifier: row.identifier ?? null,
|
|
44938
|
+
parent: row.parent ?? null,
|
|
44939
|
+
account: row.account ?? null,
|
|
44940
|
+
folderType: row.folderType ?? null,
|
|
44941
|
+
trash: row.trash ? 1 : 0,
|
|
44942
|
+
tombstoned: row.tombstoned ? 1 : 0
|
|
44943
|
+
}))
|
|
44944
|
+
};
|
|
44945
|
+
}
|
|
44946
|
+
function folderPaths(folders) {
|
|
44947
|
+
const byPk = new Map(folders.map((folder) => [folder.pk, folder]));
|
|
44948
|
+
const paths = /* @__PURE__ */ new Map();
|
|
44949
|
+
for (const folder of folders) {
|
|
44950
|
+
const segments = [];
|
|
44951
|
+
const seen = /* @__PURE__ */ new Set();
|
|
44952
|
+
let current = folder;
|
|
44953
|
+
while (current && !seen.has(current.pk)) {
|
|
44954
|
+
seen.add(current.pk);
|
|
44955
|
+
segments.unshift(escapeFolderName(current.name ?? ""));
|
|
44956
|
+
current = current.parent !== null ? byPk.get(current.parent) : void 0;
|
|
44957
|
+
}
|
|
44958
|
+
paths.set(folder.pk, segments.join("/"));
|
|
44959
|
+
}
|
|
44960
|
+
return paths;
|
|
44961
|
+
}
|
|
44962
|
+
function resolveAccountName(accounts, name) {
|
|
44963
|
+
const wanted = name.trim().toLocaleLowerCase();
|
|
44964
|
+
const exact = accounts.filter((account) => account.name.toLocaleLowerCase() === wanted);
|
|
44965
|
+
if (exact.length === 1) return exact[0];
|
|
44966
|
+
const prefix = accounts.filter((account) => account.name.toLocaleLowerCase().startsWith(wanted));
|
|
44967
|
+
if (exact.length === 0 && prefix.length === 1) return prefix[0];
|
|
44968
|
+
const names = accounts.map((account) => account.name).join(", ");
|
|
44969
|
+
throw new NoteStoreError(
|
|
44970
|
+
exact.length > 1 || prefix.length > 1 ? `Account "${name}" is ambiguous. Accounts: ${names}.` : `No account named "${name}". Accounts: ${names}.`,
|
|
44971
|
+
"invalid_input"
|
|
44972
|
+
);
|
|
44973
|
+
}
|
|
44974
|
+
|
|
44975
|
+
// src/utils/noteListings.ts
|
|
44976
|
+
var SPECIAL_LIMIT = { DEFAULT: 100, MAX: 1e3 };
|
|
44977
|
+
var HASHTAG_UTI = "com.apple.notes.inlinetextattachment.hashtag";
|
|
44978
|
+
var KIND_COLUMN = {
|
|
44979
|
+
pinned: ["ZISPINNED"],
|
|
44980
|
+
"quick-notes": ["ZISSYSTEMPAPER"],
|
|
44981
|
+
"recently-deleted": ["ZFOLDERTYPE", "ZIDENTIFIER"],
|
|
44982
|
+
locked: ["ZISPASSWORDPROTECTED"]
|
|
44983
|
+
};
|
|
44984
|
+
function kindSupported(columns, kind) {
|
|
44985
|
+
return KIND_COLUMN[kind].some((name) => columns.has(name));
|
|
44986
|
+
}
|
|
44987
|
+
var flag = (columns, alias, name) => columns.has(name) ? `COALESCE(${alias}.${name}, 0)` : "0";
|
|
44988
|
+
function kindPredicate(columns, kind) {
|
|
44989
|
+
switch (kind) {
|
|
44990
|
+
case "pinned":
|
|
44991
|
+
return `${flag(columns, "n", "ZISPINNED")} = 1 AND ${activeNoteSql(columns, "n", "f")}`;
|
|
44992
|
+
case "quick-notes":
|
|
44993
|
+
return `${flag(columns, "n", "ZISSYSTEMPAPER")} = 1 AND ${activeNoteSql(columns, "n", "f")}`;
|
|
44994
|
+
case "recently-deleted":
|
|
44995
|
+
return `f.Z_PK IS NOT NULL AND ${trashFolderSql(columns, "f")} AND ${notTombstonedSql(columns, "n")}`;
|
|
44996
|
+
case "locked":
|
|
44997
|
+
return `${flag(columns, "n", "ZISPASSWORDPROTECTED")} = 1`;
|
|
44998
|
+
}
|
|
44999
|
+
}
|
|
45000
|
+
function folderAccountJoins(columns) {
|
|
45001
|
+
const owner = col(columns, "f", "ZOWNER");
|
|
45002
|
+
const account = owner === "NULL" ? accountRef(columns, "n") : `COALESCE(${owner}, ${accountRef(columns, "n")})`;
|
|
45003
|
+
return `LEFT JOIN ZICCLOUDSYNCINGOBJECT f ON f.Z_PK = n.ZFOLDER AND f.Z_ENT = ${entity("ICFolder")} LEFT JOIN ZICCLOUDSYNCINGOBJECT a ON a.Z_PK = ${account} AND a.Z_ENT = ${entity("ICAccount")}`;
|
|
45004
|
+
}
|
|
45005
|
+
function noteFrom(columns) {
|
|
45006
|
+
return `FROM ZICCLOUDSYNCINGOBJECT n ${folderAccountJoins(columns)}`;
|
|
45007
|
+
}
|
|
45008
|
+
var REQUIRED = ["Z_PK", "Z_ENT", "ZFOLDER", "ZTITLE1"];
|
|
45009
|
+
function buildSpecialNotesSql(columns, kind, scoped) {
|
|
45010
|
+
requireColumns(columns, REQUIRED, "list-special-notes");
|
|
45011
|
+
const created = ["ZCREATIONDATE3", "ZCREATIONDATE1", "ZCREATIONDATE"].filter((name) => columns.has(name)).map((name) => `n.${name}`).join(", ") || "NULL";
|
|
45012
|
+
const createdExpr = created.includes(",") ? `COALESCE(${created})` : created;
|
|
45013
|
+
const modified = col(columns, "n", "ZMODIFICATIONDATE1");
|
|
45014
|
+
const locked = flag(columns, "n", "ZISPASSWORDPROTECTED");
|
|
45015
|
+
const where = `WHERE n.Z_ENT = ${entity("ICNote")} AND ${kindPredicate(columns, kind)}` + (scoped ? " AND a.Z_PK = @account" : "");
|
|
45016
|
+
const snippet = `CASE WHEN ${locked} = 1 THEN NULL ELSE ${col(columns, "n", "ZSNIPPET")} END`;
|
|
45017
|
+
const hint = kind === "locked" ? col(columns, "n", "ZPASSWORDHINT") : "NULL";
|
|
45018
|
+
const row = `SELECT json_object('k', 'note', 'pk', n.Z_PK, 'identifier', ${col(columns, "n", "ZIDENTIFIER")}, 'title', n.ZTITLE1, 'folder', f.Z_PK, 'account', a.Z_PK, 'created', ${createdExpr}, 'modified', ${modified}, 'pinned', ${flag(columns, "n", "ZISPINNED")}, 'locked', ${locked}, 'quick', ${flag(columns, "n", "ZISSYSTEMPAPER")}, 'trash', f.Z_PK IS NOT NULL AND ${trashFolderSql(columns, "f")}, 'tombstoned', NOT ${notTombstonedSql(columns, "n")}, 'snippet', ${snippet}, 'hint', ${hint}) ${noteFrom(columns)} ${where} ORDER BY ${modified} DESC, n.Z_PK DESC LIMIT @limit;`;
|
|
45019
|
+
return [
|
|
45020
|
+
"BEGIN;",
|
|
45021
|
+
`SELECT json_object('k', 'total', 'n', COUNT(*)) ${noteFrom(columns)} ${where};`,
|
|
45022
|
+
row,
|
|
45023
|
+
"COMMIT;"
|
|
45024
|
+
].join(" ");
|
|
45025
|
+
}
|
|
45026
|
+
function listSpecialNotes(options) {
|
|
45027
|
+
const dbPath2 = options.dbPath ?? NOTES_DB_PATH6;
|
|
45028
|
+
const limit = Math.min(
|
|
45029
|
+
Math.max(1, Math.trunc(options.limit ?? SPECIAL_LIMIT.DEFAULT)),
|
|
45030
|
+
SPECIAL_LIMIT.MAX
|
|
45031
|
+
);
|
|
45032
|
+
const columns = readColumns(dbPath2);
|
|
45033
|
+
const empty = {
|
|
45034
|
+
kind: options.kind,
|
|
45035
|
+
notes: [],
|
|
45036
|
+
count: 0,
|
|
45037
|
+
total: 0,
|
|
45038
|
+
limit,
|
|
45039
|
+
supported: false
|
|
45040
|
+
};
|
|
45041
|
+
if (!kindSupported(columns, options.kind)) return empty;
|
|
45042
|
+
const context = readStoreContext(dbPath2, columns);
|
|
45043
|
+
const scope2 = options.account ? resolveAccountName(context.accounts, options.account) : void 0;
|
|
45044
|
+
const params = { limit: { int: limit } };
|
|
45045
|
+
if (scope2) params.account = { int: scope2.pk };
|
|
45046
|
+
const rows = parseJsonLines(
|
|
45047
|
+
runReadOnlySql(dbPath2, buildSpecialNotesSql(columns, options.kind, Boolean(scope2)), params)
|
|
45048
|
+
);
|
|
45049
|
+
const paths = folderPaths(context.folders);
|
|
45050
|
+
const accountNames = new Map(context.accounts.map((account) => [account.pk, account.name]));
|
|
45051
|
+
const notes = rows.filter((row) => row.k === "note").map((row) => toSpecialRow(row, context.uuid, paths, accountNames, options.kind));
|
|
45052
|
+
return {
|
|
45053
|
+
kind: options.kind,
|
|
45054
|
+
notes,
|
|
45055
|
+
count: notes.length,
|
|
45056
|
+
total: rows.find((row) => row.k === "total")?.n ?? notes.length,
|
|
45057
|
+
limit,
|
|
45058
|
+
supported: true,
|
|
45059
|
+
...scope2 ? { account: scope2.name } : {}
|
|
45060
|
+
};
|
|
45061
|
+
}
|
|
45062
|
+
function toSpecialRow(row, uuid2, paths, accountNames, kind) {
|
|
45063
|
+
const locked = Boolean(row.locked);
|
|
45064
|
+
const note = {
|
|
45065
|
+
id: noteIdFor(uuid2, row.pk),
|
|
45066
|
+
identifier: row.identifier ?? null,
|
|
45067
|
+
title: row.title ?? null,
|
|
45068
|
+
folder: row.folder !== null ? paths.get(row.folder) ?? null : null,
|
|
45069
|
+
account: row.account !== null ? accountNames.get(row.account) ?? null : null,
|
|
45070
|
+
created: coreDataToIso(row.created),
|
|
45071
|
+
modified: coreDataToIso(row.modified),
|
|
45072
|
+
pinned: Boolean(row.pinned),
|
|
45073
|
+
locked,
|
|
45074
|
+
quickNote: Boolean(row.quick),
|
|
45075
|
+
inRecentlyDeleted: Boolean(row.trash),
|
|
45076
|
+
markedForDeletion: Boolean(row.tombstoned)
|
|
45077
|
+
};
|
|
45078
|
+
if (!locked) note.snippet = row.snippet ?? null;
|
|
45079
|
+
if (kind === "locked" && row.hint) note.passwordHint = row.hint;
|
|
45080
|
+
return note;
|
|
45081
|
+
}
|
|
45082
|
+
var TAG_REQUIRED = ["Z_PK", "Z_ENT", "ZFOLDER", "ZNOTE1", "ZTYPEUTI1", "ZALTTEXT", "ZIDENTIFIER"];
|
|
45083
|
+
function buildTagInventorySql(columns, scoped) {
|
|
45084
|
+
requireColumns(columns, TAG_REQUIRED, "list-native-tags");
|
|
45085
|
+
const accountFilter = scoped ? " AND a.Z_PK = @account" : "";
|
|
45086
|
+
const uses = `FROM ZICCLOUDSYNCINGOBJECT i JOIN ZICCLOUDSYNCINGOBJECT n ON n.Z_PK = i.ZNOTE1 AND n.Z_ENT = ${entity("ICNote")} ${folderAccountJoins(columns)} WHERE i.ZTYPEUTI1 = '${HASHTAG_UTI}' AND ${notTombstonedSql(columns, "i")} AND ${activeNoteSql(columns, "n", "f")}${accountFilter}`;
|
|
45087
|
+
const tagAccount = accountRef(columns, "t");
|
|
45088
|
+
const display = ["ZDISPLAYTEXT", "ZSTANDARDIZEDCONTENT", "ZNAME"].filter((name) => columns.has(name)).map((name) => `t.${name}`);
|
|
45089
|
+
const displayExpr = display.length > 1 ? `COALESCE(${display.join(", ")})` : display[0] || "NULL";
|
|
45090
|
+
return [
|
|
45091
|
+
"BEGIN;",
|
|
45092
|
+
`SELECT json_object('k', 'tag', 'text', ${displayExpr}, 'account', ta.Z_PK) FROM ZICCLOUDSYNCINGOBJECT t LEFT JOIN ZICCLOUDSYNCINGOBJECT ta ON ta.Z_PK = ${tagAccount} AND ta.Z_ENT = ${entity("ICAccount")} WHERE t.Z_ENT = ${entity("ICHashtag")} AND ${notTombstonedSql(columns, "t")}${scoped ? " AND ta.Z_PK = @account" : ""};`,
|
|
45093
|
+
`SELECT json_object('k', 'use', 'note', n.Z_PK, 'object', i.ZIDENTIFIER, 'text', i.ZALTTEXT, 'account', a.Z_PK, 'locked', ${flag(columns, "n", "ZISPASSWORDPROTECTED")}) ${uses};`,
|
|
45094
|
+
`SELECT json_object('k', 'body', 'note', b.Z_PK, 'data', (SELECT hex(d.ZDATA) FROM ZICNOTEDATA d WHERE d.ZNOTE = b.Z_PK ORDER BY d.Z_PK DESC LIMIT 1)) FROM ZICCLOUDSYNCINGOBJECT b WHERE b.Z_PK IN (SELECT n.Z_PK ${uses}) AND ${flag(columns, "b", "ZISPASSWORDPROTECTED")} = 0;`,
|
|
45095
|
+
"COMMIT;"
|
|
45096
|
+
].join(" ");
|
|
45097
|
+
}
|
|
45098
|
+
var bareTag = (text2) => text2.replace(/^#/, "").trim();
|
|
45099
|
+
function referencedObjects(hex3) {
|
|
45100
|
+
if (!hex3 || !/^[0-9a-f]+$/i.test(hex3)) return null;
|
|
45101
|
+
try {
|
|
45102
|
+
const data = gunzipSync6(Buffer.from(hex3, "hex"), { maxOutputLength: 32 * 1024 * 1024 });
|
|
45103
|
+
const wrapper = embeddedMessage(getField(decodeMessage(data), 2));
|
|
45104
|
+
const body = wrapper && embeddedMessage(getField(wrapper, 3));
|
|
45105
|
+
if (!body) return null;
|
|
45106
|
+
const ids = /* @__PURE__ */ new Set();
|
|
45107
|
+
for (const run of getFields(body, 5)) {
|
|
45108
|
+
const attachment = embeddedMessage(getField(embeddedMessage(run) ?? [], 12));
|
|
45109
|
+
const id2 = attachment && stringValue(getField(attachment, 1));
|
|
45110
|
+
if (id2) ids.add(id2);
|
|
45111
|
+
}
|
|
45112
|
+
return ids;
|
|
45113
|
+
} catch {
|
|
45114
|
+
return null;
|
|
45115
|
+
}
|
|
45116
|
+
}
|
|
45117
|
+
function nativeTagInventory(options = {}) {
|
|
45118
|
+
const dbPath2 = options.dbPath ?? NOTES_DB_PATH6;
|
|
45119
|
+
const columns = readColumns(dbPath2);
|
|
45120
|
+
const context = readStoreContext(dbPath2, columns);
|
|
45121
|
+
const scope2 = options.account ? resolveAccountName(context.accounts, options.account) : void 0;
|
|
45122
|
+
const rows = parseJsonLines(
|
|
45123
|
+
runReadOnlySql(
|
|
45124
|
+
dbPath2,
|
|
45125
|
+
buildTagInventorySql(columns, Boolean(scope2)),
|
|
45126
|
+
scope2 ? { account: { int: scope2.pk } } : {}
|
|
45127
|
+
)
|
|
45128
|
+
);
|
|
45129
|
+
return assembleInventory(rows, context.accounts, scope2);
|
|
45130
|
+
}
|
|
45131
|
+
function assembleInventory(rows, accounts, scope2) {
|
|
45132
|
+
const accountNames = new Map(accounts.map((account) => [account.pk, account.name]));
|
|
45133
|
+
const bodies = /* @__PURE__ */ new Map();
|
|
45134
|
+
for (const row of rows) if (row.k === "body") bodies.set(row.note, referencedObjects(row.data));
|
|
45135
|
+
const groups = /* @__PURE__ */ new Map();
|
|
45136
|
+
const group = (text2, weight) => {
|
|
45137
|
+
const key = text2.toLocaleLowerCase();
|
|
45138
|
+
let found = groups.get(key);
|
|
45139
|
+
if (!found) groups.set(key, found = { spellings: /* @__PURE__ */ new Map(), notes: /* @__PURE__ */ new Map() });
|
|
45140
|
+
found.spellings.set(text2, (found.spellings.get(text2) ?? 0) + weight);
|
|
45141
|
+
return found;
|
|
45142
|
+
};
|
|
45143
|
+
const unverified = /* @__PURE__ */ new Set();
|
|
45144
|
+
for (const row of rows) {
|
|
45145
|
+
if (row.k === "tag" && row.text && bareTag(row.text)) group(bareTag(row.text), 0);
|
|
45146
|
+
if (row.k !== "use" || !row.text || !bareTag(row.text)) continue;
|
|
45147
|
+
const referenced = row.locked ? null : bodies.get(row.note) ?? null;
|
|
45148
|
+
if (referenced && !(row.object && referenced.has(row.object))) continue;
|
|
45149
|
+
if (!referenced) unverified.add(row.note);
|
|
45150
|
+
group(bareTag(row.text), 1).notes.set(row.note, row.account);
|
|
45151
|
+
}
|
|
45152
|
+
const inventory = [...groups.values()].map((entry) => {
|
|
45153
|
+
const spellings = [...entry.spellings.entries()].sort(
|
|
45154
|
+
(a, b) => b[1] - a[1] || a[0].localeCompare(b[0])
|
|
45155
|
+
);
|
|
45156
|
+
const perAccount = {};
|
|
45157
|
+
for (const accountPk of entry.notes.values()) {
|
|
45158
|
+
const name = accountPk !== null && accountNames.get(accountPk) || "unknown";
|
|
45159
|
+
perAccount[name] = (perAccount[name] ?? 0) + 1;
|
|
45160
|
+
}
|
|
45161
|
+
const result = {
|
|
45162
|
+
tag: spellings[0][0],
|
|
45163
|
+
noteCount: entry.notes.size,
|
|
45164
|
+
accounts: perAccount
|
|
45165
|
+
};
|
|
45166
|
+
if (spellings.length > 1) result.spellings = spellings.slice(1).map(([text2]) => text2);
|
|
45167
|
+
return result;
|
|
45168
|
+
});
|
|
45169
|
+
inventory.sort((a, b) => b.noteCount - a.noteCount || a.tag.localeCompare(b.tag));
|
|
45170
|
+
return {
|
|
45171
|
+
inventory,
|
|
45172
|
+
tagCount: inventory.length,
|
|
45173
|
+
complete: unverified.size === 0,
|
|
45174
|
+
unverifiedNotes: unverified.size,
|
|
45175
|
+
...scope2 ? { account: scope2.name } : {}
|
|
45176
|
+
};
|
|
45177
|
+
}
|
|
45178
|
+
|
|
45179
|
+
// src/utils/noteIdentifiers.ts
|
|
45180
|
+
import { execFileSync as execFileSync11 } from "child_process";
|
|
45181
|
+
import * as fs6 from "fs";
|
|
45182
|
+
import * as os6 from "os";
|
|
45183
|
+
import * as path6 from "path";
|
|
45184
|
+
var NOTES_DB_PATH7 = path6.join(
|
|
45185
|
+
os6.homedir(),
|
|
45186
|
+
"Library/Group Containers/group.com.apple.notes/NoteStore.sqlite"
|
|
45187
|
+
);
|
|
44784
45188
|
var UUID_PATTERN = /^[0-9A-Fa-f]{8}(?:-[0-9A-Fa-f]{4}){3}-[0-9A-Fa-f]{12}$/;
|
|
44785
45189
|
var NUMERIC_KEY_PATTERN = /^\d{1,18}$/;
|
|
44786
45190
|
var NOTE_ID_MESSAGE = "A canonical Apple Note ID is required (x-coredata://.../ICNote/p...), or the note's Notes UUID or numeric key";
|
|
@@ -44814,10 +45218,10 @@ function assertAll(values, pattern, label) {
|
|
|
44814
45218
|
if (!pattern.test(value)) throw new Error(`Refusing to query with an invalid ${label}`);
|
|
44815
45219
|
}
|
|
44816
45220
|
}
|
|
44817
|
-
function entityClause(
|
|
44818
|
-
return `(SELECT Z_ENT FROM Z_PRIMARYKEY WHERE Z_NAME = '${
|
|
45221
|
+
function entityClause(entity3) {
|
|
45222
|
+
return `(SELECT Z_ENT FROM Z_PRIMARYKEY WHERE Z_NAME = '${entity3}')`;
|
|
44819
45223
|
}
|
|
44820
|
-
function buildResolveSql(
|
|
45224
|
+
function buildResolveSql(entity3, keys, uuids) {
|
|
44821
45225
|
assertAll(keys, NUMERIC_KEY_PATTERN, "numeric key");
|
|
44822
45226
|
assertAll(uuids, UUID_PATTERN, "UUID");
|
|
44823
45227
|
const matches = [];
|
|
@@ -44834,28 +45238,28 @@ function buildResolveSql(entity2, keys, uuids) {
|
|
|
44834
45238
|
matches.push(`o.ZIDENTIFIER IN (${[...variants].map((v) => `'${v}'`).join(", ")})`);
|
|
44835
45239
|
}
|
|
44836
45240
|
const where = matches.length > 0 ? matches.join(" OR ") : "0";
|
|
44837
|
-
return `SELECT json_object('store', (SELECT Z_UUID FROM Z_METADATA LIMIT 1), 'rows', (SELECT json_group_array(json_object('pk', o.Z_PK, 'identifier', o.ZIDENTIFIER)) FROM ZICCLOUDSYNCINGOBJECT o WHERE o.Z_ENT = ${entityClause(
|
|
45241
|
+
return `SELECT json_object('store', (SELECT Z_UUID FROM Z_METADATA LIMIT 1), 'rows', (SELECT json_group_array(json_object('pk', o.Z_PK, 'identifier', o.ZIDENTIFIER)) FROM ZICCLOUDSYNCINGOBJECT o WHERE o.Z_ENT = ${entityClause(entity3)} AND (${where})));`;
|
|
44838
45242
|
}
|
|
44839
|
-
function buildLookupSql(
|
|
45243
|
+
function buildLookupSql(entity3, keys) {
|
|
44840
45244
|
assertAll(keys, NUMERIC_KEY_PATTERN, "numeric key");
|
|
44841
45245
|
const pks = [...new Set(keys.map(canonicalKey))];
|
|
44842
45246
|
const inList = pks.length > 0 ? pks.join(", ") : "NULL";
|
|
44843
45247
|
let fields = "'pk', o.Z_PK, 'identifier', o.ZIDENTIFIER";
|
|
44844
45248
|
let joins = "";
|
|
44845
|
-
if (
|
|
45249
|
+
if (entity3 === "ICNote") {
|
|
44846
45250
|
fields += ", 'folderIdentifier', f.ZIDENTIFIER, 'accountIdentifier', a.ZIDENTIFIER";
|
|
44847
45251
|
joins = "LEFT JOIN ZICCLOUDSYNCINGOBJECT f ON f.Z_PK = o.ZFOLDER LEFT JOIN ZICCLOUDSYNCINGOBJECT a ON a.Z_PK = f.ZOWNER ";
|
|
44848
|
-
} else if (
|
|
45252
|
+
} else if (entity3 === "ICFolder") {
|
|
44849
45253
|
fields += ", 'parentIdentifier', p.ZIDENTIFIER, 'accountIdentifier', a.ZIDENTIFIER";
|
|
44850
45254
|
joins = "LEFT JOIN ZICCLOUDSYNCINGOBJECT p ON p.Z_PK = o.ZPARENT LEFT JOIN ZICCLOUDSYNCINGOBJECT a ON a.Z_PK = o.ZOWNER ";
|
|
44851
45255
|
}
|
|
44852
|
-
return `SELECT json_object('store', (SELECT Z_UUID FROM Z_METADATA LIMIT 1), 'rows', (SELECT json_group_array(json_object(${fields})) FROM ZICCLOUDSYNCINGOBJECT o ${joins}WHERE o.Z_ENT = ${entityClause(
|
|
45256
|
+
return `SELECT json_object('store', (SELECT Z_UUID FROM Z_METADATA LIMIT 1), 'rows', (SELECT json_group_array(json_object(${fields})) FROM ZICCLOUDSYNCINGOBJECT o ${joins}WHERE o.Z_ENT = ${entityClause(entity3)} AND o.Z_PK IN (${inList})));`;
|
|
44853
45257
|
}
|
|
44854
45258
|
function runJsonQuery(sql, dbPath2) {
|
|
44855
|
-
if (!
|
|
45259
|
+
if (!fs6.existsSync(dbPath2)) throw new IdentifierResolutionError("no_fda", NO_FDA_MESSAGE);
|
|
44856
45260
|
let out;
|
|
44857
45261
|
try {
|
|
44858
|
-
out =
|
|
45262
|
+
out = execFileSync11("sqlite3", ["-readonly", dbPath2, sql], {
|
|
44859
45263
|
encoding: "utf8",
|
|
44860
45264
|
timeout: 5e3,
|
|
44861
45265
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -44872,10 +45276,10 @@ function runJsonQuery(sql, dbPath2) {
|
|
|
44872
45276
|
const rows = typeof parsed.rows === "string" ? JSON.parse(parsed.rows) : parsed.rows;
|
|
44873
45277
|
return { store: parsed.store ?? null, rows: rows ?? [] };
|
|
44874
45278
|
}
|
|
44875
|
-
function coreDataId(store,
|
|
44876
|
-
return `x-coredata://${store}/${
|
|
45279
|
+
function coreDataId(store, entity3, pk) {
|
|
45280
|
+
return `x-coredata://${store}/${entity3}/p${pk}`;
|
|
44877
45281
|
}
|
|
44878
|
-
function resolveIdentifiers(values,
|
|
45282
|
+
function resolveIdentifiers(values, entity3, dbPath2 = NOTES_DB_PATH7) {
|
|
44879
45283
|
const resolved = /* @__PURE__ */ new Map();
|
|
44880
45284
|
const keys = [];
|
|
44881
45285
|
const uuids = [];
|
|
@@ -44887,7 +45291,7 @@ function resolveIdentifiers(values, entity2, dbPath2 = NOTES_DB_PATH6) {
|
|
|
44887
45291
|
}
|
|
44888
45292
|
if (keys.length === 0 && uuids.length === 0) return resolved;
|
|
44889
45293
|
const { store, rows } = runJsonQuery(
|
|
44890
|
-
buildResolveSql(
|
|
45294
|
+
buildResolveSql(entity3, keys, uuids),
|
|
44891
45295
|
dbPath2
|
|
44892
45296
|
);
|
|
44893
45297
|
if (!store) {
|
|
@@ -44900,16 +45304,16 @@ function resolveIdentifiers(values, entity2, dbPath2 = NOTES_DB_PATH6) {
|
|
|
44900
45304
|
const byUuid = new Map(
|
|
44901
45305
|
rows.filter((row) => row.identifier).map((row) => [String(row.identifier).toUpperCase(), row])
|
|
44902
45306
|
);
|
|
44903
|
-
const label = ENTITY_LABEL[
|
|
45307
|
+
const label = ENTITY_LABEL[entity3];
|
|
44904
45308
|
const missing = [];
|
|
44905
45309
|
for (const key of keys) {
|
|
44906
45310
|
const row = byKey.get(canonicalKey(key));
|
|
44907
|
-
if (row) resolved.set(key, coreDataId(store,
|
|
45311
|
+
if (row) resolved.set(key, coreDataId(store, entity3, row.pk));
|
|
44908
45312
|
else missing.push(`numeric key ${key}`);
|
|
44909
45313
|
}
|
|
44910
45314
|
for (const uuid2 of uuids) {
|
|
44911
45315
|
const row = byUuid.get(uuid2.toUpperCase());
|
|
44912
|
-
if (row) resolved.set(uuid2, coreDataId(store,
|
|
45316
|
+
if (row) resolved.set(uuid2, coreDataId(store, entity3, row.pk));
|
|
44913
45317
|
else missing.push(`identifier ${uuid2}`);
|
|
44914
45318
|
}
|
|
44915
45319
|
if (missing.length > 0) {
|
|
@@ -44921,12 +45325,12 @@ function resolveIdentifiers(values, entity2, dbPath2 = NOTES_DB_PATH6) {
|
|
|
44921
45325
|
return resolved;
|
|
44922
45326
|
}
|
|
44923
45327
|
var COREDATA_PARTS = /^x-coredata:\/\/([0-9A-Fa-f-]+)\/(ICNote|ICFolder|ICAccount)\/p(\d{1,18})$/;
|
|
44924
|
-
function lookupStableIdentifiers(ids,
|
|
45328
|
+
function lookupStableIdentifiers(ids, entity3, dbPath2 = NOTES_DB_PATH7) {
|
|
44925
45329
|
const result = /* @__PURE__ */ new Map();
|
|
44926
45330
|
const wanted = /* @__PURE__ */ new Map();
|
|
44927
45331
|
for (const id2 of ids) {
|
|
44928
45332
|
const match = COREDATA_PARTS.exec(id2);
|
|
44929
|
-
if (!match || match[2] !==
|
|
45333
|
+
if (!match || match[2] !== entity3) continue;
|
|
44930
45334
|
const pk = canonicalKey(match[3]);
|
|
44931
45335
|
const list = wanted.get(pk) ?? [];
|
|
44932
45336
|
list.push({ id: id2, store: match[1] });
|
|
@@ -44935,7 +45339,7 @@ function lookupStableIdentifiers(ids, entity2, dbPath2 = NOTES_DB_PATH6) {
|
|
|
44935
45339
|
if (wanted.size === 0) return result;
|
|
44936
45340
|
let query;
|
|
44937
45341
|
try {
|
|
44938
|
-
query = runJsonQuery(buildLookupSql(
|
|
45342
|
+
query = runJsonQuery(buildLookupSql(entity3, [...wanted.keys()]), dbPath2);
|
|
44939
45343
|
} catch {
|
|
44940
45344
|
return result;
|
|
44941
45345
|
}
|
|
@@ -44957,16 +45361,16 @@ function lookupStableIdentifiers(ids, entity2, dbPath2 = NOTES_DB_PATH6) {
|
|
|
44957
45361
|
}
|
|
44958
45362
|
return result;
|
|
44959
45363
|
}
|
|
44960
|
-
function withStableIdentifiers(items,
|
|
45364
|
+
function withStableIdentifiers(items, entity3, dbPath2 = NOTES_DB_PATH7) {
|
|
44961
45365
|
const ids = items.map((item) => item.id).filter((id2) => typeof id2 === "string");
|
|
44962
45366
|
if (ids.length === 0) return items;
|
|
44963
|
-
const found = lookupStableIdentifiers(ids,
|
|
45367
|
+
const found = lookupStableIdentifiers(ids, entity3, dbPath2);
|
|
44964
45368
|
if (found.size === 0) return items;
|
|
44965
45369
|
return items.map(
|
|
44966
45370
|
(item) => item.id && found.has(item.id) ? { ...item, ...found.get(item.id) } : item
|
|
44967
45371
|
);
|
|
44968
45372
|
}
|
|
44969
|
-
var defaultResolver = (values,
|
|
45373
|
+
var defaultResolver = (values, entity3) => resolveIdentifiers(values, entity3);
|
|
44970
45374
|
var DEFAULT_MAX_ID_LENGTH = 2e3;
|
|
44971
45375
|
function acceptAlternateForms(pattern) {
|
|
44972
45376
|
return new RegExp(
|
|
@@ -44974,10 +45378,10 @@ function acceptAlternateForms(pattern) {
|
|
|
44974
45378
|
pattern.flags
|
|
44975
45379
|
);
|
|
44976
45380
|
}
|
|
44977
|
-
function resolveInSchema(values,
|
|
45381
|
+
function resolveInSchema(values, entity3, ctx, resolver) {
|
|
44978
45382
|
if (!values.some(isAlternateIdentifier)) return new Map(values.map((v) => [v, v]));
|
|
44979
45383
|
try {
|
|
44980
|
-
return resolver(values,
|
|
45384
|
+
return resolver(values, entity3);
|
|
44981
45385
|
} catch (error2) {
|
|
44982
45386
|
ctx.addIssue({
|
|
44983
45387
|
code: external_exports.ZodIssueCode.custom,
|
|
@@ -44986,26 +45390,26 @@ function resolveInSchema(values, entity2, ctx, resolver) {
|
|
|
44986
45390
|
return null;
|
|
44987
45391
|
}
|
|
44988
45392
|
}
|
|
44989
|
-
function exactIdInput(
|
|
45393
|
+
function exactIdInput(entity3, pattern, message, options = {}) {
|
|
44990
45394
|
const resolver = options.resolver ?? defaultResolver;
|
|
44991
45395
|
return external_exports.string().max(options.maxLength ?? DEFAULT_MAX_ID_LENGTH).regex(acceptAlternateForms(pattern), message).transform((value, ctx) => {
|
|
44992
|
-
const map = resolveInSchema([value],
|
|
45396
|
+
const map = resolveInSchema([value], entity3, ctx, resolver);
|
|
44993
45397
|
return map ? map.get(value) ?? value : external_exports.NEVER;
|
|
44994
45398
|
});
|
|
44995
45399
|
}
|
|
44996
|
-
function exactIdArrayInput(
|
|
45400
|
+
function exactIdArrayInput(entity3, pattern, message, options = {}) {
|
|
44997
45401
|
const resolver = options.resolver ?? defaultResolver;
|
|
44998
45402
|
const item = external_exports.string().max(options.maxLength ?? DEFAULT_MAX_ID_LENGTH).regex(acceptAlternateForms(pattern), message);
|
|
44999
45403
|
const array2 = options.maxItems === void 0 ? external_exports.array(item) : external_exports.array(item).max(options.maxItems);
|
|
45000
45404
|
return array2.transform((values, ctx) => {
|
|
45001
|
-
const map = resolveInSchema(values,
|
|
45405
|
+
const map = resolveInSchema(values, entity3, ctx, resolver);
|
|
45002
45406
|
return map ? values.map((value) => map.get(value) ?? value) : external_exports.NEVER;
|
|
45003
45407
|
});
|
|
45004
45408
|
}
|
|
45005
|
-
function looseIdTransform(
|
|
45409
|
+
function looseIdTransform(entity3, resolver = defaultResolver) {
|
|
45006
45410
|
return (value, ctx) => {
|
|
45007
45411
|
if (!isAlternateIdentifier(value)) return value;
|
|
45008
|
-
const map = resolveInSchema([value],
|
|
45412
|
+
const map = resolveInSchema([value], entity3, ctx, resolver);
|
|
45009
45413
|
return map ? map.get(value) ?? value : external_exports.NEVER;
|
|
45010
45414
|
};
|
|
45011
45415
|
}
|
|
@@ -45027,10 +45431,10 @@ function htmlToText(html) {
|
|
|
45027
45431
|
var HASHTAG_RE = new RegExp("(?<![\\p{L}\\p{N}_])#([\\p{L}\\p{N}_]*\\p{L}[\\p{L}\\p{N}_]*)", "gu");
|
|
45028
45432
|
function parseHashtags(body) {
|
|
45029
45433
|
if (!body) return [];
|
|
45030
|
-
const
|
|
45434
|
+
const text2 = htmlToText(body);
|
|
45031
45435
|
const seen = /* @__PURE__ */ new Set();
|
|
45032
45436
|
const result = [];
|
|
45033
|
-
for (const match of
|
|
45437
|
+
for (const match of text2.matchAll(HASHTAG_RE)) {
|
|
45034
45438
|
const tag = match[1];
|
|
45035
45439
|
const key = tag.toLowerCase();
|
|
45036
45440
|
if (!seen.has(key)) {
|
|
@@ -45046,7 +45450,7 @@ var BLOCK_END_RE = /<\/(?:div|h[1-6]|p|li)>/gi;
|
|
|
45046
45450
|
var BREAK_RE = /<br\s*\/?\s*>/gi;
|
|
45047
45451
|
var TAG_RE = /<[^>]*>/g;
|
|
45048
45452
|
var NON_RENDERED_BLOCK_RE = /<(script|style)\b[^>]*>[\s\S]*?(?:<\/\1>|$)/gi;
|
|
45049
|
-
function decodeHtmlEntities(
|
|
45453
|
+
function decodeHtmlEntities(text2) {
|
|
45050
45454
|
const decodeCodePoint = (match, value, radix) => {
|
|
45051
45455
|
const codePoint = Number.parseInt(value, radix);
|
|
45052
45456
|
if (!Number.isInteger(codePoint) || codePoint < 0 || codePoint > 1114111 || codePoint >= 55296 && codePoint <= 57343) {
|
|
@@ -45054,21 +45458,21 @@ function decodeHtmlEntities(text) {
|
|
|
45054
45458
|
}
|
|
45055
45459
|
return String.fromCodePoint(codePoint);
|
|
45056
45460
|
};
|
|
45057
|
-
return
|
|
45461
|
+
return text2.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, "&");
|
|
45058
45462
|
}
|
|
45059
45463
|
function firstVisibleHtmlLine(html) {
|
|
45060
|
-
let
|
|
45464
|
+
let text2 = html;
|
|
45061
45465
|
let previous;
|
|
45062
45466
|
do {
|
|
45063
|
-
previous =
|
|
45064
|
-
|
|
45065
|
-
} while (
|
|
45066
|
-
|
|
45467
|
+
previous = text2;
|
|
45468
|
+
text2 = text2.replace(NON_RENDERED_BLOCK_RE, "");
|
|
45469
|
+
} while (text2 !== previous);
|
|
45470
|
+
text2 = text2.replace(BREAK_RE, "\n").replace(BLOCK_END_RE, "\n");
|
|
45067
45471
|
do {
|
|
45068
|
-
previous =
|
|
45069
|
-
|
|
45070
|
-
} while (
|
|
45071
|
-
return decodeHtmlEntities(
|
|
45472
|
+
previous = text2;
|
|
45473
|
+
text2 = text2.replace(TAG_RE, "");
|
|
45474
|
+
} while (text2 !== previous);
|
|
45475
|
+
return decodeHtmlEntities(text2).split(/[\r\n\u2028\u2029]+/).map((line) => line.replace(/\s+/g, " ").trim()).find(Boolean);
|
|
45072
45476
|
}
|
|
45073
45477
|
function resolveUpdateResponseTitle(currentTitle, newTitle, format, newContent) {
|
|
45074
45478
|
if (format === "html") return firstVisibleHtmlLine(newContent) ?? currentTitle;
|
|
@@ -45233,15 +45637,15 @@ function splitComparison(value) {
|
|
|
45233
45637
|
const match = COMPARE_RE.exec(value);
|
|
45234
45638
|
return [match[1] ?? "=", match[2]];
|
|
45235
45639
|
}
|
|
45236
|
-
function parseLocalDate(
|
|
45237
|
-
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(
|
|
45640
|
+
function parseLocalDate(text2, pos) {
|
|
45641
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(text2);
|
|
45238
45642
|
if (!match) {
|
|
45239
|
-
throw new NoteQueryError(`Expected a date as YYYY-MM-DD, got "${
|
|
45643
|
+
throw new NoteQueryError(`Expected a date as YYYY-MM-DD, got "${text2}"`, pos);
|
|
45240
45644
|
}
|
|
45241
45645
|
const [year, month, day] = [Number(match[1]), Number(match[2]), Number(match[3])];
|
|
45242
45646
|
const start = new Date(year, month - 1, day);
|
|
45243
45647
|
if (start.getFullYear() !== year || start.getMonth() !== month - 1 || start.getDate() !== day) {
|
|
45244
|
-
throw new NoteQueryError(`"${
|
|
45648
|
+
throw new NoteQueryError(`"${text2}" is not a valid calendar date`, pos);
|
|
45245
45649
|
}
|
|
45246
45650
|
return { start: start.getTime(), end: new Date(year, month - 1, day + 1).getTime() };
|
|
45247
45651
|
}
|
|
@@ -45415,8 +45819,8 @@ var Parser = class {
|
|
|
45415
45819
|
function parseNoteQuery(input) {
|
|
45416
45820
|
return new Parser(tokenize(input), input.length).parse();
|
|
45417
45821
|
}
|
|
45418
|
-
function normalizeForMatch(
|
|
45419
|
-
return
|
|
45822
|
+
function normalizeForMatch(text2) {
|
|
45823
|
+
return text2.normalize("NFC").replace(/[\ufffc\u00a0]/gu, " ").toLowerCase();
|
|
45420
45824
|
}
|
|
45421
45825
|
function needsContent(node) {
|
|
45422
45826
|
switch (node.type) {
|
|
@@ -45545,18 +45949,18 @@ function positiveTextTerms(node, negated = false) {
|
|
|
45545
45949
|
}
|
|
45546
45950
|
|
|
45547
45951
|
// src/utils/noteQueryStore.ts
|
|
45548
|
-
import { execFileSync as
|
|
45549
|
-
import * as
|
|
45550
|
-
import * as
|
|
45551
|
-
import * as
|
|
45552
|
-
import { gunzipSync as
|
|
45553
|
-
var
|
|
45554
|
-
|
|
45952
|
+
import { execFileSync as execFileSync12 } from "child_process";
|
|
45953
|
+
import * as fs7 from "fs";
|
|
45954
|
+
import * as os7 from "os";
|
|
45955
|
+
import * as path7 from "path";
|
|
45956
|
+
import { gunzipSync as gunzipSync7 } from "zlib";
|
|
45957
|
+
var NOTES_DB_PATH8 = path7.join(
|
|
45958
|
+
os7.homedir(),
|
|
45555
45959
|
"Library/Group Containers/group.com.apple.notes/NoteStore.sqlite"
|
|
45556
45960
|
);
|
|
45557
45961
|
var QUERY_SCAN = { DEFAULT: 500, MAX: 5e3 };
|
|
45558
45962
|
var QUERY_RESULTS = { DEFAULT: 50, MAX: 500 };
|
|
45559
|
-
var
|
|
45963
|
+
var CORE_DATA_EPOCH_MS2 = Date.UTC(2001, 0, 1);
|
|
45560
45964
|
var SNIPPET_BEFORE = 60;
|
|
45561
45965
|
var SNIPPET_LENGTH = 180;
|
|
45562
45966
|
var QUERY_FDA_MESSAGE = `Full Disk Access is required to query notes. In System Settings > Privacy & Security > Full Disk Access, grant access to the app that launches this server (Claude Desktop / Terminal / iTerm2), then fully quit and relaunch it. Setup guide: ${FULL_DISK_ACCESS_GUIDE_URL} \u2014 run the doctor tool to verify.`;
|
|
@@ -45595,8 +45999,8 @@ var CHECKLIST_STYLE = 103;
|
|
|
45595
45999
|
function decodeNoteBody(data) {
|
|
45596
46000
|
const wrapper = embeddedMessage(getField(decodeMessage(data), 2));
|
|
45597
46001
|
const body = wrapper && embeddedMessage(getField(wrapper, 3));
|
|
45598
|
-
const
|
|
45599
|
-
if (!body ||
|
|
46002
|
+
const text2 = body && stringValue(getField(body, 2));
|
|
46003
|
+
if (!body || text2 === void 0) return null;
|
|
45600
46004
|
const facets = /* @__PURE__ */ new Set();
|
|
45601
46005
|
const objectIds = /* @__PURE__ */ new Set();
|
|
45602
46006
|
const checklist = /* @__PURE__ */ new Map();
|
|
@@ -45617,7 +46021,7 @@ function decodeNoteBody(data) {
|
|
|
45617
46021
|
if (paragraph && varintValue(getField(paragraph, 1)) === CHECKLIST_STYLE) {
|
|
45618
46022
|
const item = embeddedMessage(getField(paragraph, 5));
|
|
45619
46023
|
const rawId = item && getField(item, 1)?.value;
|
|
45620
|
-
const key = rawId instanceof Uint8Array ? Buffer.from(rawId).toString("hex") : `line:${
|
|
46024
|
+
const key = rawId instanceof Uint8Array ? Buffer.from(rawId).toString("hex") : `line:${text2.lastIndexOf("\n", position - 1) + 1}`;
|
|
45621
46025
|
checklist.set(key, (item && varintValue(getField(item, 2))) === 1);
|
|
45622
46026
|
}
|
|
45623
46027
|
position += length;
|
|
@@ -45625,24 +46029,24 @@ function decodeNoteBody(data) {
|
|
|
45625
46029
|
if (checklist.size > 0) facets.add("checklist");
|
|
45626
46030
|
const done = [...checklist.values()].filter(Boolean).length;
|
|
45627
46031
|
return {
|
|
45628
|
-
text,
|
|
46032
|
+
text: text2,
|
|
45629
46033
|
facets,
|
|
45630
46034
|
checklist: { total: checklist.size, open: checklist.size - done },
|
|
45631
46035
|
objectIds
|
|
45632
46036
|
};
|
|
45633
46037
|
}
|
|
45634
|
-
function countWords(
|
|
46038
|
+
function countWords(text2) {
|
|
45635
46039
|
let count = 0;
|
|
45636
|
-
for (const word of
|
|
46040
|
+
for (const word of text2.replace(/\ufffc/gu, " ").split(/\s+/u)) {
|
|
45637
46041
|
if (/[\p{L}\p{N}]/u.test(word)) count++;
|
|
45638
46042
|
}
|
|
45639
46043
|
return count;
|
|
45640
46044
|
}
|
|
45641
46045
|
var REQUIRED_COLUMNS3 = ["Z_PK", "Z_ENT", "ZTITLE1", "ZFOLDER", "ZMODIFICATIONDATE1"];
|
|
45642
|
-
function
|
|
46046
|
+
function col2(available, alias, name) {
|
|
45643
46047
|
return available.has(name) ? `${alias}.${name}` : "NULL";
|
|
45644
46048
|
}
|
|
45645
|
-
var
|
|
46049
|
+
var entity2 = (name) => `(SELECT Z_ENT FROM Z_PRIMARYKEY WHERE Z_NAME='${name}')`;
|
|
45646
46050
|
function buildScanSql(available, options) {
|
|
45647
46051
|
const missing = REQUIRED_COLUMNS3.filter((c) => !available.has(c));
|
|
45648
46052
|
if (missing.length) {
|
|
@@ -45660,21 +46064,21 @@ function buildScanSql(available, options) {
|
|
|
45660
46064
|
const bool = (name) => available.has(name) ? `COALESCE(n.${name}, 0)` : "0";
|
|
45661
46065
|
const notNull = (alias, name) => available.has(name) ? `${alias}.${name} IS NOT NULL` : "0";
|
|
45662
46066
|
const tagsExpr = options.withTags && ["ZNOTE1", "ZTYPEUTI1", "ZALTTEXT", "ZIDENTIFIER"].every((c) => available.has(c)) ? `(SELECT json_group_array(json_array(t.ZIDENTIFIER, t.ZALTTEXT)) FROM ZICCLOUDSYNCINGOBJECT t WHERE t.ZNOTE1 = n.Z_PK AND t.ZTYPEUTI1 = 'com.apple.notes.inlinetextattachment.hashtag')` : "NULL";
|
|
45663
|
-
const where = [`n.Z_ENT = ${
|
|
46067
|
+
const where = [`n.Z_ENT = ${entity2("ICNote")}`];
|
|
45664
46068
|
if (!options.includeDeleted) {
|
|
45665
46069
|
where.push("n.ZFOLDER IS NOT NULL");
|
|
45666
46070
|
if (available.has("ZMARKEDFORDELETION")) where.push("COALESCE(n.ZMARKEDFORDELETION, 0) = 0");
|
|
45667
46071
|
if (available.has("ZFOLDERTYPE")) {
|
|
45668
46072
|
where.push(
|
|
45669
|
-
`n.ZFOLDER NOT IN (SELECT Z_PK FROM ZICCLOUDSYNCINGOBJECT WHERE Z_ENT = ${
|
|
46073
|
+
`n.ZFOLDER NOT IN (SELECT Z_PK FROM ZICCLOUDSYNCINGOBJECT WHERE Z_ENT = ${entity2("ICFolder")} AND ZFOLDERTYPE = 1)`
|
|
45670
46074
|
);
|
|
45671
46075
|
}
|
|
45672
46076
|
}
|
|
45673
46077
|
const whereSql = where.join(" AND ");
|
|
45674
|
-
const folderRow = `SELECT json_object('k', 'folder', 'pk', f.Z_PK, 'name', ${
|
|
45675
|
-
const accountRow = `SELECT json_object('k', 'account', 'pk', a.Z_PK, 'name', ${
|
|
46078
|
+
const folderRow = `SELECT json_object('k', 'folder', 'pk', f.Z_PK, 'name', ${col2(available, "f", "ZTITLE2")}, 'parent', ${col2(available, "f", "ZPARENT")}, 'type', ${col2(available, "f", "ZFOLDERTYPE")}, 'owner', ${col2(available, "f", "ZOWNER")}, 'shared', ${notNull("f", "ZSERVERSHAREDATA")}) FROM ZICCLOUDSYNCINGOBJECT f WHERE f.Z_ENT = ${entity2("ICFolder")};`;
|
|
46079
|
+
const accountRow = `SELECT json_object('k', 'account', 'pk', a.Z_PK, 'name', ${col2(available, "a", "ZNAME")}) FROM ZICCLOUDSYNCINGOBJECT a WHERE a.Z_ENT = ${entity2("ICAccount")};`;
|
|
45676
46080
|
const dataExpr = options.withBodies ? "(SELECT hex(d.ZDATA) FROM ZICNOTEDATA d WHERE d.ZNOTE = n.Z_PK ORDER BY d.Z_PK DESC LIMIT 1)" : "NULL";
|
|
45677
|
-
const noteRow = `SELECT json_object('k', 'note', 'pk', n.Z_PK, 'title', n.ZTITLE1, 'folder', n.ZFOLDER, 'created', ${createdExpr}, 'modified', n.ZMODIFICATIONDATE1, 'pinned', ${bool("ZISPINNED")}, 'locked', ${bool("ZISPASSWORDPROTECTED")}, 'shared', ${notNull("n", "ZSERVERSHAREDATA")}, 'snippet', ${
|
|
46081
|
+
const noteRow = `SELECT json_object('k', 'note', 'pk', n.Z_PK, 'title', n.ZTITLE1, 'folder', n.ZFOLDER, 'created', ${createdExpr}, 'modified', n.ZMODIFICATIONDATE1, 'pinned', ${bool("ZISPINNED")}, 'locked', ${bool("ZISPASSWORDPROTECTED")}, 'shared', ${notNull("n", "ZSERVERSHAREDATA")}, 'snippet', ${col2(available, "n", "ZSNIPPET")}, 'data', ${dataExpr}, 'tags', ${tagsExpr}) FROM ZICCLOUDSYNCINGOBJECT n WHERE ${whereSql} ORDER BY n.ZMODIFICATIONDATE1 DESC, n.Z_PK DESC LIMIT ${scan};`;
|
|
45678
46082
|
return [
|
|
45679
46083
|
"BEGIN;",
|
|
45680
46084
|
"SELECT json_object('k', 'meta', 'uuid', (SELECT Z_UUID FROM Z_METADATA LIMIT 1));",
|
|
@@ -45686,7 +46090,7 @@ function buildScanSql(available, options) {
|
|
|
45686
46090
|
].join(" ");
|
|
45687
46091
|
}
|
|
45688
46092
|
function runSqlite6(dbPath2, query) {
|
|
45689
|
-
return
|
|
46093
|
+
return execFileSync12("sqlite3", ["-readonly", dbPath2, query], {
|
|
45690
46094
|
encoding: "utf8",
|
|
45691
46095
|
timeout: 3e4,
|
|
45692
46096
|
maxBuffer: 512 * 1024 * 1024,
|
|
@@ -45705,32 +46109,32 @@ var escapeSegment = escapeFolderName;
|
|
|
45705
46109
|
function resolveFolders(rows) {
|
|
45706
46110
|
const byPk = new Map(rows.map((row) => [row.pk, row]));
|
|
45707
46111
|
const resolved = /* @__PURE__ */ new Map();
|
|
45708
|
-
const
|
|
46112
|
+
const resolve5 = (pk, seen) => {
|
|
45709
46113
|
const cached2 = resolved.get(pk);
|
|
45710
46114
|
if (cached2) return cached2;
|
|
45711
46115
|
const row = byPk.get(pk);
|
|
45712
46116
|
if (!row || seen.has(pk)) return void 0;
|
|
45713
46117
|
seen.add(pk);
|
|
45714
|
-
const parent = row.parent !== null ?
|
|
46118
|
+
const parent = row.parent !== null ? resolve5(row.parent, seen) : void 0;
|
|
45715
46119
|
const name = row.name ?? "";
|
|
45716
|
-
const
|
|
46120
|
+
const path8 = parent ? `${parent.path}/${escapeSegment(name)}` : escapeSegment(name);
|
|
45717
46121
|
const plainPath = parent ? `${parent.plainPath}/${name}` : name;
|
|
45718
46122
|
const info = {
|
|
45719
|
-
path:
|
|
46123
|
+
path: path8,
|
|
45720
46124
|
plainPath,
|
|
45721
|
-
keys: [...new Set([name, plainPath,
|
|
46125
|
+
keys: [...new Set([name, plainPath, path8].map(normalizeForMatch))],
|
|
45722
46126
|
accountPk: row.owner ?? parent?.accountPk ?? null,
|
|
45723
46127
|
shared: Boolean(row.shared) || Boolean(parent?.shared)
|
|
45724
46128
|
};
|
|
45725
46129
|
resolved.set(pk, info);
|
|
45726
46130
|
return info;
|
|
45727
46131
|
};
|
|
45728
|
-
for (const row of rows)
|
|
46132
|
+
for (const row of rows) resolve5(row.pk, /* @__PURE__ */ new Set());
|
|
45729
46133
|
return resolved;
|
|
45730
46134
|
}
|
|
45731
|
-
var coreDataMs = (seconds) => seconds === null || !Number.isFinite(seconds) ? void 0 :
|
|
45732
|
-
function buildSnippet(
|
|
45733
|
-
const clean =
|
|
46135
|
+
var coreDataMs = (seconds) => seconds === null || !Number.isFinite(seconds) ? void 0 : CORE_DATA_EPOCH_MS2 + seconds * 1e3;
|
|
46136
|
+
function buildSnippet(text2, terms) {
|
|
46137
|
+
const clean = text2.replace(/\ufffc/gu, " ");
|
|
45734
46138
|
const firstBreak = clean.indexOf("\n");
|
|
45735
46139
|
const body = firstBreak === -1 ? clean : clean.slice(firstBreak + 1);
|
|
45736
46140
|
const lower = normalizeForMatch(body);
|
|
@@ -45750,8 +46154,8 @@ function queryNotes(expression, options = {}) {
|
|
|
45750
46154
|
const includeDeleted = options.includeDeleted ?? false;
|
|
45751
46155
|
const withBodies = needsContent(ast);
|
|
45752
46156
|
const withTags = needsTags(ast);
|
|
45753
|
-
const dbPath2 = options.dbPath ??
|
|
45754
|
-
if (!
|
|
46157
|
+
const dbPath2 = options.dbPath ?? NOTES_DB_PATH8;
|
|
46158
|
+
if (!fs7.existsSync(dbPath2)) throw new NoteQueryStoreError(QUERY_FDA_MESSAGE, "no_fda");
|
|
45755
46159
|
let output;
|
|
45756
46160
|
try {
|
|
45757
46161
|
const available = presentColumns2(dbPath2);
|
|
@@ -45811,7 +46215,7 @@ function queryNotes(expression, options = {}) {
|
|
|
45811
46215
|
try {
|
|
45812
46216
|
decoded = decodeNoteBody(
|
|
45813
46217
|
new Uint8Array(
|
|
45814
|
-
|
|
46218
|
+
gunzipSync7(Buffer.from(row.data, "hex"), { maxOutputLength: 32 * 1024 * 1024 })
|
|
45815
46219
|
)
|
|
45816
46220
|
);
|
|
45817
46221
|
} catch {
|
|
@@ -45833,8 +46237,8 @@ function queryNotes(expression, options = {}) {
|
|
|
45833
46237
|
if (content !== void 0) return content;
|
|
45834
46238
|
const body2 = decode2();
|
|
45835
46239
|
if (!body2) return content = null;
|
|
45836
|
-
const
|
|
45837
|
-
const firstBreak =
|
|
46240
|
+
const text2 = body2.text;
|
|
46241
|
+
const firstBreak = text2.indexOf("\n");
|
|
45838
46242
|
const tags = /* @__PURE__ */ new Set();
|
|
45839
46243
|
for (const [id2, alt] of row.tags ?? []) {
|
|
45840
46244
|
if (id2 && alt && body2.objectIds.has(id2))
|
|
@@ -45843,9 +46247,9 @@ function queryNotes(expression, options = {}) {
|
|
|
45843
46247
|
const facets = new Set(body2.facets);
|
|
45844
46248
|
if (tags.size) facets.add("tag");
|
|
45845
46249
|
content = {
|
|
45846
|
-
textLower: normalizeForMatch(
|
|
45847
|
-
bodyLower: normalizeForMatch(firstBreak === -1 ? "" :
|
|
45848
|
-
words: countWords(
|
|
46250
|
+
textLower: normalizeForMatch(text2),
|
|
46251
|
+
bodyLower: normalizeForMatch(firstBreak === -1 ? "" : text2.slice(firstBreak + 1)),
|
|
46252
|
+
words: countWords(text2),
|
|
45849
46253
|
facets,
|
|
45850
46254
|
checklist: body2.checklist,
|
|
45851
46255
|
tags: [...tags]
|
|
@@ -45886,10 +46290,10 @@ function queryNotes(expression, options = {}) {
|
|
|
45886
46290
|
import { spawnSync } from "child_process";
|
|
45887
46291
|
|
|
45888
46292
|
// src/services/nativeTags.ts
|
|
45889
|
-
import { execFileSync as
|
|
46293
|
+
import { execFileSync as execFileSync13 } from "node:child_process";
|
|
45890
46294
|
import { mkdtempSync as mkdtempSync2, writeFileSync, rmSync as rmSync2 } from "node:fs";
|
|
45891
46295
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
45892
|
-
import { join as
|
|
46296
|
+
import { join as join14 } from "node:path";
|
|
45893
46297
|
|
|
45894
46298
|
// src/services/shortcutConsent.ts
|
|
45895
46299
|
function shortcutConsentHint(shortcut) {
|
|
@@ -45943,12 +46347,12 @@ function addNativeTags(request, deps) {
|
|
|
45943
46347
|
}
|
|
45944
46348
|
const after = deps.read(request.id);
|
|
45945
46349
|
const allTags = [.../* @__PURE__ */ new Set([...before.rich.nativeTags, ...tags])];
|
|
45946
|
-
const textWithoutTags = (
|
|
46350
|
+
const textWithoutTags = (text2) => {
|
|
45947
46351
|
for (const tag of [...allTags].sort((a, b) => b.length - a.length)) {
|
|
45948
46352
|
const escaped = tag.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
45949
|
-
|
|
46353
|
+
text2 = text2.replace(new RegExp(`#${escaped}(?![\\p{L}\\p{N}_-])`, "gu"), "");
|
|
45950
46354
|
}
|
|
45951
|
-
return
|
|
46355
|
+
return text2.replace(/[\s\ufffc]/gu, "");
|
|
45952
46356
|
};
|
|
45953
46357
|
if (after.title !== before.title || allTags.some((tag) => !after.rich.nativeTags.includes(tag)) || textWithoutTags(before.rich.text) !== textWithoutTags(after.rich.text) || linkSignature(before.rich.links) !== linkSignature(after.rich.links) || before.rich.nativeObjectIds.some((id2) => !after.rich.nativeObjectIds.includes(id2)) || before.rich.hasChecklist !== after.rich.hasChecklist) {
|
|
45954
46358
|
throw new Error(
|
|
@@ -45965,7 +46369,7 @@ function addNativeTags(request, deps) {
|
|
|
45965
46369
|
};
|
|
45966
46370
|
}
|
|
45967
46371
|
function listInstalledShortcuts() {
|
|
45968
|
-
return
|
|
46372
|
+
return execFileSync13("/usr/bin/shortcuts", ["list", "--show-identifiers"], {
|
|
45969
46373
|
encoding: "utf8",
|
|
45970
46374
|
timeout: 15e3,
|
|
45971
46375
|
maxBuffer: 1024 * 1024,
|
|
@@ -45991,11 +46395,11 @@ function runNativeTagsShortcut(input) {
|
|
|
45991
46395
|
const status = nativeTagsStatus();
|
|
45992
46396
|
if (!status.installed)
|
|
45993
46397
|
throw new Error(`Import the supplied ${status.shortcut}.shortcut in Shortcuts first`);
|
|
45994
|
-
const directory = mkdtempSync2(
|
|
46398
|
+
const directory = mkdtempSync2(join14(tmpdir2(), "apple-notes-native-tags-"));
|
|
45995
46399
|
try {
|
|
45996
|
-
const
|
|
45997
|
-
writeFileSync(
|
|
45998
|
-
|
|
46400
|
+
const path8 = join14(directory, "request.json");
|
|
46401
|
+
writeFileSync(path8, JSON.stringify(input), { mode: 384 });
|
|
46402
|
+
execFileSync13("/usr/bin/shortcuts", ["run", status.identifier, "--input-path", path8], {
|
|
45999
46403
|
encoding: "utf8",
|
|
46000
46404
|
timeout: 6e4,
|
|
46001
46405
|
maxBuffer: 1024 * 1024,
|
|
@@ -46014,10 +46418,10 @@ function runNativeTagsShortcut(input) {
|
|
|
46014
46418
|
}
|
|
46015
46419
|
|
|
46016
46420
|
// src/services/backgroundNotes.ts
|
|
46017
|
-
import { execFileSync as
|
|
46421
|
+
import { execFileSync as execFileSync14 } from "node:child_process";
|
|
46018
46422
|
import { mkdtempSync as mkdtempSync3, writeFileSync as writeFileSync2, rmSync as rmSync3 } from "node:fs";
|
|
46019
46423
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
46020
|
-
import { join as
|
|
46424
|
+
import { join as join15 } from "node:path";
|
|
46021
46425
|
|
|
46022
46426
|
// src/utils/appendMarkdown.ts
|
|
46023
46427
|
var escape2 = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
@@ -46069,9 +46473,9 @@ function renderMarkdown(markdown, options = {}) {
|
|
|
46069
46473
|
dividers: 0,
|
|
46070
46474
|
highlights: []
|
|
46071
46475
|
};
|
|
46072
|
-
const inline = (
|
|
46476
|
+
const inline = (text2) => {
|
|
46073
46477
|
const spans = [];
|
|
46074
|
-
let value =
|
|
46478
|
+
let value = text2;
|
|
46075
46479
|
if (blocks)
|
|
46076
46480
|
value = value.replace(/`([^`\n]+)`/g, (_s, code2) => {
|
|
46077
46481
|
if (/^\s|\s$/.test(code2)) throw new Error("Inline code cannot start or end with a space");
|
|
@@ -46093,13 +46497,13 @@ function renderMarkdown(markdown, options = {}) {
|
|
|
46093
46497
|
return value.replace(/(\d+)/g, (_s, i) => links[Number(i)]).replace(/(\d+)/g, (_s, i) => spans[Number(i)]);
|
|
46094
46498
|
};
|
|
46095
46499
|
const withoutTags = (html2) => {
|
|
46096
|
-
let
|
|
46500
|
+
let text2 = "", inTag = false;
|
|
46097
46501
|
for (const ch of html2) {
|
|
46098
46502
|
if (ch === "<") inTag = true;
|
|
46099
46503
|
else if (ch === ">" && inTag) inTag = false;
|
|
46100
|
-
else if (!inTag)
|
|
46504
|
+
else if (!inTag) text2 += ch;
|
|
46101
46505
|
}
|
|
46102
|
-
return
|
|
46506
|
+
return text2;
|
|
46103
46507
|
};
|
|
46104
46508
|
const visible = (html2) => withoutTags(html2).replace(/"/g, '"').replace(/</g, "<").replace(/>/g, ">").replace(/&/g, "&");
|
|
46105
46509
|
let html = "", list, quote = false, code, previousBlank = true;
|
|
@@ -46136,9 +46540,9 @@ function renderMarkdown(markdown, options = {}) {
|
|
|
46136
46540
|
continue;
|
|
46137
46541
|
}
|
|
46138
46542
|
if (line.startsWith(">")) {
|
|
46139
|
-
const
|
|
46140
|
-
if (!
|
|
46141
|
-
if (/^(?:#|[-+*][ \t]|\d+[.)][ \t]|>|```)/.test(
|
|
46543
|
+
const text2 = line.replace(/^> ?/, "");
|
|
46544
|
+
if (!text2.trim()) throw new Error("Empty block quote lines are unsupported");
|
|
46545
|
+
if (/^(?:#|[-+*][ \t]|\d+[.)][ \t]|>|```)/.test(text2))
|
|
46142
46546
|
throw new Error("Block quotes support text and inline formatting only");
|
|
46143
46547
|
if (!quote) {
|
|
46144
46548
|
close();
|
|
@@ -46146,7 +46550,7 @@ function renderMarkdown(markdown, options = {}) {
|
|
|
46146
46550
|
quote = true;
|
|
46147
46551
|
expect.quotes.push("");
|
|
46148
46552
|
}
|
|
46149
|
-
const rendered = inline(
|
|
46553
|
+
const rendered = inline(text2);
|
|
46150
46554
|
html += `<div>${rendered}</div>`;
|
|
46151
46555
|
expect.quotes[expect.quotes.length - 1] += ` ${visible(rendered)}`;
|
|
46152
46556
|
previousBlank = false;
|
|
@@ -46342,9 +46746,9 @@ function runBackgroundShortcut(input, status = backgroundStatus()) {
|
|
|
46342
46746
|
throw new Error(
|
|
46343
46747
|
`Install the supplied "${status.shortcut}" Shortcut once; Shortcuts must list it exactly once`
|
|
46344
46748
|
);
|
|
46345
|
-
const directory = mkdtempSync3(
|
|
46749
|
+
const directory = mkdtempSync3(join15(tmpdir3(), "apple-notes-background-"));
|
|
46346
46750
|
try {
|
|
46347
|
-
const file =
|
|
46751
|
+
const file = join15(directory, "request.json");
|
|
46348
46752
|
writeFileSync2(
|
|
46349
46753
|
file,
|
|
46350
46754
|
JSON.stringify({
|
|
@@ -46364,7 +46768,7 @@ function runBackgroundShortcut(input, status = backgroundStatus()) {
|
|
|
46364
46768
|
{ mode: 384 }
|
|
46365
46769
|
);
|
|
46366
46770
|
try {
|
|
46367
|
-
|
|
46771
|
+
execFileSync14("/usr/bin/shortcuts", ["run", status.identifier, "--input-path", file], {
|
|
46368
46772
|
encoding: "utf8",
|
|
46369
46773
|
timeout: callTimeoutMs() ?? 6e4,
|
|
46370
46774
|
maxBuffer: 1024 * 1024,
|
|
@@ -46507,11 +46911,11 @@ function appendNative(manager, request) {
|
|
|
46507
46911
|
throw new Error("Use create-table for verified native table insertion");
|
|
46508
46912
|
const markdownHtml = request.format === "markdown" ? appendMarkdownHtml(request.content) : null;
|
|
46509
46913
|
const op = request.format === "plaintext" ? "append-text" : request.format === "markdown" ? "append-markdown" : "append-html";
|
|
46510
|
-
const
|
|
46914
|
+
const text2 = request.format === "html" ? "<div><br></div>" + request.content : "\n\n" + request.content;
|
|
46511
46915
|
return mutateBackground(
|
|
46512
46916
|
request,
|
|
46513
46917
|
op,
|
|
46514
|
-
{ text },
|
|
46918
|
+
{ text: text2 },
|
|
46515
46919
|
(before, after) => {
|
|
46516
46920
|
assertPreserved(before, after, { append: true });
|
|
46517
46921
|
const verifyHtml = markdownHtml ?? request.content;
|
|
@@ -46551,7 +46955,7 @@ function setNativeTag(manager, request) {
|
|
|
46551
46955
|
deps
|
|
46552
46956
|
);
|
|
46553
46957
|
}
|
|
46554
|
-
var literalMarkdown = (
|
|
46958
|
+
var literalMarkdown = (text2) => text2.replace(/[!-/:-@[-`{-~]/g, "\\$&");
|
|
46555
46959
|
function headingLevels(html) {
|
|
46556
46960
|
return [...html.matchAll(/<h([1-3])\b[^>]*>([\s\S]*?)<\/h\1>/gi)].filter((match) => comparableVisibleText(match[2])).map((match) => Number(match[1]));
|
|
46557
46961
|
}
|
|
@@ -46599,7 +47003,7 @@ function createMarkdownNote(manager, request, run = runBackgroundShortcut) {
|
|
|
46599
47003
|
throw new Error(
|
|
46600
47004
|
`Install the supplied "${status.shortcut}" Shortcut once; Shortcuts must list it exactly once`
|
|
46601
47005
|
);
|
|
46602
|
-
const segments = (
|
|
47006
|
+
const segments = (path8) => JSON.stringify(splitFolderPath(path8).map((part) => part.toLocaleLowerCase()));
|
|
46603
47007
|
if (request.folder) {
|
|
46604
47008
|
const wanted = segments(request.folder);
|
|
46605
47009
|
if (!manager.listAccounts().some(
|
|
@@ -46689,7 +47093,7 @@ ${request.content}`
|
|
|
46689
47093
|
}
|
|
46690
47094
|
|
|
46691
47095
|
// src/services/capabilityMatrix.ts
|
|
46692
|
-
import { execFileSync as
|
|
47096
|
+
import { execFileSync as execFileSync15 } from "node:child_process";
|
|
46693
47097
|
import { release } from "node:os";
|
|
46694
47098
|
var MACOS_SHORTCUTS_CLI = "12.0";
|
|
46695
47099
|
var MACOS_MARKDOWN_IMPORT = "26.0";
|
|
@@ -46896,7 +47300,7 @@ function evaluateFeatures(env, features = FEATURES) {
|
|
|
46896
47300
|
function readMacOSVersion() {
|
|
46897
47301
|
if (process.platform !== "darwin") return null;
|
|
46898
47302
|
try {
|
|
46899
|
-
const out =
|
|
47303
|
+
const out = execFileSync15("/usr/bin/sw_vers", ["-productVersion"], {
|
|
46900
47304
|
encoding: "utf8",
|
|
46901
47305
|
timeout: 3e3,
|
|
46902
47306
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -46929,9 +47333,9 @@ function getCapabilityMatrix(probe = probeCapabilityEnvironment) {
|
|
|
46929
47333
|
return evaluateFeatures(probe());
|
|
46930
47334
|
}
|
|
46931
47335
|
function formatCapabilityMatrix(matrix) {
|
|
46932
|
-
const
|
|
47336
|
+
const os8 = matrix.runtimeOS;
|
|
46933
47337
|
const lines = [
|
|
46934
|
-
`Feature matrix (macOS ${
|
|
47338
|
+
`Feature matrix (macOS ${os8.macOSVersion ?? "unknown"}, Darwin ${os8.darwinRelease}):`
|
|
46935
47339
|
];
|
|
46936
47340
|
for (const [name, status] of Object.entries(matrix.features)) {
|
|
46937
47341
|
lines.push(
|
|
@@ -47049,19 +47453,19 @@ function formatDoctorReport(r) {
|
|
|
47049
47453
|
}
|
|
47050
47454
|
|
|
47051
47455
|
// src/services/fileConfig.ts
|
|
47052
|
-
import { existsSync as
|
|
47053
|
-
import { join as
|
|
47054
|
-
import { homedir as
|
|
47456
|
+
import { existsSync as existsSync10, readFileSync as readFileSync2 } from "fs";
|
|
47457
|
+
import { join as join16 } from "path";
|
|
47458
|
+
import { homedir as homedir13 } from "os";
|
|
47055
47459
|
function fileConfigPath(env = process.env) {
|
|
47056
47460
|
const override = env.APPLE_NOTES_MCP_CONFIG_FILE;
|
|
47057
47461
|
if (override && override.trim()) return override.trim();
|
|
47058
|
-
return
|
|
47462
|
+
return join16(homedir13(), "Library", "Application Support", "apple-notes-mcp", "config.json");
|
|
47059
47463
|
}
|
|
47060
|
-
function loadFileConfig(env = process.env,
|
|
47464
|
+
function loadFileConfig(env = process.env, path8 = fileConfigPath(env)) {
|
|
47061
47465
|
const applied = [];
|
|
47062
47466
|
try {
|
|
47063
|
-
if (!
|
|
47064
|
-
const parsed = JSON.parse(readFileSync2(
|
|
47467
|
+
if (!existsSync10(path8)) return applied;
|
|
47468
|
+
const parsed = JSON.parse(readFileSync2(path8, "utf8"));
|
|
47065
47469
|
if (!parsed || typeof parsed !== "object") return applied;
|
|
47066
47470
|
for (const [k, v] of Object.entries(parsed)) {
|
|
47067
47471
|
if (typeof v !== "string") continue;
|
|
@@ -47071,7 +47475,7 @@ function loadFileConfig(env = process.env, path7 = fileConfigPath(env)) {
|
|
|
47071
47475
|
}
|
|
47072
47476
|
}
|
|
47073
47477
|
} catch (e) {
|
|
47074
|
-
console.error(`Failed to load apple-notes-mcp config file ${
|
|
47478
|
+
console.error(`Failed to load apple-notes-mcp config file ${path8}: ${String(e)}`);
|
|
47075
47479
|
}
|
|
47076
47480
|
return applied;
|
|
47077
47481
|
}
|
|
@@ -47308,18 +47712,18 @@ var NOTHING_WRITTEN = /nothing (?:was )?(?:changed|created|written)|no replaceme
|
|
|
47308
47712
|
var WRITE_ACCEPTED = /\baccepted (?:the|an) \w+, but/i;
|
|
47309
47713
|
function classifyError(message, cause) {
|
|
47310
47714
|
if (cause instanceof CodedError) return { ...cause.envelope };
|
|
47311
|
-
const
|
|
47715
|
+
const text2 = cause instanceof Error && cause.message && !message.includes(cause.message) ? `${message}
|
|
47312
47716
|
${cause.message}` : message;
|
|
47313
47717
|
const timeoutCause = typeof cause === "object" && cause !== null && cause.code === "ETIMEDOUT";
|
|
47314
47718
|
let code = "operation_failed";
|
|
47315
47719
|
if (timeoutCause) code = "timeout_indeterminate";
|
|
47316
|
-
else if (isPermissionDenied(
|
|
47317
|
-
else code = RULES.find((rule) => rule.pattern.test(
|
|
47720
|
+
else if (isPermissionDenied(text2)) code = "permission_denied";
|
|
47721
|
+
else code = RULES.find((rule) => rule.pattern.test(text2))?.code ?? "operation_failed";
|
|
47318
47722
|
const envelope = { code };
|
|
47319
47723
|
if (code === "timeout_indeterminate" || code === "verification_failed") {
|
|
47320
47724
|
envelope.indeterminate = true;
|
|
47321
|
-
if (WRITE_ACCEPTED.test(
|
|
47322
|
-
} else if (code === "revision_conflict" || NOTHING_WRITTEN.test(
|
|
47725
|
+
if (WRITE_ACCEPTED.test(text2)) envelope.committed = true;
|
|
47726
|
+
} else if (code === "revision_conflict" || NOTHING_WRITTEN.test(text2)) {
|
|
47323
47727
|
envelope.committed = false;
|
|
47324
47728
|
envelope.indeterminate = false;
|
|
47325
47729
|
}
|
|
@@ -47358,11 +47762,11 @@ function createShutdown(stream, exit, timeoutMs = SHUTDOWN_DRAIN_TIMEOUT_MS) {
|
|
|
47358
47762
|
}
|
|
47359
47763
|
|
|
47360
47764
|
// src/utils/noteBlocks.ts
|
|
47361
|
-
import { execFileSync as
|
|
47362
|
-
import { existsSync as
|
|
47363
|
-
import { homedir as
|
|
47364
|
-
import { join as
|
|
47365
|
-
import { gunzipSync as
|
|
47765
|
+
import { execFileSync as execFileSync16 } from "node:child_process";
|
|
47766
|
+
import { existsSync as existsSync11 } from "node:fs";
|
|
47767
|
+
import { homedir as homedir14 } from "node:os";
|
|
47768
|
+
import { join as join17 } from "node:path";
|
|
47769
|
+
import { gunzipSync as gunzipSync8 } from "node:zlib";
|
|
47366
47770
|
var NoteBlocksError = class extends Error {
|
|
47367
47771
|
code;
|
|
47368
47772
|
constructor(code, message) {
|
|
@@ -47509,7 +47913,7 @@ function decodeNoteBlocks(data) {
|
|
|
47509
47913
|
const textBytes = note && bytesOf(note, 2);
|
|
47510
47914
|
if (!note || !textBytes)
|
|
47511
47915
|
throw new NoteBlocksError("unsupported-structure", "Unsupported Notes document structure");
|
|
47512
|
-
const
|
|
47916
|
+
const text2 = utf8.decode(textBytes);
|
|
47513
47917
|
const runTally = /* @__PURE__ */ new Map();
|
|
47514
47918
|
const paragraphTally = /* @__PURE__ */ new Map();
|
|
47515
47919
|
const runs = [];
|
|
@@ -47520,7 +47924,7 @@ function decodeNoteBlocks(data) {
|
|
|
47520
47924
|
throw new NoteBlocksError("invalid-runs", "Invalid Notes attribute run");
|
|
47521
47925
|
const fields = decodeWireFields(field.bytes);
|
|
47522
47926
|
const length = varintOf(fields, 1);
|
|
47523
|
-
if (length === void 0 || length < 0 || position + length >
|
|
47927
|
+
if (length === void 0 || length < 0 || position + length > text2.length)
|
|
47524
47928
|
throw new NoteBlocksError("invalid-runs", "Invalid Notes run length");
|
|
47525
47929
|
for (const n of new Set(fields.map((f) => f.fieldNumber)))
|
|
47526
47930
|
if (!KNOWN_RUN_FIELDS.has(n)) runTally.set(n, (runTally.get(n) || 0) + 1);
|
|
@@ -47535,15 +47939,15 @@ function decodeNoteBlocks(data) {
|
|
|
47535
47939
|
} catch (error2) {
|
|
47536
47940
|
wrap(error2);
|
|
47537
47941
|
}
|
|
47538
|
-
if (position !==
|
|
47942
|
+
if (position !== text2.length)
|
|
47539
47943
|
throw new NoteBlocksError("invalid-runs", "Incomplete Notes attribute runs");
|
|
47540
47944
|
const blocks = [];
|
|
47541
47945
|
const attachments = [];
|
|
47542
47946
|
let runIndex = 0;
|
|
47543
47947
|
let paragraphStart = 0;
|
|
47544
|
-
while (paragraphStart <
|
|
47545
|
-
const newline =
|
|
47546
|
-
const end = newline === -1 ?
|
|
47948
|
+
while (paragraphStart < text2.length) {
|
|
47949
|
+
const newline = text2.indexOf("\n", paragraphStart);
|
|
47950
|
+
const end = newline === -1 ? text2.length : newline;
|
|
47547
47951
|
while (runIndex < runs.length - 1 && runs[runIndex].start + runs[runIndex].length <= paragraphStart)
|
|
47548
47952
|
runIndex++;
|
|
47549
47953
|
const attrs = runs[runIndex]?.paragraph ?? DEFAULT_PARAGRAPH;
|
|
@@ -47553,7 +47957,7 @@ function decodeNoteBlocks(data) {
|
|
|
47553
47957
|
index: blocks.length,
|
|
47554
47958
|
start: paragraphStart,
|
|
47555
47959
|
length: end - paragraphStart,
|
|
47556
|
-
text:
|
|
47960
|
+
text: text2.slice(paragraphStart, end),
|
|
47557
47961
|
style,
|
|
47558
47962
|
styleType: attrs.styleType,
|
|
47559
47963
|
indent: attrs.indent,
|
|
@@ -47573,11 +47977,11 @@ function decodeNoteBlocks(data) {
|
|
|
47573
47977
|
block.runs.push({
|
|
47574
47978
|
start,
|
|
47575
47979
|
length: stop - start,
|
|
47576
|
-
text:
|
|
47980
|
+
text: text2.slice(start, stop),
|
|
47577
47981
|
...run.inline
|
|
47578
47982
|
});
|
|
47579
47983
|
if (run.inline.attachment)
|
|
47580
|
-
for (let at =
|
|
47984
|
+
for (let at = text2.indexOf("\uFFFC", start); at !== -1 && at < stop; at = text2.indexOf("\uFFFC", at + 1)) {
|
|
47581
47985
|
const marker = { ...run.inline.attachment, start: at, blockIndex: block.index };
|
|
47582
47986
|
block.attachments.push(marker);
|
|
47583
47987
|
attachments.push(marker);
|
|
@@ -47587,8 +47991,8 @@ function decodeNoteBlocks(data) {
|
|
|
47587
47991
|
paragraphStart = end + 1;
|
|
47588
47992
|
}
|
|
47589
47993
|
return {
|
|
47590
|
-
text,
|
|
47591
|
-
textLength:
|
|
47994
|
+
text: text2,
|
|
47995
|
+
textLength: text2.length,
|
|
47592
47996
|
blocks,
|
|
47593
47997
|
attachments,
|
|
47594
47998
|
undecodedFields: {
|
|
@@ -47650,7 +48054,7 @@ function summarize(blocks, attachments) {
|
|
|
47650
48054
|
function decodeCompressedNoteBlocks(compressed) {
|
|
47651
48055
|
let data;
|
|
47652
48056
|
try {
|
|
47653
|
-
data =
|
|
48057
|
+
data = gunzipSync8(compressed, { maxOutputLength: 32 * 1024 * 1024 });
|
|
47654
48058
|
} catch (error2) {
|
|
47655
48059
|
throw new NoteBlocksError(
|
|
47656
48060
|
"decompress-failed",
|
|
@@ -47704,23 +48108,23 @@ function pageNoteBlocks(doc, { offset = 0, limit = 500, maxBytes = blocksMaxResp
|
|
|
47704
48108
|
undecodedFields: doc.undecodedFields
|
|
47705
48109
|
};
|
|
47706
48110
|
}
|
|
47707
|
-
var
|
|
47708
|
-
|
|
48111
|
+
var NOTES_DB_PATH9 = join17(
|
|
48112
|
+
homedir14(),
|
|
47709
48113
|
"Library/Group Containers/group.com.apple.notes/NoteStore.sqlite"
|
|
47710
48114
|
);
|
|
47711
|
-
function readNoteBlocks(id2, { dbPath: dbPath2 =
|
|
48115
|
+
function readNoteBlocks(id2, { dbPath: dbPath2 = NOTES_DB_PATH9 } = {}) {
|
|
47712
48116
|
const pk = /^x-coredata:\/\/[0-9a-f-]+\/ICNote\/p([0-9]{1,18})$/i.exec(id2)?.[1];
|
|
47713
48117
|
if (!pk)
|
|
47714
48118
|
throw new NoteBlocksError(
|
|
47715
48119
|
"invalid-id",
|
|
47716
48120
|
`Invalid note ID: expected x-coredata://<store>/ICNote/p<number>`
|
|
47717
48121
|
);
|
|
47718
|
-
if (!
|
|
48122
|
+
if (!existsSync11(dbPath2))
|
|
47719
48123
|
throw new NoteBlocksError("no-full-disk-access", "The Notes database is not readable");
|
|
47720
48124
|
const sql = "SELECT json_object('exists', (SELECT count(*) FROM ZICCLOUDSYNCINGOBJECT WHERE Z_PK = @pk AND Z_ENT = (SELECT Z_ENT FROM Z_PRIMARYKEY WHERE Z_NAME = 'ICNote')), 'data', (SELECT hex(ZDATA) FROM ZICNOTEDATA WHERE ZNOTE = @pk), 'encrypted', (SELECT ZCRYPTOINITIALIZATIONVECTOR IS NOT NULL FROM ZICNOTEDATA WHERE ZNOTE = @pk));";
|
|
47721
48125
|
let output;
|
|
47722
48126
|
try {
|
|
47723
|
-
output =
|
|
48127
|
+
output = execFileSync16(
|
|
47724
48128
|
"/usr/bin/sqlite3",
|
|
47725
48129
|
["-readonly", "-cmd", ".parameter init", "-cmd", `.parameter set @pk ${pk}`, dbPath2, sql],
|
|
47726
48130
|
{
|
|
@@ -47778,7 +48182,7 @@ function validateLinkLabel(label) {
|
|
|
47778
48182
|
throw new Error("Hyperlink label must be one line without control characters");
|
|
47779
48183
|
return label;
|
|
47780
48184
|
}
|
|
47781
|
-
var escapeText = (
|
|
48185
|
+
var escapeText = (text2) => text2.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
47782
48186
|
var escapeHref = (url) => escapeText(url).replace(/"/g, """);
|
|
47783
48187
|
function buildLinkInsertion(request) {
|
|
47784
48188
|
const url = validateLinkUrl(request.url);
|
|
@@ -47868,20 +48272,1068 @@ function insertLink(request, deps) {
|
|
|
47868
48272
|
};
|
|
47869
48273
|
}
|
|
47870
48274
|
|
|
47871
|
-
// src/
|
|
47872
|
-
import {
|
|
48275
|
+
// src/services/notesExport.ts
|
|
48276
|
+
import { mkdirSync as mkdirSync5 } from "node:fs";
|
|
48277
|
+
import { dirname as dirname4 } from "node:path";
|
|
48278
|
+
|
|
48279
|
+
// src/utils/exportAssets.ts
|
|
47873
48280
|
import {
|
|
47874
48281
|
closeSync as closeSync4,
|
|
47875
48282
|
constants as constants4,
|
|
47876
48283
|
fstatSync as fstatSync4,
|
|
47877
|
-
|
|
48284
|
+
mkdirSync as mkdirSync4,
|
|
47878
48285
|
openSync as openSync4,
|
|
48286
|
+
readdirSync as readdirSync3,
|
|
48287
|
+
readSync as readSync3,
|
|
48288
|
+
realpathSync as realpathSync3,
|
|
48289
|
+
statSync as statSync3,
|
|
48290
|
+
writeSync as writeSync3
|
|
48291
|
+
} from "node:fs";
|
|
48292
|
+
import { homedir as homedir15 } from "node:os";
|
|
48293
|
+
import { basename as basename3, extname as extname3, join as join18, relative as relative3, resolve as resolve3, sep as sep3 } from "node:path";
|
|
48294
|
+
var NOTES_CONTAINER = join18(homedir15(), "Library/Group Containers/group.com.apple.notes");
|
|
48295
|
+
var MAX_EMBED_BYTES = 10 * 1024 * 1024;
|
|
48296
|
+
var MAX_DIRECTORY_ENTRIES = 2e4;
|
|
48297
|
+
var MAX_BUNDLE_ENTRIES2 = 64;
|
|
48298
|
+
var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".heic", ".gif", ".tiff", ".webp"]);
|
|
48299
|
+
function safeComponent2(value) {
|
|
48300
|
+
if (!value || value.length > 255) return void 0;
|
|
48301
|
+
if (value === "." || value === ".." || /[/\\\0]/.test(value)) return void 0;
|
|
48302
|
+
return value;
|
|
48303
|
+
}
|
|
48304
|
+
function confine(candidate, root) {
|
|
48305
|
+
try {
|
|
48306
|
+
const real = realpathSync3.native(candidate);
|
|
48307
|
+
return real.startsWith(root + sep3) ? real : void 0;
|
|
48308
|
+
} catch {
|
|
48309
|
+
return void 0;
|
|
48310
|
+
}
|
|
48311
|
+
}
|
|
48312
|
+
function listDirectory(dir, limit) {
|
|
48313
|
+
try {
|
|
48314
|
+
const names = readdirSync3(dir);
|
|
48315
|
+
return names.length > limit ? [] : names.sort();
|
|
48316
|
+
} catch {
|
|
48317
|
+
return [];
|
|
48318
|
+
}
|
|
48319
|
+
}
|
|
48320
|
+
function isFile(path8) {
|
|
48321
|
+
let fd;
|
|
48322
|
+
try {
|
|
48323
|
+
fd = openSync4(path8, constants4.O_RDONLY | constants4.O_NOFOLLOW);
|
|
48324
|
+
return fstatSync4(fd).isFile();
|
|
48325
|
+
} catch {
|
|
48326
|
+
return false;
|
|
48327
|
+
} finally {
|
|
48328
|
+
if (fd !== void 0) closeSync4(fd);
|
|
48329
|
+
}
|
|
48330
|
+
}
|
|
48331
|
+
function isDirectory2(path8) {
|
|
48332
|
+
try {
|
|
48333
|
+
return statSync3(path8).isDirectory();
|
|
48334
|
+
} catch {
|
|
48335
|
+
return false;
|
|
48336
|
+
}
|
|
48337
|
+
}
|
|
48338
|
+
function previewArea(name) {
|
|
48339
|
+
const sizes = [...name.matchAll(/-(\d{1,5})x(\d{1,5})(?=-|\.|$)/g)];
|
|
48340
|
+
const last = sizes[sizes.length - 1];
|
|
48341
|
+
return last ? Number(last[1]) * Number(last[2]) : 0;
|
|
48342
|
+
}
|
|
48343
|
+
var AssetLocator = class {
|
|
48344
|
+
accounts;
|
|
48345
|
+
previewIndex = /* @__PURE__ */ new Map();
|
|
48346
|
+
constructor(container = NOTES_CONTAINER) {
|
|
48347
|
+
let accountsRoot = "";
|
|
48348
|
+
try {
|
|
48349
|
+
accountsRoot = realpathSync3.native(join18(container, "Accounts"));
|
|
48350
|
+
} catch {
|
|
48351
|
+
}
|
|
48352
|
+
this.accounts = accountsRoot ? listDirectory(accountsRoot, 1e3).flatMap((name) => {
|
|
48353
|
+
const dir = safeComponent2(name) && confine(join18(accountsRoot, name), accountsRoot);
|
|
48354
|
+
return dir && isDirectory2(dir) ? [dir] : [];
|
|
48355
|
+
}) : [];
|
|
48356
|
+
}
|
|
48357
|
+
/** Canonical account directories found in the container. */
|
|
48358
|
+
get accountDirs() {
|
|
48359
|
+
return [...this.accounts];
|
|
48360
|
+
}
|
|
48361
|
+
/** The attachment's own file and its best preview, when present. */
|
|
48362
|
+
locate(source) {
|
|
48363
|
+
const id2 = safeComponent2(source.id);
|
|
48364
|
+
if (!id2) return {};
|
|
48365
|
+
for (const account of this.accounts) {
|
|
48366
|
+
const files = this.locateIn(account, id2, source);
|
|
48367
|
+
if (files.primary || files.preview) return files;
|
|
48368
|
+
}
|
|
48369
|
+
return {};
|
|
48370
|
+
}
|
|
48371
|
+
locateIn(account, id2, source) {
|
|
48372
|
+
const preview = this.preview(account, id2);
|
|
48373
|
+
const media = this.media(account, source);
|
|
48374
|
+
switch (source.kind) {
|
|
48375
|
+
case "drawing":
|
|
48376
|
+
case "paper": {
|
|
48377
|
+
const fallback = this.fallback(
|
|
48378
|
+
account,
|
|
48379
|
+
"FallbackImages",
|
|
48380
|
+
id2,
|
|
48381
|
+
source.fallbackImageGeneration,
|
|
48382
|
+
["FallbackImage.png", "FallbackImage.jpg"]
|
|
48383
|
+
);
|
|
48384
|
+
if (fallback)
|
|
48385
|
+
return { primary: { path: fallback, name: `${source.kind}.png`, role: "fallback" } };
|
|
48386
|
+
return preview ? { primary: preview } : {};
|
|
48387
|
+
}
|
|
48388
|
+
case "scan": {
|
|
48389
|
+
const pdf = this.fallback(account, "FallbackPDFs", id2, source.fallbackPdfGeneration, [
|
|
48390
|
+
"FallbackPDF.pdf"
|
|
48391
|
+
]);
|
|
48392
|
+
return {
|
|
48393
|
+
...pdf ? { primary: { path: pdf, name: "scan.pdf", role: "fallback" } } : {},
|
|
48394
|
+
...preview ? { preview } : {}
|
|
48395
|
+
};
|
|
48396
|
+
}
|
|
48397
|
+
case "link":
|
|
48398
|
+
return preview ? { preview } : {};
|
|
48399
|
+
default:
|
|
48400
|
+
return {
|
|
48401
|
+
...media ? { primary: media } : {},
|
|
48402
|
+
...preview ? { preview } : {}
|
|
48403
|
+
};
|
|
48404
|
+
}
|
|
48405
|
+
}
|
|
48406
|
+
/** Media/<media-id>/<generation>/<filename>, then without the generation. */
|
|
48407
|
+
media(account, source) {
|
|
48408
|
+
const mediaId = safeComponent2(source.mediaId);
|
|
48409
|
+
const filename = safeComponent2(source.mediaFilename);
|
|
48410
|
+
if (!mediaId || !filename) return void 0;
|
|
48411
|
+
const generation = safeComponent2(source.mediaGeneration);
|
|
48412
|
+
const candidates = [
|
|
48413
|
+
...generation ? [join18(account, "Media", mediaId, generation, filename)] : [],
|
|
48414
|
+
join18(account, "Media", mediaId, filename)
|
|
48415
|
+
];
|
|
48416
|
+
for (const candidate of candidates) {
|
|
48417
|
+
const path8 = confine(candidate, account);
|
|
48418
|
+
if (path8 && isFile(path8)) return { path: path8, name: filename, role: "original" };
|
|
48419
|
+
}
|
|
48420
|
+
return void 0;
|
|
48421
|
+
}
|
|
48422
|
+
/** <dir>/<id>/<generation>/<name>, <dir>/<id>/<name>, then any generation. */
|
|
48423
|
+
fallback(account, dir, id2, generation, names) {
|
|
48424
|
+
const base = join18(account, dir, id2);
|
|
48425
|
+
const gen = safeComponent2(generation);
|
|
48426
|
+
const generations = [
|
|
48427
|
+
...gen ? [gen] : [],
|
|
48428
|
+
"",
|
|
48429
|
+
...listDirectory(base, MAX_BUNDLE_ENTRIES2).filter((name) => name !== gen && safeComponent2(name)).reverse()
|
|
48430
|
+
];
|
|
48431
|
+
for (const g of generations)
|
|
48432
|
+
for (const name of names) {
|
|
48433
|
+
const path8 = confine(g ? join18(base, g, name) : join18(base, name), account);
|
|
48434
|
+
if (path8 && isFile(path8)) return path8;
|
|
48435
|
+
}
|
|
48436
|
+
return void 0;
|
|
48437
|
+
}
|
|
48438
|
+
/** The largest rendered preview image for an attachment. */
|
|
48439
|
+
preview(account, id2) {
|
|
48440
|
+
let index = this.previewIndex.get(account);
|
|
48441
|
+
if (!index) {
|
|
48442
|
+
index = /* @__PURE__ */ new Map();
|
|
48443
|
+
for (const name of listDirectory(join18(account, "Previews"), MAX_DIRECTORY_ENTRIES)) {
|
|
48444
|
+
const key = name.slice(0, 36).toUpperCase();
|
|
48445
|
+
const entries3 = index.get(key) ?? [];
|
|
48446
|
+
entries3.push(name);
|
|
48447
|
+
index.set(key, entries3);
|
|
48448
|
+
}
|
|
48449
|
+
this.previewIndex.set(account, index);
|
|
48450
|
+
}
|
|
48451
|
+
const entries2 = (index.get(id2.toUpperCase()) ?? []).filter((name) => name.slice(36, 37) === "-" || name.length === 36).filter((name) => {
|
|
48452
|
+
const ext = extname3(name).toLowerCase();
|
|
48453
|
+
return !ext || IMAGE_EXTENSIONS.has(ext) || /^\.\d+$/.test(ext);
|
|
48454
|
+
}).sort((a, b) => previewArea(b) - previewArea(a) || a.localeCompare(b));
|
|
48455
|
+
for (const name of entries2) {
|
|
48456
|
+
const entry = confine(join18(account, "Previews", name), account);
|
|
48457
|
+
if (!entry) continue;
|
|
48458
|
+
const file = isFile(entry) ? entry : this.bundleImage(entry, account);
|
|
48459
|
+
if (file) return { path: file, name: "preview", role: "preview" };
|
|
48460
|
+
}
|
|
48461
|
+
return void 0;
|
|
48462
|
+
}
|
|
48463
|
+
/** Preview.png (or another image) at most two levels inside a bundle. */
|
|
48464
|
+
bundleImage(bundle, account) {
|
|
48465
|
+
const found = [];
|
|
48466
|
+
for (const child of listDirectory(bundle, MAX_BUNDLE_ENTRIES2)) {
|
|
48467
|
+
const path8 = confine(join18(bundle, child), account);
|
|
48468
|
+
if (!path8) continue;
|
|
48469
|
+
if (isFile(path8)) found.push(path8);
|
|
48470
|
+
else
|
|
48471
|
+
for (const grandchild of listDirectory(path8, MAX_BUNDLE_ENTRIES2)) {
|
|
48472
|
+
const inner = confine(join18(path8, grandchild), account);
|
|
48473
|
+
if (inner && isFile(inner)) found.push(inner);
|
|
48474
|
+
}
|
|
48475
|
+
}
|
|
48476
|
+
return found.find((path8) => basename3(path8) === "Preview.png") ?? found.find((path8) => IMAGE_EXTENSIONS.has(extname3(path8).toLowerCase()));
|
|
48477
|
+
}
|
|
48478
|
+
};
|
|
48479
|
+
function sniffMime(head, name) {
|
|
48480
|
+
const ascii = Buffer.from(head).toString("latin1");
|
|
48481
|
+
if (ascii.startsWith("\x89PNG")) return "image/png";
|
|
48482
|
+
if (head[0] === 255 && head[1] === 216) return "image/jpeg";
|
|
48483
|
+
if (ascii.startsWith("GIF8")) return "image/gif";
|
|
48484
|
+
if (ascii.startsWith("%PDF")) return "application/pdf";
|
|
48485
|
+
if (ascii.slice(4, 12) === "ftypheic" || ascii.slice(4, 12) === "ftypmif1") return "image/heic";
|
|
48486
|
+
if (ascii.startsWith("RIFF") && ascii.slice(8, 12) === "WEBP") return "image/webp";
|
|
48487
|
+
const byExtension = {
|
|
48488
|
+
".png": "image/png",
|
|
48489
|
+
".jpg": "image/jpeg",
|
|
48490
|
+
".jpeg": "image/jpeg",
|
|
48491
|
+
".gif": "image/gif",
|
|
48492
|
+
".heic": "image/heic",
|
|
48493
|
+
".tiff": "image/tiff",
|
|
48494
|
+
".webp": "image/webp",
|
|
48495
|
+
".pdf": "application/pdf",
|
|
48496
|
+
".m4a": "audio/mp4",
|
|
48497
|
+
".mp3": "audio/mpeg",
|
|
48498
|
+
".wav": "audio/wav",
|
|
48499
|
+
".mov": "video/quicktime",
|
|
48500
|
+
".mp4": "video/mp4",
|
|
48501
|
+
".txt": "text/plain"
|
|
48502
|
+
};
|
|
48503
|
+
return byExtension[extname3(name).toLowerCase()] ?? "application/octet-stream";
|
|
48504
|
+
}
|
|
48505
|
+
function extensionFor(mime) {
|
|
48506
|
+
const map = {
|
|
48507
|
+
"image/png": ".png",
|
|
48508
|
+
"image/jpeg": ".jpg",
|
|
48509
|
+
"image/gif": ".gif",
|
|
48510
|
+
"image/heic": ".heic",
|
|
48511
|
+
"image/webp": ".webp",
|
|
48512
|
+
"application/pdf": ".pdf"
|
|
48513
|
+
};
|
|
48514
|
+
return map[mime] ?? "";
|
|
48515
|
+
}
|
|
48516
|
+
function safeAssetName(name, mime) {
|
|
48517
|
+
let clean = basename3(name).normalize("NFC").replace(/[^\p{L}\p{N}._ -]+/gu, "_").replace(/^[.\s]+/, "").trim();
|
|
48518
|
+
if (!clean) clean = "attachment";
|
|
48519
|
+
if (!extname3(clean)) clean += extensionFor(mime);
|
|
48520
|
+
const ext = extname3(clean);
|
|
48521
|
+
if (clean.length > 120) clean = clean.slice(0, 120 - ext.length) + ext;
|
|
48522
|
+
return clean;
|
|
48523
|
+
}
|
|
48524
|
+
function encodePathUrl(path8) {
|
|
48525
|
+
return path8.split("/").map(encodeURIComponent).join("/");
|
|
48526
|
+
}
|
|
48527
|
+
function canonicalForm(abs) {
|
|
48528
|
+
let current = abs;
|
|
48529
|
+
let rest = "";
|
|
48530
|
+
for (; ; ) {
|
|
48531
|
+
try {
|
|
48532
|
+
const real = realpathSync3.native(current);
|
|
48533
|
+
return rest ? join18(real, rest) : real;
|
|
48534
|
+
} catch {
|
|
48535
|
+
const parent = resolve3(current, "..");
|
|
48536
|
+
if (parent === current) return abs;
|
|
48537
|
+
rest = rest ? join18(basename3(current), rest) : basename3(current);
|
|
48538
|
+
current = parent;
|
|
48539
|
+
}
|
|
48540
|
+
}
|
|
48541
|
+
}
|
|
48542
|
+
function assertExportPath(p, container = NOTES_CONTAINER) {
|
|
48543
|
+
const abs = assertSafeSavePath(p);
|
|
48544
|
+
const within = (path8, root) => path8 === root || path8.startsWith(root + sep3);
|
|
48545
|
+
const roots = [resolve3(container), canonicalForm(resolve3(container))];
|
|
48546
|
+
const forms = [abs, canonicalForm(abs)];
|
|
48547
|
+
if (forms.some((form) => roots.some((root) => within(form, root))))
|
|
48548
|
+
throw new Error("Refusing to write inside the Notes library container.");
|
|
48549
|
+
return abs;
|
|
48550
|
+
}
|
|
48551
|
+
var CREATE_FLAGS = constants4.O_WRONLY | constants4.O_CREAT | constants4.O_EXCL | constants4.O_NOFOLLOW;
|
|
48552
|
+
var OutputExistsError = class extends Error {
|
|
48553
|
+
code = "output_exists";
|
|
48554
|
+
constructor(path8) {
|
|
48555
|
+
super(`Output file already exists: ${path8}. Choose a new path or remove the old file first.`);
|
|
48556
|
+
this.name = "OutputExistsError";
|
|
48557
|
+
}
|
|
48558
|
+
};
|
|
48559
|
+
function openCreateOnly(path8) {
|
|
48560
|
+
try {
|
|
48561
|
+
return openSync4(path8, CREATE_FLAGS, 420);
|
|
48562
|
+
} catch (error2) {
|
|
48563
|
+
if (error2.code === "EEXIST") throw new OutputExistsError(path8);
|
|
48564
|
+
throw error2;
|
|
48565
|
+
}
|
|
48566
|
+
}
|
|
48567
|
+
function writeAllAndClose(fd, content) {
|
|
48568
|
+
try {
|
|
48569
|
+
const data = Buffer.from(content, "utf8");
|
|
48570
|
+
let written = 0;
|
|
48571
|
+
while (written < data.length) written += writeSync3(fd, data, written);
|
|
48572
|
+
return data.length;
|
|
48573
|
+
} finally {
|
|
48574
|
+
closeSync4(fd);
|
|
48575
|
+
}
|
|
48576
|
+
}
|
|
48577
|
+
function openSource(path8) {
|
|
48578
|
+
const fd = openSync4(path8, constants4.O_RDONLY | constants4.O_NOFOLLOW);
|
|
48579
|
+
const stat = fstatSync4(fd);
|
|
48580
|
+
if (!stat.isFile()) {
|
|
48581
|
+
closeSync4(fd);
|
|
48582
|
+
throw new Error("Asset is not a regular file");
|
|
48583
|
+
}
|
|
48584
|
+
return { fd, size: stat.size };
|
|
48585
|
+
}
|
|
48586
|
+
function readHead(fd) {
|
|
48587
|
+
const head = Buffer.alloc(16);
|
|
48588
|
+
const n = readSync3(fd, head, 0, 16, 0);
|
|
48589
|
+
return head.subarray(0, n);
|
|
48590
|
+
}
|
|
48591
|
+
var SidecarWriter = class {
|
|
48592
|
+
constructor(dir, linkBase) {
|
|
48593
|
+
this.dir = dir;
|
|
48594
|
+
this.linkBase = linkBase;
|
|
48595
|
+
}
|
|
48596
|
+
dir;
|
|
48597
|
+
linkBase;
|
|
48598
|
+
placed = /* @__PURE__ */ new Map();
|
|
48599
|
+
created = false;
|
|
48600
|
+
count = 0;
|
|
48601
|
+
place(asset) {
|
|
48602
|
+
const done = this.placed.get(asset.path);
|
|
48603
|
+
if (done) return done;
|
|
48604
|
+
let source;
|
|
48605
|
+
try {
|
|
48606
|
+
source = openSource(asset.path);
|
|
48607
|
+
} catch {
|
|
48608
|
+
return { error: "unreadable" };
|
|
48609
|
+
}
|
|
48610
|
+
try {
|
|
48611
|
+
const mime = sniffMime(readHead(source.fd), asset.name);
|
|
48612
|
+
if (!this.created) {
|
|
48613
|
+
assertExportPath(this.dir);
|
|
48614
|
+
mkdirSync4(this.dir, { recursive: true });
|
|
48615
|
+
this.created = true;
|
|
48616
|
+
}
|
|
48617
|
+
const name = safeAssetName(asset.name, mime);
|
|
48618
|
+
const ext = extname3(name);
|
|
48619
|
+
const stem = name.slice(0, name.length - ext.length);
|
|
48620
|
+
let target;
|
|
48621
|
+
let out;
|
|
48622
|
+
for (let n = 1; n <= 1e3 && out === void 0; n++) {
|
|
48623
|
+
target = join18(this.dir, n === 1 ? name : `${stem}-${n}${ext}`);
|
|
48624
|
+
try {
|
|
48625
|
+
out = openSync4(target, CREATE_FLAGS, 420);
|
|
48626
|
+
} catch (error2) {
|
|
48627
|
+
if (error2.code !== "EEXIST") throw error2;
|
|
48628
|
+
}
|
|
48629
|
+
}
|
|
48630
|
+
if (out === void 0 || !target) return { error: "no-free-name" };
|
|
48631
|
+
try {
|
|
48632
|
+
const chunk = Buffer.alloc(1024 * 1024);
|
|
48633
|
+
for (let position = 0; ; ) {
|
|
48634
|
+
const n = readSync3(source.fd, chunk, 0, chunk.length, position);
|
|
48635
|
+
if (n <= 0) break;
|
|
48636
|
+
let written = 0;
|
|
48637
|
+
while (written < n) written += writeSync3(out, chunk, written, n - written);
|
|
48638
|
+
position += n;
|
|
48639
|
+
}
|
|
48640
|
+
} finally {
|
|
48641
|
+
closeSync4(out);
|
|
48642
|
+
}
|
|
48643
|
+
this.count++;
|
|
48644
|
+
const url = this.linkBase ? encodePathUrl(relative3(this.linkBase, target).split(sep3).join("/")) : target;
|
|
48645
|
+
const result = { url, mime };
|
|
48646
|
+
this.placed.set(asset.path, result);
|
|
48647
|
+
return result;
|
|
48648
|
+
} catch (error2) {
|
|
48649
|
+
return { error: error2 instanceof Error ? error2.message : String(error2) };
|
|
48650
|
+
} finally {
|
|
48651
|
+
closeSync4(source.fd);
|
|
48652
|
+
}
|
|
48653
|
+
}
|
|
48654
|
+
};
|
|
48655
|
+
|
|
48656
|
+
// src/utils/exportRender.ts
|
|
48657
|
+
var emptyStats = () => ({
|
|
48658
|
+
attachments: 0,
|
|
48659
|
+
placed: 0,
|
|
48660
|
+
placeholders: 0,
|
|
48661
|
+
unavailable: 0,
|
|
48662
|
+
tables: 0,
|
|
48663
|
+
unreadableTables: 0,
|
|
48664
|
+
unreferenced: 0
|
|
48665
|
+
});
|
|
48666
|
+
var isSafeHref = (url) => /^(?:https?:\/\/|notes:\/\/|applenotes:|mailto:)/i.test(url) && !Array.from(url).some((char) => char.charCodeAt(0) < 32);
|
|
48667
|
+
var LABELS = {
|
|
48668
|
+
table: "Table",
|
|
48669
|
+
image: "Image",
|
|
48670
|
+
drawing: "Drawing",
|
|
48671
|
+
paper: "Drawing",
|
|
48672
|
+
scan: "Scanned document",
|
|
48673
|
+
pdf: "PDF",
|
|
48674
|
+
audio: "Audio",
|
|
48675
|
+
video: "Video",
|
|
48676
|
+
link: "Link",
|
|
48677
|
+
gallery: "Gallery",
|
|
48678
|
+
divider: "Divider",
|
|
48679
|
+
inline: "Inline attachment",
|
|
48680
|
+
file: "File"
|
|
48681
|
+
};
|
|
48682
|
+
var attachmentLabel = (kind) => LABELS[kind];
|
|
48683
|
+
function fmtOf(run) {
|
|
48684
|
+
const fmt = {};
|
|
48685
|
+
if (run.bold) fmt.bold = true;
|
|
48686
|
+
if (run.italic) fmt.italic = true;
|
|
48687
|
+
if (run.underline) fmt.underline = true;
|
|
48688
|
+
if (run.strikethrough) fmt.strikethrough = true;
|
|
48689
|
+
if (run.superscript) fmt.superscript = true;
|
|
48690
|
+
if (run.subscript) fmt.subscript = true;
|
|
48691
|
+
if (run.highlight) fmt.highlight = run.highlight;
|
|
48692
|
+
if (run.color) fmt.color = run.color;
|
|
48693
|
+
if (run.link && run.linkSafe) fmt.link = run.link;
|
|
48694
|
+
return fmt;
|
|
48695
|
+
}
|
|
48696
|
+
var sameFmt = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
48697
|
+
function blockPieces(block, plan) {
|
|
48698
|
+
const pieces = [];
|
|
48699
|
+
const pushText = (text2, fmt) => {
|
|
48700
|
+
if (!text2) return;
|
|
48701
|
+
const last = pieces[pieces.length - 1];
|
|
48702
|
+
if (last?.type === "text" && sameFmt(last.fmt, fmt)) last.text += text2;
|
|
48703
|
+
else pieces.push({ type: "text", text: text2, fmt });
|
|
48704
|
+
};
|
|
48705
|
+
for (const run of block.runs) {
|
|
48706
|
+
const fmt = fmtOf(run);
|
|
48707
|
+
const parts = run.text.split("\uFFFC");
|
|
48708
|
+
parts.forEach((part, i) => {
|
|
48709
|
+
if (i > 0 && run.attachment)
|
|
48710
|
+
pieces.push({ type: "attachment", id: run.attachment.id, plan: plan(run.attachment.id) });
|
|
48711
|
+
pushText(part, fmt);
|
|
48712
|
+
});
|
|
48713
|
+
}
|
|
48714
|
+
return pieces;
|
|
48715
|
+
}
|
|
48716
|
+
var isBlockPlan = (plan) => plan.type === "table" || plan.type === "divider" || plan.type === "gallery";
|
|
48717
|
+
function titleBlockIndex(note) {
|
|
48718
|
+
const first2 = note.doc.blocks.find((block) => block.text.trim());
|
|
48719
|
+
if (!first2) return -1;
|
|
48720
|
+
if (first2.style === "title") return first2.index;
|
|
48721
|
+
return first2.text.trim() === note.title.trim() && first2.style !== "monospaced" ? first2.index : -1;
|
|
48722
|
+
}
|
|
48723
|
+
function place(ctx, asset) {
|
|
48724
|
+
return asset && ctx.writer ? ctx.writer.place(asset) : void 0;
|
|
48725
|
+
}
|
|
48726
|
+
function planAttachment(attachment, ctx) {
|
|
48727
|
+
ctx.stats.attachments++;
|
|
48728
|
+
const unavailable = (label2, reason, name2) => {
|
|
48729
|
+
ctx.stats.unavailable++;
|
|
48730
|
+
return { type: "unavailable", label: label2, reason, ...name2 ? { name: name2 } : {} };
|
|
48731
|
+
};
|
|
48732
|
+
if (!attachment) return unavailable("Attachment", "missing");
|
|
48733
|
+
const label = attachmentLabel(attachment.kind);
|
|
48734
|
+
const name = attachment.title;
|
|
48735
|
+
switch (attachment.kind) {
|
|
48736
|
+
case "inline": {
|
|
48737
|
+
const link = attachment.uti.endsWith(".link") && attachment.tokenId && isSafeHref(attachment.tokenId) ? attachment.tokenId : void 0;
|
|
48738
|
+
return { type: "inline", text: attachment.altText ?? "", ...link ? { link } : {} };
|
|
48739
|
+
}
|
|
48740
|
+
case "divider":
|
|
48741
|
+
return { type: "divider" };
|
|
48742
|
+
case "table": {
|
|
48743
|
+
ctx.stats.tables++;
|
|
48744
|
+
try {
|
|
48745
|
+
if (!attachment.tableData) throw new Error("no table data");
|
|
48746
|
+
return {
|
|
48747
|
+
type: "table",
|
|
48748
|
+
rows: parseNoteTable(Buffer.from(attachment.tableData, "hex")).rows
|
|
48749
|
+
};
|
|
48750
|
+
} catch {
|
|
48751
|
+
ctx.stats.unreadableTables++;
|
|
48752
|
+
return unavailable(label, "undecodable");
|
|
48753
|
+
}
|
|
48754
|
+
}
|
|
48755
|
+
case "gallery": {
|
|
48756
|
+
ctx.stats.attachments--;
|
|
48757
|
+
return {
|
|
48758
|
+
type: "gallery",
|
|
48759
|
+
items: attachment.children.map((child) => planAttachment(child, ctx))
|
|
48760
|
+
};
|
|
48761
|
+
}
|
|
48762
|
+
case "link": {
|
|
48763
|
+
const url = attachment.url ?? "";
|
|
48764
|
+
const preview = ctx.locator ? place(ctx, ctx.locator.locate(attachment).preview) : void 0;
|
|
48765
|
+
if (preview && "url" in preview) ctx.stats.placed++;
|
|
48766
|
+
return {
|
|
48767
|
+
type: "card",
|
|
48768
|
+
title: name ?? url,
|
|
48769
|
+
displayUrl: url,
|
|
48770
|
+
...isSafeHref(url) ? { url } : {},
|
|
48771
|
+
...preview && "url" in preview ? { previewUrl: preview.url } : {}
|
|
48772
|
+
};
|
|
48773
|
+
}
|
|
48774
|
+
default: {
|
|
48775
|
+
if (!ctx.writer) {
|
|
48776
|
+
ctx.stats.placeholders++;
|
|
48777
|
+
return { type: "placeholder", label, ...name ? { name } : {} };
|
|
48778
|
+
}
|
|
48779
|
+
const files = ctx.locator?.locate(attachment) ?? {};
|
|
48780
|
+
const primary = place(ctx, files.primary);
|
|
48781
|
+
const visual = ["image", "drawing", "paper"].includes(attachment.kind);
|
|
48782
|
+
const wantsPreview = attachment.kind === "scan" || attachment.kind === "pdf";
|
|
48783
|
+
const preview = files.preview && (wantsPreview || visual && !(primary && "url" in primary)) ? place(ctx, files.preview) : void 0;
|
|
48784
|
+
const previewUrl = preview && "url" in preview ? preview.url : void 0;
|
|
48785
|
+
if (primary && "url" in primary) {
|
|
48786
|
+
ctx.stats.placed++;
|
|
48787
|
+
const display = visual ? "image" : attachment.kind === "audio" ? "audio" : attachment.kind === "video" ? "video" : "link";
|
|
48788
|
+
return {
|
|
48789
|
+
type: "asset",
|
|
48790
|
+
label,
|
|
48791
|
+
...name ? { name } : {},
|
|
48792
|
+
display,
|
|
48793
|
+
url: primary.url,
|
|
48794
|
+
mime: primary.mime,
|
|
48795
|
+
...previewUrl ? { previewUrl } : {}
|
|
48796
|
+
};
|
|
48797
|
+
}
|
|
48798
|
+
if (visual && previewUrl) {
|
|
48799
|
+
ctx.stats.placed++;
|
|
48800
|
+
return {
|
|
48801
|
+
type: "asset",
|
|
48802
|
+
label,
|
|
48803
|
+
...name ? { name } : {},
|
|
48804
|
+
display: "image",
|
|
48805
|
+
url: previewUrl,
|
|
48806
|
+
mime: preview.mime
|
|
48807
|
+
};
|
|
48808
|
+
}
|
|
48809
|
+
const reason = primary && "error" in primary ? primary.error : "missing";
|
|
48810
|
+
return unavailable(label, reason, name);
|
|
48811
|
+
}
|
|
48812
|
+
}
|
|
48813
|
+
}
|
|
48814
|
+
function unreferencedAttachments(note) {
|
|
48815
|
+
const referenced = new Set(note.doc.attachments.map((marker) => marker.id));
|
|
48816
|
+
return note.ordered.filter(
|
|
48817
|
+
(attachment) => !referenced.has(attachment.id) && attachment.kind !== "table" && attachment.kind !== "inline" && attachment.kind !== "divider"
|
|
48818
|
+
);
|
|
48819
|
+
}
|
|
48820
|
+
|
|
48821
|
+
// src/utils/markdownExport.ts
|
|
48822
|
+
var NOTE_SEPARATOR = "\n\n---\n\n";
|
|
48823
|
+
function escapeMarkdown(text2) {
|
|
48824
|
+
return text2.replace(/[\\`*_[\]<>~|]/g, (char) => `\\${char}`).replace(/&(?=#?[A-Za-z0-9]+;)/g, "&").replace(/==/g, "\\=\\=");
|
|
48825
|
+
}
|
|
48826
|
+
function escapeLineStart(line) {
|
|
48827
|
+
return line.replace(
|
|
48828
|
+
/^(\s*)([#>+-]|\d+[.)])(?=\s|$)/,
|
|
48829
|
+
(_, space, marker) => /^\d/.test(marker) ? `${space}${marker.slice(0, -1)}\\${marker.slice(-1)}` : `${space}\\${marker}`
|
|
48830
|
+
);
|
|
48831
|
+
}
|
|
48832
|
+
function linkDestination(url) {
|
|
48833
|
+
return url.replace(
|
|
48834
|
+
/[\s()<>]/g,
|
|
48835
|
+
(char) => char === " " ? "%20" : `%${char.charCodeAt(0).toString(16).toUpperCase().padStart(2, "0")}`
|
|
48836
|
+
);
|
|
48837
|
+
}
|
|
48838
|
+
function delimit(text2, open, close = open) {
|
|
48839
|
+
const match = /^(\s*)([\s\S]*?)(\s*)$/.exec(text2);
|
|
48840
|
+
return match[2] ? `${match[1]}${open}${match[2]}${close}${match[3]}` : text2;
|
|
48841
|
+
}
|
|
48842
|
+
var LAYERS = [
|
|
48843
|
+
["italic", "*", "*"],
|
|
48844
|
+
["bold", "**", "**"],
|
|
48845
|
+
["strikethrough", "~~", "~~"],
|
|
48846
|
+
["underline", "<u>", "</u>"],
|
|
48847
|
+
["highlight", "==", "=="],
|
|
48848
|
+
["superscript", "<sup>", "</sup>"],
|
|
48849
|
+
["subscript", "<sub>", "</sub>"]
|
|
48850
|
+
];
|
|
48851
|
+
function joinSafe(left, right) {
|
|
48852
|
+
return left && right && /[*~=]$/.test(left) && left.at(-1) === right[0] ? `${left}<!-- -->${right}` : left + right;
|
|
48853
|
+
}
|
|
48854
|
+
function layered(pieces, depth = 0) {
|
|
48855
|
+
if (depth === LAYERS.length)
|
|
48856
|
+
return pieces.map((piece) => escapeMarkdown(piece.text.replace(/\n/g, " "))).join("");
|
|
48857
|
+
const [key, open, close] = LAYERS[depth];
|
|
48858
|
+
let out = "";
|
|
48859
|
+
for (let i = 0; i < pieces.length; ) {
|
|
48860
|
+
const on = !!pieces[i].fmt[key];
|
|
48861
|
+
let j = i;
|
|
48862
|
+
while (j < pieces.length && !!pieces[j].fmt[key] === on) j++;
|
|
48863
|
+
const inner = layered(pieces.slice(i, j), depth + 1);
|
|
48864
|
+
out = joinSafe(out, on ? delimit(inner, open, close) : inner);
|
|
48865
|
+
i = j;
|
|
48866
|
+
}
|
|
48867
|
+
return out;
|
|
48868
|
+
}
|
|
48869
|
+
var bracket = (label, name) => `\\[${escapeMarkdown(name ? `${label}: ${name}` : label)}\\]`;
|
|
48870
|
+
function planMarkdown(plan) {
|
|
48871
|
+
switch (plan.type) {
|
|
48872
|
+
case "inline":
|
|
48873
|
+
return plan.link ? `[${escapeMarkdown(plan.text)}](${linkDestination(plan.link)})` : escapeMarkdown(plan.text);
|
|
48874
|
+
case "divider":
|
|
48875
|
+
return "---";
|
|
48876
|
+
case "table":
|
|
48877
|
+
return tableMarkdown(plan.rows);
|
|
48878
|
+
case "placeholder":
|
|
48879
|
+
return bracket(plan.label, plan.name);
|
|
48880
|
+
case "unavailable":
|
|
48881
|
+
return bracket(`${plan.label} unavailable`, plan.name);
|
|
48882
|
+
case "asset": {
|
|
48883
|
+
const text2 = escapeMarkdown(plan.name ?? plan.label);
|
|
48884
|
+
if (plan.display === "image") return `})`;
|
|
48885
|
+
const inner = plan.previewUrl ? `})` : text2;
|
|
48886
|
+
return `[${inner}](${linkDestination(plan.url)})`;
|
|
48887
|
+
}
|
|
48888
|
+
case "card":
|
|
48889
|
+
return plan.url ? `[${escapeMarkdown(plan.title)}](${linkDestination(plan.url)})` : `${escapeMarkdown(plan.title)} (${escapeMarkdown(plan.displayUrl)})`;
|
|
48890
|
+
case "gallery":
|
|
48891
|
+
return plan.items.map(planMarkdown).join("\n\n");
|
|
48892
|
+
}
|
|
48893
|
+
}
|
|
48894
|
+
function tableMarkdown(rows) {
|
|
48895
|
+
const width = Math.max(1, ...rows.map((row) => row.length));
|
|
48896
|
+
const cell = (value) => escapeMarkdown(value ?? "").replace(/\r?\n/g, "<br>").trim() || " ";
|
|
48897
|
+
const line = (row) => `| ${Array.from({ length: width }, (_, i) => cell(row[i])).join(" | ")} |`;
|
|
48898
|
+
const [head = [], ...body] = rows;
|
|
48899
|
+
return [line(head), `| ${Array(width).fill("---").join(" | ")} |`, ...body.map(line)].join("\n");
|
|
48900
|
+
}
|
|
48901
|
+
function inlineMarkdown(pieces) {
|
|
48902
|
+
let out = "";
|
|
48903
|
+
for (let i = 0; i < pieces.length; ) {
|
|
48904
|
+
const piece = pieces[i];
|
|
48905
|
+
if (piece.type === "attachment") {
|
|
48906
|
+
out = joinSafe(out, planMarkdown(piece.plan));
|
|
48907
|
+
i++;
|
|
48908
|
+
continue;
|
|
48909
|
+
}
|
|
48910
|
+
const link = piece.fmt.link;
|
|
48911
|
+
let j = i;
|
|
48912
|
+
while (j < pieces.length && pieces[j].type === "text" && pieces[j].fmt.link === link)
|
|
48913
|
+
j++;
|
|
48914
|
+
const inner = layered(pieces.slice(i, j));
|
|
48915
|
+
out = joinSafe(out, link ? delimit(inner, "[", `](${linkDestination(link)})`) : inner);
|
|
48916
|
+
i = j;
|
|
48917
|
+
}
|
|
48918
|
+
return out;
|
|
48919
|
+
}
|
|
48920
|
+
var LIST_STYLES = /* @__PURE__ */ new Set(["bulleted", "dashed", "numbered", "checklist"]);
|
|
48921
|
+
function renderNoteMarkdown(note, ctx) {
|
|
48922
|
+
const plan = (id2) => planAttachment(note.attachments.get(id2), ctx);
|
|
48923
|
+
const titleIndex = titleBlockIndex(note);
|
|
48924
|
+
const lines = [];
|
|
48925
|
+
const counters = [];
|
|
48926
|
+
let code;
|
|
48927
|
+
const flushCode = () => {
|
|
48928
|
+
if (!code) return;
|
|
48929
|
+
const longest = Math.max(
|
|
48930
|
+
2,
|
|
48931
|
+
...code.lines.map((l) => Math.max(0, ...(l.match(/`+/g) ?? []).map((m) => m.length)))
|
|
48932
|
+
);
|
|
48933
|
+
const fence = "`".repeat(longest + 1);
|
|
48934
|
+
lines.push({
|
|
48935
|
+
text: [fence, ...code.lines, fence].join("\n"),
|
|
48936
|
+
group: "code",
|
|
48937
|
+
quote: code.quote
|
|
48938
|
+
});
|
|
48939
|
+
code = void 0;
|
|
48940
|
+
};
|
|
48941
|
+
if (titleIndex === -1 && note.title.trim())
|
|
48942
|
+
lines.push({ text: `# ${escapeMarkdown(note.title.trim())}`, group: "para", quote: false });
|
|
48943
|
+
for (const block of note.doc.blocks) {
|
|
48944
|
+
if (block.style === "monospaced") {
|
|
48945
|
+
if (code && code.quote !== block.blockQuote) flushCode();
|
|
48946
|
+
code ??= { lines: [], quote: block.blockQuote };
|
|
48947
|
+
code.lines.push(block.text.replace(/\ufffc/g, ""));
|
|
48948
|
+
continue;
|
|
48949
|
+
}
|
|
48950
|
+
flushCode();
|
|
48951
|
+
if (!LIST_STYLES.has(block.style)) counters.length = 0;
|
|
48952
|
+
if (!block.text.trim()) continue;
|
|
48953
|
+
const pieces = blockPieces(block, plan);
|
|
48954
|
+
let segment = [];
|
|
48955
|
+
const segments = [];
|
|
48956
|
+
for (const piece of pieces) {
|
|
48957
|
+
if (piece.type === "attachment" && isBlockPlan(piece.plan)) {
|
|
48958
|
+
segments.push(segment, piece.plan);
|
|
48959
|
+
segment = [];
|
|
48960
|
+
} else segment.push(piece);
|
|
48961
|
+
}
|
|
48962
|
+
segments.push(segment);
|
|
48963
|
+
let first2 = true;
|
|
48964
|
+
for (const segment2 of segments) {
|
|
48965
|
+
if (!Array.isArray(segment2)) {
|
|
48966
|
+
lines.push({ text: planMarkdown(segment2), group: "block", quote: block.blockQuote });
|
|
48967
|
+
continue;
|
|
48968
|
+
}
|
|
48969
|
+
const body = inlineMarkdown(segment2).trim();
|
|
48970
|
+
if (!body) continue;
|
|
48971
|
+
lines.push(renderLine(block, body, first2, block.index === titleIndex, counters));
|
|
48972
|
+
first2 = false;
|
|
48973
|
+
}
|
|
48974
|
+
}
|
|
48975
|
+
flushCode();
|
|
48976
|
+
for (const attachment of unreferencedAttachments(note)) {
|
|
48977
|
+
ctx.stats.unreferenced++;
|
|
48978
|
+
lines.push({
|
|
48979
|
+
text: planMarkdown(planAttachment(attachment, ctx)),
|
|
48980
|
+
group: "block",
|
|
48981
|
+
quote: false
|
|
48982
|
+
});
|
|
48983
|
+
}
|
|
48984
|
+
return joinLines(lines);
|
|
48985
|
+
}
|
|
48986
|
+
function renderLine(block, body, first2, isTitle, counters) {
|
|
48987
|
+
const quote = block.blockQuote;
|
|
48988
|
+
if (isTitle || block.style === "title") return { text: `# ${body}`, group: "para", quote };
|
|
48989
|
+
if (block.style === "heading") return { text: `## ${body}`, group: "para", quote };
|
|
48990
|
+
if (block.style === "subheading") return { text: `### ${body}`, group: "para", quote };
|
|
48991
|
+
if (!LIST_STYLES.has(block.style) || !first2)
|
|
48992
|
+
return { text: escapeLineStart(body), group: "para", quote };
|
|
48993
|
+
const level = Math.min(block.indent, 20);
|
|
48994
|
+
counters.length = Math.min(counters.length, level + 1);
|
|
48995
|
+
while (counters.length <= level) counters.push(0);
|
|
48996
|
+
const indent = " ".repeat(level);
|
|
48997
|
+
let marker = "-";
|
|
48998
|
+
if (block.style === "numbered") marker = `${++counters[level]}.`;
|
|
48999
|
+
else {
|
|
49000
|
+
counters[level] = 0;
|
|
49001
|
+
if (block.style === "checklist") marker = block.checklist?.done ? "- [x]" : "- [ ]";
|
|
49002
|
+
}
|
|
49003
|
+
return { text: `${indent}${marker} ${body}`, group: "list", quote };
|
|
49004
|
+
}
|
|
49005
|
+
function joinLines(lines) {
|
|
49006
|
+
let out = "";
|
|
49007
|
+
let previous;
|
|
49008
|
+
for (const line of lines) {
|
|
49009
|
+
const text2 = line.quote ? line.text.split("\n").map((l) => l ? `> ${l}` : ">").join("\n") : line.text;
|
|
49010
|
+
if (previous) {
|
|
49011
|
+
const tight = previous.group === "list" && line.group === "list" && previous.quote === line.quote;
|
|
49012
|
+
out += tight ? "\n" : previous.quote && line.quote ? "\n>\n" : "\n\n";
|
|
49013
|
+
}
|
|
49014
|
+
out += text2;
|
|
49015
|
+
previous = line;
|
|
49016
|
+
}
|
|
49017
|
+
return out;
|
|
49018
|
+
}
|
|
49019
|
+
function wrapMarkdown(markdown, width) {
|
|
49020
|
+
if (!width) return markdown;
|
|
49021
|
+
let fenced = false;
|
|
49022
|
+
const out = [];
|
|
49023
|
+
for (const line of markdown.split("\n")) {
|
|
49024
|
+
const bare = line.replace(/^(?:> ?)+/, "");
|
|
49025
|
+
if (/^\s*```/.test(bare)) fenced = !fenced;
|
|
49026
|
+
if (fenced || /^\s*```/.test(bare) || line.length <= width || /^\s*(#|\||!\[)/.test(bare)) {
|
|
49027
|
+
out.push(line);
|
|
49028
|
+
continue;
|
|
49029
|
+
}
|
|
49030
|
+
const prefix = /^((?:> ?)*\s*(?:(?:[-*+]|\d+\.)(?: \[[ x]\])? )?)/.exec(line)[1];
|
|
49031
|
+
const hang = prefix.replace(/[^>\s]/g, " ").replace(/>(?! )/g, "> ");
|
|
49032
|
+
const words = line.slice(prefix.length).split(" ");
|
|
49033
|
+
let current = prefix;
|
|
49034
|
+
let empty = true;
|
|
49035
|
+
for (const word of words) {
|
|
49036
|
+
if (!empty && current.length + 1 + word.length > width) {
|
|
49037
|
+
out.push(current);
|
|
49038
|
+
current = hang + word;
|
|
49039
|
+
} else current += (empty ? "" : " ") + word;
|
|
49040
|
+
empty = false;
|
|
49041
|
+
}
|
|
49042
|
+
out.push(current);
|
|
49043
|
+
}
|
|
49044
|
+
return out.join("\n");
|
|
49045
|
+
}
|
|
49046
|
+
function renderNotesMarkdown(notes, ctx, { wrap: wrap2 = 0 } = {}) {
|
|
49047
|
+
const body = notes.map((note) => renderNoteMarkdown(note, ctx)).join(NOTE_SEPARATOR);
|
|
49048
|
+
return (wrap2 ? wrapMarkdown(body, wrap2) : body) + (notes.length ? "\n" : "");
|
|
49049
|
+
}
|
|
49050
|
+
|
|
49051
|
+
// src/utils/noteExportData.ts
|
|
49052
|
+
import { execFileSync as execFileSync17 } from "node:child_process";
|
|
49053
|
+
import { homedir as homedir16 } from "node:os";
|
|
49054
|
+
import { join as join19 } from "node:path";
|
|
49055
|
+
var NOTES_DB_PATH10 = join19(
|
|
49056
|
+
homedir16(),
|
|
49057
|
+
"Library/Group Containers/group.com.apple.notes/NoteStore.sqlite"
|
|
49058
|
+
);
|
|
49059
|
+
var IMAGE_UTIS2 = /* @__PURE__ */ new Set([
|
|
49060
|
+
"public.jpeg",
|
|
49061
|
+
"public.png",
|
|
49062
|
+
"public.heic",
|
|
49063
|
+
"public.heif",
|
|
49064
|
+
"public.image",
|
|
49065
|
+
"public.tiff",
|
|
49066
|
+
"public.webp",
|
|
49067
|
+
"org.webmproject.webp",
|
|
49068
|
+
"com.compuserve.gif",
|
|
49069
|
+
"com.microsoft.bmp",
|
|
49070
|
+
"com.adobe.raw-image",
|
|
49071
|
+
"public.camera-raw-image"
|
|
49072
|
+
]);
|
|
49073
|
+
var AUDIO_UTIS = /* @__PURE__ */ new Set([
|
|
49074
|
+
"com.apple.m4a-audio",
|
|
49075
|
+
"public.mpeg-4-audio",
|
|
49076
|
+
"public.mp3",
|
|
49077
|
+
"public.audio",
|
|
49078
|
+
"public.aiff-audio",
|
|
49079
|
+
"com.microsoft.waveform-audio"
|
|
49080
|
+
]);
|
|
49081
|
+
var VIDEO_UTIS = /* @__PURE__ */ new Set([
|
|
49082
|
+
"public.movie",
|
|
49083
|
+
"public.video",
|
|
49084
|
+
"public.mpeg-4",
|
|
49085
|
+
"com.apple.quicktime-movie"
|
|
49086
|
+
]);
|
|
49087
|
+
function classifyUti(uti) {
|
|
49088
|
+
if (uti === "com.apple.notes.table") return "table";
|
|
49089
|
+
if (uti === "com.apple.notes.inlinetextattachment.dividerline") return "divider";
|
|
49090
|
+
if (uti.startsWith("com.apple.notes.inlinetextattachment.")) return "inline";
|
|
49091
|
+
if (uti === "com.apple.notes.gallery") return "gallery";
|
|
49092
|
+
if (uti === "com.apple.drawing" || uti === "com.apple.drawing.2") return "drawing";
|
|
49093
|
+
if (uti === "com.apple.paper.doc.scan") return "scan";
|
|
49094
|
+
if (uti === "com.apple.paper") return "paper";
|
|
49095
|
+
if (uti === "public.url") return "link";
|
|
49096
|
+
if (uti === "com.adobe.pdf") return "pdf";
|
|
49097
|
+
if (IMAGE_UTIS2.has(uti)) return "image";
|
|
49098
|
+
if (AUDIO_UTIS.has(uti)) return "audio";
|
|
49099
|
+
if (VIDEO_UTIS.has(uti)) return "video";
|
|
49100
|
+
return "file";
|
|
49101
|
+
}
|
|
49102
|
+
var ATTACHMENT_COLUMNS = [
|
|
49103
|
+
["uti0", "a", "ZTYPEUTI"],
|
|
49104
|
+
["uti1", "a", "ZTYPEUTI1"],
|
|
49105
|
+
["parent", "a", "ZPARENTATTACHMENT"],
|
|
49106
|
+
["title", "a", "ZTITLE"],
|
|
49107
|
+
["userTitle", "a", "ZUSERTITLE"],
|
|
49108
|
+
["url", "a", "ZURLSTRING"],
|
|
49109
|
+
["alt", "a", "ZALTTEXT"],
|
|
49110
|
+
["token", "a", "ZTOKENCONTENTIDENTIFIER"],
|
|
49111
|
+
["fbImageGen", "a", "ZFALLBACKIMAGEGENERATION"],
|
|
49112
|
+
["fbPdfGen", "a", "ZFALLBACKPDFGENERATION"],
|
|
49113
|
+
["mediaId", "m", "ZIDENTIFIER"],
|
|
49114
|
+
["mediaFilename", "m", "ZFILENAME"],
|
|
49115
|
+
["mediaGen", "m", "ZGENERATION1"]
|
|
49116
|
+
];
|
|
49117
|
+
var columnCache = /* @__PURE__ */ new Map();
|
|
49118
|
+
function sqlite(dbPath2, args) {
|
|
49119
|
+
try {
|
|
49120
|
+
return execFileSync17(
|
|
49121
|
+
"/usr/bin/sqlite3",
|
|
49122
|
+
["-readonly", ...args.slice(0, -1), dbPath2, args.at(-1)],
|
|
49123
|
+
{
|
|
49124
|
+
encoding: "utf8",
|
|
49125
|
+
timeout: 1e4,
|
|
49126
|
+
maxBuffer: 256 * 1024 * 1024,
|
|
49127
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
49128
|
+
}
|
|
49129
|
+
).trim();
|
|
49130
|
+
} catch (error2) {
|
|
49131
|
+
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
49132
|
+
if (/authorization denied|unable to open database/i.test(message))
|
|
49133
|
+
throw new NoteBlocksError("no-full-disk-access", "The Notes database is not readable");
|
|
49134
|
+
throw new NoteBlocksError("query-failed", "Failed to query the Notes database");
|
|
49135
|
+
}
|
|
49136
|
+
}
|
|
49137
|
+
function objectColumns(dbPath2 = NOTES_DB_PATH10) {
|
|
49138
|
+
let columns = columnCache.get(dbPath2);
|
|
49139
|
+
if (!columns) {
|
|
49140
|
+
columns = new Set(
|
|
49141
|
+
sqlite(dbPath2, ["SELECT name FROM pragma_table_info('ZICCLOUDSYNCINGOBJECT');"]).split("\n").filter(Boolean)
|
|
49142
|
+
);
|
|
49143
|
+
columnCache.set(dbPath2, columns);
|
|
49144
|
+
}
|
|
49145
|
+
return columns;
|
|
49146
|
+
}
|
|
49147
|
+
function attachmentQuery(columns) {
|
|
49148
|
+
const col3 = (alias, name) => columns.has(name) ? `${alias}.${name}` : "NULL";
|
|
49149
|
+
const fields = ATTACHMENT_COLUMNS.map(([key, alias, name]) => `'${key}', ${col3(alias, name)}`);
|
|
49150
|
+
const uti = `COALESCE(${col3("a", "ZTYPEUTI")}, ${col3("a", "ZTYPEUTI1")})`;
|
|
49151
|
+
const mergeable = columns.has("ZMERGEABLEDATA1") ? columns.has("ZMERGEABLEDATA") ? "COALESCE(a.ZMERGEABLEDATA1, a.ZMERGEABLEDATA)" : "a.ZMERGEABLEDATA1" : col3("a", "ZMERGEABLEDATA");
|
|
49152
|
+
const noteLinks = ["ZNOTE", "ZNOTE1"].filter((c) => columns.has(c)).map((c) => `a.${c} = @pk`);
|
|
49153
|
+
const owner = noteLinks.length ? `(${noteLinks.join(" OR ")})` : "0";
|
|
49154
|
+
const media = columns.has("ZMEDIA") ? "m.Z_PK = a.ZMEDIA" : "0";
|
|
49155
|
+
const live = columns.has("ZMARKEDFORDELETION") ? "AND COALESCE(a.ZMARKEDFORDELETION, 0) = 0" : "";
|
|
49156
|
+
return `SELECT json_object('title', (SELECT ${col3("n", "ZTITLE1")} FROM ZICCLOUDSYNCINGOBJECT n WHERE n.Z_PK = @pk), 'attachments', (SELECT json_group_array(json_object('pk', a.Z_PK, 'id', a.ZIDENTIFIER, ${fields.join(", ")}, 'table', CASE WHEN ${uti} = 'com.apple.notes.table' THEN hex(${mergeable}) END)) FROM ZICCLOUDSYNCINGOBJECT a LEFT JOIN ZICCLOUDSYNCINGOBJECT m ON ${media} WHERE ${owner} AND a.ZIDENTIFIER IS NOT NULL ${live}));`;
|
|
49157
|
+
}
|
|
49158
|
+
var text = (value) => typeof value === "string" && value.length ? value : typeof value === "number" ? String(value) : void 0;
|
|
49159
|
+
function buildAttachments(rows) {
|
|
49160
|
+
const all = rows.filter((row) => typeof row.id === "string" && Number.isInteger(row.pk)).map((row) => {
|
|
49161
|
+
const uti = text(row.uti0) ?? text(row.uti1) ?? "unknown";
|
|
49162
|
+
const attachment = {
|
|
49163
|
+
id: row.id,
|
|
49164
|
+
pk: row.pk,
|
|
49165
|
+
uti,
|
|
49166
|
+
kind: classifyUti(uti),
|
|
49167
|
+
children: []
|
|
49168
|
+
};
|
|
49169
|
+
const set = (key, value) => {
|
|
49170
|
+
if (value !== void 0) attachment[key] = value;
|
|
49171
|
+
};
|
|
49172
|
+
set("parentPk", Number.isInteger(row.parent) ? row.parent : void 0);
|
|
49173
|
+
set("title", text(row.title) ?? text(row.userTitle) ?? text(row.mediaFilename));
|
|
49174
|
+
set("url", text(row.url));
|
|
49175
|
+
set("altText", text(row.alt));
|
|
49176
|
+
set("tokenId", text(row.token));
|
|
49177
|
+
set("mediaId", text(row.mediaId));
|
|
49178
|
+
set("mediaFilename", text(row.mediaFilename));
|
|
49179
|
+
set("mediaGeneration", text(row.mediaGen));
|
|
49180
|
+
set("fallbackImageGeneration", text(row.fbImageGen));
|
|
49181
|
+
set("fallbackPdfGeneration", text(row.fbPdfGen));
|
|
49182
|
+
const table = text(row.table);
|
|
49183
|
+
set("tableData", table && /^[0-9a-f]+$/i.test(table) ? table : void 0);
|
|
49184
|
+
return attachment;
|
|
49185
|
+
}).sort((a, b) => a.pk - b.pk);
|
|
49186
|
+
const byPk = new Map(all.map((a) => [a.pk, a]));
|
|
49187
|
+
const ordered = [];
|
|
49188
|
+
for (const attachment of all) {
|
|
49189
|
+
const parent = attachment.parentPk !== void 0 ? byPk.get(attachment.parentPk) : void 0;
|
|
49190
|
+
if (parent) parent.children.push(attachment);
|
|
49191
|
+
else ordered.push(attachment);
|
|
49192
|
+
}
|
|
49193
|
+
return { byId: new Map(all.map((a) => [a.id, a])), ordered };
|
|
49194
|
+
}
|
|
49195
|
+
function readExportNote(id2, { dbPath: dbPath2 = NOTES_DB_PATH10 } = {}) {
|
|
49196
|
+
const doc = readNoteBlocks(id2, { dbPath: dbPath2 });
|
|
49197
|
+
const pk = /\/ICNote\/p([0-9]{1,18})$/.exec(id2)[1];
|
|
49198
|
+
const output = sqlite(dbPath2, [
|
|
49199
|
+
"-cmd",
|
|
49200
|
+
".parameter init",
|
|
49201
|
+
"-cmd",
|
|
49202
|
+
`.parameter set @pk ${pk}`,
|
|
49203
|
+
attachmentQuery(objectColumns(dbPath2))
|
|
49204
|
+
]);
|
|
49205
|
+
let parsed;
|
|
49206
|
+
try {
|
|
49207
|
+
parsed = JSON.parse(output);
|
|
49208
|
+
} catch {
|
|
49209
|
+
throw new NoteBlocksError("query-failed", "Unexpected Notes database response");
|
|
49210
|
+
}
|
|
49211
|
+
const rows = Array.isArray(parsed.attachments) ? parsed.attachments : [];
|
|
49212
|
+
const { byId, ordered } = buildAttachments(rows);
|
|
49213
|
+
const firstLine = doc.blocks.find((block) => block.text.trim())?.text.trim() ?? "";
|
|
49214
|
+
return {
|
|
49215
|
+
id: id2,
|
|
49216
|
+
title: text(parsed.title) ?? firstLine,
|
|
49217
|
+
doc,
|
|
49218
|
+
attachments: byId,
|
|
49219
|
+
ordered
|
|
49220
|
+
};
|
|
49221
|
+
}
|
|
49222
|
+
|
|
49223
|
+
// src/services/notesExport.ts
|
|
49224
|
+
var DEFAULT_FOLDER_EXPORT_LIMIT = 100;
|
|
49225
|
+
var MAX_FOLDER_EXPORT_LIMIT = 1e3;
|
|
49226
|
+
var NotesExportError = class extends Error {
|
|
49227
|
+
constructor(code, message) {
|
|
49228
|
+
super(message);
|
|
49229
|
+
this.code = code;
|
|
49230
|
+
this.name = "NotesExportError";
|
|
49231
|
+
}
|
|
49232
|
+
code;
|
|
49233
|
+
};
|
|
49234
|
+
function validPath(path8, what) {
|
|
49235
|
+
try {
|
|
49236
|
+
return assertExportPath(path8);
|
|
49237
|
+
} catch (error2) {
|
|
49238
|
+
throw new NotesExportError(
|
|
49239
|
+
"invalid-path",
|
|
49240
|
+
`${what}: ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
49241
|
+
);
|
|
49242
|
+
}
|
|
49243
|
+
}
|
|
49244
|
+
function selectNotes(request, deps) {
|
|
49245
|
+
if (!!request.id === !!request.folder)
|
|
49246
|
+
throw new NotesExportError("invalid-request", "Provide exactly one of 'id' or 'folder'.");
|
|
49247
|
+
if (request.id) return [request.id];
|
|
49248
|
+
const limit = Math.min(request.limit ?? DEFAULT_FOLDER_EXPORT_LIMIT, MAX_FOLDER_EXPORT_LIMIT);
|
|
49249
|
+
try {
|
|
49250
|
+
return deps.listNoteRefs(request.account, request.folder, void 0, limit).map((ref) => ref.id);
|
|
49251
|
+
} catch (error2) {
|
|
49252
|
+
throw new NotesExportError(
|
|
49253
|
+
"folder-unavailable",
|
|
49254
|
+
`Could not list folder "${request.folder}": ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
49255
|
+
);
|
|
49256
|
+
}
|
|
49257
|
+
}
|
|
49258
|
+
function loadNotes(ids, single, read) {
|
|
49259
|
+
const notes = [];
|
|
49260
|
+
const skipped = [];
|
|
49261
|
+
for (const id2 of ids) {
|
|
49262
|
+
try {
|
|
49263
|
+
notes.push(read ? read(id2) : readExportNote(id2));
|
|
49264
|
+
} catch (error2) {
|
|
49265
|
+
if (!(error2 instanceof NoteBlocksError)) throw error2;
|
|
49266
|
+
if (single) throw new NotesExportError(error2.code, error2.message);
|
|
49267
|
+
skipped.push({ id: id2, code: error2.code });
|
|
49268
|
+
}
|
|
49269
|
+
}
|
|
49270
|
+
return { notes, skipped };
|
|
49271
|
+
}
|
|
49272
|
+
function exportNotesMarkdown(request, deps) {
|
|
49273
|
+
const output = request.outputPath ? validPath(request.outputPath, "outputPath") : void 0;
|
|
49274
|
+
const assetsDir = request.assetsDir ? validPath(request.assetsDir, "assetsDir") : void 0;
|
|
49275
|
+
if (output && assetsDir && output === assetsDir)
|
|
49276
|
+
throw new NotesExportError("invalid-path", "outputPath and assetsDir must differ.");
|
|
49277
|
+
const ids = selectNotes(request, deps);
|
|
49278
|
+
const { notes, skipped } = loadNotes(ids, !!request.id, deps.readNote);
|
|
49279
|
+
let fd;
|
|
49280
|
+
if (output) {
|
|
49281
|
+
mkdirSync5(dirname4(output), { recursive: true });
|
|
49282
|
+
try {
|
|
49283
|
+
fd = openCreateOnly(output);
|
|
49284
|
+
} catch (error2) {
|
|
49285
|
+
if (error2 instanceof OutputExistsError)
|
|
49286
|
+
throw new NotesExportError("output_exists", error2.message);
|
|
49287
|
+
throw error2;
|
|
49288
|
+
}
|
|
49289
|
+
}
|
|
49290
|
+
const writer = assetsDir ? new SidecarWriter(assetsDir, output ? dirname4(output) : void 0) : void 0;
|
|
49291
|
+
const ctx = {
|
|
49292
|
+
stats: emptyStats(),
|
|
49293
|
+
...writer ? { writer, locator: deps.locator ?? new AssetLocator() } : {}
|
|
49294
|
+
};
|
|
49295
|
+
let markdown;
|
|
49296
|
+
try {
|
|
49297
|
+
markdown = renderNotesMarkdown(notes, ctx, { wrap: request.wrap ?? 0 });
|
|
49298
|
+
} catch (error2) {
|
|
49299
|
+
if (fd !== void 0) writeAllAndClose(fd, "");
|
|
49300
|
+
throw error2;
|
|
49301
|
+
}
|
|
49302
|
+
const bytes = Buffer.byteLength(markdown);
|
|
49303
|
+
const receipt = {
|
|
49304
|
+
format: "markdown",
|
|
49305
|
+
count: notes.length,
|
|
49306
|
+
bytes,
|
|
49307
|
+
stats: ctx.stats,
|
|
49308
|
+
skipped,
|
|
49309
|
+
...assetsDir ? { assets: { dir: assetsDir, files: writer.count } } : {}
|
|
49310
|
+
};
|
|
49311
|
+
if (fd !== void 0) {
|
|
49312
|
+
writeAllAndClose(fd, markdown);
|
|
49313
|
+
return { ...receipt, output };
|
|
49314
|
+
}
|
|
49315
|
+
if (bytes > deps.maxInlineBytes)
|
|
49316
|
+
throw new NotesExportError(
|
|
49317
|
+
"too-large",
|
|
49318
|
+
`The Markdown is ${bytes} bytes, over the ${deps.maxInlineBytes}-byte inline limit. Pass outputPath to write it to a file, or export fewer notes.`
|
|
49319
|
+
);
|
|
49320
|
+
return { ...receipt, markdown };
|
|
49321
|
+
}
|
|
49322
|
+
|
|
49323
|
+
// src/tools/directOperations.ts
|
|
49324
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
49325
|
+
import {
|
|
49326
|
+
closeSync as closeSync5,
|
|
49327
|
+
constants as constants5,
|
|
49328
|
+
fstatSync as fstatSync5,
|
|
49329
|
+
mkdtempSync as mkdtempSync4,
|
|
49330
|
+
openSync as openSync5,
|
|
47879
49331
|
readFileSync as readFileSync3,
|
|
47880
49332
|
rmSync as rmSync4,
|
|
47881
49333
|
writeFileSync as writeFileSync3
|
|
47882
49334
|
} from "node:fs";
|
|
47883
49335
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
47884
|
-
import { basename as
|
|
49336
|
+
import { basename as basename4, extname as extname4, isAbsolute as isAbsolute3, join as join20 } from "node:path";
|
|
47885
49337
|
var noteId = exactIdInput(
|
|
47886
49338
|
"ICNote",
|
|
47887
49339
|
/^x-coredata:\/\/[0-9a-f-]+\/ICNote\/p\d+$/i,
|
|
@@ -47904,7 +49356,7 @@ function readSnapshot(manager, id2) {
|
|
|
47904
49356
|
function assertExistingContentPreserved(before, after) {
|
|
47905
49357
|
if (before.id !== after.id || before.title !== after.title)
|
|
47906
49358
|
throw new Error("Note identity changed");
|
|
47907
|
-
const tidy = (
|
|
49359
|
+
const tidy = (text2) => text2.replace(/\r\n/g, "\n").replace(/[\s\ufffc]+$/gu, "");
|
|
47908
49360
|
if (!tidy(after.rich.text).startsWith(tidy(before.rich.text)))
|
|
47909
49361
|
throw new Error("Existing note text was not preserved");
|
|
47910
49362
|
if (linkSignature(before.rich.links) !== linkSignature(after.rich.links.slice(0, before.rich.links.length)))
|
|
@@ -47924,11 +49376,11 @@ function assertExistingContentPreserved(before, after) {
|
|
|
47924
49376
|
throw new Error("Existing native object content or presentation changed");
|
|
47925
49377
|
}
|
|
47926
49378
|
}
|
|
47927
|
-
function localAttachment(
|
|
47928
|
-
if (!isAbsolute3(
|
|
47929
|
-
const descriptor =
|
|
49379
|
+
function localAttachment(path8) {
|
|
49380
|
+
if (!isAbsolute3(path8)) throw new Error("An absolute local file path is required");
|
|
49381
|
+
const descriptor = openSync5(path8, constants5.O_RDONLY | constants5.O_NOFOLLOW);
|
|
47930
49382
|
try {
|
|
47931
|
-
const stat =
|
|
49383
|
+
const stat = fstatSync5(descriptor);
|
|
47932
49384
|
if (!stat.isFile() || stat.size === 0 || stat.size > 64 * 1024 * 1024)
|
|
47933
49385
|
throw new Error("Attachment must be a nonempty regular file of at most 64 MiB");
|
|
47934
49386
|
const bytes = readFileSync3(descriptor);
|
|
@@ -47936,7 +49388,7 @@ function localAttachment(path7) {
|
|
|
47936
49388
|
throw new Error("Attachment changed while it was being read; try again");
|
|
47937
49389
|
return bytes;
|
|
47938
49390
|
} finally {
|
|
47939
|
-
|
|
49391
|
+
closeSync5(descriptor);
|
|
47940
49392
|
}
|
|
47941
49393
|
}
|
|
47942
49394
|
function registerDirectOperations(server2, manager) {
|
|
@@ -48048,8 +49500,8 @@ function registerDirectOperations(server2, manager) {
|
|
|
48048
49500
|
}
|
|
48049
49501
|
);
|
|
48050
49502
|
}
|
|
48051
|
-
function attachmentName(
|
|
48052
|
-
const source =
|
|
49503
|
+
function attachmentName(path8, filename) {
|
|
49504
|
+
const source = basename4(path8);
|
|
48053
49505
|
if (filename === void 0) return source;
|
|
48054
49506
|
if (Buffer.byteLength(filename, "utf8") > 255)
|
|
48055
49507
|
throw new Error("filename must be at most 255 bytes");
|
|
@@ -48057,21 +49509,21 @@ function attachmentName(path7, filename) {
|
|
|
48057
49509
|
throw new Error(
|
|
48058
49510
|
"filename must be one path component with no slash, colon, backslash, control character, leading dot, or surrounding spaces"
|
|
48059
49511
|
);
|
|
48060
|
-
if (
|
|
49512
|
+
if (extname4(filename).toLowerCase() !== extname4(source).toLowerCase())
|
|
48061
49513
|
throw new Error(
|
|
48062
|
-
`filename must keep the source file's extension (${
|
|
49514
|
+
`filename must keep the source file's extension (${extname4(source) || "none"})`
|
|
48063
49515
|
);
|
|
48064
49516
|
return filename;
|
|
48065
49517
|
}
|
|
48066
49518
|
function attachFile(manager, args) {
|
|
48067
|
-
const { id: id2, expectedContentHash, path:
|
|
48068
|
-
const name = attachmentName(
|
|
49519
|
+
const { id: id2, expectedContentHash, path: path8 } = args;
|
|
49520
|
+
const name = attachmentName(path8, args.filename);
|
|
48069
49521
|
const before = readSnapshot(manager, id2);
|
|
48070
49522
|
if (before.hash !== expectedContentHash) throw new Error("Note revision changed");
|
|
48071
|
-
const bytes = localAttachment(
|
|
49523
|
+
const bytes = localAttachment(path8);
|
|
48072
49524
|
const beforeAttachments = manager.listAttachmentsById(id2);
|
|
48073
|
-
const directory = mkdtempSync4(
|
|
48074
|
-
const temporaryFile =
|
|
49525
|
+
const directory = mkdtempSync4(join20(tmpdir4(), "notes-attachment-add-"));
|
|
49526
|
+
const temporaryFile = join20(directory, name);
|
|
48075
49527
|
try {
|
|
48076
49528
|
writeFileSync3(temporaryFile, bytes, { mode: 384 });
|
|
48077
49529
|
if (readSnapshot(manager, id2).hash !== before.hash) throw new Error("Note revision changed");
|
|
@@ -48263,18 +49715,18 @@ function appendChecklistItems(args, deps, readRich) {
|
|
|
48263
49715
|
const existing = new Set(byPosition(readRich(args.id).checklistItems).map((item) => item.id));
|
|
48264
49716
|
const landed = [];
|
|
48265
49717
|
let contentHash = args.expectedContentHash;
|
|
48266
|
-
for (const [index,
|
|
49718
|
+
for (const [index, text2] of args.items.entries()) {
|
|
48267
49719
|
let wrote = false;
|
|
48268
49720
|
try {
|
|
48269
49721
|
const result = mutateBackground(
|
|
48270
49722
|
{ ...args, expectedContentHash: contentHash },
|
|
48271
49723
|
"create-checklist-item",
|
|
48272
|
-
{ text },
|
|
49724
|
+
{ text: text2 },
|
|
48273
49725
|
(before, after) => {
|
|
48274
49726
|
wrote = true;
|
|
48275
49727
|
assertPreserved(before, after, { append: true });
|
|
48276
49728
|
const added = after.checklist.slice(before.checklist.length);
|
|
48277
|
-
if (added.length !== 1 || added[0].text !==
|
|
49729
|
+
if (added.length !== 1 || added[0].text !== text2 || added[0].done)
|
|
48278
49730
|
throw new Error("Native checklist item not verified");
|
|
48279
49731
|
},
|
|
48280
49732
|
deps
|
|
@@ -48283,14 +49735,14 @@ function appendChecklistItems(args, deps, readRich) {
|
|
|
48283
49735
|
const fresh = items.filter(
|
|
48284
49736
|
(item) => !existing.has(item.id) && !landed.some((done) => done.id === item.id)
|
|
48285
49737
|
);
|
|
48286
|
-
if (fresh.length !== 1 || fresh[0].text !==
|
|
49738
|
+
if (fresh.length !== 1 || fresh[0].text !== text2 || fresh[0].done)
|
|
48287
49739
|
throw new Error("Native checklist identity not verified");
|
|
48288
49740
|
for (const done of landed) {
|
|
48289
49741
|
const current = items.find((item) => item.id === done.id);
|
|
48290
49742
|
if (!current || current.text !== done.text || current.done)
|
|
48291
49743
|
throw new Error("An earlier appended item changed identity or text");
|
|
48292
49744
|
}
|
|
48293
|
-
landed.push({ index, id: fresh[0].id, text });
|
|
49745
|
+
landed.push({ index, id: fresh[0].id, text: text2 });
|
|
48294
49746
|
contentHash = result.contentHash;
|
|
48295
49747
|
} catch (error2) {
|
|
48296
49748
|
return {
|
|
@@ -48299,7 +49751,7 @@ function appendChecklistItems(args, deps, readRich) {
|
|
|
48299
49751
|
landed,
|
|
48300
49752
|
stoppedAt: {
|
|
48301
49753
|
index,
|
|
48302
|
-
text,
|
|
49754
|
+
text: text2,
|
|
48303
49755
|
outcome: wrote ? "uncertain" : "not-written",
|
|
48304
49756
|
error: error2 instanceof Error ? error2.message : String(error2)
|
|
48305
49757
|
},
|
|
@@ -48629,9 +50081,9 @@ function registerNativeOperations(server2, manager) {
|
|
|
48629
50081
|
|
|
48630
50082
|
// src/setupShortcuts.ts
|
|
48631
50083
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
48632
|
-
import { existsSync as
|
|
50084
|
+
import { existsSync as existsSync12 } from "node:fs";
|
|
48633
50085
|
import { release as release2 } from "node:os";
|
|
48634
|
-
import { dirname as
|
|
50086
|
+
import { dirname as dirname5, resolve as resolve4 } from "node:path";
|
|
48635
50087
|
import { fileURLToPath } from "node:url";
|
|
48636
50088
|
var OPTIONAL_BRIDGE_NOTE = "(optional \u2014 needed only for create-note format: markdown, macOS 26+)";
|
|
48637
50089
|
var MARKDOWN_MIN_DARWIN_MAJOR = 25;
|
|
@@ -48649,16 +50101,16 @@ var shortcutFiles = [
|
|
|
48649
50101
|
];
|
|
48650
50102
|
function setupShortcuts(checkOnly, dependencies = {}) {
|
|
48651
50103
|
const status = dependencies.status || nativeTagsStatus;
|
|
48652
|
-
const exists = dependencies.exists ||
|
|
48653
|
-
const open = dependencies.open || ((
|
|
48654
|
-
const result = spawnSync2("/usr/bin/open", [
|
|
50104
|
+
const exists = dependencies.exists || existsSync12;
|
|
50105
|
+
const open = dependencies.open || ((path8) => {
|
|
50106
|
+
const result = spawnSync2("/usr/bin/open", [path8], { encoding: "utf8" });
|
|
48655
50107
|
return result.status === 0 ? { ok: true } : { ok: false, error: result.stderr || result.error?.message || "open failed" };
|
|
48656
50108
|
});
|
|
48657
|
-
const baseDirectory = dependencies.baseDirectory ||
|
|
50109
|
+
const baseDirectory = dependencies.baseDirectory || resolve4(dirname5(fileURLToPath(import.meta.url)), "../shortcuts");
|
|
48658
50110
|
const osRelease = (dependencies.osRelease || release2)();
|
|
48659
50111
|
const darwinMajor = Number.parseInt(osRelease.split(".")[0], 10);
|
|
48660
50112
|
const items = shortcutFiles.map(({ name, file, optional: optional2 }) => {
|
|
48661
|
-
const
|
|
50113
|
+
const path8 = resolve4(baseDirectory, file);
|
|
48662
50114
|
let installed = false;
|
|
48663
50115
|
let identifier;
|
|
48664
50116
|
let error2;
|
|
@@ -48674,9 +50126,9 @@ function setupShortcuts(checkOnly, dependencies = {}) {
|
|
|
48674
50126
|
if (!installed && !checkOnly) {
|
|
48675
50127
|
if (optional2 && !(darwinMajor >= MARKDOWN_MIN_DARWIN_MAJOR))
|
|
48676
50128
|
skipped = `requires macOS 26 or later (this Mac reports Darwin ${osRelease})`;
|
|
48677
|
-
else if (!exists(
|
|
50129
|
+
else if (!exists(path8)) error2 = `Packaged Shortcut is missing: ${path8}`;
|
|
48678
50130
|
else {
|
|
48679
|
-
const result = open(
|
|
50131
|
+
const result = open(path8);
|
|
48680
50132
|
opened = result.ok;
|
|
48681
50133
|
if (!result.ok) error2 = result.error || `Could not open ${file}`;
|
|
48682
50134
|
}
|
|
@@ -48685,7 +50137,7 @@ function setupShortcuts(checkOnly, dependencies = {}) {
|
|
|
48685
50137
|
name,
|
|
48686
50138
|
installed,
|
|
48687
50139
|
identifier,
|
|
48688
|
-
file:
|
|
50140
|
+
file: path8,
|
|
48689
50141
|
opened,
|
|
48690
50142
|
...optional2 ? { optional: optional2 } : {},
|
|
48691
50143
|
...skipped ? { skipped } : {},
|
|
@@ -49616,19 +51068,47 @@ registerTool(
|
|
|
49616
51068
|
registerTool(
|
|
49617
51069
|
"list-native-tags",
|
|
49618
51070
|
{
|
|
49619
|
-
description: "Use when: listing actual native Notes tags
|
|
51071
|
+
description: "Use when: listing actual native Notes tags, either in one folder (pass folder) or as an account-wide inventory with note counts (omit folder; account then optionally narrows it, else every account is counted).\nReturns: folder mode maps each tag to exact matching note IDs, plus completeness and per-note errors; inventory mode returns each tag with noteCount and per-account counts, sorted by count.\nDo not use when: searching textual #hashtags in note bodies (search-notes).\nSafety: read-only; requires Full Disk Access and discloses partial reads.",
|
|
49620
51072
|
inputSchema: {
|
|
49621
|
-
account: external_exports.string().min(1).max(MAX.ACCOUNT)
|
|
49622
|
-
|
|
51073
|
+
account: external_exports.string().min(1).max(MAX.ACCOUNT).optional().describe(
|
|
51074
|
+
"Account name (exact or unique prefix). Folder mode: defaults to Notes.app's default account. Inventory mode: omit to count every account."
|
|
51075
|
+
),
|
|
51076
|
+
folder: external_exports.string().min(1).max(MAX.FOLDER).optional().describe("Folder to list tags in. Omit for the account-wide inventory with counts.")
|
|
49623
51077
|
},
|
|
49624
51078
|
outputSchema: {
|
|
49625
51079
|
tags: external_exports.record(external_exports.array(external_exports.string())).optional(),
|
|
49626
51080
|
complete: external_exports.boolean().optional(),
|
|
49627
|
-
errors: external_exports.record(external_exports.string()).optional()
|
|
51081
|
+
errors: external_exports.record(external_exports.string()).optional(),
|
|
51082
|
+
inventory: external_exports.array(
|
|
51083
|
+
external_exports.object({
|
|
51084
|
+
tag: external_exports.string(),
|
|
51085
|
+
noteCount: external_exports.number(),
|
|
51086
|
+
accounts: external_exports.record(external_exports.number()),
|
|
51087
|
+
spellings: external_exports.array(external_exports.string()).optional()
|
|
51088
|
+
}).passthrough()
|
|
51089
|
+
).optional(),
|
|
51090
|
+
tagCount: external_exports.number().optional(),
|
|
51091
|
+
unverifiedNotes: external_exports.number().optional(),
|
|
51092
|
+
account: external_exports.string().optional()
|
|
49628
51093
|
},
|
|
49629
51094
|
annotations: { readOnlyHint: true }
|
|
49630
51095
|
},
|
|
49631
51096
|
withErrorHandling(({ account, folder }) => {
|
|
51097
|
+
if (!folder) {
|
|
51098
|
+
const result = nativeTagInventory({ account });
|
|
51099
|
+
const scope2 = result.account ? ` in ${result.account}` : " across all accounts";
|
|
51100
|
+
const lines = result.inventory.map(
|
|
51101
|
+
(entry) => ` - ${entry.tag}: ${entry.noteCount} note${entry.noteCount === 1 ? "" : "s"}`
|
|
51102
|
+
);
|
|
51103
|
+
const partial2 = result.complete ? "" : `
|
|
51104
|
+
|
|
51105
|
+
${result.unverifiedNotes} note(s) could not be checked against their body (locked or unreadable) and were counted from tag objects alone.`;
|
|
51106
|
+
return successResponse(
|
|
51107
|
+
`${result.tagCount} native tag${result.tagCount === 1 ? "" : "s"}${scope2}` + (lines.length ? `:
|
|
51108
|
+
${lines.join("\n")}` : ".") + partial2,
|
|
51109
|
+
result
|
|
51110
|
+
);
|
|
51111
|
+
}
|
|
49632
51112
|
const tags = {};
|
|
49633
51113
|
const errors = {};
|
|
49634
51114
|
for (const note of notesManager.listNoteRefs(account, folder)) {
|
|
@@ -49764,17 +51244,17 @@ function guardedAppend({
|
|
|
49764
51244
|
scopeText,
|
|
49765
51245
|
htmlSeparator
|
|
49766
51246
|
}, onRoute) {
|
|
49767
|
-
const contentToHtml = (
|
|
49768
|
-
if (format === "html") return
|
|
49769
|
-
return
|
|
51247
|
+
const contentToHtml = (text2) => {
|
|
51248
|
+
if (format === "html") return text2;
|
|
51249
|
+
return text2.split("\n").map((line) => {
|
|
49770
51250
|
const escaped = line.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
49771
51251
|
return `<div>${escaped || "<br>"}</div>`;
|
|
49772
51252
|
}).join("");
|
|
49773
51253
|
};
|
|
49774
|
-
const separatorToHtml = (
|
|
49775
|
-
if (format === "html") return
|
|
49776
|
-
if (
|
|
49777
|
-
const escaped =
|
|
51254
|
+
const separatorToHtml = (sep4) => {
|
|
51255
|
+
if (format === "html") return sep4;
|
|
51256
|
+
if (sep4 === "\n\n") return "<div><br></div>";
|
|
51257
|
+
const escaped = sep4.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
49778
51258
|
return `<div>${escaped}</div>`;
|
|
49779
51259
|
};
|
|
49780
51260
|
const snapshot = readExactNoteSnapshot(id2);
|
|
@@ -50538,8 +52018,8 @@ registerTool(
|
|
|
50538
52018
|
if (firstImage && id2) {
|
|
50539
52019
|
const assets = notesManager.getAttachmentAssetsById(id2);
|
|
50540
52020
|
const first2 = firstImageView(id2, selectFirstImage(assets));
|
|
50541
|
-
const
|
|
50542
|
-
return successResponse(
|
|
52021
|
+
const text2 = first2 ? `Lead visual: ${first2.kind} attachment ${first2.attachmentId} (${first2.path ? "asset on disk" : first2.previewPath ? "preview only" : "not downloaded"}; order from ${assets.orderSource}).` : "This note has no image, scan, or drawing attachment.";
|
|
52022
|
+
return successResponse(text2, { firstImage: first2, orderSource: assets.orderSource });
|
|
50543
52023
|
}
|
|
50544
52024
|
if (id2) {
|
|
50545
52025
|
const note2 = notesManager.getNoteById(id2);
|
|
@@ -51043,6 +52523,67 @@ registerTool(
|
|
|
51043
52523
|
return successResponse(markdown, { markdown });
|
|
51044
52524
|
}, "Error getting note as markdown")
|
|
51045
52525
|
);
|
|
52526
|
+
var exportPathInput = (what) => external_exports.string().min(1).max(MAX.SAVE_PATH).optional().describe(
|
|
52527
|
+
`${what} (absolute; under home, a temp dir, or /Volumes; never inside the Notes library)`
|
|
52528
|
+
);
|
|
52529
|
+
var exportStatsSchema = external_exports.object({
|
|
52530
|
+
attachments: external_exports.number(),
|
|
52531
|
+
placed: external_exports.number(),
|
|
52532
|
+
placeholders: external_exports.number(),
|
|
52533
|
+
unavailable: external_exports.number(),
|
|
52534
|
+
tables: external_exports.number(),
|
|
52535
|
+
unreadableTables: external_exports.number(),
|
|
52536
|
+
unreferenced: external_exports.number()
|
|
52537
|
+
});
|
|
52538
|
+
registerTool(
|
|
52539
|
+
"export-notes-markdown",
|
|
52540
|
+
{
|
|
52541
|
+
description: "Use when: exporting one note (by exact id) or a folder's notes as one Markdown document rendered from the decoded note body: headings, bulleted/dashed/numbered lists with indent, checklists with state, block quotes, monospaced blocks, bold/italic/strikethrough/underline/highlight, links, tables, and attachments in body order.\nReturns: the Markdown inline (capped by APPLE_NOTES_MCP_EXPORT_MAX_BYTES), or with outputPath a receipt {format, count, bytes, output}; plus attachment counts and skipped notes (for example password-protected ones).\nDo not use when: you need the legacy HTML-converted Markdown of one note (get-note-markdown) or a restorable backup (export-notes-json). A folder document separates notes with '---' and is a presentation format, not something to import back.\nSafety: read-only against Notes; requires Full Disk Access. outputPath is create-only (an existing file is refused with [output_exists]); assetsDir copies attachment files without replacing existing ones (collisions get -2, -3 suffixes). Without assetsDir, attachments render as labeled placeholders.",
|
|
52542
|
+
inputSchema: {
|
|
52543
|
+
id: noteIdInput.optional(),
|
|
52544
|
+
folder: external_exports.string().min(1).max(MAX.FOLDER).optional().describe("Folder path to export instead of one note (nested paths use '/')"),
|
|
52545
|
+
account: external_exports.string().max(MAX.ACCOUNT).optional().describe("Account holding the folder (defaults to Notes.app's default account)"),
|
|
52546
|
+
limit: external_exports.number().int().min(1).max(MAX_FOLDER_EXPORT_LIMIT).optional().describe(
|
|
52547
|
+
`Maximum notes read from the folder (default 100, max ${MAX_FOLDER_EXPORT_LIMIT})`
|
|
52548
|
+
),
|
|
52549
|
+
outputPath: exportPathInput("File to create for the Markdown"),
|
|
52550
|
+
assetsDir: exportPathInput("Directory that receives copies of attachment files"),
|
|
52551
|
+
wrap: external_exports.number().int().min(0).max(1e3).optional().describe("Hard-wrap prose at this many columns (0 or omitted: no wrapping)")
|
|
52552
|
+
},
|
|
52553
|
+
outputSchema: {
|
|
52554
|
+
format: external_exports.string().optional(),
|
|
52555
|
+
count: external_exports.number().optional(),
|
|
52556
|
+
bytes: external_exports.number().optional(),
|
|
52557
|
+
markdown: external_exports.string().optional(),
|
|
52558
|
+
output: external_exports.string().optional(),
|
|
52559
|
+
assets: external_exports.object({ dir: external_exports.string(), files: external_exports.number() }).optional(),
|
|
52560
|
+
stats: exportStatsSchema.optional(),
|
|
52561
|
+
skipped: external_exports.array(external_exports.object({ id: external_exports.string(), code: external_exports.string() })).optional()
|
|
52562
|
+
},
|
|
52563
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false }
|
|
52564
|
+
},
|
|
52565
|
+
withErrorHandling((request) => {
|
|
52566
|
+
let receipt;
|
|
52567
|
+
try {
|
|
52568
|
+
receipt = exportNotesMarkdown(request, {
|
|
52569
|
+
listNoteRefs: (account, folder, since, limit) => notesManager.listNoteRefs(account, folder, since, limit),
|
|
52570
|
+
// The document travels twice (text and structuredContent).
|
|
52571
|
+
maxInlineBytes: Math.floor(exportMaxResponseBytes() / 2) - 64 * 1024
|
|
52572
|
+
});
|
|
52573
|
+
} catch (error2) {
|
|
52574
|
+
if (!(error2 instanceof NotesExportError || error2 instanceof NoteBlocksError)) throw error2;
|
|
52575
|
+
const hint = error2.code === "no-full-disk-access" ? ` Grant Full Disk Access to the app that launches this server: ${FULL_DISK_ACCESS_GUIDE_URL}` : "";
|
|
52576
|
+
return errorResponse(`Error exporting Markdown [${error2.code}]: ${error2.message}${hint}`);
|
|
52577
|
+
}
|
|
52578
|
+
const skipped = receipt.skipped.length ? `; skipped ${receipt.skipped.length}` : "";
|
|
52579
|
+
if (receipt.output)
|
|
52580
|
+
return successResponse(
|
|
52581
|
+
`Wrote ${receipt.count} note(s) as Markdown (${receipt.bytes} bytes) to ${receipt.output}` + (receipt.assets ? `; copied ${receipt.assets.files} asset file(s) to ${receipt.assets.dir}` : "") + `${skipped}.`,
|
|
52582
|
+
{ ...receipt }
|
|
52583
|
+
);
|
|
52584
|
+
return successResponse(receipt.markdown ?? "", { ...receipt });
|
|
52585
|
+
}, "Error exporting Markdown")
|
|
52586
|
+
);
|
|
51046
52587
|
registerTool(
|
|
51047
52588
|
"get-checklist-state",
|
|
51048
52589
|
{
|
|
@@ -51150,6 +52691,57 @@ registerTool(
|
|
|
51150
52691
|
return successResponse(summary, metadata);
|
|
51151
52692
|
}, "Error reading note metadata")
|
|
51152
52693
|
);
|
|
52694
|
+
var SPECIAL_KIND_LABEL = {
|
|
52695
|
+
pinned: "pinned notes",
|
|
52696
|
+
"quick-notes": "Quick Notes",
|
|
52697
|
+
"recently-deleted": "notes in Recently Deleted",
|
|
52698
|
+
locked: "password-protected notes"
|
|
52699
|
+
};
|
|
52700
|
+
registerTool(
|
|
52701
|
+
"list-special-notes",
|
|
52702
|
+
{
|
|
52703
|
+
description: "Use when: listing pinned notes, Quick Notes, notes in Recently Deleted, or password-protected (locked) notes \u2014 sets AppleScript cannot enumerate.\nReturns: metadata rows newest first (id, identifier, title, folder path, account, created, modified, and pinned/locked/quickNote/inRecentlyDeleted flags; snippet except for locked notes; passwordHint for kind locked), plus total before limit. supported is false when this macOS version's database cannot answer that kind.\nDo not use when: you need note content (get-note-content) or a folder listing (list-notes).\nNote: reads the NoteStore SQLite database read-only and requires Full Disk Access. Pinned and Quick Notes listings cover notes in folders outside Recently Deleted; the locked listing includes trashed and folderless locked notes, flagged as such. Never reads locked note bodies.",
|
|
52704
|
+
inputSchema: {
|
|
52705
|
+
kind: external_exports.enum(["pinned", "quick-notes", "recently-deleted", "locked"]).describe("Which set of notes to list"),
|
|
52706
|
+
account: external_exports.string().min(1).max(MAX.ACCOUNT).optional().describe("Only this account (exact or unique-prefix name). Omit for every account."),
|
|
52707
|
+
limit: external_exports.number().int().min(1).max(SPECIAL_LIMIT.MAX).optional().describe(`Maximum notes to return (default ${SPECIAL_LIMIT.DEFAULT})`)
|
|
52708
|
+
},
|
|
52709
|
+
outputSchema: {
|
|
52710
|
+
kind: external_exports.string().optional(),
|
|
52711
|
+
notes: external_exports.array(external_exports.object({}).passthrough()).optional(),
|
|
52712
|
+
count: external_exports.number().optional(),
|
|
52713
|
+
total: external_exports.number().optional(),
|
|
52714
|
+
limit: external_exports.number().optional(),
|
|
52715
|
+
supported: external_exports.boolean().optional(),
|
|
52716
|
+
account: external_exports.string().optional()
|
|
52717
|
+
},
|
|
52718
|
+
annotations: { readOnlyHint: true }
|
|
52719
|
+
},
|
|
52720
|
+
withErrorHandling(({ kind, account, limit }) => {
|
|
52721
|
+
const result = listSpecialNotes({ kind, account, limit });
|
|
52722
|
+
const label = SPECIAL_KIND_LABEL[kind];
|
|
52723
|
+
const structured = result;
|
|
52724
|
+
if (!result.supported) {
|
|
52725
|
+
return successResponse(
|
|
52726
|
+
`This macOS version's Notes database does not record ${label}.`,
|
|
52727
|
+
structured
|
|
52728
|
+
);
|
|
52729
|
+
}
|
|
52730
|
+
const scope2 = result.account ? ` in ${result.account}` : "";
|
|
52731
|
+
if (result.count === 0) return successResponse(`No ${label}${scope2}.`, structured);
|
|
52732
|
+
const lines = result.notes.map(
|
|
52733
|
+
(row) => ` - ${row.title ?? "(untitled)"}${row.folder ? ` (${row.folder})` : ""} [id: ${row.id}]`
|
|
52734
|
+
);
|
|
52735
|
+
const more = result.total > result.count ? `
|
|
52736
|
+
|
|
52737
|
+
Showing ${result.count} of ${result.total}; pass a higher limit to see more.` : "";
|
|
52738
|
+
return successResponse(
|
|
52739
|
+
`Found ${result.total} ${label}${scope2}:
|
|
52740
|
+
${lines.join("\n")}${more}`,
|
|
52741
|
+
structured
|
|
52742
|
+
);
|
|
52743
|
+
}, "Error listing notes")
|
|
52744
|
+
);
|
|
51153
52745
|
registerResourcesAndPrompts(server, notesManager);
|
|
51154
52746
|
process.on("uncaughtException", (err) => {
|
|
51155
52747
|
if (err?.code === "EPIPE") process.exit(0);
|