@hasna/skills 0.10.20 → 0.10.23
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 +39 -8
- package/bin/index.js +652 -354
- package/bin/mcp.js +310 -119
- package/bin/migrate.js +1 -1
- package/bin/server.js +1 -1
- package/bin/worker.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +466 -177
- package/dist/lib/agent-discovery.d.ts +4 -1
- package/dist/lib/agent-integration.d.ts +4 -0
- package/dist/lib/codex-hook-rpc.d.ts +1 -1
- package/dist/lib/codex-native-compatibility.d.ts +3 -0
- package/dist/lib/codex-native-skill-catalog.d.ts +4 -0
- package/dist/lib/codex-plugin-skill-controls.d.ts +2 -0
- package/dist/lib/codex-settings-witness-v1.d.ts +12 -0
- package/dist/lib/codex-settings-witness.d.ts +13 -5
- package/dist/sdk/index.js +537 -249
- package/package.json +1 -1
package/dist/sdk/index.js
CHANGED
|
@@ -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: sep9, join: join4 } = __require("path");
|
|
9007
|
-
var { createHash:
|
|
9007
|
+
var { createHash: createHash21 } = __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 = createHash21("sha1");
|
|
9163
9163
|
const cacheName = hasher.update(id2).digest("hex");
|
|
9164
9164
|
return join4(getHomeDir(), ".aws", "sso", "cache", `${cacheName}.json`);
|
|
9165
9165
|
};
|
|
@@ -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: createHash21, getRandomValues } = __require("crypto");
|
|
10515
10515
|
var { hasOwn: hasOwn2, HttpResponse } = require_transport();
|
|
10516
10516
|
exports.hasOwn = hasOwn2;
|
|
10517
10517
|
var { ReadStream, lstatSync: lstatSync23, 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)) : createHash21(this.algorithmIdentifier);
|
|
11420
11420
|
}
|
|
11421
11421
|
}
|
|
11422
11422
|
function castSourceData(toCast, encoding) {
|
|
@@ -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: createHash21, 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;
|
|
@@ -12320,7 +12320,7 @@ var require_checksum = __commonJS((exports) => {
|
|
|
12320
12320
|
}
|
|
12321
12321
|
var hasNativeCrypto$1 = (() => {
|
|
12322
12322
|
try {
|
|
12323
|
-
|
|
12323
|
+
createHash21("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 = createHash21("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 = createHash21("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
|
+
createHash21("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)) : createHash21("sha256");
|
|
12673
12673
|
}
|
|
12674
12674
|
};
|
|
12675
12675
|
}
|
|
@@ -14538,8 +14538,8 @@ var require_protocols = __commonJS((exports) => {
|
|
|
14538
14538
|
class Fields {
|
|
14539
14539
|
entries = {};
|
|
14540
14540
|
encoding;
|
|
14541
|
-
constructor({ fields = [], encoding = "utf-8" }) {
|
|
14542
|
-
|
|
14541
|
+
constructor({ fields: fields2 = [], encoding = "utf-8" }) {
|
|
14542
|
+
fields2.forEach(this.setField.bind(this));
|
|
14543
14543
|
this.encoding = encoding;
|
|
14544
14544
|
}
|
|
14545
14545
|
setField(field2) {
|
|
@@ -18166,7 +18166,7 @@ ${toHex(hashedRequest)}`;
|
|
|
18166
18166
|
return hash2.digest();
|
|
18167
18167
|
};
|
|
18168
18168
|
var getCanonicalHeaders = ({ headers }, unsignableHeaders, signableHeaders) => {
|
|
18169
|
-
const
|
|
18169
|
+
const canonical6 = {};
|
|
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
|
+
canonical6[canonicalHeaderName] = headers[headerName].trim().replace(/\s+/g, " ");
|
|
18181
18181
|
}
|
|
18182
|
-
return
|
|
18182
|
+
return canonical6;
|
|
18183
18183
|
};
|
|
18184
18184
|
var getPayloadHash = async ({ headers, body }, hashConstructor) => {
|
|
18185
18185
|
for (const headerName in headers) {
|
|
@@ -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 canonical6 = String(value);
|
|
21704
|
+
if (normalized === canonical6) {
|
|
21705
21705
|
return true;
|
|
21706
21706
|
}
|
|
21707
|
-
if (/[eE]/.test(
|
|
21708
|
-
return normalized === expandToDecimal(
|
|
21707
|
+
if (/[eE]/.test(canonical6)) {
|
|
21708
|
+
return normalized === expandToDecimal(canonical6);
|
|
21709
21709
|
}
|
|
21710
21710
|
return false;
|
|
21711
21711
|
}
|
|
@@ -29443,7 +29443,7 @@ 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 createHash21, createPrivateKey, createPublicKey, sign } from "crypto";
|
|
29447
29447
|
import { promises as fs2 } from "fs";
|
|
29448
29448
|
import { homedir as homedir7 } from "os";
|
|
29449
29449
|
import { dirname as dirname21, join as join33 } from "path";
|
|
@@ -29615,7 +29615,7 @@ var init_LoginCredentialsFetcher = __esm(() => {
|
|
|
29615
29615
|
getTokenFilePath() {
|
|
29616
29616
|
const directory = process.env.AWS_LOGIN_CACHE_DIRECTORY ?? join33(homedir7(), ".aws", "login", "cache");
|
|
29617
29617
|
const loginSessionBytes = Buffer.from(this.loginSession, "utf8");
|
|
29618
|
-
const loginSessionSha256 =
|
|
29618
|
+
const loginSessionSha256 = createHash21("sha256").update(loginSessionBytes).digest("hex");
|
|
29619
29619
|
return join33(directory, `${loginSessionSha256}.json`);
|
|
29620
29620
|
}
|
|
29621
29621
|
derToRawSignature(derSignature) {
|
|
@@ -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.23",
|
|
32377
32377
|
description: "Skills library for AI coding agents",
|
|
32378
32378
|
type: "module",
|
|
32379
32379
|
bin: {
|
|
@@ -37455,7 +37455,7 @@ async function reconcileSkillSession(input, options = {}) {
|
|
|
37455
37455
|
return { applied: true, plan, planDigest, ...result };
|
|
37456
37456
|
}
|
|
37457
37457
|
// src/lib/selected-run.ts
|
|
37458
|
-
import { createHash as
|
|
37458
|
+
import { createHash as createHash20 } from "crypto";
|
|
37459
37459
|
import { spawn as spawn2 } from "child_process";
|
|
37460
37460
|
import { mkdirSync as mkdirSync10, mkdtempSync as mkdtempSync3, writeFileSync as writeFileSync9, realpathSync as realpathSync11 } from "fs";
|
|
37461
37461
|
import { dirname as dirname20, join as join32, resolve as resolve18 } from "path";
|
|
@@ -38009,6 +38009,25 @@ function hashNativeJsonControls(text, excludedMetadata) {
|
|
|
38009
38009
|
import { basename as basename3, dirname as dirname5, join as join10, relative as relative3, resolve as resolve4, sep as sep2 } from "path";
|
|
38010
38010
|
import { lstatSync as lstatSync6, readdirSync as readdirSync3, readlinkSync as readlinkSync2, realpathSync as realpathSync5 } from "fs";
|
|
38011
38011
|
|
|
38012
|
+
// src/lib/codex-native-compatibility.ts
|
|
38013
|
+
var MEASURED_CODEX_CAPABILITIES = {
|
|
38014
|
+
"codex-cli 0.153.0": ["hooks"],
|
|
38015
|
+
"codex-cli 0.154.0": ["hooks"],
|
|
38016
|
+
"codex-cli 0.155.0": ["hooks"],
|
|
38017
|
+
"codex-cli 0.155.1": ["hooks"],
|
|
38018
|
+
"codex-cli 0.156.1": ["hooks"],
|
|
38019
|
+
"codex-cli 0.157.0": ["hooks"],
|
|
38020
|
+
"codex-cli 0.157.1": ["hooks"],
|
|
38021
|
+
"codex-cli 0.158.0": ["hooks"],
|
|
38022
|
+
"codex-cli 0.159.0": ["hooks"],
|
|
38023
|
+
"codex-cli 0.159.2": ["hooks", "qualified-skill-catalog"],
|
|
38024
|
+
"codex-cli 0.160.0": ["hooks", "qualified-skill-catalog"]
|
|
38025
|
+
};
|
|
38026
|
+
function supportsCodexNativeCapability(version, capability) {
|
|
38027
|
+
return typeof version === "string" && Object.hasOwn(MEASURED_CODEX_CAPABILITIES, version) && MEASURED_CODEX_CAPABILITIES[version].includes(capability);
|
|
38028
|
+
}
|
|
38029
|
+
var SUPPORTED_CODEX_HOOK_VERSIONS = Object.freeze(Object.keys(MEASURED_CODEX_CAPABILITIES).filter((version) => supportsCodexNativeCapability(version, "hooks")));
|
|
38030
|
+
|
|
38012
38031
|
// src/lib/codex-native-skill-catalog.ts
|
|
38013
38032
|
import { realpathSync as realpathSync4 } from "fs";
|
|
38014
38033
|
import { isAbsolute as isAbsolute5, normalize } from "path";
|
|
@@ -38018,7 +38037,6 @@ import { execFile, spawn } from "child_process";
|
|
|
38018
38037
|
import { realpathSync as realpathSync3, statSync as statSync3 } from "fs";
|
|
38019
38038
|
import { isAbsolute as isAbsolute4 } from "path";
|
|
38020
38039
|
import { promisify } from "util";
|
|
38021
|
-
var SUPPORTED_CODEX_HOOK_VERSIONS = ["codex-cli 0.153.0", "codex-cli 0.154.0", "codex-cli 0.155.0", "codex-cli 0.155.1", "codex-cli 0.156.1", "codex-cli 0.157.0", "codex-cli 0.157.1", "codex-cli 0.158.0", "codex-cli 0.159.0", "codex-cli 0.159.2"];
|
|
38022
38040
|
async function connectCodexHookRpc(options) {
|
|
38023
38041
|
const timeoutMs = options.timeoutMs ?? 20000;
|
|
38024
38042
|
if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 100 || timeoutMs > 20000)
|
|
@@ -38036,7 +38054,7 @@ async function connectCodexHookRpc(options) {
|
|
|
38036
38054
|
} catch {
|
|
38037
38055
|
throw new Error("CODEX_HOOK_TRUST_NATIVE_UNAVAILABLE");
|
|
38038
38056
|
}
|
|
38039
|
-
if (!
|
|
38057
|
+
if (!supportsCodexNativeCapability(version, "hooks"))
|
|
38040
38058
|
throw new Error("CODEX_HOOK_TRUST_NATIVE_UNSUPPORTED_VERSION");
|
|
38041
38059
|
const current = statSync3(binary);
|
|
38042
38060
|
if (realpathSync3(found) !== binary || ["dev", "ino", "size", "mtimeMs", "ctimeMs"].some((k) => stat[k] !== current[k]))
|
|
@@ -38161,12 +38179,12 @@ var MAX_SKILLS = 4096;
|
|
|
38161
38179
|
var MAX_NAME_BYTES = 1024;
|
|
38162
38180
|
var MAX_PATH_BYTES = 16384;
|
|
38163
38181
|
var MAX_PLUGIN_ID_BYTES = 1024;
|
|
38164
|
-
var SUPPORTED_NAME_CONTROL_VERSIONS = new Set(["codex-cli 0.159.2"]);
|
|
38165
38182
|
function refuse2() {
|
|
38166
38183
|
throw new Error("CODEX_NATIVE_SKILL_CATALOG_INVALID");
|
|
38167
38184
|
}
|
|
38168
38185
|
var object2 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
38169
38186
|
var scalar = (value, max) => typeof value === "string" && value.length > 0 && value.trim() === value && Buffer.byteLength(value, "utf8") <= max && !/[\u0000-\u001f\u007f]/u.test(value);
|
|
38187
|
+
var remotePluginIdentifier = (value) => typeof value === "string" && /^[A-Za-z0-9_~-]{1,1024}$/.test(value);
|
|
38170
38188
|
var absolutePath2 = (value) => scalar(value, MAX_PATH_BYTES) && isAbsolute5(value);
|
|
38171
38189
|
function projectCodexNativeSkillCatalog(response, cwd) {
|
|
38172
38190
|
if (!absolutePath2(cwd) || !object2(response) || !Array.isArray(response.data) || response.data.length !== 1)
|
|
@@ -38194,7 +38212,11 @@ function projectCodexInstalledPlugins(response) {
|
|
|
38194
38212
|
for (const value of marketplace.plugins) {
|
|
38195
38213
|
if (!object2(value) || !scalar(value.id, MAX_PLUGIN_ID_BYTES) || !scalar(value.name, MAX_NAME_BYTES) || value.id !== `${value.name}@${marketplace.name}`)
|
|
38196
38214
|
refuse2();
|
|
38197
|
-
plugins.push({
|
|
38215
|
+
plugins.push({
|
|
38216
|
+
...value,
|
|
38217
|
+
marketplace: marketplace.name,
|
|
38218
|
+
sourceType: object2(value.source) && value.source.type === "remote" ? "remote" : undefined
|
|
38219
|
+
});
|
|
38198
38220
|
}
|
|
38199
38221
|
}
|
|
38200
38222
|
return projectCodexInstalledPluginEntries(plugins);
|
|
@@ -38204,13 +38226,21 @@ function projectCodexInstalledPluginEntries(value) {
|
|
|
38204
38226
|
refuse2();
|
|
38205
38227
|
const ids = new Set;
|
|
38206
38228
|
return value.map((item) => {
|
|
38207
|
-
if (!object2(item) || !scalar(item.id, MAX_PLUGIN_ID_BYTES) || !scalar(item.name, MAX_NAME_BYTES) || typeof item.installed !== "boolean" || typeof item.enabled !== "boolean" || item.localVersion !== null && !scalar(item.localVersion, MAX_NAME_BYTES))
|
|
38229
|
+
if (!object2(item) || !scalar(item.id, MAX_PLUGIN_ID_BYTES) || !scalar(item.name, MAX_NAME_BYTES) || typeof item.installed !== "boolean" || typeof item.enabled !== "boolean" || item.localVersion !== null && !scalar(item.localVersion, MAX_NAME_BYTES) || item.remotePluginId !== undefined && item.remotePluginId !== null && !remotePluginIdentifier(item.remotePluginId) || item.sourceType !== undefined && item.sourceType !== "remote")
|
|
38208
38230
|
refuse2();
|
|
38209
38231
|
const at = item.id.lastIndexOf("@");
|
|
38210
38232
|
if (at < 1 || item.id.slice(0, at) !== item.name || at === item.id.length - 1 || ids.has(item.id))
|
|
38211
38233
|
refuse2();
|
|
38212
38234
|
ids.add(item.id);
|
|
38213
|
-
return {
|
|
38235
|
+
return {
|
|
38236
|
+
id: item.id,
|
|
38237
|
+
name: item.name,
|
|
38238
|
+
installed: item.installed,
|
|
38239
|
+
enabled: item.enabled,
|
|
38240
|
+
localVersion: item.localVersion ?? null,
|
|
38241
|
+
...item.sourceType === "remote" ? { sourceType: "remote" } : {},
|
|
38242
|
+
...item.remotePluginId == null ? {} : { remotePluginId: item.remotePluginId }
|
|
38243
|
+
};
|
|
38214
38244
|
});
|
|
38215
38245
|
}
|
|
38216
38246
|
async function captureCodexNativeSkillCatalog(options, connect = connectCodexHookRpc) {
|
|
@@ -38223,7 +38253,7 @@ async function captureCodexNativeSkillCatalog(options, connect = connectCodexHoo
|
|
|
38223
38253
|
...options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }
|
|
38224
38254
|
});
|
|
38225
38255
|
try {
|
|
38226
|
-
if (!
|
|
38256
|
+
if (!supportsCodexNativeCapability(rpc.version, "qualified-skill-catalog"))
|
|
38227
38257
|
throw new Error("CODEX_NATIVE_SKILL_CATALOG_UNSUPPORTED_VERSION");
|
|
38228
38258
|
const response = await rpc.request("skills/list", { cwds: [options.cwd], forceReload: true });
|
|
38229
38259
|
const installed = await rpc.request("plugin/installed", { cwds: [options.cwd] });
|
|
@@ -38281,6 +38311,21 @@ var CODEX_DEFAULT_AGENT_PLUGIN_VERSION = "1.0.0";
|
|
|
38281
38311
|
function refuse3() {
|
|
38282
38312
|
throw new Error("CODEX_NATIVE_SKILL_IDENTITY_UNSUPPORTED: review native plugin names and hook controls");
|
|
38283
38313
|
}
|
|
38314
|
+
function remoteInstallationMatches(parent, remotePluginId, read) {
|
|
38315
|
+
try {
|
|
38316
|
+
if (!remotePluginIdentifier(remotePluginId) || !lstatSync6(parent).isDirectory() || realpathSync5(parent) !== parent)
|
|
38317
|
+
return false;
|
|
38318
|
+
const path = join10(parent, ".codex-remote-plugin-install.json"), stat = lstatSync6(path, { throwIfNoEntry: false });
|
|
38319
|
+
if (!stat?.isFile() || stat.isSymbolicLink() || stat.size > 16384)
|
|
38320
|
+
return false;
|
|
38321
|
+
const text = read(path);
|
|
38322
|
+
hashNativeJsonControls(text);
|
|
38323
|
+
const value = JSON.parse(text);
|
|
38324
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === 2 && value.schema_version === 1 && value.remote_plugin_id === remotePluginId);
|
|
38325
|
+
} catch {
|
|
38326
|
+
return false;
|
|
38327
|
+
}
|
|
38328
|
+
}
|
|
38284
38329
|
function appControls(path, read) {
|
|
38285
38330
|
const text = read(path);
|
|
38286
38331
|
let value, sha2562;
|
|
@@ -38302,6 +38347,42 @@ function appControls(path, read) {
|
|
|
38302
38347
|
}
|
|
38303
38348
|
return sha2562;
|
|
38304
38349
|
}
|
|
38350
|
+
function mcpControls(path, read) {
|
|
38351
|
+
const text = read(path);
|
|
38352
|
+
let value, sha2562;
|
|
38353
|
+
try {
|
|
38354
|
+
sha2562 = hashNativeJsonControls(text);
|
|
38355
|
+
value = JSON.parse(text);
|
|
38356
|
+
} catch {
|
|
38357
|
+
refuse3();
|
|
38358
|
+
}
|
|
38359
|
+
const object3 = (v) => Boolean(v && typeof v === "object" && !Array.isArray(v));
|
|
38360
|
+
const textField = (v, empty = false) => typeof v === "string" && (empty || Boolean(v.trim())) && Buffer.byteLength(v) <= 16384 && !/[\x00-\x1f\x7f]/.test(v);
|
|
38361
|
+
const envName = (v) => typeof v === "string" && /^[A-Za-z_][A-Za-z0-9_]{0,255}$/.test(v);
|
|
38362
|
+
if (!object3(value) || Object.keys(value).length !== 1 || !object3(value.mcpServers))
|
|
38363
|
+
refuse3();
|
|
38364
|
+
const servers = Object.entries(value.mcpServers);
|
|
38365
|
+
if (!servers.length || servers.length > 256)
|
|
38366
|
+
refuse3();
|
|
38367
|
+
for (const [name, server] of servers) {
|
|
38368
|
+
if (!identifier3(name) || !object3(server) || !Object.keys(server).every((key) => ["command", "args", "cwd", "env_vars"].includes(key)) || !textField(server.command) || server.args !== undefined && (!Array.isArray(server.args) || server.args.length > 256 || !server.args.every((arg) => textField(arg, true))) || server.cwd !== undefined && !textField(server.cwd))
|
|
38369
|
+
refuse3();
|
|
38370
|
+
if (server.env_vars !== undefined) {
|
|
38371
|
+
if (!Array.isArray(server.env_vars) || server.env_vars.length > 256)
|
|
38372
|
+
refuse3();
|
|
38373
|
+
const names = server.env_vars.map((entry) => {
|
|
38374
|
+
if (envName(entry))
|
|
38375
|
+
return entry;
|
|
38376
|
+
if (!object3(entry) || !Object.keys(entry).every((key) => ["name", "source"].includes(key)) || !envName(entry.name) || entry.source !== undefined && entry.source !== "local")
|
|
38377
|
+
refuse3();
|
|
38378
|
+
return entry.name;
|
|
38379
|
+
});
|
|
38380
|
+
if (new Set(names).size !== names.length)
|
|
38381
|
+
refuse3();
|
|
38382
|
+
}
|
|
38383
|
+
}
|
|
38384
|
+
return sha2562;
|
|
38385
|
+
}
|
|
38305
38386
|
function rootControls(root, read) {
|
|
38306
38387
|
const manifestPath = join10(root, ".codex-plugin/plugin.json"), manifestFile = lstatSync6(manifestPath, { throwIfNoEntry: false });
|
|
38307
38388
|
if (!lstatSync6(join10(root, ".codex-plugin"), { throwIfNoEntry: false })?.isDirectory() || !manifestFile?.isFile() || manifestFile.size > 1024 * 1024)
|
|
@@ -38319,15 +38400,21 @@ function rootControls(root, read) {
|
|
|
38319
38400
|
const cacheVersion = basename3(root), declaredVersion = manifest.version === undefined ? "" : typeof manifest.version === "string" ? manifest.version.trim() : null;
|
|
38320
38401
|
if (declaredVersion === null || (declaredVersion ? declaredVersion !== cacheVersion : cacheVersion !== CODEX_DEFAULT_AGENT_PLUGIN_VERSION))
|
|
38321
38402
|
refuse3();
|
|
38322
|
-
if (manifest.hooks !== undefined || manifest.
|
|
38403
|
+
if (manifest.hooks !== undefined || manifest.commands !== undefined || manifest.mcpServers !== undefined && manifest.mcpServers !== "./.mcp.json" || manifest.apps !== undefined && manifest.apps !== "./.app.json" || lstatSync6(join10(root, "hooks"), { throwIfNoEntry: false }))
|
|
38404
|
+
refuse3();
|
|
38405
|
+
const mcp = join10(root, ".mcp.json"), mcpPresent = lstatSync6(mcp, { throwIfNoEntry: false });
|
|
38406
|
+
if (mcpPresent && (!mcpPresent.isFile() || mcpPresent.isSymbolicLink() || mcpPresent.size > 1024 * 1024 || realpathSync5(mcp) !== mcp))
|
|
38407
|
+
refuse3();
|
|
38408
|
+
if (Boolean(mcpPresent) !== (manifest.mcpServers !== undefined))
|
|
38323
38409
|
refuse3();
|
|
38410
|
+
const mcpSha256 = mcpPresent ? mcpControls(mcp, read) : undefined;
|
|
38324
38411
|
const app = join10(root, ".app.json"), present = lstatSync6(app, { throwIfNoEntry: false });
|
|
38325
38412
|
if (present && (!present.isFile() || present.isSymbolicLink() || present.size > 1024 * 1024))
|
|
38326
38413
|
refuse3();
|
|
38327
38414
|
if (manifest.apps !== undefined && !present)
|
|
38328
38415
|
refuse3();
|
|
38329
38416
|
const appSha256 = present ? appControls(app, read) : undefined;
|
|
38330
|
-
return { namespace: manifest.name, manifestSha256, ...appSha256 ? { appSha256 } : {} };
|
|
38417
|
+
return { namespace: manifest.name, manifestSha256, ...appSha256 ? { appSha256 } : {}, ...mcpSha256 ? { mcpSha256 } : {} };
|
|
38331
38418
|
}
|
|
38332
38419
|
function identity(document, cache, read) {
|
|
38333
38420
|
if (!document.startsWith(cache + sep2) || !document.endsWith(sep2 + "SKILL.md"))
|
|
@@ -38370,6 +38457,10 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache, controls, read) {
|
|
|
38370
38457
|
for (const parent of new Set(controls.map((control) => control.pluginParent))) {
|
|
38371
38458
|
if (!parent.startsWith(cache + sep2) || !lstatSync6(parent, { throwIfNoEntry: false })?.isDirectory())
|
|
38372
38459
|
return false;
|
|
38460
|
+
for (const control of controls.filter((control2) => control2.pluginParent === parent)) {
|
|
38461
|
+
if (control.remotePluginId !== undefined && !remoteInstallationMatches(parent, control.remotePluginId, read))
|
|
38462
|
+
return false;
|
|
38463
|
+
}
|
|
38373
38464
|
const names = readdirSync3(parent);
|
|
38374
38465
|
entries += names.length;
|
|
38375
38466
|
if (entries > 4096)
|
|
@@ -38386,7 +38477,7 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache, controls, read) {
|
|
|
38386
38477
|
if (!stat.isDirectory() || ![".codex-plugin/plugin.json", ".app.json", "hooks", ".mcp.json"].some((path) => lstatSync6(join10(root, path), { throwIfNoEntry: false })))
|
|
38387
38478
|
continue;
|
|
38388
38479
|
const parsed = rootControls(root, read);
|
|
38389
|
-
if (!controls.some((control) => control.pluginParent === parent && control.namespace === parsed.namespace && control.manifestSha256 === parsed.manifestSha256 && control.appSha256 === parsed.appSha256))
|
|
38480
|
+
if (!controls.some((control) => control.pluginParent === parent && control.namespace === parsed.namespace && control.manifestSha256 === parsed.manifestSha256 && control.appSha256 === parsed.appSha256 && control.mcpSha256 === parsed.mcpSha256))
|
|
38390
38481
|
return false;
|
|
38391
38482
|
}
|
|
38392
38483
|
}
|
|
@@ -38396,7 +38487,7 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache, controls, read) {
|
|
|
38396
38487
|
}
|
|
38397
38488
|
}
|
|
38398
38489
|
function reviewCodexPluginSkillControls(catalog, documents, cache, cwd, read, rules) {
|
|
38399
|
-
if (catalog?.version
|
|
38490
|
+
if (!supportsCodexNativeCapability(catalog?.version, "qualified-skill-catalog") || catalog.cwd !== cwd)
|
|
38400
38491
|
refuse3();
|
|
38401
38492
|
const skills = projectCodexNativeSkillCatalog({ data: [{ cwd, errors: [], skills: catalog.skills }] }, cwd);
|
|
38402
38493
|
const allowed = new Set(documents), result = [];
|
|
@@ -38423,22 +38514,30 @@ function reviewCodexPluginSkillControls(catalog, documents, cache, cwd, read, ru
|
|
|
38423
38514
|
const listed = skills.filter((skill) => skill.path === document);
|
|
38424
38515
|
if (listed.length > 1)
|
|
38425
38516
|
refuse3();
|
|
38517
|
+
let remotePluginId;
|
|
38426
38518
|
if (listed.length === 1) {
|
|
38427
38519
|
if (listed[0].name !== parsed.name || listed[0].pluginId !== expectedPluginId)
|
|
38428
38520
|
refuse3();
|
|
38429
38521
|
} else {
|
|
38430
|
-
const installed = installedPlugins.filter((
|
|
38431
|
-
if (installed.length !== 1 || !installed[0].installed || !installed[0].enabled
|
|
38522
|
+
const installed = installedPlugins.filter((plugin2) => plugin2.id === expectedPluginId && plugin2.name === pluginName);
|
|
38523
|
+
if (installed.length !== 1 || !installed[0].installed || !installed[0].enabled)
|
|
38432
38524
|
refuse3();
|
|
38433
|
-
|
|
38434
|
-
|
|
38525
|
+
const plugin = installed[0];
|
|
38526
|
+
if (plugin.localVersion !== null) {
|
|
38527
|
+
if (plugin.localVersion !== basename3(dirname5(dirname5(dirname5(document)))))
|
|
38528
|
+
continue;
|
|
38529
|
+
} else {
|
|
38530
|
+
if (plugin.sourceType !== "remote" || !plugin.remotePluginId || !remoteInstallationMatches(parsed.pluginParent, plugin.remotePluginId, read) || !lstatSync6(document).isFile() || realpathSync5(document) !== document)
|
|
38531
|
+
refuse3();
|
|
38532
|
+
remotePluginId = plugin.remotePluginId;
|
|
38533
|
+
}
|
|
38435
38534
|
const exactPathDeny = Array.isArray(rules) && rules.some((rule) => rule?.path === document && rule?.enabled === false);
|
|
38436
38535
|
if (!exactPathDeny || !isCodexNativeSkillDisabled({ name: parsed.name, path: document, pluginId: expectedPluginId, enabled: true }, rules))
|
|
38437
38536
|
refuse3();
|
|
38438
38537
|
}
|
|
38439
|
-
result.push({ ...parsed, pluginId: expectedPluginId });
|
|
38538
|
+
result.push({ ...parsed, pluginId: expectedPluginId, ...remotePluginId ? { remotePluginId } : {} });
|
|
38440
38539
|
}
|
|
38441
|
-
if (!result.length || new Set(result.map((item) => item.name)).size !== result.length)
|
|
38540
|
+
if (!result.length && documents.some((document) => document.startsWith(cache + sep2)) || new Set(result.map((item) => item.name)).size !== result.length)
|
|
38442
38541
|
refuse3();
|
|
38443
38542
|
return result;
|
|
38444
38543
|
}
|
|
@@ -38451,8 +38550,8 @@ function isReviewedCodexPluginSkillDisabled(document, cache, controls, rules, re
|
|
|
38451
38550
|
} catch {
|
|
38452
38551
|
return false;
|
|
38453
38552
|
}
|
|
38454
|
-
const reviewed = controls.find((item) => item.name === parsed.name && item.namespace === parsed.namespace && item.pluginParent === parsed.pluginParent && item.manifestSha256 === parsed.manifestSha256 && item.appSha256 === parsed.appSha256);
|
|
38455
|
-
if (!reviewed)
|
|
38553
|
+
const reviewed = controls.find((item) => item.name === parsed.name && item.namespace === parsed.namespace && item.pluginParent === parsed.pluginParent && item.manifestSha256 === parsed.manifestSha256 && item.appSha256 === parsed.appSha256 && item.mcpSha256 === parsed.mcpSha256);
|
|
38554
|
+
if (!reviewed || reviewed.remotePluginId !== undefined && !remoteInstallationMatches(reviewed.pluginParent, reviewed.remotePluginId, read))
|
|
38456
38555
|
return false;
|
|
38457
38556
|
return isCodexNativeSkillDisabled({ name: parsed.name, path: document, pluginId: reviewed.pluginId, enabled: true }, rules);
|
|
38458
38557
|
}
|
|
@@ -38471,7 +38570,7 @@ enabled = false
|
|
|
38471
38570
|
return text;
|
|
38472
38571
|
}
|
|
38473
38572
|
|
|
38474
|
-
// src/lib/codex-settings-witness.ts
|
|
38573
|
+
// src/lib/codex-settings-witness-v1.ts
|
|
38475
38574
|
import { createHash as createHash6 } from "crypto";
|
|
38476
38575
|
var sha = (text) => createHash6("sha256").update(text).digest("hex");
|
|
38477
38576
|
var EFFORT = new Set(["none", "minimal", "low", "medium", "high", "xhigh"]);
|
|
@@ -38565,15 +38664,162 @@ function captureCodexSettings(path, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
|
38565
38664
|
const text = readNativeSettingsWitnessFile(path, budget, "config.toml");
|
|
38566
38665
|
return { path, hashMode: "codex-settings-v1", sha256: hashCodexSettingsReplacement(text) };
|
|
38567
38666
|
}
|
|
38667
|
+
|
|
38668
|
+
// src/lib/codex-settings-witness.ts
|
|
38669
|
+
import { createHash as createHash7 } from "crypto";
|
|
38670
|
+
var sha2 = (text) => createHash7("sha256").update(text).digest("hex");
|
|
38671
|
+
var EFFORT2 = new Set(["none", "minimal", "low", "medium", "high", "xhigh"]);
|
|
38672
|
+
var VERBOSITY2 = new Set(["low", "medium", "high"]);
|
|
38673
|
+
var MODEL = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$/;
|
|
38674
|
+
var CODEX_DISCOVERY_PROJECTION_FIELDS = ["plugins", "marketplaces", "skills"];
|
|
38675
|
+
var INFERENCE = ["model", "model_reasoning_effort", "model_verbosity"];
|
|
38676
|
+
function need3(value) {
|
|
38677
|
+
if (!value)
|
|
38678
|
+
throw new Error("Invalid Codex settings witness");
|
|
38679
|
+
}
|
|
38680
|
+
function isRecord(value) {
|
|
38681
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
38682
|
+
}
|
|
38683
|
+
function isDate(value) {
|
|
38684
|
+
return value instanceof Date;
|
|
38685
|
+
}
|
|
38686
|
+
function numericTokens2(text) {
|
|
38687
|
+
const result = [];
|
|
38688
|
+
for (let at = 0;at < text.length; ) {
|
|
38689
|
+
const char = text[at];
|
|
38690
|
+
if (char === "#") {
|
|
38691
|
+
while (at < text.length && text[at] !== `
|
|
38692
|
+
`)
|
|
38693
|
+
at++;
|
|
38694
|
+
continue;
|
|
38695
|
+
}
|
|
38696
|
+
if (char === '"' || char === "'") {
|
|
38697
|
+
const quote = char, triple = text.slice(at, at + 3) === quote.repeat(3);
|
|
38698
|
+
at += triple ? 3 : 1;
|
|
38699
|
+
while (at < text.length) {
|
|
38700
|
+
if (quote === '"' && text[at] === "\\") {
|
|
38701
|
+
at += 2;
|
|
38702
|
+
continue;
|
|
38703
|
+
}
|
|
38704
|
+
if (text.slice(at, at + (triple ? 3 : 1)) === quote.repeat(triple ? 3 : 1)) {
|
|
38705
|
+
at += triple ? 3 : 1;
|
|
38706
|
+
break;
|
|
38707
|
+
}
|
|
38708
|
+
at++;
|
|
38709
|
+
}
|
|
38710
|
+
continue;
|
|
38711
|
+
}
|
|
38712
|
+
if (/[0-9+-]/.test(char)) {
|
|
38713
|
+
const start = at;
|
|
38714
|
+
while (at < text.length && !/[\s,\]{}#=]/.test(text[at]))
|
|
38715
|
+
at++;
|
|
38716
|
+
if (at > start) {
|
|
38717
|
+
result.push(text.slice(start, at));
|
|
38718
|
+
continue;
|
|
38719
|
+
}
|
|
38720
|
+
}
|
|
38721
|
+
at++;
|
|
38722
|
+
}
|
|
38723
|
+
return result.sort();
|
|
38724
|
+
}
|
|
38725
|
+
function canonical3(value, depth = 0, budget = { remaining: 65536 }) {
|
|
38726
|
+
need3(depth <= 32 && --budget.remaining >= 0);
|
|
38727
|
+
if (value === null)
|
|
38728
|
+
return ["null"];
|
|
38729
|
+
if (typeof value === "string")
|
|
38730
|
+
return ["string", value];
|
|
38731
|
+
if (typeof value === "boolean")
|
|
38732
|
+
return ["boolean", value];
|
|
38733
|
+
if (typeof value === "number") {
|
|
38734
|
+
need3(Number.isFinite(value));
|
|
38735
|
+
return ["number", String(value)];
|
|
38736
|
+
}
|
|
38737
|
+
if (isDate(value)) {
|
|
38738
|
+
need3(Number.isFinite(value.getTime()));
|
|
38739
|
+
return ["date", value.toISOString()];
|
|
38740
|
+
}
|
|
38741
|
+
if (Array.isArray(value))
|
|
38742
|
+
return ["array", value.map((child) => canonical3(child, depth + 1, budget))];
|
|
38743
|
+
need3(isRecord(value));
|
|
38744
|
+
return ["object", Object.entries(value).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, child]) => [key, canonical3(child, depth + 1, budget)])];
|
|
38745
|
+
}
|
|
38746
|
+
function normalize2(config) {
|
|
38747
|
+
if (isRecord(config.hooks)) {
|
|
38748
|
+
delete config.hooks.state;
|
|
38749
|
+
if (!Object.keys(config.hooks).length)
|
|
38750
|
+
delete config.hooks;
|
|
38751
|
+
}
|
|
38752
|
+
if (isRecord(config.skills) && Array.isArray(config.skills.config)) {
|
|
38753
|
+
const skills = config.skills;
|
|
38754
|
+
const retained = skills.config.filter((entry) => !disablesOneSkill(entry));
|
|
38755
|
+
if (retained.length !== skills.config.length) {
|
|
38756
|
+
if (retained.length)
|
|
38757
|
+
skills.config = retained;
|
|
38758
|
+
else
|
|
38759
|
+
delete skills.config;
|
|
38760
|
+
}
|
|
38761
|
+
if (!Object.keys(skills).length)
|
|
38762
|
+
delete config.skills;
|
|
38763
|
+
}
|
|
38764
|
+
inference(config);
|
|
38765
|
+
if (isRecord(config.profiles)) {
|
|
38766
|
+
for (const profile of Object.values(config.profiles))
|
|
38767
|
+
if (isRecord(profile))
|
|
38768
|
+
inference(profile);
|
|
38769
|
+
}
|
|
38770
|
+
}
|
|
38771
|
+
function disablesOneSkill(entry) {
|
|
38772
|
+
if (!isRecord(entry) || entry.enabled !== false)
|
|
38773
|
+
return false;
|
|
38774
|
+
const keys2 = Object.keys(entry);
|
|
38775
|
+
if (!keys2.every((key) => key === "path" || key === "name" || key === "enabled"))
|
|
38776
|
+
return false;
|
|
38777
|
+
const selector = ["path", "name"].filter((key) => Object.hasOwn(entry, key));
|
|
38778
|
+
return selector.length === 1 && typeof entry[selector[0]] === "string" && entry[selector[0]].length > 0;
|
|
38779
|
+
}
|
|
38780
|
+
function inference(target) {
|
|
38781
|
+
for (const key of INFERENCE)
|
|
38782
|
+
if (Object.hasOwn(target, key)) {
|
|
38783
|
+
const value = target[key];
|
|
38784
|
+
if (key === "model")
|
|
38785
|
+
need3(typeof value === "string" && MODEL.test(value));
|
|
38786
|
+
else
|
|
38787
|
+
need3(typeof value === "string" && (key === "model_reasoning_effort" ? EFFORT2.has(value) : VERBOSITY2.has(value)));
|
|
38788
|
+
delete target[key];
|
|
38789
|
+
}
|
|
38790
|
+
}
|
|
38791
|
+
function settingsDigest2(text) {
|
|
38792
|
+
let config;
|
|
38793
|
+
try {
|
|
38794
|
+
config = Bun.TOML.parse(text);
|
|
38795
|
+
} catch {
|
|
38796
|
+
throw new Error("Invalid Codex settings witness");
|
|
38797
|
+
}
|
|
38798
|
+
need3(isRecord(config));
|
|
38799
|
+
normalize2(config);
|
|
38800
|
+
return sha2(`hasna.skills.codex-settings.v2\x00${JSON.stringify([canonical3(config), numericTokens2(text)])}`);
|
|
38801
|
+
}
|
|
38802
|
+
function hashCodexSettingsReplacementV2(text, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
38803
|
+
need3(Buffer.byteLength(text) <= 1024 * 1024 && budget.remaining >= Buffer.byteLength(text));
|
|
38804
|
+
budget.remaining -= Buffer.byteLength(text);
|
|
38805
|
+
return settingsDigest2(text);
|
|
38806
|
+
}
|
|
38807
|
+
function captureCodexSettingsV2(path, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
38808
|
+
const text = readNativeSettingsWitnessFile(path, budget, "config.toml");
|
|
38809
|
+
return { path, hashMode: "codex-settings-v2", sha256: settingsDigest2(text) };
|
|
38810
|
+
}
|
|
38811
|
+
function readCodexSettingsPreimage(path, budget = { remaining: 2 * 1024 * 1024 }) {
|
|
38812
|
+
return readNativeSettingsWitnessFile(path, budget, "config.toml");
|
|
38813
|
+
}
|
|
38568
38814
|
function upgradeCodexSettingsWitness(previous, reviewedSettingsPath) {
|
|
38569
|
-
|
|
38815
|
+
need3(previous && Object.keys(previous).every((key) => ["path", "hashMode", "sha256"].includes(key)) && (previous.hashMode === undefined || previous.hashMode === "bytes" || previous.hashMode === "codex-settings-v1") && /^[a-f0-9]{64}$/.test(previous.sha256));
|
|
38570
38816
|
const budget = { remaining: 2 * 1024 * 1024 };
|
|
38571
38817
|
const before = readNativeSettingsWitnessFile(reviewedSettingsPath, budget, "config.toml"), current = readNativeSettingsWitnessFile(previous.path, budget, "config.toml");
|
|
38572
|
-
|
|
38573
|
-
const sha2562 =
|
|
38574
|
-
if (
|
|
38818
|
+
need3((previous.hashMode === "codex-settings-v1" ? hashCodexSettingsReplacement(before) : sha2(before)) === previous.sha256);
|
|
38819
|
+
const sha2562 = settingsDigest2(current);
|
|
38820
|
+
if (settingsDigest2(before) !== sha2562)
|
|
38575
38821
|
throw new Error("Codex non-preference settings changed; explicit discovery review required");
|
|
38576
|
-
return { path: previous.path, hashMode: "codex-settings-
|
|
38822
|
+
return { path: previous.path, hashMode: "codex-settings-v2", sha256: sha2562 };
|
|
38577
38823
|
}
|
|
38578
38824
|
|
|
38579
38825
|
// src/lib/native-discovery-roots.ts
|
|
@@ -38596,7 +38842,8 @@ var NATIVE_SKILL_ROOTS = [
|
|
|
38596
38842
|
];
|
|
38597
38843
|
|
|
38598
38844
|
// src/lib/agent-integration.ts
|
|
38599
|
-
import { createHash as
|
|
38845
|
+
import { createHash as createHash18, randomUUID as randomUUID3 } from "crypto";
|
|
38846
|
+
import { isDeepStrictEqual as isDeepStrictEqual5 } from "util";
|
|
38600
38847
|
import { existsSync as existsSync6, lstatSync as lstatSync19, statSync as statSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync14, readdirSync as readdirSync8, opendirSync as opendirSync5, readlinkSync as readlinkSync4, realpathSync as realpathSync7, renameSync as renameSync3, rmdirSync as rmdirSync3, writeFileSync as writeFileSync4, unlinkSync as unlinkSync4, chmodSync, openSync as openSync16, closeSync as closeSync16, fsyncSync as fsyncSync4, fstatSync as fstatSync16, readSync as readSync11, constants as constants12, linkSync as linkSync2 } from "fs";
|
|
38601
38848
|
import { dirname as dirname15, join as join22, resolve as resolve15, relative as relative4, isAbsolute as isAbsolute17, sep as sep5 } from "path";
|
|
38602
38849
|
import { homedir as homedir3 } from "os";
|
|
@@ -38655,12 +38902,16 @@ function assertAgentPolicyCollections(policy) {
|
|
|
38655
38902
|
}
|
|
38656
38903
|
if (bridge.codexPluginSkills !== undefined)
|
|
38657
38904
|
for (const control of array(bridge.codexPluginSkills, 4096)) {
|
|
38658
|
-
requireBound(object3(control) && Object.keys(control).every((key) => ["name", "pluginId", "namespace", "pluginParent", "manifestSha256", "appSha256"].includes(key)));
|
|
38905
|
+
requireBound(object3(control) && Object.keys(control).every((key) => ["name", "pluginId", "namespace", "pluginParent", "manifestSha256", "appSha256", "mcpSha256", "remotePluginId"].includes(key)));
|
|
38659
38906
|
text(control.name, 129);
|
|
38660
38907
|
text(control.pluginId, 1024);
|
|
38661
38908
|
text(control.namespace, 64);
|
|
38662
38909
|
text(control.pluginParent);
|
|
38663
38910
|
requireBound(isAbsolute6(control.pluginParent) && resolve5(control.pluginParent) === control.pluginParent && /^[a-f0-9]{64}$/.test(control.manifestSha256));
|
|
38911
|
+
if (control.remotePluginId !== undefined)
|
|
38912
|
+
requireBound(typeof control.remotePluginId === "string" && /^[A-Za-z0-9_~-]{1,1024}$/.test(control.remotePluginId));
|
|
38913
|
+
if (control.mcpSha256 !== undefined)
|
|
38914
|
+
requireBound(typeof control.mcpSha256 === "string" && /^[a-f0-9]{64}$/.test(control.mcpSha256));
|
|
38664
38915
|
if (control.appSha256 !== undefined)
|
|
38665
38916
|
requireBound(typeof control.appSha256 === "string" && /^[a-f0-9]{64}$/.test(control.appSha256));
|
|
38666
38917
|
}
|
|
@@ -38683,8 +38934,8 @@ function assertAgentPolicyCollections(policy) {
|
|
|
38683
38934
|
text(source.path);
|
|
38684
38935
|
requireBound(source.sha256 === null || typeof source.sha256 === "string" && /^[a-f0-9]{64}$/.test(source.sha256));
|
|
38685
38936
|
if (source.hashMode !== undefined)
|
|
38686
|
-
requireBound(["bytes", "path-bytes", "claude-plugin-registry", "claude-marketplace-registry", "claude-settings-v1", "claude-settings-v2", "claude-settings-v3", "claude-marketplace-registry-v2", "codex-settings-v1"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
|
|
38687
|
-
if (source.hashMode === "codex-settings-v1")
|
|
38937
|
+
requireBound(["bytes", "path-bytes", "claude-plugin-registry", "claude-marketplace-registry", "claude-settings-v1", "claude-settings-v2", "claude-settings-v3", "claude-marketplace-registry-v2", "codex-settings-v1", "codex-settings-v2"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
|
|
38938
|
+
if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2")
|
|
38688
38939
|
requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute6(source.path) && resolve5(source.path) === source.path && basename4(source.path) === "config.toml");
|
|
38689
38940
|
if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3")
|
|
38690
38941
|
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute6(source.path) && resolve5(source.path) === source.path && basename4(source.path) === "settings.json");
|
|
@@ -38798,7 +39049,7 @@ function requiresCliSkillLoading(dataDir2 = getDataDirReadOnly()) {
|
|
|
38798
39049
|
}
|
|
38799
39050
|
|
|
38800
39051
|
// src/lib/agent-bridge.ts
|
|
38801
|
-
import { createHash as
|
|
39052
|
+
import { createHash as createHash8 } from "crypto";
|
|
38802
39053
|
import { lstatSync as lstatSync8, readFileSync as readFileSync9, readdirSync as readdirSync4 } from "fs";
|
|
38803
39054
|
import { join as join12 } from "path";
|
|
38804
39055
|
var CLI_BRIDGE_NAME = "skills-cli";
|
|
@@ -38817,7 +39068,7 @@ Use the Skills CLI as the skill authority for this station.
|
|
|
38817
39068
|
|
|
38818
39069
|
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.
|
|
38819
39070
|
`;
|
|
38820
|
-
var CLI_BRIDGE_DIGEST =
|
|
39071
|
+
var CLI_BRIDGE_DIGEST = createHash8("sha256").update(markdown).digest("hex");
|
|
38821
39072
|
var CLI_BRIDGE_FILES = Object.freeze({
|
|
38822
39073
|
"SKILL.md": markdown,
|
|
38823
39074
|
".hasna-skills.json": `${JSON.stringify({ managedBy: "@hasna/skills", kind: "cli-bridge", version: CLI_BRIDGE_VERSION, protocol: "selection-v1", contentSha256: CLI_BRIDGE_DIGEST }, null, 2)}
|
|
@@ -38841,7 +39092,7 @@ function isOwnedCliBridge(path, expectedPaths) {
|
|
|
38841
39092
|
}
|
|
38842
39093
|
|
|
38843
39094
|
// src/lib/agent-discovery.ts
|
|
38844
|
-
import { createHash as
|
|
39095
|
+
import { createHash as createHash17 } from "crypto";
|
|
38845
39096
|
import { lstatSync as lstatSync18, readFileSync as readFileSync13, readdirSync as readdirSync7, realpathSync as realpathSync6 } from "fs";
|
|
38846
39097
|
import { basename as basename7, dirname as dirname14, isAbsolute as isAbsolute16, join as join21, resolve as resolve14, sep as sep4 } from "path";
|
|
38847
39098
|
import { isDeepStrictEqual as isDeepStrictEqual3 } from "util";
|
|
@@ -39100,17 +39351,17 @@ if (failed) process.exitCode = 2;
|
|
|
39100
39351
|
}
|
|
39101
39352
|
|
|
39102
39353
|
// src/lib/agent-discovery-directories.ts
|
|
39103
|
-
import { createHash as
|
|
39354
|
+
import { createHash as createHash9 } from "crypto";
|
|
39104
39355
|
import { lstatSync as lstatSync10, opendirSync as opendirSync2 } from "fs";
|
|
39105
39356
|
import { dirname as dirname7, isAbsolute as isAbsolute8, join as join14, resolve as resolve7 } from "path";
|
|
39106
|
-
function
|
|
39357
|
+
function need4(value, message) {
|
|
39107
39358
|
if (!value)
|
|
39108
39359
|
throw new Error(message);
|
|
39109
39360
|
}
|
|
39110
39361
|
function safe(path) {
|
|
39111
|
-
|
|
39362
|
+
need4(typeof path === "string" && path.length <= AGENT_POLICY_LIMITS.pathCharacters && isAbsolute8(path) && resolve7(path) === path && !path.includes("\x00"), "Expected a canonical absolute discovery directory path");
|
|
39112
39363
|
for (let cursor = path;; cursor = dirname7(cursor)) {
|
|
39113
|
-
|
|
39364
|
+
need4(!lstatSync10(cursor, { throwIfNoEntry: false })?.isSymbolicLink(), "Refusing symlink native discovery directory");
|
|
39114
39365
|
if (dirname7(cursor) === cursor)
|
|
39115
39366
|
break;
|
|
39116
39367
|
}
|
|
@@ -39123,55 +39374,55 @@ function capture(path, budget) {
|
|
|
39123
39374
|
const root = lstatSync10(path, { throwIfNoEntry: false });
|
|
39124
39375
|
if (!root)
|
|
39125
39376
|
return { path, sha256: null };
|
|
39126
|
-
|
|
39127
|
-
const hash2 =
|
|
39377
|
+
need4(root.isDirectory(), "Unsupported native discovery directory input");
|
|
39378
|
+
const hash2 = createHash9("sha256");
|
|
39128
39379
|
function walk2(current, relative4, before, depth) {
|
|
39129
|
-
|
|
39380
|
+
need4(depth <= 64, "Native discovery directory depth limit exceeded");
|
|
39130
39381
|
const names = [], directory = opendirSync2(current);
|
|
39131
39382
|
try {
|
|
39132
39383
|
for (let entry = directory.readSync();entry; entry = directory.readSync()) {
|
|
39133
|
-
|
|
39384
|
+
need4(++budget.entries <= AGENT_POLICY_LIMITS.discoveryDirectoryEntries, "Native discovery directory entry limit exceeded");
|
|
39134
39385
|
names.push(entry.name);
|
|
39135
39386
|
}
|
|
39136
39387
|
} finally {
|
|
39137
39388
|
directory.closeSync();
|
|
39138
39389
|
}
|
|
39139
|
-
|
|
39390
|
+
need4(new Set(names).size === names.length, "Ambiguous native discovery directory names");
|
|
39140
39391
|
for (const name of names.sort()) {
|
|
39141
39392
|
const child = join14(current, name), childRelative = relative4 ? `${relative4}/${name}` : name;
|
|
39142
|
-
|
|
39393
|
+
need4(child.length <= AGENT_POLICY_LIMITS.pathCharacters, "Native discovery directory path limit exceeded");
|
|
39143
39394
|
const stat = lstatSync10(child);
|
|
39144
|
-
|
|
39395
|
+
need4(stat.isFile() || stat.isDirectory(), "Refusing symlink or special native discovery directory member");
|
|
39145
39396
|
const row = JSON.stringify([childRelative, stat.isDirectory() ? "directory" : "file"]) + `
|
|
39146
39397
|
`;
|
|
39147
39398
|
budget.bytes += Buffer.byteLength(row);
|
|
39148
|
-
|
|
39399
|
+
need4(budget.bytes <= AGENT_POLICY_LIMITS.discoveryDirectoryBytes, "Native discovery directory metadata limit exceeded");
|
|
39149
39400
|
hash2.update(row);
|
|
39150
39401
|
if (stat.isDirectory())
|
|
39151
39402
|
walk2(child, childRelative, stat, depth + 1);
|
|
39152
39403
|
}
|
|
39153
|
-
|
|
39404
|
+
need4(same(before, lstatSync10(current, { throwIfNoEntry: false })), "Native discovery directory changed while reading");
|
|
39154
39405
|
}
|
|
39155
39406
|
walk2(path, "", root, 0);
|
|
39156
39407
|
safe(path);
|
|
39157
39408
|
return { path, sha256: hash2.digest("hex") };
|
|
39158
39409
|
}
|
|
39159
39410
|
function captureDiscoveryDirectories(paths) {
|
|
39160
|
-
|
|
39411
|
+
need4(Array.isArray(paths) && paths.length <= AGENT_POLICY_LIMITS.discoveryDirectories && new Set(paths).size === paths.length, "Invalid native discovery directory collection");
|
|
39161
39412
|
const budget = { entries: 0, bytes: 0 };
|
|
39162
39413
|
return paths.map((path) => capture(path, budget));
|
|
39163
39414
|
}
|
|
39164
39415
|
function verifyDiscoveryDirectories(directories) {
|
|
39165
|
-
|
|
39416
|
+
need4(Array.isArray(directories) && directories.length <= AGENT_POLICY_LIMITS.discoveryDirectories, "Invalid native discovery directory collection");
|
|
39166
39417
|
for (const directory of directories)
|
|
39167
|
-
|
|
39418
|
+
need4(directory && typeof directory === "object" && (directory.sha256 === null || typeof directory.sha256 === "string" && /^[a-f0-9]{64}$/.test(directory.sha256)), "Invalid native discovery directory digest");
|
|
39168
39419
|
const current = captureDiscoveryDirectories(directories.map((directory) => directory.path));
|
|
39169
39420
|
for (let i = 0;i < directories.length; i++)
|
|
39170
|
-
|
|
39421
|
+
need4(current[i].sha256 === directories[i].sha256, `Native discovery directory membership changed; run skills hook install with a fresh discovery review: ${directories[i].path}`);
|
|
39171
39422
|
}
|
|
39172
39423
|
|
|
39173
39424
|
// src/lib/agent-discovery-bytes.ts
|
|
39174
|
-
import { createHash as
|
|
39425
|
+
import { createHash as createHash10 } from "crypto";
|
|
39175
39426
|
import { closeSync as closeSync11, constants as constants7, fstatSync as fstatSync11, lstatSync as lstatSync11, openSync as openSync11, readSync as readSync6 } from "fs";
|
|
39176
39427
|
import { dirname as dirname8, isAbsolute as isAbsolute9, resolve as resolve8 } from "path";
|
|
39177
39428
|
function discoveryByteBudget() {
|
|
@@ -39202,7 +39453,7 @@ function hashRawDiscoveryFile(path, budget, changes) {
|
|
|
39202
39453
|
if (bytes > AGENT_POLICY_LIMITS.discoveryRawSourceBytes)
|
|
39203
39454
|
throw new Error("Raw discovery file byte limit exceeded");
|
|
39204
39455
|
consume(budget, bytes);
|
|
39205
|
-
return
|
|
39456
|
+
return createHash10("sha256").update(text2).digest("hex");
|
|
39206
39457
|
}
|
|
39207
39458
|
const initial = lstatSync11(path, { throwIfNoEntry: false });
|
|
39208
39459
|
if (!initial)
|
|
@@ -39216,7 +39467,7 @@ function hashRawDiscoveryFile(path, budget, changes) {
|
|
|
39216
39467
|
const opened = fstatSync11(fd);
|
|
39217
39468
|
if (!opened.isFile() || !same2(initial, opened))
|
|
39218
39469
|
throw new Error("Raw discovery input changed during open");
|
|
39219
|
-
const hash2 =
|
|
39470
|
+
const hash2 = createHash10("sha256"), buffer = Buffer.alloc(64 * 1024);
|
|
39220
39471
|
let bytes = 0;
|
|
39221
39472
|
while (true) {
|
|
39222
39473
|
const count = readSync6(fd, buffer, 0, Math.min(buffer.length, AGENT_POLICY_LIMITS.discoveryRawSourceBytes - bytes + 1), null);
|
|
@@ -39239,7 +39490,7 @@ function hashRawDiscoveryFile(path, budget, changes) {
|
|
|
39239
39490
|
}
|
|
39240
39491
|
|
|
39241
39492
|
// src/lib/agent-discovery-path-bytes.ts
|
|
39242
|
-
import { createHash as
|
|
39493
|
+
import { createHash as createHash11 } from "crypto";
|
|
39243
39494
|
import { lstatSync as lstatSync12, readlinkSync as readlinkSync3 } from "fs";
|
|
39244
39495
|
import { dirname as dirname9, isAbsolute as isAbsolute10, join as join15, parse as parse3, resolve as resolve9, sep as sep3 } from "path";
|
|
39245
39496
|
function identity3(stat, mutable = false) {
|
|
@@ -39252,12 +39503,12 @@ function identity3(stat, mutable = false) {
|
|
|
39252
39503
|
...mutable ? { size: String(stat.size), mtimeNs: String(stat.mtimeNs), ctimeNs: String(stat.ctimeNs) } : {}
|
|
39253
39504
|
};
|
|
39254
39505
|
}
|
|
39255
|
-
function
|
|
39506
|
+
function canonical4(path) {
|
|
39256
39507
|
if (typeof path !== "string" || !isAbsolute10(path) || path !== resolve9(path) || path.length > AGENT_POLICY_LIMITS.pathCharacters || path.includes("\x00") || Buffer.from(path).toString("utf8") !== path)
|
|
39257
39508
|
throw new Error("Expected a canonical absolute discovery path");
|
|
39258
39509
|
}
|
|
39259
39510
|
function trace(path) {
|
|
39260
|
-
|
|
39511
|
+
canonical4(path);
|
|
39261
39512
|
const rows = [], paths = [];
|
|
39262
39513
|
let metadataBytes = 0, steps = 0, links = 0, cursor = parse3(path).root, pending = path.slice(cursor.length).split(sep3);
|
|
39263
39514
|
function record3(path2, row) {
|
|
@@ -39349,7 +39600,7 @@ function hashDiscoveryPathFile(path, budget, changes) {
|
|
|
39349
39600
|
const after = trace(path);
|
|
39350
39601
|
if (JSON.stringify(before.rows) !== JSON.stringify(after.rows) || before.file !== after.file)
|
|
39351
39602
|
throw new Error("Discovery path input changed during read");
|
|
39352
|
-
return
|
|
39603
|
+
return createHash11("sha256").update(JSON.stringify({ version: 1, path, rows: before.rows, content })).digest("hex");
|
|
39353
39604
|
}
|
|
39354
39605
|
|
|
39355
39606
|
// src/lib/plugin-discovery.ts
|
|
@@ -39361,7 +39612,7 @@ import { homedir as homedir2 } from "os";
|
|
|
39361
39612
|
import { isAbsolute as isAbsolute13, join as join19, resolve as resolve11 } from "path";
|
|
39362
39613
|
|
|
39363
39614
|
// src/lib/plugin-projection.ts
|
|
39364
|
-
import { createHash as
|
|
39615
|
+
import { createHash as createHash12 } from "crypto";
|
|
39365
39616
|
import { posix as posix2 } from "path";
|
|
39366
39617
|
var PLUGIN_PROJECTION_MANIFEST = "plugin-projection.json";
|
|
39367
39618
|
var PLUGIN_PROJECTION_LIMITS = Object.freeze({ files: 1024, bytes: 64 * 1024 * 1024, fileBytes: 16 * 1024 * 1024, metadataBytes: 512 * 1024, registrations: 64, history: 128 });
|
|
@@ -39372,7 +39623,7 @@ function pluginNeed(value, message) {
|
|
|
39372
39623
|
if (!value)
|
|
39373
39624
|
pluginRefusal(message);
|
|
39374
39625
|
}
|
|
39375
|
-
var pluginHash = (bytes) =>
|
|
39626
|
+
var pluginHash = (bytes) => createHash12("sha256").update(bytes).digest("hex");
|
|
39376
39627
|
function pluginObject(value) {
|
|
39377
39628
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
39378
39629
|
}
|
|
@@ -39560,7 +39811,7 @@ function buildPluginProjection(entries) {
|
|
|
39560
39811
|
}
|
|
39561
39812
|
|
|
39562
39813
|
// src/lib/plugin-projection-store.ts
|
|
39563
|
-
import { createHash as
|
|
39814
|
+
import { createHash as createHash13, randomUUID as randomUUID2 } from "crypto";
|
|
39564
39815
|
import { constants as constants8, closeSync as closeSync12, fchmodSync, fstatSync as fstatSync12, fsyncSync as fsyncSync2, linkSync, lstatSync as lstatSync13, mkdirSync as mkdirSync4, openSync as openSync12, opendirSync as opendirSync3, readSync as readSync7, renameSync as renameSync2, rmdirSync as rmdirSync2, rmSync, unlinkSync as unlinkSync3, writeSync as writeSync2 } from "fs";
|
|
39565
39816
|
import { dirname as dirname10, isAbsolute as isAbsolute11, join as join16, parse as parse5, resolve as resolve10 } from "path";
|
|
39566
39817
|
var READ_FLAGS = constants8.O_RDONLY | constants8.O_NOFOLLOW | constants8.O_NONBLOCK;
|
|
@@ -39576,7 +39827,7 @@ function stat(path) {
|
|
|
39576
39827
|
return pluginRefusal("Cannot inspect plugin filesystem entry");
|
|
39577
39828
|
}
|
|
39578
39829
|
}
|
|
39579
|
-
function
|
|
39830
|
+
function canonical5(path) {
|
|
39580
39831
|
pluginNeed(typeof path === "string" && path.length <= 8192 && isAbsolute11(path) && resolve10(path) === path && !/[\x00-\x1f\x7f]/.test(path), "Plugin storage paths must be canonical absolute paths");
|
|
39581
39832
|
}
|
|
39582
39833
|
function owner(stats, system = false) {
|
|
@@ -39587,7 +39838,7 @@ function same3(left, right, identityOnly = false) {
|
|
|
39587
39838
|
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");
|
|
39588
39839
|
}
|
|
39589
39840
|
function ancestors(path, create = false) {
|
|
39590
|
-
|
|
39841
|
+
canonical5(path);
|
|
39591
39842
|
const result = [], parent = dirname10(path), filesystemRoot = parse5(parent).root;
|
|
39592
39843
|
let current = filesystemRoot;
|
|
39593
39844
|
for (const segment of ["", ...parent.slice(filesystemRoot.length).split("/").filter(Boolean)]) {
|
|
@@ -39902,7 +40153,7 @@ function pluginExecutableDigest(path) {
|
|
|
39902
40153
|
const opened = fstatSync12(fd, { bigint: true });
|
|
39903
40154
|
same3(before, opened);
|
|
39904
40155
|
fileShape(opened, maximum, "executable");
|
|
39905
|
-
const hash2 =
|
|
40156
|
+
const hash2 = createHash13("sha256"), buffer = new Uint8Array(64 * 1024);
|
|
39906
40157
|
let remaining = Number(opened.size);
|
|
39907
40158
|
while (remaining > 0) {
|
|
39908
40159
|
const count = readSync7(fd, buffer, 0, Math.min(buffer.byteLength, remaining), null);
|
|
@@ -39927,7 +40178,7 @@ function pluginExecutableDigest(path) {
|
|
|
39927
40178
|
|
|
39928
40179
|
// src/lib/skill-validation.ts
|
|
39929
40180
|
import { existsSync as existsSync5, lstatSync as lstatSync14, readFileSync as readFileSync12, readdirSync as readdirSync6, statSync as statSync5 } from "fs";
|
|
39930
|
-
import { isAbsolute as isAbsolute12, join as join18, normalize as
|
|
40181
|
+
import { isAbsolute as isAbsolute12, join as join18, normalize as normalize3 } from "path";
|
|
39931
40182
|
|
|
39932
40183
|
// src/lib/hosted-skill-set.ts
|
|
39933
40184
|
import { existsSync as existsSync4, readFileSync as readFileSync11, readdirSync as readdirSync5, statSync as statSync4 } from "fs";
|
|
@@ -40033,7 +40284,7 @@ function sortMessages(messages) {
|
|
|
40033
40284
|
function isSafeRelativePath(value) {
|
|
40034
40285
|
if (!value.trim() || isAbsolute12(value))
|
|
40035
40286
|
return false;
|
|
40036
|
-
const normalized =
|
|
40287
|
+
const normalized = normalize3(value).replace(/\\/g, "/");
|
|
40037
40288
|
return normalized !== ".." && !normalized.startsWith("../") && !normalized.includes("/../");
|
|
40038
40289
|
}
|
|
40039
40290
|
function validateRuntimeEntry(skillPath, entrypoint, issues, warnings) {
|
|
@@ -40897,23 +41148,23 @@ function captureManagedPluginRegistry(path, managedPlugins) {
|
|
|
40897
41148
|
}
|
|
40898
41149
|
|
|
40899
41150
|
// src/lib/claude-marketplace-registry.ts
|
|
40900
|
-
import { createHash as
|
|
41151
|
+
import { createHash as createHash14 } from "crypto";
|
|
40901
41152
|
import { closeSync as closeSync14, constants as constants10, fstatSync as fstatSync14, lstatSync as lstatSync16, openSync as openSync14, readSync as readSync9 } from "fs";
|
|
40902
41153
|
import { basename as basename6, dirname as dirname12, isAbsolute as isAbsolute15, resolve as resolve13 } from "path";
|
|
40903
41154
|
var CLAUDE_MARKETPLACE_REGISTRY_LIMITS = Object.freeze({ bytes: 1024 * 1024, rows: 1024, depth: 32, nodes: 65536, stringCharacters: 16384, pathCharacters: 4096 });
|
|
40904
|
-
function
|
|
41155
|
+
function need5(value, reason) {
|
|
40905
41156
|
if (!value)
|
|
40906
41157
|
throw new Error(`Claude marketplace registry ${reason}`);
|
|
40907
41158
|
}
|
|
40908
41159
|
function absolutePath3(value) {
|
|
40909
|
-
|
|
41160
|
+
need5(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute15(value) && resolve13(value) === value, "requires a normalized absolute path");
|
|
40910
41161
|
}
|
|
40911
41162
|
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;
|
|
40912
41163
|
function parents2(path) {
|
|
40913
41164
|
const result = [];
|
|
40914
41165
|
for (let at = dirname12(path);; at = dirname12(at)) {
|
|
40915
41166
|
const stat2 = lstatSync16(at, { bigint: true });
|
|
40916
|
-
|
|
41167
|
+
need5(stat2.isDirectory() && !stat2.isSymbolicLink(), "path traverses a symlink or non-directory");
|
|
40917
41168
|
result.push([at, stat2]);
|
|
40918
41169
|
if (at === dirname12(at))
|
|
40919
41170
|
return result;
|
|
@@ -40921,15 +41172,15 @@ function parents2(path) {
|
|
|
40921
41172
|
}
|
|
40922
41173
|
function readRegistry2(path, budget) {
|
|
40923
41174
|
absolutePath3(path);
|
|
40924
|
-
|
|
40925
|
-
|
|
41175
|
+
need5(basename6(path) === "known_marketplaces.json", "requires known_marketplaces.json");
|
|
41176
|
+
need5(Number.isSafeInteger(budget.remaining) && budget.remaining >= 0, "has an invalid byte budget");
|
|
40926
41177
|
const ancestors2 = parents2(path), initial = lstatSync16(path, { bigint: true });
|
|
40927
|
-
|
|
40928
|
-
|
|
41178
|
+
need5(initial.isFile() && !initial.isSymbolicLink() && initial.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
|
|
41179
|
+
need5(initial.size <= BigInt(budget.remaining), "exceeds its aggregate byte limit");
|
|
40929
41180
|
const fd = openSync14(path, constants10.O_RDONLY | constants10.O_NOFOLLOW | constants10.O_NONBLOCK);
|
|
40930
41181
|
try {
|
|
40931
41182
|
const opened = fstatSync14(fd, { bigint: true });
|
|
40932
|
-
|
|
41183
|
+
need5(opened.isFile() && sameFile2(initial, opened), "changed during open");
|
|
40933
41184
|
const bytes = Buffer.alloc(Number(opened.size) + 1);
|
|
40934
41185
|
let length = 0;
|
|
40935
41186
|
while (length < bytes.length) {
|
|
@@ -40939,10 +41190,10 @@ function readRegistry2(path, budget) {
|
|
|
40939
41190
|
length += count;
|
|
40940
41191
|
}
|
|
40941
41192
|
const after = fstatSync14(fd, { bigint: true }), current = lstatSync16(path, { bigint: true });
|
|
40942
|
-
|
|
41193
|
+
need5(current.isFile() && sameFile2(opened, after) && sameFile2(after, current) && BigInt(length) === opened.size, "changed during read");
|
|
40943
41194
|
for (const [ancestor, before] of ancestors2) {
|
|
40944
41195
|
const now = lstatSync16(ancestor, { bigint: true });
|
|
40945
|
-
|
|
41196
|
+
need5(now.isDirectory() && before.dev === now.dev && before.ino === now.ino && before.mode === now.mode, "parent changed during read");
|
|
40946
41197
|
}
|
|
40947
41198
|
budget.remaining -= length;
|
|
40948
41199
|
try {
|
|
@@ -40962,7 +41213,7 @@ function parse6(text2) {
|
|
|
40962
41213
|
at++;
|
|
40963
41214
|
};
|
|
40964
41215
|
function string() {
|
|
40965
|
-
|
|
41216
|
+
need5(text2[at] === '"', "contains invalid JSON");
|
|
40966
41217
|
const start = at++;
|
|
40967
41218
|
while (at < text2.length) {
|
|
40968
41219
|
const character = text2[at++];
|
|
@@ -40973,7 +41224,7 @@ function parse6(text2) {
|
|
|
40973
41224
|
} catch {
|
|
40974
41225
|
throw new Error("Claude marketplace registry contains invalid JSON string");
|
|
40975
41226
|
}
|
|
40976
|
-
|
|
41227
|
+
need5(value2.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.stringCharacters, "exceeds its string limit");
|
|
40977
41228
|
return value2;
|
|
40978
41229
|
}
|
|
40979
41230
|
if (character === "\\")
|
|
@@ -40982,7 +41233,7 @@ function parse6(text2) {
|
|
|
40982
41233
|
throw new Error("Claude marketplace registry contains an unterminated JSON string");
|
|
40983
41234
|
}
|
|
40984
41235
|
function value(depth) {
|
|
40985
|
-
|
|
41236
|
+
need5(depth <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.depth && ++nodes <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.nodes, "exceeds its nesting or node limit");
|
|
40986
41237
|
space();
|
|
40987
41238
|
const character = text2[at];
|
|
40988
41239
|
if (character === '"')
|
|
@@ -40996,17 +41247,17 @@ function parse6(text2) {
|
|
|
40996
41247
|
if (object5) {
|
|
40997
41248
|
space();
|
|
40998
41249
|
const key = string();
|
|
40999
|
-
|
|
41250
|
+
need5(!keys2.has(key), "contains a duplicate JSON key");
|
|
41000
41251
|
keys2.add(key);
|
|
41001
41252
|
space();
|
|
41002
|
-
|
|
41253
|
+
need5(text2[at++] === ":", "contains invalid JSON");
|
|
41003
41254
|
entries.push([key, value(depth + 1)]);
|
|
41004
41255
|
} else
|
|
41005
41256
|
items.push(value(depth + 1));
|
|
41006
41257
|
space();
|
|
41007
41258
|
if (text2[at] === end)
|
|
41008
41259
|
break;
|
|
41009
|
-
|
|
41260
|
+
need5(text2[at++] === ",", "contains invalid JSON");
|
|
41010
41261
|
}
|
|
41011
41262
|
at++;
|
|
41012
41263
|
return object5 ? { kind: "object", entries } : { kind: "array", items };
|
|
@@ -41018,14 +41269,14 @@ function parse6(text2) {
|
|
|
41018
41269
|
}
|
|
41019
41270
|
numberPattern.lastIndex = at;
|
|
41020
41271
|
const number = numberPattern.exec(text2);
|
|
41021
|
-
|
|
41272
|
+
need5(number, "contains invalid JSON");
|
|
41022
41273
|
at += number[0].length;
|
|
41023
41274
|
return { kind: "number", value: number[0] };
|
|
41024
41275
|
}
|
|
41025
41276
|
const root2 = value(0);
|
|
41026
41277
|
space();
|
|
41027
|
-
|
|
41028
|
-
|
|
41278
|
+
need5(at === text2.length && root2.kind === "object", "requires a JSON object without trailing content");
|
|
41279
|
+
need5(root2.entries.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.rows, "exceeds its marketplace row limit");
|
|
41029
41280
|
return root2;
|
|
41030
41281
|
}
|
|
41031
41282
|
function exactKeys2(value, keys2) {
|
|
@@ -41033,7 +41284,7 @@ function exactKeys2(value, keys2) {
|
|
|
41033
41284
|
}
|
|
41034
41285
|
var field = (object5, key) => object5.entries.find(([name]) => name === key)?.[1];
|
|
41035
41286
|
function textField(value) {
|
|
41036
|
-
|
|
41287
|
+
need5(value?.kind === "string" && value.value.length > 0 && !/[\x00-\x1f\x7f]/.test(value.value), "contains an invalid recognized field");
|
|
41037
41288
|
return value.value;
|
|
41038
41289
|
}
|
|
41039
41290
|
function normalizeRow(row, version = 1) {
|
|
@@ -41041,7 +41292,7 @@ function normalizeRow(row, version = 1) {
|
|
|
41041
41292
|
if (version !== 2 || !exactKeys2(row, ["source", "installLocation", "lastUpdated", "autoUpdate"]))
|
|
41042
41293
|
return;
|
|
41043
41294
|
const autoUpdate = field(row, "autoUpdate");
|
|
41044
|
-
|
|
41295
|
+
need5(autoUpdate?.kind === "literal" && (autoUpdate.value === "true" || autoUpdate.value === "false"), "contains an invalid automatic-update preference");
|
|
41045
41296
|
}
|
|
41046
41297
|
const source = field(row, "source");
|
|
41047
41298
|
if (source?.kind !== "object")
|
|
@@ -41057,34 +41308,34 @@ function normalizeRow(row, version = 1) {
|
|
|
41057
41308
|
absolutePath3(sourceLocation);
|
|
41058
41309
|
absolutePath3(textField(field(row, "installLocation")));
|
|
41059
41310
|
const updated = textField(field(row, "lastUpdated"));
|
|
41060
|
-
|
|
41311
|
+
need5(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(updated), "contains an invalid recognized update timestamp");
|
|
41061
41312
|
const millis = Date.parse(updated);
|
|
41062
|
-
|
|
41313
|
+
need5(Number.isFinite(millis) && new Date(millis).toISOString() === updated, "contains an invalid recognized update timestamp");
|
|
41063
41314
|
row.entries = row.entries.map(([key, value]) => [key, key === "lastUpdated" ? { kind: "validated-update-time" } : value]);
|
|
41064
41315
|
}
|
|
41065
41316
|
function captureClaudeMarketplaceRegistry(path, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
41066
41317
|
const value = parse6(readRegistry2(path, budget));
|
|
41067
41318
|
for (const [, row] of value.entries)
|
|
41068
41319
|
normalizeRow(row);
|
|
41069
|
-
const sha2562 =
|
|
41320
|
+
const sha2562 = createHash14("sha256").update("hasna.skills.claude-marketplace-registry.v1\x00").update(JSON.stringify(value)).digest("hex");
|
|
41070
41321
|
return { path, hashMode: "claude-marketplace-registry", sha256: sha2562 };
|
|
41071
41322
|
}
|
|
41072
41323
|
function captureClaudeMarketplaceRegistryV2(path, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
41073
41324
|
const value = parse6(readRegistry2(path, budget));
|
|
41074
41325
|
for (const [, row] of value.entries)
|
|
41075
41326
|
normalizeRow(row, 2);
|
|
41076
|
-
const sha2562 =
|
|
41327
|
+
const sha2562 = createHash14("sha256").update("hasna.skills.claude-marketplace-registry.v2\x00").update(JSON.stringify(value)).digest("hex");
|
|
41077
41328
|
return { path, hashMode: "claude-marketplace-registry-v2", sha256: sha2562 };
|
|
41078
41329
|
}
|
|
41079
41330
|
|
|
41080
41331
|
// src/lib/codex-hook-discovery-recovery.ts
|
|
41081
|
-
import { createHash as
|
|
41332
|
+
import { createHash as createHash16 } from "crypto";
|
|
41082
41333
|
|
|
41083
41334
|
// src/lib/codex-hook-trust-files.ts
|
|
41084
41335
|
import { closeSync as closeSync15, constants as constants11, fstatSync as fstatSync15, fsyncSync as fsyncSync3, lstatSync as lstatSync17, openSync as openSync15, readSync as readSync10, writeFileSync as writeFileSync3 } from "fs";
|
|
41085
|
-
import { createHash as
|
|
41336
|
+
import { createHash as createHash15 } from "crypto";
|
|
41086
41337
|
import { dirname as dirname13 } from "path";
|
|
41087
|
-
function
|
|
41338
|
+
function need6(value, code) {
|
|
41088
41339
|
if (!value)
|
|
41089
41340
|
throw new Error(`CODEX_HOOK_TRUST_${code}`);
|
|
41090
41341
|
}
|
|
@@ -41092,8 +41343,8 @@ var sameStat = (a, b) => ["dev", "ino", "uid", "nlink", "mode", "size", "mtimeNs
|
|
|
41092
41343
|
function safeParents(file) {
|
|
41093
41344
|
for (let p = dirname13(file);; p = dirname13(p)) {
|
|
41094
41345
|
const s = lstatSync17(p);
|
|
41095
|
-
|
|
41096
|
-
|
|
41346
|
+
need6(s.isDirectory() && !s.isSymbolicLink(), "UNSAFE_PARENT");
|
|
41347
|
+
need6((s.mode & 18) === 0 || s.uid === 0 && (s.mode & 512) !== 0, "UNSAFE_PARENT");
|
|
41097
41348
|
if (dirname13(p) === p)
|
|
41098
41349
|
break;
|
|
41099
41350
|
}
|
|
@@ -41102,12 +41353,12 @@ function snapshot(file, privateFile = false, options = {}) {
|
|
|
41102
41353
|
const readOnlyPackage = options.readOnlyPackage === true && !privateFile;
|
|
41103
41354
|
safeParents(file);
|
|
41104
41355
|
const initial = lstatSync17(file, { bigint: true });
|
|
41105
|
-
|
|
41106
|
-
|
|
41356
|
+
need6(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");
|
|
41357
|
+
need6(initial.size <= 8n * 1024n * 1024n, "FILE_BOUND");
|
|
41107
41358
|
const fd = openSync15(file, constants11.O_RDONLY | constants11.O_NOFOLLOW | constants11.O_NONBLOCK);
|
|
41108
41359
|
try {
|
|
41109
41360
|
const before = fstatSync15(fd, { bigint: true });
|
|
41110
|
-
|
|
41361
|
+
need6(sameStat(initial, before), "INPUT_CHANGED");
|
|
41111
41362
|
const bytes = Buffer.alloc(Number(before.size) + 1);
|
|
41112
41363
|
let length = 0;
|
|
41113
41364
|
while (length < bytes.length) {
|
|
@@ -41116,16 +41367,16 @@ function snapshot(file, privateFile = false, options = {}) {
|
|
|
41116
41367
|
break;
|
|
41117
41368
|
length += n2;
|
|
41118
41369
|
}
|
|
41119
|
-
|
|
41370
|
+
need6(length === Number(before.size) && sameStat(before, fstatSync15(fd, { bigint: true })) && sameStat(before, lstatSync17(file, { bigint: true })), "INPUT_CHANGED");
|
|
41120
41371
|
const content = bytes.subarray(0, length), text2 = new TextDecoder("utf-8", { fatal: true }).decode(content);
|
|
41121
|
-
return { file, privateFile, readOnlyPackage, text: text2, bytes: content, stat: before, sha256:
|
|
41372
|
+
return { file, privateFile, readOnlyPackage, text: text2, bytes: content, stat: before, sha256: createHash15("sha256").update(content).digest("hex") };
|
|
41122
41373
|
} finally {
|
|
41123
41374
|
closeSync15(fd);
|
|
41124
41375
|
}
|
|
41125
41376
|
}
|
|
41126
41377
|
function unchanged2(before) {
|
|
41127
41378
|
const after = snapshot(before.file, before.privateFile, before.readOnlyPackage ? { readOnlyPackage: true } : {});
|
|
41128
|
-
|
|
41379
|
+
need6(sameStat(before.stat, after.stat) && after.sha256 === before.sha256, "INPUT_CHANGED");
|
|
41129
41380
|
}
|
|
41130
41381
|
|
|
41131
41382
|
// src/lib/codex-hook-additions-review.ts
|
|
@@ -41134,11 +41385,12 @@ var matchedEvents = { ...events, PreToolUse: ["preToolUse", "pre_tool_use"] };
|
|
|
41134
41385
|
var proofs = new WeakMap;
|
|
41135
41386
|
|
|
41136
41387
|
// src/lib/codex-hook-discovery-recovery.ts
|
|
41137
|
-
var
|
|
41388
|
+
var sha3 = (text2) => createHash16("sha256").update(text2).digest("hex");
|
|
41389
|
+
var fields = [...CODEX_DISCOVERY_PROJECTION_FIELDS];
|
|
41138
41390
|
var proofs2 = new WeakMap;
|
|
41139
41391
|
function assertCodexHookDiscoveryRecovery(binding, witness) {
|
|
41140
41392
|
const proof = proofs2.get(witness);
|
|
41141
|
-
|
|
41393
|
+
need6(!!proof && binding.agent === "codex" && witness.discoverySha256 === sha3(JSON.stringify(binding)), "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
|
|
41142
41394
|
unchanged2(proof.before);
|
|
41143
41395
|
unchanged2(proof.current);
|
|
41144
41396
|
proof.recheckAdditions();
|
|
@@ -41147,12 +41399,12 @@ function verifiesCodexHookDiscoverySource(binding, source, currentDigest, witnes
|
|
|
41147
41399
|
if (!witness || source.path !== witness.configPath || source.hashMode !== "bytes")
|
|
41148
41400
|
return false;
|
|
41149
41401
|
assertCodexHookDiscoveryRecovery(binding, witness);
|
|
41150
|
-
|
|
41402
|
+
need6(source.sha256 === witness.beforeSha256 && currentDigest === witness.currentSha256, "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
|
|
41151
41403
|
return true;
|
|
41152
41404
|
}
|
|
41153
41405
|
|
|
41154
41406
|
// src/lib/agent-discovery.ts
|
|
41155
|
-
var digest2 = (text2) =>
|
|
41407
|
+
var digest2 = (text2) => createHash17("sha256").update(text2).digest("hex");
|
|
41156
41408
|
function parseConfig(text2, path, toml = false) {
|
|
41157
41409
|
try {
|
|
41158
41410
|
const value = toml ? Bun.TOML.parse(text2) : JSON.parse(text2);
|
|
@@ -41184,14 +41436,26 @@ function read2(path, changes) {
|
|
|
41184
41436
|
throw new Error(`Unsupported or oversized native discovery input: ${path}`);
|
|
41185
41437
|
return readFileSync13(path, "utf8");
|
|
41186
41438
|
}
|
|
41439
|
+
function projectNativeDiscoveryFields(text2, format, fields2, path) {
|
|
41440
|
+
const object5 = format === "yaml" ? parseHermesConfig(text2) : parseConfig(text2, path, format === "toml");
|
|
41441
|
+
if (!object5 || typeof object5 !== "object" || Array.isArray(object5))
|
|
41442
|
+
throw new Error("Expected native discovery configuration object");
|
|
41443
|
+
return digest2(JSON.stringify(Object.fromEntries(fields2.map((field2) => [field2, object5[field2] ?? null]))));
|
|
41444
|
+
}
|
|
41445
|
+
function isSupersededCodexProjection(agent, configPath, source) {
|
|
41446
|
+
return agent === "codex" && source.path === configPath && source.format === "toml" && isDeepStrictEqual3(source.fields, [...CODEX_DISCOVERY_PROJECTION_FIELDS]);
|
|
41447
|
+
}
|
|
41448
|
+
function supersedesCodexProjection(sources, configPath) {
|
|
41449
|
+
return sources.some((source) => source.path === configPath && source.hashMode === "codex-settings-v2");
|
|
41450
|
+
}
|
|
41187
41451
|
function projected(source, changes, budget = discoveryByteBudget()) {
|
|
41188
|
-
if (source.hashMode === "codex-settings-v1") {
|
|
41452
|
+
if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2") {
|
|
41189
41453
|
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
41190
41454
|
throw new Error("Codex settings witnesses require exact typed metadata");
|
|
41191
|
-
const current = captureCodexSettings(source.path, budget).sha256;
|
|
41455
|
+
const current = (source.hashMode === "codex-settings-v2" ? captureCodexSettingsV2 : captureCodexSettings)(source.path, budget).sha256;
|
|
41192
41456
|
if (current !== source.sha256)
|
|
41193
41457
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
41194
|
-
return changes?.has(source.path) ? hashCodexSettingsReplacement(changes.get(source.path), budget) : current;
|
|
41458
|
+
return changes?.has(source.path) ? (source.hashMode === "codex-settings-v2" ? hashCodexSettingsReplacementV2 : hashCodexSettingsReplacement)(changes.get(source.path), budget) : current;
|
|
41195
41459
|
}
|
|
41196
41460
|
if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") {
|
|
41197
41461
|
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
@@ -41230,10 +41494,7 @@ function projected(source, changes, budget = discoveryByteBudget()) {
|
|
|
41230
41494
|
return null;
|
|
41231
41495
|
if (!source.format)
|
|
41232
41496
|
return digest2(text2);
|
|
41233
|
-
|
|
41234
|
-
if (!object5 || typeof object5 !== "object" || Array.isArray(object5))
|
|
41235
|
-
throw new Error("Expected native discovery configuration object");
|
|
41236
|
-
return digest2(JSON.stringify(Object.fromEntries((source.fields ?? []).map((field2) => [field2, object5[field2] ?? null]))));
|
|
41497
|
+
return projectNativeDiscoveryFields(text2, source.format, source.fields ?? [], source.path);
|
|
41237
41498
|
}
|
|
41238
41499
|
function verifyAgentDiscovery(binding, codexRecovery) {
|
|
41239
41500
|
if (codexRecovery)
|
|
@@ -41261,7 +41522,7 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
41261
41522
|
safe4(root2);
|
|
41262
41523
|
}
|
|
41263
41524
|
function assertMarketplaceBinding(binding, source) {
|
|
41264
|
-
if (source.hashMode === "codex-settings-v1" && (binding.agent !== "codex" || binding.method !== "reviewed" || basename7(source.path) !== "config.toml"))
|
|
41525
|
+
if ((source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2") && (binding.agent !== "codex" || binding.method !== "reviewed" || basename7(source.path) !== "config.toml"))
|
|
41265
41526
|
throw new Error("Codex settings witnesses require explicit reviewed Codex configuration");
|
|
41266
41527
|
if ((source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") && (binding.agent !== "claude" || binding.method !== "reviewed" || basename7(source.path) !== "settings.json"))
|
|
41267
41528
|
throw new Error("Claude settings witnesses require explicit reviewed Claude configuration");
|
|
@@ -41290,8 +41551,8 @@ function captureDiscoveryPathSources(paths) {
|
|
|
41290
41551
|
const budget = discoveryByteBudget();
|
|
41291
41552
|
return paths.map((path) => ({ path, hashMode: "path-bytes", sha256: hashDiscoveryPathFile(path, budget) }));
|
|
41292
41553
|
}
|
|
41293
|
-
function assertProjectDiscovery(agent, directories, home,
|
|
41294
|
-
const homeConfigPath =
|
|
41554
|
+
function assertProjectDiscovery(agent, directories, home, canonical6 = resolve14, reviewed) {
|
|
41555
|
+
const homeConfigPath = canonical6(agentDiscoveryConfigPath(home, agent));
|
|
41295
41556
|
for (const directory of directories) {
|
|
41296
41557
|
const isHome = resolve14(directory) === resolve14(home);
|
|
41297
41558
|
if (agent === "hermes") {
|
|
@@ -41302,7 +41563,7 @@ function assertProjectDiscovery(agent, directories, home, canonical5 = resolve14
|
|
|
41302
41563
|
continue;
|
|
41303
41564
|
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"] : [".cursor/hooks.json"];
|
|
41304
41565
|
for (const suffix of paths) {
|
|
41305
|
-
const path =
|
|
41566
|
+
const path = canonical6(join21(directory, suffix)), raw = read2(path);
|
|
41306
41567
|
if (raw === null)
|
|
41307
41568
|
continue;
|
|
41308
41569
|
const isRootAliasedHomeConfig = agent === "claude" && suffix === ".claude/settings.json" || agent === "codex" && suffix === ".codex/config.toml";
|
|
@@ -41318,14 +41579,14 @@ function assertProjectDiscovery(agent, directories, home, canonical5 = resolve14
|
|
|
41318
41579
|
const managed = reviewed.sources.flatMap((source) => source.hashMode === "claude-plugin-registry" ? source.managedPlugins ?? [] : []);
|
|
41319
41580
|
if (exact && projected(exact) === exact.sha256 && managed.length) {
|
|
41320
41581
|
const bindings = managed.map((item) => readPluginBinding(item.storeRoot, item.bindingId));
|
|
41321
|
-
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 ===
|
|
41582
|
+
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 === canonical6(directory))));
|
|
41322
41583
|
}
|
|
41323
41584
|
}
|
|
41324
41585
|
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)))
|
|
41325
41586
|
throw new Error(`NATIVE_SKILL_DRIFT: higher-precedence project skill or hook configuration requires review: ${path}`);
|
|
41326
41587
|
}
|
|
41327
41588
|
if (agent === "claude") {
|
|
41328
|
-
const commands =
|
|
41589
|
+
const commands = canonical6(join21(directory, ".claude/commands"));
|
|
41329
41590
|
safe4(commands);
|
|
41330
41591
|
if (lstatSync18(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync7(commands).length)
|
|
41331
41592
|
throw new Error("NATIVE_SKILL_DRIFT: legacy project command discovery requires a dedicated format adapter");
|
|
@@ -41336,10 +41597,10 @@ function agentDiscoveryConfigPath(home, agent) {
|
|
|
41336
41597
|
return join21(home, agent === "hermes" ? ".hermes/config.yaml" : agent === "opencode" ? ".config/opencode/opencode.json" : `.${agent}/${agent === "codex" ? "config.toml" : agent === "cursor" ? "hooks.json" : "settings.json"}`);
|
|
41337
41598
|
}
|
|
41338
41599
|
function resolveAgentDiscovery(options) {
|
|
41339
|
-
const
|
|
41600
|
+
const canonical6 = options.canonical ?? resolve14, home = resolve14(options.home), agent = options.agent;
|
|
41340
41601
|
const sources = [], roots = new Set, builtinNames = [];
|
|
41341
|
-
const witness = (path, format,
|
|
41342
|
-
const source = { path:
|
|
41602
|
+
const witness = (path, format, fields2) => {
|
|
41603
|
+
const source = { path: canonical6(path), sha256: null, ...format ? { format, fields: fields2 } : {} };
|
|
41343
41604
|
source.sha256 = projected(source);
|
|
41344
41605
|
sources.push(source);
|
|
41345
41606
|
return read2(source.path);
|
|
@@ -41347,7 +41608,7 @@ function resolveAgentDiscovery(options) {
|
|
|
41347
41608
|
if (agent === "hermes")
|
|
41348
41609
|
assertHermesEnvironment(home);
|
|
41349
41610
|
const configPath = agentDiscoveryConfigPath(home, agent);
|
|
41350
|
-
const configText = witness(configPath, agent === "hermes" ? "yaml" : agent === "codex" ? "toml" : "json", agent === "hermes" ? ["skills", "plugins", "hooks"] : agent === "claude" ? ["enabledPlugins", "extraKnownMarketplaces"] : agent === "codex" ? [
|
|
41611
|
+
const configText = witness(configPath, agent === "hermes" ? "yaml" : agent === "codex" ? "toml" : "json", agent === "hermes" ? ["skills", "plugins", "hooks"] : agent === "claude" ? ["enabledPlugins", "extraKnownMarketplaces"] : agent === "codex" ? [...CODEX_DISCOVERY_PROJECTION_FIELDS] : agent === "gemini" ? ["skills", "extensions", "security"] : agent === "opencode" ? ["plugin", "skills"] : ["version"]);
|
|
41351
41612
|
const config = configText === null ? {} : agent === "hermes" ? parseHermesConfig(configText) : parseConfig(configText, configPath, agent === "codex");
|
|
41352
41613
|
const unresolved = (detail) => {
|
|
41353
41614
|
throw new Error(`Native discovery is unresolved (${agent}: ${detail}); provide a reviewed --discovery-inputs file`);
|
|
@@ -41406,11 +41667,12 @@ function resolveAgentDiscovery(options) {
|
|
|
41406
41667
|
if (retained.agent !== agent || retained.method !== "reviewed")
|
|
41407
41668
|
unresolved("invalid retained review");
|
|
41408
41669
|
verifyAgentDiscovery(retained);
|
|
41409
|
-
if (!retained.sources.some((source) => source.path ===
|
|
41670
|
+
if (!retained.sources.some((source) => source.path === canonical6(configPath) && source.format === undefined && source.fields === undefined))
|
|
41410
41671
|
unresolved("retained review is missing the full agent configuration source");
|
|
41411
|
-
if (retained.sources.some((source) => (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "codex-settings-v1")) && source.path !==
|
|
41672
|
+
if (retained.sources.some((source) => (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2"))) && source.path !== canonical6(configPath)))
|
|
41412
41673
|
unresolved("retained settings witness names another configuration source");
|
|
41413
|
-
|
|
41674
|
+
const covered = supersedesCodexProjection(retained.sources, canonical6(configPath)) ? sources.filter((source) => !isSupersededCodexProjection(agent, canonical6(configPath), source)) : sources;
|
|
41675
|
+
if (covered.some((source) => !retained.sources.some((saved) => isDeepStrictEqual3(saved, source))) || [...roots].some((root2) => !retained.roots.includes(root2)) || agent === "gemini" && JSON.stringify(retained.builtinNames) !== JSON.stringify(builtinNames))
|
|
41414
41676
|
unresolved("retained review is missing current runtime discovery coverage");
|
|
41415
41677
|
return retained;
|
|
41416
41678
|
}
|
|
@@ -41424,14 +41686,15 @@ function resolveAgentDiscovery(options) {
|
|
|
41424
41686
|
if (review.sources.some((source) => source.format !== undefined || source.fields !== undefined))
|
|
41425
41687
|
throw new Error("Explicit discovery reviews require full source-file hashes");
|
|
41426
41688
|
verifyAgentDiscovery(supplied);
|
|
41427
|
-
if (review.sources.some((source) => (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "codex-settings-v1")) && source.path !==
|
|
41689
|
+
if (review.sources.some((source) => (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2"))) && source.path !== canonical6(configPath)))
|
|
41428
41690
|
throw new Error("Semantic settings witnesses must name the configured Claude configuration source");
|
|
41429
|
-
if (!review.sources.some((source) => source.path ===
|
|
41691
|
+
if (!review.sources.some((source) => source.path === canonical6(configPath)))
|
|
41430
41692
|
throw new Error("Discovery review must include the agent configuration source");
|
|
41431
|
-
|
|
41693
|
+
const reviewedSources = supersedesCodexProjection(review.sources, canonical6(configPath)) ? sources.filter((source) => !isSupersededCodexProjection(agent, canonical6(configPath), source)) : sources;
|
|
41694
|
+
return { ...supplied, roots: [...new Set([...roots, ...supplied.roots])].sort(), sources: [...reviewedSources, ...review.sources], ...agent === "gemini" ? { builtinNames } : {} };
|
|
41432
41695
|
}
|
|
41433
41696
|
function plugin(root2) {
|
|
41434
|
-
root2 =
|
|
41697
|
+
root2 = canonical6(root2);
|
|
41435
41698
|
safe4(root2);
|
|
41436
41699
|
const manifestPath = join21(root2, agent === "claude" ? ".claude-plugin/plugin.json" : ".codex-plugin/plugin.json");
|
|
41437
41700
|
const raw = witness(manifestPath);
|
|
@@ -41463,7 +41726,7 @@ function resolveAgentDiscovery(options) {
|
|
|
41463
41726
|
if (agent === "claude") {
|
|
41464
41727
|
const registrations = witness(join21(home, ".claude/plugins/installed_plugins.json"));
|
|
41465
41728
|
const installed = registrations === null ? {} : parseConfig(registrations, join21(home, ".claude/plugins/installed_plugins.json")).plugins;
|
|
41466
|
-
const commands =
|
|
41729
|
+
const commands = canonical6(join21(home, ".claude/commands"));
|
|
41467
41730
|
safe4(commands);
|
|
41468
41731
|
if (lstatSync18(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync7(commands).length)
|
|
41469
41732
|
unresolved("legacy home command discovery requires a dedicated format adapter");
|
|
@@ -41537,7 +41800,7 @@ function resolveAgentDiscovery(options) {
|
|
|
41537
41800
|
roots.add(join21(root2, "skills"));
|
|
41538
41801
|
}
|
|
41539
41802
|
}
|
|
41540
|
-
return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join21(home, ".hermes/plugins"), join21(home, ".hermes/hermes-agent")].map((path) =>
|
|
41803
|
+
return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join21(home, ".hermes/plugins"), join21(home, ".hermes/hermes-agent")].map((path) => canonical6(path))) } : {} };
|
|
41541
41804
|
}
|
|
41542
41805
|
|
|
41543
41806
|
// src/lib/agent-adapters.ts
|
|
@@ -41716,10 +41979,10 @@ function inlineRowsAsTables(value, newline) {
|
|
|
41716
41979
|
for (const row of rows) {
|
|
41717
41980
|
if (!row.startsWith("{") || !row.endsWith("}"))
|
|
41718
41981
|
return null;
|
|
41719
|
-
const
|
|
41720
|
-
if (!
|
|
41982
|
+
const fields2 = splitTopLevel(row.slice(1, -1), ",");
|
|
41983
|
+
if (!fields2)
|
|
41721
41984
|
return null;
|
|
41722
|
-
const lines =
|
|
41985
|
+
const lines = fields2.map((field2) => field2.trim()).filter(Boolean);
|
|
41723
41986
|
if (lines.some((line) => !/^(?:path|name|enabled)\s*=/.test(line)))
|
|
41724
41987
|
return null;
|
|
41725
41988
|
const keys2 = lines.map((line) => line.slice(0, line.indexOf("=")).trim());
|
|
@@ -41875,7 +42138,7 @@ function disableCodexBundledSkills(text2) {
|
|
|
41875
42138
|
}
|
|
41876
42139
|
|
|
41877
42140
|
// src/lib/agent-integration.ts
|
|
41878
|
-
var
|
|
42141
|
+
var sha4 = (data) => createHash18("sha256").update(data).digest("hex");
|
|
41879
42142
|
var ROOTS = NATIVE_SKILL_ROOTS;
|
|
41880
42143
|
function assertSafePath(path) {
|
|
41881
42144
|
let cursor = resolve15(path);
|
|
@@ -41982,7 +42245,7 @@ function readNativeBytes(path, maximum = 64 * 1024 * 1024) {
|
|
|
41982
42245
|
}
|
|
41983
42246
|
}
|
|
41984
42247
|
function treeHash(root2) {
|
|
41985
|
-
const hash2 =
|
|
42248
|
+
const hash2 = createHash18("sha256");
|
|
41986
42249
|
let bytes = 0, files = 0;
|
|
41987
42250
|
function visit2(path) {
|
|
41988
42251
|
const stat2 = lstatSync19(path);
|
|
@@ -42367,7 +42630,7 @@ function planAgentIntegration(options) {
|
|
|
42367
42630
|
const observedNativeSources = [];
|
|
42368
42631
|
const codexPluginSkills = options.codexNativeCatalog ? reviewCodexPluginSkillControls(options.codexNativeCatalog, nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor).map((entry) => join22(entry.path, "SKILL.md")), canonicalAgentPath(join22(home, ".codex/plugins/cache"), aliases), resolve15(options.projectDir ?? home), (path) => {
|
|
42369
42632
|
const bytes = readNativeBytes(path, 1024 * 1024);
|
|
42370
|
-
observedNativeSources.push({ path, sha256:
|
|
42633
|
+
observedNativeSources.push({ path, sha256: sha4(bytes) });
|
|
42371
42634
|
return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
42372
42635
|
}, codexConfig.skills?.config ?? []) : policy.bridge?.codexPluginSkills ?? [];
|
|
42373
42636
|
const changes = [];
|
|
@@ -42395,7 +42658,7 @@ function planAgentIntegration(options) {
|
|
|
42395
42658
|
throw new Error("Refusing to overwrite an unrecognized Hermes supervisor");
|
|
42396
42659
|
if (supervisorBefore !== supervisorAfter)
|
|
42397
42660
|
changes.push({ path: supervisorPath, before: supervisorBefore, after: supervisorAfter });
|
|
42398
|
-
const supervisor = { path: supervisorPath, runtime: process.execPath, sha256:
|
|
42661
|
+
const supervisor = { path: supervisorPath, runtime: process.execPath, sha256: sha4(supervisorAfter) };
|
|
42399
42662
|
const after2 = configureHermesHooks(before, supervisor, previous);
|
|
42400
42663
|
if (before !== after2)
|
|
42401
42664
|
changes.push({ path, before, after: after2 });
|
|
@@ -42442,12 +42705,12 @@ function planAgentIntegration(options) {
|
|
|
42442
42705
|
agents: [...new Set([...priorAgents, ...options.agents])].sort(),
|
|
42443
42706
|
home: resolve15(home),
|
|
42444
42707
|
includeVendor: true,
|
|
42445
|
-
...options.agents.includes("hermes") ? { supervisors: { ...policy.bridge?.supervisors, hermes: { path: join22(dataDir2, "agent-hooks", "hermes.js"), runtime: process.execPath, sha256:
|
|
42708
|
+
...options.agents.includes("hermes") ? { supervisors: { ...policy.bridge?.supervisors, hermes: { path: join22(dataDir2, "agent-hooks", "hermes.js"), runtime: process.execPath, sha256: sha4(renderHermesSupervisor(bindings.get("hermes").command, bindings.get("hermes").profileId)) } } } : {},
|
|
42446
42709
|
commands: { ...policy.bridge?.commands, ...Object.fromEntries([...bindings].map(([agent, binding]) => [agent, binding.command])) },
|
|
42447
42710
|
profiles: Object.fromEntries([...new Set([...priorAgents, ...options.agents])].sort().map((agent) => [agent, bindings.get(agent)?.profileId ?? policy.bridge?.profiles?.[agent] ?? policy.profileId])),
|
|
42448
42711
|
disabledBuiltins: options.agents.includes("codex") ? nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor && entry.path.startsWith(canonicalAgentPath(join22(home, ".codex", "skills", ".system"), aliases) + sep5)).map((entry) => ({ path: entry.path, hash: entry.hash })) : policy.bridge?.disabledBuiltins ?? [],
|
|
42449
42712
|
rootAliases: aliases,
|
|
42450
|
-
...codexPluginSkills.length ? { codexPluginSkills, codexPluginSkillReview: options.codexNativeCatalog ? { version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, catalogSha256:
|
|
42713
|
+
...codexPluginSkills.length ? { codexPluginSkills, codexPluginSkillReview: options.codexNativeCatalog ? { version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, catalogSha256: sha4(JSON.stringify({ version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, skills: projectCodexNativeSkillCatalog({ data: [{ cwd: options.codexNativeCatalog.cwd, errors: [], skills: options.codexNativeCatalog.skills }] }, options.codexNativeCatalog.cwd), ...options.codexNativeCatalog.plugins === undefined ? {} : { plugins: projectCodexInstalledPluginEntries(options.codexNativeCatalog.plugins) } })), configSha256: changes.find((change) => change.path === canonicalAgentPath(join22(home, ".codex/config.toml"), aliases))?.before === null ? null : sha4(readOptional(canonicalAgentPath(join22(home, ".codex/config.toml"), aliases)) ?? "") } : policy.bridge?.codexPluginSkillReview } : {},
|
|
42451
42714
|
discovery: { ...policy.bridge?.discovery, ...Object.fromEntries(discoveryAfter.map((binding) => [binding.agent, binding])) }
|
|
42452
42715
|
} };
|
|
42453
42716
|
const serializedPolicy = serializeManagedSkillPolicy(nextPolicy);
|
|
@@ -42463,12 +42726,12 @@ function planClaudePreToolUseHookUpdate(options) {
|
|
|
42463
42726
|
return planClaudeHookEventsUpdate({ ...options, events: ["PreToolUse"] });
|
|
42464
42727
|
}
|
|
42465
42728
|
function claudeSettingsConsumers(home, path, discoveries, aliases) {
|
|
42466
|
-
const
|
|
42729
|
+
const canonical6 = (value) => canonicalAgentPath(value, aliases);
|
|
42467
42730
|
const containsSettings = (root2) => {
|
|
42468
|
-
const distance = relative4(
|
|
42731
|
+
const distance = relative4(canonical6(root2), path);
|
|
42469
42732
|
return distance === "" || distance !== ".." && !distance.startsWith(`..${sep5}`) && !isAbsolute17(distance);
|
|
42470
42733
|
};
|
|
42471
|
-
return discoveries.filter((binding) => binding.agent === "claude" || binding.agent === "opencode" ||
|
|
42734
|
+
return discoveries.filter((binding) => binding.agent === "claude" || binding.agent === "opencode" || canonical6(join22(home, AGENT_ADAPTERS[binding.agent].config)) === path || binding.sources.some((source) => canonical6(source.path) === path) || binding.roots.some(containsSettings) || binding.directories?.some((directory) => containsSettings(directory.path))).map((binding) => binding.agent);
|
|
42472
42735
|
}
|
|
42473
42736
|
function verifyCoordinatedDiscovery(binding, home, aliases) {
|
|
42474
42737
|
try {
|
|
@@ -42500,7 +42763,7 @@ function planClaudeHookEventsUpdate(options) {
|
|
|
42500
42763
|
const path = canonicalAgentPath(join22(home, ".claude", "settings.json"), aliases);
|
|
42501
42764
|
assertSafePath(path);
|
|
42502
42765
|
const before = lstatSync19(path, { throwIfNoEntry: false }) ? new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(readNativeBytes(path, 1024 * 1024)) : null;
|
|
42503
|
-
if ((before === null ? "absent" :
|
|
42766
|
+
if ((before === null ? "absent" : sha4(before)) !== options.expectedSettingsSha256)
|
|
42504
42767
|
throw new Error("Claude settings preimage changed");
|
|
42505
42768
|
assertClaudeHookEventsReplacement(before, options.replacement, options.events);
|
|
42506
42769
|
const agents = bridge.agents;
|
|
@@ -42566,7 +42829,7 @@ function atomicWrite2(path, content) {
|
|
|
42566
42829
|
function planAgentSettingsWitnessUpgrade(options) {
|
|
42567
42830
|
const home = resolve15(options.home ?? homedir3()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
|
|
42568
42831
|
const snapshot2 = readManagedSkillPolicySnapshot(dataDir2);
|
|
42569
|
-
if (!snapshot2 ||
|
|
42832
|
+
if (!snapshot2 || sha4(snapshot2.text) !== options.expectedPolicySha256)
|
|
42570
42833
|
throw new Error("Managed policy preimage changed");
|
|
42571
42834
|
const policy = snapshot2.value, aliases = policy.bridge?.rootAliases ?? [];
|
|
42572
42835
|
recheckRootAliases(aliases);
|
|
@@ -42575,7 +42838,7 @@ function planAgentSettingsWitnessUpgrade(options) {
|
|
|
42575
42838
|
throw new Error("Settings witness upgrade requires an existing reviewed native binding");
|
|
42576
42839
|
const configPath = canonicalAgentPath(join22(home, options.agent === "claude" ? ".claude/settings.json" : ".codex/config.toml"), aliases);
|
|
42577
42840
|
const settings = readOptional(configPath);
|
|
42578
|
-
if (settings === null ||
|
|
42841
|
+
if (settings === null || sha4(settings) !== options.expectedSettingsSha256)
|
|
42579
42842
|
throw new Error("Native settings preimage changed");
|
|
42580
42843
|
const sources = binding.sources.filter((source) => source.path === configPath && source.format === undefined && source.fields === undefined);
|
|
42581
42844
|
if (sources.length !== 1)
|
|
@@ -42583,15 +42846,40 @@ function planAgentSettingsWitnessUpgrade(options) {
|
|
|
42583
42846
|
const previous = sources[0];
|
|
42584
42847
|
if (typeof previous.sha256 !== "string")
|
|
42585
42848
|
throw new Error("Settings witness upgrade requires a preserved settings preimage");
|
|
42849
|
+
const replaced = [previous];
|
|
42850
|
+
if (options.agent === "codex") {
|
|
42851
|
+
if (previous.hashMode !== undefined && previous.hashMode !== "bytes" && previous.hashMode !== "codex-settings-v1")
|
|
42852
|
+
throw new Error("Codex settings witness upgrade requires a preserved raw or codex-settings-v1 configuration witness");
|
|
42853
|
+
const preimage = readCodexSettingsPreimage(options.reviewedPreimage);
|
|
42854
|
+
for (const source of binding.sources) {
|
|
42855
|
+
if (source === previous || source.path !== configPath)
|
|
42856
|
+
continue;
|
|
42857
|
+
const fields2 = source.fields;
|
|
42858
|
+
if (source.hashMode !== undefined || source.format !== "toml" || !Array.isArray(fields2) || !isDeepStrictEqual5(fields2, [...CODEX_DISCOVERY_PROJECTION_FIELDS]) || typeof source.sha256 !== "string")
|
|
42859
|
+
throw new Error("Codex settings witness upgrade found an unrecognized configuration witness");
|
|
42860
|
+
if (projectNativeDiscoveryFields(preimage, "toml", fields2, configPath) !== source.sha256)
|
|
42861
|
+
throw new Error("Reviewed preimage does not explain the Codex discovery projection witness");
|
|
42862
|
+
replaced.push(source);
|
|
42863
|
+
}
|
|
42864
|
+
}
|
|
42586
42865
|
const next = options.agent === "claude" ? upgradeClaudeSettingsWitness(previous, options.reviewedPreimage) : upgradeCodexSettingsWitness(previous, options.reviewedPreimage);
|
|
42587
|
-
const
|
|
42866
|
+
const rebound = [];
|
|
42867
|
+
for (const source of binding.sources) {
|
|
42868
|
+
if (!replaced.includes(source)) {
|
|
42869
|
+
rebound.push(source);
|
|
42870
|
+
continue;
|
|
42871
|
+
}
|
|
42872
|
+
if (source === replaced[0])
|
|
42873
|
+
rebound.push(next);
|
|
42874
|
+
}
|
|
42875
|
+
const replacement = { ...binding, sources: rebound };
|
|
42588
42876
|
verifyAgentDiscovery(replacement);
|
|
42589
42877
|
const after = serializeManagedSkillPolicy({ ...policy, bridge: { ...policy.bridge, discovery: { ...policy.bridge.discovery, [options.agent]: replacement } } });
|
|
42590
|
-
return { dataDir: dataDir2, profileId: policy.profileId, changes: [{ path: join22(dataDir2, "agent-policy.json"), before: snapshot2.text, after }], nativeSkills: [], observedPolicy: { path: join22(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 } };
|
|
42878
|
+
return { dataDir: dataDir2, profileId: policy.profileId, changes: [{ path: join22(dataDir2, "agent-policy.json"), before: snapshot2.text, after }], nativeSkills: [], observedPolicy: { path: join22(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 })) } };
|
|
42591
42879
|
}
|
|
42592
42880
|
function applyAgentIntegration(plan) {
|
|
42593
42881
|
for (const source of plan.observedNativeSources ?? [])
|
|
42594
|
-
if (
|
|
42882
|
+
if (sha4(readNativeBytes(source.path, 1024 * 1024)) !== source.sha256)
|
|
42595
42883
|
throw new Error("Native identity source changed after planning");
|
|
42596
42884
|
if (plan.observedSettings && readOptional(plan.observedSettings.path) !== plan.observedSettings.before)
|
|
42597
42885
|
throw new Error("Native settings changed after witness planning");
|
|
@@ -42611,7 +42899,7 @@ function applyAgentIntegration(plan) {
|
|
|
42611
42899
|
const upgrade = plan.settingsWitnessUpgrade;
|
|
42612
42900
|
if (!plan.managedAgentChecks || !plan.observedPolicy?.before)
|
|
42613
42901
|
throw new Error("Invalid settings witness upgrade plan");
|
|
42614
|
-
const verified = planAgentSettingsWitnessUpgrade({ agent: upgrade.agent, reviewedPreimage: upgrade.reviewedPreimage, home: plan.managedAgentChecks.home, dataDir: plan.dataDir, expectedPolicySha256:
|
|
42902
|
+
const verified = planAgentSettingsWitnessUpgrade({ agent: upgrade.agent, reviewedPreimage: upgrade.reviewedPreimage, home: plan.managedAgentChecks.home, dataDir: plan.dataDir, expectedPolicySha256: sha4(plan.observedPolicy.before), expectedSettingsSha256: upgrade.currentSettingsSha256 });
|
|
42615
42903
|
if (JSON.stringify(verified.changes) !== JSON.stringify(plan.changes) || JSON.stringify(verified.settingsWitnessUpgrade) !== JSON.stringify(upgrade))
|
|
42616
42904
|
throw new Error("Settings witness upgrade plan changed");
|
|
42617
42905
|
provenDiscovery = verified.discoveryBefore[0];
|
|
@@ -42639,7 +42927,7 @@ function applyAgentIntegration(plan) {
|
|
|
42639
42927
|
chmodSync(backupRoot, 448);
|
|
42640
42928
|
for (const [index, change] of plan.changes.entries())
|
|
42641
42929
|
if (change.before !== null) {
|
|
42642
|
-
const backup = join22(backupRoot, `${index}-${
|
|
42930
|
+
const backup = join22(backupRoot, `${index}-${sha4(change.path).slice(0, 12)}.backup`);
|
|
42643
42931
|
writeFileSync4(backup, change.before, { mode: 384, flag: "wx" });
|
|
42644
42932
|
if (readFileSync14(backup, "utf8") !== change.before)
|
|
42645
42933
|
throw new Error("Native configuration preservation readback failed");
|
|
@@ -42658,7 +42946,7 @@ function applyAgentIntegration(plan) {
|
|
|
42658
42946
|
}
|
|
42659
42947
|
recheckRootAliases(aliases);
|
|
42660
42948
|
for (const source of plan.observedNativeSources ?? [])
|
|
42661
|
-
if (
|
|
42949
|
+
if (sha4(readNativeBytes(source.path, 1024 * 1024)) !== source.sha256)
|
|
42662
42950
|
throw new Error("Native identity source changed during application");
|
|
42663
42951
|
if (plan.observedSettings && readOptional(plan.observedSettings.path) !== plan.observedSettings.before)
|
|
42664
42952
|
throw new Error("Native settings changed during witness application");
|
|
@@ -42670,7 +42958,7 @@ function applyAgentIntegration(plan) {
|
|
|
42670
42958
|
}
|
|
42671
42959
|
for (const agent of plan.managedAgentChecks?.agents ?? [])
|
|
42672
42960
|
assertManagedAgentBridge(agent, { home: plan.managedAgentChecks.home, dataDir: plan.dataDir, projectDir: plan.managedAgentChecks.home });
|
|
42673
|
-
atomicWrite2(join22(backupRoot, "receipt.json"), JSON.stringify({ version: 1, changes: written.map((change) => ({ path: change.path, beforeHash: change.before === null ? null :
|
|
42961
|
+
atomicWrite2(join22(backupRoot, "receipt.json"), JSON.stringify({ version: 1, changes: written.map((change) => ({ path: change.path, beforeHash: change.before === null ? null : sha4(change.before), afterHash: sha4(change.after) })), backups, ...aliases.length ? { rootAliases: aliases } : {} }) + `
|
|
42674
42962
|
`);
|
|
42675
42963
|
} catch (error) {
|
|
42676
42964
|
for (const change of written.reverse()) {
|
|
@@ -42749,8 +43037,8 @@ function archiveNativeSkills(inventory, options) {
|
|
|
42749
43037
|
const operationId = randomUUID3(), archiveRoot = join22(options.dataDir ?? getDataDir(), "migration", operationId, "native"), receiptPath = join22(archiveRoot, "receipt.json");
|
|
42750
43038
|
const entries = selected.map((entry, index) => ({
|
|
42751
43039
|
source: entry.vendor ? join22(entry.path, "SKILL.md") : entry.path,
|
|
42752
|
-
archive: join22(archiveRoot, `${index}-${
|
|
42753
|
-
hash: entry.vendor ?
|
|
43040
|
+
archive: join22(archiveRoot, `${index}-${sha4(entry.path).slice(0, 12)}`),
|
|
43041
|
+
hash: entry.vendor ? sha4(readNativeBytes(join22(entry.path, "SKILL.md"))) : entry.hash,
|
|
42754
43042
|
...entry.vendor ? { discoveryOnly: true } : {},
|
|
42755
43043
|
status: "planned"
|
|
42756
43044
|
}));
|
|
@@ -42761,7 +43049,7 @@ function archiveNativeSkills(inventory, options) {
|
|
|
42761
43049
|
const stat2 = lstatSync19(entry.archive);
|
|
42762
43050
|
if (entry.discoveryOnly ? !stat2.isFile() : !stat2.isDirectory())
|
|
42763
43051
|
throw new Error("Archive type changed");
|
|
42764
|
-
if ((entry.discoveryOnly ?
|
|
43052
|
+
if ((entry.discoveryOnly ? sha4(readNativeBytes(entry.archive)) : treeHash(entry.archive)) !== entry.hash)
|
|
42765
43053
|
throw new Error("Archive bytes changed");
|
|
42766
43054
|
};
|
|
42767
43055
|
assertSafePath(archiveRoot);
|
|
@@ -42881,7 +43169,7 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
|
|
|
42881
43169
|
throw new Error("NATIVE_SKILL_DRIFT: the hook selection profile differs from its managed binding; restart the native client after reviewing skills hook install");
|
|
42882
43170
|
if (agent === "hermes") {
|
|
42883
43171
|
const supervisor = binding.supervisors?.hermes;
|
|
42884
|
-
if (supervisor?.path !== join22(dataDir2, "agent-hooks", "hermes.js") || supervisor?.sha256 !==
|
|
43172
|
+
if (supervisor?.path !== join22(dataDir2, "agent-hooks", "hermes.js") || supervisor?.sha256 !== sha4(renderHermesSupervisor(command, profile)))
|
|
42885
43173
|
throw new Error("NATIVE_SKILL_DRIFT: Hermes supervisor binding changed; run skills hook install");
|
|
42886
43174
|
assertHermesProtection(home, config, command, profile, supervisor);
|
|
42887
43175
|
} else if (agent === "opencode") {
|
|
@@ -42979,13 +43267,13 @@ import {
|
|
|
42979
43267
|
statSync as statSync9,
|
|
42980
43268
|
writeFileSync as writeFileSync6
|
|
42981
43269
|
} from "fs";
|
|
42982
|
-
import { basename as basename10, dirname as dirname18, isAbsolute as isAbsolute18, join as join26, normalize as
|
|
43270
|
+
import { basename as basename10, dirname as dirname18, isAbsolute as isAbsolute18, join as join26, normalize as normalize4, relative as relative6, resolve as resolve17, sep as sep8 } from "path";
|
|
42983
43271
|
|
|
42984
43272
|
// src/lib/registry-data/index.ts
|
|
42985
43273
|
var SKILLS = [];
|
|
42986
43274
|
|
|
42987
43275
|
// src/lib/skill-hash.ts
|
|
42988
|
-
import { createHash as
|
|
43276
|
+
import { createHash as createHash19 } from "crypto";
|
|
42989
43277
|
import { existsSync as existsSync7, readdirSync as readdirSync9, readFileSync as readFileSync15, statSync as statSync7 } from "fs";
|
|
42990
43278
|
import { join as join23, sep as sep6 } from "path";
|
|
42991
43279
|
var CONTENT_HASH_ALGORITHM = "sha256";
|
|
@@ -43109,13 +43397,13 @@ function* bundleHashParts(files) {
|
|
|
43109
43397
|
yield new TextEncoder().encode("\x00");
|
|
43110
43398
|
}
|
|
43111
43399
|
function hashBundleFiles(files) {
|
|
43112
|
-
const hash2 =
|
|
43400
|
+
const hash2 = createHash19(CONTENT_HASH_ALGORITHM);
|
|
43113
43401
|
for (const part of bundleHashParts(files))
|
|
43114
43402
|
hash2.update(part);
|
|
43115
43403
|
return hash2.digest("hex");
|
|
43116
43404
|
}
|
|
43117
43405
|
async function hashBundleFilesCooperatively(files, check) {
|
|
43118
|
-
const hash2 =
|
|
43406
|
+
const hash2 = createHash19(CONTENT_HASH_ALGORITHM);
|
|
43119
43407
|
let bytesSinceYield = 0;
|
|
43120
43408
|
for (const part of bundleHashParts(files)) {
|
|
43121
43409
|
for (let offset = 0;offset < part.byteLength; offset += 64 * 1024) {
|
|
@@ -43373,7 +43661,7 @@ var MAX_RUNTIME_TIMEOUT_SECONDS = 900;
|
|
|
43373
43661
|
function add2(target, code, message) {
|
|
43374
43662
|
target.push({ code, message });
|
|
43375
43663
|
}
|
|
43376
|
-
function
|
|
43664
|
+
function isRecord2(value) {
|
|
43377
43665
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
43378
43666
|
}
|
|
43379
43667
|
function isNonEmptyString(value) {
|
|
@@ -43401,7 +43689,7 @@ function validatePortableManifestContract(manifest, options = {}) {
|
|
|
43401
43689
|
}
|
|
43402
43690
|
validateRuntimeContract(manifest, issues, options.strict === true);
|
|
43403
43691
|
const provenance = manifest.provenance;
|
|
43404
|
-
if (provenance && !
|
|
43692
|
+
if (provenance && !isRecord2(provenance)) {
|
|
43405
43693
|
add2(issues, "contract.provenance_invalid", "provenance must be an object");
|
|
43406
43694
|
} else {
|
|
43407
43695
|
const sourceCommit = provenance?.source_commit;
|
|
@@ -43434,7 +43722,7 @@ function validateRuntimeContract(manifest, issues, strict) {
|
|
|
43434
43722
|
}
|
|
43435
43723
|
return;
|
|
43436
43724
|
}
|
|
43437
|
-
if (!
|
|
43725
|
+
if (!isRecord2(runtime)) {
|
|
43438
43726
|
add2(issues, "contract.runtime_invalid", "runtime must be an object");
|
|
43439
43727
|
return;
|
|
43440
43728
|
}
|
|
@@ -43721,7 +44009,7 @@ function readExistingSkillJson(skillPath) {
|
|
|
43721
44009
|
return {};
|
|
43722
44010
|
try {
|
|
43723
44011
|
const parsed = JSON.parse(readFileSync16(path, "utf-8"));
|
|
43724
|
-
return
|
|
44012
|
+
return isRecord3(parsed) ? parsed : {};
|
|
43725
44013
|
} catch {
|
|
43726
44014
|
return {};
|
|
43727
44015
|
}
|
|
@@ -43777,7 +44065,7 @@ function ensurePackageJson(skillPath, manifest) {
|
|
|
43777
44065
|
}
|
|
43778
44066
|
const existing = readJsonObject(pkgPath);
|
|
43779
44067
|
const bin = {};
|
|
43780
|
-
if (
|
|
44068
|
+
if (isRecord3(existing.bin)) {
|
|
43781
44069
|
for (const [name, value] of Object.entries(existing.bin)) {
|
|
43782
44070
|
if (typeof value === "string" && value.trim())
|
|
43783
44071
|
bin[normalizePortableSkillName(name)] = value.replace(/^\.\//, "");
|
|
@@ -43788,7 +44076,7 @@ function ensurePackageJson(skillPath, manifest) {
|
|
|
43788
44076
|
bin[manifest.name] = binEntry.replace(/^\.\//, "");
|
|
43789
44077
|
}
|
|
43790
44078
|
bin[commandName] = entry;
|
|
43791
|
-
const scripts =
|
|
44079
|
+
const scripts = isRecord3(existing.scripts) ? { ...existing.scripts } : {};
|
|
43792
44080
|
if (!stringValue(scripts.dev))
|
|
43793
44081
|
scripts.dev = `bun run ${entry}`;
|
|
43794
44082
|
writeFileSync5(pkgPath, `${JSON.stringify({
|
|
@@ -44009,7 +44297,7 @@ function parseManifestCommands(value) {
|
|
|
44009
44297
|
if (!Array.isArray(raw))
|
|
44010
44298
|
return;
|
|
44011
44299
|
const commands = raw.map((item) => {
|
|
44012
|
-
if (!
|
|
44300
|
+
if (!isRecord3(item))
|
|
44013
44301
|
return null;
|
|
44014
44302
|
const name = stringValue(item.name);
|
|
44015
44303
|
if (!name)
|
|
@@ -44026,7 +44314,7 @@ function parseManifestCommands(value) {
|
|
|
44026
44314
|
}
|
|
44027
44315
|
function parseManifestRuntime(value) {
|
|
44028
44316
|
const raw = value?.runtime;
|
|
44029
|
-
if (!
|
|
44317
|
+
if (!isRecord3(raw))
|
|
44030
44318
|
return;
|
|
44031
44319
|
const runtimeName = stringValue(raw.runtime);
|
|
44032
44320
|
if (!runtimeName)
|
|
@@ -44052,7 +44340,7 @@ function parseManifestRuntime(value) {
|
|
|
44052
44340
|
}
|
|
44053
44341
|
function parseManifestProvenance(value) {
|
|
44054
44342
|
const raw = value?.provenance;
|
|
44055
|
-
if (!
|
|
44343
|
+
if (!isRecord3(raw))
|
|
44056
44344
|
return;
|
|
44057
44345
|
const parsed = {};
|
|
44058
44346
|
if (stringValue(raw.source_commit))
|
|
@@ -44068,7 +44356,7 @@ function parseManifestInputs(value) {
|
|
|
44068
44356
|
if (!Array.isArray(raw))
|
|
44069
44357
|
return;
|
|
44070
44358
|
const inputs = raw.map((item) => {
|
|
44071
|
-
if (!
|
|
44359
|
+
if (!isRecord3(item))
|
|
44072
44360
|
return null;
|
|
44073
44361
|
const name = stringValue(item.name);
|
|
44074
44362
|
const type = stringValue(item.type);
|
|
@@ -44086,7 +44374,7 @@ function parseManifestInputs(value) {
|
|
|
44086
44374
|
function inferPackageCommands(pkg, fallbackName) {
|
|
44087
44375
|
if (!pkg)
|
|
44088
44376
|
return;
|
|
44089
|
-
if (
|
|
44377
|
+
if (isRecord3(pkg.bin)) {
|
|
44090
44378
|
const commands = Object.entries(pkg.bin).filter((entry) => typeof entry[1] === "string" && entry[1].trim().length > 0).map(([name, entry]) => ({
|
|
44091
44379
|
name: normalizePortableSkillName(name),
|
|
44092
44380
|
entry: entry.replace(/^\.\//, ""),
|
|
@@ -44095,7 +44383,7 @@ function inferPackageCommands(pkg, fallbackName) {
|
|
|
44095
44383
|
if (commands.length)
|
|
44096
44384
|
return commands;
|
|
44097
44385
|
}
|
|
44098
|
-
const scripts =
|
|
44386
|
+
const scripts = isRecord3(pkg.scripts) ? pkg.scripts : undefined;
|
|
44099
44387
|
const dev = stringValue(scripts?.dev);
|
|
44100
44388
|
const match = dev?.match(/(?:bun\s+run\s+|bun\s+)([^ ]+)/);
|
|
44101
44389
|
if (match?.[1]) {
|
|
@@ -44111,20 +44399,20 @@ function inferRuntimeFromCommands(commands) {
|
|
|
44111
44399
|
}
|
|
44112
44400
|
function readJsonObject(path) {
|
|
44113
44401
|
const parsed = JSON.parse(readFileSync16(path, "utf-8"));
|
|
44114
|
-
if (!
|
|
44402
|
+
if (!isRecord3(parsed))
|
|
44115
44403
|
throw new Error(`${basename8(path)} must contain a JSON object`);
|
|
44116
44404
|
return parsed;
|
|
44117
44405
|
}
|
|
44118
44406
|
function hasPackageDependencies(pkgPath) {
|
|
44119
44407
|
try {
|
|
44120
44408
|
const pkg = readJsonObject(pkgPath);
|
|
44121
|
-
const deps =
|
|
44409
|
+
const deps = isRecord3(pkg.dependencies) ? Object.keys(pkg.dependencies) : [];
|
|
44122
44410
|
return deps.length > 0;
|
|
44123
44411
|
} catch {
|
|
44124
44412
|
return false;
|
|
44125
44413
|
}
|
|
44126
44414
|
}
|
|
44127
|
-
function
|
|
44415
|
+
function isRecord3(value) {
|
|
44128
44416
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
44129
44417
|
}
|
|
44130
44418
|
function stringField(value, key) {
|
|
@@ -44339,7 +44627,7 @@ function scaffoldPortableSkill(name, options = {}) {
|
|
|
44339
44627
|
return { name: skillName, path: skillPath, manifest, created: true };
|
|
44340
44628
|
}
|
|
44341
44629
|
function portPortableSkillDirectory(sourceDir, options = {}) {
|
|
44342
|
-
const absoluteSource =
|
|
44630
|
+
const absoluteSource = normalize4(sourceDir);
|
|
44343
44631
|
if (!existsSync9(absoluteSource) || !statSync9(absoluteSource).isDirectory()) {
|
|
44344
44632
|
throw new Error(`Import directory not found: ${sourceDir}`);
|
|
44345
44633
|
}
|
|
@@ -44406,7 +44694,7 @@ function assertDisjointImportPaths(source, destination) {
|
|
|
44406
44694
|
}
|
|
44407
44695
|
}
|
|
44408
44696
|
function portPortableSkill(sourcePath, options = {}) {
|
|
44409
|
-
const absoluteSource =
|
|
44697
|
+
const absoluteSource = normalize4(sourcePath);
|
|
44410
44698
|
if (!existsSync9(absoluteSource) || !statSync9(absoluteSource).isDirectory()) {
|
|
44411
44699
|
throw new Error(`Skill source directory not found: ${sourcePath}`);
|
|
44412
44700
|
}
|
|
@@ -44682,7 +44970,7 @@ function safeIsDirectory(path) {
|
|
|
44682
44970
|
function isSafeRelativePath2(value) {
|
|
44683
44971
|
if (!value.trim() || isAbsolute18(value))
|
|
44684
44972
|
return false;
|
|
44685
|
-
const normalized =
|
|
44973
|
+
const normalized = normalize4(value).replace(/\\/g, "/");
|
|
44686
44974
|
return normalized !== ".." && !normalized.startsWith("../") && !normalized.includes("/../");
|
|
44687
44975
|
}
|
|
44688
44976
|
function add3(target, code, message) {
|
|
@@ -46333,7 +46621,7 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
46333
46621
|
selection: selection2,
|
|
46334
46622
|
target: "local",
|
|
46335
46623
|
runtime: runtimeName,
|
|
46336
|
-
inputDigest: `sha256:${
|
|
46624
|
+
inputDigest: `sha256:${createHash20("sha256").update(input).digest("hex")}`,
|
|
46337
46625
|
runDirectory,
|
|
46338
46626
|
...executionGrant ? { executionGrant } : {},
|
|
46339
46627
|
...bindings ? { secretBinding: { schema: bindings.schema, selection: bindings.selection, consumer: bindings.consumer, secretsAuthority: bindings.secretsAuthority, bindings: bindings.bindings } } : {},
|
|
@@ -46391,7 +46679,7 @@ async function subprocess(command, cwd, env, input, timeoutMs) {
|
|
|
46391
46679
|
// src/lib/remote-run-contract.ts
|
|
46392
46680
|
var REMOTE_SKILL_RUN_CONTRACT_VERSION = 1;
|
|
46393
46681
|
function normalizeRemoteSkillRunContract(payload, fallbackSkill) {
|
|
46394
|
-
const record3 =
|
|
46682
|
+
const record3 = isRecord4(payload) ? payload : {};
|
|
46395
46683
|
return {
|
|
46396
46684
|
contractVersion: REMOTE_SKILL_RUN_CONTRACT_VERSION,
|
|
46397
46685
|
...pickString(record3, "id"),
|
|
@@ -46413,7 +46701,7 @@ function normalizeRemoteSkillRunContract(payload, fallbackSkill) {
|
|
|
46413
46701
|
...hasOwn(record3, "details") ? { details: record3.details } : {}
|
|
46414
46702
|
};
|
|
46415
46703
|
}
|
|
46416
|
-
function
|
|
46704
|
+
function isRecord4(value) {
|
|
46417
46705
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
46418
46706
|
}
|
|
46419
46707
|
function hasOwn(record3, key) {
|
|
@@ -55623,7 +55911,7 @@ var import_node_http_handler2 = __toESM(require_dist_cjs6(), 1);
|
|
|
55623
55911
|
|
|
55624
55912
|
// node_modules/@aws-sdk/checksums/dist-cjs/submodules/sha/index.js
|
|
55625
55913
|
var { toUint8Array: toUint8Array2, concatBytes } = require_serde();
|
|
55626
|
-
var { createHmac: createHmac2, createHash:
|
|
55914
|
+
var { createHmac: createHmac2, createHash: createHash22 } = __require("crypto");
|
|
55627
55915
|
var { Sha256: Sha2562, Sha256Js, Sha256Node } = require_checksum();
|
|
55628
55916
|
var BLOCK2 = 64;
|
|
55629
55917
|
var DIGEST_LENGTH = 20;
|
|
@@ -55792,7 +56080,7 @@ class Sha1Js {
|
|
|
55792
56080
|
}
|
|
55793
56081
|
var hasNativeCrypto = (() => {
|
|
55794
56082
|
try {
|
|
55795
|
-
|
|
56083
|
+
createHash22("sha1");
|
|
55796
56084
|
return true;
|
|
55797
56085
|
} catch {
|
|
55798
56086
|
return false;
|
|
@@ -55832,7 +56120,7 @@ function buildNativeClass() {
|
|
|
55832
56120
|
this.finished = false;
|
|
55833
56121
|
}
|
|
55834
56122
|
createHash() {
|
|
55835
|
-
return this.secret ? createHmac2("sha1", toBuffer(this.secret)) :
|
|
56123
|
+
return this.secret ? createHmac2("sha1", toBuffer(this.secret)) : createHash22("sha1");
|
|
55836
56124
|
}
|
|
55837
56125
|
};
|
|
55838
56126
|
}
|
|
@@ -56700,9 +56988,9 @@ import { mkdirSync as mkdirSync11, readFileSync as readFileSync23, readdirSync a
|
|
|
56700
56988
|
import { dirname as dirname23, join as join36 } from "path";
|
|
56701
56989
|
|
|
56702
56990
|
// src/server/auth.ts
|
|
56703
|
-
import { createHash as
|
|
56991
|
+
import { createHash as createHash23 } from "crypto";
|
|
56704
56992
|
function hashApiKey(token) {
|
|
56705
|
-
return
|
|
56993
|
+
return createHash23("sha256").update(token).digest("hex");
|
|
56706
56994
|
}
|
|
56707
56995
|
function bearerToken(request2) {
|
|
56708
56996
|
const header = request2.headers.get("authorization") || "";
|
|
@@ -57024,7 +57312,7 @@ function validOperatorScopeEnrollmentInput(input) {
|
|
|
57024
57312
|
}
|
|
57025
57313
|
|
|
57026
57314
|
// src/lib/revision.ts
|
|
57027
|
-
import { createHash as
|
|
57315
|
+
import { createHash as createHash24 } from "crypto";
|
|
57028
57316
|
var REVISION_ID_PATTERN = /^[0-9a-f]{64}$/;
|
|
57029
57317
|
function revisionIdOf(content) {
|
|
57030
57318
|
const canonicalContent = {
|
|
@@ -57045,8 +57333,8 @@ function revisionIdOf(content) {
|
|
|
57045
57333
|
canonicalContent.archiveReason = content.archiveReason ?? null;
|
|
57046
57334
|
canonicalContent.replacementSlug = content.replacementSlug ?? null;
|
|
57047
57335
|
}
|
|
57048
|
-
const
|
|
57049
|
-
return
|
|
57336
|
+
const canonical6 = JSON.stringify(canonicalContent);
|
|
57337
|
+
return createHash24("sha256").update(canonical6).digest("hex");
|
|
57050
57338
|
}
|
|
57051
57339
|
function revisionIdOfRecord(record3) {
|
|
57052
57340
|
return revisionIdOf(record3);
|
|
@@ -58130,7 +58418,7 @@ function nextMonthPrefix(monthPrefix) {
|
|
|
58130
58418
|
}
|
|
58131
58419
|
|
|
58132
58420
|
// src/server/skills-api.ts
|
|
58133
|
-
import { createHash as
|
|
58421
|
+
import { createHash as createHash25 } from "crypto";
|
|
58134
58422
|
var SLUG_PATTERN = /^[a-z0-9][a-z0-9._-]*$/;
|
|
58135
58423
|
var SHA256_HEX2 = /^[0-9a-f]{64}$/;
|
|
58136
58424
|
var MAX_SLUG_LENGTH = 128;
|
|
@@ -58320,7 +58608,7 @@ async function parsePublishRequest(request2, config) {
|
|
|
58320
58608
|
if (bundleBytes.byteLength === 0) {
|
|
58321
58609
|
throw new SkillRequestError(400, "BUNDLE_EMPTY", "the uploaded bundle is empty");
|
|
58322
58610
|
}
|
|
58323
|
-
const sha2562 =
|
|
58611
|
+
const sha2562 = createHash25("sha256").update(bundleBytes).digest("hex");
|
|
58324
58612
|
const claimed = optionalString(manifest.bundleSha256);
|
|
58325
58613
|
if (claimed)
|
|
58326
58614
|
assertSha2562(claimed);
|
|
@@ -58435,7 +58723,7 @@ async function readPublishedBundle(store, artifactStorage, principal, slug) {
|
|
|
58435
58723
|
if (!bytes) {
|
|
58436
58724
|
throw new SkillRequestError(503, "BUNDLE_BACKEND_UNAVAILABLE", "bundle storage backend unavailable");
|
|
58437
58725
|
}
|
|
58438
|
-
const actual =
|
|
58726
|
+
const actual = createHash25("sha256").update(bytes).digest("hex");
|
|
58439
58727
|
if (actual !== record3.bundleSha256) {
|
|
58440
58728
|
throw new SkillRequestError(500, "BUNDLE_DIGEST_DRIFT", `stored bundle for '${slug}' hashes to ${actual} but was published as ${record3.bundleSha256}`);
|
|
58441
58729
|
}
|
|
@@ -58583,7 +58871,7 @@ async function readSkillVersionBundle(store, artifactStorage, principal, slug, v
|
|
|
58583
58871
|
const bytes = await artifactStorage.readBundle(bundle2);
|
|
58584
58872
|
if (!bytes)
|
|
58585
58873
|
throw new SkillRequestError(503, "BUNDLE_BACKEND_UNAVAILABLE", "bundle storage backend unavailable");
|
|
58586
|
-
const actual =
|
|
58874
|
+
const actual = createHash25("sha256").update(bytes).digest("hex");
|
|
58587
58875
|
if (actual !== found.bundleSha256) {
|
|
58588
58876
|
throw new SkillRequestError(500, "BUNDLE_DIGEST_DRIFT", `stored bundle for '${slug}@${version2}' hashes to ${actual} but was published as ${found.bundleSha256}`);
|
|
58589
58877
|
}
|
|
@@ -59286,7 +59574,7 @@ class RuntimeExecutionStore {
|
|
|
59286
59574
|
}
|
|
59287
59575
|
|
|
59288
59576
|
// src/sdk/execution/admission.ts
|
|
59289
|
-
import { createHash as
|
|
59577
|
+
import { createHash as createHash27 } from "crypto";
|
|
59290
59578
|
|
|
59291
59579
|
// src/sdk/execution/image-profile.ts
|
|
59292
59580
|
class ImageProfileResolutionError extends Error {
|
|
@@ -59898,11 +60186,11 @@ function ownedAdmission(admission) {
|
|
|
59898
60186
|
};
|
|
59899
60187
|
}
|
|
59900
60188
|
function digestInput(input) {
|
|
59901
|
-
return
|
|
60189
|
+
return createHash27("sha256").update(canonicalJson2(input)).digest("hex");
|
|
59902
60190
|
}
|
|
59903
60191
|
|
|
59904
60192
|
// src/sdk/execution/dispatchers/ecs.ts
|
|
59905
|
-
import { createHash as
|
|
60193
|
+
import { createHash as createHash28 } from "crypto";
|
|
59906
60194
|
|
|
59907
60195
|
// src/sdk/execution/state-machine.ts
|
|
59908
60196
|
var LEGAL_TRANSITIONS = {
|
|
@@ -63302,13 +63590,13 @@ function observedTask(states, taskArn) {
|
|
|
63302
63590
|
return state2.lastStatus === "STOPPED" || LIVE_TASK_STATUSES.has(state2.lastStatus) ? state2 : undefined;
|
|
63303
63591
|
}
|
|
63304
63592
|
function clientTokenFor(runId3, attemptId) {
|
|
63305
|
-
return
|
|
63593
|
+
return createHash28("sha256").update(`${runId3}\x00${attemptId}`).digest("hex").slice(0, CLIENT_TOKEN_BYTES * 2);
|
|
63306
63594
|
}
|
|
63307
63595
|
function startedByFor(runId3, attemptNumber) {
|
|
63308
63596
|
return `skills-exec/${runId3}/a${attemptNumber}`;
|
|
63309
63597
|
}
|
|
63310
63598
|
function requestDigestFor(admission, attemptId) {
|
|
63311
|
-
return
|
|
63599
|
+
return createHash28("sha256").update(canonicalJson2({ admission, attemptId })).digest("hex");
|
|
63312
63600
|
}
|
|
63313
63601
|
|
|
63314
63602
|
class EcsDispatcher {
|
|
@@ -63604,10 +63892,10 @@ function validText(value) {
|
|
|
63604
63892
|
}
|
|
63605
63893
|
|
|
63606
63894
|
// src/server/runtime-policy.ts
|
|
63607
|
-
import { createHash as
|
|
63895
|
+
import { createHash as createHash30, createHmac as createHmac3, timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
63608
63896
|
|
|
63609
63897
|
// src/server/runtime-pure-contract.ts
|
|
63610
|
-
import { createHash as
|
|
63898
|
+
import { createHash as createHash29 } from "crypto";
|
|
63611
63899
|
var PURE_DESCRIPTOR = Object.freeze({
|
|
63612
63900
|
id: "regex-test.v1",
|
|
63613
63901
|
runtime: "bun",
|
|
@@ -63631,7 +63919,7 @@ var PURE_LIMITS = Object.freeze({
|
|
|
63631
63919
|
maxArtifactsBytes: 0,
|
|
63632
63920
|
maxConcurrency: 1
|
|
63633
63921
|
});
|
|
63634
|
-
var hash2 = (bytes) =>
|
|
63922
|
+
var hash2 = (bytes) => createHash29("sha256").update(bytes).digest("hex");
|
|
63635
63923
|
var object6 = (v2) => {
|
|
63636
63924
|
if (!v2 || typeof v2 !== "object" || Array.isArray(v2))
|
|
63637
63925
|
throw Error("Pure contract requires an object");
|
|
@@ -63860,7 +64148,7 @@ function verifyRuntimeToken(token, key, admission, attempt, now = Date.now()) {
|
|
|
63860
64148
|
const actual = Buffer.from(token);
|
|
63861
64149
|
return actual.length === expected.length && timingSafeEqual2(actual, expected);
|
|
63862
64150
|
}
|
|
63863
|
-
var hashBytes = (bytes) =>
|
|
64151
|
+
var hashBytes = (bytes) => createHash30("sha256").update(bytes).digest("hex");
|
|
63864
64152
|
|
|
63865
64153
|
// src/server/runtime-api.ts
|
|
63866
64154
|
async function createRuntimeService(options) {
|
|
@@ -66048,7 +66336,7 @@ async function readJson(request2, limitBytes) {
|
|
|
66048
66336
|
if (!text2.trim())
|
|
66049
66337
|
return {};
|
|
66050
66338
|
const parsed = JSON.parse(text2);
|
|
66051
|
-
return
|
|
66339
|
+
return isRecord5(parsed) ? parsed : {};
|
|
66052
66340
|
}
|
|
66053
66341
|
function pathSegments(pathname) {
|
|
66054
66342
|
return pathname.split("/").filter(Boolean).map(decodeSegment);
|
|
@@ -66069,7 +66357,7 @@ function json4(payload, init = {}) {
|
|
|
66069
66357
|
headers: { "Cache-Control": "no-store", ...init.headers }
|
|
66070
66358
|
});
|
|
66071
66359
|
}
|
|
66072
|
-
function
|
|
66360
|
+
function isRecord5(value) {
|
|
66073
66361
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
66074
66362
|
}
|
|
66075
66363
|
function clampInt(value, fallback, max) {
|
|
@@ -70232,7 +70520,7 @@ var localRunExecutor = {
|
|
|
70232
70520
|
// src/sdk/storage.ts
|
|
70233
70521
|
var artifactStorageSeam = ArtifactStorage;
|
|
70234
70522
|
// src/sdk/outputs.ts
|
|
70235
|
-
import { createHash as
|
|
70523
|
+
import { createHash as createHash31 } from "crypto";
|
|
70236
70524
|
class DatabaseOnlyObjectStore {
|
|
70237
70525
|
usesS3 = false;
|
|
70238
70526
|
async materialize(run, artifact, body4) {
|
|
@@ -70279,7 +70567,7 @@ function createGovernedArtifactWriter(options) {
|
|
|
70279
70567
|
const stamped = {
|
|
70280
70568
|
...meta,
|
|
70281
70569
|
byteSize: outputBytes,
|
|
70282
|
-
sha256:
|
|
70570
|
+
sha256: createHash31("sha256").update(persistedBytes).digest("hex"),
|
|
70283
70571
|
visibility: options.visibility ?? config.defaultVisibility,
|
|
70284
70572
|
...config.artifactTtlSeconds !== undefined ? { expiresAt: expiresAtFor(createdAt, config.artifactTtlSeconds) } : {}
|
|
70285
70573
|
};
|
|
@@ -73750,15 +74038,15 @@ var $ZodDate = /* @__PURE__ */ $constructor("$ZodDate", (inst, def) => {
|
|
|
73750
74038
|
} catch (_err) {}
|
|
73751
74039
|
}
|
|
73752
74040
|
const input = payload.value;
|
|
73753
|
-
const
|
|
73754
|
-
const isValidDate =
|
|
74041
|
+
const isDate2 = input instanceof Date;
|
|
74042
|
+
const isValidDate = isDate2 && !Number.isNaN(input.getTime());
|
|
73755
74043
|
if (isValidDate)
|
|
73756
74044
|
return payload;
|
|
73757
74045
|
payload.issues.push({
|
|
73758
74046
|
expected: "date",
|
|
73759
74047
|
code: "invalid_type",
|
|
73760
74048
|
input,
|
|
73761
|
-
...
|
|
74049
|
+
...isDate2 ? { received: "Invalid Date" } : {},
|
|
73762
74050
|
inst
|
|
73763
74051
|
});
|
|
73764
74052
|
return payload;
|
|
@@ -89046,7 +89334,7 @@ function date4(params) {
|
|
|
89046
89334
|
return _coercedDate(ZodDate2, params);
|
|
89047
89335
|
}
|
|
89048
89336
|
// src/lib/canonical-json.ts
|
|
89049
|
-
import { createHash as
|
|
89337
|
+
import { createHash as createHash32 } from "crypto";
|
|
89050
89338
|
function canonicalJson3(value, maximumBytes = 2 * 1024 * 1024) {
|
|
89051
89339
|
return canonicalJsonAtDepth(value, maximumBytes, 64);
|
|
89052
89340
|
}
|
|
@@ -89090,7 +89378,7 @@ function canonicalJsonAtDepth(value, maximumBytes, maximumDepth) {
|
|
|
89090
89378
|
return visit3(value, 0);
|
|
89091
89379
|
}
|
|
89092
89380
|
function canonicalJsonSha256(value, maximumBytes) {
|
|
89093
|
-
return
|
|
89381
|
+
return createHash32("sha256").update(canonicalJson3(value, maximumBytes)).digest("hex");
|
|
89094
89382
|
}
|
|
89095
89383
|
|
|
89096
89384
|
// src/lib/remote-recurring-contract.ts
|
|
@@ -89956,7 +90244,7 @@ function creditCheckoutFailure(value, status, key) {
|
|
|
89956
90244
|
|
|
89957
90245
|
// src/lib/remote-profile.ts
|
|
89958
90246
|
function customerNamePatch(input2, field2) {
|
|
89959
|
-
if (!
|
|
90247
|
+
if (!isRecord6(input2) || Object.keys(input2).length !== 1 || !Object.hasOwn(input2, field2))
|
|
89960
90248
|
throw new Error("Provide only the requested name field.");
|
|
89961
90249
|
const value = input2[field2];
|
|
89962
90250
|
if (typeof value !== "string" || /[\p{Cc}\p{Cs}\u2028\u2029]/u.test(value) || !value.trim() || [...value.trim()].length > 100) {
|
|
@@ -89964,22 +90252,22 @@ function customerNamePatch(input2, field2) {
|
|
|
89964
90252
|
}
|
|
89965
90253
|
return { [field2]: value.trim() };
|
|
89966
90254
|
}
|
|
89967
|
-
function
|
|
90255
|
+
function isRecord6(value) {
|
|
89968
90256
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
89969
90257
|
}
|
|
89970
90258
|
function string4(value) {
|
|
89971
90259
|
return typeof value === "string" && value.length > 0;
|
|
89972
90260
|
}
|
|
89973
90261
|
function parseUpdatedProfile(value) {
|
|
89974
|
-
const user =
|
|
89975
|
-
if (!
|
|
90262
|
+
const user = isRecord6(value) && value.user;
|
|
90263
|
+
if (!isRecord6(user) || !string4(user.id) || !string4(user.email) || !(user.displayName === null || typeof user.displayName === "string") || typeof user.role !== "string" || !["owner", "admin", "member", "viewer"].includes(user.role)) {
|
|
89976
90264
|
throw new Error("The server returned an invalid account profile.");
|
|
89977
90265
|
}
|
|
89978
90266
|
return { user: { id: user.id, email: user.email, displayName: user.displayName, role: user.role } };
|
|
89979
90267
|
}
|
|
89980
90268
|
function parseUpdatedWorkspace(value) {
|
|
89981
|
-
const organization2 =
|
|
89982
|
-
if (!
|
|
90269
|
+
const organization2 = isRecord6(value) && value.organization;
|
|
90270
|
+
if (!isRecord6(organization2) || !string4(organization2.id) || !string4(organization2.slug) || !string4(organization2.name)) {
|
|
89983
90271
|
throw new Error("The server returned an invalid workspace.");
|
|
89984
90272
|
}
|
|
89985
90273
|
return { organization: { id: organization2.id, slug: organization2.slug, name: organization2.name } };
|
|
@@ -91204,7 +91492,7 @@ async function requestInvitationEmail(origin, action, input2) {
|
|
|
91204
91492
|
}
|
|
91205
91493
|
|
|
91206
91494
|
// src/lib/remote-private-publications.ts
|
|
91207
|
-
import { createHash as
|
|
91495
|
+
import { createHash as createHash33 } from "crypto";
|
|
91208
91496
|
var PRIVATE_PUBLICATION_MAX_BYTES = 16 * 1024 * 1024;
|
|
91209
91497
|
var failures2 = {
|
|
91210
91498
|
INVALID_REQUEST: [400, "The publication request is invalid."],
|
|
@@ -91251,7 +91539,7 @@ var hash4 = (v2) => typeof v2 === "string" && /^[a-f0-9]{64}$/.test(v2);
|
|
|
91251
91539
|
var record9 = (v2) => !!v2 && typeof v2 === "object" && !Array.isArray(v2);
|
|
91252
91540
|
var exact = (v2, keys3) => record9(v2) && Object.keys(v2).sort().join(",") === keys3.sort().join(",");
|
|
91253
91541
|
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));
|
|
91254
|
-
var publicationSha256 = (bytes) =>
|
|
91542
|
+
var publicationSha256 = (bytes) => createHash33("sha256").update(bytes).digest("hex");
|
|
91255
91543
|
function checkedPublicationDeclaration(value) {
|
|
91256
91544
|
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)
|
|
91257
91545
|
return bad();
|
|
@@ -91550,7 +91838,7 @@ async function requestAuthApi(instance, path2, options) {
|
|
|
91550
91838
|
const text3 = await res.text();
|
|
91551
91839
|
const body4 = text3 ? parseJsonBody(text3) : {};
|
|
91552
91840
|
if (!res.ok) {
|
|
91553
|
-
const record10 =
|
|
91841
|
+
const record10 = isRecord7(body4) ? body4 : {};
|
|
91554
91842
|
const detail = typeof record10.detail === "string" ? record10.detail : undefined;
|
|
91555
91843
|
const error61 = typeof record10.error === "string" ? record10.error : undefined;
|
|
91556
91844
|
const code = typeof record10.code === "string" ? record10.code : undefined;
|
|
@@ -91578,7 +91866,7 @@ function condenseErrorBody(text3) {
|
|
|
91578
91866
|
return collapsed;
|
|
91579
91867
|
return `${collapsed.slice(0, MAX_ERROR_DETAIL_LENGTH - 1).trimEnd()}\u2026`;
|
|
91580
91868
|
}
|
|
91581
|
-
function
|
|
91869
|
+
function isRecord7(value) {
|
|
91582
91870
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
91583
91871
|
}
|
|
91584
91872
|
|
|
@@ -92086,16 +92374,16 @@ function resultSnapshot(input2, requestId) {
|
|
|
92086
92374
|
const value = snapshot2(input2, SKILL_OPERATION_LIMITS.resultBytes).value;
|
|
92087
92375
|
if (!record10(value) || value.contractVersion !== 1 || value.requestId !== requestId)
|
|
92088
92376
|
throw Error();
|
|
92089
|
-
const
|
|
92377
|
+
const fields2 = ["contractVersion", "requestId", "status"];
|
|
92090
92378
|
if (value.status === "succeeded")
|
|
92091
|
-
|
|
92379
|
+
fields2.push("output");
|
|
92092
92380
|
else if (value.status === "refused") {
|
|
92093
|
-
|
|
92381
|
+
fields2.push("code");
|
|
92094
92382
|
if (!refusalCodes.has(value.code))
|
|
92095
92383
|
throw Error();
|
|
92096
92384
|
} else if (!["not-executed", "pending", "unknown"].includes(value.status))
|
|
92097
92385
|
throw Error();
|
|
92098
|
-
if (!exact2(value,
|
|
92386
|
+
if (!exact2(value, fields2))
|
|
92099
92387
|
throw Error();
|
|
92100
92388
|
return value;
|
|
92101
92389
|
} catch {
|