apple-numbers-mcp 1.2.0 → 1.2.2
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/build/index.js +427 -153
- package/docs/NODE-RUNTIME-AND-TCC-PERMISSIONS.md +32 -8
- package/package.json +1 -1
package/build/index.js
CHANGED
|
@@ -3104,15 +3104,33 @@ var require_data = __commonJS({
|
|
|
3104
3104
|
}
|
|
3105
3105
|
});
|
|
3106
3106
|
|
|
3107
|
-
// node_modules/.pnpm/fast-uri@3.1.
|
|
3107
|
+
// node_modules/.pnpm/fast-uri@3.1.6/node_modules/fast-uri/lib/utils.js
|
|
3108
3108
|
var require_utils = __commonJS({
|
|
3109
|
-
"node_modules/.pnpm/fast-uri@3.1.
|
|
3109
|
+
"node_modules/.pnpm/fast-uri@3.1.6/node_modules/fast-uri/lib/utils.js"(exports, module) {
|
|
3110
3110
|
"use strict";
|
|
3111
3111
|
var isUUID = RegExp.prototype.test.bind(/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu);
|
|
3112
3112
|
var isIPv4 = RegExp.prototype.test.bind(/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u);
|
|
3113
3113
|
var isHexPair = RegExp.prototype.test.bind(/^[\da-f]{2}$/iu);
|
|
3114
3114
|
var isUnreserved = RegExp.prototype.test.bind(/^[\da-z\-._~]$/iu);
|
|
3115
|
-
var isPathCharacter = RegExp.prototype.test.bind(/^[
|
|
3115
|
+
var isPathCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:@/]$/u);
|
|
3116
|
+
var isQueryFragmentCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:@/?]$/u);
|
|
3117
|
+
var isUserinfoCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:]$/u);
|
|
3118
|
+
var BYTE_HEX = new Array(256);
|
|
3119
|
+
{
|
|
3120
|
+
const HEX_DIGITS = "0123456789ABCDEF";
|
|
3121
|
+
for (let i = 0; i < 256; i++) {
|
|
3122
|
+
BYTE_HEX[i] = "%" + HEX_DIGITS[i >> 4] + HEX_DIGITS[i & 15];
|
|
3123
|
+
}
|
|
3124
|
+
}
|
|
3125
|
+
function percentEncodeNonAscii(cp) {
|
|
3126
|
+
if (cp < 2048) {
|
|
3127
|
+
return BYTE_HEX[192 | cp >> 6] + BYTE_HEX[128 | cp & 63];
|
|
3128
|
+
}
|
|
3129
|
+
if (cp < 65536) {
|
|
3130
|
+
return BYTE_HEX[224 | cp >> 12] + BYTE_HEX[128 | cp >> 6 & 63] + BYTE_HEX[128 | cp & 63];
|
|
3131
|
+
}
|
|
3132
|
+
return BYTE_HEX[240 | cp >> 18] + BYTE_HEX[128 | cp >> 12 & 63] + BYTE_HEX[128 | cp >> 6 & 63] + BYTE_HEX[128 | cp & 63];
|
|
3133
|
+
}
|
|
3116
3134
|
function stringArrayToHexStripped(input) {
|
|
3117
3135
|
let acc = "";
|
|
3118
3136
|
let code = 0;
|
|
@@ -3137,91 +3155,105 @@ var require_utils = __commonJS({
|
|
|
3137
3155
|
}
|
|
3138
3156
|
return acc;
|
|
3139
3157
|
}
|
|
3158
|
+
var isHextet = RegExp.prototype.test.bind(/^[\dA-Fa-f]{1,4}$/);
|
|
3159
|
+
var isIPvFuture = RegExp.prototype.test.bind(/^[vV][\dA-Fa-f]+\.[A-Za-z\d\-._~!$&'()*+,;=:]+$/);
|
|
3160
|
+
var isZoneCharacter = RegExp.prototype.test.bind(/^[A-Za-z\d\-._~]$/);
|
|
3140
3161
|
var nonSimpleDomain = RegExp.prototype.test.bind(/[^!"$&'()*+,\-.;=_`a-z{}~]/u);
|
|
3141
|
-
function
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
if (hex !== "") {
|
|
3149
|
-
address.push(hex);
|
|
3150
|
-
} else {
|
|
3151
|
-
output.error = true;
|
|
3152
|
-
return false;
|
|
3162
|
+
function isZoneIdentifier(zone) {
|
|
3163
|
+
if (zone.length === 0) return false;
|
|
3164
|
+
for (let i = 0; i < zone.length; i++) {
|
|
3165
|
+
if (isZoneCharacter(zone[i])) continue;
|
|
3166
|
+
if (zone[i] === "%" && i + 2 < zone.length && isHexPair(zone.slice(i + 1, i + 3))) {
|
|
3167
|
+
i += 2;
|
|
3168
|
+
continue;
|
|
3153
3169
|
}
|
|
3154
|
-
|
|
3170
|
+
return false;
|
|
3155
3171
|
}
|
|
3156
3172
|
return true;
|
|
3157
3173
|
}
|
|
3158
|
-
function
|
|
3159
|
-
let
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
let
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
}
|
|
3171
|
-
if (cursor === ":") {
|
|
3172
|
-
if (endipv6Encountered === true) {
|
|
3173
|
-
endIpv6 = true;
|
|
3174
|
-
}
|
|
3175
|
-
if (!consume(buffer, address, output)) {
|
|
3176
|
-
break;
|
|
3177
|
-
}
|
|
3178
|
-
if (++tokenCount > 7) {
|
|
3179
|
-
output.error = true;
|
|
3180
|
-
break;
|
|
3181
|
-
}
|
|
3182
|
-
if (i > 0 && input[i - 1] === ":") {
|
|
3183
|
-
endipv6Encountered = true;
|
|
3184
|
-
}
|
|
3185
|
-
address.push(":");
|
|
3186
|
-
continue;
|
|
3187
|
-
} else if (cursor === "%") {
|
|
3188
|
-
if (!consume(buffer, address, output)) {
|
|
3189
|
-
break;
|
|
3174
|
+
function compressIPv6ZeroRun(hextets) {
|
|
3175
|
+
let bestStart = -1;
|
|
3176
|
+
let bestLength = 0;
|
|
3177
|
+
let runStart = -1;
|
|
3178
|
+
let runLength = 0;
|
|
3179
|
+
for (let i = 0; i < hextets.length; i++) {
|
|
3180
|
+
if (hextets[i] === "0") {
|
|
3181
|
+
if (runStart === -1) runStart = i;
|
|
3182
|
+
runLength++;
|
|
3183
|
+
if (runLength > bestLength) {
|
|
3184
|
+
bestLength = runLength;
|
|
3185
|
+
bestStart = runStart;
|
|
3190
3186
|
}
|
|
3191
|
-
consume = consumeIsZone;
|
|
3192
3187
|
} else {
|
|
3193
|
-
|
|
3188
|
+
runStart = -1;
|
|
3189
|
+
runLength = 0;
|
|
3190
|
+
}
|
|
3191
|
+
}
|
|
3192
|
+
if (bestLength < 2) return hextets.join(":");
|
|
3193
|
+
const head = hextets.slice(0, bestStart).join(":");
|
|
3194
|
+
const tail = hextets.slice(bestStart + bestLength).join(":");
|
|
3195
|
+
return head + "::" + tail;
|
|
3196
|
+
}
|
|
3197
|
+
function normalizeIPv6Address(input) {
|
|
3198
|
+
const compression = input.indexOf("::");
|
|
3199
|
+
if (compression !== -1 && input.indexOf("::", compression + 1) !== -1) return void 0;
|
|
3200
|
+
const left = compression === -1 ? input.split(":") : input.slice(0, compression).split(":");
|
|
3201
|
+
const right = compression === -1 ? [] : input.slice(compression + 2).split(":");
|
|
3202
|
+
if (compression !== -1) {
|
|
3203
|
+
if (left.length === 1 && left[0] === "") left.length = 0;
|
|
3204
|
+
if (right.length === 1 && right[0] === "") right.length = 0;
|
|
3205
|
+
}
|
|
3206
|
+
const parts = left.concat(right);
|
|
3207
|
+
let hextetCount = 0;
|
|
3208
|
+
for (let i = 0; i < parts.length; i++) {
|
|
3209
|
+
const part = parts[i];
|
|
3210
|
+
if (part === "") return void 0;
|
|
3211
|
+
if (part.indexOf(".") !== -1) {
|
|
3212
|
+
if (i !== parts.length - 1 || compression !== -1 && right.length === 0 || !isIPv4(part)) return void 0;
|
|
3213
|
+
hextetCount += 2;
|
|
3194
3214
|
continue;
|
|
3195
3215
|
}
|
|
3216
|
+
if (!isHextet(part)) return void 0;
|
|
3217
|
+
parts[i] = parseInt(part, 16).toString(16);
|
|
3218
|
+
hextetCount++;
|
|
3196
3219
|
}
|
|
3197
|
-
if (
|
|
3198
|
-
if (
|
|
3199
|
-
|
|
3200
|
-
} else if (endIpv6) {
|
|
3201
|
-
address.push(buffer.join(""));
|
|
3202
|
-
} else {
|
|
3203
|
-
address.push(stringArrayToHexStripped(buffer));
|
|
3204
|
-
}
|
|
3220
|
+
if (compression === -1) {
|
|
3221
|
+
if (hextetCount !== 8) return void 0;
|
|
3222
|
+
return compressIPv6ZeroRun(parts);
|
|
3205
3223
|
}
|
|
3206
|
-
|
|
3207
|
-
|
|
3224
|
+
if (hextetCount >= 8) return void 0;
|
|
3225
|
+
const expanded = parts.slice(0, left.length);
|
|
3226
|
+
for (let i = hextetCount; i < 8; i++) expanded.push("0");
|
|
3227
|
+
for (let i = left.length; i < parts.length; i++) expanded.push(parts[i]);
|
|
3228
|
+
return compressIPv6ZeroRun(expanded);
|
|
3208
3229
|
}
|
|
3209
3230
|
function normalizeIPv6(host) {
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
}
|
|
3213
|
-
|
|
3214
|
-
if (
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3231
|
+
const bracketed = host[0] === "[" && host[host.length - 1] === "]";
|
|
3232
|
+
const hasBracket = host[0] === "[" || host[host.length - 1] === "]";
|
|
3233
|
+
if (hasBracket && !bracketed) return { host, isIPV6: false, error: true };
|
|
3234
|
+
let input = bracketed ? host.slice(1, -1) : host;
|
|
3235
|
+
if (bracketed && isIPvFuture(input)) {
|
|
3236
|
+
input = input.toLowerCase();
|
|
3237
|
+
return { host: `[${input}]`, escapedHost: input, isIPV6: false, isIPVFuture: true };
|
|
3238
|
+
}
|
|
3239
|
+
if (findToken(input, ":") < 2) {
|
|
3240
|
+
return { host, isIPV6: false, error: bracketed };
|
|
3241
|
+
}
|
|
3242
|
+
let zoneIdentifier = "";
|
|
3243
|
+
const zoneSeparator = input.indexOf("%");
|
|
3244
|
+
if (zoneSeparator !== -1) {
|
|
3245
|
+
const separatorLength = input.slice(zoneSeparator, zoneSeparator + 3).toLowerCase() === "%25" ? 3 : 1;
|
|
3246
|
+
zoneIdentifier = input.slice(zoneSeparator + separatorLength);
|
|
3247
|
+
if (!isZoneIdentifier(zoneIdentifier)) return { host, isIPV6: false, error: true };
|
|
3248
|
+
input = input.slice(0, zoneSeparator);
|
|
3249
|
+
}
|
|
3250
|
+
const address = normalizeIPv6Address(input);
|
|
3251
|
+
if (address === void 0) return { host, isIPV6: false, error: true };
|
|
3252
|
+
return {
|
|
3253
|
+
host: address + (zoneIdentifier ? "%" + zoneIdentifier : ""),
|
|
3254
|
+
escapedHost: address + (zoneIdentifier ? "%25" + zoneIdentifier : ""),
|
|
3255
|
+
isIPV6: true
|
|
3256
|
+
};
|
|
3225
3257
|
}
|
|
3226
3258
|
function findToken(str, token) {
|
|
3227
3259
|
let ind = 0;
|
|
@@ -3340,7 +3372,8 @@ var require_utils = __commonJS({
|
|
|
3340
3372
|
function normalizePathEncoding(input) {
|
|
3341
3373
|
let output = "";
|
|
3342
3374
|
for (let i = 0; i < input.length; i++) {
|
|
3343
|
-
|
|
3375
|
+
const ch = input[i];
|
|
3376
|
+
if (ch === "%" && i + 2 < input.length) {
|
|
3344
3377
|
const hex = input.slice(i + 1, i + 3);
|
|
3345
3378
|
if (isHexPair(hex)) {
|
|
3346
3379
|
const normalizedHex = hex.toUpperCase();
|
|
@@ -3354,10 +3387,152 @@ var require_utils = __commonJS({
|
|
|
3354
3387
|
continue;
|
|
3355
3388
|
}
|
|
3356
3389
|
}
|
|
3357
|
-
if (isPathCharacter(
|
|
3358
|
-
output +=
|
|
3390
|
+
if (isPathCharacter(ch)) {
|
|
3391
|
+
output += ch;
|
|
3359
3392
|
} else {
|
|
3360
|
-
|
|
3393
|
+
const code = input.charCodeAt(i);
|
|
3394
|
+
if (code < 128) {
|
|
3395
|
+
output += isEscapeSafe(code) ? ch : BYTE_HEX[code];
|
|
3396
|
+
} else if (code < 55296 || code > 57343) {
|
|
3397
|
+
output += percentEncodeNonAscii(code);
|
|
3398
|
+
} else if (code <= 56319 && i + 1 < input.length) {
|
|
3399
|
+
const low = input.charCodeAt(i + 1);
|
|
3400
|
+
if (low >= 56320 && low <= 57343) {
|
|
3401
|
+
output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
|
|
3402
|
+
i++;
|
|
3403
|
+
} else {
|
|
3404
|
+
output += percentEncodeNonAscii(65533);
|
|
3405
|
+
}
|
|
3406
|
+
} else {
|
|
3407
|
+
output += percentEncodeNonAscii(65533);
|
|
3408
|
+
}
|
|
3409
|
+
}
|
|
3410
|
+
}
|
|
3411
|
+
return output;
|
|
3412
|
+
}
|
|
3413
|
+
function serializePathEncoding(input, pathNoScheme = false) {
|
|
3414
|
+
let output = "";
|
|
3415
|
+
let firstSegment = pathNoScheme && input[0] !== "/";
|
|
3416
|
+
for (let i = 0; i < input.length; i++) {
|
|
3417
|
+
const ch = input[i];
|
|
3418
|
+
if (ch === "%" && i + 2 < input.length) {
|
|
3419
|
+
const hex = input.slice(i + 1, i + 3);
|
|
3420
|
+
if (isHexPair(hex)) {
|
|
3421
|
+
output += "%" + hex.toUpperCase();
|
|
3422
|
+
i += 2;
|
|
3423
|
+
continue;
|
|
3424
|
+
}
|
|
3425
|
+
}
|
|
3426
|
+
if (ch === "/") {
|
|
3427
|
+
firstSegment = false;
|
|
3428
|
+
}
|
|
3429
|
+
if (isPathCharacter(ch) && (ch !== ":" || !firstSegment)) {
|
|
3430
|
+
output += ch;
|
|
3431
|
+
} else {
|
|
3432
|
+
const code = input.charCodeAt(i);
|
|
3433
|
+
if (code < 128) {
|
|
3434
|
+
output += BYTE_HEX[code];
|
|
3435
|
+
} else if (code < 55296 || code > 57343) {
|
|
3436
|
+
output += percentEncodeNonAscii(code);
|
|
3437
|
+
} else if (code <= 56319 && i + 1 < input.length) {
|
|
3438
|
+
const low = input.charCodeAt(i + 1);
|
|
3439
|
+
if (low >= 56320 && low <= 57343) {
|
|
3440
|
+
output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
|
|
3441
|
+
i++;
|
|
3442
|
+
} else {
|
|
3443
|
+
output += percentEncodeNonAscii(65533);
|
|
3444
|
+
}
|
|
3445
|
+
} else {
|
|
3446
|
+
output += percentEncodeNonAscii(65533);
|
|
3447
|
+
}
|
|
3448
|
+
}
|
|
3449
|
+
}
|
|
3450
|
+
return output;
|
|
3451
|
+
}
|
|
3452
|
+
function encodeComponent(input, isAllowed) {
|
|
3453
|
+
let output = "";
|
|
3454
|
+
for (let i = 0; i < input.length; i++) {
|
|
3455
|
+
const ch = input[i];
|
|
3456
|
+
if (ch === "%" && i + 2 < input.length) {
|
|
3457
|
+
const hex = input.slice(i + 1, i + 3);
|
|
3458
|
+
if (isHexPair(hex)) {
|
|
3459
|
+
output += "%" + hex.toUpperCase();
|
|
3460
|
+
i += 2;
|
|
3461
|
+
continue;
|
|
3462
|
+
}
|
|
3463
|
+
}
|
|
3464
|
+
if (isAllowed(ch)) {
|
|
3465
|
+
output += ch;
|
|
3466
|
+
} else {
|
|
3467
|
+
const code = input.charCodeAt(i);
|
|
3468
|
+
if (code < 128) {
|
|
3469
|
+
output += BYTE_HEX[code];
|
|
3470
|
+
} else if (code < 55296 || code > 57343) {
|
|
3471
|
+
output += percentEncodeNonAscii(code);
|
|
3472
|
+
} else if (code <= 56319 && i + 1 < input.length) {
|
|
3473
|
+
const low = input.charCodeAt(i + 1);
|
|
3474
|
+
if (low >= 56320 && low <= 57343) {
|
|
3475
|
+
output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
|
|
3476
|
+
i++;
|
|
3477
|
+
} else {
|
|
3478
|
+
output += percentEncodeNonAscii(65533);
|
|
3479
|
+
}
|
|
3480
|
+
} else {
|
|
3481
|
+
output += percentEncodeNonAscii(65533);
|
|
3482
|
+
}
|
|
3483
|
+
}
|
|
3484
|
+
}
|
|
3485
|
+
return output;
|
|
3486
|
+
}
|
|
3487
|
+
function encodeUserinfo(input) {
|
|
3488
|
+
return encodeComponent(input, isUserinfoCharacter);
|
|
3489
|
+
}
|
|
3490
|
+
function encodeQuery(input) {
|
|
3491
|
+
return encodeComponent(input, isQueryFragmentCharacter);
|
|
3492
|
+
}
|
|
3493
|
+
function encodeFragment(input) {
|
|
3494
|
+
return encodeComponent(input, isQueryFragmentCharacter);
|
|
3495
|
+
}
|
|
3496
|
+
function isEscapeSafe(cp) {
|
|
3497
|
+
return cp >= 48 && cp <= 57 || cp >= 65 && cp <= 90 || cp >= 97 && cp <= 122 || cp === 42 || cp === 43 || cp === 45 || cp === 46 || cp === 47 || cp === 64 || cp === 95;
|
|
3498
|
+
}
|
|
3499
|
+
function normalizeQueryFragmentEncoding(input) {
|
|
3500
|
+
let output = "";
|
|
3501
|
+
for (let i = 0; i < input.length; i++) {
|
|
3502
|
+
const ch = input[i];
|
|
3503
|
+
if (ch === "%" && i + 2 < input.length) {
|
|
3504
|
+
const hex = input.slice(i + 1, i + 3);
|
|
3505
|
+
if (isHexPair(hex)) {
|
|
3506
|
+
const normalizedHex = hex.toUpperCase();
|
|
3507
|
+
const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
|
|
3508
|
+
if (isUnreserved(decoded)) {
|
|
3509
|
+
output += decoded;
|
|
3510
|
+
} else {
|
|
3511
|
+
output += "%" + normalizedHex;
|
|
3512
|
+
}
|
|
3513
|
+
i += 2;
|
|
3514
|
+
continue;
|
|
3515
|
+
}
|
|
3516
|
+
}
|
|
3517
|
+
if (isQueryFragmentCharacter(ch)) {
|
|
3518
|
+
output += ch;
|
|
3519
|
+
} else {
|
|
3520
|
+
const code = input.charCodeAt(i);
|
|
3521
|
+
if (code < 128) {
|
|
3522
|
+
output += isEscapeSafe(code) ? ch : BYTE_HEX[code];
|
|
3523
|
+
} else if (code < 55296 || code > 57343) {
|
|
3524
|
+
output += percentEncodeNonAscii(code);
|
|
3525
|
+
} else if (code <= 56319 && i + 1 < input.length) {
|
|
3526
|
+
const low = input.charCodeAt(i + 1);
|
|
3527
|
+
if (low >= 56320 && low <= 57343) {
|
|
3528
|
+
output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
|
|
3529
|
+
i++;
|
|
3530
|
+
} else {
|
|
3531
|
+
output += percentEncodeNonAscii(65533);
|
|
3532
|
+
}
|
|
3533
|
+
} else {
|
|
3534
|
+
output += percentEncodeNonAscii(65533);
|
|
3535
|
+
}
|
|
3361
3536
|
}
|
|
3362
3537
|
}
|
|
3363
3538
|
return output;
|
|
@@ -3380,14 +3555,18 @@ var require_utils = __commonJS({
|
|
|
3380
3555
|
function recomposeAuthority(component) {
|
|
3381
3556
|
const uriTokens = [];
|
|
3382
3557
|
if (component.userinfo !== void 0) {
|
|
3383
|
-
uriTokens.push(component.userinfo);
|
|
3558
|
+
uriTokens.push(encodeUserinfo(component.userinfo));
|
|
3384
3559
|
uriTokens.push("@");
|
|
3385
3560
|
}
|
|
3386
3561
|
if (component.host !== void 0) {
|
|
3387
|
-
let host =
|
|
3562
|
+
let host = component.host;
|
|
3388
3563
|
if (!isIPv4(host)) {
|
|
3389
|
-
|
|
3390
|
-
if (ipV6res.isIPV6
|
|
3564
|
+
let ipV6res = normalizeIPv6(host);
|
|
3565
|
+
if (ipV6res.isIPV6 !== true && ipV6res.isIPVFuture !== true) {
|
|
3566
|
+
host = normalizePercentEncoding(host, true);
|
|
3567
|
+
ipV6res = normalizeIPv6(host);
|
|
3568
|
+
}
|
|
3569
|
+
if (ipV6res.isIPV6 === true || ipV6res.isIPVFuture === true) {
|
|
3391
3570
|
host = `[${ipV6res.escapedHost}]`;
|
|
3392
3571
|
} else {
|
|
3393
3572
|
host = reescapeHostDelimiters(host, false);
|
|
@@ -3407,6 +3586,11 @@ var require_utils = __commonJS({
|
|
|
3407
3586
|
reescapeHostDelimiters,
|
|
3408
3587
|
normalizePercentEncoding,
|
|
3409
3588
|
normalizePathEncoding,
|
|
3589
|
+
serializePathEncoding,
|
|
3590
|
+
normalizeQueryFragmentEncoding,
|
|
3591
|
+
encodeUserinfo,
|
|
3592
|
+
encodeQuery,
|
|
3593
|
+
encodeFragment,
|
|
3410
3594
|
escapePreservingEscapes,
|
|
3411
3595
|
removeDotSegments,
|
|
3412
3596
|
isIPv4,
|
|
@@ -3417,12 +3601,12 @@ var require_utils = __commonJS({
|
|
|
3417
3601
|
}
|
|
3418
3602
|
});
|
|
3419
3603
|
|
|
3420
|
-
// node_modules/.pnpm/fast-uri@3.1.
|
|
3604
|
+
// node_modules/.pnpm/fast-uri@3.1.6/node_modules/fast-uri/lib/schemes.js
|
|
3421
3605
|
var require_schemes = __commonJS({
|
|
3422
|
-
"node_modules/.pnpm/fast-uri@3.1.
|
|
3606
|
+
"node_modules/.pnpm/fast-uri@3.1.6/node_modules/fast-uri/lib/schemes.js"(exports, module) {
|
|
3423
3607
|
"use strict";
|
|
3424
3608
|
var { isUUID } = require_utils();
|
|
3425
|
-
var URN_REG =
|
|
3609
|
+
var URN_REG = /^([\da-z][\d\-a-z]{0,31}):((?:[\w!$'()*+,\-./:;=@]|%[\da-f]{2})+)$/iu;
|
|
3426
3610
|
var supportedSchemeNames = (
|
|
3427
3611
|
/** @type {const} */
|
|
3428
3612
|
[
|
|
@@ -3483,9 +3667,10 @@ var require_schemes = __commonJS({
|
|
|
3483
3667
|
wsComponent.secure = void 0;
|
|
3484
3668
|
}
|
|
3485
3669
|
if (wsComponent.resourceName) {
|
|
3486
|
-
const
|
|
3670
|
+
const queryIndex = wsComponent.resourceName.indexOf("?");
|
|
3671
|
+
const path = queryIndex === -1 ? wsComponent.resourceName : wsComponent.resourceName.slice(0, queryIndex);
|
|
3487
3672
|
wsComponent.path = path && path !== "/" ? path : void 0;
|
|
3488
|
-
wsComponent.query =
|
|
3673
|
+
wsComponent.query = queryIndex === -1 ? void 0 : wsComponent.resourceName.slice(queryIndex + 1);
|
|
3489
3674
|
wsComponent.resourceName = void 0;
|
|
3490
3675
|
}
|
|
3491
3676
|
wsComponent.fragment = void 0;
|
|
@@ -3497,7 +3682,7 @@ var require_schemes = __commonJS({
|
|
|
3497
3682
|
return urnComponent;
|
|
3498
3683
|
}
|
|
3499
3684
|
const matches = urnComponent.path.match(URN_REG);
|
|
3500
|
-
if (matches) {
|
|
3685
|
+
if (matches && matches[0] === urnComponent.path) {
|
|
3501
3686
|
const scheme = options.scheme || urnComponent.scheme || "urn";
|
|
3502
3687
|
urnComponent.nid = matches[1].toLowerCase();
|
|
3503
3688
|
urnComponent.nss = matches[2];
|
|
@@ -3627,12 +3812,21 @@ var require_schemes = __commonJS({
|
|
|
3627
3812
|
}
|
|
3628
3813
|
});
|
|
3629
3814
|
|
|
3630
|
-
// node_modules/.pnpm/fast-uri@3.1.
|
|
3815
|
+
// node_modules/.pnpm/fast-uri@3.1.6/node_modules/fast-uri/index.js
|
|
3631
3816
|
var require_fast_uri = __commonJS({
|
|
3632
|
-
"node_modules/.pnpm/fast-uri@3.1.
|
|
3817
|
+
"node_modules/.pnpm/fast-uri@3.1.6/node_modules/fast-uri/index.js"(exports, module) {
|
|
3633
3818
|
"use strict";
|
|
3634
|
-
var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding,
|
|
3819
|
+
var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, serializePathEncoding, normalizeQueryFragmentEncoding, encodeQuery, encodeFragment, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils();
|
|
3635
3820
|
var { SCHEMES, getSchemeHandler } = require_schemes();
|
|
3821
|
+
var VALID_SCHEME = /^[A-Za-z][A-Za-z0-9+.-]*$/u;
|
|
3822
|
+
var MALFORMED_SCHEME_ERROR = "URI scheme is malformed.";
|
|
3823
|
+
function decodeValidScheme(scheme) {
|
|
3824
|
+
const decodedScheme = unescape(String(scheme));
|
|
3825
|
+
if (!VALID_SCHEME.test(decodedScheme)) {
|
|
3826
|
+
throw new TypeError(MALFORMED_SCHEME_ERROR);
|
|
3827
|
+
}
|
|
3828
|
+
return decodedScheme;
|
|
3829
|
+
}
|
|
3636
3830
|
function normalize(uri, options) {
|
|
3637
3831
|
if (typeof uri === "string") {
|
|
3638
3832
|
uri = /** @type {T} */
|
|
@@ -3645,12 +3839,34 @@ var require_fast_uri = __commonJS({
|
|
|
3645
3839
|
}
|
|
3646
3840
|
function resolve3(baseURI, relativeURI, options) {
|
|
3647
3841
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
3648
|
-
const {
|
|
3649
|
-
|
|
3650
|
-
|
|
3842
|
+
const {
|
|
3843
|
+
parsed: baseParsed,
|
|
3844
|
+
malformedAuthorityOrPort: baseMalformed,
|
|
3845
|
+
malformedPercentEncoding: baseMalformedPercentEncoding,
|
|
3846
|
+
malformedSchemeSpecific: baseMalformedSchemeSpecific,
|
|
3847
|
+
malformedHost: baseMalformedHost,
|
|
3848
|
+
malformedScheme: baseMalformedScheme
|
|
3849
|
+
} = parseWithStatus(baseURI, schemelessOptions);
|
|
3850
|
+
const {
|
|
3851
|
+
parsed: relativeParsed,
|
|
3852
|
+
malformedAuthorityOrPort: relativeMalformed,
|
|
3853
|
+
malformedPercentEncoding: relativeMalformedPercentEncoding,
|
|
3854
|
+
malformedSchemeSpecific: relativeMalformedSchemeSpecific,
|
|
3855
|
+
malformedHost: relativeMalformedHost,
|
|
3856
|
+
malformedScheme: relativeMalformedScheme
|
|
3857
|
+
} = parseWithStatus(relativeURI, schemelessOptions);
|
|
3858
|
+
if (baseMalformed || relativeMalformed || baseMalformedPercentEncoding || relativeMalformedPercentEncoding || baseMalformedSchemeSpecific || relativeMalformedSchemeSpecific || baseMalformedHost || relativeMalformedHost || baseMalformedScheme || relativeMalformedScheme) {
|
|
3651
3859
|
throw new Error(baseParsed.error || relativeParsed.error || "URI is malformed.");
|
|
3652
3860
|
}
|
|
3653
3861
|
const resolved = resolveComponent(baseParsed, relativeParsed, schemelessOptions, true);
|
|
3862
|
+
const resolvedSchemeHandler = getSchemeHandler(options && options.scheme || resolved.scheme);
|
|
3863
|
+
const resolvedHost = resolved.host;
|
|
3864
|
+
const resolvedHostIsIP = resolvedHost !== void 0 && resolvedHost !== "" && (isIPv4(resolvedHost) || normalizeIPv6(resolvedHost).isIPV6);
|
|
3865
|
+
canonicalizeHost(resolved, options || {}, resolvedSchemeHandler, resolvedHostIsIP);
|
|
3866
|
+
const encodedASCIIHost = resolvedHost && resolvedHost.indexOf("%") !== -1 && !new RegExp("\\P{ASCII}", "u").test(resolvedHost);
|
|
3867
|
+
if (resolved.error && !encodedASCIIHost) {
|
|
3868
|
+
throw new Error(resolved.error);
|
|
3869
|
+
}
|
|
3654
3870
|
schemelessOptions.skipEscape = true;
|
|
3655
3871
|
return serialize(resolved, schemelessOptions);
|
|
3656
3872
|
}
|
|
@@ -3710,7 +3926,7 @@ var require_fast_uri = __commonJS({
|
|
|
3710
3926
|
function equal(uriA, uriB, options) {
|
|
3711
3927
|
const normalizedA = normalizeComparableURI(uriA, options);
|
|
3712
3928
|
const normalizedB = normalizeComparableURI(uriB, options);
|
|
3713
|
-
return normalizedA !== void 0 && normalizedB !== void 0 && normalizedA
|
|
3929
|
+
return normalizedA !== void 0 && normalizedB !== void 0 && normalizedA === normalizedB;
|
|
3714
3930
|
}
|
|
3715
3931
|
function serialize(cmpts, opts) {
|
|
3716
3932
|
const component = {
|
|
@@ -3731,19 +3947,22 @@ var require_fast_uri = __commonJS({
|
|
|
3731
3947
|
};
|
|
3732
3948
|
const options = Object.assign({}, opts);
|
|
3733
3949
|
const uriTokens = [];
|
|
3950
|
+
if (component.scheme) {
|
|
3951
|
+
component.scheme = decodeValidScheme(component.scheme);
|
|
3952
|
+
}
|
|
3734
3953
|
const schemeHandler = getSchemeHandler(options.scheme || component.scheme);
|
|
3735
3954
|
if (schemeHandler && schemeHandler.serialize) schemeHandler.serialize(component, options);
|
|
3955
|
+
const hasAuthority = component.userinfo !== void 0 || component.host !== void 0 || component.port !== void 0;
|
|
3956
|
+
const pathNoScheme = !options.skipEscape && component.scheme === void 0 && !hasAuthority;
|
|
3736
3957
|
if (component.path !== void 0) {
|
|
3737
3958
|
if (!options.skipEscape) {
|
|
3738
|
-
component.path =
|
|
3739
|
-
if (component.scheme !== void 0) {
|
|
3740
|
-
component.path = component.path.split("%3A").join(":");
|
|
3741
|
-
}
|
|
3959
|
+
component.path = serializePathEncoding(component.path, pathNoScheme);
|
|
3742
3960
|
} else {
|
|
3743
3961
|
component.path = normalizePercentEncoding(component.path);
|
|
3744
3962
|
}
|
|
3745
3963
|
}
|
|
3746
3964
|
if (options.reference !== "suffix" && component.scheme) {
|
|
3965
|
+
component.scheme = decodeValidScheme(component.scheme);
|
|
3747
3966
|
uriTokens.push(component.scheme, ":");
|
|
3748
3967
|
}
|
|
3749
3968
|
const authority = recomposeAuthority(component);
|
|
@@ -3761,16 +3980,19 @@ var require_fast_uri = __commonJS({
|
|
|
3761
3980
|
if (!options.absolutePath && (!schemeHandler || !schemeHandler.absolutePath)) {
|
|
3762
3981
|
s = removeDotSegments(s);
|
|
3763
3982
|
}
|
|
3983
|
+
if (pathNoScheme) {
|
|
3984
|
+
s = serializePathEncoding(s, true);
|
|
3985
|
+
}
|
|
3764
3986
|
if (authority === void 0 && s[0] === "/" && s[1] === "/") {
|
|
3765
3987
|
s = "/%2F" + s.slice(2);
|
|
3766
3988
|
}
|
|
3767
3989
|
uriTokens.push(s);
|
|
3768
3990
|
}
|
|
3769
3991
|
if (component.query !== void 0) {
|
|
3770
|
-
uriTokens.push("?", component.query);
|
|
3992
|
+
uriTokens.push("?", encodeQuery(component.query));
|
|
3771
3993
|
}
|
|
3772
3994
|
if (component.fragment !== void 0) {
|
|
3773
|
-
uriTokens.push("#", component.fragment);
|
|
3995
|
+
uriTokens.push("#", encodeFragment(component.fragment));
|
|
3774
3996
|
}
|
|
3775
3997
|
return uriTokens.join("");
|
|
3776
3998
|
}
|
|
@@ -3786,6 +4008,32 @@ var require_fast_uri = __commonJS({
|
|
|
3786
4008
|
}
|
|
3787
4009
|
return void 0;
|
|
3788
4010
|
}
|
|
4011
|
+
function hasMalformedPercentEncoding(component) {
|
|
4012
|
+
if (component === void 0) return false;
|
|
4013
|
+
let percent = component.indexOf("%");
|
|
4014
|
+
while (percent !== -1) {
|
|
4015
|
+
if (percent + 2 >= component.length || !/^[\da-f]{2}$/iu.test(component.slice(percent + 1, percent + 3))) {
|
|
4016
|
+
return true;
|
|
4017
|
+
}
|
|
4018
|
+
percent = component.indexOf("%", percent + 3);
|
|
4019
|
+
}
|
|
4020
|
+
return false;
|
|
4021
|
+
}
|
|
4022
|
+
function hasMalformedComponentPercentEncoding(matches) {
|
|
4023
|
+
const host = matches[4];
|
|
4024
|
+
return hasMalformedPercentEncoding(matches[3]) || host !== void 0 && !(host[0] === "[" && host[host.length - 1] === "]") && hasMalformedPercentEncoding(host) || hasMalformedPercentEncoding(matches[6]) || hasMalformedPercentEncoding(matches[7]) || hasMalformedPercentEncoding(matches[8]);
|
|
4025
|
+
}
|
|
4026
|
+
function canonicalizeHost(parsed, options, schemeHandler, isIP) {
|
|
4027
|
+
if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport) && parsed.host && parsed.host[0] !== "[" && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP === false && nonSimpleDomain(parsed.host)) {
|
|
4028
|
+
try {
|
|
4029
|
+
parsed.host = new URL("http://" + parsed.host).hostname;
|
|
4030
|
+
} catch (e) {
|
|
4031
|
+
parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e;
|
|
4032
|
+
return true;
|
|
4033
|
+
}
|
|
4034
|
+
}
|
|
4035
|
+
return false;
|
|
4036
|
+
}
|
|
3789
4037
|
function parseWithStatus(uri, opts) {
|
|
3790
4038
|
const options = Object.assign({}, opts);
|
|
3791
4039
|
const parsed = {
|
|
@@ -3798,6 +4046,11 @@ var require_fast_uri = __commonJS({
|
|
|
3798
4046
|
fragment: void 0
|
|
3799
4047
|
};
|
|
3800
4048
|
let malformedAuthorityOrPort = false;
|
|
4049
|
+
let malformedPercentEncoding = false;
|
|
4050
|
+
let malformedSchemeSpecific = false;
|
|
4051
|
+
let malformedHost = false;
|
|
4052
|
+
let malformedIPLiteral = false;
|
|
4053
|
+
let malformedScheme = false;
|
|
3801
4054
|
let isIP = false;
|
|
3802
4055
|
if (options.reference === "suffix") {
|
|
3803
4056
|
if (options.scheme) {
|
|
@@ -3834,6 +4087,19 @@ var require_fast_uri = __commonJS({
|
|
|
3834
4087
|
parsed.path = matches[6] || "";
|
|
3835
4088
|
parsed.query = matches[7];
|
|
3836
4089
|
parsed.fragment = matches[8];
|
|
4090
|
+
if (parsed.scheme !== void 0) {
|
|
4091
|
+
const decodedScheme = unescape(parsed.scheme);
|
|
4092
|
+
if (VALID_SCHEME.test(decodedScheme)) {
|
|
4093
|
+
parsed.scheme = decodedScheme.toLowerCase();
|
|
4094
|
+
} else {
|
|
4095
|
+
parsed.error = parsed.error || MALFORMED_SCHEME_ERROR;
|
|
4096
|
+
malformedScheme = true;
|
|
4097
|
+
}
|
|
4098
|
+
}
|
|
4099
|
+
malformedPercentEncoding = hasMalformedComponentPercentEncoding(matches);
|
|
4100
|
+
if (malformedPercentEncoding) {
|
|
4101
|
+
parsed.error = parsed.error || "URI contains malformed percent-encoding.";
|
|
4102
|
+
}
|
|
3837
4103
|
if (isNaN(parsed.port)) {
|
|
3838
4104
|
parsed.port = matches[5];
|
|
3839
4105
|
}
|
|
@@ -3845,9 +4111,15 @@ var require_fast_uri = __commonJS({
|
|
|
3845
4111
|
if (parsed.host) {
|
|
3846
4112
|
const ipv4result = isIPv4(parsed.host);
|
|
3847
4113
|
if (ipv4result === false) {
|
|
4114
|
+
const bracketedIPLiteral = parsed.host[0] === "[" && parsed.host[parsed.host.length - 1] === "]";
|
|
3848
4115
|
const ipv6result = normalizeIPv6(parsed.host);
|
|
3849
|
-
|
|
3850
|
-
|
|
4116
|
+
isIP = ipv6result.isIPV6 || ipv6result.isIPVFuture === true;
|
|
4117
|
+
malformedIPLiteral = bracketedIPLiteral && ipv6result.error === true;
|
|
4118
|
+
parsed.host = isIP ? ipv6result.host : ipv6result.host.toLowerCase();
|
|
4119
|
+
if (malformedIPLiteral) {
|
|
4120
|
+
parsed.error = parsed.error || "URI host is malformed.";
|
|
4121
|
+
malformedAuthorityOrPort = true;
|
|
4122
|
+
}
|
|
3851
4123
|
} else {
|
|
3852
4124
|
isIP = true;
|
|
3853
4125
|
}
|
|
@@ -3865,42 +4137,34 @@ var require_fast_uri = __commonJS({
|
|
|
3865
4137
|
parsed.error = parsed.error || "URI is not a " + options.reference + " reference.";
|
|
3866
4138
|
}
|
|
3867
4139
|
const schemeHandler = getSchemeHandler(options.scheme || parsed.scheme);
|
|
3868
|
-
|
|
3869
|
-
if (parsed.host && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP === false && nonSimpleDomain(parsed.host)) {
|
|
3870
|
-
try {
|
|
3871
|
-
parsed.host = new URL("http://" + parsed.host).hostname;
|
|
3872
|
-
} catch (e) {
|
|
3873
|
-
parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e;
|
|
3874
|
-
}
|
|
3875
|
-
}
|
|
3876
|
-
}
|
|
4140
|
+
malformedHost = canonicalizeHost(parsed, options, schemeHandler, isIP);
|
|
3877
4141
|
if (!schemeHandler || schemeHandler && !schemeHandler.skipNormalize) {
|
|
3878
4142
|
if (uri.indexOf("%") !== -1) {
|
|
3879
|
-
if (parsed.
|
|
3880
|
-
parsed.
|
|
3881
|
-
|
|
3882
|
-
if (parsed.host !== void 0) {
|
|
3883
|
-
parsed.host = reescapeHostDelimiters(unescape(parsed.host), isIP);
|
|
4143
|
+
if (parsed.host !== void 0 && !malformedIPLiteral) {
|
|
4144
|
+
const host = isIP ? parsed.host : normalizePercentEncoding(parsed.host, true);
|
|
4145
|
+
parsed.host = reescapeHostDelimiters(host, isIP);
|
|
3884
4146
|
}
|
|
3885
4147
|
}
|
|
3886
4148
|
if (parsed.path) {
|
|
3887
4149
|
parsed.path = normalizePathEncoding(parsed.path);
|
|
3888
4150
|
}
|
|
4151
|
+
if (parsed.query) {
|
|
4152
|
+
parsed.query = normalizeQueryFragmentEncoding(parsed.query);
|
|
4153
|
+
}
|
|
3889
4154
|
if (parsed.fragment) {
|
|
3890
|
-
|
|
3891
|
-
parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment));
|
|
3892
|
-
} catch {
|
|
3893
|
-
parsed.error = parsed.error || "URI malformed";
|
|
3894
|
-
}
|
|
4155
|
+
parsed.fragment = normalizeQueryFragmentEncoding(parsed.fragment);
|
|
3895
4156
|
}
|
|
3896
4157
|
}
|
|
3897
4158
|
if (schemeHandler && schemeHandler.parse) {
|
|
3898
4159
|
schemeHandler.parse(parsed, options);
|
|
4160
|
+
if (schemeHandler === SCHEMES.urn && parsed.nid === void 0) {
|
|
4161
|
+
malformedSchemeSpecific = true;
|
|
4162
|
+
}
|
|
3899
4163
|
}
|
|
3900
4164
|
} else {
|
|
3901
4165
|
parsed.error = parsed.error || "URI can not be parsed.";
|
|
3902
4166
|
}
|
|
3903
|
-
return { parsed, malformedAuthorityOrPort };
|
|
4167
|
+
return { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme };
|
|
3904
4168
|
}
|
|
3905
4169
|
function parse4(uri, opts) {
|
|
3906
4170
|
return parseWithStatus(uri, opts).parsed;
|
|
@@ -3909,20 +4173,28 @@ var require_fast_uri = __commonJS({
|
|
|
3909
4173
|
return normalizeStringWithStatus(uri, opts).normalized;
|
|
3910
4174
|
}
|
|
3911
4175
|
function normalizeStringWithStatus(uri, opts) {
|
|
3912
|
-
const { parsed, malformedAuthorityOrPort } = parseWithStatus(uri, opts);
|
|
4176
|
+
const { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme } = parseWithStatus(uri, opts);
|
|
3913
4177
|
return {
|
|
3914
|
-
normalized: malformedAuthorityOrPort ? uri : serialize(parsed, opts),
|
|
3915
|
-
malformedAuthorityOrPort
|
|
4178
|
+
normalized: malformedAuthorityOrPort || malformedPercentEncoding || malformedSchemeSpecific || malformedHost || malformedScheme ? uri : serialize(parsed, opts),
|
|
4179
|
+
malformedAuthorityOrPort,
|
|
4180
|
+
malformedPercentEncoding,
|
|
4181
|
+
malformedSchemeSpecific,
|
|
4182
|
+
malformedHost,
|
|
4183
|
+
malformedScheme
|
|
3916
4184
|
};
|
|
3917
4185
|
}
|
|
3918
4186
|
function normalizeComparableURI(uri, opts) {
|
|
3919
|
-
if (typeof uri
|
|
3920
|
-
|
|
3921
|
-
return malformedAuthorityOrPort ? void 0 : normalized;
|
|
4187
|
+
if (typeof uri !== "string" && typeof uri !== "object") {
|
|
4188
|
+
return void 0;
|
|
3922
4189
|
}
|
|
3923
|
-
|
|
3924
|
-
|
|
4190
|
+
let value;
|
|
4191
|
+
try {
|
|
4192
|
+
value = typeof uri === "string" ? uri : serialize(uri, opts);
|
|
4193
|
+
} catch {
|
|
4194
|
+
return void 0;
|
|
3925
4195
|
}
|
|
4196
|
+
const { normalized, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme } = normalizeStringWithStatus(value, opts);
|
|
4197
|
+
return malformedAuthorityOrPort || malformedPercentEncoding || malformedSchemeSpecific || malformedHost || malformedScheme ? void 0 : normalized;
|
|
3926
4198
|
}
|
|
3927
4199
|
var fastUri = {
|
|
3928
4200
|
SCHEMES,
|
|
@@ -22623,6 +22895,8 @@ var MAX_NAME_LEN = 1024;
|
|
|
22623
22895
|
var MAX_QUERY_LEN = 1e4;
|
|
22624
22896
|
var MAX_HEADER_LEN = 1024;
|
|
22625
22897
|
var headerCellSchema = external_exports.string().max(MAX_HEADER_LEN);
|
|
22898
|
+
var PATH_BOUNDARY_NOTE = `
|
|
22899
|
+
Paths: the file must resolve \u2014 after ~ expansion and symlink resolution \u2014 to a location under ${ALLOWED_EXPORT_ROOTS_TEXT}; anything else is rejected with an error naming those roots. Add directories with the ${EXTRA_ROOTS_ENV} environment variable.`;
|
|
22626
22900
|
var server = new McpServer({
|
|
22627
22901
|
name: "apple-numbers",
|
|
22628
22902
|
version: version2,
|
|
@@ -22677,7 +22951,7 @@ registerTool(
|
|
|
22677
22951
|
registerTool(
|
|
22678
22952
|
"get-file-info",
|
|
22679
22953
|
{
|
|
22680
|
-
description: "Use when: you need to discover the structure of a .numbers file before reading or writing \u2014 the exact sheet and table names, their dimensions, and header rows. Call this first when sheet/table names are unknown.\nReturns: each sheet with its tables, per-table row\xD7col counts, and the header row (row 0) cells.\nDo not use when: you want the actual cell data \u2014 use read-table; or a single cell \u2014 use get-cell.",
|
|
22954
|
+
description: "Use when: you need to discover the structure of a .numbers file before reading or writing \u2014 the exact sheet and table names, their dimensions, and header rows. Call this first when sheet/table names are unknown.\nReturns: each sheet with its tables, per-table row\xD7col counts, and the header row (row 0) cells.\nDo not use when: you want the actual cell data \u2014 use read-table; or a single cell \u2014 use get-cell." + PATH_BOUNDARY_NOTE,
|
|
22681
22955
|
inputSchema: {
|
|
22682
22956
|
path: external_exports.string().describe("Absolute or ~-relative path to the .numbers file")
|
|
22683
22957
|
},
|
|
@@ -22721,7 +22995,7 @@ ${summary}`,
|
|
|
22721
22995
|
registerTool(
|
|
22722
22996
|
"read-table",
|
|
22723
22997
|
{
|
|
22724
|
-
description: "Use when: you want the data from a table \u2014 headers plus rows, optionally limited to a row range (0-based inclusive indices; header is row 0, so data starts at row 1) and/or a subset of columns. Defaults to the first sheet and first table if sheet/table are omitted.\nReturns: sheet name, table name, the headers and rows selected, and numRows/numCols describing the SELECTION \u2014 not the table. Use get-file-info for the table's full dimensions.\nDo not use when: you only need one cell \u2014 use get-cell; you need the file's structure/names \u2014 use get-file-info; or you want to find a value's location \u2014 use search.",
|
|
22998
|
+
description: "Use when: you want the data from a table \u2014 headers plus rows, optionally limited to a row range (0-based inclusive indices; header is row 0, so data starts at row 1) and/or a subset of columns. Defaults to the first sheet and first table if sheet/table are omitted.\nReturns: sheet name, table name, the headers and rows selected, and numRows/numCols describing the SELECTION \u2014 not the table. Use get-file-info for the table's full dimensions.\nDo not use when: you only need one cell \u2014 use get-cell; you need the file's structure/names \u2014 use get-file-info; or you want to find a value's location \u2014 use search." + PATH_BOUNDARY_NOTE,
|
|
22725
22999
|
inputSchema: {
|
|
22726
23000
|
path: external_exports.string().describe("Path to the .numbers file"),
|
|
22727
23001
|
sheet: external_exports.string().optional().describe("Sheet name (default: first sheet)"),
|
|
@@ -22757,7 +23031,7 @@ ${dataRows}`,
|
|
|
22757
23031
|
registerTool(
|
|
22758
23032
|
"search",
|
|
22759
23033
|
{
|
|
22760
|
-
description: "Use when: you need to locate where a text value appears across every cell in a .numbers file (case-insensitive partial match), optionally limited to one sheet.\nReturns: a match count and each match's sheet, table, row, column header, and value.\nDo not use when: you already know the cell's coordinates \u2014 use get-cell; or you want a whole table's contents \u2014 use read-table.",
|
|
23034
|
+
description: "Use when: you need to locate where a text value appears across every cell in a .numbers file (case-insensitive partial match), optionally limited to one sheet.\nReturns: a match count and each match's sheet, table, row, column header, and value.\nDo not use when: you already know the cell's coordinates \u2014 use get-cell; or you want a whole table's contents \u2014 use read-table." + PATH_BOUNDARY_NOTE,
|
|
22761
23035
|
inputSchema: {
|
|
22762
23036
|
path: external_exports.string().describe("Path to the .numbers file"),
|
|
22763
23037
|
query: external_exports.string().max(MAX_QUERY_LEN).describe("Text to search for (case-insensitive)"),
|
|
@@ -22823,7 +23097,7 @@ registerTool(
|
|
|
22823
23097
|
registerTool(
|
|
22824
23098
|
"get-cell",
|
|
22825
23099
|
{
|
|
22826
|
-
description: "Use when: you need a single cell's value by 0-based row and column index (header is row 0). Set verbose=true to also get the formula, formatted value, and merge info.\nReturns: the cell's value and type, plus formula/formatted-value/merge details when verbose.\nDo not use when: you want many cells or whole rows \u2014 use read-table; or you don't know the coordinates \u2014 use search.",
|
|
23100
|
+
description: "Use when: you need a single cell's value by 0-based row and column index (header is row 0). Set verbose=true to also get the formula, formatted value, and merge info.\nReturns: the cell's value and type, plus formula/formatted-value/merge details when verbose.\nDo not use when: you want many cells or whole rows \u2014 use read-table; or you don't know the coordinates \u2014 use search." + PATH_BOUNDARY_NOTE,
|
|
22827
23101
|
inputSchema: {
|
|
22828
23102
|
path: external_exports.string().describe("Path to the .numbers file"),
|
|
22829
23103
|
sheet: external_exports.string().describe("Sheet name"),
|
|
@@ -22892,7 +23166,7 @@ registerTool(
|
|
|
22892
23166
|
description: `Use when: you need to write a computed value to one cell in an existing .numbers file, addressed by 0-based row and column (header is row 0). Defaults to the first sheet/table if omitted.
|
|
22893
23167
|
Returns: the written coordinates, value, and the sheet/table affected.
|
|
22894
23168
|
Do not use when: you're writing many cells \u2014 use set-cells-batch; replacing whole rows \u2014 use update-rows; or writing a live formula \u2014 use set-formula (passing "=SUM(...)" here writes literal text, not a formula).
|
|
22895
|
-
Safety: modifies the .numbers file in place via the numbers-parser sidecar (does not require Numbers.app) and OVERWRITES any existing data in the target cell
|
|
23169
|
+
Safety: modifies the .numbers file in place via the numbers-parser sidecar (does not require Numbers.app) and OVERWRITES any existing data in the target cell.` + PATH_BOUNDARY_NOTE,
|
|
22896
23170
|
inputSchema: {
|
|
22897
23171
|
path: external_exports.string().describe("Path to the .numbers file"),
|
|
22898
23172
|
row: external_exports.number().int().min(0).max(MAX_INDEX).describe("Row index (0-based)"),
|
|
@@ -22924,7 +23198,7 @@ Safety: modifies the .numbers file in place via the numbers-parser sidecar (does
|
|
|
22924
23198
|
registerTool(
|
|
22925
23199
|
"set-cells-batch",
|
|
22926
23200
|
{
|
|
22927
|
-
description: "Use when: you need to write computed values to multiple cells at once (each with 0-based row/col); more efficient than many set-cell calls. Defaults to the first sheet/table if omitted.\nReturns: the number of cells written and the sheet/table affected.\nDo not use when: replacing whole rows by index \u2014 use update-rows; appending new rows \u2014 use add-rows; or writing live formulas \u2014 use set-formulas-batch.\nSafety: modifies the .numbers file in place via the numbers-parser sidecar (does not require Numbers.app) and OVERWRITES any existing data in the targeted cells.",
|
|
23201
|
+
description: "Use when: you need to write computed values to multiple cells at once (each with 0-based row/col); more efficient than many set-cell calls. Defaults to the first sheet/table if omitted.\nReturns: the number of cells written and the sheet/table affected.\nDo not use when: replacing whole rows by index \u2014 use update-rows; appending new rows \u2014 use add-rows; or writing live formulas \u2014 use set-formulas-batch.\nSafety: modifies the .numbers file in place via the numbers-parser sidecar (does not require Numbers.app) and OVERWRITES any existing data in the targeted cells." + PATH_BOUNDARY_NOTE,
|
|
22928
23202
|
inputSchema: {
|
|
22929
23203
|
path: external_exports.string().describe("Path to the .numbers file"),
|
|
22930
23204
|
updates: external_exports.array(
|
|
@@ -22958,7 +23232,7 @@ registerTool(
|
|
|
22958
23232
|
registerTool(
|
|
22959
23233
|
"add-rows",
|
|
22960
23234
|
{
|
|
22961
|
-
description: "Use when: you want to append new rows of data to the end of an existing table; rows are added after the last existing row. Defaults to the first sheet/table if omitted.\nReturns: the number of rows added, the starting row index, and the new total row count.\nDo not use when: overwriting existing rows by index \u2014 use update-rows; setting individual cells \u2014 use set-cell / set-cells-batch.\nSafety: modifies the .numbers file in place via the numbers-parser sidecar (does not require Numbers.app). Additive (appends rows) and does not overwrite existing data, but still mutates the file.",
|
|
23235
|
+
description: "Use when: you want to append new rows of data to the end of an existing table; rows are added after the last existing row. Defaults to the first sheet/table if omitted.\nReturns: the number of rows added, the starting row index, and the new total row count.\nDo not use when: overwriting existing rows by index \u2014 use update-rows; setting individual cells \u2014 use set-cell / set-cells-batch.\nSafety: modifies the .numbers file in place via the numbers-parser sidecar (does not require Numbers.app). Additive (appends rows) and does not overwrite existing data, but still mutates the file." + PATH_BOUNDARY_NOTE,
|
|
22962
23236
|
inputSchema: {
|
|
22963
23237
|
path: external_exports.string().describe("Path to the .numbers file"),
|
|
22964
23238
|
rows: external_exports.array(external_exports.array(external_exports.union([external_exports.string(), external_exports.number(), external_exports.boolean(), external_exports.null()]))).min(1).max(MAX_BATCH).describe(
|
|
@@ -22987,7 +23261,7 @@ registerTool(
|
|
|
22987
23261
|
registerTool(
|
|
22988
23262
|
"delete-rows",
|
|
22989
23263
|
{
|
|
22990
|
-
description: "Use when: you need to permanently remove a contiguous range of rows from a table; both startRow and endRow are 0-based inclusive indices (header is row 0). Defaults to the first sheet/table if omitted.\nReturns: the number of rows deleted and the new total row count.\nDo not use when: you only want to clear values while keeping the rows \u2014 use set-cells-batch with empty values; or overwrite rows in place \u2014 use update-rows.\nSafety: DESTRUCTIVE \u2014 requires explicit user confirmation; not undoable; the .numbers file is modified in place via the numbers-parser sidecar (does not require Numbers.app) and the deleted rows cannot be recovered. Double-check the 0-based inclusive range before calling.",
|
|
23264
|
+
description: "Use when: you need to permanently remove a contiguous range of rows from a table; both startRow and endRow are 0-based inclusive indices (header is row 0). Defaults to the first sheet/table if omitted.\nReturns: the number of rows deleted and the new total row count.\nDo not use when: you only want to clear values while keeping the rows \u2014 use set-cells-batch with empty values; or overwrite rows in place \u2014 use update-rows.\nSafety: DESTRUCTIVE \u2014 requires explicit user confirmation; not undoable; the .numbers file is modified in place via the numbers-parser sidecar (does not require Numbers.app) and the deleted rows cannot be recovered. Double-check the 0-based inclusive range before calling." + PATH_BOUNDARY_NOTE,
|
|
22991
23265
|
inputSchema: {
|
|
22992
23266
|
path: external_exports.string().describe("Path to the .numbers file"),
|
|
22993
23267
|
startRow: external_exports.number().int().min(0).max(MAX_INDEX).describe("First row to delete (0-based, inclusive)"),
|
|
@@ -23014,7 +23288,7 @@ registerTool(
|
|
|
23014
23288
|
registerTool(
|
|
23015
23289
|
"add-sheet",
|
|
23016
23290
|
{
|
|
23017
|
-
description: "Use when: you want to add a new sheet to an existing .numbers file, optionally naming its default table and providing its headers. Geometry depends on headers: with headers the table is created 1 row x headers.length columns; without them it is a 12 x 8 grid of empty cells (not overridable through MCP).\nReturns: the new sheet name, its default table name, and the table's dimensions.\nDo not use when: adding a table to an existing sheet \u2014 use add-table; or creating a whole new file \u2014 use create-spreadsheet.\nSafety: modifies the .numbers file in place via the numbers-parser sidecar (does not require Numbers.app). Additive (adds a new sheet) and does not overwrite existing data, but still mutates the file.",
|
|
23291
|
+
description: "Use when: you want to add a new sheet to an existing .numbers file, optionally naming its default table and providing its headers. Geometry depends on headers: with headers the table is created 1 row x headers.length columns; without them it is a 12 x 8 grid of empty cells (not overridable through MCP).\nReturns: the new sheet name, its default table name, and the table's dimensions.\nDo not use when: adding a table to an existing sheet \u2014 use add-table; or creating a whole new file \u2014 use create-spreadsheet.\nSafety: modifies the .numbers file in place via the numbers-parser sidecar (does not require Numbers.app). Additive (adds a new sheet) and does not overwrite existing data, but still mutates the file." + PATH_BOUNDARY_NOTE,
|
|
23018
23292
|
inputSchema: {
|
|
23019
23293
|
path: external_exports.string().describe("Path to the .numbers file"),
|
|
23020
23294
|
sheetName: external_exports.string().max(MAX_NAME_LEN).describe("Name for the new sheet"),
|
|
@@ -23040,7 +23314,7 @@ registerTool(
|
|
|
23040
23314
|
registerTool(
|
|
23041
23315
|
"add-table",
|
|
23042
23316
|
{
|
|
23043
|
-
description: "Use when: you want to add a new table to an existing sheet, optionally naming it and providing its headers. Defaults to the first sheet if omitted. Geometry depends on headers: with headers the table is created 1 row x headers.length columns; without them it is a 12 x 8 grid of empty cells (not overridable through MCP).\nReturns: the new table name, the sheet it was added to, and the table's dimensions.\nDo not use when: adding a whole new sheet \u2014 use add-sheet; or creating a new file \u2014 use create-spreadsheet.\nSafety: modifies the .numbers file in place via the numbers-parser sidecar (does not require Numbers.app). Additive (adds a new table) and does not overwrite existing data, but still mutates the file.",
|
|
23317
|
+
description: "Use when: you want to add a new table to an existing sheet, optionally naming it and providing its headers. Defaults to the first sheet if omitted. Geometry depends on headers: with headers the table is created 1 row x headers.length columns; without them it is a 12 x 8 grid of empty cells (not overridable through MCP).\nReturns: the new table name, the sheet it was added to, and the table's dimensions.\nDo not use when: adding a whole new sheet \u2014 use add-sheet; or creating a new file \u2014 use create-spreadsheet.\nSafety: modifies the .numbers file in place via the numbers-parser sidecar (does not require Numbers.app). Additive (adds a new table) and does not overwrite existing data, but still mutates the file." + PATH_BOUNDARY_NOTE,
|
|
23044
23318
|
inputSchema: {
|
|
23045
23319
|
path: external_exports.string().describe("Path to the .numbers file"),
|
|
23046
23320
|
sheet: external_exports.string().optional().describe("Sheet name (default: first sheet)"),
|
|
@@ -23098,7 +23372,7 @@ Sheet: "${result.sheetName}" | Table: "${result.tableName}"`,
|
|
|
23098
23372
|
registerTool(
|
|
23099
23373
|
"update-rows",
|
|
23100
23374
|
{
|
|
23101
|
-
description: "Use when: you need to replace whole rows by 0-based index in an existing file; each update carries a row index and a complete array of column values. Carrying multiple {row, values} entries is more efficient than per-row writes. Defaults to the first sheet/table if omitted.\nReturns: the number of rows updated and the sheet/table affected.\nDo not use when: appending new rows \u2014 use add-rows; writing individual cells \u2014 use set-cell / set-cells-batch; or writing live formulas \u2014 use set-formulas-batch.\nSafety: modifies the .numbers file in place via the numbers-parser sidecar (does not require Numbers.app) and OVERWRITES the entire contents of each targeted row.",
|
|
23375
|
+
description: "Use when: you need to replace whole rows by 0-based index in an existing file; each update carries a row index and a complete array of column values. Carrying multiple {row, values} entries is more efficient than per-row writes. Defaults to the first sheet/table if omitted.\nReturns: the number of rows updated and the sheet/table affected.\nDo not use when: appending new rows \u2014 use add-rows; writing individual cells \u2014 use set-cell / set-cells-batch; or writing live formulas \u2014 use set-formulas-batch.\nSafety: modifies the .numbers file in place via the numbers-parser sidecar (does not require Numbers.app) and OVERWRITES the entire contents of each targeted row." + PATH_BOUNDARY_NOTE,
|
|
23102
23376
|
inputSchema: {
|
|
23103
23377
|
path: external_exports.string().describe("Path to the .numbers file"),
|
|
23104
23378
|
updates: external_exports.array(
|
|
@@ -23130,7 +23404,7 @@ registerTool(
|
|
|
23130
23404
|
registerTool(
|
|
23131
23405
|
"rename-sheet",
|
|
23132
23406
|
{
|
|
23133
|
-
description: "Use when: you want to change a sheet's name in a .numbers file. Defaults to the first sheet if the current name is omitted.\nReturns: the old and new sheet names.\nDo not use when: renaming a table \u2014 use rename-table.\nSafety: modifies the .numbers file in place via the numbers-parser sidecar (does not require Numbers.app).",
|
|
23407
|
+
description: "Use when: you want to change a sheet's name in a .numbers file. Defaults to the first sheet if the current name is omitted.\nReturns: the old and new sheet names.\nDo not use when: renaming a table \u2014 use rename-table.\nSafety: modifies the .numbers file in place via the numbers-parser sidecar (does not require Numbers.app)." + PATH_BOUNDARY_NOTE,
|
|
23134
23408
|
inputSchema: {
|
|
23135
23409
|
path: external_exports.string().describe("Path to the .numbers file"),
|
|
23136
23410
|
newName: external_exports.string().max(MAX_NAME_LEN).describe("New name for the sheet"),
|
|
@@ -23153,7 +23427,7 @@ registerTool(
|
|
|
23153
23427
|
registerTool(
|
|
23154
23428
|
"rename-table",
|
|
23155
23429
|
{
|
|
23156
|
-
description: "Use when: you want to change a table's name in a .numbers file. Defaults to the first sheet/table if omitted.\nReturns: the old and new table names and the sheet it belongs to.\nDo not use when: renaming a sheet \u2014 use rename-sheet.\nSafety: modifies the .numbers file in place via the numbers-parser sidecar (does not require Numbers.app).",
|
|
23430
|
+
description: "Use when: you want to change a table's name in a .numbers file. Defaults to the first sheet/table if omitted.\nReturns: the old and new table names and the sheet it belongs to.\nDo not use when: renaming a sheet \u2014 use rename-sheet.\nSafety: modifies the .numbers file in place via the numbers-parser sidecar (does not require Numbers.app)." + PATH_BOUNDARY_NOTE,
|
|
23157
23431
|
inputSchema: {
|
|
23158
23432
|
path: external_exports.string().describe("Path to the .numbers file"),
|
|
23159
23433
|
newName: external_exports.string().max(MAX_NAME_LEN).describe("New name for the table"),
|
|
@@ -23178,7 +23452,7 @@ registerTool(
|
|
|
23178
23452
|
registerTool(
|
|
23179
23453
|
"set-formula",
|
|
23180
23454
|
{
|
|
23181
|
-
description: 'Use when: you need to write a live formula (e.g. "=SUM(A2:A10)") into a cell so it computes in Numbers, addressed by 0-based row/col. Requires explicit sheet and table.\nReturns: the cell, the formula set, and its computed value.\nDo not use when: writing a plain computed value \u2014 use set-cell (this tool is for live formulas); or setting many formulas \u2014 use set-formulas-batch.\nSafety: drives Numbers.app via AppleScript and requires Numbers.app INSTALLED (it need not already be running) plus Automation permission. The file is opened in Numbers.app if not already open, launching the app; the formula OVERWRITES any existing content in the target cell; the WHOLE document is saved, which commits any unsaved edits the user has open in it; and the document is left open afterwards.',
|
|
23455
|
+
description: 'Use when: you need to write a live formula (e.g. "=SUM(A2:A10)") into a cell so it computes in Numbers, addressed by 0-based row/col. Requires explicit sheet and table.\nReturns: the cell, the formula set, and its computed value.\nDo not use when: writing a plain computed value \u2014 use set-cell (this tool is for live formulas); or setting many formulas \u2014 use set-formulas-batch.\nSafety: drives Numbers.app via AppleScript and requires Numbers.app INSTALLED (it need not already be running) plus Automation permission. The file is opened in Numbers.app if not already open, launching the app; the formula OVERWRITES any existing content in the target cell; the WHOLE document is saved, which commits any unsaved edits the user has open in it; and the document is left open afterwards.' + PATH_BOUNDARY_NOTE,
|
|
23182
23456
|
inputSchema: {
|
|
23183
23457
|
path: external_exports.string().describe("Path to the .numbers file"),
|
|
23184
23458
|
sheet: external_exports.string().describe("Sheet name"),
|
|
@@ -23209,7 +23483,7 @@ Computed value: ${result.computedValue}`,
|
|
|
23209
23483
|
registerTool(
|
|
23210
23484
|
"set-formulas-batch",
|
|
23211
23485
|
{
|
|
23212
|
-
description: "Use when: you need to write live formulas to multiple cells at once (each with 0-based row/col); more efficient than many set-formula calls. Requires explicit sheet and table.\nReturns: the number of formulas set and the sheet/table affected.\nDo not use when: writing plain computed values \u2014 use set-cells-batch; or setting a single formula \u2014 use set-formula.\nSafety: drives Numbers.app via AppleScript and requires Numbers.app INSTALLED (it need not already be running) plus Automation permission. Opens the file in Numbers.app if it isn't open already, launching the app; OVERWRITES any existing content in the targeted cells; saves the WHOLE document, which commits any unsaved edits the user has open in it; and leaves the document open afterwards.",
|
|
23486
|
+
description: "Use when: you need to write live formulas to multiple cells at once (each with 0-based row/col); more efficient than many set-formula calls. Requires explicit sheet and table.\nReturns: the number of formulas set and the sheet/table affected.\nDo not use when: writing plain computed values \u2014 use set-cells-batch; or setting a single formula \u2014 use set-formula.\nSafety: drives Numbers.app via AppleScript and requires Numbers.app INSTALLED (it need not already be running) plus Automation permission. Opens the file in Numbers.app if it isn't open already, launching the app; OVERWRITES any existing content in the targeted cells; saves the WHOLE document, which commits any unsaved edits the user has open in it; and leaves the document open afterwards." + PATH_BOUNDARY_NOTE,
|
|
23213
23487
|
inputSchema: {
|
|
23214
23488
|
path: external_exports.string().describe("Path to the .numbers file"),
|
|
23215
23489
|
sheet: external_exports.string().describe("Sheet name"),
|
|
@@ -23267,7 +23541,7 @@ var cellStyleSchema = external_exports.object({
|
|
|
23267
23541
|
registerTool(
|
|
23268
23542
|
"set-cell-style",
|
|
23269
23543
|
{
|
|
23270
|
-
description: "Use when: you need to format one cell \u2014 font, text/background color, number format, alignment, text wrap \u2014 addressed by 0-based row/col. Requires explicit sheet and table.\nReturns: the styled cell and the sheet/table affected.\nDo not use when: styling many cells \u2014 use set-cells-style-batch; or writing a value/formula rather than formatting \u2014 use set-cell / set-formula.\nSafety: drives Numbers.app via AppleScript \u2014 requires Numbers.app INSTALLED (it need not already be running) plus Automation permission. Opens the file in Numbers.app if it isn't open already, launching the app; modifies it in place; saves the WHOLE document, which commits any unsaved edits the user has open in it; and leaves the document open afterwards.",
|
|
23544
|
+
description: "Use when: you need to format one cell \u2014 font, text/background color, number format, alignment, text wrap \u2014 addressed by 0-based row/col. Requires explicit sheet and table.\nReturns: the styled cell and the sheet/table affected.\nDo not use when: styling many cells \u2014 use set-cells-style-batch; or writing a value/formula rather than formatting \u2014 use set-cell / set-formula.\nSafety: drives Numbers.app via AppleScript \u2014 requires Numbers.app INSTALLED (it need not already be running) plus Automation permission. Opens the file in Numbers.app if it isn't open already, launching the app; modifies it in place; saves the WHOLE document, which commits any unsaved edits the user has open in it; and leaves the document open afterwards." + PATH_BOUNDARY_NOTE,
|
|
23271
23545
|
inputSchema: {
|
|
23272
23546
|
path: external_exports.string().describe("Path to the .numbers file"),
|
|
23273
23547
|
sheet: external_exports.string().describe("Sheet name"),
|
|
@@ -23294,7 +23568,7 @@ registerTool(
|
|
|
23294
23568
|
registerTool(
|
|
23295
23569
|
"set-cells-style-batch",
|
|
23296
23570
|
{
|
|
23297
|
-
description: "Use when: you need to format multiple cells at once (each with 0-based row/col); more efficient than many set-cell-style calls. Requires explicit sheet and table.\nReturns: the number of cells styled and the sheet/table affected.\nDo not use when: styling a single cell \u2014 use set-cell-style; or writing values/formulas rather than formatting \u2014 use set-cells-batch / set-formulas-batch.\nSafety: drives Numbers.app via AppleScript \u2014 requires Numbers.app INSTALLED (it need not already be running) plus Automation permission. Opens the file in Numbers.app if it isn't open already, launching the app; modifies it in place; saves the WHOLE document, which commits any unsaved edits the user has open in it; and leaves the document open afterwards.",
|
|
23571
|
+
description: "Use when: you need to format multiple cells at once (each with 0-based row/col); more efficient than many set-cell-style calls. Requires explicit sheet and table.\nReturns: the number of cells styled and the sheet/table affected.\nDo not use when: styling a single cell \u2014 use set-cell-style; or writing values/formulas rather than formatting \u2014 use set-cells-batch / set-formulas-batch.\nSafety: drives Numbers.app via AppleScript \u2014 requires Numbers.app INSTALLED (it need not already be running) plus Automation permission. Opens the file in Numbers.app if it isn't open already, launching the app; modifies it in place; saves the WHOLE document, which commits any unsaved edits the user has open in it; and leaves the document open afterwards." + PATH_BOUNDARY_NOTE,
|
|
23298
23572
|
inputSchema: {
|
|
23299
23573
|
path: external_exports.string().describe("Path to the .numbers file"),
|
|
23300
23574
|
sheet: external_exports.string().describe("Sheet name"),
|
|
@@ -23325,7 +23599,7 @@ registerTool(
|
|
|
23325
23599
|
registerTool(
|
|
23326
23600
|
"set-column-width",
|
|
23327
23601
|
{
|
|
23328
|
-
description: "Use when: you need to set a column's width in pixels, addressed by 0-based column index. Requires explicit sheet and table.\nReturns: the column index and the width applied.\nDo not use when: setting a row's height \u2014 use set-row-height.\nSafety: drives Numbers.app via AppleScript \u2014 requires Numbers.app INSTALLED (it need not already be running) plus Automation permission. Opens the file in Numbers.app if it isn't open already, launching the app; modifies it in place; saves the WHOLE document, which commits any unsaved edits the user has open in it; and leaves the document open afterwards.",
|
|
23602
|
+
description: "Use when: you need to set a column's width in pixels, addressed by 0-based column index. Requires explicit sheet and table.\nReturns: the column index and the width applied.\nDo not use when: setting a row's height \u2014 use set-row-height.\nSafety: drives Numbers.app via AppleScript \u2014 requires Numbers.app INSTALLED (it need not already be running) plus Automation permission. Opens the file in Numbers.app if it isn't open already, launching the app; modifies it in place; saves the WHOLE document, which commits any unsaved edits the user has open in it; and leaves the document open afterwards." + PATH_BOUNDARY_NOTE,
|
|
23329
23603
|
inputSchema: {
|
|
23330
23604
|
path: external_exports.string().describe("Path to the .numbers file"),
|
|
23331
23605
|
sheet: external_exports.string().describe("Sheet name"),
|
|
@@ -23355,7 +23629,7 @@ registerTool(
|
|
|
23355
23629
|
registerTool(
|
|
23356
23630
|
"set-row-height",
|
|
23357
23631
|
{
|
|
23358
|
-
description: "Use when: you need to set a row's height in pixels, addressed by 0-based row index. Requires explicit sheet and table.\nReturns: the row index and the height applied.\nDo not use when: setting a column's width \u2014 use set-column-width.\nSafety: drives Numbers.app via AppleScript \u2014 requires Numbers.app INSTALLED (it need not already be running) plus Automation permission. Opens the file in Numbers.app if it isn't open already, launching the app; modifies it in place; saves the WHOLE document, which commits any unsaved edits the user has open in it; and leaves the document open afterwards.",
|
|
23632
|
+
description: "Use when: you need to set a row's height in pixels, addressed by 0-based row index. Requires explicit sheet and table.\nReturns: the row index and the height applied.\nDo not use when: setting a column's width \u2014 use set-column-width.\nSafety: drives Numbers.app via AppleScript \u2014 requires Numbers.app INSTALLED (it need not already be running) plus Automation permission. Opens the file in Numbers.app if it isn't open already, launching the app; modifies it in place; saves the WHOLE document, which commits any unsaved edits the user has open in it; and leaves the document open afterwards." + PATH_BOUNDARY_NOTE,
|
|
23359
23633
|
inputSchema: {
|
|
23360
23634
|
path: external_exports.string().describe("Path to the .numbers file"),
|
|
23361
23635
|
sheet: external_exports.string().describe("Sheet name"),
|
|
@@ -23385,7 +23659,7 @@ registerTool(
|
|
|
23385
23659
|
registerTool(
|
|
23386
23660
|
"merge-cells",
|
|
23387
23661
|
{
|
|
23388
|
-
description: "Use when: you need to merge a rectangular range of cells into one, given 0-based inclusive top-left and bottom-right coordinates. Requires explicit sheet and table.\nReturns: the merged range and the sheet/table affected.\nDo not use when: undoing a merge \u2014 use unmerge-cells.\nSafety: drives Numbers.app via AppleScript \u2014 requires Numbers.app INSTALLED (it need not already be running) plus Automation permission. Opens the file in Numbers.app if it isn't open already, launching the app; modifies it in place; saves the WHOLE document, which commits any unsaved edits the user has open in it; and leaves the document open afterwards. Merging keeps only the top-left cell's content and can DROP the values in the other cells of the range.",
|
|
23662
|
+
description: "Use when: you need to merge a rectangular range of cells into one, given 0-based inclusive top-left and bottom-right coordinates. Requires explicit sheet and table.\nReturns: the merged range and the sheet/table affected.\nDo not use when: undoing a merge \u2014 use unmerge-cells.\nSafety: drives Numbers.app via AppleScript \u2014 requires Numbers.app INSTALLED (it need not already be running) plus Automation permission. Opens the file in Numbers.app if it isn't open already, launching the app; modifies it in place; saves the WHOLE document, which commits any unsaved edits the user has open in it; and leaves the document open afterwards. Merging keeps only the top-left cell's content and can DROP the values in the other cells of the range." + PATH_BOUNDARY_NOTE,
|
|
23389
23663
|
inputSchema: {
|
|
23390
23664
|
path: external_exports.string().describe("Path to the .numbers file"),
|
|
23391
23665
|
sheet: external_exports.string().describe("Sheet name"),
|
|
@@ -23412,7 +23686,7 @@ registerTool(
|
|
|
23412
23686
|
registerTool(
|
|
23413
23687
|
"unmerge-cells",
|
|
23414
23688
|
{
|
|
23415
|
-
description: "Use when: you need to split a previously merged range back into individual cells, given 0-based inclusive top-left and bottom-right coordinates. Requires explicit sheet and table.\nReturns: the unmerged range and the sheet/table affected.\nDo not use when: creating a merge \u2014 use merge-cells.\nSafety: drives Numbers.app via AppleScript \u2014 requires Numbers.app INSTALLED (it need not already be running) plus Automation permission. Opens the file in Numbers.app if it isn't open already, launching the app; modifies it in place; saves the WHOLE document, which commits any unsaved edits the user has open in it; and leaves the document open afterwards. Previously merged cells stay empty (the original non-top-left values are not restored).",
|
|
23689
|
+
description: "Use when: you need to split a previously merged range back into individual cells, given 0-based inclusive top-left and bottom-right coordinates. Requires explicit sheet and table.\nReturns: the unmerged range and the sheet/table affected.\nDo not use when: creating a merge \u2014 use merge-cells.\nSafety: drives Numbers.app via AppleScript \u2014 requires Numbers.app INSTALLED (it need not already be running) plus Automation permission. Opens the file in Numbers.app if it isn't open already, launching the app; modifies it in place; saves the WHOLE document, which commits any unsaved edits the user has open in it; and leaves the document open afterwards. Previously merged cells stay empty (the original non-top-left values are not restored)." + PATH_BOUNDARY_NOTE,
|
|
23416
23690
|
inputSchema: {
|
|
23417
23691
|
path: external_exports.string().describe("Path to the .numbers file"),
|
|
23418
23692
|
sheet: external_exports.string().describe("Sheet name"),
|
|
@@ -60,8 +60,8 @@ the MCP runtime from your Homebrew/dev Node, which can keep updating freely.
|
|
|
60
60
|
curl -O https://nodejs.org/dist/$VER/node-$VER-$ARCH.tar.gz
|
|
61
61
|
curl -O https://nodejs.org/dist/$VER/SHASUMS256.txt
|
|
62
62
|
grep " node-$VER-$ARCH.tar.gz$" SHASUMS256.txt | shasum -a 256 -c - # must print OK
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
mkdir -p node-current
|
|
64
|
+
tar -xzf node-$VER-$ARCH.tar.gz --strip-components=1 -C node-current
|
|
65
65
|
```
|
|
66
66
|
|
|
67
67
|
2. Confirm it's Developer-ID signed:
|
|
@@ -98,12 +98,36 @@ the MCP runtime from your Homebrew/dev Node, which can keep updating freely.
|
|
|
98
98
|
- *Automation*: the first time the server drives an app you'll get a one-time
|
|
99
99
|
`"node" wants to control "<App>"` prompt — click **Allow**.
|
|
100
100
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
101
|
+
⚠️ **A TCC grant is keyed to the binary's resolved *path*, not only to its
|
|
102
|
+
signature.** Because the steps above unpack Node into a fixed directory
|
|
103
|
+
(`~/mcp-runtime/node-current`) rather than a versioned one, that path never
|
|
104
|
+
moves and the grants survive Node updates — see "Updating" below. If you
|
|
105
|
+
instead point `node-current` at a `node-vX.Y.Z-…` directory, every update
|
|
106
|
+
changes the resolved path, presents a brand-new ungranted identity, and you
|
|
107
|
+
will be re-prompted for all of it.
|
|
108
|
+
|
|
109
|
+
You can delete any stale "node" rows from the Full Disk Access list.
|
|
104
110
|
|
|
105
111
|
### Updating the dedicated Node later
|
|
106
112
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
113
|
+
Replace the **contents** of the same directory — do not create a new one and do
|
|
114
|
+
not repoint anything:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
VER=v24.19.0 ARCH=darwin-arm64
|
|
118
|
+
cd ~/mcp-runtime
|
|
119
|
+
curl -O https://nodejs.org/dist/$VER/node-$VER-$ARCH.tar.gz
|
|
120
|
+
curl -O https://nodejs.org/dist/$VER/SHASUMS256.txt
|
|
121
|
+
grep " node-$VER-$ARCH.tar.gz$" SHASUMS256.txt | shasum -a 256 -c - # must print OK
|
|
122
|
+
rm -rf node-current && mkdir -p node-current
|
|
123
|
+
tar -xzf node-$VER-$ARCH.tar.gz --strip-components=1 -C node-current
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The path is unchanged and the official builds are Developer-ID signed with a
|
|
127
|
+
requirement that pins identifier + Team ID (no cdhash), so **both** halves of
|
|
128
|
+
the grant still match: existing grants carry over with no re-approval.
|
|
129
|
+
|
|
130
|
+
⚠️ **Restart your MCP client afterwards.** Replacing the binary unlinks the one
|
|
131
|
+
any already-running server is executing; macOS then cannot validate that path,
|
|
132
|
+
so those processes fail with *"Permission denied"* until they are restarted.
|
|
133
|
+
Nothing is wrong with your grants — a freshly launched server works fine.
|
package/package.json
CHANGED