@hasna/skills 0.2.0 → 0.3.0
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 +100 -36
- package/bin/index.js +2151 -650
- package/bin/mcp.js +1787 -625
- package/bin/migrate.js +5 -0
- package/bin/server.js +365 -198
- package/bin/worker.js +346 -179
- package/dist/cli/cli.test-utils.d.ts +14 -0
- package/dist/cli/commands/publish.d.ts +14 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1100 -152
- package/dist/lib/api-url.d.ts +32 -23
- package/dist/lib/auth-store.d.ts +111 -42
- package/dist/lib/config.d.ts +19 -21
- package/dist/lib/feedback.d.ts +8 -3
- package/dist/lib/fleet-credentials.d.ts +246 -0
- package/dist/lib/portable-skills-files.d.ts +9 -0
- package/dist/lib/portable-skills.d.ts +2 -2
- package/dist/lib/remote-client.d.ts +20 -10
- package/dist/lib/remote-registry.d.ts +31 -11
- package/dist/lib/run-routing.d.ts +6 -4
- package/dist/lib/vendor-host-policy.d.ts +31 -0
- package/dist/sdk/index.d.ts +6 -0
- package/dist/sdk/index.js +1738 -572
- package/dist/server/artifact-storage.d.ts +11 -0
- package/dist/server/skills-api.d.ts +13 -2
- package/dist/storage.js +9 -14
- package/package.json +3 -1
package/bin/mcp.js
CHANGED
|
@@ -3048,13 +3048,32 @@ var require_data = __commonJS((exports, module) => {
|
|
|
3048
3048
|
};
|
|
3049
3049
|
});
|
|
3050
3050
|
|
|
3051
|
-
// ../../node_modules/.bun/fast-uri@3.1.
|
|
3051
|
+
// ../../node_modules/.bun/fast-uri@3.1.7/node_modules/fast-uri/lib/utils.js
|
|
3052
3052
|
var require_utils = __commonJS((exports, module) => {
|
|
3053
3053
|
var isUUID = RegExp.prototype.test.bind(/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu);
|
|
3054
3054
|
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);
|
|
3055
|
+
var isPort = RegExp.prototype.test.bind(/^\d*$/u);
|
|
3055
3056
|
var isHexPair = RegExp.prototype.test.bind(/^[\da-f]{2}$/iu);
|
|
3056
3057
|
var isUnreserved = RegExp.prototype.test.bind(/^[\da-z\-._~]$/iu);
|
|
3057
|
-
var isPathCharacter = RegExp.prototype.test.bind(/^[
|
|
3058
|
+
var isPathCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:@/]$/u);
|
|
3059
|
+
var isQueryFragmentCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:@/?]$/u);
|
|
3060
|
+
var isUserinfoCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:]$/u);
|
|
3061
|
+
var BYTE_HEX = new Array(256);
|
|
3062
|
+
{
|
|
3063
|
+
const HEX_DIGITS = "0123456789ABCDEF";
|
|
3064
|
+
for (let i = 0;i < 256; i++) {
|
|
3065
|
+
BYTE_HEX[i] = "%" + HEX_DIGITS[i >> 4] + HEX_DIGITS[i & 15];
|
|
3066
|
+
}
|
|
3067
|
+
}
|
|
3068
|
+
function percentEncodeNonAscii(cp) {
|
|
3069
|
+
if (cp < 2048) {
|
|
3070
|
+
return BYTE_HEX[192 | cp >> 6] + BYTE_HEX[128 | cp & 63];
|
|
3071
|
+
}
|
|
3072
|
+
if (cp < 65536) {
|
|
3073
|
+
return BYTE_HEX[224 | cp >> 12] + BYTE_HEX[128 | cp >> 6 & 63] + BYTE_HEX[128 | cp & 63];
|
|
3074
|
+
}
|
|
3075
|
+
return BYTE_HEX[240 | cp >> 18] + BYTE_HEX[128 | cp >> 12 & 63] + BYTE_HEX[128 | cp >> 6 & 63] + BYTE_HEX[128 | cp & 63];
|
|
3076
|
+
}
|
|
3058
3077
|
function stringArrayToHexStripped(input) {
|
|
3059
3078
|
let acc = "";
|
|
3060
3079
|
let code = 0;
|
|
@@ -3079,91 +3098,122 @@ var require_utils = __commonJS((exports, module) => {
|
|
|
3079
3098
|
}
|
|
3080
3099
|
return acc;
|
|
3081
3100
|
}
|
|
3101
|
+
var isHextet = RegExp.prototype.test.bind(/^[\dA-Fa-f]{1,4}$/);
|
|
3102
|
+
var isIPvFuture = RegExp.prototype.test.bind(/^[vV][\dA-Fa-f]+\.[A-Za-z\d\-._~!$&'()*+,;=:]+$/);
|
|
3103
|
+
var isZoneCharacter = RegExp.prototype.test.bind(/^[A-Za-z\d\-._~]$/);
|
|
3082
3104
|
var nonSimpleDomain = RegExp.prototype.test.bind(/[^!"$&'()*+,\-.;=_`a-z{}~]/u);
|
|
3083
|
-
function
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
} else {
|
|
3093
|
-
output.error = true;
|
|
3094
|
-
return false;
|
|
3105
|
+
function isZoneIdentifier(zone) {
|
|
3106
|
+
if (zone.length === 0)
|
|
3107
|
+
return false;
|
|
3108
|
+
for (let i = 0;i < zone.length; i++) {
|
|
3109
|
+
if (isZoneCharacter(zone[i]))
|
|
3110
|
+
continue;
|
|
3111
|
+
if (zone[i] === "%" && i + 2 < zone.length && isHexPair(zone.slice(i + 1, i + 3))) {
|
|
3112
|
+
i += 2;
|
|
3113
|
+
continue;
|
|
3095
3114
|
}
|
|
3096
|
-
|
|
3115
|
+
return false;
|
|
3097
3116
|
}
|
|
3098
3117
|
return true;
|
|
3099
3118
|
}
|
|
3100
|
-
function
|
|
3101
|
-
let
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
let
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
if (cursor === ":") {
|
|
3114
|
-
if (endipv6Encountered === true) {
|
|
3115
|
-
endIpv6 = true;
|
|
3116
|
-
}
|
|
3117
|
-
if (!consume(buffer, address, output)) {
|
|
3118
|
-
break;
|
|
3119
|
-
}
|
|
3120
|
-
if (++tokenCount > 7) {
|
|
3121
|
-
output.error = true;
|
|
3122
|
-
break;
|
|
3123
|
-
}
|
|
3124
|
-
if (i > 0 && input[i - 1] === ":") {
|
|
3125
|
-
endipv6Encountered = true;
|
|
3126
|
-
}
|
|
3127
|
-
address.push(":");
|
|
3128
|
-
continue;
|
|
3129
|
-
} else if (cursor === "%") {
|
|
3130
|
-
if (!consume(buffer, address, output)) {
|
|
3131
|
-
break;
|
|
3119
|
+
function compressIPv6ZeroRun(hextets) {
|
|
3120
|
+
let bestStart = -1;
|
|
3121
|
+
let bestLength = 0;
|
|
3122
|
+
let runStart = -1;
|
|
3123
|
+
let runLength = 0;
|
|
3124
|
+
for (let i = 0;i < hextets.length; i++) {
|
|
3125
|
+
if (hextets[i] === "0") {
|
|
3126
|
+
if (runStart === -1)
|
|
3127
|
+
runStart = i;
|
|
3128
|
+
runLength++;
|
|
3129
|
+
if (runLength > bestLength) {
|
|
3130
|
+
bestLength = runLength;
|
|
3131
|
+
bestStart = runStart;
|
|
3132
3132
|
}
|
|
3133
|
-
consume = consumeIsZone;
|
|
3134
3133
|
} else {
|
|
3135
|
-
|
|
3136
|
-
|
|
3134
|
+
runStart = -1;
|
|
3135
|
+
runLength = 0;
|
|
3137
3136
|
}
|
|
3138
3137
|
}
|
|
3139
|
-
if (
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3138
|
+
if (bestLength < 2)
|
|
3139
|
+
return hextets.join(":");
|
|
3140
|
+
const head = hextets.slice(0, bestStart).join(":");
|
|
3141
|
+
const tail = hextets.slice(bestStart + bestLength).join(":");
|
|
3142
|
+
return head + "::" + tail;
|
|
3143
|
+
}
|
|
3144
|
+
function normalizeIPv6Address(input) {
|
|
3145
|
+
const compression = input.indexOf("::");
|
|
3146
|
+
if (compression !== -1 && input.indexOf("::", compression + 1) !== -1)
|
|
3147
|
+
return;
|
|
3148
|
+
const left = compression === -1 ? input.split(":") : input.slice(0, compression).split(":");
|
|
3149
|
+
const right = compression === -1 ? [] : input.slice(compression + 2).split(":");
|
|
3150
|
+
if (compression !== -1) {
|
|
3151
|
+
if (left.length === 1 && left[0] === "")
|
|
3152
|
+
left.length = 0;
|
|
3153
|
+
if (right.length === 1 && right[0] === "")
|
|
3154
|
+
right.length = 0;
|
|
3155
|
+
}
|
|
3156
|
+
const parts = left.concat(right);
|
|
3157
|
+
let hextetCount = 0;
|
|
3158
|
+
for (let i = 0;i < parts.length; i++) {
|
|
3159
|
+
const part = parts[i];
|
|
3160
|
+
if (part === "")
|
|
3161
|
+
return;
|
|
3162
|
+
if (part.indexOf(".") !== -1) {
|
|
3163
|
+
if (i !== parts.length - 1 || compression !== -1 && right.length === 0 || !isIPv4(part))
|
|
3164
|
+
return;
|
|
3165
|
+
hextetCount += 2;
|
|
3166
|
+
continue;
|
|
3146
3167
|
}
|
|
3168
|
+
if (!isHextet(part))
|
|
3169
|
+
return;
|
|
3170
|
+
parts[i] = parseInt(part, 16).toString(16);
|
|
3171
|
+
hextetCount++;
|
|
3147
3172
|
}
|
|
3148
|
-
|
|
3149
|
-
|
|
3173
|
+
if (compression === -1) {
|
|
3174
|
+
if (hextetCount !== 8)
|
|
3175
|
+
return;
|
|
3176
|
+
return compressIPv6ZeroRun(parts);
|
|
3177
|
+
}
|
|
3178
|
+
if (hextetCount >= 8)
|
|
3179
|
+
return;
|
|
3180
|
+
const expanded = parts.slice(0, left.length);
|
|
3181
|
+
for (let i = hextetCount;i < 8; i++)
|
|
3182
|
+
expanded.push("0");
|
|
3183
|
+
for (let i = left.length;i < parts.length; i++)
|
|
3184
|
+
expanded.push(parts[i]);
|
|
3185
|
+
return compressIPv6ZeroRun(expanded);
|
|
3150
3186
|
}
|
|
3151
3187
|
function normalizeIPv6(host) {
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
}
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3188
|
+
const bracketed = host[0] === "[" && host[host.length - 1] === "]";
|
|
3189
|
+
const hasBracket = host[0] === "[" || host[host.length - 1] === "]";
|
|
3190
|
+
if (hasBracket && !bracketed)
|
|
3191
|
+
return { host, isIPV6: false, error: true };
|
|
3192
|
+
let input = bracketed ? host.slice(1, -1) : host;
|
|
3193
|
+
if (bracketed && isIPvFuture(input)) {
|
|
3194
|
+
input = input.toLowerCase();
|
|
3195
|
+
return { host: `[${input}]`, escapedHost: input, isIPV6: false, isIPVFuture: true };
|
|
3196
|
+
}
|
|
3197
|
+
if (findToken(input, ":") < 2) {
|
|
3198
|
+
return { host, isIPV6: false, error: bracketed };
|
|
3199
|
+
}
|
|
3200
|
+
let zoneIdentifier = "";
|
|
3201
|
+
const zoneSeparator = input.indexOf("%");
|
|
3202
|
+
if (zoneSeparator !== -1) {
|
|
3203
|
+
const separatorLength = input.slice(zoneSeparator, zoneSeparator + 3).toLowerCase() === "%25" ? 3 : 1;
|
|
3204
|
+
zoneIdentifier = input.slice(zoneSeparator + separatorLength);
|
|
3205
|
+
if (!isZoneIdentifier(zoneIdentifier))
|
|
3206
|
+
return { host, isIPV6: false, error: true };
|
|
3207
|
+
input = input.slice(0, zoneSeparator);
|
|
3208
|
+
}
|
|
3209
|
+
const address = normalizeIPv6Address(input);
|
|
3210
|
+
if (address === undefined)
|
|
3211
|
+
return { host, isIPV6: false, error: true };
|
|
3212
|
+
return {
|
|
3213
|
+
host: address + (zoneIdentifier ? "%" + zoneIdentifier : ""),
|
|
3214
|
+
escapedHost: address + (zoneIdentifier ? "%25" + zoneIdentifier : ""),
|
|
3215
|
+
isIPV6: true
|
|
3216
|
+
};
|
|
3167
3217
|
}
|
|
3168
3218
|
function findToken(str, token) {
|
|
3169
3219
|
let ind = 0;
|
|
@@ -3283,7 +3333,8 @@ var require_utils = __commonJS((exports, module) => {
|
|
|
3283
3333
|
function normalizePathEncoding(input) {
|
|
3284
3334
|
let output = "";
|
|
3285
3335
|
for (let i = 0;i < input.length; i++) {
|
|
3286
|
-
|
|
3336
|
+
const ch = input[i];
|
|
3337
|
+
if (ch === "%" && i + 2 < input.length) {
|
|
3287
3338
|
const hex = input.slice(i + 1, i + 3);
|
|
3288
3339
|
if (isHexPair(hex)) {
|
|
3289
3340
|
const normalizedHex = hex.toUpperCase();
|
|
@@ -3297,10 +3348,152 @@ var require_utils = __commonJS((exports, module) => {
|
|
|
3297
3348
|
continue;
|
|
3298
3349
|
}
|
|
3299
3350
|
}
|
|
3300
|
-
if (isPathCharacter(
|
|
3301
|
-
output +=
|
|
3351
|
+
if (isPathCharacter(ch)) {
|
|
3352
|
+
output += ch;
|
|
3353
|
+
} else {
|
|
3354
|
+
const code = input.charCodeAt(i);
|
|
3355
|
+
if (code < 128) {
|
|
3356
|
+
output += isEscapeSafe(code) ? ch : BYTE_HEX[code];
|
|
3357
|
+
} else if (code < 55296 || code > 57343) {
|
|
3358
|
+
output += percentEncodeNonAscii(code);
|
|
3359
|
+
} else if (code <= 56319 && i + 1 < input.length) {
|
|
3360
|
+
const low = input.charCodeAt(i + 1);
|
|
3361
|
+
if (low >= 56320 && low <= 57343) {
|
|
3362
|
+
output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
|
|
3363
|
+
i++;
|
|
3364
|
+
} else {
|
|
3365
|
+
output += percentEncodeNonAscii(65533);
|
|
3366
|
+
}
|
|
3367
|
+
} else {
|
|
3368
|
+
output += percentEncodeNonAscii(65533);
|
|
3369
|
+
}
|
|
3370
|
+
}
|
|
3371
|
+
}
|
|
3372
|
+
return output;
|
|
3373
|
+
}
|
|
3374
|
+
function serializePathEncoding(input, pathNoScheme = false) {
|
|
3375
|
+
let output = "";
|
|
3376
|
+
let firstSegment = pathNoScheme && input[0] !== "/";
|
|
3377
|
+
for (let i = 0;i < input.length; i++) {
|
|
3378
|
+
const ch = input[i];
|
|
3379
|
+
if (ch === "%" && i + 2 < input.length) {
|
|
3380
|
+
const hex = input.slice(i + 1, i + 3);
|
|
3381
|
+
if (isHexPair(hex)) {
|
|
3382
|
+
output += "%" + hex.toUpperCase();
|
|
3383
|
+
i += 2;
|
|
3384
|
+
continue;
|
|
3385
|
+
}
|
|
3386
|
+
}
|
|
3387
|
+
if (ch === "/") {
|
|
3388
|
+
firstSegment = false;
|
|
3389
|
+
}
|
|
3390
|
+
if (isPathCharacter(ch) && (ch !== ":" || !firstSegment)) {
|
|
3391
|
+
output += ch;
|
|
3392
|
+
} else {
|
|
3393
|
+
const code = input.charCodeAt(i);
|
|
3394
|
+
if (code < 128) {
|
|
3395
|
+
output += 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 encodeComponent(input, isAllowed) {
|
|
3414
|
+
let output = "";
|
|
3415
|
+
for (let i = 0;i < input.length; i++) {
|
|
3416
|
+
const ch = input[i];
|
|
3417
|
+
if (ch === "%" && i + 2 < input.length) {
|
|
3418
|
+
const hex = input.slice(i + 1, i + 3);
|
|
3419
|
+
if (isHexPair(hex)) {
|
|
3420
|
+
output += "%" + hex.toUpperCase();
|
|
3421
|
+
i += 2;
|
|
3422
|
+
continue;
|
|
3423
|
+
}
|
|
3424
|
+
}
|
|
3425
|
+
if (isAllowed(ch)) {
|
|
3426
|
+
output += ch;
|
|
3427
|
+
} else {
|
|
3428
|
+
const code = input.charCodeAt(i);
|
|
3429
|
+
if (code < 128) {
|
|
3430
|
+
output += BYTE_HEX[code];
|
|
3431
|
+
} else if (code < 55296 || code > 57343) {
|
|
3432
|
+
output += percentEncodeNonAscii(code);
|
|
3433
|
+
} else if (code <= 56319 && i + 1 < input.length) {
|
|
3434
|
+
const low = input.charCodeAt(i + 1);
|
|
3435
|
+
if (low >= 56320 && low <= 57343) {
|
|
3436
|
+
output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
|
|
3437
|
+
i++;
|
|
3438
|
+
} else {
|
|
3439
|
+
output += percentEncodeNonAscii(65533);
|
|
3440
|
+
}
|
|
3441
|
+
} else {
|
|
3442
|
+
output += percentEncodeNonAscii(65533);
|
|
3443
|
+
}
|
|
3444
|
+
}
|
|
3445
|
+
}
|
|
3446
|
+
return output;
|
|
3447
|
+
}
|
|
3448
|
+
function encodeUserinfo(input) {
|
|
3449
|
+
return encodeComponent(input, isUserinfoCharacter);
|
|
3450
|
+
}
|
|
3451
|
+
function encodeQuery(input) {
|
|
3452
|
+
return encodeComponent(input, isQueryFragmentCharacter);
|
|
3453
|
+
}
|
|
3454
|
+
function encodeFragment(input) {
|
|
3455
|
+
return encodeComponent(input, isQueryFragmentCharacter);
|
|
3456
|
+
}
|
|
3457
|
+
function isEscapeSafe(cp) {
|
|
3458
|
+
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;
|
|
3459
|
+
}
|
|
3460
|
+
function normalizeQueryFragmentEncoding(input) {
|
|
3461
|
+
let output = "";
|
|
3462
|
+
for (let i = 0;i < input.length; i++) {
|
|
3463
|
+
const ch = input[i];
|
|
3464
|
+
if (ch === "%" && i + 2 < input.length) {
|
|
3465
|
+
const hex = input.slice(i + 1, i + 3);
|
|
3466
|
+
if (isHexPair(hex)) {
|
|
3467
|
+
const normalizedHex = hex.toUpperCase();
|
|
3468
|
+
const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
|
|
3469
|
+
if (isUnreserved(decoded)) {
|
|
3470
|
+
output += decoded;
|
|
3471
|
+
} else {
|
|
3472
|
+
output += "%" + normalizedHex;
|
|
3473
|
+
}
|
|
3474
|
+
i += 2;
|
|
3475
|
+
continue;
|
|
3476
|
+
}
|
|
3477
|
+
}
|
|
3478
|
+
if (isQueryFragmentCharacter(ch)) {
|
|
3479
|
+
output += ch;
|
|
3302
3480
|
} else {
|
|
3303
|
-
|
|
3481
|
+
const code = input.charCodeAt(i);
|
|
3482
|
+
if (code < 128) {
|
|
3483
|
+
output += isEscapeSafe(code) ? ch : BYTE_HEX[code];
|
|
3484
|
+
} else if (code < 55296 || code > 57343) {
|
|
3485
|
+
output += percentEncodeNonAscii(code);
|
|
3486
|
+
} else if (code <= 56319 && i + 1 < input.length) {
|
|
3487
|
+
const low = input.charCodeAt(i + 1);
|
|
3488
|
+
if (low >= 56320 && low <= 57343) {
|
|
3489
|
+
output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
|
|
3490
|
+
i++;
|
|
3491
|
+
} else {
|
|
3492
|
+
output += percentEncodeNonAscii(65533);
|
|
3493
|
+
}
|
|
3494
|
+
} else {
|
|
3495
|
+
output += percentEncodeNonAscii(65533);
|
|
3496
|
+
}
|
|
3304
3497
|
}
|
|
3305
3498
|
}
|
|
3306
3499
|
return output;
|
|
@@ -3323,14 +3516,18 @@ var require_utils = __commonJS((exports, module) => {
|
|
|
3323
3516
|
function recomposeAuthority(component) {
|
|
3324
3517
|
const uriTokens = [];
|
|
3325
3518
|
if (component.userinfo !== undefined) {
|
|
3326
|
-
uriTokens.push(component.userinfo);
|
|
3519
|
+
uriTokens.push(encodeUserinfo(component.userinfo));
|
|
3327
3520
|
uriTokens.push("@");
|
|
3328
3521
|
}
|
|
3329
3522
|
if (component.host !== undefined) {
|
|
3330
|
-
let host =
|
|
3523
|
+
let host = component.host;
|
|
3331
3524
|
if (!isIPv4(host)) {
|
|
3332
|
-
|
|
3333
|
-
if (ipV6res.isIPV6
|
|
3525
|
+
let ipV6res = normalizeIPv6(host);
|
|
3526
|
+
if (ipV6res.isIPV6 !== true && ipV6res.isIPVFuture !== true) {
|
|
3527
|
+
host = normalizePercentEncoding(host, true);
|
|
3528
|
+
ipV6res = normalizeIPv6(host);
|
|
3529
|
+
}
|
|
3530
|
+
if (ipV6res.isIPV6 === true || ipV6res.isIPVFuture === true) {
|
|
3334
3531
|
host = `[${ipV6res.escapedHost}]`;
|
|
3335
3532
|
} else {
|
|
3336
3533
|
host = reescapeHostDelimiters(host, false);
|
|
@@ -3339,8 +3536,12 @@ var require_utils = __commonJS((exports, module) => {
|
|
|
3339
3536
|
uriTokens.push(host);
|
|
3340
3537
|
}
|
|
3341
3538
|
if (typeof component.port === "number" || typeof component.port === "string") {
|
|
3539
|
+
const port = String(component.port);
|
|
3540
|
+
if (!isPort(port)) {
|
|
3541
|
+
throw new TypeError("URI port is malformed.");
|
|
3542
|
+
}
|
|
3342
3543
|
uriTokens.push(":");
|
|
3343
|
-
uriTokens.push(
|
|
3544
|
+
uriTokens.push(port);
|
|
3344
3545
|
}
|
|
3345
3546
|
return uriTokens.length ? uriTokens.join("") : undefined;
|
|
3346
3547
|
}
|
|
@@ -3350,6 +3551,11 @@ var require_utils = __commonJS((exports, module) => {
|
|
|
3350
3551
|
reescapeHostDelimiters,
|
|
3351
3552
|
normalizePercentEncoding,
|
|
3352
3553
|
normalizePathEncoding,
|
|
3554
|
+
serializePathEncoding,
|
|
3555
|
+
normalizeQueryFragmentEncoding,
|
|
3556
|
+
encodeUserinfo,
|
|
3557
|
+
encodeQuery,
|
|
3558
|
+
encodeFragment,
|
|
3353
3559
|
escapePreservingEscapes,
|
|
3354
3560
|
removeDotSegments,
|
|
3355
3561
|
isIPv4,
|
|
@@ -3359,10 +3565,10 @@ var require_utils = __commonJS((exports, module) => {
|
|
|
3359
3565
|
};
|
|
3360
3566
|
});
|
|
3361
3567
|
|
|
3362
|
-
// ../../node_modules/.bun/fast-uri@3.1.
|
|
3568
|
+
// ../../node_modules/.bun/fast-uri@3.1.7/node_modules/fast-uri/lib/schemes.js
|
|
3363
3569
|
var require_schemes = __commonJS((exports, module) => {
|
|
3364
3570
|
var { isUUID } = require_utils();
|
|
3365
|
-
var URN_REG =
|
|
3571
|
+
var URN_REG = /^([\da-z][\d\-a-z]{0,31}):((?:[\w!$'()*+,\-./:;=@]|%[\da-f]{2})+)$/iu;
|
|
3366
3572
|
var supportedSchemeNames = [
|
|
3367
3573
|
"http",
|
|
3368
3574
|
"https",
|
|
@@ -3417,9 +3623,10 @@ var require_schemes = __commonJS((exports, module) => {
|
|
|
3417
3623
|
wsComponent.secure = undefined;
|
|
3418
3624
|
}
|
|
3419
3625
|
if (wsComponent.resourceName) {
|
|
3420
|
-
const
|
|
3626
|
+
const queryIndex = wsComponent.resourceName.indexOf("?");
|
|
3627
|
+
const path = queryIndex === -1 ? wsComponent.resourceName : wsComponent.resourceName.slice(0, queryIndex);
|
|
3421
3628
|
wsComponent.path = path && path !== "/" ? path : undefined;
|
|
3422
|
-
wsComponent.query =
|
|
3629
|
+
wsComponent.query = queryIndex === -1 ? undefined : wsComponent.resourceName.slice(queryIndex + 1);
|
|
3423
3630
|
wsComponent.resourceName = undefined;
|
|
3424
3631
|
}
|
|
3425
3632
|
wsComponent.fragment = undefined;
|
|
@@ -3431,7 +3638,7 @@ var require_schemes = __commonJS((exports, module) => {
|
|
|
3431
3638
|
return urnComponent;
|
|
3432
3639
|
}
|
|
3433
3640
|
const matches = urnComponent.path.match(URN_REG);
|
|
3434
|
-
if (matches) {
|
|
3641
|
+
if (matches && matches[0] === urnComponent.path) {
|
|
3435
3642
|
const scheme = options.scheme || urnComponent.scheme || "urn";
|
|
3436
3643
|
urnComponent.nid = matches[1].toLowerCase();
|
|
3437
3644
|
urnComponent.nss = matches[2];
|
|
@@ -3533,10 +3740,19 @@ var require_schemes = __commonJS((exports, module) => {
|
|
|
3533
3740
|
};
|
|
3534
3741
|
});
|
|
3535
3742
|
|
|
3536
|
-
// ../../node_modules/.bun/fast-uri@3.1.
|
|
3743
|
+
// ../../node_modules/.bun/fast-uri@3.1.7/node_modules/fast-uri/index.js
|
|
3537
3744
|
var require_fast_uri = __commonJS((exports, module) => {
|
|
3538
|
-
var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding,
|
|
3745
|
+
var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, serializePathEncoding, normalizeQueryFragmentEncoding, encodeQuery, encodeFragment, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils();
|
|
3539
3746
|
var { SCHEMES, getSchemeHandler } = require_schemes();
|
|
3747
|
+
var VALID_SCHEME = /^[A-Za-z][A-Za-z0-9+.-]*$/u;
|
|
3748
|
+
var MALFORMED_SCHEME_ERROR = "URI scheme is malformed.";
|
|
3749
|
+
function decodeValidScheme(scheme) {
|
|
3750
|
+
const decodedScheme = unescape(String(scheme));
|
|
3751
|
+
if (!VALID_SCHEME.test(decodedScheme)) {
|
|
3752
|
+
throw new TypeError(MALFORMED_SCHEME_ERROR);
|
|
3753
|
+
}
|
|
3754
|
+
return decodedScheme;
|
|
3755
|
+
}
|
|
3540
3756
|
function normalize(uri, options) {
|
|
3541
3757
|
if (typeof uri === "string") {
|
|
3542
3758
|
uri = normalizeString(uri, options);
|
|
@@ -3547,12 +3763,34 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3547
3763
|
}
|
|
3548
3764
|
function resolve(baseURI, relativeURI, options) {
|
|
3549
3765
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
3550
|
-
const {
|
|
3551
|
-
|
|
3552
|
-
|
|
3766
|
+
const {
|
|
3767
|
+
parsed: baseParsed,
|
|
3768
|
+
malformedAuthorityOrPort: baseMalformed,
|
|
3769
|
+
malformedPercentEncoding: baseMalformedPercentEncoding,
|
|
3770
|
+
malformedSchemeSpecific: baseMalformedSchemeSpecific,
|
|
3771
|
+
malformedHost: baseMalformedHost,
|
|
3772
|
+
malformedScheme: baseMalformedScheme
|
|
3773
|
+
} = parseWithStatus(baseURI, schemelessOptions);
|
|
3774
|
+
const {
|
|
3775
|
+
parsed: relativeParsed,
|
|
3776
|
+
malformedAuthorityOrPort: relativeMalformed,
|
|
3777
|
+
malformedPercentEncoding: relativeMalformedPercentEncoding,
|
|
3778
|
+
malformedSchemeSpecific: relativeMalformedSchemeSpecific,
|
|
3779
|
+
malformedHost: relativeMalformedHost,
|
|
3780
|
+
malformedScheme: relativeMalformedScheme
|
|
3781
|
+
} = parseWithStatus(relativeURI, schemelessOptions);
|
|
3782
|
+
if (baseMalformed || relativeMalformed || baseMalformedPercentEncoding || relativeMalformedPercentEncoding || baseMalformedSchemeSpecific || relativeMalformedSchemeSpecific || baseMalformedHost || relativeMalformedHost || baseMalformedScheme || relativeMalformedScheme) {
|
|
3553
3783
|
throw new Error(baseParsed.error || relativeParsed.error || "URI is malformed.");
|
|
3554
3784
|
}
|
|
3555
3785
|
const resolved = resolveComponent(baseParsed, relativeParsed, schemelessOptions, true);
|
|
3786
|
+
const resolvedSchemeHandler = getSchemeHandler(options && options.scheme || resolved.scheme);
|
|
3787
|
+
const resolvedHost = resolved.host;
|
|
3788
|
+
const resolvedHostIsIP = resolvedHost !== undefined && resolvedHost !== "" && (isIPv4(resolvedHost) || normalizeIPv6(resolvedHost).isIPV6);
|
|
3789
|
+
canonicalizeHost(resolved, options || {}, resolvedSchemeHandler, resolvedHostIsIP);
|
|
3790
|
+
const encodedASCIIHost = resolvedHost && resolvedHost.indexOf("%") !== -1 && !/\P{ASCII}/u.test(resolvedHost);
|
|
3791
|
+
if (resolved.error && !encodedASCIIHost) {
|
|
3792
|
+
throw new Error(resolved.error);
|
|
3793
|
+
}
|
|
3556
3794
|
schemelessOptions.skipEscape = true;
|
|
3557
3795
|
return serialize(resolved, schemelessOptions);
|
|
3558
3796
|
}
|
|
@@ -3612,7 +3850,7 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3612
3850
|
function equal(uriA, uriB, options) {
|
|
3613
3851
|
const normalizedA = normalizeComparableURI(uriA, options);
|
|
3614
3852
|
const normalizedB = normalizeComparableURI(uriB, options);
|
|
3615
|
-
return normalizedA !== undefined && normalizedB !== undefined && normalizedA
|
|
3853
|
+
return normalizedA !== undefined && normalizedB !== undefined && normalizedA === normalizedB;
|
|
3616
3854
|
}
|
|
3617
3855
|
function serialize(cmpts, opts) {
|
|
3618
3856
|
const component = {
|
|
@@ -3633,20 +3871,23 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3633
3871
|
};
|
|
3634
3872
|
const options = Object.assign({}, opts);
|
|
3635
3873
|
const uriTokens = [];
|
|
3874
|
+
if (component.scheme) {
|
|
3875
|
+
component.scheme = decodeValidScheme(component.scheme);
|
|
3876
|
+
}
|
|
3636
3877
|
const schemeHandler = getSchemeHandler(options.scheme || component.scheme);
|
|
3637
3878
|
if (schemeHandler && schemeHandler.serialize)
|
|
3638
3879
|
schemeHandler.serialize(component, options);
|
|
3880
|
+
const hasAuthority = component.userinfo !== undefined || component.host !== undefined || component.port !== undefined;
|
|
3881
|
+
const pathNoScheme = !options.skipEscape && component.scheme === undefined && !hasAuthority;
|
|
3639
3882
|
if (component.path !== undefined) {
|
|
3640
3883
|
if (!options.skipEscape) {
|
|
3641
|
-
component.path =
|
|
3642
|
-
if (component.scheme !== undefined) {
|
|
3643
|
-
component.path = component.path.split("%3A").join(":");
|
|
3644
|
-
}
|
|
3884
|
+
component.path = serializePathEncoding(component.path, pathNoScheme);
|
|
3645
3885
|
} else {
|
|
3646
3886
|
component.path = normalizePercentEncoding(component.path);
|
|
3647
3887
|
}
|
|
3648
3888
|
}
|
|
3649
3889
|
if (options.reference !== "suffix" && component.scheme) {
|
|
3890
|
+
component.scheme = decodeValidScheme(component.scheme);
|
|
3650
3891
|
uriTokens.push(component.scheme, ":");
|
|
3651
3892
|
}
|
|
3652
3893
|
const authority = recomposeAuthority(component);
|
|
@@ -3664,16 +3905,19 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3664
3905
|
if (!options.absolutePath && (!schemeHandler || !schemeHandler.absolutePath)) {
|
|
3665
3906
|
s = removeDotSegments(s);
|
|
3666
3907
|
}
|
|
3908
|
+
if (pathNoScheme) {
|
|
3909
|
+
s = serializePathEncoding(s, true);
|
|
3910
|
+
}
|
|
3667
3911
|
if (authority === undefined && s[0] === "/" && s[1] === "/") {
|
|
3668
3912
|
s = "/%2F" + s.slice(2);
|
|
3669
3913
|
}
|
|
3670
3914
|
uriTokens.push(s);
|
|
3671
3915
|
}
|
|
3672
3916
|
if (component.query !== undefined) {
|
|
3673
|
-
uriTokens.push("?", component.query);
|
|
3917
|
+
uriTokens.push("?", encodeQuery(component.query));
|
|
3674
3918
|
}
|
|
3675
3919
|
if (component.fragment !== undefined) {
|
|
3676
|
-
uriTokens.push("#", component.fragment);
|
|
3920
|
+
uriTokens.push("#", encodeFragment(component.fragment));
|
|
3677
3921
|
}
|
|
3678
3922
|
return uriTokens.join("");
|
|
3679
3923
|
}
|
|
@@ -3689,6 +3933,36 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3689
3933
|
}
|
|
3690
3934
|
return;
|
|
3691
3935
|
}
|
|
3936
|
+
function hasMalformedPercentEncoding(component) {
|
|
3937
|
+
if (component === undefined)
|
|
3938
|
+
return false;
|
|
3939
|
+
let percent = component.indexOf("%");
|
|
3940
|
+
while (percent !== -1) {
|
|
3941
|
+
if (percent + 2 >= component.length || !/^[\da-f]{2}$/iu.test(component.slice(percent + 1, percent + 3))) {
|
|
3942
|
+
return true;
|
|
3943
|
+
}
|
|
3944
|
+
percent = component.indexOf("%", percent + 3);
|
|
3945
|
+
}
|
|
3946
|
+
return false;
|
|
3947
|
+
}
|
|
3948
|
+
function isIPLiteral(host) {
|
|
3949
|
+
return host[0] === "[" && host[host.length - 1] === "]";
|
|
3950
|
+
}
|
|
3951
|
+
function hasMalformedComponentPercentEncoding(matches) {
|
|
3952
|
+
const host = matches[4];
|
|
3953
|
+
return hasMalformedPercentEncoding(matches[3]) || host !== undefined && !isIPLiteral(host) && hasMalformedPercentEncoding(host) || hasMalformedPercentEncoding(matches[6]) || hasMalformedPercentEncoding(matches[7]) || hasMalformedPercentEncoding(matches[8]);
|
|
3954
|
+
}
|
|
3955
|
+
function canonicalizeHost(parsed, options, schemeHandler, isIP) {
|
|
3956
|
+
if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport) && parsed.host && !isIPLiteral(parsed.host) && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP === false && nonSimpleDomain(parsed.host)) {
|
|
3957
|
+
try {
|
|
3958
|
+
parsed.host = new URL("http://" + parsed.host).hostname;
|
|
3959
|
+
} catch (e) {
|
|
3960
|
+
parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e;
|
|
3961
|
+
return true;
|
|
3962
|
+
}
|
|
3963
|
+
}
|
|
3964
|
+
return false;
|
|
3965
|
+
}
|
|
3692
3966
|
function parseWithStatus(uri, opts) {
|
|
3693
3967
|
const options = Object.assign({}, opts);
|
|
3694
3968
|
const parsed = {
|
|
@@ -3701,6 +3975,11 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3701
3975
|
fragment: undefined
|
|
3702
3976
|
};
|
|
3703
3977
|
let malformedAuthorityOrPort = false;
|
|
3978
|
+
let malformedPercentEncoding = false;
|
|
3979
|
+
let malformedSchemeSpecific = false;
|
|
3980
|
+
let malformedHost = false;
|
|
3981
|
+
let malformedIPLiteral = false;
|
|
3982
|
+
let malformedScheme = false;
|
|
3704
3983
|
let isIP = false;
|
|
3705
3984
|
if (options.reference === "suffix") {
|
|
3706
3985
|
if (options.scheme) {
|
|
@@ -3737,6 +4016,19 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3737
4016
|
parsed.path = matches[6] || "";
|
|
3738
4017
|
parsed.query = matches[7];
|
|
3739
4018
|
parsed.fragment = matches[8];
|
|
4019
|
+
if (parsed.scheme !== undefined) {
|
|
4020
|
+
const decodedScheme = unescape(parsed.scheme);
|
|
4021
|
+
if (VALID_SCHEME.test(decodedScheme)) {
|
|
4022
|
+
parsed.scheme = decodedScheme.toLowerCase();
|
|
4023
|
+
} else {
|
|
4024
|
+
parsed.error = parsed.error || MALFORMED_SCHEME_ERROR;
|
|
4025
|
+
malformedScheme = true;
|
|
4026
|
+
}
|
|
4027
|
+
}
|
|
4028
|
+
malformedPercentEncoding = hasMalformedComponentPercentEncoding(matches);
|
|
4029
|
+
if (malformedPercentEncoding) {
|
|
4030
|
+
parsed.error = parsed.error || "URI contains malformed percent-encoding.";
|
|
4031
|
+
}
|
|
3740
4032
|
if (isNaN(parsed.port)) {
|
|
3741
4033
|
parsed.port = matches[5];
|
|
3742
4034
|
}
|
|
@@ -3748,9 +4040,16 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3748
4040
|
if (parsed.host) {
|
|
3749
4041
|
const ipv4result = isIPv4(parsed.host);
|
|
3750
4042
|
if (ipv4result === false) {
|
|
4043
|
+
const bracketedIPLiteral = isIPLiteral(parsed.host);
|
|
4044
|
+
const hasIPLiteralBracket = parsed.host.indexOf("[") !== -1 || parsed.host.indexOf("]") !== -1;
|
|
3751
4045
|
const ipv6result = normalizeIPv6(parsed.host);
|
|
3752
|
-
|
|
3753
|
-
|
|
4046
|
+
isIP = ipv6result.isIPV6 || ipv6result.isIPVFuture === true;
|
|
4047
|
+
malformedIPLiteral = hasIPLiteralBracket && (!bracketedIPLiteral || ipv6result.error === true);
|
|
4048
|
+
parsed.host = isIP ? ipv6result.host : ipv6result.host.toLowerCase();
|
|
4049
|
+
if (malformedIPLiteral) {
|
|
4050
|
+
parsed.error = parsed.error || "URI host is malformed.";
|
|
4051
|
+
malformedAuthorityOrPort = true;
|
|
4052
|
+
}
|
|
3754
4053
|
} else {
|
|
3755
4054
|
isIP = true;
|
|
3756
4055
|
}
|
|
@@ -3768,42 +4067,36 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3768
4067
|
parsed.error = parsed.error || "URI is not a " + options.reference + " reference.";
|
|
3769
4068
|
}
|
|
3770
4069
|
const schemeHandler = getSchemeHandler(options.scheme || parsed.scheme);
|
|
3771
|
-
if (!
|
|
3772
|
-
|
|
3773
|
-
try {
|
|
3774
|
-
parsed.host = new URL("http://" + parsed.host).hostname;
|
|
3775
|
-
} catch (e) {
|
|
3776
|
-
parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e;
|
|
3777
|
-
}
|
|
3778
|
-
}
|
|
4070
|
+
if (!malformedIPLiteral) {
|
|
4071
|
+
malformedHost = canonicalizeHost(parsed, options, schemeHandler, isIP);
|
|
3779
4072
|
}
|
|
3780
4073
|
if (!schemeHandler || schemeHandler && !schemeHandler.skipNormalize) {
|
|
3781
4074
|
if (uri.indexOf("%") !== -1) {
|
|
3782
|
-
if (parsed.
|
|
3783
|
-
parsed.
|
|
3784
|
-
|
|
3785
|
-
if (parsed.host !== undefined) {
|
|
3786
|
-
parsed.host = reescapeHostDelimiters(unescape(parsed.host), isIP);
|
|
4075
|
+
if (parsed.host !== undefined && !malformedIPLiteral) {
|
|
4076
|
+
const host = isIP ? parsed.host : normalizePercentEncoding(parsed.host, true);
|
|
4077
|
+
parsed.host = reescapeHostDelimiters(host, isIP);
|
|
3787
4078
|
}
|
|
3788
4079
|
}
|
|
3789
4080
|
if (parsed.path) {
|
|
3790
4081
|
parsed.path = normalizePathEncoding(parsed.path);
|
|
3791
4082
|
}
|
|
4083
|
+
if (parsed.query) {
|
|
4084
|
+
parsed.query = normalizeQueryFragmentEncoding(parsed.query);
|
|
4085
|
+
}
|
|
3792
4086
|
if (parsed.fragment) {
|
|
3793
|
-
|
|
3794
|
-
parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment));
|
|
3795
|
-
} catch {
|
|
3796
|
-
parsed.error = parsed.error || "URI malformed";
|
|
3797
|
-
}
|
|
4087
|
+
parsed.fragment = normalizeQueryFragmentEncoding(parsed.fragment);
|
|
3798
4088
|
}
|
|
3799
4089
|
}
|
|
3800
4090
|
if (schemeHandler && schemeHandler.parse) {
|
|
3801
4091
|
schemeHandler.parse(parsed, options);
|
|
4092
|
+
if (schemeHandler === SCHEMES.urn && parsed.nid === undefined) {
|
|
4093
|
+
malformedSchemeSpecific = true;
|
|
4094
|
+
}
|
|
3802
4095
|
}
|
|
3803
4096
|
} else {
|
|
3804
4097
|
parsed.error = parsed.error || "URI can not be parsed.";
|
|
3805
4098
|
}
|
|
3806
|
-
return { parsed, malformedAuthorityOrPort };
|
|
4099
|
+
return { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme };
|
|
3807
4100
|
}
|
|
3808
4101
|
function parse6(uri, opts) {
|
|
3809
4102
|
return parseWithStatus(uri, opts).parsed;
|
|
@@ -3812,20 +4105,28 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3812
4105
|
return normalizeStringWithStatus(uri, opts).normalized;
|
|
3813
4106
|
}
|
|
3814
4107
|
function normalizeStringWithStatus(uri, opts) {
|
|
3815
|
-
const { parsed, malformedAuthorityOrPort } = parseWithStatus(uri, opts);
|
|
4108
|
+
const { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme } = parseWithStatus(uri, opts);
|
|
3816
4109
|
return {
|
|
3817
|
-
normalized: malformedAuthorityOrPort ? uri : serialize(parsed, opts),
|
|
3818
|
-
malformedAuthorityOrPort
|
|
4110
|
+
normalized: malformedAuthorityOrPort || malformedPercentEncoding || malformedSchemeSpecific || malformedHost || malformedScheme ? uri : serialize(parsed, opts),
|
|
4111
|
+
malformedAuthorityOrPort,
|
|
4112
|
+
malformedPercentEncoding,
|
|
4113
|
+
malformedSchemeSpecific,
|
|
4114
|
+
malformedHost,
|
|
4115
|
+
malformedScheme
|
|
3819
4116
|
};
|
|
3820
4117
|
}
|
|
3821
4118
|
function normalizeComparableURI(uri, opts) {
|
|
3822
|
-
if (typeof uri
|
|
3823
|
-
|
|
3824
|
-
return malformedAuthorityOrPort ? undefined : normalized;
|
|
4119
|
+
if (typeof uri !== "string" && typeof uri !== "object") {
|
|
4120
|
+
return;
|
|
3825
4121
|
}
|
|
3826
|
-
|
|
3827
|
-
|
|
4122
|
+
let value;
|
|
4123
|
+
try {
|
|
4124
|
+
value = typeof uri === "string" ? uri : serialize(uri, opts);
|
|
4125
|
+
} catch {
|
|
4126
|
+
return;
|
|
3828
4127
|
}
|
|
4128
|
+
const { normalized, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme } = normalizeStringWithStatus(value, opts);
|
|
4129
|
+
return malformedAuthorityOrPort || malformedPercentEncoding || malformedSchemeSpecific || malformedHost || malformedScheme ? undefined : normalized;
|
|
3829
4130
|
}
|
|
3830
4131
|
var fastUri = {
|
|
3831
4132
|
SCHEMES,
|
|
@@ -6631,451 +6932,855 @@ var require_dist = __commonJS((exports, module) => {
|
|
|
6631
6932
|
exports.default = formatsPlugin;
|
|
6632
6933
|
});
|
|
6633
6934
|
|
|
6634
|
-
// src/lib/
|
|
6635
|
-
function
|
|
6636
|
-
const
|
|
6637
|
-
|
|
6638
|
-
|
|
6639
|
-
|
|
6935
|
+
// src/lib/remote-run-contract.ts
|
|
6936
|
+
function normalizeRemoteSkillRunContract(payload, fallbackSkill) {
|
|
6937
|
+
const record3 = isRecord3(payload) ? payload : {};
|
|
6938
|
+
return {
|
|
6939
|
+
contractVersion: REMOTE_SKILL_RUN_CONTRACT_VERSION,
|
|
6940
|
+
...pickString(record3, "id"),
|
|
6941
|
+
skill: pickStringValue(record3, "skill") ?? fallbackSkill,
|
|
6942
|
+
...pickString(record3, "requestedSlug"),
|
|
6943
|
+
...pickString(record3, "status"),
|
|
6944
|
+
...pickNumber(record3, "exitCode"),
|
|
6945
|
+
...pickString(record3, "correlationId"),
|
|
6946
|
+
...pickString(record3, "createdAt"),
|
|
6947
|
+
...pickString(record3, "startedAt"),
|
|
6948
|
+
...pickString(record3, "completedAt"),
|
|
6949
|
+
...pickNumber(record3, "durationMs"),
|
|
6950
|
+
...pickString(record3, "outputType"),
|
|
6951
|
+
...hasOwn(record3, "outputPreview") ? { outputPreview: record3.outputPreview } : {},
|
|
6952
|
+
...pickString(record3, "errorCode"),
|
|
6953
|
+
...pickString(record3, "errorMessage"),
|
|
6954
|
+
...pickString(record3, "error"),
|
|
6955
|
+
...pickString(record3, "code"),
|
|
6956
|
+
...hasOwn(record3, "details") ? { details: record3.details } : {}
|
|
6957
|
+
};
|
|
6640
6958
|
}
|
|
6641
|
-
function
|
|
6642
|
-
|
|
6643
|
-
for (const [name, value] of Object.entries(env)) {
|
|
6644
|
-
if (value === undefined || value === "")
|
|
6645
|
-
continue;
|
|
6646
|
-
if (isRetiredModeEnvVar(name, app))
|
|
6647
|
-
found.push({ name, value });
|
|
6648
|
-
}
|
|
6649
|
-
return found.sort((a, b) => a.name.localeCompare(b.name));
|
|
6959
|
+
function isRecord3(value) {
|
|
6960
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
6650
6961
|
}
|
|
6651
|
-
function
|
|
6652
|
-
|
|
6653
|
-
if (found.length === 0)
|
|
6654
|
-
return;
|
|
6655
|
-
const names = found.map((entry) => entry.name);
|
|
6656
|
-
throw new RetiredSettingError(names[0], `${names.join(", ")} ${names.length === 1 ? "is" : "are"} no longer read. ` + "Deployment modes were removed: where a server keeps its data is decided by the " + `database it is given, not by a declared label. Set ${options.replacement} to a ` + "postgres:// URL to use PostgreSQL, or leave it unset for the on-box SQLite database. " + `Then unset ${names.join(" and ")}. ` + "Refused rather than ignored, because a discarded setting looks exactly like a " + "working one until something needs the data.");
|
|
6962
|
+
function hasOwn(record3, key) {
|
|
6963
|
+
return Object.prototype.hasOwnProperty.call(record3, key);
|
|
6657
6964
|
}
|
|
6658
|
-
function
|
|
6659
|
-
|
|
6660
|
-
|
|
6661
|
-
continue;
|
|
6662
|
-
throw new RetiredSettingError(key, `${source}: "${key}" is no longer a configuration key. ` + "Deployment modes were removed: a Skills client either has an API origin " + "configured or it does not, and that is the whole of it. " + `Use "${replacement}" instead (skills config set ${replacement} <origin>), and ` + `remove the old key with: skills config unset ${key}. ` + "Refused rather than ignored, because silently dropping it would leave an " + "operator believing they had pointed this install at a server.");
|
|
6663
|
-
}
|
|
6965
|
+
function pickString(record3, key) {
|
|
6966
|
+
const value = pickStringValue(record3, key);
|
|
6967
|
+
return value === undefined ? {} : { [key]: value };
|
|
6664
6968
|
}
|
|
6665
|
-
|
|
6666
|
-
|
|
6667
|
-
|
|
6668
|
-
|
|
6669
|
-
|
|
6670
|
-
|
|
6671
|
-
|
|
6672
|
-
|
|
6673
|
-
|
|
6674
|
-
constructor(setting, message) {
|
|
6675
|
-
super(message);
|
|
6676
|
-
this.name = "RetiredSettingError";
|
|
6677
|
-
this.setting = setting;
|
|
6678
|
-
}
|
|
6679
|
-
};
|
|
6680
|
-
});
|
|
6969
|
+
function pickStringValue(record3, key) {
|
|
6970
|
+
const value = record3[key];
|
|
6971
|
+
return typeof value === "string" ? value : undefined;
|
|
6972
|
+
}
|
|
6973
|
+
function pickNumber(record3, key) {
|
|
6974
|
+
const value = record3[key];
|
|
6975
|
+
return typeof value === "number" && Number.isFinite(value) ? { [key]: value } : {};
|
|
6976
|
+
}
|
|
6977
|
+
var REMOTE_SKILL_RUN_CONTRACT_VERSION = 1;
|
|
6681
6978
|
|
|
6682
|
-
//
|
|
6683
|
-
import {
|
|
6684
|
-
import {
|
|
6685
|
-
import {
|
|
6686
|
-
import {
|
|
6687
|
-
import {
|
|
6688
|
-
|
|
6689
|
-
|
|
6690
|
-
|
|
6691
|
-
|
|
6692
|
-
|
|
6693
|
-
|
|
6694
|
-
|
|
6979
|
+
// ../contracts/dist/client/transport.js
|
|
6980
|
+
import { isIP } from "net";
|
|
6981
|
+
import { spawnSync } from "child_process";
|
|
6982
|
+
import { closeSync, fstatSync, openSync, readFileSync as readFileSync11 } from "fs";
|
|
6983
|
+
import { O_NOFOLLOW, O_NONBLOCK, O_RDONLY } from "constants";
|
|
6984
|
+
import { createRequire } from "module";
|
|
6985
|
+
import { hostname as osHostname } from "os";
|
|
6986
|
+
import { isAbsolute as isAbsolute3, join as join13 } from "path";
|
|
6987
|
+
function envToken(name) {
|
|
6988
|
+
return name.toUpperCase().replace(/-/g, "_");
|
|
6989
|
+
}
|
|
6990
|
+
function clientTransportEnvKeys(name) {
|
|
6991
|
+
const envSegment = envToken(name);
|
|
6992
|
+
return {
|
|
6993
|
+
apiUrlKeys: [`HASNA_${envSegment}_API_URL`, `${envSegment}_API_URL`],
|
|
6994
|
+
apiKeyKeys: [`HASNA_${envSegment}_API_KEY`, `${envSegment}_API_KEY`]
|
|
6995
|
+
};
|
|
6695
6996
|
}
|
|
6696
|
-
function
|
|
6697
|
-
|
|
6698
|
-
throw new TypeError(`paths: invalid path kind "${kind}" \u2014 expected one of ${Object.keys(PATHS_RESOLVER_KIND_ENV).join(", ")}`);
|
|
6699
|
-
}
|
|
6997
|
+
function credentialOverrideEnvKey(name) {
|
|
6998
|
+
return `HASNA_${envToken(name)}_API_KEY_OVERRIDE`;
|
|
6700
6999
|
}
|
|
6701
|
-
function
|
|
6702
|
-
|
|
6703
|
-
|
|
6704
|
-
|
|
6705
|
-
|
|
7000
|
+
function credentialPointerEnvKey(name) {
|
|
7001
|
+
return `HASNA_${envToken(name)}_API_KEY_REF`;
|
|
7002
|
+
}
|
|
7003
|
+
function homeDir(env) {
|
|
7004
|
+
const home = env.HOME?.trim();
|
|
7005
|
+
return home ? home : null;
|
|
7006
|
+
}
|
|
7007
|
+
function absoluteOverride(env, key) {
|
|
7008
|
+
const value = env[key]?.trim();
|
|
7009
|
+
return value && isAbsolute3(value) ? value : null;
|
|
7010
|
+
}
|
|
7011
|
+
function hasnaHomeDir(env) {
|
|
7012
|
+
const override = absoluteOverride(env, HASNA_HOME_ENV_KEY);
|
|
7013
|
+
if (override)
|
|
6706
7014
|
return override;
|
|
6707
|
-
const home =
|
|
6708
|
-
|
|
6709
|
-
|
|
6710
|
-
|
|
6711
|
-
|
|
6712
|
-
|
|
6713
|
-
|
|
6714
|
-
|
|
6715
|
-
|
|
6716
|
-
|
|
6717
|
-
|
|
6718
|
-
|
|
6719
|
-
|
|
6720
|
-
|
|
6721
|
-
|
|
6722
|
-
|
|
6723
|
-
|
|
6724
|
-
|
|
6725
|
-
case "state":
|
|
6726
|
-
return pathsResolverJoin(home, ".local", "state", "hasna");
|
|
6727
|
-
case "cache":
|
|
6728
|
-
return pathsResolverJoin(home, ".cache", "hasna");
|
|
6729
|
-
}
|
|
7015
|
+
const home = homeDir(env);
|
|
7016
|
+
return home ? join13(home, HASNA_HOME_DIR) : null;
|
|
7017
|
+
}
|
|
7018
|
+
function appConfigDir(name, env) {
|
|
7019
|
+
const configRoot = absoluteOverride(env, HASNA_CONFIG_HOME_ENV_KEY);
|
|
7020
|
+
if (configRoot)
|
|
7021
|
+
return join13(configRoot, name);
|
|
7022
|
+
const root = hasnaHomeDir(env);
|
|
7023
|
+
return root ? join13(root, name, CONFIG_SUBDIR) : null;
|
|
7024
|
+
}
|
|
7025
|
+
function credentialDiskSourceList(name, env, profile = null) {
|
|
7026
|
+
if (!SAFE_APP_SLUG.test(name))
|
|
7027
|
+
return [];
|
|
7028
|
+
const directory = appConfigDir(name, env);
|
|
7029
|
+
if (!directory)
|
|
7030
|
+
return [];
|
|
7031
|
+
const file = profile ? `${CREDENTIALS_FILE}-${profile}` : CREDENTIALS_FILE;
|
|
7032
|
+
return [{ path: join13(directory, file), tier: "disk" }];
|
|
6730
7033
|
}
|
|
6731
|
-
function
|
|
6732
|
-
|
|
6733
|
-
const appSegment = options.internal === true ? pathsResolverJoin("internal", options.app) : options.app;
|
|
6734
|
-
return pathsResolverJoin(pathsResolverBaseDir(kind, options), appSegment);
|
|
7034
|
+
function credentialDiskSources(name, env) {
|
|
7035
|
+
return credentialDiskSourceList(name, env, null).map((s) => s.path);
|
|
6735
7036
|
}
|
|
6736
|
-
function
|
|
6737
|
-
return
|
|
7037
|
+
function profileDiskSources(name, env, profile) {
|
|
7038
|
+
return credentialDiskSourceList(name, env, profile).map((s) => s.path);
|
|
6738
7039
|
}
|
|
6739
|
-
function
|
|
6740
|
-
|
|
7040
|
+
function parseEnvFile(text) {
|
|
7041
|
+
const values = new Map;
|
|
7042
|
+
const unusable = new Set;
|
|
7043
|
+
for (const rawLine of text.split(/\r?\n/)) {
|
|
7044
|
+
const line = rawLine.trim();
|
|
7045
|
+
if (line.length === 0 || line.startsWith("#"))
|
|
7046
|
+
continue;
|
|
7047
|
+
const withoutExport = line.startsWith("export ") ? line.slice("export ".length).trim() : line;
|
|
7048
|
+
const equals = withoutExport.indexOf("=");
|
|
7049
|
+
if (equals <= 0)
|
|
7050
|
+
continue;
|
|
7051
|
+
const key = withoutExport.slice(0, equals).trim();
|
|
7052
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key))
|
|
7053
|
+
continue;
|
|
7054
|
+
let value = withoutExport.slice(equals + 1).trim();
|
|
7055
|
+
const quote = value[0];
|
|
7056
|
+
if (quote === '"' || quote === "'") {
|
|
7057
|
+
if (value.length < 2 || !value.endsWith(quote)) {
|
|
7058
|
+
unusable.add(key);
|
|
7059
|
+
continue;
|
|
7060
|
+
}
|
|
7061
|
+
value = value.slice(1, -1);
|
|
7062
|
+
}
|
|
7063
|
+
if (value.trim().length === 0) {
|
|
7064
|
+
unusable.add(key);
|
|
7065
|
+
continue;
|
|
7066
|
+
}
|
|
7067
|
+
if (values.has(key) && values.get(key) !== value)
|
|
7068
|
+
unusable.add(key);
|
|
7069
|
+
values.set(key, value);
|
|
7070
|
+
}
|
|
7071
|
+
return { values, unusable };
|
|
6741
7072
|
}
|
|
6742
|
-
function
|
|
6743
|
-
|
|
7073
|
+
function configFileModeAllowed(mode) {
|
|
7074
|
+
const permissions = mode & 4095;
|
|
7075
|
+
return permissions === 256 || permissions === 384;
|
|
6744
7076
|
}
|
|
6745
|
-
function
|
|
6746
|
-
return
|
|
7077
|
+
function configFileReadsCoherent(before, after) {
|
|
7078
|
+
return before.dev === after.dev && before.ino === after.ino && before.size === after.size && before.mtimeMs === after.mtimeMs && before.ctimeMs === after.ctimeMs;
|
|
6747
7079
|
}
|
|
6748
|
-
function
|
|
6749
|
-
const
|
|
6750
|
-
|
|
6751
|
-
|
|
6752
|
-
|
|
7080
|
+
function readAppConfigFile(path) {
|
|
7081
|
+
const unsafe = (reason) => {
|
|
7082
|
+
throw new CredentialFileUnsafeError(path, reason);
|
|
7083
|
+
};
|
|
7084
|
+
let fd = -1;
|
|
7085
|
+
try {
|
|
7086
|
+
fd = openSync(path, O_RDONLY | O_NOFOLLOW | O_NONBLOCK);
|
|
7087
|
+
} catch (error2) {
|
|
7088
|
+
const code = error2.code;
|
|
7089
|
+
if (code === "ENOENT" || code === "ENOTDIR")
|
|
7090
|
+
return null;
|
|
7091
|
+
if (code === "ELOOP")
|
|
7092
|
+
unsafe("the path is a symlink");
|
|
7093
|
+
unsafe(`the path could not be opened (${code ?? "unknown error"})`);
|
|
7094
|
+
}
|
|
7095
|
+
try {
|
|
7096
|
+
const before = fstatSync(fd);
|
|
7097
|
+
if (!before.isFile())
|
|
7098
|
+
unsafe("the path is not a regular file");
|
|
7099
|
+
if (!configFileModeAllowed(before.mode)) {
|
|
7100
|
+
unsafe(`permission mode ${(before.mode & 4095).toString(8).padStart(4, "0")} is not owner-only 0400 or 0600`);
|
|
7101
|
+
}
|
|
7102
|
+
const uid = process.getuid?.() ?? process.geteuid?.();
|
|
7103
|
+
if (uid !== undefined && before.uid !== uid)
|
|
7104
|
+
unsafe("the file is not owned by the current user");
|
|
7105
|
+
if (before.size > MAX_CREDENTIAL_FILE_BYTES)
|
|
7106
|
+
unsafe("the file exceeds the size limit");
|
|
7107
|
+
const bytes = readFileSync11(fd);
|
|
7108
|
+
const after = fstatSync(fd);
|
|
7109
|
+
if (!configFileReadsCoherent(before, after)) {
|
|
7110
|
+
unsafe("the file changed while being read");
|
|
7111
|
+
}
|
|
7112
|
+
return parseEnvFile(bytes.toString("utf8"));
|
|
7113
|
+
} finally {
|
|
7114
|
+
if (fd !== -1)
|
|
7115
|
+
closeSync(fd);
|
|
7116
|
+
}
|
|
6753
7117
|
}
|
|
6754
|
-
function
|
|
6755
|
-
|
|
6756
|
-
|
|
6757
|
-
|
|
6758
|
-
|
|
7118
|
+
function readCredentialFile(path, apiKeyKeys) {
|
|
7119
|
+
const parsed = readAppConfigFile(path);
|
|
7120
|
+
if (!parsed)
|
|
7121
|
+
return null;
|
|
7122
|
+
for (const key of apiKeyKeys) {
|
|
7123
|
+
if (parsed.unusable.has(key)) {
|
|
7124
|
+
throw new CredentialFileUnsafeError(path, `${key} is declared but blank or malformed`);
|
|
7125
|
+
}
|
|
6759
7126
|
}
|
|
6760
|
-
|
|
7127
|
+
const values = apiKeyKeys.map((key) => parsed.values.get(key)?.trim()).filter((value) => Boolean(value));
|
|
7128
|
+
if (new Set(values).size > 1) {
|
|
7129
|
+
throw new CredentialFileUnsafeError(path, "credential aliases disagree");
|
|
7130
|
+
}
|
|
7131
|
+
return values[0] ?? null;
|
|
6761
7132
|
}
|
|
6762
|
-
function
|
|
6763
|
-
|
|
7133
|
+
function appConfigDiskValue(name, env, keys) {
|
|
7134
|
+
const wanted = keys.filter((key) => !CREDENTIAL_SHAPED_KEY.test(key));
|
|
7135
|
+
if (wanted.length === 0)
|
|
7136
|
+
return null;
|
|
7137
|
+
for (const path of credentialDiskSources(name, env)) {
|
|
7138
|
+
const parsed = readAppConfigFile(path);
|
|
7139
|
+
if (!parsed)
|
|
7140
|
+
continue;
|
|
7141
|
+
if (wanted.some((key) => parsed.unusable.has(key))) {
|
|
7142
|
+
return { key: wanted.find((key) => parsed.unusable.has(key)), value: "", path, unusable: true };
|
|
7143
|
+
}
|
|
7144
|
+
const values = wanted.map((key) => parsed.values.get(key)?.trim()).filter((value) => Boolean(value));
|
|
7145
|
+
if (new Set(values).size > 1)
|
|
7146
|
+
throw new CredentialFileUnsafeError(path, "configuration aliases disagree");
|
|
7147
|
+
for (const key of wanted) {
|
|
7148
|
+
if (parsed.unusable.has(key))
|
|
7149
|
+
return { key, value: "", path, unusable: true };
|
|
7150
|
+
const value = parsed.values.get(key)?.trim();
|
|
7151
|
+
if (value)
|
|
7152
|
+
return { key, value, path };
|
|
7153
|
+
}
|
|
7154
|
+
}
|
|
7155
|
+
return null;
|
|
6764
7156
|
}
|
|
6765
|
-
function
|
|
6766
|
-
|
|
7157
|
+
function assertUsableCredential(appName, source, value) {
|
|
7158
|
+
if (VAULT_POINTER_SHAPE.test(value)) {
|
|
7159
|
+
throw new CredentialResolutionError(appName, `The credential from ${source} looks like a secrets-vault pointer (a path-shaped reference like ` + `'namespace/app/live/api_key'). A vault path is NEVER accepted as a literal API key. ` + `Use ${credentialPointerEnvKey(appName)} to resolve the key through the vault, or provide the actual key value.`, [source]);
|
|
7160
|
+
}
|
|
7161
|
+
if (!ILLEGAL_IN_HEADER_VALUE.test(value))
|
|
7162
|
+
return;
|
|
7163
|
+
throw new CredentialResolutionError(appName, `The credential from ${source} contains characters that cannot be sent in an HTTP header ` + `(a control character or non-ASCII byte). A file written with CR-only line endings is the usual ` + `cause. Rewrite that credential file with one LF-terminated KEY=value line. ` + `The value is not shown here, and is deliberately never logged.`, [source]);
|
|
7164
|
+
}
|
|
7165
|
+
function sealCredential(fields) {
|
|
7166
|
+
const { apiKey } = fields;
|
|
7167
|
+
const visible = {
|
|
7168
|
+
tier: fields.tier,
|
|
7169
|
+
source: fields.source,
|
|
7170
|
+
deliberate: fields.deliberate,
|
|
7171
|
+
diskCandidates: Object.freeze([...fields.diskCandidates]),
|
|
7172
|
+
warning: fields.warning
|
|
7173
|
+
};
|
|
7174
|
+
const sealed = { ...visible };
|
|
7175
|
+
Object.defineProperty(sealed, "apiKey", {
|
|
7176
|
+
value: apiKey,
|
|
7177
|
+
enumerable: false,
|
|
7178
|
+
writable: false,
|
|
7179
|
+
configurable: false
|
|
7180
|
+
});
|
|
7181
|
+
if (fields.pointerVaultKey !== undefined) {
|
|
7182
|
+
Object.defineProperty(sealed, "pointerVaultKey", {
|
|
7183
|
+
value: fields.pointerVaultKey,
|
|
7184
|
+
enumerable: false,
|
|
7185
|
+
writable: false,
|
|
7186
|
+
configurable: false
|
|
7187
|
+
});
|
|
7188
|
+
}
|
|
7189
|
+
Object.defineProperty(sealed, INSPECT_CUSTOM, {
|
|
7190
|
+
value: () => ({ ...visible, apiKey: "[redacted]" }),
|
|
7191
|
+
enumerable: false,
|
|
7192
|
+
writable: false,
|
|
7193
|
+
configurable: false
|
|
7194
|
+
});
|
|
7195
|
+
Object.defineProperty(sealed, CREDENTIAL_SEAL, {
|
|
7196
|
+
value: true,
|
|
7197
|
+
enumerable: false,
|
|
7198
|
+
writable: false,
|
|
7199
|
+
configurable: false
|
|
7200
|
+
});
|
|
7201
|
+
return Object.freeze(sealed);
|
|
6767
7202
|
}
|
|
6768
|
-
function
|
|
6769
|
-
const
|
|
6770
|
-
|
|
6771
|
-
|
|
6772
|
-
|
|
6773
|
-
|
|
7203
|
+
function firstEnvValue(env, keys) {
|
|
7204
|
+
for (const key of keys) {
|
|
7205
|
+
if (!Object.prototype.hasOwnProperty.call(env, key))
|
|
7206
|
+
continue;
|
|
7207
|
+
const value = env[key]?.trim();
|
|
7208
|
+
if (value)
|
|
7209
|
+
return { key, value };
|
|
7210
|
+
}
|
|
7211
|
+
return null;
|
|
6774
7212
|
}
|
|
6775
|
-
|
|
6776
|
-
|
|
6777
|
-
PATHS_RESOLVER_KIND_ENV = {
|
|
6778
|
-
config: "HASNA_CONFIG_HOME",
|
|
6779
|
-
data: "HASNA_DATA_HOME",
|
|
6780
|
-
state: "HASNA_STATE_HOME",
|
|
6781
|
-
cache: "HASNA_CACHE_HOME"
|
|
6782
|
-
};
|
|
6783
|
-
PATHS_RESOLVER_APP_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
6784
|
-
});
|
|
6785
|
-
|
|
6786
|
-
// src/lib/config.ts
|
|
6787
|
-
import { existsSync as existsSync2, readFileSync, writeFileSync, mkdirSync, copyFileSync, readdirSync, statSync } from "fs";
|
|
6788
|
-
import { join as join2, dirname } from "path";
|
|
6789
|
-
import { homedir as homedir2 } from "os";
|
|
6790
|
-
function validKeys() {
|
|
6791
|
-
return [...Object.keys(ENUM_KEYS), ...STRING_KEYS];
|
|
7213
|
+
function isAmbientEnvironment(env) {
|
|
7214
|
+
return env === process.env || env[AMBIENT_ENVIRONMENT] === true;
|
|
6792
7215
|
}
|
|
6793
|
-
function
|
|
6794
|
-
|
|
7216
|
+
function defaultKeychainRunner(argv) {
|
|
7217
|
+
const result = spawnSync(KEYCHAIN_SECURITY_BIN, [...argv], {
|
|
7218
|
+
encoding: "utf8",
|
|
7219
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
7220
|
+
timeout: KEYCHAIN_SPAWN_TIMEOUT_MS
|
|
7221
|
+
});
|
|
7222
|
+
return {
|
|
7223
|
+
status: result.status,
|
|
7224
|
+
stdout: result.stdout ?? "",
|
|
7225
|
+
stderr: result.error ? result.error.message : result.stderr ?? ""
|
|
7226
|
+
};
|
|
6795
7227
|
}
|
|
6796
|
-
function
|
|
6797
|
-
if (
|
|
6798
|
-
return;
|
|
6799
|
-
|
|
6800
|
-
|
|
6801
|
-
|
|
6802
|
-
|
|
6803
|
-
|
|
6804
|
-
|
|
6805
|
-
|
|
6806
|
-
|
|
6807
|
-
|
|
6808
|
-
|
|
6809
|
-
|
|
6810
|
-
|
|
6811
|
-
|
|
7228
|
+
function keychainTierEnabled(env, options) {
|
|
7229
|
+
if ((options.platform ?? process.platform) !== "darwin")
|
|
7230
|
+
return false;
|
|
7231
|
+
if (options.enabled !== undefined)
|
|
7232
|
+
return options.enabled;
|
|
7233
|
+
return options.run !== undefined || isAmbientEnvironment(env);
|
|
7234
|
+
}
|
|
7235
|
+
function keychainAccount(env, options) {
|
|
7236
|
+
const station = env[KEYCHAIN_STATION_ENV_KEY]?.trim();
|
|
7237
|
+
if (station)
|
|
7238
|
+
return station;
|
|
7239
|
+
const host = (options.hostname ?? osHostname)().split(".")[0]?.trim() ?? "";
|
|
7240
|
+
if (host)
|
|
7241
|
+
return host;
|
|
7242
|
+
const user = env.USER?.trim();
|
|
7243
|
+
return user || null;
|
|
7244
|
+
}
|
|
7245
|
+
function keychainFailureHint(text) {
|
|
7246
|
+
const line = text.split(/\r?\n/).find((entry) => entry.trim().length > 0)?.trim() ?? "";
|
|
7247
|
+
const clean = line.replace(/[\u0000-\u001f\u007f]/g, "").slice(0, 200);
|
|
7248
|
+
return clean ? `: ${clean}` : "";
|
|
7249
|
+
}
|
|
7250
|
+
function readKeychainItem(name, env, kind, options) {
|
|
7251
|
+
if (!SAFE_APP_SLUG.test(name) || !keychainTierEnabled(env, options))
|
|
7252
|
+
return null;
|
|
7253
|
+
const account = keychainAccount(env, options);
|
|
7254
|
+
if (!account)
|
|
7255
|
+
return null;
|
|
7256
|
+
const service = `${KEYCHAIN_SERVICE_PREFIX}.${name}.${kind}`;
|
|
7257
|
+
const source = `keychain:${service}@${account}`;
|
|
7258
|
+
const run = options.run ?? defaultKeychainRunner;
|
|
7259
|
+
let result;
|
|
7260
|
+
try {
|
|
7261
|
+
result = run(["find-generic-password", "-a", account, "-s", service, "-w"]);
|
|
7262
|
+
} catch (error2) {
|
|
7263
|
+
const reason = keychainFailureHint(error2 instanceof Error ? error2.message : String(error2));
|
|
7264
|
+
throw new CredentialResolutionError(name, `The Keychain lookup for ${source} could not run${reason}. A Keychain failure is never resolved ` + `around: fix the keychain, or delete the item to fall through to the credential on disk.`, [source]);
|
|
6812
7265
|
}
|
|
6813
|
-
|
|
6814
|
-
|
|
6815
|
-
if (
|
|
6816
|
-
|
|
6817
|
-
|
|
6818
|
-
|
|
6819
|
-
|
|
6820
|
-
|
|
6821
|
-
|
|
6822
|
-
|
|
6823
|
-
|
|
6824
|
-
|
|
6825
|
-
|
|
6826
|
-
|
|
6827
|
-
|
|
7266
|
+
if (result.status === KEYCHAIN_ITEM_NOT_FOUND_STATUS)
|
|
7267
|
+
return null;
|
|
7268
|
+
if (result.status !== 0) {
|
|
7269
|
+
throw new CredentialResolutionError(name, `The Keychain lookup for ${source} failed (security exited ` + `${result.status ?? "without a status"}${keychainFailureHint(result.stderr)}). A Keychain item that ` + `exists but cannot be read is never resolved around: unlock the keychain, run from a session that ` + `may use it, or delete the item to fall through to the credential on disk.`, [source]);
|
|
7270
|
+
}
|
|
7271
|
+
const value = result.stdout.trim();
|
|
7272
|
+
if (!value) {
|
|
7273
|
+
throw new CredentialResolutionError(name, `${source} exists but holds an empty value; a declared item never falls through to another ` + `identity. Store a value in it or delete the item.`, [source]);
|
|
7274
|
+
}
|
|
7275
|
+
return { value, source };
|
|
7276
|
+
}
|
|
7277
|
+
function keychainConfigValue(name, env, options = {}) {
|
|
7278
|
+
return readKeychainItem(name, env, "api-url", options);
|
|
7279
|
+
}
|
|
7280
|
+
function snapshotClientEnvironment(name, env) {
|
|
7281
|
+
const keys = clientTransportEnvKeys(name);
|
|
7282
|
+
const ambient = isAmbientEnvironment(env);
|
|
7283
|
+
const snapshot = Object.create(null);
|
|
7284
|
+
for (const key of [
|
|
7285
|
+
...keys.apiUrlKeys,
|
|
7286
|
+
...keys.apiKeyKeys,
|
|
7287
|
+
credentialOverrideEnvKey(name),
|
|
7288
|
+
credentialPointerEnvKey(name),
|
|
7289
|
+
CREDENTIAL_PROFILE_ENV_KEY,
|
|
7290
|
+
"HOME",
|
|
7291
|
+
HASNA_HOME_ENV_KEY,
|
|
7292
|
+
HASNA_CONFIG_HOME_ENV_KEY,
|
|
7293
|
+
KEYCHAIN_STATION_ENV_KEY,
|
|
7294
|
+
"USER"
|
|
7295
|
+
]) {
|
|
7296
|
+
const descriptor = Object.getOwnPropertyDescriptor(env, key);
|
|
7297
|
+
if (!descriptor)
|
|
7298
|
+
continue;
|
|
7299
|
+
if (!("value" in descriptor)) {
|
|
7300
|
+
throw new CredentialResolutionError(name, `${key} is accessor-backed; client configuration requires own data properties.`, [key]);
|
|
7301
|
+
}
|
|
7302
|
+
if (descriptor.value !== undefined && typeof descriptor.value !== "string") {
|
|
7303
|
+
throw new CredentialResolutionError(name, `${key} must be a string data property.`, [key]);
|
|
6828
7304
|
}
|
|
7305
|
+
snapshot[key] = descriptor.value;
|
|
6829
7306
|
}
|
|
6830
|
-
if (
|
|
6831
|
-
|
|
6832
|
-
|
|
6833
|
-
|
|
6834
|
-
|
|
6835
|
-
|
|
7307
|
+
if (ambient) {
|
|
7308
|
+
Object.defineProperty(snapshot, AMBIENT_ENVIRONMENT, {
|
|
7309
|
+
value: true,
|
|
7310
|
+
enumerable: false,
|
|
7311
|
+
writable: false,
|
|
7312
|
+
configurable: false
|
|
7313
|
+
});
|
|
7314
|
+
}
|
|
7315
|
+
return Object.freeze(snapshot);
|
|
7316
|
+
}
|
|
7317
|
+
function resolveCredential(name, env, options = {}) {
|
|
7318
|
+
env = snapshotClientEnvironment(name, env);
|
|
7319
|
+
const { apiKeyKeys } = clientTransportEnvKeys(name);
|
|
7320
|
+
const diskPaths = credentialDiskSources(name, env);
|
|
7321
|
+
if (options.apiKey !== undefined) {
|
|
7322
|
+
const explicitKey = options.apiKey.trim();
|
|
7323
|
+
if (!explicitKey) {
|
|
7324
|
+
throw new CredentialResolutionError(name, "The explicit apiKey argument is blank; an explicit credential never falls through to another identity.", ["explicit apiKey argument"]);
|
|
7325
|
+
}
|
|
7326
|
+
assertUsableCredential(name, "the explicit apiKey argument", explicitKey);
|
|
7327
|
+
return sealCredential({
|
|
7328
|
+
apiKey: explicitKey,
|
|
7329
|
+
tier: "argument",
|
|
7330
|
+
source: "explicit apiKey argument",
|
|
7331
|
+
deliberate: true,
|
|
7332
|
+
diskCandidates: diskPaths,
|
|
7333
|
+
warning: null
|
|
7334
|
+
});
|
|
7335
|
+
}
|
|
7336
|
+
const overrideKeyName = credentialOverrideEnvKey(name);
|
|
7337
|
+
const overrideRaw = Object.prototype.hasOwnProperty.call(env, overrideKeyName) ? env[overrideKeyName] : undefined;
|
|
7338
|
+
if (overrideRaw !== undefined) {
|
|
7339
|
+
const override = overrideRaw.trim();
|
|
7340
|
+
if (!override) {
|
|
7341
|
+
throw new CredentialResolutionError(name, `${overrideKeyName} is set but empty. It is a deliberate override, so it is not resolved around: ` + `either give it a real key or unset it to fall back to the credential on disk.`, [overrideKeyName]);
|
|
7342
|
+
}
|
|
7343
|
+
assertUsableCredential(name, overrideKeyName, override);
|
|
7344
|
+
return sealCredential({
|
|
7345
|
+
apiKey: override,
|
|
7346
|
+
tier: "override",
|
|
7347
|
+
source: overrideKeyName,
|
|
7348
|
+
deliberate: true,
|
|
7349
|
+
diskCandidates: diskPaths,
|
|
7350
|
+
warning: null
|
|
7351
|
+
});
|
|
7352
|
+
}
|
|
7353
|
+
const pointerKeyName = credentialPointerEnvKey(name);
|
|
7354
|
+
const pointerRaw = Object.prototype.hasOwnProperty.call(env, pointerKeyName) ? env[pointerKeyName] : undefined;
|
|
7355
|
+
if (pointerRaw !== undefined) {
|
|
7356
|
+
const pointer = pointerRaw.trim();
|
|
7357
|
+
if (!pointer) {
|
|
7358
|
+
throw new CredentialResolutionError(name, `${pointerKeyName} is set but empty. It is a deliberate vault pointer, so it is not resolved around: ` + `either give it a vault item key or unset it to fall back to the credential on disk.`, [pointerKeyName]);
|
|
7359
|
+
}
|
|
7360
|
+
if (!VAULT_POINTER_SHAPE.test(pointer)) {
|
|
7361
|
+
throw new CredentialResolutionError(name, `${pointerKeyName} must name a vault ITEM KEY (a path-shaped reference like ` + `'namespace/app/live/api_key'), not a credential value. A pointer that carries a literal is refused.`, [pointerKeyName]);
|
|
7362
|
+
}
|
|
7363
|
+
return sealCredential({
|
|
7364
|
+
apiKey: "",
|
|
7365
|
+
pointerVaultKey: pointer,
|
|
7366
|
+
tier: "pointer",
|
|
7367
|
+
source: pointerKeyName,
|
|
7368
|
+
deliberate: true,
|
|
7369
|
+
diskCandidates: diskPaths,
|
|
7370
|
+
warning: null
|
|
7371
|
+
});
|
|
7372
|
+
}
|
|
7373
|
+
if (options.profile !== undefined && !options.profile.trim()) {
|
|
7374
|
+
throw new CredentialResolutionError(name, "The explicit profile argument is blank; an explicit identity selection never falls through.", ["explicit profile argument"]);
|
|
7375
|
+
}
|
|
7376
|
+
const profileRaw = Object.prototype.hasOwnProperty.call(env, CREDENTIAL_PROFILE_ENV_KEY) ? env[CREDENTIAL_PROFILE_ENV_KEY] : undefined;
|
|
7377
|
+
if (profileRaw !== undefined && !profileRaw.trim()) {
|
|
7378
|
+
throw new CredentialResolutionError(name, `${CREDENTIAL_PROFILE_ENV_KEY} is set but blank.`, [CREDENTIAL_PROFILE_ENV_KEY]);
|
|
7379
|
+
}
|
|
7380
|
+
const profile = options.profile?.trim() || profileRaw?.trim();
|
|
7381
|
+
if (profile) {
|
|
7382
|
+
const profileSource = options.profile?.trim() ? "explicit profile argument" : CREDENTIAL_PROFILE_ENV_KEY;
|
|
7383
|
+
if (!SAFE_PROFILE.test(profile)) {
|
|
7384
|
+
throw new CredentialResolutionError(name, `Profile name from ${profileSource} is not usable in a path. ` + `Use letters, digits, dot, dash, or underscore.`, [profileSource]);
|
|
7385
|
+
}
|
|
7386
|
+
const paths = profileDiskSources(name, env, profile);
|
|
7387
|
+
for (const path of paths) {
|
|
7388
|
+
const value = readCredentialFile(path, apiKeyKeys);
|
|
7389
|
+
if (value) {
|
|
7390
|
+
assertUsableCredential(name, path, value);
|
|
7391
|
+
return sealCredential({
|
|
7392
|
+
apiKey: value,
|
|
7393
|
+
tier: "profile",
|
|
7394
|
+
source: path,
|
|
7395
|
+
deliberate: true,
|
|
7396
|
+
diskCandidates: paths,
|
|
7397
|
+
warning: null
|
|
7398
|
+
});
|
|
7399
|
+
}
|
|
7400
|
+
}
|
|
7401
|
+
throw new CredentialResolutionError(name, `Profile '${profile}' (from ${profileSource}) has no ${apiKeyKeys[0]} for '${name}'. ` + `Looked in: ${paths.join(", ") || "<no HOME in this environment>"}. ` + `A profile names WHICH identity to use, so it is never resolved around \u2014 ` + `create the profile's credential file or unset ${CREDENTIAL_PROFILE_ENV_KEY}.`, paths);
|
|
7402
|
+
}
|
|
7403
|
+
const definedEnvEntries = apiKeyKeys.filter((key) => Object.prototype.hasOwnProperty.call(env, key) && env[key] !== undefined).map((key) => ({ key, value: String(env[key]).trim() }));
|
|
7404
|
+
const blankEnv = definedEnvEntries.find((entry) => entry.value.length === 0);
|
|
7405
|
+
if (blankEnv) {
|
|
7406
|
+
throw new CredentialResolutionError(name, `${blankEnv.key} is set but blank; a declared credential never falls through to another alias or identity.`, [blankEnv.key]);
|
|
7407
|
+
}
|
|
7408
|
+
if (definedEnvEntries.length > 1 && new Set(definedEnvEntries.map((entry) => entry.value)).size > 1) {
|
|
7409
|
+
throw new CredentialResolutionError(name, `${definedEnvEntries.map((entry) => entry.key).join(" and ")} disagree; credential aliases must be identical or only one may be set.`, definedEnvEntries.map((entry) => entry.key));
|
|
7410
|
+
}
|
|
7411
|
+
const envHit = firstEnvValue(env, apiKeyKeys);
|
|
7412
|
+
const keychainHit = readKeychainItem(name, env, "api-key", options.keychain ?? {});
|
|
7413
|
+
if (keychainHit) {
|
|
7414
|
+
assertUsableCredential(name, keychainHit.source, keychainHit.value);
|
|
7415
|
+
const warning = envHit && envHit.value !== keychainHit.value ? `Credential sources disagree for '${name}': ${keychainHit.source} and ${envHit.key} hold ` + `different keys. ${keychainHit.source} wins, because the Keychain is re-read on every call while ` + `an environment variable is a snapshot. Reconcile them \u2014 a rotation that updated only one leaves ` + `the other to fail 401 wherever it is loaded first.` : null;
|
|
7416
|
+
return sealCredential({
|
|
7417
|
+
apiKey: keychainHit.value,
|
|
7418
|
+
tier: "keychain",
|
|
7419
|
+
source: keychainHit.source,
|
|
7420
|
+
deliberate: false,
|
|
7421
|
+
diskCandidates: diskPaths,
|
|
7422
|
+
warning
|
|
7423
|
+
});
|
|
7424
|
+
}
|
|
7425
|
+
const diskSourceList = credentialDiskSourceList(name, env, null);
|
|
7426
|
+
const diskHits = diskSourceList.map((src) => ({ src, value: readCredentialFile(src.path, apiKeyKeys) })).filter((hit) => hit.value !== null);
|
|
7427
|
+
if (diskHits.length > 0) {
|
|
7428
|
+
const winner = diskHits[0];
|
|
7429
|
+
assertUsableCredential(name, winner.src.path, winner.value);
|
|
7430
|
+
const divergentSources = [
|
|
7431
|
+
...diskHits.slice(1).filter((hit) => hit.value !== winner.value).map((hit) => hit.src.path),
|
|
7432
|
+
...envHit && envHit.value !== winner.value ? [envHit.key] : []
|
|
7433
|
+
];
|
|
7434
|
+
const warning = divergentSources.length > 0 ? `Credential sources disagree for '${name}': ${winner.src.path} and ` + `${divergentSources.join(", ")} hold different keys. ${winner.src.path} wins, because a file on ` + `disk is re-read on every call while an environment variable is a snapshot. Reconcile them \u2014 ` + `a rotation that updated only one leaves the other to fail 401 wherever it is loaded first.` : null;
|
|
7435
|
+
return sealCredential({
|
|
7436
|
+
apiKey: winner.value,
|
|
7437
|
+
tier: winner.src.tier,
|
|
7438
|
+
source: winner.src.path,
|
|
7439
|
+
deliberate: false,
|
|
7440
|
+
diskCandidates: diskPaths,
|
|
7441
|
+
warning
|
|
7442
|
+
});
|
|
7443
|
+
}
|
|
7444
|
+
if (envHit) {
|
|
7445
|
+
assertUsableCredential(name, envHit.key, envHit.value);
|
|
7446
|
+
return sealCredential({
|
|
7447
|
+
apiKey: envHit.value,
|
|
7448
|
+
tier: "env",
|
|
7449
|
+
source: envHit.key,
|
|
7450
|
+
deliberate: false,
|
|
7451
|
+
diskCandidates: diskPaths,
|
|
7452
|
+
warning: null
|
|
7453
|
+
});
|
|
7454
|
+
}
|
|
7455
|
+
return null;
|
|
6836
7456
|
}
|
|
6837
|
-
function
|
|
6838
|
-
const
|
|
7457
|
+
async function completePointerCredential(name, pointerResolution, env = process.env) {
|
|
7458
|
+
const vaultKey = pointerResolution.pointerVaultKey;
|
|
7459
|
+
const pointerEnvKey = pointerResolution.source;
|
|
7460
|
+
if (!vaultKey) {
|
|
7461
|
+
throw new CredentialResolutionError(name, `Pointer resolution from ${pointerEnvKey} carries no vault item key; this is a defect in the resolver.`, [pointerEnvKey]);
|
|
7462
|
+
}
|
|
7463
|
+
let secretsSdk;
|
|
6839
7464
|
try {
|
|
6840
|
-
|
|
6841
|
-
} catch {
|
|
6842
|
-
|
|
6843
|
-
|
|
6844
|
-
|
|
6845
|
-
const oldDir = join2(home, ".skills");
|
|
6846
|
-
const oldConfigFile = join2(home, ".skillsrc");
|
|
7465
|
+
secretsSdk = requireSecretsSdk(SECRETS_PACKAGE_SPECIFIER);
|
|
7466
|
+
} catch {
|
|
7467
|
+
throw new CredentialResolutionError(name, `${pointerEnvKey} names vault item '${vaultKey}', but the secrets SDK (@hasna/secrets) is not installed ` + `in this process. A vault pointer is TERMINAL: install @hasna/secrets to resolve it, or unset ${pointerEnvKey}.`, [pointerEnvKey]);
|
|
7468
|
+
}
|
|
7469
|
+
let client;
|
|
6847
7470
|
try {
|
|
6848
|
-
|
|
6849
|
-
} catch {
|
|
6850
|
-
|
|
6851
|
-
try {
|
|
6852
|
-
copyFileSync(oldConfigFile, join2(root, "config.json"));
|
|
6853
|
-
} catch {}
|
|
7471
|
+
client = secretsSdk.createSecretsClientFromEnv(env);
|
|
7472
|
+
} catch {
|
|
7473
|
+
throw new CredentialResolutionError(name, `${pointerEnvKey} names vault item '${vaultKey}', but the secrets client could not be configured from this ` + `environment (the secrets service URL and key env are missing or invalid). A vault pointer is TERMINAL and ` + `never falls through to a literal or disk credential.`, [pointerEnvKey]);
|
|
6854
7474
|
}
|
|
6855
|
-
|
|
7475
|
+
let secret;
|
|
7476
|
+
try {
|
|
7477
|
+
secret = await client.getSecret({ key: vaultKey });
|
|
7478
|
+
} catch {
|
|
7479
|
+
throw new CredentialResolutionError(name, `${pointerEnvKey} names vault item '${vaultKey}', but the vault could not be reached or the item is ` + `unavailable. A vault pointer is TERMINAL and never falls through to a literal or disk credential.`, [pointerEnvKey]);
|
|
7480
|
+
}
|
|
7481
|
+
const value = secret.value;
|
|
7482
|
+
if (!value) {
|
|
7483
|
+
throw new CredentialResolutionError(name, `${pointerEnvKey} resolved vault item '${vaultKey}', but it holds no value. A vault pointer is TERMINAL.`, [pointerEnvKey]);
|
|
7484
|
+
}
|
|
7485
|
+
assertUsableCredential(name, `${pointerEnvKey} -> vault:${vaultKey}`, value);
|
|
7486
|
+
return sealCredential({
|
|
7487
|
+
apiKey: value,
|
|
7488
|
+
tier: "pointer",
|
|
7489
|
+
source: `${pointerEnvKey} -> vault:${vaultKey}`,
|
|
7490
|
+
deliberate: true,
|
|
7491
|
+
diskCandidates: pointerResolution.diskCandidates,
|
|
7492
|
+
warning: null
|
|
7493
|
+
});
|
|
6856
7494
|
}
|
|
6857
|
-
function
|
|
6858
|
-
return
|
|
7495
|
+
function defaultFleetGatewayBaseUrl(name) {
|
|
7496
|
+
return `${DEFAULT_FLEET_GATEWAY_ORIGIN}/${validateAppSlug(name)}`;
|
|
6859
7497
|
}
|
|
6860
|
-
function
|
|
6861
|
-
if (
|
|
6862
|
-
return
|
|
6863
|
-
|
|
7498
|
+
function isValidDnsDomain(value) {
|
|
7499
|
+
if (value.length === 0 || value.length > 253 || ASCII_CONTROL_PATTERN.test(value) || /[^\x00-\x7f]/.test(value)) {
|
|
7500
|
+
return false;
|
|
7501
|
+
}
|
|
7502
|
+
return value.split(".").every((label) => label.length <= 63 && !label.startsWith("xn--") && DNS_LABEL_PATTERN.test(label));
|
|
6864
7503
|
}
|
|
6865
|
-
function
|
|
6866
|
-
|
|
6867
|
-
|
|
6868
|
-
if (existsSync2(canonicalConfigPath)) {
|
|
6869
|
-
globalConfig2 = readConfigFile(canonicalConfigPath);
|
|
6870
|
-
} else if (hasOperatorOverride()) {
|
|
6871
|
-
globalConfig2 = {};
|
|
6872
|
-
} else {
|
|
6873
|
-
globalConfig2 = readConfigFile(legacyConfigFilePath());
|
|
7504
|
+
function validateAppSlug(name) {
|
|
7505
|
+
if (name.length > 63 || !DNS_LABEL_PATTERN.test(name)) {
|
|
7506
|
+
throw new Error("App name must be one lowercase DNS label.");
|
|
6874
7507
|
}
|
|
6875
|
-
|
|
6876
|
-
return { ...globalConfig2, ...projectConfig };
|
|
7508
|
+
return name;
|
|
6877
7509
|
}
|
|
6878
|
-
function
|
|
6879
|
-
|
|
7510
|
+
function rawAuthority(value) {
|
|
7511
|
+
const match = /^[a-z][a-z0-9+.-]*:\/\//i.exec(value);
|
|
7512
|
+
if (!match)
|
|
7513
|
+
throw new Error("API URL must be absolute.");
|
|
7514
|
+
const afterScheme = value.slice(match[0].length);
|
|
7515
|
+
const boundary = afterScheme.search(/[/?#]/);
|
|
7516
|
+
const authority = boundary === -1 ? afterScheme : afterScheme.slice(0, boundary);
|
|
7517
|
+
if (!authority)
|
|
7518
|
+
throw new Error("API URL must include a hostname.");
|
|
7519
|
+
return authority;
|
|
6880
7520
|
}
|
|
6881
|
-
function
|
|
6882
|
-
if (
|
|
6883
|
-
|
|
7521
|
+
function assertCanonicalPort(port) {
|
|
7522
|
+
if (!/^[0-9]+$/.test(port) || port.length > 1 && port.startsWith("0")) {
|
|
7523
|
+
throw new Error("API URL authority must contain a canonical port between 1 and 65535.");
|
|
6884
7524
|
}
|
|
6885
|
-
|
|
6886
|
-
|
|
6887
|
-
|
|
6888
|
-
if (!existsSync2(path))
|
|
6889
|
-
return {};
|
|
6890
|
-
let parsed;
|
|
6891
|
-
try {
|
|
6892
|
-
parsed = JSON.parse(readFileSync(path, "utf-8"));
|
|
6893
|
-
} catch {
|
|
6894
|
-
return {};
|
|
7525
|
+
const numericPort = Number(port);
|
|
7526
|
+
if (!Number.isSafeInteger(numericPort) || numericPort < 1 || numericPort > 65535) {
|
|
7527
|
+
throw new Error("API URL authority must contain a canonical port between 1 and 65535.");
|
|
6895
7528
|
}
|
|
6896
|
-
|
|
6897
|
-
|
|
6898
|
-
|
|
6899
|
-
|
|
6900
|
-
|
|
6901
|
-
|
|
6902
|
-
|
|
6903
|
-
|
|
7529
|
+
}
|
|
7530
|
+
function canonicalAuthorityHostname(authority) {
|
|
7531
|
+
let rawHostname;
|
|
7532
|
+
if (authority.startsWith("[")) {
|
|
7533
|
+
const closingBracket = authority.indexOf("]");
|
|
7534
|
+
if (closingBracket === -1) {
|
|
7535
|
+
throw new Error("API URL authority must contain a canonical hostname.");
|
|
7536
|
+
}
|
|
7537
|
+
rawHostname = authority.slice(0, closingBracket + 1);
|
|
7538
|
+
const portSuffix = authority.slice(closingBracket + 1);
|
|
7539
|
+
if (portSuffix) {
|
|
7540
|
+
if (!portSuffix.startsWith(":")) {
|
|
7541
|
+
throw new Error("API URL authority must contain a canonical hostname and port.");
|
|
7542
|
+
}
|
|
7543
|
+
assertCanonicalPort(portSuffix.slice(1));
|
|
7544
|
+
}
|
|
7545
|
+
if (isIP(rawHostname.slice(1, -1)) !== 6) {
|
|
7546
|
+
throw new Error("API URL authority must contain a canonical IPv6 literal.");
|
|
7547
|
+
}
|
|
7548
|
+
} else {
|
|
7549
|
+
const firstColon = authority.indexOf(":");
|
|
7550
|
+
const lastColon = authority.lastIndexOf(":");
|
|
7551
|
+
if (firstColon !== lastColon) {
|
|
7552
|
+
throw new Error("IPv6 API URL authorities must use brackets.");
|
|
7553
|
+
}
|
|
7554
|
+
if (lastColon !== -1) {
|
|
7555
|
+
const port = authority.slice(lastColon + 1);
|
|
7556
|
+
assertCanonicalPort(port);
|
|
7557
|
+
rawHostname = authority.slice(0, lastColon);
|
|
7558
|
+
} else {
|
|
7559
|
+
rawHostname = authority;
|
|
7560
|
+
}
|
|
7561
|
+
const ipVersion = isIP(rawHostname);
|
|
7562
|
+
const numericAddressParts = rawHostname.split(".");
|
|
7563
|
+
const looksLikeNonCanonicalIpv4 = numericAddressParts.every((part) => /^(?:0x[0-9a-f]+|[0-9]+)$/i.test(part));
|
|
7564
|
+
if (ipVersion !== 4 && looksLikeNonCanonicalIpv4 || ipVersion !== 4 && !isValidDnsDomain(rawHostname.toLowerCase())) {
|
|
7565
|
+
throw new Error("API URL authority must contain a canonical ASCII hostname.");
|
|
7566
|
+
}
|
|
6904
7567
|
}
|
|
6905
|
-
return
|
|
7568
|
+
return rawHostname.toLowerCase();
|
|
6906
7569
|
}
|
|
6907
|
-
function
|
|
6908
|
-
|
|
6909
|
-
const projectConfig = readConfigFile(getConfigPath("project"));
|
|
6910
|
-
return { ...globalConfig2, ...projectConfig };
|
|
7570
|
+
function isDeliberateLoopbackHttpAuthority(authority) {
|
|
7571
|
+
return /^(?:localhost|127\.0\.0\.1|\[::1\])(?::[0-9]+)?$/i.test(authority);
|
|
6911
7572
|
}
|
|
6912
|
-
|
|
6913
|
-
|
|
6914
|
-
|
|
6915
|
-
|
|
6916
|
-
|
|
6917
|
-
|
|
6918
|
-
|
|
6919
|
-
|
|
6920
|
-
|
|
6921
|
-
|
|
6922
|
-
|
|
6923
|
-
|
|
6924
|
-
|
|
6925
|
-
|
|
6926
|
-
|
|
6927
|
-
|
|
7573
|
+
function toV1BaseUrl(apiUrl) {
|
|
7574
|
+
if (ASCII_CONTROL_PATTERN.test(apiUrl)) {
|
|
7575
|
+
throw new Error("API URL must not contain ASCII control characters.");
|
|
7576
|
+
}
|
|
7577
|
+
const input = apiUrl.trim();
|
|
7578
|
+
const authority = rawAuthority(input);
|
|
7579
|
+
if (authority.includes("@") || authority.includes("\\") || authority.includes("%") || /[^\x00-\x7f]/.test(authority)) {
|
|
7580
|
+
throw new Error("API URL authority must be canonical ASCII without credentials.");
|
|
7581
|
+
}
|
|
7582
|
+
const canonicalHostname = canonicalAuthorityHostname(authority);
|
|
7583
|
+
const url = new URL(input);
|
|
7584
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
7585
|
+
throw new Error("API URL must use http or https.");
|
|
7586
|
+
}
|
|
7587
|
+
if (url.username || url.password) {
|
|
7588
|
+
throw new Error("API URL must not include credentials.");
|
|
7589
|
+
}
|
|
7590
|
+
if (!url.hostname || url.hostname.endsWith(".")) {
|
|
7591
|
+
throw new Error("API URL must include a canonical hostname.");
|
|
7592
|
+
}
|
|
7593
|
+
if (url.hostname.toLowerCase() !== canonicalHostname) {
|
|
7594
|
+
throw new Error("API URL authority must not rely on parser hostname normalization.");
|
|
7595
|
+
}
|
|
7596
|
+
if (url.hostname.split(".").some((label) => label.toLowerCase().startsWith("xn--"))) {
|
|
7597
|
+
throw new Error("API URL must not use IDN or punycode hostnames.");
|
|
7598
|
+
}
|
|
7599
|
+
if (url.protocol === "http:" && !isDeliberateLoopbackHttpAuthority(authority)) {
|
|
7600
|
+
throw new Error("API URL may use http only for an exact loopback authority.");
|
|
7601
|
+
}
|
|
7602
|
+
if (url.search || url.hash) {
|
|
7603
|
+
throw new Error("API URL must not include a query string or fragment.");
|
|
7604
|
+
}
|
|
7605
|
+
let path = url.pathname.replace(/\/+$/, "");
|
|
7606
|
+
if (path.endsWith("/v1"))
|
|
7607
|
+
path = path.slice(0, -"/v1".length);
|
|
7608
|
+
url.pathname = `${path}/v1`;
|
|
7609
|
+
return url.toString().replace(/\/+$/, "");
|
|
7610
|
+
}
|
|
7611
|
+
function resolveClientTransportSnapshot(name, env = process.env, options = {}) {
|
|
7612
|
+
env = snapshotClientEnvironment(name, env);
|
|
7613
|
+
const keys = clientTransportEnvKeys(name);
|
|
7614
|
+
const definedUrlEntries = keys.apiUrlKeys.filter((key) => Object.prototype.hasOwnProperty.call(env, key) && env[key] !== undefined).map((key) => ({ key, raw: String(env[key]) }));
|
|
7615
|
+
const blankUrl = definedUrlEntries.find((entry) => entry.raw.trim().length === 0);
|
|
7616
|
+
if (blankUrl) {
|
|
7617
|
+
throw new ClientTransportConfigurationError(name, `${blankUrl.key} is set but blank; public clients require an explicit HTTPS API URL and never select local storage.`, [blankUrl.key]);
|
|
7618
|
+
}
|
|
7619
|
+
const controlledUrl = definedUrlEntries.find((entry) => ASCII_CONTROL_PATTERN.test(entry.raw));
|
|
7620
|
+
if (controlledUrl) {
|
|
7621
|
+
throw new ClientTransportConfigurationError(name, `${controlledUrl.key} contains ASCII control characters.`, [controlledUrl.key]);
|
|
7622
|
+
}
|
|
7623
|
+
const usableUrlEntries = definedUrlEntries.map((entry) => ({ key: entry.key, value: entry.raw.trim() }));
|
|
7624
|
+
if (usableUrlEntries.length > 1 && new Set(usableUrlEntries.map((entry) => entry.value)).size > 1) {
|
|
7625
|
+
throw new ClientTransportConfigurationError(name, `${usableUrlEntries.map((entry) => entry.key).join(" and ")} disagree; client authority aliases must be identical or only one may be set.`, usableUrlEntries.map((entry) => entry.key));
|
|
7626
|
+
}
|
|
7627
|
+
const envUrlHit = usableUrlEntries[0] ?? null;
|
|
7628
|
+
const keychainUrlHit = keychainConfigValue(name, env, options.credentials?.keychain);
|
|
7629
|
+
const diskConfigUrlHit = appConfigDiskValue(name, env, keys.apiUrlKeys);
|
|
7630
|
+
if (diskConfigUrlHit?.unusable) {
|
|
7631
|
+
throw new ClientTransportConfigurationError(name, `${diskConfigUrlHit.key} in ${diskConfigUrlHit.path} is declared but blank or malformed; public clients require a valid HTTPS service authority.`, [diskConfigUrlHit.path]);
|
|
7632
|
+
}
|
|
7633
|
+
const urlCandidates = [
|
|
7634
|
+
...envUrlHit ? [envUrlHit] : [],
|
|
7635
|
+
...keychainUrlHit ? [{ key: keychainUrlHit.source, value: keychainUrlHit.value }] : [],
|
|
7636
|
+
...diskConfigUrlHit ? [{ key: diskConfigUrlHit.path, value: diskConfigUrlHit.value.trim() }] : []
|
|
7637
|
+
];
|
|
7638
|
+
const configuredUrl = urlCandidates[0] ?? null;
|
|
7639
|
+
const divergentUrls = urlCandidates.filter((candidate) => candidate.value !== configuredUrl?.value);
|
|
7640
|
+
if (configuredUrl && divergentUrls.length > 0) {
|
|
7641
|
+
throw new ClientTransportConfigurationError(name, `${configuredUrl.key} and ${divergentUrls.map((candidate) => candidate.key).join(" and ")} select different service authorities; refusing to send a credential written for one authority to the other.`, urlCandidates.map((candidate) => candidate.key));
|
|
7642
|
+
}
|
|
7643
|
+
const warnings = [];
|
|
7644
|
+
if (configuredUrl && !envUrlHit) {
|
|
7645
|
+
warnings.push(`No ${keys.apiUrlKeys[0]} in the environment; the server URL in ${configuredUrl.key} was used, so this client connects to the server. ` + `Keep that entry aligned with the intended service authority.`);
|
|
7646
|
+
}
|
|
7647
|
+
const credential = resolveCredential(name, env, options.credentials);
|
|
7648
|
+
if (!credential) {
|
|
7649
|
+
const diskHint = credentialDiskSourcesForMessage(name, env);
|
|
7650
|
+
const lead = configuredUrl ? `${configuredUrl.key} selects the HTTP server for '${name}', but no API key could be resolved` : `${keys.apiUrlKeys[0]} is not set and no API key could be resolved for '${name}'; a credential is required before the default fleet gateway authority applies`;
|
|
7651
|
+
warnings.push(`${lead}; refusing to create an unauthenticated client \u2014 public clients never fall back to SQLite or another local store. ` + `Looked in the Keychain (macOS only), then for a credential file at ${diskHint}, then for ${keys.apiKeyKeys[0]} in the environment.`);
|
|
7652
|
+
throw new ClientTransportConfigurationError(name, warnings.join(" "), [configuredUrl?.key ?? keys.apiUrlKeys[0]]);
|
|
7653
|
+
}
|
|
7654
|
+
if (credential.warning)
|
|
7655
|
+
warnings.push(credential.warning);
|
|
7656
|
+
let urlHit;
|
|
7657
|
+
if (configuredUrl) {
|
|
7658
|
+
urlHit = configuredUrl;
|
|
7659
|
+
} else {
|
|
7660
|
+
try {
|
|
7661
|
+
urlHit = { key: DEFAULT_AUTHORITY_SOURCE, value: defaultFleetGatewayBaseUrl(name) };
|
|
7662
|
+
} catch (error2) {
|
|
7663
|
+
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
7664
|
+
throw new ClientTransportConfigurationError(name, `No ${keys.apiUrlKeys[0]} is configured and the default fleet gateway authority cannot be composed for '${name}': ${message}`, [keys.apiUrlKeys[0]]);
|
|
7665
|
+
}
|
|
7666
|
+
}
|
|
7667
|
+
const apiUrlSource = urlHit.key;
|
|
7668
|
+
let baseUrl;
|
|
7669
|
+
try {
|
|
7670
|
+
baseUrl = toV1BaseUrl(urlHit.value);
|
|
7671
|
+
} catch (error2) {
|
|
7672
|
+
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
7673
|
+
throw new ClientTransportConfigurationError(name, `Invalid API URL from ${apiUrlSource}: ${message}`, [apiUrlSource]);
|
|
7674
|
+
}
|
|
6928
7675
|
return {
|
|
6929
|
-
|
|
6930
|
-
|
|
6931
|
-
|
|
6932
|
-
|
|
6933
|
-
|
|
6934
|
-
|
|
6935
|
-
|
|
6936
|
-
|
|
6937
|
-
|
|
6938
|
-
|
|
6939
|
-
|
|
6940
|
-
|
|
6941
|
-
...hasOwn(record3, "outputPreview") ? { outputPreview: record3.outputPreview } : {},
|
|
6942
|
-
...pickString(record3, "errorCode"),
|
|
6943
|
-
...pickString(record3, "errorMessage"),
|
|
6944
|
-
...pickString(record3, "error"),
|
|
6945
|
-
...pickString(record3, "code"),
|
|
6946
|
-
...hasOwn(record3, "details") ? { details: record3.details } : {}
|
|
7676
|
+
resolution: {
|
|
7677
|
+
transport: "http",
|
|
7678
|
+
transportSource: urlHit.key,
|
|
7679
|
+
baseUrl,
|
|
7680
|
+
apiUrlSource,
|
|
7681
|
+
apiKeyPresent: true,
|
|
7682
|
+
apiKeySource: credential.source,
|
|
7683
|
+
apiKeyTier: credential.tier,
|
|
7684
|
+
misconfigured: false,
|
|
7685
|
+
warning: warnings.length > 0 ? warnings.join(" ") : null
|
|
7686
|
+
},
|
|
7687
|
+
credential
|
|
6947
7688
|
};
|
|
6948
7689
|
}
|
|
6949
|
-
function
|
|
6950
|
-
return
|
|
6951
|
-
}
|
|
6952
|
-
function hasOwn(record3, key) {
|
|
6953
|
-
return Object.prototype.hasOwnProperty.call(record3, key);
|
|
7690
|
+
function resolveClientTransport(name, env = process.env, options = {}) {
|
|
7691
|
+
return resolveClientTransportSnapshot(name, env, options).resolution;
|
|
6954
7692
|
}
|
|
6955
|
-
function
|
|
6956
|
-
const
|
|
6957
|
-
return
|
|
7693
|
+
function credentialDiskSourcesForMessage(name, env) {
|
|
7694
|
+
const paths = credentialDiskSources(name, env);
|
|
7695
|
+
return paths.length > 0 ? paths.join(" or ") : "<no HOME or HASNA_HOME set in this environment, so no credential file was consulted>";
|
|
6958
7696
|
}
|
|
6959
|
-
|
|
6960
|
-
|
|
6961
|
-
|
|
6962
|
-
|
|
6963
|
-
|
|
6964
|
-
|
|
6965
|
-
|
|
6966
|
-
|
|
6967
|
-
|
|
6968
|
-
|
|
6969
|
-
|
|
6970
|
-
|
|
6971
|
-
|
|
6972
|
-
|
|
6973
|
-
|
|
6974
|
-
}
|
|
6975
|
-
|
|
6976
|
-
|
|
6977
|
-
if (!resolved)
|
|
6978
|
-
throw new MissingApiUrlError(action);
|
|
6979
|
-
return resolved;
|
|
6980
|
-
}
|
|
6981
|
-
var API_URL_ENV_VAR = "SKILLS_API_URL", API_URL_CONFIG_KEY = "apiUrl", MISSING_API_URL_HINT, MissingApiUrlError;
|
|
6982
|
-
var init_api_url = __esm(() => {
|
|
6983
|
-
init_config();
|
|
6984
|
-
MISSING_API_URL_HINT = `set ${API_URL_ENV_VAR}=<your Skills instance origin>, ` + `or run: skills setup --api-url <your Skills instance origin>`;
|
|
6985
|
-
MissingApiUrlError = class MissingApiUrlError extends Error {
|
|
6986
|
-
code = "MISSING_API_URL";
|
|
6987
|
-
constructor(action = "This command") {
|
|
6988
|
-
super(`${action} requires a Skills API URL and none is configured \u2014 ${MISSING_API_URL_HINT}`);
|
|
6989
|
-
this.name = "MissingApiUrlError";
|
|
7697
|
+
var CREDENTIAL_PROFILE_ENV_KEY = "HASNA_PROFILE", CredentialResolutionError, CredentialFileUnsafeError, HASNA_HOME_ENV_KEY = "HASNA_HOME", HASNA_CONFIG_HOME_ENV_KEY = "HASNA_CONFIG_HOME", KEYCHAIN_STATION_ENV_KEY = "HASNA_STATION", HASNA_HOME_DIR = ".hasna", CONFIG_SUBDIR = "config", CREDENTIALS_FILE = "credentials", KEYCHAIN_SECURITY_BIN = "/usr/bin/security", KEYCHAIN_SERVICE_PREFIX = "hasna.credentials", KEYCHAIN_ITEM_NOT_FOUND_STATUS = 44, KEYCHAIN_SPAWN_TIMEOUT_MS = 1e4, MAX_CREDENTIAL_FILE_BYTES, SAFE_APP_SLUG, SAFE_PROFILE, ILLEGAL_IN_HEADER_VALUE, VAULT_POINTER_SHAPE, CREDENTIAL_SHAPED_KEY, INSPECT_CUSTOM, CREDENTIAL_SEAL, AMBIENT_ENVIRONMENT, SECRETS_PACKAGE_SPECIFIER, requireSecretsSdk, DEFAULT_FLEET_GATEWAY_ORIGIN = "https://api.hasna.com", DEFAULT_AUTHORITY_SOURCE = "default", ASCII_CONTROL_PATTERN, DNS_LABEL_PATTERN, ClientTransportConfigurationError, IDEMPOTENT_METHODS, AUTHORITY_OVERRIDE_HEADERS;
|
|
7698
|
+
var init_transport = __esm(() => {
|
|
7699
|
+
CredentialResolutionError = class CredentialResolutionError extends Error {
|
|
7700
|
+
appName;
|
|
7701
|
+
attempted;
|
|
7702
|
+
constructor(appName, message, attempted) {
|
|
7703
|
+
super(message);
|
|
7704
|
+
this.name = "CredentialResolutionError";
|
|
7705
|
+
this.appName = appName;
|
|
7706
|
+
this.attempted = attempted;
|
|
7707
|
+
}
|
|
7708
|
+
};
|
|
7709
|
+
CredentialFileUnsafeError = class CredentialFileUnsafeError extends Error {
|
|
7710
|
+
path;
|
|
7711
|
+
constructor(path, reason) {
|
|
7712
|
+
super(`Refusing unsafe credential/config file ${path}: ${reason}.`);
|
|
7713
|
+
this.name = "CredentialFileUnsafeError";
|
|
7714
|
+
this.path = path;
|
|
6990
7715
|
}
|
|
6991
7716
|
};
|
|
7717
|
+
MAX_CREDENTIAL_FILE_BYTES = 64 * 1024;
|
|
7718
|
+
SAFE_APP_SLUG = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
7719
|
+
SAFE_PROFILE = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;
|
|
7720
|
+
ILLEGAL_IN_HEADER_VALUE = /[^\t\x20-\x7e]/;
|
|
7721
|
+
VAULT_POINTER_SHAPE = /^[a-z0-9][a-z0-9-]*(?:\/[a-z0-9][a-z0-9-_.]*){2,}$/;
|
|
7722
|
+
CREDENTIAL_SHAPED_KEY = /(?:^|_)(?:API_KEY|KEY|TOKEN|SECRET|PASSWORD|PASSWD|CREDENTIAL|AUTH)(?:_|$)/;
|
|
7723
|
+
INSPECT_CUSTOM = Symbol.for("nodejs.util.inspect.custom");
|
|
7724
|
+
CREDENTIAL_SEAL = Symbol.for("hasna:contracts:sealedCredential");
|
|
7725
|
+
AMBIENT_ENVIRONMENT = Symbol.for("hasna:contracts:ambientClientEnvironment");
|
|
7726
|
+
SECRETS_PACKAGE_SPECIFIER = "@hasna/" + "secrets";
|
|
7727
|
+
requireSecretsSdk = createRequire(import.meta.url);
|
|
7728
|
+
ASCII_CONTROL_PATTERN = /[\u0000-\u001f\u007f]/;
|
|
7729
|
+
DNS_LABEL_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
7730
|
+
ClientTransportConfigurationError = class ClientTransportConfigurationError extends Error {
|
|
7731
|
+
appName;
|
|
7732
|
+
sources;
|
|
7733
|
+
constructor(appName, message, sources = []) {
|
|
7734
|
+
super(message);
|
|
7735
|
+
this.name = "ClientTransportConfigurationError";
|
|
7736
|
+
this.appName = appName;
|
|
7737
|
+
this.sources = Object.freeze([...sources]);
|
|
7738
|
+
}
|
|
7739
|
+
};
|
|
7740
|
+
IDEMPOTENT_METHODS = new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
|
|
7741
|
+
AUTHORITY_OVERRIDE_HEADERS = new Set([
|
|
7742
|
+
"host",
|
|
7743
|
+
":authority",
|
|
7744
|
+
"forwarded",
|
|
7745
|
+
"x-forwarded-host",
|
|
7746
|
+
"x-original-host"
|
|
7747
|
+
]);
|
|
6992
7748
|
});
|
|
6993
7749
|
|
|
6994
|
-
// src/lib/
|
|
6995
|
-
var
|
|
6996
|
-
__export(
|
|
6997
|
-
|
|
7750
|
+
// src/lib/fleet-credentials.ts
|
|
7751
|
+
var exports_fleet_credentials = {};
|
|
7752
|
+
__export(exports_fleet_credentials, {
|
|
7753
|
+
skillsCredentialOrReason: () => skillsCredentialOrReason,
|
|
7754
|
+
skillsCredentialFiles: () => skillsCredentialFiles,
|
|
7755
|
+
skillsCredentialFilePath: () => skillsCredentialFilePath,
|
|
7756
|
+
resolveSkillsFleet: () => resolveSkillsFleet,
|
|
7757
|
+
resolveSkillsApiOrigin: () => resolveSkillsApiOrigin,
|
|
7758
|
+
resolveSkillsApiKey: () => resolveSkillsApiKey,
|
|
7759
|
+
resetLocalSkillsModeNotice: () => resetLocalSkillsModeNotice,
|
|
7760
|
+
requireSkillsFleet: () => requireSkillsFleet,
|
|
7761
|
+
requireSkillsApiOrigin: () => requireSkillsApiOrigin,
|
|
7762
|
+
requireSkillsApiKey: () => requireSkillsApiKey,
|
|
7763
|
+
noticeLocalSkillsMode: () => noticeLocalSkillsMode,
|
|
6998
7764
|
normalizeSkillsApiOrigin: () => normalizeSkillsApiOrigin,
|
|
6999
|
-
|
|
7000
|
-
|
|
7001
|
-
|
|
7002
|
-
|
|
7003
|
-
|
|
7004
|
-
|
|
7005
|
-
|
|
7006
|
-
|
|
7007
|
-
});
|
|
7008
|
-
|
|
7009
|
-
|
|
7010
|
-
|
|
7011
|
-
function
|
|
7012
|
-
return
|
|
7013
|
-
}
|
|
7014
|
-
function
|
|
7015
|
-
|
|
7016
|
-
}
|
|
7017
|
-
function legacyAuthFilePath() {
|
|
7018
|
-
return join13(process.env["HOME"] || process.env["USERPROFILE"] || homedir4(), ".skills", "auth.json");
|
|
7019
|
-
}
|
|
7020
|
-
function getAuthConfig() {
|
|
7021
|
-
if (cachedConfig !== undefined)
|
|
7022
|
-
return cachedConfig;
|
|
7023
|
-
try {
|
|
7024
|
-
const file = existsSync13(getAuthFilePath()) ? getAuthFilePath() : legacyAuthFilePath();
|
|
7025
|
-
const raw = readFileSync11(file, "utf-8");
|
|
7026
|
-
const config2 = JSON.parse(raw);
|
|
7027
|
-
if (!config2.apiKey) {
|
|
7028
|
-
cachedConfig = null;
|
|
7029
|
-
return null;
|
|
7030
|
-
}
|
|
7031
|
-
cachedConfig = config2;
|
|
7032
|
-
return config2;
|
|
7033
|
-
} catch {
|
|
7034
|
-
cachedConfig = null;
|
|
7035
|
-
return null;
|
|
7036
|
-
}
|
|
7037
|
-
}
|
|
7038
|
-
function saveAuthConfig(config2) {
|
|
7039
|
-
const file = getAuthFilePath();
|
|
7040
|
-
mkdirSync6(dirname5(file), { recursive: true, mode: 448 });
|
|
7041
|
-
writeFileSync6(file, JSON.stringify(config2, null, 2) + `
|
|
7042
|
-
`, { mode: 384 });
|
|
7043
|
-
cachedConfig = config2;
|
|
7044
|
-
}
|
|
7045
|
-
function clearAuthConfig() {
|
|
7046
|
-
try {
|
|
7047
|
-
unlinkSync(getAuthFilePath());
|
|
7048
|
-
} catch {}
|
|
7049
|
-
try {
|
|
7050
|
-
unlinkSync(legacyAuthFilePath());
|
|
7051
|
-
} catch {}
|
|
7052
|
-
cachedConfig = undefined;
|
|
7053
|
-
}
|
|
7054
|
-
function getApiKey() {
|
|
7055
|
-
if (process.env.SKILLS_API_KEY)
|
|
7056
|
-
return process.env.SKILLS_API_KEY;
|
|
7057
|
-
if (process.env.SKILL_API_KEY)
|
|
7058
|
-
return process.env.SKILL_API_KEY;
|
|
7059
|
-
return getAuthConfig()?.apiKey || null;
|
|
7060
|
-
}
|
|
7061
|
-
function getAuthConfigReadOnly() {
|
|
7062
|
-
try {
|
|
7063
|
-
const file = existsSync13(getAuthFilePathReadOnly()) ? getAuthFilePathReadOnly() : legacyAuthFilePath();
|
|
7064
|
-
const raw = readFileSync11(file, "utf-8");
|
|
7065
|
-
const config2 = JSON.parse(raw);
|
|
7066
|
-
if (!config2.apiKey)
|
|
7067
|
-
return null;
|
|
7068
|
-
return config2;
|
|
7069
|
-
} catch {
|
|
7765
|
+
configuredSkillsApiUrl: () => configuredSkillsApiUrl,
|
|
7766
|
+
SkillsFleetCredentialError: () => SkillsFleetCredentialError,
|
|
7767
|
+
SKILLS_APP: () => SKILLS_APP,
|
|
7768
|
+
SKILLS_API_URL_ENV_KEYS: () => SKILLS_API_URL_ENV_KEYS,
|
|
7769
|
+
SKILLS_API_URL_ENV: () => SKILLS_API_URL_ENV,
|
|
7770
|
+
SKILLS_API_KEY_ENV_KEYS: () => SKILLS_API_KEY_ENV_KEYS,
|
|
7771
|
+
SKILLS_API_KEY_ENV: () => SKILLS_API_KEY_ENV,
|
|
7772
|
+
MissingSkillsFleetError: () => MissingSkillsFleetError
|
|
7773
|
+
});
|
|
7774
|
+
function isClientTransportConfigurationError(error2) {
|
|
7775
|
+
return error2 instanceof ClientTransportConfigurationError || typeof error2 === "object" && error2 !== null && error2.name === "ClientTransportConfigurationError";
|
|
7776
|
+
}
|
|
7777
|
+
function isCredentialResolutionError(error2) {
|
|
7778
|
+
return error2 instanceof CredentialResolutionError || typeof error2 === "object" && error2 !== null && error2.name === "CredentialResolutionError";
|
|
7779
|
+
}
|
|
7780
|
+
function asSkillsFleetCredentialError(error2) {
|
|
7781
|
+
if (!isCredentialResolutionError(error2))
|
|
7070
7782
|
return null;
|
|
7071
|
-
|
|
7072
|
-
}
|
|
7073
|
-
function getApiKeyReadOnly() {
|
|
7074
|
-
if (process.env.SKILLS_API_KEY)
|
|
7075
|
-
return process.env.SKILLS_API_KEY;
|
|
7076
|
-
if (process.env.SKILL_API_KEY)
|
|
7077
|
-
return process.env.SKILL_API_KEY;
|
|
7078
|
-
return getAuthConfigReadOnly()?.apiKey || null;
|
|
7783
|
+
return new SkillsFleetCredentialError(error2.message, "MISSING_API_CREDENTIAL");
|
|
7079
7784
|
}
|
|
7080
7785
|
function normalizeSkillsApiOrigin(apiUrl) {
|
|
7081
7786
|
const url = new URL(apiUrl);
|
|
@@ -7089,13 +7794,182 @@ function normalizeSkillsApiOrigin(apiUrl) {
|
|
|
7089
7794
|
}
|
|
7090
7795
|
return url.toString().replace(/\/+$/, "");
|
|
7091
7796
|
}
|
|
7092
|
-
function
|
|
7093
|
-
|
|
7797
|
+
function configuredSkillsApiUrl(env = process.env, keychain) {
|
|
7798
|
+
for (const key of SKILLS_API_URL_ENV_KEYS) {
|
|
7799
|
+
const value = env[key]?.trim();
|
|
7800
|
+
if (value)
|
|
7801
|
+
return { value, source: key };
|
|
7802
|
+
}
|
|
7803
|
+
const fromKeychain = keychainConfigValue(SKILLS_APP, env, keychain);
|
|
7804
|
+
if (fromKeychain)
|
|
7805
|
+
return { value: fromKeychain.value.trim(), source: fromKeychain.source };
|
|
7806
|
+
const fromDisk = appConfigDiskValue(SKILLS_APP, env, SKILLS_API_URL_ENV_KEYS);
|
|
7807
|
+
if (fromDisk?.unusable) {
|
|
7808
|
+
throw new SkillsFleetCredentialError(`${fromDisk.key} in ${fromDisk.path} is declared but blank or malformed; ` + `a Skills authority must be a valid https URL (or an exact loopback http URL).`, "INVALID_API_URL");
|
|
7809
|
+
}
|
|
7810
|
+
if (fromDisk)
|
|
7811
|
+
return { value: fromDisk.value.trim(), source: fromDisk.path };
|
|
7812
|
+
return null;
|
|
7094
7813
|
}
|
|
7095
|
-
|
|
7096
|
-
|
|
7097
|
-
|
|
7098
|
-
|
|
7814
|
+
function skillsCredentialFiles(env = process.env) {
|
|
7815
|
+
return credentialDiskSources(SKILLS_APP, env);
|
|
7816
|
+
}
|
|
7817
|
+
function skillsCredentialFilePath(env = process.env) {
|
|
7818
|
+
const paths = skillsCredentialFiles(env);
|
|
7819
|
+
const path = paths[0];
|
|
7820
|
+
if (!path) {
|
|
7821
|
+
throw new Error("No home directory is set (HOME or HASNA_HOME), so there is nowhere to store a Skills credential.");
|
|
7822
|
+
}
|
|
7823
|
+
return path;
|
|
7824
|
+
}
|
|
7825
|
+
function noticeLocalSkillsMode(write = (line) => console.error(line)) {
|
|
7826
|
+
if (localNoticePrinted)
|
|
7827
|
+
return;
|
|
7828
|
+
localNoticePrinted = true;
|
|
7829
|
+
write(`skills: local mode \u2014 no ${SKILLS_API_KEY_ENV} and no ${SKILLS_API_URL_ENV} resolved, ` + `so this runs on this machine against the bundled corpus. ` + `Sign in with: skills auth login`);
|
|
7830
|
+
}
|
|
7831
|
+
function resetLocalSkillsModeNotice() {
|
|
7832
|
+
localNoticePrinted = false;
|
|
7833
|
+
}
|
|
7834
|
+
function resolveSkillsFleet(env = process.env, options = {}) {
|
|
7835
|
+
try {
|
|
7836
|
+
return resolveSkillsFleetOrThrow(env, options);
|
|
7837
|
+
} catch (error2) {
|
|
7838
|
+
const translated = asSkillsFleetCredentialError(error2);
|
|
7839
|
+
if (translated)
|
|
7840
|
+
throw translated;
|
|
7841
|
+
throw error2;
|
|
7842
|
+
}
|
|
7843
|
+
}
|
|
7844
|
+
function resolveSkillsFleetOrThrow(env, options) {
|
|
7845
|
+
let resolution;
|
|
7846
|
+
try {
|
|
7847
|
+
resolution = resolveClientTransport(SKILLS_APP, env, { credentials: options.credentials });
|
|
7848
|
+
} catch (error2) {
|
|
7849
|
+
if (!isClientTransportConfigurationError(error2))
|
|
7850
|
+
throw error2;
|
|
7851
|
+
const configured2 = configuredSkillsApiUrl(env, options.credentials?.keychain);
|
|
7852
|
+
const credential2 = resolveCredential(SKILLS_APP, env, options.credentials);
|
|
7853
|
+
if (!configured2 && !credential2) {
|
|
7854
|
+
if (env === process.env)
|
|
7855
|
+
noticeLocalSkillsMode();
|
|
7856
|
+
return { mode: "local", apiOrigin: null, apiKey: null };
|
|
7857
|
+
}
|
|
7858
|
+
if (configured2 && !credential2) {
|
|
7859
|
+
throw new SkillsFleetCredentialError(`${configured2.source} points this CLI at a Skills service but no API key resolved \u2014 ` + `refusing to run locally instead. Looked in the Keychain item ` + `hasna.credentials.${SKILLS_APP}.api-key, then ${skillsCredentialFiles(env).join(" or ") || "no credentials file (no HOME)"}, ` + `then ${SKILLS_API_KEY_ENV}. Sign in with: skills auth login`);
|
|
7860
|
+
}
|
|
7861
|
+
throw error2;
|
|
7862
|
+
}
|
|
7863
|
+
const configured = configuredSkillsApiUrl(env, options.credentials?.keychain);
|
|
7864
|
+
const apiOrigin = configured ? normalizeSkillsApiOrigin(configured.value) : stripV1(resolution.baseUrl);
|
|
7865
|
+
const credential = resolveCredential(SKILLS_APP, env, options.credentials);
|
|
7866
|
+
if (!credential) {
|
|
7867
|
+
throw new SkillsFleetCredentialError(`A Skills authority resolved but no API key did. Sign in with: skills auth login`);
|
|
7868
|
+
}
|
|
7869
|
+
const base = {
|
|
7870
|
+
mode: "hosted",
|
|
7871
|
+
apiOrigin,
|
|
7872
|
+
apiUrlSource: resolution.apiUrlSource ?? (configured?.source ?? "default"),
|
|
7873
|
+
apiKeySource: resolution.apiKeySource ?? credential.source,
|
|
7874
|
+
apiKeyTier: resolution.apiKeyTier,
|
|
7875
|
+
warning: resolution.warning
|
|
7876
|
+
};
|
|
7877
|
+
if (credential.tier === "pointer") {
|
|
7878
|
+
return { ...base, apiKey: null, apiKeyPointer: credential };
|
|
7879
|
+
}
|
|
7880
|
+
if (!credential.apiKey.trim()) {
|
|
7881
|
+
throw new SkillsFleetCredentialError(`The Skills API key from ${credential.source} is empty \u2014 refusing to send an unauthenticated request. ` + `Sign in with: skills auth login`);
|
|
7882
|
+
}
|
|
7883
|
+
return { ...base, apiKey: credential.apiKey, apiKeyPointer: null };
|
|
7884
|
+
}
|
|
7885
|
+
async function resolveSkillsApiKey(env = process.env, options = {}) {
|
|
7886
|
+
const fleet = resolveSkillsFleet(env, options);
|
|
7887
|
+
if (fleet.mode !== "hosted")
|
|
7888
|
+
return null;
|
|
7889
|
+
if (fleet.apiKey)
|
|
7890
|
+
return fleet.apiKey;
|
|
7891
|
+
const pointer = fleet.apiKeyPointer;
|
|
7892
|
+
if (!pointer) {
|
|
7893
|
+
throw new SkillsFleetCredentialError(`A Skills authority resolved but no API key did. Sign in with: skills auth login`);
|
|
7894
|
+
}
|
|
7895
|
+
let completed;
|
|
7896
|
+
try {
|
|
7897
|
+
completed = await completePointerCredential(SKILLS_APP, pointer, env);
|
|
7898
|
+
} catch (error2) {
|
|
7899
|
+
const translated = asSkillsFleetCredentialError(error2);
|
|
7900
|
+
if (translated)
|
|
7901
|
+
throw translated;
|
|
7902
|
+
throw error2;
|
|
7903
|
+
}
|
|
7904
|
+
if (!completed.apiKey?.trim()) {
|
|
7905
|
+
throw new SkillsFleetCredentialError(`${credentialPointerEnvKey(SKILLS_APP)} names a vault item that produced an empty Skills API key \u2014 ` + `refusing to send an unauthenticated request.`);
|
|
7906
|
+
}
|
|
7907
|
+
return completed.apiKey;
|
|
7908
|
+
}
|
|
7909
|
+
async function requireSkillsApiKey(action = "This command", env = process.env, options = {}) {
|
|
7910
|
+
const apiKey = await resolveSkillsApiKey(env, options);
|
|
7911
|
+
if (!apiKey)
|
|
7912
|
+
throw new MissingSkillsFleetError(action);
|
|
7913
|
+
return apiKey;
|
|
7914
|
+
}
|
|
7915
|
+
function stripV1(baseUrl) {
|
|
7916
|
+
return baseUrl.replace(/\/v1$/, "").replace(/\/+$/, "");
|
|
7917
|
+
}
|
|
7918
|
+
async function skillsCredentialOrReason(env = process.env, options = {}) {
|
|
7919
|
+
try {
|
|
7920
|
+
const apiKey = await resolveSkillsApiKey(env, options);
|
|
7921
|
+
return apiKey ? { apiKey, reason: null } : { apiKey: null, reason: null };
|
|
7922
|
+
} catch (error2) {
|
|
7923
|
+
if (error2 instanceof SkillsFleetCredentialError || error2?.name === "SkillsFleetCredentialError") {
|
|
7924
|
+
return { apiKey: null, reason: error2.message };
|
|
7925
|
+
}
|
|
7926
|
+
throw error2;
|
|
7927
|
+
}
|
|
7928
|
+
}
|
|
7929
|
+
function resolveSkillsApiOrigin(env = process.env, options = {}) {
|
|
7930
|
+
const configured = configuredSkillsApiUrl(env, options.credentials?.keychain);
|
|
7931
|
+
if (configured) {
|
|
7932
|
+
toV1BaseUrl(configured.value);
|
|
7933
|
+
return { origin: normalizeSkillsApiOrigin(configured.value), source: configured.source };
|
|
7934
|
+
}
|
|
7935
|
+
const fleet = resolveSkillsFleet(env, options);
|
|
7936
|
+
return fleet.mode === "hosted" ? { origin: fleet.apiOrigin, source: fleet.apiUrlSource } : null;
|
|
7937
|
+
}
|
|
7938
|
+
function requireSkillsApiOrigin(action = "This command", env = process.env, options = {}) {
|
|
7939
|
+
const resolved = resolveSkillsApiOrigin(env, options);
|
|
7940
|
+
if (!resolved)
|
|
7941
|
+
throw new MissingSkillsFleetError(action);
|
|
7942
|
+
return resolved.origin;
|
|
7943
|
+
}
|
|
7944
|
+
function requireSkillsFleet(action = "This command", env = process.env, options = {}) {
|
|
7945
|
+
const fleet = resolveSkillsFleet(env, options);
|
|
7946
|
+
if (fleet.mode === "hosted")
|
|
7947
|
+
return fleet;
|
|
7948
|
+
throw new MissingSkillsFleetError(action);
|
|
7949
|
+
}
|
|
7950
|
+
var SKILLS_APP = "skills", ENV_KEYS, SKILLS_API_URL_ENV_KEYS, SKILLS_API_KEY_ENV_KEYS, SKILLS_API_URL_ENV, SKILLS_API_KEY_ENV, SkillsFleetCredentialError, localNoticePrinted = false, MissingSkillsFleetError;
|
|
7951
|
+
var init_fleet_credentials = __esm(() => {
|
|
7952
|
+
init_transport();
|
|
7953
|
+
ENV_KEYS = clientTransportEnvKeys(SKILLS_APP);
|
|
7954
|
+
SKILLS_API_URL_ENV_KEYS = ENV_KEYS.apiUrlKeys;
|
|
7955
|
+
SKILLS_API_KEY_ENV_KEYS = ENV_KEYS.apiKeyKeys;
|
|
7956
|
+
SKILLS_API_URL_ENV = SKILLS_API_URL_ENV_KEYS[0];
|
|
7957
|
+
SKILLS_API_KEY_ENV = SKILLS_API_KEY_ENV_KEYS[0];
|
|
7958
|
+
SkillsFleetCredentialError = class SkillsFleetCredentialError extends Error {
|
|
7959
|
+
code;
|
|
7960
|
+
constructor(message, code = "MISSING_API_CREDENTIAL") {
|
|
7961
|
+
super(message);
|
|
7962
|
+
this.name = "SkillsFleetCredentialError";
|
|
7963
|
+
this.code = code;
|
|
7964
|
+
}
|
|
7965
|
+
};
|
|
7966
|
+
MissingSkillsFleetError = class MissingSkillsFleetError extends Error {
|
|
7967
|
+
code = "MISSING_API_URL";
|
|
7968
|
+
constructor(action = "This command") {
|
|
7969
|
+
super(`${action} requires a Skills API credential and none is configured \u2014 ` + `run: skills auth login, or set ${SKILLS_API_KEY_ENV} ` + `(add the Keychain item hasna.credentials.${SKILLS_APP}.api-key, or write ~/.hasna/skills/config/credentials). ` + `Point at your own instance with ${SKILLS_API_URL_ENV}, or run: skills setup --api-url <your Skills instance origin>`);
|
|
7970
|
+
this.name = "MissingSkillsFleetError";
|
|
7971
|
+
}
|
|
7972
|
+
};
|
|
7099
7973
|
});
|
|
7100
7974
|
|
|
7101
7975
|
// src/lib/blog-article.ts
|
|
@@ -7228,6 +8102,15 @@ var init_blog_article = __esm(() => {
|
|
|
7228
8102
|
ARTICLE_LENGTHS = ["short", "medium", "long"];
|
|
7229
8103
|
});
|
|
7230
8104
|
|
|
8105
|
+
// src/lib/auth-store.ts
|
|
8106
|
+
function getApiUrl(action, env = process.env, options = {}) {
|
|
8107
|
+
return requireSkillsApiOrigin(action, env, options);
|
|
8108
|
+
}
|
|
8109
|
+
var init_auth_store = __esm(() => {
|
|
8110
|
+
init_fleet_credentials();
|
|
8111
|
+
init_fleet_credentials();
|
|
8112
|
+
});
|
|
8113
|
+
|
|
7231
8114
|
// src/lib/remote-client.ts
|
|
7232
8115
|
var exports_remote_client = {};
|
|
7233
8116
|
__export(exports_remote_client, {
|
|
@@ -7501,26 +8384,23 @@ function normalizeUpdatedSincePage(payload) {
|
|
|
7501
8384
|
}
|
|
7502
8385
|
return { skills, nextCursor };
|
|
7503
8386
|
}
|
|
7504
|
-
function createRemoteSkillsClient() {
|
|
7505
|
-
const
|
|
7506
|
-
if (
|
|
8387
|
+
async function createRemoteSkillsClient(env = process.env) {
|
|
8388
|
+
const fleet = resolveSkillsFleet(env);
|
|
8389
|
+
if (fleet.mode !== "hosted")
|
|
7507
8390
|
return null;
|
|
7508
|
-
|
|
7509
|
-
|
|
7510
|
-
|
|
7511
|
-
|
|
7512
|
-
|
|
7513
|
-
|
|
7514
|
-
|
|
7515
|
-
|
|
7516
|
-
throw new MissingApiUrlError("the cloud group's sync verb (--dry-run)");
|
|
7517
|
-
return new RemoteSkillsClient(apiKey, apiUrl);
|
|
8391
|
+
const apiKey = await resolveSkillsApiKey(env);
|
|
8392
|
+
if (!apiKey) {
|
|
8393
|
+
throw new Error("A Skills authority resolved but no API key did. Sign in with: skills auth login");
|
|
8394
|
+
}
|
|
8395
|
+
return new RemoteSkillsClient(apiKey, fleet.apiOrigin);
|
|
8396
|
+
}
|
|
8397
|
+
function createRemoteSkillsClientReadOnly(env = process.env) {
|
|
8398
|
+
return createRemoteSkillsClient(env);
|
|
7518
8399
|
}
|
|
7519
8400
|
var RemoteRouteUnsupportedError, RemoteRequestError;
|
|
7520
8401
|
var init_remote_client = __esm(() => {
|
|
7521
8402
|
init_auth_store();
|
|
7522
|
-
|
|
7523
|
-
init_config();
|
|
8403
|
+
init_fleet_credentials();
|
|
7524
8404
|
RemoteRouteUnsupportedError = class RemoteRouteUnsupportedError extends Error {
|
|
7525
8405
|
path;
|
|
7526
8406
|
status;
|
|
@@ -7651,7 +8531,7 @@ var require_content_type = __commonJS((exports) => {
|
|
|
7651
8531
|
}
|
|
7652
8532
|
});
|
|
7653
8533
|
|
|
7654
|
-
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
8534
|
+
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0+2b91fc17bf64bdfd/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
7655
8535
|
import process2 from "process";
|
|
7656
8536
|
|
|
7657
8537
|
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v4/core/core.js
|
|
@@ -12109,7 +12989,7 @@ function preprocess(fn, schema) {
|
|
|
12109
12989
|
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v4/classic/external.js
|
|
12110
12990
|
config(en_default());
|
|
12111
12991
|
|
|
12112
|
-
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0/node_modules/@modelcontextprotocol/sdk/dist/esm/types.js
|
|
12992
|
+
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0+2b91fc17bf64bdfd/node_modules/@modelcontextprotocol/sdk/dist/esm/types.js
|
|
12113
12993
|
var LATEST_PROTOCOL_VERSION = "2025-11-25";
|
|
12114
12994
|
var DEFAULT_NEGOTIATED_PROTOCOL_VERSION = "2025-03-26";
|
|
12115
12995
|
var SUPPORTED_PROTOCOL_VERSIONS = [LATEST_PROTOCOL_VERSION, "2025-06-18", "2025-03-26", "2024-11-05", "2024-10-07"];
|
|
@@ -12956,7 +13836,7 @@ class UrlElicitationRequiredError extends McpError {
|
|
|
12956
13836
|
}
|
|
12957
13837
|
}
|
|
12958
13838
|
|
|
12959
|
-
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
|
|
13839
|
+
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0+2b91fc17bf64bdfd/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
|
|
12960
13840
|
var STDIO_DEFAULT_MAX_BUFFER_SIZE = 10 * 1024 * 1024;
|
|
12961
13841
|
|
|
12962
13842
|
class ReadBuffer {
|
|
@@ -12996,7 +13876,7 @@ function serializeMessage(message) {
|
|
|
12996
13876
|
`;
|
|
12997
13877
|
}
|
|
12998
13878
|
|
|
12999
|
-
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
13879
|
+
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0+2b91fc17bf64bdfd/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
13000
13880
|
class StdioServerTransport {
|
|
13001
13881
|
constructor(_stdin = process2.stdin, _stdout = process2.stdout, options) {
|
|
13002
13882
|
this._stdin = _stdin;
|
|
@@ -13061,12 +13941,13 @@ class StdioServerTransport {
|
|
|
13061
13941
|
// package.json
|
|
13062
13942
|
var package_default = {
|
|
13063
13943
|
name: "@hasna/skills",
|
|
13064
|
-
version: "0.
|
|
13944
|
+
version: "0.3.0",
|
|
13065
13945
|
description: "Skills library for AI coding agents",
|
|
13066
13946
|
type: "module",
|
|
13067
13947
|
bin: {
|
|
13068
13948
|
skills: "bin/index.js",
|
|
13069
13949
|
"skills-mcp": "bin/mcp.js",
|
|
13950
|
+
"skills-serve": "bin/server.js",
|
|
13070
13951
|
"skills-server": "bin/server.js",
|
|
13071
13952
|
"skills-worker": "bin/worker.js",
|
|
13072
13953
|
"skills-migrate": "bin/migrate.js"
|
|
@@ -13152,6 +14033,7 @@ var package_default = {
|
|
|
13152
14033
|
dependencies: {
|
|
13153
14034
|
"@aws-sdk/client-ecs": "^3.1079.0",
|
|
13154
14035
|
"@aws-sdk/client-s3": "^3.1079.0",
|
|
14036
|
+
"@hasna/contracts": "1.0.1",
|
|
13155
14037
|
"@hasna/events": "0.1.16",
|
|
13156
14038
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
13157
14039
|
chalk: "^5.3.0",
|
|
@@ -17195,7 +18077,7 @@ function object2(shape, params) {
|
|
|
17195
18077
|
};
|
|
17196
18078
|
return new ZodMiniObject(def);
|
|
17197
18079
|
}
|
|
17198
|
-
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-compat.js
|
|
18080
|
+
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0+2b91fc17bf64bdfd/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-compat.js
|
|
17199
18081
|
function isZ4Schema(s) {
|
|
17200
18082
|
const schema = s;
|
|
17201
18083
|
return !!schema._zod;
|
|
@@ -17356,7 +18238,7 @@ function getLiteralValue(schema) {
|
|
|
17356
18238
|
return;
|
|
17357
18239
|
}
|
|
17358
18240
|
|
|
17359
|
-
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/interfaces.js
|
|
18241
|
+
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0+2b91fc17bf64bdfd/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/interfaces.js
|
|
17360
18242
|
function isTerminal(status) {
|
|
17361
18243
|
return status === "completed" || status === "failed" || status === "cancelled";
|
|
17362
18244
|
}
|
|
@@ -18597,7 +19479,7 @@ var zodToJsonSchema = (schema, options) => {
|
|
|
18597
19479
|
}
|
|
18598
19480
|
return combined;
|
|
18599
19481
|
};
|
|
18600
|
-
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-json-schema-compat.js
|
|
19482
|
+
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0+2b91fc17bf64bdfd/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-json-schema-compat.js
|
|
18601
19483
|
function mapMiniTarget(t) {
|
|
18602
19484
|
if (!t)
|
|
18603
19485
|
return "draft-7";
|
|
@@ -18639,7 +19521,7 @@ function parseWithCompat(schema, data) {
|
|
|
18639
19521
|
return result.data;
|
|
18640
19522
|
}
|
|
18641
19523
|
|
|
18642
|
-
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/protocol.js
|
|
19524
|
+
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0+2b91fc17bf64bdfd/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/protocol.js
|
|
18643
19525
|
var DEFAULT_REQUEST_TIMEOUT_MSEC = 60000;
|
|
18644
19526
|
|
|
18645
19527
|
class Protocol {
|
|
@@ -19480,7 +20362,7 @@ function mergeCapabilities(base, additional) {
|
|
|
19480
20362
|
return result;
|
|
19481
20363
|
}
|
|
19482
20364
|
|
|
19483
|
-
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0/node_modules/@modelcontextprotocol/sdk/dist/esm/validation/ajv-provider.js
|
|
20365
|
+
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0+2b91fc17bf64bdfd/node_modules/@modelcontextprotocol/sdk/dist/esm/validation/ajv-provider.js
|
|
19484
20366
|
var import_ajv = __toESM(require_ajv(), 1);
|
|
19485
20367
|
var import_ajv_formats = __toESM(require_dist(), 1);
|
|
19486
20368
|
function createDefaultAjvInstance() {
|
|
@@ -19520,7 +20402,7 @@ class AjvJsonSchemaValidator {
|
|
|
19520
20402
|
}
|
|
19521
20403
|
}
|
|
19522
20404
|
|
|
19523
|
-
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/server.js
|
|
20405
|
+
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0+2b91fc17bf64bdfd/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/server.js
|
|
19524
20406
|
class ExperimentalServerTasks {
|
|
19525
20407
|
constructor(_server) {
|
|
19526
20408
|
this._server = _server;
|
|
@@ -19598,7 +20480,7 @@ class ExperimentalServerTasks {
|
|
|
19598
20480
|
}
|
|
19599
20481
|
}
|
|
19600
20482
|
|
|
19601
|
-
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/helpers.js
|
|
20483
|
+
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0+2b91fc17bf64bdfd/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/helpers.js
|
|
19602
20484
|
function assertToolsCallTaskCapability(requests, method, entityName) {
|
|
19603
20485
|
if (!requests) {
|
|
19604
20486
|
throw new Error(`${entityName} does not support task creation (required for ${method})`);
|
|
@@ -19633,7 +20515,7 @@ function assertClientRequestTaskCapability(requests, method, entityName) {
|
|
|
19633
20515
|
}
|
|
19634
20516
|
}
|
|
19635
20517
|
|
|
19636
|
-
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js
|
|
20518
|
+
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0+2b91fc17bf64bdfd/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js
|
|
19637
20519
|
class Server extends Protocol {
|
|
19638
20520
|
constructor(_serverInfo, options) {
|
|
19639
20521
|
super(options);
|
|
@@ -19957,7 +20839,7 @@ class Server extends Protocol {
|
|
|
19957
20839
|
}
|
|
19958
20840
|
}
|
|
19959
20841
|
|
|
19960
|
-
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0/node_modules/@modelcontextprotocol/sdk/dist/esm/server/completable.js
|
|
20842
|
+
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0+2b91fc17bf64bdfd/node_modules/@modelcontextprotocol/sdk/dist/esm/server/completable.js
|
|
19961
20843
|
var COMPLETABLE_SYMBOL = Symbol.for("mcp.completable");
|
|
19962
20844
|
function isCompletable(schema) {
|
|
19963
20845
|
return !!schema && typeof schema === "object" && COMPLETABLE_SYMBOL in schema;
|
|
@@ -19971,7 +20853,7 @@ var McpZodTypeKind;
|
|
|
19971
20853
|
McpZodTypeKind2["Completable"] = "McpCompletable";
|
|
19972
20854
|
})(McpZodTypeKind || (McpZodTypeKind = {}));
|
|
19973
20855
|
|
|
19974
|
-
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/uriTemplate.js
|
|
20856
|
+
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0+2b91fc17bf64bdfd/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/uriTemplate.js
|
|
19975
20857
|
var MAX_TEMPLATE_LENGTH = 1e6;
|
|
19976
20858
|
var MAX_VARIABLE_LENGTH = 1e6;
|
|
19977
20859
|
var MAX_TEMPLATE_EXPRESSIONS = 1e4;
|
|
@@ -20189,7 +21071,7 @@ class UriTemplate {
|
|
|
20189
21071
|
}
|
|
20190
21072
|
}
|
|
20191
21073
|
|
|
20192
|
-
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/toolNameValidation.js
|
|
21074
|
+
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0+2b91fc17bf64bdfd/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/toolNameValidation.js
|
|
20193
21075
|
var TOOL_NAME_REGEX = /^[A-Za-z0-9._-]{1,128}$/;
|
|
20194
21076
|
function validateToolName(name) {
|
|
20195
21077
|
const warnings = [];
|
|
@@ -20247,7 +21129,7 @@ function validateAndWarnToolName(name) {
|
|
|
20247
21129
|
return result.isValid;
|
|
20248
21130
|
}
|
|
20249
21131
|
|
|
20250
|
-
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/mcp-server.js
|
|
21132
|
+
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0+2b91fc17bf64bdfd/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/mcp-server.js
|
|
20251
21133
|
class ExperimentalMcpServerTasks {
|
|
20252
21134
|
constructor(_mcpServer) {
|
|
20253
21135
|
this._mcpServer = _mcpServer;
|
|
@@ -20261,7 +21143,7 @@ class ExperimentalMcpServerTasks {
|
|
|
20261
21143
|
return mcpServerInternal._createRegisteredTool(name, config2.title, config2.description, config2.inputSchema, config2.outputSchema, config2.annotations, execution, config2._meta, handler);
|
|
20262
21144
|
}
|
|
20263
21145
|
}
|
|
20264
|
-
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js
|
|
21146
|
+
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0+2b91fc17bf64bdfd/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js
|
|
20265
21147
|
class McpServer {
|
|
20266
21148
|
constructor(serverInfo, options) {
|
|
20267
21149
|
this._registeredResources = {};
|
|
@@ -21004,12 +21886,270 @@ var EMPTY_COMPLETION_RESULT = {
|
|
|
21004
21886
|
};
|
|
21005
21887
|
|
|
21006
21888
|
// src/lib/registry.ts
|
|
21007
|
-
init_config();
|
|
21008
21889
|
import { existsSync as existsSync8, readFileSync as readFileSync6, readdirSync as readdirSync6 } from "fs";
|
|
21009
21890
|
import { join as join8 } from "path";
|
|
21010
21891
|
|
|
21892
|
+
// src/lib/config.ts
|
|
21893
|
+
import { existsSync as existsSync2, readFileSync, writeFileSync, mkdirSync, copyFileSync, readdirSync, statSync } from "fs";
|
|
21894
|
+
import { join as join2, dirname } from "path";
|
|
21895
|
+
|
|
21896
|
+
// src/lib/retired-settings.ts
|
|
21897
|
+
var RETIRED_ENV_SUFFIXES = ["_STORAGE_MODE", "_DEPLOYMENT_MODE", "_CLOUD_MODE"];
|
|
21898
|
+
var RETIRED_CONFIG_KEYS = {
|
|
21899
|
+
mode: "a configured API origin",
|
|
21900
|
+
apiUrl: "skills setup --api-url <origin>"
|
|
21901
|
+
};
|
|
21902
|
+
var RETIRED_CONFIG_KEY_REASONS = {
|
|
21903
|
+
mode: "Deployment modes were removed: a Skills client either resolves a credential " + "or it does not, and that is the whole of it.",
|
|
21904
|
+
apiUrl: "The service address is no longer kept in this app's config file: it is read from " + "HASNA_SKILLS_API_URL, then the macOS Keychain item hasna.credentials.skills.api-url, " + "then ~/.hasna/skills/config/credentials, then the fleet gateway."
|
|
21905
|
+
};
|
|
21906
|
+
|
|
21907
|
+
class RetiredSettingError extends Error {
|
|
21908
|
+
code = "RETIRED_SETTING";
|
|
21909
|
+
setting;
|
|
21910
|
+
constructor(setting, message) {
|
|
21911
|
+
super(message);
|
|
21912
|
+
this.name = "RetiredSettingError";
|
|
21913
|
+
this.setting = setting;
|
|
21914
|
+
}
|
|
21915
|
+
}
|
|
21916
|
+
function isRetiredModeEnvVar(name, app) {
|
|
21917
|
+
const upper = name.toUpperCase();
|
|
21918
|
+
if (!upper.includes(app.toUpperCase()))
|
|
21919
|
+
return false;
|
|
21920
|
+
return RETIRED_ENV_SUFFIXES.some((suffix) => upper.endsWith(suffix));
|
|
21921
|
+
}
|
|
21922
|
+
function findRetiredModeEnvVars(env, app) {
|
|
21923
|
+
const found = [];
|
|
21924
|
+
for (const [name, value] of Object.entries(env)) {
|
|
21925
|
+
if (value === undefined || value === "")
|
|
21926
|
+
continue;
|
|
21927
|
+
if (isRetiredModeEnvVar(name, app))
|
|
21928
|
+
found.push({ name, value });
|
|
21929
|
+
}
|
|
21930
|
+
return found.sort((a, b) => a.name.localeCompare(b.name));
|
|
21931
|
+
}
|
|
21932
|
+
function assertNoRetiredModeEnvVars(env, options) {
|
|
21933
|
+
const found = findRetiredModeEnvVars(env, options.app);
|
|
21934
|
+
if (found.length === 0)
|
|
21935
|
+
return;
|
|
21936
|
+
const names = found.map((entry) => entry.name);
|
|
21937
|
+
throw new RetiredSettingError(names[0], `${names.join(", ")} ${names.length === 1 ? "is" : "are"} no longer read. ` + "Deployment modes were removed: where a server keeps its data is decided by the " + `database it is given, not by a declared label. Set ${options.replacement} to a ` + "postgres:// URL to use PostgreSQL, or leave it unset for the on-box SQLite database. " + `Then unset ${names.join(" and ")}. ` + "Refused rather than ignored, because a discarded setting looks exactly like a " + "working one until something needs the data.");
|
|
21938
|
+
}
|
|
21939
|
+
function assertNoRetiredConfigKeys(config2, source) {
|
|
21940
|
+
for (const [key, replacement] of Object.entries(RETIRED_CONFIG_KEYS)) {
|
|
21941
|
+
if (!(key in config2))
|
|
21942
|
+
continue;
|
|
21943
|
+
throw new RetiredSettingError(key, `${source}: "${key}" is no longer a configuration key. ` + `${RETIRED_CONFIG_KEY_REASONS[key] ?? ""} ` + `Use ${replacement} instead, and remove the old key with: skills config unset ${key}. ` + "Refused rather than ignored, because silently dropping it would leave an " + "operator believing they had pointed this install at a server.");
|
|
21944
|
+
}
|
|
21945
|
+
}
|
|
21946
|
+
|
|
21947
|
+
// src/lib/app-home.ts
|
|
21948
|
+
import { existsSync } from "fs";
|
|
21949
|
+
import { homedir } from "os";
|
|
21950
|
+
import { join, resolve } from "path";
|
|
21951
|
+
import { homedir as pathsResolverHomedir } from "os";
|
|
21952
|
+
import { join as pathsResolverJoin } from "path";
|
|
21953
|
+
var PATHS_RESOLVER_KIND_ENV = {
|
|
21954
|
+
config: "HASNA_CONFIG_HOME",
|
|
21955
|
+
data: "HASNA_DATA_HOME",
|
|
21956
|
+
state: "HASNA_STATE_HOME",
|
|
21957
|
+
cache: "HASNA_CACHE_HOME"
|
|
21958
|
+
};
|
|
21959
|
+
var PATHS_RESOLVER_APP_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
21960
|
+
function pathsResolverAssertApp(app) {
|
|
21961
|
+
if (typeof app !== "string" || app.length === 0) {
|
|
21962
|
+
throw new TypeError("paths: app must be a non-empty string");
|
|
21963
|
+
}
|
|
21964
|
+
if (!PATHS_RESOLVER_APP_SLUG_RE.test(app)) {
|
|
21965
|
+
throw new TypeError(`paths: invalid app slug "${app}" \u2014 expected lowercase kebab-case ([a-z0-9]+(-[a-z0-9]+)*)`);
|
|
21966
|
+
}
|
|
21967
|
+
}
|
|
21968
|
+
function pathsResolverAssertKind(kind) {
|
|
21969
|
+
if (!Object.keys(PATHS_RESOLVER_KIND_ENV).includes(kind)) {
|
|
21970
|
+
throw new TypeError(`paths: invalid path kind "${kind}" \u2014 expected one of ${Object.keys(PATHS_RESOLVER_KIND_ENV).join(", ")}`);
|
|
21971
|
+
}
|
|
21972
|
+
}
|
|
21973
|
+
function pathsResolverBaseDir(kind, options) {
|
|
21974
|
+
pathsResolverAssertKind(kind);
|
|
21975
|
+
const env = options.env ?? process.env;
|
|
21976
|
+
const override = env[PATHS_RESOLVER_KIND_ENV[kind]];
|
|
21977
|
+
if (typeof override === "string" && override.length > 0)
|
|
21978
|
+
return override;
|
|
21979
|
+
const home = options.home ?? pathsResolverHomedir();
|
|
21980
|
+
const platform = options.platform ?? process.platform;
|
|
21981
|
+
if (platform === "darwin") {
|
|
21982
|
+
switch (kind) {
|
|
21983
|
+
case "config":
|
|
21984
|
+
case "data":
|
|
21985
|
+
return pathsResolverJoin(home, "Library", "Application Support", "Hasna");
|
|
21986
|
+
case "cache":
|
|
21987
|
+
return pathsResolverJoin(home, "Library", "Caches", "Hasna");
|
|
21988
|
+
case "state":
|
|
21989
|
+
return pathsResolverJoin(home, "Library", "Logs", "Hasna");
|
|
21990
|
+
}
|
|
21991
|
+
}
|
|
21992
|
+
switch (kind) {
|
|
21993
|
+
case "config":
|
|
21994
|
+
return pathsResolverJoin(home, ".config", "hasna");
|
|
21995
|
+
case "data":
|
|
21996
|
+
return pathsResolverJoin(home, ".local", "share", "hasna");
|
|
21997
|
+
case "state":
|
|
21998
|
+
return pathsResolverJoin(home, ".local", "state", "hasna");
|
|
21999
|
+
case "cache":
|
|
22000
|
+
return pathsResolverJoin(home, ".cache", "hasna");
|
|
22001
|
+
}
|
|
22002
|
+
}
|
|
22003
|
+
function pathsResolverResolve(kind, options) {
|
|
22004
|
+
pathsResolverAssertApp(options.app);
|
|
22005
|
+
const appSegment = options.internal === true ? pathsResolverJoin("internal", options.app) : options.app;
|
|
22006
|
+
return pathsResolverJoin(pathsResolverBaseDir(kind, options), appSegment);
|
|
22007
|
+
}
|
|
22008
|
+
function dataDir(options) {
|
|
22009
|
+
return pathsResolverResolve("data", options);
|
|
22010
|
+
}
|
|
22011
|
+
var DATA_DIR_ENV = "HASNA_SKILLS_DIR";
|
|
22012
|
+
var HASNA_SKILLS_HOME_ENV = "HASNA_SKILLS_HOME";
|
|
22013
|
+
var SKILLS_HOME_ENV = "SKILLS_HOME";
|
|
22014
|
+
var DEFAULT_SQLITE_FILENAME = "server.db";
|
|
22015
|
+
var GLOBAL_CONFIG_FILENAME = "config.json";
|
|
22016
|
+
function effectiveHome() {
|
|
22017
|
+
return process.env["HOME"] || process.env["USERPROFILE"] || homedir() || "/tmp";
|
|
22018
|
+
}
|
|
22019
|
+
function legacyDataRoot() {
|
|
22020
|
+
return join(effectiveHome(), ".hasna", "skills");
|
|
22021
|
+
}
|
|
22022
|
+
function resolverDataRoot(home = effectiveHome(), env) {
|
|
22023
|
+
return dataDir({ app: "skills", home, env });
|
|
22024
|
+
}
|
|
22025
|
+
function adoptResolverDataRoot(resolved, env = process.env) {
|
|
22026
|
+
const dataOverride = env.HASNA_DATA_HOME;
|
|
22027
|
+
if (typeof dataOverride === "string" && dataOverride.trim().length > 0)
|
|
22028
|
+
return true;
|
|
22029
|
+
return existsSync(join(resolved, DEFAULT_SQLITE_FILENAME)) || existsSync(join(resolved, GLOBAL_CONFIG_FILENAME));
|
|
22030
|
+
}
|
|
22031
|
+
function exactDataRoot() {
|
|
22032
|
+
for (const key of [DATA_DIR_ENV, HASNA_SKILLS_HOME_ENV, SKILLS_HOME_ENV]) {
|
|
22033
|
+
const dir = process.env[key]?.trim();
|
|
22034
|
+
if (dir)
|
|
22035
|
+
return resolve(dir);
|
|
22036
|
+
}
|
|
22037
|
+
return;
|
|
22038
|
+
}
|
|
22039
|
+
function hasExactOverride(env = process.env) {
|
|
22040
|
+
return Boolean(env[DATA_DIR_ENV]?.trim()) || Boolean(env[HASNA_SKILLS_HOME_ENV]?.trim()) || Boolean(env[SKILLS_HOME_ENV]?.trim());
|
|
22041
|
+
}
|
|
22042
|
+
function hasOperatorOverride(env = process.env) {
|
|
22043
|
+
return hasExactOverride(env) || Boolean(env.HASNA_DATA_HOME?.trim());
|
|
22044
|
+
}
|
|
22045
|
+
function getDataRoot() {
|
|
22046
|
+
const exact = exactDataRoot();
|
|
22047
|
+
if (exact)
|
|
22048
|
+
return exact;
|
|
22049
|
+
const resolved = resolverDataRoot();
|
|
22050
|
+
return adoptResolverDataRoot(resolved) ? resolve(resolved) : resolve(legacyDataRoot());
|
|
22051
|
+
}
|
|
22052
|
+
|
|
22053
|
+
// src/lib/config.ts
|
|
22054
|
+
var ENUM_KEYS = {
|
|
22055
|
+
defaultAgent: ["claude", "codex", "gemini", "pi", "opencode", "all"],
|
|
22056
|
+
defaultScope: ["global", "project"],
|
|
22057
|
+
format: ["compact", "json", "csv"]
|
|
22058
|
+
};
|
|
22059
|
+
var STRING_KEYS = ["extensionsDir"];
|
|
22060
|
+
function validKeys() {
|
|
22061
|
+
return [...Object.keys(ENUM_KEYS), ...STRING_KEYS];
|
|
22062
|
+
}
|
|
22063
|
+
function allowedValues(key) {
|
|
22064
|
+
return ENUM_KEYS[key];
|
|
22065
|
+
}
|
|
22066
|
+
function mergeDirectoryContents(sourceDir, targetDir) {
|
|
22067
|
+
if (!existsSync2(sourceDir))
|
|
22068
|
+
return;
|
|
22069
|
+
mkdirSync(targetDir, { recursive: true });
|
|
22070
|
+
for (const entry of readdirSync(sourceDir)) {
|
|
22071
|
+
const sourcePath = join2(sourceDir, entry);
|
|
22072
|
+
const targetPath = join2(targetDir, entry);
|
|
22073
|
+
try {
|
|
22074
|
+
const sourceStat = statSync(sourcePath);
|
|
22075
|
+
if (sourceStat.isDirectory()) {
|
|
22076
|
+
mergeDirectoryContents(sourcePath, targetPath);
|
|
22077
|
+
continue;
|
|
22078
|
+
}
|
|
22079
|
+
if (!existsSync2(targetPath))
|
|
22080
|
+
copyFileSync(sourcePath, targetPath);
|
|
22081
|
+
} catch {}
|
|
22082
|
+
}
|
|
22083
|
+
}
|
|
22084
|
+
function normalizeConfigValue(key, value) {
|
|
22085
|
+
if (typeof value !== "string")
|
|
22086
|
+
return;
|
|
22087
|
+
const allowed = allowedValues(key);
|
|
22088
|
+
if (allowed)
|
|
22089
|
+
return allowed.includes(value) ? value : undefined;
|
|
22090
|
+
if (key === "extensionsDir")
|
|
22091
|
+
return value.trim() ? value : undefined;
|
|
22092
|
+
return;
|
|
22093
|
+
}
|
|
22094
|
+
var INSTALLED_SKILLS_DIRNAME = "installed";
|
|
22095
|
+
var SKILLS_CACHE_DIRNAME = "skills";
|
|
22096
|
+
var LAYOUT_MIGRATION_RECORD = ".layout-migration.json";
|
|
22097
|
+
function isOwnerLayoutMigrated(appDir) {
|
|
22098
|
+
return existsSync2(join2(appDir, SKILLS_CACHE_DIRNAME, LAYOUT_MIGRATION_RECORD));
|
|
22099
|
+
}
|
|
22100
|
+
function getDataDir() {
|
|
22101
|
+
const root = getDataRoot();
|
|
22102
|
+
try {
|
|
22103
|
+
mkdirSync(root, { recursive: true });
|
|
22104
|
+
} catch {}
|
|
22105
|
+
if (hasOperatorOverride())
|
|
22106
|
+
return root;
|
|
22107
|
+
const home = effectiveHome();
|
|
22108
|
+
const oldDir = join2(home, ".skills");
|
|
22109
|
+
const oldConfigFile = join2(home, ".skillsrc");
|
|
22110
|
+
try {
|
|
22111
|
+
mergeDirectoryContents(oldDir, root);
|
|
22112
|
+
} catch {}
|
|
22113
|
+
if (existsSync2(oldConfigFile) && !existsSync2(join2(root, "config.json"))) {
|
|
22114
|
+
try {
|
|
22115
|
+
copyFileSync(oldConfigFile, join2(root, "config.json"));
|
|
22116
|
+
} catch {}
|
|
22117
|
+
}
|
|
22118
|
+
return root;
|
|
22119
|
+
}
|
|
22120
|
+
function getConfigPath(scope) {
|
|
22121
|
+
if (scope === "global") {
|
|
22122
|
+
return join2(getDataDir(), "config.json");
|
|
22123
|
+
}
|
|
22124
|
+
return join2(process.cwd(), "skills.config.json");
|
|
22125
|
+
}
|
|
22126
|
+
function readConfigFile(path) {
|
|
22127
|
+
if (!existsSync2(path))
|
|
22128
|
+
return {};
|
|
22129
|
+
let parsed;
|
|
22130
|
+
try {
|
|
22131
|
+
parsed = JSON.parse(readFileSync(path, "utf-8"));
|
|
22132
|
+
} catch {
|
|
22133
|
+
return {};
|
|
22134
|
+
}
|
|
22135
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
|
|
22136
|
+
return {};
|
|
22137
|
+
assertNoRetiredConfigKeys(parsed, path);
|
|
22138
|
+
const config2 = {};
|
|
22139
|
+
for (const key of validKeys()) {
|
|
22140
|
+
const value = normalizeConfigValue(key, parsed[key]);
|
|
22141
|
+
if (value !== undefined)
|
|
22142
|
+
config2[key] = value;
|
|
22143
|
+
}
|
|
22144
|
+
return config2;
|
|
22145
|
+
}
|
|
22146
|
+
function loadConfig() {
|
|
22147
|
+
const globalConfig2 = readConfigFile(getConfigPath("global"));
|
|
22148
|
+
const projectConfig = readConfigFile(getConfigPath("project"));
|
|
22149
|
+
return { ...globalConfig2, ...projectConfig };
|
|
22150
|
+
}
|
|
22151
|
+
|
|
21011
22152
|
// src/lib/portable-skills.ts
|
|
21012
|
-
init_config();
|
|
21013
22153
|
import {
|
|
21014
22154
|
cpSync as cpSync2,
|
|
21015
22155
|
existsSync as existsSync7,
|
|
@@ -22445,7 +23585,7 @@ function readPortableSkillManifest(skillPath, fallbackName = basename(skillPath)
|
|
|
22445
23585
|
const pkg = existsSync6(pkgPath) ? readJsonObject(pkgPath) : undefined;
|
|
22446
23586
|
const name = normalizePortableSkillName(stringField(jsonManifest, "name") ?? frontmatter?.name ?? stringValue(pkg?.name) ?? fallbackName);
|
|
22447
23587
|
const description = stringField(jsonManifest, "description") ?? frontmatter?.description ?? stringValue(pkg?.description) ?? `${name} skill`;
|
|
22448
|
-
const version2 =
|
|
23588
|
+
const version2 = readDeclaredSkillVersion(skillPath) ?? PORTABLE_SKILL_DEFAULT_VERSION;
|
|
22449
23589
|
const kind = parseSkillKind(stringField(jsonManifest, "kind") ?? frontmatter?.kind);
|
|
22450
23590
|
const commands = parseManifestCommands(jsonManifest) ?? (kind === "instruction" ? [] : inferPackageCommands(pkg, name)) ?? [];
|
|
22451
23591
|
return {
|
|
@@ -22469,6 +23609,15 @@ function parseSkillKind(value) {
|
|
|
22469
23609
|
return value;
|
|
22470
23610
|
return;
|
|
22471
23611
|
}
|
|
23612
|
+
function readDeclaredSkillVersion(skillPath) {
|
|
23613
|
+
const skillJsonPath = join6(skillPath, "skill.json");
|
|
23614
|
+
const skillMdPath = join6(skillPath, "SKILL.md");
|
|
23615
|
+
const pkgPath = join6(skillPath, "package.json");
|
|
23616
|
+
const jsonManifest = existsSync6(skillJsonPath) ? readJsonObject(skillJsonPath) : undefined;
|
|
23617
|
+
const frontmatter = existsSync6(skillMdPath) ? parseSkillFrontmatter(readFileSync5(skillMdPath, "utf-8")) ?? undefined : undefined;
|
|
23618
|
+
const pkg = existsSync6(pkgPath) ? readJsonObject(pkgPath) : undefined;
|
|
23619
|
+
return stringField(jsonManifest, "version") ?? frontmatter?.version ?? stringValue(pkg?.version);
|
|
23620
|
+
}
|
|
22472
23621
|
function createInstructionManifest(name, options) {
|
|
22473
23622
|
return {
|
|
22474
23623
|
$schema: PORTABLE_SKILL_SCHEMA,
|
|
@@ -23591,21 +24740,13 @@ function mergeCustomSkills(skills) {
|
|
|
23591
24740
|
// src/lib/installer.ts
|
|
23592
24741
|
import { existsSync as existsSync10, readFileSync as readFileSync8, rmSync as rmSync2 } from "fs";
|
|
23593
24742
|
import { dirname as dirname4, join as join10 } from "path";
|
|
23594
|
-
import { homedir as
|
|
24743
|
+
import { homedir as homedir2 } from "os";
|
|
23595
24744
|
import { fileURLToPath } from "url";
|
|
23596
|
-
|
|
23597
|
-
// src/lib/home-migration.ts
|
|
23598
|
-
init_config();
|
|
23599
|
-
init_config();
|
|
23600
|
-
|
|
23601
24745
|
// src/lib/utils.ts
|
|
23602
24746
|
function normalizeSkillName(name) {
|
|
23603
24747
|
return name;
|
|
23604
24748
|
}
|
|
23605
24749
|
|
|
23606
|
-
// src/lib/installer.ts
|
|
23607
|
-
init_config();
|
|
23608
|
-
|
|
23609
24750
|
// src/lib/project-state.ts
|
|
23610
24751
|
import { existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
|
|
23611
24752
|
import { join as join9 } from "path";
|
|
@@ -23815,11 +24956,11 @@ function getAgentSkillsDir(agent, scope = "global", projectDir) {
|
|
|
23815
24956
|
const base = projectDir || process.cwd();
|
|
23816
24957
|
switch (agent) {
|
|
23817
24958
|
case "pi":
|
|
23818
|
-
return scope === "project" ? join10(base, ".pi", "skills") : join10(
|
|
24959
|
+
return scope === "project" ? join10(base, ".pi", "skills") : join10(homedir2(), ".pi", "agent", "skills");
|
|
23819
24960
|
case "opencode":
|
|
23820
|
-
return scope === "project" ? join10(base, ".opencode", "skills") : join10(
|
|
24961
|
+
return scope === "project" ? join10(base, ".opencode", "skills") : join10(homedir2(), ".config", "opencode", "skills");
|
|
23821
24962
|
default:
|
|
23822
|
-
return scope === "project" ? join10(base, `.${agent}`, "skills") : join10(
|
|
24963
|
+
return scope === "project" ? join10(base, `.${agent}`, "skills") : join10(homedir2(), `.${agent}`, "skills");
|
|
23823
24964
|
}
|
|
23824
24965
|
}
|
|
23825
24966
|
function warnMissingDependencies(name, targetDir) {
|
|
@@ -23914,7 +25055,8 @@ function getSkillRequirements(name) {
|
|
|
23914
25055
|
}
|
|
23915
25056
|
}
|
|
23916
25057
|
envVars.delete("SKILL_API_KEY");
|
|
23917
|
-
envVars.
|
|
25058
|
+
envVars.delete("SKILLS_API_KEY");
|
|
25059
|
+
envVars.add("HASNA_SKILLS_API_KEY");
|
|
23918
25060
|
}
|
|
23919
25061
|
const systemDeps = new Set;
|
|
23920
25062
|
const depPatterns = [
|
|
@@ -25049,7 +26191,7 @@ var TOOL_PRIMITIVES = [
|
|
|
25049
26191
|
cliCommands: ["skills tools deps <skill>", "skills run <skill>"],
|
|
25050
26192
|
mcpTools: ["get_skill_tool_dependencies", "run_skill"],
|
|
25051
26193
|
apiSurfaces: ["runSkill", "SkillRunRecord", "RemoteSkillRunContract"],
|
|
25052
|
-
envVars: ["
|
|
26194
|
+
envVars: ["HASNA_SKILLS_API_KEY"],
|
|
25053
26195
|
outputTypes: ["text", "json", "markdown", "artifact"],
|
|
25054
26196
|
capabilities: ["completion", "reasoning", "tool-calling", "vision-input", "structured-output"]
|
|
25055
26197
|
},
|
|
@@ -25105,7 +26247,7 @@ var TOOL_PRIMITIVES = [
|
|
|
25105
26247
|
cliCommands: ["skills tools deps <skill>", "skills run <skill>"],
|
|
25106
26248
|
mcpTools: ["get_skill_tool_dependencies", "run_skill"],
|
|
25107
26249
|
apiSurfaces: ["runSkill", "RemoteSkillRunContract"],
|
|
25108
|
-
envVars: ["
|
|
26250
|
+
envVars: ["HASNA_SKILLS_API_KEY"],
|
|
25109
26251
|
outputTypes: ["png", "jpeg", "webp", "svg", "zip"],
|
|
25110
26252
|
capabilities: ["image-generation", "image-analysis", "image-editing", "asset-packaging"]
|
|
25111
26253
|
},
|
|
@@ -25119,7 +26261,7 @@ var TOOL_PRIMITIVES = [
|
|
|
25119
26261
|
cliCommands: ["skills tools deps <skill>", "skills run <skill>"],
|
|
25120
26262
|
mcpTools: ["get_skill_tool_dependencies", "run_skill"],
|
|
25121
26263
|
apiSurfaces: ["runSkill", "RemoteSkillRunContract"],
|
|
25122
|
-
envVars: ["
|
|
26264
|
+
envVars: ["HASNA_SKILLS_API_KEY"],
|
|
25123
26265
|
outputTypes: ["mp3", "wav", "txt", "srt", "json", "zip"],
|
|
25124
26266
|
capabilities: ["transcription", "audio-generation", "voiceover", "audio-cleanup"]
|
|
25125
26267
|
},
|
|
@@ -25133,7 +26275,7 @@ var TOOL_PRIMITIVES = [
|
|
|
25133
26275
|
cliCommands: ["skills tools deps <skill>", "skills run <skill>"],
|
|
25134
26276
|
mcpTools: ["get_skill_tool_dependencies", "run_skill"],
|
|
25135
26277
|
apiSurfaces: ["runSkill", "RemoteSkillRunContract"],
|
|
25136
|
-
envVars: ["
|
|
26278
|
+
envVars: ["HASNA_SKILLS_API_KEY"],
|
|
25137
26279
|
outputTypes: ["mp4", "mov", "srt", "png", "json", "zip"],
|
|
25138
26280
|
capabilities: ["video-generation", "video-analysis", "captioning", "highlight-extraction"]
|
|
25139
26281
|
},
|
|
@@ -25161,7 +26303,7 @@ var TOOL_PRIMITIVES = [
|
|
|
25161
26303
|
cliCommands: ["skills tools deps <skill>", "skills run <skill>"],
|
|
25162
26304
|
mcpTools: ["get_skill_tool_dependencies", "run_skill"],
|
|
25163
26305
|
apiSurfaces: ["SkillRunContext", "RemoteSkillRunContract"],
|
|
25164
|
-
envVars: ["
|
|
26306
|
+
envVars: ["HASNA_SKILLS_API_KEY"],
|
|
25165
26307
|
outputTypes: ["json", "artifact"],
|
|
25166
26308
|
capabilities: ["approval", "external-api", "account-scoped-execution"]
|
|
25167
26309
|
},
|
|
@@ -25203,7 +26345,7 @@ var TOOL_PRIMITIVES = [
|
|
|
25203
26345
|
cliCommands: ["skills auth login", "skills run <skill>"],
|
|
25204
26346
|
mcpTools: ["run_skill"],
|
|
25205
26347
|
apiSurfaces: ["RemoteSkillsClient", "RemoteSkillRunContract"],
|
|
25206
|
-
envVars: ["
|
|
26348
|
+
envVars: ["HASNA_SKILLS_API_KEY"],
|
|
25207
26349
|
outputTypes: ["json"],
|
|
25208
26350
|
capabilities: ["account-auth", "remote-run-submit"]
|
|
25209
26351
|
}
|
|
@@ -25699,7 +26841,7 @@ function registerDiscoveryTools(server) {
|
|
|
25699
26841
|
}
|
|
25700
26842
|
|
|
25701
26843
|
// src/mcp/operation-tools.ts
|
|
25702
|
-
import { existsSync as
|
|
26844
|
+
import { existsSync as existsSync13, readdirSync as readdirSync8, statSync as statSync8 } from "fs";
|
|
25703
26845
|
import { join as join14 } from "path";
|
|
25704
26846
|
|
|
25705
26847
|
// src/lib/run-state.ts
|
|
@@ -25882,8 +27024,7 @@ function mimeForPath(path) {
|
|
|
25882
27024
|
}
|
|
25883
27025
|
}
|
|
25884
27026
|
// src/lib/run-routing.ts
|
|
25885
|
-
|
|
25886
|
-
init_auth_store();
|
|
27027
|
+
init_fleet_credentials();
|
|
25887
27028
|
function isServerOwnedSkill(skill) {
|
|
25888
27029
|
return skill.serverOwned === true;
|
|
25889
27030
|
}
|
|
@@ -25894,7 +27035,7 @@ function resolveRunRouting(skill, apiKey, apiUrl) {
|
|
|
25894
27035
|
return {
|
|
25895
27036
|
route: "error",
|
|
25896
27037
|
code: "REMOTE_REQUIRES_ORIGIN",
|
|
25897
|
-
error: `${skill.name} is a server-owned skill. Point the CLI at a Skills API: ` + `skills setup --api-url <url> (or export
|
|
27038
|
+
error: `${skill.name} is a server-owned skill. Point the CLI at a Skills API: ` + `skills setup --api-url <url> (or export HASNA_SKILLS_API_URL)`
|
|
25898
27039
|
};
|
|
25899
27040
|
}
|
|
25900
27041
|
if (!apiKey) {
|
|
@@ -25906,8 +27047,23 @@ function resolveRunRouting(skill, apiKey, apiUrl) {
|
|
|
25906
27047
|
}
|
|
25907
27048
|
return { route: "remote", apiKey };
|
|
25908
27049
|
}
|
|
25909
|
-
function resolveConfiguredRunRouting(skill) {
|
|
25910
|
-
|
|
27050
|
+
async function resolveConfiguredRunRouting(skill, env = process.env) {
|
|
27051
|
+
let fleet;
|
|
27052
|
+
let apiKey;
|
|
27053
|
+
try {
|
|
27054
|
+
fleet = resolveSkillsFleet(env);
|
|
27055
|
+
apiKey = fleet.mode === "hosted" ? await resolveSkillsApiKey(env) : null;
|
|
27056
|
+
} catch (error2) {
|
|
27057
|
+
const isMissingCredential = (error2 instanceof SkillsFleetCredentialError || error2?.name === "SkillsFleetCredentialError") && error2.code === "MISSING_API_CREDENTIAL";
|
|
27058
|
+
if (!isMissingCredential)
|
|
27059
|
+
throw error2;
|
|
27060
|
+
return {
|
|
27061
|
+
route: "error",
|
|
27062
|
+
code: "REMOTE_REQUIRES_CREDENTIAL",
|
|
27063
|
+
error: `${skill.name} is a server-owned skill. ${error2.message}`
|
|
27064
|
+
};
|
|
27065
|
+
}
|
|
27066
|
+
return resolveRunRouting(skill, apiKey, fleet.apiOrigin ?? undefined);
|
|
25911
27067
|
}
|
|
25912
27068
|
|
|
25913
27069
|
// src/mcp/operation-tools.ts
|
|
@@ -26131,7 +27287,7 @@ function registerOperationTools(server) {
|
|
|
26131
27287
|
return mcpError("INVALID_BLOG_ARTICLE_OPTIONS", validation.errors.join(" "));
|
|
26132
27288
|
}
|
|
26133
27289
|
}
|
|
26134
|
-
const routing = resolveConfiguredRunRouting(skill);
|
|
27290
|
+
const routing = await resolveConfiguredRunRouting(skill);
|
|
26135
27291
|
const runContext = createSkillRun({
|
|
26136
27292
|
skill: skillName,
|
|
26137
27293
|
args: runArgs,
|
|
@@ -26210,10 +27366,10 @@ function registerOperationTools(server) {
|
|
|
26210
27366
|
detail: exports_external.boolean().optional()
|
|
26211
27367
|
}
|
|
26212
27368
|
}, async ({ run_id, detail }) => {
|
|
26213
|
-
const {
|
|
26214
|
-
const apiKey =
|
|
27369
|
+
const { skillsCredentialOrReason: skillsCredentialOrReason2 } = await Promise.resolve().then(() => (init_fleet_credentials(), exports_fleet_credentials));
|
|
27370
|
+
const { apiKey, reason } = await skillsCredentialOrReason2();
|
|
26215
27371
|
if (!apiKey) {
|
|
26216
|
-
return mcpError("AUTH_REQUIRED", "Remote run status requires API access. Run: skills auth login", ["skills auth login"]);
|
|
27372
|
+
return mcpError("AUTH_REQUIRED", reason ?? "Remote run status requires API access. Run: skills auth login", ["skills auth login"]);
|
|
26217
27373
|
}
|
|
26218
27374
|
const localRun = findSkillRun(run_id);
|
|
26219
27375
|
const remoteRunId = localRun?.remoteRunId || run_id;
|
|
@@ -26307,7 +27463,7 @@ function registerOperationTools(server) {
|
|
|
26307
27463
|
const agents = [];
|
|
26308
27464
|
for (const agent of AGENT_TARGETS) {
|
|
26309
27465
|
const agentSkillsPath = getAgentSkillsDir(agent, "global");
|
|
26310
|
-
const exists =
|
|
27466
|
+
const exists = existsSync13(agentSkillsPath);
|
|
26311
27467
|
let skillCount = 0;
|
|
26312
27468
|
if (exists) {
|
|
26313
27469
|
try {
|
|
@@ -26358,19 +27514,29 @@ function compactRunToolPayload(payload, detailHint) {
|
|
|
26358
27514
|
}
|
|
26359
27515
|
|
|
26360
27516
|
// src/lib/feedback.ts
|
|
26361
|
-
|
|
26362
|
-
|
|
26363
|
-
import { appendFileSync, existsSync as existsSync15, mkdirSync as mkdirSync7 } from "fs";
|
|
26364
|
-
import { dirname as dirname6, join as join15 } from "path";
|
|
27517
|
+
import { appendFileSync, existsSync as existsSync14, mkdirSync as mkdirSync6 } from "fs";
|
|
27518
|
+
import { dirname as dirname5, join as join15 } from "path";
|
|
26365
27519
|
import { Database } from "bun:sqlite";
|
|
27520
|
+
|
|
27521
|
+
// src/lib/api-url.ts
|
|
27522
|
+
init_fleet_credentials();
|
|
27523
|
+
init_fleet_credentials();
|
|
27524
|
+
var API_URL_ENV_VAR = SKILLS_API_URL_ENV;
|
|
27525
|
+
var MISSING_API_URL_HINT = `run: skills auth login, or set ${API_URL_ENV_VAR}=<your Skills instance origin>, ` + `or run: skills setup --api-url <your Skills instance origin>`;
|
|
27526
|
+
function resolveApiUrl(env = process.env, options = {}) {
|
|
27527
|
+
const fleet = resolveSkillsFleet(env, options);
|
|
27528
|
+
return fleet.mode === "hosted" ? fleet.apiOrigin : undefined;
|
|
27529
|
+
}
|
|
27530
|
+
|
|
27531
|
+
// src/lib/feedback.ts
|
|
26366
27532
|
function getFeedbackDbPath() {
|
|
26367
27533
|
return join15(getDataDir(), "skills.db");
|
|
26368
27534
|
}
|
|
26369
27535
|
function getFeedbackDb() {
|
|
26370
27536
|
const dbPath = getFeedbackDbPath();
|
|
26371
|
-
const dir =
|
|
26372
|
-
if (!
|
|
26373
|
-
|
|
27537
|
+
const dir = dirname5(dbPath);
|
|
27538
|
+
if (!existsSync14(dir))
|
|
27539
|
+
mkdirSync6(dir, { recursive: true });
|
|
26374
27540
|
const db = new Database(dbPath);
|
|
26375
27541
|
db.exec("PRAGMA journal_mode = WAL");
|
|
26376
27542
|
db.exec([
|
|
@@ -26397,9 +27563,9 @@ function saveFeedback(input) {
|
|
|
26397
27563
|
const category = input.category ?? "general";
|
|
26398
27564
|
if (isApiMode()) {
|
|
26399
27565
|
const path = join15(getDataDir(), "feedback.jsonl");
|
|
26400
|
-
const dir =
|
|
26401
|
-
if (!
|
|
26402
|
-
|
|
27566
|
+
const dir = dirname5(path);
|
|
27567
|
+
if (!existsSync14(dir))
|
|
27568
|
+
mkdirSync6(dir, { recursive: true });
|
|
26403
27569
|
appendFileSync(path, JSON.stringify({ message, category, email: input.email ?? null, agent: input.agent ?? null, version: input.version ?? null, createdAt: new Date().toISOString() }) + `
|
|
26404
27570
|
`);
|
|
26405
27571
|
return { saved: true, category, path };
|
|
@@ -26413,12 +27579,10 @@ function saveFeedback(input) {
|
|
|
26413
27579
|
return { saved: true, category, path: getFeedbackDbPath() };
|
|
26414
27580
|
}
|
|
26415
27581
|
function isApiMode(env = process.env) {
|
|
26416
|
-
if (env.HASNA_SKILLS_API_URL?.trim())
|
|
26417
|
-
return true;
|
|
26418
27582
|
try {
|
|
26419
|
-
return Boolean(resolveApiUrl(
|
|
27583
|
+
return Boolean(resolveApiUrl(env));
|
|
26420
27584
|
} catch {
|
|
26421
|
-
return
|
|
27585
|
+
return true;
|
|
26422
27586
|
}
|
|
26423
27587
|
}
|
|
26424
27588
|
|
|
@@ -26546,14 +27710,14 @@ function registerResourceMetaTools(server) {
|
|
|
26546
27710
|
}
|
|
26547
27711
|
|
|
26548
27712
|
// src/lib/scheduler.ts
|
|
26549
|
-
import { existsSync as
|
|
27713
|
+
import { existsSync as existsSync15, readFileSync as readFileSync12, writeFileSync as writeFileSync6, mkdirSync as mkdirSync7 } from "fs";
|
|
26550
27714
|
import { join as join16 } from "path";
|
|
26551
27715
|
function getSchedulesPath(targetDir = process.cwd()) {
|
|
26552
27716
|
return join16(targetDir, ".skills", "schedules.json");
|
|
26553
27717
|
}
|
|
26554
27718
|
function loadSchedules(targetDir = process.cwd()) {
|
|
26555
27719
|
const path = getSchedulesPath(targetDir);
|
|
26556
|
-
if (
|
|
27720
|
+
if (existsSync15(path)) {
|
|
26557
27721
|
try {
|
|
26558
27722
|
return JSON.parse(readFileSync12(path, "utf-8"));
|
|
26559
27723
|
} catch {}
|
|
@@ -26563,9 +27727,9 @@ function loadSchedules(targetDir = process.cwd()) {
|
|
|
26563
27727
|
function saveSchedules(data, targetDir = process.cwd()) {
|
|
26564
27728
|
const path = getSchedulesPath(targetDir);
|
|
26565
27729
|
const dir = join16(targetDir, ".skills");
|
|
26566
|
-
if (!
|
|
26567
|
-
|
|
26568
|
-
|
|
27730
|
+
if (!existsSync15(dir))
|
|
27731
|
+
mkdirSync7(dir, { recursive: true });
|
|
27732
|
+
writeFileSync6(path, JSON.stringify(data, null, 2));
|
|
26569
27733
|
}
|
|
26570
27734
|
function validateCronField(expr, min, max, label) {
|
|
26571
27735
|
for (const part of expr.split(",")) {
|
|
@@ -26823,18 +27987,16 @@ function registerScheduleTools(server) {
|
|
|
26823
27987
|
}
|
|
26824
27988
|
|
|
26825
27989
|
// src/lib/native-storage.ts
|
|
26826
|
-
init_config();
|
|
26827
27990
|
import { createHash as createHash3, createHmac } from "crypto";
|
|
26828
27991
|
import {
|
|
26829
|
-
existsSync as
|
|
26830
|
-
mkdirSync as
|
|
27992
|
+
existsSync as existsSync16,
|
|
27993
|
+
mkdirSync as mkdirSync8,
|
|
26831
27994
|
readFileSync as readFileSync13,
|
|
26832
27995
|
readdirSync as readdirSync9,
|
|
26833
27996
|
statSync as statSync9,
|
|
26834
|
-
writeFileSync as
|
|
27997
|
+
writeFileSync as writeFileSync7
|
|
26835
27998
|
} from "fs";
|
|
26836
|
-
import { dirname as
|
|
26837
|
-
init_retired_settings();
|
|
27999
|
+
import { dirname as dirname6, join as join17, normalize as normalize3, relative as relative3, sep as sep2 } from "path";
|
|
26838
28000
|
var SKILLS_STORAGE_TABLES = [
|
|
26839
28001
|
"skills_sync_records",
|
|
26840
28002
|
"skills_sync_cursors"
|
|
@@ -26930,7 +28092,7 @@ function getStorageStatus(options = {}) {
|
|
|
26930
28092
|
function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
|
|
26931
28093
|
const projectStateDir = getProjectStateDir(targetDir);
|
|
26932
28094
|
const files = [];
|
|
26933
|
-
if (
|
|
28095
|
+
if (existsSync16(projectStateDir)) {
|
|
26934
28096
|
for (const filePath of walkFiles2(projectStateDir)) {
|
|
26935
28097
|
const bytes = readFileSync13(filePath);
|
|
26936
28098
|
const relativePath = toPosix(relative3(targetDir, filePath));
|
|
@@ -27685,7 +28847,7 @@ var getRequestListener = (fetchCallback, options = {}) => {
|
|
|
27685
28847
|
};
|
|
27686
28848
|
};
|
|
27687
28849
|
|
|
27688
|
-
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/mediaType.js
|
|
28850
|
+
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0+2b91fc17bf64bdfd/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/mediaType.js
|
|
27689
28851
|
var import_content_type = __toESM(require_content_type(), 1);
|
|
27690
28852
|
function mediaTypeEssence(header) {
|
|
27691
28853
|
if (!header) {
|
|
@@ -27708,7 +28870,7 @@ function isJsonContentType(header) {
|
|
|
27708
28870
|
return mediaTypeEssence(header) === "application/json";
|
|
27709
28871
|
}
|
|
27710
28872
|
|
|
27711
|
-
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0/node_modules/@modelcontextprotocol/sdk/dist/esm/server/sseKeepAlive.js
|
|
28873
|
+
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0+2b91fc17bf64bdfd/node_modules/@modelcontextprotocol/sdk/dist/esm/server/sseKeepAlive.js
|
|
27712
28874
|
var DEFAULT_SSE_KEEP_ALIVE_MS = 15000;
|
|
27713
28875
|
var MAX_TIMER_DELAY_MS = 2 ** 31 - 1;
|
|
27714
28876
|
function armSseKeepAlive(intervalMs, onTick) {
|
|
@@ -27720,7 +28882,7 @@ function armSseKeepAlive(intervalMs, onTick) {
|
|
|
27720
28882
|
return timer;
|
|
27721
28883
|
}
|
|
27722
28884
|
|
|
27723
|
-
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0/node_modules/@modelcontextprotocol/sdk/dist/esm/server/webStandardStreamableHttp.js
|
|
28885
|
+
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0+2b91fc17bf64bdfd/node_modules/@modelcontextprotocol/sdk/dist/esm/server/webStandardStreamableHttp.js
|
|
27724
28886
|
class WebStandardStreamableHTTPServerTransport {
|
|
27725
28887
|
constructor(options = {}) {
|
|
27726
28888
|
this._started = false;
|
|
@@ -28377,7 +29539,7 @@ data:
|
|
|
28377
29539
|
}
|
|
28378
29540
|
}
|
|
28379
29541
|
|
|
28380
|
-
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0/node_modules/@modelcontextprotocol/sdk/dist/esm/server/streamableHttp.js
|
|
29542
|
+
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0+2b91fc17bf64bdfd/node_modules/@modelcontextprotocol/sdk/dist/esm/server/streamableHttp.js
|
|
28381
29543
|
class StreamableHTTPServerTransport {
|
|
28382
29544
|
constructor(options = {}) {
|
|
28383
29545
|
this._requestContext = new WeakMap;
|