apple-notes-mcp 2.8.38 → 2.8.39
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 +9 -2
- package/build/index.js +479 -321
- package/package.json +1 -1
package/build/index.js
CHANGED
|
@@ -3268,8 +3268,8 @@ var require_utils = __commonJS({
|
|
|
3268
3268
|
}
|
|
3269
3269
|
return ind;
|
|
3270
3270
|
}
|
|
3271
|
-
function removeDotSegments(
|
|
3272
|
-
let input =
|
|
3271
|
+
function removeDotSegments(path9) {
|
|
3272
|
+
let input = path9;
|
|
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 path9 = queryIndex === -1 ? wsComponent.resourceName : wsComponent.resourceName.slice(0, queryIndex);
|
|
3678
|
+
wsComponent.path = path9 && path9 !== "/" ? path9 : void 0;
|
|
3679
3679
|
wsComponent.query = queryIndex === -1 ? void 0 : wsComponent.resourceName.slice(queryIndex + 1);
|
|
3680
3680
|
wsComponent.resourceName = void 0;
|
|
3681
3681
|
}
|
|
@@ -7181,12 +7181,12 @@ var require_dist = __commonJS({
|
|
|
7181
7181
|
throw new Error(`Unknown format "${name}"`);
|
|
7182
7182
|
return f;
|
|
7183
7183
|
};
|
|
7184
|
-
function addFormats(ajv, list,
|
|
7184
|
+
function addFormats(ajv, list, fs9, 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, fs9[f]);
|
|
7190
7190
|
}
|
|
7191
7191
|
module.exports = exports = formatsPlugin;
|
|
7192
7192
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -12238,32 +12238,32 @@ var require_URL = __commonJS({
|
|
|
12238
12238
|
else
|
|
12239
12239
|
return basepath.substring(0, lastslash + 1) + refpath;
|
|
12240
12240
|
}
|
|
12241
|
-
function remove_dot_segments(
|
|
12242
|
-
if (!
|
|
12241
|
+
function remove_dot_segments(path9) {
|
|
12242
|
+
if (!path9) return path9;
|
|
12243
12243
|
var output = "";
|
|
12244
|
-
while (
|
|
12245
|
-
if (
|
|
12246
|
-
|
|
12244
|
+
while (path9.length > 0) {
|
|
12245
|
+
if (path9 === "." || path9 === "..") {
|
|
12246
|
+
path9 = "";
|
|
12247
12247
|
break;
|
|
12248
12248
|
}
|
|
12249
|
-
var twochars =
|
|
12250
|
-
var threechars =
|
|
12251
|
-
var fourchars =
|
|
12249
|
+
var twochars = path9.substring(0, 2);
|
|
12250
|
+
var threechars = path9.substring(0, 3);
|
|
12251
|
+
var fourchars = path9.substring(0, 4);
|
|
12252
12252
|
if (threechars === "../") {
|
|
12253
|
-
|
|
12253
|
+
path9 = path9.substring(3);
|
|
12254
12254
|
} else if (twochars === "./") {
|
|
12255
|
-
|
|
12255
|
+
path9 = path9.substring(2);
|
|
12256
12256
|
} else if (threechars === "/./") {
|
|
12257
|
-
|
|
12258
|
-
} else if (twochars === "/." &&
|
|
12259
|
-
|
|
12260
|
-
} else if (fourchars === "/../" || threechars === "/.." &&
|
|
12261
|
-
|
|
12257
|
+
path9 = "/" + path9.substring(3);
|
|
12258
|
+
} else if (twochars === "/." && path9.length === 2) {
|
|
12259
|
+
path9 = "/";
|
|
12260
|
+
} else if (fourchars === "/../" || threechars === "/.." && path9.length === 3) {
|
|
12261
|
+
path9 = "/" + path9.substring(4);
|
|
12262
12262
|
output = output.replace(/\/?[^\/]*$/, "");
|
|
12263
12263
|
} else {
|
|
12264
|
-
var segment =
|
|
12264
|
+
var segment = path9.match(/(\/?([^\/]*))/)[0];
|
|
12265
12265
|
output += segment;
|
|
12266
|
-
|
|
12266
|
+
path9 = path9.substring(segment.length);
|
|
12267
12267
|
}
|
|
12268
12268
|
}
|
|
12269
12269
|
return output;
|
|
@@ -24465,14 +24465,14 @@ var require_turndown_cjs = __commonJS({
|
|
|
24465
24465
|
} else if (node.nodeType === 1) {
|
|
24466
24466
|
replacement = replacementForNode.call(self, node);
|
|
24467
24467
|
}
|
|
24468
|
-
return
|
|
24468
|
+
return join23(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 = join23(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 join23(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: path9, errorMaps, issueData } = params;
|
|
24983
|
+
const fullPath = [...path9, ...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, path9, key) {
|
|
25100
25100
|
this._cachedPath = [];
|
|
25101
25101
|
this.parent = parent;
|
|
25102
25102
|
this.data = value;
|
|
25103
|
-
this._path =
|
|
25103
|
+
this._path = path9;
|
|
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, path9) {
|
|
28741
|
+
if (!path9)
|
|
28742
28742
|
return obj;
|
|
28743
|
-
return
|
|
28743
|
+
return path9.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(path9, 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(path9);
|
|
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(path9) {
|
|
32479
|
+
if (path9.length === 0) {
|
|
32480
32480
|
return "object root";
|
|
32481
32481
|
}
|
|
32482
|
-
return
|
|
32482
|
+
return path9.reduce((acc, seg, index) => {
|
|
32483
32483
|
if (index === 0) {
|
|
32484
32484
|
return String(seg);
|
|
32485
32485
|
}
|
|
@@ -39452,9 +39452,9 @@ function queryNoteData(noteId3) {
|
|
|
39452
39452
|
return { hex: null, error: "invalid_id" };
|
|
39453
39453
|
}
|
|
39454
39454
|
const pk = pkMatch[1];
|
|
39455
|
-
const
|
|
39455
|
+
const query2 = `SELECT hex(nd.ZDATA) FROM ZICNOTEDATA nd JOIN ZICCLOUDSYNCINGOBJECT n ON nd.ZNOTE = n.Z_PK WHERE n.Z_PK = ${pk};`;
|
|
39456
39456
|
try {
|
|
39457
|
-
const result = execFileSync2("sqlite3", ["-readonly", NOTES_DB_PATH,
|
|
39457
|
+
const result = execFileSync2("sqlite3", ["-readonly", NOTES_DB_PATH, query2], {
|
|
39458
39458
|
encoding: "utf8",
|
|
39459
39459
|
timeout: 5e3,
|
|
39460
39460
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -40713,7 +40713,7 @@ function decodeSmartFolderQuery(raw, context = {}) {
|
|
|
40713
40713
|
inner = type.and.filter((clause) => !isDeletedWrapper(clause));
|
|
40714
40714
|
}
|
|
40715
40715
|
}
|
|
40716
|
-
const
|
|
40716
|
+
const query2 = inner.length === 1 ? inner[0] : { and: inner };
|
|
40717
40717
|
let match = "all";
|
|
40718
40718
|
let filters;
|
|
40719
40719
|
const only = inner.length === 1 && isClause(inner[0]) ? inner[0] : void 0;
|
|
@@ -40732,7 +40732,7 @@ function decodeSmartFolderQuery(raw, context = {}) {
|
|
|
40732
40732
|
return {
|
|
40733
40733
|
match,
|
|
40734
40734
|
filters,
|
|
40735
|
-
query,
|
|
40735
|
+
query: query2,
|
|
40736
40736
|
...includesRecentlyDeleted === void 0 ? {} : { includesRecentlyDeleted },
|
|
40737
40737
|
fullyDecoded: decoder.fullyDecoded
|
|
40738
40738
|
};
|
|
@@ -40854,11 +40854,55 @@ function readSmartFolders(dbPath2 = NOTES_DB_PATH3) {
|
|
|
40854
40854
|
}
|
|
40855
40855
|
}
|
|
40856
40856
|
|
|
40857
|
+
// src/utils/trashFolders.ts
|
|
40858
|
+
import { execFileSync as execFileSync6 } from "child_process";
|
|
40859
|
+
import * as fs3 from "fs";
|
|
40860
|
+
import * as os3 from "os";
|
|
40861
|
+
import * as path3 from "path";
|
|
40862
|
+
var NOTES_DB_PATH4 = path3.join(
|
|
40863
|
+
os3.homedir(),
|
|
40864
|
+
"Library/Group Containers/group.com.apple.notes/NoteStore.sqlite"
|
|
40865
|
+
);
|
|
40866
|
+
var RECENTLY_DELETED_FOLDER_NAME = "Recently Deleted";
|
|
40867
|
+
var CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
40868
|
+
var cache = null;
|
|
40869
|
+
function query(dbPath2, sql) {
|
|
40870
|
+
return execFileSync6("sqlite3", ["-readonly", dbPath2, sql], {
|
|
40871
|
+
encoding: "utf8",
|
|
40872
|
+
timeout: 5e3,
|
|
40873
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
40874
|
+
});
|
|
40875
|
+
}
|
|
40876
|
+
function readTrashFolderIds(dbPath2 = NOTES_DB_PATH4) {
|
|
40877
|
+
if (cache && cache.dbPath === dbPath2 && Date.now() - cache.at < CACHE_TTL_MS) {
|
|
40878
|
+
return cache.ids;
|
|
40879
|
+
}
|
|
40880
|
+
try {
|
|
40881
|
+
if (!fs3.existsSync(dbPath2)) return [];
|
|
40882
|
+
const columns = new Set(
|
|
40883
|
+
query(dbPath2, "SELECT name FROM pragma_table_info('ZICCLOUDSYNCINGOBJECT');").split("\n").map((line) => line.trim()).filter(Boolean)
|
|
40884
|
+
);
|
|
40885
|
+
const predicates = [];
|
|
40886
|
+
if (columns.has("ZFOLDERTYPE")) predicates.push("COALESCE(ZFOLDERTYPE, 0) = 1");
|
|
40887
|
+
if (columns.has("ZIDENTIFIER"))
|
|
40888
|
+
predicates.push("COALESCE(ZIDENTIFIER, '') LIKE 'TrashFolder%'");
|
|
40889
|
+
if (!predicates.length) return [];
|
|
40890
|
+
const sql = `SELECT (SELECT Z_UUID FROM Z_METADATA LIMIT 1); SELECT Z_PK FROM ZICCLOUDSYNCINGOBJECT WHERE Z_ENT = (SELECT Z_ENT FROM Z_PRIMARYKEY WHERE Z_NAME = 'ICFolder') AND (${predicates.join(" OR ")}) ORDER BY Z_PK;`;
|
|
40891
|
+
const [uuid2, ...pks] = query(dbPath2, sql).split("\n").map((line) => line.trim()).filter(Boolean);
|
|
40892
|
+
if (!uuid2 || !/^[0-9A-F-]+$/i.test(uuid2)) return [];
|
|
40893
|
+
const ids = pks.filter((pk) => /^\d+$/.test(pk)).map((pk) => `x-coredata://${uuid2}/ICFolder/p${pk}`);
|
|
40894
|
+
cache = { dbPath: dbPath2, at: Date.now(), ids };
|
|
40895
|
+
return ids;
|
|
40896
|
+
} catch {
|
|
40897
|
+
return [];
|
|
40898
|
+
}
|
|
40899
|
+
}
|
|
40900
|
+
|
|
40857
40901
|
// src/utils/attachmentFs.ts
|
|
40858
40902
|
import {
|
|
40859
40903
|
closeSync,
|
|
40860
40904
|
constants,
|
|
40861
|
-
existsSync as
|
|
40905
|
+
existsSync as existsSync4,
|
|
40862
40906
|
fstatSync,
|
|
40863
40907
|
lstatSync,
|
|
40864
40908
|
mkdirSync,
|
|
@@ -40869,11 +40913,11 @@ import {
|
|
|
40869
40913
|
rmSync,
|
|
40870
40914
|
statSync
|
|
40871
40915
|
} from "fs";
|
|
40872
|
-
import { dirname, isAbsolute, join as
|
|
40873
|
-
import { homedir as
|
|
40916
|
+
import { dirname, isAbsolute, join as join6, relative, resolve, sep } from "path";
|
|
40917
|
+
import { homedir as homedir6, tmpdir } from "os";
|
|
40874
40918
|
function allowedSaveRoots() {
|
|
40875
40919
|
return [
|
|
40876
|
-
resolve(
|
|
40920
|
+
resolve(homedir6()),
|
|
40877
40921
|
resolve(tmpdir()),
|
|
40878
40922
|
"/Volumes",
|
|
40879
40923
|
"/private/var/folders",
|
|
@@ -40881,8 +40925,8 @@ function allowedSaveRoots() {
|
|
|
40881
40925
|
"/private/tmp"
|
|
40882
40926
|
];
|
|
40883
40927
|
}
|
|
40884
|
-
function canonicalize(
|
|
40885
|
-
return realpathSync.native(
|
|
40928
|
+
function canonicalize(path9) {
|
|
40929
|
+
return realpathSync.native(path9);
|
|
40886
40930
|
}
|
|
40887
40931
|
function isWithinRoots(candidate, roots) {
|
|
40888
40932
|
return roots.some((root) => {
|
|
@@ -40904,9 +40948,9 @@ function canonicalRoots(roots) {
|
|
|
40904
40948
|
}
|
|
40905
40949
|
return canonical;
|
|
40906
40950
|
}
|
|
40907
|
-
function entryExists(
|
|
40951
|
+
function entryExists(path9) {
|
|
40908
40952
|
try {
|
|
40909
|
-
lstatSync(
|
|
40953
|
+
lstatSync(path9);
|
|
40910
40954
|
return true;
|
|
40911
40955
|
} catch (e) {
|
|
40912
40956
|
const code = e.code;
|
|
@@ -40947,7 +40991,7 @@ function assertSafeSavePath(p, roots = allowedSaveRoots()) {
|
|
|
40947
40991
|
if (suffix.split(sep).includes("..")) {
|
|
40948
40992
|
throw new Error(`Refusing to write outside allowed locations (home, temp, /Volumes): "${abs}"`);
|
|
40949
40993
|
}
|
|
40950
|
-
const canonicalDest = suffix ?
|
|
40994
|
+
const canonicalDest = suffix ? join6(canonicalAncestor, suffix) : canonicalAncestor;
|
|
40951
40995
|
const allowed = canonicalRoots(roots);
|
|
40952
40996
|
if (!isWithinRoots(canonicalAncestor, allowed) || !isWithinRoots(canonicalDest, allowed)) {
|
|
40953
40997
|
throw new Error(
|
|
@@ -41031,13 +41075,13 @@ function readAllowedTextFile(p, maxBytes, roots = allowedSaveRoots()) {
|
|
|
41031
41075
|
}
|
|
41032
41076
|
function cleanupTempDir(dir) {
|
|
41033
41077
|
try {
|
|
41034
|
-
if (
|
|
41078
|
+
if (existsSync4(dir)) rmSync(dir, { recursive: true, force: true });
|
|
41035
41079
|
} catch {
|
|
41036
41080
|
}
|
|
41037
41081
|
}
|
|
41038
41082
|
|
|
41039
41083
|
// src/utils/paperAttachments.ts
|
|
41040
|
-
import { execFileSync as
|
|
41084
|
+
import { execFileSync as execFileSync8 } from "node:child_process";
|
|
41041
41085
|
import {
|
|
41042
41086
|
closeSync as closeSync3,
|
|
41043
41087
|
constants as constants3,
|
|
@@ -41050,10 +41094,10 @@ import {
|
|
|
41050
41094
|
unlinkSync as unlinkSync2,
|
|
41051
41095
|
writeSync as writeSync2
|
|
41052
41096
|
} from "node:fs";
|
|
41053
|
-
import { basename as basename2, dirname as dirname3, extname as extname2, join as
|
|
41097
|
+
import { basename as basename2, dirname as dirname3, extname as extname2, join as join8 } from "node:path";
|
|
41054
41098
|
|
|
41055
41099
|
// src/utils/attachmentAssets.ts
|
|
41056
|
-
import { execFileSync as
|
|
41100
|
+
import { execFileSync as execFileSync7 } from "node:child_process";
|
|
41057
41101
|
import {
|
|
41058
41102
|
closeSync as closeSync2,
|
|
41059
41103
|
constants as constants2,
|
|
@@ -41067,11 +41111,11 @@ import {
|
|
|
41067
41111
|
unlinkSync,
|
|
41068
41112
|
writeSync
|
|
41069
41113
|
} from "node:fs";
|
|
41070
|
-
import { homedir as
|
|
41071
|
-
import { basename, dirname as dirname2, extname, isAbsolute as isAbsolute2, join as
|
|
41114
|
+
import { homedir as homedir7 } from "node:os";
|
|
41115
|
+
import { basename, dirname as dirname2, extname, isAbsolute as isAbsolute2, join as join7, relative as relative2, resolve as resolve2, sep as sep2 } from "node:path";
|
|
41072
41116
|
import { gunzipSync as gunzipSync5 } from "node:zlib";
|
|
41073
|
-
var NOTES_CONTAINER_DIR =
|
|
41074
|
-
|
|
41117
|
+
var NOTES_CONTAINER_DIR = join7(
|
|
41118
|
+
homedir7(),
|
|
41075
41119
|
"Library/Group Containers/group.com.apple.notes"
|
|
41076
41120
|
);
|
|
41077
41121
|
var AttachmentStoreError = class extends Error {
|
|
@@ -41176,7 +41220,7 @@ function buildAttachmentRowsSql(notePk, columns) {
|
|
|
41176
41220
|
}
|
|
41177
41221
|
function runSqlite3(dbPath2, sql) {
|
|
41178
41222
|
try {
|
|
41179
|
-
return
|
|
41223
|
+
return execFileSync7("/usr/bin/sqlite3", ["-readonly", dbPath2, sql], {
|
|
41180
41224
|
encoding: "utf8",
|
|
41181
41225
|
timeout: 1e4,
|
|
41182
41226
|
maxBuffer: 128 * 1024 * 1024,
|
|
@@ -41244,7 +41288,7 @@ function attachmentOrderFromNoteData(hex3) {
|
|
|
41244
41288
|
return null;
|
|
41245
41289
|
}
|
|
41246
41290
|
}
|
|
41247
|
-
function readNoteAttachmentRows(noteId3, dbPath2 =
|
|
41291
|
+
function readNoteAttachmentRows(noteId3, dbPath2 = join7(NOTES_CONTAINER_DIR, "NoteStore.sqlite")) {
|
|
41248
41292
|
const { pk } = parseNoteId2(noteId3);
|
|
41249
41293
|
const columnList = runSqlite3(
|
|
41250
41294
|
dbPath2,
|
|
@@ -41274,24 +41318,24 @@ function safeComponent(value) {
|
|
|
41274
41318
|
if (value === "." || value === ".." || value.includes("/") || value.includes("\0")) return null;
|
|
41275
41319
|
return value;
|
|
41276
41320
|
}
|
|
41277
|
-
function realInside(
|
|
41321
|
+
function realInside(path9, rootReal) {
|
|
41278
41322
|
try {
|
|
41279
|
-
const real = realpathSync2.native(
|
|
41323
|
+
const real = realpathSync2.native(path9);
|
|
41280
41324
|
return real === rootReal || real.startsWith(rootReal + sep2) ? real : null;
|
|
41281
41325
|
} catch {
|
|
41282
41326
|
return null;
|
|
41283
41327
|
}
|
|
41284
41328
|
}
|
|
41285
|
-
function isRegularFile(
|
|
41329
|
+
function isRegularFile(path9) {
|
|
41286
41330
|
try {
|
|
41287
|
-
return lstatSync2(
|
|
41331
|
+
return lstatSync2(path9).isFile();
|
|
41288
41332
|
} catch {
|
|
41289
41333
|
return false;
|
|
41290
41334
|
}
|
|
41291
41335
|
}
|
|
41292
|
-
function isDirectory(
|
|
41336
|
+
function isDirectory(path9) {
|
|
41293
41337
|
try {
|
|
41294
|
-
return lstatSync2(
|
|
41338
|
+
return lstatSync2(path9).isDirectory();
|
|
41295
41339
|
} catch {
|
|
41296
41340
|
return false;
|
|
41297
41341
|
}
|
|
@@ -41305,7 +41349,7 @@ function boundedEntries(dir, limit) {
|
|
|
41305
41349
|
}
|
|
41306
41350
|
}
|
|
41307
41351
|
function resolveAccountDir(containerDir, accountIdentifier) {
|
|
41308
|
-
const accountsDir =
|
|
41352
|
+
const accountsDir = join7(containerDir, "Accounts");
|
|
41309
41353
|
let accountsReal;
|
|
41310
41354
|
try {
|
|
41311
41355
|
accountsReal = realpathSync2.native(accountsDir);
|
|
@@ -41314,14 +41358,14 @@ function resolveAccountDir(containerDir, accountIdentifier) {
|
|
|
41314
41358
|
}
|
|
41315
41359
|
const account = safeComponent(accountIdentifier);
|
|
41316
41360
|
if (account) {
|
|
41317
|
-
const dir = realInside(
|
|
41361
|
+
const dir = realInside(join7(accountsReal, account), accountsReal);
|
|
41318
41362
|
if (dir && isDirectory(dir)) return dir;
|
|
41319
41363
|
}
|
|
41320
41364
|
const entries2 = (boundedEntries(accountsReal, 64) ?? []).filter(
|
|
41321
|
-
(e) => isDirectory(
|
|
41365
|
+
(e) => isDirectory(join7(accountsReal, e))
|
|
41322
41366
|
);
|
|
41323
41367
|
if (entries2.length !== 1) return null;
|
|
41324
|
-
return realInside(
|
|
41368
|
+
return realInside(join7(accountsReal, entries2[0]), accountsReal);
|
|
41325
41369
|
}
|
|
41326
41370
|
function generationRank(name) {
|
|
41327
41371
|
const m = /^(\d+)_/.exec(name);
|
|
@@ -41329,23 +41373,23 @@ function generationRank(name) {
|
|
|
41329
41373
|
}
|
|
41330
41374
|
function generationDirs(base, accountDir) {
|
|
41331
41375
|
const entries2 = boundedEntries(base, MAX_GENERATION_DIRS) ?? [];
|
|
41332
|
-
return entries2.map((e) => realInside(
|
|
41376
|
+
return entries2.map((e) => realInside(join7(base, e), accountDir)).filter((p) => p !== null && isDirectory(p)).sort((a, b) => generationRank(basename(b)) - generationRank(basename(a)));
|
|
41333
41377
|
}
|
|
41334
41378
|
function fallbackFiles(accountDir, rootName, identifier, generation, names) {
|
|
41335
|
-
const base =
|
|
41379
|
+
const base = join7(accountDir, rootName, identifier);
|
|
41336
41380
|
const found = [];
|
|
41337
41381
|
const add = (candidate) => {
|
|
41338
41382
|
const real = realInside(candidate, accountDir);
|
|
41339
41383
|
if (real && isRegularFile(real) && !found.includes(real)) found.push(real);
|
|
41340
41384
|
};
|
|
41341
41385
|
const gen = safeComponent(generation);
|
|
41342
|
-
if (gen) for (const name of names) add(
|
|
41386
|
+
if (gen) for (const name of names) add(join7(base, gen, name));
|
|
41343
41387
|
if (isDirectory(base)) {
|
|
41344
41388
|
for (const dir of generationDirs(base, accountDir))
|
|
41345
|
-
for (const name of names) add(
|
|
41346
|
-
for (const name of names) add(
|
|
41389
|
+
for (const name of names) add(join7(dir, name));
|
|
41390
|
+
for (const name of names) add(join7(base, name));
|
|
41347
41391
|
}
|
|
41348
|
-
for (const name of names) add(
|
|
41392
|
+
for (const name of names) add(join7(accountDir, rootName, `${identifier}${extname(name)}`));
|
|
41349
41393
|
return found;
|
|
41350
41394
|
}
|
|
41351
41395
|
function previewPixelArea(name) {
|
|
@@ -41357,7 +41401,7 @@ function previewFileInBundle(bundle, accountDir) {
|
|
|
41357
41401
|
const direct = [];
|
|
41358
41402
|
const nested = [];
|
|
41359
41403
|
for (const entry of boundedEntries(bundle, MAX_BUNDLE_ENTRIES) ?? []) {
|
|
41360
|
-
const child = realInside(
|
|
41404
|
+
const child = realInside(join7(bundle, entry), accountDir);
|
|
41361
41405
|
if (!child) continue;
|
|
41362
41406
|
if (isRegularFile(child)) direct.push(child);
|
|
41363
41407
|
else if (isDirectory(child)) nested.push(child);
|
|
@@ -41365,14 +41409,14 @@ function previewFileInBundle(bundle, accountDir) {
|
|
|
41365
41409
|
nested.sort((a, b) => generationRank(basename(b)) - generationRank(basename(a)));
|
|
41366
41410
|
const pick2 = (files) => files.find((f) => basename(f) === "Preview.png") ?? files.find((f) => PREVIEW_IMAGE_SUFFIXES.has(extname(f).toLowerCase())) ?? null;
|
|
41367
41411
|
for (const dir of nested) {
|
|
41368
|
-
const files = (boundedEntries(dir, MAX_BUNDLE_ENTRIES) ?? []).map((e) => realInside(
|
|
41412
|
+
const files = (boundedEntries(dir, MAX_BUNDLE_ENTRIES) ?? []).map((e) => realInside(join7(dir, e), accountDir)).filter((p) => p !== null && isRegularFile(p));
|
|
41369
41413
|
const chosen = pick2(files);
|
|
41370
41414
|
if (chosen) return chosen;
|
|
41371
41415
|
}
|
|
41372
41416
|
return pick2(direct);
|
|
41373
41417
|
}
|
|
41374
41418
|
function listPreviewEntries(accountDir) {
|
|
41375
|
-
return boundedEntries(
|
|
41419
|
+
return boundedEntries(join7(accountDir, "Previews"), MAX_PREVIEW_DIR_ENTRIES) ?? [];
|
|
41376
41420
|
}
|
|
41377
41421
|
function previewPaths(accountDir, identifier, entries2) {
|
|
41378
41422
|
const id2 = safeComponent(identifier);
|
|
@@ -41384,7 +41428,7 @@ function previewPaths(accountDir, identifier, entries2) {
|
|
|
41384
41428
|
}).sort((a, b) => previewPixelArea(b) - previewPixelArea(a) || a.localeCompare(b));
|
|
41385
41429
|
const files = [];
|
|
41386
41430
|
for (const name of candidates) {
|
|
41387
|
-
const real = realInside(
|
|
41431
|
+
const real = realInside(join7(accountDir, "Previews", name), accountDir);
|
|
41388
41432
|
if (!real) continue;
|
|
41389
41433
|
const file = isRegularFile(real) ? real : isDirectory(real) ? previewFileInBundle(real, accountDir) : null;
|
|
41390
41434
|
if (file && !files.includes(file)) files.push(file);
|
|
@@ -41401,13 +41445,13 @@ function assetPathsFor(accountDir, row) {
|
|
|
41401
41445
|
const mediaName = safeComponent(row.mediaFilename);
|
|
41402
41446
|
const mediaGen = safeComponent(row.mediaGeneration);
|
|
41403
41447
|
if (mediaId && mediaName) {
|
|
41404
|
-
if (mediaGen) add(
|
|
41405
|
-
add(
|
|
41448
|
+
if (mediaGen) add(join7(accountDir, "Media", mediaId, mediaGen, mediaName));
|
|
41449
|
+
add(join7(accountDir, "Media", mediaId, mediaName));
|
|
41406
41450
|
}
|
|
41407
41451
|
const id2 = safeComponent(row.identifier);
|
|
41408
41452
|
if (!id2) return found;
|
|
41409
41453
|
const ownName = safeComponent(row.filename);
|
|
41410
|
-
if (ownName) add(
|
|
41454
|
+
if (ownName) add(join7(accountDir, "Media", id2, ownName));
|
|
41411
41455
|
for (const file of fallbackFiles(accountDir, "FallbackImages", id2, row.fallbackImageGeneration, [
|
|
41412
41456
|
"FallbackImage.png",
|
|
41413
41457
|
"FallbackImage.jpg"
|
|
@@ -41498,10 +41542,10 @@ function canonicalTail(p) {
|
|
|
41498
41542
|
const tail = [];
|
|
41499
41543
|
for (; ; ) {
|
|
41500
41544
|
try {
|
|
41501
|
-
return
|
|
41545
|
+
return join7(realpathSync2.native(current), ...tail);
|
|
41502
41546
|
} catch {
|
|
41503
41547
|
const parent = dirname2(current);
|
|
41504
|
-
if (parent === current) return
|
|
41548
|
+
if (parent === current) return join7(current, ...tail);
|
|
41505
41549
|
tail.unshift(basename(current));
|
|
41506
41550
|
current = parent;
|
|
41507
41551
|
}
|
|
@@ -41583,7 +41627,7 @@ function exportOneAttachment(record2, dir, source) {
|
|
|
41583
41627
|
if (!source) return base;
|
|
41584
41628
|
const name = exportFileName(record2, source.path, source.kind);
|
|
41585
41629
|
for (let attempt = 1; attempt <= MAX_COLLISION_SUFFIX; attempt++) {
|
|
41586
|
-
const dest =
|
|
41630
|
+
const dest = join7(dir, collisionName(name, attempt));
|
|
41587
41631
|
try {
|
|
41588
41632
|
assertSafeSavePath(dest);
|
|
41589
41633
|
copyFileExclusive(source.path, dest);
|
|
@@ -41671,10 +41715,10 @@ function readImageInfoFd(fd) {
|
|
|
41671
41715
|
const read = readSync2(fd, buf, 0, buf.length, 0);
|
|
41672
41716
|
return parseImageHeader(buf.subarray(0, read));
|
|
41673
41717
|
}
|
|
41674
|
-
function readImageInfo(
|
|
41718
|
+
function readImageInfo(path9) {
|
|
41675
41719
|
let fd;
|
|
41676
41720
|
try {
|
|
41677
|
-
fd = openSync3(
|
|
41721
|
+
fd = openSync3(path9, constants3.O_RDONLY | constants3.O_NOFOLLOW);
|
|
41678
41722
|
} catch {
|
|
41679
41723
|
return null;
|
|
41680
41724
|
}
|
|
@@ -41710,7 +41754,7 @@ function buildDrawingRowsSql(notePk, columns) {
|
|
|
41710
41754
|
}
|
|
41711
41755
|
function runSqlite4(dbPath2, sql) {
|
|
41712
41756
|
try {
|
|
41713
|
-
return
|
|
41757
|
+
return execFileSync8("/usr/bin/sqlite3", ["-readonly", dbPath2, sql], {
|
|
41714
41758
|
encoding: "utf8",
|
|
41715
41759
|
timeout: 1e4,
|
|
41716
41760
|
maxBuffer: 16 * 1024 * 1024,
|
|
@@ -41750,7 +41794,7 @@ function parseDrawingRows(json2) {
|
|
|
41750
41794
|
}
|
|
41751
41795
|
return rows.sort((a, b) => a.pk - b.pk);
|
|
41752
41796
|
}
|
|
41753
|
-
function readDrawingRows(noteId3, dbPath2 =
|
|
41797
|
+
function readDrawingRows(noteId3, dbPath2 = join8(NOTES_CONTAINER_DIR, "NoteStore.sqlite")) {
|
|
41754
41798
|
const { pk } = parseNoteId2(noteId3);
|
|
41755
41799
|
const columns = new Set(
|
|
41756
41800
|
runSqlite4(
|
|
@@ -41774,9 +41818,9 @@ function readDrawingRows(noteId3, dbPath2 = join7(NOTES_CONTAINER_DIR, "NoteStor
|
|
|
41774
41818
|
throw new AttachmentStoreError("Drawing rows could not be parsed", "query_error");
|
|
41775
41819
|
}
|
|
41776
41820
|
}
|
|
41777
|
-
function kindOf(
|
|
41821
|
+
function kindOf(path9) {
|
|
41778
41822
|
try {
|
|
41779
|
-
const st = lstatSync3(
|
|
41823
|
+
const st = lstatSync3(path9);
|
|
41780
41824
|
return st.isFile() ? "file" : st.isDirectory() ? "dir" : null;
|
|
41781
41825
|
} catch {
|
|
41782
41826
|
return null;
|
|
@@ -41794,16 +41838,16 @@ var byGenerationDesc = (a, b) => generationRank(basename2(b)) - generationRank(b
|
|
|
41794
41838
|
function findFallbackImage(accountDir, identifier, generation) {
|
|
41795
41839
|
const id2 = safeComponent(identifier);
|
|
41796
41840
|
if (!id2) return null;
|
|
41797
|
-
const base =
|
|
41841
|
+
const base = join8(accountDir, "FallbackImages", id2);
|
|
41798
41842
|
const names = ["FallbackImage.png", "FallbackImage.jpg"];
|
|
41799
41843
|
const candidates = [];
|
|
41800
41844
|
const gen = safeComponent(generation);
|
|
41801
|
-
if (gen) for (const n of names) candidates.push(
|
|
41802
|
-
const gens = entries(base, MAX_DIR_ENTRIES).map((e) =>
|
|
41803
|
-
for (const g of gens) for (const n of names) candidates.push(
|
|
41804
|
-
for (const n of names) candidates.push(
|
|
41805
|
-
candidates.push(
|
|
41806
|
-
candidates.push(
|
|
41845
|
+
if (gen) for (const n of names) candidates.push(join8(base, gen, n));
|
|
41846
|
+
const gens = entries(base, MAX_DIR_ENTRIES).map((e) => join8(base, e)).sort(byGenerationDesc);
|
|
41847
|
+
for (const g of gens) for (const n of names) candidates.push(join8(g, n));
|
|
41848
|
+
for (const n of names) candidates.push(join8(base, n));
|
|
41849
|
+
candidates.push(join8(accountDir, "FallbackImages", `${id2}.png`));
|
|
41850
|
+
candidates.push(join8(accountDir, "FallbackImages", `${id2}.jpg`));
|
|
41807
41851
|
for (const c of candidates) {
|
|
41808
41852
|
const real = realInside(c, accountDir);
|
|
41809
41853
|
if (real && kindOf(real) === "file") return real;
|
|
@@ -41813,21 +41857,21 @@ function findFallbackImage(accountDir, identifier, generation) {
|
|
|
41813
41857
|
function findLargestPreview(accountDir, identifier) {
|
|
41814
41858
|
const id2 = safeComponent(identifier);
|
|
41815
41859
|
if (!id2) return null;
|
|
41816
|
-
const dir =
|
|
41860
|
+
const dir = join8(accountDir, "Previews");
|
|
41817
41861
|
const prefix = `${id2}-`.toLowerCase();
|
|
41818
41862
|
const names = entries(dir, MAX_PREVIEW_DIR_ENTRIES2).filter((n) => n.toLowerCase().startsWith(prefix)).filter((n) => {
|
|
41819
41863
|
const ext = extname2(n).toLowerCase();
|
|
41820
41864
|
return !ext || IMAGE_SUFFIXES.has(ext) || /^\.\d+$/.test(ext);
|
|
41821
41865
|
}).sort((a, b) => previewPixelArea(b) - previewPixelArea(a) || a.localeCompare(b));
|
|
41822
41866
|
for (const name of names) {
|
|
41823
|
-
const real = realInside(
|
|
41867
|
+
const real = realInside(join8(dir, name), accountDir);
|
|
41824
41868
|
if (!real) continue;
|
|
41825
41869
|
const kind = kindOf(real);
|
|
41826
41870
|
if (kind === "file") return real;
|
|
41827
41871
|
if (kind !== "dir") continue;
|
|
41828
|
-
const gens = entries(real, MAX_DIR_ENTRIES).map((e) => realInside(
|
|
41872
|
+
const gens = entries(real, MAX_DIR_ENTRIES).map((e) => realInside(join8(real, e), accountDir)).filter((p) => p !== null && kindOf(p) === "dir").sort(byGenerationDesc);
|
|
41829
41873
|
for (const g of [...gens, real]) {
|
|
41830
|
-
const file = realInside(
|
|
41874
|
+
const file = realInside(join8(g, "Preview.png"), accountDir);
|
|
41831
41875
|
if (file && kindOf(file) === "file") return file;
|
|
41832
41876
|
}
|
|
41833
41877
|
}
|
|
@@ -41840,15 +41884,15 @@ function describeDrawings(rows, containerDir = NOTES_CONTAINER_DIR) {
|
|
|
41840
41884
|
const id2 = safeComponent(row.identifier);
|
|
41841
41885
|
const fallbackImagePath = accountDir ? findFallbackImage(accountDir, row.identifier, row.fallbackImageGeneration) : null;
|
|
41842
41886
|
const previewPath = accountDir ? findLargestPreview(accountDir, row.identifier) : null;
|
|
41843
|
-
const bundle = accountDir && id2 && kind === "paper" ? realInside(
|
|
41887
|
+
const bundle = accountDir && id2 && kind === "paper" ? realInside(join8(accountDir, "Paper", "Bundles", `${id2}.bundle`), accountDir) : null;
|
|
41844
41888
|
let raster = null;
|
|
41845
|
-
for (const [
|
|
41889
|
+
for (const [path9, source] of [
|
|
41846
41890
|
[fallbackImagePath, "fallback"],
|
|
41847
41891
|
[previewPath, "preview"]
|
|
41848
41892
|
]) {
|
|
41849
|
-
const info =
|
|
41850
|
-
if (
|
|
41851
|
-
raster = { path:
|
|
41893
|
+
const info = path9 ? readImageInfo(path9) : null;
|
|
41894
|
+
if (path9 && info) {
|
|
41895
|
+
raster = { path: path9, source, ...info };
|
|
41852
41896
|
break;
|
|
41853
41897
|
}
|
|
41854
41898
|
}
|
|
@@ -41865,10 +41909,10 @@ function describeDrawings(rows, containerDir = NOTES_CONTAINER_DIR) {
|
|
|
41865
41909
|
};
|
|
41866
41910
|
});
|
|
41867
41911
|
}
|
|
41868
|
-
function verifyWrittenImage(fd,
|
|
41912
|
+
function verifyWrittenImage(fd, path9, expected) {
|
|
41869
41913
|
const check2 = readImageInfoFd(fd);
|
|
41870
41914
|
if (!check2 || check2.format !== expected.format || check2.width !== expected.width || check2.height !== expected.height) {
|
|
41871
|
-
unlinkSync2(
|
|
41915
|
+
unlinkSync2(path9);
|
|
41872
41916
|
throw new Error("The exported image failed validation and was removed.");
|
|
41873
41917
|
}
|
|
41874
41918
|
return check2;
|
|
@@ -41966,13 +42010,34 @@ function exportDrawingRaster(drawing, savePath, containerDir = NOTES_CONTAINER_D
|
|
|
41966
42010
|
|
|
41967
42011
|
// src/services/appleNotesManager.ts
|
|
41968
42012
|
var import_turndown = __toESM(require_turndown_cjs(), 1);
|
|
41969
|
-
import { existsSync as
|
|
41970
|
-
import { homedir as
|
|
41971
|
-
import { join as
|
|
42013
|
+
import { existsSync as existsSync5 } from "fs";
|
|
42014
|
+
import { homedir as homedir8 } from "os";
|
|
42015
|
+
import { join as join9 } from "path";
|
|
41972
42016
|
var FIELD_SEP = "";
|
|
41973
42017
|
var RECORD_SEP = "";
|
|
41974
42018
|
var AS_FIELD_SEP = "(character id 31)";
|
|
41975
42019
|
var AS_RECORD_SEP = "(character id 30)";
|
|
42020
|
+
var GROUP_SEP = "";
|
|
42021
|
+
var AS_GROUP_SEP = "(character id 29)";
|
|
42022
|
+
var FOLDER_ID_PATTERN = /^x-coredata:\/\/[0-9A-F-]+\/ICFolder\/p\d+$/i;
|
|
42023
|
+
function trashFolderIdList() {
|
|
42024
|
+
const ids = readTrashFolderIds().filter((id2) => FOLDER_ID_PATTERN.test(id2));
|
|
42025
|
+
return `{${ids.map((id2) => `"${id2}"`).join(", ")}}`;
|
|
42026
|
+
}
|
|
42027
|
+
function buildTrashNoteIdsCollector() {
|
|
42028
|
+
return `
|
|
42029
|
+
set __trashNoteIds to {}
|
|
42030
|
+
repeat with __trashFolderId in ${trashFolderIdList()}
|
|
42031
|
+
try
|
|
42032
|
+
set __trashNoteIds to __trashNoteIds & (id of notes of folder id (contents of __trashFolderId))
|
|
42033
|
+
end try
|
|
42034
|
+
end repeat
|
|
42035
|
+
try
|
|
42036
|
+
repeat with __trashFolder in (every folder whose name is "${RECENTLY_DELETED_FOLDER_NAME}")
|
|
42037
|
+
set __trashNoteIds to __trashNoteIds & (id of notes of __trashFolder)
|
|
42038
|
+
end repeat
|
|
42039
|
+
end try`;
|
|
42040
|
+
}
|
|
41976
42041
|
var DEFAULT_EXPORT_PAGE_SIZE = 50;
|
|
41977
42042
|
var DEFAULT_EXPORT_MAX_RESPONSE_BYTES = 8 * 1024 * 1024;
|
|
41978
42043
|
function exportMaxResponseBytes(env = process.env) {
|
|
@@ -42196,8 +42261,8 @@ function getNoteLinkFromDB(coreDataId2) {
|
|
|
42196
42261
|
const match = coreDataId2.match(/\/p(\d+)$/);
|
|
42197
42262
|
if (!match) return null;
|
|
42198
42263
|
const pk = parseInt(match[1], 10);
|
|
42199
|
-
const dbPath2 =
|
|
42200
|
-
if (!
|
|
42264
|
+
const dbPath2 = join9(homedir8(), "Library/Group Containers/group.com.apple.notes/NoteStore.sqlite");
|
|
42265
|
+
if (!existsSync5(dbPath2)) return null;
|
|
42201
42266
|
try {
|
|
42202
42267
|
const { DatabaseSync } = __require("node:sqlite");
|
|
42203
42268
|
const db = new DatabaseSync(dbPath2, { readOnly: true });
|
|
@@ -42402,9 +42467,9 @@ var AppleNotesManager = class {
|
|
|
42402
42467
|
* const topResults = manager.searchNotes("project", false, undefined, undefined, undefined, 10);
|
|
42403
42468
|
* ```
|
|
42404
42469
|
*/
|
|
42405
|
-
searchNotes(
|
|
42470
|
+
searchNotes(query2, searchContent = false, account, folder, modifiedSince, limit) {
|
|
42406
42471
|
const targetAccount = this.resolveAccount(account);
|
|
42407
|
-
const safeQuery = escapePlainStringForAppleScript(
|
|
42472
|
+
const safeQuery = escapePlainStringForAppleScript(query2);
|
|
42408
42473
|
const safeLimit = limit !== void 0 && limit > 0 ? Math.floor(limit) : void 0;
|
|
42409
42474
|
const whereParts = [];
|
|
42410
42475
|
if (searchContent) {
|
|
@@ -42462,7 +42527,7 @@ var AppleNotesManager = class {
|
|
|
42462
42527
|
const script = buildAccountScopedScript({ account: targetAccount }, searchCommand);
|
|
42463
42528
|
const result = executeAppleScript(script);
|
|
42464
42529
|
if (!result.success) {
|
|
42465
|
-
throw new Error(`Failed to search notes for "${
|
|
42530
|
+
throw new Error(`Failed to search notes for "${query2}": ${result.error ?? "unknown error"}`);
|
|
42466
42531
|
}
|
|
42467
42532
|
if (!result.output.trim()) {
|
|
42468
42533
|
return [];
|
|
@@ -42762,6 +42827,16 @@ var AppleNotesManager = class {
|
|
|
42762
42827
|
try
|
|
42763
42828
|
set originalFolder to container of noteRef
|
|
42764
42829
|
end try
|
|
42830
|
+
if originalFolder is not missing value then
|
|
42831
|
+
set __inTrash to false
|
|
42832
|
+
try
|
|
42833
|
+
if ${trashFolderIdList()} contains (id of originalFolder) then set __inTrash to true
|
|
42834
|
+
end try
|
|
42835
|
+
try
|
|
42836
|
+
if (name of originalFolder) is "${RECENTLY_DELETED_FOLDER_NAME}" then set __inTrash to true
|
|
42837
|
+
end try
|
|
42838
|
+
if __inTrash then return "SAFETY_IN_RECENTLY_DELETED"
|
|
42839
|
+
end if
|
|
42765
42840
|
set currentBody to body of noteRef
|
|
42766
42841
|
considering case
|
|
42767
42842
|
if currentBody is not "${safeExpectedBody}" and currentBody is not "${safeExpectedBody}" & linefeed then return "SAFETY_CONFLICT"
|
|
@@ -42781,6 +42856,7 @@ var AppleNotesManager = class {
|
|
|
42781
42856
|
}
|
|
42782
42857
|
const status = result.output.trim();
|
|
42783
42858
|
if (status === "SAFETY_CONFLICT") return { status: "conflict" };
|
|
42859
|
+
if (status === "SAFETY_IN_RECENTLY_DELETED") return { status: "in-recently-deleted" };
|
|
42784
42860
|
if (status === "SAFETY_NOT_DELETED") return { status: "not-deleted" };
|
|
42785
42861
|
return status === "SAFETY_DELETED" ? { status: "deleted" } : { status: "failed" };
|
|
42786
42862
|
}
|
|
@@ -42806,14 +42882,20 @@ var AppleNotesManager = class {
|
|
|
42806
42882
|
* dateSetup: a date filter must scan every note's date). The script then
|
|
42807
42883
|
* returns the total note count as a leading record so the caller can
|
|
42808
42884
|
* detect a dedup shortfall and fall back to a full fetch.
|
|
42885
|
+
* @param trashCheck - Also return the ids of notes in Recently Deleted,
|
|
42886
|
+
* after a group separator, so the caller can exclude or flag them (#207).
|
|
42887
|
+
* Only valid inside an account-scoped script.
|
|
42809
42888
|
*/
|
|
42810
42889
|
buildBulkListCommand(opts) {
|
|
42811
|
-
const { folderRef, dateSetup, sliceLimit } = opts;
|
|
42890
|
+
const { folderRef, dateSetup, sliceLimit, trashCheck } = opts;
|
|
42812
42891
|
const fullSource = folderRef ? `notes of ${folderRef}` : "notes";
|
|
42892
|
+
const trashSetup = trashCheck ? `${buildTrashNoteIdsCollector()}
|
|
42893
|
+
` : "";
|
|
42894
|
+
const trashSuffix = trashCheck ? ` & ${AS_GROUP_SEP} & (__trashNoteIds as text)` : "";
|
|
42813
42895
|
const countGuard = (listVar) => `if (count of ${listVar}) is not (count of noteNames) then error "${BULK_LIST_MUTATION_ERROR}"`;
|
|
42814
42896
|
if (sliceLimit !== void 0) {
|
|
42815
42897
|
const slicedSource = folderRef ? `(notes 1 thru fetchCount of ${folderRef})` : `(notes 1 thru fetchCount)`;
|
|
42816
|
-
return
|
|
42898
|
+
return `${trashSetup}
|
|
42817
42899
|
set totalCount to count of ${fullSource}
|
|
42818
42900
|
set fetchCount to ${sliceLimit}
|
|
42819
42901
|
if fetchCount > totalCount then set fetchCount to totalCount
|
|
@@ -42840,7 +42922,7 @@ var AppleNotesManager = class {
|
|
|
42840
42922
|
end repeat
|
|
42841
42923
|
end if
|
|
42842
42924
|
set AppleScript's text item delimiters to ${AS_RECORD_SEP}
|
|
42843
|
-
return (totalCount as text) & ${AS_RECORD_SEP} & (resultList as text)
|
|
42925
|
+
return (totalCount as text) & ${AS_RECORD_SEP} & (resultList as text)${trashSuffix}
|
|
42844
42926
|
`;
|
|
42845
42927
|
}
|
|
42846
42928
|
const dateFetch = dateSetup ? `set noteDates to modification date of ${fullSource}
|
|
@@ -42851,7 +42933,7 @@ var AppleNotesManager = class {
|
|
|
42851
42933
|
` : "";
|
|
42852
42934
|
const dateGuardClose = dateSetup ? `
|
|
42853
42935
|
end if` : "";
|
|
42854
|
-
return
|
|
42936
|
+
return `${trashSetup}
|
|
42855
42937
|
${dateSetup ?? ""}set noteNames to name of ${fullSource}
|
|
42856
42938
|
set noteIds to id of ${fullSource}
|
|
42857
42939
|
${dateFetch}${countGuard("noteIds")}
|
|
@@ -42860,7 +42942,7 @@ var AppleNotesManager = class {
|
|
|
42860
42942
|
${dateGuardOpen}set end of resultList to (item i of noteNames) & ${AS_FIELD_SEP} & (item i of noteIds)${dateGuardClose}
|
|
42861
42943
|
end repeat
|
|
42862
42944
|
set AppleScript's text item delimiters to ${AS_RECORD_SEP}
|
|
42863
|
-
return resultList as text
|
|
42945
|
+
return (resultList as text)${trashSuffix}
|
|
42864
42946
|
`;
|
|
42865
42947
|
}
|
|
42866
42948
|
/**
|
|
@@ -42922,19 +43004,49 @@ var AppleNotesManager = class {
|
|
|
42922
43004
|
* after dedup so duplicates never count against it.
|
|
42923
43005
|
*/
|
|
42924
43006
|
parseBulkListOutput(output, safeLimit) {
|
|
42925
|
-
|
|
42926
|
-
|
|
43007
|
+
return this.parseBulkListRecords(output, safeLimit).refs;
|
|
43008
|
+
}
|
|
43009
|
+
/**
|
|
43010
|
+
* Splits a trash-checked listing (see buildBulkListCommand's trashCheck)
|
|
43011
|
+
* into the listing records and the set of note ids in Recently Deleted.
|
|
43012
|
+
* Output without the group separator carries no trash information (null).
|
|
43013
|
+
*/
|
|
43014
|
+
splitTrashIds(output) {
|
|
43015
|
+
const idx = output.lastIndexOf(GROUP_SEP);
|
|
43016
|
+
if (idx === -1) return { records: output, trashIds: null };
|
|
43017
|
+
const trashIds = new Set(
|
|
43018
|
+
output.slice(idx + 1).split(RECORD_SEP).map((id2) => id2.trim()).filter(Boolean)
|
|
43019
|
+
);
|
|
43020
|
+
return { records: output.slice(0, idx), trashIds };
|
|
43021
|
+
}
|
|
43022
|
+
/**
|
|
43023
|
+
* Parses bulk listing records, deduplicated by id. Notes whose id is in
|
|
43024
|
+
* `trash.ids` are dropped (and counted) unless `trash.include`, in which
|
|
43025
|
+
* case they are kept and flagged `inRecentlyDeleted`. The limit applies
|
|
43026
|
+
* after both dedup and trash filtering.
|
|
43027
|
+
*/
|
|
43028
|
+
parseBulkListRecords(output, safeLimit, trash) {
|
|
42927
43029
|
const refs = [];
|
|
43030
|
+
let excludedRecentlyDeleted = 0;
|
|
43031
|
+
if (!output.trim()) return { refs, excludedRecentlyDeleted };
|
|
43032
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
42928
43033
|
for (const item of output.split(RECORD_SEP)) {
|
|
42929
43034
|
const [title, id2] = item.split(FIELD_SEP);
|
|
42930
43035
|
if (!title?.trim()) continue;
|
|
42931
43036
|
const noteId3 = id2?.trim() || generateFallbackId();
|
|
42932
43037
|
if (seenIds.has(noteId3)) continue;
|
|
42933
43038
|
seenIds.add(noteId3);
|
|
42934
|
-
|
|
43039
|
+
const trashed = trash?.ids?.has(noteId3) ?? false;
|
|
43040
|
+
if (trashed && !trash?.include) {
|
|
43041
|
+
excludedRecentlyDeleted++;
|
|
43042
|
+
continue;
|
|
43043
|
+
}
|
|
43044
|
+
refs.push(
|
|
43045
|
+
trashed ? { title: title.trim(), id: noteId3, inRecentlyDeleted: true } : { title: title.trim(), id: noteId3 }
|
|
43046
|
+
);
|
|
42935
43047
|
if (safeLimit !== void 0 && refs.length >= safeLimit) break;
|
|
42936
43048
|
}
|
|
42937
|
-
return refs;
|
|
43049
|
+
return { refs, excludedRecentlyDeleted };
|
|
42938
43050
|
}
|
|
42939
43051
|
/**
|
|
42940
43052
|
* Core listing path shared by `listNotes()` and `listNoteRefs()`: lists
|
|
@@ -42942,7 +43054,7 @@ var AppleNotesManager = class {
|
|
|
42942
43054
|
* returning (title, id) pairs. Kept private because both public callers
|
|
42943
43055
|
* need to apply their own return shape.
|
|
42944
43056
|
*/
|
|
42945
|
-
listNotesCore(account, folder, modifiedSince, limit) {
|
|
43057
|
+
listNotesCore(account, folder, modifiedSince, limit, includeRecentlyDeleted = false) {
|
|
42946
43058
|
const targetAccount = this.resolveAccount(account);
|
|
42947
43059
|
const safeLimit = limit !== void 0 && limit > 0 ? Math.floor(limit) : void 0;
|
|
42948
43060
|
const folderRef = folder ? buildFolderReference(folder) : void 0;
|
|
@@ -42956,30 +43068,38 @@ var AppleNotesManager = class {
|
|
|
42956
43068
|
if (safeLimit !== void 0 && !dateSetup) {
|
|
42957
43069
|
const script2 = buildAccountScopedScript(
|
|
42958
43070
|
{ account: targetAccount },
|
|
42959
|
-
this.buildBulkListCommand({ folderRef, sliceLimit: safeLimit })
|
|
43071
|
+
this.buildBulkListCommand({ folderRef, sliceLimit: safeLimit, trashCheck: true })
|
|
42960
43072
|
);
|
|
42961
43073
|
const result2 = executeAppleScript(script2);
|
|
42962
43074
|
if (!result2.success) {
|
|
42963
43075
|
throw new Error(`Failed to list notes: ${result2.error ?? "unknown error"}`);
|
|
42964
43076
|
}
|
|
42965
|
-
const
|
|
42966
|
-
const
|
|
43077
|
+
const { records: body, trashIds: trashIds2 } = this.splitTrashIds(result2.output);
|
|
43078
|
+
const sepIdx = body.indexOf(RECORD_SEP);
|
|
43079
|
+
const header = sepIdx === -1 ? body : body.slice(0, sepIdx);
|
|
42967
43080
|
const totalCount = Number.parseInt(header.trim(), 10);
|
|
42968
|
-
const
|
|
42969
|
-
const
|
|
42970
|
-
|
|
42971
|
-
|
|
43081
|
+
const records2 = sepIdx === -1 ? "" : body.slice(sepIdx + 1);
|
|
43082
|
+
const parsed = this.parseBulkListRecords(records2, safeLimit, {
|
|
43083
|
+
ids: trashIds2,
|
|
43084
|
+
include: includeRecentlyDeleted
|
|
43085
|
+
});
|
|
43086
|
+
if (!Number.isNaN(totalCount) && (parsed.refs.length >= safeLimit || totalCount <= safeLimit)) {
|
|
43087
|
+
return parsed;
|
|
42972
43088
|
}
|
|
42973
43089
|
}
|
|
42974
43090
|
const script = buildAccountScopedScript(
|
|
42975
43091
|
{ account: targetAccount },
|
|
42976
|
-
this.buildBulkListCommand({ folderRef, dateSetup })
|
|
43092
|
+
this.buildBulkListCommand({ folderRef, dateSetup, trashCheck: true })
|
|
42977
43093
|
);
|
|
42978
43094
|
const result = executeAppleScript(script);
|
|
42979
43095
|
if (!result.success) {
|
|
42980
43096
|
throw new Error(`Failed to list notes: ${result.error ?? "unknown error"}`);
|
|
42981
43097
|
}
|
|
42982
|
-
|
|
43098
|
+
const { records, trashIds } = this.splitTrashIds(result.output);
|
|
43099
|
+
return this.parseBulkListRecords(records, safeLimit, {
|
|
43100
|
+
ids: trashIds,
|
|
43101
|
+
include: includeRecentlyDeleted
|
|
43102
|
+
});
|
|
42983
43103
|
}
|
|
42984
43104
|
/**
|
|
42985
43105
|
* Lists all notes in an account, optionally filtered by folder, date, and limit.
|
|
@@ -42991,7 +43111,7 @@ var AppleNotesManager = class {
|
|
|
42991
43111
|
* @returns Array of note titles
|
|
42992
43112
|
*/
|
|
42993
43113
|
listNotes(account, folder, modifiedSince, limit) {
|
|
42994
|
-
return this.listNotesCore(account, folder, modifiedSince, limit).map((ref) => ref.title);
|
|
43114
|
+
return this.listNotesCore(account, folder, modifiedSince, limit).refs.map((ref) => ref.title);
|
|
42995
43115
|
}
|
|
42996
43116
|
/**
|
|
42997
43117
|
* Lists all notes in an account, optionally filtered by folder, date, and
|
|
@@ -43002,10 +43122,23 @@ var AppleNotesManager = class {
|
|
|
43002
43122
|
* specifier resolves ambiguously to the same one note every time — see
|
|
43003
43123
|
* the fix in exportNotesAsJson for the failure mode this avoids).
|
|
43004
43124
|
*
|
|
43125
|
+
* Notes in Recently Deleted are excluded (#207); use
|
|
43126
|
+
* `listNoteRefsDetailed()` to include and flag them.
|
|
43127
|
+
*
|
|
43005
43128
|
* @returns Array of { title, id } pairs, deduplicated by id
|
|
43006
43129
|
*/
|
|
43007
43130
|
listNoteRefs(account, folder, modifiedSince, limit) {
|
|
43008
|
-
return this.listNotesCore(account, folder, modifiedSince, limit);
|
|
43131
|
+
return this.listNotesCore(account, folder, modifiedSince, limit).refs;
|
|
43132
|
+
}
|
|
43133
|
+
/**
|
|
43134
|
+
* Same as `listNoteRefs()`, plus control over notes in Recently Deleted and
|
|
43135
|
+
* a count of how many were skipped. Notes.app's account-wide `notes`
|
|
43136
|
+
* includes Recently Deleted, so they are excluded unless
|
|
43137
|
+
* `includeRecentlyDeleted`, in which case each is flagged
|
|
43138
|
+
* `inRecentlyDeleted: true`. (#207)
|
|
43139
|
+
*/
|
|
43140
|
+
listNoteRefsDetailed(account, folder, modifiedSince, limit, includeRecentlyDeleted = false) {
|
|
43141
|
+
return this.listNotesCore(account, folder, modifiedSince, limit, includeRecentlyDeleted);
|
|
43009
43142
|
}
|
|
43010
43143
|
/**
|
|
43011
43144
|
* Lists all shared (collaborative) notes across all accounts.
|
|
@@ -44075,7 +44208,7 @@ var AppleNotesManager = class {
|
|
|
44075
44208
|
if (parts[0] !== "OK") {
|
|
44076
44209
|
return { success: false, error: parts[1]?.trim() || "attachment not found" };
|
|
44077
44210
|
}
|
|
44078
|
-
if (!
|
|
44211
|
+
if (!existsSync5(abs) || fileSize(abs) === 0) {
|
|
44079
44212
|
return { success: false, error: `Notes reported success but no file was written to ${abs}` };
|
|
44080
44213
|
}
|
|
44081
44214
|
return {
|
|
@@ -44580,15 +44713,15 @@ var AppleNotesManager = class {
|
|
|
44580
44713
|
};
|
|
44581
44714
|
|
|
44582
44715
|
// src/utils/syncDetection.ts
|
|
44583
|
-
import { execFileSync as
|
|
44584
|
-
import * as
|
|
44585
|
-
import * as
|
|
44586
|
-
import * as
|
|
44587
|
-
var
|
|
44588
|
-
|
|
44716
|
+
import { execFileSync as execFileSync9 } from "child_process";
|
|
44717
|
+
import * as fs4 from "fs";
|
|
44718
|
+
import * as path4 from "path";
|
|
44719
|
+
import * as os4 from "os";
|
|
44720
|
+
var NOTES_DB_PATH5 = path4.join(
|
|
44721
|
+
os4.homedir(),
|
|
44589
44722
|
"Library/Group Containers/group.com.apple.notes/NoteStore.sqlite"
|
|
44590
44723
|
);
|
|
44591
|
-
var WAL_PATH = `${
|
|
44724
|
+
var WAL_PATH = `${NOTES_DB_PATH5}-wal`;
|
|
44592
44725
|
var RECENT_ACTIVITY_THRESHOLD_SECONDS = 5;
|
|
44593
44726
|
var SYNC_STATUS_CACHE_TTL_MS = 2e3;
|
|
44594
44727
|
var cachedSyncStatus = null;
|
|
@@ -44604,19 +44737,19 @@ function getSyncStatus(useCache = true) {
|
|
|
44604
44737
|
recentActivity: false
|
|
44605
44738
|
};
|
|
44606
44739
|
try {
|
|
44607
|
-
if (!
|
|
44740
|
+
if (!fs4.existsSync(NOTES_DB_PATH5)) {
|
|
44608
44741
|
status.error = "Notes database not found";
|
|
44609
44742
|
cachedSyncStatus = status;
|
|
44610
44743
|
cacheTimestamp = Date.now();
|
|
44611
44744
|
return status;
|
|
44612
44745
|
}
|
|
44613
|
-
if (
|
|
44614
|
-
const walStats =
|
|
44746
|
+
if (fs4.existsSync(WAL_PATH)) {
|
|
44747
|
+
const walStats = fs4.statSync(WAL_PATH);
|
|
44615
44748
|
const secondsAgo = (Date.now() - walStats.mtimeMs) / 1e3;
|
|
44616
44749
|
status.secondsSinceLastChange = Math.round(secondsAgo);
|
|
44617
44750
|
status.recentActivity = secondsAgo < RECENT_ACTIVITY_THRESHOLD_SECONDS;
|
|
44618
44751
|
}
|
|
44619
|
-
const
|
|
44752
|
+
const query2 = `
|
|
44620
44753
|
SELECT COUNT(*) FROM ZICCLOUDSTATE state
|
|
44621
44754
|
WHERE state.ZCURRENTLOCALVERSION > state.ZLATESTVERSIONSYNCEDTOCLOUD
|
|
44622
44755
|
AND state.ZLATESTVERSIONSYNCEDTOCLOUD IS NOT NULL
|
|
@@ -44625,9 +44758,9 @@ function getSyncStatus(useCache = true) {
|
|
|
44625
44758
|
WHERE object.ZCLOUDSTATE = state.Z_PK
|
|
44626
44759
|
);
|
|
44627
44760
|
`;
|
|
44628
|
-
const result =
|
|
44761
|
+
const result = execFileSync9(
|
|
44629
44762
|
"sqlite3",
|
|
44630
|
-
["-readonly",
|
|
44763
|
+
["-readonly", NOTES_DB_PATH5, query2.replace(/\n/g, " ")],
|
|
44631
44764
|
{
|
|
44632
44765
|
encoding: "utf8",
|
|
44633
44766
|
timeout: 5e3,
|
|
@@ -44684,12 +44817,12 @@ function withSyncAwarenessSync(operation, fn) {
|
|
|
44684
44817
|
}
|
|
44685
44818
|
|
|
44686
44819
|
// src/utils/noteMetadata.ts
|
|
44687
|
-
import { execFileSync as
|
|
44688
|
-
import * as
|
|
44689
|
-
import * as
|
|
44690
|
-
import * as
|
|
44691
|
-
var
|
|
44692
|
-
|
|
44820
|
+
import { execFileSync as execFileSync10 } from "child_process";
|
|
44821
|
+
import * as fs5 from "fs";
|
|
44822
|
+
import * as path5 from "path";
|
|
44823
|
+
import * as os5 from "os";
|
|
44824
|
+
var NOTES_DB_PATH6 = path5.join(
|
|
44825
|
+
os5.homedir(),
|
|
44693
44826
|
"Library/Group Containers/group.com.apple.notes/NoteStore.sqlite"
|
|
44694
44827
|
);
|
|
44695
44828
|
var FDA_MESSAGE2 = `Full Disk Access is required to read note metadata. In System Settings > Privacy & Security > Full Disk Access, grant access to the app that launches this server (Claude Desktop / Terminal / iTerm2), then fully quit and relaunch it. Setup guide: ${FULL_DISK_ACCESS_GUIDE_URL} \u2014 run the doctor tool to verify.`;
|
|
@@ -44704,8 +44837,8 @@ var COLUMN_MAP = [
|
|
|
44704
44837
|
{ key: "widgetSnippet", column: "ZWIDGETSNIPPET", type: "text" },
|
|
44705
44838
|
{ key: "smartFolderQuery", column: "ZSMARTFOLDERQUERYJSON", type: "text" }
|
|
44706
44839
|
];
|
|
44707
|
-
function runSqlite5(
|
|
44708
|
-
return
|
|
44840
|
+
function runSqlite5(query2) {
|
|
44841
|
+
return execFileSync10("sqlite3", ["-readonly", NOTES_DB_PATH6, query2], {
|
|
44709
44842
|
encoding: "utf8",
|
|
44710
44843
|
timeout: 5e3,
|
|
44711
44844
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -44730,7 +44863,7 @@ function getNoteMetadata(noteId3) {
|
|
|
44730
44863
|
};
|
|
44731
44864
|
}
|
|
44732
44865
|
const pk = pkMatch[1];
|
|
44733
|
-
if (!
|
|
44866
|
+
if (!fs5.existsSync(NOTES_DB_PATH6)) {
|
|
44734
44867
|
return { metadata: null, error: "no_fda", message: FDA_MESSAGE2 };
|
|
44735
44868
|
}
|
|
44736
44869
|
try {
|
|
@@ -44776,12 +44909,12 @@ function getNoteMetadata(noteId3) {
|
|
|
44776
44909
|
import { gunzipSync as gunzipSync6 } from "zlib";
|
|
44777
44910
|
|
|
44778
44911
|
// src/utils/noteStoreSql.ts
|
|
44779
|
-
import { execFileSync as
|
|
44780
|
-
import * as
|
|
44781
|
-
import * as
|
|
44782
|
-
import * as
|
|
44783
|
-
var
|
|
44784
|
-
|
|
44912
|
+
import { execFileSync as execFileSync11 } from "child_process";
|
|
44913
|
+
import * as fs6 from "fs";
|
|
44914
|
+
import * as os6 from "os";
|
|
44915
|
+
import * as path6 from "path";
|
|
44916
|
+
var NOTES_DB_PATH7 = path6.join(
|
|
44917
|
+
os6.homedir(),
|
|
44785
44918
|
"Library/Group Containers/group.com.apple.notes/NoteStore.sqlite"
|
|
44786
44919
|
);
|
|
44787
44920
|
var CORE_DATA_EPOCH_MS = Date.UTC(2001, 0, 1);
|
|
@@ -44819,7 +44952,7 @@ function renderValue(value) {
|
|
|
44819
44952
|
return `ieee754_from_blob(x'${doubleToHex(double)}')`;
|
|
44820
44953
|
}
|
|
44821
44954
|
function runReadOnlySql(dbPath2, sql, params = {}) {
|
|
44822
|
-
if (!
|
|
44955
|
+
if (!fs6.existsSync(dbPath2)) throw new NoteStoreError(STORE_FDA_MESSAGE, "no_fda");
|
|
44823
44956
|
const args = ["-readonly"];
|
|
44824
44957
|
const names = Object.keys(params);
|
|
44825
44958
|
if (names.length) args.push("-cmd", ".parameter init");
|
|
@@ -44831,7 +44964,7 @@ function runReadOnlySql(dbPath2, sql, params = {}) {
|
|
|
44831
44964
|
}
|
|
44832
44965
|
args.push(dbPath2, sql);
|
|
44833
44966
|
try {
|
|
44834
|
-
return
|
|
44967
|
+
return execFileSync11("sqlite3", args, {
|
|
44835
44968
|
encoding: "utf8",
|
|
44836
44969
|
timeout: 3e4,
|
|
44837
44970
|
maxBuffer: 512 * 1024 * 1024,
|
|
@@ -45024,7 +45157,7 @@ function buildSpecialNotesSql(columns, kind, scoped) {
|
|
|
45024
45157
|
].join(" ");
|
|
45025
45158
|
}
|
|
45026
45159
|
function listSpecialNotes(options) {
|
|
45027
|
-
const dbPath2 = options.dbPath ??
|
|
45160
|
+
const dbPath2 = options.dbPath ?? NOTES_DB_PATH7;
|
|
45028
45161
|
const limit = Math.min(
|
|
45029
45162
|
Math.max(1, Math.trunc(options.limit ?? SPECIAL_LIMIT.DEFAULT)),
|
|
45030
45163
|
SPECIAL_LIMIT.MAX
|
|
@@ -45115,7 +45248,7 @@ function referencedObjects(hex3) {
|
|
|
45115
45248
|
}
|
|
45116
45249
|
}
|
|
45117
45250
|
function nativeTagInventory(options = {}) {
|
|
45118
|
-
const dbPath2 = options.dbPath ??
|
|
45251
|
+
const dbPath2 = options.dbPath ?? NOTES_DB_PATH7;
|
|
45119
45252
|
const columns = readColumns(dbPath2);
|
|
45120
45253
|
const context = readStoreContext(dbPath2, columns);
|
|
45121
45254
|
const scope2 = options.account ? resolveAccountName(context.accounts, options.account) : void 0;
|
|
@@ -45177,12 +45310,12 @@ function assembleInventory(rows, accounts, scope2) {
|
|
|
45177
45310
|
}
|
|
45178
45311
|
|
|
45179
45312
|
// src/utils/noteIdentifiers.ts
|
|
45180
|
-
import { execFileSync as
|
|
45181
|
-
import * as
|
|
45182
|
-
import * as
|
|
45183
|
-
import * as
|
|
45184
|
-
var
|
|
45185
|
-
|
|
45313
|
+
import { execFileSync as execFileSync12 } from "child_process";
|
|
45314
|
+
import * as fs7 from "fs";
|
|
45315
|
+
import * as os7 from "os";
|
|
45316
|
+
import * as path7 from "path";
|
|
45317
|
+
var NOTES_DB_PATH8 = path7.join(
|
|
45318
|
+
os7.homedir(),
|
|
45186
45319
|
"Library/Group Containers/group.com.apple.notes/NoteStore.sqlite"
|
|
45187
45320
|
);
|
|
45188
45321
|
var UUID_PATTERN = /^[0-9A-Fa-f]{8}(?:-[0-9A-Fa-f]{4}){3}-[0-9A-Fa-f]{12}$/;
|
|
@@ -45256,10 +45389,10 @@ function buildLookupSql(entity3, keys) {
|
|
|
45256
45389
|
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})));`;
|
|
45257
45390
|
}
|
|
45258
45391
|
function runJsonQuery(sql, dbPath2) {
|
|
45259
|
-
if (!
|
|
45392
|
+
if (!fs7.existsSync(dbPath2)) throw new IdentifierResolutionError("no_fda", NO_FDA_MESSAGE);
|
|
45260
45393
|
let out;
|
|
45261
45394
|
try {
|
|
45262
|
-
out =
|
|
45395
|
+
out = execFileSync12("sqlite3", ["-readonly", dbPath2, sql], {
|
|
45263
45396
|
encoding: "utf8",
|
|
45264
45397
|
timeout: 5e3,
|
|
45265
45398
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -45279,7 +45412,7 @@ function runJsonQuery(sql, dbPath2) {
|
|
|
45279
45412
|
function coreDataId(store, entity3, pk) {
|
|
45280
45413
|
return `x-coredata://${store}/${entity3}/p${pk}`;
|
|
45281
45414
|
}
|
|
45282
|
-
function resolveIdentifiers(values, entity3, dbPath2 =
|
|
45415
|
+
function resolveIdentifiers(values, entity3, dbPath2 = NOTES_DB_PATH8) {
|
|
45283
45416
|
const resolved = /* @__PURE__ */ new Map();
|
|
45284
45417
|
const keys = [];
|
|
45285
45418
|
const uuids = [];
|
|
@@ -45325,7 +45458,7 @@ function resolveIdentifiers(values, entity3, dbPath2 = NOTES_DB_PATH7) {
|
|
|
45325
45458
|
return resolved;
|
|
45326
45459
|
}
|
|
45327
45460
|
var COREDATA_PARTS = /^x-coredata:\/\/([0-9A-Fa-f-]+)\/(ICNote|ICFolder|ICAccount)\/p(\d{1,18})$/;
|
|
45328
|
-
function lookupStableIdentifiers(ids, entity3, dbPath2 =
|
|
45461
|
+
function lookupStableIdentifiers(ids, entity3, dbPath2 = NOTES_DB_PATH8) {
|
|
45329
45462
|
const result = /* @__PURE__ */ new Map();
|
|
45330
45463
|
const wanted = /* @__PURE__ */ new Map();
|
|
45331
45464
|
for (const id2 of ids) {
|
|
@@ -45337,14 +45470,14 @@ function lookupStableIdentifiers(ids, entity3, dbPath2 = NOTES_DB_PATH7) {
|
|
|
45337
45470
|
wanted.set(pk, list);
|
|
45338
45471
|
}
|
|
45339
45472
|
if (wanted.size === 0) return result;
|
|
45340
|
-
let
|
|
45473
|
+
let query2;
|
|
45341
45474
|
try {
|
|
45342
|
-
|
|
45475
|
+
query2 = runJsonQuery(buildLookupSql(entity3, [...wanted.keys()]), dbPath2);
|
|
45343
45476
|
} catch {
|
|
45344
45477
|
return result;
|
|
45345
45478
|
}
|
|
45346
|
-
const store =
|
|
45347
|
-
for (const row of
|
|
45479
|
+
const store = query2.store?.toUpperCase();
|
|
45480
|
+
for (const row of query2.rows) {
|
|
45348
45481
|
const fields = {};
|
|
45349
45482
|
for (const key of [
|
|
45350
45483
|
"identifier",
|
|
@@ -45361,7 +45494,7 @@ function lookupStableIdentifiers(ids, entity3, dbPath2 = NOTES_DB_PATH7) {
|
|
|
45361
45494
|
}
|
|
45362
45495
|
return result;
|
|
45363
45496
|
}
|
|
45364
|
-
function withStableIdentifiers(items, entity3, dbPath2 =
|
|
45497
|
+
function withStableIdentifiers(items, entity3, dbPath2 = NOTES_DB_PATH8) {
|
|
45365
45498
|
const ids = items.map((item) => item.id).filter((id2) => typeof id2 === "string");
|
|
45366
45499
|
if (ids.length === 0) return items;
|
|
45367
45500
|
const found = lookupStableIdentifiers(ids, entity3, dbPath2);
|
|
@@ -45949,13 +46082,13 @@ function positiveTextTerms(node, negated = false) {
|
|
|
45949
46082
|
}
|
|
45950
46083
|
|
|
45951
46084
|
// src/utils/noteQueryStore.ts
|
|
45952
|
-
import { execFileSync as
|
|
45953
|
-
import * as
|
|
45954
|
-
import * as
|
|
45955
|
-
import * as
|
|
46085
|
+
import { execFileSync as execFileSync13 } from "child_process";
|
|
46086
|
+
import * as fs8 from "fs";
|
|
46087
|
+
import * as os8 from "os";
|
|
46088
|
+
import * as path8 from "path";
|
|
45956
46089
|
import { gunzipSync as gunzipSync7 } from "zlib";
|
|
45957
|
-
var
|
|
45958
|
-
|
|
46090
|
+
var NOTES_DB_PATH9 = path8.join(
|
|
46091
|
+
os8.homedir(),
|
|
45959
46092
|
"Library/Group Containers/group.com.apple.notes/NoteStore.sqlite"
|
|
45960
46093
|
);
|
|
45961
46094
|
var QUERY_SCAN = { DEFAULT: 500, MAX: 5e3 };
|
|
@@ -46089,8 +46222,8 @@ function buildScanSql(available, options) {
|
|
|
46089
46222
|
"COMMIT;"
|
|
46090
46223
|
].join(" ");
|
|
46091
46224
|
}
|
|
46092
|
-
function runSqlite6(dbPath2,
|
|
46093
|
-
return
|
|
46225
|
+
function runSqlite6(dbPath2, query2) {
|
|
46226
|
+
return execFileSync13("sqlite3", ["-readonly", dbPath2, query2], {
|
|
46094
46227
|
encoding: "utf8",
|
|
46095
46228
|
timeout: 3e4,
|
|
46096
46229
|
maxBuffer: 512 * 1024 * 1024,
|
|
@@ -46117,12 +46250,12 @@ function resolveFolders(rows) {
|
|
|
46117
46250
|
seen.add(pk);
|
|
46118
46251
|
const parent = row.parent !== null ? resolve5(row.parent, seen) : void 0;
|
|
46119
46252
|
const name = row.name ?? "";
|
|
46120
|
-
const
|
|
46253
|
+
const path9 = parent ? `${parent.path}/${escapeSegment(name)}` : escapeSegment(name);
|
|
46121
46254
|
const plainPath = parent ? `${parent.plainPath}/${name}` : name;
|
|
46122
46255
|
const info = {
|
|
46123
|
-
path:
|
|
46256
|
+
path: path9,
|
|
46124
46257
|
plainPath,
|
|
46125
|
-
keys: [...new Set([name, plainPath,
|
|
46258
|
+
keys: [...new Set([name, plainPath, path9].map(normalizeForMatch))],
|
|
46126
46259
|
accountPk: row.owner ?? parent?.accountPk ?? null,
|
|
46127
46260
|
shared: Boolean(row.shared) || Boolean(parent?.shared)
|
|
46128
46261
|
};
|
|
@@ -46154,8 +46287,8 @@ function queryNotes(expression, options = {}) {
|
|
|
46154
46287
|
const includeDeleted = options.includeDeleted ?? false;
|
|
46155
46288
|
const withBodies = needsContent(ast);
|
|
46156
46289
|
const withTags = needsTags(ast);
|
|
46157
|
-
const dbPath2 = options.dbPath ??
|
|
46158
|
-
if (!
|
|
46290
|
+
const dbPath2 = options.dbPath ?? NOTES_DB_PATH9;
|
|
46291
|
+
if (!fs8.existsSync(dbPath2)) throw new NoteQueryStoreError(QUERY_FDA_MESSAGE, "no_fda");
|
|
46159
46292
|
let output;
|
|
46160
46293
|
try {
|
|
46161
46294
|
const available = presentColumns2(dbPath2);
|
|
@@ -46290,10 +46423,10 @@ function queryNotes(expression, options = {}) {
|
|
|
46290
46423
|
import { spawnSync } from "child_process";
|
|
46291
46424
|
|
|
46292
46425
|
// src/services/nativeTags.ts
|
|
46293
|
-
import { execFileSync as
|
|
46426
|
+
import { execFileSync as execFileSync14 } from "node:child_process";
|
|
46294
46427
|
import { mkdtempSync as mkdtempSync2, writeFileSync, rmSync as rmSync2 } from "node:fs";
|
|
46295
46428
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
46296
|
-
import { join as
|
|
46429
|
+
import { join as join15 } from "node:path";
|
|
46297
46430
|
|
|
46298
46431
|
// src/services/shortcutConsent.ts
|
|
46299
46432
|
function shortcutConsentHint(shortcut) {
|
|
@@ -46369,7 +46502,7 @@ function addNativeTags(request, deps) {
|
|
|
46369
46502
|
};
|
|
46370
46503
|
}
|
|
46371
46504
|
function listInstalledShortcuts() {
|
|
46372
|
-
return
|
|
46505
|
+
return execFileSync14("/usr/bin/shortcuts", ["list", "--show-identifiers"], {
|
|
46373
46506
|
encoding: "utf8",
|
|
46374
46507
|
timeout: 15e3,
|
|
46375
46508
|
maxBuffer: 1024 * 1024,
|
|
@@ -46395,11 +46528,11 @@ function runNativeTagsShortcut(input) {
|
|
|
46395
46528
|
const status = nativeTagsStatus();
|
|
46396
46529
|
if (!status.installed)
|
|
46397
46530
|
throw new Error(`Import the supplied ${status.shortcut}.shortcut in Shortcuts first`);
|
|
46398
|
-
const directory = mkdtempSync2(
|
|
46531
|
+
const directory = mkdtempSync2(join15(tmpdir2(), "apple-notes-native-tags-"));
|
|
46399
46532
|
try {
|
|
46400
|
-
const
|
|
46401
|
-
writeFileSync(
|
|
46402
|
-
|
|
46533
|
+
const path9 = join15(directory, "request.json");
|
|
46534
|
+
writeFileSync(path9, JSON.stringify(input), { mode: 384 });
|
|
46535
|
+
execFileSync14("/usr/bin/shortcuts", ["run", status.identifier, "--input-path", path9], {
|
|
46403
46536
|
encoding: "utf8",
|
|
46404
46537
|
timeout: 6e4,
|
|
46405
46538
|
maxBuffer: 1024 * 1024,
|
|
@@ -46418,10 +46551,10 @@ function runNativeTagsShortcut(input) {
|
|
|
46418
46551
|
}
|
|
46419
46552
|
|
|
46420
46553
|
// src/services/backgroundNotes.ts
|
|
46421
|
-
import { execFileSync as
|
|
46554
|
+
import { execFileSync as execFileSync15 } from "node:child_process";
|
|
46422
46555
|
import { mkdtempSync as mkdtempSync3, writeFileSync as writeFileSync2, rmSync as rmSync3 } from "node:fs";
|
|
46423
46556
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
46424
|
-
import { join as
|
|
46557
|
+
import { join as join16 } from "node:path";
|
|
46425
46558
|
|
|
46426
46559
|
// src/utils/appendMarkdown.ts
|
|
46427
46560
|
var escape2 = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
@@ -46746,9 +46879,9 @@ function runBackgroundShortcut(input, status = backgroundStatus()) {
|
|
|
46746
46879
|
throw new Error(
|
|
46747
46880
|
`Install the supplied "${status.shortcut}" Shortcut once; Shortcuts must list it exactly once`
|
|
46748
46881
|
);
|
|
46749
|
-
const directory = mkdtempSync3(
|
|
46882
|
+
const directory = mkdtempSync3(join16(tmpdir3(), "apple-notes-background-"));
|
|
46750
46883
|
try {
|
|
46751
|
-
const file =
|
|
46884
|
+
const file = join16(directory, "request.json");
|
|
46752
46885
|
writeFileSync2(
|
|
46753
46886
|
file,
|
|
46754
46887
|
JSON.stringify({
|
|
@@ -46768,7 +46901,7 @@ function runBackgroundShortcut(input, status = backgroundStatus()) {
|
|
|
46768
46901
|
{ mode: 384 }
|
|
46769
46902
|
);
|
|
46770
46903
|
try {
|
|
46771
|
-
|
|
46904
|
+
execFileSync15("/usr/bin/shortcuts", ["run", status.identifier, "--input-path", file], {
|
|
46772
46905
|
encoding: "utf8",
|
|
46773
46906
|
timeout: callTimeoutMs() ?? 6e4,
|
|
46774
46907
|
maxBuffer: 1024 * 1024,
|
|
@@ -47003,7 +47136,7 @@ function createMarkdownNote(manager, request, run = runBackgroundShortcut) {
|
|
|
47003
47136
|
throw new Error(
|
|
47004
47137
|
`Install the supplied "${status.shortcut}" Shortcut once; Shortcuts must list it exactly once`
|
|
47005
47138
|
);
|
|
47006
|
-
const segments = (
|
|
47139
|
+
const segments = (path9) => JSON.stringify(splitFolderPath(path9).map((part) => part.toLocaleLowerCase()));
|
|
47007
47140
|
if (request.folder) {
|
|
47008
47141
|
const wanted = segments(request.folder);
|
|
47009
47142
|
if (!manager.listAccounts().some(
|
|
@@ -47093,7 +47226,7 @@ ${request.content}`
|
|
|
47093
47226
|
}
|
|
47094
47227
|
|
|
47095
47228
|
// src/services/capabilityMatrix.ts
|
|
47096
|
-
import { execFileSync as
|
|
47229
|
+
import { execFileSync as execFileSync16 } from "node:child_process";
|
|
47097
47230
|
import { release } from "node:os";
|
|
47098
47231
|
var MACOS_SHORTCUTS_CLI = "12.0";
|
|
47099
47232
|
var MACOS_MARKDOWN_IMPORT = "26.0";
|
|
@@ -47300,7 +47433,7 @@ function evaluateFeatures(env, features = FEATURES) {
|
|
|
47300
47433
|
function readMacOSVersion() {
|
|
47301
47434
|
if (process.platform !== "darwin") return null;
|
|
47302
47435
|
try {
|
|
47303
|
-
const out =
|
|
47436
|
+
const out = execFileSync16("/usr/bin/sw_vers", ["-productVersion"], {
|
|
47304
47437
|
encoding: "utf8",
|
|
47305
47438
|
timeout: 3e3,
|
|
47306
47439
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -47333,9 +47466,9 @@ function getCapabilityMatrix(probe = probeCapabilityEnvironment) {
|
|
|
47333
47466
|
return evaluateFeatures(probe());
|
|
47334
47467
|
}
|
|
47335
47468
|
function formatCapabilityMatrix(matrix) {
|
|
47336
|
-
const
|
|
47469
|
+
const os9 = matrix.runtimeOS;
|
|
47337
47470
|
const lines = [
|
|
47338
|
-
`Feature matrix (macOS ${
|
|
47471
|
+
`Feature matrix (macOS ${os9.macOSVersion ?? "unknown"}, Darwin ${os9.darwinRelease}):`
|
|
47339
47472
|
];
|
|
47340
47473
|
for (const [name, status] of Object.entries(matrix.features)) {
|
|
47341
47474
|
lines.push(
|
|
@@ -47453,19 +47586,19 @@ function formatDoctorReport(r) {
|
|
|
47453
47586
|
}
|
|
47454
47587
|
|
|
47455
47588
|
// src/services/fileConfig.ts
|
|
47456
|
-
import { existsSync as
|
|
47457
|
-
import { join as
|
|
47458
|
-
import { homedir as
|
|
47589
|
+
import { existsSync as existsSync11, readFileSync as readFileSync2 } from "fs";
|
|
47590
|
+
import { join as join17 } from "path";
|
|
47591
|
+
import { homedir as homedir14 } from "os";
|
|
47459
47592
|
function fileConfigPath(env = process.env) {
|
|
47460
47593
|
const override = env.APPLE_NOTES_MCP_CONFIG_FILE;
|
|
47461
47594
|
if (override && override.trim()) return override.trim();
|
|
47462
|
-
return
|
|
47595
|
+
return join17(homedir14(), "Library", "Application Support", "apple-notes-mcp", "config.json");
|
|
47463
47596
|
}
|
|
47464
|
-
function loadFileConfig(env = process.env,
|
|
47597
|
+
function loadFileConfig(env = process.env, path9 = fileConfigPath(env)) {
|
|
47465
47598
|
const applied = [];
|
|
47466
47599
|
try {
|
|
47467
|
-
if (!
|
|
47468
|
-
const parsed = JSON.parse(readFileSync2(
|
|
47600
|
+
if (!existsSync11(path9)) return applied;
|
|
47601
|
+
const parsed = JSON.parse(readFileSync2(path9, "utf8"));
|
|
47469
47602
|
if (!parsed || typeof parsed !== "object") return applied;
|
|
47470
47603
|
for (const [k, v] of Object.entries(parsed)) {
|
|
47471
47604
|
if (typeof v !== "string") continue;
|
|
@@ -47475,7 +47608,7 @@ function loadFileConfig(env = process.env, path8 = fileConfigPath(env)) {
|
|
|
47475
47608
|
}
|
|
47476
47609
|
}
|
|
47477
47610
|
} catch (e) {
|
|
47478
|
-
console.error(`Failed to load apple-notes-mcp config file ${
|
|
47611
|
+
console.error(`Failed to load apple-notes-mcp config file ${path9}: ${String(e)}`);
|
|
47479
47612
|
}
|
|
47480
47613
|
return applied;
|
|
47481
47614
|
}
|
|
@@ -47762,10 +47895,10 @@ function createShutdown(stream, exit, timeoutMs = SHUTDOWN_DRAIN_TIMEOUT_MS) {
|
|
|
47762
47895
|
}
|
|
47763
47896
|
|
|
47764
47897
|
// src/utils/noteBlocks.ts
|
|
47765
|
-
import { execFileSync as
|
|
47766
|
-
import { existsSync as
|
|
47767
|
-
import { homedir as
|
|
47768
|
-
import { join as
|
|
47898
|
+
import { execFileSync as execFileSync17 } from "node:child_process";
|
|
47899
|
+
import { existsSync as existsSync12 } from "node:fs";
|
|
47900
|
+
import { homedir as homedir15 } from "node:os";
|
|
47901
|
+
import { join as join18 } from "node:path";
|
|
47769
47902
|
import { gunzipSync as gunzipSync8 } from "node:zlib";
|
|
47770
47903
|
var NoteBlocksError = class extends Error {
|
|
47771
47904
|
code;
|
|
@@ -48108,23 +48241,23 @@ function pageNoteBlocks(doc, { offset = 0, limit = 500, maxBytes = blocksMaxResp
|
|
|
48108
48241
|
undecodedFields: doc.undecodedFields
|
|
48109
48242
|
};
|
|
48110
48243
|
}
|
|
48111
|
-
var
|
|
48112
|
-
|
|
48244
|
+
var NOTES_DB_PATH10 = join18(
|
|
48245
|
+
homedir15(),
|
|
48113
48246
|
"Library/Group Containers/group.com.apple.notes/NoteStore.sqlite"
|
|
48114
48247
|
);
|
|
48115
|
-
function readNoteBlocks(id2, { dbPath: dbPath2 =
|
|
48248
|
+
function readNoteBlocks(id2, { dbPath: dbPath2 = NOTES_DB_PATH10 } = {}) {
|
|
48116
48249
|
const pk = /^x-coredata:\/\/[0-9a-f-]+\/ICNote\/p([0-9]{1,18})$/i.exec(id2)?.[1];
|
|
48117
48250
|
if (!pk)
|
|
48118
48251
|
throw new NoteBlocksError(
|
|
48119
48252
|
"invalid-id",
|
|
48120
48253
|
`Invalid note ID: expected x-coredata://<store>/ICNote/p<number>`
|
|
48121
48254
|
);
|
|
48122
|
-
if (!
|
|
48255
|
+
if (!existsSync12(dbPath2))
|
|
48123
48256
|
throw new NoteBlocksError("no-full-disk-access", "The Notes database is not readable");
|
|
48124
48257
|
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));";
|
|
48125
48258
|
let output;
|
|
48126
48259
|
try {
|
|
48127
|
-
output =
|
|
48260
|
+
output = execFileSync17(
|
|
48128
48261
|
"/usr/bin/sqlite3",
|
|
48129
48262
|
["-readonly", "-cmd", ".parameter init", "-cmd", `.parameter set @pk ${pk}`, dbPath2, sql],
|
|
48130
48263
|
{
|
|
@@ -48274,7 +48407,7 @@ function insertLink(request, deps) {
|
|
|
48274
48407
|
|
|
48275
48408
|
// src/services/notesExport.ts
|
|
48276
48409
|
import { mkdirSync as mkdirSync5 } from "node:fs";
|
|
48277
|
-
import { basename as basename4, dirname as dirname4, extname as extname4, join as
|
|
48410
|
+
import { basename as basename4, dirname as dirname4, extname as extname4, join as join21 } from "node:path";
|
|
48278
48411
|
|
|
48279
48412
|
// src/utils/exportAssets.ts
|
|
48280
48413
|
import {
|
|
@@ -48289,9 +48422,9 @@ import {
|
|
|
48289
48422
|
statSync as statSync3,
|
|
48290
48423
|
writeSync as writeSync3
|
|
48291
48424
|
} from "node:fs";
|
|
48292
|
-
import { homedir as
|
|
48293
|
-
import { basename as basename3, extname as extname3, join as
|
|
48294
|
-
var NOTES_CONTAINER =
|
|
48425
|
+
import { homedir as homedir16 } from "node:os";
|
|
48426
|
+
import { basename as basename3, extname as extname3, join as join19, relative as relative3, resolve as resolve3, sep as sep3 } from "node:path";
|
|
48427
|
+
var NOTES_CONTAINER = join19(homedir16(), "Library/Group Containers/group.com.apple.notes");
|
|
48295
48428
|
var MAX_EMBED_BYTES = 10 * 1024 * 1024;
|
|
48296
48429
|
var MAX_EMBED_TOTAL_BYTES = 256 * 1024 * 1024;
|
|
48297
48430
|
var MAX_DIRECTORY_ENTRIES = 2e4;
|
|
@@ -48318,10 +48451,10 @@ function listDirectory(dir, limit) {
|
|
|
48318
48451
|
return [];
|
|
48319
48452
|
}
|
|
48320
48453
|
}
|
|
48321
|
-
function isFile(
|
|
48454
|
+
function isFile(path9) {
|
|
48322
48455
|
let fd;
|
|
48323
48456
|
try {
|
|
48324
|
-
fd = openSync4(
|
|
48457
|
+
fd = openSync4(path9, constants4.O_RDONLY | constants4.O_NOFOLLOW);
|
|
48325
48458
|
return fstatSync4(fd).isFile();
|
|
48326
48459
|
} catch {
|
|
48327
48460
|
return false;
|
|
@@ -48329,9 +48462,9 @@ function isFile(path8) {
|
|
|
48329
48462
|
if (fd !== void 0) closeSync4(fd);
|
|
48330
48463
|
}
|
|
48331
48464
|
}
|
|
48332
|
-
function isDirectory2(
|
|
48465
|
+
function isDirectory2(path9) {
|
|
48333
48466
|
try {
|
|
48334
|
-
return statSync3(
|
|
48467
|
+
return statSync3(path9).isDirectory();
|
|
48335
48468
|
} catch {
|
|
48336
48469
|
return false;
|
|
48337
48470
|
}
|
|
@@ -48347,11 +48480,11 @@ var AssetLocator = class {
|
|
|
48347
48480
|
constructor(container = NOTES_CONTAINER) {
|
|
48348
48481
|
let accountsRoot = "";
|
|
48349
48482
|
try {
|
|
48350
|
-
accountsRoot = realpathSync3.native(
|
|
48483
|
+
accountsRoot = realpathSync3.native(join19(container, "Accounts"));
|
|
48351
48484
|
} catch {
|
|
48352
48485
|
}
|
|
48353
48486
|
this.accounts = accountsRoot ? listDirectory(accountsRoot, 1e3).flatMap((name) => {
|
|
48354
|
-
const dir = safeComponent2(name) && confine(
|
|
48487
|
+
const dir = safeComponent2(name) && confine(join19(accountsRoot, name), accountsRoot);
|
|
48355
48488
|
return dir && isDirectory2(dir) ? [dir] : [];
|
|
48356
48489
|
}) : [];
|
|
48357
48490
|
}
|
|
@@ -48411,18 +48544,18 @@ var AssetLocator = class {
|
|
|
48411
48544
|
if (!mediaId || !filename) return void 0;
|
|
48412
48545
|
const generation = safeComponent2(source.mediaGeneration);
|
|
48413
48546
|
const candidates = [
|
|
48414
|
-
...generation ? [
|
|
48415
|
-
|
|
48547
|
+
...generation ? [join19(account, "Media", mediaId, generation, filename)] : [],
|
|
48548
|
+
join19(account, "Media", mediaId, filename)
|
|
48416
48549
|
];
|
|
48417
48550
|
for (const candidate of candidates) {
|
|
48418
|
-
const
|
|
48419
|
-
if (
|
|
48551
|
+
const path9 = confine(candidate, account);
|
|
48552
|
+
if (path9 && isFile(path9)) return { path: path9, name: filename, role: "original" };
|
|
48420
48553
|
}
|
|
48421
48554
|
return void 0;
|
|
48422
48555
|
}
|
|
48423
48556
|
/** <dir>/<id>/<generation>/<name>, <dir>/<id>/<name>, then any generation. */
|
|
48424
48557
|
fallback(account, dir, id2, generation, names) {
|
|
48425
|
-
const base =
|
|
48558
|
+
const base = join19(account, dir, id2);
|
|
48426
48559
|
const gen = safeComponent2(generation);
|
|
48427
48560
|
const generations = [
|
|
48428
48561
|
...gen ? [gen] : [],
|
|
@@ -48431,8 +48564,8 @@ var AssetLocator = class {
|
|
|
48431
48564
|
];
|
|
48432
48565
|
for (const g of generations)
|
|
48433
48566
|
for (const name of names) {
|
|
48434
|
-
const
|
|
48435
|
-
if (
|
|
48567
|
+
const path9 = confine(g ? join19(base, g, name) : join19(base, name), account);
|
|
48568
|
+
if (path9 && isFile(path9)) return path9;
|
|
48436
48569
|
}
|
|
48437
48570
|
return void 0;
|
|
48438
48571
|
}
|
|
@@ -48441,7 +48574,7 @@ var AssetLocator = class {
|
|
|
48441
48574
|
let index = this.previewIndex.get(account);
|
|
48442
48575
|
if (!index) {
|
|
48443
48576
|
index = /* @__PURE__ */ new Map();
|
|
48444
|
-
for (const name of listDirectory(
|
|
48577
|
+
for (const name of listDirectory(join19(account, "Previews"), MAX_DIRECTORY_ENTRIES)) {
|
|
48445
48578
|
const key = name.slice(0, 36).toUpperCase();
|
|
48446
48579
|
const entries3 = index.get(key) ?? [];
|
|
48447
48580
|
entries3.push(name);
|
|
@@ -48454,7 +48587,7 @@ var AssetLocator = class {
|
|
|
48454
48587
|
return !ext || IMAGE_EXTENSIONS.has(ext) || /^\.\d+$/.test(ext);
|
|
48455
48588
|
}).sort((a, b) => previewArea(b) - previewArea(a) || a.localeCompare(b));
|
|
48456
48589
|
for (const name of entries2) {
|
|
48457
|
-
const entry = confine(
|
|
48590
|
+
const entry = confine(join19(account, "Previews", name), account);
|
|
48458
48591
|
if (!entry) continue;
|
|
48459
48592
|
const file = isFile(entry) ? entry : this.bundleImage(entry, account);
|
|
48460
48593
|
if (file) return { path: file, name: "preview", role: "preview" };
|
|
@@ -48465,16 +48598,16 @@ var AssetLocator = class {
|
|
|
48465
48598
|
bundleImage(bundle, account) {
|
|
48466
48599
|
const found = [];
|
|
48467
48600
|
for (const child of listDirectory(bundle, MAX_BUNDLE_ENTRIES2)) {
|
|
48468
|
-
const
|
|
48469
|
-
if (!
|
|
48470
|
-
if (isFile(
|
|
48601
|
+
const path9 = confine(join19(bundle, child), account);
|
|
48602
|
+
if (!path9) continue;
|
|
48603
|
+
if (isFile(path9)) found.push(path9);
|
|
48471
48604
|
else
|
|
48472
|
-
for (const grandchild of listDirectory(
|
|
48473
|
-
const inner = confine(
|
|
48605
|
+
for (const grandchild of listDirectory(path9, MAX_BUNDLE_ENTRIES2)) {
|
|
48606
|
+
const inner = confine(join19(path9, grandchild), account);
|
|
48474
48607
|
if (inner && isFile(inner)) found.push(inner);
|
|
48475
48608
|
}
|
|
48476
48609
|
}
|
|
48477
|
-
return found.find((
|
|
48610
|
+
return found.find((path9) => basename3(path9) === "Preview.png") ?? found.find((path9) => IMAGE_EXTENSIONS.has(extname3(path9).toLowerCase()));
|
|
48478
48611
|
}
|
|
48479
48612
|
};
|
|
48480
48613
|
function sniffMime(head, name) {
|
|
@@ -48522,8 +48655,8 @@ function safeAssetName(name, mime) {
|
|
|
48522
48655
|
if (clean.length > 120) clean = clean.slice(0, 120 - ext.length) + ext;
|
|
48523
48656
|
return clean;
|
|
48524
48657
|
}
|
|
48525
|
-
function encodePathUrl(
|
|
48526
|
-
return
|
|
48658
|
+
function encodePathUrl(path9) {
|
|
48659
|
+
return path9.split("/").map(encodeURIComponent).join("/");
|
|
48527
48660
|
}
|
|
48528
48661
|
function canonicalForm(abs) {
|
|
48529
48662
|
let current = abs;
|
|
@@ -48531,18 +48664,18 @@ function canonicalForm(abs) {
|
|
|
48531
48664
|
for (; ; ) {
|
|
48532
48665
|
try {
|
|
48533
48666
|
const real = realpathSync3.native(current);
|
|
48534
|
-
return rest ?
|
|
48667
|
+
return rest ? join19(real, rest) : real;
|
|
48535
48668
|
} catch {
|
|
48536
48669
|
const parent = resolve3(current, "..");
|
|
48537
48670
|
if (parent === current) return abs;
|
|
48538
|
-
rest = rest ?
|
|
48671
|
+
rest = rest ? join19(basename3(current), rest) : basename3(current);
|
|
48539
48672
|
current = parent;
|
|
48540
48673
|
}
|
|
48541
48674
|
}
|
|
48542
48675
|
}
|
|
48543
48676
|
function assertExportPath(p, container = NOTES_CONTAINER) {
|
|
48544
48677
|
const abs = assertSafeSavePath(p);
|
|
48545
|
-
const within = (
|
|
48678
|
+
const within = (path9, root) => path9 === root || path9.startsWith(root + sep3);
|
|
48546
48679
|
const roots = [resolve3(container), canonicalForm(resolve3(container))];
|
|
48547
48680
|
const forms = [abs, canonicalForm(abs)];
|
|
48548
48681
|
if (forms.some((form) => roots.some((root) => within(form, root))))
|
|
@@ -48552,16 +48685,16 @@ function assertExportPath(p, container = NOTES_CONTAINER) {
|
|
|
48552
48685
|
var CREATE_FLAGS = constants4.O_WRONLY | constants4.O_CREAT | constants4.O_EXCL | constants4.O_NOFOLLOW;
|
|
48553
48686
|
var OutputExistsError = class extends Error {
|
|
48554
48687
|
code = "output_exists";
|
|
48555
|
-
constructor(
|
|
48556
|
-
super(`Output file already exists: ${
|
|
48688
|
+
constructor(path9) {
|
|
48689
|
+
super(`Output file already exists: ${path9}. Choose a new path or remove the old file first.`);
|
|
48557
48690
|
this.name = "OutputExistsError";
|
|
48558
48691
|
}
|
|
48559
48692
|
};
|
|
48560
|
-
function openCreateOnly(
|
|
48693
|
+
function openCreateOnly(path9) {
|
|
48561
48694
|
try {
|
|
48562
|
-
return openSync4(
|
|
48695
|
+
return openSync4(path9, CREATE_FLAGS, 420);
|
|
48563
48696
|
} catch (error2) {
|
|
48564
|
-
if (error2.code === "EEXIST") throw new OutputExistsError(
|
|
48697
|
+
if (error2.code === "EEXIST") throw new OutputExistsError(path9);
|
|
48565
48698
|
throw error2;
|
|
48566
48699
|
}
|
|
48567
48700
|
}
|
|
@@ -48575,8 +48708,8 @@ function writeAllAndClose(fd, content) {
|
|
|
48575
48708
|
closeSync4(fd);
|
|
48576
48709
|
}
|
|
48577
48710
|
}
|
|
48578
|
-
function openSource(
|
|
48579
|
-
const fd = openSync4(
|
|
48711
|
+
function openSource(path9) {
|
|
48712
|
+
const fd = openSync4(path9, constants4.O_RDONLY | constants4.O_NOFOLLOW);
|
|
48580
48713
|
const stat = fstatSync4(fd);
|
|
48581
48714
|
if (!stat.isFile()) {
|
|
48582
48715
|
closeSync4(fd);
|
|
@@ -48621,7 +48754,7 @@ var SidecarWriter = class {
|
|
|
48621
48754
|
let target;
|
|
48622
48755
|
let out;
|
|
48623
48756
|
for (let n = 1; n <= 1e3 && out === void 0; n++) {
|
|
48624
|
-
target =
|
|
48757
|
+
target = join19(this.dir, n === 1 ? name : `${stem}-${n}${ext}`);
|
|
48625
48758
|
try {
|
|
48626
48759
|
out = openSync4(target, CREATE_FLAGS, 420);
|
|
48627
48760
|
} catch (error2) {
|
|
@@ -49376,11 +49509,11 @@ function renderNotesMarkdown(notes, ctx, { wrap: wrap2 = 0 } = {}) {
|
|
|
49376
49509
|
}
|
|
49377
49510
|
|
|
49378
49511
|
// src/utils/noteExportData.ts
|
|
49379
|
-
import { execFileSync as
|
|
49380
|
-
import { homedir as
|
|
49381
|
-
import { join as
|
|
49382
|
-
var
|
|
49383
|
-
|
|
49512
|
+
import { execFileSync as execFileSync18 } from "node:child_process";
|
|
49513
|
+
import { homedir as homedir17 } from "node:os";
|
|
49514
|
+
import { join as join20 } from "node:path";
|
|
49515
|
+
var NOTES_DB_PATH11 = join20(
|
|
49516
|
+
homedir17(),
|
|
49384
49517
|
"Library/Group Containers/group.com.apple.notes/NoteStore.sqlite"
|
|
49385
49518
|
);
|
|
49386
49519
|
var IMAGE_UTIS2 = /* @__PURE__ */ new Set([
|
|
@@ -49444,7 +49577,7 @@ var ATTACHMENT_COLUMNS = [
|
|
|
49444
49577
|
var columnCache = /* @__PURE__ */ new Map();
|
|
49445
49578
|
function sqlite(dbPath2, args) {
|
|
49446
49579
|
try {
|
|
49447
|
-
return
|
|
49580
|
+
return execFileSync18(
|
|
49448
49581
|
"/usr/bin/sqlite3",
|
|
49449
49582
|
["-readonly", ...args.slice(0, -1), dbPath2, args.at(-1)],
|
|
49450
49583
|
{
|
|
@@ -49461,7 +49594,7 @@ function sqlite(dbPath2, args) {
|
|
|
49461
49594
|
throw new NoteBlocksError("query-failed", "Failed to query the Notes database");
|
|
49462
49595
|
}
|
|
49463
49596
|
}
|
|
49464
|
-
function objectColumns(dbPath2 =
|
|
49597
|
+
function objectColumns(dbPath2 = NOTES_DB_PATH11) {
|
|
49465
49598
|
let columns = columnCache.get(dbPath2);
|
|
49466
49599
|
if (!columns) {
|
|
49467
49600
|
columns = new Set(
|
|
@@ -49519,7 +49652,7 @@ function buildAttachments(rows) {
|
|
|
49519
49652
|
}
|
|
49520
49653
|
return { byId: new Map(all.map((a) => [a.id, a])), ordered };
|
|
49521
49654
|
}
|
|
49522
|
-
function readExportNote(id2, { dbPath: dbPath2 =
|
|
49655
|
+
function readExportNote(id2, { dbPath: dbPath2 = NOTES_DB_PATH11 } = {}) {
|
|
49523
49656
|
const doc = readNoteBlocks(id2, { dbPath: dbPath2 });
|
|
49524
49657
|
const pk = /\/ICNote\/p([0-9]{1,18})$/.exec(id2)[1];
|
|
49525
49658
|
const output = sqlite(dbPath2, [
|
|
@@ -49558,9 +49691,9 @@ var NotesExportError = class extends Error {
|
|
|
49558
49691
|
}
|
|
49559
49692
|
code;
|
|
49560
49693
|
};
|
|
49561
|
-
function validPath(
|
|
49694
|
+
function validPath(path9, what) {
|
|
49562
49695
|
try {
|
|
49563
|
-
return assertExportPath(
|
|
49696
|
+
return assertExportPath(path9);
|
|
49564
49697
|
} catch (error2) {
|
|
49565
49698
|
throw new NotesExportError(
|
|
49566
49699
|
"invalid-path",
|
|
@@ -49652,7 +49785,7 @@ function exportNotesMarkdown(request, deps) {
|
|
|
49652
49785
|
return { ...receipt, markdown };
|
|
49653
49786
|
}
|
|
49654
49787
|
function defaultSidecarDir(output) {
|
|
49655
|
-
return
|
|
49788
|
+
return join21(dirname4(output), `${basename4(output, extname4(output))}.assets`);
|
|
49656
49789
|
}
|
|
49657
49790
|
function exportNotesHtml(request, deps) {
|
|
49658
49791
|
if (!request.outputPath)
|
|
@@ -49706,7 +49839,7 @@ import {
|
|
|
49706
49839
|
writeFileSync as writeFileSync3
|
|
49707
49840
|
} from "node:fs";
|
|
49708
49841
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
49709
|
-
import { basename as basename5, extname as extname5, isAbsolute as isAbsolute3, join as
|
|
49842
|
+
import { basename as basename5, extname as extname5, isAbsolute as isAbsolute3, join as join22 } from "node:path";
|
|
49710
49843
|
var noteId = exactIdInput(
|
|
49711
49844
|
"ICNote",
|
|
49712
49845
|
/^x-coredata:\/\/[0-9a-f-]+\/ICNote\/p\d+$/i,
|
|
@@ -49749,9 +49882,9 @@ function assertExistingContentPreserved(before, after) {
|
|
|
49749
49882
|
throw new Error("Existing native object content or presentation changed");
|
|
49750
49883
|
}
|
|
49751
49884
|
}
|
|
49752
|
-
function localAttachment(
|
|
49753
|
-
if (!isAbsolute3(
|
|
49754
|
-
const descriptor = openSync5(
|
|
49885
|
+
function localAttachment(path9) {
|
|
49886
|
+
if (!isAbsolute3(path9)) throw new Error("An absolute local file path is required");
|
|
49887
|
+
const descriptor = openSync5(path9, constants5.O_RDONLY | constants5.O_NOFOLLOW);
|
|
49755
49888
|
try {
|
|
49756
49889
|
const stat = fstatSync5(descriptor);
|
|
49757
49890
|
if (!stat.isFile() || stat.size === 0 || stat.size > 64 * 1024 * 1024)
|
|
@@ -49873,8 +50006,8 @@ function registerDirectOperations(server2, manager) {
|
|
|
49873
50006
|
}
|
|
49874
50007
|
);
|
|
49875
50008
|
}
|
|
49876
|
-
function attachmentName(
|
|
49877
|
-
const source = basename5(
|
|
50009
|
+
function attachmentName(path9, filename) {
|
|
50010
|
+
const source = basename5(path9);
|
|
49878
50011
|
if (filename === void 0) return source;
|
|
49879
50012
|
if (Buffer.byteLength(filename, "utf8") > 255)
|
|
49880
50013
|
throw new Error("filename must be at most 255 bytes");
|
|
@@ -49889,14 +50022,14 @@ function attachmentName(path8, filename) {
|
|
|
49889
50022
|
return filename;
|
|
49890
50023
|
}
|
|
49891
50024
|
function attachFile(manager, args) {
|
|
49892
|
-
const { id: id2, expectedContentHash, path:
|
|
49893
|
-
const name = attachmentName(
|
|
50025
|
+
const { id: id2, expectedContentHash, path: path9 } = args;
|
|
50026
|
+
const name = attachmentName(path9, args.filename);
|
|
49894
50027
|
const before = readSnapshot(manager, id2);
|
|
49895
50028
|
if (before.hash !== expectedContentHash) throw new Error("Note revision changed");
|
|
49896
|
-
const bytes = localAttachment(
|
|
50029
|
+
const bytes = localAttachment(path9);
|
|
49897
50030
|
const beforeAttachments = manager.listAttachmentsById(id2);
|
|
49898
|
-
const directory = mkdtempSync4(
|
|
49899
|
-
const temporaryFile =
|
|
50031
|
+
const directory = mkdtempSync4(join22(tmpdir4(), "notes-attachment-add-"));
|
|
50032
|
+
const temporaryFile = join22(directory, name);
|
|
49900
50033
|
try {
|
|
49901
50034
|
writeFileSync3(temporaryFile, bytes, { mode: 384 });
|
|
49902
50035
|
if (readSnapshot(manager, id2).hash !== before.hash) throw new Error("Note revision changed");
|
|
@@ -50454,7 +50587,7 @@ function registerNativeOperations(server2, manager) {
|
|
|
50454
50587
|
|
|
50455
50588
|
// src/setupShortcuts.ts
|
|
50456
50589
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
50457
|
-
import { existsSync as
|
|
50590
|
+
import { existsSync as existsSync13 } from "node:fs";
|
|
50458
50591
|
import { release as release2 } from "node:os";
|
|
50459
50592
|
import { dirname as dirname5, resolve as resolve4 } from "node:path";
|
|
50460
50593
|
import { fileURLToPath } from "node:url";
|
|
@@ -50474,16 +50607,16 @@ var shortcutFiles = [
|
|
|
50474
50607
|
];
|
|
50475
50608
|
function setupShortcuts(checkOnly, dependencies = {}) {
|
|
50476
50609
|
const status = dependencies.status || nativeTagsStatus;
|
|
50477
|
-
const exists = dependencies.exists ||
|
|
50478
|
-
const open = dependencies.open || ((
|
|
50479
|
-
const result = spawnSync2("/usr/bin/open", [
|
|
50610
|
+
const exists = dependencies.exists || existsSync13;
|
|
50611
|
+
const open = dependencies.open || ((path9) => {
|
|
50612
|
+
const result = spawnSync2("/usr/bin/open", [path9], { encoding: "utf8" });
|
|
50480
50613
|
return result.status === 0 ? { ok: true } : { ok: false, error: result.stderr || result.error?.message || "open failed" };
|
|
50481
50614
|
});
|
|
50482
50615
|
const baseDirectory = dependencies.baseDirectory || resolve4(dirname5(fileURLToPath(import.meta.url)), "../shortcuts");
|
|
50483
50616
|
const osRelease = (dependencies.osRelease || release2)();
|
|
50484
50617
|
const darwinMajor = Number.parseInt(osRelease.split(".")[0], 10);
|
|
50485
50618
|
const items = shortcutFiles.map(({ name, file, optional: optional2 }) => {
|
|
50486
|
-
const
|
|
50619
|
+
const path9 = resolve4(baseDirectory, file);
|
|
50487
50620
|
let installed = false;
|
|
50488
50621
|
let identifier;
|
|
50489
50622
|
let error2;
|
|
@@ -50499,9 +50632,9 @@ function setupShortcuts(checkOnly, dependencies = {}) {
|
|
|
50499
50632
|
if (!installed && !checkOnly) {
|
|
50500
50633
|
if (optional2 && !(darwinMajor >= MARKDOWN_MIN_DARWIN_MAJOR))
|
|
50501
50634
|
skipped = `requires macOS 26 or later (this Mac reports Darwin ${osRelease})`;
|
|
50502
|
-
else if (!exists(
|
|
50635
|
+
else if (!exists(path9)) error2 = `Packaged Shortcut is missing: ${path9}`;
|
|
50503
50636
|
else {
|
|
50504
|
-
const result = open(
|
|
50637
|
+
const result = open(path9);
|
|
50505
50638
|
opened = result.ok;
|
|
50506
50639
|
if (!result.ok) error2 = result.error || `Could not open ${file}`;
|
|
50507
50640
|
}
|
|
@@ -50510,7 +50643,7 @@ function setupShortcuts(checkOnly, dependencies = {}) {
|
|
|
50510
50643
|
name,
|
|
50511
50644
|
installed,
|
|
50512
50645
|
identifier,
|
|
50513
|
-
file:
|
|
50646
|
+
file: path9,
|
|
50514
50647
|
opened,
|
|
50515
50648
|
...optional2 ? { optional: optional2 } : {},
|
|
50516
50649
|
...skipped ? { skipped } : {},
|
|
@@ -50640,6 +50773,9 @@ function readExactNoteSnapshot(id2) {
|
|
|
50640
50773
|
return { note, body, rich, contentHash: richContentHash(body, rich) };
|
|
50641
50774
|
}
|
|
50642
50775
|
var NOT_DELETED_MESSAGE = "Notes.app accepted the delete, but the note is still in its original folder, so it was not moved to Recently Deleted. Nothing was deleted; read the note again before retrying.";
|
|
50776
|
+
function inRecentlyDeletedMessage(title) {
|
|
50777
|
+
return `Note "${title}" is already in Recently Deleted, where deleting it would remove it permanently. Nothing was deleted. Remove it from Recently Deleted in Notes.app if that is intended.`;
|
|
50778
|
+
}
|
|
50643
50779
|
function revisionConflictMessage(title) {
|
|
50644
50780
|
return `Note "${title}" changed after it was read. Read it again and review the newer version before retrying.`;
|
|
50645
50781
|
}
|
|
@@ -50818,7 +50954,7 @@ registerTool(
|
|
|
50818
50954
|
count: external_exports.number().optional()
|
|
50819
50955
|
}
|
|
50820
50956
|
},
|
|
50821
|
-
withErrorHandling(({ query, searchContent = false, account, folder, modifiedSince, limit }) => {
|
|
50957
|
+
withErrorHandling(({ query: query2, searchContent = false, account, folder, modifiedSince, limit }) => {
|
|
50822
50958
|
const effectiveLimit = resolveSearchLimit(limit);
|
|
50823
50959
|
const limitWasDefault = limit === void 0;
|
|
50824
50960
|
const {
|
|
@@ -50827,7 +50963,7 @@ registerTool(
|
|
|
50827
50963
|
syncInterference
|
|
50828
50964
|
} = withSyncAwarenessSync(
|
|
50829
50965
|
"search-notes",
|
|
50830
|
-
() => notesManager.searchNotes(
|
|
50966
|
+
() => notesManager.searchNotes(query2, searchContent, account, folder, modifiedSince, effectiveLimit)
|
|
50831
50967
|
);
|
|
50832
50968
|
const searchType = searchContent ? "content" : "titles";
|
|
50833
50969
|
const folderInfo = folder ? ` in folder "${folder}"` : "";
|
|
@@ -50850,7 +50986,7 @@ ${syncWarnings.join(" ")}` : "";
|
|
|
50850
50986
|
if (notes.length === 0) {
|
|
50851
50987
|
const scopeHint = describeSearchScope(searchContent, notes.length);
|
|
50852
50988
|
return successResponse(
|
|
50853
|
-
`No notes found matching "${
|
|
50989
|
+
`No notes found matching "${query2}" in ${searchType}${folderInfo}${dateInfo}${scopeHint}${syncNote}`,
|
|
50854
50990
|
{ notes: [], count: 0 }
|
|
50855
50991
|
);
|
|
50856
50992
|
}
|
|
@@ -50902,10 +51038,10 @@ registerTool(
|
|
|
50902
51038
|
},
|
|
50903
51039
|
annotations: { readOnlyHint: true }
|
|
50904
51040
|
},
|
|
50905
|
-
withErrorHandling(({ query, limit, scanLimit, includeDeleted }) => {
|
|
51041
|
+
withErrorHandling(({ query: query2, limit, scanLimit, includeDeleted }) => {
|
|
50906
51042
|
let result;
|
|
50907
51043
|
try {
|
|
50908
|
-
result = queryNotes(
|
|
51044
|
+
result = queryNotes(query2, { limit, scanLimit, includeDeleted });
|
|
50909
51045
|
} catch (error2) {
|
|
50910
51046
|
if (error2 instanceof NoteQueryError || error2 instanceof NoteQueryStoreError) {
|
|
50911
51047
|
return errorResponse(
|
|
@@ -51816,7 +51952,7 @@ registerTool(
|
|
|
51816
51952
|
registerTool(
|
|
51817
51953
|
"delete-note",
|
|
51818
51954
|
{
|
|
51819
|
-
description: "Use when: moving one exact note to Recently Deleted after reading and reviewing it.\nReturns: confirmation with the exact id.\nDo not use when: you only have a title or the note changed since review.\nSafety: requires id and expectedContentHash from get-note-content. The body comparison and delete happen in one AppleScript, so a newer edit is preserved.",
|
|
51955
|
+
description: "Use when: moving one exact note to Recently Deleted after reading and reviewing it.\nReturns: confirmation with the exact id.\nDo not use when: you only have a title or the note changed since review.\nSafety: requires id and expectedContentHash from get-note-content. The body comparison and delete happen in one AppleScript, so a newer edit is preserved. Refuses a note already in Recently Deleted, where a delete would be permanent.",
|
|
51820
51956
|
inputSchema: {
|
|
51821
51957
|
id: noteIdInput,
|
|
51822
51958
|
expectedContentHash: expectedContentHashInput,
|
|
@@ -51840,6 +51976,9 @@ registerTool(
|
|
|
51840
51976
|
if (result.status === "conflict") {
|
|
51841
51977
|
return errorResponse(revisionConflictMessage(snapshot.note.title));
|
|
51842
51978
|
}
|
|
51979
|
+
if (result.status === "in-recently-deleted") {
|
|
51980
|
+
return errorResponse(inRecentlyDeletedMessage(snapshot.note.title));
|
|
51981
|
+
}
|
|
51843
51982
|
if (result.status === "not-deleted") {
|
|
51844
51983
|
return errorResponse(NOT_DELETED_MESSAGE);
|
|
51845
51984
|
}
|
|
@@ -51908,36 +52047,47 @@ registerTool(
|
|
|
51908
52047
|
registerTool(
|
|
51909
52048
|
"list-notes",
|
|
51910
52049
|
{
|
|
51911
|
-
description: "Use when: enumerating notes in an account or folder; supports modifiedSince and limit for large collections.\nReturns: each note's title and id (ids are safe to use for follow-up reads/edits even when titles are duplicated \u2014 see search-notes for keyword-based lookup instead).\nDo not use when: you need content (get-note-content).\nNote:
|
|
52050
|
+
description: "Use when: enumerating notes in an account or folder; supports modifiedSince and limit for large collections.\nReturns: each note's title and id (ids are safe to use for follow-up reads/edits even when titles are duplicated \u2014 see search-notes for keyword-based lookup instead).\nDo not use when: you need content (get-note-content).\nNote: excludes notes in Recently Deleted unless includeRecentlyDeleted is true, which flags them inRecentlyDeleted. Warns if iCloud sync is active and results may be partial.",
|
|
51912
52051
|
inputSchema: {
|
|
51913
52052
|
account: external_exports.string().max(MAX.ACCOUNT).optional().describe("Account to list notes from"),
|
|
51914
52053
|
folder: external_exports.string().max(MAX.FOLDER).optional().describe("Filter to specific folder"),
|
|
51915
52054
|
modifiedSince: external_exports.string().max(64).optional().describe(
|
|
51916
52055
|
"ISO 8601 date string to filter notes modified on or after this date (e.g., '2025-01-01'). Useful for listing only recent notes in large collections."
|
|
51917
52056
|
),
|
|
51918
|
-
limit: external_exports.number().int().positive().optional().describe("Maximum number of notes to return")
|
|
52057
|
+
limit: external_exports.number().int().positive().optional().describe("Maximum number of notes to return"),
|
|
52058
|
+
includeRecentlyDeleted: external_exports.boolean().optional().describe(
|
|
52059
|
+
"Also list notes in Recently Deleted, each flagged inRecentlyDeleted (default false)"
|
|
52060
|
+
)
|
|
51919
52061
|
},
|
|
51920
52062
|
outputSchema: {
|
|
51921
52063
|
notes: external_exports.array(
|
|
51922
52064
|
external_exports.object({
|
|
51923
52065
|
title: external_exports.string(),
|
|
51924
52066
|
id: external_exports.string(),
|
|
52067
|
+
inRecentlyDeleted: external_exports.boolean().optional(),
|
|
51925
52068
|
identifier: external_exports.string().optional(),
|
|
51926
52069
|
folderIdentifier: external_exports.string().optional(),
|
|
51927
52070
|
accountIdentifier: external_exports.string().optional()
|
|
51928
52071
|
})
|
|
51929
52072
|
).optional(),
|
|
51930
|
-
count: external_exports.number().optional()
|
|
52073
|
+
count: external_exports.number().optional(),
|
|
52074
|
+
excludedRecentlyDeleted: external_exports.number().optional()
|
|
51931
52075
|
}
|
|
51932
52076
|
},
|
|
51933
|
-
withErrorHandling(({ account, folder, modifiedSince, limit }) => {
|
|
52077
|
+
withErrorHandling(({ account, folder, modifiedSince, limit, includeRecentlyDeleted }) => {
|
|
51934
52078
|
const {
|
|
51935
|
-
result: notes,
|
|
52079
|
+
result: { refs: notes, excludedRecentlyDeleted },
|
|
51936
52080
|
syncBefore,
|
|
51937
52081
|
syncInterference
|
|
51938
52082
|
} = withSyncAwarenessSync(
|
|
51939
52083
|
"list-notes",
|
|
51940
|
-
() => notesManager.
|
|
52084
|
+
() => notesManager.listNoteRefsDetailed(
|
|
52085
|
+
account,
|
|
52086
|
+
folder,
|
|
52087
|
+
modifiedSince,
|
|
52088
|
+
limit,
|
|
52089
|
+
includeRecentlyDeleted ?? false
|
|
52090
|
+
)
|
|
51941
52091
|
);
|
|
51942
52092
|
const location = folder ? ` in folder "${folder}"` : "";
|
|
51943
52093
|
const acct = account ? ` (${account})` : "";
|
|
@@ -51953,17 +52103,22 @@ registerTool(
|
|
|
51953
52103
|
const syncNote = syncWarnings.length > 0 ? `
|
|
51954
52104
|
|
|
51955
52105
|
${syncWarnings.join(" ")}` : "";
|
|
52106
|
+
const trashNote = excludedRecentlyDeleted > 0 ? `
|
|
52107
|
+
|
|
52108
|
+
Skipped ${excludedRecentlyDeleted} note(s) in Recently Deleted; pass includeRecentlyDeleted: true to list them.` : "";
|
|
52109
|
+
const trashData = excludedRecentlyDeleted > 0 ? { excludedRecentlyDeleted } : {};
|
|
51956
52110
|
if (notes.length === 0) {
|
|
51957
|
-
return successResponse(`No notes found${location}${acct}${dateInfo}${syncNote}`, {
|
|
52111
|
+
return successResponse(`No notes found${location}${acct}${dateInfo}${trashNote}${syncNote}`, {
|
|
51958
52112
|
notes: [],
|
|
51959
|
-
count: 0
|
|
52113
|
+
count: 0,
|
|
52114
|
+
...trashData
|
|
51960
52115
|
});
|
|
51961
52116
|
}
|
|
51962
|
-
const noteList = notes.map((n) => ` - ${n.title} [id: ${n.id}]`).join("\n");
|
|
52117
|
+
const noteList = notes.map((n) => ` - ${n.title}${n.inRecentlyDeleted ? " [RECENTLY DELETED]" : ""} [id: ${n.id}]`).join("\n");
|
|
51963
52118
|
return successResponse(
|
|
51964
52119
|
`Found ${notes.length} notes${location}${acct}${dateInfo}${limitInfo}:
|
|
51965
|
-
${noteList}${syncNote}`,
|
|
51966
|
-
{ notes: withStableIdentifiers(notes, "ICNote"), count: notes.length }
|
|
52120
|
+
${noteList}${trashNote}${syncNote}`,
|
|
52121
|
+
{ notes: withStableIdentifiers(notes, "ICNote"), count: notes.length, ...trashData }
|
|
51967
52122
|
);
|
|
51968
52123
|
}, "Error listing notes")
|
|
51969
52124
|
);
|
|
@@ -52469,7 +52624,7 @@ ${attachmentList}`,
|
|
|
52469
52624
|
registerTool(
|
|
52470
52625
|
"batch-delete-notes",
|
|
52471
52626
|
{
|
|
52472
|
-
description: "Use when: moving several reviewed notes to Recently Deleted.\nReturns: per-note success or conflict.\nDo not use when: deleting a single note.\nSafety: every entry requires an exact id and the content hash from get-note-content. Any note changed since review is preserved and reported as a conflict.",
|
|
52627
|
+
description: "Use when: moving several reviewed notes to Recently Deleted.\nReturns: per-note success or conflict.\nDo not use when: deleting a single note.\nSafety: every entry requires an exact id and the content hash from get-note-content. Any note changed since review is preserved and reported as a conflict. A note already in Recently Deleted is refused, since deleting it there would be permanent.",
|
|
52473
52628
|
inputSchema: {
|
|
52474
52629
|
notes: external_exports.array(
|
|
52475
52630
|
external_exports.object({
|
|
@@ -52500,6 +52655,9 @@ registerTool(
|
|
|
52500
52655
|
if (result.status === "conflict") {
|
|
52501
52656
|
return { id: id2, success: false, error: revisionConflictMessage(snapshot.note.title) };
|
|
52502
52657
|
}
|
|
52658
|
+
if (result.status === "in-recently-deleted") {
|
|
52659
|
+
return { id: id2, success: false, error: inRecentlyDeletedMessage(snapshot.note.title) };
|
|
52660
|
+
}
|
|
52503
52661
|
if (result.status === "not-deleted")
|
|
52504
52662
|
return { id: id2, success: false, error: NOT_DELETED_MESSAGE };
|
|
52505
52663
|
return { id: id2, success: false, error: "Delete result uncertain; inspect this exact ID" };
|