@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/bin/index.js
CHANGED
|
@@ -36868,7 +36868,7 @@ var package_default;
|
|
|
36868
36868
|
var init_package = __esm(() => {
|
|
36869
36869
|
package_default = {
|
|
36870
36870
|
name: "@hasna/skills",
|
|
36871
|
-
version: "0.10.
|
|
36871
|
+
version: "0.10.23",
|
|
36872
36872
|
description: "Skills library for AI coding agents",
|
|
36873
36873
|
type: "module",
|
|
36874
36874
|
bin: {
|
|
@@ -39931,12 +39931,16 @@ function assertAgentPolicyCollections(policy) {
|
|
|
39931
39931
|
}
|
|
39932
39932
|
if (bridge.codexPluginSkills !== undefined)
|
|
39933
39933
|
for (const control of array(bridge.codexPluginSkills, 4096)) {
|
|
39934
|
-
requireBound(object(control) && Object.keys(control).every((key) => ["name", "pluginId", "namespace", "pluginParent", "manifestSha256", "appSha256"].includes(key)));
|
|
39934
|
+
requireBound(object(control) && Object.keys(control).every((key) => ["name", "pluginId", "namespace", "pluginParent", "manifestSha256", "appSha256", "mcpSha256", "remotePluginId"].includes(key)));
|
|
39935
39935
|
text(control.name, 129);
|
|
39936
39936
|
text(control.pluginId, 1024);
|
|
39937
39937
|
text(control.namespace, 64);
|
|
39938
39938
|
text(control.pluginParent);
|
|
39939
39939
|
requireBound(isAbsolute2(control.pluginParent) && resolve3(control.pluginParent) === control.pluginParent && /^[a-f0-9]{64}$/.test(control.manifestSha256));
|
|
39940
|
+
if (control.remotePluginId !== undefined)
|
|
39941
|
+
requireBound(typeof control.remotePluginId === "string" && /^[A-Za-z0-9_~-]{1,1024}$/.test(control.remotePluginId));
|
|
39942
|
+
if (control.mcpSha256 !== undefined)
|
|
39943
|
+
requireBound(typeof control.mcpSha256 === "string" && /^[a-f0-9]{64}$/.test(control.mcpSha256));
|
|
39940
39944
|
if (control.appSha256 !== undefined)
|
|
39941
39945
|
requireBound(typeof control.appSha256 === "string" && /^[a-f0-9]{64}$/.test(control.appSha256));
|
|
39942
39946
|
}
|
|
@@ -39959,8 +39963,8 @@ function assertAgentPolicyCollections(policy) {
|
|
|
39959
39963
|
text(source.path);
|
|
39960
39964
|
requireBound(source.sha256 === null || typeof source.sha256 === "string" && /^[a-f0-9]{64}$/.test(source.sha256));
|
|
39961
39965
|
if (source.hashMode !== undefined)
|
|
39962
|
-
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));
|
|
39963
|
-
if (source.hashMode === "codex-settings-v1")
|
|
39966
|
+
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));
|
|
39967
|
+
if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2")
|
|
39964
39968
|
requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute2(source.path) && resolve3(source.path) === source.path && basename2(source.path) === "config.toml");
|
|
39965
39969
|
if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3")
|
|
39966
39970
|
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute2(source.path) && resolve3(source.path) === source.path && basename2(source.path) === "settings.json");
|
|
@@ -50884,6 +50888,28 @@ var init_claude_settings_witness = __esm(() => {
|
|
|
50884
50888
|
PERSISTED_EFFORT_LEVELS = new Set(["low", "medium", "high", "xhigh"]);
|
|
50885
50889
|
});
|
|
50886
50890
|
|
|
50891
|
+
// src/lib/codex-native-compatibility.ts
|
|
50892
|
+
function supportsCodexNativeCapability(version, capability) {
|
|
50893
|
+
return typeof version === "string" && Object.hasOwn(MEASURED_CODEX_CAPABILITIES, version) && MEASURED_CODEX_CAPABILITIES[version].includes(capability);
|
|
50894
|
+
}
|
|
50895
|
+
var MEASURED_CODEX_CAPABILITIES, SUPPORTED_CODEX_HOOK_VERSIONS;
|
|
50896
|
+
var init_codex_native_compatibility = __esm(() => {
|
|
50897
|
+
MEASURED_CODEX_CAPABILITIES = {
|
|
50898
|
+
"codex-cli 0.153.0": ["hooks"],
|
|
50899
|
+
"codex-cli 0.154.0": ["hooks"],
|
|
50900
|
+
"codex-cli 0.155.0": ["hooks"],
|
|
50901
|
+
"codex-cli 0.155.1": ["hooks"],
|
|
50902
|
+
"codex-cli 0.156.1": ["hooks"],
|
|
50903
|
+
"codex-cli 0.157.0": ["hooks"],
|
|
50904
|
+
"codex-cli 0.157.1": ["hooks"],
|
|
50905
|
+
"codex-cli 0.158.0": ["hooks"],
|
|
50906
|
+
"codex-cli 0.159.0": ["hooks"],
|
|
50907
|
+
"codex-cli 0.159.2": ["hooks", "qualified-skill-catalog"],
|
|
50908
|
+
"codex-cli 0.160.0": ["hooks", "qualified-skill-catalog"]
|
|
50909
|
+
};
|
|
50910
|
+
SUPPORTED_CODEX_HOOK_VERSIONS = Object.freeze(Object.keys(MEASURED_CODEX_CAPABILITIES).filter((version) => supportsCodexNativeCapability(version, "hooks")));
|
|
50911
|
+
});
|
|
50912
|
+
|
|
50887
50913
|
// src/lib/codex-hook-rpc.ts
|
|
50888
50914
|
import { execFile, spawn as spawn2 } from "child_process";
|
|
50889
50915
|
import { realpathSync as realpathSync3, statSync as statSync7 } from "fs";
|
|
@@ -50906,7 +50932,7 @@ async function connectCodexHookRpc(options) {
|
|
|
50906
50932
|
} catch {
|
|
50907
50933
|
throw new Error("CODEX_HOOK_TRUST_NATIVE_UNAVAILABLE");
|
|
50908
50934
|
}
|
|
50909
|
-
if (!
|
|
50935
|
+
if (!supportsCodexNativeCapability(version, "hooks"))
|
|
50910
50936
|
throw new Error("CODEX_HOOK_TRUST_NATIVE_UNSUPPORTED_VERSION");
|
|
50911
50937
|
const current = statSync7(binary);
|
|
50912
50938
|
if (realpathSync3(found) !== binary || ["dev", "ino", "size", "mtimeMs", "ctimeMs"].some((k) => stat[k] !== current[k]))
|
|
@@ -51025,9 +51051,9 @@ async function connectCodexHookRpc(options) {
|
|
|
51025
51051
|
throw new Error("CODEX_HOOK_TRUST_NATIVE_UNSUPPORTED: native hooks/list and versioned config writes are required");
|
|
51026
51052
|
}
|
|
51027
51053
|
}
|
|
51028
|
-
var SUPPORTED_CODEX_HOOK_VERSIONS;
|
|
51029
51054
|
var init_codex_hook_rpc = __esm(() => {
|
|
51030
|
-
|
|
51055
|
+
init_codex_native_compatibility();
|
|
51056
|
+
init_codex_native_compatibility();
|
|
51031
51057
|
});
|
|
51032
51058
|
|
|
51033
51059
|
// src/lib/codex-native-skill-catalog.ts
|
|
@@ -51062,7 +51088,11 @@ function projectCodexInstalledPlugins(response) {
|
|
|
51062
51088
|
for (const value of marketplace.plugins) {
|
|
51063
51089
|
if (!object4(value) || !scalar(value.id, MAX_PLUGIN_ID_BYTES) || !scalar(value.name, MAX_NAME_BYTES) || value.id !== `${value.name}@${marketplace.name}`)
|
|
51064
51090
|
refuse();
|
|
51065
|
-
plugins.push({
|
|
51091
|
+
plugins.push({
|
|
51092
|
+
...value,
|
|
51093
|
+
marketplace: marketplace.name,
|
|
51094
|
+
sourceType: object4(value.source) && value.source.type === "remote" ? "remote" : undefined
|
|
51095
|
+
});
|
|
51066
51096
|
}
|
|
51067
51097
|
}
|
|
51068
51098
|
return projectCodexInstalledPluginEntries(plugins);
|
|
@@ -51072,13 +51102,21 @@ function projectCodexInstalledPluginEntries(value) {
|
|
|
51072
51102
|
refuse();
|
|
51073
51103
|
const ids = new Set;
|
|
51074
51104
|
return value.map((item) => {
|
|
51075
|
-
if (!object4(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))
|
|
51105
|
+
if (!object4(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")
|
|
51076
51106
|
refuse();
|
|
51077
51107
|
const at2 = item.id.lastIndexOf("@");
|
|
51078
51108
|
if (at2 < 1 || item.id.slice(0, at2) !== item.name || at2 === item.id.length - 1 || ids.has(item.id))
|
|
51079
51109
|
refuse();
|
|
51080
51110
|
ids.add(item.id);
|
|
51081
|
-
return {
|
|
51111
|
+
return {
|
|
51112
|
+
id: item.id,
|
|
51113
|
+
name: item.name,
|
|
51114
|
+
installed: item.installed,
|
|
51115
|
+
enabled: item.enabled,
|
|
51116
|
+
localVersion: item.localVersion ?? null,
|
|
51117
|
+
...item.sourceType === "remote" ? { sourceType: "remote" } : {},
|
|
51118
|
+
...item.remotePluginId == null ? {} : { remotePluginId: item.remotePluginId }
|
|
51119
|
+
};
|
|
51082
51120
|
});
|
|
51083
51121
|
}
|
|
51084
51122
|
async function captureCodexNativeSkillCatalog(options, connect = connectCodexHookRpc) {
|
|
@@ -51091,7 +51129,7 @@ async function captureCodexNativeSkillCatalog(options, connect = connectCodexHoo
|
|
|
51091
51129
|
...options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }
|
|
51092
51130
|
});
|
|
51093
51131
|
try {
|
|
51094
|
-
if (!
|
|
51132
|
+
if (!supportsCodexNativeCapability(rpc.version, "qualified-skill-catalog"))
|
|
51095
51133
|
throw new Error("CODEX_NATIVE_SKILL_CATALOG_UNSUPPORTED_VERSION");
|
|
51096
51134
|
const response = await rpc.request("skills/list", { cwds: [options.cwd], forceReload: true });
|
|
51097
51135
|
const installed = await rpc.request("plugin/installed", { cwds: [options.cwd] });
|
|
@@ -51142,10 +51180,10 @@ function isCodexNativeSkillDisabled(skill, rules) {
|
|
|
51142
51180
|
}
|
|
51143
51181
|
return disabled;
|
|
51144
51182
|
}
|
|
51145
|
-
var MAX_SKILLS = 4096, MAX_NAME_BYTES = 1024, MAX_PATH_BYTES = 16384, MAX_PLUGIN_ID_BYTES = 1024,
|
|
51183
|
+
var MAX_SKILLS = 4096, MAX_NAME_BYTES = 1024, MAX_PATH_BYTES = 16384, MAX_PLUGIN_ID_BYTES = 1024, object4 = (value) => value !== null && typeof value === "object" && !Array.isArray(value), scalar = (value, max2) => typeof value === "string" && value.length > 0 && value.trim() === value && Buffer.byteLength(value, "utf8") <= max2 && !/[\u0000-\u001f\u007f]/u.test(value), remotePluginIdentifier = (value) => typeof value === "string" && /^[A-Za-z0-9_~-]{1,1024}$/.test(value), absolutePath2 = (value) => scalar(value, MAX_PATH_BYTES) && isAbsolute10(value);
|
|
51146
51184
|
var init_codex_native_skill_catalog = __esm(() => {
|
|
51147
51185
|
init_codex_hook_rpc();
|
|
51148
|
-
|
|
51186
|
+
init_codex_native_compatibility();
|
|
51149
51187
|
});
|
|
51150
51188
|
|
|
51151
51189
|
// src/lib/codex-plugin-skill-controls.ts
|
|
@@ -51154,6 +51192,21 @@ import { lstatSync as lstatSync12, readdirSync as readdirSync6, readlinkSync as
|
|
|
51154
51192
|
function refuse2() {
|
|
51155
51193
|
throw new Error("CODEX_NATIVE_SKILL_IDENTITY_UNSUPPORTED: review native plugin names and hook controls");
|
|
51156
51194
|
}
|
|
51195
|
+
function remoteInstallationMatches(parent, remotePluginId, read2) {
|
|
51196
|
+
try {
|
|
51197
|
+
if (!remotePluginIdentifier(remotePluginId) || !lstatSync12(parent).isDirectory() || realpathSync5(parent) !== parent)
|
|
51198
|
+
return false;
|
|
51199
|
+
const path = join18(parent, ".codex-remote-plugin-install.json"), stat = lstatSync12(path, { throwIfNoEntry: false });
|
|
51200
|
+
if (!stat?.isFile() || stat.isSymbolicLink() || stat.size > 16384)
|
|
51201
|
+
return false;
|
|
51202
|
+
const text2 = read2(path);
|
|
51203
|
+
hashNativeJsonControls(text2);
|
|
51204
|
+
const value = JSON.parse(text2);
|
|
51205
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === 2 && value.schema_version === 1 && value.remote_plugin_id === remotePluginId);
|
|
51206
|
+
} catch {
|
|
51207
|
+
return false;
|
|
51208
|
+
}
|
|
51209
|
+
}
|
|
51157
51210
|
function appControls(path, read2) {
|
|
51158
51211
|
const text2 = read2(path);
|
|
51159
51212
|
let value, sha2562;
|
|
@@ -51175,6 +51228,42 @@ function appControls(path, read2) {
|
|
|
51175
51228
|
}
|
|
51176
51229
|
return sha2562;
|
|
51177
51230
|
}
|
|
51231
|
+
function mcpControls(path, read2) {
|
|
51232
|
+
const text2 = read2(path);
|
|
51233
|
+
let value, sha2562;
|
|
51234
|
+
try {
|
|
51235
|
+
sha2562 = hashNativeJsonControls(text2);
|
|
51236
|
+
value = JSON.parse(text2);
|
|
51237
|
+
} catch {
|
|
51238
|
+
refuse2();
|
|
51239
|
+
}
|
|
51240
|
+
const object5 = (v) => Boolean(v && typeof v === "object" && !Array.isArray(v));
|
|
51241
|
+
const textField = (v, empty = false) => typeof v === "string" && (empty || Boolean(v.trim())) && Buffer.byteLength(v) <= 16384 && !/[\x00-\x1f\x7f]/.test(v);
|
|
51242
|
+
const envName = (v) => typeof v === "string" && /^[A-Za-z_][A-Za-z0-9_]{0,255}$/.test(v);
|
|
51243
|
+
if (!object5(value) || Object.keys(value).length !== 1 || !object5(value.mcpServers))
|
|
51244
|
+
refuse2();
|
|
51245
|
+
const servers = Object.entries(value.mcpServers);
|
|
51246
|
+
if (!servers.length || servers.length > 256)
|
|
51247
|
+
refuse2();
|
|
51248
|
+
for (const [name, server] of servers) {
|
|
51249
|
+
if (!identifier2(name) || !object5(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))
|
|
51250
|
+
refuse2();
|
|
51251
|
+
if (server.env_vars !== undefined) {
|
|
51252
|
+
if (!Array.isArray(server.env_vars) || server.env_vars.length > 256)
|
|
51253
|
+
refuse2();
|
|
51254
|
+
const names = server.env_vars.map((entry) => {
|
|
51255
|
+
if (envName(entry))
|
|
51256
|
+
return entry;
|
|
51257
|
+
if (!object5(entry) || !Object.keys(entry).every((key) => ["name", "source"].includes(key)) || !envName(entry.name) || entry.source !== undefined && entry.source !== "local")
|
|
51258
|
+
refuse2();
|
|
51259
|
+
return entry.name;
|
|
51260
|
+
});
|
|
51261
|
+
if (new Set(names).size !== names.length)
|
|
51262
|
+
refuse2();
|
|
51263
|
+
}
|
|
51264
|
+
}
|
|
51265
|
+
return sha2562;
|
|
51266
|
+
}
|
|
51178
51267
|
function rootControls(root, read2) {
|
|
51179
51268
|
const manifestPath = join18(root, ".codex-plugin/plugin.json"), manifestFile = lstatSync12(manifestPath, { throwIfNoEntry: false });
|
|
51180
51269
|
if (!lstatSync12(join18(root, ".codex-plugin"), { throwIfNoEntry: false })?.isDirectory() || !manifestFile?.isFile() || manifestFile.size > 1024 * 1024)
|
|
@@ -51192,15 +51281,21 @@ function rootControls(root, read2) {
|
|
|
51192
51281
|
const cacheVersion = basename5(root), declaredVersion = manifest.version === undefined ? "" : typeof manifest.version === "string" ? manifest.version.trim() : null;
|
|
51193
51282
|
if (declaredVersion === null || (declaredVersion ? declaredVersion !== cacheVersion : cacheVersion !== CODEX_DEFAULT_AGENT_PLUGIN_VERSION))
|
|
51194
51283
|
refuse2();
|
|
51195
|
-
if (manifest.hooks !== undefined || manifest.
|
|
51284
|
+
if (manifest.hooks !== undefined || manifest.commands !== undefined || manifest.mcpServers !== undefined && manifest.mcpServers !== "./.mcp.json" || manifest.apps !== undefined && manifest.apps !== "./.app.json" || lstatSync12(join18(root, "hooks"), { throwIfNoEntry: false }))
|
|
51196
51285
|
refuse2();
|
|
51286
|
+
const mcp = join18(root, ".mcp.json"), mcpPresent = lstatSync12(mcp, { throwIfNoEntry: false });
|
|
51287
|
+
if (mcpPresent && (!mcpPresent.isFile() || mcpPresent.isSymbolicLink() || mcpPresent.size > 1024 * 1024 || realpathSync5(mcp) !== mcp))
|
|
51288
|
+
refuse2();
|
|
51289
|
+
if (Boolean(mcpPresent) !== (manifest.mcpServers !== undefined))
|
|
51290
|
+
refuse2();
|
|
51291
|
+
const mcpSha256 = mcpPresent ? mcpControls(mcp, read2) : undefined;
|
|
51197
51292
|
const app = join18(root, ".app.json"), present = lstatSync12(app, { throwIfNoEntry: false });
|
|
51198
51293
|
if (present && (!present.isFile() || present.isSymbolicLink() || present.size > 1024 * 1024))
|
|
51199
51294
|
refuse2();
|
|
51200
51295
|
if (manifest.apps !== undefined && !present)
|
|
51201
51296
|
refuse2();
|
|
51202
51297
|
const appSha256 = present ? appControls(app, read2) : undefined;
|
|
51203
|
-
return { namespace: manifest.name, manifestSha256, ...appSha256 ? { appSha256 } : {} };
|
|
51298
|
+
return { namespace: manifest.name, manifestSha256, ...appSha256 ? { appSha256 } : {}, ...mcpSha256 ? { mcpSha256 } : {} };
|
|
51204
51299
|
}
|
|
51205
51300
|
function identity4(document3, cache3, read2) {
|
|
51206
51301
|
if (!document3.startsWith(cache3 + sep4) || !document3.endsWith(sep4 + "SKILL.md"))
|
|
@@ -51243,6 +51338,10 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache3, controls, read2) {
|
|
|
51243
51338
|
for (const parent of new Set(controls.map((control) => control.pluginParent))) {
|
|
51244
51339
|
if (!parent.startsWith(cache3 + sep4) || !lstatSync12(parent, { throwIfNoEntry: false })?.isDirectory())
|
|
51245
51340
|
return false;
|
|
51341
|
+
for (const control of controls.filter((control2) => control2.pluginParent === parent)) {
|
|
51342
|
+
if (control.remotePluginId !== undefined && !remoteInstallationMatches(parent, control.remotePluginId, read2))
|
|
51343
|
+
return false;
|
|
51344
|
+
}
|
|
51246
51345
|
const names = readdirSync6(parent);
|
|
51247
51346
|
entries += names.length;
|
|
51248
51347
|
if (entries > 4096)
|
|
@@ -51259,7 +51358,7 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache3, controls, read2) {
|
|
|
51259
51358
|
if (!stat.isDirectory() || ![".codex-plugin/plugin.json", ".app.json", "hooks", ".mcp.json"].some((path) => lstatSync12(join18(root, path), { throwIfNoEntry: false })))
|
|
51260
51359
|
continue;
|
|
51261
51360
|
const parsed = rootControls(root, read2);
|
|
51262
|
-
if (!controls.some((control) => control.pluginParent === parent && control.namespace === parsed.namespace && control.manifestSha256 === parsed.manifestSha256 && control.appSha256 === parsed.appSha256))
|
|
51361
|
+
if (!controls.some((control) => control.pluginParent === parent && control.namespace === parsed.namespace && control.manifestSha256 === parsed.manifestSha256 && control.appSha256 === parsed.appSha256 && control.mcpSha256 === parsed.mcpSha256))
|
|
51263
51362
|
return false;
|
|
51264
51363
|
}
|
|
51265
51364
|
}
|
|
@@ -51269,7 +51368,7 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache3, controls, read2) {
|
|
|
51269
51368
|
}
|
|
51270
51369
|
}
|
|
51271
51370
|
function reviewCodexPluginSkillControls(catalog, documents, cache3, cwd2, read2, rules) {
|
|
51272
|
-
if (catalog?.version
|
|
51371
|
+
if (!supportsCodexNativeCapability(catalog?.version, "qualified-skill-catalog") || catalog.cwd !== cwd2)
|
|
51273
51372
|
refuse2();
|
|
51274
51373
|
const skills = projectCodexNativeSkillCatalog({ data: [{ cwd: cwd2, errors: [], skills: catalog.skills }] }, cwd2);
|
|
51275
51374
|
const allowed = new Set(documents), result2 = [];
|
|
@@ -51296,22 +51395,30 @@ function reviewCodexPluginSkillControls(catalog, documents, cache3, cwd2, read2,
|
|
|
51296
51395
|
const listed = skills.filter((skill) => skill.path === document3);
|
|
51297
51396
|
if (listed.length > 1)
|
|
51298
51397
|
refuse2();
|
|
51398
|
+
let remotePluginId;
|
|
51299
51399
|
if (listed.length === 1) {
|
|
51300
51400
|
if (listed[0].name !== parsed.name || listed[0].pluginId !== expectedPluginId)
|
|
51301
51401
|
refuse2();
|
|
51302
51402
|
} else {
|
|
51303
|
-
const installed = installedPlugins.filter((
|
|
51304
|
-
if (installed.length !== 1 || !installed[0].installed || !installed[0].enabled
|
|
51403
|
+
const installed = installedPlugins.filter((plugin2) => plugin2.id === expectedPluginId && plugin2.name === pluginName);
|
|
51404
|
+
if (installed.length !== 1 || !installed[0].installed || !installed[0].enabled)
|
|
51305
51405
|
refuse2();
|
|
51306
|
-
|
|
51307
|
-
|
|
51406
|
+
const plugin = installed[0];
|
|
51407
|
+
if (plugin.localVersion !== null) {
|
|
51408
|
+
if (plugin.localVersion !== basename5(dirname10(dirname10(dirname10(document3)))))
|
|
51409
|
+
continue;
|
|
51410
|
+
} else {
|
|
51411
|
+
if (plugin.sourceType !== "remote" || !plugin.remotePluginId || !remoteInstallationMatches(parsed.pluginParent, plugin.remotePluginId, read2) || !lstatSync12(document3).isFile() || realpathSync5(document3) !== document3)
|
|
51412
|
+
refuse2();
|
|
51413
|
+
remotePluginId = plugin.remotePluginId;
|
|
51414
|
+
}
|
|
51308
51415
|
const exactPathDeny = Array.isArray(rules) && rules.some((rule) => rule?.path === document3 && rule?.enabled === false);
|
|
51309
51416
|
if (!exactPathDeny || !isCodexNativeSkillDisabled({ name: parsed.name, path: document3, pluginId: expectedPluginId, enabled: true }, rules))
|
|
51310
51417
|
refuse2();
|
|
51311
51418
|
}
|
|
51312
|
-
result2.push({ ...parsed, pluginId: expectedPluginId });
|
|
51419
|
+
result2.push({ ...parsed, pluginId: expectedPluginId, ...remotePluginId ? { remotePluginId } : {} });
|
|
51313
51420
|
}
|
|
51314
|
-
if (!result2.length || new Set(result2.map((item) => item.name)).size !== result2.length)
|
|
51421
|
+
if (!result2.length && documents.some((document3) => document3.startsWith(cache3 + sep4)) || new Set(result2.map((item) => item.name)).size !== result2.length)
|
|
51315
51422
|
refuse2();
|
|
51316
51423
|
return result2;
|
|
51317
51424
|
}
|
|
@@ -51324,8 +51431,8 @@ function isReviewedCodexPluginSkillDisabled(document3, cache3, controls, rules,
|
|
|
51324
51431
|
} catch {
|
|
51325
51432
|
return false;
|
|
51326
51433
|
}
|
|
51327
|
-
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);
|
|
51328
|
-
if (!reviewed)
|
|
51434
|
+
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);
|
|
51435
|
+
if (!reviewed || reviewed.remotePluginId !== undefined && !remoteInstallationMatches(reviewed.pluginParent, reviewed.remotePluginId, read2))
|
|
51329
51436
|
return false;
|
|
51330
51437
|
return isCodexNativeSkillDisabled({ name: parsed.name, path: document3, pluginId: reviewed.pluginId, enabled: true }, rules);
|
|
51331
51438
|
}
|
|
@@ -51346,10 +51453,11 @@ enabled = false
|
|
|
51346
51453
|
var identifier2 = (v) => typeof v === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(v), CODEX_DEFAULT_AGENT_PLUGIN_VERSION = "1.0.0";
|
|
51347
51454
|
var init_codex_plugin_skill_controls = __esm(() => {
|
|
51348
51455
|
init_claude_settings_witness();
|
|
51456
|
+
init_codex_native_compatibility();
|
|
51349
51457
|
init_codex_native_skill_catalog();
|
|
51350
51458
|
});
|
|
51351
51459
|
|
|
51352
|
-
// src/lib/codex-settings-witness.ts
|
|
51460
|
+
// src/lib/codex-settings-witness-v1.ts
|
|
51353
51461
|
import { createHash as createHash9 } from "crypto";
|
|
51354
51462
|
function need3(value) {
|
|
51355
51463
|
if (!value)
|
|
@@ -51440,21 +51548,173 @@ function captureCodexSettings(path, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
|
51440
51548
|
const text2 = readNativeSettingsWitnessFile(path, budget, "config.toml");
|
|
51441
51549
|
return { path, hashMode: "codex-settings-v1", sha256: hashCodexSettingsReplacement(text2) };
|
|
51442
51550
|
}
|
|
51551
|
+
var sha = (text2) => createHash9("sha256").update(text2).digest("hex"), EFFORT, VERBOSITY;
|
|
51552
|
+
var init_codex_settings_witness_v1 = __esm(() => {
|
|
51553
|
+
init_claude_settings_witness();
|
|
51554
|
+
EFFORT = new Set(["none", "minimal", "low", "medium", "high", "xhigh"]);
|
|
51555
|
+
VERBOSITY = new Set(["low", "medium", "high"]);
|
|
51556
|
+
});
|
|
51557
|
+
|
|
51558
|
+
// src/lib/codex-settings-witness.ts
|
|
51559
|
+
import { createHash as createHash10 } from "crypto";
|
|
51560
|
+
function need4(value) {
|
|
51561
|
+
if (!value)
|
|
51562
|
+
throw new Error("Invalid Codex settings witness");
|
|
51563
|
+
}
|
|
51564
|
+
function isRecord3(value) {
|
|
51565
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
51566
|
+
}
|
|
51567
|
+
function isDate2(value) {
|
|
51568
|
+
return value instanceof Date;
|
|
51569
|
+
}
|
|
51570
|
+
function numericTokens2(text2) {
|
|
51571
|
+
const result2 = [];
|
|
51572
|
+
for (let at2 = 0;at2 < text2.length; ) {
|
|
51573
|
+
const char = text2[at2];
|
|
51574
|
+
if (char === "#") {
|
|
51575
|
+
while (at2 < text2.length && text2[at2] !== `
|
|
51576
|
+
`)
|
|
51577
|
+
at2++;
|
|
51578
|
+
continue;
|
|
51579
|
+
}
|
|
51580
|
+
if (char === '"' || char === "'") {
|
|
51581
|
+
const quote = char, triple = text2.slice(at2, at2 + 3) === quote.repeat(3);
|
|
51582
|
+
at2 += triple ? 3 : 1;
|
|
51583
|
+
while (at2 < text2.length) {
|
|
51584
|
+
if (quote === '"' && text2[at2] === "\\") {
|
|
51585
|
+
at2 += 2;
|
|
51586
|
+
continue;
|
|
51587
|
+
}
|
|
51588
|
+
if (text2.slice(at2, at2 + (triple ? 3 : 1)) === quote.repeat(triple ? 3 : 1)) {
|
|
51589
|
+
at2 += triple ? 3 : 1;
|
|
51590
|
+
break;
|
|
51591
|
+
}
|
|
51592
|
+
at2++;
|
|
51593
|
+
}
|
|
51594
|
+
continue;
|
|
51595
|
+
}
|
|
51596
|
+
if (/[0-9+-]/.test(char)) {
|
|
51597
|
+
const start = at2;
|
|
51598
|
+
while (at2 < text2.length && !/[\s,\]{}#=]/.test(text2[at2]))
|
|
51599
|
+
at2++;
|
|
51600
|
+
if (at2 > start) {
|
|
51601
|
+
result2.push(text2.slice(start, at2));
|
|
51602
|
+
continue;
|
|
51603
|
+
}
|
|
51604
|
+
}
|
|
51605
|
+
at2++;
|
|
51606
|
+
}
|
|
51607
|
+
return result2.sort();
|
|
51608
|
+
}
|
|
51609
|
+
function canonical4(value, depth = 0, budget = { remaining: 65536 }) {
|
|
51610
|
+
need4(depth <= 32 && --budget.remaining >= 0);
|
|
51611
|
+
if (value === null)
|
|
51612
|
+
return ["null"];
|
|
51613
|
+
if (typeof value === "string")
|
|
51614
|
+
return ["string", value];
|
|
51615
|
+
if (typeof value === "boolean")
|
|
51616
|
+
return ["boolean", value];
|
|
51617
|
+
if (typeof value === "number") {
|
|
51618
|
+
need4(Number.isFinite(value));
|
|
51619
|
+
return ["number", String(value)];
|
|
51620
|
+
}
|
|
51621
|
+
if (isDate2(value)) {
|
|
51622
|
+
need4(Number.isFinite(value.getTime()));
|
|
51623
|
+
return ["date", value.toISOString()];
|
|
51624
|
+
}
|
|
51625
|
+
if (Array.isArray(value))
|
|
51626
|
+
return ["array", value.map((child) => canonical4(child, depth + 1, budget))];
|
|
51627
|
+
need4(isRecord3(value));
|
|
51628
|
+
return ["object", Object.entries(value).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, child]) => [key, canonical4(child, depth + 1, budget)])];
|
|
51629
|
+
}
|
|
51630
|
+
function normalize3(config) {
|
|
51631
|
+
if (isRecord3(config.hooks)) {
|
|
51632
|
+
delete config.hooks.state;
|
|
51633
|
+
if (!Object.keys(config.hooks).length)
|
|
51634
|
+
delete config.hooks;
|
|
51635
|
+
}
|
|
51636
|
+
if (isRecord3(config.skills) && Array.isArray(config.skills.config)) {
|
|
51637
|
+
const skills = config.skills;
|
|
51638
|
+
const retained = skills.config.filter((entry) => !disablesOneSkill(entry));
|
|
51639
|
+
if (retained.length !== skills.config.length) {
|
|
51640
|
+
if (retained.length)
|
|
51641
|
+
skills.config = retained;
|
|
51642
|
+
else
|
|
51643
|
+
delete skills.config;
|
|
51644
|
+
}
|
|
51645
|
+
if (!Object.keys(skills).length)
|
|
51646
|
+
delete config.skills;
|
|
51647
|
+
}
|
|
51648
|
+
inference(config);
|
|
51649
|
+
if (isRecord3(config.profiles)) {
|
|
51650
|
+
for (const profile of Object.values(config.profiles))
|
|
51651
|
+
if (isRecord3(profile))
|
|
51652
|
+
inference(profile);
|
|
51653
|
+
}
|
|
51654
|
+
}
|
|
51655
|
+
function disablesOneSkill(entry) {
|
|
51656
|
+
if (!isRecord3(entry) || entry.enabled !== false)
|
|
51657
|
+
return false;
|
|
51658
|
+
const keys2 = Object.keys(entry);
|
|
51659
|
+
if (!keys2.every((key) => key === "path" || key === "name" || key === "enabled"))
|
|
51660
|
+
return false;
|
|
51661
|
+
const selector = ["path", "name"].filter((key) => Object.hasOwn(entry, key));
|
|
51662
|
+
return selector.length === 1 && typeof entry[selector[0]] === "string" && entry[selector[0]].length > 0;
|
|
51663
|
+
}
|
|
51664
|
+
function inference(target) {
|
|
51665
|
+
for (const key of INFERENCE)
|
|
51666
|
+
if (Object.hasOwn(target, key)) {
|
|
51667
|
+
const value = target[key];
|
|
51668
|
+
if (key === "model")
|
|
51669
|
+
need4(typeof value === "string" && MODEL.test(value));
|
|
51670
|
+
else
|
|
51671
|
+
need4(typeof value === "string" && (key === "model_reasoning_effort" ? EFFORT2.has(value) : VERBOSITY2.has(value)));
|
|
51672
|
+
delete target[key];
|
|
51673
|
+
}
|
|
51674
|
+
}
|
|
51675
|
+
function settingsDigest2(text2) {
|
|
51676
|
+
let config;
|
|
51677
|
+
try {
|
|
51678
|
+
config = Bun.TOML.parse(text2);
|
|
51679
|
+
} catch {
|
|
51680
|
+
throw new Error("Invalid Codex settings witness");
|
|
51681
|
+
}
|
|
51682
|
+
need4(isRecord3(config));
|
|
51683
|
+
normalize3(config);
|
|
51684
|
+
return sha2(`hasna.skills.codex-settings.v2\x00${JSON.stringify([canonical4(config), numericTokens2(text2)])}`);
|
|
51685
|
+
}
|
|
51686
|
+
function hashCodexSettingsReplacementV2(text2, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
51687
|
+
need4(Buffer.byteLength(text2) <= 1024 * 1024 && budget.remaining >= Buffer.byteLength(text2));
|
|
51688
|
+
budget.remaining -= Buffer.byteLength(text2);
|
|
51689
|
+
return settingsDigest2(text2);
|
|
51690
|
+
}
|
|
51691
|
+
function captureCodexSettingsV2(path, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
51692
|
+
const text2 = readNativeSettingsWitnessFile(path, budget, "config.toml");
|
|
51693
|
+
return { path, hashMode: "codex-settings-v2", sha256: settingsDigest2(text2) };
|
|
51694
|
+
}
|
|
51695
|
+
function readCodexSettingsPreimage(path, budget = { remaining: 2 * 1024 * 1024 }) {
|
|
51696
|
+
return readNativeSettingsWitnessFile(path, budget, "config.toml");
|
|
51697
|
+
}
|
|
51443
51698
|
function upgradeCodexSettingsWitness(previous, reviewedSettingsPath) {
|
|
51444
|
-
|
|
51699
|
+
need4(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));
|
|
51445
51700
|
const budget = { remaining: 2 * 1024 * 1024 };
|
|
51446
51701
|
const before2 = readNativeSettingsWitnessFile(reviewedSettingsPath, budget, "config.toml"), current = readNativeSettingsWitnessFile(previous.path, budget, "config.toml");
|
|
51447
|
-
|
|
51448
|
-
const sha2562 =
|
|
51449
|
-
if (
|
|
51702
|
+
need4((previous.hashMode === "codex-settings-v1" ? hashCodexSettingsReplacement(before2) : sha2(before2)) === previous.sha256);
|
|
51703
|
+
const sha2562 = settingsDigest2(current);
|
|
51704
|
+
if (settingsDigest2(before2) !== sha2562)
|
|
51450
51705
|
throw new Error("Codex non-preference settings changed; explicit discovery review required");
|
|
51451
|
-
return { path: previous.path, hashMode: "codex-settings-
|
|
51706
|
+
return { path: previous.path, hashMode: "codex-settings-v2", sha256: sha2562 };
|
|
51452
51707
|
}
|
|
51453
|
-
var
|
|
51708
|
+
var sha2 = (text2) => createHash10("sha256").update(text2).digest("hex"), EFFORT2, VERBOSITY2, MODEL, CODEX_DISCOVERY_PROJECTION_FIELDS, INFERENCE;
|
|
51454
51709
|
var init_codex_settings_witness = __esm(() => {
|
|
51710
|
+
init_codex_settings_witness_v1();
|
|
51711
|
+
init_codex_settings_witness_v1();
|
|
51455
51712
|
init_claude_settings_witness();
|
|
51456
|
-
|
|
51457
|
-
|
|
51713
|
+
EFFORT2 = new Set(["none", "minimal", "low", "medium", "high", "xhigh"]);
|
|
51714
|
+
VERBOSITY2 = new Set(["low", "medium", "high"]);
|
|
51715
|
+
MODEL = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$/;
|
|
51716
|
+
CODEX_DISCOVERY_PROJECTION_FIELDS = ["plugins", "marketplaces", "skills"];
|
|
51717
|
+
INFERENCE = ["model", "model_reasoning_effort", "model_verbosity"];
|
|
51458
51718
|
});
|
|
51459
51719
|
|
|
51460
51720
|
// src/lib/managed-policy.ts
|
|
@@ -51543,7 +51803,7 @@ var init_managed_policy = __esm(() => {
|
|
|
51543
51803
|
});
|
|
51544
51804
|
|
|
51545
51805
|
// src/lib/agent-bridge.ts
|
|
51546
|
-
import { createHash as
|
|
51806
|
+
import { createHash as createHash11 } from "crypto";
|
|
51547
51807
|
import { lstatSync as lstatSync14, readFileSync as readFileSync12, readdirSync as readdirSync7 } from "fs";
|
|
51548
51808
|
import { join as join20 } from "path";
|
|
51549
51809
|
function isOwnedCliBridge(path, expectedPaths) {
|
|
@@ -51577,7 +51837,7 @@ Use the Skills CLI as the skill authority for this station.
|
|
|
51577
51837
|
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.
|
|
51578
51838
|
`, CLI_BRIDGE_DIGEST, CLI_BRIDGE_FILES;
|
|
51579
51839
|
var init_agent_bridge = __esm(() => {
|
|
51580
|
-
CLI_BRIDGE_DIGEST =
|
|
51840
|
+
CLI_BRIDGE_DIGEST = createHash11("sha256").update(markdown).digest("hex");
|
|
51581
51841
|
CLI_BRIDGE_FILES = Object.freeze({
|
|
51582
51842
|
"SKILL.md": markdown,
|
|
51583
51843
|
".hasna-skills.json": `${JSON.stringify({ managedBy: "@hasna/skills", kind: "cli-bridge", version: CLI_BRIDGE_VERSION, protocol: "selection-v1", contentSha256: CLI_BRIDGE_DIGEST }, null, 2)}
|
|
@@ -51856,7 +52116,8 @@ var init_agent_codex = __esm(() => {
|
|
|
51856
52116
|
});
|
|
51857
52117
|
|
|
51858
52118
|
// src/lib/agent-integration.ts
|
|
51859
|
-
import { createHash as
|
|
52119
|
+
import { createHash as createHash12, randomUUID as randomUUID5 } from "crypto";
|
|
52120
|
+
import { isDeepStrictEqual as isDeepStrictEqual4 } from "util";
|
|
51860
52121
|
import { existsSync as existsSync12, lstatSync as lstatSync15, statSync as statSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync13, readdirSync as readdirSync8, opendirSync as opendirSync3, readlinkSync as readlinkSync4, realpathSync as realpathSync6, renameSync as renameSync2, rmdirSync as rmdirSync2, writeFileSync as writeFileSync4, unlinkSync as unlinkSync3, chmodSync, openSync as openSync8, closeSync as closeSync8, fsyncSync as fsyncSync2, fstatSync as fstatSync8, readSync as readSync6, constants as constants8, linkSync } from "fs";
|
|
51861
52122
|
import { dirname as dirname11, join as join21, resolve as resolve11, relative as relative5, isAbsolute as isAbsolute11, sep as sep5 } from "path";
|
|
51862
52123
|
import { homedir as homedir3 } from "os";
|
|
@@ -51965,7 +52226,7 @@ function readNativeBytes(path, maximum = 64 * 1024 * 1024) {
|
|
|
51965
52226
|
}
|
|
51966
52227
|
}
|
|
51967
52228
|
function treeHash(root) {
|
|
51968
|
-
const hash2 =
|
|
52229
|
+
const hash2 = createHash12("sha256");
|
|
51969
52230
|
let bytes = 0, files = 0;
|
|
51970
52231
|
function visit2(path) {
|
|
51971
52232
|
const stat = lstatSync15(path);
|
|
@@ -51992,7 +52253,7 @@ function treeHash(root) {
|
|
|
51992
52253
|
return hash2.digest("hex");
|
|
51993
52254
|
}
|
|
51994
52255
|
function parseNativeMigrationTargetManifest(input) {
|
|
51995
|
-
const digest =
|
|
52256
|
+
const digest = sha3(input);
|
|
51996
52257
|
let value;
|
|
51997
52258
|
try {
|
|
51998
52259
|
value = JSON.parse(input.toString());
|
|
@@ -52397,7 +52658,7 @@ function planAgentIntegration(options) {
|
|
|
52397
52658
|
const observedNativeSources = [];
|
|
52398
52659
|
const codexPluginSkills = options.codexNativeCatalog ? reviewCodexPluginSkillControls(options.codexNativeCatalog, nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor).map((entry) => join21(entry.path, "SKILL.md")), canonicalAgentPath(join21(home, ".codex/plugins/cache"), aliases), resolve11(options.projectDir ?? home), (path) => {
|
|
52399
52660
|
const bytes = readNativeBytes(path, 1024 * 1024);
|
|
52400
|
-
observedNativeSources.push({ path, sha256:
|
|
52661
|
+
observedNativeSources.push({ path, sha256: sha3(bytes) });
|
|
52401
52662
|
return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
52402
52663
|
}, codexConfig.skills?.config ?? []) : policy.bridge?.codexPluginSkills ?? [];
|
|
52403
52664
|
const changes = [];
|
|
@@ -52425,7 +52686,7 @@ function planAgentIntegration(options) {
|
|
|
52425
52686
|
throw new Error("Refusing to overwrite an unrecognized Hermes supervisor");
|
|
52426
52687
|
if (supervisorBefore !== supervisorAfter)
|
|
52427
52688
|
changes.push({ path: supervisorPath, before: supervisorBefore, after: supervisorAfter });
|
|
52428
|
-
const supervisor = { path: supervisorPath, runtime: process.execPath, sha256:
|
|
52689
|
+
const supervisor = { path: supervisorPath, runtime: process.execPath, sha256: sha3(supervisorAfter) };
|
|
52429
52690
|
const after3 = configureHermesHooks(before2, supervisor, previous);
|
|
52430
52691
|
if (before2 !== after3)
|
|
52431
52692
|
changes.push({ path, before: before2, after: after3 });
|
|
@@ -52472,12 +52733,12 @@ function planAgentIntegration(options) {
|
|
|
52472
52733
|
agents: [...new Set([...priorAgents, ...options.agents])].sort(),
|
|
52473
52734
|
home: resolve11(home),
|
|
52474
52735
|
includeVendor: true,
|
|
52475
|
-
...options.agents.includes("hermes") ? { supervisors: { ...policy.bridge?.supervisors, hermes: { path: join21(dataDir3, "agent-hooks", "hermes.js"), runtime: process.execPath, sha256:
|
|
52736
|
+
...options.agents.includes("hermes") ? { supervisors: { ...policy.bridge?.supervisors, hermes: { path: join21(dataDir3, "agent-hooks", "hermes.js"), runtime: process.execPath, sha256: sha3(renderHermesSupervisor(bindings.get("hermes").command, bindings.get("hermes").profileId)) } } } : {},
|
|
52476
52737
|
commands: { ...policy.bridge?.commands, ...Object.fromEntries([...bindings].map(([agent, binding]) => [agent, binding.command])) },
|
|
52477
52738
|
profiles: Object.fromEntries([...new Set([...priorAgents, ...options.agents])].sort().map((agent) => [agent, bindings.get(agent)?.profileId ?? policy.bridge?.profiles?.[agent] ?? policy.profileId])),
|
|
52478
52739
|
disabledBuiltins: options.agents.includes("codex") ? nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor && entry.path.startsWith(canonicalAgentPath(join21(home, ".codex", "skills", ".system"), aliases) + sep5)).map((entry) => ({ path: entry.path, hash: entry.hash })) : policy.bridge?.disabledBuiltins ?? [],
|
|
52479
52740
|
rootAliases: aliases,
|
|
52480
|
-
...codexPluginSkills.length ? { codexPluginSkills, codexPluginSkillReview: options.codexNativeCatalog ? { version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, catalogSha256:
|
|
52741
|
+
...codexPluginSkills.length ? { codexPluginSkills, codexPluginSkillReview: options.codexNativeCatalog ? { version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, catalogSha256: sha3(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(join21(home, ".codex/config.toml"), aliases))?.before === null ? null : sha3(readOptional(canonicalAgentPath(join21(home, ".codex/config.toml"), aliases)) ?? "") } : policy.bridge?.codexPluginSkillReview } : {},
|
|
52481
52742
|
discovery: { ...policy.bridge?.discovery, ...Object.fromEntries(discoveryAfter.map((binding) => [binding.agent, binding])) }
|
|
52482
52743
|
} };
|
|
52483
52744
|
const serializedPolicy = serializeManagedSkillPolicy(nextPolicy);
|
|
@@ -52515,7 +52776,7 @@ function atomicWrite2(path, content) {
|
|
|
52515
52776
|
function planAgentSettingsWitnessUpgrade(options) {
|
|
52516
52777
|
const home = resolve11(options.home ?? homedir3()), dataDir3 = options.dataDir ?? getDataDirReadOnly();
|
|
52517
52778
|
const snapshot = readManagedSkillPolicySnapshot(dataDir3);
|
|
52518
|
-
if (!snapshot ||
|
|
52779
|
+
if (!snapshot || sha3(snapshot.text) !== options.expectedPolicySha256)
|
|
52519
52780
|
throw new Error("Managed policy preimage changed");
|
|
52520
52781
|
const policy = snapshot.value, aliases = policy.bridge?.rootAliases ?? [];
|
|
52521
52782
|
recheckRootAliases(aliases);
|
|
@@ -52524,7 +52785,7 @@ function planAgentSettingsWitnessUpgrade(options) {
|
|
|
52524
52785
|
throw new Error("Settings witness upgrade requires an existing reviewed native binding");
|
|
52525
52786
|
const configPath = canonicalAgentPath(join21(home, options.agent === "claude" ? ".claude/settings.json" : ".codex/config.toml"), aliases);
|
|
52526
52787
|
const settings = readOptional(configPath);
|
|
52527
|
-
if (settings === null ||
|
|
52788
|
+
if (settings === null || sha3(settings) !== options.expectedSettingsSha256)
|
|
52528
52789
|
throw new Error("Native settings preimage changed");
|
|
52529
52790
|
const sources = binding.sources.filter((source) => source.path === configPath && source.format === undefined && source.fields === undefined);
|
|
52530
52791
|
if (sources.length !== 1)
|
|
@@ -52532,15 +52793,40 @@ function planAgentSettingsWitnessUpgrade(options) {
|
|
|
52532
52793
|
const previous = sources[0];
|
|
52533
52794
|
if (typeof previous.sha256 !== "string")
|
|
52534
52795
|
throw new Error("Settings witness upgrade requires a preserved settings preimage");
|
|
52796
|
+
const replaced = [previous];
|
|
52797
|
+
if (options.agent === "codex") {
|
|
52798
|
+
if (previous.hashMode !== undefined && previous.hashMode !== "bytes" && previous.hashMode !== "codex-settings-v1")
|
|
52799
|
+
throw new Error("Codex settings witness upgrade requires a preserved raw or codex-settings-v1 configuration witness");
|
|
52800
|
+
const preimage = readCodexSettingsPreimage(options.reviewedPreimage);
|
|
52801
|
+
for (const source of binding.sources) {
|
|
52802
|
+
if (source === previous || source.path !== configPath)
|
|
52803
|
+
continue;
|
|
52804
|
+
const fields = source.fields;
|
|
52805
|
+
if (source.hashMode !== undefined || source.format !== "toml" || !Array.isArray(fields) || !isDeepStrictEqual4(fields, [...CODEX_DISCOVERY_PROJECTION_FIELDS]) || typeof source.sha256 !== "string")
|
|
52806
|
+
throw new Error("Codex settings witness upgrade found an unrecognized configuration witness");
|
|
52807
|
+
if (projectNativeDiscoveryFields(preimage, "toml", fields, configPath) !== source.sha256)
|
|
52808
|
+
throw new Error("Reviewed preimage does not explain the Codex discovery projection witness");
|
|
52809
|
+
replaced.push(source);
|
|
52810
|
+
}
|
|
52811
|
+
}
|
|
52535
52812
|
const next = options.agent === "claude" ? upgradeClaudeSettingsWitness(previous, options.reviewedPreimage) : upgradeCodexSettingsWitness(previous, options.reviewedPreimage);
|
|
52536
|
-
const
|
|
52813
|
+
const rebound = [];
|
|
52814
|
+
for (const source of binding.sources) {
|
|
52815
|
+
if (!replaced.includes(source)) {
|
|
52816
|
+
rebound.push(source);
|
|
52817
|
+
continue;
|
|
52818
|
+
}
|
|
52819
|
+
if (source === replaced[0])
|
|
52820
|
+
rebound.push(next);
|
|
52821
|
+
}
|
|
52822
|
+
const replacement = { ...binding, sources: rebound };
|
|
52537
52823
|
verifyAgentDiscovery(replacement);
|
|
52538
52824
|
const after2 = serializeManagedSkillPolicy({ ...policy, bridge: { ...policy.bridge, discovery: { ...policy.bridge.discovery, [options.agent]: replacement } } });
|
|
52539
|
-
return { dataDir: dataDir3, profileId: policy.profileId, changes: [{ path: join21(dataDir3, "agent-policy.json"), before: snapshot.text, after: after2 }], nativeSkills: [], observedPolicy: { path: join21(dataDir3, "agent-policy.json"), before: snapshot.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 } };
|
|
52825
|
+
return { dataDir: dataDir3, profileId: policy.profileId, changes: [{ path: join21(dataDir3, "agent-policy.json"), before: snapshot.text, after: after2 }], nativeSkills: [], observedPolicy: { path: join21(dataDir3, "agent-policy.json"), before: snapshot.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 })) } };
|
|
52540
52826
|
}
|
|
52541
52827
|
function applyAgentIntegration(plan) {
|
|
52542
52828
|
for (const source of plan.observedNativeSources ?? [])
|
|
52543
|
-
if (
|
|
52829
|
+
if (sha3(readNativeBytes(source.path, 1024 * 1024)) !== source.sha256)
|
|
52544
52830
|
throw new Error("Native identity source changed after planning");
|
|
52545
52831
|
if (plan.observedSettings && readOptional(plan.observedSettings.path) !== plan.observedSettings.before)
|
|
52546
52832
|
throw new Error("Native settings changed after witness planning");
|
|
@@ -52560,7 +52846,7 @@ function applyAgentIntegration(plan) {
|
|
|
52560
52846
|
const upgrade = plan.settingsWitnessUpgrade;
|
|
52561
52847
|
if (!plan.managedAgentChecks || !plan.observedPolicy?.before)
|
|
52562
52848
|
throw new Error("Invalid settings witness upgrade plan");
|
|
52563
|
-
const verified = planAgentSettingsWitnessUpgrade({ agent: upgrade.agent, reviewedPreimage: upgrade.reviewedPreimage, home: plan.managedAgentChecks.home, dataDir: plan.dataDir, expectedPolicySha256:
|
|
52849
|
+
const verified = planAgentSettingsWitnessUpgrade({ agent: upgrade.agent, reviewedPreimage: upgrade.reviewedPreimage, home: plan.managedAgentChecks.home, dataDir: plan.dataDir, expectedPolicySha256: sha3(plan.observedPolicy.before), expectedSettingsSha256: upgrade.currentSettingsSha256 });
|
|
52564
52850
|
if (JSON.stringify(verified.changes) !== JSON.stringify(plan.changes) || JSON.stringify(verified.settingsWitnessUpgrade) !== JSON.stringify(upgrade))
|
|
52565
52851
|
throw new Error("Settings witness upgrade plan changed");
|
|
52566
52852
|
provenDiscovery = verified.discoveryBefore[0];
|
|
@@ -52588,7 +52874,7 @@ function applyAgentIntegration(plan) {
|
|
|
52588
52874
|
chmodSync(backupRoot, 448);
|
|
52589
52875
|
for (const [index, change] of plan.changes.entries())
|
|
52590
52876
|
if (change.before !== null) {
|
|
52591
|
-
const backup = join21(backupRoot, `${index}-${
|
|
52877
|
+
const backup = join21(backupRoot, `${index}-${sha3(change.path).slice(0, 12)}.backup`);
|
|
52592
52878
|
writeFileSync4(backup, change.before, { mode: 384, flag: "wx" });
|
|
52593
52879
|
if (readFileSync13(backup, "utf8") !== change.before)
|
|
52594
52880
|
throw new Error("Native configuration preservation readback failed");
|
|
@@ -52607,7 +52893,7 @@ function applyAgentIntegration(plan) {
|
|
|
52607
52893
|
}
|
|
52608
52894
|
recheckRootAliases(aliases);
|
|
52609
52895
|
for (const source of plan.observedNativeSources ?? [])
|
|
52610
|
-
if (
|
|
52896
|
+
if (sha3(readNativeBytes(source.path, 1024 * 1024)) !== source.sha256)
|
|
52611
52897
|
throw new Error("Native identity source changed during application");
|
|
52612
52898
|
if (plan.observedSettings && readOptional(plan.observedSettings.path) !== plan.observedSettings.before)
|
|
52613
52899
|
throw new Error("Native settings changed during witness application");
|
|
@@ -52619,7 +52905,7 @@ function applyAgentIntegration(plan) {
|
|
|
52619
52905
|
}
|
|
52620
52906
|
for (const agent of plan.managedAgentChecks?.agents ?? [])
|
|
52621
52907
|
assertManagedAgentBridge(agent, { home: plan.managedAgentChecks.home, dataDir: plan.dataDir, projectDir: plan.managedAgentChecks.home });
|
|
52622
|
-
atomicWrite2(join21(backupRoot, "receipt.json"), JSON.stringify({ version: 1, changes: written.map((change) => ({ path: change.path, beforeHash: change.before === null ? null :
|
|
52908
|
+
atomicWrite2(join21(backupRoot, "receipt.json"), JSON.stringify({ version: 1, changes: written.map((change) => ({ path: change.path, beforeHash: change.before === null ? null : sha3(change.before), afterHash: sha3(change.after) })), backups, ...aliases.length ? { rootAliases: aliases } : {} }) + `
|
|
52623
52909
|
`);
|
|
52624
52910
|
} catch (error) {
|
|
52625
52911
|
for (const change of written.reverse()) {
|
|
@@ -52698,8 +52984,8 @@ function archiveNativeSkills(inventory, options) {
|
|
|
52698
52984
|
const operationId = randomUUID5(), archiveRoot = join21(options.dataDir ?? getDataDir(), "migration", operationId, "native"), receiptPath = join21(archiveRoot, "receipt.json");
|
|
52699
52985
|
const entries = selected.map((entry, index) => ({
|
|
52700
52986
|
source: entry.vendor ? join21(entry.path, "SKILL.md") : entry.path,
|
|
52701
|
-
archive: join21(archiveRoot, `${index}-${
|
|
52702
|
-
hash: entry.vendor ?
|
|
52987
|
+
archive: join21(archiveRoot, `${index}-${sha3(entry.path).slice(0, 12)}`),
|
|
52988
|
+
hash: entry.vendor ? sha3(readNativeBytes(join21(entry.path, "SKILL.md"))) : entry.hash,
|
|
52703
52989
|
...entry.vendor ? { discoveryOnly: true } : {},
|
|
52704
52990
|
status: "planned"
|
|
52705
52991
|
}));
|
|
@@ -52710,7 +52996,7 @@ function archiveNativeSkills(inventory, options) {
|
|
|
52710
52996
|
const stat = lstatSync15(entry.archive);
|
|
52711
52997
|
if (entry.discoveryOnly ? !stat.isFile() : !stat.isDirectory())
|
|
52712
52998
|
throw new Error("Archive type changed");
|
|
52713
|
-
if ((entry.discoveryOnly ?
|
|
52999
|
+
if ((entry.discoveryOnly ? sha3(readNativeBytes(entry.archive)) : treeHash(entry.archive)) !== entry.hash)
|
|
52714
53000
|
throw new Error("Archive bytes changed");
|
|
52715
53001
|
};
|
|
52716
53002
|
assertSafePath(archiveRoot);
|
|
@@ -52830,7 +53116,7 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
|
|
|
52830
53116
|
throw new Error("NATIVE_SKILL_DRIFT: the hook selection profile differs from its managed binding; restart the native client after reviewing skills hook install");
|
|
52831
53117
|
if (agent === "hermes") {
|
|
52832
53118
|
const supervisor = binding.supervisors?.hermes;
|
|
52833
|
-
if (supervisor?.path !== join21(dataDir3, "agent-hooks", "hermes.js") || supervisor?.sha256 !==
|
|
53119
|
+
if (supervisor?.path !== join21(dataDir3, "agent-hooks", "hermes.js") || supervisor?.sha256 !== sha3(renderHermesSupervisor(command, profile)))
|
|
52834
53120
|
throw new Error("NATIVE_SKILL_DRIFT: Hermes supervisor binding changed; run skills hook install");
|
|
52835
53121
|
assertHermesProtection(home, config, command, profile, supervisor);
|
|
52836
53122
|
} else if (agent === "opencode") {
|
|
@@ -52946,7 +53232,7 @@ function assertNativeExportAllowed(dataDir3 = getDataDirReadOnly()) {
|
|
|
52946
53232
|
if (requiresCliSkillLoading(dataDir3))
|
|
52947
53233
|
throw new Error("NATIVE_SKILL_EXPORT_DISABLED: this station loads skills through the Skills CLI; use skills sync --selection-profile <id>");
|
|
52948
53234
|
}
|
|
52949
|
-
var
|
|
53235
|
+
var sha3 = (data) => createHash12("sha256").update(data).digest("hex"), HOOK_EVENTS, ROOTS, SKILLS_LOADING_POLICY = "Skills loading policy: discover skills with `skills list` or `skills search`, and read selected instructions with `skills load <slug>`. Use `skills sync` to refresh the shared profile. The only native skill is the owned skills-cli bridge. Create and edit payload skills in the Skills authoring workspace; do not copy payload instructions into native discovery folders. Context loading does not authorize execution; use `skills run` only when the task calls for running a skill.";
|
|
52950
53236
|
var init_agent_integration = __esm(() => {
|
|
52951
53237
|
init_codex_plugin_skill_controls();
|
|
52952
53238
|
init_codex_native_skill_catalog();
|
|
@@ -54528,7 +54814,7 @@ var init_selection_resolver = __esm(() => {
|
|
|
54528
54814
|
});
|
|
54529
54815
|
|
|
54530
54816
|
// src/lib/plugin-projection.ts
|
|
54531
|
-
import { createHash as
|
|
54817
|
+
import { createHash as createHash13 } from "crypto";
|
|
54532
54818
|
import { posix } from "path";
|
|
54533
54819
|
function pluginRefusal(message) {
|
|
54534
54820
|
throw new SkillSelectionError("PLUGIN_ADMISSION_REFUSED", message);
|
|
@@ -54721,7 +55007,7 @@ function buildPluginProjection(entries) {
|
|
|
54721
55007
|
files.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
54722
55008
|
return { manifest, payloads: manifest.payloads, files, witnesses: pluginFileWitnesses(files), originalTreeDigest, projectionTreeDigest: pluginTreeDigest(files), removed: removed.length ? pluginFileWitnesses(removed) : [] };
|
|
54723
55009
|
}
|
|
54724
|
-
var PLUGIN_PROJECTION_MANIFEST = "plugin-projection.json", PLUGIN_PROJECTION_LIMITS, pluginHash = (bytes) =>
|
|
55010
|
+
var PLUGIN_PROJECTION_MANIFEST = "plugin-projection.json", PLUGIN_PROJECTION_LIMITS, pluginHash = (bytes) => createHash13("sha256").update(bytes).digest("hex"), MANIFEST_FIELDS;
|
|
54725
55011
|
var init_plugin_projection = __esm(() => {
|
|
54726
55012
|
init_selection_cache();
|
|
54727
55013
|
PLUGIN_PROJECTION_LIMITS = Object.freeze({ files: 1024, bytes: 64 * 1024 * 1024, fileBytes: 16 * 1024 * 1024, metadataBytes: 512 * 1024, registrations: 64, history: 128 });
|
|
@@ -54729,7 +55015,7 @@ var init_plugin_projection = __esm(() => {
|
|
|
54729
55015
|
});
|
|
54730
55016
|
|
|
54731
55017
|
// src/lib/plugin-projection-store.ts
|
|
54732
|
-
import { createHash as
|
|
55018
|
+
import { createHash as createHash14, randomUUID as randomUUID6 } from "crypto";
|
|
54733
55019
|
import { constants as constants9, closeSync as closeSync9, fchmodSync, fstatSync as fstatSync9, fsyncSync as fsyncSync3, linkSync as linkSync2, lstatSync as lstatSync17, mkdirSync as mkdirSync9, openSync as openSync9, opendirSync as opendirSync4, readSync as readSync7, renameSync as renameSync5, rmdirSync as rmdirSync3, rmSync as rmSync4, unlinkSync as unlinkSync4, writeSync as writeSync2 } from "fs";
|
|
54734
55020
|
import { dirname as dirname13, isAbsolute as isAbsolute12, join as join29, parse as parse5, resolve as resolve12 } from "path";
|
|
54735
55021
|
function stat(path) {
|
|
@@ -54741,7 +55027,7 @@ function stat(path) {
|
|
|
54741
55027
|
return pluginRefusal("Cannot inspect plugin filesystem entry");
|
|
54742
55028
|
}
|
|
54743
55029
|
}
|
|
54744
|
-
function
|
|
55030
|
+
function canonical5(path) {
|
|
54745
55031
|
pluginNeed(typeof path === "string" && path.length <= 8192 && isAbsolute12(path) && resolve12(path) === path && !/[\x00-\x1f\x7f]/.test(path), "Plugin storage paths must be canonical absolute paths");
|
|
54746
55032
|
}
|
|
54747
55033
|
function owner(stats, system = false) {
|
|
@@ -54752,7 +55038,7 @@ function same3(left, right, identityOnly = false) {
|
|
|
54752
55038
|
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");
|
|
54753
55039
|
}
|
|
54754
55040
|
function ancestors(path, create3 = false) {
|
|
54755
|
-
|
|
55041
|
+
canonical5(path);
|
|
54756
55042
|
const result2 = [], parent = dirname13(path), filesystemRoot = parse5(parent).root;
|
|
54757
55043
|
let current = filesystemRoot;
|
|
54758
55044
|
for (const segment of ["", ...parent.slice(filesystemRoot.length).split("/").filter(Boolean)]) {
|
|
@@ -55067,7 +55353,7 @@ function pluginExecutableDigest(path) {
|
|
|
55067
55353
|
const opened = fstatSync9(fd, { bigint: true });
|
|
55068
55354
|
same3(before2, opened);
|
|
55069
55355
|
fileShape(opened, maximum, "executable");
|
|
55070
|
-
const hash2 =
|
|
55356
|
+
const hash2 = createHash14("sha256"), buffer = new Uint8Array(64 * 1024);
|
|
55071
55357
|
let remaining = Number(opened.size);
|
|
55072
55358
|
while (remaining > 0) {
|
|
55073
55359
|
const count = readSync7(fd, buffer, 0, Math.min(buffer.byteLength, remaining), null);
|
|
@@ -55650,21 +55936,21 @@ var init_plugin_discovery = __esm(() => {
|
|
|
55650
55936
|
});
|
|
55651
55937
|
|
|
55652
55938
|
// src/lib/claude-marketplace-registry.ts
|
|
55653
|
-
import { createHash as
|
|
55939
|
+
import { createHash as createHash15 } from "crypto";
|
|
55654
55940
|
import { closeSync as closeSync11, constants as constants11, fstatSync as fstatSync11, lstatSync as lstatSync19, openSync as openSync11, readSync as readSync9 } from "fs";
|
|
55655
55941
|
import { basename as basename8, dirname as dirname15, isAbsolute as isAbsolute15, resolve as resolve15 } from "path";
|
|
55656
|
-
function
|
|
55942
|
+
function need5(value, reason) {
|
|
55657
55943
|
if (!value)
|
|
55658
55944
|
throw new Error(`Claude marketplace registry ${reason}`);
|
|
55659
55945
|
}
|
|
55660
55946
|
function absolutePath3(value) {
|
|
55661
|
-
|
|
55947
|
+
need5(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute15(value) && resolve15(value) === value, "requires a normalized absolute path");
|
|
55662
55948
|
}
|
|
55663
55949
|
function parents2(path) {
|
|
55664
55950
|
const result2 = [];
|
|
55665
55951
|
for (let at2 = dirname15(path);; at2 = dirname15(at2)) {
|
|
55666
55952
|
const stat2 = lstatSync19(at2, { bigint: true });
|
|
55667
|
-
|
|
55953
|
+
need5(stat2.isDirectory() && !stat2.isSymbolicLink(), "path traverses a symlink or non-directory");
|
|
55668
55954
|
result2.push([at2, stat2]);
|
|
55669
55955
|
if (at2 === dirname15(at2))
|
|
55670
55956
|
return result2;
|
|
@@ -55672,15 +55958,15 @@ function parents2(path) {
|
|
|
55672
55958
|
}
|
|
55673
55959
|
function readRegistry2(path, budget) {
|
|
55674
55960
|
absolutePath3(path);
|
|
55675
|
-
|
|
55676
|
-
|
|
55961
|
+
need5(basename8(path) === "known_marketplaces.json", "requires known_marketplaces.json");
|
|
55962
|
+
need5(Number.isSafeInteger(budget.remaining) && budget.remaining >= 0, "has an invalid byte budget");
|
|
55677
55963
|
const ancestors2 = parents2(path), initial2 = lstatSync19(path, { bigint: true });
|
|
55678
|
-
|
|
55679
|
-
|
|
55964
|
+
need5(initial2.isFile() && !initial2.isSymbolicLink() && initial2.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
|
|
55965
|
+
need5(initial2.size <= BigInt(budget.remaining), "exceeds its aggregate byte limit");
|
|
55680
55966
|
const fd = openSync11(path, constants11.O_RDONLY | constants11.O_NOFOLLOW | constants11.O_NONBLOCK);
|
|
55681
55967
|
try {
|
|
55682
55968
|
const opened = fstatSync11(fd, { bigint: true });
|
|
55683
|
-
|
|
55969
|
+
need5(opened.isFile() && sameFile2(initial2, opened), "changed during open");
|
|
55684
55970
|
const bytes = Buffer.alloc(Number(opened.size) + 1);
|
|
55685
55971
|
let length = 0;
|
|
55686
55972
|
while (length < bytes.length) {
|
|
@@ -55690,10 +55976,10 @@ function readRegistry2(path, budget) {
|
|
|
55690
55976
|
length += count;
|
|
55691
55977
|
}
|
|
55692
55978
|
const after2 = fstatSync11(fd, { bigint: true }), current = lstatSync19(path, { bigint: true });
|
|
55693
|
-
|
|
55979
|
+
need5(current.isFile() && sameFile2(opened, after2) && sameFile2(after2, current) && BigInt(length) === opened.size, "changed during read");
|
|
55694
55980
|
for (const [ancestor, before2] of ancestors2) {
|
|
55695
55981
|
const now3 = lstatSync19(ancestor, { bigint: true });
|
|
55696
|
-
|
|
55982
|
+
need5(now3.isDirectory() && before2.dev === now3.dev && before2.ino === now3.ino && before2.mode === now3.mode, "parent changed during read");
|
|
55697
55983
|
}
|
|
55698
55984
|
budget.remaining -= length;
|
|
55699
55985
|
try {
|
|
@@ -55713,7 +55999,7 @@ function parse6(text2) {
|
|
|
55713
55999
|
at2++;
|
|
55714
56000
|
};
|
|
55715
56001
|
function string() {
|
|
55716
|
-
|
|
56002
|
+
need5(text2[at2] === '"', "contains invalid JSON");
|
|
55717
56003
|
const start = at2++;
|
|
55718
56004
|
while (at2 < text2.length) {
|
|
55719
56005
|
const character = text2[at2++];
|
|
@@ -55724,7 +56010,7 @@ function parse6(text2) {
|
|
|
55724
56010
|
} catch {
|
|
55725
56011
|
throw new Error("Claude marketplace registry contains invalid JSON string");
|
|
55726
56012
|
}
|
|
55727
|
-
|
|
56013
|
+
need5(value2.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.stringCharacters, "exceeds its string limit");
|
|
55728
56014
|
return value2;
|
|
55729
56015
|
}
|
|
55730
56016
|
if (character === "\\")
|
|
@@ -55733,7 +56019,7 @@ function parse6(text2) {
|
|
|
55733
56019
|
throw new Error("Claude marketplace registry contains an unterminated JSON string");
|
|
55734
56020
|
}
|
|
55735
56021
|
function value(depth) {
|
|
55736
|
-
|
|
56022
|
+
need5(depth <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.depth && ++nodes <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.nodes, "exceeds its nesting or node limit");
|
|
55737
56023
|
space();
|
|
55738
56024
|
const character = text2[at2];
|
|
55739
56025
|
if (character === '"')
|
|
@@ -55747,17 +56033,17 @@ function parse6(text2) {
|
|
|
55747
56033
|
if (object5) {
|
|
55748
56034
|
space();
|
|
55749
56035
|
const key = string();
|
|
55750
|
-
|
|
56036
|
+
need5(!keys2.has(key), "contains a duplicate JSON key");
|
|
55751
56037
|
keys2.add(key);
|
|
55752
56038
|
space();
|
|
55753
|
-
|
|
56039
|
+
need5(text2[at2++] === ":", "contains invalid JSON");
|
|
55754
56040
|
entries.push([key, value(depth + 1)]);
|
|
55755
56041
|
} else
|
|
55756
56042
|
items.push(value(depth + 1));
|
|
55757
56043
|
space();
|
|
55758
56044
|
if (text2[at2] === end)
|
|
55759
56045
|
break;
|
|
55760
|
-
|
|
56046
|
+
need5(text2[at2++] === ",", "contains invalid JSON");
|
|
55761
56047
|
}
|
|
55762
56048
|
at2++;
|
|
55763
56049
|
return object5 ? { kind: "object", entries } : { kind: "array", items };
|
|
@@ -55769,21 +56055,21 @@ function parse6(text2) {
|
|
|
55769
56055
|
}
|
|
55770
56056
|
numberPattern.lastIndex = at2;
|
|
55771
56057
|
const number = numberPattern.exec(text2);
|
|
55772
|
-
|
|
56058
|
+
need5(number, "contains invalid JSON");
|
|
55773
56059
|
at2 += number[0].length;
|
|
55774
56060
|
return { kind: "number", value: number[0] };
|
|
55775
56061
|
}
|
|
55776
56062
|
const root2 = value(0);
|
|
55777
56063
|
space();
|
|
55778
|
-
|
|
55779
|
-
|
|
56064
|
+
need5(at2 === text2.length && root2.kind === "object", "requires a JSON object without trailing content");
|
|
56065
|
+
need5(root2.entries.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.rows, "exceeds its marketplace row limit");
|
|
55780
56066
|
return root2;
|
|
55781
56067
|
}
|
|
55782
56068
|
function exactKeys(value, keys2) {
|
|
55783
56069
|
return value?.kind === "object" && value.entries.length === keys2.length && value.entries.every(([key]) => keys2.includes(key));
|
|
55784
56070
|
}
|
|
55785
56071
|
function textField(value) {
|
|
55786
|
-
|
|
56072
|
+
need5(value?.kind === "string" && value.value.length > 0 && !/[\x00-\x1f\x7f]/.test(value.value), "contains an invalid recognized field");
|
|
55787
56073
|
return value.value;
|
|
55788
56074
|
}
|
|
55789
56075
|
function normalizeRow(row, version = 1) {
|
|
@@ -55791,7 +56077,7 @@ function normalizeRow(row, version = 1) {
|
|
|
55791
56077
|
if (version !== 2 || !exactKeys(row, ["source", "installLocation", "lastUpdated", "autoUpdate"]))
|
|
55792
56078
|
return;
|
|
55793
56079
|
const autoUpdate = field(row, "autoUpdate");
|
|
55794
|
-
|
|
56080
|
+
need5(autoUpdate?.kind === "literal" && (autoUpdate.value === "true" || autoUpdate.value === "false"), "contains an invalid automatic-update preference");
|
|
55795
56081
|
}
|
|
55796
56082
|
const source = field(row, "source");
|
|
55797
56083
|
if (source?.kind !== "object")
|
|
@@ -55807,23 +56093,23 @@ function normalizeRow(row, version = 1) {
|
|
|
55807
56093
|
absolutePath3(sourceLocation);
|
|
55808
56094
|
absolutePath3(textField(field(row, "installLocation")));
|
|
55809
56095
|
const updated = textField(field(row, "lastUpdated"));
|
|
55810
|
-
|
|
56096
|
+
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");
|
|
55811
56097
|
const millis = Date.parse(updated);
|
|
55812
|
-
|
|
56098
|
+
need5(Number.isFinite(millis) && new Date(millis).toISOString() === updated, "contains an invalid recognized update timestamp");
|
|
55813
56099
|
row.entries = row.entries.map(([key, value]) => [key, key === "lastUpdated" ? { kind: "validated-update-time" } : value]);
|
|
55814
56100
|
}
|
|
55815
56101
|
function captureClaudeMarketplaceRegistry(path, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
55816
56102
|
const value = parse6(readRegistry2(path, budget));
|
|
55817
56103
|
for (const [, row] of value.entries)
|
|
55818
56104
|
normalizeRow(row);
|
|
55819
|
-
const sha2562 =
|
|
56105
|
+
const sha2562 = createHash15("sha256").update("hasna.skills.claude-marketplace-registry.v1\x00").update(JSON.stringify(value)).digest("hex");
|
|
55820
56106
|
return { path, hashMode: "claude-marketplace-registry", sha256: sha2562 };
|
|
55821
56107
|
}
|
|
55822
56108
|
function captureClaudeMarketplaceRegistryV2(path, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
55823
56109
|
const value = parse6(readRegistry2(path, budget));
|
|
55824
56110
|
for (const [, row] of value.entries)
|
|
55825
56111
|
normalizeRow(row, 2);
|
|
55826
|
-
const sha2562 =
|
|
56112
|
+
const sha2562 = createHash15("sha256").update("hasna.skills.claude-marketplace-registry.v2\x00").update(JSON.stringify(value)).digest("hex");
|
|
55827
56113
|
return { path, hashMode: "claude-marketplace-registry-v2", sha256: sha2562 };
|
|
55828
56114
|
}
|
|
55829
56115
|
var CLAUDE_MARKETPLACE_REGISTRY_LIMITS, 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, field = (object5, key) => object5.entries.find(([name]) => name === key)?.[1];
|
|
@@ -55833,17 +56119,17 @@ var init_claude_marketplace_registry = __esm(() => {
|
|
|
55833
56119
|
|
|
55834
56120
|
// src/lib/codex-hook-trust-files.ts
|
|
55835
56121
|
import { closeSync as closeSync12, constants as constants12, fstatSync as fstatSync12, fsyncSync as fsyncSync4, lstatSync as lstatSync20, openSync as openSync12, readSync as readSync10, writeFileSync as writeFileSync8 } from "fs";
|
|
55836
|
-
import { createHash as
|
|
56122
|
+
import { createHash as createHash16 } from "crypto";
|
|
55837
56123
|
import { dirname as dirname16 } from "path";
|
|
55838
|
-
function
|
|
56124
|
+
function need6(value, code) {
|
|
55839
56125
|
if (!value)
|
|
55840
56126
|
throw new Error(`CODEX_HOOK_TRUST_${code}`);
|
|
55841
56127
|
}
|
|
55842
56128
|
function safeParents(file) {
|
|
55843
56129
|
for (let p = dirname16(file);; p = dirname16(p)) {
|
|
55844
56130
|
const s = lstatSync20(p);
|
|
55845
|
-
|
|
55846
|
-
|
|
56131
|
+
need6(s.isDirectory() && !s.isSymbolicLink(), "UNSAFE_PARENT");
|
|
56132
|
+
need6((s.mode & 18) === 0 || s.uid === 0 && (s.mode & 512) !== 0, "UNSAFE_PARENT");
|
|
55847
56133
|
if (dirname16(p) === p)
|
|
55848
56134
|
break;
|
|
55849
56135
|
}
|
|
@@ -55852,12 +56138,12 @@ function snapshot(file, privateFile = false, options = {}) {
|
|
|
55852
56138
|
const readOnlyPackage = options.readOnlyPackage === true && !privateFile;
|
|
55853
56139
|
safeParents(file);
|
|
55854
56140
|
const initial2 = lstatSync20(file, { bigint: true });
|
|
55855
|
-
|
|
55856
|
-
|
|
56141
|
+
need6(initial2.isFile() && initial2.uid === BigInt(process.getuid()) && (initial2.nlink === 1n || readOnlyPackage && initial2.nlink > 1n) && (initial2.mode & 0o022n) === 0n && (!privateFile || (initial2.mode & 0o777n) === 0o600n), "UNSAFE_FILE");
|
|
56142
|
+
need6(initial2.size <= 8n * 1024n * 1024n, "FILE_BOUND");
|
|
55857
56143
|
const fd = openSync12(file, constants12.O_RDONLY | constants12.O_NOFOLLOW | constants12.O_NONBLOCK);
|
|
55858
56144
|
try {
|
|
55859
56145
|
const before2 = fstatSync12(fd, { bigint: true });
|
|
55860
|
-
|
|
56146
|
+
need6(sameStat(initial2, before2), "INPUT_CHANGED");
|
|
55861
56147
|
const bytes = Buffer.alloc(Number(before2.size) + 1);
|
|
55862
56148
|
let length = 0;
|
|
55863
56149
|
while (length < bytes.length) {
|
|
@@ -55866,16 +56152,16 @@ function snapshot(file, privateFile = false, options = {}) {
|
|
|
55866
56152
|
break;
|
|
55867
56153
|
length += n2;
|
|
55868
56154
|
}
|
|
55869
|
-
|
|
56155
|
+
need6(length === Number(before2.size) && sameStat(before2, fstatSync12(fd, { bigint: true })) && sameStat(before2, lstatSync20(file, { bigint: true })), "INPUT_CHANGED");
|
|
55870
56156
|
const content = bytes.subarray(0, length), text2 = new TextDecoder("utf-8", { fatal: true }).decode(content);
|
|
55871
|
-
return { file, privateFile, readOnlyPackage, text: text2, bytes: content, stat: before2, sha256:
|
|
56157
|
+
return { file, privateFile, readOnlyPackage, text: text2, bytes: content, stat: before2, sha256: createHash16("sha256").update(content).digest("hex") };
|
|
55872
56158
|
} finally {
|
|
55873
56159
|
closeSync12(fd);
|
|
55874
56160
|
}
|
|
55875
56161
|
}
|
|
55876
56162
|
function unchanged2(before2) {
|
|
55877
56163
|
const after2 = snapshot(before2.file, before2.privateFile, before2.readOnlyPackage ? { readOnlyPackage: true } : {});
|
|
55878
|
-
|
|
56164
|
+
need6(sameStat(before2.stat, after2.stat) && after2.sha256 === before2.sha256, "INPUT_CHANGED");
|
|
55879
56165
|
}
|
|
55880
56166
|
function save(file, content) {
|
|
55881
56167
|
safeParents(file);
|
|
@@ -55891,7 +56177,7 @@ var sameStat = (a, b) => ["dev", "ino", "uid", "nlink", "mode", "size", "mtimeNs
|
|
|
55891
56177
|
var init_codex_hook_trust_files = () => {};
|
|
55892
56178
|
|
|
55893
56179
|
// src/lib/codex-hook-trust-layout.ts
|
|
55894
|
-
import { isDeepStrictEqual as
|
|
56180
|
+
import { isDeepStrictEqual as isDeepStrictEqual5 } from "util";
|
|
55895
56181
|
function codexTrustTextWitness(text2, keys2, canonicalize = true) {
|
|
55896
56182
|
const parsed = Bun.TOML.parse(text2), wanted = new Set(keys2);
|
|
55897
56183
|
const headers = [...text2.matchAll(/^[ \t]*(\[[^\r\n]+\])[ \t]*(#[^\r\n]*)?(?:\r?\n|$)/gm)];
|
|
@@ -55956,7 +56242,7 @@ function codexTrustTextWitness(text2, keys2, canonicalize = true) {
|
|
|
55956
56242
|
if (expected.hooks)
|
|
55957
56243
|
delete expected.hooks.state;
|
|
55958
56244
|
try {
|
|
55959
|
-
if (!
|
|
56245
|
+
if (!isDeepStrictEqual5(prune(Bun.TOML.parse(noState)), prune(expected)))
|
|
55960
56246
|
throw fail2();
|
|
55961
56247
|
} catch {
|
|
55962
56248
|
throw fail2();
|
|
@@ -56026,55 +56312,55 @@ var init_codex_hook_trust_layout = () => {};
|
|
|
56026
56312
|
|
|
56027
56313
|
// src/lib/codex-hook-additions-review.ts
|
|
56028
56314
|
import { isAbsolute as isAbsolute16 } from "path";
|
|
56029
|
-
import { isDeepStrictEqual as
|
|
56315
|
+
import { isDeepStrictEqual as isDeepStrictEqual6 } from "util";
|
|
56030
56316
|
function exactKeys2(value, keys2) {
|
|
56031
|
-
|
|
56317
|
+
need6(value && typeof value === "object" && !Array.isArray(value) && isDeepStrictEqual6(Object.keys(value).sort(), [...keys2].sort()), "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
|
|
56032
56318
|
}
|
|
56033
56319
|
function readReviewedAdditionTrustStates(proof, before2, current, journalHooks) {
|
|
56034
56320
|
const captured = proofs.get(proof);
|
|
56035
|
-
|
|
56321
|
+
need6(!!captured && captured.before.file === before2.file && captured.before.sha256 === before2.sha256 && captured.current.file === current.file && captured.current.sha256 === current.sha256 && isDeepStrictEqual6(captured.journalHooks, journalHooks.map(({ key, currentHash }) => ({ key, currentHash }))), "RECONCILE_ADDITIONS_PROOF_CHANGED");
|
|
56036
56322
|
captured.recheck();
|
|
56037
56323
|
unchanged2(before2);
|
|
56038
56324
|
unchanged2(current);
|
|
56039
56325
|
return captured.states;
|
|
56040
56326
|
}
|
|
56041
56327
|
function reviewNativeHookAdditions(options) {
|
|
56042
|
-
|
|
56328
|
+
need6(isAbsolute16(options.path), "RECONCILE_ADDITIONS_REVIEW_PATH");
|
|
56043
56329
|
const reviewFile = snapshot(options.path, true), review = JSON.parse(reviewFile.text);
|
|
56044
56330
|
exactKeys2(review, ["version", "kind", "reason", "producerEvidence", "journalIntentSha256", "policySha256", "configCurrentSha256", "hooksCurrentSha256", "producerBefore", "additions"]);
|
|
56045
|
-
|
|
56331
|
+
need6((review.version === 1 || review.version === 2) && review.kind === "native-hook-additions" && text2(review.reason) && text2(review.producerEvidence), "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
|
|
56046
56332
|
for (const [name, expected] of [["journalIntentSha256", options.intent.sha256], ["policySha256", options.policy.sha256], ["configCurrentSha256", options.configCurrent.sha256], ["hooksCurrentSha256", options.hooksCurrent.sha256]])
|
|
56047
|
-
|
|
56333
|
+
need6(hash2(review[name]) && review[name] === expected, "RECONCILE_ADDITIONS_REVIEW_CHANGED");
|
|
56048
56334
|
exactKeys2(review.producerBefore, ["configPath", "configSha256", "hooksPath", "hooksSha256"]);
|
|
56049
56335
|
const before2 = review.producerBefore;
|
|
56050
|
-
|
|
56336
|
+
need6(isAbsolute16(before2.configPath) && isAbsolute16(before2.hooksPath) && hash2(before2.configSha256) && hash2(before2.hooksSha256), "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
|
|
56051
56337
|
const producerConfig = snapshot(before2.configPath, true), producerHooks = snapshot(before2.hooksPath, true);
|
|
56052
|
-
|
|
56338
|
+
need6(producerConfig.sha256 === before2.configSha256 && producerHooks.sha256 === before2.hooksSha256 && producerHooks.sha256 === options.hooksBefore.sha256, "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
|
|
56053
56339
|
const original = structure(options.configBefore.text), producer = structure(producerConfig.text), expectedProducer = structuredClone(original), originalKeys = options.journalHooks.map((hook) => hook.key);
|
|
56054
56340
|
expectedProducer.hooks ??= {};
|
|
56055
56341
|
expectedProducer.hooks.state ??= {};
|
|
56056
56342
|
for (const hook of options.journalHooks)
|
|
56057
56343
|
expectedProducer.hooks.state[hook.key] = { ...expectedProducer.hooks.state[hook.key], enabled: true, trusted_hash: hook.currentHash };
|
|
56058
|
-
|
|
56059
|
-
|
|
56344
|
+
need6(isDeepStrictEqual6(expectedProducer, producer) && codexTrustReconcileWitness(options.configBefore.text, originalKeys) === codexTrustReconcileWitness(producerConfig.text, originalKeys) && codexTrustUnmanagedSemantic(options.configBefore.text, originalKeys) === codexTrustUnmanagedSemantic(producerConfig.text, originalKeys), "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
|
|
56345
|
+
need6(Array.isArray(review.additions) && review.additions.length > 0 && review.additions.length <= 20, "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
|
|
56060
56346
|
const expectedHooks = JSON.parse(options.hooksBefore.text), currentHooks = JSON.parse(options.hooksCurrent.text), expectedConfig = structuredClone(producer);
|
|
56061
|
-
|
|
56347
|
+
need6(expectedHooks.hooks && typeof expectedHooks.hooks === "object" && !Array.isArray(expectedHooks.hooks), "RECONCILE_ADDITIONS_DECLARATIONS");
|
|
56062
56348
|
const added = [], states = [], seen = new Set, commands = new Set(options.recordedNativeHooks.map((hook) => hook.command));
|
|
56063
56349
|
for (const addition of review.additions) {
|
|
56064
56350
|
exactKeys2(addition, review.version === 1 ? ["event", "nativeHook"] : ["event", "nativeHook", "trustState"]);
|
|
56065
|
-
|
|
56351
|
+
need6(Object.hasOwn(review.version === 1 ? events : matchedEvents, addition.event), "RECONCILE_ADDITIONS_DECLARATIONS");
|
|
56066
56352
|
const { event, nativeHook: hook } = addition;
|
|
56067
56353
|
exactKeys2(hook, nativeKeys);
|
|
56068
56354
|
const groups = expectedHooks.hooks[event] ?? [];
|
|
56069
|
-
|
|
56355
|
+
need6(Array.isArray(groups), "RECONCILE_ADDITIONS_DECLARATIONS");
|
|
56070
56356
|
const key = `${options.nativeHooksPath}:${matchedEvents[event][1]}:${groups.length}:0`;
|
|
56071
|
-
|
|
56072
|
-
|
|
56357
|
+
need6(hook.key === key && !seen.has(key) && !options.recordedNativeHooks.some((originalHook) => originalHook.key === key) && !Object.hasOwn(expectedConfig.hooks.state, key), "RECONCILE_ADDITIONS_IDENTITY");
|
|
56358
|
+
need6(hook.eventName === matchedEvents[event][0] && hook.handlerType === "command" && (review.version === 2 ? v2Command(hook.command) : text2(hook.command, 16384)) && !commands.has(hook.command) && Number.isInteger(hook.timeoutSec) && hook.timeoutSec > 0 && hook.timeoutSec <= 60 && (event === "PreToolUse" ? text2(hook.matcher) : hook.matcher === null) && hook.async === false && hook.statusMessage === null && hook.additionalContextLimit === null && hook.sourcePath === options.nativeHooksPath && hook.source === "user" && hook.pluginId === null && hook.isManaged === false && /^sha256:[a-f0-9]{64}$/.test(hook.currentHash) && hook.enabled === true && hook.trustStatus === "trusted", "RECONCILE_ADDITIONS_IDENTITY");
|
|
56073
56359
|
let trustState = { enabled: true, trusted_hash: hook.currentHash };
|
|
56074
56360
|
if (review.version === 2) {
|
|
56075
56361
|
const state = addition.trustState;
|
|
56076
56362
|
exactKeys2(state, state && Object.hasOwn(state, "enabled") ? ["enabled", "trusted_hash"] : ["trusted_hash"]);
|
|
56077
|
-
|
|
56363
|
+
need6(state.trusted_hash === hook.currentHash && (!Object.hasOwn(state, "enabled") || state.enabled === true), "RECONCILE_ADDITIONS_TRUST_STATE");
|
|
56078
56364
|
trustState = { ...state };
|
|
56079
56365
|
}
|
|
56080
56366
|
seen.add(key);
|
|
@@ -56084,9 +56370,9 @@ function reviewNativeHookAdditions(options) {
|
|
|
56084
56370
|
expectedHooks.hooks[event] = [...groups, { ...event === "PreToolUse" ? { matcher: hook.matcher } : {}, hooks: [{ type: "command", command: hook.command, timeout: hook.timeoutSec }] }];
|
|
56085
56371
|
expectedConfig.hooks.state[key] = trustState;
|
|
56086
56372
|
}
|
|
56087
|
-
|
|
56373
|
+
need6(isDeepStrictEqual6(expectedHooks, currentHooks), "RECONCILE_ADDITIONS_DECLARATIONS");
|
|
56088
56374
|
const keys2 = added.map((hook) => hook.key);
|
|
56089
|
-
|
|
56375
|
+
need6(isDeepStrictEqual6(expectedConfig, structure(options.configCurrent.text)) && codexTrustReconcileWitness(producerConfig.text, keys2) === codexTrustReconcileWitness(options.configCurrent.text, keys2) && codexTrustUnmanagedSemantic(producerConfig.text, keys2) === codexTrustUnmanagedSemantic(options.configCurrent.text, keys2), "RECONCILE_ADDITIONS_CONFIG");
|
|
56090
56376
|
const inputs = [reviewFile, producerConfig, producerHooks, options.intent, options.policy, options.configBefore, options.configCurrent, options.hooksBefore, options.hooksCurrent];
|
|
56091
56377
|
const recheck = () => {
|
|
56092
56378
|
for (const input of inputs)
|
|
@@ -56108,8 +56394,8 @@ var init_codex_hook_additions_review = __esm(() => {
|
|
|
56108
56394
|
});
|
|
56109
56395
|
|
|
56110
56396
|
// src/lib/codex-hook-discovery-recovery.ts
|
|
56111
|
-
import { createHash as
|
|
56112
|
-
import { isDeepStrictEqual as
|
|
56397
|
+
import { createHash as createHash17 } from "crypto";
|
|
56398
|
+
import { isDeepStrictEqual as isDeepStrictEqual7 } from "util";
|
|
56113
56399
|
function createCodexHookDiscoveryRecovery(binding, before2, current, hooks, additions) {
|
|
56114
56400
|
const journalHooks = hooks.map(({ key, currentHash }) => ({ key, currentHash }));
|
|
56115
56401
|
const additionStates = additions ? readReviewedAdditionTrustStates(additions, before2, current, journalHooks) : [];
|
|
@@ -56120,16 +56406,16 @@ function createCodexHookDiscoveryRecovery(binding, before2, current, hooks, addi
|
|
|
56120
56406
|
const raw = binding.sources.filter((source) => source.path === current.file && source.hashMode === "bytes");
|
|
56121
56407
|
if (!raw.some((source) => source.sha256 !== current.sha256))
|
|
56122
56408
|
return;
|
|
56123
|
-
|
|
56124
|
-
|
|
56409
|
+
need6(binding.agent === "codex" && binding.method === "reviewed" && raw.length === 1 && raw[0].sha256 === before2.sha256 && before2.sha256 !== current.sha256, "RECONCILE_DISCOVERY_CONFIG_WITNESS");
|
|
56410
|
+
need6(raw[0].format === undefined && raw[0].fields === undefined && raw[0].managedPlugins === undefined, "RECONCILE_DISCOVERY_CONFIG_WITNESS");
|
|
56125
56411
|
const typed = binding.sources.filter((source) => source.path === current.file && source.format === "toml");
|
|
56126
|
-
|
|
56412
|
+
need6(typed.length === 1 && typed[0].hashMode === undefined && isDeepStrictEqual7(typed[0].fields, fields), "RECONCILE_DISCOVERY_TYPED_WITNESS");
|
|
56127
56413
|
const original = structure2(before2.text), actual = structure2(current.text);
|
|
56128
56414
|
const project = (value) => Object.fromEntries(fields.map((field2) => [field2, value[field2] ?? null]));
|
|
56129
|
-
const projection =
|
|
56130
|
-
|
|
56415
|
+
const projection = sha4(JSON.stringify(project(original)));
|
|
56416
|
+
need6(typed[0].sha256 === projection && sha4(JSON.stringify(project(actual))) === projection && isDeepStrictEqual7(project(original), project(actual)), "RECONCILE_DISCOVERY_TYPED_WITNESS");
|
|
56131
56417
|
const keys2 = [...journalHooks.map((hook) => hook.key), ...additionStates.map((hook) => hook.key)];
|
|
56132
|
-
|
|
56418
|
+
need6(journalHooks.length > 0 && keys2.length <= 100 && new Set(keys2).size === keys2.length && journalHooks.every((hook) => typeof hook.key === "string" && /^sha256:[a-f0-9]{64}$/.test(hook.currentHash)), "RECONCILE_DISCOVERY_TRUST_WITNESS");
|
|
56133
56419
|
const expected = structuredClone(original);
|
|
56134
56420
|
expected.hooks ??= {};
|
|
56135
56421
|
expected.hooks.state ??= {};
|
|
@@ -56137,16 +56423,16 @@ function createCodexHookDiscoveryRecovery(binding, before2, current, hooks, addi
|
|
|
56137
56423
|
expected.hooks.state[hook.key] = { ...expected.hooks.state[hook.key], enabled: true, trusted_hash: hook.currentHash };
|
|
56138
56424
|
for (const { key, state } of additionStates)
|
|
56139
56425
|
expected.hooks.state[key] = { ...state };
|
|
56140
|
-
|
|
56426
|
+
need6(isDeepStrictEqual7(expected, actual) && codexTrustReconcileWitness(before2.text, keys2) === codexTrustReconcileWitness(current.text, keys2) && codexTrustUnmanagedSemantic(before2.text, keys2) === codexTrustUnmanagedSemantic(current.text, keys2), "RECONCILE_DISCOVERY_TRUST_WITNESS");
|
|
56141
56427
|
unchanged2(before2);
|
|
56142
56428
|
unchanged2(current);
|
|
56143
|
-
const witness = Object.freeze({ configPath: current.file, beforeSha256: before2.sha256, currentSha256: current.sha256, discoverySha256:
|
|
56429
|
+
const witness = Object.freeze({ configPath: current.file, beforeSha256: before2.sha256, currentSha256: current.sha256, discoverySha256: sha4(JSON.stringify(binding)), typedProjectionSha256: projection });
|
|
56144
56430
|
proofs2.set(witness, { before: before2, current, recheckAdditions });
|
|
56145
56431
|
return witness;
|
|
56146
56432
|
}
|
|
56147
56433
|
function assertCodexHookDiscoveryRecovery(binding, witness) {
|
|
56148
56434
|
const proof = proofs2.get(witness);
|
|
56149
|
-
|
|
56435
|
+
need6(!!proof && binding.agent === "codex" && witness.discoverySha256 === sha4(JSON.stringify(binding)), "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
|
|
56150
56436
|
unchanged2(proof.before);
|
|
56151
56437
|
unchanged2(proof.current);
|
|
56152
56438
|
proof.recheckAdditions();
|
|
@@ -56155,23 +56441,24 @@ function verifiesCodexHookDiscoverySource(binding, source, currentDigest, witnes
|
|
|
56155
56441
|
if (!witness || source.path !== witness.configPath || source.hashMode !== "bytes")
|
|
56156
56442
|
return false;
|
|
56157
56443
|
assertCodexHookDiscoveryRecovery(binding, witness);
|
|
56158
|
-
|
|
56444
|
+
need6(source.sha256 === witness.beforeSha256 && currentDigest === witness.currentSha256, "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
|
|
56159
56445
|
return true;
|
|
56160
56446
|
}
|
|
56161
|
-
var
|
|
56447
|
+
var sha4 = (text3) => createHash17("sha256").update(text3).digest("hex"), fields, structure2 = (text3) => JSON.parse(JSON.stringify(Bun.TOML.parse(text3))), proofs2;
|
|
56162
56448
|
var init_codex_hook_discovery_recovery = __esm(() => {
|
|
56163
56449
|
init_codex_hook_trust_files();
|
|
56164
56450
|
init_codex_hook_trust_layout();
|
|
56165
56451
|
init_codex_hook_additions_review();
|
|
56166
|
-
|
|
56452
|
+
init_codex_settings_witness();
|
|
56453
|
+
fields = [...CODEX_DISCOVERY_PROJECTION_FIELDS];
|
|
56167
56454
|
proofs2 = new WeakMap;
|
|
56168
56455
|
});
|
|
56169
56456
|
|
|
56170
56457
|
// src/lib/agent-discovery.ts
|
|
56171
|
-
import { createHash as
|
|
56458
|
+
import { createHash as createHash18 } from "crypto";
|
|
56172
56459
|
import { lstatSync as lstatSync21, readFileSync as readFileSync18, readdirSync as readdirSync11, realpathSync as realpathSync7 } from "fs";
|
|
56173
56460
|
import { basename as basename9, dirname as dirname17, isAbsolute as isAbsolute17, join as join32, resolve as resolve16, sep as sep6 } from "path";
|
|
56174
|
-
import { isDeepStrictEqual as
|
|
56461
|
+
import { isDeepStrictEqual as isDeepStrictEqual8 } from "util";
|
|
56175
56462
|
function parseConfig(text3, path, toml = false) {
|
|
56176
56463
|
try {
|
|
56177
56464
|
const value = toml ? Bun.TOML.parse(text3) : JSON.parse(text3);
|
|
@@ -56203,14 +56490,26 @@ function read2(path, changes) {
|
|
|
56203
56490
|
throw new Error(`Unsupported or oversized native discovery input: ${path}`);
|
|
56204
56491
|
return readFileSync18(path, "utf8");
|
|
56205
56492
|
}
|
|
56493
|
+
function projectNativeDiscoveryFields(text3, format, fields2, path) {
|
|
56494
|
+
const object5 = format === "yaml" ? parseHermesConfig(text3) : parseConfig(text3, path, format === "toml");
|
|
56495
|
+
if (!object5 || typeof object5 !== "object" || Array.isArray(object5))
|
|
56496
|
+
throw new Error("Expected native discovery configuration object");
|
|
56497
|
+
return digest(JSON.stringify(Object.fromEntries(fields2.map((field2) => [field2, object5[field2] ?? null]))));
|
|
56498
|
+
}
|
|
56499
|
+
function isSupersededCodexProjection(agent, configPath, source) {
|
|
56500
|
+
return agent === "codex" && source.path === configPath && source.format === "toml" && isDeepStrictEqual8(source.fields, [...CODEX_DISCOVERY_PROJECTION_FIELDS]);
|
|
56501
|
+
}
|
|
56502
|
+
function supersedesCodexProjection(sources, configPath) {
|
|
56503
|
+
return sources.some((source) => source.path === configPath && source.hashMode === "codex-settings-v2");
|
|
56504
|
+
}
|
|
56206
56505
|
function projected(source, changes, budget = discoveryByteBudget()) {
|
|
56207
|
-
if (source.hashMode === "codex-settings-v1") {
|
|
56506
|
+
if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2") {
|
|
56208
56507
|
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
56209
56508
|
throw new Error("Codex settings witnesses require exact typed metadata");
|
|
56210
|
-
const current = captureCodexSettings(source.path, budget).sha256;
|
|
56509
|
+
const current = (source.hashMode === "codex-settings-v2" ? captureCodexSettingsV2 : captureCodexSettings)(source.path, budget).sha256;
|
|
56211
56510
|
if (current !== source.sha256)
|
|
56212
56511
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
56213
|
-
return changes?.has(source.path) ? hashCodexSettingsReplacement(changes.get(source.path), budget) : current;
|
|
56512
|
+
return changes?.has(source.path) ? (source.hashMode === "codex-settings-v2" ? hashCodexSettingsReplacementV2 : hashCodexSettingsReplacement)(changes.get(source.path), budget) : current;
|
|
56214
56513
|
}
|
|
56215
56514
|
if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") {
|
|
56216
56515
|
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
@@ -56249,10 +56548,7 @@ function projected(source, changes, budget = discoveryByteBudget()) {
|
|
|
56249
56548
|
return null;
|
|
56250
56549
|
if (!source.format)
|
|
56251
56550
|
return digest(text3);
|
|
56252
|
-
|
|
56253
|
-
if (!object5 || typeof object5 !== "object" || Array.isArray(object5))
|
|
56254
|
-
throw new Error("Expected native discovery configuration object");
|
|
56255
|
-
return digest(JSON.stringify(Object.fromEntries((source.fields ?? []).map((field2) => [field2, object5[field2] ?? null]))));
|
|
56551
|
+
return projectNativeDiscoveryFields(text3, source.format, source.fields ?? [], source.path);
|
|
56256
56552
|
}
|
|
56257
56553
|
function verifyAgentDiscovery(binding, codexRecovery) {
|
|
56258
56554
|
if (codexRecovery)
|
|
@@ -56280,7 +56576,7 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
56280
56576
|
safe4(root2);
|
|
56281
56577
|
}
|
|
56282
56578
|
function assertMarketplaceBinding(binding, source) {
|
|
56283
|
-
if (source.hashMode === "codex-settings-v1" && (binding.agent !== "codex" || binding.method !== "reviewed" || basename9(source.path) !== "config.toml"))
|
|
56579
|
+
if ((source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2") && (binding.agent !== "codex" || binding.method !== "reviewed" || basename9(source.path) !== "config.toml"))
|
|
56284
56580
|
throw new Error("Codex settings witnesses require explicit reviewed Codex configuration");
|
|
56285
56581
|
if ((source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") && (binding.agent !== "claude" || binding.method !== "reviewed" || basename9(source.path) !== "settings.json"))
|
|
56286
56582
|
throw new Error("Claude settings witnesses require explicit reviewed Claude configuration");
|
|
@@ -56297,8 +56593,8 @@ function rebindAgentDiscovery(binding, changes) {
|
|
|
56297
56593
|
return { ...source, sha256: sha2562 };
|
|
56298
56594
|
}) };
|
|
56299
56595
|
}
|
|
56300
|
-
function assertProjectDiscovery(agent, directories, home,
|
|
56301
|
-
const homeConfigPath =
|
|
56596
|
+
function assertProjectDiscovery(agent, directories, home, canonical6 = resolve16, reviewed) {
|
|
56597
|
+
const homeConfigPath = canonical6(agentDiscoveryConfigPath(home, agent));
|
|
56302
56598
|
for (const directory of directories) {
|
|
56303
56599
|
const isHome = resolve16(directory) === resolve16(home);
|
|
56304
56600
|
if (agent === "hermes") {
|
|
@@ -56309,7 +56605,7 @@ function assertProjectDiscovery(agent, directories, home, canonical5 = resolve16
|
|
|
56309
56605
|
continue;
|
|
56310
56606
|
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"];
|
|
56311
56607
|
for (const suffix of paths) {
|
|
56312
|
-
const path =
|
|
56608
|
+
const path = canonical6(join32(directory, suffix)), raw = read2(path);
|
|
56313
56609
|
if (raw === null)
|
|
56314
56610
|
continue;
|
|
56315
56611
|
const isRootAliasedHomeConfig = agent === "claude" && suffix === ".claude/settings.json" || agent === "codex" && suffix === ".codex/config.toml";
|
|
@@ -56325,14 +56621,14 @@ function assertProjectDiscovery(agent, directories, home, canonical5 = resolve16
|
|
|
56325
56621
|
const managed = reviewed.sources.flatMap((source) => source.hashMode === "claude-plugin-registry" ? source.managedPlugins ?? [] : []);
|
|
56326
56622
|
if (exact && projected(exact) === exact.sha256 && managed.length) {
|
|
56327
56623
|
const bindings = managed.map((item) => readPluginBinding(item.storeRoot, item.bindingId));
|
|
56328
|
-
admittedPlugins = Object.entries(config.enabledPlugins).every(([id, enabled]) => typeof enabled === "boolean" && bindings.some((binding) => binding.target.pluginId === id && binding.target.registrations.some((scope) => scope.scope === "project" && scope.projectPath ===
|
|
56624
|
+
admittedPlugins = Object.entries(config.enabledPlugins).every(([id, enabled]) => typeof enabled === "boolean" && bindings.some((binding) => binding.target.pluginId === id && binding.target.registrations.some((scope) => scope.scope === "project" && scope.projectPath === canonical6(directory))));
|
|
56329
56625
|
}
|
|
56330
56626
|
}
|
|
56331
56627
|
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)))
|
|
56332
56628
|
throw new Error(`NATIVE_SKILL_DRIFT: higher-precedence project skill or hook configuration requires review: ${path}`);
|
|
56333
56629
|
}
|
|
56334
56630
|
if (agent === "claude") {
|
|
56335
|
-
const commands =
|
|
56631
|
+
const commands = canonical6(join32(directory, ".claude/commands"));
|
|
56336
56632
|
safe4(commands);
|
|
56337
56633
|
if (lstatSync21(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync11(commands).length)
|
|
56338
56634
|
throw new Error("NATIVE_SKILL_DRIFT: legacy project command discovery requires a dedicated format adapter");
|
|
@@ -56343,10 +56639,10 @@ function agentDiscoveryConfigPath(home, agent) {
|
|
|
56343
56639
|
return join32(home, agent === "hermes" ? ".hermes/config.yaml" : agent === "opencode" ? ".config/opencode/opencode.json" : `.${agent}/${agent === "codex" ? "config.toml" : agent === "cursor" ? "hooks.json" : "settings.json"}`);
|
|
56344
56640
|
}
|
|
56345
56641
|
function resolveAgentDiscovery(options) {
|
|
56346
|
-
const
|
|
56642
|
+
const canonical6 = options.canonical ?? resolve16, home = resolve16(options.home), agent = options.agent;
|
|
56347
56643
|
const sources = [], roots = new Set, builtinNames = [];
|
|
56348
56644
|
const witness = (path, format, fields2) => {
|
|
56349
|
-
const source = { path:
|
|
56645
|
+
const source = { path: canonical6(path), sha256: null, ...format ? { format, fields: fields2 } : {} };
|
|
56350
56646
|
source.sha256 = projected(source);
|
|
56351
56647
|
sources.push(source);
|
|
56352
56648
|
return read2(source.path);
|
|
@@ -56354,7 +56650,7 @@ function resolveAgentDiscovery(options) {
|
|
|
56354
56650
|
if (agent === "hermes")
|
|
56355
56651
|
assertHermesEnvironment(home);
|
|
56356
56652
|
const configPath = agentDiscoveryConfigPath(home, agent);
|
|
56357
|
-
const configText = witness(configPath, agent === "hermes" ? "yaml" : agent === "codex" ? "toml" : "json", agent === "hermes" ? ["skills", "plugins", "hooks"] : agent === "claude" ? ["enabledPlugins", "extraKnownMarketplaces"] : agent === "codex" ? [
|
|
56653
|
+
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"]);
|
|
56358
56654
|
const config = configText === null ? {} : agent === "hermes" ? parseHermesConfig(configText) : parseConfig(configText, configPath, agent === "codex");
|
|
56359
56655
|
const unresolved = (detail) => {
|
|
56360
56656
|
throw new Error(`Native discovery is unresolved (${agent}: ${detail}); provide a reviewed --discovery-inputs file`);
|
|
@@ -56413,11 +56709,12 @@ function resolveAgentDiscovery(options) {
|
|
|
56413
56709
|
if (retained.agent !== agent || retained.method !== "reviewed")
|
|
56414
56710
|
unresolved("invalid retained review");
|
|
56415
56711
|
verifyAgentDiscovery(retained);
|
|
56416
|
-
if (!retained.sources.some((source) => source.path ===
|
|
56712
|
+
if (!retained.sources.some((source) => source.path === canonical6(configPath) && source.format === undefined && source.fields === undefined))
|
|
56417
56713
|
unresolved("retained review is missing the full agent configuration source");
|
|
56418
|
-
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 !==
|
|
56714
|
+
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)))
|
|
56419
56715
|
unresolved("retained settings witness names another configuration source");
|
|
56420
|
-
|
|
56716
|
+
const covered = supersedesCodexProjection(retained.sources, canonical6(configPath)) ? sources.filter((source) => !isSupersededCodexProjection(agent, canonical6(configPath), source)) : sources;
|
|
56717
|
+
if (covered.some((source) => !retained.sources.some((saved) => isDeepStrictEqual8(saved, source))) || [...roots].some((root2) => !retained.roots.includes(root2)) || agent === "gemini" && JSON.stringify(retained.builtinNames) !== JSON.stringify(builtinNames))
|
|
56421
56718
|
unresolved("retained review is missing current runtime discovery coverage");
|
|
56422
56719
|
return retained;
|
|
56423
56720
|
}
|
|
@@ -56431,14 +56728,15 @@ function resolveAgentDiscovery(options) {
|
|
|
56431
56728
|
if (review.sources.some((source) => source.format !== undefined || source.fields !== undefined))
|
|
56432
56729
|
throw new Error("Explicit discovery reviews require full source-file hashes");
|
|
56433
56730
|
verifyAgentDiscovery(supplied);
|
|
56434
|
-
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 !==
|
|
56731
|
+
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)))
|
|
56435
56732
|
throw new Error("Semantic settings witnesses must name the configured Claude configuration source");
|
|
56436
|
-
if (!review.sources.some((source) => source.path ===
|
|
56733
|
+
if (!review.sources.some((source) => source.path === canonical6(configPath)))
|
|
56437
56734
|
throw new Error("Discovery review must include the agent configuration source");
|
|
56438
|
-
|
|
56735
|
+
const reviewedSources = supersedesCodexProjection(review.sources, canonical6(configPath)) ? sources.filter((source) => !isSupersededCodexProjection(agent, canonical6(configPath), source)) : sources;
|
|
56736
|
+
return { ...supplied, roots: [...new Set([...roots, ...supplied.roots])].sort(), sources: [...reviewedSources, ...review.sources], ...agent === "gemini" ? { builtinNames } : {} };
|
|
56439
56737
|
}
|
|
56440
56738
|
function plugin(root2) {
|
|
56441
|
-
root2 =
|
|
56739
|
+
root2 = canonical6(root2);
|
|
56442
56740
|
safe4(root2);
|
|
56443
56741
|
const manifestPath = join32(root2, agent === "claude" ? ".claude-plugin/plugin.json" : ".codex-plugin/plugin.json");
|
|
56444
56742
|
const raw = witness(manifestPath);
|
|
@@ -56470,7 +56768,7 @@ function resolveAgentDiscovery(options) {
|
|
|
56470
56768
|
if (agent === "claude") {
|
|
56471
56769
|
const registrations = witness(join32(home, ".claude/plugins/installed_plugins.json"));
|
|
56472
56770
|
const installed = registrations === null ? {} : parseConfig(registrations, join32(home, ".claude/plugins/installed_plugins.json")).plugins;
|
|
56473
|
-
const commands =
|
|
56771
|
+
const commands = canonical6(join32(home, ".claude/commands"));
|
|
56474
56772
|
safe4(commands);
|
|
56475
56773
|
if (lstatSync21(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync11(commands).length)
|
|
56476
56774
|
unresolved("legacy home command discovery requires a dedicated format adapter");
|
|
@@ -56544,9 +56842,9 @@ function resolveAgentDiscovery(options) {
|
|
|
56544
56842
|
roots.add(join32(root2, "skills"));
|
|
56545
56843
|
}
|
|
56546
56844
|
}
|
|
56547
|
-
return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join32(home, ".hermes/plugins"), join32(home, ".hermes/hermes-agent")].map((path) =>
|
|
56845
|
+
return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join32(home, ".hermes/plugins"), join32(home, ".hermes/hermes-agent")].map((path) => canonical6(path))) } : {} };
|
|
56548
56846
|
}
|
|
56549
|
-
var digest = (text3) =>
|
|
56847
|
+
var digest = (text3) => createHash18("sha256").update(text3).digest("hex");
|
|
56550
56848
|
var init_agent_discovery = __esm(() => {
|
|
56551
56849
|
init_agent_policy_limits();
|
|
56552
56850
|
init_agent_hermes();
|
|
@@ -56679,7 +56977,7 @@ import {
|
|
|
56679
56977
|
statSync as statSync11,
|
|
56680
56978
|
writeFileSync as writeFileSync9
|
|
56681
56979
|
} from "fs";
|
|
56682
|
-
import { basename as basename11, dirname as dirname19, isAbsolute as isAbsolute18, join as join34, normalize as
|
|
56980
|
+
import { basename as basename11, dirname as dirname19, isAbsolute as isAbsolute18, join as join34, normalize as normalize4, relative as relative6, resolve as resolve18, sep as sep8 } from "path";
|
|
56683
56981
|
function getPortableSkillsRoot(options = {}) {
|
|
56684
56982
|
return resolvePortableSkillsRoot(options, true);
|
|
56685
56983
|
}
|
|
@@ -56777,7 +57075,7 @@ function scaffoldPortableSkill(name, options = {}) {
|
|
|
56777
57075
|
return { name: skillName, path: skillPath, manifest, created: true };
|
|
56778
57076
|
}
|
|
56779
57077
|
function portPortableSkillDirectory(sourceDir, options = {}) {
|
|
56780
|
-
const absoluteSource =
|
|
57078
|
+
const absoluteSource = normalize4(sourceDir);
|
|
56781
57079
|
if (!existsSync18(absoluteSource) || !statSync11(absoluteSource).isDirectory()) {
|
|
56782
57080
|
throw new Error(`Import directory not found: ${sourceDir}`);
|
|
56783
57081
|
}
|
|
@@ -56844,7 +57142,7 @@ function assertDisjointImportPaths(source, destination) {
|
|
|
56844
57142
|
}
|
|
56845
57143
|
}
|
|
56846
57144
|
function portPortableSkill(sourcePath, options = {}) {
|
|
56847
|
-
const absoluteSource =
|
|
57145
|
+
const absoluteSource = normalize4(sourcePath);
|
|
56848
57146
|
if (!existsSync18(absoluteSource) || !statSync11(absoluteSource).isDirectory()) {
|
|
56849
57147
|
throw new Error(`Skill source directory not found: ${sourcePath}`);
|
|
56850
57148
|
}
|
|
@@ -57056,7 +57354,7 @@ function safeIsDirectory(path) {
|
|
|
57056
57354
|
function isSafeRelativePath2(value) {
|
|
57057
57355
|
if (!value.trim() || isAbsolute18(value))
|
|
57058
57356
|
return false;
|
|
57059
|
-
const normalized =
|
|
57357
|
+
const normalized = normalize4(value).replace(/\\/g, "/");
|
|
57060
57358
|
return normalized !== ".." && !normalized.startsWith("../") && !normalized.includes("/../");
|
|
57061
57359
|
}
|
|
57062
57360
|
function add4(target, code, message) {
|
|
@@ -59482,7 +59780,7 @@ var init_remote_workspace_selection = __esm(() => {
|
|
|
59482
59780
|
});
|
|
59483
59781
|
|
|
59484
59782
|
// src/lib/remote-private-publications.ts
|
|
59485
|
-
import { createHash as
|
|
59783
|
+
import { createHash as createHash19 } from "crypto";
|
|
59486
59784
|
function checkedPublicationDeclaration(value) {
|
|
59487
59785
|
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 || !hash3(value.archiveSha256) || !Number.isSafeInteger(value.archiveByteSize) || Number(value.archiveByteSize) < 1 || Number(value.archiveByteSize) > PRIVATE_PUBLICATION_MAX_BYTES)
|
|
59488
59786
|
return bad();
|
|
@@ -59743,7 +60041,7 @@ var PRIVATE_PUBLICATION_MAX_BYTES, failures, PrivatePublicationError, bad = () =
|
|
|
59743
60041
|
throw new PrivatePublicationError("INVALID_PUBLICATION_INPUT", "Invalid publication input or recovery data.");
|
|
59744
60042
|
}, invalid3 = () => {
|
|
59745
60043
|
throw new PrivatePublicationError("INVALID_PUBLICATION_RESPONSE", "The server returned an invalid publication result.");
|
|
59746
|
-
}, publicationUuid = (v) => typeof v === "string" && /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(v), hash3 = (v) => typeof v === "string" && /^[a-f0-9]{64}$/.test(v), record4 = (v) => !!v && typeof v === "object" && !Array.isArray(v), exact = (v, keys2) => record4(v) && Object.keys(v).sort().join(",") === keys2.sort().join(","), date = (v) => typeof v === "string" && /^\d{4}-\d\d-\d\dT[0-9:.]+(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/.test(v) && Number.isFinite(Date.parse(v)), publicationSha256 = (bytes) =>
|
|
60044
|
+
}, publicationUuid = (v) => typeof v === "string" && /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(v), hash3 = (v) => typeof v === "string" && /^[a-f0-9]{64}$/.test(v), record4 = (v) => !!v && typeof v === "object" && !Array.isArray(v), exact = (v, keys2) => record4(v) && Object.keys(v).sort().join(",") === keys2.sort().join(","), date = (v) => typeof v === "string" && /^\d{4}-\d\d-\d\dT[0-9:.]+(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/.test(v) && Number.isFinite(Date.parse(v)), publicationSha256 = (bytes) => createHash19("sha256").update(bytes).digest("hex");
|
|
59747
60045
|
var init_remote_private_publications = __esm(() => {
|
|
59748
60046
|
init_fleet_credentials();
|
|
59749
60047
|
init_remote_workspace_selection();
|
|
@@ -63282,15 +63580,15 @@ var init_schemas = __esm(() => {
|
|
|
63282
63580
|
} catch (_err) {}
|
|
63283
63581
|
}
|
|
63284
63582
|
const input = payload.value;
|
|
63285
|
-
const
|
|
63286
|
-
const isValidDate =
|
|
63583
|
+
const isDate3 = input instanceof Date;
|
|
63584
|
+
const isValidDate = isDate3 && !Number.isNaN(input.getTime());
|
|
63287
63585
|
if (isValidDate)
|
|
63288
63586
|
return payload;
|
|
63289
63587
|
payload.issues.push({
|
|
63290
63588
|
expected: "date",
|
|
63291
63589
|
code: "invalid_type",
|
|
63292
63590
|
input,
|
|
63293
|
-
...
|
|
63591
|
+
...isDate3 ? { received: "Invalid Date" } : {},
|
|
63294
63592
|
inst
|
|
63295
63593
|
});
|
|
63296
63594
|
return payload;
|
|
@@ -79132,7 +79430,7 @@ var init_v4 = __esm(() => {
|
|
|
79132
79430
|
});
|
|
79133
79431
|
|
|
79134
79432
|
// src/lib/canonical-json.ts
|
|
79135
|
-
import { createHash as
|
|
79433
|
+
import { createHash as createHash20 } from "crypto";
|
|
79136
79434
|
function canonicalJson2(value, maximumBytes = 2 * 1024 * 1024) {
|
|
79137
79435
|
return canonicalJsonAtDepth(value, maximumBytes, 64);
|
|
79138
79436
|
}
|
|
@@ -79176,7 +79474,7 @@ function canonicalJsonAtDepth(value, maximumBytes, maximumDepth) {
|
|
|
79176
79474
|
return visit3(value, 0);
|
|
79177
79475
|
}
|
|
79178
79476
|
function canonicalJsonSha256(value, maximumBytes) {
|
|
79179
|
-
return
|
|
79477
|
+
return createHash20("sha256").update(canonicalJson2(value, maximumBytes)).digest("hex");
|
|
79180
79478
|
}
|
|
79181
79479
|
var init_canonical_json = () => {};
|
|
79182
79480
|
|
|
@@ -79511,7 +79809,7 @@ var init_remote_recurring = __esm(() => {
|
|
|
79511
79809
|
|
|
79512
79810
|
// src/lib/remote-run-contract.ts
|
|
79513
79811
|
function normalizeRemoteSkillRunContract(payload, fallbackSkill) {
|
|
79514
|
-
const record8 =
|
|
79812
|
+
const record8 = isRecord4(payload) ? payload : {};
|
|
79515
79813
|
return {
|
|
79516
79814
|
contractVersion: REMOTE_SKILL_RUN_CONTRACT_VERSION,
|
|
79517
79815
|
...pickString(record8, "id"),
|
|
@@ -79533,7 +79831,7 @@ function normalizeRemoteSkillRunContract(payload, fallbackSkill) {
|
|
|
79533
79831
|
...hasOwn(record8, "details") ? { details: record8.details } : {}
|
|
79534
79832
|
};
|
|
79535
79833
|
}
|
|
79536
|
-
function
|
|
79834
|
+
function isRecord4(value) {
|
|
79537
79835
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
79538
79836
|
}
|
|
79539
79837
|
function hasOwn(record8, key) {
|
|
@@ -79672,7 +79970,7 @@ var init_remote_credit_checkout = __esm(() => {
|
|
|
79672
79970
|
|
|
79673
79971
|
// src/lib/remote-profile.ts
|
|
79674
79972
|
function customerNamePatch(input2, field2) {
|
|
79675
|
-
if (!
|
|
79973
|
+
if (!isRecord5(input2) || Object.keys(input2).length !== 1 || !Object.hasOwn(input2, field2))
|
|
79676
79974
|
throw new Error("Provide only the requested name field.");
|
|
79677
79975
|
const value = input2[field2];
|
|
79678
79976
|
if (typeof value !== "string" || /[\p{Cc}\p{Cs}\u2028\u2029]/u.test(value) || !value.trim() || [...value.trim()].length > 100) {
|
|
@@ -79680,22 +79978,22 @@ function customerNamePatch(input2, field2) {
|
|
|
79680
79978
|
}
|
|
79681
79979
|
return { [field2]: value.trim() };
|
|
79682
79980
|
}
|
|
79683
|
-
function
|
|
79981
|
+
function isRecord5(value) {
|
|
79684
79982
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
79685
79983
|
}
|
|
79686
79984
|
function string4(value) {
|
|
79687
79985
|
return typeof value === "string" && value.length > 0;
|
|
79688
79986
|
}
|
|
79689
79987
|
function parseUpdatedProfile(value) {
|
|
79690
|
-
const user =
|
|
79691
|
-
if (!
|
|
79988
|
+
const user = isRecord5(value) && value.user;
|
|
79989
|
+
if (!isRecord5(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)) {
|
|
79692
79990
|
throw new Error("The server returned an invalid account profile.");
|
|
79693
79991
|
}
|
|
79694
79992
|
return { user: { id: user.id, email: user.email, displayName: user.displayName, role: user.role } };
|
|
79695
79993
|
}
|
|
79696
79994
|
function parseUpdatedWorkspace(value) {
|
|
79697
|
-
const organization2 =
|
|
79698
|
-
if (!
|
|
79995
|
+
const organization2 = isRecord5(value) && value.organization;
|
|
79996
|
+
if (!isRecord5(organization2) || !string4(organization2.id) || !string4(organization2.slug) || !string4(organization2.name)) {
|
|
79699
79997
|
throw new Error("The server returned an invalid workspace.");
|
|
79700
79998
|
}
|
|
79701
79999
|
return { organization: { id: organization2.id, slug: organization2.slug, name: organization2.name } };
|
|
@@ -80877,7 +81175,7 @@ async function requestAuthApi(instance, path, options) {
|
|
|
80877
81175
|
const text4 = await res.text();
|
|
80878
81176
|
const body = text4 ? parseJsonBody(text4) : {};
|
|
80879
81177
|
if (!res.ok) {
|
|
80880
|
-
const record9 =
|
|
81178
|
+
const record9 = isRecord6(body) ? body : {};
|
|
80881
81179
|
const detail = typeof record9.detail === "string" ? record9.detail : undefined;
|
|
80882
81180
|
const error61 = typeof record9.error === "string" ? record9.error : undefined;
|
|
80883
81181
|
const code = typeof record9.code === "string" ? record9.code : undefined;
|
|
@@ -80905,7 +81203,7 @@ function condenseErrorBody(text4) {
|
|
|
80905
81203
|
return collapsed;
|
|
80906
81204
|
return `${collapsed.slice(0, MAX_ERROR_DETAIL_LENGTH - 1).trimEnd()}\u2026`;
|
|
80907
81205
|
}
|
|
80908
|
-
function
|
|
81206
|
+
function isRecord6(value) {
|
|
80909
81207
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
80910
81208
|
}
|
|
80911
81209
|
|
|
@@ -81090,10 +81388,10 @@ var init_remote_auth = __esm(() => {
|
|
|
81090
81388
|
});
|
|
81091
81389
|
|
|
81092
81390
|
// src/lib/sign-in.ts
|
|
81093
|
-
import { createHash as
|
|
81391
|
+
import { createHash as createHash21 } from "crypto";
|
|
81094
81392
|
import { chmodSync as chmodSync3, mkdirSync as mkdirSync12, readFileSync as readFileSync21, readdirSync as readdirSync14, renameSync as renameSync8, unlinkSync as unlinkSync6, writeFileSync as writeFileSync11 } from "fs";
|
|
81095
81393
|
import { basename as basename13, dirname as dirname21, join as join37 } from "path";
|
|
81096
|
-
function
|
|
81394
|
+
function isRecord7(value) {
|
|
81097
81395
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
81098
81396
|
}
|
|
81099
81397
|
function boundedText(value, max2 = 2048) {
|
|
@@ -81118,7 +81416,7 @@ function clampIntervalMs(seconds) {
|
|
|
81118
81416
|
return Math.min(MAX_INTERVAL_MS, Math.max(MIN_INTERVAL_MS, Math.round(seconds * 1000)));
|
|
81119
81417
|
}
|
|
81120
81418
|
function parseDeviceAuthorizationStart(body) {
|
|
81121
|
-
const record9 =
|
|
81419
|
+
const record9 = isRecord7(body) ? body : {};
|
|
81122
81420
|
if (typeof record9.error === "string") {
|
|
81123
81421
|
throw new Error(typeof record9.detail === "string" ? record9.detail : record9.error);
|
|
81124
81422
|
}
|
|
@@ -81152,7 +81450,7 @@ function pollDeviceToken(origin, deviceCode) {
|
|
|
81152
81450
|
});
|
|
81153
81451
|
}
|
|
81154
81452
|
function deviceErrorCode(error61) {
|
|
81155
|
-
if (!(error61 instanceof HostedApiError) && !(
|
|
81453
|
+
if (!(error61 instanceof HostedApiError) && !(isRecord7(error61) && error61.name === "HostedApiError"))
|
|
81156
81454
|
return;
|
|
81157
81455
|
const failure = error61;
|
|
81158
81456
|
const named = [failure.code, failure.detail, failure.message].find((value) => value === "slow_down" || value === "authorization_pending" || value === "expired_token" || value === "invalid_device_code" || value === "access_denied");
|
|
@@ -81213,7 +81511,7 @@ async function pollDeviceAuthorization(input2) {
|
|
|
81213
81511
|
throw error61;
|
|
81214
81512
|
}
|
|
81215
81513
|
}
|
|
81216
|
-
const record9 =
|
|
81514
|
+
const record9 = isRecord7(body) ? body : {};
|
|
81217
81515
|
const code = typeof record9.error === "string" ? record9.error : undefined;
|
|
81218
81516
|
if (code === "authorization_pending" || code === undefined && record9.status === "pending") {
|
|
81219
81517
|
await wait();
|
|
@@ -81241,7 +81539,7 @@ function pendingDeviceSignInStem(env3) {
|
|
|
81241
81539
|
}
|
|
81242
81540
|
function pendingDeviceSignInPath(origin, env3 = process.env) {
|
|
81243
81541
|
const { dir, stem } = pendingDeviceSignInStem(env3);
|
|
81244
|
-
return join37(dir, `${stem}-${
|
|
81542
|
+
return join37(dir, `${stem}-${createHash21("sha256").update(origin).digest("hex").slice(0, 16)}.json`);
|
|
81245
81543
|
}
|
|
81246
81544
|
function savePendingDeviceSignIn(origin, start, env3 = process.env, now3 = Date.now()) {
|
|
81247
81545
|
const path = pendingDeviceSignInPath(origin, env3);
|
|
@@ -81271,7 +81569,7 @@ function loadPendingDeviceSignIn(origin, env3 = process.env, now3 = Date.now())
|
|
|
81271
81569
|
} catch {
|
|
81272
81570
|
return null;
|
|
81273
81571
|
}
|
|
81274
|
-
if (!
|
|
81572
|
+
if (!isRecord7(parsed))
|
|
81275
81573
|
return null;
|
|
81276
81574
|
const deviceCode = boundedText(parsed.deviceCode, 512);
|
|
81277
81575
|
const userCode = boundedText(parsed.userCode, 64);
|
|
@@ -81313,7 +81611,7 @@ function pendingDeviceSignInOrigins(env3 = process.env, now3 = Date.now()) {
|
|
|
81313
81611
|
continue;
|
|
81314
81612
|
try {
|
|
81315
81613
|
const parsed = JSON.parse(readFileSync21(join37(location.dir, entry), "utf8"));
|
|
81316
|
-
if (
|
|
81614
|
+
if (isRecord7(parsed) && typeof parsed.origin === "string" && Number(parsed.expiresAt) > now3 && pendingDeviceSignInPath(parsed.origin, env3) === join37(location.dir, entry))
|
|
81317
81615
|
origins.push(parsed.origin);
|
|
81318
81616
|
} catch {}
|
|
81319
81617
|
}
|
|
@@ -81355,7 +81653,7 @@ async function persistSignIn(result2, origin, env3 = process.env, issuedBy = "si
|
|
|
81355
81653
|
headers: { Authorization: `Bearer ${result2.token}` },
|
|
81356
81654
|
body: JSON.stringify({ name: "cli" })
|
|
81357
81655
|
});
|
|
81358
|
-
apiKey =
|
|
81656
|
+
apiKey = isRecord7(created) && typeof created.key === "string" && created.key.trim() ? created.key : undefined;
|
|
81359
81657
|
}
|
|
81360
81658
|
if (!apiKey)
|
|
81361
81659
|
throw new Error("Sign-in succeeded but the server returned no API key");
|
|
@@ -81394,7 +81692,7 @@ async function revokeStoredKey(origin, apiKey) {
|
|
|
81394
81692
|
}
|
|
81395
81693
|
return { outcome: "failed", detail: "the server could not be reached" };
|
|
81396
81694
|
}
|
|
81397
|
-
if (
|
|
81695
|
+
if (isRecord7(body) && body.revoked === true)
|
|
81398
81696
|
return { outcome: "revoked" };
|
|
81399
81697
|
return { outcome: "not_revoked", detail: "the server answered without confirming revocation" };
|
|
81400
81698
|
}
|
|
@@ -81518,10 +81816,10 @@ async function readSignedInAccount(env3 = process.env) {
|
|
|
81518
81816
|
const body = await new RemoteSkillsAuthClient(connection.apiOrigin).request("/api/auth/whoami", {
|
|
81519
81817
|
headers: { Authorization: `Bearer ${connection.apiKey}` }
|
|
81520
81818
|
});
|
|
81521
|
-
const record9 =
|
|
81522
|
-
const data =
|
|
81523
|
-
const user =
|
|
81524
|
-
const organization2 =
|
|
81819
|
+
const record9 = isRecord7(body) ? body : {};
|
|
81820
|
+
const data = isRecord7(record9.data) ? record9.data : {};
|
|
81821
|
+
const user = isRecord7(record9.user) ? record9.user : isRecord7(data.user) ? data.user : {};
|
|
81822
|
+
const organization2 = isRecord7(record9.organization) ? record9.organization : isRecord7(data.organization) ? data.organization : {};
|
|
81525
81823
|
const email4 = boundedText(user.email, 320);
|
|
81526
81824
|
const org = boundedText(organization2.slug, 200) ?? boundedText(organization2.name, 200);
|
|
81527
81825
|
return { ...base2, ...email4 ? { email: email4 } : {}, ...org ? { organization: org } : {} };
|
|
@@ -81936,7 +82234,7 @@ function optionPrefix(program2, args) {
|
|
|
81936
82234
|
}
|
|
81937
82235
|
|
|
81938
82236
|
// src/lib/revision.ts
|
|
81939
|
-
import { createHash as
|
|
82237
|
+
import { createHash as createHash22 } from "crypto";
|
|
81940
82238
|
function revisionIdOf(content) {
|
|
81941
82239
|
const canonicalContent = {
|
|
81942
82240
|
slug: content.slug,
|
|
@@ -81956,8 +82254,8 @@ function revisionIdOf(content) {
|
|
|
81956
82254
|
canonicalContent.archiveReason = content.archiveReason ?? null;
|
|
81957
82255
|
canonicalContent.replacementSlug = content.replacementSlug ?? null;
|
|
81958
82256
|
}
|
|
81959
|
-
const
|
|
81960
|
-
return
|
|
82257
|
+
const canonical6 = JSON.stringify(canonicalContent);
|
|
82258
|
+
return createHash22("sha256").update(canonical6).digest("hex");
|
|
81961
82259
|
}
|
|
81962
82260
|
var REVISION_ID_PATTERN;
|
|
81963
82261
|
var init_revision = __esm(() => {
|
|
@@ -82406,7 +82704,7 @@ var init_pull = __esm(() => {
|
|
|
82406
82704
|
});
|
|
82407
82705
|
|
|
82408
82706
|
// src/lib/skill-context.ts
|
|
82409
|
-
import { createHash as
|
|
82707
|
+
import { createHash as createHash23 } from "crypto";
|
|
82410
82708
|
import { resolve as resolve19 } from "path";
|
|
82411
82709
|
function words2(value) {
|
|
82412
82710
|
return new Set(value.toLowerCase().match(/[a-z0-9]+/g) ?? []);
|
|
@@ -82495,7 +82793,7 @@ ${content}`;
|
|
|
82495
82793
|
`);
|
|
82496
82794
|
const receipt = {
|
|
82497
82795
|
schemaVersion: 1,
|
|
82498
|
-
id:
|
|
82796
|
+
id: createHash23("sha256").update(JSON.stringify({ profile: profile.profileRevision, sessionId, selections, omitted })).digest("hex"),
|
|
82499
82797
|
profileId: profile.profileId,
|
|
82500
82798
|
profileRevision: profile.profileRevision,
|
|
82501
82799
|
authority: profile.authority,
|
|
@@ -82517,8 +82815,8 @@ var init_skill_context = __esm(() => {
|
|
|
82517
82815
|
});
|
|
82518
82816
|
|
|
82519
82817
|
// src/lib/session-reconciliation.ts
|
|
82520
|
-
import { createHash as
|
|
82521
|
-
import { isDeepStrictEqual as
|
|
82818
|
+
import { createHash as createHash24 } from "crypto";
|
|
82819
|
+
import { isDeepStrictEqual as isDeepStrictEqual9 } from "util";
|
|
82522
82820
|
function exactTimestamp(value) {
|
|
82523
82821
|
const parsed = value === undefined ? Number.NaN : Date.parse(value);
|
|
82524
82822
|
if (!Number.isFinite(parsed) || new Date(parsed).toISOString() !== value) {
|
|
@@ -82575,7 +82873,7 @@ async function reconcileSkillSessionIfSafe(sessionId, profileId, options = {}) {
|
|
|
82575
82873
|
for (const key of old.loaded) {
|
|
82576
82874
|
const previous = oldByKey.get(key);
|
|
82577
82875
|
const current = targetBySlug.get(previous.slug);
|
|
82578
|
-
if (!current || !
|
|
82876
|
+
if (!current || !isDeepStrictEqual9({ ...previous, profileRevision: target.profileRevision }, current)) {
|
|
82579
82877
|
throw new SkillSelectionError("SESSION_RECONCILIATION_REQUIRED", "A loaded Skills selection was removed or changed; review skills sessions reconcile before changing this session's pin.");
|
|
82580
82878
|
}
|
|
82581
82879
|
}
|
|
@@ -82657,7 +82955,7 @@ async function reconcileSkillSession(input2, options = {}) {
|
|
|
82657
82955
|
const result2 = replaceSkillSession(skillSessionSnapshotBinding(snapshot2), replacement, { ...plan, planDigest }, options, () => assertPlanWindow(issuedAt, expiresAt, (options.now ?? Date.now)()));
|
|
82658
82956
|
return { applied: true, plan, planDigest, ...result2 };
|
|
82659
82957
|
}
|
|
82660
|
-
var SESSION_RECONCILIATION_PLAN_TTL_MS, digest3 = (value) =>
|
|
82958
|
+
var SESSION_RECONCILIATION_PLAN_TTL_MS, digest3 = (value) => createHash24("sha256").update(JSON.stringify(value)).digest("hex");
|
|
82661
82959
|
var init_session_reconciliation = __esm(() => {
|
|
82662
82960
|
init_profile_client();
|
|
82663
82961
|
init_selection_cache();
|
|
@@ -83793,7 +84091,7 @@ function handleDiff(name, options) {
|
|
|
83793
84091
|
const sourcePath = getSkillPath(bare);
|
|
83794
84092
|
const canonicalDir = join39(resolveCorpusRoot(), normalized);
|
|
83795
84093
|
const canonicalSkillMd = join39(canonicalDir, "SKILL.md");
|
|
83796
|
-
const
|
|
84094
|
+
const canonical6 = {
|
|
83797
84095
|
present: existsSync22(canonicalSkillMd),
|
|
83798
84096
|
path: canonicalDir,
|
|
83799
84097
|
...existsSync22(canonicalSkillMd) ? { hash: hashSkillMarkdownFile(canonicalSkillMd) } : {},
|
|
@@ -83825,7 +84123,7 @@ function handleDiff(name, options) {
|
|
|
83825
84123
|
stub = undefined;
|
|
83826
84124
|
}
|
|
83827
84125
|
}
|
|
83828
|
-
const diverged = present &&
|
|
84126
|
+
const diverged = present && canonical6.present && managed && hash5 !== canonical6.hash;
|
|
83829
84127
|
homes.push({
|
|
83830
84128
|
agent,
|
|
83831
84129
|
path: dir,
|
|
@@ -83840,7 +84138,7 @@ function handleDiff(name, options) {
|
|
|
83840
84138
|
if (options.json) {
|
|
83841
84139
|
console.log(JSON.stringify({
|
|
83842
84140
|
name: bare,
|
|
83843
|
-
canonical:
|
|
84141
|
+
canonical: canonical6,
|
|
83844
84142
|
pinned,
|
|
83845
84143
|
installedVersion,
|
|
83846
84144
|
registryVersion,
|
|
@@ -83848,10 +84146,10 @@ function handleDiff(name, options) {
|
|
|
83848
84146
|
homes
|
|
83849
84147
|
}, null, 2));
|
|
83850
84148
|
} else {
|
|
83851
|
-
if (!
|
|
84149
|
+
if (!canonical6.present) {
|
|
83852
84150
|
console.log(source_default.yellow(`${bare}: no canonical corpus entry`));
|
|
83853
84151
|
} else {
|
|
83854
|
-
console.log(source_default.dim(`${bare} canonical: ${
|
|
84152
|
+
console.log(source_default.dim(`${bare} canonical: ${canonical6.hash?.slice(0, 12)}\u2026`));
|
|
83855
84153
|
}
|
|
83856
84154
|
if (pinned) {
|
|
83857
84155
|
console.log(upToDate ? source_default.green(`\u2713 pin is up to date (${installedVersion})`) : source_default.yellow(`pin metadata differs: ${installedVersion} \u2192 ${registryVersion}`));
|
|
@@ -83862,14 +84160,14 @@ function handleDiff(name, options) {
|
|
|
83862
84160
|
} else if (!home.managed) {
|
|
83863
84161
|
console.log(`${source_default.dim("\u2022")} ${home.agent}: ${source_default.yellow("unmarked (adoption candidate)")}`);
|
|
83864
84162
|
} else if (home.diverged) {
|
|
83865
|
-
const stubNote = home.stub === true ? " (home is a pointer stub; canonical holds content)" :
|
|
83866
|
-
console.log(`${source_default.red("\u2717")} ${home.agent}: ${source_default.red("diverged")} ${source_default.dim(home.hash?.slice(0, 12))} \u2260 ${source_default.dim(
|
|
84163
|
+
const stubNote = home.stub === true ? " (home is a pointer stub; canonical holds content)" : canonical6.stub === true ? " (home holds content; canonical renders a pointer stub \u2014 sync refuses to replace it)" : "";
|
|
84164
|
+
console.log(`${source_default.red("\u2717")} ${home.agent}: ${source_default.red("diverged")} ${source_default.dim(home.hash?.slice(0, 12))} \u2260 ${source_default.dim(canonical6.hash?.slice(0, 12))}${stubNote}`);
|
|
83867
84165
|
} else {
|
|
83868
84166
|
console.log(`${source_default.green("\u2713")} ${home.agent}: ${source_default.green("matches canonical")}`);
|
|
83869
84167
|
}
|
|
83870
84168
|
}
|
|
83871
84169
|
}
|
|
83872
|
-
if (divergedHomes.length > 0 || homes.length > 0 && !
|
|
84170
|
+
if (divergedHomes.length > 0 || homes.length > 0 && !canonical6.present)
|
|
83873
84171
|
process.exitCode = 1;
|
|
83874
84172
|
}
|
|
83875
84173
|
var init_introspect = __esm(() => {
|
|
@@ -87175,7 +87473,7 @@ var init_execution_grants = __esm(() => {
|
|
|
87175
87473
|
});
|
|
87176
87474
|
|
|
87177
87475
|
// src/lib/execution-grant-client.ts
|
|
87178
|
-
import { isDeepStrictEqual as
|
|
87476
|
+
import { isDeepStrictEqual as isDeepStrictEqual10 } from "util";
|
|
87179
87477
|
function id(value) {
|
|
87180
87478
|
if (!grantIdentifier(value))
|
|
87181
87479
|
throw new Error("Invalid execution grant profile or revision identifier.");
|
|
@@ -87227,7 +87525,7 @@ async function saveExecutionGrantPolicy(profileId, grants, revision) {
|
|
|
87227
87525
|
headers: revision === undefined ? { "If-None-Match": "*" } : { "If-Match": `"${revision}"` },
|
|
87228
87526
|
body: JSON.stringify({ grants: snapshot2 })
|
|
87229
87527
|
}));
|
|
87230
|
-
if (policy.profileId !== profileId || policy.previousRevision !== (revision ?? null) || !
|
|
87528
|
+
if (policy.profileId !== profileId || policy.previousRevision !== (revision ?? null) || !isDeepStrictEqual10(policy.grants, snapshot2)) {
|
|
87231
87529
|
throw new Error("The API did not preserve the reviewed execution grant policy; read it before retrying.");
|
|
87232
87530
|
}
|
|
87233
87531
|
return policy;
|
|
@@ -87238,7 +87536,7 @@ async function resolveExecutionGrant(input2) {
|
|
|
87238
87536
|
if (!grantRecord(value) || Object.keys(value).length !== 3 || !grantIdentifier(value.policyRevision) || !grantIdentifier(value.grantId) || !grantRecord(value.bindings)) {
|
|
87239
87537
|
throw new SkillSelectionError("INVALID_EXECUTION_GRANT", "The Skills API returned an invalid execution grant.");
|
|
87240
87538
|
}
|
|
87241
|
-
if (!
|
|
87539
|
+
if (!isDeepStrictEqual10(value.bindings.selection, snapshot2.selection) || !isDeepStrictEqual10(value.bindings.consumer, snapshot2.consumer)) {
|
|
87242
87540
|
throw new SkillSelectionError("EXECUTION_GRANT_SCOPE_MISMATCH", "The Skills API returned a grant for a different selection or consumer.");
|
|
87243
87541
|
}
|
|
87244
87542
|
return value;
|
|
@@ -87257,7 +87555,7 @@ __export(exports_selected_run, {
|
|
|
87257
87555
|
prepareSelectedSecretBindings: () => prepareSelectedSecretBindings,
|
|
87258
87556
|
executeSelectedLocal: () => executeSelectedLocal
|
|
87259
87557
|
});
|
|
87260
|
-
import { createHash as
|
|
87558
|
+
import { createHash as createHash25 } from "crypto";
|
|
87261
87559
|
import { spawn as spawn3 } from "child_process";
|
|
87262
87560
|
import { mkdirSync as mkdirSync15, mkdtempSync as mkdtempSync4, writeFileSync as writeFileSync15, realpathSync as realpathSync11 } from "fs";
|
|
87263
87561
|
import { dirname as dirname23, join as join45, resolve as resolve20 } from "path";
|
|
@@ -87383,7 +87681,7 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
87383
87681
|
selection: selection2,
|
|
87384
87682
|
target: "local",
|
|
87385
87683
|
runtime: runtimeName,
|
|
87386
|
-
inputDigest: `sha256:${
|
|
87684
|
+
inputDigest: `sha256:${createHash25("sha256").update(input2).digest("hex")}`,
|
|
87387
87685
|
runDirectory,
|
|
87388
87686
|
...executionGrant ? { executionGrant } : {},
|
|
87389
87687
|
...bindings ? { secretBinding: { schema: bindings.schema, selection: bindings.selection, consumer: bindings.consumer, secretsAuthority: bindings.secretsAuthority, bindings: bindings.bindings } } : {},
|
|
@@ -91600,7 +91898,7 @@ var init_runs = __esm(() => {
|
|
|
91600
91898
|
});
|
|
91601
91899
|
|
|
91602
91900
|
// src/lib/run-state.ts
|
|
91603
|
-
import { createHash as
|
|
91901
|
+
import { createHash as createHash26, randomBytes } from "crypto";
|
|
91604
91902
|
import { existsSync as existsSync27, mkdirSync as mkdirSync16, readFileSync as readFileSync32, readdirSync as readdirSync18, statSync as statSync16, writeFileSync as writeFileSync16 } from "fs";
|
|
91605
91903
|
import { extname, join as join46, relative as relative7 } from "path";
|
|
91606
91904
|
function createSkillRun(params, targetDir = process.cwd()) {
|
|
@@ -91737,7 +92035,7 @@ function collectRunArtifacts(context) {
|
|
|
91737
92035
|
artifacts.push({
|
|
91738
92036
|
path: toProjectRelative(context.targetDir, path),
|
|
91739
92037
|
mime: mimeForPath(path),
|
|
91740
|
-
sha256:
|
|
92038
|
+
sha256: createHash26("sha256").update(bytes).digest("hex"),
|
|
91741
92039
|
sizeBytes: stat2.size
|
|
91742
92040
|
});
|
|
91743
92041
|
}
|
|
@@ -97463,8 +97761,8 @@ var require_resolve = __commonJS((exports) => {
|
|
|
97463
97761
|
}
|
|
97464
97762
|
return count;
|
|
97465
97763
|
}
|
|
97466
|
-
function getFullPath(resolver, id2 = "",
|
|
97467
|
-
if (
|
|
97764
|
+
function getFullPath(resolver, id2 = "", normalize5) {
|
|
97765
|
+
if (normalize5 !== false)
|
|
97468
97766
|
id2 = normalizeId(id2);
|
|
97469
97767
|
const p = resolver.parse(id2);
|
|
97470
97768
|
return _getFullPath(resolver, p);
|
|
@@ -99023,7 +99321,7 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
99023
99321
|
}
|
|
99024
99322
|
return decodedScheme;
|
|
99025
99323
|
}
|
|
99026
|
-
function
|
|
99324
|
+
function normalize5(uri, options) {
|
|
99027
99325
|
if (typeof uri === "string") {
|
|
99028
99326
|
uri = normalizeString(uri, options);
|
|
99029
99327
|
} else if (typeof uri === "object") {
|
|
@@ -99400,7 +99698,7 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
99400
99698
|
}
|
|
99401
99699
|
var fastUri = {
|
|
99402
99700
|
SCHEMES,
|
|
99403
|
-
normalize:
|
|
99701
|
+
normalize: normalize5,
|
|
99404
99702
|
resolve: resolve21,
|
|
99405
99703
|
resolveComponent,
|
|
99406
99704
|
equal,
|
|
@@ -104410,7 +104708,7 @@ async function continueRecurringRecovery(customer, directory, options) {
|
|
|
104410
104708
|
throw error61;
|
|
104411
104709
|
}
|
|
104412
104710
|
}
|
|
104413
|
-
var uuid11,
|
|
104711
|
+
var uuid11, sha5, common2, intentSchema, stateSchema, invalid6 = () => {
|
|
104414
104712
|
throw new RecurringCustomerError("RECURRING_RECOVERY_INVALID", "The original recovery directory or record is invalid or changed. Preserve it; do not create a replacement activation automatically.");
|
|
104415
104713
|
};
|
|
104416
104714
|
var init_recurring_recovery = __esm(() => {
|
|
@@ -104420,7 +104718,7 @@ var init_recurring_recovery = __esm(() => {
|
|
|
104420
104718
|
init_remote_recurring();
|
|
104421
104719
|
init_recurring_customer();
|
|
104422
104720
|
uuid11 = exports_external.string().regex(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/);
|
|
104423
|
-
|
|
104721
|
+
sha5 = exports_external.string().regex(/^[a-f0-9]{64}$/);
|
|
104424
104722
|
common2 = exports_external.object({
|
|
104425
104723
|
contractVersion: exports_external.literal(1),
|
|
104426
104724
|
apiOrigin: exports_external.string().min(1).max(4096),
|
|
@@ -104433,7 +104731,7 @@ var init_recurring_recovery = __esm(() => {
|
|
|
104433
104731
|
common2.extend({
|
|
104434
104732
|
operation: exports_external.literal("activate"),
|
|
104435
104733
|
draftId: uuid11,
|
|
104436
|
-
termsSha256:
|
|
104734
|
+
termsSha256: sha5,
|
|
104437
104735
|
approvalDeadline: exports_external.string().datetime(),
|
|
104438
104736
|
approval: recurringActivationSchema
|
|
104439
104737
|
}).strict(),
|
|
@@ -104441,7 +104739,7 @@ var init_recurring_recovery = __esm(() => {
|
|
|
104441
104739
|
]);
|
|
104442
104740
|
stateSchema = exports_external.object({
|
|
104443
104741
|
contractVersion: exports_external.literal(1),
|
|
104444
|
-
intentSha256:
|
|
104742
|
+
intentSha256: sha5,
|
|
104445
104743
|
phase: exports_external.enum(["prepared", "pending", "observed"]),
|
|
104446
104744
|
consentId: uuid11.nullable()
|
|
104447
104745
|
}).strict();
|
|
@@ -106985,7 +107283,7 @@ var init_schedule_tools = __esm(() => {
|
|
|
106985
107283
|
});
|
|
106986
107284
|
|
|
106987
107285
|
// src/lib/native-storage.ts
|
|
106988
|
-
import { createHash as
|
|
107286
|
+
import { createHash as createHash27, createHmac as createHmac3 } from "crypto";
|
|
106989
107287
|
import {
|
|
106990
107288
|
existsSync as existsSync31,
|
|
106991
107289
|
mkdirSync as mkdirSync21,
|
|
@@ -106994,7 +107292,7 @@ import {
|
|
|
106994
107292
|
statSync as statSync18,
|
|
106995
107293
|
writeFileSync as writeFileSync20
|
|
106996
107294
|
} from "fs";
|
|
106997
|
-
import { dirname as dirname27, join as join52, normalize as
|
|
107295
|
+
import { dirname as dirname27, join as join52, normalize as normalize5, relative as relative8, sep as sep9 } from "path";
|
|
106998
107296
|
function resolveSkillsNativeStorageConfig(env3 = process.env) {
|
|
106999
107297
|
assertNoRetiredModeEnvVars(env3, {
|
|
107000
107298
|
app: SKILLS_ENV_NAMESPACE,
|
|
@@ -107062,7 +107360,7 @@ function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
|
|
|
107062
107360
|
files.push({
|
|
107063
107361
|
path: relativePath,
|
|
107064
107362
|
sizeBytes: bytes.byteLength,
|
|
107065
|
-
sha256:
|
|
107363
|
+
sha256: createHash27("sha256").update(bytes).digest("hex"),
|
|
107066
107364
|
...options.includeFileContents ? { contentBase64: Buffer.from(bytes).toString("base64") } : {}
|
|
107067
107365
|
});
|
|
107068
107366
|
}
|
|
@@ -108244,7 +108542,7 @@ var init_remote_account2 = __esm(() => {
|
|
|
108244
108542
|
});
|
|
108245
108543
|
|
|
108246
108544
|
// src/cli/commands/runtime-copyfile.ts
|
|
108247
|
-
import { createHash as
|
|
108545
|
+
import { createHash as createHash28, randomUUID as randomUUID9 } from "crypto";
|
|
108248
108546
|
import { Readable } from "stream";
|
|
108249
108547
|
import { createGunzip as createGunzip2 } from "zlib";
|
|
108250
108548
|
import {
|
|
@@ -108268,7 +108566,7 @@ function object9(value, code2) {
|
|
|
108268
108566
|
return value;
|
|
108269
108567
|
}
|
|
108270
108568
|
function hash5(bytes) {
|
|
108271
|
-
return
|
|
108569
|
+
return createHash28("sha256").update(bytes).digest("hex");
|
|
108272
108570
|
}
|
|
108273
108571
|
function isWithin(parent, child) {
|
|
108274
108572
|
const rel = relative9(parent, child);
|
|
@@ -108419,7 +108717,7 @@ function verifyIntegrity(bytes, integrity) {
|
|
|
108419
108717
|
const match = /^sha512-([A-Za-z0-9+/]+={0,2})$/.exec(integrity);
|
|
108420
108718
|
if (!match)
|
|
108421
108719
|
throw new Error("REGISTRY_INTEGRITY_UNSUPPORTED");
|
|
108422
|
-
const actual =
|
|
108720
|
+
const actual = createHash28("sha512").update(bytes).digest("base64");
|
|
108423
108721
|
if (actual !== match[1])
|
|
108424
108722
|
throw new Error("TARBALL_INTEGRITY_MISMATCH");
|
|
108425
108723
|
}
|
|
@@ -109420,7 +109718,7 @@ var exports_runtime = {};
|
|
|
109420
109718
|
__export(exports_runtime, {
|
|
109421
109719
|
registerRuntime: () => registerRuntime
|
|
109422
109720
|
});
|
|
109423
|
-
import { createHash as
|
|
109721
|
+
import { createHash as createHash29, randomUUID as randomUUID10 } from "crypto";
|
|
109424
109722
|
import { lstatSync as lstatSync29, mkdirSync as mkdirSync25, readFileSync as readFileSync38, realpathSync as realpathSync15, writeFileSync as writeFileSync24 } from "fs";
|
|
109425
109723
|
import { basename as basename15, isAbsolute as isAbsolute25, join as join56 } from "path";
|
|
109426
109724
|
import { createInterface } from "readline";
|
|
@@ -109461,7 +109759,7 @@ function registerRuntime(parent) {
|
|
|
109461
109759
|
if (!expected)
|
|
109462
109760
|
throw new Error("Cloud artifact not found");
|
|
109463
109761
|
const bytes = await client2.download(id2, name);
|
|
109464
|
-
if (bytes.length !== expected.byteSize ||
|
|
109762
|
+
if (bytes.length !== expected.byteSize || createHash29("sha256").update(bytes).digest("hex") !== expected.sha256)
|
|
109465
109763
|
throw new Error("Cloud artifact integrity verification failed");
|
|
109466
109764
|
writeFileSync24(options.output, bytes, { flag: "wx", mode: 384 });
|
|
109467
109765
|
console.log(JSON.stringify({ path: options.output, sha256: expected.sha256, byteSize: bytes.length }));
|
|
@@ -111104,7 +111402,7 @@ var init_portable_snapshot_filter = __esm(() => {
|
|
|
111104
111402
|
});
|
|
111105
111403
|
|
|
111106
111404
|
// src/lib/station-snapshot.ts
|
|
111107
|
-
import { createHash as
|
|
111405
|
+
import { createHash as createHash30 } from "crypto";
|
|
111108
111406
|
import {
|
|
111109
111407
|
copyFileSync as copyFileSync2,
|
|
111110
111408
|
mkdirSync as mkdirSync26,
|
|
@@ -111119,7 +111417,7 @@ function validateStationId(stationId) {
|
|
|
111119
111417
|
}
|
|
111120
111418
|
}
|
|
111121
111419
|
function sha256File(filePath) {
|
|
111122
|
-
return
|
|
111420
|
+
return createHash30("sha256").update(readFileSync39(filePath)).digest("hex");
|
|
111123
111421
|
}
|
|
111124
111422
|
function scanHome(definition, homesRoot) {
|
|
111125
111423
|
const homePath = homePathFor(definition, homesRoot);
|
|
@@ -111691,8 +111989,8 @@ var init_create_sync_config = __esm(() => {
|
|
|
111691
111989
|
});
|
|
111692
111990
|
|
|
111693
111991
|
// src/lib/codex-native-config.ts
|
|
111694
|
-
import { isDeepStrictEqual as
|
|
111695
|
-
function
|
|
111992
|
+
import { isDeepStrictEqual as isDeepStrictEqual11 } from "util";
|
|
111993
|
+
function isRecord8(value) {
|
|
111696
111994
|
if (!value || typeof value !== "object")
|
|
111697
111995
|
return false;
|
|
111698
111996
|
const prototype = Object.getPrototypeOf(value);
|
|
@@ -111713,10 +112011,10 @@ function decimalIdentity(text4) {
|
|
|
111713
112011
|
return `${match[1]}${coefficient}e${exponent}`;
|
|
111714
112012
|
}
|
|
111715
112013
|
function codexNativeConfigEqual(native, expected) {
|
|
111716
|
-
if (
|
|
112014
|
+
if (isDeepStrictEqual11(native, expected))
|
|
111717
112015
|
return true;
|
|
111718
112016
|
if (typeof expected === "number") {
|
|
111719
|
-
if (!Number.isFinite(expected) || !
|
|
112017
|
+
if (!Number.isFinite(expected) || !isRecord8(native))
|
|
111720
112018
|
return false;
|
|
111721
112019
|
const keys3 = Object.keys(native);
|
|
111722
112020
|
const value = native[NUMBER_TAG];
|
|
@@ -111728,7 +112026,7 @@ function codexNativeConfigEqual(native, expected) {
|
|
|
111728
112026
|
if (Array.isArray(native) || Array.isArray(expected)) {
|
|
111729
112027
|
return Array.isArray(native) && Array.isArray(expected) && native.length === expected.length && native.every((value, index) => codexNativeConfigEqual(value, expected[index]));
|
|
111730
112028
|
}
|
|
111731
|
-
if (!
|
|
112029
|
+
if (!isRecord8(native) || !isRecord8(expected))
|
|
111732
112030
|
return false;
|
|
111733
112031
|
const actual = native, wanted = expected;
|
|
111734
112032
|
return Object.keys(actual).length === Object.keys(wanted).length && Object.keys(wanted).every((key) => Object.hasOwn(actual, key) && codexNativeConfigEqual(actual[key], wanted[key]));
|
|
@@ -111739,42 +112037,42 @@ var init_codex_native_config = () => {};
|
|
|
111739
112037
|
// src/lib/codex-hook-trust-identity.ts
|
|
111740
112038
|
import { realpathSync as realpathSync16 } from "fs";
|
|
111741
112039
|
import { dirname as dirname33, isAbsolute as isAbsolute27, join as join59 } from "path";
|
|
111742
|
-
import { isDeepStrictEqual as
|
|
112040
|
+
import { isDeepStrictEqual as isDeepStrictEqual12 } from "util";
|
|
111743
112041
|
function inspectRecordedSkillsCli(command, expected) {
|
|
111744
|
-
|
|
112042
|
+
need6(isAbsolute27(command) && !command.includes("\x00"), "RECONCILE_RECORDED_COMMAND_REQUIRED");
|
|
111745
112043
|
const resolved = realpathSync16(command);
|
|
111746
112044
|
const cli = snapshot(resolved, false, { readOnlyPackage: true });
|
|
111747
112045
|
const manifest = snapshot(join59(dirname33(dirname33(resolved)), "package.json"), false, { readOnlyPackage: true });
|
|
111748
112046
|
const pkg = JSON.parse(manifest.text);
|
|
111749
|
-
|
|
111750
|
-
|
|
112047
|
+
need6(pkg.name === "@hasna/skills" && /^\d+\.\d+\.\d+$/.test(pkg.version) && pkg.bin?.skills === "bin/index.js" && resolved === join59(dirname33(manifest.file), "bin/index.js"), "SKILLS_PACKAGE_MISMATCH");
|
|
112048
|
+
need6((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
|
|
111751
112049
|
const receipt = { path: resolved, version: pkg.version, sha256: cli.sha256, manifestSha256: manifest.sha256 };
|
|
111752
|
-
|
|
112050
|
+
need6(isDeepStrictEqual12(receipt, expected), "RECONCILE_SKILLS_BINDING_CHANGED");
|
|
111753
112051
|
return { receipt, recheck() {
|
|
111754
|
-
|
|
112052
|
+
need6(realpathSync16(command) === resolved, "SKILLS_COMMAND_CHANGED");
|
|
111755
112053
|
unchanged2(cli);
|
|
111756
112054
|
unchanged2(manifest);
|
|
111757
112055
|
} };
|
|
111758
112056
|
}
|
|
111759
112057
|
function bindSkillsCli(command, reviewed) {
|
|
111760
112058
|
const normal = Bun.which("skills", { PATH: process.env.PATH });
|
|
111761
|
-
|
|
112059
|
+
need6(normal, "SKILLS_COMMAND_UNAVAILABLE");
|
|
111762
112060
|
const resolved = realpathSync16(normal);
|
|
111763
112061
|
const bound = isAbsolute27(command) ? command : command === "skills" ? normal : undefined;
|
|
111764
|
-
|
|
112062
|
+
need6(bound && realpathSync16(bound) === resolved, "SKILLS_COMMAND_MISMATCH");
|
|
111765
112063
|
const entrypoint = reviewed?.path ?? process.argv[1];
|
|
111766
|
-
|
|
112064
|
+
need6(entrypoint && realpathSync16(entrypoint) === resolved, "SKILLS_ENTRYPOINT_MISMATCH");
|
|
111767
112065
|
const cli = snapshot(resolved, false, { readOnlyPackage: true });
|
|
111768
112066
|
const manifest = snapshot(join59(dirname33(dirname33(resolved)), "package.json"), false, { readOnlyPackage: true });
|
|
111769
112067
|
const pkg = JSON.parse(manifest.text);
|
|
111770
|
-
|
|
112068
|
+
need6(pkg.name === "@hasna/skills" && /^\d+\.\d+\.\d+$/.test(pkg.version) && pkg.bin?.skills === "bin/index.js" && resolved === join59(dirname33(manifest.file), "bin/index.js"), "SKILLS_PACKAGE_MISMATCH");
|
|
111771
112069
|
if (reviewed)
|
|
111772
|
-
|
|
111773
|
-
|
|
112070
|
+
need6(/^[a-f0-9]{64}$/.test(reviewed.sha256) && reviewed.sha256 === cli.sha256 && reviewed.version === pkg.version, "SKILLS_RELEASE_MISMATCH");
|
|
112071
|
+
need6((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
|
|
111774
112072
|
return {
|
|
111775
112073
|
receipt: { path: resolved, version: pkg.version, sha256: cli.sha256, manifestSha256: manifest.sha256 },
|
|
111776
112074
|
recheck() {
|
|
111777
|
-
|
|
112075
|
+
need6(Bun.which("skills", { PATH: process.env.PATH }) === normal && realpathSync16(normal) === resolved && realpathSync16(bound) === resolved && realpathSync16(entrypoint) === resolved, "SKILLS_COMMAND_CHANGED");
|
|
111778
112076
|
unchanged2(cli);
|
|
111779
112077
|
unchanged2(manifest);
|
|
111780
112078
|
}
|
|
@@ -111785,19 +112083,19 @@ var init_codex_hook_trust_identity = __esm(() => {
|
|
|
111785
112083
|
});
|
|
111786
112084
|
|
|
111787
112085
|
// src/lib/codex-hook-policy-recovery.ts
|
|
111788
|
-
import { isDeepStrictEqual as
|
|
112086
|
+
import { isDeepStrictEqual as isDeepStrictEqual13 } from "util";
|
|
111789
112087
|
function reviewedClaudeDiscoveryChange(beforeText, currentText, options) {
|
|
111790
|
-
|
|
111791
|
-
|
|
112088
|
+
need6(typeof options.reason === "string" && options.reason.trim().length > 0 && options.reason.length <= 512 && !/[\x00-\x1f\x7f]/.test(options.reason), "RECONCILE_RECOVERY_REASON_REQUIRED");
|
|
112089
|
+
need6(options.reviewedPlanDigest === undefined || /^[a-f0-9]{64}$/.test(options.reviewedPlanDigest), "RECONCILE_RECOVERY_PLAN_CHANGED");
|
|
111792
112090
|
const before2 = parseManagedSkillPolicy(beforeText), current = parseManagedSkillPolicy(currentText);
|
|
111793
112091
|
const oldDiscovery = before2.bridge?.discovery?.claude, newDiscovery = current.bridge?.discovery?.claude;
|
|
111794
|
-
|
|
111795
|
-
const changes = ["roots", "sources"].filter((key) => !
|
|
111796
|
-
|
|
112092
|
+
need6(oldDiscovery?.agent === "claude" && newDiscovery?.agent === "claude" && oldDiscovery.method === "reviewed" && newDiscovery.method === "reviewed", "RECONCILE_POLICY_CHANGED");
|
|
112093
|
+
const changes = ["roots", "sources"].filter((key) => !isDeepStrictEqual13(oldDiscovery[key], newDiscovery[key])).map((key) => ({ path: `bridge.discovery.claude.${key}`, before: oldDiscovery[key], after: newDiscovery[key] }));
|
|
112094
|
+
need6(changes.length > 0, "RECONCILE_POLICY_CHANGED");
|
|
111797
112095
|
const compared = structuredClone(current);
|
|
111798
112096
|
compared.bridge.discovery.claude.roots = oldDiscovery.roots;
|
|
111799
112097
|
compared.bridge.discovery.claude.sources = oldDiscovery.sources;
|
|
111800
|
-
|
|
112098
|
+
need6(isDeepStrictEqual13(before2, compared), "RECONCILE_POLICY_CHANGED");
|
|
111801
112099
|
verifyAgentDiscovery(newDiscovery);
|
|
111802
112100
|
return { reason: options.reason, changes };
|
|
111803
112101
|
}
|
|
@@ -111809,21 +112107,21 @@ var init_codex_hook_policy_recovery = __esm(() => {
|
|
|
111809
112107
|
|
|
111810
112108
|
// src/lib/agent-codex-trust.ts
|
|
111811
112109
|
import { lstatSync as lstatSync31, mkdirSync as mkdirSync27, readdirSync as readdirSync23, readFileSync as readFileSync40, realpathSync as realpathSync17, statSync as statSync21 } from "fs";
|
|
111812
|
-
import { createHash as
|
|
112110
|
+
import { createHash as createHash31, randomUUID as randomUUID11 } from "crypto";
|
|
111813
112111
|
import { execFileSync } from "child_process";
|
|
111814
112112
|
import { dirname as dirname34, isAbsolute as isAbsolute28, join as join60, resolve as resolve25 } from "path";
|
|
111815
112113
|
import { homedir as homedir12 } from "os";
|
|
111816
|
-
import { isDeepStrictEqual as
|
|
112114
|
+
import { isDeepStrictEqual as isDeepStrictEqual14 } from "util";
|
|
111817
112115
|
function verifyReleaseArtifact(proof, skillsCli) {
|
|
111818
|
-
|
|
112116
|
+
need6(isAbsolute28(proof.packageTarPath) && !proof.packageTarPath.includes("\x00"), "RECONCILE_RELEASE_PROVENANCE_PATH");
|
|
111819
112117
|
const tarPath = realpathSync17(proof.packageTarPath);
|
|
111820
|
-
|
|
112118
|
+
need6(statSync21(tarPath).isFile(), "RECONCILE_RELEASE_PROVENANCE_PATH");
|
|
111821
112119
|
const tarBytes = readFileSync40(tarPath);
|
|
111822
|
-
|
|
112120
|
+
need6(tarBytes.byteLength === proof.packageTarBytes && createHash31("sha256").update(tarBytes).digest("hex") === proof.packageTarSha256, "RECONCILE_RELEASE_ARTIFACT_CHANGED");
|
|
111823
112121
|
const packageRoot = dirname34(dirname34(realpathSync17(skillsCli.receipt.path)));
|
|
111824
112122
|
const manifest = readFileSync40(join60(packageRoot, "package.json"));
|
|
111825
|
-
|
|
111826
|
-
|
|
112123
|
+
need6(createHash31("sha256").update(manifest).digest("hex") === skillsCli.receipt.manifestSha256 && skillsCli.receipt.manifestSha256 === proof.manifestSha256, "RECONCILE_RELEASE_MANIFEST_CHANGED");
|
|
112124
|
+
need6(createHash31("sha256").update(readFileSync40(skillsCli.receipt.path)).digest("hex") === proof.executableSha256 && skillsCli.receipt.sha256 === proof.executableSha256, "RECONCILE_RELEASE_EXECUTABLE_CHANGED");
|
|
111827
112125
|
const members2 = [["package/package.json", manifest], ["package/bin/index.js", readFileSync40(skillsCli.receipt.path)]];
|
|
111828
112126
|
for (const [member, expected] of members2) {
|
|
111829
112127
|
let actual;
|
|
@@ -111832,7 +112130,7 @@ function verifyReleaseArtifact(proof, skillsCli) {
|
|
|
111832
112130
|
} catch {
|
|
111833
112131
|
throw new Error("RECONCILE_RELEASE_ARTIFACT_MEMBER_MISSING");
|
|
111834
112132
|
}
|
|
111835
|
-
|
|
112133
|
+
need6(Buffer.compare(actual, expected) === 0, "RECONCILE_RELEASE_ARTIFACT_MEMBER_CHANGED");
|
|
111836
112134
|
}
|
|
111837
112135
|
}
|
|
111838
112136
|
async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc) {
|
|
@@ -111840,48 +112138,48 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
111840
112138
|
try {
|
|
111841
112139
|
const home = resolve25(options.home ?? homedir12()), dataDir3 = resolve25(options.dataDir ?? getDataDirReadOnly());
|
|
111842
112140
|
const parent = resolve25(join60(dataDir3, "native-hook-trust")), journal = resolve25(options.journal);
|
|
111843
|
-
|
|
112141
|
+
need6(journal.startsWith(parent + "/") && /^[a-f0-9-]{36}$/.test(journal.slice(parent.length + 1)), "RECONCILE_JOURNAL_PATH");
|
|
111844
112142
|
const dir = lstatSync31(journal, { throwIfNoEntry: false });
|
|
111845
|
-
|
|
111846
|
-
|
|
111847
|
-
|
|
112143
|
+
need6(!!dir && dir.isDirectory() && !dir.isSymbolicLink() && dir.uid === process.getuid() && (dir.mode & 511) === 448, "UNSAFE_JOURNAL");
|
|
112144
|
+
need6(!lstatSync31(join60(journal, "receipt.json"), { throwIfNoEntry: false }), "RECONCILE_ALREADY_COMPLETE");
|
|
112145
|
+
need6(lstatSync31(join60(journal, "stopped.json"), { throwIfNoEntry: false })?.isFile(), "RECONCILE_JOURNAL_INCOMPLETE");
|
|
111848
112146
|
const stoppedFile = snapshot(join60(journal, "stopped.json"), true);
|
|
111849
112147
|
const intentFile = snapshot(join60(journal, "intent.json"), true), intent = JSON.parse(intentFile.text);
|
|
111850
112148
|
const configBefore = snapshot(join60(journal, "config.before.toml"), true), hooksBefore = snapshot(join60(journal, "hooks.before.json"), true), policyBefore = snapshot(join60(journal, "policy.before.json"), true);
|
|
111851
112149
|
const legacyIntent = intent.home === undefined && intent.configSha256 === undefined && intent.configVersion === undefined && intent.declarations === undefined && intent.admitted === undefined && intent.nativeHooks === undefined;
|
|
111852
|
-
|
|
112150
|
+
need6(intent.version === 1 && /^[a-f0-9]{64}$/.test(intent.planDigest) && typeof intent.configPath === "string" && /^[a-f0-9]{64}$/.test(intent.policySha256) && /^[a-f0-9]{64}$/.test(intent.hooksSha256) && Array.isArray(intent.hooks) && intent.hooks.length > 0 && intent.hooks.length <= 100 && (legacyIntent || typeof intent.home === "string" && intent.home === home && /^[a-f0-9]{64}$/.test(intent.configSha256) && typeof intent.configVersion === "string" && Array.isArray(intent.declarations) && Array.isArray(intent.admitted) && Array.isArray(intent.nativeHooks)), "RECONCILE_INTENT_INVALID");
|
|
111853
112151
|
const declarations = intent.declarations ?? intent.hooks.map((hook) => ({ event: hook.event, key: `${join60(home, ".codex/hooks.json")}${hook.key.slice(hook.key.indexOf(".codex/hooks.json") + ".codex/hooks.json".length)}`, command: hook.command }));
|
|
111854
112152
|
const admitted = intent.admitted ?? intent.hooks;
|
|
111855
112153
|
const configSha256 = intent.configSha256 ?? configBefore.sha256, configVersion = intent.configVersion ?? intent.expectedVersion;
|
|
111856
112154
|
const digestInput = { version: 1, home: intent.home ?? home, configPath: intent.configPath, ...intent.nativeConfigPath !== undefined ? { nativeConfigPath: intent.nativeConfigPath } : {}, configSha256, configVersion, policySha256: intent.policySha256, hooksSha256: intent.hooksSha256, skillsCli: intent.skillsCli, nativeVersion: intent.nativeVersion, declarations, admitted };
|
|
111857
|
-
|
|
111858
|
-
|
|
111859
|
-
|
|
112155
|
+
need6(makePlanDigest(digestInput) === intent.planDigest, "RECONCILE_PLAN_CHANGED");
|
|
112156
|
+
need6(isDeepStrictEqual14(intent.hooks, admitted.filter((hook) => !hook.enabled || hook.trustStatus !== "trusted")), "RECONCILE_INTENT_HOOKS_CHANGED");
|
|
112157
|
+
need6(configBefore.sha256 === (intent.beforeSha256 ?? intent.configSha256) && hooksBefore.sha256 === intent.hooksSha256 && policyBefore.sha256 === intent.policySha256, "RECONCILE_JOURNAL_CHANGED");
|
|
111860
112158
|
const policyCurrent = snapshot(join60(dataDir3, "agent-policy.json"), true);
|
|
111861
112159
|
const { claudeDiscoveryRecovery: claudeRecovery, nativeHookAdditionsRecovery: additionsRecovery } = options;
|
|
111862
112160
|
const recovery = claudeRecovery ?? additionsRecovery;
|
|
111863
|
-
|
|
111864
|
-
|
|
111865
|
-
|
|
112161
|
+
need6(!recovery || !options.supersedeBinding, "RECONCILE_RECOVERY_MODE_CONFLICT");
|
|
112162
|
+
need6(!claudeRecovery || !additionsRecovery || claudeRecovery.reviewedPlanDigest === additionsRecovery.reviewedPlanDigest, "RECONCILE_RECOVERY_MODE_CONFLICT");
|
|
112163
|
+
need6(recovery?.reviewedPlanDigest === undefined || /^[a-f0-9]{64}$/.test(recovery.reviewedPlanDigest), "RECONCILE_RECOVERY_PLAN_CHANGED");
|
|
111866
112164
|
const policyChange = claudeRecovery ? reviewedClaudeDiscoveryChange(policyBefore.text, policyCurrent.text, claudeRecovery) : undefined;
|
|
111867
112165
|
let supersededBinding = false;
|
|
111868
112166
|
if (policyCurrent.sha256 !== policyBefore.sha256 && !claudeRecovery) {
|
|
111869
|
-
|
|
112167
|
+
need6(options.supersedeBinding === true, "RECONCILE_POLICY_CHANGED");
|
|
111870
112168
|
const oldPolicy = JSON.parse(policyBefore.text), currentPolicy = JSON.parse(policyCurrent.text);
|
|
111871
|
-
|
|
112169
|
+
need6(isDeepStrictEqual14(withoutCodexCommand(oldPolicy), withoutCodexCommand(currentPolicy)), "RECONCILE_POLICY_CHANGED");
|
|
111872
112170
|
supersededBinding = true;
|
|
111873
112171
|
}
|
|
111874
112172
|
if (supersededBinding || recovery) {
|
|
111875
|
-
|
|
112173
|
+
need6(Array.isArray(intent.nativeHooks) && intent.nativeHooks.length > 0, "RECONCILE_NATIVE_INVENTORY_REQUIRED");
|
|
111876
112174
|
const proof = options.releaseProof;
|
|
111877
|
-
|
|
112175
|
+
need6(!!proof && isAbsolute28(proof.packageTarPath) && /^[a-f0-9]{64}$/.test(proof.packageTarSha256) && Number.isInteger(proof.packageTarBytes) && proof.packageTarBytes > 0 && /^[a-f0-9]{64}$/.test(proof.manifestSha256) && /^[a-f0-9]{64}$/.test(proof.executableSha256), "RECONCILE_RELEASE_PROVENANCE_REQUIRED");
|
|
111878
112176
|
}
|
|
111879
112177
|
const currentConfig = snapshot(intent.configPath, true);
|
|
111880
112178
|
const policy = parseManagedSkillPolicy(policyCurrent.text), binding = policy.bridge;
|
|
111881
112179
|
const alias = binding.rootAliases?.find((item) => item.agent === "codex"), physicalRoot = alias?.target ?? join60(home, ".codex"), hooksPath = join60(physicalRoot, "hooks.json");
|
|
111882
|
-
|
|
112180
|
+
need6(resolve25(intent.configPath) === resolve25(join60(physicalRoot, "config.toml")), "RECONCILE_CONFIG_PATH_CHANGED");
|
|
111883
112181
|
const nativeConfigPath = intent.nativeConfigPath ?? intent.configPath;
|
|
111884
|
-
|
|
112182
|
+
need6([join60(home, ".codex/config.toml"), join60(physicalRoot, "config.toml")].includes(nativeConfigPath), "RECONCILE_NATIVE_CONFIG_PATH_CHANGED");
|
|
111885
112183
|
const codexHome = nativeConfigPath !== intent.configPath ? undefined : dirname34(nativeConfigPath);
|
|
111886
112184
|
const hooksCurrent = snapshot(hooksPath);
|
|
111887
112185
|
const additions = additionsRecovery ? reviewNativeHookAdditions({ path: additionsRecovery.path, intent: intentFile, policy: policyCurrent, configBefore, configCurrent: currentConfig, hooksBefore, hooksCurrent, nativeHooksPath: join60(dirname34(nativeConfigPath), "hooks.json"), journalHooks: intent.hooks, recordedNativeHooks: intent.nativeHooks }) : undefined;
|
|
@@ -111889,7 +112187,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
111889
112187
|
const managedKeys = managedHooks.map((h) => h.key);
|
|
111890
112188
|
const witnessSame = codexTrustReconcileWitness(configBefore.text, managedKeys) === codexTrustReconcileWitness(currentConfig.text, managedKeys);
|
|
111891
112189
|
const unmanagedSame = codexTrustUnmanagedSemantic(configBefore.text, managedKeys) === codexTrustUnmanagedSemantic(currentConfig.text, managedKeys);
|
|
111892
|
-
|
|
112190
|
+
need6(unmanagedSame && (witnessSame || supersededBinding), "RECONCILE_UNRELATED_CONFIG_CHANGED");
|
|
111893
112191
|
const before2 = structure3(configBefore.text), current = structure3(currentConfig.text), expectedConfig = structuredClone(before2);
|
|
111894
112192
|
expectedConfig.hooks ??= {};
|
|
111895
112193
|
expectedConfig.hooks.state ??= {};
|
|
@@ -111901,10 +112199,10 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
111901
112199
|
if (supersededBinding) {
|
|
111902
112200
|
for (const hook of intent.hooks) {
|
|
111903
112201
|
const state = current.hooks?.state?.[hook.key];
|
|
111904
|
-
|
|
112202
|
+
need6(state?.enabled === true && typeof state.trusted_hash === "string" && /^sha256:[a-f0-9]{64}$/.test(state.trusted_hash), "RECONCILE_CONFIG_DRIFT");
|
|
111905
112203
|
}
|
|
111906
112204
|
} else
|
|
111907
|
-
|
|
112205
|
+
need6(isDeepStrictEqual14(expectedConfig, current), "RECONCILE_CONFIG_DRIFT");
|
|
111908
112206
|
const configDiscoveryRecovery = recovery && binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, configBefore, currentConfig, intent.hooks, additions?.trustProof) : undefined;
|
|
111909
112207
|
assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: configDiscoveryRecovery });
|
|
111910
112208
|
const recoveryCli = recovery ? bindSkillsCli("skills", options.reviewedSkillsCli) : undefined;
|
|
@@ -111913,29 +112211,29 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
111913
112211
|
const skillsCli = recovery ? inspectRecordedSkillsCli(binding.commands.codex, intent.skillsCli) : bindSkillsCli(binding.commands.codex, options.reviewedSkillsCli);
|
|
111914
112212
|
if (supersededBinding)
|
|
111915
112213
|
verifyReleaseArtifact(options.releaseProof, skillsCli);
|
|
111916
|
-
const skillsBindingChanged = !
|
|
111917
|
-
|
|
112214
|
+
const skillsBindingChanged = !isDeepStrictEqual14(skillsCli.receipt, intent.skillsCli);
|
|
112215
|
+
need6(!skillsBindingChanged || supersededBinding, "RECONCILE_SKILLS_BINDING_CHANGED");
|
|
111918
112216
|
if (!additions && hooksCurrent.sha256 !== intent.hooksSha256 && hooksCurrent.sha256 !== hooksBefore.sha256) {
|
|
111919
|
-
|
|
112217
|
+
need6(supersededBinding, "RECONCILE_HOOKS_CHANGED");
|
|
111920
112218
|
const currentDeclarations = JSON.parse(hooksCurrent.text).hooks;
|
|
111921
112219
|
for (const [event, [nativeEvent]] of Object.entries(eventNames)) {
|
|
111922
112220
|
const command = renderAgentHookCommand(binding.commands.codex, "codex", binding.profiles.codex, event);
|
|
111923
|
-
|
|
112221
|
+
need6(isDeepStrictEqual14(currentDeclarations?.[event], [{ hooks: [{ type: "command", command, timeout: 15 }] }]), "RECONCILE_BINDING_HOOK_CHANGED");
|
|
111924
112222
|
}
|
|
111925
112223
|
}
|
|
111926
112224
|
rpc = await connect({ command: options.codexCommand ?? "codex", home, codexHome });
|
|
111927
|
-
|
|
112225
|
+
need6(rpc.version === intent.nativeVersion, "RECONCILE_NATIVE_VERSION_CHANGED");
|
|
111928
112226
|
const discovered = await rpc.request("hooks/list", { cwds: [home] });
|
|
111929
|
-
|
|
112227
|
+
need6(Array.isArray(discovered?.data) && discovered.data.length === 1 && discovered.data[0].cwd === home && !discovered.data[0].errors?.length && !discovered.data[0].warnings?.length, "RECONCILE_NATIVE_DISCOVERY_REFUSED");
|
|
111930
112228
|
const nativeHooks = discovered.data[0].hooks;
|
|
111931
112229
|
const recordedNativeHooks = intent.nativeHooks;
|
|
111932
112230
|
if (recordedNativeHooks)
|
|
111933
|
-
|
|
112231
|
+
need6(nativeHooks.length === recordedNativeHooks.length + (additions?.hooks.length ?? 0), "RECONCILE_NATIVE_HOOK_LIST_CHANGED");
|
|
111934
112232
|
const plannedKeys = new Set(intent.hooks.map((hook) => hook.key));
|
|
111935
112233
|
let nativeTrustPending = false;
|
|
111936
112234
|
for (const expected of [...recordedNativeHooks ?? [], ...additions?.hooks ?? []]) {
|
|
111937
112235
|
const matches2 = nativeHooks.filter((hook) => hook.key === expected.key);
|
|
111938
|
-
|
|
112236
|
+
need6(matches2.length === 1, "RECONCILE_NATIVE_HOOK_LIST_CHANGED");
|
|
111939
112237
|
const actual = safeNativeHook(matches2[0]);
|
|
111940
112238
|
const stable = (hook) => {
|
|
111941
112239
|
const { enabled, trustStatus, ...identity5 } = hook;
|
|
@@ -111943,35 +112241,35 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
111943
112241
|
delete identity5.command;
|
|
111944
112242
|
return identity5;
|
|
111945
112243
|
};
|
|
111946
|
-
|
|
112244
|
+
need6(isDeepStrictEqual14(stable(actual), stable(expected)), "RECONCILE_NATIVE_IDENTITY_CHANGED");
|
|
111947
112245
|
if (!plannedKeys.has(expected.key))
|
|
111948
|
-
|
|
112246
|
+
need6(isDeepStrictEqual14(actual, expected), "RECONCILE_UNRELATED_HOOK_CHANGED");
|
|
111949
112247
|
}
|
|
111950
112248
|
for (const wanted of intent.hooks) {
|
|
111951
112249
|
const matches2 = nativeHooks.filter((h2) => h2.key === wanted.key || h2.key === wanted.key.replace(join60(home, ".codex/hooks.json"), hooksPath));
|
|
111952
|
-
|
|
112250
|
+
need6(matches2.length === 1, "RECONCILE_NATIVE_IDENTITY_CHANGED");
|
|
111953
112251
|
const h = matches2[0];
|
|
111954
112252
|
const trusted = h.trustStatus === "trusted";
|
|
111955
|
-
|
|
112253
|
+
need6(h.enabled === true && (trusted || supersededBinding && h.trustStatus === "modified") && (h.currentHash === wanted.currentHash || supersededBinding && /^sha256:[a-f0-9]{64}$/.test(h.currentHash)), "RECONCILE_NATIVE_STATE_INCOMPLETE");
|
|
111956
112254
|
if (!trusted)
|
|
111957
112255
|
nativeTrustPending = true;
|
|
111958
112256
|
if (supersededBinding) {
|
|
111959
112257
|
const nativeToCliEvent = { userPromptSubmit: "UserPromptSubmit", sessionStart: "SessionStart", subagentStart: "SubagentStart" };
|
|
111960
|
-
|
|
112258
|
+
need6(h.command === renderAgentHookCommand(binding.commands.codex, "codex", binding.profiles.codex, nativeToCliEvent[wanted.event] ?? ""), "RECONCILE_BINDING_HOOK_CHANGED");
|
|
111961
112259
|
}
|
|
111962
112260
|
}
|
|
111963
112261
|
const config2 = await rpc.request("config/read", { includeLayers: true, cwd: home });
|
|
111964
112262
|
const layers = config2?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
|
|
111965
|
-
|
|
112263
|
+
need6(layers?.length === 1 && !layers[0].disabledReason && codexNativeConfigEqual(layers[0].config, current), "RECONCILE_NATIVE_CONFIG_MISMATCH");
|
|
111966
112264
|
const finalDiscovery = await rpc.request("hooks/list", { cwds: [home] });
|
|
111967
|
-
|
|
112265
|
+
need6(Array.isArray(finalDiscovery?.data) && finalDiscovery.data.length === 1 && finalDiscovery.data[0].cwd === home && !finalDiscovery.data[0].errors?.length && !finalDiscovery.data[0].warnings?.length && (!recordedNativeHooks || isDeepStrictEqual14(finalDiscovery.data[0].hooks.map(safeNativeHook), nativeHooks.map(safeNativeHook))), "RECONCILE_NATIVE_STATE_CHANGED");
|
|
111968
112266
|
const finalConfig = await rpc.request("config/read", { includeLayers: true, cwd: home });
|
|
111969
112267
|
const finalLayers = finalConfig?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
|
|
111970
|
-
|
|
112268
|
+
need6(finalLayers?.length === 1 && !finalLayers[0].disabledReason && codexNativeConfigEqual(finalLayers[0].config, current), "RECONCILE_NATIVE_CONFIG_CHANGED");
|
|
111971
112269
|
if (recovery) {
|
|
111972
112270
|
for (const response of [config2, finalConfig]) {
|
|
111973
112271
|
const layerIndex = response.layers.findIndex((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
|
|
111974
|
-
|
|
112272
|
+
need6(response.config && response.config.features?.hooks !== false && response.layers.slice(0, layerIndex).every((layer) => layer.config?.hooks === undefined && layer.config?.features?.hooks === undefined), "RECONCILE_NATIVE_CONFIG_OVERRIDDEN");
|
|
111975
112273
|
}
|
|
111976
112274
|
recoveryCli.recheck();
|
|
111977
112275
|
verifyReleaseArtifact(options.releaseProof, recoveryCli);
|
|
@@ -111992,7 +112290,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
111992
112290
|
const recoveryPlan = recovery ? { version: 1, kind: additions ? claudeRecovery ? "claude-discovery-and-native-hook-additions" : "native-hook-additions" : "claude-discovery-only", journal, journalIntentSha256: intentFile.sha256, stoppedSha256: stoppedFile.sha256, originalPlanDigest: intent.planDigest, policyBeforeSha256: policyBefore.sha256, policyCurrentSha256: policyCurrent.sha256, configBeforeSha256: configBefore.sha256, configCurrentSha256: currentConfig.sha256, ...configDiscoveryRecovery ? { configDiscoveryRecovery } : {}, ...additions ? { nativeHookAdditions: additions.receipt } : {}, hooksSha256: hooksCurrent.sha256, nativeConfigPath, nativeVersion: rpc.version, nativeInventorySha256: makePlanDigest(nativeHooks.map(safeNativeHook)), recordedNativeInventorySha256: makePlanDigest(recordedNativeHooks), boundSkillsCli: skillsCli.receipt, recoveryCli: recoveryCli.receipt, releaseProof: options.releaseProof, ...policyChange } : undefined;
|
|
111993
112291
|
const recoveryPlanDigest = recoveryPlan ? makePlanDigest(recoveryPlan) : undefined;
|
|
111994
112292
|
if (recovery?.reviewedPlanDigest !== undefined)
|
|
111995
|
-
|
|
112293
|
+
need6(recovery.reviewedPlanDigest === recoveryPlanDigest, "RECONCILE_RECOVERY_PLAN_CHANGED");
|
|
111996
112294
|
const preview2 = !!recovery && recovery.reviewedPlanDigest === undefined;
|
|
111997
112295
|
const receipt = { version: 1, status: preview2 ? "recovery-review-required" : supersededBinding ? "superseded" : "reconciled", reconciled: !preview2, supersededBinding, automaticRollback: false, journal, planDigest: intent.planDigest, nativeVersion: rpc.version, nativeStateVerified: !nativeTrustPending, nativeTrustPending, bindingRefreshRequired: !!configDiscoveryRecovery, nativeExecutionVerified: false, configSha256: currentConfig.sha256, hooksSha256: hooksCurrent.sha256, policySha256: policyBefore.sha256, policyBeforeSha256: policyBefore.sha256, policyCurrentSha256: policyCurrent.sha256, previousSkillsCli: intent.skillsCli, skillsCli: skillsCli.receipt, releaseProof: options.releaseProof, nativeInventoryScope: recordedNativeHooks ? "complete" : "declared-managed-hooks-only", unrelatedNativeHooksPreserved: !!recordedNativeHooks, unrelatedSettingsAndCommentsPreserved: true, ...recoveryPlan ? { recoveryPlan, recoveryPlanDigest } : {} };
|
|
111998
112296
|
if (preview2)
|
|
@@ -112015,7 +112313,7 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
|
|
|
112015
112313
|
const binding = policy.bridge, alias = binding.rootAliases?.find((item) => item.agent === "codex");
|
|
112016
112314
|
const skillsCli = bindSkillsCli(binding.commands.codex, options.reviewedSkillsCli);
|
|
112017
112315
|
const physicalRoot = alias?.target ?? join60(home, ".codex"), hooksPath = join60(physicalRoot, "hooks.json"), configPath = join60(physicalRoot, "config.toml");
|
|
112018
|
-
|
|
112316
|
+
need6(options.codexHome === undefined || isAbsolute28(options.codexHome) && [join60(home, ".codex"), physicalRoot].includes(options.codexHome), "NATIVE_HOME_NOT_ADMITTED");
|
|
112019
112317
|
const codexHome = options.codexHome === undefined ? undefined : physicalRoot;
|
|
112020
112318
|
const nativeConfigPath = join60(codexHome ?? join60(home, ".codex"), "config.toml");
|
|
112021
112319
|
const hooksFile = snapshot(hooksPath), configFile = snapshot(configPath, true), original = structure3(configFile.text);
|
|
@@ -112023,38 +112321,38 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
|
|
|
112023
112321
|
for (const [event, [nativeEvent, label]] of Object.entries(eventNames)) {
|
|
112024
112322
|
const command = renderAgentHookCommand(binding.commands.codex, "codex", binding.profiles.codex, event);
|
|
112025
112323
|
const groups = declarations[event];
|
|
112026
|
-
|
|
112324
|
+
need6(Array.isArray(groups), "DECLARATION_CHANGED");
|
|
112027
112325
|
const matches2 = groups.flatMap((group, gi) => (group.hooks ?? []).flatMap((entry, hi) => entry.command === command ? [{ group, entry, gi, hi }] : []));
|
|
112028
|
-
|
|
112326
|
+
need6(matches2.length === 1 && isDeepStrictEqual14(matches2[0].group, { hooks: [{ type: "command", command, timeout: 15 }] }), "DECLARATION_CHANGED");
|
|
112029
112327
|
expected.push({ event: nativeEvent, key: `${join60(home, ".codex/hooks.json")}:${label}:${matches2[0].gi}:${matches2[0].hi}`, command });
|
|
112030
112328
|
}
|
|
112031
112329
|
codexTrustTextWitness(configFile.text, expected.map((h) => h.key));
|
|
112032
112330
|
rpc = await connect({ command: options.codexCommand ?? "codex", home, codexHome });
|
|
112033
|
-
|
|
112331
|
+
need6(SUPPORTED_CODEX_HOOK_VERSIONS.includes(rpc.version), "NATIVE_UNSUPPORTED_VERSION");
|
|
112034
112332
|
const list2 = async () => {
|
|
112035
112333
|
const response = await rpc.request("hooks/list", { cwds: [home] });
|
|
112036
112334
|
const nativeRoots = [...new Set([physicalRoot, join60(home, ".codex")])];
|
|
112037
112335
|
const coexistenceWarnings = nativeRoots.flatMap((hooksRoot) => nativeRoots.map((configRoot) => `loading hooks from both ${join60(hooksRoot, "hooks.json")} and ${join60(configRoot, "config.toml")}; prefer a single representation for this layer`));
|
|
112038
112336
|
const entry = response?.data?.[0];
|
|
112039
|
-
|
|
112337
|
+
need6(Array.isArray(response?.data) && response.data.length === 1 && entry.cwd === home && Array.isArray(entry.hooks) && entry.hooks.length <= 1e4 && Array.isArray(entry.errors) && entry.errors.length === 0 && Array.isArray(entry.warnings) && entry.warnings.length <= 1 && entry.warnings.every((warning) => typeof warning === "string" && coexistenceWarnings.includes(warning)), "NATIVE_DISCOVERY_REFUSED");
|
|
112040
112338
|
return response.data[0].hooks;
|
|
112041
112339
|
};
|
|
112042
112340
|
const admit = (hooks) => expected.map((wanted) => {
|
|
112043
112341
|
const canonicalKey = wanted.key.replace(join60(home, ".codex/hooks.json"), hooksPath);
|
|
112044
112342
|
const matches2 = hooks.filter((h2) => h2.key === wanted.key || h2.key === canonicalKey);
|
|
112045
|
-
|
|
112343
|
+
need6(matches2.length === 1, "AMBIGUOUS_IDENTITY");
|
|
112046
112344
|
const h = matches2[0];
|
|
112047
|
-
|
|
112048
|
-
|
|
112049
|
-
|
|
112345
|
+
need6(h.eventName === wanted.event && h.handlerType === "command" && h.command === wanted.command && h.matcher === null && h.timeoutSec === 15 && h.async === false && h.statusMessage === null && h.additionalContextLimit === null && [hooksPath, join60(home, ".codex/hooks.json")].includes(h.sourcePath) && h.source === "user" && h.pluginId === null && h.isManaged === false && /^sha256:[a-f0-9]{64}$/.test(h.currentHash) && typeof h.enabled === "boolean", "NATIVE_IDENTITY_CHANGED");
|
|
112346
|
+
need6(hooks.filter((other) => other.command === wanted.command).length === 1, "AMBIGUOUS_IDENTITY");
|
|
112347
|
+
need6(["trusted", "untrusted", "modified"].includes(h.trustStatus), "UNKNOWN_TRUST_STATUS");
|
|
112050
112348
|
return { key: h.key, event: wanted.event, command: wanted.command, handlerType: h.handlerType, timeoutSec: h.timeoutSec, sourcePath: h.sourcePath, currentHash: h.currentHash, enabled: h.enabled, trustStatus: h.trustStatus };
|
|
112051
112349
|
});
|
|
112052
112350
|
const discovered = await list2(), admitted = admit(discovered);
|
|
112053
112351
|
const config2 = await rpc.request("config/read", { includeLayers: true, cwd: home });
|
|
112054
112352
|
const layers = config2?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
|
|
112055
|
-
|
|
112056
|
-
|
|
112057
|
-
|
|
112353
|
+
need6(layers?.length === 1 && /^sha256:[a-f0-9]{64}$/.test(layers[0].version) && !layers[0].disabledReason && codexNativeConfigEqual(layers[0].config, original), "NATIVE_CONFIG_MISMATCH");
|
|
112354
|
+
need6(config2.config && config2.config.features?.hooks !== false, "NATIVE_HOOKS_DISABLED");
|
|
112355
|
+
need6(config2.layers.slice(0, config2.layers.indexOf(layers[0])).every((layer) => layer.config?.hooks === undefined && layer.config?.features?.hooks === undefined), "NATIVE_CONFIG_OVERRIDDEN");
|
|
112058
112356
|
const keys3 = admitted.map((h) => h.key), planned = admitted.filter((h) => !h.enabled || h.trustStatus !== "trusted");
|
|
112059
112357
|
const preservationText = codexTrustTextWitness(configFile.text, keys3);
|
|
112060
112358
|
const checkInputs = () => {
|
|
@@ -112069,16 +112367,16 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
|
|
|
112069
112367
|
const planDigest = makePlanDigest(digestInput);
|
|
112070
112368
|
const baseReceipt = { planDigest, skillsCli: skillsCli.receipt, nativeVersion: rpc.version, nativeConfigPath, ownedNativeProcessId: rpc.processId, agent: "codex", applied: false, planned, nativeEligible: planned.length === 0, bindingRefreshRequired: false, transport: "owned-stdio-process", existingSessionsReloaded: false, nativeExecutionVerified: false };
|
|
112071
112369
|
if (options.apply)
|
|
112072
|
-
|
|
112370
|
+
need6(options.reviewedPlanDigest === planDigest, "PLAN_CHANGED: run the dry-run again and pass its reviewed --plan-digest with --apply");
|
|
112073
112371
|
const parent = join60(dataDir3, "native-hook-trust");
|
|
112074
112372
|
const st = lstatSync31(parent, { throwIfNoEntry: false });
|
|
112075
112373
|
if (st) {
|
|
112076
|
-
|
|
112374
|
+
need6(st.isDirectory() && !st.isSymbolicLink() && st.uid === process.getuid() && (st.mode & 511) === 448, "UNSAFE_JOURNAL");
|
|
112077
112375
|
const priorJournals = readdirSync23(parent);
|
|
112078
|
-
|
|
112376
|
+
need6(priorJournals.length < 1000, "JOURNAL_BOUND");
|
|
112079
112377
|
for (const name of priorJournals) {
|
|
112080
|
-
|
|
112081
|
-
|
|
112378
|
+
need6(/^[a-f0-9-]{36}$/.test(name), "UNSAFE_JOURNAL");
|
|
112379
|
+
need6(lstatSync31(join60(parent, name, "receipt.json"), { throwIfNoEntry: false })?.isFile(), "RECONCILE_REQUIRED: inspect the incomplete private journal before applying again");
|
|
112082
112380
|
}
|
|
112083
112381
|
}
|
|
112084
112382
|
if (!options.apply || !planned.length)
|
|
@@ -112091,7 +112389,7 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
|
|
|
112091
112389
|
save(join60(journal, "hooks.before.json"), hooksFile.bytes);
|
|
112092
112390
|
save(join60(journal, "policy.before.json"), policyFile.bytes);
|
|
112093
112391
|
save(join60(journal, "intent.json"), json2({ ...digestInput, planDigest, hooks: planned, nativeHooks: discovered.map(safeNativeHook) }));
|
|
112094
|
-
|
|
112392
|
+
need6(isDeepStrictEqual14(admit(await list2()), admitted), "NATIVE_DISCOVERY_CHANGED");
|
|
112095
112393
|
checkInputs();
|
|
112096
112394
|
let result2;
|
|
112097
112395
|
try {
|
|
@@ -112099,22 +112397,22 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
|
|
|
112099
112397
|
} catch {
|
|
112100
112398
|
throw new Error("CODEX_HOOK_TRUST_NATIVE_WRITE_FAILED: reconcile the private journal before retrying");
|
|
112101
112399
|
}
|
|
112102
|
-
|
|
112400
|
+
need6(result2?.status === "ok" && result2.filePath === configPath && /^sha256:[a-f0-9]{64}$/.test(result2.version), "NATIVE_WRITE_OVERRIDDEN");
|
|
112103
112401
|
const after2 = snapshot(configPath, true), expectedConfig = structuredClone(original);
|
|
112104
112402
|
expectedConfig.hooks ??= {};
|
|
112105
112403
|
expectedConfig.hooks.state ??= {};
|
|
112106
112404
|
for (const h of planned)
|
|
112107
112405
|
expectedConfig.hooks.state[h.key] = { ...expectedConfig.hooks.state[h.key], enabled: true, trusted_hash: h.currentHash };
|
|
112108
|
-
|
|
112406
|
+
need6(isDeepStrictEqual14(structure3(after2.text), expectedConfig) && codexTrustTextWitness(after2.text, keys3) === preservationText, "PRESERVATION_FAILED");
|
|
112109
112407
|
const savedConfig = snapshot(join60(journal, "config.before.toml"), true);
|
|
112110
|
-
|
|
112408
|
+
need6(savedConfig.sha256 === configFile.sha256, "JOURNAL_CHANGED");
|
|
112111
112409
|
const discoveryTransition = binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, savedConfig, after2, planned) : undefined;
|
|
112112
112410
|
unchanged2(policyFile);
|
|
112113
112411
|
unchanged2(hooksFile);
|
|
112114
112412
|
assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: discoveryTransition });
|
|
112115
112413
|
const current = await list2(), confirmed = admit(current);
|
|
112116
|
-
|
|
112117
|
-
|
|
112414
|
+
need6(confirmed.every((h) => h.enabled && h.trustStatus === "trusted") && isDeepStrictEqual14(confirmed.map((h) => [h.key, h.currentHash]), admitted.map((h) => [h.key, h.currentHash])), "NATIVE_NOT_ELIGIBLE");
|
|
112415
|
+
need6(isDeepStrictEqual14(current.filter((h) => !keys3.includes(h.key)), discovered.filter((h) => !keys3.includes(h.key))), "UNRELATED_HOOK_CHANGED");
|
|
112118
112416
|
unchanged2(after2);
|
|
112119
112417
|
unchanged2(savedConfig);
|
|
112120
112418
|
unchanged2(hooksFile);
|
|
@@ -112137,7 +112435,7 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
|
|
|
112137
112435
|
}
|
|
112138
112436
|
}
|
|
112139
112437
|
var json2 = (value) => JSON.stringify(value, null, 2) + `
|
|
112140
|
-
`, structure3 = (text4) => JSON.parse(JSON.stringify(Bun.TOML.parse(text4))), eventNames, makePlanDigest = (value) =>
|
|
112438
|
+
`, structure3 = (text4) => JSON.parse(JSON.stringify(Bun.TOML.parse(text4))), eventNames, makePlanDigest = (value) => createHash31("sha256").update(json2(value)).digest("hex"), safeNativeHook = (hook) => ({ key: hook.key, eventName: hook.eventName, handlerType: hook.handlerType, command: hook.command, matcher: hook.matcher, timeoutSec: hook.timeoutSec, async: hook.async, statusMessage: hook.statusMessage, additionalContextLimit: hook.additionalContextLimit, sourcePath: hook.sourcePath, source: hook.source, pluginId: hook.pluginId, isManaged: hook.isManaged, currentHash: hook.currentHash, enabled: hook.enabled, trustStatus: hook.trustStatus }), withoutCodexCommand = (value) => {
|
|
112141
112439
|
const copy = structuredClone(value);
|
|
112142
112440
|
if (copy?.bridge?.commands && Object.hasOwn(copy.bridge.commands, "codex"))
|
|
112143
112441
|
copy.bridge.commands.codex = "<reviewed-codex-binding>";
|
|
@@ -112277,7 +112575,7 @@ __export(exports_agent_integration, {
|
|
|
112277
112575
|
registerAgentIntegration: () => registerAgentIntegration
|
|
112278
112576
|
});
|
|
112279
112577
|
import { existsSync as existsSync35, lstatSync as lstatSync32, readFileSync as readFileSync41, writeFileSync as writeFileSync26 } from "fs";
|
|
112280
|
-
import { createHash as
|
|
112578
|
+
import { createHash as createHash32 } from "crypto";
|
|
112281
112579
|
import { homedir as homedir13 } from "os";
|
|
112282
112580
|
import { isAbsolute as isAbsolute29 } from "path";
|
|
112283
112581
|
function pinnedHookProfile(input3, configuredProfile) {
|
|
@@ -112375,7 +112673,7 @@ function registerAgentIntegration(parent) {
|
|
|
112375
112673
|
skillCount: catalog.skills.length,
|
|
112376
112674
|
output: options.output,
|
|
112377
112675
|
bytes: Buffer.byteLength(bytes),
|
|
112378
|
-
sha256:
|
|
112676
|
+
sha256: createHash32("sha256").update(bytes).digest("hex")
|
|
112379
112677
|
};
|
|
112380
112678
|
await writeCliOutput(options.json ? JSON.stringify(receipt) : `Captured ${receipt.skillCount} native Codex skill(s) in ${receipt.output}.`);
|
|
112381
112679
|
} catch (error61) {
|
|
@@ -112384,10 +112682,10 @@ function registerAgentIntegration(parent) {
|
|
|
112384
112682
|
process.exitCode = 1;
|
|
112385
112683
|
}
|
|
112386
112684
|
});
|
|
112387
|
-
hook.command("witness").requiredOption("--kind <kind>", "claude-settings-v3, claude-settings-v2, codex-settings-v1 or claude-marketplace-registry-v2").requiredOption("--path <path>", "Canonical absolute path to the reviewed settings or registry file").option("--json", "Output the discovery witness as JSON", false).description("Capture an explicit versioned review witness without installing it").action(async (options) => {
|
|
112388
|
-
const capture2 = options.kind === "codex-settings-v1" ? captureCodexSettings : options.kind === "claude-settings-v3" ? captureClaudeSettingsV3 : options.kind === "claude-settings-v2" ? captureClaudeSettingsV2 : options.kind === "claude-marketplace-registry-v2" ? captureClaudeMarketplaceRegistryV2 : null;
|
|
112685
|
+
hook.command("witness").requiredOption("--kind <kind>", "claude-settings-v3, claude-settings-v2, codex-settings-v2, codex-settings-v1 or claude-marketplace-registry-v2").requiredOption("--path <path>", "Canonical absolute path to the reviewed settings or registry file").option("--json", "Output the discovery witness as JSON", false).description("Capture an explicit versioned review witness without installing it").action(async (options) => {
|
|
112686
|
+
const capture2 = options.kind === "codex-settings-v2" ? captureCodexSettingsV2 : options.kind === "codex-settings-v1" ? captureCodexSettings : options.kind === "claude-settings-v3" ? captureClaudeSettingsV3 : options.kind === "claude-settings-v2" ? captureClaudeSettingsV2 : options.kind === "claude-marketplace-registry-v2" ? captureClaudeMarketplaceRegistryV2 : null;
|
|
112389
112687
|
if (!capture2)
|
|
112390
|
-
throw new Error("Unsupported witness kind; select claude-settings-v3, claude-settings-v2, codex-settings-v1 or claude-marketplace-registry-v2");
|
|
112688
|
+
throw new Error("Unsupported witness kind; select claude-settings-v3, claude-settings-v2, codex-settings-v2, codex-settings-v1 or claude-marketplace-registry-v2");
|
|
112391
112689
|
await writeCliOutput(JSON.stringify(capture2(options.path), null, 2));
|
|
112392
112690
|
});
|
|
112393
112691
|
hook.command("rebind-settings").requiredOption("--agent <agent>", "claude or codex").requiredOption("--reviewed-preimage <path>", "Exact preserved legacy settings.json or config.toml").requiredOption("--expected-policy-sha256 <sha256>", "Exact current managed policy bytes").requiredOption("--expected-settings-sha256 <sha256>", "Exact current native settings bytes").option("--apply", "Apply the explicit semantic witness upgrade with preservation and readback", false).option("--json", "Return the metadata-only plan or receipt", false).description("Explicitly migrate a legacy native settings witness after proving only known preferences changed").action(async (options) => {
|
|
@@ -112406,7 +112704,7 @@ function registerAgentIntegration(parent) {
|
|
|
112406
112704
|
hook.command("agents").option("--json", "Output the adapter capability inventory", false).description("Show maintained native adapters and explicit coverage limits").action(async () => {
|
|
112407
112705
|
await writeCliOutput(JSON.stringify({ agents: INTEGRATION_AGENTS.map((agent) => ({ agent, bridge: true, ...AGENT_ADAPTERS[agent] })), inventoryOnly: ["codewith", "windsurf", "pi", "amp", "cline", "roo", "copilot"], limitations: ["Cursor prompt hooks gate submission; selected context is injected at session start only.", "Native discovery checks cover known home roots and current project ancestors. External plugin hook injection and arbitrary added directories require separate review.", "Hermes injects selected prompt context, but native pre_llm_call fails open. Exact native hook trust, bundled reseeding opt-out, native payload retirement and a supervised pre-tool guard are required. Child failures block explicitly; native host/supervisor death is not a universal fail-closed guarantee.", "Restart agents and use their normal hook trust controls after installation."] }, null, 2));
|
|
112408
112706
|
});
|
|
112409
|
-
hook.command("install").option("--agent <agent>", `Agent to configure: ${INTEGRATION_AGENTS.join(", ")}, all`, "all").option("--command <path>", "Skills executable used by the hook (preserves existing binding; new agents use skills)").option("--selection-profile <id>", "Selection profile (preserves existing binding; new agents use default)").option("--include-vendor", "Retained for compatibility; vendor system skills are always inventoried and disabled", false).option("--discovery-inputs <file>", "Advanced reviewed active plugin roots and source hashes for unsupported registrations").option("--codex-native-catalog <file>", "Reviewed Codex
|
|
112707
|
+
hook.command("install").option("--agent <agent>", `Agent to configure: ${INTEGRATION_AGENTS.join(", ")}, all`, "all").option("--command <path>", "Skills executable used by the hook (preserves existing binding; new agents use skills)").option("--selection-profile <id>", "Selection profile (preserves existing binding; new agents use default)").option("--include-vendor", "Retained for compatibility; vendor system skills are always inventoried and disabled", false).option("--discovery-inputs <file>", "Advanced reviewed active plugin roots and source hashes for unsupported registrations").option("--codex-native-catalog <file>", "Reviewed supported Codex skill and installed-plugin receipt for exact qualified-name disables").option("--reviewed-cache-alias <path>", "Exact skill-containing vendor cache alias reviewed for this hook plan").option("--allow-root-aliases", "Allow home .claude/.codex aliases to existing directories within this home", false).option("--apply", "Apply the plan, preserving prior configuration in private backups", false).option("--json", "Output a receipt as JSON", false).description("Plan or install one Skills CLI bridge plus native prompt hooks").action(async (options) => {
|
|
112410
112708
|
try {
|
|
112411
112709
|
const discoveryInputs = options.discoveryInputs ? JSON.parse(readFileSync41(options.discoveryInputs, "utf8")) : undefined;
|
|
112412
112710
|
const plan = planAgentIntegration({ projectDir: process.cwd(), agents: agents(options.agent), command: options.command, profileId: options.selectionProfile, includeVendor: options.includeVendor, discoveryInputs, allowRootAliases: options.allowRootAliases, reviewedCacheAlias: options.reviewedCacheAlias, codexNativeCatalog: options.codexNativeCatalog ? JSON.parse(readFileSync41(options.codexNativeCatalog, "utf8")) : undefined });
|
|
@@ -112889,7 +113187,7 @@ var init_grants = __esm(() => {
|
|
|
112889
113187
|
});
|
|
112890
113188
|
|
|
112891
113189
|
// src/lib/station-hydrate.ts
|
|
112892
|
-
import { createHash as
|
|
113190
|
+
import { createHash as createHash33 } from "crypto";
|
|
112893
113191
|
import {
|
|
112894
113192
|
copyFileSync as copyFileSync3,
|
|
112895
113193
|
mkdirSync as mkdirSync28,
|
|
@@ -113092,7 +113390,7 @@ function skillSha256(skill) {
|
|
|
113092
113390
|
return sha256File(skill.files[0].winner.fullPath);
|
|
113093
113391
|
}
|
|
113094
113392
|
const joined = skill.files.map((file2) => sha256File(file2.winner.fullPath));
|
|
113095
|
-
return
|
|
113393
|
+
return createHash33("sha256").update(joined.sort().join(`
|
|
113096
113394
|
`)).digest("hex");
|
|
113097
113395
|
}
|
|
113098
113396
|
function writeStationHydration(options) {
|
|
@@ -113249,7 +113547,7 @@ var init_hydrate = __esm(() => {
|
|
|
113249
113547
|
});
|
|
113250
113548
|
|
|
113251
113549
|
// src/lib/prepare-skill.ts
|
|
113252
|
-
import { createHash as
|
|
113550
|
+
import { createHash as createHash34, randomUUID as randomUUID12 } from "crypto";
|
|
113253
113551
|
import { chmodSync as chmodSync5, existsSync as existsSync36, lstatSync as lstatSync33, mkdirSync as mkdirSync29, mkdtempSync as mkdtempSync6, readFileSync as readFileSync43, readdirSync as readdirSync25, renameSync as renameSync14, rmSync as rmSync9, writeFileSync as writeFileSync30 } from "fs";
|
|
113254
113552
|
import { tmpdir as tmpdir2 } from "os";
|
|
113255
113553
|
import { dirname as dirname36, isAbsolute as isAbsolute30, join as join62, relative as relative11, resolve as resolve27, sep as sep14 } from "path";
|
|
@@ -113266,7 +113564,7 @@ function prepareSkill(name, options) {
|
|
|
113266
113564
|
let manifest;
|
|
113267
113565
|
try {
|
|
113268
113566
|
const parsed = JSON.parse(manifestFile.bytes.toString("utf8"));
|
|
113269
|
-
if (!
|
|
113567
|
+
if (!isRecord9(parsed))
|
|
113270
113568
|
throw new Error("not an object");
|
|
113271
113569
|
manifest = parsed;
|
|
113272
113570
|
} catch {
|
|
@@ -113288,7 +113586,7 @@ function prepareSkill(name, options) {
|
|
|
113288
113586
|
if (documentKind !== undefined && documentKind !== kind) {
|
|
113289
113587
|
throw new Error("SKILL.md kind conflicts with the candidate skill.json kind. Review and align both declarations (or remove the optional frontmatter kind), then prepare again; no files were changed.");
|
|
113290
113588
|
}
|
|
113291
|
-
if (manifest.provenance !== undefined && !
|
|
113589
|
+
if (manifest.provenance !== undefined && !isRecord9(manifest.provenance))
|
|
113292
113590
|
throw new Error("skill.json provenance must be an object.");
|
|
113293
113591
|
const provenance = manifest.provenance;
|
|
113294
113592
|
const candidate2 = { ...manifest, version: options.version, kind, provenance: { ...provenance } };
|
|
@@ -113353,7 +113651,7 @@ function escapedRelativePath(path) {
|
|
|
113353
113651
|
return JSON.stringify(bounded);
|
|
113354
113652
|
}
|
|
113355
113653
|
function validateRuntimeEntrypoint(candidate2, root2) {
|
|
113356
|
-
if (candidate2.kind !== "executable" || !
|
|
113654
|
+
if (candidate2.kind !== "executable" || !isRecord9(candidate2.runtime))
|
|
113357
113655
|
return;
|
|
113358
113656
|
const entry = candidate2.runtime.entrypoint;
|
|
113359
113657
|
if (typeof entry !== "string")
|
|
@@ -113363,7 +113661,7 @@ function validateRuntimeEntrypoint(candidate2, root2) {
|
|
|
113363
113661
|
throw new Error("Executable runtime.entrypoint must name an existing regular file inside the skill directory.");
|
|
113364
113662
|
}
|
|
113365
113663
|
}
|
|
113366
|
-
function
|
|
113664
|
+
function isRecord9(value) {
|
|
113367
113665
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
113368
113666
|
}
|
|
113369
113667
|
function validateRawCandidate(candidate2) {
|
|
@@ -113388,7 +113686,7 @@ function validateRawCandidate(candidate2) {
|
|
|
113388
113686
|
if (!Array.isArray(items))
|
|
113389
113687
|
throw new Error(`skill.json ${field2} must be an array.`);
|
|
113390
113688
|
for (const item of items) {
|
|
113391
|
-
if (!
|
|
113689
|
+
if (!isRecord9(item) || typeof item.name !== "string" || !item.name.trim())
|
|
113392
113690
|
throw new Error(`Invalid skill.json ${field2} name.`);
|
|
113393
113691
|
if (field2 === "inputs" && (typeof item.type !== "string" || !item.type.trim() || item.required !== undefined && typeof item.required !== "boolean"))
|
|
113394
113692
|
throw new Error("Invalid skill.json input type or required flag.");
|
|
@@ -113407,7 +113705,7 @@ function validateRawCandidate(candidate2) {
|
|
|
113407
113705
|
}
|
|
113408
113706
|
}
|
|
113409
113707
|
function validateRuntimeEntrypointCompatibility(candidate2) {
|
|
113410
|
-
if (candidate2.kind !== "executable" || !
|
|
113708
|
+
if (candidate2.kind !== "executable" || !isRecord9(candidate2.runtime))
|
|
113411
113709
|
return;
|
|
113412
113710
|
const runtime = candidate2.runtime.runtime;
|
|
113413
113711
|
const entrypoint = candidate2.runtime.entrypoint;
|
|
@@ -113448,7 +113746,7 @@ function snapshot2(root2) {
|
|
|
113448
113746
|
if (rootStat.isSymbolicLink() || !rootStat.isDirectory())
|
|
113449
113747
|
throw new Error("Skill root must be a real directory, not a symlink.");
|
|
113450
113748
|
const files = [], directories = [];
|
|
113451
|
-
const hash6 =
|
|
113749
|
+
const hash6 = createHash34("sha256").update(`${rootStat.dev}:${rootStat.ino}\x00`);
|
|
113452
113750
|
let count = 0, bytes = 0;
|
|
113453
113751
|
const walk2 = (relative12) => {
|
|
113454
113752
|
for (const name of readdirSync25(join62(root2, relative12)).sort()) {
|
|
@@ -114734,7 +115032,7 @@ async function apiRequest(path, options, instance) {
|
|
|
114734
115032
|
const origin = instance ?? getApiUrl(`${(options?.method || "GET").toUpperCase()} ${path}`);
|
|
114735
115033
|
return new RemoteSkillsAuthClient(origin).request(path, options);
|
|
114736
115034
|
}
|
|
114737
|
-
function
|
|
115035
|
+
function isRecord10(value) {
|
|
114738
115036
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
114739
115037
|
}
|
|
114740
115038
|
function commandErrorPayload(err, fallback) {
|
|
@@ -114748,11 +115046,11 @@ function commandErrorPayload(err, fallback) {
|
|
|
114748
115046
|
...err.apiUrl ? { apiUrl: err.apiUrl } : {}
|
|
114749
115047
|
};
|
|
114750
115048
|
}
|
|
114751
|
-
const code2 =
|
|
115049
|
+
const code2 = isRecord10(err) && typeof err.code === "string" ? err.code : undefined;
|
|
114752
115050
|
return {
|
|
114753
115051
|
error: err?.message || fallback,
|
|
114754
115052
|
...code2 ? { code: code2 } : {},
|
|
114755
|
-
...
|
|
115053
|
+
...isRecord10(err) && Array.isArray(err.next) ? { next: err.next } : {}
|
|
114756
115054
|
};
|
|
114757
115055
|
}
|
|
114758
115056
|
function writeCommandError(err, fallback, json3) {
|
|
@@ -114777,7 +115075,7 @@ function stringField2(value) {
|
|
|
114777
115075
|
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
114778
115076
|
}
|
|
114779
115077
|
function recordField(value) {
|
|
114780
|
-
return
|
|
115078
|
+
return isRecord10(value) ? value : undefined;
|
|
114781
115079
|
}
|
|
114782
115080
|
function identityApiKey(live) {
|
|
114783
115081
|
const root2 = recordField(live);
|
|
@@ -115250,7 +115548,7 @@ async function runWhoami(options) {
|
|
|
115250
115548
|
} catch {}
|
|
115251
115549
|
payload.permissions = { publish: access?.permissions?.publish ?? null, profilesWrite: access?.permissions?.profilesWrite ?? null };
|
|
115252
115550
|
const apiKey = identityApiKey(res);
|
|
115253
|
-
if (access?.scopes && (apiKey === undefined ||
|
|
115551
|
+
if (access?.scopes && (apiKey === undefined || isRecord10(apiKey) && !Object.hasOwn(apiKey, "scopes"))) {
|
|
115254
115552
|
payload.scopes = access.scopes;
|
|
115255
115553
|
}
|
|
115256
115554
|
if (options.json) {
|