@hasna/skills 0.10.51 → 0.10.52
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 +78 -0
- package/bin/index.js +1795 -1346
- package/bin/mcp.js +702 -457
- package/bin/migrate.js +1 -1
- package/bin/server.js +11 -4
- package/bin/worker.js +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1023 -679
- package/dist/lib/agent-discovery.d.ts +37 -1
- package/dist/lib/agent-integration.d.ts +4 -1
- package/dist/lib/claude-marketplace-entry-witness.d.ts +26 -0
- package/dist/lib/claude-settings-witness.d.ts +25 -1
- package/dist/lib/codex-hook-trust-files.d.ts +17 -0
- package/dist/lib/selection-cache.d.ts +2 -2
- package/dist/lib/session-reconciliation.d.ts +9 -0
- package/dist/sdk/index.js +990 -649
- package/docs/plugin-admission.md +185 -0
- package/package.json +1 -1
package/dist/sdk/index.js
CHANGED
|
@@ -5267,8 +5267,8 @@ var require_cst_visit = __commonJS((exports) => {
|
|
|
5267
5267
|
visit.REMOVE = REMOVE;
|
|
5268
5268
|
visit.itemAtPath = (cst, path) => {
|
|
5269
5269
|
let item = cst;
|
|
5270
|
-
for (const [
|
|
5271
|
-
const tok = item?.[
|
|
5270
|
+
for (const [field2, index] of path) {
|
|
5271
|
+
const tok = item?.[field2];
|
|
5272
5272
|
if (tok && "items" in tok) {
|
|
5273
5273
|
item = tok.items[index];
|
|
5274
5274
|
} else
|
|
@@ -5278,8 +5278,8 @@ var require_cst_visit = __commonJS((exports) => {
|
|
|
5278
5278
|
};
|
|
5279
5279
|
visit.parentCollection = (cst, path) => {
|
|
5280
5280
|
const parent = visit.itemAtPath(cst, path.slice(0, -1));
|
|
5281
|
-
const
|
|
5282
|
-
const coll = parent?.[
|
|
5281
|
+
const field2 = path[path.length - 1][0];
|
|
5282
|
+
const coll = parent?.[field2];
|
|
5283
5283
|
if (coll && "items" in coll)
|
|
5284
5284
|
return coll;
|
|
5285
5285
|
throw new Error("Parent collection not found");
|
|
@@ -5288,11 +5288,11 @@ var require_cst_visit = __commonJS((exports) => {
|
|
|
5288
5288
|
let ctrl = visitor(item, path);
|
|
5289
5289
|
if (typeof ctrl === "symbol")
|
|
5290
5290
|
return ctrl;
|
|
5291
|
-
for (const
|
|
5292
|
-
const token = item[
|
|
5291
|
+
for (const field2 of ["key", "value"]) {
|
|
5292
|
+
const token = item[field2];
|
|
5293
5293
|
if (token && "items" in token) {
|
|
5294
5294
|
for (let i = 0;i < token.items.length; ++i) {
|
|
5295
|
-
const ci = _visit(Object.freeze(path.concat([[
|
|
5295
|
+
const ci = _visit(Object.freeze(path.concat([[field2, i]])), token.items[i], visitor);
|
|
5296
5296
|
if (typeof ci === "number")
|
|
5297
5297
|
i = ci - 1;
|
|
5298
5298
|
else if (ci === BREAK)
|
|
@@ -5302,7 +5302,7 @@ var require_cst_visit = __commonJS((exports) => {
|
|
|
5302
5302
|
i -= 1;
|
|
5303
5303
|
}
|
|
5304
5304
|
}
|
|
5305
|
-
if (typeof ctrl === "function" &&
|
|
5305
|
+
if (typeof ctrl === "function" && field2 === "key")
|
|
5306
5306
|
ctrl = ctrl(item, path);
|
|
5307
5307
|
}
|
|
5308
5308
|
}
|
|
@@ -5728,9 +5728,9 @@ var require_lexer = __commonJS((exports) => {
|
|
|
5728
5728
|
}
|
|
5729
5729
|
}
|
|
5730
5730
|
*parseQuotedScalar() {
|
|
5731
|
-
const
|
|
5732
|
-
let end = this.buffer.indexOf(
|
|
5733
|
-
if (
|
|
5731
|
+
const quote2 = this.charAt(0);
|
|
5732
|
+
let end = this.buffer.indexOf(quote2, this.pos + 1);
|
|
5733
|
+
if (quote2 === "'") {
|
|
5734
5734
|
while (end !== -1 && this.buffer[end + 1] === "'")
|
|
5735
5735
|
end = this.buffer.indexOf("'", end + 2);
|
|
5736
5736
|
} else {
|
|
@@ -8209,7 +8209,7 @@ var require_client = __commonJS((exports) => {
|
|
|
8209
8209
|
};
|
|
8210
8210
|
};
|
|
8211
8211
|
var sleep = (seconds) => {
|
|
8212
|
-
return new Promise((
|
|
8212
|
+
return new Promise((resolve24) => setTimeout(resolve24, seconds * 1000));
|
|
8213
8213
|
};
|
|
8214
8214
|
var waiterServiceDefaults = {
|
|
8215
8215
|
minDelay: 2,
|
|
@@ -8264,14 +8264,14 @@ var require_client = __commonJS((exports) => {
|
|
|
8264
8264
|
}
|
|
8265
8265
|
await sleep(delayMs / 1000);
|
|
8266
8266
|
}
|
|
8267
|
-
const { state, reason } = await acceptorChecks(client2, input);
|
|
8268
|
-
if (
|
|
8269
|
-
const message = createMessageFromResponse(
|
|
8267
|
+
const { state, reason: reason2 } = await acceptorChecks(client2, input);
|
|
8268
|
+
if (reason2) {
|
|
8269
|
+
const message = createMessageFromResponse(reason2);
|
|
8270
8270
|
observedResponses[message] |= 0;
|
|
8271
8271
|
observedResponses[message] += 1;
|
|
8272
8272
|
}
|
|
8273
8273
|
if (state !== WaiterState.RETRY) {
|
|
8274
|
-
return { state, reason, final:
|
|
8274
|
+
return { state, reason: reason2, final: reason2, observedResponses };
|
|
8275
8275
|
}
|
|
8276
8276
|
currentAttempt += 1;
|
|
8277
8277
|
if (!didWarn403 && Date.now() >= warn403Time) {
|
|
@@ -8295,18 +8295,18 @@ var require_client = __commonJS((exports) => {
|
|
|
8295
8295
|
warningLogger.warn(`@smithy/util-waiter WARN - 403 status code encountered during waiter polling.`);
|
|
8296
8296
|
}
|
|
8297
8297
|
};
|
|
8298
|
-
var createMessageFromResponse = (
|
|
8299
|
-
const status =
|
|
8300
|
-
if (
|
|
8301
|
-
return `${status ? status + ": " : ""}Deserialization error for body: ${
|
|
8298
|
+
var createMessageFromResponse = (reason2) => {
|
|
8299
|
+
const status = reason2?.$response?.statusCode ?? reason2?.$metadata?.httpStatusCode;
|
|
8300
|
+
if (reason2?.$responseBodyText) {
|
|
8301
|
+
return `${status ? status + ": " : ""}Deserialization error for body: ${reason2.$responseBodyText}`;
|
|
8302
8302
|
}
|
|
8303
8303
|
if (status) {
|
|
8304
|
-
if (
|
|
8305
|
-
return `${status ?? "Unknown"}: ${
|
|
8304
|
+
if (reason2?.$response || reason2?.message) {
|
|
8305
|
+
return `${status ?? "Unknown"}: ${reason2?.message}`;
|
|
8306
8306
|
}
|
|
8307
8307
|
return `${status}: OK`;
|
|
8308
8308
|
}
|
|
8309
|
-
return String(
|
|
8309
|
+
return String(reason2?.message ?? JSON.stringify(reason2, getCircularReplacer()) ?? "Unknown");
|
|
8310
8310
|
};
|
|
8311
8311
|
var exponentialBackoffWithJitter = (minDelayMs, maxDelayMs, attempt, waitUntil) => {
|
|
8312
8312
|
const attemptCountCeiling = Math.log(maxDelayMs / minDelayMs) / Math.log(2) + 1;
|
|
@@ -8338,8 +8338,8 @@ var require_client = __commonJS((exports) => {
|
|
|
8338
8338
|
};
|
|
8339
8339
|
var abortTimeout = (abortSignal) => {
|
|
8340
8340
|
let onAbort;
|
|
8341
|
-
const promise = new Promise((
|
|
8342
|
-
onAbort = () =>
|
|
8341
|
+
const promise = new Promise((resolve24) => {
|
|
8342
|
+
onAbort = () => resolve24({ state: WaiterState.ABORTED });
|
|
8343
8343
|
if (typeof abortSignal.addEventListener === "function") {
|
|
8344
8344
|
abortSignal.addEventListener("abort", onAbort);
|
|
8345
8345
|
} else {
|
|
@@ -9004,7 +9004,7 @@ var require_client = __commonJS((exports) => {
|
|
|
9004
9004
|
var require_config = __commonJS((exports) => {
|
|
9005
9005
|
var { homedir: homedir7 } = __require("os");
|
|
9006
9006
|
var { sep: sep11, join: join4 } = __require("path");
|
|
9007
|
-
var { createHash:
|
|
9007
|
+
var { createHash: createHash28 } = __require("crypto");
|
|
9008
9008
|
var { readFile: readFile$1 } = __require("fs/promises");
|
|
9009
9009
|
var { IniSectionType } = require_dist_cjs();
|
|
9010
9010
|
var { normalizeProvider } = require_client();
|
|
@@ -9159,7 +9159,7 @@ var require_config = __commonJS((exports) => {
|
|
|
9159
9159
|
var DEFAULT_PROFILE = "default";
|
|
9160
9160
|
var getProfileName = (init) => init.profile || process.env[ENV_PROFILE] || DEFAULT_PROFILE;
|
|
9161
9161
|
var getSSOTokenFilepath = (id2) => {
|
|
9162
|
-
const hasher =
|
|
9162
|
+
const hasher = createHash28("sha1");
|
|
9163
9163
|
const cacheName = hasher.update(id2).digest("hex");
|
|
9164
9164
|
return join4(getHomeDir(), ".aws", "sso", "cache", `${cacheName}.json`);
|
|
9165
9165
|
};
|
|
@@ -9477,7 +9477,7 @@ var require_config = __commonJS((exports) => {
|
|
|
9477
9477
|
};
|
|
9478
9478
|
var imdsRequest = async (options) => {
|
|
9479
9479
|
const { request: request2 } = __require("http");
|
|
9480
|
-
return new Promise((
|
|
9480
|
+
return new Promise((resolve24, reject) => {
|
|
9481
9481
|
const req = request2({
|
|
9482
9482
|
hostname: options.hostname,
|
|
9483
9483
|
port: options.port,
|
|
@@ -9505,7 +9505,7 @@ var require_config = __commonJS((exports) => {
|
|
|
9505
9505
|
const chunks = [];
|
|
9506
9506
|
res.on("data", (chunk) => chunks.push(chunk));
|
|
9507
9507
|
res.on("end", () => {
|
|
9508
|
-
|
|
9508
|
+
resolve24(Buffer.concat(chunks));
|
|
9509
9509
|
req.destroy();
|
|
9510
9510
|
});
|
|
9511
9511
|
});
|
|
@@ -10511,7 +10511,7 @@ var require_endpoints = __commonJS((exports) => {
|
|
|
10511
10511
|
|
|
10512
10512
|
// node_modules/@smithy/core/dist-cjs/submodules/serde/index.js
|
|
10513
10513
|
var require_serde = __commonJS((exports) => {
|
|
10514
|
-
var { createHmac: createHmac2, createHash:
|
|
10514
|
+
var { createHmac: createHmac2, createHash: createHash28, getRandomValues } = __require("crypto");
|
|
10515
10515
|
var { hasOwn: hasOwn2, HttpResponse } = require_transport();
|
|
10516
10516
|
exports.hasOwn = hasOwn2;
|
|
10517
10517
|
var { ReadStream, lstatSync: lstatSync27, fstatSync: fstatSync4 } = __require("fs");
|
|
@@ -11416,7 +11416,7 @@ var require_serde = __commonJS((exports) => {
|
|
|
11416
11416
|
return Promise.resolve(this.hash.digest());
|
|
11417
11417
|
}
|
|
11418
11418
|
reset() {
|
|
11419
|
-
this.hash = this.secret ? createHmac2(this.algorithmIdentifier, castSourceData(this.secret)) :
|
|
11419
|
+
this.hash = this.secret ? createHmac2(this.algorithmIdentifier, castSourceData(this.secret)) : createHash28(this.algorithmIdentifier);
|
|
11420
11420
|
}
|
|
11421
11421
|
}
|
|
11422
11422
|
function castSourceData(toCast, encoding) {
|
|
@@ -11861,7 +11861,7 @@ ${value}\r
|
|
|
11861
11861
|
if (isReadableStream(stream)) {
|
|
11862
11862
|
return headStream$1(stream, bytes);
|
|
11863
11863
|
}
|
|
11864
|
-
return new Promise((
|
|
11864
|
+
return new Promise((resolve24, reject) => {
|
|
11865
11865
|
const collector = new Collector$1;
|
|
11866
11866
|
collector.limit = bytes;
|
|
11867
11867
|
stream.pipe(collector);
|
|
@@ -11872,7 +11872,7 @@ ${value}\r
|
|
|
11872
11872
|
collector.on("error", reject);
|
|
11873
11873
|
collector.on("finish", function() {
|
|
11874
11874
|
const bytes2 = concatBytes(this.buffers);
|
|
11875
|
-
|
|
11875
|
+
resolve24(bytes2);
|
|
11876
11876
|
});
|
|
11877
11877
|
});
|
|
11878
11878
|
};
|
|
@@ -11986,7 +11986,7 @@ ${value}\r
|
|
|
11986
11986
|
if (isReadableStream(stream)) {
|
|
11987
11987
|
return collectReadableStream(stream);
|
|
11988
11988
|
}
|
|
11989
|
-
return new Promise((
|
|
11989
|
+
return new Promise((resolve24, reject) => {
|
|
11990
11990
|
const collector = new Collector;
|
|
11991
11991
|
const nodeStream = stream;
|
|
11992
11992
|
nodeStream.pipe(collector);
|
|
@@ -11997,7 +11997,7 @@ ${value}\r
|
|
|
11997
11997
|
collector.on("error", reject);
|
|
11998
11998
|
collector.on("finish", function() {
|
|
11999
11999
|
const bytes = concatBytes(this.bufferedBytes);
|
|
12000
|
-
|
|
12000
|
+
resolve24(bytes);
|
|
12001
12001
|
});
|
|
12002
12002
|
});
|
|
12003
12003
|
};
|
|
@@ -12155,7 +12155,7 @@ var require_checksum = __commonJS((exports) => {
|
|
|
12155
12155
|
var { createReadStream } = __require("fs");
|
|
12156
12156
|
var { Writable } = __require("stream");
|
|
12157
12157
|
var { toUint8Array, concatBytes } = require_serde();
|
|
12158
|
-
var { createHash:
|
|
12158
|
+
var { createHash: createHash28, createHmac: createHmac2 } = __require("crypto");
|
|
12159
12159
|
var zlib = __require("zlib");
|
|
12160
12160
|
async function blobReader(blob, onChunk, chunkSize = 1024 * 1024) {
|
|
12161
12161
|
const size = blob.size;
|
|
@@ -12189,7 +12189,7 @@ var require_checksum = __commonJS((exports) => {
|
|
|
12189
12189
|
callback();
|
|
12190
12190
|
}
|
|
12191
12191
|
}
|
|
12192
|
-
var fileStreamHasher = (hashCtor, fileStream) => new Promise((
|
|
12192
|
+
var fileStreamHasher = (hashCtor, fileStream) => new Promise((resolve24, reject) => {
|
|
12193
12193
|
if (!isReadStream(fileStream)) {
|
|
12194
12194
|
reject(new Error("Unable to calculate hash for non-file streams."));
|
|
12195
12195
|
return;
|
|
@@ -12207,7 +12207,7 @@ var require_checksum = __commonJS((exports) => {
|
|
|
12207
12207
|
});
|
|
12208
12208
|
hashCalculator.on("error", reject);
|
|
12209
12209
|
hashCalculator.on("finish", function() {
|
|
12210
|
-
hash2.digest().then(
|
|
12210
|
+
hash2.digest().then(resolve24).catch(reject);
|
|
12211
12211
|
});
|
|
12212
12212
|
});
|
|
12213
12213
|
var isReadStream = (stream) => typeof stream.path === "string";
|
|
@@ -12218,14 +12218,14 @@ var require_checksum = __commonJS((exports) => {
|
|
|
12218
12218
|
const hash2 = new hashCtor;
|
|
12219
12219
|
const hashCalculator = new HashCalculator(hash2);
|
|
12220
12220
|
readableStream.pipe(hashCalculator);
|
|
12221
|
-
return new Promise((
|
|
12221
|
+
return new Promise((resolve24, reject) => {
|
|
12222
12222
|
readableStream.on("error", (err) => {
|
|
12223
12223
|
hashCalculator.end();
|
|
12224
12224
|
reject(err);
|
|
12225
12225
|
});
|
|
12226
12226
|
hashCalculator.on("error", reject);
|
|
12227
12227
|
hashCalculator.on("finish", () => {
|
|
12228
|
-
hash2.digest().then(
|
|
12228
|
+
hash2.digest().then(resolve24).catch(reject);
|
|
12229
12229
|
});
|
|
12230
12230
|
});
|
|
12231
12231
|
};
|
|
@@ -12320,7 +12320,7 @@ var require_checksum = __commonJS((exports) => {
|
|
|
12320
12320
|
}
|
|
12321
12321
|
var hasNativeCrypto$1 = (() => {
|
|
12322
12322
|
try {
|
|
12323
|
-
|
|
12323
|
+
createHash28("md5");
|
|
12324
12324
|
return true;
|
|
12325
12325
|
} catch {
|
|
12326
12326
|
return false;
|
|
@@ -12330,7 +12330,7 @@ var require_checksum = __commonJS((exports) => {
|
|
|
12330
12330
|
function buildNativeClass$2() {
|
|
12331
12331
|
return class Md5Node2 {
|
|
12332
12332
|
digestLength = 16;
|
|
12333
|
-
hash =
|
|
12333
|
+
hash = createHash28("md5");
|
|
12334
12334
|
update(data) {
|
|
12335
12335
|
this.hash.update(toUint8Array(data));
|
|
12336
12336
|
}
|
|
@@ -12339,7 +12339,7 @@ var require_checksum = __commonJS((exports) => {
|
|
|
12339
12339
|
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
12340
12340
|
}
|
|
12341
12341
|
reset() {
|
|
12342
|
-
this.hash =
|
|
12342
|
+
this.hash = createHash28("md5");
|
|
12343
12343
|
}
|
|
12344
12344
|
};
|
|
12345
12345
|
}
|
|
@@ -12629,7 +12629,7 @@ var require_checksum = __commonJS((exports) => {
|
|
|
12629
12629
|
]);
|
|
12630
12630
|
var hasNativeCrypto = (() => {
|
|
12631
12631
|
try {
|
|
12632
|
-
|
|
12632
|
+
createHash28("sha256");
|
|
12633
12633
|
return true;
|
|
12634
12634
|
} catch {
|
|
12635
12635
|
return false;
|
|
@@ -12669,7 +12669,7 @@ var require_checksum = __commonJS((exports) => {
|
|
|
12669
12669
|
this.finished = false;
|
|
12670
12670
|
}
|
|
12671
12671
|
createHash() {
|
|
12672
|
-
return this.secret ? createHmac2("sha256", toBuffer(this.secret)) :
|
|
12672
|
+
return this.secret ? createHmac2("sha256", toBuffer(this.secret)) : createHash28("sha256");
|
|
12673
12673
|
}
|
|
12674
12674
|
};
|
|
12675
12675
|
}
|
|
@@ -13334,7 +13334,7 @@ var require_event_streams = __commonJS((exports) => {
|
|
|
13334
13334
|
streamEnded = true;
|
|
13335
13335
|
});
|
|
13336
13336
|
while (!generationEnded) {
|
|
13337
|
-
const value = await new Promise((
|
|
13337
|
+
const value = await new Promise((resolve24) => setTimeout(() => resolve24(records.shift()), 0));
|
|
13338
13338
|
if (value) {
|
|
13339
13339
|
yield value;
|
|
13340
13340
|
}
|
|
@@ -14542,8 +14542,8 @@ var require_protocols = __commonJS((exports) => {
|
|
|
14542
14542
|
fields2.forEach(this.setField.bind(this));
|
|
14543
14543
|
this.encoding = encoding;
|
|
14544
14544
|
}
|
|
14545
|
-
setField(
|
|
14546
|
-
this.entries[
|
|
14545
|
+
setField(field3) {
|
|
14546
|
+
this.entries[field3.name.toLowerCase()] = field3;
|
|
14547
14547
|
}
|
|
14548
14548
|
getField(name) {
|
|
14549
14549
|
return this.entries[name.toLowerCase()];
|
|
@@ -14552,7 +14552,7 @@ var require_protocols = __commonJS((exports) => {
|
|
|
14552
14552
|
delete this.entries[name.toLowerCase()];
|
|
14553
14553
|
}
|
|
14554
14554
|
getByType(kind) {
|
|
14555
|
-
return Object.values(this.entries).filter((
|
|
14555
|
+
return Object.values(this.entries).filter((field3) => field3.kind === kind);
|
|
14556
14556
|
}
|
|
14557
14557
|
}
|
|
14558
14558
|
var getHttpHandlerExtensionConfiguration = (runtimeConfig) => {
|
|
@@ -14852,7 +14852,7 @@ var require_retry = __commonJS((exports) => {
|
|
|
14852
14852
|
}
|
|
14853
14853
|
};
|
|
14854
14854
|
}
|
|
14855
|
-
var cooldown = (ms) => new Promise((
|
|
14855
|
+
var cooldown = (ms) => new Promise((resolve24) => setTimeout(resolve24, ms));
|
|
14856
14856
|
var isRetryStrategyV2 = (retryStrategy) => typeof retryStrategy.acquireInitialRetryToken !== "undefined" && typeof retryStrategy.refreshRetryTokenForRetry !== "undefined" && typeof retryStrategy.recordSuccess !== "undefined";
|
|
14857
14857
|
var getRetryErrorInfo = (error, logger) => {
|
|
14858
14858
|
const errorInfo = {
|
|
@@ -14951,7 +14951,7 @@ var require_retry = __commonJS((exports) => {
|
|
|
14951
14951
|
this.refillTokenBucket();
|
|
14952
14952
|
while (amount > this.availableTokens) {
|
|
14953
14953
|
const delay = (amount - this.availableTokens) / this.fillRate * 1000;
|
|
14954
|
-
await new Promise((
|
|
14954
|
+
await new Promise((resolve24) => DefaultRateLimiter.setTimeoutFn(resolve24, delay));
|
|
14955
14955
|
this.refillTokenBucket();
|
|
14956
14956
|
}
|
|
14957
14957
|
this.availableTokens = this.availableTokens - amount;
|
|
@@ -15293,7 +15293,7 @@ var require_retry = __commonJS((exports) => {
|
|
|
15293
15293
|
const delayFromResponse = getDelayFromRetryAfterHeader(err.$response);
|
|
15294
15294
|
const delay = Math.max(delayFromResponse || 0, delayFromDecider);
|
|
15295
15295
|
totalDelay += delay;
|
|
15296
|
-
await new Promise((
|
|
15296
|
+
await new Promise((resolve24) => setTimeout(resolve24, delay));
|
|
15297
15297
|
continue;
|
|
15298
15298
|
}
|
|
15299
15299
|
if (!err.$metadata) {
|
|
@@ -18166,7 +18166,7 @@ ${toHex(hashedRequest)}`;
|
|
|
18166
18166
|
return hash2.digest();
|
|
18167
18167
|
};
|
|
18168
18168
|
var getCanonicalHeaders = ({ headers }, unsignableHeaders, signableHeaders) => {
|
|
18169
|
-
const
|
|
18169
|
+
const canonical8 = {};
|
|
18170
18170
|
for (const headerName of Object.keys(headers).sort()) {
|
|
18171
18171
|
if (headers[headerName] == undefined) {
|
|
18172
18172
|
continue;
|
|
@@ -18177,9 +18177,9 @@ ${toHex(hashedRequest)}`;
|
|
|
18177
18177
|
continue;
|
|
18178
18178
|
}
|
|
18179
18179
|
}
|
|
18180
|
-
|
|
18180
|
+
canonical8[canonicalHeaderName] = headers[headerName].trim().replace(/\s+/g, " ");
|
|
18181
18181
|
}
|
|
18182
|
-
return
|
|
18182
|
+
return canonical8;
|
|
18183
18183
|
};
|
|
18184
18184
|
var getPayloadHash = async ({ headers, body }, hashConstructor) => {
|
|
18185
18185
|
for (const headerName in headers) {
|
|
@@ -20175,7 +20175,7 @@ var require_cbor = __commonJS((exports) => {
|
|
|
20175
20175
|
const { memberSchemas, encodedKeys, memberNames } = cache;
|
|
20176
20176
|
const z = encodedKeys.length;
|
|
20177
20177
|
const result = {};
|
|
20178
|
-
let
|
|
20178
|
+
let unknownKey2;
|
|
20179
20179
|
let unknownValue;
|
|
20180
20180
|
let unknownCount = 0;
|
|
20181
20181
|
let hasType = false;
|
|
@@ -20197,7 +20197,7 @@ var require_cbor = __commonJS((exports) => {
|
|
|
20197
20197
|
if (key === "__type" && typeof val === "string") {
|
|
20198
20198
|
hasType = true;
|
|
20199
20199
|
} else {
|
|
20200
|
-
|
|
20200
|
+
unknownKey2 = key;
|
|
20201
20201
|
unknownValue = val;
|
|
20202
20202
|
++unknownCount;
|
|
20203
20203
|
}
|
|
@@ -20212,7 +20212,7 @@ var require_cbor = __commonJS((exports) => {
|
|
|
20212
20212
|
break;
|
|
20213
20213
|
}
|
|
20214
20214
|
if (resultEmpty && unknownCount === 1) {
|
|
20215
|
-
result.$unknown = [
|
|
20215
|
+
result.$unknown = [unknownKey2, unknownValue];
|
|
20216
20216
|
}
|
|
20217
20217
|
} else if (hasType) {
|
|
20218
20218
|
pos = startPos;
|
|
@@ -20360,7 +20360,7 @@ var require_cbor = __commonJS((exports) => {
|
|
|
20360
20360
|
const z = encodedKeys.length;
|
|
20361
20361
|
const isUnion = ns.isUnionSchema();
|
|
20362
20362
|
const result = {};
|
|
20363
|
-
let
|
|
20363
|
+
let unknownKey2;
|
|
20364
20364
|
let unknownValue;
|
|
20365
20365
|
let unknownCount = 0;
|
|
20366
20366
|
let hint = 0;
|
|
@@ -20376,7 +20376,7 @@ var require_cbor = __commonJS((exports) => {
|
|
|
20376
20376
|
break;
|
|
20377
20377
|
}
|
|
20378
20378
|
if (resultEmpty && unknownCount === 1) {
|
|
20379
|
-
result.$unknown = [
|
|
20379
|
+
result.$unknown = [unknownKey2, unknownValue];
|
|
20380
20380
|
}
|
|
20381
20381
|
}
|
|
20382
20382
|
return result;
|
|
@@ -20395,7 +20395,7 @@ var require_cbor = __commonJS((exports) => {
|
|
|
20395
20395
|
const key = readUtf8String();
|
|
20396
20396
|
const val = readValue(NormalizedSchema.of(15));
|
|
20397
20397
|
if (key !== "__type") {
|
|
20398
|
-
|
|
20398
|
+
unknownKey2 = key;
|
|
20399
20399
|
unknownValue = val;
|
|
20400
20400
|
++unknownCount;
|
|
20401
20401
|
}
|
|
@@ -21110,8 +21110,8 @@ var require_dist_cjs5 = __commonJS((exports) => {
|
|
|
21110
21110
|
this.attributes[name] = value;
|
|
21111
21111
|
return this;
|
|
21112
21112
|
}
|
|
21113
|
-
addChildNode(
|
|
21114
|
-
this.children.push(
|
|
21113
|
+
addChildNode(child2) {
|
|
21114
|
+
this.children.push(child2);
|
|
21115
21115
|
return this;
|
|
21116
21116
|
}
|
|
21117
21117
|
removeAttribute(name) {
|
|
@@ -21122,8 +21122,8 @@ var require_dist_cjs5 = __commonJS((exports) => {
|
|
|
21122
21122
|
this.name = name;
|
|
21123
21123
|
return this;
|
|
21124
21124
|
}
|
|
21125
|
-
c(
|
|
21126
|
-
this.children.push(
|
|
21125
|
+
c(child2) {
|
|
21126
|
+
this.children.push(child2);
|
|
21127
21127
|
return this;
|
|
21128
21128
|
}
|
|
21129
21129
|
a(name, value) {
|
|
@@ -21132,9 +21132,9 @@ var require_dist_cjs5 = __commonJS((exports) => {
|
|
|
21132
21132
|
}
|
|
21133
21133
|
return this;
|
|
21134
21134
|
}
|
|
21135
|
-
cc(input,
|
|
21136
|
-
if (input[
|
|
21137
|
-
const node = XmlNode.of(
|
|
21135
|
+
cc(input, field3, withName = field3) {
|
|
21136
|
+
if (input[field3] != null) {
|
|
21137
|
+
const node = XmlNode.of(field3, input[field3]).withName(withName);
|
|
21138
21138
|
this.c(node);
|
|
21139
21139
|
}
|
|
21140
21140
|
}
|
|
@@ -21240,10 +21240,10 @@ var require_dist_cjs5 = __commonJS((exports) => {
|
|
|
21240
21240
|
}
|
|
21241
21241
|
readAttrValue() {
|
|
21242
21242
|
const p = this;
|
|
21243
|
-
const
|
|
21243
|
+
const quote3 = p.x[p.i];
|
|
21244
21244
|
++p.i;
|
|
21245
21245
|
let value = "";
|
|
21246
|
-
while (p.i < p.z && p.x[p.i] !==
|
|
21246
|
+
while (p.i < p.z && p.x[p.i] !== quote3) {
|
|
21247
21247
|
value += p.x[p.i++];
|
|
21248
21248
|
}
|
|
21249
21249
|
++p.i;
|
|
@@ -21350,18 +21350,18 @@ var require_dist_cjs5 = __commonJS((exports) => {
|
|
|
21350
21350
|
}
|
|
21351
21351
|
obj["#text"] = "#text" in obj ? obj["#text"] + text2 : text2;
|
|
21352
21352
|
}
|
|
21353
|
-
for (const
|
|
21354
|
-
if (
|
|
21353
|
+
for (const child2 of childTags) {
|
|
21354
|
+
if (child2.tag === "__proto__") {
|
|
21355
21355
|
writeKey(obj);
|
|
21356
21356
|
}
|
|
21357
|
-
if (
|
|
21358
|
-
if (Array.isArray(obj[
|
|
21359
|
-
obj[
|
|
21357
|
+
if (child2.tag in obj) {
|
|
21358
|
+
if (Array.isArray(obj[child2.tag])) {
|
|
21359
|
+
obj[child2.tag].push(child2.value);
|
|
21360
21360
|
} else {
|
|
21361
|
-
obj[
|
|
21361
|
+
obj[child2.tag] = [obj[child2.tag], child2.value];
|
|
21362
21362
|
}
|
|
21363
21363
|
} else {
|
|
21364
|
-
obj[
|
|
21364
|
+
obj[child2.tag] = child2.value;
|
|
21365
21365
|
}
|
|
21366
21366
|
}
|
|
21367
21367
|
for (const [k, v] of Object.entries(attrs)) {
|
|
@@ -21700,12 +21700,12 @@ var require_protocols2 = __commonJS((exports) => {
|
|
|
21700
21700
|
return expandToDecimal(numericString) === expandToDecimal(String(value));
|
|
21701
21701
|
}
|
|
21702
21702
|
const normalized = numericString.replace(/(\.\d*?)0+$/, "$1").replace(/\.$/, "");
|
|
21703
|
-
const
|
|
21704
|
-
if (normalized ===
|
|
21703
|
+
const canonical8 = String(value);
|
|
21704
|
+
if (normalized === canonical8) {
|
|
21705
21705
|
return true;
|
|
21706
21706
|
}
|
|
21707
|
-
if (/[eE]/.test(
|
|
21708
|
-
return normalized === expandToDecimal(
|
|
21707
|
+
if (/[eE]/.test(canonical8)) {
|
|
21708
|
+
return normalized === expandToDecimal(canonical8);
|
|
21709
21709
|
}
|
|
21710
21710
|
return false;
|
|
21711
21711
|
}
|
|
@@ -24646,7 +24646,7 @@ var init_node_http = () => {};
|
|
|
24646
24646
|
|
|
24647
24647
|
// node_modules/@smithy/credential-provider-imds/dist-es/remoteProvider/httpRequest.js
|
|
24648
24648
|
function httpRequest(options) {
|
|
24649
|
-
return new Promise((
|
|
24649
|
+
return new Promise((resolve24, reject) => {
|
|
24650
24650
|
const req = node_http.request({
|
|
24651
24651
|
method: "GET",
|
|
24652
24652
|
...options,
|
|
@@ -24671,7 +24671,7 @@ function httpRequest(options) {
|
|
|
24671
24671
|
chunks.push(chunk);
|
|
24672
24672
|
});
|
|
24673
24673
|
res.on("end", () => {
|
|
24674
|
-
|
|
24674
|
+
resolve24(Buffer.concat(chunks));
|
|
24675
24675
|
req.destroy();
|
|
24676
24676
|
});
|
|
24677
24677
|
});
|
|
@@ -25036,15 +25036,15 @@ var require_dist_cjs6 = __commonJS((exports) => {
|
|
|
25036
25036
|
var { Readable: Readable2 } = __require("stream");
|
|
25037
25037
|
var http2 = __require("http2");
|
|
25038
25038
|
function buildAbortError(abortSignal) {
|
|
25039
|
-
const
|
|
25040
|
-
if (
|
|
25041
|
-
if (
|
|
25039
|
+
const reason2 = abortSignal && typeof abortSignal === "object" && "reason" in abortSignal ? abortSignal.reason : undefined;
|
|
25040
|
+
if (reason2) {
|
|
25041
|
+
if (reason2 instanceof Error) {
|
|
25042
25042
|
const abortError3 = new Error("Request aborted");
|
|
25043
25043
|
abortError3.name = "AbortError";
|
|
25044
|
-
abortError3.cause =
|
|
25044
|
+
abortError3.cause = reason2;
|
|
25045
25045
|
return abortError3;
|
|
25046
25046
|
}
|
|
25047
|
-
const abortError2 = new Error(String(
|
|
25047
|
+
const abortError2 = new Error(String(reason2));
|
|
25048
25048
|
abortError2.name = "AbortError";
|
|
25049
25049
|
return abortError2;
|
|
25050
25050
|
}
|
|
@@ -25168,21 +25168,21 @@ var require_dist_cjs6 = __commonJS((exports) => {
|
|
|
25168
25168
|
let sendBody = true;
|
|
25169
25169
|
if (!externalAgent && expect === "100-continue") {
|
|
25170
25170
|
sendBody = await Promise.race([
|
|
25171
|
-
new Promise((
|
|
25172
|
-
timeoutId = Number(timing.setTimeout(() =>
|
|
25171
|
+
new Promise((resolve24) => {
|
|
25172
|
+
timeoutId = Number(timing.setTimeout(() => resolve24(true), Math.max(MIN_WAIT_TIME, maxContinueTimeoutMs)));
|
|
25173
25173
|
}),
|
|
25174
|
-
new Promise((
|
|
25174
|
+
new Promise((resolve24) => {
|
|
25175
25175
|
httpRequest2.on("continue", () => {
|
|
25176
25176
|
timing.clearTimeout(timeoutId);
|
|
25177
|
-
|
|
25177
|
+
resolve24(true);
|
|
25178
25178
|
});
|
|
25179
25179
|
httpRequest2.on("response", () => {
|
|
25180
25180
|
timing.clearTimeout(timeoutId);
|
|
25181
|
-
|
|
25181
|
+
resolve24(false);
|
|
25182
25182
|
});
|
|
25183
25183
|
httpRequest2.on("error", () => {
|
|
25184
25184
|
timing.clearTimeout(timeoutId);
|
|
25185
|
-
|
|
25185
|
+
resolve24(false);
|
|
25186
25186
|
});
|
|
25187
25187
|
})
|
|
25188
25188
|
]);
|
|
@@ -25198,8 +25198,8 @@ var require_dist_cjs6 = __commonJS((exports) => {
|
|
|
25198
25198
|
}
|
|
25199
25199
|
if (body) {
|
|
25200
25200
|
const isBuffer = Buffer.isBuffer(body);
|
|
25201
|
-
const
|
|
25202
|
-
if (isBuffer ||
|
|
25201
|
+
const isString2 = typeof body === "string";
|
|
25202
|
+
if (isBuffer || isString2) {
|
|
25203
25203
|
if (isBuffer && body.byteLength === 0) {
|
|
25204
25204
|
httpRequest2.end();
|
|
25205
25205
|
} else {
|
|
@@ -25259,13 +25259,13 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
|
|
|
25259
25259
|
return socketWarningTimestamp;
|
|
25260
25260
|
}
|
|
25261
25261
|
constructor(options) {
|
|
25262
|
-
this.configProvider = new Promise((
|
|
25262
|
+
this.configProvider = new Promise((resolve24, reject) => {
|
|
25263
25263
|
if (typeof options === "function") {
|
|
25264
25264
|
options().then((_options) => {
|
|
25265
|
-
|
|
25265
|
+
resolve24(this.resolveDefaultConfig(_options));
|
|
25266
25266
|
}).catch(reject);
|
|
25267
25267
|
} else {
|
|
25268
|
-
|
|
25268
|
+
resolve24(this.resolveDefaultConfig(options));
|
|
25269
25269
|
}
|
|
25270
25270
|
});
|
|
25271
25271
|
}
|
|
@@ -25297,7 +25297,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
|
|
|
25297
25297
|
timing.clearTimeout(socketTimeoutId);
|
|
25298
25298
|
timing.clearTimeout(keepAliveTimeoutId);
|
|
25299
25299
|
};
|
|
25300
|
-
const
|
|
25300
|
+
const resolve24 = async (arg) => {
|
|
25301
25301
|
await writeRequestBodyPromise;
|
|
25302
25302
|
clearTimeouts();
|
|
25303
25303
|
_resolve(arg);
|
|
@@ -25361,7 +25361,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
|
|
|
25361
25361
|
headers: getTransformedHeaders(res.headers),
|
|
25362
25362
|
body: res
|
|
25363
25363
|
});
|
|
25364
|
-
|
|
25364
|
+
resolve24({ response: httpResponse });
|
|
25365
25365
|
});
|
|
25366
25366
|
req.on("error", (err) => {
|
|
25367
25367
|
if (NODEJS_TIMEOUT_ERROR_CODES.includes(err.code)) {
|
|
@@ -25693,13 +25693,13 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
|
|
|
25693
25693
|
return new NodeHttp2Handler(instanceOrOptions);
|
|
25694
25694
|
}
|
|
25695
25695
|
constructor(options) {
|
|
25696
|
-
this.configProvider = new Promise((
|
|
25696
|
+
this.configProvider = new Promise((resolve24, reject) => {
|
|
25697
25697
|
if (typeof options === "function") {
|
|
25698
25698
|
options().then((opts) => {
|
|
25699
|
-
|
|
25699
|
+
resolve24(opts || {});
|
|
25700
25700
|
}).catch(reject);
|
|
25701
25701
|
} else {
|
|
25702
|
-
|
|
25702
|
+
resolve24(options || {});
|
|
25703
25703
|
}
|
|
25704
25704
|
});
|
|
25705
25705
|
}
|
|
@@ -25724,7 +25724,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
|
|
|
25724
25724
|
return new Promise((_resolve, _reject) => {
|
|
25725
25725
|
let fulfilled = false;
|
|
25726
25726
|
let writeRequestBodyPromise = undefined;
|
|
25727
|
-
const
|
|
25727
|
+
const resolve24 = async (arg) => {
|
|
25728
25728
|
await writeRequestBodyPromise;
|
|
25729
25729
|
_resolve(arg);
|
|
25730
25730
|
};
|
|
@@ -25809,7 +25809,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
|
|
|
25809
25809
|
body: clientHttp2Stream
|
|
25810
25810
|
});
|
|
25811
25811
|
fulfilled = true;
|
|
25812
|
-
|
|
25812
|
+
resolve24({ response: httpResponse });
|
|
25813
25813
|
if (useIsolatedSession) {
|
|
25814
25814
|
session.close();
|
|
25815
25815
|
clientHttp2Stream.on("end", () => {
|
|
@@ -25942,7 +25942,7 @@ var retryWrapper = (toRetry, maxRetries, delayMs) => {
|
|
|
25942
25942
|
try {
|
|
25943
25943
|
return await toRetry();
|
|
25944
25944
|
} catch (e3) {
|
|
25945
|
-
await new Promise((
|
|
25945
|
+
await new Promise((resolve24) => setTimeout(resolve24, delayMs));
|
|
25946
25946
|
}
|
|
25947
25947
|
}
|
|
25948
25948
|
return await toRetry();
|
|
@@ -29443,10 +29443,10 @@ var require_signin = __commonJS((exports) => {
|
|
|
29443
29443
|
});
|
|
29444
29444
|
|
|
29445
29445
|
// node_modules/@aws-sdk/credential-provider-ini/node_modules/@aws-sdk/credential-provider-login/dist-es/LoginCredentialsFetcher.js
|
|
29446
|
-
import { createHash as
|
|
29446
|
+
import { createHash as createHash28, createPrivateKey, createPublicKey, sign } from "crypto";
|
|
29447
29447
|
import { promises as fs2 } from "fs";
|
|
29448
29448
|
import { homedir as homedir7 } from "os";
|
|
29449
|
-
import { dirname as
|
|
29449
|
+
import { dirname as dirname24, join as join38 } from "path";
|
|
29450
29450
|
var import_config28, import_protocols3, LoginCredentialsFetcher;
|
|
29451
29451
|
var init_LoginCredentialsFetcher = __esm(() => {
|
|
29452
29452
|
import_config28 = __toESM(require_config(), 1);
|
|
@@ -29606,7 +29606,7 @@ var init_LoginCredentialsFetcher = __esm(() => {
|
|
|
29606
29606
|
}
|
|
29607
29607
|
async saveToken(token) {
|
|
29608
29608
|
const tokenFilePath = this.getTokenFilePath();
|
|
29609
|
-
const directory =
|
|
29609
|
+
const directory = dirname24(tokenFilePath);
|
|
29610
29610
|
try {
|
|
29611
29611
|
await fs2.mkdir(directory, { recursive: true });
|
|
29612
29612
|
} catch (error) {}
|
|
@@ -29615,7 +29615,7 @@ var init_LoginCredentialsFetcher = __esm(() => {
|
|
|
29615
29615
|
getTokenFilePath() {
|
|
29616
29616
|
const directory = process.env.AWS_LOGIN_CACHE_DIRECTORY ?? join38(homedir7(), ".aws", "login", "cache");
|
|
29617
29617
|
const loginSessionBytes = Buffer.from(this.loginSession, "utf8");
|
|
29618
|
-
const loginSessionSha256 =
|
|
29618
|
+
const loginSessionSha256 = createHash28("sha256").update(loginSessionBytes).digest("hex");
|
|
29619
29619
|
return join38(directory, `${loginSessionSha256}.json`);
|
|
29620
29620
|
}
|
|
29621
29621
|
derToRawSignature(derSignature) {
|
|
@@ -31067,7 +31067,7 @@ import { existsSync as existsSync22 } from "fs";
|
|
|
31067
31067
|
import { join as join210 } from "path";
|
|
31068
31068
|
import { existsSync as existsSync17 } from "fs";
|
|
31069
31069
|
import { homedir as homedir8 } from "os";
|
|
31070
|
-
import { join as join42, resolve as
|
|
31070
|
+
import { join as join42, resolve as resolve24 } from "path";
|
|
31071
31071
|
import { homedir as pathsResolverHomedir2 } from "os";
|
|
31072
31072
|
import { join as pathsResolverJoin2 } from "path";
|
|
31073
31073
|
import { createHmac as createHmac4, timingSafeEqual as timingSafeEqual3 } from "crypto";
|
|
@@ -31251,9 +31251,9 @@ function exactEventsHome() {
|
|
|
31251
31251
|
function getEventsHome() {
|
|
31252
31252
|
const exact = exactEventsHome();
|
|
31253
31253
|
if (exact)
|
|
31254
|
-
return
|
|
31254
|
+
return resolve24(exact);
|
|
31255
31255
|
const resolved = resolverHome();
|
|
31256
|
-
return adoptResolverHome(resolved) ?
|
|
31256
|
+
return adoptResolverHome(resolved) ? resolve24(resolved) : resolve24(legacyHomeDir());
|
|
31257
31257
|
}
|
|
31258
31258
|
function getEventsDataDir(override) {
|
|
31259
31259
|
return override || getEventsHome();
|
|
@@ -31793,7 +31793,7 @@ async function pinnedNativeRequest(target, addresses, method, headers, body4, si
|
|
|
31793
31793
|
callback(null, entries);
|
|
31794
31794
|
}
|
|
31795
31795
|
};
|
|
31796
|
-
return new Promise((
|
|
31796
|
+
return new Promise((resolve25, reject) => {
|
|
31797
31797
|
const request2 = isHttps ? nodeHttpsRequest(requestOptions, onResponse) : nodeHttpRequest(requestOptions, onResponse);
|
|
31798
31798
|
const onAbort = () => {
|
|
31799
31799
|
const error = new Error("The operation was aborted.");
|
|
@@ -31820,7 +31820,7 @@ async function pinnedNativeRequest(target, addresses, method, headers, body4, si
|
|
|
31820
31820
|
else if (Array.isArray(value))
|
|
31821
31821
|
headersRecord[name] = value.join(", ");
|
|
31822
31822
|
}
|
|
31823
|
-
|
|
31823
|
+
resolve25(new Response(Buffer.concat(chunks), { status: response.statusCode ?? 200, headers: headersRecord }));
|
|
31824
31824
|
});
|
|
31825
31825
|
}
|
|
31826
31826
|
});
|
|
@@ -31917,25 +31917,25 @@ async function dispatchCommand(event, channel) {
|
|
|
31917
31917
|
HASNA_EVENT_SCHEMA_VERSION: event.schemaVersion,
|
|
31918
31918
|
HASNA_EVENT_JSON: eventJson
|
|
31919
31919
|
};
|
|
31920
|
-
return new Promise((
|
|
31921
|
-
const
|
|
31920
|
+
return new Promise((resolve25) => {
|
|
31921
|
+
const child2 = spawn3(channel.command.command, channel.command.args ?? [], {
|
|
31922
31922
|
cwd: channel.command.cwd,
|
|
31923
31923
|
env,
|
|
31924
31924
|
stdio: ["pipe", "pipe", "pipe"]
|
|
31925
31925
|
});
|
|
31926
31926
|
let stdout = "";
|
|
31927
31927
|
let stderr = "";
|
|
31928
|
-
const timeout = setTimeout(() =>
|
|
31929
|
-
|
|
31930
|
-
|
|
31928
|
+
const timeout = setTimeout(() => child2.kill("SIGTERM"), channel.command.timeoutMs ?? 15000);
|
|
31929
|
+
child2.stdin.end(eventJson);
|
|
31930
|
+
child2.stdout.on("data", (chunk) => {
|
|
31931
31931
|
stdout += chunk.toString();
|
|
31932
31932
|
});
|
|
31933
|
-
|
|
31933
|
+
child2.stderr.on("data", (chunk) => {
|
|
31934
31934
|
stderr += chunk.toString();
|
|
31935
31935
|
});
|
|
31936
|
-
|
|
31936
|
+
child2.on("error", (error) => {
|
|
31937
31937
|
clearTimeout(timeout);
|
|
31938
|
-
|
|
31938
|
+
resolve25({
|
|
31939
31939
|
attempt: 1,
|
|
31940
31940
|
status: "failed",
|
|
31941
31941
|
startedAt,
|
|
@@ -31945,10 +31945,10 @@ async function dispatchCommand(event, channel) {
|
|
|
31945
31945
|
error: error.message
|
|
31946
31946
|
});
|
|
31947
31947
|
});
|
|
31948
|
-
|
|
31948
|
+
child2.on("close", (code, signal) => {
|
|
31949
31949
|
clearTimeout(timeout);
|
|
31950
31950
|
const success = code === 0;
|
|
31951
|
-
|
|
31951
|
+
resolve25({
|
|
31952
31952
|
attempt: 1,
|
|
31953
31953
|
status: success ? "success" : "failed",
|
|
31954
31954
|
startedAt,
|
|
@@ -32373,7 +32373,7 @@ var init_event_sink = __esm(() => {
|
|
|
32373
32373
|
// package.json
|
|
32374
32374
|
var package_default = {
|
|
32375
32375
|
name: "@hasna/skills",
|
|
32376
|
-
version: "0.10.
|
|
32376
|
+
version: "0.10.52",
|
|
32377
32377
|
description: "Skills library for AI coding agents",
|
|
32378
32378
|
type: "module",
|
|
32379
32379
|
bin: {
|
|
@@ -34672,7 +34672,14 @@ async function inspectSkillBundle(bundle, options = {}) {
|
|
|
34672
34672
|
decoder.destroy(terminalError);
|
|
34673
34673
|
};
|
|
34674
34674
|
const onAbort = () => stop("BUNDLE_ABORTED");
|
|
34675
|
-
const
|
|
34675
|
+
const expire = () => {
|
|
34676
|
+
const remaining = deadline - performance.now();
|
|
34677
|
+
if (remaining > 0)
|
|
34678
|
+
timer = setTimeout(expire, Math.max(1, Math.ceil(remaining)));
|
|
34679
|
+
else
|
|
34680
|
+
stop("BUNDLE_TIMEOUT");
|
|
34681
|
+
};
|
|
34682
|
+
let timer = setTimeout(expire, Math.max(1, Math.ceil(deadline - performance.now())));
|
|
34676
34683
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
34677
34684
|
let decompressedByteSize = 0;
|
|
34678
34685
|
let bytesSinceYield = 0;
|
|
@@ -34916,8 +34923,8 @@ function profileSelectionSnapshot(selections) {
|
|
|
34916
34923
|
// src/lib/selection-cache.ts
|
|
34917
34924
|
class SkillSelectionError extends Error {
|
|
34918
34925
|
code;
|
|
34919
|
-
constructor(code, message) {
|
|
34920
|
-
super(message);
|
|
34926
|
+
constructor(code, message, options) {
|
|
34927
|
+
super(message, options);
|
|
34921
34928
|
this.code = code;
|
|
34922
34929
|
this.name = "SkillSelectionError";
|
|
34923
34930
|
}
|
|
@@ -35051,8 +35058,8 @@ function atomicWrite(path, bytes, mode, durable = false) {
|
|
|
35051
35058
|
}
|
|
35052
35059
|
}
|
|
35053
35060
|
}
|
|
35054
|
-
function readSelectionJson(path) {
|
|
35055
|
-
const bytes = readRegularFile(path, MAX_PROFILE_DOCUMENT_BYTES);
|
|
35061
|
+
function readSelectionJson(path, maximumBytes = MAX_PROFILE_DOCUMENT_BYTES) {
|
|
35062
|
+
const bytes = readRegularFile(path, Math.min(maximumBytes, MAX_PROFILE_DOCUMENT_BYTES));
|
|
35056
35063
|
if (!bytes)
|
|
35057
35064
|
return null;
|
|
35058
35065
|
try {
|
|
@@ -35064,10 +35071,10 @@ function readSelectionJson(path) {
|
|
|
35064
35071
|
async function verifiedEntries(selection, bytes, signal, deadline) {
|
|
35065
35072
|
if (`sha256:${sha256Hex(bytes)}` !== selection.bundleDigest)
|
|
35066
35073
|
throw new SkillSelectionError("BUNDLE_DIGEST_MISMATCH", "The skill bundle does not match its selected digest.");
|
|
35067
|
-
const remaining = deadline === undefined ? undefined : Math.
|
|
35074
|
+
const remaining = deadline === undefined ? undefined : Math.ceil(deadline - performance.now());
|
|
35068
35075
|
signal?.throwIfAborted();
|
|
35069
35076
|
if (remaining !== undefined && remaining <= 0)
|
|
35070
|
-
throw new
|
|
35077
|
+
throw new SkillBundleInspectionError("BUNDLE_TIMEOUT", "Bundle inspection deadline exceeded");
|
|
35071
35078
|
const bundle = await inspectSkillBundle(bytes, { signal, ...remaining === undefined ? {} : { limits: { timeoutMs: remaining } } });
|
|
35072
35079
|
return bundle.entries;
|
|
35073
35080
|
}
|
|
@@ -37311,6 +37318,10 @@ function identifier2(value) {
|
|
|
37311
37318
|
function invalid2() {
|
|
37312
37319
|
throw new Error("The Skills API returned an invalid profile response");
|
|
37313
37320
|
}
|
|
37321
|
+
function unavailable(error, message) {
|
|
37322
|
+
const name = error?.name;
|
|
37323
|
+
return new SkillSelectionError("SKILLS_API_UNAVAILABLE", message, name === "AbortError" || name === "TimeoutError" ? { cause: new DOMException("The Skills API request was cut short", name) } : undefined);
|
|
37324
|
+
}
|
|
37314
37325
|
function validateSelection2(value) {
|
|
37315
37326
|
if (!object(value) || !identifier2(value.slug) || typeof value.version !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/.test(value.version) || value.version.includes("..") || typeof value.bundleDigest !== "string" || !/^sha256:[a-f0-9]{64}$/.test(value.bundleDigest))
|
|
37316
37327
|
invalid2();
|
|
@@ -37358,8 +37369,8 @@ class HttpProfileClient {
|
|
|
37358
37369
|
...init.headers
|
|
37359
37370
|
}
|
|
37360
37371
|
});
|
|
37361
|
-
} catch {
|
|
37362
|
-
throw
|
|
37372
|
+
} catch (error) {
|
|
37373
|
+
throw unavailable(error, "Unable to reach the configured Skills API");
|
|
37363
37374
|
}
|
|
37364
37375
|
if (!response.ok) {
|
|
37365
37376
|
response.body?.cancel().catch(() => {});
|
|
@@ -37376,7 +37387,9 @@ class HttpProfileClient {
|
|
|
37376
37387
|
async read(response, limit = MAX_PROFILE_DOCUMENT_BYTES) {
|
|
37377
37388
|
try {
|
|
37378
37389
|
return JSON.parse(new TextDecoder().decode(await readBoundedResponse(response, limit, this.signal)));
|
|
37379
|
-
} catch {
|
|
37390
|
+
} catch (error) {
|
|
37391
|
+
if (this.signal?.aborted)
|
|
37392
|
+
throw unavailable(this.signal.reason ?? error, "The Skills API response was cut short");
|
|
37380
37393
|
invalid2();
|
|
37381
37394
|
}
|
|
37382
37395
|
}
|
|
@@ -37493,6 +37506,8 @@ function inspectSkillSession(sessionId, options = {}) {
|
|
|
37493
37506
|
loadedCount: receipt.loaded.length
|
|
37494
37507
|
};
|
|
37495
37508
|
}
|
|
37509
|
+
var SESSION_RENEWAL_REFUSAL_TTL_MS = 5 * 60 * 1000;
|
|
37510
|
+
var SESSION_RENEWAL_REFUSAL_MAX_BYTES = 4 * 1024;
|
|
37496
37511
|
async function reconcileSkillSession(input, options = {}) {
|
|
37497
37512
|
if (![input.fromProfile, input.fromRevision, input.selectionProfile, input.profileRevision].every((value) => typeof value === "string" && value.trim()) || !/^[a-f0-9]{64}$/.test(input.receiptSha256)) {
|
|
37498
37513
|
throw new SkillSelectionError("INVALID_SESSION_RECONCILIATION", "Name the exact old receipt SHA256, old profile/revision and intended target profile/revision.");
|
|
@@ -37554,10 +37569,10 @@ async function reconcileSkillSession(input, options = {}) {
|
|
|
37554
37569
|
return { applied: true, plan, planDigest, ...result };
|
|
37555
37570
|
}
|
|
37556
37571
|
// src/lib/selected-run.ts
|
|
37557
|
-
import { createHash as
|
|
37572
|
+
import { createHash as createHash27 } from "crypto";
|
|
37558
37573
|
import { spawn as spawn2 } from "child_process";
|
|
37559
37574
|
import { mkdirSync as mkdirSync11, mkdtempSync as mkdtempSync3, writeFileSync as writeFileSync10, realpathSync as realpathSync15 } from "fs";
|
|
37560
|
-
import { dirname as
|
|
37575
|
+
import { dirname as dirname23, join as join37, resolve as resolve23 } from "path";
|
|
37561
37576
|
import { tmpdir, hostname as stationHostname2 } from "os";
|
|
37562
37577
|
|
|
37563
37578
|
// src/lib/dependency-preparation.ts
|
|
@@ -37952,7 +37967,7 @@ import {
|
|
|
37952
37967
|
writeFileSync as writeFileSync8
|
|
37953
37968
|
} from "fs";
|
|
37954
37969
|
import { homedir as homedir5 } from "os";
|
|
37955
|
-
import { basename as
|
|
37970
|
+
import { basename as basename13, dirname as dirname22, join as join32 } from "path";
|
|
37956
37971
|
|
|
37957
37972
|
// src/lib/sumi-settings-witness.ts
|
|
37958
37973
|
import { createHash as createHash7 } from "crypto";
|
|
@@ -38089,6 +38104,10 @@ function parse2(text) {
|
|
|
38089
38104
|
need(root.entries.length <= CLAUDE_SETTINGS_WITNESS_LIMITS.rows, "exceeds its settings field limit");
|
|
38090
38105
|
return root;
|
|
38091
38106
|
}
|
|
38107
|
+
function parseNativeJsonObject(text) {
|
|
38108
|
+
need(typeof text === "string" && Buffer.byteLength(text) <= CLAUDE_SETTINGS_WITNESS_LIMITS.bytes, "exceeds its byte limit");
|
|
38109
|
+
return parse2(text);
|
|
38110
|
+
}
|
|
38092
38111
|
var BOOLEAN_PREFERENCES = new Set([
|
|
38093
38112
|
"autoScrollEnabled",
|
|
38094
38113
|
"axScreenReader",
|
|
@@ -40278,10 +40297,10 @@ var NATIVE_SKILL_ROOTS = [
|
|
|
40278
40297
|
];
|
|
40279
40298
|
|
|
40280
40299
|
// src/lib/agent-integration.ts
|
|
40281
|
-
import { createHash as
|
|
40300
|
+
import { createHash as createHash25, randomUUID as randomUUID4 } from "crypto";
|
|
40282
40301
|
import { isDeepStrictEqual as isDeepStrictEqual8 } from "util";
|
|
40283
|
-
import { existsSync as existsSync7, lstatSync as lstatSync23, statSync as statSync7, mkdirSync as mkdirSync6, readFileSync as readFileSync17, readdirSync as readdirSync8, opendirSync as opendirSync5, readlinkSync as
|
|
40284
|
-
import { dirname as
|
|
40302
|
+
import { existsSync as existsSync7, lstatSync as lstatSync23, statSync as statSync7, mkdirSync as mkdirSync6, readFileSync as readFileSync17, readdirSync as readdirSync8, opendirSync as opendirSync5, readlinkSync as readlinkSync7, realpathSync as realpathSync11, renameSync as renameSync4, rmdirSync as rmdirSync3, writeFileSync as writeFileSync5, unlinkSync as unlinkSync5, chmodSync, openSync as openSync18, closeSync as closeSync18, fsyncSync as fsyncSync6, fstatSync as fstatSync18, readSync as readSync12, constants as constants15, linkSync as linkSync3 } from "fs";
|
|
40303
|
+
import { dirname as dirname18, join as join27, resolve as resolve20, relative as relative5, isAbsolute as isAbsolute22, sep as sep7 } from "path";
|
|
40285
40304
|
import { homedir as homedir3 } from "os";
|
|
40286
40305
|
|
|
40287
40306
|
// src/lib/managed-policy.ts
|
|
@@ -40289,7 +40308,202 @@ import { closeSync as closeSync11, constants as constants8, fstatSync as fstatSy
|
|
|
40289
40308
|
import { join as join15 } from "path";
|
|
40290
40309
|
|
|
40291
40310
|
// src/lib/agent-policy-limits.ts
|
|
40292
|
-
import { basename as
|
|
40311
|
+
import { basename as basename6, isAbsolute as isAbsolute9, join as join14, resolve as resolve8, sep as sep4 } from "path";
|
|
40312
|
+
|
|
40313
|
+
// src/lib/claude-marketplace-entry-witness.ts
|
|
40314
|
+
import { createHash as createHash12 } from "crypto";
|
|
40315
|
+
import { basename as basename5, dirname as dirname8, isAbsolute as isAbsolute8, resolve as resolve7 } from "path";
|
|
40316
|
+
var CLAUDE_MARKETPLACE_ENTRY_HASH_MODE = "claude-marketplace-entry-v1";
|
|
40317
|
+
var DOMAIN = "hasna.skills.claude-marketplace-entry.v1\x00";
|
|
40318
|
+
var PATH_CHARACTERS = 4096;
|
|
40319
|
+
var NAME = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
40320
|
+
function need4(value, reason) {
|
|
40321
|
+
if (!value)
|
|
40322
|
+
throw new Error(`Claude marketplace entry witness ${reason}`);
|
|
40323
|
+
}
|
|
40324
|
+
var bounded = (key) => key.length > 64 ? `${key.slice(0, 64)}...` : key;
|
|
40325
|
+
var quote = (text) => JSON.stringify(text).replace(/[^\x20-\x7e]/g, (character) => `\\u${character.charCodeAt(0).toString(16).padStart(4, "0")}`);
|
|
40326
|
+
var child = (path, key) => path + (/^[A-Za-z0-9_$-]{1,64}$/.test(key) ? `.${key}` : `[${JSON.stringify(bounded(key))}]`);
|
|
40327
|
+
function unknownKey(selector, path, key) {
|
|
40328
|
+
throw new Error(path === null ? `${CLAUDE_MARKETPLACE_ENTRY_HASH_MODE}: unknown top-level key ${quote(bounded(key))} in ${selector.marketplace}` : `${CLAUDE_MARKETPLACE_ENTRY_HASH_MODE}: unknown key ${quote(child(path, key))} in ${selector.marketplace}`);
|
|
40329
|
+
}
|
|
40330
|
+
function knownKeys(object4, allowed, selector, path) {
|
|
40331
|
+
for (const [key] of object4.entries)
|
|
40332
|
+
if (!allowed.has(key))
|
|
40333
|
+
unknownKey(selector, path, key);
|
|
40334
|
+
}
|
|
40335
|
+
var reason = (error) => String(error?.message ?? error).replace(/^Claude settings witness /, "");
|
|
40336
|
+
var MARKETPLACE_KEYS = new Set(["$schema", "name", "owner", "plugins", "description", "version", "metadata", "forceRemoveDeletedPlugins", "allowCrossMarketplaceDependenciesOn", "renames"]);
|
|
40337
|
+
var MARKETPLACE_METADATA_KEYS = new Set(["description", "version", "pluginRoot"]);
|
|
40338
|
+
var ENTRY_BOUND_KEYS = new Set([
|
|
40339
|
+
"name",
|
|
40340
|
+
"source",
|
|
40341
|
+
"strict",
|
|
40342
|
+
"defaultEnabled",
|
|
40343
|
+
"dependencies",
|
|
40344
|
+
"relevance",
|
|
40345
|
+
"headers",
|
|
40346
|
+
"headersHelper",
|
|
40347
|
+
"settings",
|
|
40348
|
+
"userConfig",
|
|
40349
|
+
"types",
|
|
40350
|
+
"channels",
|
|
40351
|
+
"skills",
|
|
40352
|
+
"commands",
|
|
40353
|
+
"agents",
|
|
40354
|
+
"hooks",
|
|
40355
|
+
"mcpServers",
|
|
40356
|
+
"lspServers",
|
|
40357
|
+
"outputStyles",
|
|
40358
|
+
"workflows",
|
|
40359
|
+
"experimental",
|
|
40360
|
+
"themes",
|
|
40361
|
+
"monitors"
|
|
40362
|
+
]);
|
|
40363
|
+
var ENTRY_OMITTED_KEYS = new Set(["$schema", "description", "version", "author", "homepage", "repository", "license", "keywords", "category", "tags", "displayName", "metadata"]);
|
|
40364
|
+
var EXPERIMENTAL_KEYS = new Set(["themes", "monitors", "evals"]);
|
|
40365
|
+
var SOURCE_KEYS = Object.freeze({
|
|
40366
|
+
github: ["source", "repo", "ref", "sha"],
|
|
40367
|
+
url: ["source", "url", "ref", "sha", "path"],
|
|
40368
|
+
"git-subdir": ["source", "url", "path", "ref", "sha"],
|
|
40369
|
+
npm: ["source", "package", "version", "registry"],
|
|
40370
|
+
archive: ["source", "url", "sha256"],
|
|
40371
|
+
command: ["source", "command", "timeout", "mode"]
|
|
40372
|
+
});
|
|
40373
|
+
var field = (object4, key) => object4.entries.find(([name]) => name === key)?.[1];
|
|
40374
|
+
var isString = (value) => value?.kind === "string";
|
|
40375
|
+
var isBoolean = (value) => value?.kind === "literal" && (value.value === "true" || value.value === "false");
|
|
40376
|
+
var stringArray = (value) => value?.kind === "array" && value.items.every(isString);
|
|
40377
|
+
var stringObject = (value) => value?.kind === "object" && value.entries.every(([, item]) => isString(item));
|
|
40378
|
+
function claudeMarketplaceEntrySourceValid(source) {
|
|
40379
|
+
const path = source?.path;
|
|
40380
|
+
return typeof path === "string" && path.length > 0 && path.length <= PATH_CHARACTERS && !/[\x00-\x1f\x7f]/.test(path) && isAbsolute8(path) && resolve7(path) === path && basename5(path) === "marketplace.json" && basename5(dirname8(path)) === ".claude-plugin" && typeof source.marketplace === "string" && NAME.test(source.marketplace) && !source.marketplace.includes("..") && typeof source.plugin === "string" && NAME.test(source.plugin);
|
|
40381
|
+
}
|
|
40382
|
+
function canonical4(value) {
|
|
40383
|
+
if (value.kind === "string")
|
|
40384
|
+
return JSON.stringify(value.value);
|
|
40385
|
+
if (value.kind === "number" || value.kind === "literal")
|
|
40386
|
+
return value.value;
|
|
40387
|
+
if (value.kind === "array")
|
|
40388
|
+
return "[" + value.items.map(canonical4).join(",") + "]";
|
|
40389
|
+
return "{" + [...value.entries].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, item]) => JSON.stringify(key) + ":" + canonical4(item)).join(",") + "}";
|
|
40390
|
+
}
|
|
40391
|
+
function validateMarketplace(root, selector) {
|
|
40392
|
+
knownKeys(root, MARKETPLACE_KEYS, selector, null);
|
|
40393
|
+
const name = field(root, "name");
|
|
40394
|
+
need4(isString(name) && name.value === selector.marketplace, "marketplace name does not match the reviewed binding");
|
|
40395
|
+
for (const key of ["$schema", "description", "version"]) {
|
|
40396
|
+
const value = field(root, key);
|
|
40397
|
+
need4(value === undefined || isString(value), `has an invalid marketplace ${key}`);
|
|
40398
|
+
}
|
|
40399
|
+
const owner = field(root, "owner");
|
|
40400
|
+
need4(owner === undefined || owner.kind === "object", "has an invalid marketplace owner");
|
|
40401
|
+
const metadata = field(root, "metadata");
|
|
40402
|
+
if (metadata !== undefined) {
|
|
40403
|
+
need4(metadata.kind === "object", "has an invalid marketplace metadata object");
|
|
40404
|
+
knownKeys(metadata, MARKETPLACE_METADATA_KEYS, selector, "metadata");
|
|
40405
|
+
for (const [key, value] of metadata.entries)
|
|
40406
|
+
need4(isString(value), `has an invalid marketplace metadata.${key}`);
|
|
40407
|
+
}
|
|
40408
|
+
const remove = field(root, "forceRemoveDeletedPlugins");
|
|
40409
|
+
need4(remove === undefined || isBoolean(remove), "has an invalid forceRemoveDeletedPlugins value");
|
|
40410
|
+
const cross = field(root, "allowCrossMarketplaceDependenciesOn");
|
|
40411
|
+
need4(cross === undefined || stringArray(cross), "has an invalid allowCrossMarketplaceDependenciesOn value");
|
|
40412
|
+
const renames = field(root, "renames");
|
|
40413
|
+
if (renames !== undefined) {
|
|
40414
|
+
need4(renames.kind === "object" && renames.entries.every(([, target]) => isString(target) || target.kind === "literal" && target.value === "null"), "has an invalid renames map");
|
|
40415
|
+
need4(!renames.entries.some(([from]) => from.toLowerCase() === selector.plugin.toLowerCase()), "plugin id is redirected by the marketplace renames map");
|
|
40416
|
+
}
|
|
40417
|
+
}
|
|
40418
|
+
function validateSource(source, selector, path) {
|
|
40419
|
+
if (isString(source)) {
|
|
40420
|
+
need4(source.value.length > 0, "has an empty plugin source");
|
|
40421
|
+
return;
|
|
40422
|
+
}
|
|
40423
|
+
need4(source?.kind === "object", "has an invalid plugin source");
|
|
40424
|
+
const type = field(source, "source");
|
|
40425
|
+
need4(isString(type) && Object.hasOwn(SOURCE_KEYS, type.value), "has an unreviewed plugin source type");
|
|
40426
|
+
knownKeys(source, new Set(SOURCE_KEYS[type.value]), selector, path);
|
|
40427
|
+
}
|
|
40428
|
+
function projectEntry(entry, selector) {
|
|
40429
|
+
const path = `plugins[${selector.plugin}]`;
|
|
40430
|
+
knownKeys(entry, { has: (key) => ENTRY_BOUND_KEYS.has(key) || ENTRY_OMITTED_KEYS.has(key) }, selector, path);
|
|
40431
|
+
const name = field(entry, "name");
|
|
40432
|
+
need4(isString(name) && name.value === selector.plugin, "selected entry name does not match");
|
|
40433
|
+
validateSource(field(entry, "source"), selector, `${path}.source`);
|
|
40434
|
+
for (const key of ["strict", "defaultEnabled"]) {
|
|
40435
|
+
const value = field(entry, key);
|
|
40436
|
+
need4(value === undefined || isBoolean(value), `has an invalid entry ${key}`);
|
|
40437
|
+
}
|
|
40438
|
+
const headersHelper = field(entry, "headersHelper");
|
|
40439
|
+
need4(headersHelper === undefined || isString(headersHelper), "has an invalid entry headersHelper");
|
|
40440
|
+
const experimental = field(entry, "experimental");
|
|
40441
|
+
if (experimental !== undefined) {
|
|
40442
|
+
need4(experimental.kind === "object", "has an invalid entry experimental object");
|
|
40443
|
+
knownKeys(experimental, EXPERIMENTAL_KEYS, selector, `${path}.experimental`);
|
|
40444
|
+
}
|
|
40445
|
+
for (const key of ["$schema", "description", "version", "homepage", "license", "category", "displayName"]) {
|
|
40446
|
+
const value = field(entry, key);
|
|
40447
|
+
need4(value === undefined || isString(value), `has an invalid entry ${key}`);
|
|
40448
|
+
}
|
|
40449
|
+
for (const [key, keys2] of [["author", new Set(["name", "email", "url"])], ["repository", new Set(["type", "url", "directory"])]]) {
|
|
40450
|
+
const value = field(entry, key);
|
|
40451
|
+
if (value?.kind === "object")
|
|
40452
|
+
knownKeys(value, keys2, selector, `${path}.${key}`);
|
|
40453
|
+
need4(value === undefined || isString(value) || stringObject(value), `has an invalid entry ${key}`);
|
|
40454
|
+
}
|
|
40455
|
+
for (const key of ["keywords", "tags"]) {
|
|
40456
|
+
const value = field(entry, key);
|
|
40457
|
+
need4(value === undefined || stringArray(value), `has an invalid entry ${key}`);
|
|
40458
|
+
}
|
|
40459
|
+
const metadata = field(entry, "metadata");
|
|
40460
|
+
need4(metadata === undefined || metadata.kind === "object", "has an invalid entry metadata object");
|
|
40461
|
+
return { kind: "object", entries: entry.entries.filter(([key]) => ENTRY_BOUND_KEYS.has(key)) };
|
|
40462
|
+
}
|
|
40463
|
+
function hashClaudeMarketplaceEntry(text, selector) {
|
|
40464
|
+
need4(selector && typeof selector.marketplace === "string" && NAME.test(selector.marketplace) && !selector.marketplace.includes("..") && typeof selector.plugin === "string" && NAME.test(selector.plugin), "requires an exact marketplace and plugin name");
|
|
40465
|
+
let root;
|
|
40466
|
+
try {
|
|
40467
|
+
root = parseNativeJsonObject(text);
|
|
40468
|
+
} catch (error) {
|
|
40469
|
+
throw new Error(`Claude marketplace entry witness cannot parse marketplace.json: ${reason(error)}`);
|
|
40470
|
+
}
|
|
40471
|
+
validateMarketplace(root, selector);
|
|
40472
|
+
const plugins = field(root, "plugins");
|
|
40473
|
+
need4(plugins?.kind === "array", "requires a plugins array");
|
|
40474
|
+
const entryName = (item) => {
|
|
40475
|
+
if (item.kind !== "object")
|
|
40476
|
+
return;
|
|
40477
|
+
const name = field(item, "name");
|
|
40478
|
+
return isString(name) ? name.value : undefined;
|
|
40479
|
+
};
|
|
40480
|
+
const exact = plugins.items.filter((item) => entryName(item) === selector.plugin);
|
|
40481
|
+
const folded = plugins.items.filter((item) => entryName(item)?.toLowerCase() === selector.plugin.toLowerCase());
|
|
40482
|
+
need4(exact.length > 0, "selected plugin entry is missing");
|
|
40483
|
+
need4(exact.length === 1 && folded.length === 1, "selected plugin entry is duplicated or ambiguous");
|
|
40484
|
+
const entry = projectEntry(exact[0], selector);
|
|
40485
|
+
const metadata = field(root, "metadata"), pluginRoot = metadata?.kind === "object" ? field(metadata, "pluginRoot") : undefined;
|
|
40486
|
+
const nullValue = { kind: "literal", value: "null" };
|
|
40487
|
+
const marketplace = { kind: "object", entries: [
|
|
40488
|
+
["name", field(root, "name")],
|
|
40489
|
+
["pluginRoot", pluginRoot ?? nullValue],
|
|
40490
|
+
["allowCrossMarketplaceDependenciesOn", field(root, "allowCrossMarketplaceDependenciesOn") ?? nullValue]
|
|
40491
|
+
] };
|
|
40492
|
+
const projection = { kind: "object", entries: [["marketplace", marketplace], ["plugin", entry]] };
|
|
40493
|
+
return createHash12("sha256").update(DOMAIN).update(canonical4(projection)).digest("hex");
|
|
40494
|
+
}
|
|
40495
|
+
function captureClaudeMarketplaceEntry(path, marketplace, plugin, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
40496
|
+
need4(claudeMarketplaceEntrySourceValid({ path, marketplace, plugin }), "requires a normalized absolute .claude-plugin/marketplace.json path and exact names");
|
|
40497
|
+
let text;
|
|
40498
|
+
try {
|
|
40499
|
+
text = readNativeSettingsWitnessFile(path, budget2, "marketplace.json");
|
|
40500
|
+
} catch (error) {
|
|
40501
|
+
throw new Error(`Claude marketplace entry witness cannot read marketplace.json: ${reason(error)}`);
|
|
40502
|
+
}
|
|
40503
|
+
return { path, hashMode: CLAUDE_MARKETPLACE_ENTRY_HASH_MODE, marketplace, plugin, sha256: hashClaudeMarketplaceEntry(text, { marketplace, plugin }) };
|
|
40504
|
+
}
|
|
40505
|
+
|
|
40506
|
+
// src/lib/agent-policy-limits.ts
|
|
40293
40507
|
var AGENT_POLICY_LIMITS = Object.freeze({ bytes: 1024 * 1024, agents: 16, discoverySources: 2048, discoveryRawSourceBytes: 64 * 1024 * 1024, discoveryRawTotalBytes: 256 * 1024 * 1024, discoveryPathLinks: 40, discoveryPathSteps: 256, discoveryPathSourceMetadataBytes: 64 * 1024, discoveryPathTotalMetadataBytes: 8 * 1024 * 1024, discoveryRoots: 512, discoveryDirectories: 64, discoveryDirectoryEntries: 20000, discoveryDirectoryBytes: 8 * 1024 * 1024, builtinNames: 2048, rootAliases: 2, fields: 64, pathCharacters: 4096 });
|
|
40294
40508
|
function object4(value) {
|
|
40295
40509
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
@@ -40343,7 +40557,7 @@ function assertAgentPolicyCollections(policy) {
|
|
|
40343
40557
|
text(control.pluginId, 1024);
|
|
40344
40558
|
text(control.namespace, 64);
|
|
40345
40559
|
text(control.pluginParent);
|
|
40346
|
-
requireBound(
|
|
40560
|
+
requireBound(isAbsolute9(control.pluginParent) && resolve8(control.pluginParent) === control.pluginParent && /^[a-f0-9]{64}$/.test(control.manifestSha256));
|
|
40347
40561
|
if (control.remotePluginId !== undefined)
|
|
40348
40562
|
requireBound(typeof control.remotePluginId === "string" && /^[A-Za-z0-9_~-]{1,1024}$/.test(control.remotePluginId));
|
|
40349
40563
|
if (control.skillsOnly !== undefined)
|
|
@@ -40361,10 +40575,18 @@ function assertAgentPolicyCollections(policy) {
|
|
|
40361
40575
|
text(control.pluginId, 1024);
|
|
40362
40576
|
text(control.namespace, 64);
|
|
40363
40577
|
text(control.pluginParent);
|
|
40364
|
-
requireBound(!ids.has(control.pluginId) &&
|
|
40578
|
+
requireBound(!ids.has(control.pluginId) && isAbsolute9(control.pluginParent) && resolve8(control.pluginParent) === control.pluginParent && ["local", "git", "npm"].includes(control.sourceType) && typeof control.sourceSha256 === "string" && /^[a-f0-9]{64}$/.test(control.sourceSha256));
|
|
40365
40579
|
ids.add(control.pluginId);
|
|
40366
40580
|
}
|
|
40367
40581
|
}
|
|
40582
|
+
if (bridge.discoveryExecutables !== undefined)
|
|
40583
|
+
for (const [agent, executable2] of Object.entries(record3(bridge.discoveryExecutables, AGENT_POLICY_LIMITS.agents))) {
|
|
40584
|
+
requireBound(agent === "gemini" && object4(executable2) && Object.keys(executable2).length === 3 && executable2.command === "gemini");
|
|
40585
|
+
for (const path of [executable2.path, executable2.target]) {
|
|
40586
|
+
text(path);
|
|
40587
|
+
requireBound(!/[\x00-\x1f\x7f-\x9f\u200e\u200f\u202a-\u202e\u2066-\u2069]/.test(path) && isAbsolute9(path) && resolve8(path) === path);
|
|
40588
|
+
}
|
|
40589
|
+
}
|
|
40368
40590
|
if (bridge.disabledBuiltins !== undefined)
|
|
40369
40591
|
for (const builtin of array(bridge.disabledBuiltins, AGENT_POLICY_LIMITS.builtinNames)) {
|
|
40370
40592
|
requireBound(object4(builtin));
|
|
@@ -40390,11 +40612,11 @@ function assertAgentPolicyCollections(policy) {
|
|
|
40390
40612
|
requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && Object.keys(proof).every((key) => ["roots", "parents", "directories"].includes(key)) && roots.length + parents2.length > 0 && new Set(roots).size === roots.length && new Set(parents2).size === parents2.length);
|
|
40391
40613
|
for (const root of roots) {
|
|
40392
40614
|
text(root);
|
|
40393
|
-
requireBound(
|
|
40615
|
+
requireBound(isAbsolute9(root) && resolve8(root) === root);
|
|
40394
40616
|
}
|
|
40395
40617
|
for (const parent of parents2) {
|
|
40396
40618
|
text(parent);
|
|
40397
|
-
requireBound(
|
|
40619
|
+
requireBound(isAbsolute9(parent) && resolve8(parent) === parent);
|
|
40398
40620
|
}
|
|
40399
40621
|
for (const directory of array(proof.directories, AGENT_POLICY_LIMITS.discoveryDirectories)) {
|
|
40400
40622
|
requireBound(object4(directory));
|
|
@@ -40414,7 +40636,7 @@ function assertAgentPolicyCollections(policy) {
|
|
|
40414
40636
|
text(input.namespace, 64);
|
|
40415
40637
|
text(input.pluginParent);
|
|
40416
40638
|
text(input.sourceRoot);
|
|
40417
|
-
requireBound(!ids.has(input.pluginId) && [input.pluginParent, input.sourceRoot].every((path) =>
|
|
40639
|
+
requireBound(!ids.has(input.pluginId) && [input.pluginParent, input.sourceRoot].every((path) => isAbsolute9(path) && resolve8(path) === path) && typeof input.sourceSha256 === "string" && /^[a-f0-9]{64}$/.test(input.sourceSha256));
|
|
40418
40640
|
ids.add(input.pluginId);
|
|
40419
40641
|
}
|
|
40420
40642
|
if (proof.directories !== undefined)
|
|
@@ -40431,17 +40653,19 @@ function assertAgentPolicyCollections(policy) {
|
|
|
40431
40653
|
text(source.path);
|
|
40432
40654
|
requireBound(source.sha256 === null || typeof source.sha256 === "string" && /^[a-f0-9]{64}$/.test(source.sha256));
|
|
40433
40655
|
if (source.hashMode !== undefined)
|
|
40434
|
-
requireBound(["bytes", "path-bytes", "claude-plugin-manifest-v1", "claude-plugin-registry", "claude-marketplace-registry", "claude-settings-v1", "claude-settings-v2", "claude-settings-v3", "claude-settings-v4", "claude-marketplace-registry-v2", "codex-settings-v1", "codex-settings-v2", "codex-settings-v3", "codex-settings-v4", "sumi-settings-v1"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
|
|
40656
|
+
requireBound(["bytes", "path-bytes", "claude-plugin-manifest-v1", "claude-plugin-registry", "claude-marketplace-registry", "claude-settings-v1", "claude-settings-v2", "claude-settings-v3", "claude-settings-v4", "claude-marketplace-registry-v2", "codex-settings-v1", "codex-settings-v2", "codex-settings-v3", "codex-settings-v4", "sumi-settings-v1", "claude-marketplace-entry-v1"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
|
|
40435
40657
|
if (source.hashMode === "claude-plugin-manifest-v1")
|
|
40436
|
-
requireBound(agent === "claude" && value.agent === "claude" && ["automatic", "reviewed"].includes(value.method) && !/[\x00-\x1f\x7f]/.test(source.path) &&
|
|
40658
|
+
requireBound(agent === "claude" && value.agent === "claude" && ["automatic", "reviewed"].includes(value.method) && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute9(source.path) && resolve8(source.path) === source.path && source.path.endsWith(join14(sep4, ".claude-plugin", "plugin.json")) && source.managedPlugins === undefined);
|
|
40437
40659
|
if (source.hashMode === "sumi-settings-v1")
|
|
40438
|
-
requireBound(agent === "sumi" && value.agent === "sumi" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) &&
|
|
40660
|
+
requireBound(agent === "sumi" && value.agent === "sumi" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute9(source.path) && resolve8(source.path) === source.path && basename6(source.path) === "sumi.json");
|
|
40439
40661
|
if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4"))
|
|
40440
|
-
requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) &&
|
|
40662
|
+
requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute9(source.path) && resolve8(source.path) === source.path && basename6(source.path) === "config.toml");
|
|
40441
40663
|
if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4"))
|
|
40442
|
-
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) &&
|
|
40664
|
+
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute9(source.path) && resolve8(source.path) === source.path && basename6(source.path) === "settings.json");
|
|
40443
40665
|
if (source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2")
|
|
40444
|
-
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) &&
|
|
40666
|
+
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute9(source.path) && resolve8(source.path) === source.path && basename6(source.path) === "known_marketplaces.json");
|
|
40667
|
+
if (source.hashMode === "claude-marketplace-entry-v1")
|
|
40668
|
+
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && claudeMarketplaceEntrySourceValid(source));
|
|
40445
40669
|
if (source.hashMode === "claude-plugin-registry") {
|
|
40446
40670
|
requireBound(agent === "claude");
|
|
40447
40671
|
const managed = array(source.managedPlugins, 64);
|
|
@@ -40456,8 +40680,8 @@ function assertAgentPolicyCollections(policy) {
|
|
|
40456
40680
|
if (source.format !== undefined)
|
|
40457
40681
|
requireBound(["json", "toml", "yaml"].includes(source.format));
|
|
40458
40682
|
if (source.fields !== undefined)
|
|
40459
|
-
for (const
|
|
40460
|
-
text(
|
|
40683
|
+
for (const field2 of array(source.fields, AGENT_POLICY_LIMITS.fields))
|
|
40684
|
+
text(field2, 256);
|
|
40461
40685
|
}
|
|
40462
40686
|
if (value.directories !== undefined)
|
|
40463
40687
|
for (const directory of array(value.directories, AGENT_POLICY_LIMITS.discoveryDirectories)) {
|
|
@@ -40472,8 +40696,8 @@ function assertAgentPolicyCollections(policy) {
|
|
|
40472
40696
|
}
|
|
40473
40697
|
|
|
40474
40698
|
// src/lib/managed-policy.ts
|
|
40475
|
-
function refusal(
|
|
40476
|
-
return new SkillSelectionError("INVALID_AGENT_POLICY", `The Skills agent loading policy ${
|
|
40699
|
+
function refusal(reason2 = "is unreadable") {
|
|
40700
|
+
return new SkillSelectionError("INVALID_AGENT_POLICY", `The Skills agent loading policy ${reason2}; refusing legacy fallback.`);
|
|
40477
40701
|
}
|
|
40478
40702
|
function parseManagedSkillPolicy(text2) {
|
|
40479
40703
|
if (Buffer.byteLength(text2) > AGENT_POLICY_LIMITS.bytes)
|
|
@@ -40550,7 +40774,7 @@ function requiresCliSkillLoading(dataDir2 = getDataDirReadOnly()) {
|
|
|
40550
40774
|
}
|
|
40551
40775
|
|
|
40552
40776
|
// src/lib/agent-bridge.ts
|
|
40553
|
-
import { createHash as
|
|
40777
|
+
import { createHash as createHash13 } from "crypto";
|
|
40554
40778
|
import { lstatSync as lstatSync10, readFileSync as readFileSync11, readdirSync as readdirSync4 } from "fs";
|
|
40555
40779
|
import { join as join16 } from "path";
|
|
40556
40780
|
var CLI_BRIDGE_NAME = "skills-cli";
|
|
@@ -40569,7 +40793,7 @@ Use the Skills CLI as the skill authority for this station.
|
|
|
40569
40793
|
|
|
40570
40794
|
This bridge contains no skill payloads. Do not copy skill content into agent-native skill directories or load other native skill copies. If a Skills command refuses authority, selection, integrity, or native drift, report that refusal and use its repair guidance; do not substitute bundled or stale local content. Explicit local draft authoring remains available.
|
|
40571
40795
|
`;
|
|
40572
|
-
var CLI_BRIDGE_DIGEST =
|
|
40796
|
+
var CLI_BRIDGE_DIGEST = createHash13("sha256").update(markdown).digest("hex");
|
|
40573
40797
|
var CLI_BRIDGE_FILES = Object.freeze({
|
|
40574
40798
|
"SKILL.md": markdown,
|
|
40575
40799
|
".hasna-skills.json": `${JSON.stringify({ managedBy: "@hasna/skills", kind: "cli-bridge", version: CLI_BRIDGE_VERSION, protocol: "selection-v1", contentSha256: CLI_BRIDGE_DIGEST }, null, 2)}
|
|
@@ -40593,9 +40817,9 @@ function isOwnedCliBridge(path, expectedPaths) {
|
|
|
40593
40817
|
}
|
|
40594
40818
|
|
|
40595
40819
|
// src/lib/agent-discovery.ts
|
|
40596
|
-
import { createHash as
|
|
40820
|
+
import { createHash as createHash23 } from "crypto";
|
|
40597
40821
|
import { lstatSync as lstatSync21, readFileSync as readFileSync15, readdirSync as readdirSync7, realpathSync as realpathSync9 } from "fs";
|
|
40598
|
-
import { basename as
|
|
40822
|
+
import { basename as basename9, dirname as dirname17, isAbsolute as isAbsolute20, join as join26, resolve as resolve19, sep as sep6 } from "path";
|
|
40599
40823
|
import { isDeepStrictEqual as isDeepStrictEqual6 } from "util";
|
|
40600
40824
|
|
|
40601
40825
|
// node_modules/yaml/dist/index.js
|
|
@@ -40645,7 +40869,7 @@ var $visit = visit.visit;
|
|
|
40645
40869
|
var $visitAsync = visit.visitAsync;
|
|
40646
40870
|
|
|
40647
40871
|
// src/lib/agent-hermes.ts
|
|
40648
|
-
import { dirname as
|
|
40872
|
+
import { dirname as dirname9, isAbsolute as isAbsolute10, join as join17, resolve as resolve9 } from "path";
|
|
40649
40873
|
import { lstatSync as lstatSync11, readFileSync as readFileSync12, opendirSync } from "fs";
|
|
40650
40874
|
var HERMES_OPT_OUT = ".no-bundled-skills";
|
|
40651
40875
|
var EVENTS = ["pre_llm_call", "pre_tool_call"];
|
|
@@ -40683,7 +40907,7 @@ function quoted(value) {
|
|
|
40683
40907
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
40684
40908
|
}
|
|
40685
40909
|
function hermesHookDefinitions(supervisor) {
|
|
40686
|
-
if (!
|
|
40910
|
+
if (!isAbsolute10(supervisor.runtime) || !isAbsolute10(supervisor.path))
|
|
40687
40911
|
throw new Error("Expected absolute Hermes supervisor paths");
|
|
40688
40912
|
const entry = (event) => ({ command: `${quoted(supervisor.runtime)} ${quoted(supervisor.path)} --event ${event}`, timeout: 15, ...event === "pre_tool_call" ? { fail_closed: true } : {} });
|
|
40689
40913
|
return { pre_llm_call: entry("pre_llm_call"), pre_tool_call: entry("pre_tool_call") };
|
|
@@ -40719,16 +40943,16 @@ function assertHermesEnvironment(home) {
|
|
|
40719
40943
|
throw new Error(`NATIVE_SKILL_DRIFT: Hermes ${variable} requires a dedicated discovery adapter; unset it before using this adapter`);
|
|
40720
40944
|
}
|
|
40721
40945
|
const selected = process.env.HERMES_HOME?.trim();
|
|
40722
|
-
if (selected && (!
|
|
40946
|
+
if (selected && (!isAbsolute10(selected) || resolve9(selected) !== join17(resolve9(home), ".hermes")))
|
|
40723
40947
|
throw new Error("NATIVE_SKILL_DRIFT: custom Hermes homes/profiles require their own reviewed bridge");
|
|
40724
40948
|
if (process.env.HERMES_ENABLE_PROJECT_PLUGINS?.trim() && !["0", "false", "no", "off"].includes(process.env.HERMES_ENABLE_PROJECT_PLUGINS.trim().toLowerCase()))
|
|
40725
40949
|
throw new Error("NATIVE_SKILL_DRIFT: Hermes project plugins require a dedicated discovery review");
|
|
40726
40950
|
}
|
|
40727
40951
|
function read(path) {
|
|
40728
|
-
for (let current = path;; current =
|
|
40952
|
+
for (let current = path;; current = dirname9(current)) {
|
|
40729
40953
|
if (lstatSync11(current, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
40730
40954
|
throw new Error("NATIVE_SKILL_DRIFT: symlink Hermes protection input");
|
|
40731
|
-
if (
|
|
40955
|
+
if (dirname9(current) === current)
|
|
40732
40956
|
break;
|
|
40733
40957
|
}
|
|
40734
40958
|
const stat = lstatSync11(path, { throwIfNoEntry: false });
|
|
@@ -40742,7 +40966,7 @@ function assertHermesProtection(home, config, command, profile, supervisor) {
|
|
|
40742
40966
|
assertHermesEnvironment(home);
|
|
40743
40967
|
if (read(join17(home, ".hermes", HERMES_OPT_OUT)) === null)
|
|
40744
40968
|
throw new Error("NATIVE_SKILL_DRIFT: Hermes bundled skill reseeding is not disabled; run skills hook install");
|
|
40745
|
-
if (!supervisor || !
|
|
40969
|
+
if (!supervisor || !isAbsolute10(supervisor.path) || supervisor.runtime !== process.execPath || read(supervisor.path) !== renderHermesSupervisor(command, profile))
|
|
40746
40970
|
throw new Error("NATIVE_SKILL_DRIFT: Hermes owned supervisor changed; run skills hook install");
|
|
40747
40971
|
const raw = read(join17(home, ".hermes/shell-hooks-allowlist.json"));
|
|
40748
40972
|
let trust;
|
|
@@ -40768,10 +40992,10 @@ function assertHermesProtection(home, config, command, profile, supervisor) {
|
|
|
40768
40992
|
}
|
|
40769
40993
|
function assertNoHermesLegacyShadow(root) {
|
|
40770
40994
|
let entries = 0;
|
|
40771
|
-
for (let cursor =
|
|
40995
|
+
for (let cursor = resolve9(root);; cursor = dirname9(cursor)) {
|
|
40772
40996
|
if (lstatSync11(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
40773
40997
|
throw new Error("NATIVE_SKILL_DRIFT: symlink Hermes legacy discovery root");
|
|
40774
|
-
if (
|
|
40998
|
+
if (dirname9(cursor) === cursor)
|
|
40775
40999
|
break;
|
|
40776
41000
|
}
|
|
40777
41001
|
function scan(path, depth) {
|
|
@@ -40792,10 +41016,10 @@ function assertNoHermesLegacyShadow(root) {
|
|
|
40792
41016
|
const hasDescriptor = Boolean(lstatSync11(join17(path, "SKILL.md"), { throwIfNoEntry: false }));
|
|
40793
41017
|
const directory = opendirSync(path);
|
|
40794
41018
|
try {
|
|
40795
|
-
for (let
|
|
40796
|
-
if (hasDescriptor && ["references", "templates", "assets", "scripts"].includes(
|
|
41019
|
+
for (let child2 = directory.readSync();child2; child2 = directory.readSync()) {
|
|
41020
|
+
if (hasDescriptor && ["references", "templates", "assets", "scripts"].includes(child2.name))
|
|
40797
41021
|
continue;
|
|
40798
|
-
scan(join17(path,
|
|
41022
|
+
scan(join17(path, child2.name), depth + 1);
|
|
40799
41023
|
}
|
|
40800
41024
|
} finally {
|
|
40801
41025
|
directory.closeSync();
|
|
@@ -40852,18 +41076,18 @@ if (failed) process.exitCode = 2;
|
|
|
40852
41076
|
}
|
|
40853
41077
|
|
|
40854
41078
|
// src/lib/agent-discovery-directories.ts
|
|
40855
|
-
import { createHash as
|
|
41079
|
+
import { createHash as createHash14 } from "crypto";
|
|
40856
41080
|
import { lstatSync as lstatSync12, opendirSync as opendirSync2 } from "fs";
|
|
40857
|
-
import { dirname as
|
|
40858
|
-
function
|
|
41081
|
+
import { dirname as dirname10, isAbsolute as isAbsolute11, join as join18, resolve as resolve10 } from "path";
|
|
41082
|
+
function need5(value, message) {
|
|
40859
41083
|
if (!value)
|
|
40860
41084
|
throw new Error(message);
|
|
40861
41085
|
}
|
|
40862
41086
|
function safe(path) {
|
|
40863
|
-
|
|
40864
|
-
for (let cursor = path;; cursor =
|
|
40865
|
-
|
|
40866
|
-
if (
|
|
41087
|
+
need5(typeof path === "string" && path.length <= AGENT_POLICY_LIMITS.pathCharacters && isAbsolute11(path) && resolve10(path) === path && !path.includes("\x00"), "Expected a canonical absolute discovery directory path");
|
|
41088
|
+
for (let cursor = path;; cursor = dirname10(cursor)) {
|
|
41089
|
+
need5(!lstatSync12(cursor, { throwIfNoEntry: false })?.isSymbolicLink(), "Refusing symlink native discovery directory");
|
|
41090
|
+
if (dirname10(cursor) === cursor)
|
|
40867
41091
|
break;
|
|
40868
41092
|
}
|
|
40869
41093
|
}
|
|
@@ -40877,45 +41101,45 @@ function capture(path, budget2, excludedRoots, omittedRoots = [], rows) {
|
|
|
40877
41101
|
const root = lstatSync12(path, { throwIfNoEntry: false });
|
|
40878
41102
|
if (!root)
|
|
40879
41103
|
return { path, sha256: null };
|
|
40880
|
-
|
|
40881
|
-
const hash2 =
|
|
41104
|
+
need5(root.isDirectory(), "Unsupported native discovery directory input");
|
|
41105
|
+
const hash2 = createHash14("sha256");
|
|
40882
41106
|
function walk2(current, relative5, before, depth) {
|
|
40883
|
-
|
|
41107
|
+
need5(depth <= 64, "Native discovery directory depth limit exceeded");
|
|
40884
41108
|
const names = [], directory = opendirSync2(current);
|
|
40885
41109
|
try {
|
|
40886
41110
|
for (let entry = directory.readSync();entry; entry = directory.readSync()) {
|
|
40887
|
-
|
|
41111
|
+
need5(++budget2.entries <= AGENT_POLICY_LIMITS.discoveryDirectoryEntries, "Native discovery directory entry limit exceeded");
|
|
40888
41112
|
names.push(entry.name);
|
|
40889
41113
|
}
|
|
40890
41114
|
} finally {
|
|
40891
41115
|
directory.closeSync();
|
|
40892
41116
|
}
|
|
40893
|
-
|
|
41117
|
+
need5(new Set(names).size === names.length, "Ambiguous native discovery directory names");
|
|
40894
41118
|
for (const name of names.sort()) {
|
|
40895
|
-
const
|
|
40896
|
-
if (omittedRoots.includes(
|
|
41119
|
+
const child2 = join18(current, name), childRelative = relative5 ? `${relative5}/${name}` : name;
|
|
41120
|
+
if (omittedRoots.includes(child2))
|
|
40897
41121
|
continue;
|
|
40898
|
-
|
|
40899
|
-
const stat = lstatSync12(
|
|
40900
|
-
|
|
41122
|
+
need5(child2.length <= AGENT_POLICY_LIMITS.pathCharacters, "Native discovery directory path limit exceeded");
|
|
41123
|
+
const stat = lstatSync12(child2);
|
|
41124
|
+
need5(stat.isFile() || stat.isDirectory(), "Refusing symlink or special native discovery directory member");
|
|
40901
41125
|
const row = JSON.stringify([childRelative, stat.isDirectory() ? "directory" : "file"]) + `
|
|
40902
41126
|
`;
|
|
40903
41127
|
budget2.bytes += Buffer.byteLength(row);
|
|
40904
|
-
|
|
41128
|
+
need5(budget2.bytes <= AGENT_POLICY_LIMITS.discoveryDirectoryBytes, "Native discovery directory metadata limit exceeded");
|
|
40905
41129
|
hash2.update(row);
|
|
40906
41130
|
rows?.push(row);
|
|
40907
|
-
if (stat.isDirectory() && !excludedRoots.includes(
|
|
40908
|
-
walk2(
|
|
41131
|
+
if (stat.isDirectory() && !excludedRoots.includes(child2))
|
|
41132
|
+
walk2(child2, childRelative, stat, depth + 1);
|
|
40909
41133
|
}
|
|
40910
|
-
|
|
41134
|
+
need5(same(before, lstatSync12(current, { throwIfNoEntry: false })), "Native discovery directory changed while reading");
|
|
40911
41135
|
}
|
|
40912
41136
|
walk2(path, "", root, 0);
|
|
40913
41137
|
safe(path);
|
|
40914
41138
|
return { path, sha256: hash2.digest("hex") };
|
|
40915
41139
|
}
|
|
40916
41140
|
function captureDiscoveryDirectoryProjection(paths, omittedRoots) {
|
|
40917
|
-
|
|
40918
|
-
|
|
41141
|
+
need5(Array.isArray(paths) && paths.length <= AGENT_POLICY_LIMITS.discoveryDirectories && new Set(paths).size === paths.length, "Invalid projected discovery directory collection");
|
|
41142
|
+
need5(omittedRoots.length <= AGENT_POLICY_LIMITS.discoveryRoots && new Set(omittedRoots).size === omittedRoots.length, "Invalid inactive discovery roots");
|
|
40919
41143
|
for (const root of omittedRoots)
|
|
40920
41144
|
safe(root);
|
|
40921
41145
|
const budget2 = { entries: 0, bytes: 0 };
|
|
@@ -40925,62 +41149,62 @@ function captureDiscoveryDirectoryProjection(paths, omittedRoots) {
|
|
|
40925
41149
|
});
|
|
40926
41150
|
}
|
|
40927
41151
|
function verifyDiscoveryDirectoryProjection(directories, omittedRoots) {
|
|
40928
|
-
|
|
41152
|
+
need5(directories.length <= AGENT_POLICY_LIMITS.discoveryDirectories, "Invalid projected discovery directory collection");
|
|
40929
41153
|
let count = 0, bytes = 0;
|
|
40930
41154
|
const expected = directories.map((directory) => {
|
|
40931
41155
|
safe(directory.path);
|
|
40932
|
-
|
|
40933
|
-
const hash2 =
|
|
41156
|
+
need5(Array.isArray(directory.entries), "Missing reviewed directory membership inventory");
|
|
41157
|
+
const hash2 = createHash14("sha256");
|
|
40934
41158
|
const kept = [];
|
|
40935
41159
|
for (const row of directory.entries) {
|
|
40936
|
-
|
|
41160
|
+
need5(typeof row === "string" && ++count <= AGENT_POLICY_LIMITS.discoveryDirectoryEntries, "Invalid reviewed directory membership rows");
|
|
40937
41161
|
bytes += Buffer.byteLength(row);
|
|
40938
|
-
|
|
41162
|
+
need5(bytes <= AGENT_POLICY_LIMITS.discoveryDirectoryBytes, "Reviewed directory membership byte limit exceeded");
|
|
40939
41163
|
const value = JSON.parse(row);
|
|
40940
|
-
|
|
41164
|
+
need5(Array.isArray(value) && value.length === 2 && typeof value[0] === "string" && value[0] && !isAbsolute11(value[0]) && !value[0].split("/").some((part) => !part || part === "." || part === "..") && ["file", "directory"].includes(value[1]) && row === JSON.stringify(value) + `
|
|
40941
41165
|
`, "Invalid reviewed directory member");
|
|
40942
41166
|
hash2.update(row);
|
|
40943
41167
|
const path = join18(directory.path, value[0]);
|
|
40944
41168
|
if (!omittedRoots.some((root) => path === root || path.startsWith(root + "/")))
|
|
40945
41169
|
kept.push(row);
|
|
40946
41170
|
}
|
|
40947
|
-
|
|
41171
|
+
need5(directory.sha256 === null ? directory.entries.length === 0 : hash2.digest("hex") === directory.sha256, "Reviewed directory inventory does not match its fingerprint");
|
|
40948
41172
|
const absent = omittedRoots.some((root) => directory.path === root || directory.path.startsWith(root + "/"));
|
|
40949
|
-
return { path: directory.path, sha256: absent || directory.sha256 === null ? null :
|
|
41173
|
+
return { path: directory.path, sha256: absent || directory.sha256 === null ? null : createHash14("sha256").update(kept.join("")).digest("hex") };
|
|
40950
41174
|
});
|
|
40951
41175
|
const current = captureDiscoveryDirectoryProjection(directories.map((item) => item.path), omittedRoots);
|
|
40952
|
-
|
|
41176
|
+
need5(current.every((item, index) => item.sha256 === expected[index].sha256), "Native discovery directory membership changed outside retired Codex roots");
|
|
40953
41177
|
}
|
|
40954
41178
|
function captureDiscoveryDirectories(paths, excludedRoots = []) {
|
|
40955
|
-
|
|
41179
|
+
need5(Array.isArray(paths) && paths.length <= AGENT_POLICY_LIMITS.discoveryDirectories && new Set(paths).size === paths.length, "Invalid native discovery directory collection");
|
|
40956
41180
|
const budget2 = { entries: 0, bytes: 0 };
|
|
40957
41181
|
for (const root of excludedRoots)
|
|
40958
41182
|
safe(root);
|
|
40959
41183
|
return paths.map((path) => capture(path, budget2, excludedRoots));
|
|
40960
41184
|
}
|
|
40961
41185
|
function verifyDiscoveryDirectories(directories, excludedRoots = []) {
|
|
40962
|
-
|
|
41186
|
+
need5(Array.isArray(directories) && directories.length <= AGENT_POLICY_LIMITS.discoveryDirectories, "Invalid native discovery directory collection");
|
|
40963
41187
|
for (const directory of directories)
|
|
40964
|
-
|
|
41188
|
+
need5(directory && typeof directory === "object" && (directory.sha256 === null || typeof directory.sha256 === "string" && /^[a-f0-9]{64}$/.test(directory.sha256)), "Invalid native discovery directory digest");
|
|
40965
41189
|
const current = captureDiscoveryDirectories(directories.map((directory) => directory.path), excludedRoots);
|
|
40966
41190
|
for (let i = 0;i < directories.length; i++)
|
|
40967
|
-
|
|
41191
|
+
need5(current[i].sha256 === directories[i].sha256, `Native discovery directory membership changed; run skills hook install with a fresh discovery review: ${directories[i].path}`);
|
|
40968
41192
|
}
|
|
40969
41193
|
|
|
40970
41194
|
// src/lib/agent-discovery-bytes.ts
|
|
40971
|
-
import { createHash as
|
|
41195
|
+
import { createHash as createHash15 } from "crypto";
|
|
40972
41196
|
import { closeSync as closeSync12, constants as constants9, fstatSync as fstatSync12, lstatSync as lstatSync13, openSync as openSync12, readSync as readSync7 } from "fs";
|
|
40973
|
-
import { dirname as
|
|
41197
|
+
import { dirname as dirname11, isAbsolute as isAbsolute12, resolve as resolve11 } from "path";
|
|
40974
41198
|
function discoveryByteBudget() {
|
|
40975
41199
|
return { remaining: AGENT_POLICY_LIMITS.discoveryRawTotalBytes };
|
|
40976
41200
|
}
|
|
40977
41201
|
function safe2(path) {
|
|
40978
|
-
if (typeof path !== "string" || !
|
|
41202
|
+
if (typeof path !== "string" || !isAbsolute12(path) || path !== resolve11(path) || path.length > AGENT_POLICY_LIMITS.pathCharacters || path.includes("\x00"))
|
|
40979
41203
|
throw new Error("Expected a canonical absolute raw discovery path");
|
|
40980
|
-
for (let cursor = path;; cursor =
|
|
41204
|
+
for (let cursor = path;; cursor = dirname11(cursor)) {
|
|
40981
41205
|
if (lstatSync13(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
40982
41206
|
throw new Error("Refusing symlink raw discovery input");
|
|
40983
|
-
if (
|
|
41207
|
+
if (dirname11(cursor) === cursor)
|
|
40984
41208
|
break;
|
|
40985
41209
|
}
|
|
40986
41210
|
}
|
|
@@ -40999,7 +41223,7 @@ function hashRawDiscoveryFile(path, budget2, changes) {
|
|
|
40999
41223
|
if (bytes > AGENT_POLICY_LIMITS.discoveryRawSourceBytes)
|
|
41000
41224
|
throw new Error("Raw discovery file byte limit exceeded");
|
|
41001
41225
|
consume(budget2, bytes);
|
|
41002
|
-
return
|
|
41226
|
+
return createHash15("sha256").update(text2).digest("hex");
|
|
41003
41227
|
}
|
|
41004
41228
|
const initial = lstatSync13(path, { throwIfNoEntry: false });
|
|
41005
41229
|
if (!initial)
|
|
@@ -41013,7 +41237,7 @@ function hashRawDiscoveryFile(path, budget2, changes) {
|
|
|
41013
41237
|
const opened = fstatSync12(fd);
|
|
41014
41238
|
if (!opened.isFile() || !same2(initial, opened))
|
|
41015
41239
|
throw new Error("Raw discovery input changed during open");
|
|
41016
|
-
const hash2 =
|
|
41240
|
+
const hash2 = createHash15("sha256"), buffer = Buffer.alloc(64 * 1024);
|
|
41017
41241
|
let bytes = 0;
|
|
41018
41242
|
while (true) {
|
|
41019
41243
|
const count = readSync7(fd, buffer, 0, Math.min(buffer.length, AGENT_POLICY_LIMITS.discoveryRawSourceBytes - bytes + 1), null);
|
|
@@ -41036,9 +41260,9 @@ function hashRawDiscoveryFile(path, budget2, changes) {
|
|
|
41036
41260
|
}
|
|
41037
41261
|
|
|
41038
41262
|
// src/lib/agent-discovery-path-bytes.ts
|
|
41039
|
-
import { createHash as
|
|
41263
|
+
import { createHash as createHash16 } from "crypto";
|
|
41040
41264
|
import { lstatSync as lstatSync14, readlinkSync as readlinkSync4 } from "fs";
|
|
41041
|
-
import { dirname as
|
|
41265
|
+
import { dirname as dirname12, isAbsolute as isAbsolute13, join as join19, parse as parse3, resolve as resolve12, sep as sep5 } from "path";
|
|
41042
41266
|
function identity4(stat, mutable = false) {
|
|
41043
41267
|
return {
|
|
41044
41268
|
dev: String(stat.dev),
|
|
@@ -41049,12 +41273,12 @@ function identity4(stat, mutable = false) {
|
|
|
41049
41273
|
...mutable ? { size: String(stat.size), mtimeNs: String(stat.mtimeNs), ctimeNs: String(stat.ctimeNs) } : {}
|
|
41050
41274
|
};
|
|
41051
41275
|
}
|
|
41052
|
-
function
|
|
41053
|
-
if (typeof path !== "string" || !
|
|
41276
|
+
function canonical5(path) {
|
|
41277
|
+
if (typeof path !== "string" || !isAbsolute13(path) || path !== resolve12(path) || path.length > AGENT_POLICY_LIMITS.pathCharacters || path.includes("\x00") || Buffer.from(path).toString("utf8") !== path)
|
|
41054
41278
|
throw new Error("Expected a canonical absolute discovery path");
|
|
41055
41279
|
}
|
|
41056
41280
|
function trace(path) {
|
|
41057
|
-
|
|
41281
|
+
canonical5(path);
|
|
41058
41282
|
const rows = [], paths = [];
|
|
41059
41283
|
let metadataBytes = 0, steps = 0, links = 0, cursor = parse3(path).root, pending = path.slice(cursor.length).split(sep5);
|
|
41060
41284
|
function record4(path2, row) {
|
|
@@ -41079,7 +41303,7 @@ function trace(path) {
|
|
|
41079
41303
|
if (!component || component === ".")
|
|
41080
41304
|
continue;
|
|
41081
41305
|
if (component === "..") {
|
|
41082
|
-
cursor =
|
|
41306
|
+
cursor = dirname12(cursor);
|
|
41083
41307
|
continue;
|
|
41084
41308
|
}
|
|
41085
41309
|
const candidate = join19(cursor, component);
|
|
@@ -41099,11 +41323,11 @@ function trace(path) {
|
|
|
41099
41323
|
if (!target || target.includes("\x00") || Buffer.byteLength(target) > AGENT_POLICY_LIMITS.pathCharacters || !after.isSymbolicLink() || JSON.stringify(identity4(stat, true)) !== JSON.stringify(identity4(after, true)))
|
|
41100
41324
|
throw new Error("Discovery link changed during read");
|
|
41101
41325
|
record4(candidate, { type: "link", target, ...identity4(stat, true) });
|
|
41102
|
-
if (
|
|
41326
|
+
if (isAbsolute13(target)) {
|
|
41103
41327
|
cursor = parse3(target).root;
|
|
41104
41328
|
root();
|
|
41105
41329
|
}
|
|
41106
|
-
const remainder =
|
|
41330
|
+
const remainder = isAbsolute13(target) ? target.slice(parse3(target).root.length) : target;
|
|
41107
41331
|
pending = [...remainder.split(sep5), ...pending];
|
|
41108
41332
|
if (pending.length + steps > AGENT_POLICY_LIMITS.discoveryPathSteps)
|
|
41109
41333
|
throw new Error("Discovery path step limit exceeded");
|
|
@@ -41146,15 +41370,15 @@ function hashDiscoveryPathFile(path, budget2, changes) {
|
|
|
41146
41370
|
const after = trace(path);
|
|
41147
41371
|
if (JSON.stringify(before.rows) !== JSON.stringify(after.rows) || before.file !== after.file)
|
|
41148
41372
|
throw new Error("Discovery path input changed during read");
|
|
41149
|
-
return
|
|
41373
|
+
return createHash16("sha256").update(JSON.stringify({ version: 1, path, rows: before.rows, content })).digest("hex");
|
|
41150
41374
|
}
|
|
41151
41375
|
|
|
41152
41376
|
// src/lib/claude-plugin-manifest-witness.ts
|
|
41153
|
-
import { createHash as
|
|
41377
|
+
import { createHash as createHash17 } from "crypto";
|
|
41154
41378
|
var CLAUDE_PLUGIN_MANIFEST_LIMITS = Object.freeze({ bytes: 1024 * 1024, depth: 32, nodes: 65536, stringCharacters: 16384 });
|
|
41155
|
-
function requireValue(value,
|
|
41379
|
+
function requireValue(value, reason2) {
|
|
41156
41380
|
if (!value)
|
|
41157
|
-
throw new Error("Claude plugin manifest " +
|
|
41381
|
+
throw new Error("Claude plugin manifest " + reason2);
|
|
41158
41382
|
}
|
|
41159
41383
|
function parse4(text2) {
|
|
41160
41384
|
requireValue(Buffer.byteLength(text2, "utf8") <= CLAUDE_PLUGIN_MANIFEST_LIMITS.bytes, "exceeds its byte limit");
|
|
@@ -41230,7 +41454,7 @@ function parse4(text2) {
|
|
|
41230
41454
|
requireValue(at === text2.length && root.kind === "object", "requires a JSON object without trailing content");
|
|
41231
41455
|
return root;
|
|
41232
41456
|
}
|
|
41233
|
-
function
|
|
41457
|
+
function canonical6(value) {
|
|
41234
41458
|
if (value.kind === "string")
|
|
41235
41459
|
return JSON.stringify(value.value);
|
|
41236
41460
|
if (value.kind === "number")
|
|
@@ -41238,19 +41462,19 @@ function canonical5(value) {
|
|
|
41238
41462
|
if (value.kind === "literal")
|
|
41239
41463
|
return value.value;
|
|
41240
41464
|
if (value.kind === "array")
|
|
41241
|
-
return "[" + value.items.map(
|
|
41242
|
-
return "{" + value.entries.map(([key, item]) => JSON.stringify(key) + ":" +
|
|
41465
|
+
return "[" + value.items.map(canonical6).join(",") + "]";
|
|
41466
|
+
return "{" + value.entries.map(([key, item]) => JSON.stringify(key) + ":" + canonical6(item)).join(",") + "}";
|
|
41243
41467
|
}
|
|
41244
41468
|
var DESCRIPTIVE_FIELDS = new Set(["description", "version", "author", "homepage", "repository", "license", "keywords"]);
|
|
41245
|
-
function validateText(value,
|
|
41246
|
-
requireValue(value?.kind === "string" && value.value.length <= CLAUDE_PLUGIN_MANIFEST_LIMITS.stringCharacters, "has an invalid " +
|
|
41469
|
+
function validateText(value, field2) {
|
|
41470
|
+
requireValue(value?.kind === "string" && value.value.length <= CLAUDE_PLUGIN_MANIFEST_LIMITS.stringCharacters, "has an invalid " + field2 + " field");
|
|
41247
41471
|
}
|
|
41248
41472
|
function validateDescriptiveFields(manifest) {
|
|
41249
41473
|
const values = new Map(manifest.entries);
|
|
41250
|
-
for (const
|
|
41251
|
-
const value = values.get(
|
|
41474
|
+
for (const field2 of ["description", "version", "homepage", "license"]) {
|
|
41475
|
+
const value = values.get(field2);
|
|
41252
41476
|
if (value !== undefined)
|
|
41253
|
-
validateText(value,
|
|
41477
|
+
validateText(value, field2);
|
|
41254
41478
|
}
|
|
41255
41479
|
const author = values.get("author");
|
|
41256
41480
|
if (author !== undefined) {
|
|
@@ -41275,10 +41499,10 @@ function hashClaudePluginManifest(text2) {
|
|
|
41275
41499
|
const manifest = parse4(text2);
|
|
41276
41500
|
validateDescriptiveFields(manifest);
|
|
41277
41501
|
const discovery = { kind: "object", entries: manifest.entries.filter(([key]) => !DESCRIPTIVE_FIELDS.has(key)) };
|
|
41278
|
-
return
|
|
41502
|
+
return createHash17("sha256").update(canonical6(discovery)).digest("hex");
|
|
41279
41503
|
}
|
|
41280
41504
|
function projectReviewedClaudePluginManifest(text2, reviewedSha256) {
|
|
41281
|
-
if (!/^[a-f0-9]{64}$/.test(reviewedSha256) ||
|
|
41505
|
+
if (!/^[a-f0-9]{64}$/.test(reviewedSha256) || createHash17("sha256").update(text2).digest("hex") !== reviewedSha256) {
|
|
41282
41506
|
throw new Error("Reviewed Claude plugin manifest changed before semantic projection");
|
|
41283
41507
|
}
|
|
41284
41508
|
return hashClaudePluginManifest(text2);
|
|
@@ -41286,14 +41510,14 @@ function projectReviewedClaudePluginManifest(text2, reviewedSha256) {
|
|
|
41286
41510
|
|
|
41287
41511
|
// src/lib/plugin-discovery.ts
|
|
41288
41512
|
import { closeSync as closeSync14, constants as constants11, fstatSync as fstatSync14, lstatSync as lstatSync17, openSync as openSync14, opendirSync as opendirSync4, readSync as readSync9 } from "fs";
|
|
41289
|
-
import { basename as
|
|
41513
|
+
import { basename as basename7, dirname as dirname14, isAbsolute as isAbsolute17, join as join24, resolve as resolve15 } from "path";
|
|
41290
41514
|
|
|
41291
41515
|
// src/lib/plugin-admission.ts
|
|
41292
41516
|
import { homedir as homedir2 } from "os";
|
|
41293
|
-
import { isAbsolute as
|
|
41517
|
+
import { isAbsolute as isAbsolute16, join as join23, resolve as resolve14 } from "path";
|
|
41294
41518
|
|
|
41295
41519
|
// src/lib/plugin-projection.ts
|
|
41296
|
-
import { createHash as
|
|
41520
|
+
import { createHash as createHash18 } from "crypto";
|
|
41297
41521
|
import { posix as posix2 } from "path";
|
|
41298
41522
|
var PLUGIN_PROJECTION_MANIFEST = "plugin-projection.json";
|
|
41299
41523
|
var PLUGIN_PROJECTION_LIMITS = Object.freeze({ files: 1024, bytes: 64 * 1024 * 1024, fileBytes: 16 * 1024 * 1024, metadataBytes: 512 * 1024, registrations: 64, history: 128 });
|
|
@@ -41304,7 +41528,7 @@ function pluginNeed(value, message) {
|
|
|
41304
41528
|
if (!value)
|
|
41305
41529
|
pluginRefusal(message);
|
|
41306
41530
|
}
|
|
41307
|
-
var pluginHash = (bytes) =>
|
|
41531
|
+
var pluginHash = (bytes) => createHash18("sha256").update(bytes).digest("hex");
|
|
41308
41532
|
function pluginObject(value) {
|
|
41309
41533
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
41310
41534
|
}
|
|
@@ -41492,9 +41716,9 @@ function buildPluginProjection(entries) {
|
|
|
41492
41716
|
}
|
|
41493
41717
|
|
|
41494
41718
|
// src/lib/plugin-projection-store.ts
|
|
41495
|
-
import { createHash as
|
|
41719
|
+
import { createHash as createHash19, randomUUID as randomUUID3 } from "crypto";
|
|
41496
41720
|
import { constants as constants10, closeSync as closeSync13, fchmodSync, fstatSync as fstatSync13, fsyncSync as fsyncSync3, linkSync as linkSync2, lstatSync as lstatSync15, mkdirSync as mkdirSync5, openSync as openSync13, opendirSync as opendirSync3, readSync as readSync8, renameSync as renameSync3, rmdirSync as rmdirSync2, rmSync, unlinkSync as unlinkSync4, writeSync as writeSync2 } from "fs";
|
|
41497
|
-
import { dirname as
|
|
41721
|
+
import { dirname as dirname13, isAbsolute as isAbsolute14, join as join20, parse as parse6, resolve as resolve13 } from "path";
|
|
41498
41722
|
var READ_FLAGS = constants10.O_RDONLY | constants10.O_NOFOLLOW | constants10.O_NONBLOCK;
|
|
41499
41723
|
var WRITE_FLAGS = constants10.O_WRONLY | constants10.O_CREAT | constants10.O_EXCL | constants10.O_NOFOLLOW | constants10.O_NONBLOCK;
|
|
41500
41724
|
var uid = () => typeof process.getuid === "function" ? BigInt(process.getuid()) : undefined;
|
|
@@ -41508,8 +41732,8 @@ function stat(path) {
|
|
|
41508
41732
|
return pluginRefusal("Cannot inspect plugin filesystem entry");
|
|
41509
41733
|
}
|
|
41510
41734
|
}
|
|
41511
|
-
function
|
|
41512
|
-
pluginNeed(typeof path === "string" && path.length <= 8192 &&
|
|
41735
|
+
function canonical7(path) {
|
|
41736
|
+
pluginNeed(typeof path === "string" && path.length <= 8192 && isAbsolute14(path) && resolve13(path) === path && !/[\x00-\x1f\x7f]/.test(path), "Plugin storage paths must be canonical absolute paths");
|
|
41513
41737
|
}
|
|
41514
41738
|
function owner(stats, system = false) {
|
|
41515
41739
|
const current = uid();
|
|
@@ -41519,8 +41743,8 @@ function same3(left, right, identityOnly = false) {
|
|
|
41519
41743
|
pluginNeed(right && left.dev === right.dev && left.ino === right.ino && left.mode === right.mode && left.uid === right.uid && left.gid === right.gid && (identityOnly || left.size === right.size && left.nlink === right.nlink && left.mtimeNs === right.mtimeNs && left.ctimeNs === right.ctimeNs), "Plugin filesystem entry changed during access");
|
|
41520
41744
|
}
|
|
41521
41745
|
function ancestors(path, create = false) {
|
|
41522
|
-
|
|
41523
|
-
const result = [], parent =
|
|
41746
|
+
canonical7(path);
|
|
41747
|
+
const result = [], parent = dirname13(path), filesystemRoot = parse6(parent).root;
|
|
41524
41748
|
let current = filesystemRoot;
|
|
41525
41749
|
for (const segment of ["", ...parent.slice(filesystemRoot.length).split("/").filter(Boolean)]) {
|
|
41526
41750
|
if (segment)
|
|
@@ -41548,7 +41772,7 @@ function verifyAncestors(chain, identityOnly = true) {
|
|
|
41548
41772
|
}
|
|
41549
41773
|
function privateParent(path) {
|
|
41550
41774
|
const chain = ancestors(path, true), parent = chain.at(-1);
|
|
41551
|
-
pluginNeed(parent && parent.path ===
|
|
41775
|
+
pluginNeed(parent && parent.path === dirname13(path), "Plugin storage parent is unavailable");
|
|
41552
41776
|
owner(parent.stat);
|
|
41553
41777
|
pluginNeed((parent.stat.mode & 0o7777n) === 0o700n, "Plugin storage parent must have mode 0700");
|
|
41554
41778
|
return chain;
|
|
@@ -41834,7 +42058,7 @@ function pluginExecutableDigest(path) {
|
|
|
41834
42058
|
const opened = fstatSync13(fd, { bigint: true });
|
|
41835
42059
|
same3(before, opened);
|
|
41836
42060
|
fileShape(opened, maximum, "executable");
|
|
41837
|
-
const hash2 =
|
|
42061
|
+
const hash2 = createHash19("sha256"), buffer = new Uint8Array(64 * 1024);
|
|
41838
42062
|
let remaining = Number(opened.size);
|
|
41839
42063
|
while (remaining > 0) {
|
|
41840
42064
|
const count = readSync8(fd, buffer, 0, Math.min(buffer.byteLength, remaining), null);
|
|
@@ -41859,7 +42083,7 @@ function pluginExecutableDigest(path) {
|
|
|
41859
42083
|
|
|
41860
42084
|
// src/lib/skill-validation.ts
|
|
41861
42085
|
import { existsSync as existsSync5, lstatSync as lstatSync16, readFileSync as readFileSync14, readdirSync as readdirSync6, statSync as statSync6 } from "fs";
|
|
41862
|
-
import { isAbsolute as
|
|
42086
|
+
import { isAbsolute as isAbsolute15, join as join22, normalize as normalize3 } from "path";
|
|
41863
42087
|
|
|
41864
42088
|
// src/lib/hosted-skill-set.ts
|
|
41865
42089
|
import { existsSync as existsSync4, readFileSync as readFileSync13, readdirSync as readdirSync5, statSync as statSync5 } from "fs";
|
|
@@ -41963,7 +42187,7 @@ function sortMessages(messages) {
|
|
|
41963
42187
|
return [...messages].sort((a, b) => a.code.localeCompare(b.code) || a.message.localeCompare(b.message));
|
|
41964
42188
|
}
|
|
41965
42189
|
function isSafeRelativePath(value) {
|
|
41966
|
-
if (!value.trim() ||
|
|
42190
|
+
if (!value.trim() || isAbsolute15(value))
|
|
41967
42191
|
return false;
|
|
41968
42192
|
const normalized = normalize3(value).replace(/\\/g, "/");
|
|
41969
42193
|
return normalized !== ".." && !normalized.startsWith("../") && !normalized.includes("/../");
|
|
@@ -42328,7 +42552,7 @@ function validatePluginTarget(value) {
|
|
|
42328
42552
|
for (const registration of value.registrations) {
|
|
42329
42553
|
pluginKeys(registration, ["scope", "projectPath"]);
|
|
42330
42554
|
pluginNeed(registration.scope === "user" || registration.scope === "project", "Unsupported plugin registration scope");
|
|
42331
|
-
pluginNeed(registration.scope === "user" ? registration.projectPath === null : typeof registration.projectPath === "string" &&
|
|
42555
|
+
pluginNeed(registration.scope === "user" ? registration.projectPath === null : typeof registration.projectPath === "string" && isAbsolute16(registration.projectPath) && resolve14(registration.projectPath) === registration.projectPath, "Plugin scope requires its exact project path");
|
|
42332
42556
|
const key = JSON.stringify([registration.scope, registration.projectPath]);
|
|
42333
42557
|
pluginNeed(!scopes.has(key), "Duplicate plugin registration scope");
|
|
42334
42558
|
scopes.add(key);
|
|
@@ -42336,7 +42560,7 @@ function validatePluginTarget(value) {
|
|
|
42336
42560
|
for (const key of ["native", "resolver"]) {
|
|
42337
42561
|
pluginKeys(value[key], key === "native" ? ["version", "executable", "digest"] : ["executable", "digest"]);
|
|
42338
42562
|
pluginText(value[key].executable);
|
|
42339
|
-
pluginNeed(
|
|
42563
|
+
pluginNeed(isAbsolute16(value[key].executable) && resolve14(value[key].executable) === value[key].executable, "Plugin executable must have a canonical absolute path");
|
|
42340
42564
|
pluginDigest(value[key].digest);
|
|
42341
42565
|
}
|
|
42342
42566
|
pluginNeed(["2.1.274", "2.1.276"].includes(value.native.version), "Plugin admission requires a certified Claude command-source runtime (2.1.274 or 2.1.276)");
|
|
@@ -42481,14 +42705,14 @@ function validatePlan(value) {
|
|
|
42481
42705
|
pluginNeed(observedEvidenceDigest(plan.observation) === plan.evidenceDigest, "Plugin receipt observed evidence changed");
|
|
42482
42706
|
pluginNeed(identityDigest(plan) === plan.planDigest, "Plugin receipt immutable identity changed");
|
|
42483
42707
|
}
|
|
42484
|
-
var
|
|
42708
|
+
var quote2 = (value) => `'${value.replaceAll("'", "'\\''")}'`;
|
|
42485
42709
|
var resolverGuard = 'exec 9<"$1"; actual=$(/usr/bin/sha256sum /proc/self/fd/9); actual=${actual%% *}; [ "sha256:$actual" = "$2" ]; exec /proc/self/fd/9 integration plugin resolve --binding "$3"';
|
|
42486
42710
|
function pluginResolverCommand(binding) {
|
|
42487
|
-
return `${
|
|
42711
|
+
return `${quote2("/bin/sh")} -eu -c ${quote2(resolverGuard)} plugin-resolver ${quote2(binding.target.resolver.executable)} ${quote2(binding.target.resolver.digest)} ${quote2(bindingId(binding))}`;
|
|
42488
42712
|
}
|
|
42489
42713
|
function root(options) {
|
|
42490
42714
|
const path = options.storeRoot ?? pluginAdmissionRoot();
|
|
42491
|
-
pluginNeed(
|
|
42715
|
+
pluginNeed(isAbsolute16(path) && resolve14(path) === path, "Invalid plugin admission store root");
|
|
42492
42716
|
return path;
|
|
42493
42717
|
}
|
|
42494
42718
|
function pluginBindingPath(storeRoot, id2) {
|
|
@@ -42693,15 +42917,15 @@ function validateManagedPluginWitnesses(value) {
|
|
|
42693
42917
|
pluginNeed(typeof item.bindingId === "string" && /^[a-f0-9]{64}$/.test(item.bindingId) && !seen.has(item.bindingId), "Invalid or duplicate managed plugin witness");
|
|
42694
42918
|
seen.add(item.bindingId);
|
|
42695
42919
|
pluginText(item.storeRoot);
|
|
42696
|
-
pluginNeed(
|
|
42920
|
+
pluginNeed(isAbsolute17(item.storeRoot) && resolve15(item.storeRoot) === item.storeRoot, "Invalid plugin receipt store path");
|
|
42697
42921
|
}
|
|
42698
42922
|
}
|
|
42699
42923
|
function safe3(path) {
|
|
42700
42924
|
pluginText(path);
|
|
42701
|
-
pluginNeed(
|
|
42702
|
-
for (let at = path;; at =
|
|
42925
|
+
pluginNeed(isAbsolute17(path) && resolve15(path) === path, "Invalid plugin registry path");
|
|
42926
|
+
for (let at = path;; at = dirname14(at)) {
|
|
42703
42927
|
pluginNeed(!lstatSync17(at, { throwIfNoEntry: false })?.isSymbolicLink(), "Plugin registry path traverses a symlink");
|
|
42704
|
-
if (at ===
|
|
42928
|
+
if (at === dirname14(at))
|
|
42705
42929
|
break;
|
|
42706
42930
|
}
|
|
42707
42931
|
}
|
|
@@ -42751,7 +42975,7 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
42751
42975
|
seen.add(target.pluginId);
|
|
42752
42976
|
const rows = plugins[target.pluginId];
|
|
42753
42977
|
pluginNeed(Array.isArray(rows) && rows.length === target.registrations.length, "Managed plugin registration membership changed");
|
|
42754
|
-
const [name, market] = target.pluginId.split("@"), cacheRoot = join24(
|
|
42978
|
+
const [name, market] = target.pluginId.split("@"), cacheRoot = join24(dirname14(path), "cache", market, name);
|
|
42755
42979
|
const scopes = new Set, approvals = new Map, currentFiles = new Map;
|
|
42756
42980
|
plugins[target.pluginId] = rows.map((row) => {
|
|
42757
42981
|
pluginNeed(pluginObject(row), "Invalid managed plugin registration");
|
|
@@ -42767,7 +42991,7 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
42767
42991
|
pluginNeed(/^(?:[A-Za-z0-9][A-Za-z0-9._+-]*-)?[a-f0-9]{12}$/.test(row.version) && row.installPath === join24(cacheRoot, row.version), "Managed plugin cache path or version is outside its registration");
|
|
42768
42992
|
const approval = (producer) => {
|
|
42769
42993
|
pluginText(producer);
|
|
42770
|
-
const digest2 = `sha256:${
|
|
42994
|
+
const digest2 = `sha256:${basename7(producer)}`;
|
|
42771
42995
|
const receipt2 = readPluginAdmissionReceipt(witness.storeRoot, witness.bindingId, digest2);
|
|
42772
42996
|
pluginNeed(receipt2.materializedPath === producer, "Managed producer path is not an approved immutable projection");
|
|
42773
42997
|
if (!verified.has(producer)) {
|
|
@@ -42829,39 +43053,39 @@ function captureManagedPluginRegistry(path, managedPlugins) {
|
|
|
42829
43053
|
}
|
|
42830
43054
|
|
|
42831
43055
|
// src/lib/claude-marketplace-registry.ts
|
|
42832
|
-
import { createHash as
|
|
43056
|
+
import { createHash as createHash20 } from "crypto";
|
|
42833
43057
|
import { closeSync as closeSync15, constants as constants12, fstatSync as fstatSync15, lstatSync as lstatSync18, openSync as openSync15, readSync as readSync10 } from "fs";
|
|
42834
|
-
import { basename as
|
|
43058
|
+
import { basename as basename8, dirname as dirname15, isAbsolute as isAbsolute18, resolve as resolve16 } from "path";
|
|
42835
43059
|
var CLAUDE_MARKETPLACE_REGISTRY_LIMITS = Object.freeze({ bytes: 1024 * 1024, rows: 1024, depth: 32, nodes: 65536, stringCharacters: 16384, pathCharacters: 4096 });
|
|
42836
|
-
function
|
|
43060
|
+
function need6(value, reason2) {
|
|
42837
43061
|
if (!value)
|
|
42838
|
-
throw new Error(`Claude marketplace registry ${
|
|
43062
|
+
throw new Error(`Claude marketplace registry ${reason2}`);
|
|
42839
43063
|
}
|
|
42840
43064
|
function absolutePath3(value) {
|
|
42841
|
-
|
|
43065
|
+
need6(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute18(value) && resolve16(value) === value, "requires a normalized absolute path");
|
|
42842
43066
|
}
|
|
42843
43067
|
var sameFile2 = (a, b) => a.dev === b.dev && a.ino === b.ino && a.mode === b.mode && a.uid === b.uid && a.gid === b.gid && a.nlink === b.nlink && a.size === b.size && a.mtimeNs === b.mtimeNs && a.ctimeNs === b.ctimeNs;
|
|
42844
43068
|
function parents2(path) {
|
|
42845
43069
|
const result = [];
|
|
42846
|
-
for (let at =
|
|
43070
|
+
for (let at = dirname15(path);; at = dirname15(at)) {
|
|
42847
43071
|
const stat2 = lstatSync18(at, { bigint: true });
|
|
42848
|
-
|
|
43072
|
+
need6(stat2.isDirectory() && !stat2.isSymbolicLink(), "path traverses a symlink or non-directory");
|
|
42849
43073
|
result.push([at, stat2]);
|
|
42850
|
-
if (at ===
|
|
43074
|
+
if (at === dirname15(at))
|
|
42851
43075
|
return result;
|
|
42852
43076
|
}
|
|
42853
43077
|
}
|
|
42854
43078
|
function readRegistry2(path, budget2) {
|
|
42855
43079
|
absolutePath3(path);
|
|
42856
|
-
|
|
42857
|
-
|
|
43080
|
+
need6(basename8(path) === "known_marketplaces.json", "requires known_marketplaces.json");
|
|
43081
|
+
need6(Number.isSafeInteger(budget2.remaining) && budget2.remaining >= 0, "has an invalid byte budget");
|
|
42858
43082
|
const ancestors2 = parents2(path), initial = lstatSync18(path, { bigint: true });
|
|
42859
|
-
|
|
42860
|
-
|
|
43083
|
+
need6(initial.isFile() && !initial.isSymbolicLink() && initial.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
|
|
43084
|
+
need6(initial.size <= BigInt(budget2.remaining), "exceeds its aggregate byte limit");
|
|
42861
43085
|
const fd = openSync15(path, constants12.O_RDONLY | constants12.O_NOFOLLOW | constants12.O_NONBLOCK);
|
|
42862
43086
|
try {
|
|
42863
43087
|
const opened = fstatSync15(fd, { bigint: true });
|
|
42864
|
-
|
|
43088
|
+
need6(opened.isFile() && sameFile2(initial, opened), "changed during open");
|
|
42865
43089
|
const bytes = Buffer.alloc(Number(opened.size) + 1);
|
|
42866
43090
|
let length = 0;
|
|
42867
43091
|
while (length < bytes.length) {
|
|
@@ -42871,10 +43095,10 @@ function readRegistry2(path, budget2) {
|
|
|
42871
43095
|
length += count;
|
|
42872
43096
|
}
|
|
42873
43097
|
const after = fstatSync15(fd, { bigint: true }), current = lstatSync18(path, { bigint: true });
|
|
42874
|
-
|
|
43098
|
+
need6(current.isFile() && sameFile2(opened, after) && sameFile2(after, current) && BigInt(length) === opened.size, "changed during read");
|
|
42875
43099
|
for (const [ancestor, before] of ancestors2) {
|
|
42876
43100
|
const now = lstatSync18(ancestor, { bigint: true });
|
|
42877
|
-
|
|
43101
|
+
need6(now.isDirectory() && before.dev === now.dev && before.ino === now.ino && before.mode === now.mode, "parent changed during read");
|
|
42878
43102
|
}
|
|
42879
43103
|
budget2.remaining -= length;
|
|
42880
43104
|
try {
|
|
@@ -42894,7 +43118,7 @@ function parse7(text2) {
|
|
|
42894
43118
|
at++;
|
|
42895
43119
|
};
|
|
42896
43120
|
function string() {
|
|
42897
|
-
|
|
43121
|
+
need6(text2[at] === '"', "contains invalid JSON");
|
|
42898
43122
|
const start = at++;
|
|
42899
43123
|
while (at < text2.length) {
|
|
42900
43124
|
const character = text2[at++];
|
|
@@ -42905,7 +43129,7 @@ function parse7(text2) {
|
|
|
42905
43129
|
} catch {
|
|
42906
43130
|
throw new Error("Claude marketplace registry contains invalid JSON string");
|
|
42907
43131
|
}
|
|
42908
|
-
|
|
43132
|
+
need6(value2.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.stringCharacters, "exceeds its string limit");
|
|
42909
43133
|
return value2;
|
|
42910
43134
|
}
|
|
42911
43135
|
if (character === "\\")
|
|
@@ -42914,7 +43138,7 @@ function parse7(text2) {
|
|
|
42914
43138
|
throw new Error("Claude marketplace registry contains an unterminated JSON string");
|
|
42915
43139
|
}
|
|
42916
43140
|
function value(depth) {
|
|
42917
|
-
|
|
43141
|
+
need6(depth <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.depth && ++nodes <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.nodes, "exceeds its nesting or node limit");
|
|
42918
43142
|
space();
|
|
42919
43143
|
const character = text2[at];
|
|
42920
43144
|
if (character === '"')
|
|
@@ -42928,17 +43152,17 @@ function parse7(text2) {
|
|
|
42928
43152
|
if (object6) {
|
|
42929
43153
|
space();
|
|
42930
43154
|
const key = string();
|
|
42931
|
-
|
|
43155
|
+
need6(!keys2.has(key), "contains a duplicate JSON key");
|
|
42932
43156
|
keys2.add(key);
|
|
42933
43157
|
space();
|
|
42934
|
-
|
|
43158
|
+
need6(text2[at++] === ":", "contains invalid JSON");
|
|
42935
43159
|
entries.push([key, value(depth + 1)]);
|
|
42936
43160
|
} else
|
|
42937
43161
|
items.push(value(depth + 1));
|
|
42938
43162
|
space();
|
|
42939
43163
|
if (text2[at] === end)
|
|
42940
43164
|
break;
|
|
42941
|
-
|
|
43165
|
+
need6(text2[at++] === ",", "contains invalid JSON");
|
|
42942
43166
|
}
|
|
42943
43167
|
at++;
|
|
42944
43168
|
return object6 ? { kind: "object", entries } : { kind: "array", items };
|
|
@@ -42950,96 +43174,112 @@ function parse7(text2) {
|
|
|
42950
43174
|
}
|
|
42951
43175
|
numberPattern.lastIndex = at;
|
|
42952
43176
|
const number = numberPattern.exec(text2);
|
|
42953
|
-
|
|
43177
|
+
need6(number, "contains invalid JSON");
|
|
42954
43178
|
at += number[0].length;
|
|
42955
43179
|
return { kind: "number", value: number[0] };
|
|
42956
43180
|
}
|
|
42957
43181
|
const root2 = value(0);
|
|
42958
43182
|
space();
|
|
42959
|
-
|
|
42960
|
-
|
|
43183
|
+
need6(at === text2.length && root2.kind === "object", "requires a JSON object without trailing content");
|
|
43184
|
+
need6(root2.entries.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.rows, "exceeds its marketplace row limit");
|
|
42961
43185
|
return root2;
|
|
42962
43186
|
}
|
|
42963
43187
|
function exactKeys2(value, keys2) {
|
|
42964
43188
|
return value?.kind === "object" && value.entries.length === keys2.length && value.entries.every(([key]) => keys2.includes(key));
|
|
42965
43189
|
}
|
|
42966
|
-
var
|
|
43190
|
+
var field2 = (object6, key) => object6.entries.find(([name]) => name === key)?.[1];
|
|
42967
43191
|
function textField(value) {
|
|
42968
|
-
|
|
43192
|
+
need6(value?.kind === "string" && value.value.length > 0 && !/[\x00-\x1f\x7f]/.test(value.value), "contains an invalid recognized field");
|
|
42969
43193
|
return value.value;
|
|
42970
43194
|
}
|
|
42971
43195
|
function normalizeRow(row, version = 1) {
|
|
42972
43196
|
if (!exactKeys2(row, ["source", "installLocation", "lastUpdated"])) {
|
|
42973
43197
|
if (version !== 2 || !exactKeys2(row, ["source", "installLocation", "lastUpdated", "autoUpdate"]))
|
|
42974
43198
|
return;
|
|
42975
|
-
const autoUpdate =
|
|
42976
|
-
|
|
43199
|
+
const autoUpdate = field2(row, "autoUpdate");
|
|
43200
|
+
need6(autoUpdate?.kind === "literal" && (autoUpdate.value === "true" || autoUpdate.value === "false"), "contains an invalid automatic-update preference");
|
|
42977
43201
|
}
|
|
42978
|
-
const source =
|
|
43202
|
+
const source = field2(row, "source");
|
|
42979
43203
|
if (source?.kind !== "object")
|
|
42980
43204
|
return;
|
|
42981
|
-
const type =
|
|
43205
|
+
const type = field2(source, "source");
|
|
42982
43206
|
if (type?.kind !== "string" || !["github", "directory"].includes(type.value))
|
|
42983
43207
|
return;
|
|
42984
43208
|
const location = type.value === "github" ? "repo" : "path";
|
|
42985
43209
|
if (!exactKeys2(source, ["source", location]))
|
|
42986
43210
|
return;
|
|
42987
|
-
const sourceLocation = textField(
|
|
43211
|
+
const sourceLocation = textField(field2(source, location));
|
|
42988
43212
|
if (type.value === "directory")
|
|
42989
43213
|
absolutePath3(sourceLocation);
|
|
42990
|
-
absolutePath3(textField(
|
|
42991
|
-
const updated = textField(
|
|
42992
|
-
|
|
43214
|
+
absolutePath3(textField(field2(row, "installLocation")));
|
|
43215
|
+
const updated = textField(field2(row, "lastUpdated"));
|
|
43216
|
+
need6(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(updated), "contains an invalid recognized update timestamp");
|
|
42993
43217
|
const millis = Date.parse(updated);
|
|
42994
|
-
|
|
43218
|
+
need6(Number.isFinite(millis) && new Date(millis).toISOString() === updated, "contains an invalid recognized update timestamp");
|
|
42995
43219
|
row.entries = row.entries.map(([key, value]) => [key, key === "lastUpdated" ? { kind: "validated-update-time" } : value]);
|
|
42996
43220
|
}
|
|
42997
43221
|
function captureClaudeMarketplaceRegistry(path, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
42998
43222
|
const value = parse7(readRegistry2(path, budget2));
|
|
42999
43223
|
for (const [, row] of value.entries)
|
|
43000
43224
|
normalizeRow(row);
|
|
43001
|
-
const sha2562 =
|
|
43225
|
+
const sha2562 = createHash20("sha256").update("hasna.skills.claude-marketplace-registry.v1\x00").update(JSON.stringify(value)).digest("hex");
|
|
43002
43226
|
return { path, hashMode: "claude-marketplace-registry", sha256: sha2562 };
|
|
43003
43227
|
}
|
|
43004
43228
|
function captureClaudeMarketplaceRegistryV2(path, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
43005
43229
|
const value = parse7(readRegistry2(path, budget2));
|
|
43006
43230
|
for (const [, row] of value.entries)
|
|
43007
43231
|
normalizeRow(row, 2);
|
|
43008
|
-
const sha2562 =
|
|
43232
|
+
const sha2562 = createHash20("sha256").update("hasna.skills.claude-marketplace-registry.v2\x00").update(JSON.stringify(value)).digest("hex");
|
|
43009
43233
|
return { path, hashMode: "claude-marketplace-registry-v2", sha256: sha2562 };
|
|
43010
43234
|
}
|
|
43011
43235
|
|
|
43012
43236
|
// src/lib/codex-hook-discovery-recovery.ts
|
|
43013
|
-
import { createHash as
|
|
43237
|
+
import { createHash as createHash22 } from "crypto";
|
|
43014
43238
|
|
|
43015
43239
|
// src/lib/codex-hook-trust-files.ts
|
|
43016
|
-
import { closeSync as closeSync16, constants as constants13, fstatSync as fstatSync16, fsyncSync as fsyncSync4, lstatSync as lstatSync19, openSync as openSync16, readSync as readSync11, writeFileSync as writeFileSync4 } from "fs";
|
|
43017
|
-
import { createHash as
|
|
43018
|
-
import { dirname as
|
|
43019
|
-
function
|
|
43240
|
+
import { closeSync as closeSync16, constants as constants13, fstatSync as fstatSync16, fsyncSync as fsyncSync4, lstatSync as lstatSync19, openSync as openSync16, readlinkSync as readlinkSync5, readSync as readSync11, writeFileSync as writeFileSync4 } from "fs";
|
|
43241
|
+
import { createHash as createHash21 } from "crypto";
|
|
43242
|
+
import { dirname as dirname16, isAbsolute as isAbsolute19, resolve as resolve17 } from "path";
|
|
43243
|
+
function need7(value, code) {
|
|
43020
43244
|
if (!value)
|
|
43021
43245
|
throw new Error(`CODEX_HOOK_TRUST_${code}`);
|
|
43022
43246
|
}
|
|
43023
43247
|
var sameStat = (a, b) => ["dev", "ino", "uid", "nlink", "mode", "size", "mtimeNs", "ctimeNs"].every((key) => a[key] === b[key]);
|
|
43248
|
+
function trustedAncestorOwner(uid2) {
|
|
43249
|
+
return BigInt(uid2) === 0n || BigInt(uid2) === BigInt(process.getuid());
|
|
43250
|
+
}
|
|
43024
43251
|
function safeParents(file) {
|
|
43025
|
-
for (let p =
|
|
43252
|
+
for (let p = dirname16(file);; p = dirname16(p)) {
|
|
43026
43253
|
const s = lstatSync19(p);
|
|
43027
|
-
|
|
43028
|
-
|
|
43029
|
-
if (
|
|
43254
|
+
need7(s.isDirectory() && !s.isSymbolicLink() && trustedAncestorOwner(s.uid), "UNSAFE_PARENT");
|
|
43255
|
+
need7((s.mode & 18) === 0 || s.uid === 0 && (s.mode & 512) !== 0, "UNSAFE_PARENT");
|
|
43256
|
+
if (dirname16(p) === p)
|
|
43030
43257
|
break;
|
|
43031
43258
|
}
|
|
43032
43259
|
}
|
|
43260
|
+
function directAliasTarget(link) {
|
|
43261
|
+
const text2 = readlinkSync5(link), parts = text2.split("/");
|
|
43262
|
+
let first = 0;
|
|
43263
|
+
if (isAbsolute19(text2))
|
|
43264
|
+
first = 1;
|
|
43265
|
+
else
|
|
43266
|
+
while (parts[first] === "..")
|
|
43267
|
+
first++;
|
|
43268
|
+
const names = parts.slice(first);
|
|
43269
|
+
if (!names.length || names.some((part) => part === "" || part === "." || part === ".."))
|
|
43270
|
+
return;
|
|
43271
|
+
return resolve17(dirname16(link), text2);
|
|
43272
|
+
}
|
|
43033
43273
|
function snapshot(file, privateFile = false, options = {}) {
|
|
43034
43274
|
const readOnlyPackage = options.readOnlyPackage === true && !privateFile;
|
|
43035
43275
|
safeParents(file);
|
|
43036
43276
|
const initial = lstatSync19(file, { bigint: true });
|
|
43037
|
-
|
|
43038
|
-
|
|
43277
|
+
need7(initial.isFile() && initial.uid === BigInt(process.getuid()) && (initial.nlink === 1n || readOnlyPackage && initial.nlink > 1n) && (initial.mode & 0o022n) === 0n && (!privateFile || (initial.mode & 0o777n) === 0o600n), "UNSAFE_FILE");
|
|
43278
|
+
need7(initial.size <= 8n * 1024n * 1024n, "FILE_BOUND");
|
|
43039
43279
|
const fd = openSync16(file, constants13.O_RDONLY | constants13.O_NOFOLLOW | constants13.O_NONBLOCK);
|
|
43040
43280
|
try {
|
|
43041
43281
|
const before = fstatSync16(fd, { bigint: true });
|
|
43042
|
-
|
|
43282
|
+
need7(sameStat(initial, before), "INPUT_CHANGED");
|
|
43043
43283
|
const bytes = Buffer.alloc(Number(before.size) + 1);
|
|
43044
43284
|
let length = 0;
|
|
43045
43285
|
while (length < bytes.length) {
|
|
@@ -43048,16 +43288,16 @@ function snapshot(file, privateFile = false, options = {}) {
|
|
|
43048
43288
|
break;
|
|
43049
43289
|
length += n2;
|
|
43050
43290
|
}
|
|
43051
|
-
|
|
43291
|
+
need7(length === Number(before.size) && sameStat(before, fstatSync16(fd, { bigint: true })) && sameStat(before, lstatSync19(file, { bigint: true })), "INPUT_CHANGED");
|
|
43052
43292
|
const content = bytes.subarray(0, length), text2 = new TextDecoder("utf-8", { fatal: true }).decode(content);
|
|
43053
|
-
return { file, privateFile, readOnlyPackage, text: text2, bytes: content, stat: before, sha256:
|
|
43293
|
+
return { file, privateFile, readOnlyPackage, text: text2, bytes: content, stat: before, sha256: createHash21("sha256").update(content).digest("hex") };
|
|
43054
43294
|
} finally {
|
|
43055
43295
|
closeSync16(fd);
|
|
43056
43296
|
}
|
|
43057
43297
|
}
|
|
43058
43298
|
function unchanged2(before) {
|
|
43059
43299
|
const after = snapshot(before.file, before.privateFile, before.readOnlyPackage ? { readOnlyPackage: true } : {});
|
|
43060
|
-
|
|
43300
|
+
need7(sameStat(before.stat, after.stat) && after.sha256 === before.sha256, "INPUT_CHANGED");
|
|
43061
43301
|
}
|
|
43062
43302
|
|
|
43063
43303
|
// src/lib/codex-hook-additions-review.ts
|
|
@@ -43066,12 +43306,12 @@ var matchedEvents = { ...events, PreToolUse: ["preToolUse", "pre_tool_use"] };
|
|
|
43066
43306
|
var proofs = new WeakMap;
|
|
43067
43307
|
|
|
43068
43308
|
// src/lib/codex-hook-discovery-recovery.ts
|
|
43069
|
-
var sha3 = (text2) =>
|
|
43309
|
+
var sha3 = (text2) => createHash22("sha256").update(text2).digest("hex");
|
|
43070
43310
|
var fields = [...CODEX_DISCOVERY_PROJECTION_FIELDS];
|
|
43071
43311
|
var proofs2 = new WeakMap;
|
|
43072
43312
|
function assertCodexHookDiscoveryRecovery(binding, witness) {
|
|
43073
43313
|
const proof = proofs2.get(witness);
|
|
43074
|
-
|
|
43314
|
+
need7(!!proof && binding.agent === "codex" && witness.discoverySha256 === sha3(JSON.stringify(binding)), "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
|
|
43075
43315
|
unchanged2(proof.before);
|
|
43076
43316
|
unchanged2(proof.current);
|
|
43077
43317
|
proof.recheckAdditions();
|
|
@@ -43080,34 +43320,34 @@ function verifiesCodexHookDiscoverySource(binding, source, currentDigest, witnes
|
|
|
43080
43320
|
if (!witness || source.path !== witness.configPath || source.hashMode !== "bytes")
|
|
43081
43321
|
return false;
|
|
43082
43322
|
assertCodexHookDiscoveryRecovery(binding, witness);
|
|
43083
|
-
|
|
43323
|
+
need7(source.sha256 === witness.beforeSha256 && currentDigest === witness.currentSha256, "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
|
|
43084
43324
|
return true;
|
|
43085
43325
|
}
|
|
43086
43326
|
|
|
43087
43327
|
// src/lib/agent-sumi.ts
|
|
43088
43328
|
import { existsSync as existsSync6, lstatSync as lstatSync20, realpathSync as realpathSync8 } from "fs";
|
|
43089
|
-
import { join as join25, resolve as
|
|
43329
|
+
import { join as join25, resolve as resolve18 } from "path";
|
|
43090
43330
|
function sumiConfigDirectory(home, env = process.env) {
|
|
43091
43331
|
for (const key of ["SUMI_CONFIG", "SUMI_CONFIG_CONTENT"])
|
|
43092
43332
|
if (env[key] !== undefined)
|
|
43093
43333
|
throw new Error(`Sumi ${key} requires a dedicated discovery adapter; unset it before Skills integration`);
|
|
43094
43334
|
const selected = (key) => env[key]?.trim() ? env[key] : undefined;
|
|
43095
|
-
const expand = (value) =>
|
|
43335
|
+
const expand = (value) => resolve18(value === "~" ? home : value.startsWith("~/") ? join25(home, value.slice(2)) : value);
|
|
43096
43336
|
const explicit = selected("SUMI_CONFIG_DIR");
|
|
43097
43337
|
const xdg = selected("XDG_CONFIG_HOME");
|
|
43098
43338
|
const custom = selected("SUMI_HOME");
|
|
43099
|
-
const
|
|
43339
|
+
const canonical8 = explicit ? expand(explicit) : xdg ? join25(expand(xdg), "sumi") : join25(custom ? expand(custom) : join25(home, ".hasna-internal/sumi"), "config");
|
|
43100
43340
|
if (explicit || xdg || custom)
|
|
43101
|
-
return
|
|
43341
|
+
return canonical8;
|
|
43102
43342
|
const legacy = join25(home, ".config/sumi");
|
|
43103
|
-
const a = lstatSync20(
|
|
43104
|
-
if (a && b && realpathSync8(
|
|
43343
|
+
const a = lstatSync20(canonical8, { throwIfNoEntry: false }), b = lstatSync20(legacy, { throwIfNoEntry: false });
|
|
43344
|
+
if (a && b && realpathSync8(canonical8) !== realpathSync8(legacy))
|
|
43105
43345
|
throw new Error("Sumi config roots conflict; complete native home adoption before Skills integration");
|
|
43106
|
-
const path = a ?
|
|
43346
|
+
const path = a ? canonical8 : b ? legacy : canonical8;
|
|
43107
43347
|
if (!existsSync6(path))
|
|
43108
43348
|
return path;
|
|
43109
43349
|
const physical = realpathSync8(path);
|
|
43110
|
-
if ((a?.isSymbolicLink() || b?.isSymbolicLink()) && ![
|
|
43350
|
+
if ((a?.isSymbolicLink() || b?.isSymbolicLink()) && ![canonical8, legacy].includes(physical))
|
|
43111
43351
|
throw new Error("Sumi config alias must resolve to its canonical or legacy root");
|
|
43112
43352
|
return physical;
|
|
43113
43353
|
}
|
|
@@ -43207,7 +43447,38 @@ var SUMI_SKILL_PERMISSIONS = [
|
|
|
43207
43447
|
];
|
|
43208
43448
|
|
|
43209
43449
|
// src/lib/agent-discovery.ts
|
|
43210
|
-
var
|
|
43450
|
+
var DISCOVERY_RUNTIME_COMMANDS = Object.freeze({ gemini: "gemini" });
|
|
43451
|
+
var DISCOVERY_ROOT_UNRESOLVED = "DISCOVERY_ROOT_UNRESOLVED";
|
|
43452
|
+
function discoveryRootUnresolved(agent, command, detail) {
|
|
43453
|
+
return new Error(`${DISCOVERY_ROOT_UNRESOLVED}: ${agent} discovery cannot resolve its "${command}" executable: ${detail}. The reviewed discovery is unchanged; this is an environment gap, not drift.`);
|
|
43454
|
+
}
|
|
43455
|
+
function isDiscoveryRootUnresolved(error) {
|
|
43456
|
+
return error instanceof Error && error.message.startsWith(`${DISCOVERY_ROOT_UNRESOLVED}: `);
|
|
43457
|
+
}
|
|
43458
|
+
var quotedPath = (path) => JSON.stringify(path).replace(/[^\x20-\x7e]/g, (character) => `\\u${character.charCodeAt(0).toString(16).padStart(4, "0")}`);
|
|
43459
|
+
var realpathOrNull = (path) => {
|
|
43460
|
+
try {
|
|
43461
|
+
return realpathSync9(path);
|
|
43462
|
+
} catch {
|
|
43463
|
+
return null;
|
|
43464
|
+
}
|
|
43465
|
+
};
|
|
43466
|
+
function discoveryExecutable(agent) {
|
|
43467
|
+
const command = DISCOVERY_RUNTIME_COMMANDS[agent];
|
|
43468
|
+
const found = command ? Bun.which(command) : null;
|
|
43469
|
+
if (!command || !found)
|
|
43470
|
+
return null;
|
|
43471
|
+
const path = resolve19(found), target = realpathOrNull(path);
|
|
43472
|
+
return target === null ? null : { command, path, target };
|
|
43473
|
+
}
|
|
43474
|
+
function recordedDiscoveryExecutable(agent, recorded) {
|
|
43475
|
+
const command = DISCOVERY_RUNTIME_COMMANDS[agent];
|
|
43476
|
+
if (!command || recorded.command !== command)
|
|
43477
|
+
throw new Error(`Recorded ${agent} discovery executable names another command`);
|
|
43478
|
+
const target = realpathOrNull(recorded.path);
|
|
43479
|
+
return target === null ? null : { command, path: recorded.path, target };
|
|
43480
|
+
}
|
|
43481
|
+
var digest2 = (text2) => createHash23("sha256").update(text2).digest("hex");
|
|
43211
43482
|
function parseConfig(text2, path, toml = false) {
|
|
43212
43483
|
try {
|
|
43213
43484
|
const value = toml ? Bun.TOML.parse(text2) : JSON.parse(text2);
|
|
@@ -43219,12 +43490,12 @@ function parseConfig(text2, path, toml = false) {
|
|
|
43219
43490
|
}
|
|
43220
43491
|
}
|
|
43221
43492
|
function safe4(path) {
|
|
43222
|
-
if (!
|
|
43493
|
+
if (!isAbsolute20(path) || path.includes("\x00"))
|
|
43223
43494
|
throw new Error("Expected an absolute native discovery path");
|
|
43224
|
-
for (let cursor = path;; cursor =
|
|
43495
|
+
for (let cursor = path;; cursor = dirname17(cursor)) {
|
|
43225
43496
|
if (lstatSync21(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
43226
43497
|
throw new Error(`Refusing symlink native discovery input: ${cursor}`);
|
|
43227
|
-
if (
|
|
43498
|
+
if (dirname17(cursor) === cursor)
|
|
43228
43499
|
break;
|
|
43229
43500
|
}
|
|
43230
43501
|
}
|
|
@@ -43243,7 +43514,7 @@ function projectNativeDiscoveryFields(text2, format, fields2, path) {
|
|
|
43243
43514
|
const object6 = format === "yaml" ? parseHermesConfig(text2) : parseConfig(text2, path, format === "toml");
|
|
43244
43515
|
if (!object6 || typeof object6 !== "object" || Array.isArray(object6))
|
|
43245
43516
|
throw new Error("Expected native discovery configuration object");
|
|
43246
|
-
return digest2(JSON.stringify(Object.fromEntries(fields2.map((
|
|
43517
|
+
return digest2(JSON.stringify(Object.fromEntries(fields2.map((field3) => [field3, object6[field3] ?? null]))));
|
|
43247
43518
|
}
|
|
43248
43519
|
function isSupersededSettingsProjection(agent, configPath, source) {
|
|
43249
43520
|
if (agent === "sumi")
|
|
@@ -43288,6 +43559,14 @@ function projected(source, changes, budget2 = discoveryByteBudget()) {
|
|
|
43288
43559
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
43289
43560
|
return sha2562;
|
|
43290
43561
|
}
|
|
43562
|
+
if (source.hashMode === "claude-marketplace-entry-v1") {
|
|
43563
|
+
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256) || changes?.has(source.path) || !claudeMarketplaceEntrySourceValid(source))
|
|
43564
|
+
throw new Error("Claude marketplace entry witnesses require an exact reviewed entry without synthetic changes");
|
|
43565
|
+
const sha2562 = captureClaudeMarketplaceEntry(source.path, source.marketplace, source.plugin, budget2).sha256;
|
|
43566
|
+
if (sha2562 !== source.sha256)
|
|
43567
|
+
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
43568
|
+
return sha2562;
|
|
43569
|
+
}
|
|
43291
43570
|
if (source.hashMode === "claude-plugin-registry") {
|
|
43292
43571
|
if (source.format !== undefined || source.fields !== undefined || !source.managedPlugins || changes?.has(source.path))
|
|
43293
43572
|
throw new Error("Managed plugin registry witnesses require verified native registrations");
|
|
@@ -43325,7 +43604,7 @@ function absentCodexSkillRoots(binding) {
|
|
|
43325
43604
|
throw new Error("Invalid disabled Codex discovery proof");
|
|
43326
43605
|
if (binding.method !== "reviewed" || controls.every((control) => lstatSync21(control.pluginParent, { throwIfNoEntry: false })))
|
|
43327
43606
|
return [];
|
|
43328
|
-
const cache =
|
|
43607
|
+
const cache = dirname17(dirname17(controls[0].pluginParent)), config = join26(dirname17(dirname17(cache)), "config.toml");
|
|
43329
43608
|
const source = binding.sources.find((source2) => source2.path === config && source2.sha256 !== null && source2.format === undefined && source2.fields === undefined);
|
|
43330
43609
|
if (!source || projected(source) !== source.sha256)
|
|
43331
43610
|
throw new Error("Missing current disabled Codex configuration witness");
|
|
@@ -43333,7 +43612,7 @@ function absentCodexSkillRoots(binding) {
|
|
|
43333
43612
|
return [...new Set(controls.map((control) => control.pluginParent))].filter((parent) => !codexDirectHookSelects(cache, parent) && absentDisabledCodexPluginParent(cache, parent, controls, rules));
|
|
43334
43613
|
}
|
|
43335
43614
|
function codexDirectHookSelects(cache, root2) {
|
|
43336
|
-
const codex =
|
|
43615
|
+
const codex = dirname17(dirname17(cache)), config = Bun.TOML.parse(read2(join26(codex, "config.toml")) ?? "");
|
|
43337
43616
|
const hooks = read2(join26(codex, "hooks.json"));
|
|
43338
43617
|
if (hooks !== null)
|
|
43339
43618
|
hashNativeJsonControls(hooks);
|
|
@@ -43346,7 +43625,7 @@ function retiredCodexRoots(binding) {
|
|
|
43346
43625
|
const controls = binding.codexDisabledPluginSkills;
|
|
43347
43626
|
if (binding.agent !== "codex" || binding.method !== "reviewed" || !Array.isArray(controls) || !controls.length || !Array.isArray(proof.roots) || proof.roots.length > AGENT_POLICY_LIMITS.discoveryRoots || new Set(proof.roots).size !== proof.roots.length || !Array.isArray(proof.directories) || proof.parents !== undefined && (!Array.isArray(proof.parents) || proof.parents.length > AGENT_POLICY_LIMITS.discoveryRoots || new Set(proof.parents).size !== proof.parents.length) || !proof.roots.length && !proof.parents?.length)
|
|
43348
43627
|
throw new Error("Invalid retired Codex materialization proof");
|
|
43349
|
-
const cache =
|
|
43628
|
+
const cache = dirname17(dirname17(controls[0].pluginParent)), config = join26(dirname17(dirname17(cache)), "config.toml");
|
|
43350
43629
|
const source = binding.sources.find((source2) => source2.path === config && source2.sha256 !== null && source2.format === undefined && source2.fields === undefined);
|
|
43351
43630
|
if (!source || projected(source) !== source.sha256)
|
|
43352
43631
|
throw new Error("Missing current retired Codex configuration witness");
|
|
@@ -43363,8 +43642,8 @@ function retiredCodexRoots(binding) {
|
|
|
43363
43642
|
function captureRetiredCodexDiscovery(binding, controls, rules) {
|
|
43364
43643
|
if (binding.agent !== "codex" || binding.method !== "reviewed" || !controls.length)
|
|
43365
43644
|
return binding;
|
|
43366
|
-
const cache =
|
|
43367
|
-
const candidates = binding.sources.filter((source) => source.path.endsWith(sep6 + ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined && [undefined, "bytes"].includes(source.hashMode)).map((source) =>
|
|
43645
|
+
const cache = dirname17(dirname17(controls[0].pluginParent));
|
|
43646
|
+
const candidates = binding.sources.filter((source) => source.path.endsWith(sep6 + ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined && [undefined, "bytes"].includes(source.hashMode)).map((source) => dirname17(dirname17(source.path)));
|
|
43368
43647
|
const roots = [...new Set(candidates)].filter((root2) => !codexDirectHookSelects(cache, root2) && reviewedRetiredCodexRoot(cache, root2, controls, rules, (path) => read2(path), binding.codexRetiredMaterializations?.roots.includes(root2) ?? false)).sort();
|
|
43369
43648
|
const parents3 = reviewedCodexPluginCapabilitiesUnchanged(cache, controls, (path) => read2(path), rules) ? [...new Set(controls.map((control) => control.pluginParent))].filter((parent) => !codexDirectHookSelects(cache, parent) && reviewedDisabledCodexPluginParent(cache, parent, controls, rules)).sort() : [];
|
|
43370
43649
|
const { codexRetiredMaterializations: previous, ...current } = binding;
|
|
@@ -43393,7 +43672,7 @@ function absentRetiredClaudeRoots(binding) {
|
|
|
43393
43672
|
safe4(root2);
|
|
43394
43673
|
if (lstatSync21(root2, { throwIfNoEntry: false }))
|
|
43395
43674
|
continue;
|
|
43396
|
-
const claude =
|
|
43675
|
+
const claude = dirname17(dirname17(cache)), settings = join26(claude, "settings.json"), registry = join26(claude, "plugins/installed_plugins.json");
|
|
43397
43676
|
const full = (path) => binding.sources.find((item) => item.path === path && item.sha256 !== null && item.format === undefined && item.fields === undefined);
|
|
43398
43677
|
const configSource = full(settings), registrySource = full(registry);
|
|
43399
43678
|
if (!configSource || !registrySource || projected(configSource) !== configSource.sha256 || projected(registrySource) !== registrySource.sha256)
|
|
@@ -43410,7 +43689,7 @@ function absentRetiredClaudeRoots(binding) {
|
|
|
43410
43689
|
if (!Array.isArray(rows) || rows.length !== 1 || rows[0]?.scope !== "user" || typeof rows[0]?.installPath !== "string")
|
|
43411
43690
|
continue;
|
|
43412
43691
|
const active = rows[0].installPath;
|
|
43413
|
-
if (rows[0].version !==
|
|
43692
|
+
if (rows[0].version !== basename9(active) || resolve19(active) !== active || dirname17(active) !== dirname17(root2) || active === root2 || !lstatSync21(active, { throwIfNoEntry: false })?.isDirectory() || realpathSync9(active) !== active)
|
|
43414
43693
|
continue;
|
|
43415
43694
|
const activeManifest = full(join26(active, ".claude-plugin/plugin.json"));
|
|
43416
43695
|
if (!activeManifest || projected(activeManifest) !== activeManifest.sha256)
|
|
@@ -43461,7 +43740,7 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
43461
43740
|
assertMarketplaceBinding(binding, source);
|
|
43462
43741
|
if (source.hashMode === "claude-plugin-registry" && binding.agent !== "claude")
|
|
43463
43742
|
throw new Error("Managed Claude registry witnesses cannot apply to another agent");
|
|
43464
|
-
if (source.format !== undefined && (!["json", "toml", "yaml"].includes(source.format) || !Array.isArray(source.fields) || !source.fields.length || source.fields.length > 64 || source.fields.some((
|
|
43743
|
+
if (source.format !== undefined && (!["json", "toml", "yaml"].includes(source.format) || !Array.isArray(source.fields) || !source.fields.length || source.fields.length > 64 || source.fields.some((field3) => typeof field3 !== "string" || !field3)))
|
|
43465
43744
|
throw new Error("Invalid native discovery projection");
|
|
43466
43745
|
if (source.sha256 !== null && !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
43467
43746
|
throw new Error("Invalid native discovery digest");
|
|
@@ -43491,13 +43770,13 @@ function codexInstallationRoots(binding) {
|
|
|
43491
43770
|
return [];
|
|
43492
43771
|
if (binding.agent !== "codex" || binding.method !== "reviewed" || !supportsCodexNativeCapability(proof.version, "installed-plugin-review") || !/^[a-f0-9]{64}$/.test(proof.catalogSha256) || !Array.isArray(proof.plugins) || !proof.plugins.length)
|
|
43493
43772
|
throw new Error("Invalid native installation input proof");
|
|
43494
|
-
const cache =
|
|
43495
|
-
const config = join26(
|
|
43773
|
+
const cache = dirname17(dirname17(proof.plugins[0].pluginParent));
|
|
43774
|
+
const config = join26(dirname17(dirname17(cache)), "config.toml"), home = dirname17(dirname17(dirname17(cache)));
|
|
43496
43775
|
const configSource = binding.sources.find((source) => source.path === config && source.sha256 !== null && (!source.format || source.format === "toml" && source.fields?.includes("plugins")));
|
|
43497
43776
|
const nativeRoots = NATIVE_SKILL_ROOTS.filter(([agent]) => agent === "codex").map(([, path]) => join26(home, path));
|
|
43498
|
-
if (!configSource || proof.plugins.some((input) => nativeRoots.some((root2) => root2 === input.sourceRoot || root2.startsWith(input.sourceRoot + sep6) || input.sourceRoot.startsWith(root2 + sep6)) || binding.sources.some((source) =>
|
|
43777
|
+
if (!configSource || proof.plugins.some((input) => nativeRoots.some((root2) => root2 === input.sourceRoot || root2.startsWith(input.sourceRoot + sep6) || input.sourceRoot.startsWith(root2 + sep6)) || binding.sources.some((source) => basename9(source.path) === "config.toml" && (source.path === input.sourceRoot || source.path.startsWith(input.sourceRoot + sep6)))))
|
|
43499
43778
|
throw new Error("Native installation input overlaps configuration or loading roots");
|
|
43500
|
-
if (proof.plugins.some((input) =>
|
|
43779
|
+
if (proof.plugins.some((input) => dirname17(dirname17(input.pluginParent)) !== cache || !binding.sources.some((source) => source.path === join26(input.sourceRoot, ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined)))
|
|
43501
43780
|
throw new Error("Missing native installation input source witness");
|
|
43502
43781
|
return reviewedCodexPluginSourceRoots(cache, proof.plugins, (path) => {
|
|
43503
43782
|
const text2 = read2(path);
|
|
@@ -43507,16 +43786,18 @@ function codexInstallationRoots(binding) {
|
|
|
43507
43786
|
});
|
|
43508
43787
|
}
|
|
43509
43788
|
function assertMarketplaceBinding(binding, source) {
|
|
43510
|
-
if (source.hashMode === "claude-plugin-manifest-v1" && (binding.agent !== "claude" ||
|
|
43789
|
+
if (source.hashMode === "claude-plugin-manifest-v1" && (binding.agent !== "claude" || basename9(source.path) !== "plugin.json" || !source.path.endsWith(join26(sep6, ".claude-plugin", "plugin.json"))))
|
|
43511
43790
|
throw new Error("Claude plugin manifest witnesses require Claude plugin discovery");
|
|
43512
|
-
if (source.hashMode === "sumi-settings-v1" && (binding.agent !== "sumi" || binding.method !== "reviewed" ||
|
|
43791
|
+
if (source.hashMode === "sumi-settings-v1" && (binding.agent !== "sumi" || binding.method !== "reviewed" || basename9(source.path) !== "sumi.json"))
|
|
43513
43792
|
throw new Error("Sumi settings witnesses require explicit reviewed Sumi configuration");
|
|
43514
|
-
if ((source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")) && (binding.agent !== "codex" || binding.method !== "reviewed" ||
|
|
43793
|
+
if ((source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")) && (binding.agent !== "codex" || binding.method !== "reviewed" || basename9(source.path) !== "config.toml"))
|
|
43515
43794
|
throw new Error("Codex settings witnesses require explicit reviewed Codex configuration");
|
|
43516
|
-
if ((source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4")) && (binding.agent !== "claude" || binding.method !== "reviewed" ||
|
|
43795
|
+
if ((source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4")) && (binding.agent !== "claude" || binding.method !== "reviewed" || basename9(source.path) !== "settings.json"))
|
|
43517
43796
|
throw new Error("Claude settings witnesses require explicit reviewed Claude configuration");
|
|
43518
43797
|
if ((source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2") && (binding.agent !== "claude" || binding.method !== "reviewed"))
|
|
43519
43798
|
throw new Error("Claude marketplace witnesses require explicit reviewed Claude discovery");
|
|
43799
|
+
if (source.hashMode === "claude-marketplace-entry-v1" && (binding.agent !== "claude" || binding.method !== "reviewed" || !claudeMarketplaceEntrySourceValid(source)))
|
|
43800
|
+
throw new Error("Claude marketplace entry witnesses require explicit reviewed Claude discovery of one named entry");
|
|
43520
43801
|
}
|
|
43521
43802
|
function rebindAgentDiscovery(binding, changes) {
|
|
43522
43803
|
const budget2 = discoveryByteBudget();
|
|
@@ -43549,10 +43830,10 @@ function captureDiscoveryPathSources(paths) {
|
|
|
43549
43830
|
const budget2 = discoveryByteBudget();
|
|
43550
43831
|
return paths.map((path) => ({ path, hashMode: "path-bytes", sha256: hashDiscoveryPathFile(path, budget2) }));
|
|
43551
43832
|
}
|
|
43552
|
-
function assertProjectDiscovery(agent, directories, home,
|
|
43553
|
-
const homeConfigPath =
|
|
43833
|
+
function assertProjectDiscovery(agent, directories, home, canonical8 = resolve19, reviewed) {
|
|
43834
|
+
const homeConfigPath = canonical8(agentDiscoveryConfigPath(home, agent));
|
|
43554
43835
|
for (const directory of directories) {
|
|
43555
|
-
const isHome =
|
|
43836
|
+
const isHome = resolve19(directory) === resolve19(home);
|
|
43556
43837
|
if (agent === "hermes") {
|
|
43557
43838
|
assertHermesEnvironment(home);
|
|
43558
43839
|
continue;
|
|
@@ -43561,7 +43842,7 @@ function assertProjectDiscovery(agent, directories, home, canonical7 = resolve17
|
|
|
43561
43842
|
continue;
|
|
43562
43843
|
const paths = agent === "claude" ? [...isHome ? [] : [".claude/settings.json"], ".claude/settings.local.json"] : agent === "codex" ? [".codex/config.toml"] : agent === "gemini" ? [".gemini/settings.json"] : agent === "opencode" ? ["opencode.json", "opencode.jsonc", ".opencode/opencode.json", ".opencode/opencode.jsonc"] : agent === "sumi" ? ["sumi.json", "sumi.jsonc", ".sumi/sumi.json", ".sumi/sumi.jsonc"] : [".cursor/hooks.json"];
|
|
43563
43844
|
for (const suffix of paths) {
|
|
43564
|
-
const path =
|
|
43845
|
+
const path = canonical8(join26(directory, suffix)), raw = read2(path);
|
|
43565
43846
|
if (raw === null)
|
|
43566
43847
|
continue;
|
|
43567
43848
|
const isRootAliasedHomeConfig = agent === "claude" && suffix === ".claude/settings.json" || agent === "codex" && suffix === ".codex/config.toml";
|
|
@@ -43577,7 +43858,7 @@ function assertProjectDiscovery(agent, directories, home, canonical7 = resolve17
|
|
|
43577
43858
|
const managed = reviewed.sources.flatMap((source) => source.hashMode === "claude-plugin-registry" ? source.managedPlugins ?? [] : []);
|
|
43578
43859
|
if (exact && projected(exact) === exact.sha256 && managed.length) {
|
|
43579
43860
|
const bindings = managed.map((item) => readPluginBinding(item.storeRoot, item.bindingId));
|
|
43580
|
-
admittedPlugins = Object.entries(config.enabledPlugins).every(([id2, enabled]) => typeof enabled === "boolean" && bindings.some((binding) => binding.target.pluginId === id2 && binding.target.registrations.some((scope) => scope.scope === "project" && scope.projectPath ===
|
|
43861
|
+
admittedPlugins = Object.entries(config.enabledPlugins).every(([id2, enabled]) => typeof enabled === "boolean" && bindings.some((binding) => binding.target.pluginId === id2 && binding.target.registrations.some((scope) => scope.scope === "project" && scope.projectPath === canonical8(directory))));
|
|
43581
43862
|
}
|
|
43582
43863
|
}
|
|
43583
43864
|
if (keys2.some((key) => config[key] !== undefined && !(key === "enabledPlugins" && admittedPlugins)) || config.disableAllHooks === true || config.disableBundledSkills === false || config.hooksConfig?.enabled === false || config.permission?.skill !== undefined || config.permissions?.deny?.some((rule) => typeof rule === "string" && /^Skill(?:\(|$)/.test(rule)))
|
|
@@ -43585,13 +43866,13 @@ function assertProjectDiscovery(agent, directories, home, canonical7 = resolve17
|
|
|
43585
43866
|
}
|
|
43586
43867
|
if (agent === "sumi")
|
|
43587
43868
|
for (const name of ["plugin", "plugins"]) {
|
|
43588
|
-
const path =
|
|
43869
|
+
const path = canonical8(join26(directory, ".sumi", name));
|
|
43589
43870
|
safe4(path);
|
|
43590
43871
|
if (lstatSync21(path, { throwIfNoEntry: false })?.isDirectory() && readdirSync7(path).length)
|
|
43591
43872
|
throw new Error(`NATIVE_SKILL_DRIFT: project Sumi plugins require a dedicated discovery review: ${path}`);
|
|
43592
43873
|
}
|
|
43593
43874
|
if (agent === "claude") {
|
|
43594
|
-
const commands =
|
|
43875
|
+
const commands = canonical8(join26(directory, ".claude/commands"));
|
|
43595
43876
|
safe4(commands);
|
|
43596
43877
|
if (lstatSync21(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync7(commands).length)
|
|
43597
43878
|
throw new Error("NATIVE_SKILL_DRIFT: legacy project command discovery requires a dedicated format adapter");
|
|
@@ -43603,11 +43884,37 @@ function agentDiscoveryConfigPath(home, agent) {
|
|
|
43603
43884
|
return sumiConfigPath(home);
|
|
43604
43885
|
return join26(home, agent === "hermes" ? ".hermes/config.yaml" : agent === "opencode" ? ".config/opencode/opencode.json" : `.${agent}/${agent === "codex" ? "config.toml" : agent === "cursor" ? "hooks.json" : "settings.json"}`);
|
|
43605
43886
|
}
|
|
43887
|
+
function verifyAutomaticDiscoveryClosure(binding, options) {
|
|
43888
|
+
const command = DISCOVERY_RUNTIME_COMMANDS[binding.agent], recorded = options.executable;
|
|
43889
|
+
const onPath = discoveryExecutable(binding.agent);
|
|
43890
|
+
let runtime, gap;
|
|
43891
|
+
if (recorded) {
|
|
43892
|
+
runtime = recordedDiscoveryExecutable(binding.agent, recorded);
|
|
43893
|
+
if (runtime && runtime.target !== recorded.target)
|
|
43894
|
+
throw new Error(`${options.change}: the recorded ${binding.agent} executable now resolves to ${quotedPath(runtime.target)}, not the reviewed ${quotedPath(recorded.target)}`);
|
|
43895
|
+
if (onPath && onPath.target !== recorded.target)
|
|
43896
|
+
throw new Error(`${options.change}: the "${command}" on this process's PATH resolves to ${quotedPath(onPath.target)}, not the reviewed ${quotedPath(recorded.target)}`);
|
|
43897
|
+
if (!runtime)
|
|
43898
|
+
gap = `the recorded executable ${quotedPath(recorded.path)} no longer resolves. Restore it, or review the change with skills hook install`;
|
|
43899
|
+
} else {
|
|
43900
|
+
runtime = onPath;
|
|
43901
|
+
if (!runtime)
|
|
43902
|
+
gap = "it is not on this process's PATH, and the reviewed policy has no recorded executable path. Run with the PATH used for the review, or run skills hook install there to record it";
|
|
43903
|
+
}
|
|
43904
|
+
const current = resolveAgentDiscovery({ home: options.home, agent: binding.agent, canonical: options.canonical, executable: runtime });
|
|
43905
|
+
if (JSON.stringify(current) === JSON.stringify(binding))
|
|
43906
|
+
return;
|
|
43907
|
+
const reviewedWithRuntime = (binding.builtinNames?.length ?? 0) > 0 || binding.sources.some((source) => basename9(source.path) === "package.json");
|
|
43908
|
+
const otherwiseCurrent = current.method === binding.method && JSON.stringify(current.roots) === JSON.stringify(binding.roots) && JSON.stringify(current.directories) === JSON.stringify(binding.directories) && current.sources.every((source) => binding.sources.some((saved) => isDeepStrictEqual6(saved, source)));
|
|
43909
|
+
if (command && gap && runtime === null && reviewedWithRuntime && otherwiseCurrent)
|
|
43910
|
+
throw discoveryRootUnresolved(binding.agent, command, gap);
|
|
43911
|
+
throw new Error(options.change);
|
|
43912
|
+
}
|
|
43606
43913
|
function resolveAgentDiscovery(options) {
|
|
43607
|
-
const
|
|
43914
|
+
const canonical8 = options.canonical ?? resolve19, home = resolve19(options.home), agent = options.agent;
|
|
43608
43915
|
const sources = [], roots = new Set, builtinNames = [];
|
|
43609
43916
|
const witness = (path, format, fields2, hashMode) => {
|
|
43610
|
-
const source = { path:
|
|
43917
|
+
const source = { path: canonical8(path), sha256: null, ...format ? { format, fields: fields2 } : {}, ...hashMode ? { hashMode } : {} };
|
|
43611
43918
|
source.sha256 = projected(source);
|
|
43612
43919
|
sources.push(source);
|
|
43613
43920
|
return read2(source.path);
|
|
@@ -43629,13 +43936,13 @@ function resolveAgentDiscovery(options) {
|
|
|
43629
43936
|
unresolved("JSONC configuration requires a supported format adapter");
|
|
43630
43937
|
for (const root2 of [directory, join26(home, ".claude"), join26(home, ".agents")])
|
|
43631
43938
|
for (const name of ["skill", "skills"])
|
|
43632
|
-
roots.add(
|
|
43939
|
+
roots.add(canonical8(join26(root2, name)));
|
|
43633
43940
|
if (config.skills !== undefined && (!Array.isArray(config.skills) || config.skills.some((path) => typeof path !== "string")))
|
|
43634
43941
|
unresolved("skills must be a string array");
|
|
43635
43942
|
for (const value of config.skills ?? []) {
|
|
43636
|
-
if (typeof value !== "string" || /[\0$]/.test(value) || !value || !(
|
|
43943
|
+
if (typeof value !== "string" || /[\0$]/.test(value) || !value || !(isAbsolute20(value) || value.startsWith("~/")))
|
|
43637
43944
|
unresolved("remote or relative skill sources need a dedicated discovery adapter");
|
|
43638
|
-
roots.add(
|
|
43945
|
+
roots.add(canonical8(value.startsWith("~/") ? join26(home, value.slice(2)) : value));
|
|
43639
43946
|
}
|
|
43640
43947
|
for (const key of ["plugin", "plugins"])
|
|
43641
43948
|
if (config[key] !== undefined && !Array.isArray(config[key]))
|
|
@@ -43674,23 +43981,23 @@ function resolveAgentDiscovery(options) {
|
|
|
43674
43981
|
continue;
|
|
43675
43982
|
if (normalized.startsWith("~") && normalized !== "~" && !normalized.startsWith("~/"))
|
|
43676
43983
|
unresolved("user-specific tilde expansion requires a separate discovery adapter");
|
|
43677
|
-
const path = normalized === "~" ? home : normalized.startsWith("~/") ? join26(home, normalized.slice(2)) :
|
|
43984
|
+
const path = normalized === "~" ? home : normalized.startsWith("~/") ? join26(home, normalized.slice(2)) : resolve19(home, ".hermes", normalized);
|
|
43678
43985
|
safe4(path);
|
|
43679
43986
|
roots.add(path);
|
|
43680
43987
|
}
|
|
43681
43988
|
}
|
|
43682
43989
|
if (agent === "gemini") {
|
|
43683
|
-
const executable2 =
|
|
43990
|
+
const executable2 = options.executable === undefined ? discoveryExecutable(agent) : options.executable;
|
|
43684
43991
|
if (executable2) {
|
|
43685
43992
|
let packageRoot;
|
|
43686
|
-
for (let directory =
|
|
43993
|
+
for (let directory = dirname17(executable2.target), depth = 0;depth < 8; directory = dirname17(directory), depth++) {
|
|
43687
43994
|
const path = join26(directory, "package.json"), raw = read2(path);
|
|
43688
43995
|
if (raw !== null && parseConfig(raw, path).name === "@google/gemini-cli") {
|
|
43689
43996
|
packageRoot = directory;
|
|
43690
43997
|
witness(path);
|
|
43691
43998
|
break;
|
|
43692
43999
|
}
|
|
43693
|
-
if (
|
|
44000
|
+
if (dirname17(directory) === directory)
|
|
43694
44001
|
break;
|
|
43695
44002
|
}
|
|
43696
44003
|
if (!packageRoot)
|
|
@@ -43713,11 +44020,11 @@ function resolveAgentDiscovery(options) {
|
|
|
43713
44020
|
if (retained.agent !== agent || retained.method !== "reviewed")
|
|
43714
44021
|
unresolved("invalid retained review");
|
|
43715
44022
|
verifyAgentDiscovery(retained);
|
|
43716
|
-
if (!retained.sources.some((source) => source.path ===
|
|
44023
|
+
if (!retained.sources.some((source) => source.path === canonical8(configPath) && source.format === undefined && source.fields === undefined))
|
|
43717
44024
|
unresolved("retained review is missing the full agent configuration source");
|
|
43718
|
-
if (retained.sources.some((source) => (source.hashMode === "sumi-settings-v1" || source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")))) && source.path !==
|
|
44025
|
+
if (retained.sources.some((source) => (source.hashMode === "sumi-settings-v1" || source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")))) && source.path !== canonical8(configPath)))
|
|
43719
44026
|
unresolved("retained settings witness names another configuration source");
|
|
43720
|
-
const covered = supersedesSettingsProjection(agent, retained.sources,
|
|
44027
|
+
const covered = supersedesSettingsProjection(agent, retained.sources, canonical8(configPath)) ? sources.filter((source) => !isSupersededSettingsProjection(agent, canonical8(configPath), source)) : sources;
|
|
43721
44028
|
if (covered.some((source) => !retained.sources.some((saved) => isDeepStrictEqual6(saved, source))) || [...roots].some((root2) => !retained.roots.includes(root2)) || agent === "gemini" && JSON.stringify(retained.builtinNames) !== JSON.stringify(builtinNames))
|
|
43722
44029
|
unresolved("retained review is missing current runtime discovery coverage");
|
|
43723
44030
|
return retained;
|
|
@@ -43729,15 +44036,15 @@ function resolveAgentDiscovery(options) {
|
|
|
43729
44036
|
if (review.sources.some((source) => source.format !== undefined || source.fields !== undefined))
|
|
43730
44037
|
throw new Error("Explicit discovery reviews require full source-file hashes");
|
|
43731
44038
|
verifyAgentDiscovery(supplied);
|
|
43732
|
-
if (review.sources.some((source) => (source.hashMode === "sumi-settings-v1" || source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")))) && source.path !==
|
|
44039
|
+
if (review.sources.some((source) => (source.hashMode === "sumi-settings-v1" || source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")))) && source.path !== canonical8(configPath)))
|
|
43733
44040
|
throw new Error("Semantic settings witnesses must name the configured agent configuration source");
|
|
43734
|
-
if (!review.sources.some((source) => source.path ===
|
|
44041
|
+
if (!review.sources.some((source) => source.path === canonical8(configPath)))
|
|
43735
44042
|
throw new Error("Discovery review must include the agent configuration source");
|
|
43736
|
-
const reviewedSources = supersedesSettingsProjection(agent, review.sources,
|
|
44043
|
+
const reviewedSources = supersedesSettingsProjection(agent, review.sources, canonical8(configPath)) ? sources.filter((source) => !isSupersededSettingsProjection(agent, canonical8(configPath), source)) : sources;
|
|
43737
44044
|
const reviewedSourcesWithManifestProjection = review.sources.map((source) => {
|
|
43738
|
-
if (agent !== "claude" || source.sha256 === null || source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || source.hashMode !== undefined && source.hashMode !== "bytes" ||
|
|
44045
|
+
if (agent !== "claude" || source.sha256 === null || source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || source.hashMode !== undefined && source.hashMode !== "bytes" || basename9(source.path) !== "plugin.json" || !source.path.endsWith(join26(sep6, ".claude-plugin", "plugin.json")))
|
|
43739
44046
|
return source;
|
|
43740
|
-
const pluginRoot =
|
|
44047
|
+
const pluginRoot = dirname17(dirname17(source.path)), hooksPath = join26(pluginRoot, "hooks/hooks.json");
|
|
43741
44048
|
const hookStat = lstatSync21(hooksPath, { throwIfNoEntry: false });
|
|
43742
44049
|
const text2 = read2(source.path);
|
|
43743
44050
|
if (text2 === null)
|
|
@@ -43752,13 +44059,13 @@ function resolveAgentDiscovery(options) {
|
|
|
43752
44059
|
if (manifest.hooks !== undefined) {
|
|
43753
44060
|
if (typeof manifest.hooks !== "string")
|
|
43754
44061
|
throw new Error("Reviewed Claude plugin manifest has an unsupported hooks target");
|
|
43755
|
-
const declaredHookPath =
|
|
44062
|
+
const declaredHookPath = resolve19(pluginRoot, manifest.hooks);
|
|
43756
44063
|
if (!declaredHookPath.startsWith(pluginRoot + sep6))
|
|
43757
44064
|
throw new Error("Reviewed Claude plugin hooks target escapes its root");
|
|
43758
44065
|
reviewedHookPaths.add(declaredHookPath);
|
|
43759
44066
|
}
|
|
43760
44067
|
for (const hooksFile of reviewedHookPaths)
|
|
43761
|
-
if (!review.sources.some((hook) => hook.path ===
|
|
44068
|
+
if (!review.sources.some((hook) => hook.path === canonical8(hooksFile) && hook.sha256 !== null && hook.format === undefined && hook.fields === undefined && hook.managedPlugins === undefined && (hook.hashMode === undefined || hook.hashMode === "bytes")))
|
|
43762
44069
|
throw new Error("Reviewed Claude plugin manifest requires separately reviewed exact hook file sources");
|
|
43763
44070
|
return { path: source.path, sha256: manifestSha256, hashMode: "claude-plugin-manifest-v1" };
|
|
43764
44071
|
});
|
|
@@ -43767,7 +44074,7 @@ function resolveAgentDiscovery(options) {
|
|
|
43767
44074
|
return { ...supplied, roots: [...new Set([...roots, ...supplied.roots])].sort(), sources: unique, ...agent === "gemini" ? { builtinNames } : {} };
|
|
43768
44075
|
}
|
|
43769
44076
|
function plugin(root2) {
|
|
43770
|
-
root2 =
|
|
44077
|
+
root2 = canonical8(root2);
|
|
43771
44078
|
safe4(root2);
|
|
43772
44079
|
const manifestPath = join26(root2, agent === "claude" ? ".claude-plugin/plugin.json" : ".codex-plugin/plugin.json");
|
|
43773
44080
|
const raw = witness(manifestPath, undefined, undefined, agent === "claude" ? "claude-plugin-manifest-v1" : undefined);
|
|
@@ -43790,16 +44097,16 @@ function resolveAgentDiscovery(options) {
|
|
|
43790
44097
|
if (agent === "claude")
|
|
43791
44098
|
roots.add(join26(root2, "skills"));
|
|
43792
44099
|
for (const value of declared) {
|
|
43793
|
-
const path =
|
|
44100
|
+
const path = resolve19(root2, value);
|
|
43794
44101
|
if (path !== root2 && !path.startsWith(root2 + sep6))
|
|
43795
44102
|
unresolved("plugin skill path escapes its root");
|
|
43796
|
-
roots.add(path.endsWith(`${sep6}SKILL.md`) ?
|
|
44103
|
+
roots.add(path.endsWith(`${sep6}SKILL.md`) ? dirname17(path) : path);
|
|
43797
44104
|
}
|
|
43798
44105
|
}
|
|
43799
44106
|
if (agent === "claude") {
|
|
43800
44107
|
const registrations = witness(join26(home, ".claude/plugins/installed_plugins.json"));
|
|
43801
44108
|
const installed = registrations === null ? {} : parseConfig(registrations, join26(home, ".claude/plugins/installed_plugins.json")).plugins;
|
|
43802
|
-
const commands =
|
|
44109
|
+
const commands = canonical8(join26(home, ".claude/commands"));
|
|
43803
44110
|
safe4(commands);
|
|
43804
44111
|
if (lstatSync21(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync7(commands).length)
|
|
43805
44112
|
unresolved("legacy home command discovery requires a dedicated format adapter");
|
|
@@ -43821,7 +44128,7 @@ function resolveAgentDiscovery(options) {
|
|
|
43821
44128
|
unresolved("unsupported plugin enablement");
|
|
43822
44129
|
const split = id2.lastIndexOf("@"), name = id2.slice(0, split), marketplace = id2.slice(split + 1);
|
|
43823
44130
|
const market = config.marketplaces?.[marketplace] ?? (marketplace === "personal" ? { source_type: "local", source: home } : undefined);
|
|
43824
|
-
if (split < 1 || market?.source_type !== "local" || typeof market.source !== "string" || !
|
|
44131
|
+
if (split < 1 || market?.source_type !== "local" || typeof market.source !== "string" || !isAbsolute20(market.source))
|
|
43825
44132
|
unresolved("enabled plugin marketplace is not an explicit local source");
|
|
43826
44133
|
const catalogText = witness(join26(market.source, ".agents/plugins/marketplace.json"));
|
|
43827
44134
|
if (catalogText === null)
|
|
@@ -43829,7 +44136,7 @@ function resolveAgentDiscovery(options) {
|
|
|
43829
44136
|
const catalog = parseConfig(catalogText, join26(market.source, ".agents/plugins/marketplace.json")), matches = Array.isArray(catalog.plugins) ? catalog.plugins.filter((item) => item.name === name) : [];
|
|
43830
44137
|
if (matches.length !== 1 || matches[0]?.source?.source !== "local" || typeof matches[0]?.source?.path !== "string")
|
|
43831
44138
|
unresolved("plugin catalog source is missing or ambiguous");
|
|
43832
|
-
plugin(
|
|
44139
|
+
plugin(resolve19(market.source, matches[0].source.path));
|
|
43833
44140
|
}
|
|
43834
44141
|
} else if (agent === "opencode") {
|
|
43835
44142
|
if (witness(join26(home, ".config/opencode/opencode.jsonc")) !== null || witness(join26(home, ".config/opencode/config.json")) !== null)
|
|
@@ -43837,7 +44144,7 @@ function resolveAgentDiscovery(options) {
|
|
|
43837
44144
|
if ((config.plugin?.length ?? 0) > 0 || config.skills?.urls?.length)
|
|
43838
44145
|
unresolved("external plugin or remote skill source");
|
|
43839
44146
|
for (const path of config.skills?.paths ?? []) {
|
|
43840
|
-
if (typeof path !== "string" || !
|
|
44147
|
+
if (typeof path !== "string" || !isAbsolute20(path))
|
|
43841
44148
|
unresolved("relative or malformed added skill root");
|
|
43842
44149
|
roots.add(path);
|
|
43843
44150
|
}
|
|
@@ -43846,7 +44153,7 @@ function resolveAgentDiscovery(options) {
|
|
|
43846
44153
|
if (lstatSync21(localPlugins, { throwIfNoEntry: false }) && readdirSync7(localPlugins).some((name) => name !== "skills-cli.js"))
|
|
43847
44154
|
unresolved("additional local plugin hooks require review");
|
|
43848
44155
|
} else if (agent === "sumi") {
|
|
43849
|
-
if ((config.plugin?.length ?? 0) > 0 || (config.plugins?.length ?? 0) > 0 || sources.some((source) => source.path !==
|
|
44156
|
+
if ((config.plugin?.length ?? 0) > 0 || (config.plugins?.length ?? 0) > 0 || sources.some((source) => source.path !== canonical8(configPath) && source.path !== canonical8(join26(sumiConfigDirectory(home), "sumi.jsonc")) && source.sha256 !== null))
|
|
43850
44157
|
unresolved("external or foreign local plugins require review");
|
|
43851
44158
|
} else if (agent === "hermes") {
|
|
43852
44159
|
for (const directory of [join26(home, ".hermes/plugins"), join26(home, ".hermes/hermes-agent")]) {
|
|
@@ -43876,7 +44183,7 @@ function resolveAgentDiscovery(options) {
|
|
|
43876
44183
|
roots.add(join26(root2, "skills"));
|
|
43877
44184
|
}
|
|
43878
44185
|
}
|
|
43879
|
-
return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join26(home, ".hermes/plugins"), join26(home, ".hermes/hermes-agent")].map((path) =>
|
|
44186
|
+
return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join26(home, ".hermes/plugins"), join26(home, ".hermes/hermes-agent")].map((path) => canonical8(path))) } : {} };
|
|
43880
44187
|
}
|
|
43881
44188
|
|
|
43882
44189
|
// src/lib/agent-adapters.ts
|
|
@@ -43952,29 +44259,29 @@ var CODEX_SKILL_CONFIG_SECTIONS = /^\[\[skills\.config\]\][^\n]*(?:\n(?!\s*\[)[^
|
|
|
43952
44259
|
var codexPathConfigRefusal = () => new Error("Codex skill path controls require ordinary [[skills.config]] TOML tables or a native single-line inline array; preserve and review unsupported inline, dotted, or malformed definitions before running skills hook install");
|
|
43953
44260
|
function splitTopLevel(value, delimiter2) {
|
|
43954
44261
|
const result = [];
|
|
43955
|
-
let start = 0, square = 0, curly = 0,
|
|
44262
|
+
let start = 0, square = 0, curly = 0, quote3 = null, escaped = false;
|
|
43956
44263
|
for (let index = 0;index < value.length; index++) {
|
|
43957
44264
|
const char = value[index];
|
|
43958
|
-
if (
|
|
44265
|
+
if (quote3 === "double") {
|
|
43959
44266
|
if (escaped)
|
|
43960
44267
|
escaped = false;
|
|
43961
44268
|
else if (char === "\\")
|
|
43962
44269
|
escaped = true;
|
|
43963
44270
|
else if (char === '"')
|
|
43964
|
-
|
|
44271
|
+
quote3 = null;
|
|
43965
44272
|
continue;
|
|
43966
44273
|
}
|
|
43967
|
-
if (
|
|
44274
|
+
if (quote3 === "literal") {
|
|
43968
44275
|
if (char === "'")
|
|
43969
|
-
|
|
44276
|
+
quote3 = null;
|
|
43970
44277
|
continue;
|
|
43971
44278
|
}
|
|
43972
44279
|
if (char === '"') {
|
|
43973
|
-
|
|
44280
|
+
quote3 = "double";
|
|
43974
44281
|
continue;
|
|
43975
44282
|
}
|
|
43976
44283
|
if (char === "'") {
|
|
43977
|
-
|
|
44284
|
+
quote3 = "literal";
|
|
43978
44285
|
continue;
|
|
43979
44286
|
}
|
|
43980
44287
|
if (char === "[")
|
|
@@ -43992,7 +44299,7 @@ function splitTopLevel(value, delimiter2) {
|
|
|
43992
44299
|
start = index + 1;
|
|
43993
44300
|
}
|
|
43994
44301
|
}
|
|
43995
|
-
if (
|
|
44302
|
+
if (quote3 !== null || square !== 0 || curly !== 0)
|
|
43996
44303
|
return null;
|
|
43997
44304
|
result.push(value.slice(start));
|
|
43998
44305
|
return result;
|
|
@@ -44000,29 +44307,29 @@ function splitTopLevel(value, delimiter2) {
|
|
|
44000
44307
|
function inlineArrayEnd(value) {
|
|
44001
44308
|
if (!value.startsWith("["))
|
|
44002
44309
|
return null;
|
|
44003
|
-
let square = 0, curly = 0,
|
|
44310
|
+
let square = 0, curly = 0, quote3 = null, escaped = false;
|
|
44004
44311
|
for (let index = 0;index < value.length; index++) {
|
|
44005
44312
|
const char = value[index];
|
|
44006
|
-
if (
|
|
44313
|
+
if (quote3 === "double") {
|
|
44007
44314
|
if (escaped)
|
|
44008
44315
|
escaped = false;
|
|
44009
44316
|
else if (char === "\\")
|
|
44010
44317
|
escaped = true;
|
|
44011
44318
|
else if (char === '"')
|
|
44012
|
-
|
|
44319
|
+
quote3 = null;
|
|
44013
44320
|
continue;
|
|
44014
44321
|
}
|
|
44015
|
-
if (
|
|
44322
|
+
if (quote3 === "literal") {
|
|
44016
44323
|
if (char === "'")
|
|
44017
|
-
|
|
44324
|
+
quote3 = null;
|
|
44018
44325
|
continue;
|
|
44019
44326
|
}
|
|
44020
44327
|
if (char === '"') {
|
|
44021
|
-
|
|
44328
|
+
quote3 = "double";
|
|
44022
44329
|
continue;
|
|
44023
44330
|
}
|
|
44024
44331
|
if (char === "'") {
|
|
44025
|
-
|
|
44332
|
+
quote3 = "literal";
|
|
44026
44333
|
continue;
|
|
44027
44334
|
}
|
|
44028
44335
|
if (char === "[")
|
|
@@ -44059,7 +44366,7 @@ function inlineRowsAsTables(value, newline) {
|
|
|
44059
44366
|
const fields2 = splitTopLevel(row.slice(1, -1), ",");
|
|
44060
44367
|
if (!fields2)
|
|
44061
44368
|
return null;
|
|
44062
|
-
const lines = fields2.map((
|
|
44369
|
+
const lines = fields2.map((field3) => field3.trim()).filter(Boolean);
|
|
44063
44370
|
if (lines.some((line) => !/^(?:path|name|enabled)\s*=/.test(line)))
|
|
44064
44371
|
return null;
|
|
44065
44372
|
const keys2 = lines.map((line) => line.slice(0, line.indexOf("=")).trim());
|
|
@@ -44084,27 +44391,27 @@ function normalizeCodexInlinePathConfig(text2) {
|
|
|
44084
44391
|
const matches = [];
|
|
44085
44392
|
for (const assignment of text2.matchAll(/^([ \t]*config[ \t]*=[ \t]*)(.*?)(\r?)$/gm)) {
|
|
44086
44393
|
const rawValue = assignment[2].trimEnd();
|
|
44087
|
-
let
|
|
44394
|
+
let quote3 = null, escaped = false, comment = "";
|
|
44088
44395
|
for (let index = 0;index < rawValue.length; index++) {
|
|
44089
44396
|
const char = rawValue[index];
|
|
44090
|
-
if (
|
|
44397
|
+
if (quote3 === "double") {
|
|
44091
44398
|
if (escaped)
|
|
44092
44399
|
escaped = false;
|
|
44093
44400
|
else if (char === "\\")
|
|
44094
44401
|
escaped = true;
|
|
44095
44402
|
else if (char === '"')
|
|
44096
|
-
|
|
44403
|
+
quote3 = null;
|
|
44097
44404
|
continue;
|
|
44098
44405
|
}
|
|
44099
|
-
if (
|
|
44406
|
+
if (quote3 === "literal") {
|
|
44100
44407
|
if (char === "'")
|
|
44101
|
-
|
|
44408
|
+
quote3 = null;
|
|
44102
44409
|
continue;
|
|
44103
44410
|
}
|
|
44104
44411
|
if (char === '"')
|
|
44105
|
-
|
|
44412
|
+
quote3 = "double";
|
|
44106
44413
|
else if (char === "'")
|
|
44107
|
-
|
|
44414
|
+
quote3 = "literal";
|
|
44108
44415
|
else if (char === "#") {
|
|
44109
44416
|
comment = rawValue.slice(index);
|
|
44110
44417
|
break;
|
|
@@ -44215,9 +44522,9 @@ function disableCodexBundledSkills(text2) {
|
|
|
44215
44522
|
}
|
|
44216
44523
|
|
|
44217
44524
|
// src/cli/commands/runtime-launcher.ts
|
|
44218
|
-
import { createHash as
|
|
44219
|
-
import { closeSync as closeSync17, constants as constants14, fchmodSync as fchmodSync2, fstatSync as fstatSync17, fsyncSync as fsyncSync5, lstatSync as lstatSync22, openSync as openSync17, readFileSync as readFileSync16, readlinkSync as
|
|
44220
|
-
import { isAbsolute as
|
|
44525
|
+
import { createHash as createHash24 } from "crypto";
|
|
44526
|
+
import { closeSync as closeSync17, constants as constants14, fchmodSync as fchmodSync2, fstatSync as fstatSync17, fsyncSync as fsyncSync5, lstatSync as lstatSync22, openSync as openSync17, readFileSync as readFileSync16, readlinkSync as readlinkSync6, realpathSync as realpathSync10, symlinkSync, writeSync as writeSync3 } from "fs";
|
|
44527
|
+
import { isAbsolute as isAbsolute21 } from "path";
|
|
44221
44528
|
var PINNED_LAUNCHER_SCHEMA = "hasna-skills-pinned-launcher-v1";
|
|
44222
44529
|
var LAUNCH_CWD_VARIABLE = "HASNA_SKILLS_LAUNCH_CWD";
|
|
44223
44530
|
var PINNED_LAUNCHER_BUN_FLAGS = ["--config=/dev/null", "--no-env-file", "--no-macros", "--no-install"];
|
|
@@ -44258,10 +44565,10 @@ var PINNED_LAUNCHER_ENV_PREFIXES = ["HASNA", "SKILLS", "SKILL", "MCP", "XDG", "L
|
|
|
44258
44565
|
var ENV_PREFIX = new RegExp(`^(${PINNED_LAUNCHER_ENV_PREFIXES.join("|")})_`);
|
|
44259
44566
|
var ENV_EXACT = new Set(PINNED_LAUNCHER_ENV_NAMES);
|
|
44260
44567
|
function sha2562(bytes) {
|
|
44261
|
-
return
|
|
44568
|
+
return createHash24("sha256").update(bytes).digest("hex");
|
|
44262
44569
|
}
|
|
44263
44570
|
function assertLauncherPath(value, code) {
|
|
44264
|
-
if (typeof value !== "string" || !
|
|
44571
|
+
if (typeof value !== "string" || !isAbsolute21(value) || /['\x00-\x1f\x7f]/.test(value))
|
|
44265
44572
|
throw new Error(code);
|
|
44266
44573
|
}
|
|
44267
44574
|
function renderPinnedLauncher(binding) {
|
|
@@ -44351,7 +44658,7 @@ function assertPinnedLauncherRuntimeSafe(runtime) {
|
|
|
44351
44658
|
}
|
|
44352
44659
|
|
|
44353
44660
|
// src/lib/agent-integration.ts
|
|
44354
|
-
var sha4 = (data) =>
|
|
44661
|
+
var sha4 = (data) => createHash25("sha256").update(data).digest("hex");
|
|
44355
44662
|
var ROOTS = NATIVE_SKILL_ROOTS;
|
|
44356
44663
|
function hasTrustedDarwinAcl(fd, allowDenyOnly = false) {
|
|
44357
44664
|
try {
|
|
@@ -44401,9 +44708,10 @@ function isSystemRootAlias(path) {
|
|
|
44401
44708
|
return false;
|
|
44402
44709
|
const target = `/private${path}`, link = `private${path}`;
|
|
44403
44710
|
const identity5 = (stat2) => `${stat2.dev}:${stat2.ino}:${stat2.ctimeNs}:${stat2.uid}:${stat2.mode}`;
|
|
44711
|
+
const directoryIdentity = (stat2) => `${stat2.dev}:${stat2.ino}:${stat2.uid}:${stat2.mode}`;
|
|
44404
44712
|
try {
|
|
44405
44713
|
const before = lstatSync23(path, { bigint: true });
|
|
44406
|
-
if (!before.isSymbolicLink() || before.uid !== 0n ||
|
|
44714
|
+
if (!before.isSymbolicLink() || before.uid !== 0n || readlinkSync7(path) !== link)
|
|
44407
44715
|
return false;
|
|
44408
44716
|
const directories = ["/", "/private", target].map((directory) => {
|
|
44409
44717
|
const stat2 = lstatSync23(directory, { bigint: true });
|
|
@@ -44416,20 +44724,20 @@ function isSystemRootAlias(path) {
|
|
|
44416
44724
|
throw new Error("Unprotected system temporary directory");
|
|
44417
44725
|
const fd = openSync18(directory, constants15.O_RDONLY | constants15.O_DIRECTORY | constants15.O_NOFOLLOW);
|
|
44418
44726
|
try {
|
|
44419
|
-
if (
|
|
44727
|
+
if (directoryIdentity(fstatSync18(fd, { bigint: true })) !== directoryIdentity(stat2) || !hasTrustedDarwinAcl(fd) || directoryIdentity(fstatSync18(fd, { bigint: true })) !== directoryIdentity(stat2))
|
|
44420
44728
|
throw new Error("Unverified system alias directory ACL");
|
|
44421
44729
|
} finally {
|
|
44422
44730
|
closeSync18(fd);
|
|
44423
44731
|
}
|
|
44424
|
-
return { directory, identity:
|
|
44732
|
+
return { directory, identity: directoryIdentity(stat2) };
|
|
44425
44733
|
});
|
|
44426
|
-
return realpathSync11(path) === target &&
|
|
44734
|
+
return realpathSync11(path) === target && readlinkSync7(path) === link && identity5(lstatSync23(path, { bigint: true })) === identity5(before) && directories.every((item) => directoryIdentity(lstatSync23(item.directory, { bigint: true })) === item.identity);
|
|
44427
44735
|
} catch {
|
|
44428
44736
|
return false;
|
|
44429
44737
|
}
|
|
44430
44738
|
}
|
|
44431
44739
|
function canonicalSystemPath(path) {
|
|
44432
|
-
const absolute =
|
|
44740
|
+
const absolute = resolve20(path), root2 = `/${absolute.split(sep7)[1]}`;
|
|
44433
44741
|
if (process.platform !== "darwin" || !["/var", "/tmp", "/etc"].includes(root2) || !lstatSync23(root2, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
44434
44742
|
return absolute;
|
|
44435
44743
|
if (!isSystemRootAlias(root2))
|
|
@@ -44437,11 +44745,11 @@ function canonicalSystemPath(path) {
|
|
|
44437
44745
|
return `/private${absolute}`;
|
|
44438
44746
|
}
|
|
44439
44747
|
function assertSafePath(path) {
|
|
44440
|
-
let cursor =
|
|
44748
|
+
let cursor = resolve20(path);
|
|
44441
44749
|
while (true) {
|
|
44442
44750
|
if (lstatSync23(cursor, { throwIfNoEntry: false })?.isSymbolicLink() && !isSystemRootAlias(cursor))
|
|
44443
44751
|
throw new Error(`Refusing symlink path: ${cursor}`);
|
|
44444
|
-
const parent =
|
|
44752
|
+
const parent = dirname18(cursor);
|
|
44445
44753
|
if (parent === cursor)
|
|
44446
44754
|
return;
|
|
44447
44755
|
cursor = parent;
|
|
@@ -44453,13 +44761,13 @@ function readRootAlias(home, agent) {
|
|
|
44453
44761
|
const stat2 = lstatSync23(alias, { throwIfNoEntry: false, bigint: true });
|
|
44454
44762
|
if (!stat2?.isSymbolicLink())
|
|
44455
44763
|
throw new Error(`Agent root alias changed after planning: ${alias}`);
|
|
44456
|
-
const link =
|
|
44764
|
+
const link = readlinkSync7(alias), targetPath = resolve20(dirname18(alias), link);
|
|
44457
44765
|
assertSafePath(targetPath);
|
|
44458
44766
|
const targetStat = lstatSync23(targetPath, { throwIfNoEntry: false });
|
|
44459
44767
|
if (!targetStat?.isDirectory())
|
|
44460
44768
|
throw new Error(`Agent root alias must target an existing directory: ${alias}`);
|
|
44461
44769
|
const target = realpathSync11(targetPath), inside = relative5(realHome, target);
|
|
44462
|
-
if (!inside || inside === ".." || inside.startsWith(`..${sep7}`) ||
|
|
44770
|
+
if (!inside || inside === ".." || inside.startsWith(`..${sep7}`) || isAbsolute22(inside))
|
|
44463
44771
|
throw new Error(`Agent root alias target must be inside the real home: ${alias}`);
|
|
44464
44772
|
return { agent, home: realHome, alias, target, link, aliasIdentity: `${stat2.dev}:${stat2.ino}:${stat2.ctimeNs}`, targetIdentity: `${targetStat.dev}:${targetStat.ino}` };
|
|
44465
44773
|
}
|
|
@@ -44485,13 +44793,13 @@ function disabledCodexSkillPaths(config, aliases) {
|
|
|
44485
44793
|
const rows = skills.config;
|
|
44486
44794
|
if (!Array.isArray(rows))
|
|
44487
44795
|
return [];
|
|
44488
|
-
if (rows.some((entry) => !entry || typeof entry !== "object" || Array.isArray(entry) || typeof entry.enabled !== "boolean" || entry.path !== undefined === (entry.name !== undefined) || entry.path !== undefined && (typeof entry.path !== "string" || !
|
|
44796
|
+
if (rows.some((entry) => !entry || typeof entry !== "object" || Array.isArray(entry) || typeof entry.enabled !== "boolean" || entry.path !== undefined === (entry.name !== undefined) || entry.path !== undefined && (typeof entry.path !== "string" || !isAbsolute22(entry.path)) || entry.name !== undefined && (typeof entry.name !== "string" || !entry.name.trim())))
|
|
44489
44797
|
return [];
|
|
44490
44798
|
if (rows.some((entry) => entry.name !== undefined && entry.enabled !== false))
|
|
44491
44799
|
return [];
|
|
44492
44800
|
const settings = new Map;
|
|
44493
44801
|
for (const entry of rows) {
|
|
44494
|
-
if (typeof entry.path !== "string" || !
|
|
44802
|
+
if (typeof entry.path !== "string" || !isAbsolute22(entry.path))
|
|
44495
44803
|
continue;
|
|
44496
44804
|
let document2;
|
|
44497
44805
|
try {
|
|
@@ -44503,7 +44811,7 @@ function disabledCodexSkillPaths(config, aliases) {
|
|
|
44503
44811
|
continue;
|
|
44504
44812
|
settings.set(document2, [...settings.get(document2) ?? [], entry.enabled === false]);
|
|
44505
44813
|
}
|
|
44506
|
-
return [...settings].filter(([, values]) => values.length === 1 && values[0] === true).map(([document2]) =>
|
|
44814
|
+
return [...settings].filter(([, values]) => values.length === 1 && values[0] === true).map(([document2]) => dirname18(document2));
|
|
44507
44815
|
}
|
|
44508
44816
|
function recheckRootAliases(aliases) {
|
|
44509
44817
|
for (const binding of aliases) {
|
|
@@ -44545,7 +44853,7 @@ function readNativeBytes(path, maximum = 64 * 1024 * 1024) {
|
|
|
44545
44853
|
}
|
|
44546
44854
|
}
|
|
44547
44855
|
function treeHash(root2) {
|
|
44548
|
-
const hash2 =
|
|
44856
|
+
const hash2 = createHash25("sha256");
|
|
44549
44857
|
let bytes = 0, files = 0;
|
|
44550
44858
|
function visit2(path) {
|
|
44551
44859
|
const stat2 = lstatSync23(path);
|
|
@@ -44577,20 +44885,20 @@ function selectNativeMigrationTargets(inventory, manifest) {
|
|
|
44577
44885
|
const identities = new Set;
|
|
44578
44886
|
const selected = [];
|
|
44579
44887
|
for (const target of manifest.targets) {
|
|
44580
|
-
if (!
|
|
44888
|
+
if (!isAbsolute22(target.projectRoot) || resolve20(target.projectRoot) !== target.projectRoot)
|
|
44581
44889
|
throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
|
|
44582
|
-
const projectRoot = canonicalSystemPath(target.projectRoot), normalized = relative5(projectRoot,
|
|
44890
|
+
const projectRoot = canonicalSystemPath(target.projectRoot), normalized = relative5(projectRoot, resolve20(projectRoot, target.path));
|
|
44583
44891
|
if (!existsSync7(projectRoot) || !lstatSync23(projectRoot).isDirectory())
|
|
44584
44892
|
throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
|
|
44585
44893
|
assertSafePath(projectRoot);
|
|
44586
|
-
if (
|
|
44894
|
+
if (isAbsolute22(target.path) || target.path.includes("\\") || target.path.includes("\x00") || !normalized || normalized === ".." || normalized.startsWith(`..${sep7}`) || normalized !== target.path || !/^[0-9a-f]{64}$/.test(target.treeSha256))
|
|
44587
44895
|
throw new Error(`Invalid native migration target: ${target.path}`);
|
|
44588
44896
|
const identity5 = `${target.agent}\x00${canonicalSystemPath(projectRoot)}\x00${normalized}`;
|
|
44589
44897
|
if (identities.has(identity5))
|
|
44590
44898
|
throw new Error(`Duplicate native migration target: ${target.path}`);
|
|
44591
44899
|
identities.add(identity5);
|
|
44592
|
-
const expected = canonicalSystemPath(
|
|
44593
|
-
const matches = inventory.filter((entry2) => entry2.agent === target.agent &&
|
|
44900
|
+
const expected = canonicalSystemPath(resolve20(target.projectRoot, target.path));
|
|
44901
|
+
const matches = inventory.filter((entry2) => entry2.agent === target.agent && resolve20(entry2.path) === expected);
|
|
44594
44902
|
if (matches.length !== 1)
|
|
44595
44903
|
throw new Error(`Native migration target was not found exactly once: ${target.agent} ${target.projectRoot}/${target.path}`);
|
|
44596
44904
|
const entry = matches[0];
|
|
@@ -44609,7 +44917,7 @@ function projectAncestorDirectories(projects) {
|
|
|
44609
44917
|
if (depth >= 100)
|
|
44610
44918
|
throw new Error("NATIVE_SKILL_DRIFT: project ancestor discovery limit exceeded");
|
|
44611
44919
|
directories.add(path);
|
|
44612
|
-
const parent =
|
|
44920
|
+
const parent = dirname18(path);
|
|
44613
44921
|
if (parent === path)
|
|
44614
44922
|
break;
|
|
44615
44923
|
path = parent;
|
|
@@ -44618,7 +44926,7 @@ function projectAncestorDirectories(projects) {
|
|
|
44618
44926
|
return [...directories];
|
|
44619
44927
|
}
|
|
44620
44928
|
function isCodexSkillDiscoveryInput(path) {
|
|
44621
|
-
for (let cursor = canonicalSystemPath(path);cursor !==
|
|
44929
|
+
for (let cursor = canonicalSystemPath(path);cursor !== dirname18(cursor); cursor = dirname18(cursor)) {
|
|
44622
44930
|
if (ROOTS.some(([agent, root2]) => agent === "codex" && cursor.endsWith(join27(sep7, root2))))
|
|
44623
44931
|
return true;
|
|
44624
44932
|
}
|
|
@@ -44626,9 +44934,9 @@ function isCodexSkillDiscoveryInput(path) {
|
|
|
44626
44934
|
}
|
|
44627
44935
|
function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
44628
44936
|
home = canonicalSystemPath(home);
|
|
44629
|
-
if (options.reviewedCacheAlias !== undefined && (!options.includeVendor || !
|
|
44937
|
+
if (options.reviewedCacheAlias !== undefined && (!options.includeVendor || !isAbsolute22(options.reviewedCacheAlias) || resolve20(options.reviewedCacheAlias) !== options.reviewedCacheAlias))
|
|
44630
44938
|
throw new Error("A reviewed cache alias requires vendor inventory and an exact absolute path");
|
|
44631
|
-
if (options.disabledVendorPaths?.some((path) => !
|
|
44939
|
+
if (options.disabledVendorPaths?.some((path) => !isAbsolute22(path) || resolve20(path) !== path))
|
|
44632
44940
|
throw new Error("Disabled vendor paths must be exact absolute paths");
|
|
44633
44941
|
const reviewedCacheAlias = options.reviewedCacheAlias === undefined ? undefined : canonicalSystemPath(options.reviewedCacheAlias);
|
|
44634
44942
|
const disabledVendorPaths = new Set((options.disabledVendorPaths ?? []).map(canonicalSystemPath));
|
|
@@ -44647,7 +44955,7 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
44647
44955
|
roots.push(["sumi", canonicalAgentPath(join27(project, directory, name), aliases)]);
|
|
44648
44956
|
}
|
|
44649
44957
|
const installationInputs = options.codexInstallationInputRoots ?? [];
|
|
44650
|
-
if (installationInputs.some((input) =>
|
|
44958
|
+
if (installationInputs.some((input) => resolve20(input) !== input || realpathSync11(input) !== input || roots.some(([agent, path]) => agent === "codex" && (path === input || path.startsWith(input + sep7) || input.startsWith(path + sep7)))))
|
|
44651
44959
|
throw new Error("Native installation input overlaps an unconditional skill-loading root");
|
|
44652
44960
|
const entries = [], seen = new Set;
|
|
44653
44961
|
const cacheScans = new Map, maxAliasProofEntries = 1e4;
|
|
@@ -44661,11 +44969,11 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
44661
44969
|
}
|
|
44662
44970
|
let reviewedCacheAliasFound = false;
|
|
44663
44971
|
function verifiedSiblingCacheAlias(agent, path, parent) {
|
|
44664
|
-
const link =
|
|
44665
|
-
if (
|
|
44972
|
+
const link = readlinkSync7(path), lexicalTarget = resolve20(parent, link);
|
|
44973
|
+
if (isAbsolute22(link) ? link !== lexicalTarget : dirname18(link) !== ".")
|
|
44666
44974
|
return false;
|
|
44667
44975
|
const target = canonicalSystemPath(lexicalTarget);
|
|
44668
|
-
if (
|
|
44976
|
+
if (dirname18(target) !== parent)
|
|
44669
44977
|
return false;
|
|
44670
44978
|
if (!lstatSync23(target, { throwIfNoEntry: false })?.isDirectory())
|
|
44671
44979
|
return false;
|
|
@@ -44714,17 +45022,17 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
44714
45022
|
}
|
|
44715
45023
|
const bridge = (!vendor || agent === "sumi") && isOwnedCliBridge(path, bridgePaths);
|
|
44716
45024
|
const rootAlias = aliases.find((item) => path === item.target || path.startsWith(item.target + sep7));
|
|
44717
|
-
entries.push({ agent, path, hash: treeHash(path), managed, vendor, ...agent === "codex" || isCodexSkillDiscoveryInput(path) ? { codexHome: process.env.CODEX_HOME ?? join27(home, ".codex") } : {}, ...agent === "codex" && path.startsWith(canonicalAgentPath(join27(home, ".codex", "skills", ".system"), aliases) + sep7) ? { system: true } : {}, ...bridge ? { bridge: true, bridgeHome:
|
|
45025
|
+
entries.push({ agent, path, hash: treeHash(path), managed, vendor, ...agent === "codex" || isCodexSkillDiscoveryInput(path) ? { codexHome: process.env.CODEX_HOME ?? join27(home, ".codex") } : {}, ...agent === "codex" && path.startsWith(canonicalAgentPath(join27(home, ".codex", "skills", ".system"), aliases) + sep7) ? { system: true } : {}, ...bridge ? { bridge: true, bridgeHome: resolve20(home) } : {}, ...rootAlias ? { rootAlias } : {} });
|
|
44718
45026
|
return scan;
|
|
44719
45027
|
}
|
|
44720
45028
|
if (depth > (agent === "sumi" ? 32 : vendor ? 32 : 3))
|
|
44721
45029
|
return { ...scan, complete: false };
|
|
44722
45030
|
const children = [], directory = opendirSync5(path);
|
|
44723
45031
|
try {
|
|
44724
|
-
let
|
|
44725
|
-
while ((
|
|
44726
|
-
admit(join27(path,
|
|
44727
|
-
children.push(
|
|
45032
|
+
let child2;
|
|
45033
|
+
while ((child2 = directory.readSync()) !== null) {
|
|
45034
|
+
admit(join27(path, child2.name));
|
|
45035
|
+
children.push(child2);
|
|
44728
45036
|
}
|
|
44729
45037
|
} finally {
|
|
44730
45038
|
directory.closeSync();
|
|
@@ -44740,15 +45048,15 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
44740
45048
|
const isVendor = vendor || name === ".system";
|
|
44741
45049
|
if (isVendor && !options.includeVendor)
|
|
44742
45050
|
continue;
|
|
44743
|
-
const
|
|
44744
|
-
if (isVendor && lstatSync23(
|
|
44745
|
-
const target = statSync7(
|
|
44746
|
-
if (target?.isFile() || pluginCache && target?.isDirectory() && verifiedSiblingCacheAlias(agent,
|
|
45051
|
+
const child2 = join27(path, name);
|
|
45052
|
+
if (isVendor && lstatSync23(child2, { throwIfNoEntry: false })?.isSymbolicLink()) {
|
|
45053
|
+
const target = statSync7(child2, { throwIfNoEntry: false });
|
|
45054
|
+
if (target?.isFile() || pluginCache && target?.isDirectory() && verifiedSiblingCacheAlias(agent, child2, path)) {
|
|
44747
45055
|
scan.entries++;
|
|
44748
45056
|
continue;
|
|
44749
45057
|
}
|
|
44750
45058
|
}
|
|
44751
|
-
const childScan = visit2(agent,
|
|
45059
|
+
const childScan = visit2(agent, child2, isVendor, depth + 1, pluginCache, true, configuredRoot);
|
|
44752
45060
|
scan.complete &&= childScan.complete;
|
|
44753
45061
|
scan.hasSkills ||= childScan.hasSkills;
|
|
44754
45062
|
scan.entries += childScan.entries;
|
|
@@ -44884,7 +45192,7 @@ function configureHooks(config, agent, command, profileId, nativeReady) {
|
|
|
44884
45192
|
function disableCodexSkills(text2, skills, aliases, bridgePath) {
|
|
44885
45193
|
const bundled = disableCodexBundledSkills(text2);
|
|
44886
45194
|
let result = normalizeCodexInlinePathConfig(bundled);
|
|
44887
|
-
const bridgeSelector = (entry) => typeof entry.name === "string" && entry.name.trim() === CLI_BRIDGE_NAME || typeof entry.path === "string" && [
|
|
45195
|
+
const bridgeSelector = (entry) => typeof entry.name === "string" && entry.name.trim() === CLI_BRIDGE_NAME || typeof entry.path === "string" && [resolve20(bridgePath), resolve20(join27(bridgePath, "SKILL.md"))].includes(canonicalAgentPath(entry.path, aliases));
|
|
44888
45196
|
const previousConfig = Bun.TOML.parse(bundled).skills?.config;
|
|
44889
45197
|
if (previousConfig !== undefined && (!Array.isArray(previousConfig) || previousConfig.some((entry) => !entry || typeof entry !== "object" || entry.path !== undefined && entry.name !== undefined)))
|
|
44890
45198
|
throw new Error("Codex skill controls require one path or name selector per [[skills.config]] entry; review ambiguous entries before running skills hook install");
|
|
@@ -44896,7 +45204,7 @@ function disableCodexSkills(text2, skills, aliases, bridgePath) {
|
|
|
44896
45204
|
result = result.replace(CODEX_SKILL_CONFIG_SECTIONS, (section) => {
|
|
44897
45205
|
const parsed = Bun.TOML.parse(section);
|
|
44898
45206
|
const declared = parsed.skills?.config?.[0];
|
|
44899
|
-
if (!declared || !(skill.enabled && bridgeSelector(declared)) && !(typeof declared.path === "string" && [
|
|
45207
|
+
if (!declared || !(skill.enabled && bridgeSelector(declared)) && !(typeof declared.path === "string" && [resolve20(path), resolve20(skill.path)].includes(canonicalAgentPath(declared.path, aliases))))
|
|
44900
45208
|
return section;
|
|
44901
45209
|
found = true;
|
|
44902
45210
|
return /^\s*enabled\s*=/m.test(section) ? section.replace(/^\s*enabled\s*=.*$/m, `enabled = ${skill.enabled}`) : `${section.trimEnd()}
|
|
@@ -44917,7 +45225,7 @@ enabled = false
|
|
|
44917
45225
|
return result;
|
|
44918
45226
|
}
|
|
44919
45227
|
function assertCodexInstallationInputs(home, projectDirs, inputs) {
|
|
44920
|
-
const nativeRoots = [home, ...projectAncestorDirectories(projectDirs)].flatMap((directory) => ROOTS.filter(([agent]) => agent === "codex").map(([, path]) =>
|
|
45228
|
+
const nativeRoots = [home, ...projectAncestorDirectories(projectDirs)].flatMap((directory) => ROOTS.filter(([agent]) => agent === "codex").map(([, path]) => resolve20(directory, path)));
|
|
44921
45229
|
if (inputs.some((input) => nativeRoots.some((root2) => root2 === input || root2.startsWith(input + sep7) || input.startsWith(root2 + sep7))))
|
|
44922
45230
|
throw new Error("Native installation input overlaps an unconditional skill-loading root");
|
|
44923
45231
|
}
|
|
@@ -44933,9 +45241,9 @@ function planAgentIntegration(options) {
|
|
|
44933
45241
|
throw new Error("Invalid existing Skills bridge policy");
|
|
44934
45242
|
if (policy.bridge?.agents !== undefined && (!Array.isArray(policy.bridge.agents) || policy.bridge.agents.some((agent) => !INTEGRATION_AGENTS.includes(agent))))
|
|
44935
45243
|
throw new Error("Invalid existing bridge agent inventory");
|
|
44936
|
-
for (const
|
|
44937
|
-
if (policy.bridge?.[
|
|
44938
|
-
throw new Error(`Invalid existing bridge ${
|
|
45244
|
+
for (const field3 of ["commands", "profiles"])
|
|
45245
|
+
if (policy.bridge?.[field3] !== undefined && (!policy.bridge[field3] || typeof policy.bridge[field3] !== "object" || Array.isArray(policy.bridge[field3]) || Object.entries(policy.bridge[field3]).some(([key, value]) => !INTEGRATION_AGENTS.includes(key) || typeof value !== "string" || !value || value.includes("\x00"))))
|
|
45246
|
+
throw new Error(`Invalid existing bridge ${field3} binding`);
|
|
44939
45247
|
const priorAgents = policy.bridge?.agents ?? [];
|
|
44940
45248
|
const profileId = options.profileId ?? policy.profileId ?? "default";
|
|
44941
45249
|
const validateProfile = (value) => {
|
|
@@ -44950,13 +45258,18 @@ function planAgentIntegration(options) {
|
|
|
44950
45258
|
return [agent, { command, profileId: profileId2 }];
|
|
44951
45259
|
}));
|
|
44952
45260
|
const retainedAgents = [];
|
|
45261
|
+
const priorExecutables = policy.bridge?.discoveryExecutables ?? {};
|
|
45262
|
+
const executables = new Map;
|
|
44953
45263
|
const discoveries = [...new Set(options.agents)].map((agent) => {
|
|
45264
|
+
const prior = priorExecutables[agent];
|
|
45265
|
+
const executable2 = discoveryExecutable(agent) ?? (prior ? recordedDiscoveryExecutable(agent, prior) : null);
|
|
45266
|
+
executables.set(agent, executable2);
|
|
44954
45267
|
const retainedReview = options.discoveryInputs === undefined && policy.bridge?.discovery?.[agent]?.method === "reviewed" ? { ...policy.bridge.discovery[agent], ...agent === "codex" ? { codexDisabledPluginSkills: policy.bridge.codexPluginSkills ?? [] } : {} } : undefined;
|
|
44955
45268
|
if (retainedReview) {
|
|
44956
45269
|
assertManagedAgentBridge(agent, { home, dataDir: dataDir2, projectDir: options.projectDir ?? home });
|
|
44957
45270
|
retainedAgents.push(agent);
|
|
44958
45271
|
}
|
|
44959
|
-
return resolveAgentDiscovery({ home, agent, reviewed: options.discoveryInputs, retainedReview, canonical: (path) => canonicalAgentPath(path, aliases) });
|
|
45272
|
+
return resolveAgentDiscovery({ home, agent, reviewed: options.discoveryInputs, retainedReview, canonical: (path) => canonicalAgentPath(path, aliases), executable: executable2 });
|
|
44960
45273
|
});
|
|
44961
45274
|
const codexConfigBefore = options.agents.includes("codex") ? readOptional(canonicalAgentPath(join27(home, ".codex", "config.toml"), aliases)) : null;
|
|
44962
45275
|
const codexConfig = Bun.TOML.parse(codexConfigBefore ?? "");
|
|
@@ -44964,7 +45277,7 @@ function planAgentIntegration(options) {
|
|
|
44964
45277
|
const codexPathConfig = options.agents.includes("codex") ? disableCodexSkills(codexConfigBefore ?? "", nativeSkills, aliases, canonicalAgentPath(join27(home, ".codex/skills", CLI_BRIDGE_NAME), aliases)) : undefined;
|
|
44965
45278
|
const plannedCodexRules = codexPathConfig === undefined ? undefined : Bun.TOML.parse(codexPathConfig).skills?.config ?? [];
|
|
44966
45279
|
const observedNativeSources = [];
|
|
44967
|
-
const codexPluginControls = options.codexNativeCatalog ? reviewCodexPluginControls(options.codexNativeCatalog, nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor).map((entry) => join27(entry.path, "SKILL.md")), canonicalAgentPath(join27(home, ".codex/plugins/cache"), aliases),
|
|
45280
|
+
const codexPluginControls = options.codexNativeCatalog ? reviewCodexPluginControls(options.codexNativeCatalog, nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor).map((entry) => join27(entry.path, "SKILL.md")), canonicalAgentPath(join27(home, ".codex/plugins/cache"), aliases), resolve20(options.projectDir ?? home), (path) => {
|
|
44968
45281
|
const bytes = readNativeBytes(path, 1024 * 1024);
|
|
44969
45282
|
observedNativeSources.push({ path, sha256: sha4(bytes) });
|
|
44970
45283
|
return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
@@ -45093,7 +45406,7 @@ function planAgentIntegration(options) {
|
|
|
45093
45406
|
version: CLI_BRIDGE_VERSION,
|
|
45094
45407
|
digest: CLI_BRIDGE_DIGEST,
|
|
45095
45408
|
agents: [...new Set([...priorAgents, ...options.agents])].sort(),
|
|
45096
|
-
home:
|
|
45409
|
+
home: resolve20(home),
|
|
45097
45410
|
includeVendor: true,
|
|
45098
45411
|
...options.agents.includes("hermes") ? { supervisors: { ...policy.bridge?.supervisors, hermes: { path: join27(dataDir2, "agent-hooks", "hermes.js"), runtime: process.execPath, sha256: sha4(renderHermesSupervisor(bindings.get("hermes").command, bindings.get("hermes").profileId)) } } } : {},
|
|
45099
45412
|
commands: { ...policy.bridge?.commands, ...Object.fromEntries([...bindings].map(([agent, binding]) => [agent, binding.command])) },
|
|
@@ -45103,19 +45416,30 @@ function planAgentIntegration(options) {
|
|
|
45103
45416
|
...options.codexNativeCatalog || codexPluginSkills.length || codexInactivePlugins.length || codexPluginSourceInputs.length ? { codexPluginSkills, codexInactivePlugins, codexPluginSkillReview } : {},
|
|
45104
45417
|
discovery: { ...policy.bridge?.discovery, ...Object.fromEntries(discoveryAfter.map((binding) => [binding.agent, binding])) }
|
|
45105
45418
|
} };
|
|
45419
|
+
const discoveryExecutables = { ...priorExecutables };
|
|
45420
|
+
for (const [agent, executable2] of executables) {
|
|
45421
|
+
if (executable2)
|
|
45422
|
+
discoveryExecutables[agent] = executable2;
|
|
45423
|
+
else
|
|
45424
|
+
delete discoveryExecutables[agent];
|
|
45425
|
+
}
|
|
45426
|
+
if (Object.keys(discoveryExecutables).length)
|
|
45427
|
+
nextPolicy.bridge.discoveryExecutables = discoveryExecutables;
|
|
45428
|
+
else
|
|
45429
|
+
delete nextPolicy.bridge.discoveryExecutables;
|
|
45106
45430
|
const serializedPolicy = serializeManagedSkillPolicy(nextPolicy);
|
|
45107
45431
|
if (JSON.stringify(policy) !== JSON.stringify(nextPolicy))
|
|
45108
45432
|
changes.push({ path: policyPath, before: previousPolicy, after: serializedPolicy });
|
|
45109
45433
|
recheckRootAliases(aliases);
|
|
45110
45434
|
return { dataDir: dataDir2, profileId, changes, nativeSkills, ...observedSettings ? { observedSettings } : {}, ...observedNativeSources.length ? { observedNativeSources } : {}, ...nextPolicy.bridge.codexPluginSkillReview ? { codexPluginSkillReview: nextPolicy.bridge.codexPluginSkillReview } : {}, observedPolicy: { path: policyPath, before: previousPolicy }, discoveryBefore: discoveries, discoveryAfter, ...aliases.length ? { rootAliases: aliases } : {}, ...retainedAgents.length ? { retainedReviewChecks: { home, projectDir: options.projectDir ?? home, agents: retainedAgents } } : {} };
|
|
45111
45435
|
}
|
|
45112
|
-
function hookProjectionRefusal(
|
|
45113
|
-
throw new Error(`CLAUDE_MANAGED_HOOK_${
|
|
45436
|
+
function hookProjectionRefusal(reason2) {
|
|
45437
|
+
throw new Error(`CLAUDE_MANAGED_HOOK_${reason2}`);
|
|
45114
45438
|
}
|
|
45115
45439
|
function projectedHookAcl(path, observed) {
|
|
45116
45440
|
if (process.platform !== "darwin")
|
|
45117
45441
|
return;
|
|
45118
|
-
const identity5 = (stat2) => `${stat2.dev}:${stat2.ino}:${stat2.ctimeNs}:${stat2.uid}:${stat2.mode}:${stat2.nlink}:${stat2.size}:${stat2.mtimeNs}`;
|
|
45442
|
+
const identity5 = observed.isDirectory() ? (stat2) => `${stat2.dev}:${stat2.ino}:${stat2.uid}:${stat2.mode}` : (stat2) => `${stat2.dev}:${stat2.ino}:${stat2.ctimeNs}:${stat2.uid}:${stat2.mode}:${stat2.nlink}:${stat2.size}:${stat2.mtimeNs}`;
|
|
45119
45443
|
const fd = openSync18(path, constants15.O_RDONLY | constants15.O_NOFOLLOW | constants15.O_NONBLOCK | (observed.isDirectory() ? constants15.O_DIRECTORY : 0));
|
|
45120
45444
|
try {
|
|
45121
45445
|
if (identity5(fstatSync18(fd, { bigint: true })) !== identity5(observed) || !hasTrustedDarwinAcl(fd, true) || identity5(fstatSync18(fd, { bigint: true })) !== identity5(observed) || identity5(lstatSync23(path, { bigint: true })) !== identity5(observed))
|
|
@@ -45126,18 +45450,18 @@ function projectedHookAcl(path, observed) {
|
|
|
45126
45450
|
}
|
|
45127
45451
|
function projectedHookExecutable(command, expectedResolved) {
|
|
45128
45452
|
try {
|
|
45129
|
-
if (!
|
|
45453
|
+
if (!isAbsolute22(command) || /[\0\r\n]/.test(command) || resolve20(command) !== command)
|
|
45130
45454
|
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
45131
45455
|
command = canonicalSystemPath(command);
|
|
45132
45456
|
const parents3 = (file = command) => {
|
|
45133
45457
|
const result = [];
|
|
45134
|
-
for (let path =
|
|
45458
|
+
for (let path = dirname18(file);; path = dirname18(path)) {
|
|
45135
45459
|
const stat2 = lstatSync23(path, { bigint: true });
|
|
45136
|
-
if (!stat2.isDirectory() || (stat2.mode & 0o022n) !== 0n && !(stat2.uid === 0n && (stat2.mode & 0o1000n) !== 0n))
|
|
45460
|
+
if (!stat2.isDirectory() || !trustedAncestorOwner(stat2.uid) || (stat2.mode & 0o022n) !== 0n && !(stat2.uid === 0n && (stat2.mode & 0o1000n) !== 0n))
|
|
45137
45461
|
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
45138
45462
|
projectedHookAcl(path, stat2);
|
|
45139
45463
|
result.push(`${path}:${stat2.dev}:${stat2.ino}:${stat2.uid}:${stat2.mode}`);
|
|
45140
|
-
if (
|
|
45464
|
+
if (dirname18(path) === path)
|
|
45141
45465
|
break;
|
|
45142
45466
|
}
|
|
45143
45467
|
return result;
|
|
@@ -45147,22 +45471,33 @@ function projectedHookExecutable(command, expectedResolved) {
|
|
|
45147
45471
|
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
45148
45472
|
const linkIdentity = (stat2) => `${stat2.dev}:${stat2.ino}:${stat2.mode}:${stat2.uid}:${stat2.ctimeNs}`;
|
|
45149
45473
|
const target = resolveLauncherCommand(command), resolved = target.entry;
|
|
45474
|
+
const direct = () => link.isSymbolicLink() ? directAliasTarget(command) === target.physical : target.physical === command;
|
|
45475
|
+
if (!direct())
|
|
45476
|
+
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
45150
45477
|
if (expectedResolved !== undefined && resolved !== expectedResolved)
|
|
45151
45478
|
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
45152
45479
|
let launcher, launcherParentIdentity;
|
|
45480
|
+
let runtime;
|
|
45153
45481
|
if (target.pinned) {
|
|
45154
45482
|
launcherParentIdentity = parents3(target.physical);
|
|
45155
45483
|
launcher = snapshot(target.physical, false);
|
|
45156
45484
|
projectedHookAcl(launcher.file, launcher.stat);
|
|
45157
45485
|
if (launcher.sha256 !== target.pinned.sha256 || (launcher.stat.mode & 0o100n) === 0n)
|
|
45158
45486
|
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
45159
|
-
|
|
45487
|
+
const path = target.pinned.runtime;
|
|
45488
|
+
assertPinnedLauncherRuntimeSafe(path);
|
|
45489
|
+
if (resolve20(path) !== path)
|
|
45490
|
+
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
45491
|
+
runtime = { path, parents: parents3(path), stat: lstatSync23(path, { bigint: true }) };
|
|
45492
|
+
if (!runtime.stat.isFile())
|
|
45493
|
+
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
45494
|
+
projectedHookAcl(path, runtime.stat);
|
|
45160
45495
|
}
|
|
45161
45496
|
const resolvedParentIdentity = parents3(resolved);
|
|
45162
|
-
const manifest = snapshot(join27(
|
|
45497
|
+
const manifest = snapshot(join27(dirname18(dirname18(resolved)), "package.json"), false, { readOnlyPackage: true });
|
|
45163
45498
|
projectedHookAcl(manifest.file, manifest.stat);
|
|
45164
45499
|
const pkg = JSON.parse(manifest.text);
|
|
45165
|
-
if (pkg.name !== "@hasna/skills" || !/^\d+\.\d+\.\d+$/.test(pkg.version) || pkg.bin?.skills !== "bin/index.js" || resolved !== join27(
|
|
45500
|
+
if (pkg.name !== "@hasna/skills" || !/^\d+\.\d+\.\d+$/.test(pkg.version) || pkg.bin?.skills !== "bin/index.js" || resolved !== join27(dirname18(manifest.file), "bin/index.js"))
|
|
45166
45501
|
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
45167
45502
|
const cli = snapshot(resolved, false, { readOnlyPackage: true });
|
|
45168
45503
|
projectedHookAcl(cli.file, cli.stat);
|
|
@@ -45171,7 +45506,7 @@ function projectedHookExecutable(command, expectedResolved) {
|
|
|
45171
45506
|
const recheck = () => {
|
|
45172
45507
|
try {
|
|
45173
45508
|
const again = resolveLauncherCommand(command);
|
|
45174
|
-
if (again.entry !== resolved || again.physical !== target.physical || linkIdentity(lstatSync23(command, { bigint: true })) !== linkIdentity(link) || !isDeepStrictEqual8(parents3(), parentIdentity) || !isDeepStrictEqual8(parents3(resolved), resolvedParentIdentity))
|
|
45509
|
+
if (again.entry !== resolved || again.physical !== target.physical || linkIdentity(lstatSync23(command, { bigint: true })) !== linkIdentity(link) || !direct() || !isDeepStrictEqual8(parents3(), parentIdentity) || !isDeepStrictEqual8(parents3(resolved), resolvedParentIdentity))
|
|
45175
45510
|
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
45176
45511
|
if (launcher) {
|
|
45177
45512
|
if (!isDeepStrictEqual8(parents3(target.physical), launcherParentIdentity))
|
|
@@ -45179,6 +45514,12 @@ function projectedHookExecutable(command, expectedResolved) {
|
|
|
45179
45514
|
projectedHookAcl(launcher.file, launcher.stat);
|
|
45180
45515
|
unchanged2(launcher);
|
|
45181
45516
|
}
|
|
45517
|
+
if (runtime) {
|
|
45518
|
+
assertPinnedLauncherRuntimeSafe(runtime.path);
|
|
45519
|
+
if (!isDeepStrictEqual8(parents3(runtime.path), runtime.parents))
|
|
45520
|
+
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
45521
|
+
projectedHookAcl(runtime.path, runtime.stat);
|
|
45522
|
+
}
|
|
45182
45523
|
projectedHookAcl(cli.file, cli.stat);
|
|
45183
45524
|
projectedHookAcl(manifest.file, manifest.stat);
|
|
45184
45525
|
unchanged2(cli);
|
|
@@ -45205,7 +45546,7 @@ function planClaudeManagedHookProjection(options) {
|
|
|
45205
45546
|
} catch {
|
|
45206
45547
|
hookProjectionRefusal("TARGET_INVALID");
|
|
45207
45548
|
}
|
|
45208
|
-
const home =
|
|
45549
|
+
const home = resolve20(options.home ?? homedir3()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
|
|
45209
45550
|
const policyPath = join27(dataDir2, "agent-policy.json");
|
|
45210
45551
|
let policyBytes, settingsBytes, settingsPath, command, profile;
|
|
45211
45552
|
try {
|
|
@@ -45297,29 +45638,28 @@ function planClaudePreToolUseHookUpdate(options) {
|
|
|
45297
45638
|
return planClaudeHookEventsUpdate({ ...options, events: ["PreToolUse"] });
|
|
45298
45639
|
}
|
|
45299
45640
|
function claudeSettingsConsumers(home, path, discoveries, aliases) {
|
|
45300
|
-
const
|
|
45641
|
+
const canonical8 = (value) => canonicalAgentPath(value, aliases);
|
|
45301
45642
|
const containsSettings = (root2) => {
|
|
45302
|
-
const distance = relative5(
|
|
45303
|
-
return distance === "" || distance !== ".." && !distance.startsWith(`..${sep7}`) && !
|
|
45643
|
+
const distance = relative5(canonical8(root2), path);
|
|
45644
|
+
return distance === "" || distance !== ".." && !distance.startsWith(`..${sep7}`) && !isAbsolute22(distance);
|
|
45304
45645
|
};
|
|
45305
|
-
return discoveries.filter((binding) => binding.agent === "claude" || binding.agent === "opencode" ||
|
|
45646
|
+
return discoveries.filter((binding) => binding.agent === "claude" || binding.agent === "opencode" || canonical8(join27(home, AGENT_ADAPTERS[binding.agent].config)) === path || binding.sources.some((source) => canonical8(source.path) === path) || binding.roots.some(containsSettings) || binding.directories?.some((directory) => containsSettings(directory.path))).map((binding) => binding.agent);
|
|
45306
45647
|
}
|
|
45307
|
-
function verifyCoordinatedDiscovery(binding, home, aliases) {
|
|
45648
|
+
function verifyCoordinatedDiscovery(binding, home, aliases, executable2) {
|
|
45308
45649
|
try {
|
|
45309
45650
|
if (binding.method !== "automatic" && binding.method !== "reviewed")
|
|
45310
45651
|
throw new Error("Invalid managed discovery method");
|
|
45311
45652
|
verifyAgentDiscovery(binding);
|
|
45312
|
-
if (binding.method === "automatic")
|
|
45313
|
-
|
|
45314
|
-
if (JSON.stringify(current) !== JSON.stringify(binding))
|
|
45315
|
-
throw new Error("Configured native discovery roots changed during Claude update");
|
|
45316
|
-
}
|
|
45653
|
+
if (binding.method === "automatic")
|
|
45654
|
+
verifyAutomaticDiscoveryClosure(binding, { home, canonical: (path) => canonicalAgentPath(path, aliases), change: "Configured native discovery roots changed during Claude update", executable: executable2 });
|
|
45317
45655
|
} catch (error) {
|
|
45656
|
+
if (isDiscoveryRootUnresolved(error))
|
|
45657
|
+
throw error;
|
|
45318
45658
|
throw new Error(`NATIVE_SKILL_DRIFT: ${error.message}`);
|
|
45319
45659
|
}
|
|
45320
45660
|
}
|
|
45321
45661
|
function planClaudeHookEventsUpdate(options) {
|
|
45322
|
-
const home =
|
|
45662
|
+
const home = resolve20(options.home ?? homedir3()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
|
|
45323
45663
|
const policyPath = join27(dataDir2, "agent-policy.json");
|
|
45324
45664
|
assertSafePath(policyPath);
|
|
45325
45665
|
const snapshot2 = readManagedSkillPolicySnapshot(dataDir2);
|
|
@@ -45345,8 +45685,9 @@ function planClaudeHookEventsUpdate(options) {
|
|
|
45345
45685
|
});
|
|
45346
45686
|
if (discoveries.length !== agents.length || !agents.includes("claude"))
|
|
45347
45687
|
throw new Error("Missing managed Claude discovery coverage");
|
|
45688
|
+
const discoveryExecutables = bridge.discoveryExecutables;
|
|
45348
45689
|
for (const binding of discoveries)
|
|
45349
|
-
verifyCoordinatedDiscovery(binding, home, aliases);
|
|
45690
|
+
verifyCoordinatedDiscovery(binding, home, aliases, discoveryExecutables?.[binding.agent]);
|
|
45350
45691
|
const consumers = claudeSettingsConsumers(home, path, discoveries, aliases);
|
|
45351
45692
|
for (const agent of consumers)
|
|
45352
45693
|
assertManagedAgentBridge(agent, { home, dataDir: dataDir2, projectDir: home });
|
|
@@ -45381,13 +45722,14 @@ function planClaudeHookEventsUpdate(options) {
|
|
|
45381
45722
|
observedPolicy: { path: policyPath, before: snapshot2.text },
|
|
45382
45723
|
discoveryBefore: discoveries,
|
|
45383
45724
|
discoveryAfter,
|
|
45725
|
+
...discoveryExecutables ? { discoveryExecutables } : {},
|
|
45384
45726
|
rootAliases: aliases,
|
|
45385
45727
|
managedAgentChecks: { home, agents: consumers }
|
|
45386
45728
|
};
|
|
45387
45729
|
}
|
|
45388
45730
|
function atomicWrite2(path, content) {
|
|
45389
45731
|
assertSafePath(path);
|
|
45390
|
-
mkdirSync6(
|
|
45732
|
+
mkdirSync6(dirname18(path), { recursive: true, mode: 448 });
|
|
45391
45733
|
const temporary = `${path}.skills-${randomUUID4()}`;
|
|
45392
45734
|
try {
|
|
45393
45735
|
writeFileSync5(temporary, content, { mode: 384, flag: "wx" });
|
|
@@ -45402,7 +45744,7 @@ function planAgentSettingsWitnessUpgrade(options) {
|
|
|
45402
45744
|
throw new Error("Invalid Codex witness target version");
|
|
45403
45745
|
if (options.targetClaudeVersion !== undefined && (options.agent !== "claude" || ![3, 4].includes(options.targetClaudeVersion)))
|
|
45404
45746
|
throw new Error("Invalid Claude witness target version");
|
|
45405
|
-
const home =
|
|
45747
|
+
const home = resolve20(options.home ?? homedir3()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
|
|
45406
45748
|
const snapshot2 = readManagedSkillPolicySnapshot(dataDir2);
|
|
45407
45749
|
if (!snapshot2 || sha4(snapshot2.text) !== options.expectedPolicySha256)
|
|
45408
45750
|
throw new Error("Managed policy preimage changed");
|
|
@@ -45462,7 +45804,7 @@ function planAgentSettingsWitnessUpgrade(options) {
|
|
|
45462
45804
|
const replacement = { ...binding, sources: rebound };
|
|
45463
45805
|
verifyAgentDiscovery(replacement);
|
|
45464
45806
|
const after = serializeManagedSkillPolicy({ ...policy, bridge: { ...policy.bridge, discovery: { ...policy.bridge.discovery, [options.agent]: replacement } } });
|
|
45465
|
-
return { dataDir: dataDir2, profileId: policy.profileId, changes: [{ path: join27(dataDir2, "agent-policy.json"), before: snapshot2.text, after }], nativeSkills: [], observedPolicy: { path: join27(dataDir2, "agent-policy.json"), before: snapshot2.text }, observedSettings: { path: configPath, before: settings }, discoveryBefore: [replacement], discoveryAfter: [replacement], rootAliases: aliases, managedAgentChecks: { home, agents: [options.agent] }, settingsWitnessUpgrade: { agent: options.agent, path: configPath, fromHashMode: previous.hashMode ?? "bytes", fromSha256: previous.sha256, toHashMode: next.hashMode, toSha256: next.sha256, reviewedPreimage: options.reviewedPreimage, currentSettingsSha256: options.expectedSettingsSha256, replacedWitnesses: replaced.map((source) => ({ hashMode: source.hashMode ?? "bytes", sha256: source.sha256 })) } };
|
|
45807
|
+
return { dataDir: dataDir2, profileId: policy.profileId, changes: [{ path: join27(dataDir2, "agent-policy.json"), before: snapshot2.text, after }], nativeSkills: [], observedPolicy: { path: join27(dataDir2, "agent-policy.json"), before: snapshot2.text }, observedSettings: { path: configPath, before: settings }, discoveryBefore: [replacement], discoveryAfter: [replacement], ...policy.bridge.discoveryExecutables ? { discoveryExecutables: policy.bridge.discoveryExecutables } : {}, rootAliases: aliases, managedAgentChecks: { home, agents: [options.agent] }, settingsWitnessUpgrade: { agent: options.agent, path: configPath, fromHashMode: previous.hashMode ?? "bytes", fromSha256: previous.sha256, toHashMode: next.hashMode, toSha256: next.sha256, reviewedPreimage: options.reviewedPreimage, currentSettingsSha256: options.expectedSettingsSha256, replacedWitnesses: replaced.map((source) => ({ hashMode: source.hashMode ?? "bytes", sha256: source.sha256 })) } };
|
|
45466
45808
|
}
|
|
45467
45809
|
function applyAgentIntegration(plan, options = {}) {
|
|
45468
45810
|
const roots = plan.changes.flatMap((change) => {
|
|
@@ -45480,10 +45822,10 @@ function applyAgentIntegrationUnlocked(plan, options = {}, assertCurrent) {
|
|
|
45480
45822
|
throw new Error("Native settings changed after witness planning");
|
|
45481
45823
|
const policyPath = join27(plan.dataDir, "agent-policy.json");
|
|
45482
45824
|
assertSafePath(policyPath);
|
|
45483
|
-
const currentText = (path) =>
|
|
45825
|
+
const currentText = (path) => resolve20(path) === resolve20(policyPath) ? readManagedSkillPolicySnapshot(plan.dataDir)?.text ?? null : readOptional(path);
|
|
45484
45826
|
readManagedSkillPolicySnapshot(plan.dataDir);
|
|
45485
45827
|
for (const change of plan.changes)
|
|
45486
|
-
if (
|
|
45828
|
+
if (resolve20(change.path) === resolve20(policyPath))
|
|
45487
45829
|
parseManagedSkillPolicy(change.after);
|
|
45488
45830
|
const aliases = plan.rootAliases ?? [];
|
|
45489
45831
|
assertCurrent();
|
|
@@ -45504,7 +45846,7 @@ function applyAgentIntegrationUnlocked(plan, options = {}, assertCurrent) {
|
|
|
45504
45846
|
assertManagedAgentBridgeWithDiscovery(agent, { home: plan.managedAgentChecks.home, dataDir: plan.dataDir, projectDir: plan.managedAgentChecks.home }, provenDiscovery?.agent === agent ? provenDiscovery : undefined);
|
|
45505
45847
|
for (const binding of plan.discoveryBefore ?? []) {
|
|
45506
45848
|
if (plan.managedAgentChecks)
|
|
45507
|
-
verifyCoordinatedDiscovery(binding, plan.managedAgentChecks.home, aliases);
|
|
45849
|
+
verifyCoordinatedDiscovery(binding, plan.managedAgentChecks.home, aliases, plan.discoveryExecutables?.[binding.agent]);
|
|
45508
45850
|
else
|
|
45509
45851
|
verifyAgentDiscovery(binding);
|
|
45510
45852
|
}
|
|
@@ -45536,7 +45878,7 @@ function applyAgentIntegrationUnlocked(plan, options = {}, assertCurrent) {
|
|
|
45536
45878
|
recheckRootAliases(aliases);
|
|
45537
45879
|
if (currentText(change.path) !== change.before)
|
|
45538
45880
|
throw new Error(`Configuration changed after planning: ${change.path}`);
|
|
45539
|
-
for (let directory =
|
|
45881
|
+
for (let directory = dirname18(change.path);!existsSync7(directory); directory = dirname18(directory))
|
|
45540
45882
|
createdDirectories.add(directory);
|
|
45541
45883
|
const after = change.after;
|
|
45542
45884
|
atomicWrite2(change.path, after);
|
|
@@ -45551,7 +45893,7 @@ function applyAgentIntegrationUnlocked(plan, options = {}, assertCurrent) {
|
|
|
45551
45893
|
throw new Error("Native settings changed during witness application");
|
|
45552
45894
|
for (const binding of plan.discoveryAfter ?? []) {
|
|
45553
45895
|
if (plan.managedAgentChecks)
|
|
45554
|
-
verifyCoordinatedDiscovery(binding, plan.managedAgentChecks.home, aliases);
|
|
45896
|
+
verifyCoordinatedDiscovery(binding, plan.managedAgentChecks.home, aliases, plan.discoveryExecutables?.[binding.agent]);
|
|
45555
45897
|
else
|
|
45556
45898
|
verifyAgentDiscovery(binding);
|
|
45557
45899
|
}
|
|
@@ -45608,7 +45950,7 @@ function writeArchiveJournal(path, value) {
|
|
|
45608
45950
|
closeSync18(descriptor);
|
|
45609
45951
|
descriptor = undefined;
|
|
45610
45952
|
renameSync4(temporary, path);
|
|
45611
|
-
syncArchiveDirectory(
|
|
45953
|
+
syncArchiveDirectory(dirname18(path));
|
|
45612
45954
|
} finally {
|
|
45613
45955
|
if (descriptor !== undefined)
|
|
45614
45956
|
closeSync18(descriptor);
|
|
@@ -45666,14 +46008,14 @@ function archiveNativeSkillsUnlocked(inventory, options, assertCurrent) {
|
|
|
45666
46008
|
};
|
|
45667
46009
|
assertSafePath(archiveRoot);
|
|
45668
46010
|
const created = [];
|
|
45669
|
-
for (let path = archiveRoot;!existsSync7(path); path =
|
|
46011
|
+
for (let path = archiveRoot;!existsSync7(path); path = dirname18(path))
|
|
45670
46012
|
created.push(path);
|
|
45671
46013
|
mkdirSync6(archiveRoot, { recursive: true, mode: 448 });
|
|
45672
46014
|
try {
|
|
45673
46015
|
for (const directory of created)
|
|
45674
46016
|
syncArchiveDirectory(directory);
|
|
45675
46017
|
if (created.length)
|
|
45676
|
-
syncArchiveDirectory(
|
|
46018
|
+
syncArchiveDirectory(dirname18(created.at(-1)));
|
|
45677
46019
|
writeArchiveJournal(receiptPath, journal);
|
|
45678
46020
|
for (const [index, entry] of selected.entries()) {
|
|
45679
46021
|
assertCurrent();
|
|
@@ -45686,7 +46028,7 @@ function archiveNativeSkillsUnlocked(inventory, options, assertCurrent) {
|
|
|
45686
46028
|
writeArchiveJournal(receiptPath, journal);
|
|
45687
46029
|
renameSync4(move.source, move.archive);
|
|
45688
46030
|
moved.push(move);
|
|
45689
|
-
syncArchiveDirectory(
|
|
46031
|
+
syncArchiveDirectory(dirname18(move.source));
|
|
45690
46032
|
syncArchiveDirectory(archiveRoot);
|
|
45691
46033
|
verifyArchive(move);
|
|
45692
46034
|
move.status = "archived";
|
|
@@ -45723,7 +46065,7 @@ function archiveNativeSkillsUnlocked(inventory, options, assertCurrent) {
|
|
|
45723
46065
|
}
|
|
45724
46066
|
if (entry.discoveryOnly) {
|
|
45725
46067
|
linkSync3(entry.archive, entry.source);
|
|
45726
|
-
syncArchiveDirectory(
|
|
46068
|
+
syncArchiveDirectory(dirname18(entry.source));
|
|
45727
46069
|
unlinkSync5(entry.archive);
|
|
45728
46070
|
} else {
|
|
45729
46071
|
if (lstatSync23(entry.source, { throwIfNoEntry: false })) {
|
|
@@ -45734,7 +46076,7 @@ function archiveNativeSkillsUnlocked(inventory, options, assertCurrent) {
|
|
|
45734
46076
|
renameSync4(entry.archive, entry.source);
|
|
45735
46077
|
}
|
|
45736
46078
|
entry.status = "restored";
|
|
45737
|
-
syncArchiveDirectory(
|
|
46079
|
+
syncArchiveDirectory(dirname18(entry.source));
|
|
45738
46080
|
syncArchiveDirectory(archiveRoot);
|
|
45739
46081
|
} catch {
|
|
45740
46082
|
entry.status = "recovery-required";
|
|
@@ -45759,7 +46101,7 @@ function isInertCodexPluginCacheCopy(entry, cache, allowedHostPaths, read3) {
|
|
|
45759
46101
|
return false;
|
|
45760
46102
|
const document2 = join27(entry.path, "SKILL.md");
|
|
45761
46103
|
const inside = relative5(cache, entry.path);
|
|
45762
|
-
if (!inside ||
|
|
46104
|
+
if (!inside || isAbsolute22(inside) || inside.split(sep7).some((segment) => segment === ".."))
|
|
45763
46105
|
return false;
|
|
45764
46106
|
assertSafePath(entry.path);
|
|
45765
46107
|
if (!lstatSync23(cache).isDirectory() || !lstatSync23(entry.path).isDirectory() || !lstatSync23(document2).isFile())
|
|
@@ -45779,7 +46121,7 @@ function assertManagedAgentBridge(agent, options = {}) {
|
|
|
45779
46121
|
assertManagedAgentBridgeWithDiscovery(agent, options);
|
|
45780
46122
|
}
|
|
45781
46123
|
function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscovery) {
|
|
45782
|
-
const home =
|
|
46124
|
+
const home = resolve20(options.home ?? homedir3()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
|
|
45783
46125
|
assertSafePath(join27(dataDir2, "agent-policy.json"));
|
|
45784
46126
|
const snapshot2 = readManagedSkillPolicySnapshot(dataDir2);
|
|
45785
46127
|
if (!snapshot2)
|
|
@@ -45877,12 +46219,11 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
|
|
|
45877
46219
|
verifyAgentDiscovery(agent === "codex" ? { ...discovery, codexDisabledPluginSkills: binding.codexPluginSkills ?? [] } : discovery, options.codexDiscoveryRecovery);
|
|
45878
46220
|
if (agent === "sumi" && discovery.method === "reviewed")
|
|
45879
46221
|
resolveAgentDiscovery({ home, agent, retainedReview: discovery, canonical: (path) => canonicalAgentPath(path, aliases) });
|
|
45880
|
-
if (discovery.method === "automatic")
|
|
45881
|
-
|
|
45882
|
-
if (JSON.stringify(current) !== JSON.stringify(discovery))
|
|
45883
|
-
throw new Error("Configured native discovery roots changed");
|
|
45884
|
-
}
|
|
46222
|
+
if (discovery.method === "automatic")
|
|
46223
|
+
verifyAutomaticDiscoveryClosure(discovery, { home, canonical: (path) => canonicalAgentPath(path, aliases), change: "Configured native discovery roots changed", executable: binding.discoveryExecutables?.[agent] });
|
|
45885
46224
|
} catch (error) {
|
|
46225
|
+
if (isDiscoveryRootUnresolved(error))
|
|
46226
|
+
throw error;
|
|
45886
46227
|
throw new Error(`NATIVE_SKILL_DRIFT: ${error.message}`);
|
|
45887
46228
|
}
|
|
45888
46229
|
let installationInputRoots = [];
|
|
@@ -45938,13 +46279,13 @@ import {
|
|
|
45938
46279
|
statSync as statSync10,
|
|
45939
46280
|
writeFileSync as writeFileSync7
|
|
45940
46281
|
} from "fs";
|
|
45941
|
-
import { basename as
|
|
46282
|
+
import { basename as basename12, dirname as dirname21, isAbsolute as isAbsolute23, join as join31, normalize as normalize4, relative as relative7, resolve as resolve22, sep as sep10 } from "path";
|
|
45942
46283
|
|
|
45943
46284
|
// src/lib/registry-data/index.ts
|
|
45944
46285
|
var SKILLS = [];
|
|
45945
46286
|
|
|
45946
46287
|
// src/lib/skill-hash.ts
|
|
45947
|
-
import { createHash as
|
|
46288
|
+
import { createHash as createHash26 } from "crypto";
|
|
45948
46289
|
import { existsSync as existsSync8, readdirSync as readdirSync9, readFileSync as readFileSync18, statSync as statSync8 } from "fs";
|
|
45949
46290
|
import { join as join28, sep as sep8 } from "path";
|
|
45950
46291
|
var CONTENT_HASH_ALGORITHM = "sha256";
|
|
@@ -46068,13 +46409,13 @@ function* bundleHashParts(files) {
|
|
|
46068
46409
|
yield new TextEncoder().encode("\x00");
|
|
46069
46410
|
}
|
|
46070
46411
|
function hashBundleFiles(files) {
|
|
46071
|
-
const hash2 =
|
|
46412
|
+
const hash2 = createHash26(CONTENT_HASH_ALGORITHM);
|
|
46072
46413
|
for (const part of bundleHashParts(files))
|
|
46073
46414
|
hash2.update(part);
|
|
46074
46415
|
return hash2.digest("hex");
|
|
46075
46416
|
}
|
|
46076
46417
|
async function hashBundleFilesCooperatively(files, check) {
|
|
46077
|
-
const hash2 =
|
|
46418
|
+
const hash2 = createHash26(CONTENT_HASH_ALGORITHM);
|
|
46078
46419
|
let bytesSinceYield = 0;
|
|
46079
46420
|
for (const part of bundleHashParts(files)) {
|
|
46080
46421
|
for (let offset = 0;offset < part.byteLength; offset += 64 * 1024) {
|
|
@@ -46083,7 +46424,7 @@ async function hashBundleFilesCooperatively(files, check) {
|
|
|
46083
46424
|
hash2.update(chunk);
|
|
46084
46425
|
bytesSinceYield += chunk.byteLength;
|
|
46085
46426
|
if (bytesSinceYield >= 256 * 1024) {
|
|
46086
|
-
await new Promise((
|
|
46427
|
+
await new Promise((resolve21) => setImmediate(resolve21));
|
|
46087
46428
|
bytesSinceYield = 0;
|
|
46088
46429
|
}
|
|
46089
46430
|
}
|
|
@@ -46206,8 +46547,8 @@ function boundedManifest(raw, maxDepth) {
|
|
|
46206
46547
|
continue;
|
|
46207
46548
|
if (depth > maxDepth)
|
|
46208
46549
|
contentLimit("Content hash manifest depth limit exceeded");
|
|
46209
|
-
for (const
|
|
46210
|
-
pending.push({ value:
|
|
46550
|
+
for (const child2 of Object.values(value))
|
|
46551
|
+
pending.push({ value: child2, depth: depth + 1 });
|
|
46211
46552
|
}
|
|
46212
46553
|
return parsed;
|
|
46213
46554
|
}
|
|
@@ -46236,7 +46577,7 @@ async function hashContentEntries(entries, options) {
|
|
|
46236
46577
|
const normalized = [];
|
|
46237
46578
|
let normalizedBytes = 0;
|
|
46238
46579
|
let manifest;
|
|
46239
|
-
await new Promise((
|
|
46580
|
+
await new Promise((resolve21) => setImmediate(resolve21));
|
|
46240
46581
|
for (const entry of snapshot2) {
|
|
46241
46582
|
check();
|
|
46242
46583
|
if (!coveredContentPath(entry.path))
|
|
@@ -46249,7 +46590,7 @@ async function hashContentEntries(entries, options) {
|
|
|
46249
46590
|
contentLimit("Content hash normalized byte limit exceeded");
|
|
46250
46591
|
normalizedBytes += file.content.byteLength;
|
|
46251
46592
|
normalized.push(file);
|
|
46252
|
-
await new Promise((
|
|
46593
|
+
await new Promise((resolve21) => setImmediate(resolve21));
|
|
46253
46594
|
}
|
|
46254
46595
|
normalized.sort((a, b) => a.rel < b.rel ? -1 : a.rel > b.rel ? 1 : 0);
|
|
46255
46596
|
check();
|
|
@@ -46463,7 +46804,7 @@ import {
|
|
|
46463
46804
|
realpathSync as realpathSync12,
|
|
46464
46805
|
writeFileSync as writeFileSync6
|
|
46465
46806
|
} from "fs";
|
|
46466
|
-
import { basename as
|
|
46807
|
+
import { basename as basename10, dirname as dirname19, join as join29, relative as relative6 } from "path";
|
|
46467
46808
|
var ANY_SEGMENT_COPY_EXCLUDES = new Set([
|
|
46468
46809
|
".git",
|
|
46469
46810
|
".DS_Store",
|
|
@@ -46513,11 +46854,11 @@ function normalizeNewPortableSkillName(name) {
|
|
|
46513
46854
|
throw new Error(`Invalid skill name '${name}'. Include letters or numbers.`);
|
|
46514
46855
|
return normalized;
|
|
46515
46856
|
}
|
|
46516
|
-
function readPortableSkillManifest(skillPath, fallbackName =
|
|
46857
|
+
function readPortableSkillManifest(skillPath, fallbackName = basename10(skillPath)) {
|
|
46517
46858
|
return readManifest(skillPath, fallbackName, normalizePortableSkillName);
|
|
46518
46859
|
}
|
|
46519
46860
|
function readPortableSkillManifestForImport(skillPath) {
|
|
46520
|
-
return readManifest(skillPath,
|
|
46861
|
+
return readManifest(skillPath, basename10(skillPath), normalizeNewPortableSkillName);
|
|
46521
46862
|
}
|
|
46522
46863
|
function readManifest(skillPath, fallbackName, normalizeName) {
|
|
46523
46864
|
const skillJsonPath = join29(skillPath, "skill.json");
|
|
@@ -46710,7 +47051,7 @@ function ensurePortableSkillFiles(skillPath, manifest) {
|
|
|
46710
47051
|
};
|
|
46711
47052
|
const entry = next.commands[0]?.entry ?? "src/index.ts";
|
|
46712
47053
|
if (entry && !existsSync9(join29(skillPath, entry))) {
|
|
46713
|
-
mkdirSync7(
|
|
47054
|
+
mkdirSync7(dirname19(join29(skillPath, entry)), { recursive: true });
|
|
46714
47055
|
writeFileSync6(join29(skillPath, entry), renderEntrypoint(next));
|
|
46715
47056
|
}
|
|
46716
47057
|
if (!existsSync9(join29(skillPath, "SKILL.md")))
|
|
@@ -47071,7 +47412,7 @@ function inferRuntimeFromCommands(commands) {
|
|
|
47071
47412
|
function readJsonObject(path) {
|
|
47072
47413
|
const parsed = JSON.parse(readFileSync19(path, "utf-8"));
|
|
47073
47414
|
if (!isRecord3(parsed))
|
|
47074
|
-
throw new Error(`${
|
|
47415
|
+
throw new Error(`${basename10(path)} must contain a JSON object`);
|
|
47075
47416
|
return parsed;
|
|
47076
47417
|
}
|
|
47077
47418
|
function hasPackageDependencies(pkgPath) {
|
|
@@ -47109,10 +47450,10 @@ function escapeJsString(value) {
|
|
|
47109
47450
|
// src/lib/authoring-path.ts
|
|
47110
47451
|
import { lstatSync as lstatSync25, realpathSync as realpathSync13 } from "fs";
|
|
47111
47452
|
import { homedir as homedir4 } from "os";
|
|
47112
|
-
import { basename as
|
|
47453
|
+
import { basename as basename11, dirname as dirname20, join as join30, resolve as resolve21, sep as sep9 } from "path";
|
|
47113
47454
|
var NATIVE_DISCOVERY_ROOTS = NATIVE_SKILL_ROOTS.map(([, path]) => path.split("/"));
|
|
47114
47455
|
function pathParts(path) {
|
|
47115
|
-
return
|
|
47456
|
+
return resolve21(path).split(sep9).filter(Boolean);
|
|
47116
47457
|
}
|
|
47117
47458
|
function nativeRootMatch(path) {
|
|
47118
47459
|
const parts = pathParts(path);
|
|
@@ -47126,16 +47467,16 @@ function nativeRootMatch(path) {
|
|
|
47126
47467
|
return;
|
|
47127
47468
|
}
|
|
47128
47469
|
function physicalPath(path) {
|
|
47129
|
-
let cursor =
|
|
47470
|
+
let cursor = resolve21(path);
|
|
47130
47471
|
const suffix = [];
|
|
47131
47472
|
while (!lstatSync25(cursor, { throwIfNoEntry: false })) {
|
|
47132
|
-
suffix.unshift(
|
|
47133
|
-
const parent =
|
|
47473
|
+
suffix.unshift(basename11(cursor));
|
|
47474
|
+
const parent = dirname20(cursor);
|
|
47134
47475
|
if (parent === cursor)
|
|
47135
|
-
return
|
|
47476
|
+
return resolve21(path);
|
|
47136
47477
|
cursor = parent;
|
|
47137
47478
|
}
|
|
47138
|
-
return
|
|
47479
|
+
return resolve21(realpathSync13(cursor), ...suffix);
|
|
47139
47480
|
}
|
|
47140
47481
|
function contains(root2, path) {
|
|
47141
47482
|
return path === root2 || path.startsWith(root2 + sep9);
|
|
@@ -47143,7 +47484,7 @@ function contains(root2, path) {
|
|
|
47143
47484
|
function configuredRoots(home, explicitHome) {
|
|
47144
47485
|
const homeData = join30(home, ".hasna", "skills");
|
|
47145
47486
|
const homePolicy = readManagedSkillPolicySnapshot(homeData);
|
|
47146
|
-
const configuredPolicy = !explicitHome &&
|
|
47487
|
+
const configuredPolicy = !explicitHome && resolve21(getDataDirReadOnly()) !== resolve21(homeData) ? readManagedSkillPolicySnapshot(getDataDirReadOnly()) : null;
|
|
47147
47488
|
const policy = homePolicy ?? configuredPolicy;
|
|
47148
47489
|
const bridge = policy?.value.bridge;
|
|
47149
47490
|
if (bridge && (typeof bridge.home !== "string" || physicalPath(bridge.home) !== physicalPath(home))) {
|
|
@@ -47182,22 +47523,22 @@ function configuredRoots(home, explicitHome) {
|
|
|
47182
47523
|
function assertPortableAuthoringPath(path, options = {}) {
|
|
47183
47524
|
if (typeof path !== "string" || !path || path.includes("\x00"))
|
|
47184
47525
|
throw new Error("Invalid portable authoring path");
|
|
47185
|
-
const lexical =
|
|
47526
|
+
const lexical = resolve21(path);
|
|
47186
47527
|
const physical = physicalPath(lexical);
|
|
47187
47528
|
const candidates = [lexical, physical];
|
|
47188
47529
|
let native = candidates.map(nativeRootMatch).find(Boolean);
|
|
47189
|
-
const home =
|
|
47530
|
+
const home = resolve21(options.homeDir ?? homedir4());
|
|
47190
47531
|
const defaults = NATIVE_DISCOVERY_ROOTS.map((parts) => join30(home, ...parts));
|
|
47191
47532
|
defaults.push(join30(home, ".codex/plugins/cache"), join30(home, ".claude/plugins/cache"), join30(home, ".claude/plugins/synced"), join30(home, ".gemini/extensions"));
|
|
47192
47533
|
for (const root2 of defaults) {
|
|
47193
|
-
if (candidates.some((candidate2) => contains(
|
|
47534
|
+
if (candidates.some((candidate2) => contains(resolve21(root2), candidate2) || contains(physicalPath(root2), candidate2)))
|
|
47194
47535
|
native ??= root2;
|
|
47195
47536
|
}
|
|
47196
47537
|
if (native) {
|
|
47197
47538
|
throw new Error(`Refusing portable Skills authoring below native discovery root '${native}': ${lexical}. Set HASNA_SKILLS_DIR to a private authoring corpus outside native roots.`);
|
|
47198
47539
|
}
|
|
47199
47540
|
for (const root2 of configuredRoots(home, options.homeDir !== undefined)) {
|
|
47200
|
-
if (candidates.some((candidate2) => contains(
|
|
47541
|
+
if (candidates.some((candidate2) => contains(resolve21(root2), candidate2) || contains(physicalPath(root2), candidate2))) {
|
|
47201
47542
|
throw new Error(`Refusing portable Skills authoring below configured native discovery root: ${lexical}`);
|
|
47202
47543
|
}
|
|
47203
47544
|
}
|
|
@@ -47345,20 +47686,20 @@ function isSkillCandidate(dir) {
|
|
|
47345
47686
|
return existsSync10(join31(dir, "SKILL.md")) || existsSync10(join31(dir, "skill.json")) || existsSync10(join31(dir, "package.json"));
|
|
47346
47687
|
}
|
|
47347
47688
|
function physicalImportPath(path) {
|
|
47348
|
-
let ancestor =
|
|
47689
|
+
let ancestor = resolve22(path);
|
|
47349
47690
|
const suffix = [];
|
|
47350
47691
|
while (!existsSync10(ancestor)) {
|
|
47351
|
-
suffix.unshift(
|
|
47352
|
-
ancestor =
|
|
47692
|
+
suffix.unshift(basename12(ancestor));
|
|
47693
|
+
ancestor = dirname21(ancestor);
|
|
47353
47694
|
}
|
|
47354
47695
|
return join31(realpathSync14(ancestor), ...suffix);
|
|
47355
47696
|
}
|
|
47356
47697
|
function assertDisjointImportPaths(source, destination) {
|
|
47357
47698
|
const sourcePath = realpathSync14(source);
|
|
47358
47699
|
const destinationPath = physicalImportPath(destination);
|
|
47359
|
-
const contains2 = (parent,
|
|
47360
|
-
const path = relative7(parent,
|
|
47361
|
-
return path === "" || !
|
|
47700
|
+
const contains2 = (parent, child2) => {
|
|
47701
|
+
const path = relative7(parent, child2);
|
|
47702
|
+
return path === "" || !isAbsolute23(path) && path !== ".." && !path.startsWith(`..${sep10}`);
|
|
47362
47703
|
};
|
|
47363
47704
|
if (contains2(sourcePath, destinationPath) || contains2(destinationPath, sourcePath)) {
|
|
47364
47705
|
throw new Error("Source and destination skill directories must not overlap");
|
|
@@ -47373,8 +47714,8 @@ function portPortableSkill(sourcePath, options = {}) {
|
|
|
47373
47714
|
const explicitName = options.name != null;
|
|
47374
47715
|
const skillName = normalizeNewPortableSkillName(options.name ?? inferred.name);
|
|
47375
47716
|
if (isOfficialSkillName(skillName) && !options.allowShadow) {
|
|
47376
|
-
const sourceSlug = safeNormalizeName(
|
|
47377
|
-
const via = explicitName ? `Name '${skillName}' matches a bundled official skill.` : `Inferred name '${skillName}'${sourceSlug && sourceSlug !== skillName ? ` (from source folder '${
|
|
47717
|
+
const sourceSlug = safeNormalizeName(basename12(absoluteSource));
|
|
47718
|
+
const via = explicitName ? `Name '${skillName}' matches a bundled official skill.` : `Inferred name '${skillName}'${sourceSlug && sourceSlug !== skillName ? ` (from source folder '${basename12(absoluteSource)}')` : ""} matches a bundled official skill.`;
|
|
47378
47719
|
throw new Error(`${via} Importing it would shadow the official '${skillName}'. ` + `Pass --name to choose a different name, or --allow-shadow to override deliberately.`);
|
|
47379
47720
|
}
|
|
47380
47721
|
const readOnlyDestination = join31(resolvePortableSkillsRoot(options, false), skillName);
|
|
@@ -47389,7 +47730,7 @@ function portPortableSkill(sourcePath, options = {}) {
|
|
|
47389
47730
|
throw new Error(`Skill '${skillName}' already exists at ${destination}`);
|
|
47390
47731
|
rmSync2(destination, { recursive: true, force: true });
|
|
47391
47732
|
}
|
|
47392
|
-
mkdirSync8(
|
|
47733
|
+
mkdirSync8(dirname21(destination), { recursive: true });
|
|
47393
47734
|
copySkillDirectory(absoluteSource, destination);
|
|
47394
47735
|
const base = {
|
|
47395
47736
|
...inferred,
|
|
@@ -47639,7 +47980,7 @@ function safeIsDirectory(path) {
|
|
|
47639
47980
|
}
|
|
47640
47981
|
}
|
|
47641
47982
|
function isSafeRelativePath2(value) {
|
|
47642
|
-
if (!value.trim() ||
|
|
47983
|
+
if (!value.trim() || isAbsolute23(value))
|
|
47643
47984
|
return false;
|
|
47644
47985
|
const normalized = normalize4(value).replace(/\\/g, "/");
|
|
47645
47986
|
return normalized !== ".." && !normalized.startsWith("../") && !normalized.includes("/../");
|
|
@@ -47900,9 +48241,9 @@ function writeManagedSkillDirUnlocked(dir, skillMd, options, assertCurrent) {
|
|
|
47900
48241
|
const action = dirExists ? "update" : "create";
|
|
47901
48242
|
if (options.dryRun)
|
|
47902
48243
|
return { action, path: skillMdPath };
|
|
47903
|
-
const parentDir =
|
|
48244
|
+
const parentDir = dirname22(dir);
|
|
47904
48245
|
mkdirSync9(parentDir, { recursive: true });
|
|
47905
|
-
const transactionDir = mkdtempSync2(join32(parentDir, `.hasna-skills-write-${
|
|
48246
|
+
const transactionDir = mkdtempSync2(join32(parentDir, `.hasna-skills-write-${basename13(dir)}-`));
|
|
47906
48247
|
const candidateDir = join32(transactionDir, "candidate");
|
|
47907
48248
|
const backupDir = join32(transactionDir, "backup");
|
|
47908
48249
|
const candidateSkillMdPath = join32(candidateDir, "SKILL.md");
|
|
@@ -49289,11 +49630,11 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
49289
49630
|
throw new SkillSelectionError("INVALID_BUNDLE_PATH", "The execution bundle path exceeds its limit.");
|
|
49290
49631
|
});
|
|
49291
49632
|
const destination = join37(runDirectory, entry.path);
|
|
49292
|
-
mkdirSync11(
|
|
49633
|
+
mkdirSync11(dirname23(destination), { recursive: true, mode: 448 });
|
|
49293
49634
|
writeFileSync10(destination, entry.bytes, { flag: "wx", mode: entry.mode & 511 });
|
|
49294
49635
|
}
|
|
49295
49636
|
env.SKILLS_INPUT_JSON = input;
|
|
49296
|
-
env.SKILLS_WORKSPACE_DIR =
|
|
49637
|
+
env.SKILLS_WORKSPACE_DIR = resolve23(options.cwd ?? process.cwd());
|
|
49297
49638
|
env.SKILLS_RUN_DIR = runDirectory;
|
|
49298
49639
|
if (runtime.version) {
|
|
49299
49640
|
const version = await subprocess([executable2, ...runtimeName === "bun" ? ["--no-env-file"] : [], "--version"], runDirectory, env, "", Math.min(timeoutMs, 5000));
|
|
@@ -49323,7 +49664,7 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
49323
49664
|
selection: selection2,
|
|
49324
49665
|
target: "local",
|
|
49325
49666
|
runtime: runtimeName,
|
|
49326
|
-
inputDigest: `sha256:${
|
|
49667
|
+
inputDigest: `sha256:${createHash27("sha256").update(input).digest("hex")}`,
|
|
49327
49668
|
runDirectory,
|
|
49328
49669
|
...executionGrant ? { executionGrant } : {},
|
|
49329
49670
|
...bindings ? { secretBinding: { schema: bindings.schema, selection: bindings.selection, consumer: bindings.consumer, secretsAuthority: bindings.secretsAuthority, bindings: bindings.bindings } } : {},
|
|
@@ -49334,17 +49675,17 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
49334
49675
|
}
|
|
49335
49676
|
async function subprocess(command, cwd, env, input, timeoutMs) {
|
|
49336
49677
|
return new Promise((resolveResult) => {
|
|
49337
|
-
const
|
|
49678
|
+
const child2 = spawn2(command[0], command.slice(1), { cwd, env, shell: false, detached: process.platform !== "win32", stdio: ["pipe", "pipe", "pipe"] });
|
|
49338
49679
|
let outputBytes = 0, error, ended = false;
|
|
49339
49680
|
const stdout = [], stderr = [];
|
|
49340
49681
|
const kill = () => {
|
|
49341
49682
|
try {
|
|
49342
|
-
if (process.platform !== "win32" &&
|
|
49343
|
-
process.kill(-
|
|
49683
|
+
if (process.platform !== "win32" && child2.pid)
|
|
49684
|
+
process.kill(-child2.pid, "SIGKILL");
|
|
49344
49685
|
else
|
|
49345
|
-
|
|
49686
|
+
child2.kill("SIGKILL");
|
|
49346
49687
|
} catch {
|
|
49347
|
-
|
|
49688
|
+
child2.kill("SIGKILL");
|
|
49348
49689
|
}
|
|
49349
49690
|
};
|
|
49350
49691
|
const timer = setTimeout(() => {
|
|
@@ -49360,8 +49701,8 @@ async function subprocess(command, cwd, env, input, timeoutMs) {
|
|
|
49360
49701
|
}
|
|
49361
49702
|
target.push(chunk);
|
|
49362
49703
|
};
|
|
49363
|
-
|
|
49364
|
-
|
|
49704
|
+
child2.stdout.on("data", capture2(stdout));
|
|
49705
|
+
child2.stderr.on("data", capture2(stderr));
|
|
49365
49706
|
const finish = (code) => {
|
|
49366
49707
|
if (ended)
|
|
49367
49708
|
return;
|
|
@@ -49369,13 +49710,13 @@ async function subprocess(command, cwd, env, input, timeoutMs) {
|
|
|
49369
49710
|
clearTimeout(timer);
|
|
49370
49711
|
resolveResult({ exitCode: error === "LOCAL_RUN_TIMEOUT" ? 124 : error ? 1 : code, stdout: Buffer.concat(stdout).toString("utf8"), stderr: Buffer.concat(stderr).toString("utf8"), ...error ? { error } : {} });
|
|
49371
49712
|
};
|
|
49372
|
-
|
|
49713
|
+
child2.on("error", () => {
|
|
49373
49714
|
error = "LOCAL_RUNTIME_START_FAILED";
|
|
49374
49715
|
finish(127);
|
|
49375
49716
|
});
|
|
49376
|
-
|
|
49377
|
-
|
|
49378
|
-
|
|
49717
|
+
child2.on("close", (code) => finish(code ?? 1));
|
|
49718
|
+
child2.stdin.on("error", () => {});
|
|
49719
|
+
child2.stdin.end(input);
|
|
49379
49720
|
});
|
|
49380
49721
|
}
|
|
49381
49722
|
// src/lib/remote-run-contract.ts
|
|
@@ -58613,7 +58954,7 @@ var import_node_http_handler2 = __toESM(require_dist_cjs6(), 1);
|
|
|
58613
58954
|
|
|
58614
58955
|
// node_modules/@aws-sdk/checksums/dist-cjs/submodules/sha/index.js
|
|
58615
58956
|
var { toUint8Array: toUint8Array2, concatBytes } = require_serde();
|
|
58616
|
-
var { createHmac: createHmac2, createHash:
|
|
58957
|
+
var { createHmac: createHmac2, createHash: createHash29 } = __require("crypto");
|
|
58617
58958
|
var { Sha256: Sha2562, Sha256Js, Sha256Node } = require_checksum();
|
|
58618
58959
|
var BLOCK2 = 64;
|
|
58619
58960
|
var DIGEST_LENGTH = 20;
|
|
@@ -58782,7 +59123,7 @@ class Sha1Js {
|
|
|
58782
59123
|
}
|
|
58783
59124
|
var hasNativeCrypto = (() => {
|
|
58784
59125
|
try {
|
|
58785
|
-
|
|
59126
|
+
createHash29("sha1");
|
|
58786
59127
|
return true;
|
|
58787
59128
|
} catch {
|
|
58788
59129
|
return false;
|
|
@@ -58822,7 +59163,7 @@ function buildNativeClass() {
|
|
|
58822
59163
|
this.finished = false;
|
|
58823
59164
|
}
|
|
58824
59165
|
createHash() {
|
|
58825
|
-
return this.secret ? createHmac2("sha1", toBuffer(this.secret)) :
|
|
59166
|
+
return this.secret ? createHmac2("sha1", toBuffer(this.secret)) : createHash29("sha1");
|
|
58826
59167
|
}
|
|
58827
59168
|
};
|
|
58828
59169
|
}
|
|
@@ -59375,15 +59716,15 @@ function createCancelService(options) {
|
|
|
59375
59716
|
}
|
|
59376
59717
|
|
|
59377
59718
|
// src/sdk/amounts.ts
|
|
59378
|
-
function assertCents(value,
|
|
59719
|
+
function assertCents(value, field3) {
|
|
59379
59720
|
if (!Number.isSafeInteger(value) || value < 0) {
|
|
59380
|
-
throw new RangeError(
|
|
59721
|
+
throw new RangeError(field3 + " must be a nonnegative safe integer number of cents");
|
|
59381
59722
|
}
|
|
59382
59723
|
}
|
|
59383
|
-
function assertReservationCents(value,
|
|
59384
|
-
assertCents(value,
|
|
59724
|
+
function assertReservationCents(value, field3) {
|
|
59725
|
+
assertCents(value, field3);
|
|
59385
59726
|
if (value > 2147483647) {
|
|
59386
|
-
throw new RangeError(
|
|
59727
|
+
throw new RangeError(field3 + " must not exceed 2147483647 cents per reservation");
|
|
59387
59728
|
}
|
|
59388
59729
|
}
|
|
59389
59730
|
|
|
@@ -59391,10 +59732,10 @@ function assertReservationCents(value, field2) {
|
|
|
59391
59732
|
import { Database as Database2 } from "bun:sqlite";
|
|
59392
59733
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
59393
59734
|
import { mkdirSync as mkdirSync13 } from "fs";
|
|
59394
|
-
import { dirname as
|
|
59735
|
+
import { dirname as dirname27 } from "path";
|
|
59395
59736
|
|
|
59396
59737
|
// src/server/database-url.ts
|
|
59397
|
-
import { isAbsolute as
|
|
59738
|
+
import { isAbsolute as isAbsolute24, join as join39 } from "path";
|
|
59398
59739
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
59399
59740
|
var DEFAULT_SQLITE_FILENAME2 = "server.db";
|
|
59400
59741
|
var SQLITE_MEMORY_PATH = ":memory:";
|
|
@@ -59430,7 +59771,7 @@ function resolveDatabaseTarget(raw) {
|
|
|
59430
59771
|
throw new Error(`unsupported database scheme "${scheme}:". Supported: postgres://, postgresql://, sqlite:, file:, ` + `an absolute or relative path to a .db/.sqlite file, ":memory:", or "memory:" (non-durable, tests only). ` + `Leave the setting empty to use the default SQLite database at ${defaultSqlitePath()}.`);
|
|
59431
59772
|
}
|
|
59432
59773
|
if (looksLikeSqlitePath(value)) {
|
|
59433
|
-
const path =
|
|
59774
|
+
const path = isAbsolute24(value) ? value : join39(process.cwd(), value);
|
|
59434
59775
|
return { kind: "sqlite", path, durable: true, label: `sqlite (${path})` };
|
|
59435
59776
|
}
|
|
59436
59777
|
throw new Error(`could not resolve a database backend from "${value}". Use postgres://\u2026, sqlite:\u2026, an absolute or ` + `relative path ending in ${SQLITE_EXTENSIONS.join("/")}, ":memory:", or leave it empty for the ` + `default SQLite database at ${defaultSqlitePath()}.`);
|
|
@@ -59454,7 +59795,7 @@ function sqlitePathFromUrl(value, scheme) {
|
|
|
59454
59795
|
}
|
|
59455
59796
|
return rest.slice(2).replace(/^\/\/+/, "/");
|
|
59456
59797
|
}
|
|
59457
|
-
return
|
|
59798
|
+
return isAbsolute24(rest) ? rest : join39(process.cwd(), rest);
|
|
59458
59799
|
}
|
|
59459
59800
|
function looksLikeSqlitePath(value) {
|
|
59460
59801
|
if (value.includes("/"))
|
|
@@ -59687,12 +60028,12 @@ class PostgresSkillSelectionStore {
|
|
|
59687
60028
|
// src/server/sqlite-store.ts
|
|
59688
60029
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
59689
60030
|
import { mkdirSync as mkdirSync12, readFileSync as readFileSync26, readdirSync as readdirSync13 } from "fs";
|
|
59690
|
-
import { dirname as
|
|
60031
|
+
import { dirname as dirname26, join as join41 } from "path";
|
|
59691
60032
|
|
|
59692
60033
|
// src/server/auth.ts
|
|
59693
|
-
import { createHash as
|
|
60034
|
+
import { createHash as createHash30 } from "crypto";
|
|
59694
60035
|
function hashApiKey(token) {
|
|
59695
|
-
return
|
|
60036
|
+
return createHash30("sha256").update(token).digest("hex");
|
|
59696
60037
|
}
|
|
59697
60038
|
function bearerToken(request2) {
|
|
59698
60039
|
const header = request2.headers.get("authorization") || "";
|
|
@@ -59746,7 +60087,7 @@ function permitsSkillsRoute(principal, method, resource) {
|
|
|
59746
60087
|
|
|
59747
60088
|
// src/server/migrations-dir.ts
|
|
59748
60089
|
import { existsSync as existsSync16 } from "fs";
|
|
59749
|
-
import { dirname as
|
|
60090
|
+
import { dirname as dirname25, join as join40 } from "path";
|
|
59750
60091
|
var MIGRATION_DIALECTS = ["postgres", "sqlite"];
|
|
59751
60092
|
var MAX_WALK_UP = 6;
|
|
59752
60093
|
function findMigrationsRoot(startDirs = defaultStartDirs()) {
|
|
@@ -59756,7 +60097,7 @@ function findMigrationsRoot(startDirs = defaultStartDirs()) {
|
|
|
59756
60097
|
const candidate2 = join40(dir, "migrations");
|
|
59757
60098
|
if (MIGRATION_DIALECTS.some((dialect) => existsSync16(join40(candidate2, dialect))))
|
|
59758
60099
|
return candidate2;
|
|
59759
|
-
const parent =
|
|
60100
|
+
const parent = dirname25(dir);
|
|
59760
60101
|
if (parent === dir)
|
|
59761
60102
|
break;
|
|
59762
60103
|
dir = parent;
|
|
@@ -60011,12 +60352,12 @@ class SkillLifecycleConflictError extends Error {
|
|
|
60011
60352
|
}
|
|
60012
60353
|
}
|
|
60013
60354
|
function validOperatorScopeEnrollmentInput(input) {
|
|
60014
|
-
const
|
|
60015
|
-
return
|
|
60355
|
+
const bounded2 = (value, max = 256) => typeof value === "string" && value.length > 0 && value.length <= max && !/[\u0000-\u001f\u007f]/.test(value);
|
|
60356
|
+
return bounded2(input.keyId) && bounded2(input.stationId) && bounded2(input.orgId) && bounded2(input.operationId) && bounded2(input.manifestDigest, 64) && /^[a-f0-9]{64}$/.test(input.manifestDigest) && bounded2(input.operatorJobId) && bounded2(input.operatorTaskArn, 512) && input.expectedScopes.length > 0 && input.expectedScopes.length <= 32 && input.expectedScopes.every((scope) => bounded2(scope, 128) && /^[a-z][a-z0-9_-]*:[a-z][a-z0-9_-]*$/.test(scope));
|
|
60016
60357
|
}
|
|
60017
60358
|
|
|
60018
60359
|
// src/lib/revision.ts
|
|
60019
|
-
import { createHash as
|
|
60360
|
+
import { createHash as createHash31 } from "crypto";
|
|
60020
60361
|
var REVISION_ID_PATTERN = /^[0-9a-f]{64}$/;
|
|
60021
60362
|
function revisionIdOf(content) {
|
|
60022
60363
|
const canonicalContent = {
|
|
@@ -60037,8 +60378,8 @@ function revisionIdOf(content) {
|
|
|
60037
60378
|
canonicalContent.archiveReason = content.archiveReason ?? null;
|
|
60038
60379
|
canonicalContent.replacementSlug = content.replacementSlug ?? null;
|
|
60039
60380
|
}
|
|
60040
|
-
const
|
|
60041
|
-
return
|
|
60381
|
+
const canonical8 = JSON.stringify(canonicalContent);
|
|
60382
|
+
return createHash31("sha256").update(canonical8).digest("hex");
|
|
60042
60383
|
}
|
|
60043
60384
|
function revisionIdOfRecord(record4) {
|
|
60044
60385
|
return revisionIdOf(record4);
|
|
@@ -60063,7 +60404,7 @@ class SqliteSkillsStore {
|
|
|
60063
60404
|
constructor(path = SQLITE_MEMORY_PATH, options = {}) {
|
|
60064
60405
|
const inMemory = path === SQLITE_MEMORY_PATH;
|
|
60065
60406
|
if (!inMemory)
|
|
60066
|
-
mkdirSync12(
|
|
60407
|
+
mkdirSync12(dirname26(path), { recursive: true });
|
|
60067
60408
|
this.db = openDatabase(path);
|
|
60068
60409
|
this.db.exec(`PRAGMA busy_timeout = ${Math.max(0, options.busyTimeoutMs ?? 5000)}`);
|
|
60069
60410
|
if (!inMemory)
|
|
@@ -60780,8 +61121,8 @@ function openDatabase(path) {
|
|
|
60780
61121
|
try {
|
|
60781
61122
|
return new Database(path, { create: true, readwrite: true });
|
|
60782
61123
|
} catch (error) {
|
|
60783
|
-
const
|
|
60784
|
-
throw new Error(`cannot open the skills database at ${path}: ${
|
|
61124
|
+
const reason2 = error instanceof Error ? error.message : String(error);
|
|
61125
|
+
throw new Error(`cannot open the skills database at ${path}: ${reason2}. ` + "Check that the directory exists and is writable. Set HASNA_SKILLS_DATABASE_URL to choose a " + "different path or a postgres:// URL, or HASNA_SKILLS_DIR to relocate the whole data directory.", { cause: error });
|
|
60785
61126
|
}
|
|
60786
61127
|
}
|
|
60787
61128
|
function parseScopes(value) {
|
|
@@ -60889,7 +61230,7 @@ class SqliteGovernanceStore {
|
|
|
60889
61230
|
closed = false;
|
|
60890
61231
|
constructor(path = SQLITE_MEMORY_PATH, options = {}) {
|
|
60891
61232
|
if (path !== SQLITE_MEMORY_PATH)
|
|
60892
|
-
mkdirSync13(
|
|
61233
|
+
mkdirSync13(dirname27(path), { recursive: true });
|
|
60893
61234
|
this.db = new Database2(path, { create: true, readwrite: true });
|
|
60894
61235
|
this.db.exec("PRAGMA busy_timeout = 5000");
|
|
60895
61236
|
this.db.exec("PRAGMA foreign_keys = ON");
|
|
@@ -61122,7 +61463,7 @@ function nextMonthPrefix(monthPrefix) {
|
|
|
61122
61463
|
}
|
|
61123
61464
|
|
|
61124
61465
|
// src/server/skills-api.ts
|
|
61125
|
-
import { createHash as
|
|
61466
|
+
import { createHash as createHash32 } from "crypto";
|
|
61126
61467
|
var SLUG_PATTERN = /^[a-z0-9][a-z0-9._-]*$/;
|
|
61127
61468
|
var SHA256_HEX2 = /^[0-9a-f]{64}$/;
|
|
61128
61469
|
var MAX_SLUG_LENGTH = 128;
|
|
@@ -61312,7 +61653,7 @@ async function parsePublishRequest(request2, config) {
|
|
|
61312
61653
|
if (bundleBytes.byteLength === 0) {
|
|
61313
61654
|
throw new SkillRequestError(400, "BUNDLE_EMPTY", "the uploaded bundle is empty");
|
|
61314
61655
|
}
|
|
61315
|
-
const sha2563 =
|
|
61656
|
+
const sha2563 = createHash32("sha256").update(bundleBytes).digest("hex");
|
|
61316
61657
|
const claimed = optionalString(manifest.bundleSha256);
|
|
61317
61658
|
if (claimed)
|
|
61318
61659
|
assertSha2562(claimed);
|
|
@@ -61427,7 +61768,7 @@ async function readPublishedBundle(store, artifactStorage, principal, slug) {
|
|
|
61427
61768
|
if (!bytes) {
|
|
61428
61769
|
throw new SkillRequestError(503, "BUNDLE_BACKEND_UNAVAILABLE", "bundle storage backend unavailable");
|
|
61429
61770
|
}
|
|
61430
|
-
const actual =
|
|
61771
|
+
const actual = createHash32("sha256").update(bytes).digest("hex");
|
|
61431
61772
|
if (actual !== record4.bundleSha256) {
|
|
61432
61773
|
throw new SkillRequestError(500, "BUNDLE_DIGEST_DRIFT", `stored bundle for '${slug}' hashes to ${actual} but was published as ${record4.bundleSha256}`);
|
|
61433
61774
|
}
|
|
@@ -61484,7 +61825,7 @@ function buildPublishInput(manifest) {
|
|
|
61484
61825
|
displayName: optionalString(manifest.displayName) ?? titleize(slug),
|
|
61485
61826
|
description,
|
|
61486
61827
|
category: optionalString(manifest.category) ?? "Development Tools",
|
|
61487
|
-
tags:
|
|
61828
|
+
tags: stringArray2(manifest.tags),
|
|
61488
61829
|
source: publishSource(optionalString(manifest.source)),
|
|
61489
61830
|
kind: kindValue,
|
|
61490
61831
|
...publishVersionOf(manifest) ? { version: publishVersionOf(manifest) } : {},
|
|
@@ -61513,7 +61854,7 @@ function optionalString(value) {
|
|
|
61513
61854
|
function optionalText(value) {
|
|
61514
61855
|
return typeof value === "string" && value.trim() ? value : undefined;
|
|
61515
61856
|
}
|
|
61516
|
-
function
|
|
61857
|
+
function stringArray2(value) {
|
|
61517
61858
|
if (!Array.isArray(value))
|
|
61518
61859
|
return [];
|
|
61519
61860
|
return value.filter((item) => typeof item === "string" && item.trim().length > 0).map((item) => item.trim());
|
|
@@ -61575,7 +61916,7 @@ async function readSkillVersionBundle(store, artifactStorage, principal, slug, v
|
|
|
61575
61916
|
const bytes = await artifactStorage.readBundle(bundle2);
|
|
61576
61917
|
if (!bytes)
|
|
61577
61918
|
throw new SkillRequestError(503, "BUNDLE_BACKEND_UNAVAILABLE", "bundle storage backend unavailable");
|
|
61578
|
-
const actual =
|
|
61919
|
+
const actual = createHash32("sha256").update(bytes).digest("hex");
|
|
61579
61920
|
if (actual !== found.bundleSha256) {
|
|
61580
61921
|
throw new SkillRequestError(500, "BUNDLE_DIGEST_DRIFT", `stored bundle for '${slug}@${version2}' hashes to ${actual} but was published as ${found.bundleSha256}`);
|
|
61581
61922
|
}
|
|
@@ -61658,7 +61999,7 @@ async function validatePublishedGrant(store, artifacts, principal, grant) {
|
|
|
61658
61999
|
invalid3();
|
|
61659
62000
|
}
|
|
61660
62001
|
async function handleExecutionGrantApi(store, principal, request2, parts, config, artifacts) {
|
|
61661
|
-
const [resource, id2,
|
|
62002
|
+
const [resource, id2, child2, revision] = parts;
|
|
61662
62003
|
if (resource !== "execution-grants")
|
|
61663
62004
|
return null;
|
|
61664
62005
|
if (!grantIdentifier(id2))
|
|
@@ -61666,7 +62007,7 @@ async function handleExecutionGrantApi(store, principal, request2, parts, config
|
|
|
61666
62007
|
const { executionGrantStore: policies, selectionStore: profiles } = store;
|
|
61667
62008
|
if (!policies || !profiles)
|
|
61668
62009
|
refuse5(503, "EXECUTION_GRANTS_UNAVAILABLE", "This store does not support execution grants.");
|
|
61669
|
-
const historical = parts.length === 4 &&
|
|
62010
|
+
const historical = parts.length === 4 && child2 === "versions" && grantIdentifier(revision);
|
|
61670
62011
|
if (request2.method === "GET" && (parts.length === 2 || historical)) {
|
|
61671
62012
|
const policy = await policies.get(principal, id2, historical ? revision : undefined);
|
|
61672
62013
|
if (!policy)
|
|
@@ -61705,7 +62046,7 @@ async function handleExecutionGrantApi(store, principal, request2, parts, config
|
|
|
61705
62046
|
refuse5(409, "EXECUTION_GRANT_REVISION_CONFLICT", "Execution grant policy changed; read it before retrying.");
|
|
61706
62047
|
return json(saved, create ? 201 : 200, saved.revision);
|
|
61707
62048
|
}
|
|
61708
|
-
if (request2.method === "POST" && parts.length === 3 &&
|
|
62049
|
+
if (request2.method === "POST" && parts.length === 3 && child2 === "resolve") {
|
|
61709
62050
|
const input = await body(request2, Math.min(config.requestBodyLimitBytes, 16384));
|
|
61710
62051
|
let consumer;
|
|
61711
62052
|
try {
|
|
@@ -61870,7 +62211,7 @@ function json2(value, status = 200, revision) {
|
|
|
61870
62211
|
});
|
|
61871
62212
|
}
|
|
61872
62213
|
async function handleProfileApi(store, principal, request2, parts, config) {
|
|
61873
|
-
const [resource, id2,
|
|
62214
|
+
const [resource, id2, child2] = parts;
|
|
61874
62215
|
if (resource === "capabilities" && request2.method === "GET" && parts.length === 1)
|
|
61875
62216
|
return json2({
|
|
61876
62217
|
contractVersion: 1,
|
|
@@ -61936,13 +62277,13 @@ async function handleProfileApi(store, principal, request2, parts, config) {
|
|
|
61936
62277
|
throw new SkillRequestError(409, "PROFILE_REVISION_CONFLICT", "Profile changed; read it before retrying");
|
|
61937
62278
|
return json2(saved, create ? 201 : 200, saved.revision);
|
|
61938
62279
|
}
|
|
61939
|
-
if (resource === "profiles" && request2.method === "GET" && (parts.length === 2 || parts.length === 3 &&
|
|
62280
|
+
if (resource === "profiles" && request2.method === "GET" && (parts.length === 2 || parts.length === 3 && child2 === "resolve")) {
|
|
61940
62281
|
const profile2 = await adapter.getProfile(principal, id2);
|
|
61941
62282
|
if (!profile2)
|
|
61942
62283
|
throw new SkillRequestError(404, "PROFILE_NOT_FOUND", "Profile not found");
|
|
61943
62284
|
if (profile2.selections.length > MAX_PROFILE_SELECTIONS)
|
|
61944
62285
|
throw new SkillRequestError(413, "PROFILE_TOO_LARGE", "Profile exceeds the advertised selection limit");
|
|
61945
|
-
if (!
|
|
62286
|
+
if (!child2)
|
|
61946
62287
|
return json2(profile2, 200, profile2.revision);
|
|
61947
62288
|
const authority2 = skillsApiRequestUrl(normalizeSkillsApiOrigin(config.publicBaseUrl), "/api/v1/").replace(/\/+$/, "");
|
|
61948
62289
|
const result = resolvedProfileSnapshot(profile2, authority2);
|
|
@@ -61961,7 +62302,7 @@ async function handleProfileApi(store, principal, request2, parts, config) {
|
|
|
61961
62302
|
throw new SkillRequestError(413, "PROFILE_TOO_LARGE", "Resolved profile exceeds the advertised profile limits");
|
|
61962
62303
|
return json2(result, 200, profile2.revision);
|
|
61963
62304
|
}
|
|
61964
|
-
if (resource === "stations" && parts.length === 3 &&
|
|
62305
|
+
if (resource === "stations" && parts.length === 3 && child2 === "state") {
|
|
61965
62306
|
if (request2.method === "GET") {
|
|
61966
62307
|
const state2 = await adapter.getStationState(principal, id2);
|
|
61967
62308
|
if (!state2)
|
|
@@ -61995,7 +62336,7 @@ async function handleProfileApi(store, principal, request2, parts, config) {
|
|
|
61995
62336
|
// src/server/runtime-store.ts
|
|
61996
62337
|
import { Database as Database3 } from "bun:sqlite";
|
|
61997
62338
|
import { mkdirSync as mkdirSync14 } from "fs";
|
|
61998
|
-
import { dirname as
|
|
62339
|
+
import { dirname as dirname28 } from "path";
|
|
61999
62340
|
|
|
62000
62341
|
// src/sdk/execution/types.ts
|
|
62001
62342
|
var EXECUTION_PROTOCOL_VERSION = REMOTE_SKILL_RUN_CONTRACT_VERSION;
|
|
@@ -62051,7 +62392,7 @@ class RuntimeExecutionStore {
|
|
|
62051
62392
|
}
|
|
62052
62393
|
const path = target.kind === "sqlite" ? target.path : ":memory:";
|
|
62053
62394
|
if (path !== ":memory:")
|
|
62054
|
-
mkdirSync14(
|
|
62395
|
+
mkdirSync14(dirname28(path), { recursive: true });
|
|
62055
62396
|
const db = new Database3(path);
|
|
62056
62397
|
db.run("PRAGMA busy_timeout=5000");
|
|
62057
62398
|
db.run("PRAGMA journal_mode=WAL");
|
|
@@ -62291,7 +62632,7 @@ class RuntimeExecutionStore {
|
|
|
62291
62632
|
}
|
|
62292
62633
|
|
|
62293
62634
|
// src/sdk/execution/admission.ts
|
|
62294
|
-
import { createHash as
|
|
62635
|
+
import { createHash as createHash34 } from "crypto";
|
|
62295
62636
|
|
|
62296
62637
|
// src/sdk/execution/image-profile.ts
|
|
62297
62638
|
class ImageProfileResolutionError extends Error {
|
|
@@ -62903,11 +63244,11 @@ function ownedAdmission(admission) {
|
|
|
62903
63244
|
};
|
|
62904
63245
|
}
|
|
62905
63246
|
function digestInput(input) {
|
|
62906
|
-
return
|
|
63247
|
+
return createHash34("sha256").update(canonicalJson2(input)).digest("hex");
|
|
62907
63248
|
}
|
|
62908
63249
|
|
|
62909
63250
|
// src/sdk/execution/dispatchers/ecs.ts
|
|
62910
|
-
import { createHash as
|
|
63251
|
+
import { createHash as createHash35 } from "crypto";
|
|
62911
63252
|
|
|
62912
63253
|
// src/sdk/execution/state-machine.ts
|
|
62913
63254
|
var LEGAL_TRANSITIONS = {
|
|
@@ -66307,13 +66648,13 @@ function observedTask(states, taskArn) {
|
|
|
66307
66648
|
return state2.lastStatus === "STOPPED" || LIVE_TASK_STATUSES.has(state2.lastStatus) ? state2 : undefined;
|
|
66308
66649
|
}
|
|
66309
66650
|
function clientTokenFor(runId3, attemptId) {
|
|
66310
|
-
return
|
|
66651
|
+
return createHash35("sha256").update(`${runId3}\x00${attemptId}`).digest("hex").slice(0, CLIENT_TOKEN_BYTES * 2);
|
|
66311
66652
|
}
|
|
66312
66653
|
function startedByFor(runId3, attemptNumber) {
|
|
66313
66654
|
return `skills-exec/${runId3}/a${attemptNumber}`;
|
|
66314
66655
|
}
|
|
66315
66656
|
function requestDigestFor(admission, attemptId) {
|
|
66316
|
-
return
|
|
66657
|
+
return createHash35("sha256").update(canonicalJson2({ admission, attemptId })).digest("hex");
|
|
66317
66658
|
}
|
|
66318
66659
|
|
|
66319
66660
|
class EcsDispatcher {
|
|
@@ -66609,10 +66950,10 @@ function validText(value) {
|
|
|
66609
66950
|
}
|
|
66610
66951
|
|
|
66611
66952
|
// src/server/runtime-policy.ts
|
|
66612
|
-
import { createHash as
|
|
66953
|
+
import { createHash as createHash37, createHmac as createHmac3, timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
66613
66954
|
|
|
66614
66955
|
// src/server/runtime-pure-contract.ts
|
|
66615
|
-
import { createHash as
|
|
66956
|
+
import { createHash as createHash36 } from "crypto";
|
|
66616
66957
|
var PURE_DESCRIPTOR = Object.freeze({
|
|
66617
66958
|
id: "regex-test.v1",
|
|
66618
66959
|
runtime: "bun",
|
|
@@ -66636,7 +66977,7 @@ var PURE_LIMITS = Object.freeze({
|
|
|
66636
66977
|
maxArtifactsBytes: 0,
|
|
66637
66978
|
maxConcurrency: 1
|
|
66638
66979
|
});
|
|
66639
|
-
var hash2 = (bytes) =>
|
|
66980
|
+
var hash2 = (bytes) => createHash36("sha256").update(bytes).digest("hex");
|
|
66640
66981
|
var object7 = (v2) => {
|
|
66641
66982
|
if (!v2 || typeof v2 !== "object" || Array.isArray(v2))
|
|
66642
66983
|
throw Error("Pure contract requires an object");
|
|
@@ -66865,7 +67206,7 @@ function verifyRuntimeToken(token, key, admission, attempt, now = Date.now()) {
|
|
|
66865
67206
|
const actual = Buffer.from(token);
|
|
66866
67207
|
return actual.length === expected.length && timingSafeEqual2(actual, expected);
|
|
66867
67208
|
}
|
|
66868
|
-
var hashBytes = (bytes) =>
|
|
67209
|
+
var hashBytes = (bytes) => createHash37("sha256").update(bytes).digest("hex");
|
|
66869
67210
|
|
|
66870
67211
|
// src/server/runtime-api.ts
|
|
66871
67212
|
async function createRuntimeService(options) {
|
|
@@ -73241,7 +73582,7 @@ var localRunExecutor = {
|
|
|
73241
73582
|
// src/sdk/storage.ts
|
|
73242
73583
|
var artifactStorageSeam = ArtifactStorage;
|
|
73243
73584
|
// src/sdk/outputs.ts
|
|
73244
|
-
import { createHash as
|
|
73585
|
+
import { createHash as createHash38 } from "crypto";
|
|
73245
73586
|
class DatabaseOnlyObjectStore {
|
|
73246
73587
|
usesS3 = false;
|
|
73247
73588
|
async materialize(run, artifact, body4) {
|
|
@@ -73288,7 +73629,7 @@ function createGovernedArtifactWriter(options) {
|
|
|
73288
73629
|
const stamped = {
|
|
73289
73630
|
...meta,
|
|
73290
73631
|
byteSize: outputBytes,
|
|
73291
|
-
sha256:
|
|
73632
|
+
sha256: createHash38("sha256").update(persistedBytes).digest("hex"),
|
|
73292
73633
|
visibility: options.visibility ?? config.defaultVisibility,
|
|
73293
73634
|
...config.artifactTtlSeconds !== undefined ? { expiresAt: expiresAtFor(createdAt, config.artifactTtlSeconds) } : {}
|
|
73294
73635
|
};
|
|
@@ -76930,14 +77271,14 @@ var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => {
|
|
|
76930
77271
|
const shape = zod.def.shape;
|
|
76931
77272
|
const propValues = {};
|
|
76932
77273
|
for (const key in shape) {
|
|
76933
|
-
const
|
|
76934
|
-
if (
|
|
77274
|
+
const field3 = shape[key]._zod;
|
|
77275
|
+
if (field3.values) {
|
|
76935
77276
|
if (!Object.prototype.hasOwnProperty.call(propValues, key)) {
|
|
76936
77277
|
assignProp(propValues, key, new Set);
|
|
76937
77278
|
}
|
|
76938
|
-
for (const v2 of
|
|
77279
|
+
for (const v2 of field3.values)
|
|
76939
77280
|
propValues[key].add(v2);
|
|
76940
|
-
if (
|
|
77281
|
+
if (field3.optin !== undefined)
|
|
76941
77282
|
propValues[key].add(undefined);
|
|
76942
77283
|
}
|
|
76943
77284
|
}
|
|
@@ -78350,8 +78691,8 @@ function isRecursive(inst, stack) {
|
|
|
78350
78691
|
return true;
|
|
78351
78692
|
stack.add(inst);
|
|
78352
78693
|
let result = false;
|
|
78353
|
-
const check = (
|
|
78354
|
-
if (!result &&
|
|
78694
|
+
const check = (child2) => {
|
|
78695
|
+
if (!result && child2?._zod && isRecursive(child2, stack))
|
|
78355
78696
|
result = true;
|
|
78356
78697
|
};
|
|
78357
78698
|
const def = inst._zod.def;
|
|
@@ -89130,11 +89471,11 @@ var objectProcessor = (schema, ctx, _json, params) => {
|
|
|
89130
89471
|
}
|
|
89131
89472
|
const allKeys = new Set(Object.keys(shape));
|
|
89132
89473
|
const requiredKeys = new Set([...allKeys].filter((key) => {
|
|
89133
|
-
const
|
|
89474
|
+
const field3 = def.shape[key];
|
|
89134
89475
|
if (ctx.io === "input") {
|
|
89135
|
-
return inputOptin(
|
|
89476
|
+
return inputOptin(field3) === undefined;
|
|
89136
89477
|
} else {
|
|
89137
|
-
return
|
|
89478
|
+
return field3._zod.optout === undefined;
|
|
89138
89479
|
}
|
|
89139
89480
|
}));
|
|
89140
89481
|
if (requiredKeys.size > 0) {
|
|
@@ -92055,7 +92396,7 @@ function date4(params) {
|
|
|
92055
92396
|
return _coercedDate(ZodDate2, params);
|
|
92056
92397
|
}
|
|
92057
92398
|
// src/lib/canonical-json.ts
|
|
92058
|
-
import { createHash as
|
|
92399
|
+
import { createHash as createHash39 } from "crypto";
|
|
92059
92400
|
function canonicalJson3(value, maximumBytes = 2 * 1024 * 1024) {
|
|
92060
92401
|
return canonicalJsonAtDepth(value, maximumBytes, 64);
|
|
92061
92402
|
}
|
|
@@ -92099,7 +92440,7 @@ function canonicalJsonAtDepth(value, maximumBytes, maximumDepth) {
|
|
|
92099
92440
|
return visit3(value, 0);
|
|
92100
92441
|
}
|
|
92101
92442
|
function canonicalJsonSha256(value, maximumBytes) {
|
|
92102
|
-
return
|
|
92443
|
+
return createHash39("sha256").update(canonicalJson3(value, maximumBytes)).digest("hex");
|
|
92103
92444
|
}
|
|
92104
92445
|
|
|
92105
92446
|
// src/lib/remote-recurring-contract.ts
|
|
@@ -92879,17 +93220,17 @@ function runQuoteReceipt(value) {
|
|
|
92879
93220
|
return value;
|
|
92880
93221
|
}
|
|
92881
93222
|
function parseRemoteRunQuote(value) {
|
|
92882
|
-
const
|
|
92883
|
-
runQuoteReceipt(
|
|
92884
|
-
const pricing = object9(
|
|
92885
|
-
if (typeof
|
|
93223
|
+
const quote3 = object9(value);
|
|
93224
|
+
runQuoteReceipt(quote3.quoteReceipt);
|
|
93225
|
+
const pricing = object9(quote3.pricing);
|
|
93226
|
+
if (typeof quote3.skill !== "string" || !/^[a-z0-9][a-z0-9-]*$/.test(quote3.skill))
|
|
92886
93227
|
throw new Error("Invalid quoted skill");
|
|
92887
93228
|
const costCents = creditCount(pricing.costCredits ?? pricing.costCents);
|
|
92888
93229
|
if (pricing.costCredits !== undefined && pricing.costCents !== undefined && pricing.costCents !== costCents)
|
|
92889
93230
|
throw new Error("Inconsistent quoted credit count");
|
|
92890
|
-
if (
|
|
93231
|
+
if (quote3.availability && object9(quote3.availability).status !== "available")
|
|
92891
93232
|
throw new Error("This skill is unavailable for remote execution");
|
|
92892
|
-
return { ...
|
|
93233
|
+
return { ...quote3, skill: quote3.skill, pricing: { ...pricing, costCredits: costCents, costCents, formattedCost: `${costCents} credits` } };
|
|
92893
93234
|
}
|
|
92894
93235
|
function parseRemoteCreditPacks(value) {
|
|
92895
93236
|
if (!Array.isArray(value))
|
|
@@ -92964,14 +93305,14 @@ function creditCheckoutFailure(value, status, key) {
|
|
|
92964
93305
|
}
|
|
92965
93306
|
|
|
92966
93307
|
// src/lib/remote-profile.ts
|
|
92967
|
-
function customerNamePatch(input2,
|
|
92968
|
-
if (!isRecord6(input2) || Object.keys(input2).length !== 1 || !Object.hasOwn(input2,
|
|
93308
|
+
function customerNamePatch(input2, field3) {
|
|
93309
|
+
if (!isRecord6(input2) || Object.keys(input2).length !== 1 || !Object.hasOwn(input2, field3))
|
|
92969
93310
|
throw new Error("Provide only the requested name field.");
|
|
92970
|
-
const value = input2[
|
|
93311
|
+
const value = input2[field3];
|
|
92971
93312
|
if (typeof value !== "string" || /[\p{Cc}\p{Cs}\u2028\u2029]/u.test(value) || !value.trim() || [...value.trim()].length > 100) {
|
|
92972
93313
|
throw new Error("Use a name of 1\u2013100 characters without control characters or newlines.");
|
|
92973
93314
|
}
|
|
92974
|
-
return { [
|
|
93315
|
+
return { [field3]: value.trim() };
|
|
92975
93316
|
}
|
|
92976
93317
|
function isRecord6(value) {
|
|
92977
93318
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
@@ -93016,10 +93357,10 @@ async function readQuoteUnavailableCode(response) {
|
|
|
93016
93357
|
let timer;
|
|
93017
93358
|
let deadlineExceeded = false;
|
|
93018
93359
|
const expired = Symbol("quote body deadline");
|
|
93019
|
-
const deadline = new Promise((
|
|
93360
|
+
const deadline = new Promise((resolve25) => {
|
|
93020
93361
|
timer = setTimeout(() => {
|
|
93021
93362
|
deadlineExceeded = true;
|
|
93022
|
-
|
|
93363
|
+
resolve25(expired);
|
|
93023
93364
|
reader.cancel().catch(() => {});
|
|
93024
93365
|
}, 1500);
|
|
93025
93366
|
});
|
|
@@ -93366,18 +93707,18 @@ class RemoteSkillsClient {
|
|
|
93366
93707
|
const maximum = creditCount(approval.maxCredits ?? approval.maxCostCents ?? 0);
|
|
93367
93708
|
if (approval.maxCostCents !== undefined && approval.maxCostCents !== maximum)
|
|
93368
93709
|
throw new Error("Credit approval fields disagree");
|
|
93369
|
-
const
|
|
93370
|
-
if (
|
|
93371
|
-
throw new RemoteCreditApprovalError(
|
|
93710
|
+
const quote3 = approval.quoteReceipt === undefined ? await this.quoteRun(slug2, input2, args, approval.inputFiles?.length ? approval.inputFiles : undefined) : undefined;
|
|
93711
|
+
if (quote3 && quote3.pricing.costCents > maximum)
|
|
93712
|
+
throw new RemoteCreditApprovalError(quote3.pricing.costCents, maximum);
|
|
93372
93713
|
const capabilities = await this.getCapabilities();
|
|
93373
93714
|
if (!capabilities.capabilities.includes("runs.submit") || capabilities.billing?.boundedRunApproval !== true || capabilities.billing.unit !== "credits") {
|
|
93374
93715
|
throw new Error("The configured server does not support bounded credit approval; refusing remote submission");
|
|
93375
93716
|
}
|
|
93376
|
-
return this.submitRun(
|
|
93717
|
+
return this.submitRun(quote3?.skill ?? slug2, input2, args, {
|
|
93377
93718
|
...approval,
|
|
93378
93719
|
maxCredits: maximum,
|
|
93379
93720
|
maxCostCents: maximum,
|
|
93380
|
-
...(
|
|
93721
|
+
...(quote3?.quoteReceipt ?? approval.quoteReceipt) === undefined ? {} : { quoteReceipt: quote3?.quoteReceipt ?? approval.quoteReceipt }
|
|
93381
93722
|
});
|
|
93382
93723
|
}
|
|
93383
93724
|
async getIdentity() {
|
|
@@ -93978,13 +94319,13 @@ class RemoteSkillsClient {
|
|
|
93978
94319
|
return normalizeUpdatedSincePage(await response.json());
|
|
93979
94320
|
}
|
|
93980
94321
|
}
|
|
93981
|
-
function requireOptionalString(record9,
|
|
93982
|
-
if (record9[
|
|
94322
|
+
function requireOptionalString(record9, field3) {
|
|
94323
|
+
if (record9[field3] === undefined)
|
|
93983
94324
|
return;
|
|
93984
|
-
if (typeof record9[
|
|
93985
|
-
throw new Error(`Remote payload did not match the expected contract (${
|
|
94325
|
+
if (typeof record9[field3] !== "string") {
|
|
94326
|
+
throw new Error(`Remote payload did not match the expected contract (${field3} must be a string when present)`);
|
|
93986
94327
|
}
|
|
93987
|
-
return record9[
|
|
94328
|
+
return record9[field3];
|
|
93988
94329
|
}
|
|
93989
94330
|
var INVALID_SKILL_VERSION_RESPONSE = "Remote skill version payload did not match the expected contract.";
|
|
93990
94331
|
function isVersionRecord(value) {
|
|
@@ -94213,7 +94554,7 @@ async function requestInvitationEmail(origin, action, input2) {
|
|
|
94213
94554
|
}
|
|
94214
94555
|
|
|
94215
94556
|
// src/lib/remote-private-publications.ts
|
|
94216
|
-
import { createHash as
|
|
94557
|
+
import { createHash as createHash40 } from "crypto";
|
|
94217
94558
|
var PRIVATE_PUBLICATION_MAX_BYTES = 16 * 1024 * 1024;
|
|
94218
94559
|
var failures2 = {
|
|
94219
94560
|
INVALID_REQUEST: [400, "The publication request is invalid."],
|
|
@@ -94260,7 +94601,7 @@ var hash4 = (v2) => typeof v2 === "string" && /^[a-f0-9]{64}$/.test(v2);
|
|
|
94260
94601
|
var record10 = (v2) => !!v2 && typeof v2 === "object" && !Array.isArray(v2);
|
|
94261
94602
|
var exact = (v2, keys3) => record10(v2) && Object.keys(v2).sort().join(",") === keys3.sort().join(",");
|
|
94262
94603
|
var date5 = (v2) => typeof v2 === "string" && /^\d{4}-\d\d-\d\dT[0-9:.]+(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/.test(v2) && Number.isFinite(Date.parse(v2));
|
|
94263
|
-
var publicationSha256 = (bytes) =>
|
|
94604
|
+
var publicationSha256 = (bytes) => createHash40("sha256").update(bytes).digest("hex");
|
|
94264
94605
|
function checkedPublicationDeclaration(value) {
|
|
94265
94606
|
if (!exact(value, ["idempotencyKey", "version", "expectedCurrentVersionId", "manifestText", "archiveSha256", "archiveByteSize"]) || !publicationUuid(value.idempotencyKey) || !(value.expectedCurrentVersionId === null || publicationUuid(value.expectedCurrentVersionId)) || typeof value.version !== "string" || !value.version || value.version.length > 128 || /[\p{Cc}\p{Cs}]/u.test(value.version) || typeof value.manifestText !== "string" || Buffer.byteLength(value.manifestText) > 16384 || !hash4(value.archiveSha256) || !Number.isSafeInteger(value.archiveByteSize) || Number(value.archiveByteSize) < 1 || Number(value.archiveByteSize) > PRIVATE_PUBLICATION_MAX_BYTES)
|
|
94266
94607
|
return bad();
|
|
@@ -94505,12 +94846,12 @@ class RemotePrivatePublicationsClient {
|
|
|
94505
94846
|
previous = view;
|
|
94506
94847
|
if (!["queued", "verifying"].includes(view.state) || Date.now() >= until)
|
|
94507
94848
|
return view;
|
|
94508
|
-
await new Promise((
|
|
94849
|
+
await new Promise((resolve25) => {
|
|
94509
94850
|
const timer = setTimeout(done, Math.min(1000, until - Date.now()));
|
|
94510
94851
|
function done() {
|
|
94511
94852
|
clearTimeout(timer);
|
|
94512
94853
|
options.signal?.removeEventListener("abort", done);
|
|
94513
|
-
|
|
94854
|
+
resolve25();
|
|
94514
94855
|
}
|
|
94515
94856
|
options.signal?.addEventListener("abort", done, { once: true });
|
|
94516
94857
|
});
|
|
@@ -94743,19 +95084,19 @@ class RemoteSkillsAuthClient {
|
|
|
94743
95084
|
}
|
|
94744
95085
|
// src/lib/private-publication-recovery.ts
|
|
94745
95086
|
import { constants as constants16, closeSync as closeSync19, fsyncSync as fsyncSync7, fstatSync as fstatSync19, lstatSync as lstatSync27, mkdirSync as mkdirSync15, openSync as openSync19, readSync as readSync13, realpathSync as realpathSync16, renameSync as renameSync7, unlinkSync as unlinkSync6, writeFileSync as writeFileSync11 } from "fs";
|
|
94746
|
-
import { dirname as
|
|
95087
|
+
import { dirname as dirname29, isAbsolute as isAbsolute25, join as join43, resolve as resolve25 } from "path";
|
|
94747
95088
|
import { randomUUID as randomUUID12 } from "crypto";
|
|
94748
95089
|
var fail2 = () => {
|
|
94749
95090
|
throw new PrivatePublicationError("PUBLICATION_RECOVERY_INVALID", "The recovery directory is invalid or changed. Preserve it and inspect the existing intent; do not start a replacement automatically.");
|
|
94750
95091
|
};
|
|
94751
95092
|
function safeDirectory(directory) {
|
|
94752
|
-
if (!
|
|
95093
|
+
if (!isAbsolute25(directory) || directory !== resolve25(directory) || realpathSync16(directory) !== directory)
|
|
94753
95094
|
return fail2();
|
|
94754
|
-
for (let path2 = directory;; path2 =
|
|
95095
|
+
for (let path2 = directory;; path2 = dirname29(path2)) {
|
|
94755
95096
|
const stat2 = lstatSync27(path2);
|
|
94756
95097
|
if (!stat2.isDirectory() || stat2.isSymbolicLink())
|
|
94757
95098
|
return fail2();
|
|
94758
|
-
if (path2 ===
|
|
95099
|
+
if (path2 === dirname29(path2))
|
|
94759
95100
|
break;
|
|
94760
95101
|
}
|
|
94761
95102
|
const own2 = lstatSync27(directory);
|
|
@@ -94887,11 +95228,11 @@ async function preparePrivatePublication(client2, sourceDirectory, recoveryDirec
|
|
|
94887
95228
|
phase: "prepared",
|
|
94888
95229
|
intent: null
|
|
94889
95230
|
};
|
|
94890
|
-
if (!
|
|
95231
|
+
if (!isAbsolute25(recoveryDirectory) || resolve25(recoveryDirectory) !== recoveryDirectory || realpathSync16(dirname29(recoveryDirectory)) !== dirname29(recoveryDirectory))
|
|
94891
95232
|
return fail2();
|
|
94892
95233
|
mkdirSync15(recoveryDirectory, { mode: 448 });
|
|
94893
95234
|
safeDirectory(recoveryDirectory);
|
|
94894
|
-
const parent = openSync19(
|
|
95235
|
+
const parent = openSync19(dirname29(recoveryDirectory), constants16.O_RDONLY | constants16.O_NOFOLLOW);
|
|
94895
95236
|
try {
|
|
94896
95237
|
fsyncSync7(parent);
|
|
94897
95238
|
} finally {
|