apple-notes-mcp 2.9.16 → 2.9.17
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 +66 -0
- package/build/index.js +400 -123
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2072,6 +2072,72 @@ calling this tool again, which would create a second note.
|
|
|
2072
2072
|
|
|
2073
2073
|
---
|
|
2074
2074
|
|
|
2075
|
+
#### `add-attachment-from-pasteboard`
|
|
2076
|
+
|
|
2077
|
+
Attaches whatever image, PDF, or file is on the pasteboard (a screenshot, "Copy
|
|
2078
|
+
Image", or a file copied in Finder) to an exact note. The pasteboard is read once
|
|
2079
|
+
through AppKit's public `NSPasteboard` API (via JXA, no native build) and its
|
|
2080
|
+
bytes are frozen into a private temporary file before anything touches the note.
|
|
2081
|
+
The pasteboard itself is never written. The note and `expectedContentHash` are
|
|
2082
|
+
checked before the pasteboard is read, so a request with a wrong id, a stale
|
|
2083
|
+
revision, or a malformed `filename` never captures your clipboard. The frozen
|
|
2084
|
+
file then goes through [`add-attachment`](#add-attachment)'s checks.
|
|
2085
|
+
|
|
2086
|
+
| Parameter | Type | Required | Description |
|
|
2087
|
+
|-----------|------|----------|-------------|
|
|
2088
|
+
| `id` | string | Yes | Note ID |
|
|
2089
|
+
| `expectedContentHash` | string | Yes | The note's current `contentHash` (from `get-note-content`) |
|
|
2090
|
+
| `filename` | string | No | Attachment name. Defaults to the copied file's name, or `Pasted image.png` / `Pasted document.pdf` for image or PDF data. Without an extension, the pasted type's extension is added; with one, it must match the pasted type. Otherwise the same rules as `add-attachment` |
|
|
2091
|
+
| `allowPasteAlert` | boolean | No | Default `false`. Read the pasteboard even when macOS will show its paste alert (see **Paste privacy** below). Never overrides a Deny setting |
|
|
2092
|
+
|
|
2093
|
+
**Returns:** the `add-attachment` result plus `source` (`kind`: `file` or
|
|
2094
|
+
`data`, the pasteboard `type`, and the default `filename`). A copied file wins
|
|
2095
|
+
over image data; among data types PNG is preferred, then JPEG, HEIC, GIF, TIFF,
|
|
2096
|
+
and PDF.
|
|
2097
|
+
|
|
2098
|
+
**Paste privacy (macOS 15.4 and later):** macOS can show an alert asking
|
|
2099
|
+
whether to allow a paste when a process reads the general pasteboard without a
|
|
2100
|
+
user paste. Before reading anything, the tool checks AppKit's
|
|
2101
|
+
[`NSPasteboard.accessBehavior`](https://developer.apple.com/documentation/appkit/nspasteboard/accessbehavior-swift.enum).
|
|
2102
|
+
It reads only when the value is `alwaysAllow`, or when you pass
|
|
2103
|
+
`allowPasteAlert: true` and the value is `default` or `ask` (macOS then shows
|
|
2104
|
+
its alert, and the call waits for your answer up to the automation timeout).
|
|
2105
|
+
Otherwise it reads nothing and returns `code: "permission_denied"` with
|
|
2106
|
+
`pasteboardCode: "pasteboard_access_denied"` and `accessBehavior` (`default`,
|
|
2107
|
+
`ask`, `alwaysDeny`, or `unknown`). `alwaysDeny` is always refused; change it in
|
|
2108
|
+
System Settings, where macOS lists an app after its first paste alert. On macOS
|
|
2109
|
+
before 15.4 the property does not exist and the pasteboard is read as before.
|
|
2110
|
+
|
|
2111
|
+
**Errors** carry a `pasteboardCode` next to the shared `code`, and
|
|
2112
|
+
`committed: false` because nothing was written:
|
|
2113
|
+
|
|
2114
|
+
| `pasteboardCode` | `code` | Cause |
|
|
2115
|
+
|------------------|--------|-------|
|
|
2116
|
+
| `pasteboard_access_denied` | `permission_denied` | Reading would show the macOS paste alert, or pasting is denied (see above) |
|
|
2117
|
+
| `pasteboard_empty` | `validation_error` | Nothing is on the pasteboard |
|
|
2118
|
+
| `unsupported_content` | `validation_error` | No PNG, JPEG, HEIC, GIF, TIFF, PDF, or copied file (text belongs in `append-to-note`); the message and `types` list the pasteboard types found |
|
|
2119
|
+
| `multiple_files` | `validation_error` | More than one copied file; `count` says how many. Copy one file, or use `add-attachment` per file |
|
|
2120
|
+
| `too_large` | `validation_error` | More than 64 MiB |
|
|
2121
|
+
| `file_unreadable` | `validation_error` | The copied file is a symlink, empty, over 64 MiB, or unreadable |
|
|
2122
|
+
| `pasteboard_changed` | `operation_failed` | The pasteboard changed while it was being read; try again |
|
|
2123
|
+
| `pasteboard_timeout` | `operation_failed` | The read timed out (for example an unanswered paste alert) |
|
|
2124
|
+
| `pasteboard_unavailable` | `operation_failed` | The MCP host is not running in your logged-in GUI session (for example over SSH) |
|
|
2125
|
+
| `write_failed` | `operation_failed` | The temporary copy could not be written |
|
|
2126
|
+
|
|
2127
|
+
The pasteboard read uses the same timeout as other automation steps
|
|
2128
|
+
(`APPLE_NOTES_MCP_TIMEOUT_MS`, 30 seconds by default).
|
|
2129
|
+
|
|
2130
|
+
**Known limitation ([#236](https://github.com/sweetrb/apple-notes-mcp/issues/236)):** on macOS 27, Notes' AppleScript dictionary does not list
|
|
2131
|
+
PDF attachments, so a PDF (pasted or from `add-attachment`) is inserted but
|
|
2132
|
+
cannot be verified and the call reports "insertion outcome uncertain". Read the
|
|
2133
|
+
note before retrying.
|
|
2134
|
+
|
|
2135
|
+
For testing, `APPLE_NOTES_MCP_PASTEBOARD_NAME` makes the tool read a private
|
|
2136
|
+
named pasteboard instead of the general one, so a test never touches your
|
|
2137
|
+
clipboard.
|
|
2138
|
+
|
|
2139
|
+
---
|
|
2140
|
+
|
|
2075
2141
|
#### `list-attachments`
|
|
2076
2142
|
|
|
2077
2143
|
Lists attachments in a note.
|
package/build/index.js
CHANGED
|
@@ -417,11 +417,11 @@ var require_codegen = __commonJS({
|
|
|
417
417
|
const rhs = this.rhs === void 0 ? "" : ` = ${this.rhs}`;
|
|
418
418
|
return `${varKind} ${this.name}${rhs};` + _n;
|
|
419
419
|
}
|
|
420
|
-
optimizeNames(names,
|
|
420
|
+
optimizeNames(names, constants10) {
|
|
421
421
|
if (!names[this.name.str])
|
|
422
422
|
return;
|
|
423
423
|
if (this.rhs)
|
|
424
|
-
this.rhs = optimizeExpr(this.rhs, names,
|
|
424
|
+
this.rhs = optimizeExpr(this.rhs, names, constants10);
|
|
425
425
|
return this;
|
|
426
426
|
}
|
|
427
427
|
get names() {
|
|
@@ -438,10 +438,10 @@ var require_codegen = __commonJS({
|
|
|
438
438
|
render({ _n }) {
|
|
439
439
|
return `${this.lhs} = ${this.rhs};` + _n;
|
|
440
440
|
}
|
|
441
|
-
optimizeNames(names,
|
|
441
|
+
optimizeNames(names, constants10) {
|
|
442
442
|
if (this.lhs instanceof code_1.Name && !names[this.lhs.str] && !this.sideEffects)
|
|
443
443
|
return;
|
|
444
|
-
this.rhs = optimizeExpr(this.rhs, names,
|
|
444
|
+
this.rhs = optimizeExpr(this.rhs, names, constants10);
|
|
445
445
|
return this;
|
|
446
446
|
}
|
|
447
447
|
get names() {
|
|
@@ -502,8 +502,8 @@ var require_codegen = __commonJS({
|
|
|
502
502
|
optimizeNodes() {
|
|
503
503
|
return `${this.code}` ? this : void 0;
|
|
504
504
|
}
|
|
505
|
-
optimizeNames(names,
|
|
506
|
-
this.code = optimizeExpr(this.code, names,
|
|
505
|
+
optimizeNames(names, constants10) {
|
|
506
|
+
this.code = optimizeExpr(this.code, names, constants10);
|
|
507
507
|
return this;
|
|
508
508
|
}
|
|
509
509
|
get names() {
|
|
@@ -532,12 +532,12 @@ var require_codegen = __commonJS({
|
|
|
532
532
|
}
|
|
533
533
|
return nodes.length > 0 ? this : void 0;
|
|
534
534
|
}
|
|
535
|
-
optimizeNames(names,
|
|
535
|
+
optimizeNames(names, constants10) {
|
|
536
536
|
const { nodes } = this;
|
|
537
537
|
let i = nodes.length;
|
|
538
538
|
while (i--) {
|
|
539
539
|
const n = nodes[i];
|
|
540
|
-
if (n.optimizeNames(names,
|
|
540
|
+
if (n.optimizeNames(names, constants10))
|
|
541
541
|
continue;
|
|
542
542
|
subtractNames(names, n.names);
|
|
543
543
|
nodes.splice(i, 1);
|
|
@@ -590,12 +590,12 @@ var require_codegen = __commonJS({
|
|
|
590
590
|
return void 0;
|
|
591
591
|
return this;
|
|
592
592
|
}
|
|
593
|
-
optimizeNames(names,
|
|
593
|
+
optimizeNames(names, constants10) {
|
|
594
594
|
var _a;
|
|
595
|
-
this.else = (_a = this.else) === null || _a === void 0 ? void 0 : _a.optimizeNames(names,
|
|
596
|
-
if (!(super.optimizeNames(names,
|
|
595
|
+
this.else = (_a = this.else) === null || _a === void 0 ? void 0 : _a.optimizeNames(names, constants10);
|
|
596
|
+
if (!(super.optimizeNames(names, constants10) || this.else))
|
|
597
597
|
return;
|
|
598
|
-
this.condition = optimizeExpr(this.condition, names,
|
|
598
|
+
this.condition = optimizeExpr(this.condition, names, constants10);
|
|
599
599
|
return this;
|
|
600
600
|
}
|
|
601
601
|
get names() {
|
|
@@ -618,10 +618,10 @@ var require_codegen = __commonJS({
|
|
|
618
618
|
render(opts) {
|
|
619
619
|
return `for(${this.iteration})` + super.render(opts);
|
|
620
620
|
}
|
|
621
|
-
optimizeNames(names,
|
|
622
|
-
if (!super.optimizeNames(names,
|
|
621
|
+
optimizeNames(names, constants10) {
|
|
622
|
+
if (!super.optimizeNames(names, constants10))
|
|
623
623
|
return;
|
|
624
|
-
this.iteration = optimizeExpr(this.iteration, names,
|
|
624
|
+
this.iteration = optimizeExpr(this.iteration, names, constants10);
|
|
625
625
|
return this;
|
|
626
626
|
}
|
|
627
627
|
get names() {
|
|
@@ -657,10 +657,10 @@ var require_codegen = __commonJS({
|
|
|
657
657
|
render(opts) {
|
|
658
658
|
return `for(${this.varKind} ${this.name} ${this.loop} ${this.iterable})` + super.render(opts);
|
|
659
659
|
}
|
|
660
|
-
optimizeNames(names,
|
|
661
|
-
if (!super.optimizeNames(names,
|
|
660
|
+
optimizeNames(names, constants10) {
|
|
661
|
+
if (!super.optimizeNames(names, constants10))
|
|
662
662
|
return;
|
|
663
|
-
this.iterable = optimizeExpr(this.iterable, names,
|
|
663
|
+
this.iterable = optimizeExpr(this.iterable, names, constants10);
|
|
664
664
|
return this;
|
|
665
665
|
}
|
|
666
666
|
get names() {
|
|
@@ -702,11 +702,11 @@ var require_codegen = __commonJS({
|
|
|
702
702
|
(_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNodes();
|
|
703
703
|
return this;
|
|
704
704
|
}
|
|
705
|
-
optimizeNames(names,
|
|
705
|
+
optimizeNames(names, constants10) {
|
|
706
706
|
var _a, _b;
|
|
707
|
-
super.optimizeNames(names,
|
|
708
|
-
(_a = this.catch) === null || _a === void 0 ? void 0 : _a.optimizeNames(names,
|
|
709
|
-
(_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNames(names,
|
|
707
|
+
super.optimizeNames(names, constants10);
|
|
708
|
+
(_a = this.catch) === null || _a === void 0 ? void 0 : _a.optimizeNames(names, constants10);
|
|
709
|
+
(_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNames(names, constants10);
|
|
710
710
|
return this;
|
|
711
711
|
}
|
|
712
712
|
get names() {
|
|
@@ -1007,7 +1007,7 @@ var require_codegen = __commonJS({
|
|
|
1007
1007
|
function addExprNames(names, from) {
|
|
1008
1008
|
return from instanceof code_1._CodeOrName ? addNames(names, from.names) : names;
|
|
1009
1009
|
}
|
|
1010
|
-
function optimizeExpr(expr, names,
|
|
1010
|
+
function optimizeExpr(expr, names, constants10) {
|
|
1011
1011
|
if (expr instanceof code_1.Name)
|
|
1012
1012
|
return replaceName(expr);
|
|
1013
1013
|
if (!canOptimize(expr))
|
|
@@ -1022,14 +1022,14 @@ var require_codegen = __commonJS({
|
|
|
1022
1022
|
return items;
|
|
1023
1023
|
}, []));
|
|
1024
1024
|
function replaceName(n) {
|
|
1025
|
-
const c =
|
|
1025
|
+
const c = constants10[n.str];
|
|
1026
1026
|
if (c === void 0 || names[n.str] !== 1)
|
|
1027
1027
|
return n;
|
|
1028
1028
|
delete names[n.str];
|
|
1029
1029
|
return c;
|
|
1030
1030
|
}
|
|
1031
1031
|
function canOptimize(e) {
|
|
1032
|
-
return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 &&
|
|
1032
|
+
return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 && constants10[c.str] !== void 0);
|
|
1033
1033
|
}
|
|
1034
1034
|
}
|
|
1035
1035
|
function subtractNames(names, from) {
|
|
@@ -7422,7 +7422,7 @@ var require_DOMException = __commonJS({
|
|
|
7422
7422
|
"INVALID_NODE_TYPE_ERR (24): the supplied node is invalid or has an invalid ancestor for this operation",
|
|
7423
7423
|
"DATA_CLONE_ERR (25): the object can not be cloned."
|
|
7424
7424
|
];
|
|
7425
|
-
var
|
|
7425
|
+
var constants10 = {
|
|
7426
7426
|
INDEX_SIZE_ERR,
|
|
7427
7427
|
DOMSTRING_SIZE_ERR: 2,
|
|
7428
7428
|
// historical
|
|
@@ -7461,8 +7461,8 @@ var require_DOMException = __commonJS({
|
|
|
7461
7461
|
this.name = names[code];
|
|
7462
7462
|
}
|
|
7463
7463
|
DOMException.prototype.__proto__ = Error.prototype;
|
|
7464
|
-
for (c in
|
|
7465
|
-
v = { value:
|
|
7464
|
+
for (c in constants10) {
|
|
7465
|
+
v = { value: constants10[c] };
|
|
7466
7466
|
Object.defineProperty(DOMException, c, v);
|
|
7467
7467
|
Object.defineProperty(DOMException.prototype, c, v);
|
|
7468
7468
|
}
|
|
@@ -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 join31(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 = join31(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 join31(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);
|
|
@@ -51666,16 +51666,16 @@ var NOTE_PLACEHOLDERS = [
|
|
|
51666
51666
|
"exportStem"
|
|
51667
51667
|
];
|
|
51668
51668
|
var PLACEHOLDER_MODIFIERS = ["raw", "yaml"];
|
|
51669
|
-
var wrap2 = (before, after = "",
|
|
51669
|
+
var wrap2 = (before, after = "", join31) => ({
|
|
51670
51670
|
mode: "wrap",
|
|
51671
51671
|
before,
|
|
51672
51672
|
after,
|
|
51673
|
-
...
|
|
51673
|
+
...join31 ? { join: join31 } : {}
|
|
51674
51674
|
});
|
|
51675
|
-
var pattern = (value,
|
|
51675
|
+
var pattern = (value, join31) => ({
|
|
51676
51676
|
mode: "pattern",
|
|
51677
51677
|
value,
|
|
51678
|
-
...
|
|
51678
|
+
...join31 ? { join: join31 } : {}
|
|
51679
51679
|
});
|
|
51680
51680
|
var STANDARD = {
|
|
51681
51681
|
schemaVersion: 1,
|
|
@@ -53056,6 +53056,21 @@ function exportWithTemplate(request, deps, chosen, notes, skipped, { output, ass
|
|
|
53056
53056
|
|
|
53057
53057
|
// src/tools/directOperations.ts
|
|
53058
53058
|
import { createHash as createHash3 } from "node:crypto";
|
|
53059
|
+
import {
|
|
53060
|
+
closeSync as closeSync7,
|
|
53061
|
+
constants as constants7,
|
|
53062
|
+
fstatSync as fstatSync7,
|
|
53063
|
+
mkdtempSync as mkdtempSync6,
|
|
53064
|
+
openSync as openSync7,
|
|
53065
|
+
readFileSync as readFileSync4,
|
|
53066
|
+
rmSync as rmSync6,
|
|
53067
|
+
writeFileSync as writeFileSync5
|
|
53068
|
+
} from "node:fs";
|
|
53069
|
+
import { tmpdir as tmpdir6 } from "node:os";
|
|
53070
|
+
import { basename as basename6, extname as extname7, isAbsolute as isAbsolute4, join as join24 } from "node:path";
|
|
53071
|
+
|
|
53072
|
+
// src/utils/pasteboardFreeze.ts
|
|
53073
|
+
import { execFileSync as execFileSync19 } from "node:child_process";
|
|
53059
53074
|
import {
|
|
53060
53075
|
closeSync as closeSync6,
|
|
53061
53076
|
constants as constants6,
|
|
@@ -53064,10 +53079,224 @@ import {
|
|
|
53064
53079
|
openSync as openSync6,
|
|
53065
53080
|
readFileSync as readFileSync3,
|
|
53066
53081
|
rmSync as rmSync5,
|
|
53082
|
+
statSync as statSync4,
|
|
53067
53083
|
writeFileSync as writeFileSync4
|
|
53068
53084
|
} from "node:fs";
|
|
53069
53085
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
53070
|
-
import { basename as basename5, extname as extname6,
|
|
53086
|
+
import { basename as basename5, extname as extname6, join as join23 } from "node:path";
|
|
53087
|
+
var PASTEBOARD_NAME_ENV = "APPLE_NOTES_MCP_PASTEBOARD_NAME";
|
|
53088
|
+
var MAX_PASTEBOARD_BYTES = 64 * 1024 * 1024;
|
|
53089
|
+
var PASTEBOARD_DATA_TYPES = [
|
|
53090
|
+
{ type: "public.png", ext: "png", label: "image" },
|
|
53091
|
+
{ type: "public.jpeg", ext: "jpg", label: "image" },
|
|
53092
|
+
{ type: "public.heic", ext: "heic", label: "image" },
|
|
53093
|
+
{ type: "com.compuserve.gif", ext: "gif", label: "image" },
|
|
53094
|
+
{ type: "public.tiff", ext: "tiff", label: "image" },
|
|
53095
|
+
{ type: "com.adobe.pdf", ext: "pdf", label: "document" }
|
|
53096
|
+
];
|
|
53097
|
+
var PASTEBOARD_ACCESS_BEHAVIORS = {
|
|
53098
|
+
0: "default",
|
|
53099
|
+
1: "ask",
|
|
53100
|
+
2: "alwaysAllow",
|
|
53101
|
+
3: "alwaysDeny"
|
|
53102
|
+
};
|
|
53103
|
+
var PASTEBOARD_FREEZE_JXA = `
|
|
53104
|
+
ObjC.import("AppKit");
|
|
53105
|
+
function run(argv) {
|
|
53106
|
+
var dir = argv[0], name = argv[1], limit = Number(argv[2]), prefs = JSON.parse(argv[3]);
|
|
53107
|
+
var allowAlert = argv[4] === "1";
|
|
53108
|
+
var pb = name ? $.NSPasteboard.pasteboardWithName(name) : $.NSPasteboard.generalPasteboard;
|
|
53109
|
+
if (!pb || pb.isNil()) return JSON.stringify({ status: "error", code: "pasteboard_unavailable" });
|
|
53110
|
+
if (!name && pb.respondsToSelector("accessBehavior")) {
|
|
53111
|
+
var behavior = Number(pb.accessBehavior);
|
|
53112
|
+
if (behavior === 3 || (behavior !== 2 && !allowAlert))
|
|
53113
|
+
return JSON.stringify({ status: "error", code: "pasteboard_access_denied", accessBehavior: behavior });
|
|
53114
|
+
}
|
|
53115
|
+
var before = pb.changeCount;
|
|
53116
|
+
var types = ObjC.deepUnwrap(pb.types) || [];
|
|
53117
|
+
if (types.length === 0) return JSON.stringify({ status: "error", code: "pasteboard_empty" });
|
|
53118
|
+
var result = null;
|
|
53119
|
+
var items = pb.pasteboardItems;
|
|
53120
|
+
var itemCount = items && !items.isNil() ? Number(items.count) : 0;
|
|
53121
|
+
var fileUrls = [];
|
|
53122
|
+
for (var k = 0; k < itemCount; k++) {
|
|
53123
|
+
var item = items.objectAtIndex(k);
|
|
53124
|
+
var itemTypes = ObjC.deepUnwrap(item.types) || [];
|
|
53125
|
+
if (itemTypes.indexOf("public.file-url") < 0) continue;
|
|
53126
|
+
var value = ObjC.unwrap(item.stringForType("public.file-url"));
|
|
53127
|
+
if (value) fileUrls.push(value);
|
|
53128
|
+
}
|
|
53129
|
+
if (fileUrls.length > 1)
|
|
53130
|
+
return JSON.stringify({ status: "error", code: "multiple_files", count: fileUrls.length });
|
|
53131
|
+
if (fileUrls.length === 1) {
|
|
53132
|
+
var url = $.NSURL.URLWithString(fileUrls[0]);
|
|
53133
|
+
if (url && !url.isNil() && url.isFileURL) {
|
|
53134
|
+
result = { status: "ok", kind: "file", type: "public.file-url", path: ObjC.unwrap(url.path) };
|
|
53135
|
+
}
|
|
53136
|
+
}
|
|
53137
|
+
if (!result) {
|
|
53138
|
+
for (var i = 0; i < prefs.length && !result; i++) {
|
|
53139
|
+
if (types.indexOf(prefs[i][0]) < 0) continue;
|
|
53140
|
+
var data = pb.dataForType(prefs[i][0]);
|
|
53141
|
+
if (!data || data.isNil() || data.length === 0) continue;
|
|
53142
|
+
if (data.length > limit) return JSON.stringify({ status: "error", code: "too_large", bytes: data.length });
|
|
53143
|
+
var path = dir + "/pasteboard." + prefs[i][1];
|
|
53144
|
+
if (!data.writeToFileAtomically(path, true))
|
|
53145
|
+
return JSON.stringify({ status: "error", code: "write_failed" });
|
|
53146
|
+
result = { status: "ok", kind: "data", type: prefs[i][0], path: path, bytes: data.length };
|
|
53147
|
+
}
|
|
53148
|
+
}
|
|
53149
|
+
if (pb.changeCount !== before) return JSON.stringify({ status: "error", code: "pasteboard_changed" });
|
|
53150
|
+
return JSON.stringify(result || { status: "error", code: "unsupported_content", types: types.slice(0, 20) });
|
|
53151
|
+
}
|
|
53152
|
+
`;
|
|
53153
|
+
var ENVELOPE_CODES = {
|
|
53154
|
+
pasteboard_access_denied: "permission_denied",
|
|
53155
|
+
pasteboard_unavailable: "operation_failed",
|
|
53156
|
+
pasteboard_timeout: "operation_failed",
|
|
53157
|
+
pasteboard_empty: "validation_error",
|
|
53158
|
+
pasteboard_changed: "operation_failed",
|
|
53159
|
+
unsupported_content: "validation_error",
|
|
53160
|
+
multiple_files: "validation_error",
|
|
53161
|
+
too_large: "validation_error",
|
|
53162
|
+
write_failed: "operation_failed",
|
|
53163
|
+
file_unreadable: "validation_error"
|
|
53164
|
+
};
|
|
53165
|
+
var PasteboardError = class extends CodedError {
|
|
53166
|
+
constructor(code, message, details = {}) {
|
|
53167
|
+
super(message, {
|
|
53168
|
+
...details,
|
|
53169
|
+
code: ENVELOPE_CODES[code],
|
|
53170
|
+
pasteboardCode: code,
|
|
53171
|
+
committed: false
|
|
53172
|
+
});
|
|
53173
|
+
this.code = code;
|
|
53174
|
+
this.name = "PasteboardError";
|
|
53175
|
+
}
|
|
53176
|
+
code;
|
|
53177
|
+
};
|
|
53178
|
+
var SUPPORTED = "an image (PNG, JPEG, HEIC, GIF, TIFF), a PDF, or one copied file";
|
|
53179
|
+
var MESSAGES = {
|
|
53180
|
+
pasteboard_access_denied: "Reading the pasteboard now would make macOS ask whether to allow the paste, so nothing was read. Call again with allowPasteAlert: true to let macOS show its paste alert, or allow pasting for the app that runs this server in System Settings, where macOS lists it after its first paste alert.",
|
|
53181
|
+
pasteboard_unavailable: "The pasteboard is not reachable from this process. The MCP host must run in your logged-in GUI session (not over SSH or as a background daemon).",
|
|
53182
|
+
pasteboard_timeout: "Reading the pasteboard timed out; nothing was attached. If macOS showed a paste alert, answer it and try again.",
|
|
53183
|
+
pasteboard_empty: "The pasteboard is empty. Copy an image or a file first.",
|
|
53184
|
+
pasteboard_changed: "The pasteboard changed while it was being read. Try again.",
|
|
53185
|
+
unsupported_content: `The pasteboard holds no supported content: copy ${SUPPORTED}. Text belongs in append-to-note, not in an attachment.`,
|
|
53186
|
+
multiple_files: "The pasteboard holds more than one copied file. Copy exactly one file, or attach each file with add-attachment.",
|
|
53187
|
+
too_large: "The pasteboard contents exceed the 64 MiB attachment limit.",
|
|
53188
|
+
write_failed: "Could not write the pasteboard contents to a temporary file.",
|
|
53189
|
+
file_unreadable: "The copied file could not be read as a regular file of at most 64 MiB."
|
|
53190
|
+
};
|
|
53191
|
+
function replyError(code, reply) {
|
|
53192
|
+
if (code === "pasteboard_access_denied") {
|
|
53193
|
+
const raw = typeof reply.accessBehavior === "number" ? reply.accessBehavior : void 0;
|
|
53194
|
+
const accessBehavior = raw !== void 0 && PASTEBOARD_ACCESS_BEHAVIORS[raw] || "unknown";
|
|
53195
|
+
const message = accessBehavior === "alwaysDeny" ? "macOS is set to deny pasteboard access to the app that runs this server, so nothing was read. Change it to allow in System Settings, then try again." : MESSAGES.pasteboard_access_denied;
|
|
53196
|
+
return new PasteboardError(code, message, { accessBehavior });
|
|
53197
|
+
}
|
|
53198
|
+
if (code === "multiple_files") {
|
|
53199
|
+
const count = typeof reply.count === "number" ? reply.count : void 0;
|
|
53200
|
+
return new PasteboardError(
|
|
53201
|
+
code,
|
|
53202
|
+
count ? `The pasteboard holds ${count} copied files. Copy exactly one file, or attach each file with add-attachment.` : MESSAGES[code],
|
|
53203
|
+
count ? { count } : {}
|
|
53204
|
+
);
|
|
53205
|
+
}
|
|
53206
|
+
if (code === "unsupported_content" && Array.isArray(reply.types)) {
|
|
53207
|
+
const types = reply.types.filter((t) => typeof t === "string").slice(0, 20);
|
|
53208
|
+
if (types.length)
|
|
53209
|
+
return new PasteboardError(
|
|
53210
|
+
code,
|
|
53211
|
+
`${MESSAGES[code]} Pasteboard types found: ${types.join(", ")}.`,
|
|
53212
|
+
{ types }
|
|
53213
|
+
);
|
|
53214
|
+
}
|
|
53215
|
+
if (code === "too_large" && typeof reply.bytes === "number")
|
|
53216
|
+
return new PasteboardError(code, MESSAGES[code], { bytes: reply.bytes });
|
|
53217
|
+
return new PasteboardError(code, MESSAGES[code]);
|
|
53218
|
+
}
|
|
53219
|
+
function pasteboardTimeoutMs() {
|
|
53220
|
+
return callTimeoutMs() ?? envPositiveNumber("APPLE_NOTES_MCP_TIMEOUT_MS") ?? 3e4;
|
|
53221
|
+
}
|
|
53222
|
+
function defaultRunJxa(args) {
|
|
53223
|
+
return execFileSync19("osascript", ["-l", "JavaScript", "-e", PASTEBOARD_FREEZE_JXA, ...args], {
|
|
53224
|
+
encoding: "utf8",
|
|
53225
|
+
timeout: pasteboardTimeoutMs(),
|
|
53226
|
+
maxBuffer: 1024 * 1024,
|
|
53227
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
53228
|
+
});
|
|
53229
|
+
}
|
|
53230
|
+
function pasteboardFilename(requested, frozenFilename) {
|
|
53231
|
+
if (requested === void 0) return void 0;
|
|
53232
|
+
const ext = extname6(frozenFilename);
|
|
53233
|
+
return ext && !extname6(requested) ? requested + ext : requested;
|
|
53234
|
+
}
|
|
53235
|
+
function readRegularFile(path10) {
|
|
53236
|
+
let descriptor;
|
|
53237
|
+
try {
|
|
53238
|
+
descriptor = openSync6(path10, constants6.O_RDONLY | constants6.O_NOFOLLOW);
|
|
53239
|
+
} catch {
|
|
53240
|
+
throw new PasteboardError("file_unreadable", MESSAGES.file_unreadable);
|
|
53241
|
+
}
|
|
53242
|
+
try {
|
|
53243
|
+
const stat = fstatSync6(descriptor);
|
|
53244
|
+
if (!stat.isFile() || stat.size === 0 || stat.size > MAX_PASTEBOARD_BYTES)
|
|
53245
|
+
throw new PasteboardError("file_unreadable", MESSAGES.file_unreadable);
|
|
53246
|
+
return readFileSync3(descriptor);
|
|
53247
|
+
} finally {
|
|
53248
|
+
closeSync6(descriptor);
|
|
53249
|
+
}
|
|
53250
|
+
}
|
|
53251
|
+
function freezePasteboard(options = {}) {
|
|
53252
|
+
const directory = mkdtempSync5(join23(tmpdir5(), "notes-pasteboard-"));
|
|
53253
|
+
const cleanup = () => rmSync5(directory, { recursive: true, force: true });
|
|
53254
|
+
try {
|
|
53255
|
+
const prefs = JSON.stringify(PASTEBOARD_DATA_TYPES.map((t) => [t.type, t.ext]));
|
|
53256
|
+
let raw;
|
|
53257
|
+
try {
|
|
53258
|
+
raw = (options.runJxa ?? defaultRunJxa)([
|
|
53259
|
+
directory,
|
|
53260
|
+
options.pasteboardName ?? "",
|
|
53261
|
+
String(MAX_PASTEBOARD_BYTES),
|
|
53262
|
+
prefs,
|
|
53263
|
+
options.allowPasteAlert ? "1" : "0"
|
|
53264
|
+
]);
|
|
53265
|
+
} catch (error2) {
|
|
53266
|
+
throw error2?.code === "ETIMEDOUT" ? new PasteboardError("pasteboard_timeout", MESSAGES.pasteboard_timeout) : new PasteboardError("pasteboard_unavailable", MESSAGES.pasteboard_unavailable);
|
|
53267
|
+
}
|
|
53268
|
+
let reply;
|
|
53269
|
+
try {
|
|
53270
|
+
reply = JSON.parse(raw.trim());
|
|
53271
|
+
} catch {
|
|
53272
|
+
throw new PasteboardError("pasteboard_unavailable", MESSAGES.pasteboard_unavailable);
|
|
53273
|
+
}
|
|
53274
|
+
if (reply.status !== "ok" || !reply.path || !reply.type) {
|
|
53275
|
+
const code = reply.code && reply.code in MESSAGES ? reply.code : "pasteboard_unavailable";
|
|
53276
|
+
throw replyError(code, reply);
|
|
53277
|
+
}
|
|
53278
|
+
if (reply.kind === "file") {
|
|
53279
|
+
const bytes = readRegularFile(reply.path);
|
|
53280
|
+
const filename2 = basename5(reply.path);
|
|
53281
|
+
const path11 = join23(directory, filename2);
|
|
53282
|
+
writeFileSync4(path11, bytes, { mode: 384 });
|
|
53283
|
+
return { kind: "file", type: reply.type, path: path11, filename: filename2, bytes: bytes.length, cleanup };
|
|
53284
|
+
}
|
|
53285
|
+
if (join23(directory, basename5(reply.path)) !== reply.path)
|
|
53286
|
+
throw new PasteboardError("write_failed", MESSAGES.write_failed);
|
|
53287
|
+
const label = PASTEBOARD_DATA_TYPES.find((t) => t.type === reply.type)?.label ?? "item";
|
|
53288
|
+
const filename = `Pasted ${label}${extname6(reply.path)}`;
|
|
53289
|
+
const path10 = join23(directory, filename);
|
|
53290
|
+
writeFileSync4(path10, readFileSync3(reply.path), { mode: 384 });
|
|
53291
|
+
rmSync5(reply.path, { force: true });
|
|
53292
|
+
return { kind: "data", type: reply.type, path: path10, filename, bytes: statSync4(path10).size, cleanup };
|
|
53293
|
+
} catch (error2) {
|
|
53294
|
+
cleanup();
|
|
53295
|
+
throw error2;
|
|
53296
|
+
}
|
|
53297
|
+
}
|
|
53298
|
+
|
|
53299
|
+
// src/tools/directOperations.ts
|
|
53071
53300
|
var noteId = exactIdInput(
|
|
53072
53301
|
"ICNote",
|
|
53073
53302
|
/^x-coredata:\/\/[0-9a-f-]+\/ICNote\/p\d+$/i,
|
|
@@ -53112,17 +53341,17 @@ function assertExistingContentPreserved(before, after) {
|
|
|
53112
53341
|
}
|
|
53113
53342
|
function localAttachment(path10) {
|
|
53114
53343
|
if (!isAbsolute4(path10)) throw new Error("An absolute local file path is required");
|
|
53115
|
-
const descriptor =
|
|
53344
|
+
const descriptor = openSync7(path10, constants7.O_RDONLY | constants7.O_NOFOLLOW);
|
|
53116
53345
|
try {
|
|
53117
|
-
const stat =
|
|
53346
|
+
const stat = fstatSync7(descriptor);
|
|
53118
53347
|
if (!stat.isFile() || stat.size === 0 || stat.size > 64 * 1024 * 1024)
|
|
53119
53348
|
throw new Error("Attachment must be a nonempty regular file of at most 64 MiB");
|
|
53120
|
-
const bytes =
|
|
53349
|
+
const bytes = readFileSync4(descriptor);
|
|
53121
53350
|
if (bytes.length !== stat.size)
|
|
53122
53351
|
throw new Error("Attachment changed while it was being read; try again");
|
|
53123
53352
|
return bytes;
|
|
53124
53353
|
} finally {
|
|
53125
|
-
|
|
53354
|
+
closeSync7(descriptor);
|
|
53126
53355
|
}
|
|
53127
53356
|
}
|
|
53128
53357
|
function registerDirectOperations(server2, manager) {
|
|
@@ -53235,19 +53464,67 @@ function registerDirectOperations(server2, manager) {
|
|
|
53235
53464
|
}
|
|
53236
53465
|
}
|
|
53237
53466
|
);
|
|
53467
|
+
tool(
|
|
53468
|
+
"add-attachment-from-pasteboard",
|
|
53469
|
+
"Use when: the user copied an image, a PDF, or a file (screenshot, Copy Image, Finder Copy) and wants it attached to an exact note.\nReturns: the add-attachment result (attachment id, bytes, name, content hash) plus source: what was taken from the pasteboard (kind, type, default filename).\nDo not use when: the pasteboard holds text (use append-to-note), several copied files (refused; use add-attachment per file), or you have a file path (use add-attachment).\nSafety: checks the note and revision before reading the pasteboard; reads nothing when macOS would show its paste alert unless allowPasteAlert is true (error pasteboardCode pasteboard_access_denied); reads the pasteboard once and freezes its bytes into a private temporary file before attaching, never writes to the pasteboard, then runs add-attachment's checks: fresh rich revision, at most 64 MiB, no insertion retry, existing content and exact bytes verified. Needs the MCP host to run in the logged-in GUI session.",
|
|
53470
|
+
{
|
|
53471
|
+
id: noteId,
|
|
53472
|
+
expectedContentHash: revision,
|
|
53473
|
+
filename: attachmentInput.filename.describe(
|
|
53474
|
+
`Name the attachment gets in Notes (default: the copied file's name, or "Pasted image.png" / "Pasted document.pdf"). Without an extension, the pasted type's extension is added; with one, it must match the pasted type. Same rules as add-attachment otherwise.`
|
|
53475
|
+
),
|
|
53476
|
+
allowPasteAlert: external_exports.boolean().optional().describe(
|
|
53477
|
+
"Read the pasteboard even if macOS will show its paste alert (macOS 15.4+ paste privacy). Default false: when pasting is not already always allowed, the tool reads nothing and returns pasteboardCode pasteboard_access_denied. Set true only after the user agrees to answer the alert. Never overrides a Deny setting."
|
|
53478
|
+
)
|
|
53479
|
+
},
|
|
53480
|
+
({ id: id2, expectedContentHash, filename, allowPasteAlert }) => {
|
|
53481
|
+
if (filename !== void 0) checkAttachmentFilename(filename);
|
|
53482
|
+
const before = readSnapshot(manager, id2);
|
|
53483
|
+
if (before.hash !== expectedContentHash) throw new Error("Note revision changed");
|
|
53484
|
+
const frozen = freezePasteboard({
|
|
53485
|
+
pasteboardName: process.env[PASTEBOARD_NAME_ENV]?.trim() || void 0,
|
|
53486
|
+
allowPasteAlert: allowPasteAlert === true
|
|
53487
|
+
});
|
|
53488
|
+
try {
|
|
53489
|
+
const source = {
|
|
53490
|
+
kind: frozen.kind,
|
|
53491
|
+
type: frozen.type,
|
|
53492
|
+
filename: frozen.filename
|
|
53493
|
+
};
|
|
53494
|
+
return {
|
|
53495
|
+
...attachFile(
|
|
53496
|
+
manager,
|
|
53497
|
+
{
|
|
53498
|
+
id: id2,
|
|
53499
|
+
expectedContentHash,
|
|
53500
|
+
path: frozen.path,
|
|
53501
|
+
filename: pasteboardFilename(filename, frozen.filename)
|
|
53502
|
+
},
|
|
53503
|
+
before
|
|
53504
|
+
),
|
|
53505
|
+
source
|
|
53506
|
+
};
|
|
53507
|
+
} finally {
|
|
53508
|
+
frozen.cleanup();
|
|
53509
|
+
}
|
|
53510
|
+
}
|
|
53511
|
+
);
|
|
53238
53512
|
}
|
|
53239
|
-
function
|
|
53240
|
-
const source = basename5(path10);
|
|
53241
|
-
if (filename === void 0) return source;
|
|
53513
|
+
function checkAttachmentFilename(filename) {
|
|
53242
53514
|
if (Buffer.byteLength(filename, "utf8") > 255)
|
|
53243
53515
|
throw new Error("filename must be at most 255 bytes");
|
|
53244
53516
|
if (filename !== filename.trim() || filename === "" || filename.startsWith(".") || /[/:\\\p{Cc}]/u.test(filename))
|
|
53245
53517
|
throw new Error(
|
|
53246
53518
|
"filename must be one path component with no slash, colon, backslash, control character, leading dot, or surrounding spaces"
|
|
53247
53519
|
);
|
|
53248
|
-
|
|
53520
|
+
}
|
|
53521
|
+
function attachmentName(path10, filename) {
|
|
53522
|
+
const source = basename6(path10);
|
|
53523
|
+
if (filename === void 0) return source;
|
|
53524
|
+
checkAttachmentFilename(filename);
|
|
53525
|
+
if (extname7(filename).toLowerCase() !== extname7(source).toLowerCase())
|
|
53249
53526
|
throw new Error(
|
|
53250
|
-
`filename must keep the source file's extension (${
|
|
53527
|
+
`filename must keep the source file's extension (${extname7(source) || "none"})`
|
|
53251
53528
|
);
|
|
53252
53529
|
return filename;
|
|
53253
53530
|
}
|
|
@@ -53286,13 +53563,13 @@ function storedInsertion(manager, id2, before, bytes, returnedId) {
|
|
|
53286
53563
|
const matches = row.assetPaths.some((path10) => {
|
|
53287
53564
|
let descriptor;
|
|
53288
53565
|
try {
|
|
53289
|
-
descriptor =
|
|
53290
|
-
const stat =
|
|
53291
|
-
return stat.isFile() && stat.size === bytes.length && sha256(
|
|
53566
|
+
descriptor = openSync7(path10, constants7.O_RDONLY | constants7.O_NOFOLLOW);
|
|
53567
|
+
const stat = fstatSync7(descriptor);
|
|
53568
|
+
return stat.isFile() && stat.size === bytes.length && sha256(readFileSync4(descriptor)) === expected;
|
|
53292
53569
|
} catch {
|
|
53293
53570
|
return false;
|
|
53294
53571
|
} finally {
|
|
53295
|
-
if (descriptor !== void 0)
|
|
53572
|
+
if (descriptor !== void 0) closeSync7(descriptor);
|
|
53296
53573
|
}
|
|
53297
53574
|
});
|
|
53298
53575
|
if (!matches)
|
|
@@ -53301,18 +53578,18 @@ function storedInsertion(manager, id2, before, bytes, returnedId) {
|
|
|
53301
53578
|
);
|
|
53302
53579
|
return { attachmentId, name: row.filename };
|
|
53303
53580
|
}
|
|
53304
|
-
function attachFile(manager, args) {
|
|
53581
|
+
function attachFile(manager, args, checked) {
|
|
53305
53582
|
const { id: id2, expectedContentHash, path: path10 } = args;
|
|
53306
53583
|
const name = attachmentName(path10, args.filename);
|
|
53307
|
-
const before = readSnapshot(manager, id2);
|
|
53584
|
+
const before = checked ?? readSnapshot(manager, id2);
|
|
53308
53585
|
if (before.hash !== expectedContentHash) throw new Error("Note revision changed");
|
|
53309
53586
|
const bytes = localAttachment(path10);
|
|
53310
53587
|
const beforeAttachments = manager.listAttachmentsById(id2);
|
|
53311
53588
|
const beforeStored = storedAttachmentIds(manager, id2);
|
|
53312
|
-
const directory =
|
|
53313
|
-
const temporaryFile =
|
|
53589
|
+
const directory = mkdtempSync6(join24(tmpdir6(), "notes-attachment-add-"));
|
|
53590
|
+
const temporaryFile = join24(directory, name);
|
|
53314
53591
|
try {
|
|
53315
|
-
|
|
53592
|
+
writeFileSync5(temporaryFile, bytes, { mode: 384 });
|
|
53316
53593
|
if (readSnapshot(manager, id2).hash !== before.hash) throw new Error("Note revision changed");
|
|
53317
53594
|
let returnedId;
|
|
53318
53595
|
let transportUncertain = false;
|
|
@@ -53372,7 +53649,7 @@ function attachFile(manager, args) {
|
|
|
53372
53649
|
} : {}
|
|
53373
53650
|
};
|
|
53374
53651
|
} finally {
|
|
53375
|
-
|
|
53652
|
+
rmSync6(directory, { recursive: true, force: true });
|
|
53376
53653
|
}
|
|
53377
53654
|
}
|
|
53378
53655
|
|
|
@@ -53380,7 +53657,7 @@ function attachFile(manager, args) {
|
|
|
53380
53657
|
import { createHash as createHash4 } from "node:crypto";
|
|
53381
53658
|
|
|
53382
53659
|
// src/utils/folderStore.ts
|
|
53383
|
-
import { execFileSync as
|
|
53660
|
+
import { execFileSync as execFileSync20 } from "child_process";
|
|
53384
53661
|
import * as os9 from "os";
|
|
53385
53662
|
import * as path9 from "path";
|
|
53386
53663
|
var NOTE_STORE_PATH = path9.join(
|
|
@@ -53444,7 +53721,7 @@ function runSqlite7(dbPath2, sql, pk) {
|
|
|
53444
53721
|
const args = ["-readonly"];
|
|
53445
53722
|
if (pk !== void 0) args.push("-cmd", `.parameter set @pk ${pk}`);
|
|
53446
53723
|
args.push(dbPath2, sql);
|
|
53447
|
-
return
|
|
53724
|
+
return execFileSync20("sqlite3", args, {
|
|
53448
53725
|
encoding: "utf8",
|
|
53449
53726
|
timeout: 5e3,
|
|
53450
53727
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -53702,13 +53979,13 @@ function registerFolderDelete(server2, manager, deps = defaultDeps) {
|
|
|
53702
53979
|
// src/services/templateStore.ts
|
|
53703
53980
|
import { randomBytes } from "node:crypto";
|
|
53704
53981
|
import {
|
|
53705
|
-
closeSync as
|
|
53706
|
-
constants as
|
|
53707
|
-
fstatSync as
|
|
53982
|
+
closeSync as closeSync8,
|
|
53983
|
+
constants as constants8,
|
|
53984
|
+
fstatSync as fstatSync8,
|
|
53708
53985
|
linkSync,
|
|
53709
53986
|
lstatSync as lstatSync5,
|
|
53710
53987
|
mkdirSync as mkdirSync7,
|
|
53711
|
-
openSync as
|
|
53988
|
+
openSync as openSync8,
|
|
53712
53989
|
readdirSync as readdirSync4,
|
|
53713
53990
|
readSync as readSync5,
|
|
53714
53991
|
renameSync,
|
|
@@ -53716,7 +53993,7 @@ import {
|
|
|
53716
53993
|
writeSync as writeSync5
|
|
53717
53994
|
} from "node:fs";
|
|
53718
53995
|
import { homedir as homedir19 } from "node:os";
|
|
53719
|
-
import { isAbsolute as isAbsolute5, join as
|
|
53996
|
+
import { isAbsolute as isAbsolute5, join as join26, resolve as resolve5 } from "node:path";
|
|
53720
53997
|
var TEMPLATE_SLUG = /^[a-z0-9][a-z0-9_-]{0,63}$/;
|
|
53721
53998
|
var TemplateStoreError = class extends Error {
|
|
53722
53999
|
constructor(code, message) {
|
|
@@ -53736,7 +54013,7 @@ function templateDir(env = process.env) {
|
|
|
53736
54013
|
);
|
|
53737
54014
|
return resolve5(override);
|
|
53738
54015
|
}
|
|
53739
|
-
return
|
|
54016
|
+
return join26(homedir19(), "Library/Application Support/apple-notes-mcp/templates");
|
|
53740
54017
|
}
|
|
53741
54018
|
function checkName(name, action) {
|
|
53742
54019
|
if (isBuiltinTemplate(name) && action !== "read")
|
|
@@ -53773,19 +54050,19 @@ var TemplateStore = class {
|
|
|
53773
54050
|
return this.dir;
|
|
53774
54051
|
}
|
|
53775
54052
|
file(name) {
|
|
53776
|
-
return
|
|
54053
|
+
return join26(this.dir, `${name}.json`);
|
|
53777
54054
|
}
|
|
53778
54055
|
/** Read a saved template's text, refusing symlinks and non-regular files. */
|
|
53779
54056
|
readText(path10) {
|
|
53780
54057
|
let fd;
|
|
53781
54058
|
try {
|
|
53782
|
-
fd =
|
|
54059
|
+
fd = openSync8(path10, constants8.O_RDONLY | constants8.O_NOFOLLOW);
|
|
53783
54060
|
} catch (error2) {
|
|
53784
54061
|
if (error2.code === "ENOENT") return void 0;
|
|
53785
54062
|
throw new TemplateStoreError("unsafe-path", `Refusing to read ${path10}: not a regular file.`);
|
|
53786
54063
|
}
|
|
53787
54064
|
try {
|
|
53788
|
-
const stat =
|
|
54065
|
+
const stat = fstatSync8(fd);
|
|
53789
54066
|
if (!stat.isFile())
|
|
53790
54067
|
throw new TemplateStoreError(
|
|
53791
54068
|
"unsafe-path",
|
|
@@ -53807,7 +54084,7 @@ var TemplateStore = class {
|
|
|
53807
54084
|
}
|
|
53808
54085
|
return { text: data.subarray(0, read).toString("utf8"), bytes: read, mtime: stat.mtime };
|
|
53809
54086
|
} finally {
|
|
53810
|
-
|
|
54087
|
+
closeSync8(fd);
|
|
53811
54088
|
}
|
|
53812
54089
|
}
|
|
53813
54090
|
/** Saved templates in name order; `skipped` counts entries that are not usable. */
|
|
@@ -53887,10 +54164,10 @@ var TemplateStore = class {
|
|
|
53887
54164
|
"template-exists",
|
|
53888
54165
|
`A template named "${name}" already exists. Pass force: true to replace it.`
|
|
53889
54166
|
);
|
|
53890
|
-
const temp =
|
|
53891
|
-
const fd =
|
|
54167
|
+
const temp = join26(this.dir, `.${name}.${randomBytes(6).toString("hex")}.tmp`);
|
|
54168
|
+
const fd = openSync8(
|
|
53892
54169
|
temp,
|
|
53893
|
-
|
|
54170
|
+
constants8.O_WRONLY | constants8.O_CREAT | constants8.O_EXCL | constants8.O_NOFOLLOW,
|
|
53894
54171
|
384
|
|
53895
54172
|
);
|
|
53896
54173
|
try {
|
|
@@ -53898,7 +54175,7 @@ var TemplateStore = class {
|
|
|
53898
54175
|
let written = 0;
|
|
53899
54176
|
while (written < data.length) written += writeSync5(fd, data, written);
|
|
53900
54177
|
} finally {
|
|
53901
|
-
|
|
54178
|
+
closeSync8(fd);
|
|
53902
54179
|
}
|
|
53903
54180
|
try {
|
|
53904
54181
|
if (force) renameSync(temp, path10);
|
|
@@ -54118,7 +54395,7 @@ function registerMarkdownTemplates(server2, store = () => new TemplateStore()) {
|
|
|
54118
54395
|
|
|
54119
54396
|
// src/utils/svgAnalyzer.ts
|
|
54120
54397
|
import { createHash as createHash5 } from "node:crypto";
|
|
54121
|
-
import { closeSync as
|
|
54398
|
+
import { closeSync as closeSync9, constants as constants9, fstatSync as fstatSync9, openSync as openSync9, readSync as readSync6 } from "node:fs";
|
|
54122
54399
|
|
|
54123
54400
|
// src/utils/svgColor.ts
|
|
54124
54401
|
var NAMED = {
|
|
@@ -56087,14 +56364,14 @@ function analyzeSvgBuffer(source) {
|
|
|
56087
56364
|
function readSvgSource(path10) {
|
|
56088
56365
|
let fd;
|
|
56089
56366
|
try {
|
|
56090
|
-
fd =
|
|
56367
|
+
fd = openSync9(path10, constants9.O_RDONLY | constants9.O_NOFOLLOW | constants9.O_NONBLOCK);
|
|
56091
56368
|
} catch (error2) {
|
|
56092
56369
|
if (error2.code === "ELOOP")
|
|
56093
56370
|
throw new SvgError("svg_file_invalid", "The SVG path is a symbolic link");
|
|
56094
56371
|
throw new SvgError("svg_file_invalid", "The SVG file does not exist or cannot be read");
|
|
56095
56372
|
}
|
|
56096
56373
|
try {
|
|
56097
|
-
const info =
|
|
56374
|
+
const info = fstatSync9(fd);
|
|
56098
56375
|
if (!info.isFile())
|
|
56099
56376
|
throw new SvgError("svg_file_invalid", "The SVG path is not a regular file");
|
|
56100
56377
|
if (info.size > SVG_LIMITS.maxSourceBytes)
|
|
@@ -56116,7 +56393,7 @@ function readSvgSource(path10) {
|
|
|
56116
56393
|
}
|
|
56117
56394
|
return buffer.subarray(0, total);
|
|
56118
56395
|
} finally {
|
|
56119
|
-
|
|
56396
|
+
closeSync9(fd);
|
|
56120
56397
|
}
|
|
56121
56398
|
}
|
|
56122
56399
|
function analyzeSvgFile(path10) {
|
|
@@ -56779,14 +57056,14 @@ import {
|
|
|
56779
57056
|
chmodSync,
|
|
56780
57057
|
existsSync as existsSync14,
|
|
56781
57058
|
mkdirSync as mkdirSync8,
|
|
56782
|
-
mkdtempSync as
|
|
56783
|
-
readFileSync as
|
|
57059
|
+
mkdtempSync as mkdtempSync7,
|
|
57060
|
+
readFileSync as readFileSync5,
|
|
56784
57061
|
renameSync as renameSync2,
|
|
56785
|
-
rmSync as
|
|
56786
|
-
writeFileSync as
|
|
57062
|
+
rmSync as rmSync7,
|
|
57063
|
+
writeFileSync as writeFileSync6
|
|
56787
57064
|
} from "node:fs";
|
|
56788
57065
|
import { homedir as homedir20, release as release3 } from "node:os";
|
|
56789
|
-
import { dirname as dirname8, join as
|
|
57066
|
+
import { dirname as dirname8, join as join27, resolve as resolve7 } from "node:path";
|
|
56790
57067
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
56791
57068
|
var PUBLIC_HELPER_PROTOCOL = 1;
|
|
56792
57069
|
var PUBLIC_HELPER_DIR_ENV = "APPLE_NOTES_MCP_PUBLIC_HELPER_DIR";
|
|
@@ -56814,10 +57091,10 @@ var publicManifestSchema = external_exports.object({
|
|
|
56814
57091
|
function packageRoot(fromDir = dirname8(fileURLToPath2(import.meta.url))) {
|
|
56815
57092
|
let dir = fromDir;
|
|
56816
57093
|
for (; ; ) {
|
|
56817
|
-
const candidate =
|
|
57094
|
+
const candidate = join27(dir, "package.json");
|
|
56818
57095
|
if (existsSync14(candidate)) {
|
|
56819
57096
|
try {
|
|
56820
|
-
if (JSON.parse(
|
|
57097
|
+
if (JSON.parse(readFileSync5(candidate, "utf8")).name === "apple-notes-mcp")
|
|
56821
57098
|
return dir;
|
|
56822
57099
|
} catch {
|
|
56823
57100
|
}
|
|
@@ -56831,9 +57108,9 @@ function defaultPublicHelperDeps(overrides = {}) {
|
|
|
56831
57108
|
return {
|
|
56832
57109
|
env: process.env,
|
|
56833
57110
|
platform: process.platform,
|
|
56834
|
-
sourcePath:
|
|
57111
|
+
sourcePath: join27(packageRoot(), PUBLIC_HELPER_SOURCE),
|
|
56835
57112
|
exists: existsSync14,
|
|
56836
|
-
readFile: (path10) =>
|
|
57113
|
+
readFile: (path10) => readFileSync5(path10),
|
|
56837
57114
|
spawn: spawnSync3,
|
|
56838
57115
|
spawnAsync: spawn,
|
|
56839
57116
|
...overrides
|
|
@@ -56842,14 +57119,14 @@ function defaultPublicHelperDeps(overrides = {}) {
|
|
|
56842
57119
|
function publicHelperInstallDir(env = process.env) {
|
|
56843
57120
|
const override = env[PUBLIC_HELPER_DIR_ENV]?.trim();
|
|
56844
57121
|
if (override) return override;
|
|
56845
|
-
return
|
|
57122
|
+
return join27(homedir20(), "Library", "Application Support", "apple-notes-mcp", "public-helper");
|
|
56846
57123
|
}
|
|
56847
57124
|
function sha256Hex(data) {
|
|
56848
57125
|
return createHash6("sha256").update(data).digest("hex");
|
|
56849
57126
|
}
|
|
56850
57127
|
function inspectPublicHelper(deps = defaultPublicHelperDeps()) {
|
|
56851
57128
|
const installDir = publicHelperInstallDir(deps.env);
|
|
56852
|
-
const binaryPath =
|
|
57129
|
+
const binaryPath = join27(installDir, PUBLIC_HELPER_BINARY);
|
|
56853
57130
|
const base = { installDir, binaryPath, sourcePath: deps.sourcePath, manifest: null };
|
|
56854
57131
|
const fail = (reason, detail) => ({
|
|
56855
57132
|
...base,
|
|
@@ -56860,7 +57137,7 @@ function inspectPublicHelper(deps = defaultPublicHelperDeps()) {
|
|
|
56860
57137
|
if (deps.platform !== "darwin") return fail("unsupported_platform", "macOS only");
|
|
56861
57138
|
if (!deps.exists(deps.sourcePath))
|
|
56862
57139
|
return fail("helper_not_installed", `Packaged helper source is missing: ${deps.sourcePath}`);
|
|
56863
|
-
const manifestPath =
|
|
57140
|
+
const manifestPath = join27(installDir, PUBLIC_HELPER_MANIFEST);
|
|
56864
57141
|
if (!deps.exists(binaryPath) || !deps.exists(manifestPath))
|
|
56865
57142
|
return fail(
|
|
56866
57143
|
"helper_not_installed",
|
|
@@ -56900,14 +57177,14 @@ var UNAVAILABLE_CODES = /* @__PURE__ */ new Set([
|
|
|
56900
57177
|
"helper_modified",
|
|
56901
57178
|
"helper_manifest_invalid"
|
|
56902
57179
|
]);
|
|
56903
|
-
var
|
|
57180
|
+
var ENVELOPE_CODES2 = {
|
|
56904
57181
|
invalid_request: "validation_error",
|
|
56905
57182
|
attachment_not_found: "not_found"
|
|
56906
57183
|
};
|
|
56907
57184
|
var PublicHelperError = class extends CodedError {
|
|
56908
57185
|
constructor(code, message) {
|
|
56909
57186
|
super(message, {
|
|
56910
|
-
code: UNAVAILABLE_CODES.has(code) ? "unsupported" :
|
|
57187
|
+
code: UNAVAILABLE_CODES.has(code) ? "unsupported" : ENVELOPE_CODES2[code] ?? "operation_failed",
|
|
56911
57188
|
helperCode: code
|
|
56912
57189
|
});
|
|
56913
57190
|
this.code = code;
|
|
@@ -57137,13 +57414,13 @@ function buildPublicHelper(checkOnly, deps = defaultPublicHelperBuildDeps()) {
|
|
|
57137
57414
|
steps.push({ step: "find compiler", ok: true, detail: compiler });
|
|
57138
57415
|
const installDir = publicHelperInstallDir(deps.env);
|
|
57139
57416
|
mkdirSync8(installDir, { recursive: true, mode: 448 });
|
|
57140
|
-
const staging =
|
|
57417
|
+
const staging = mkdtempSync7(join27(installDir, ".staging-"));
|
|
57141
57418
|
try {
|
|
57142
|
-
const stagedBinary =
|
|
57143
|
-
const digestPath =
|
|
57144
|
-
const plistPath =
|
|
57145
|
-
|
|
57146
|
-
|
|
57419
|
+
const stagedBinary = join27(staging, PUBLIC_HELPER_BINARY);
|
|
57420
|
+
const digestPath = join27(staging, "source-digest.swift");
|
|
57421
|
+
const plistPath = join27(staging, "Info.plist");
|
|
57422
|
+
writeFileSync6(digestPath, sourceDigestSwift(sourceSha), { mode: 384 });
|
|
57423
|
+
writeFileSync6(plistPath, publicHelperInfoPlist(), { mode: 384 });
|
|
57147
57424
|
const compile = deps.spawn(
|
|
57148
57425
|
"/usr/bin/xcrun",
|
|
57149
57426
|
publicHelperCompileArguments(deps.sourcePath, digestPath, plistPath, stagedBinary),
|
|
@@ -57204,15 +57481,15 @@ function buildPublicHelper(checkOnly, deps = defaultPublicHelperBuildDeps()) {
|
|
|
57204
57481
|
compiler
|
|
57205
57482
|
};
|
|
57206
57483
|
chmodSync(stagedBinary, 448);
|
|
57207
|
-
renameSync2(stagedBinary,
|
|
57208
|
-
|
|
57209
|
-
|
|
57484
|
+
renameSync2(stagedBinary, join27(installDir, PUBLIC_HELPER_BINARY));
|
|
57485
|
+
writeFileSync6(
|
|
57486
|
+
join27(installDir, PUBLIC_HELPER_MANIFEST),
|
|
57210
57487
|
JSON.stringify(manifest, null, 2) + "\n",
|
|
57211
57488
|
{ mode: 384 }
|
|
57212
57489
|
);
|
|
57213
57490
|
steps.push({ step: "install", ok: true, detail: installDir });
|
|
57214
57491
|
} finally {
|
|
57215
|
-
|
|
57492
|
+
rmSync7(staging, { recursive: true, force: true });
|
|
57216
57493
|
}
|
|
57217
57494
|
const installation = inspectPublicHelper(deps);
|
|
57218
57495
|
steps.push({
|
|
@@ -57450,8 +57727,8 @@ function formatNoteDrawings(result) {
|
|
|
57450
57727
|
}
|
|
57451
57728
|
|
|
57452
57729
|
// src/utils/noteAudio.ts
|
|
57453
|
-
import { readdirSync as readdirSync5, statSync as
|
|
57454
|
-
import { join as
|
|
57730
|
+
import { readdirSync as readdirSync5, statSync as statSync5 } from "node:fs";
|
|
57731
|
+
import { join as join28 } from "node:path";
|
|
57455
57732
|
var EXTRA_AUDIO_UTIS = [
|
|
57456
57733
|
"public.mp3",
|
|
57457
57734
|
"public.aiff-audio",
|
|
@@ -57476,7 +57753,7 @@ function accountDirsFor(containerDir, accountIdentifier) {
|
|
|
57476
57753
|
if (own) return [own];
|
|
57477
57754
|
let names;
|
|
57478
57755
|
try {
|
|
57479
|
-
names = readdirSync5(
|
|
57756
|
+
names = readdirSync5(join28(containerDir, "Accounts")).sort();
|
|
57480
57757
|
} catch {
|
|
57481
57758
|
return [];
|
|
57482
57759
|
}
|
|
@@ -57488,8 +57765,8 @@ function resolveMediaPath(media, accountIdentifier = null, containerDir = NOTES_
|
|
|
57488
57765
|
if (!id2 || !filename) return null;
|
|
57489
57766
|
const generation = safeComponent(media?.generation);
|
|
57490
57767
|
for (const dir of accountDirsFor(containerDir, accountIdentifier)) {
|
|
57491
|
-
const base =
|
|
57492
|
-
const candidates = generation ? [
|
|
57768
|
+
const base = join28(dir, "Media", id2);
|
|
57769
|
+
const candidates = generation ? [join28(base, generation, filename), join28(base, filename)] : [join28(base, filename)];
|
|
57493
57770
|
for (const candidate of candidates) {
|
|
57494
57771
|
const real = realInside(candidate, dir);
|
|
57495
57772
|
if (real && isFile2(real)) return real;
|
|
@@ -57499,7 +57776,7 @@ function resolveMediaPath(media, accountIdentifier = null, containerDir = NOTES_
|
|
|
57499
57776
|
}
|
|
57500
57777
|
function isFile2(path10) {
|
|
57501
57778
|
try {
|
|
57502
|
-
return
|
|
57779
|
+
return statSync5(path10).isFile();
|
|
57503
57780
|
} catch {
|
|
57504
57781
|
return false;
|
|
57505
57782
|
}
|
|
@@ -57762,20 +58039,20 @@ import {
|
|
|
57762
58039
|
chmodSync as chmodSync2,
|
|
57763
58040
|
existsSync as existsSync16,
|
|
57764
58041
|
mkdirSync as mkdirSync9,
|
|
57765
|
-
mkdtempSync as
|
|
58042
|
+
mkdtempSync as mkdtempSync8,
|
|
57766
58043
|
renameSync as renameSync3,
|
|
57767
|
-
rmSync as
|
|
57768
|
-
writeFileSync as
|
|
58044
|
+
rmSync as rmSync8,
|
|
58045
|
+
writeFileSync as writeFileSync7
|
|
57769
58046
|
} from "node:fs";
|
|
57770
58047
|
import { release as release4 } from "node:os";
|
|
57771
|
-
import { join as
|
|
58048
|
+
import { join as join30 } from "node:path";
|
|
57772
58049
|
|
|
57773
58050
|
// src/services/privateHelper.ts
|
|
57774
58051
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
57775
58052
|
import { createHash as createHash7 } from "node:crypto";
|
|
57776
|
-
import { existsSync as existsSync15, readFileSync as
|
|
58053
|
+
import { existsSync as existsSync15, readFileSync as readFileSync6 } from "node:fs";
|
|
57777
58054
|
import { homedir as homedir21 } from "node:os";
|
|
57778
|
-
import { dirname as dirname9, join as
|
|
58055
|
+
import { dirname as dirname9, join as join29, resolve as resolve8 } from "node:path";
|
|
57779
58056
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
57780
58057
|
var PRIVATE_HELPER_PROTOCOL = 1;
|
|
57781
58058
|
var ENABLE_ENV = "APPLE_NOTES_MCP_ENABLE_PRIVATE";
|
|
@@ -57803,10 +58080,10 @@ var manifestSchema = external_exports.object({
|
|
|
57803
58080
|
function packageRoot2(fromDir = dirname9(fileURLToPath3(import.meta.url))) {
|
|
57804
58081
|
let dir = fromDir;
|
|
57805
58082
|
for (; ; ) {
|
|
57806
|
-
const candidate =
|
|
58083
|
+
const candidate = join29(dir, "package.json");
|
|
57807
58084
|
if (existsSync15(candidate)) {
|
|
57808
58085
|
try {
|
|
57809
|
-
const pkg = JSON.parse(
|
|
58086
|
+
const pkg = JSON.parse(readFileSync6(candidate, "utf8"));
|
|
57810
58087
|
if (pkg.name === "apple-notes-mcp") return dir;
|
|
57811
58088
|
} catch {
|
|
57812
58089
|
}
|
|
@@ -57820,9 +58097,9 @@ function defaultDeps2(overrides = {}) {
|
|
|
57820
58097
|
return {
|
|
57821
58098
|
env: process.env,
|
|
57822
58099
|
platform: process.platform,
|
|
57823
|
-
sourcePath:
|
|
58100
|
+
sourcePath: join29(packageRoot2(), HELPER_SOURCE_RELATIVE),
|
|
57824
58101
|
exists: existsSync15,
|
|
57825
|
-
readFile: (path10) =>
|
|
58102
|
+
readFile: (path10) => readFileSync6(path10),
|
|
57826
58103
|
spawn: spawnSync4,
|
|
57827
58104
|
...overrides
|
|
57828
58105
|
};
|
|
@@ -57833,14 +58110,14 @@ function privateHelperEnabled(env = process.env) {
|
|
|
57833
58110
|
function helperInstallDir(env = process.env) {
|
|
57834
58111
|
const override = env[HELPER_DIR_ENV]?.trim();
|
|
57835
58112
|
if (override) return override;
|
|
57836
|
-
return
|
|
58113
|
+
return join29(homedir21(), "Library", "Application Support", "apple-notes-mcp", "private-helper");
|
|
57837
58114
|
}
|
|
57838
58115
|
function sha256Hex2(data) {
|
|
57839
58116
|
return createHash7("sha256").update(data).digest("hex");
|
|
57840
58117
|
}
|
|
57841
58118
|
function inspectInstallation(deps = defaultDeps2()) {
|
|
57842
58119
|
const installDir = helperInstallDir(deps.env);
|
|
57843
|
-
const binaryPath =
|
|
58120
|
+
const binaryPath = join29(installDir, HELPER_BINARY_NAME);
|
|
57844
58121
|
const base = {
|
|
57845
58122
|
installDir,
|
|
57846
58123
|
binaryPath,
|
|
@@ -57858,7 +58135,7 @@ function inspectInstallation(deps = defaultDeps2()) {
|
|
|
57858
58135
|
if (!deps.exists(deps.sourcePath))
|
|
57859
58136
|
return fail("helper_not_installed", `Packaged helper source is missing: ${deps.sourcePath}`);
|
|
57860
58137
|
base.expectedSourceSha256 = sha256Hex2(deps.readFile(deps.sourcePath));
|
|
57861
|
-
const manifestPath =
|
|
58138
|
+
const manifestPath = join29(installDir, MANIFEST_NAME);
|
|
57862
58139
|
if (!deps.exists(binaryPath) || !deps.exists(manifestPath))
|
|
57863
58140
|
return fail(
|
|
57864
58141
|
"helper_not_installed",
|
|
@@ -58173,9 +58450,9 @@ function buildPrivateHelper(checkOnly, deps = defaultBuildDeps()) {
|
|
|
58173
58450
|
steps.push({ step: "find compiler", ok: true, detail: compiler });
|
|
58174
58451
|
const installDir = helperInstallDir(deps.env);
|
|
58175
58452
|
mkdirSync9(installDir, { recursive: true, mode: 448 });
|
|
58176
|
-
const staging =
|
|
58453
|
+
const staging = mkdtempSync8(join30(installDir, ".staging-"));
|
|
58177
58454
|
try {
|
|
58178
|
-
const stagedBinary =
|
|
58455
|
+
const stagedBinary = join30(staging, HELPER_BINARY_NAME);
|
|
58179
58456
|
const compile = deps.spawn(
|
|
58180
58457
|
"/usr/bin/xcrun",
|
|
58181
58458
|
compileArguments(deps.sourcePath, stagedBinary, sourceSha),
|
|
@@ -58252,13 +58529,13 @@ function buildPrivateHelper(checkOnly, deps = defaultBuildDeps()) {
|
|
|
58252
58529
|
compiler
|
|
58253
58530
|
};
|
|
58254
58531
|
chmodSync2(stagedBinary, 448);
|
|
58255
|
-
renameSync3(stagedBinary,
|
|
58256
|
-
|
|
58532
|
+
renameSync3(stagedBinary, join30(installDir, HELPER_BINARY_NAME));
|
|
58533
|
+
writeFileSync7(join30(installDir, MANIFEST_NAME), JSON.stringify(manifest, null, 2) + "\n", {
|
|
58257
58534
|
mode: 384
|
|
58258
58535
|
});
|
|
58259
58536
|
steps.push({ step: "install", ok: true, detail: installDir });
|
|
58260
58537
|
} finally {
|
|
58261
|
-
if (existsSync16(staging))
|
|
58538
|
+
if (existsSync16(staging)) rmSync8(staging, { recursive: true, force: true });
|
|
58262
58539
|
}
|
|
58263
58540
|
const installation = inspectInstallation(deps);
|
|
58264
58541
|
steps.push({
|
package/package.json
CHANGED