@hasna/skills 0.10.23 → 0.10.25
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 +23 -2
- package/bin/index.js +375 -53
- package/bin/mcp.js +426 -312
- package/bin/migrate.js +1 -1
- package/bin/server.js +1 -1
- package/bin/worker.js +1 -1
- package/dist/index.js +367 -50
- package/dist/lib/agent-discovery-directories.d.ts +2 -2
- package/dist/lib/agent-discovery.d.ts +7 -0
- package/dist/lib/agent-integration.d.ts +1 -0
- package/dist/lib/codex-native-skill-catalog.d.ts +9 -1
- package/dist/lib/codex-plugin-skill-controls.d.ts +28 -1
- package/dist/sdk/index.js +367 -50
- 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.25",
|
|
36872
36872
|
description: "Skills library for AI coding agents",
|
|
36873
36873
|
type: "module",
|
|
36874
36874
|
bin: {
|
|
@@ -39944,6 +39944,18 @@ function assertAgentPolicyCollections(policy) {
|
|
|
39944
39944
|
if (control.appSha256 !== undefined)
|
|
39945
39945
|
requireBound(typeof control.appSha256 === "string" && /^[a-f0-9]{64}$/.test(control.appSha256));
|
|
39946
39946
|
}
|
|
39947
|
+
if (bridge.codexInactivePlugins !== undefined) {
|
|
39948
|
+
const controls = array(bridge.codexInactivePlugins, 4096), ids = new Set;
|
|
39949
|
+
requireBound(controls.length === 0 || object(bridge.codexPluginSkillReview) && bridge.codexPluginSkillReview.version === "codex-cli 0.160.0" && typeof bridge.codexPluginSkillReview.catalogSha256 === "string" && /^[a-f0-9]{64}$/.test(bridge.codexPluginSkillReview.catalogSha256));
|
|
39950
|
+
for (const control of controls) {
|
|
39951
|
+
requireBound(object(control) && Object.keys(control).every((key) => ["pluginId", "namespace", "pluginParent", "sourceType", "sourceSha256"].includes(key)));
|
|
39952
|
+
text(control.pluginId, 1024);
|
|
39953
|
+
text(control.namespace, 64);
|
|
39954
|
+
text(control.pluginParent);
|
|
39955
|
+
requireBound(!ids.has(control.pluginId) && isAbsolute2(control.pluginParent) && resolve3(control.pluginParent) === control.pluginParent && ["local", "git", "npm"].includes(control.sourceType) && typeof control.sourceSha256 === "string" && /^[a-f0-9]{64}$/.test(control.sourceSha256));
|
|
39956
|
+
ids.add(control.pluginId);
|
|
39957
|
+
}
|
|
39958
|
+
}
|
|
39947
39959
|
if (bridge.disabledBuiltins !== undefined)
|
|
39948
39960
|
for (const builtin of array(bridge.disabledBuiltins, AGENT_POLICY_LIMITS.builtinNames)) {
|
|
39949
39961
|
requireBound(object(builtin));
|
|
@@ -39956,6 +39968,25 @@ function assertAgentPolicyCollections(policy) {
|
|
|
39956
39968
|
text(agent, 128);
|
|
39957
39969
|
requireBound(object(value));
|
|
39958
39970
|
text(value.agent, 128);
|
|
39971
|
+
if (value.codexInstallationInputs !== undefined) {
|
|
39972
|
+
const proof = record(value.codexInstallationInputs, 4), inputs = array(proof.plugins, 4096), ids = new Set;
|
|
39973
|
+
requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && proof.version === "codex-cli 0.160.0" && typeof proof.catalogSha256 === "string" && /^[a-f0-9]{64}$/.test(proof.catalogSha256) && inputs.length > 0 && object(bridge.codexPluginSkillReview) && bridge.codexPluginSkillReview.version === proof.version && bridge.codexPluginSkillReview.catalogSha256 === proof.catalogSha256);
|
|
39974
|
+
for (const input of inputs) {
|
|
39975
|
+
requireBound(object(input) && Object.keys(input).every((key) => ["pluginId", "namespace", "pluginParent", "sourceRoot", "sourceSha256"].includes(key)));
|
|
39976
|
+
text(input.pluginId, 1024);
|
|
39977
|
+
text(input.namespace, 64);
|
|
39978
|
+
text(input.pluginParent);
|
|
39979
|
+
text(input.sourceRoot);
|
|
39980
|
+
requireBound(!ids.has(input.pluginId) && [input.pluginParent, input.sourceRoot].every((path) => isAbsolute2(path) && resolve3(path) === path) && typeof input.sourceSha256 === "string" && /^[a-f0-9]{64}$/.test(input.sourceSha256));
|
|
39981
|
+
ids.add(input.pluginId);
|
|
39982
|
+
}
|
|
39983
|
+
if (proof.directories !== undefined)
|
|
39984
|
+
for (const directory of array(proof.directories, AGENT_POLICY_LIMITS.discoveryDirectories)) {
|
|
39985
|
+
requireBound(object(directory));
|
|
39986
|
+
text(directory.path);
|
|
39987
|
+
requireBound(directory.sha256 === null || typeof directory.sha256 === "string" && /^[a-f0-9]{64}$/.test(directory.sha256));
|
|
39988
|
+
}
|
|
39989
|
+
}
|
|
39959
39990
|
for (const root of array(value.roots, AGENT_POLICY_LIMITS.discoveryRoots))
|
|
39960
39991
|
text(root);
|
|
39961
39992
|
for (const source of array(value.sources, AGENT_POLICY_LIMITS.discoverySources)) {
|
|
@@ -47235,7 +47266,7 @@ function safe(path) {
|
|
|
47235
47266
|
function same(before2, after2) {
|
|
47236
47267
|
return Boolean(after2 && after2.isDirectory() && before2.dev === after2.dev && before2.ino === after2.ino && before2.mtimeMs === after2.mtimeMs && before2.ctimeMs === after2.ctimeMs);
|
|
47237
47268
|
}
|
|
47238
|
-
function capture(path, budget) {
|
|
47269
|
+
function capture(path, budget, excludedRoots) {
|
|
47239
47270
|
safe(path);
|
|
47240
47271
|
const root = lstatSync4(path, { throwIfNoEntry: false });
|
|
47241
47272
|
if (!root)
|
|
@@ -47264,7 +47295,7 @@ function capture(path, budget) {
|
|
|
47264
47295
|
budget.bytes += Buffer.byteLength(row);
|
|
47265
47296
|
need(budget.bytes <= AGENT_POLICY_LIMITS.discoveryDirectoryBytes, "Native discovery directory metadata limit exceeded");
|
|
47266
47297
|
hash.update(row);
|
|
47267
|
-
if (stat.isDirectory())
|
|
47298
|
+
if (stat.isDirectory() && !excludedRoots.includes(child))
|
|
47268
47299
|
walk(child, childRelative, stat, depth + 1);
|
|
47269
47300
|
}
|
|
47270
47301
|
need(same(before2, lstatSync4(current, { throwIfNoEntry: false })), "Native discovery directory changed while reading");
|
|
@@ -47273,16 +47304,18 @@ function capture(path, budget) {
|
|
|
47273
47304
|
safe(path);
|
|
47274
47305
|
return { path, sha256: hash.digest("hex") };
|
|
47275
47306
|
}
|
|
47276
|
-
function captureDiscoveryDirectories(paths) {
|
|
47307
|
+
function captureDiscoveryDirectories(paths, excludedRoots = []) {
|
|
47277
47308
|
need(Array.isArray(paths) && paths.length <= AGENT_POLICY_LIMITS.discoveryDirectories && new Set(paths).size === paths.length, "Invalid native discovery directory collection");
|
|
47278
47309
|
const budget = { entries: 0, bytes: 0 };
|
|
47279
|
-
|
|
47310
|
+
for (const root of excludedRoots)
|
|
47311
|
+
safe(root);
|
|
47312
|
+
return paths.map((path) => capture(path, budget, excludedRoots));
|
|
47280
47313
|
}
|
|
47281
|
-
function verifyDiscoveryDirectories(directories) {
|
|
47314
|
+
function verifyDiscoveryDirectories(directories, excludedRoots = []) {
|
|
47282
47315
|
need(Array.isArray(directories) && directories.length <= AGENT_POLICY_LIMITS.discoveryDirectories, "Invalid native discovery directory collection");
|
|
47283
47316
|
for (const directory of directories)
|
|
47284
47317
|
need(directory && typeof directory === "object" && (directory.sha256 === null || typeof directory.sha256 === "string" && /^[a-f0-9]{64}$/.test(directory.sha256)), "Invalid native discovery directory digest");
|
|
47285
|
-
const current = captureDiscoveryDirectories(directories.map((directory) => directory.path));
|
|
47318
|
+
const current = captureDiscoveryDirectories(directories.map((directory) => directory.path), excludedRoots);
|
|
47286
47319
|
for (let i = 0;i < directories.length; i++)
|
|
47287
47320
|
need(current[i].sha256 === directories[i].sha256, `Native discovery directory membership changed; run skills hook install with a fresh discovery review: ${directories[i].path}`);
|
|
47288
47321
|
}
|
|
@@ -51059,9 +51092,22 @@ var init_codex_hook_rpc = __esm(() => {
|
|
|
51059
51092
|
// src/lib/codex-native-skill-catalog.ts
|
|
51060
51093
|
import { realpathSync as realpathSync4 } from "fs";
|
|
51061
51094
|
import { isAbsolute as isAbsolute10, normalize as normalize2 } from "path";
|
|
51095
|
+
function codexPluginSourceIsConfigControlled(plugin) {
|
|
51096
|
+
const remoteRealms = ["openai-curated-remote", "created-by-me-remote", "workspace-directory", "workspace-shared-with-me", "workspace-shared-with-me-private", "workspace-shared-with-me-unlisted"];
|
|
51097
|
+
return Boolean(plugin.sourceType && ["local", "git", "npm"].includes(plugin.sourceType) && plugin.sourceSha256 && /^[a-f0-9]{64}$/.test(plugin.sourceSha256) && !plugin.remotePluginId && !remoteRealms.includes(plugin.id.slice(plugin.id.lastIndexOf("@") + 1)));
|
|
51098
|
+
}
|
|
51062
51099
|
function refuse() {
|
|
51063
51100
|
throw new Error("CODEX_NATIVE_SKILL_CATALOG_INVALID");
|
|
51064
51101
|
}
|
|
51102
|
+
function projectPluginSource(source) {
|
|
51103
|
+
if (!object4(source))
|
|
51104
|
+
return {};
|
|
51105
|
+
if (source.type === "remote")
|
|
51106
|
+
return { sourceType: "remote" };
|
|
51107
|
+
const optionalText = (value) => value === undefined || value === null || scalar(value, MAX_PATH_BYTES);
|
|
51108
|
+
const valid = source.type === "local" ? Object.keys(source).every((key) => ["type", "path"].includes(key)) && absolutePath2(source.path) : source.type === "git" ? Object.keys(source).every((key) => ["type", "url", "path", "refName", "sha"].includes(key)) && scalar(source.url, MAX_PATH_BYTES) && [source.path, source.refName, source.sha].every(optionalText) : source.type === "npm" ? Object.keys(source).every((key) => ["type", "package", "version", "registry"].includes(key)) && scalar(source.package, MAX_NAME_BYTES) && [source.version, source.registry].every(optionalText) : false;
|
|
51109
|
+
return valid ? { sourceType: source.type, sourceSha256: hashNativeJsonControls(JSON.stringify(source)), ...source.type === "local" ? { sourcePath: source.path } : {} } : {};
|
|
51110
|
+
}
|
|
51065
51111
|
function projectCodexNativeSkillCatalog(response, cwd2) {
|
|
51066
51112
|
if (!absolutePath2(cwd2) || !object4(response) || !Array.isArray(response.data) || response.data.length !== 1)
|
|
51067
51113
|
refuse();
|
|
@@ -51091,7 +51137,10 @@ function projectCodexInstalledPlugins(response) {
|
|
|
51091
51137
|
plugins.push({
|
|
51092
51138
|
...value,
|
|
51093
51139
|
marketplace: marketplace.name,
|
|
51094
|
-
sourceType:
|
|
51140
|
+
sourceType: undefined,
|
|
51141
|
+
sourceSha256: undefined,
|
|
51142
|
+
sourcePath: undefined,
|
|
51143
|
+
...projectPluginSource(value.source)
|
|
51095
51144
|
});
|
|
51096
51145
|
}
|
|
51097
51146
|
}
|
|
@@ -51102,7 +51151,7 @@ function projectCodexInstalledPluginEntries(value) {
|
|
|
51102
51151
|
refuse();
|
|
51103
51152
|
const ids = new Set;
|
|
51104
51153
|
return value.map((item) => {
|
|
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 !== "
|
|
51154
|
+
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 && !["remote", "local", "git", "npm"].includes(item.sourceType) || (["local", "git", "npm"].includes(item.sourceType) ? typeof item.sourceSha256 !== "string" || !/^[a-f0-9]{64}$/.test(item.sourceSha256) : item.sourceSha256 !== undefined) || (item.sourceType === "local" ? !absolutePath2(item.sourcePath) || normalize2(item.sourcePath) !== item.sourcePath || item.sourceSha256 !== hashNativeJsonControls(JSON.stringify({ type: "local", path: item.sourcePath })) : item.sourcePath !== undefined))
|
|
51106
51155
|
refuse();
|
|
51107
51156
|
const at2 = item.id.lastIndexOf("@");
|
|
51108
51157
|
if (at2 < 1 || item.id.slice(0, at2) !== item.name || at2 === item.id.length - 1 || ids.has(item.id))
|
|
@@ -51114,7 +51163,9 @@ function projectCodexInstalledPluginEntries(value) {
|
|
|
51114
51163
|
installed: item.installed,
|
|
51115
51164
|
enabled: item.enabled,
|
|
51116
51165
|
localVersion: item.localVersion ?? null,
|
|
51117
|
-
...item.sourceType ===
|
|
51166
|
+
...item.sourceType === undefined ? {} : { sourceType: item.sourceType },
|
|
51167
|
+
...item.sourceSha256 === undefined ? {} : { sourceSha256: item.sourceSha256 },
|
|
51168
|
+
...item.sourcePath === undefined ? {} : { sourcePath: item.sourcePath },
|
|
51118
51169
|
...item.remotePluginId == null ? {} : { remotePluginId: item.remotePluginId }
|
|
51119
51170
|
};
|
|
51120
51171
|
});
|
|
@@ -51184,6 +51235,7 @@ var MAX_SKILLS = 4096, MAX_NAME_BYTES = 1024, MAX_PATH_BYTES = 16384, MAX_PLUGIN
|
|
|
51184
51235
|
var init_codex_native_skill_catalog = __esm(() => {
|
|
51185
51236
|
init_codex_hook_rpc();
|
|
51186
51237
|
init_codex_native_compatibility();
|
|
51238
|
+
init_claude_settings_witness();
|
|
51187
51239
|
});
|
|
51188
51240
|
|
|
51189
51241
|
// src/lib/codex-plugin-skill-controls.ts
|
|
@@ -51240,27 +51292,62 @@ function mcpControls(path, read2) {
|
|
|
51240
51292
|
const object5 = (v) => Boolean(v && typeof v === "object" && !Array.isArray(v));
|
|
51241
51293
|
const textField = (v, empty = false) => typeof v === "string" && (empty || Boolean(v.trim())) && Buffer.byteLength(v) <= 16384 && !/[\x00-\x1f\x7f]/.test(v);
|
|
51242
51294
|
const envName = (v) => typeof v === "string" && /^[A-Za-z_][A-Za-z0-9_]{0,255}$/.test(v);
|
|
51295
|
+
const optional = (v, valid) => v === undefined || v === null || valid(v);
|
|
51296
|
+
const stringList = (v) => Array.isArray(v) && v.length <= 256 && v.every((item) => textField(item));
|
|
51297
|
+
const approval = (v) => ["auto", "prompt", "writes", "approve"].includes(v);
|
|
51298
|
+
const duration = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0;
|
|
51299
|
+
const positiveInteger = (v) => Number.isSafeInteger(v) && v > 0;
|
|
51300
|
+
const fields = [
|
|
51301
|
+
"command",
|
|
51302
|
+
"args",
|
|
51303
|
+
"cwd",
|
|
51304
|
+
"env",
|
|
51305
|
+
"env_vars",
|
|
51306
|
+
"enabled",
|
|
51307
|
+
"required",
|
|
51308
|
+
"environment_id",
|
|
51309
|
+
"startup_readiness",
|
|
51310
|
+
"supports_parallel_tool_calls",
|
|
51311
|
+
"tool_input_schema_max_bytes",
|
|
51312
|
+
"startup_timeout_sec",
|
|
51313
|
+
"startup_timeout_ms",
|
|
51314
|
+
"tool_timeout_sec",
|
|
51315
|
+
"default_tools_approval_mode",
|
|
51316
|
+
"enabled_tools",
|
|
51317
|
+
"disabled_tools",
|
|
51318
|
+
"omit_tools_from",
|
|
51319
|
+
"tools",
|
|
51320
|
+
"name"
|
|
51321
|
+
];
|
|
51243
51322
|
if (!object5(value) || Object.keys(value).length !== 1 || !object5(value.mcpServers))
|
|
51244
51323
|
refuse2();
|
|
51245
51324
|
const servers = Object.entries(value.mcpServers);
|
|
51246
51325
|
if (!servers.length || servers.length > 256)
|
|
51247
51326
|
refuse2();
|
|
51248
51327
|
for (const [name, server] of servers) {
|
|
51249
|
-
if (!identifier2(name) || !object5(server) || !Object.keys(server).every((key) =>
|
|
51328
|
+
if (!identifier2(name) || !object5(server) || !Object.keys(server).every((key) => fields.includes(key)) || !textField(server.command) || !optional(server.args, (v) => Array.isArray(v) && v.length <= 256 && v.every((arg) => textField(arg, true))) || !optional(server.cwd, textField) || !optional(server.env, (v) => object5(v) && Object.keys(v).length <= 256 && Object.entries(v).every(([key, value2]) => envName(key) && textField(value2, true))) || !["enabled", "required", "supports_parallel_tool_calls"].every((key) => optional(server[key], (v) => typeof v === "boolean")) || !optional(server.environment_id, (v) => v === "local") || !optional(server.startup_readiness, (v) => ["connection", "catalog"].includes(v)) || !optional(server.tool_input_schema_max_bytes, positiveInteger) || !["startup_timeout_sec", "tool_timeout_sec"].every((key) => optional(server[key], duration)) || !optional(server.startup_timeout_ms, (v) => Number.isSafeInteger(v) && v >= 0) || !optional(server.default_tools_approval_mode, approval) || !["enabled_tools", "disabled_tools"].every((key) => optional(server[key], stringList)) || !optional(server.omit_tools_from, (v) => Array.isArray(v) && v.length <= 256 && v.every((item) => ["code_mode", "deferred", "direct"].includes(item))) || !optional(server.name, textField))
|
|
51250
51329
|
refuse2();
|
|
51251
|
-
if (server.env_vars !== undefined) {
|
|
51330
|
+
if (server.env_vars !== undefined && server.env_vars !== null) {
|
|
51252
51331
|
if (!Array.isArray(server.env_vars) || server.env_vars.length > 256)
|
|
51253
51332
|
refuse2();
|
|
51254
51333
|
const names = server.env_vars.map((entry) => {
|
|
51255
51334
|
if (envName(entry))
|
|
51256
51335
|
return entry;
|
|
51257
|
-
if (!object5(entry) || !Object.keys(entry).every((key) => ["name", "source"].includes(key)) || !envName(entry.name) || entry.source
|
|
51336
|
+
if (!object5(entry) || !Object.keys(entry).every((key) => ["name", "source"].includes(key)) || !envName(entry.name) || !optional(entry.source, (v) => v === "local"))
|
|
51258
51337
|
refuse2();
|
|
51259
51338
|
return entry.name;
|
|
51260
51339
|
});
|
|
51261
51340
|
if (new Set(names).size !== names.length)
|
|
51262
51341
|
refuse2();
|
|
51263
51342
|
}
|
|
51343
|
+
if (server.tools !== undefined && server.tools !== null) {
|
|
51344
|
+
if (!object5(server.tools) || Object.keys(server.tools).length > 256)
|
|
51345
|
+
refuse2();
|
|
51346
|
+
for (const [tool, config] of Object.entries(server.tools)) {
|
|
51347
|
+
if (!textField(tool) || !object5(config) || !Object.keys(config).every((key) => ["approval_mode", "output_token_limit"].includes(key)) || !optional(config.approval_mode, approval) || !optional(config.output_token_limit, positiveInteger))
|
|
51348
|
+
refuse2();
|
|
51349
|
+
}
|
|
51350
|
+
}
|
|
51264
51351
|
}
|
|
51265
51352
|
return sha2562;
|
|
51266
51353
|
}
|
|
@@ -51297,7 +51384,7 @@ function rootControls(root, read2) {
|
|
|
51297
51384
|
const appSha256 = present ? appControls(app, read2) : undefined;
|
|
51298
51385
|
return { namespace: manifest.name, manifestSha256, ...appSha256 ? { appSha256 } : {}, ...mcpSha256 ? { mcpSha256 } : {} };
|
|
51299
51386
|
}
|
|
51300
|
-
function
|
|
51387
|
+
function documentIdentity(document3, cache3, read2) {
|
|
51301
51388
|
if (!document3.startsWith(cache3 + sep4) || !document3.endsWith(sep4 + "SKILL.md"))
|
|
51302
51389
|
refuse2();
|
|
51303
51390
|
const text2 = read2(document3);
|
|
@@ -51325,11 +51412,33 @@ function identity4(document3, cache3, read2) {
|
|
|
51325
51412
|
const path = join18(root, ".codex-plugin", "plugin.json");
|
|
51326
51413
|
if (!lstatSync12(path, { throwIfNoEntry: false }))
|
|
51327
51414
|
continue;
|
|
51328
|
-
const
|
|
51329
|
-
|
|
51415
|
+
const manifestFile = lstatSync12(path);
|
|
51416
|
+
if (!lstatSync12(join18(root, ".codex-plugin")).isDirectory() || !manifestFile.isFile() || manifestFile.size > 1024 * 1024)
|
|
51417
|
+
refuse2();
|
|
51418
|
+
let manifest;
|
|
51419
|
+
try {
|
|
51420
|
+
const text3 = read2(path);
|
|
51421
|
+
hashNativeJsonControls(text3);
|
|
51422
|
+
manifest = JSON.parse(text3);
|
|
51423
|
+
} catch {
|
|
51424
|
+
refuse2();
|
|
51425
|
+
}
|
|
51426
|
+
if (!manifest || typeof manifest !== "object" || Array.isArray(manifest) || !identifier2(manifest.name))
|
|
51427
|
+
refuse2();
|
|
51428
|
+
const declaredVersion = manifest.version === undefined ? "" : typeof manifest.version === "string" ? manifest.version.trim() : null;
|
|
51429
|
+
if (declaredVersion === null || (declaredVersion ? declaredVersion !== basename5(root) : basename5(root) !== CODEX_DEFAULT_AGENT_PLUGIN_VERSION))
|
|
51430
|
+
refuse2();
|
|
51431
|
+
return { name: `${manifest.name}:${front.name}`, namespace: manifest.name, pluginParent: dirname10(root), root };
|
|
51330
51432
|
}
|
|
51331
51433
|
refuse2();
|
|
51332
51434
|
}
|
|
51435
|
+
function identity4(document3, cache3, read2) {
|
|
51436
|
+
const parsed = documentIdentity(document3, cache3, read2);
|
|
51437
|
+
const controls = rootControls(parsed.root, read2);
|
|
51438
|
+
if (controls.namespace !== parsed.namespace)
|
|
51439
|
+
refuse2();
|
|
51440
|
+
return { name: parsed.name, pluginParent: parsed.pluginParent, ...controls };
|
|
51441
|
+
}
|
|
51333
51442
|
function reviewedCodexPluginCapabilitiesUnchanged(cache3, controls, read2) {
|
|
51334
51443
|
if (!Array.isArray(controls) || controls.length > 4096)
|
|
51335
51444
|
return false;
|
|
@@ -51367,11 +51476,13 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache3, controls, read2) {
|
|
|
51367
51476
|
return false;
|
|
51368
51477
|
}
|
|
51369
51478
|
}
|
|
51370
|
-
function
|
|
51479
|
+
function reviewCodexPluginControls(catalog, documents, cache3, cwd2, read2, rules, pluginSettings) {
|
|
51371
51480
|
if (!supportsCodexNativeCapability(catalog?.version, "qualified-skill-catalog") || catalog.cwd !== cwd2)
|
|
51372
51481
|
refuse2();
|
|
51373
51482
|
const skills = projectCodexNativeSkillCatalog({ data: [{ cwd: cwd2, errors: [], skills: catalog.skills }] }, cwd2);
|
|
51374
|
-
const allowed = new Set(documents), result2 = [];
|
|
51483
|
+
const allowed = new Set(documents), result2 = [], inertDocuments = new Set;
|
|
51484
|
+
const inactivePlugins = new Map;
|
|
51485
|
+
const sourceInputs = new Map;
|
|
51375
51486
|
let installedPlugins;
|
|
51376
51487
|
try {
|
|
51377
51488
|
installedPlugins = projectCodexInstalledPluginEntries(catalog.plugins ?? []);
|
|
@@ -51382,25 +51493,48 @@ function reviewCodexPluginSkillControls(catalog, documents, cache3, cwd2, read2,
|
|
|
51382
51493
|
for (const document3 of candidates) {
|
|
51383
51494
|
if (!document3.startsWith(cache3 + sep4))
|
|
51384
51495
|
continue;
|
|
51385
|
-
const
|
|
51386
|
-
if (
|
|
51496
|
+
const located = documentIdentity(document3, cache3, read2);
|
|
51497
|
+
if (located.name === "skills-cli" || located.name.endsWith(":skills-cli"))
|
|
51387
51498
|
refuse2();
|
|
51388
|
-
const cacheParts = relative4(cache3,
|
|
51499
|
+
const cacheParts = relative4(cache3, located.pluginParent).split(sep4);
|
|
51389
51500
|
if (cacheParts.length !== 2 || cacheParts.some((part) => !identifier2(part)))
|
|
51390
51501
|
refuse2();
|
|
51391
51502
|
const [marketplace, pluginName] = cacheParts;
|
|
51392
|
-
if (pluginName !==
|
|
51503
|
+
if (pluginName !== located.namespace)
|
|
51393
51504
|
refuse2();
|
|
51394
51505
|
const expectedPluginId = `${pluginName}@${marketplace}`;
|
|
51395
51506
|
const listed = skills.filter((skill) => skill.path === document3);
|
|
51396
51507
|
if (listed.length > 1)
|
|
51397
51508
|
refuse2();
|
|
51509
|
+
const installed = installedPlugins.filter((plugin) => plugin.id === expectedPluginId && plugin.name === pluginName);
|
|
51510
|
+
if (catalog.version === "codex-cli 0.160.0" && installed.length === 1 && installed[0].installed && installed[0].localVersion === basename5(located.root) && installed[0].sourceType === "local" && codexPluginSourceIsConfigControlled(installed[0])) {
|
|
51511
|
+
const plugin = installed[0], input = { pluginId: expectedPluginId, namespace: located.namespace, pluginParent: located.pluginParent, sourceRoot: plugin.sourcePath, sourceSha256: plugin.sourceSha256 };
|
|
51512
|
+
if (input.sourceRoot !== located.root && !input.sourceRoot.startsWith(cache3 + sep4) && (lstatSync12(input.sourceRoot, { throwIfNoEntry: false }) || documents.some((path) => path.startsWith(input.sourceRoot + sep4)))) {
|
|
51513
|
+
if (skills.some((skill) => skill.path === input.sourceRoot || skill.path.startsWith(input.sourceRoot + sep4)) || !sourceInputUnchanged(input, cache3, read2))
|
|
51514
|
+
refuse2();
|
|
51515
|
+
sourceInputs.set(expectedPluginId, input);
|
|
51516
|
+
}
|
|
51517
|
+
}
|
|
51518
|
+
const settings = pluginSettings && typeof pluginSettings === "object" && !Array.isArray(pluginSettings) ? pluginSettings : undefined;
|
|
51519
|
+
if (catalog.version === "codex-cli 0.160.0" && !listed.length && !skills.some((skill) => skill.pluginId === expectedPluginId) && installed.length === 1 && installed[0].installed && !installed[0].enabled && codexPluginSourceIsConfigControlled(installed[0]) && settings && Object.hasOwn(settings, expectedPluginId) && settings[expectedPluginId]?.enabled === false) {
|
|
51520
|
+
if (!Array.isArray(rules))
|
|
51521
|
+
refuse2();
|
|
51522
|
+
const exactPathDeny = rules.some((rule) => rule?.path === document3 && rule?.enabled === false);
|
|
51523
|
+
if (!lstatSync12(document3).isFile() || realpathSync5(document3) !== document3 || realpathSync5(located.root) !== located.root || realpathSync5(located.pluginParent) !== located.pluginParent || realpathSync5(join18(located.root, ".codex-plugin/plugin.json")) !== join18(located.root, ".codex-plugin/plugin.json") || !exactPathDeny || rules.some((rule) => typeof rule?.name === "string" && rule.name.trim() === located.name && rule?.enabled !== false) || !isCodexNativeSkillDisabled({ name: located.name, path: document3, pluginId: expectedPluginId, enabled: true }, rules))
|
|
51524
|
+
refuse2();
|
|
51525
|
+
inertDocuments.add(document3);
|
|
51526
|
+
const plugin = installed[0];
|
|
51527
|
+
inactivePlugins.set(expectedPluginId, { pluginId: expectedPluginId, namespace: located.namespace, pluginParent: located.pluginParent, sourceType: plugin.sourceType, sourceSha256: plugin.sourceSha256 });
|
|
51528
|
+
continue;
|
|
51529
|
+
}
|
|
51530
|
+
const parsed = { name: located.name, pluginParent: located.pluginParent, ...rootControls(located.root, read2) };
|
|
51531
|
+
if (parsed.namespace !== located.namespace)
|
|
51532
|
+
refuse2();
|
|
51398
51533
|
let remotePluginId;
|
|
51399
51534
|
if (listed.length === 1) {
|
|
51400
51535
|
if (listed[0].name !== parsed.name || listed[0].pluginId !== expectedPluginId)
|
|
51401
51536
|
refuse2();
|
|
51402
51537
|
} else {
|
|
51403
|
-
const installed = installedPlugins.filter((plugin2) => plugin2.id === expectedPluginId && plugin2.name === pluginName);
|
|
51404
51538
|
if (installed.length !== 1 || !installed[0].installed || !installed[0].enabled)
|
|
51405
51539
|
refuse2();
|
|
51406
51540
|
const plugin = installed[0];
|
|
@@ -51418,9 +51552,48 @@ function reviewCodexPluginSkillControls(catalog, documents, cache3, cwd2, read2,
|
|
|
51418
51552
|
}
|
|
51419
51553
|
result2.push({ ...parsed, pluginId: expectedPluginId, ...remotePluginId ? { remotePluginId } : {} });
|
|
51420
51554
|
}
|
|
51421
|
-
if (!result2.length && documents.some((document3) => document3.startsWith(cache3 + sep4)) || new Set(result2.map((item) => item.name)).size !== result2.length)
|
|
51555
|
+
if (!result2.length && documents.some((document3) => document3.startsWith(cache3 + sep4) && !inertDocuments.has(document3)) || new Set(result2.map((item) => item.name)).size !== result2.length)
|
|
51422
51556
|
refuse2();
|
|
51423
|
-
return result2;
|
|
51557
|
+
return { skills: result2, inactivePlugins: [...inactivePlugins.values()], sourceInputs: [...sourceInputs.values()] };
|
|
51558
|
+
}
|
|
51559
|
+
function sourceInputUnchanged(input, cache3, read2) {
|
|
51560
|
+
try {
|
|
51561
|
+
const parts = relative4(cache3, input.pluginParent).split(sep4);
|
|
51562
|
+
if (parts.length !== 2 || parts.some((part) => !identifier2(part)) || parts[1] !== input.namespace || input.pluginId !== `${parts[1]}@${parts[0]}` || !codexPluginSourceIsConfigControlled({ id: input.pluginId, sourceType: "local", sourceSha256: input.sourceSha256 }) || input.sourceSha256 !== hashNativeJsonControls(JSON.stringify({ type: "local", path: input.sourceRoot })) || resolve10(input.sourceRoot) !== input.sourceRoot || !lstatSync12(input.sourceRoot).isDirectory() || realpathSync5(input.sourceRoot) !== input.sourceRoot || input.sourceRoot === cache3 || input.sourceRoot.startsWith(cache3 + sep4) || cache3.startsWith(input.sourceRoot + sep4))
|
|
51563
|
+
return false;
|
|
51564
|
+
const path = join18(input.sourceRoot, ".codex-plugin/plugin.json"), stat = lstatSync12(path);
|
|
51565
|
+
if (!stat.isFile() || stat.size > 1024 * 1024 || realpathSync5(path) !== path)
|
|
51566
|
+
return false;
|
|
51567
|
+
const text2 = read2(path);
|
|
51568
|
+
hashNativeJsonControls(text2);
|
|
51569
|
+
const manifest = JSON.parse(text2);
|
|
51570
|
+
return Boolean(manifest && typeof manifest === "object" && !Array.isArray(manifest) && manifest.name === input.namespace);
|
|
51571
|
+
} catch {
|
|
51572
|
+
return false;
|
|
51573
|
+
}
|
|
51574
|
+
}
|
|
51575
|
+
function reviewedCodexPluginSourceRoots(cache3, inputs, read2) {
|
|
51576
|
+
if (!Array.isArray(inputs) || inputs.length > 4096 || new Set(inputs.map((input) => input.pluginId)).size !== inputs.length || new Set(inputs.map((input) => input.sourceRoot)).size !== inputs.length || inputs.some((input) => !sourceInputUnchanged(input, cache3, read2)))
|
|
51577
|
+
refuse2();
|
|
51578
|
+
const roots = inputs.map((input) => input.sourceRoot);
|
|
51579
|
+
if (roots.some((root) => roots.some((other) => root !== other && root.startsWith(other + sep4))))
|
|
51580
|
+
refuse2();
|
|
51581
|
+
return roots;
|
|
51582
|
+
}
|
|
51583
|
+
function isReviewedCodexPluginInactive(document3, cache3, controls, pluginSettings, rules, read2) {
|
|
51584
|
+
if (!Array.isArray(controls) || controls.length > 4096 || !pluginSettings || typeof pluginSettings !== "object" || Array.isArray(pluginSettings) || !Array.isArray(rules))
|
|
51585
|
+
return false;
|
|
51586
|
+
try {
|
|
51587
|
+
const parsed = documentIdentity(document3, cache3, read2), matches2 = controls.filter((control2) => control2.pluginParent === parsed.pluginParent && control2.namespace === parsed.namespace);
|
|
51588
|
+
if (matches2.length !== 1 || !lstatSync12(document3).isFile() || realpathSync5(document3) !== document3 || realpathSync5(parsed.root) !== parsed.root || realpathSync5(parsed.pluginParent) !== parsed.pluginParent || realpathSync5(join18(parsed.root, ".codex-plugin/plugin.json")) !== join18(parsed.root, ".codex-plugin/plugin.json"))
|
|
51589
|
+
return false;
|
|
51590
|
+
const control = matches2[0], parts = relative4(cache3, parsed.pluginParent).split(sep4);
|
|
51591
|
+
if (parts.length !== 2 || parts.some((part) => !identifier2(part)) || parts[1] !== parsed.namespace || control.pluginId !== `${parts[1]}@${parts[0]}` || !codexPluginSourceIsConfigControlled({ ...control, id: control.pluginId }) || !Object.hasOwn(pluginSettings, control.pluginId) || pluginSettings[control.pluginId]?.enabled !== false)
|
|
51592
|
+
return false;
|
|
51593
|
+
return !rules.some((rule) => (rule?.path === document3 || typeof rule?.name === "string" && rule.name.trim() === parsed.name) && rule?.enabled !== false);
|
|
51594
|
+
} catch {
|
|
51595
|
+
return false;
|
|
51596
|
+
}
|
|
51424
51597
|
}
|
|
51425
51598
|
function isReviewedCodexPluginSkillDisabled(document3, cache3, controls, rules, read2) {
|
|
51426
51599
|
if (!document3.startsWith(cache3 + sep4) || !Array.isArray(controls) || controls.length > 4096)
|
|
@@ -52121,10 +52294,75 @@ import { isDeepStrictEqual as isDeepStrictEqual4 } from "util";
|
|
|
52121
52294
|
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";
|
|
52122
52295
|
import { dirname as dirname11, join as join21, resolve as resolve11, relative as relative5, isAbsolute as isAbsolute11, sep as sep5 } from "path";
|
|
52123
52296
|
import { homedir as homedir3 } from "os";
|
|
52297
|
+
function hasNoDarwinAcl(fd) {
|
|
52298
|
+
try {
|
|
52299
|
+
const { dlopen, read: read2 } = __require("bun:ffi");
|
|
52300
|
+
const library = dlopen("/usr/lib/libSystem.B.dylib", {
|
|
52301
|
+
acl_get_fd: { args: ["i32"], returns: "ptr" },
|
|
52302
|
+
acl_free: { args: ["ptr"], returns: "i32" },
|
|
52303
|
+
__error: { args: [], returns: "ptr" }
|
|
52304
|
+
});
|
|
52305
|
+
try {
|
|
52306
|
+
const errno = library.symbols.__error();
|
|
52307
|
+
if (!errno)
|
|
52308
|
+
return false;
|
|
52309
|
+
const acl = library.symbols.acl_get_fd(fd);
|
|
52310
|
+
if (acl) {
|
|
52311
|
+
library.symbols.acl_free(acl);
|
|
52312
|
+
return false;
|
|
52313
|
+
}
|
|
52314
|
+
return (acl === null || acl === 0) && read2.i32(errno) === 2;
|
|
52315
|
+
} finally {
|
|
52316
|
+
library.close();
|
|
52317
|
+
}
|
|
52318
|
+
} catch {
|
|
52319
|
+
return false;
|
|
52320
|
+
}
|
|
52321
|
+
}
|
|
52322
|
+
function isSystemRootAlias(path) {
|
|
52323
|
+
if (process.platform !== "darwin" || !["/var", "/tmp", "/etc"].includes(path))
|
|
52324
|
+
return false;
|
|
52325
|
+
const target = `/private${path}`, link2 = `private${path}`;
|
|
52326
|
+
const identity5 = (stat) => `${stat.dev}:${stat.ino}:${stat.ctimeNs}:${stat.uid}:${stat.mode}`;
|
|
52327
|
+
try {
|
|
52328
|
+
const before2 = lstatSync15(path, { bigint: true });
|
|
52329
|
+
if (!before2.isSymbolicLink() || before2.uid !== 0n || readlinkSync4(path) !== link2)
|
|
52330
|
+
return false;
|
|
52331
|
+
const directories = ["/", "/private", target].map((directory) => {
|
|
52332
|
+
const stat = lstatSync15(directory, { bigint: true });
|
|
52333
|
+
if (!stat.isDirectory() || stat.uid !== 0n)
|
|
52334
|
+
throw new Error("Untrusted system alias directory");
|
|
52335
|
+
if (directory !== "/private/tmp") {
|
|
52336
|
+
if ((stat.mode & 0o022n) !== 0n)
|
|
52337
|
+
throw new Error("Writable system alias directory");
|
|
52338
|
+
} else if ((stat.mode & 0o1000n) === 0n)
|
|
52339
|
+
throw new Error("Unprotected system temporary directory");
|
|
52340
|
+
const fd = openSync8(directory, constants8.O_RDONLY | constants8.O_DIRECTORY | constants8.O_NOFOLLOW);
|
|
52341
|
+
try {
|
|
52342
|
+
if (identity5(fstatSync8(fd, { bigint: true })) !== identity5(stat) || !hasNoDarwinAcl(fd) || identity5(fstatSync8(fd, { bigint: true })) !== identity5(stat))
|
|
52343
|
+
throw new Error("Unverified system alias directory ACL");
|
|
52344
|
+
} finally {
|
|
52345
|
+
closeSync8(fd);
|
|
52346
|
+
}
|
|
52347
|
+
return { directory, identity: identity5(stat) };
|
|
52348
|
+
});
|
|
52349
|
+
return realpathSync6(path) === target && readlinkSync4(path) === link2 && identity5(lstatSync15(path, { bigint: true })) === identity5(before2) && directories.every((item) => identity5(lstatSync15(item.directory, { bigint: true })) === item.identity);
|
|
52350
|
+
} catch {
|
|
52351
|
+
return false;
|
|
52352
|
+
}
|
|
52353
|
+
}
|
|
52354
|
+
function canonicalSystemPath(path) {
|
|
52355
|
+
const absolute = resolve11(path), root = `/${absolute.split(sep5)[1]}`;
|
|
52356
|
+
if (process.platform !== "darwin" || !["/var", "/tmp", "/etc"].includes(root) || !lstatSync15(root, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
52357
|
+
return absolute;
|
|
52358
|
+
if (!isSystemRootAlias(root))
|
|
52359
|
+
throw new Error(`Refusing symlink path: ${root}`);
|
|
52360
|
+
return `/private${absolute}`;
|
|
52361
|
+
}
|
|
52124
52362
|
function assertSafePath(path) {
|
|
52125
52363
|
let cursor = resolve11(path);
|
|
52126
52364
|
while (true) {
|
|
52127
|
-
if (lstatSync15(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
52365
|
+
if (lstatSync15(cursor, { throwIfNoEntry: false })?.isSymbolicLink() && !isSystemRootAlias(cursor))
|
|
52128
52366
|
throw new Error(`Refusing symlink path: ${cursor}`);
|
|
52129
52367
|
const parent = dirname11(cursor);
|
|
52130
52368
|
if (parent === cursor)
|
|
@@ -52160,7 +52398,7 @@ function rootAliases(home, allowed = false) {
|
|
|
52160
52398
|
return result2;
|
|
52161
52399
|
}
|
|
52162
52400
|
function canonicalAgentPath(path, aliases) {
|
|
52163
|
-
const absolute =
|
|
52401
|
+
const absolute = canonicalSystemPath(path), binding = aliases.find((item) => absolute === item.alias || absolute.startsWith(item.alias + sep5));
|
|
52164
52402
|
return binding ? join21(binding.target, relative5(binding.alias, absolute)) : absolute;
|
|
52165
52403
|
}
|
|
52166
52404
|
function disabledCodexSkillPaths(config, aliases) {
|
|
@@ -52277,8 +52515,10 @@ function parseNativeMigrationTargetManifest(input) {
|
|
|
52277
52515
|
throw new Error("Invalid native migration target fields");
|
|
52278
52516
|
if (!ROOTS.some(([agent]) => agent === item.agent))
|
|
52279
52517
|
throw new Error(`Unsupported native migration target agent: ${item.agent}`);
|
|
52280
|
-
|
|
52281
|
-
|
|
52518
|
+
if (!isAbsolute11(item.projectRoot) || resolve11(item.projectRoot) !== item.projectRoot)
|
|
52519
|
+
throw new Error(`Native migration target project root must be an existing absolute directory: ${item.projectRoot}`);
|
|
52520
|
+
const projectRoot = canonicalSystemPath(item.projectRoot);
|
|
52521
|
+
if (!existsSync12(projectRoot) || !lstatSync15(projectRoot).isDirectory())
|
|
52282
52522
|
throw new Error(`Native migration target project root must be an existing absolute directory: ${item.projectRoot}`);
|
|
52283
52523
|
assertSafePath(projectRoot);
|
|
52284
52524
|
if (isAbsolute11(item.path) || item.path.includes("\\") || item.path.length === 0 || item.path.includes("\x00"))
|
|
@@ -52288,7 +52528,7 @@ function parseNativeMigrationTargetManifest(input) {
|
|
|
52288
52528
|
throw new Error(`Native migration target path escapes or is not normalized: ${item.path}`);
|
|
52289
52529
|
if (!/^[0-9a-f]{64}$/.test(item.treeSha256))
|
|
52290
52530
|
throw new Error(`Invalid native migration tree digest for ${item.path}`);
|
|
52291
|
-
const identity5 = `${item.agent}\x00${projectRoot}\x00${normalized}`;
|
|
52531
|
+
const identity5 = `${item.agent}\x00${canonicalSystemPath(projectRoot)}\x00${normalized}`;
|
|
52292
52532
|
if (identities.has(identity5))
|
|
52293
52533
|
throw new Error(`Duplicate native migration target: ${item.path}`);
|
|
52294
52534
|
identities.add(identity5);
|
|
@@ -52305,17 +52545,19 @@ function selectNativeMigrationTargets(inventory, manifest) {
|
|
|
52305
52545
|
const identities = new Set;
|
|
52306
52546
|
const selected = [];
|
|
52307
52547
|
for (const target of manifest.targets) {
|
|
52308
|
-
|
|
52309
|
-
|
|
52548
|
+
if (!isAbsolute11(target.projectRoot) || resolve11(target.projectRoot) !== target.projectRoot)
|
|
52549
|
+
throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
|
|
52550
|
+
const projectRoot = canonicalSystemPath(target.projectRoot), normalized = relative5(projectRoot, resolve11(projectRoot, target.path));
|
|
52551
|
+
if (!existsSync12(projectRoot) || !lstatSync15(projectRoot).isDirectory())
|
|
52310
52552
|
throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
|
|
52311
52553
|
assertSafePath(projectRoot);
|
|
52312
52554
|
if (isAbsolute11(target.path) || target.path.includes("\\") || target.path.includes("\x00") || !normalized || normalized === ".." || normalized.startsWith(`..${sep5}`) || normalized !== target.path || !/^[0-9a-f]{64}$/.test(target.treeSha256))
|
|
52313
52555
|
throw new Error(`Invalid native migration target: ${target.path}`);
|
|
52314
|
-
const identity5 = `${target.agent}\x00${projectRoot}\x00${normalized}`;
|
|
52556
|
+
const identity5 = `${target.agent}\x00${canonicalSystemPath(projectRoot)}\x00${normalized}`;
|
|
52315
52557
|
if (identities.has(identity5))
|
|
52316
52558
|
throw new Error(`Duplicate native migration target: ${target.path}`);
|
|
52317
52559
|
identities.add(identity5);
|
|
52318
|
-
const expected = resolve11(target.projectRoot, target.path);
|
|
52560
|
+
const expected = canonicalSystemPath(resolve11(target.projectRoot, target.path));
|
|
52319
52561
|
const matches2 = inventory.filter((entry2) => entry2.agent === target.agent && resolve11(entry2.path) === expected);
|
|
52320
52562
|
if (matches2.length !== 1)
|
|
52321
52563
|
throw new Error(`Native migration target was not found exactly once: ${target.agent} ${target.projectRoot}/${target.path}`);
|
|
@@ -52331,7 +52573,7 @@ function selectNativeMigrationTargets(inventory, manifest) {
|
|
|
52331
52573
|
function projectAncestorDirectories(projects) {
|
|
52332
52574
|
const directories = new Set;
|
|
52333
52575
|
for (const project of projects) {
|
|
52334
|
-
for (let path =
|
|
52576
|
+
for (let path = canonicalSystemPath(project), depth = 0;; depth++) {
|
|
52335
52577
|
if (depth >= 100)
|
|
52336
52578
|
throw new Error("NATIVE_SKILL_DRIFT: project ancestor discovery limit exceeded");
|
|
52337
52579
|
directories.add(path);
|
|
@@ -52344,11 +52586,13 @@ function projectAncestorDirectories(projects) {
|
|
|
52344
52586
|
return [...directories];
|
|
52345
52587
|
}
|
|
52346
52588
|
function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
52589
|
+
home = canonicalSystemPath(home);
|
|
52347
52590
|
if (options.reviewedCacheAlias !== undefined && (!options.includeVendor || !isAbsolute11(options.reviewedCacheAlias) || resolve11(options.reviewedCacheAlias) !== options.reviewedCacheAlias))
|
|
52348
52591
|
throw new Error("A reviewed cache alias requires vendor inventory and an exact absolute path");
|
|
52349
52592
|
if (options.disabledVendorPaths?.some((path) => !isAbsolute11(path) || resolve11(path) !== path))
|
|
52350
52593
|
throw new Error("Disabled vendor paths must be exact absolute paths");
|
|
52351
|
-
const
|
|
52594
|
+
const reviewedCacheAlias = options.reviewedCacheAlias === undefined ? undefined : canonicalSystemPath(options.reviewedCacheAlias);
|
|
52595
|
+
const disabledVendorPaths = new Set((options.disabledVendorPaths ?? []).map(canonicalSystemPath));
|
|
52352
52596
|
const aliases = rootAliases(home, options.allowRootAliases);
|
|
52353
52597
|
const selectedAgents = options.agents ? new Set(options.agents) : undefined;
|
|
52354
52598
|
const includesAgent = (agent) => !selectedAgents || selectedAgents.has(agent);
|
|
@@ -52359,6 +52603,9 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
52359
52603
|
for (const [agent, path] of rootDefinitions)
|
|
52360
52604
|
roots.push([agent, canonicalAgentPath(join21(project, path), aliases)]);
|
|
52361
52605
|
}
|
|
52606
|
+
const installationInputs = options.codexInstallationInputRoots ?? [];
|
|
52607
|
+
if (installationInputs.some((input) => resolve11(input) !== input || realpathSync6(input) !== input || roots.some(([agent, path]) => agent === "codex" && (path === input || path.startsWith(input + sep5) || input.startsWith(path + sep5)))))
|
|
52608
|
+
throw new Error("Native installation input overlaps an unconditional skill-loading root");
|
|
52362
52609
|
const entries = [], seen = new Set;
|
|
52363
52610
|
const cacheScans = new Map, maxAliasProofEntries = 1e4;
|
|
52364
52611
|
let discoveryEntries = 0, discoveryPathBytes = 0;
|
|
@@ -52371,8 +52618,11 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
52371
52618
|
}
|
|
52372
52619
|
let reviewedCacheAliasFound = false;
|
|
52373
52620
|
function verifiedSiblingCacheAlias(agent, path, parent) {
|
|
52374
|
-
const link2 = readlinkSync4(path),
|
|
52375
|
-
if (
|
|
52621
|
+
const link2 = readlinkSync4(path), lexicalTarget = resolve11(parent, link2);
|
|
52622
|
+
if (isAbsolute11(link2) ? link2 !== lexicalTarget : dirname11(link2) !== ".")
|
|
52623
|
+
return false;
|
|
52624
|
+
const target = canonicalSystemPath(lexicalTarget);
|
|
52625
|
+
if (dirname11(target) !== parent)
|
|
52376
52626
|
return false;
|
|
52377
52627
|
if (!lstatSync15(target, { throwIfNoEntry: false })?.isDirectory())
|
|
52378
52628
|
return false;
|
|
@@ -52381,20 +52631,22 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
52381
52631
|
return false;
|
|
52382
52632
|
if (scan.hasSkills) {
|
|
52383
52633
|
const targetSkills = entries.filter((entry) => entry.agent === agent && entry.vendor && (entry.path === target || entry.path.startsWith(target + sep5)));
|
|
52384
|
-
if (path ===
|
|
52634
|
+
if (path === reviewedCacheAlias && targetSkills.length > 0)
|
|
52385
52635
|
reviewedCacheAliasFound = true;
|
|
52386
52636
|
if (agent === "codex" && targetSkills.length > 0 && targetSkills.every((entry) => disabledVendorPaths.has(entry.path) || options.disabledVendorSkill?.(entry) === true))
|
|
52387
52637
|
return true;
|
|
52388
|
-
if (path !==
|
|
52638
|
+
if (path !== reviewedCacheAlias)
|
|
52389
52639
|
return false;
|
|
52390
52640
|
}
|
|
52391
52641
|
return true;
|
|
52392
52642
|
}
|
|
52393
|
-
function visit2(agent, path, vendor = false, depth = 0, pluginCache = false, admitted = false) {
|
|
52643
|
+
function visit2(agent, path, vendor = false, depth = 0, pluginCache = false, admitted = false, configuredRoot = false) {
|
|
52394
52644
|
if (!admitted)
|
|
52395
52645
|
admit(path);
|
|
52396
52646
|
const scan = { complete: true, hasSkills: false, entries: 1 };
|
|
52397
52647
|
assertSafePath(path);
|
|
52648
|
+
if (configuredRoot && agent === "codex" && installationInputs.includes(path))
|
|
52649
|
+
return scan;
|
|
52398
52650
|
if (!existsSync12(path))
|
|
52399
52651
|
return scan;
|
|
52400
52652
|
const stat = lstatSync15(path);
|
|
@@ -52450,7 +52702,7 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
52450
52702
|
continue;
|
|
52451
52703
|
}
|
|
52452
52704
|
}
|
|
52453
|
-
const childScan = visit2(agent, child, isVendor, depth + 1, pluginCache, true);
|
|
52705
|
+
const childScan = visit2(agent, child, isVendor, depth + 1, pluginCache, true, configuredRoot);
|
|
52454
52706
|
scan.complete &&= childScan.complete;
|
|
52455
52707
|
scan.hasSkills ||= childScan.hasSkills;
|
|
52456
52708
|
scan.entries += childScan.entries;
|
|
@@ -52459,10 +52711,10 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
52459
52711
|
cacheScans.set(path, scan);
|
|
52460
52712
|
return scan;
|
|
52461
52713
|
}
|
|
52462
|
-
function scanRoot(agent, path, vendor = false, pluginCache = false) {
|
|
52714
|
+
function scanRoot(agent, path, vendor = false, pluginCache = false, configuredRoot = false) {
|
|
52463
52715
|
if (agent === "hermes" || options.guardHermes && `${path}${sep5}`.includes(`${sep5}.agents${sep5}skills${sep5}`))
|
|
52464
52716
|
assertNoHermesLegacyShadow(path);
|
|
52465
|
-
if (!visit2(agent, path, vendor, 0, pluginCache).complete)
|
|
52717
|
+
if (!visit2(agent, path, vendor, 0, pluginCache, false, configuredRoot).complete)
|
|
52466
52718
|
throw new Error(`Native skill discovery limit exceeded; review this root before continuing: ${path}`);
|
|
52467
52719
|
}
|
|
52468
52720
|
for (const [agent, path] of roots)
|
|
@@ -52478,7 +52730,7 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
52478
52730
|
const configured = options.configured ? INTEGRATION_AGENTS.filter(includesAgent).flatMap((agent) => resolveAgentDiscovery({ home, agent, reviewed: options.discoveryInputs, canonical: (path) => canonicalAgentPath(path, aliases) }).roots.map((path) => ({ agent, path }))) : [];
|
|
52479
52731
|
for (const root of [...options.agentRoots ?? [], ...configured])
|
|
52480
52732
|
if (includesAgent(root.agent))
|
|
52481
|
-
scanRoot(root.agent, canonicalAgentPath(root.path, aliases), true);
|
|
52733
|
+
scanRoot(root.agent, canonicalAgentPath(root.path, aliases), true, false, true);
|
|
52482
52734
|
if (options.reviewedCacheAlias !== undefined && !reviewedCacheAliasFound)
|
|
52483
52735
|
throw new Error("Reviewed cache alias was not an inventoried skill-containing sibling alias");
|
|
52484
52736
|
recheckRootAliases(aliases);
|
|
@@ -52618,6 +52870,11 @@ enabled = false
|
|
|
52618
52870
|
Bun.TOML.parse(result2);
|
|
52619
52871
|
return result2;
|
|
52620
52872
|
}
|
|
52873
|
+
function assertCodexInstallationInputs(home, projectDirs, inputs) {
|
|
52874
|
+
const nativeRoots = [home, ...projectAncestorDirectories(projectDirs)].flatMap((directory) => ROOTS.filter(([agent]) => agent === "codex").map(([, path]) => resolve11(directory, path)));
|
|
52875
|
+
if (inputs.some((input) => nativeRoots.some((root) => root === input || root.startsWith(input + sep5) || input.startsWith(root + sep5))))
|
|
52876
|
+
throw new Error("Native installation input overlaps an unconditional skill-loading root");
|
|
52877
|
+
}
|
|
52621
52878
|
function planAgentIntegration(options) {
|
|
52622
52879
|
const home = options.home ?? homedir3(), dataDir3 = options.dataDir ?? getDataDirReadOnly();
|
|
52623
52880
|
const aliases = rootAliases(home, options.allowRootAliases);
|
|
@@ -52656,11 +52913,16 @@ function planAgentIntegration(options) {
|
|
|
52656
52913
|
const codexConfig = options.agents.includes("codex") ? Bun.TOML.parse(readOptional(canonicalAgentPath(join21(home, ".codex", "config.toml"), aliases)) ?? "") : {};
|
|
52657
52914
|
const nativeSkills = inventoryNativeSkills(home, { includeVendor: true, guardHermes: options.agents.includes("hermes"), agents: options.agents, projectDir: options.projectDir, agentRoots: discoveries.flatMap((binding) => binding.roots.map((path) => ({ agent: binding.agent, path }))), allowRootAliases: options.allowRootAliases, reviewedCacheAlias: options.reviewedCacheAlias, disabledVendorPaths: disabledCodexSkillPaths(codexConfig, aliases) });
|
|
52658
52915
|
const observedNativeSources = [];
|
|
52659
|
-
const
|
|
52916
|
+
const codexPluginControls = options.codexNativeCatalog ? reviewCodexPluginControls(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) => {
|
|
52660
52917
|
const bytes = readNativeBytes(path, 1024 * 1024);
|
|
52661
52918
|
observedNativeSources.push({ path, sha256: sha3(bytes) });
|
|
52662
52919
|
return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
52663
|
-
}, codexConfig.skills?.config ?? []) : policy.bridge?.codexPluginSkills ?? [];
|
|
52920
|
+
}, codexConfig.skills?.config ?? [], codexConfig.plugins) : { skills: policy.bridge?.codexPluginSkills ?? [], inactivePlugins: policy.bridge?.codexInactivePlugins ?? [], sourceInputs: policy.bridge?.discovery?.codex?.codexInstallationInputs?.plugins ?? [] };
|
|
52921
|
+
const codexPluginSkills = codexPluginControls.skills;
|
|
52922
|
+
const codexInactivePlugins = codexPluginControls.inactivePlugins;
|
|
52923
|
+
const codexDiscovery = discoveries.find((binding) => binding.agent === "codex");
|
|
52924
|
+
const codexPluginSourceInputs = codexPluginControls.sourceInputs.filter((input) => codexDiscovery?.method === "reviewed" && codexDiscovery.roots.some((root) => root === input.sourceRoot || root.startsWith(input.sourceRoot + sep5) || input.sourceRoot.startsWith(root + sep5)) && codexDiscovery.sources.some((source) => source.path === join21(input.sourceRoot, ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined));
|
|
52925
|
+
assertCodexInstallationInputs(home, [options.projectDir ?? home], codexPluginSourceInputs.map((input) => input.sourceRoot));
|
|
52664
52926
|
const changes = [];
|
|
52665
52927
|
for (const agent of [...new Set(options.agents)]) {
|
|
52666
52928
|
if (!INTEGRATION_AGENTS.includes(agent))
|
|
@@ -52725,7 +52987,16 @@ function planAgentIntegration(options) {
|
|
|
52725
52987
|
changes.push({ path: configPath, before: previous, after: next });
|
|
52726
52988
|
}
|
|
52727
52989
|
}
|
|
52728
|
-
const
|
|
52990
|
+
const 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;
|
|
52991
|
+
const discoveryAfter = discoveries.map((binding) => {
|
|
52992
|
+
const rebound = rebindAgentDiscovery(binding, new Map(changes.map((change) => [change.path, change.after])));
|
|
52993
|
+
if (binding.agent !== "codex")
|
|
52994
|
+
return rebound;
|
|
52995
|
+
const { codexInstallationInputs: previousInputs, ...current } = rebound;
|
|
52996
|
+
const inputs = codexPluginSourceInputs.map((input) => input.sourceRoot);
|
|
52997
|
+
const directories = options.codexNativeCatalog || !previousInputs ? captureDiscoveryDirectories((binding.directories ?? []).filter((directory) => inputs.some((root) => root.startsWith(directory.path + sep5))).map((directory) => directory.path), inputs) : previousInputs.directories;
|
|
52998
|
+
return codexPluginSourceInputs.length ? { ...current, codexInstallationInputs: { version: "codex-cli 0.160.0", catalogSha256: codexPluginSkillReview.catalogSha256, plugins: codexPluginSourceInputs, ...directories?.length ? { directories } : {} } } : current;
|
|
52999
|
+
});
|
|
52729
53000
|
const nextPolicy = { ...policy, version: 1, loading: "cli", profileId, bridge: {
|
|
52730
53001
|
...policy.bridge,
|
|
52731
53002
|
version: CLI_BRIDGE_VERSION,
|
|
@@ -52738,7 +53009,7 @@ function planAgentIntegration(options) {
|
|
|
52738
53009
|
profiles: Object.fromEntries([...new Set([...priorAgents, ...options.agents])].sort().map((agent) => [agent, bindings.get(agent)?.profileId ?? policy.bridge?.profiles?.[agent] ?? policy.profileId])),
|
|
52739
53010
|
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 ?? [],
|
|
52740
53011
|
rootAliases: aliases,
|
|
52741
|
-
...
|
|
53012
|
+
...options.codexNativeCatalog || codexPluginSkills.length || codexInactivePlugins.length || codexPluginSourceInputs.length ? { codexPluginSkills, codexInactivePlugins, codexPluginSkillReview } : {},
|
|
52742
53013
|
discovery: { ...policy.bridge?.discovery, ...Object.fromEntries(discoveryAfter.map((binding) => [binding.agent, binding])) }
|
|
52743
53014
|
} };
|
|
52744
53015
|
const serializedPolicy = serializeManagedSkillPolicy(nextPolicy);
|
|
@@ -53148,7 +53419,12 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
|
|
|
53148
53419
|
throw new Error("NATIVE_SKILL_DRIFT: the Codex CLI bridge is disabled; run skills hook install");
|
|
53149
53420
|
if (agent === "codex" && !reviewedCodexPluginCapabilitiesUnchanged(canonicalAgentPath(join21(home, ".codex/plugins/cache"), aliases), binding.codexPluginSkills ?? [], (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024))))
|
|
53150
53421
|
throw new Error("NATIVE_SKILL_DRIFT: reviewed native plugin capability controls changed; run skills hook install with a fresh discovery review");
|
|
53151
|
-
const disabledPlugin = (entry) =>
|
|
53422
|
+
const disabledPlugin = (entry) => {
|
|
53423
|
+
if (agent !== "codex" || !entry.vendor)
|
|
53424
|
+
return false;
|
|
53425
|
+
const document3 = join21(entry.path, "SKILL.md"), cache3 = canonicalAgentPath(join21(home, ".codex/plugins/cache"), aliases), read2 = (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024));
|
|
53426
|
+
return isReviewedCodexPluginInactive(document3, cache3, binding.codexInactivePlugins ?? [], codexConfig.plugins, codexConfig.skills?.config ?? [], read2) || isReviewedCodexPluginSkillDisabled(document3, cache3, binding.codexPluginSkills ?? [], codexConfig.skills?.config, read2);
|
|
53427
|
+
};
|
|
53152
53428
|
const disabledPaths = new Set(disabledCodexSkillPaths(codexConfig, aliases));
|
|
53153
53429
|
const disabledVendorSkill = (entry) => {
|
|
53154
53430
|
if (agent !== "codex" || !entry.vendor)
|
|
@@ -53185,7 +53461,15 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
|
|
|
53185
53461
|
} catch (error) {
|
|
53186
53462
|
throw new Error(`NATIVE_SKILL_DRIFT: ${error.message}`);
|
|
53187
53463
|
}
|
|
53188
|
-
|
|
53464
|
+
let installationInputRoots = [];
|
|
53465
|
+
if (agent === "codex") {
|
|
53466
|
+
try {
|
|
53467
|
+
installationInputRoots = reviewedCodexPluginSourceRoots(canonicalAgentPath(join21(home, ".codex/plugins/cache"), aliases), discovery.codexInstallationInputs?.plugins ?? [], (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024)));
|
|
53468
|
+
} catch {
|
|
53469
|
+
throw new Error("NATIVE_SKILL_DRIFT: native installation input identity changed; review discovery and catalog");
|
|
53470
|
+
}
|
|
53471
|
+
}
|
|
53472
|
+
const inventory = inventoryNativeSkills(home, { includeVendor: true, guardHermes: agent === "hermes", agents: [agent], projectDirs: [...roots], agentRoots: discovery.roots.map((path) => ({ agent, path })), allowRootAliases: aliases.length > 0, disabledVendorPaths: agent === "codex" ? disabledCodexSkillPaths(codexConfig, aliases) : [], disabledVendorSkill: disabledPlugin, codexInstallationInputRoots: installationInputRoots });
|
|
53189
53473
|
const unexpected = inventory.filter((entry) => visible(entry) && !entry.bridge && !disabledVendorSkill(entry));
|
|
53190
53474
|
if (unexpected.length) {
|
|
53191
53475
|
const paths = unexpected.slice(0, 3).map((entry) => {
|
|
@@ -56557,8 +56841,16 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
56557
56841
|
throw new Error("Invalid native discovery binding");
|
|
56558
56842
|
if (binding.agent === "hermes" && !binding.directories?.length)
|
|
56559
56843
|
throw new Error("Hermes discovery requires directory membership coverage; run skills hook install with a fresh discovery review");
|
|
56560
|
-
|
|
56561
|
-
|
|
56844
|
+
const installationRoots = codexInstallationRoots(binding);
|
|
56845
|
+
const installationInput = (path) => installationRoots.some((root2) => path === root2 || path.startsWith(root2 + sep6));
|
|
56846
|
+
if (binding.directories !== undefined) {
|
|
56847
|
+
const projected2 = binding.codexInstallationInputs?.directories ?? [];
|
|
56848
|
+
const ancestors2 = binding.directories.filter((directory) => installationRoots.some((root2) => root2.startsWith(directory.path + sep6)));
|
|
56849
|
+
if (projected2.length !== ancestors2.length || projected2.some((directory) => !ancestors2.some((original) => original.path === directory.path)))
|
|
56850
|
+
throw new Error("Missing installation input directory projection");
|
|
56851
|
+
verifyDiscoveryDirectories(binding.directories.filter((directory) => !installationInput(directory.path) && !ancestors2.includes(directory)));
|
|
56852
|
+
verifyDiscoveryDirectories(projected2, installationRoots);
|
|
56853
|
+
}
|
|
56562
56854
|
const budget = discoveryByteBudget();
|
|
56563
56855
|
for (const source of binding.sources) {
|
|
56564
56856
|
assertMarketplaceBinding(binding, source);
|
|
@@ -56568,6 +56860,10 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
56568
56860
|
throw new Error("Invalid native discovery projection");
|
|
56569
56861
|
if (source.sha256 !== null && !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
56570
56862
|
throw new Error("Invalid native discovery digest");
|
|
56863
|
+
if (installationInput(source.path)) {
|
|
56864
|
+
safe4(source.path);
|
|
56865
|
+
continue;
|
|
56866
|
+
}
|
|
56571
56867
|
const current = projected(source, undefined, budget);
|
|
56572
56868
|
if (current !== source.sha256 && !verifiesCodexHookDiscoverySource(binding, source, current, codexRecovery))
|
|
56573
56869
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
@@ -56575,6 +56871,27 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
56575
56871
|
for (const root2 of binding.roots)
|
|
56576
56872
|
safe4(root2);
|
|
56577
56873
|
}
|
|
56874
|
+
function codexInstallationRoots(binding) {
|
|
56875
|
+
const proof = binding.codexInstallationInputs;
|
|
56876
|
+
if (proof === undefined)
|
|
56877
|
+
return [];
|
|
56878
|
+
if (binding.agent !== "codex" || binding.method !== "reviewed" || proof.version !== "codex-cli 0.160.0" || !/^[a-f0-9]{64}$/.test(proof.catalogSha256) || !Array.isArray(proof.plugins) || !proof.plugins.length)
|
|
56879
|
+
throw new Error("Invalid native installation input proof");
|
|
56880
|
+
const cache3 = dirname17(dirname17(proof.plugins[0].pluginParent));
|
|
56881
|
+
const config = join32(dirname17(dirname17(cache3)), "config.toml"), home = dirname17(dirname17(dirname17(cache3)));
|
|
56882
|
+
const configSource = binding.sources.find((source) => source.path === config && source.sha256 !== null && (!source.format || source.format === "toml" && source.fields?.includes("plugins")));
|
|
56883
|
+
const nativeRoots = NATIVE_SKILL_ROOTS.filter(([agent]) => agent === "codex").map(([, path]) => join32(home, path));
|
|
56884
|
+
if (!configSource || proof.plugins.some((input) => nativeRoots.some((root2) => root2 === input.sourceRoot || root2.startsWith(input.sourceRoot + sep6) || input.sourceRoot.startsWith(root2 + sep6)) || binding.sources.some((source) => basename9(source.path) === "config.toml" && (source.path === input.sourceRoot || source.path.startsWith(input.sourceRoot + sep6)))))
|
|
56885
|
+
throw new Error("Native installation input overlaps configuration or loading roots");
|
|
56886
|
+
if (proof.plugins.some((input) => dirname17(dirname17(input.pluginParent)) !== cache3 || !binding.sources.some((source) => source.path === join32(input.sourceRoot, ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined)))
|
|
56887
|
+
throw new Error("Missing native installation input source witness");
|
|
56888
|
+
return reviewedCodexPluginSourceRoots(cache3, proof.plugins, (path) => {
|
|
56889
|
+
const text3 = read2(path);
|
|
56890
|
+
if (text3 === null)
|
|
56891
|
+
throw new Error("Missing native installation input");
|
|
56892
|
+
return text3;
|
|
56893
|
+
});
|
|
56894
|
+
}
|
|
56578
56895
|
function assertMarketplaceBinding(binding, source) {
|
|
56579
56896
|
if ((source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2") && (binding.agent !== "codex" || binding.method !== "reviewed" || basename9(source.path) !== "config.toml"))
|
|
56580
56897
|
throw new Error("Codex settings witnesses require explicit reviewed Codex configuration");
|
|
@@ -56585,8 +56902,11 @@ function assertMarketplaceBinding(binding, source) {
|
|
|
56585
56902
|
}
|
|
56586
56903
|
function rebindAgentDiscovery(binding, changes) {
|
|
56587
56904
|
const budget = discoveryByteBudget();
|
|
56905
|
+
const installationRoots = codexInstallationRoots(binding);
|
|
56588
56906
|
return { ...binding, sources: binding.sources.map((source) => {
|
|
56589
56907
|
assertMarketplaceBinding(binding, source);
|
|
56908
|
+
if (!changes.has(source.path) && installationRoots.some((root2) => source.path.startsWith(root2 + sep6)))
|
|
56909
|
+
return source;
|
|
56590
56910
|
const sha2562 = projected(source, changes, budget);
|
|
56591
56911
|
if (!changes.has(source.path) && sha2562 !== source.sha256)
|
|
56592
56912
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
@@ -56857,6 +57177,8 @@ var init_agent_discovery = __esm(() => {
|
|
|
56857
57177
|
init_claude_settings_witness();
|
|
56858
57178
|
init_codex_hook_discovery_recovery();
|
|
56859
57179
|
init_codex_settings_witness();
|
|
57180
|
+
init_codex_plugin_skill_controls();
|
|
57181
|
+
init_native_discovery_roots();
|
|
56860
57182
|
init_agent_discovery_directories();
|
|
56861
57183
|
});
|
|
56862
57184
|
|