apple-notes-mcp 2.6.16 → 2.7.1
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 +40 -16
- package/build/index.js +196 -85
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -181,7 +181,7 @@ Creates a new note in Apple Notes.
|
|
|
181
181
|
| `content` | string | Yes | The body content of the note (do not repeat the title here) |
|
|
182
182
|
| `tags` | string[] | No | Returned-only metadata — **NOT written to Notes.app**. Apple Notes tags can't be set via AppleScript, so values passed here are echoed back in the response but do not appear on the created note. Use inline `#hashtags` in `content` instead (Notes.app turns those into real tags) |
|
|
183
183
|
| `folder` | string | No | Folder to create the note in. Supports nested paths like `"Work/Clients"`. **The folder must already exist** — create it first with [`create-folder`](#create-folder). Defaults to account root |
|
|
184
|
-
| `account` | string | No | Account name (defaults to
|
|
184
|
+
| `account` | string | No | Account name (defaults to Notes.app's default account; matched exactly or by a *unique* prefix — an ambiguous prefix is refused). Must be an account Notes.app already has configured — see [`list-accounts`](#list-accounts) |
|
|
185
185
|
| `format` | string | No | Content format: `"plaintext"` (default) or `"html"`. In both formats, the title is automatically prepended as `<h1>`. In plaintext mode, newlines become `<br>`, tabs become `<br>`, and backslashes are preserved as HTML entities |
|
|
186
186
|
|
|
187
187
|
**Example (tagged with inline hashtags):**
|
|
@@ -224,7 +224,7 @@ Searches for notes by title or content.
|
|
|
224
224
|
|-----------|------|----------|-------------|
|
|
225
225
|
| `query` | string | Yes | Text to search for |
|
|
226
226
|
| `searchContent` | boolean | No | If `true`, searches note body; if `false` (default), searches titles only |
|
|
227
|
-
| `account` | string | No | Account to search in (defaults to
|
|
227
|
+
| `account` | string | No | Account to search in (defaults to Notes.app's default account; exact or unique-prefix match) |
|
|
228
228
|
| `folder` | string | No | Limit search to a specific folder (supports nested paths like `"Work/Clients"`) |
|
|
229
229
|
| `modifiedSince` | string | No | ISO 8601 date string to filter notes modified on or after this date (e.g., `"2025-01-01"`) |
|
|
230
230
|
| `limit` | number | No | Maximum number of results to return. **Defaults to 50** — a broad query reads several properties per match via AppleScript (~200ms/note), so an unbounded search over hundreds of matches can exceed Notes' 30s timeout and return an error instead of results. Pass a higher value to see more; the applied limit (and whether it truncated the results) is disclosed in the response. |
|
|
@@ -266,7 +266,7 @@ Retrieves the full content of a specific note.
|
|
|
266
266
|
|-----------|------|----------|-------------|
|
|
267
267
|
| `id` | string | No | Note ID (preferred - more reliable than title) |
|
|
268
268
|
| `title` | string | No | Note title (use `id` instead when available) |
|
|
269
|
-
| `account` | string | No | Account containing the note (defaults to
|
|
269
|
+
| `account` | string | No | Account containing the note (defaults to Notes.app's default account; exact or unique-prefix match, ignored if `id` is provided) |
|
|
270
270
|
|
|
271
271
|
**Note:** Either `id` or `title` must be provided. Using `id` is recommended as it's unique and avoids issues with duplicate titles.
|
|
272
272
|
|
|
@@ -309,7 +309,7 @@ Retrieves a note's body as plain text, with no HTML markup.
|
|
|
309
309
|
|-----------|------|----------|-------------|
|
|
310
310
|
| `id` | string | No | Note ID (preferred - more reliable than title) |
|
|
311
311
|
| `title` | string | No | Note title (use `id` instead when available) |
|
|
312
|
-
| `account` | string | No | Account containing the note (defaults to
|
|
312
|
+
| `account` | string | No | Account containing the note (defaults to Notes.app's default account; exact or unique-prefix match, ignored if `id` is provided) |
|
|
313
313
|
|
|
314
314
|
**Note:** Either `id` or `title` must be provided. This reads the note's native `plaintext` property, so it skips the HTML-to-text conversion that `get-note-content` plus a Markdown pass would do. Use `get-note-content` when you need the HTML, or `get-note-markdown` when you want Markdown with checklist state.
|
|
315
315
|
|
|
@@ -324,7 +324,7 @@ Retrieves metadata about a note (without full content).
|
|
|
324
324
|
| Parameter | Type | Required | Description |
|
|
325
325
|
|-----------|------|----------|-------------|
|
|
326
326
|
| `title` | string | Yes | Exact title of the note |
|
|
327
|
-
| `account` | string | No | Account containing the note (defaults to
|
|
327
|
+
| `account` | string | No | Account containing the note (defaults to Notes.app's default account; exact or unique-prefix match) |
|
|
328
328
|
|
|
329
329
|
**Example:**
|
|
330
330
|
```json
|
|
@@ -383,7 +383,7 @@ Updates an existing note's content and/or title.
|
|
|
383
383
|
| `title` | string | No | Current title of the note to update (use `id` instead when available) |
|
|
384
384
|
| `newTitle` | string | No | New title (if changing the title; ignored when `format` is `"html"`) |
|
|
385
385
|
| `newContent` | string | Yes | New content for the note body |
|
|
386
|
-
| `account` | string | No | Account containing the note (defaults to
|
|
386
|
+
| `account` | string | No | Account containing the note (defaults to Notes.app's default account; exact or unique-prefix match, ignored if `id` is provided) |
|
|
387
387
|
| `format` | string | No | Content format: `"plaintext"` (default) or `"html"`. When `"html"`, content replaces the entire note body as raw HTML and `newTitle` is ignored (the first HTML element serves as the title) |
|
|
388
388
|
|
|
389
389
|
**Note:** Either `id` or `title` must be provided. Using `id` is recommended.
|
|
@@ -440,7 +440,7 @@ Deletes a note (moves to Recently Deleted in Notes.app).
|
|
|
440
440
|
|-----------|------|----------|-------------|
|
|
441
441
|
| `id` | string | No | Note ID (preferred - more reliable than title) |
|
|
442
442
|
| `title` | string | No | Exact title of the note to delete (use `id` instead when available) |
|
|
443
|
-
| `account` | string | No | Account containing the note (defaults to
|
|
443
|
+
| `account` | string | No | Account containing the note (defaults to Notes.app's default account; exact or unique-prefix match, ignored if `id` is provided) |
|
|
444
444
|
|
|
445
445
|
**Note:** Either `id` or `title` must be provided. Using `id` is recommended.
|
|
446
446
|
|
|
@@ -473,7 +473,7 @@ Moves a note to a different folder. The note is relocated in place via Notes.app
|
|
|
473
473
|
| `id` | string | No | Note ID (preferred - more reliable than title) |
|
|
474
474
|
| `title` | string | No | Title of the note to move (use `id` instead when available) |
|
|
475
475
|
| `folder` | string | Yes | Destination folder name or nested path (e.g., `"Work/Clients"`) |
|
|
476
|
-
| `account` | string | No | Account containing the note (defaults to
|
|
476
|
+
| `account` | string | No | Account containing the note (defaults to Notes.app's default account; exact or unique-prefix match, ignored if `id` is provided) |
|
|
477
477
|
|
|
478
478
|
**Note:** Either `id` or `title` must be provided. Using `id` is recommended.
|
|
479
479
|
|
|
@@ -509,7 +509,7 @@ Appends or prepends content to an existing note without replacing it. Always rea
|
|
|
509
509
|
| `position` | string | No | `"after"` (default) appends to the end; `"before"` prepends to the start |
|
|
510
510
|
| `separator` | string | No | String placed between existing content and new content (default: two newlines → `<div><br></div>` in HTML) |
|
|
511
511
|
| `format` | string | No | Format of the content being appended: `"plaintext"` (default) or `"html"` |
|
|
512
|
-
| `account` | string | No | Account containing the note (defaults to
|
|
512
|
+
| `account` | string | No | Account containing the note (defaults to Notes.app's default account; exact or unique-prefix match, ignored if `id` is provided) |
|
|
513
513
|
|
|
514
514
|
**Note:** Either `id` or `title` must be provided. Using `id` is recommended.
|
|
515
515
|
|
|
@@ -545,7 +545,7 @@ Returns the `notes://showNote?identifier=<uuid>` deep-link URL for a note. The U
|
|
|
545
545
|
|-----------|------|----------|-------------|
|
|
546
546
|
| `id` | string | No | Note ID (preferred - more reliable than title) |
|
|
547
547
|
| `title` | string | No | Note title (use `id` instead when available) |
|
|
548
|
-
| `account` | string | No | Account containing the note (defaults to
|
|
548
|
+
| `account` | string | No | Account containing the note (defaults to Notes.app's default account; exact or unique-prefix match, ignored if `id` is provided) |
|
|
549
549
|
|
|
550
550
|
**Note:** Either `id` or `title` must be provided. Using `id` is recommended. Password-protected notes cannot be linked.
|
|
551
551
|
|
|
@@ -568,7 +568,7 @@ Lists all notes, optionally filtered by folder, date, and limit.
|
|
|
568
568
|
|
|
569
569
|
| Parameter | Type | Required | Description |
|
|
570
570
|
|-----------|------|----------|-------------|
|
|
571
|
-
| `account` | string | No | Account to list notes from (defaults to
|
|
571
|
+
| `account` | string | No | Account to list notes from (defaults to Notes.app's default account; exact or unique-prefix match) |
|
|
572
572
|
| `folder` | string | No | Filter to notes in this folder only (supports nested paths like `"Work/Clients"`) |
|
|
573
573
|
| `modifiedSince` | string | No | ISO 8601 date string to filter notes modified on or after this date (e.g., `"2025-01-01"`) |
|
|
574
574
|
| `limit` | number | No | Maximum number of notes to return |
|
|
@@ -593,7 +593,11 @@ Lists all notes, optionally filtered by folder, date, and limit.
|
|
|
593
593
|
}
|
|
594
594
|
```
|
|
595
595
|
|
|
596
|
-
**Returns:** List of
|
|
596
|
+
**Returns:** List of notes as `{title, id}` pairs — `notes: Array<{title, id}>`, plus `count`. The human-readable line is ` - <title> [id: <id>]`.
|
|
597
|
+
|
|
598
|
+
Use the returned `id` for any follow-up read/update/move/delete rather than re-resolving the title: titles are not unique, and a by-title lookup resolves a duplicated title to the same one note every time, silently skipping the others.
|
|
599
|
+
|
|
600
|
+
> **Changed in 2.7.0:** `notes` was previously `string[]` (titles only). Callers that treated the array as strings must now read `.title`.
|
|
597
601
|
|
|
598
602
|
---
|
|
599
603
|
|
|
@@ -615,7 +619,7 @@ Lists all folders in an account with full hierarchical paths.
|
|
|
615
619
|
|
|
616
620
|
| Parameter | Type | Required | Description |
|
|
617
621
|
|-----------|------|----------|-------------|
|
|
618
|
-
| `account` | string | No | Account to list folders from (defaults to
|
|
622
|
+
| `account` | string | No | Account to list folders from (defaults to Notes.app's default account; exact or unique-prefix match) |
|
|
619
623
|
|
|
620
624
|
**Example:**
|
|
621
625
|
```json
|
|
@@ -633,7 +637,7 @@ Creates a new folder, including a whole nested hierarchy in one call.
|
|
|
633
637
|
| Parameter | Type | Required | Description |
|
|
634
638
|
|-----------|------|----------|-------------|
|
|
635
639
|
| `name` | string | Yes | Folder name, or a nested path separated by `/` (e.g. `"Retro Tech/PC/CPUs"`). Every intermediate folder is created; segments that already exist are skipped |
|
|
636
|
-
| `account` | string | No | Account to create folder in (defaults to
|
|
640
|
+
| `account` | string | No | Account to create folder in (defaults to Notes.app's default account; exact or unique-prefix match) |
|
|
637
641
|
|
|
638
642
|
**Example:**
|
|
639
643
|
```json
|
|
@@ -660,7 +664,7 @@ Deletes a folder.
|
|
|
660
664
|
| Parameter | Type | Required | Description |
|
|
661
665
|
|-----------|------|----------|-------------|
|
|
662
666
|
| `name` | string | Yes | Name or path of the folder to delete (supports nested paths like `"Work/Old"`) |
|
|
663
|
-
| `account` | string | No | Account containing the folder (defaults to
|
|
667
|
+
| `account` | string | No | Account containing the folder (defaults to Notes.app's default account; exact or unique-prefix match) |
|
|
664
668
|
|
|
665
669
|
**Example:**
|
|
666
670
|
```json
|
|
@@ -959,7 +963,10 @@ AI: [calls get-note-content with title="Shopping List"]
|
|
|
959
963
|
|
|
960
964
|
### Working with Accounts
|
|
961
965
|
|
|
962
|
-
|
|
966
|
+
Omit `account` and an operation targets whichever account **Notes.app itself
|
|
967
|
+
reports as the default** — not a hardcoded "iCloud". That matters if your default
|
|
968
|
+
is a non-iCloud account, if the account name is localized, or if it carries a
|
|
969
|
+
trailing U+F8FF () character.
|
|
963
970
|
|
|
964
971
|
```
|
|
965
972
|
User: "What accounts do I have?"
|
|
@@ -971,6 +978,23 @@ AI: [calls list-notes with account="Gmail"]
|
|
|
971
978
|
"Your Gmail account has 5 notes..."
|
|
972
979
|
```
|
|
973
980
|
|
|
981
|
+
When you do pass `account`, it is resolved in this order:
|
|
982
|
+
|
|
983
|
+
1. **Exact name match** wins outright.
|
|
984
|
+
2. A **unique prefix match** resolves — `account="robert"` finds
|
|
985
|
+
`robert.b.sweet@gmail.com`.
|
|
986
|
+
3. An **ambiguous prefix is refused**, with every candidate named:
|
|
987
|
+
|
|
988
|
+
```
|
|
989
|
+
Account "rob" is ambiguous - it matches 2 accounts:
|
|
990
|
+
rob@superiortech.io, robert.b.sweet@gmail.com. Use the full account name.
|
|
991
|
+
```
|
|
992
|
+
|
|
993
|
+
That third rule is deliberate. Silently taking the *first* prefix match would
|
|
994
|
+
make `delete-note` or `move-note` land in the wrong account and report success.
|
|
995
|
+
An unresolvable account is reported as such rather than as "note not found", so
|
|
996
|
+
you are not sent looking for the wrong problem.
|
|
997
|
+
|
|
974
998
|
### Organizing with Folders
|
|
975
999
|
|
|
976
1000
|
```
|
package/build/index.js
CHANGED
|
@@ -39407,11 +39407,47 @@ function buildFolderReference(folderPath) {
|
|
|
39407
39407
|
}
|
|
39408
39408
|
return parts.reverse().map((part) => `folder "${escapePlainStringForAppleScript(part)}"`).join(" of ");
|
|
39409
39409
|
}
|
|
39410
|
+
var AS_ACCOUNT_REF = "__acctRef";
|
|
39411
|
+
var ACCOUNT_RESOLUTION_ERROR = "AccountResolutionError:";
|
|
39412
|
+
function throwIfAccountResolutionFailed(error2) {
|
|
39413
|
+
if (!error2) return;
|
|
39414
|
+
const at = error2.indexOf(ACCOUNT_RESOLUTION_ERROR);
|
|
39415
|
+
if (at === -1) return;
|
|
39416
|
+
throw new Error(error2.slice(at + ACCOUNT_RESOLUTION_ERROR.length).trim());
|
|
39417
|
+
}
|
|
39418
|
+
function buildAccountResolution(account) {
|
|
39419
|
+
if (account === void 0) {
|
|
39420
|
+
return `set ${AS_ACCOUNT_REF} to default account`;
|
|
39421
|
+
}
|
|
39422
|
+
const safeAccount = sanitizeAccountName(account);
|
|
39423
|
+
return `
|
|
39424
|
+
set ${AS_ACCOUNT_REF} to missing value
|
|
39425
|
+
set _exactMatches to (every account whose name is "${safeAccount}")
|
|
39426
|
+
if (count of _exactMatches) is 1 then
|
|
39427
|
+
set ${AS_ACCOUNT_REF} to item 1 of _exactMatches
|
|
39428
|
+
else
|
|
39429
|
+
set _prefixMatches to (every account whose name starts with "${safeAccount}")
|
|
39430
|
+
if (count of _prefixMatches) is 1 then
|
|
39431
|
+
set ${AS_ACCOUNT_REF} to item 1 of _prefixMatches
|
|
39432
|
+
else if (count of _prefixMatches) > 1 then
|
|
39433
|
+
set _candidateNames to {}
|
|
39434
|
+
repeat with _candidate in _prefixMatches
|
|
39435
|
+
set end of _candidateNames to name of (contents of _candidate)
|
|
39436
|
+
end repeat
|
|
39437
|
+
set AppleScript's text item delimiters to ", "
|
|
39438
|
+
set _joinedNames to _candidateNames as text
|
|
39439
|
+
set AppleScript's text item delimiters to ""
|
|
39440
|
+
error "${ACCOUNT_RESOLUTION_ERROR} Account \\"${safeAccount}\\" is ambiguous - it matches " & (count of _prefixMatches) & " accounts: " & _joinedNames & ". Use the full account name."
|
|
39441
|
+
end if
|
|
39442
|
+
end if
|
|
39443
|
+
if ${AS_ACCOUNT_REF} is missing value then error "${ACCOUNT_RESOLUTION_ERROR} Account \\"${safeAccount}\\" not found"
|
|
39444
|
+
`;
|
|
39445
|
+
}
|
|
39410
39446
|
function buildAccountScopedScript(scope, command) {
|
|
39411
|
-
const safeAccount = sanitizeAccountName(scope.account);
|
|
39412
39447
|
return `
|
|
39413
39448
|
tell application "Notes"
|
|
39414
|
-
|
|
39449
|
+
${buildAccountResolution(scope.account)}
|
|
39450
|
+
tell ${AS_ACCOUNT_REF}
|
|
39415
39451
|
${command}
|
|
39416
39452
|
end tell
|
|
39417
39453
|
end tell
|
|
@@ -39452,16 +39488,48 @@ function extractCoreDataId(output, prefix) {
|
|
|
39452
39488
|
}
|
|
39453
39489
|
var AppleNotesManager = class {
|
|
39454
39490
|
/**
|
|
39455
|
-
*
|
|
39456
|
-
*
|
|
39491
|
+
* Normalizes a caller-supplied account name for the script builders.
|
|
39492
|
+
*
|
|
39493
|
+
* Returns `undefined` when no account was requested, which
|
|
39494
|
+
* {@link buildAccountResolution} turns into Notes.app's own
|
|
39495
|
+
* `default account`. It deliberately no longer substitutes a hardcoded
|
|
39496
|
+
* `"iCloud"` — that name is wrong for anyone whose default account differs,
|
|
39497
|
+
* is localized, or carries a U+F8FF suffix (#128).
|
|
39457
39498
|
*/
|
|
39458
|
-
|
|
39499
|
+
resolveAccount(account) {
|
|
39500
|
+
const trimmed = account?.trim();
|
|
39501
|
+
return trimmed ? trimmed : void 0;
|
|
39502
|
+
}
|
|
39459
39503
|
/**
|
|
39460
|
-
*
|
|
39461
|
-
*
|
|
39504
|
+
* Cached name of Notes.app's default account, for payload reporting only.
|
|
39505
|
+
* `null` = not yet queried; `""` = queried and unavailable (don't retry).
|
|
39462
39506
|
*/
|
|
39463
|
-
|
|
39464
|
-
|
|
39507
|
+
defaultAccountName = null;
|
|
39508
|
+
/**
|
|
39509
|
+
* The account name to report back in a returned payload.
|
|
39510
|
+
*
|
|
39511
|
+
* Returns the caller's account verbatim when they named one. When they did
|
|
39512
|
+
* not, it reports the *real* default account rather than the hardcoded
|
|
39513
|
+
* "iCloud" the payloads used to claim (#128).
|
|
39514
|
+
*
|
|
39515
|
+
* Most scripts resolve the account inline via {@link buildAccountResolution}
|
|
39516
|
+
* and cost nothing extra; this exists for the handful of methods whose script
|
|
39517
|
+
* output can't carry the name back — notably `createNote`, whose nested-folder
|
|
39518
|
+
* branch depends on the implicit result of `make new note` and must not have
|
|
39519
|
+
* its return value extended (the -1728 workaround above).
|
|
39520
|
+
*
|
|
39521
|
+
* The lookup runs at most once per manager instance and is cached, including
|
|
39522
|
+
* the failure case, so a Notes.app that can't answer is not re-asked on every
|
|
39523
|
+
* call. Returns `undefined` when unknown — `account` is an optional field, and
|
|
39524
|
+
* omitting it is honest where guessing was not.
|
|
39525
|
+
*/
|
|
39526
|
+
reportedAccount(targetAccount) {
|
|
39527
|
+
if (targetAccount !== void 0) return targetAccount;
|
|
39528
|
+
if (this.defaultAccountName === null) {
|
|
39529
|
+
const result = executeAppleScript(buildAppLevelScript("return name of default account"));
|
|
39530
|
+
this.defaultAccountName = result.success ? result.output.trim() : "";
|
|
39531
|
+
}
|
|
39532
|
+
return this.defaultAccountName || void 0;
|
|
39465
39533
|
}
|
|
39466
39534
|
/**
|
|
39467
39535
|
* Checks if a note is password-protected by its ID.
|
|
@@ -39481,7 +39549,7 @@ var AppleNotesManager = class {
|
|
|
39481
39549
|
* Checks if a note is password-protected by its title.
|
|
39482
39550
|
*
|
|
39483
39551
|
* @param title - Exact title of the note
|
|
39484
|
-
* @param account - Account to search in (defaults to
|
|
39552
|
+
* @param account - Account to search in (defaults to Notes.app's default account)
|
|
39485
39553
|
* @returns true if the note is password-protected, false otherwise
|
|
39486
39554
|
*/
|
|
39487
39555
|
isNotePasswordProtected(title, account) {
|
|
@@ -39502,7 +39570,7 @@ var AppleNotesManager = class {
|
|
|
39502
39570
|
* @param content - Body content (plain text that will be HTML-escaped, or raw HTML when format is "html")
|
|
39503
39571
|
* @param tags - Optional tags (stored in returned object, not used by Notes.app)
|
|
39504
39572
|
* @param folder - Optional folder name to create the note in
|
|
39505
|
-
* @param account - Account to use (defaults to
|
|
39573
|
+
* @param account - Account to use (defaults to Notes.app's default account)
|
|
39506
39574
|
* @param format - Content format: "plaintext" escapes and wraps in div tags (default), "html" uses content as-is
|
|
39507
39575
|
* @returns Created Note object with metadata, or null on failure
|
|
39508
39576
|
*
|
|
@@ -39542,6 +39610,7 @@ var AppleNotesManager = class {
|
|
|
39542
39610
|
const script = buildAccountScopedScript({ account: targetAccount }, createCommand);
|
|
39543
39611
|
const result = executeMutationAppleScript(script);
|
|
39544
39612
|
if (!result.success) {
|
|
39613
|
+
throwIfAccountResolutionFailed(result.error);
|
|
39545
39614
|
console.error(`Failed to create note "${title}":`, result.error);
|
|
39546
39615
|
return null;
|
|
39547
39616
|
}
|
|
@@ -39557,7 +39626,7 @@ var AppleNotesManager = class {
|
|
|
39557
39626
|
created: now,
|
|
39558
39627
|
modified: now,
|
|
39559
39628
|
folder,
|
|
39560
|
-
account: targetAccount
|
|
39629
|
+
account: this.reportedAccount(targetAccount)
|
|
39561
39630
|
};
|
|
39562
39631
|
}
|
|
39563
39632
|
/**
|
|
@@ -39568,7 +39637,7 @@ var AppleNotesManager = class {
|
|
|
39568
39637
|
*
|
|
39569
39638
|
* @param query - Text to search for
|
|
39570
39639
|
* @param searchContent - If true, search note bodies; if false, search titles
|
|
39571
|
-
* @param account - Account to search in (defaults to
|
|
39640
|
+
* @param account - Account to search in (defaults to Notes.app's default account)
|
|
39572
39641
|
* @param folder - Optional folder to limit search to
|
|
39573
39642
|
* @param modifiedSince - Optional ISO 8601 date string to filter notes modified on or after this date
|
|
39574
39643
|
* @param limit - Optional maximum number of results to return (default: no limit)
|
|
@@ -39660,6 +39729,7 @@ var AppleNotesManager = class {
|
|
|
39660
39729
|
const items = result.output.split(RECORD_SEP);
|
|
39661
39730
|
const notes = [];
|
|
39662
39731
|
const seenIds = /* @__PURE__ */ new Set();
|
|
39732
|
+
const reportedAccount = this.reportedAccount(targetAccount);
|
|
39663
39733
|
for (const item of items) {
|
|
39664
39734
|
const [title, id, folder2, created, modified] = item.split(FIELD_SEP);
|
|
39665
39735
|
if (!title?.trim()) continue;
|
|
@@ -39675,7 +39745,7 @@ var AppleNotesManager = class {
|
|
|
39675
39745
|
created: parseAppleScriptDate(created ?? ""),
|
|
39676
39746
|
modified: parseAppleScriptDate(modified ?? ""),
|
|
39677
39747
|
folder: folder2?.trim(),
|
|
39678
|
-
account:
|
|
39748
|
+
account: reportedAccount
|
|
39679
39749
|
});
|
|
39680
39750
|
}
|
|
39681
39751
|
return notes;
|
|
@@ -39688,7 +39758,7 @@ var AppleNotesManager = class {
|
|
|
39688
39758
|
* getNoteDetails() or isNotePasswordProtected().
|
|
39689
39759
|
*
|
|
39690
39760
|
* @param title - Exact title of the note
|
|
39691
|
-
* @param account - Account to search in (defaults to
|
|
39761
|
+
* @param account - Account to search in (defaults to Notes.app's default account)
|
|
39692
39762
|
* @returns HTML content of the note, or empty string if not found
|
|
39693
39763
|
*
|
|
39694
39764
|
* @example
|
|
@@ -39706,6 +39776,7 @@ var AppleNotesManager = class {
|
|
|
39706
39776
|
const script = buildAccountScopedScript({ account: targetAccount }, getCommand);
|
|
39707
39777
|
const result = executeAppleScript(script);
|
|
39708
39778
|
if (!result.success) {
|
|
39779
|
+
throwIfAccountResolutionFailed(result.error);
|
|
39709
39780
|
console.error(`Failed to get content of note "${title}":`, result.error);
|
|
39710
39781
|
return "";
|
|
39711
39782
|
}
|
|
@@ -39744,7 +39815,7 @@ var AppleNotesManager = class {
|
|
|
39744
39815
|
* round-trip entirely.
|
|
39745
39816
|
*
|
|
39746
39817
|
* @param title - Exact title of the note
|
|
39747
|
-
* @param account - Account to search in (defaults to
|
|
39818
|
+
* @param account - Account to search in (defaults to Notes.app's default account)
|
|
39748
39819
|
* @returns Plain-text content of the note, or empty string if not found
|
|
39749
39820
|
*/
|
|
39750
39821
|
getNotePlaintext(title, account) {
|
|
@@ -39754,6 +39825,7 @@ var AppleNotesManager = class {
|
|
|
39754
39825
|
const script = buildAccountScopedScript({ account: targetAccount }, getCommand);
|
|
39755
39826
|
const result = executeAppleScript(script);
|
|
39756
39827
|
if (!result.success) {
|
|
39828
|
+
throwIfAccountResolutionFailed(result.error);
|
|
39757
39829
|
console.error(`Failed to get plaintext of note "${title}":`, result.error);
|
|
39758
39830
|
return "";
|
|
39759
39831
|
}
|
|
@@ -39832,7 +39904,7 @@ var AppleNotesManager = class {
|
|
|
39832
39904
|
* including creation date, modification date, and sharing status.
|
|
39833
39905
|
*
|
|
39834
39906
|
* @param title - Exact title of the note
|
|
39835
|
-
* @param account - Account to search in (defaults to
|
|
39907
|
+
* @param account - Account to search in (defaults to Notes.app's default account)
|
|
39836
39908
|
* @returns Note object with full metadata, or null if not found
|
|
39837
39909
|
*/
|
|
39838
39910
|
getNoteDetails(title, account) {
|
|
@@ -39849,6 +39921,7 @@ var AppleNotesManager = class {
|
|
|
39849
39921
|
const script = buildAccountScopedScript({ account: targetAccount }, getCommand);
|
|
39850
39922
|
const result = executeAppleScript(script);
|
|
39851
39923
|
if (!result.success) {
|
|
39924
|
+
throwIfAccountResolutionFailed(result.error);
|
|
39852
39925
|
console.error(`Failed to get details for note "${title}":`, result.error);
|
|
39853
39926
|
return null;
|
|
39854
39927
|
}
|
|
@@ -39866,7 +39939,7 @@ var AppleNotesManager = class {
|
|
|
39866
39939
|
modified: parsed.modified,
|
|
39867
39940
|
shared: parsed.shared,
|
|
39868
39941
|
passwordProtected: parsed.passwordProtected,
|
|
39869
|
-
account: targetAccount
|
|
39942
|
+
account: this.reportedAccount(targetAccount)
|
|
39870
39943
|
};
|
|
39871
39944
|
}
|
|
39872
39945
|
/**
|
|
@@ -39876,7 +39949,7 @@ var AppleNotesManager = class {
|
|
|
39876
39949
|
* from the "Recently Deleted" folder in Notes.app.
|
|
39877
39950
|
*
|
|
39878
39951
|
* @param title - Exact title of the note to delete
|
|
39879
|
-
* @param account - Account containing the note (defaults to
|
|
39952
|
+
* @param account - Account containing the note (defaults to Notes.app's default account)
|
|
39880
39953
|
* @returns true if deletion succeeded, false otherwise
|
|
39881
39954
|
*/
|
|
39882
39955
|
deleteNote(title, account) {
|
|
@@ -39886,6 +39959,7 @@ var AppleNotesManager = class {
|
|
|
39886
39959
|
const script = buildAccountScopedScript({ account: targetAccount }, deleteCommand);
|
|
39887
39960
|
const result = executeMutationAppleScript(script);
|
|
39888
39961
|
if (!result.success) {
|
|
39962
|
+
throwIfAccountResolutionFailed(result.error);
|
|
39889
39963
|
console.error(`Failed to delete note "${title}":`, result.error);
|
|
39890
39964
|
return false;
|
|
39891
39965
|
}
|
|
@@ -39928,7 +40002,7 @@ var AppleNotesManager = class {
|
|
|
39928
40002
|
* @param title - Current title of the note to update
|
|
39929
40003
|
* @param newTitle - New title (optional, keeps existing if not provided; ignored in html format)
|
|
39930
40004
|
* @param newContent - New content for the note body
|
|
39931
|
-
* @param account - Account containing the note (defaults to
|
|
40005
|
+
* @param account - Account containing the note (defaults to Notes.app's default account)
|
|
39932
40006
|
* @param format - Content format: "plaintext" wraps in div tags (default), "html" uses content as-is
|
|
39933
40007
|
* @returns true if update succeeded, false otherwise
|
|
39934
40008
|
*/
|
|
@@ -39950,6 +40024,7 @@ var AppleNotesManager = class {
|
|
|
39950
40024
|
const script = buildAccountScopedScript({ account: targetAccount }, updateCommand);
|
|
39951
40025
|
const result = executeMutationAppleScript(script);
|
|
39952
40026
|
if (!result.success) {
|
|
40027
|
+
throwIfAccountResolutionFailed(result.error);
|
|
39953
40028
|
console.error(`Failed to update note "${title}":`, result.error);
|
|
39954
40029
|
return false;
|
|
39955
40030
|
}
|
|
@@ -40100,29 +40175,12 @@ var AppleNotesManager = class {
|
|
|
40100
40175
|
return refs;
|
|
40101
40176
|
}
|
|
40102
40177
|
/**
|
|
40103
|
-
*
|
|
40104
|
-
*
|
|
40105
|
-
*
|
|
40178
|
+
* Core listing path shared by `listNotes()` and `listNoteRefs()`: lists
|
|
40179
|
+
* notes in an account, optionally filtered by folder, date, and limit,
|
|
40180
|
+
* returning (title, id) pairs. Kept private because both public callers
|
|
40181
|
+
* need to apply their own return shape.
|
|
40106
40182
|
*/
|
|
40107
|
-
|
|
40108
|
-
const folderRef = folder ? buildFolderReference(folder) : void 0;
|
|
40109
|
-
const script = buildAccountScopedScript({ account }, this.buildBulkListCommand({ folderRef }));
|
|
40110
|
-
const result = executeAppleScript(script);
|
|
40111
|
-
if (!result.success) {
|
|
40112
|
-
throw new Error(`Failed to list notes: ${result.error ?? "unknown error"}`);
|
|
40113
|
-
}
|
|
40114
|
-
return this.parseBulkListOutput(result.output);
|
|
40115
|
-
}
|
|
40116
|
-
/**
|
|
40117
|
-
* Lists all notes in an account, optionally filtered by folder, date, and limit.
|
|
40118
|
-
*
|
|
40119
|
-
* @param account - Account to list notes from (defaults to iCloud)
|
|
40120
|
-
* @param folder - Optional folder to filter by
|
|
40121
|
-
* @param modifiedSince - Optional ISO 8601 date string to filter notes modified on or after this date
|
|
40122
|
-
* @param limit - Optional maximum number of results to return (default: no limit)
|
|
40123
|
-
* @returns Array of note titles
|
|
40124
|
-
*/
|
|
40125
|
-
listNotes(account, folder, modifiedSince, limit) {
|
|
40183
|
+
listNotesCore(account, folder, modifiedSince, limit) {
|
|
40126
40184
|
const targetAccount = this.resolveAccount(account);
|
|
40127
40185
|
const safeLimit = limit !== void 0 && limit > 0 ? Math.floor(limit) : void 0;
|
|
40128
40186
|
const folderRef = folder ? buildFolderReference(folder) : void 0;
|
|
@@ -40148,7 +40206,7 @@ var AppleNotesManager = class {
|
|
|
40148
40206
|
const records = sepIdx === -1 ? "" : result2.output.slice(sepIdx + 1);
|
|
40149
40207
|
const refs = this.parseBulkListOutput(records, safeLimit);
|
|
40150
40208
|
if (!Number.isNaN(totalCount) && (refs.length >= safeLimit || totalCount <= safeLimit)) {
|
|
40151
|
-
return refs
|
|
40209
|
+
return refs;
|
|
40152
40210
|
}
|
|
40153
40211
|
}
|
|
40154
40212
|
const script = buildAccountScopedScript(
|
|
@@ -40159,7 +40217,33 @@ var AppleNotesManager = class {
|
|
|
40159
40217
|
if (!result.success) {
|
|
40160
40218
|
throw new Error(`Failed to list notes: ${result.error ?? "unknown error"}`);
|
|
40161
40219
|
}
|
|
40162
|
-
return this.parseBulkListOutput(result.output, safeLimit)
|
|
40220
|
+
return this.parseBulkListOutput(result.output, safeLimit);
|
|
40221
|
+
}
|
|
40222
|
+
/**
|
|
40223
|
+
* Lists all notes in an account, optionally filtered by folder, date, and limit.
|
|
40224
|
+
*
|
|
40225
|
+
* @param account - Account to list notes from (defaults to Notes.app's default account)
|
|
40226
|
+
* @param folder - Optional folder to filter by
|
|
40227
|
+
* @param modifiedSince - Optional ISO 8601 date string to filter notes modified on or after this date
|
|
40228
|
+
* @param limit - Optional maximum number of results to return (default: no limit)
|
|
40229
|
+
* @returns Array of note titles
|
|
40230
|
+
*/
|
|
40231
|
+
listNotes(account, folder, modifiedSince, limit) {
|
|
40232
|
+
return this.listNotesCore(account, folder, modifiedSince, limit).map((ref) => ref.title);
|
|
40233
|
+
}
|
|
40234
|
+
/**
|
|
40235
|
+
* Lists all notes in an account, optionally filtered by folder, date, and
|
|
40236
|
+
* limit — same filtering semantics as `listNotes()`, but returns each
|
|
40237
|
+
* note's id alongside its title. Prefer this over `listNotes()` when the
|
|
40238
|
+
* caller needs to resolve notes by identity afterward: re-resolving by
|
|
40239
|
+
* title is unsafe when titles are duplicated (AppleScript's `note "<name>"`
|
|
40240
|
+
* specifier resolves ambiguously to the same one note every time — see
|
|
40241
|
+
* the fix in exportNotesAsJson for the failure mode this avoids).
|
|
40242
|
+
*
|
|
40243
|
+
* @returns Array of { title, id } pairs, deduplicated by id
|
|
40244
|
+
*/
|
|
40245
|
+
listNoteRefs(account, folder, modifiedSince, limit) {
|
|
40246
|
+
return this.listNotesCore(account, folder, modifiedSince, limit);
|
|
40163
40247
|
}
|
|
40164
40248
|
/**
|
|
40165
40249
|
* Lists all shared (collaborative) notes across all accounts.
|
|
@@ -40239,12 +40323,13 @@ var AppleNotesManager = class {
|
|
|
40239
40323
|
* so that duplicate folder names (e.g., multiple "Archive" folders) are
|
|
40240
40324
|
* distinguishable and can be used directly in other operations.
|
|
40241
40325
|
*
|
|
40242
|
-
* @param account - Account to list folders from (defaults to
|
|
40326
|
+
* @param account - Account to list folders from (defaults to Notes.app's default account)
|
|
40243
40327
|
* @returns Array of Folder objects with path-based names
|
|
40244
40328
|
*/
|
|
40245
40329
|
listFolders(account) {
|
|
40246
40330
|
const targetAccount = this.resolveAccount(account);
|
|
40247
40331
|
const listCommand = `
|
|
40332
|
+
set acctName to name of it
|
|
40248
40333
|
set folderList to {}
|
|
40249
40334
|
set allFolders to every folder
|
|
40250
40335
|
repeat with f in allFolders
|
|
@@ -40255,7 +40340,7 @@ var AppleNotesManager = class {
|
|
|
40255
40340
|
set parentId to id of cRef
|
|
40256
40341
|
end if
|
|
40257
40342
|
set sharedFlag to shared of fRef as text
|
|
40258
|
-
set end of folderList to (id of fRef) & ${AS_FIELD_SEP} & (name of fRef) & ${AS_FIELD_SEP} & parentId & ${AS_FIELD_SEP} & sharedFlag
|
|
40343
|
+
set end of folderList to (id of fRef) & ${AS_FIELD_SEP} & (name of fRef) & ${AS_FIELD_SEP} & parentId & ${AS_FIELD_SEP} & sharedFlag & ${AS_FIELD_SEP} & acctName
|
|
40259
40344
|
end repeat
|
|
40260
40345
|
set AppleScript's text item delimiters to ${AS_RECORD_SEP}
|
|
40261
40346
|
return folderList as text
|
|
@@ -40275,7 +40360,11 @@ var AppleNotesManager = class {
|
|
|
40275
40360
|
id: (parts[0] || "").trim(),
|
|
40276
40361
|
name: (parts[1] || "").trim(),
|
|
40277
40362
|
parentId: (parts[2] || "").trim(),
|
|
40278
|
-
shared: (parts[3] || "").trim().toLowerCase() === "true"
|
|
40363
|
+
shared: (parts[3] || "").trim().toLowerCase() === "true",
|
|
40364
|
+
// The account name as Notes.app actually reports it. When the caller
|
|
40365
|
+
// omitted `account` this is the resolved default, which is the whole
|
|
40366
|
+
// point — reporting a hardcoded "iCloud" here was the #128 bug.
|
|
40367
|
+
account: (parts[4] || "").trim()
|
|
40279
40368
|
};
|
|
40280
40369
|
});
|
|
40281
40370
|
const byId = new Map(entries.map((e) => [e.id, e]));
|
|
@@ -40291,7 +40380,7 @@ var AppleNotesManager = class {
|
|
|
40291
40380
|
return entries.map((entry) => ({
|
|
40292
40381
|
id: entry.id,
|
|
40293
40382
|
name: buildPath(entry),
|
|
40294
|
-
account: targetAccount,
|
|
40383
|
+
account: entry.account || targetAccount || "",
|
|
40295
40384
|
shared: entry.shared
|
|
40296
40385
|
}));
|
|
40297
40386
|
}
|
|
@@ -40299,7 +40388,7 @@ var AppleNotesManager = class {
|
|
|
40299
40388
|
* Creates a new folder in an account.
|
|
40300
40389
|
*
|
|
40301
40390
|
* @param name - Name for the new folder
|
|
40302
|
-
* @param account - Account to create folder in (defaults to
|
|
40391
|
+
* @param account - Account to create folder in (defaults to Notes.app's default account)
|
|
40303
40392
|
* @returns Created Folder object, or null on failure
|
|
40304
40393
|
*/
|
|
40305
40394
|
createFolder(name, account) {
|
|
@@ -40332,6 +40421,7 @@ var AppleNotesManager = class {
|
|
|
40332
40421
|
const script = buildAccountScopedScript({ account: targetAccount }, createCommand);
|
|
40333
40422
|
const result = executeMutationAppleScript(script);
|
|
40334
40423
|
if (!result.success) {
|
|
40424
|
+
throwIfAccountResolutionFailed(result.error);
|
|
40335
40425
|
console.error(`Failed to create folder "${name}":`, result.error);
|
|
40336
40426
|
return null;
|
|
40337
40427
|
}
|
|
@@ -40339,14 +40429,15 @@ var AppleNotesManager = class {
|
|
|
40339
40429
|
const fullRef = buildFolderReference(name);
|
|
40340
40430
|
const idScript = buildAccountScopedScript(
|
|
40341
40431
|
{ account: targetAccount },
|
|
40342
|
-
`return id of ${fullRef}`
|
|
40432
|
+
`return (id of ${fullRef}) & ${AS_FIELD_SEP} & (name of it)`
|
|
40343
40433
|
);
|
|
40344
40434
|
const idResult = executeAppleScript(idScript);
|
|
40345
|
-
const
|
|
40435
|
+
const [rawId = "", rawAccount = ""] = idResult.success ? idResult.output.split(FIELD_SEP) : [];
|
|
40436
|
+
const folderId = idResult.success ? extractCoreDataId(rawId, "folder") : "";
|
|
40346
40437
|
return {
|
|
40347
40438
|
id: folderId,
|
|
40348
40439
|
name,
|
|
40349
|
-
account: targetAccount
|
|
40440
|
+
account: rawAccount.trim() || targetAccount || ""
|
|
40350
40441
|
};
|
|
40351
40442
|
}
|
|
40352
40443
|
/**
|
|
@@ -40355,7 +40446,7 @@ var AppleNotesManager = class {
|
|
|
40355
40446
|
* Note: This may fail if the folder contains notes.
|
|
40356
40447
|
*
|
|
40357
40448
|
* @param name - Name of the folder to delete
|
|
40358
|
-
* @param account - Account containing the folder (defaults to
|
|
40449
|
+
* @param account - Account containing the folder (defaults to Notes.app's default account)
|
|
40359
40450
|
* @returns true if deletion succeeded, false otherwise
|
|
40360
40451
|
*/
|
|
40361
40452
|
deleteFolder(name, account) {
|
|
@@ -40364,6 +40455,7 @@ var AppleNotesManager = class {
|
|
|
40364
40455
|
const script = buildAccountScopedScript({ account: targetAccount }, deleteCommand);
|
|
40365
40456
|
const result = executeMutationAppleScript(script);
|
|
40366
40457
|
if (!result.success) {
|
|
40458
|
+
throwIfAccountResolutionFailed(result.error);
|
|
40367
40459
|
console.error(`Failed to delete folder "${name}":`, result.error);
|
|
40368
40460
|
return false;
|
|
40369
40461
|
}
|
|
@@ -40383,7 +40475,7 @@ var AppleNotesManager = class {
|
|
|
40383
40475
|
*
|
|
40384
40476
|
* @param title - Title of the note to move
|
|
40385
40477
|
* @param destinationFolder - Name of the folder to move to (must already exist)
|
|
40386
|
-
* @param account - Account containing the note (defaults to
|
|
40478
|
+
* @param account - Account containing the note (defaults to Notes.app's default account)
|
|
40387
40479
|
* @returns true if the move succeeded, false otherwise
|
|
40388
40480
|
*/
|
|
40389
40481
|
moveNote(title, destinationFolder, account) {
|
|
@@ -40405,15 +40497,15 @@ var AppleNotesManager = class {
|
|
|
40405
40497
|
*
|
|
40406
40498
|
* @param id - CoreData URL identifier for the note
|
|
40407
40499
|
* @param destinationFolder - Name of the folder to move to (must already exist)
|
|
40408
|
-
* @param account - Account containing the destination folder (defaults to
|
|
40500
|
+
* @param account - Account containing the destination folder (defaults to Notes.app's default account)
|
|
40409
40501
|
* @returns true if the move succeeded, false otherwise
|
|
40410
40502
|
*/
|
|
40411
40503
|
moveNoteById(id, destinationFolder, account) {
|
|
40412
40504
|
const targetAccount = this.resolveAccount(account);
|
|
40413
40505
|
const safeId = sanitizeId(id);
|
|
40414
|
-
const
|
|
40415
|
-
const destFolderRef = `${buildFolderReference(destinationFolder)} of account "${safeAccount}"`;
|
|
40506
|
+
const destFolderRef = `${buildFolderReference(destinationFolder)} of ${AS_ACCOUNT_REF}`;
|
|
40416
40507
|
const moveCommand = `
|
|
40508
|
+
${buildAccountResolution(targetAccount)}
|
|
40417
40509
|
set destFolder to ${destFolderRef}
|
|
40418
40510
|
set noteRef to note id "${safeId}"
|
|
40419
40511
|
move noteRef to destFolder
|
|
@@ -40421,6 +40513,7 @@ var AppleNotesManager = class {
|
|
|
40421
40513
|
const script = buildAppLevelScript(moveCommand);
|
|
40422
40514
|
const result = executeMutationAppleScript(script);
|
|
40423
40515
|
if (!result.success) {
|
|
40516
|
+
throwIfAccountResolutionFailed(result.error);
|
|
40424
40517
|
console.error(
|
|
40425
40518
|
`Cannot move note to "${destinationFolder}" (folder may not exist):`,
|
|
40426
40519
|
result.error
|
|
@@ -40616,7 +40709,7 @@ var AppleNotesManager = class {
|
|
|
40616
40709
|
* Returns the notes:// deep-link URL for a note by title.
|
|
40617
40710
|
*
|
|
40618
40711
|
* @param title - Exact note title
|
|
40619
|
-
* @param account - Account to search in (defaults to
|
|
40712
|
+
* @param account - Account to search in (defaults to Notes.app's default account)
|
|
40620
40713
|
* @returns notes://showNote?identifier=<uuid> string, or null on failure
|
|
40621
40714
|
*/
|
|
40622
40715
|
getNoteLink(title, account) {
|
|
@@ -40790,12 +40883,11 @@ var AppleNotesManager = class {
|
|
|
40790
40883
|
});
|
|
40791
40884
|
return { healthy: false, checks };
|
|
40792
40885
|
}
|
|
40793
|
-
const
|
|
40794
|
-
const notes = this.listNotes(defaultAccount);
|
|
40886
|
+
const notes = this.listNotes();
|
|
40795
40887
|
checks.push({
|
|
40796
40888
|
name: "operations",
|
|
40797
40889
|
passed: true,
|
|
40798
|
-
message: `Basic operations working (${notes.length} note(s) in
|
|
40890
|
+
message: `Basic operations working (${notes.length} note(s) in the default account)`
|
|
40799
40891
|
});
|
|
40800
40892
|
const allPassed = checks.every((c) => c.passed);
|
|
40801
40893
|
return { healthy: allPassed, checks };
|
|
@@ -41017,18 +41109,18 @@ var AppleNotesManager = class {
|
|
|
41017
41109
|
* Lists attachments for a note by its title.
|
|
41018
41110
|
*
|
|
41019
41111
|
* @param title - Title of the note
|
|
41020
|
-
* @param account - Account containing the note (defaults to
|
|
41112
|
+
* @param account - Account containing the note (defaults to Notes.app's default account)
|
|
41021
41113
|
* @returns Array of Attachment objects, or empty array if the note genuinely has none
|
|
41022
41114
|
* @throws If the AppleScript call fails, so a lookup failure is never mistaken for
|
|
41023
41115
|
* an attachment-free note (callers gate destructive full-body updates on this)
|
|
41024
41116
|
*/
|
|
41025
41117
|
listAttachments(title, account) {
|
|
41026
41118
|
const targetAccount = this.resolveAccount(account);
|
|
41027
|
-
const safeAccount = escapePlainStringForAppleScript(targetAccount);
|
|
41028
41119
|
const safeTitle = escapePlainStringForAppleScript(title);
|
|
41029
41120
|
const script = `
|
|
41030
41121
|
tell application "Notes"
|
|
41031
|
-
|
|
41122
|
+
${buildAccountResolution(targetAccount)}
|
|
41123
|
+
tell ${AS_ACCOUNT_REF}
|
|
41032
41124
|
set theNote to note "${safeTitle}"
|
|
41033
41125
|
set attachmentList to {}
|
|
41034
41126
|
set attachmentIds to id of every attachment of theNote
|
|
@@ -41328,7 +41420,7 @@ var AppleNotesManager = class {
|
|
|
41328
41420
|
*
|
|
41329
41421
|
* @param ids - Array of CoreData URL identifiers for notes to move
|
|
41330
41422
|
* @param folder - Destination folder name
|
|
41331
|
-
* @param account - Account containing the folder (defaults to
|
|
41423
|
+
* @param account - Account containing the folder (defaults to Notes.app's default account)
|
|
41332
41424
|
* @returns Array of results with id, success status, and optional error message
|
|
41333
41425
|
*
|
|
41334
41426
|
* @example
|
|
@@ -41342,8 +41434,7 @@ var AppleNotesManager = class {
|
|
|
41342
41434
|
batchMoveNotes(ids, folder, account) {
|
|
41343
41435
|
if (ids.length === 0) return [];
|
|
41344
41436
|
const targetAccount = this.resolveAccount(account);
|
|
41345
|
-
const
|
|
41346
|
-
const destFolderRef = `${buildFolderReference(folder)} of account "${safeAccount}"`;
|
|
41437
|
+
const destFolderRef = `${buildFolderReference(folder)} of ${AS_ACCOUNT_REF}`;
|
|
41347
41438
|
const results = new Array(ids.length);
|
|
41348
41439
|
const runnable = [];
|
|
41349
41440
|
ids.forEach((id, i) => {
|
|
@@ -41360,6 +41451,7 @@ var AppleNotesManager = class {
|
|
|
41360
41451
|
if (runnable.length > 0) {
|
|
41361
41452
|
const idList = runnable.map((r) => `"${r.safe}"`).join(", ");
|
|
41362
41453
|
const script = buildAppLevelScript(`
|
|
41454
|
+
${buildAccountResolution(targetAccount)}
|
|
41363
41455
|
set destFolder to ${destFolderRef}
|
|
41364
41456
|
set out to ""
|
|
41365
41457
|
repeat with rawId in {${idList}}
|
|
@@ -41391,6 +41483,7 @@ var AppleNotesManager = class {
|
|
|
41391
41483
|
`);
|
|
41392
41484
|
const res = executeMutationAppleScript(script);
|
|
41393
41485
|
if (!res.success) {
|
|
41486
|
+
throwIfAccountResolutionFailed(res.error);
|
|
41394
41487
|
for (const r of runnable) {
|
|
41395
41488
|
results[r.index] = this.createBatchResult(
|
|
41396
41489
|
ids[r.index],
|
|
@@ -41571,7 +41664,7 @@ var AppleNotesManager = class {
|
|
|
41571
41664
|
* [x] (done) or [ ] (undone) prefixes.
|
|
41572
41665
|
*
|
|
41573
41666
|
* @param title - Exact title of the note
|
|
41574
|
-
* @param account - Account containing the note (defaults to
|
|
41667
|
+
* @param account - Account containing the note (defaults to Notes.app's default account)
|
|
41575
41668
|
* @returns Markdown content, or empty string if not found
|
|
41576
41669
|
*
|
|
41577
41670
|
* @example
|
|
@@ -42162,11 +42255,15 @@ var MAX = {
|
|
|
42162
42255
|
};
|
|
42163
42256
|
var noteTitleSchema = {
|
|
42164
42257
|
title: external_exports.string().min(1, "Note title is required").max(MAX.TITLE),
|
|
42165
|
-
account: external_exports.string().max(MAX.ACCOUNT).optional().describe(
|
|
42258
|
+
account: external_exports.string().max(MAX.ACCOUNT).optional().describe(
|
|
42259
|
+
"Account name (defaults to Notes.app's default account; exact or unique-prefix match)"
|
|
42260
|
+
)
|
|
42166
42261
|
};
|
|
42167
42262
|
var folderNameSchema = {
|
|
42168
42263
|
name: external_exports.string().min(1, "Folder name is required").max(MAX.FOLDER),
|
|
42169
|
-
account: external_exports.string().max(MAX.ACCOUNT).optional().describe(
|
|
42264
|
+
account: external_exports.string().max(MAX.ACCOUNT).optional().describe(
|
|
42265
|
+
"Account name (defaults to Notes.app's default account; exact or unique-prefix match)"
|
|
42266
|
+
)
|
|
42170
42267
|
};
|
|
42171
42268
|
function registerTool(name, config2, cb) {
|
|
42172
42269
|
const { outputSchema, ...rest } = config2;
|
|
@@ -42193,7 +42290,7 @@ registerTool(
|
|
|
42193
42290
|
"Folder to create the note in (supports nested paths like 'Work/Clients'). The folder must already exist \u2014 this tool does not create it; call create-folder first, which is idempotent and creates intermediate segments."
|
|
42194
42291
|
),
|
|
42195
42292
|
account: external_exports.string().max(MAX.ACCOUNT).optional().describe(
|
|
42196
|
-
"Account name (defaults to
|
|
42293
|
+
"Account name (defaults to the account Notes.app itself reports as default). Matched exactly, or by a unique prefix; an ambiguous prefix is refused. Must be an account Notes.app already has configured \u2014 see list-accounts."
|
|
42197
42294
|
)
|
|
42198
42295
|
},
|
|
42199
42296
|
outputSchema: {
|
|
@@ -42302,7 +42399,9 @@ registerTool(
|
|
|
42302
42399
|
inputSchema: {
|
|
42303
42400
|
id: external_exports.string().max(MAX.ID).optional().describe("Note ID (preferred - more reliable than title)"),
|
|
42304
42401
|
title: external_exports.string().max(MAX.TITLE).optional().describe("Note title (use id instead when available)"),
|
|
42305
|
-
account: external_exports.string().max(MAX.ACCOUNT).optional().describe(
|
|
42402
|
+
account: external_exports.string().max(MAX.ACCOUNT).optional().describe(
|
|
42403
|
+
"Account name (defaults to Notes.app's default account; exact or unique-prefix match, ignored if id is provided)"
|
|
42404
|
+
)
|
|
42306
42405
|
},
|
|
42307
42406
|
outputSchema: {
|
|
42308
42407
|
title: external_exports.string().optional(),
|
|
@@ -42377,7 +42476,9 @@ registerTool(
|
|
|
42377
42476
|
inputSchema: {
|
|
42378
42477
|
id: external_exports.string().max(MAX.ID).optional().describe("Note ID (preferred - more reliable than title)"),
|
|
42379
42478
|
title: external_exports.string().max(MAX.TITLE).optional().describe("Note title (use id instead when available)"),
|
|
42380
|
-
account: external_exports.string().max(MAX.ACCOUNT).optional().describe(
|
|
42479
|
+
account: external_exports.string().max(MAX.ACCOUNT).optional().describe(
|
|
42480
|
+
"Account name (defaults to Notes.app's default account; exact or unique-prefix match, ignored if id is provided)"
|
|
42481
|
+
)
|
|
42381
42482
|
},
|
|
42382
42483
|
outputSchema: {
|
|
42383
42484
|
title: external_exports.string().optional(),
|
|
@@ -42800,7 +42901,9 @@ registerTool(
|
|
|
42800
42901
|
inputSchema: {
|
|
42801
42902
|
id: external_exports.string().max(MAX.ID).optional().describe("Note ID (preferred - more reliable than title)"),
|
|
42802
42903
|
title: external_exports.string().max(MAX.TITLE).optional().describe("Note title (use id instead when available)"),
|
|
42803
|
-
account: external_exports.string().max(MAX.ACCOUNT).optional().describe(
|
|
42904
|
+
account: external_exports.string().max(MAX.ACCOUNT).optional().describe(
|
|
42905
|
+
"Account name (defaults to Notes.app's default account; exact or unique-prefix match, ignored if id is provided)"
|
|
42906
|
+
)
|
|
42804
42907
|
},
|
|
42805
42908
|
outputSchema: {
|
|
42806
42909
|
ok: external_exports.boolean().optional(),
|
|
@@ -42909,7 +43012,7 @@ registerTool(
|
|
|
42909
43012
|
registerTool(
|
|
42910
43013
|
"list-notes",
|
|
42911
43014
|
{
|
|
42912
|
-
description: "Use when: enumerating notes in an account or folder; supports modifiedSince and limit for large collections.\nReturns: note
|
|
43015
|
+
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: warns if iCloud sync is active and results may be partial.",
|
|
42913
43016
|
inputSchema: {
|
|
42914
43017
|
account: external_exports.string().max(MAX.ACCOUNT).optional().describe("Account to list notes from"),
|
|
42915
43018
|
folder: external_exports.string().max(MAX.FOLDER).optional().describe("Filter to specific folder"),
|
|
@@ -42919,7 +43022,7 @@ registerTool(
|
|
|
42919
43022
|
limit: external_exports.number().int().positive().optional().describe("Maximum number of notes to return")
|
|
42920
43023
|
},
|
|
42921
43024
|
outputSchema: {
|
|
42922
|
-
notes: external_exports.array(external_exports.string()).optional(),
|
|
43025
|
+
notes: external_exports.array(external_exports.object({ title: external_exports.string(), id: external_exports.string() })).optional(),
|
|
42923
43026
|
count: external_exports.number().optional()
|
|
42924
43027
|
}
|
|
42925
43028
|
},
|
|
@@ -42930,7 +43033,7 @@ registerTool(
|
|
|
42930
43033
|
syncInterference
|
|
42931
43034
|
} = withSyncAwarenessSync(
|
|
42932
43035
|
"list-notes",
|
|
42933
|
-
() => notesManager.
|
|
43036
|
+
() => notesManager.listNoteRefs(account, folder, modifiedSince, limit)
|
|
42934
43037
|
);
|
|
42935
43038
|
const location = folder ? ` in folder "${folder}"` : "";
|
|
42936
43039
|
const acct = account ? ` (${account})` : "";
|
|
@@ -42952,7 +43055,7 @@ ${syncWarnings.join(" ")}` : "";
|
|
|
42952
43055
|
count: 0
|
|
42953
43056
|
});
|
|
42954
43057
|
}
|
|
42955
|
-
const noteList = notes.map((
|
|
43058
|
+
const noteList = notes.map((n) => ` - ${n.title} [id: ${n.id}]`).join("\n");
|
|
42956
43059
|
return successResponse(
|
|
42957
43060
|
`Found ${notes.length} notes${location}${acct}${dateInfo}${limitInfo}:
|
|
42958
43061
|
${noteList}${syncNote}`,
|
|
@@ -43015,12 +43118,16 @@ ${syncWarnings.join(" ")}` : "";
|
|
|
43015
43118
|
if (folders.length === 0) {
|
|
43016
43119
|
return successResponse(`No folders found${acct}${syncNote}`, { folders: [], count: 0 });
|
|
43017
43120
|
}
|
|
43121
|
+
const resolvedAcct = folders[0]?.account ? ` (${folders[0].account})` : acct;
|
|
43018
43122
|
const folderList = folders.map((f) => ` - ${f.name}`).join("\n");
|
|
43019
|
-
return successResponse(
|
|
43020
|
-
${
|
|
43021
|
-
|
|
43022
|
-
|
|
43023
|
-
|
|
43123
|
+
return successResponse(
|
|
43124
|
+
`Found ${folders.length} folders${resolvedAcct}:
|
|
43125
|
+
${folderList}${syncNote}`,
|
|
43126
|
+
{
|
|
43127
|
+
folders,
|
|
43128
|
+
count: folders.length
|
|
43129
|
+
}
|
|
43130
|
+
);
|
|
43024
43131
|
}, "Error listing folders")
|
|
43025
43132
|
);
|
|
43026
43133
|
registerTool(
|
|
@@ -43031,7 +43138,9 @@ registerTool(
|
|
|
43031
43138
|
name: external_exports.string().min(1, "Folder name is required").max(MAX.FOLDER).describe(
|
|
43032
43139
|
'Folder name or nested path separated by "/". E.g., "Retro Tech/PC/CPUs" creates all intermediate folders. Existing segments are skipped.'
|
|
43033
43140
|
),
|
|
43034
|
-
account: external_exports.string().max(MAX.ACCOUNT).optional().describe(
|
|
43141
|
+
account: external_exports.string().max(MAX.ACCOUNT).optional().describe(
|
|
43142
|
+
"Account name (defaults to Notes.app's default account; exact or unique-prefix match)"
|
|
43143
|
+
)
|
|
43035
43144
|
},
|
|
43036
43145
|
outputSchema: {
|
|
43037
43146
|
ok: external_exports.boolean().optional(),
|
|
@@ -43374,7 +43483,9 @@ registerTool(
|
|
|
43374
43483
|
folder: external_exports.string().max(MAX.FOLDER).describe(
|
|
43375
43484
|
'Destination folder name or nested path (e.g. "Work/Clients"). Must already exist \u2014 create-folder first.'
|
|
43376
43485
|
),
|
|
43377
|
-
account: external_exports.string().max(MAX.ACCOUNT).optional().describe(
|
|
43486
|
+
account: external_exports.string().max(MAX.ACCOUNT).optional().describe(
|
|
43487
|
+
"Account containing the destination folder (defaults to Notes.app's default account; exact or unique-prefix match)"
|
|
43488
|
+
)
|
|
43378
43489
|
},
|
|
43379
43490
|
outputSchema: {
|
|
43380
43491
|
ok: external_exports.boolean().optional(),
|
package/package.json
CHANGED