@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/dist/sdk/index.js
CHANGED
|
@@ -32373,7 +32373,7 @@ var init_event_sink = __esm(() => {
|
|
|
32373
32373
|
// package.json
|
|
32374
32374
|
var package_default = {
|
|
32375
32375
|
name: "@hasna/skills",
|
|
32376
|
-
version: "0.10.
|
|
32376
|
+
version: "0.10.25",
|
|
32377
32377
|
description: "Skills library for AI coding agents",
|
|
32378
32378
|
type: "module",
|
|
32379
32379
|
bin: {
|
|
@@ -38175,6 +38175,10 @@ async function connectCodexHookRpc(options) {
|
|
|
38175
38175
|
}
|
|
38176
38176
|
|
|
38177
38177
|
// src/lib/codex-native-skill-catalog.ts
|
|
38178
|
+
function codexPluginSourceIsConfigControlled(plugin) {
|
|
38179
|
+
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"];
|
|
38180
|
+
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)));
|
|
38181
|
+
}
|
|
38178
38182
|
var MAX_SKILLS = 4096;
|
|
38179
38183
|
var MAX_NAME_BYTES = 1024;
|
|
38180
38184
|
var MAX_PATH_BYTES = 16384;
|
|
@@ -38186,6 +38190,15 @@ var object2 = (value) => value !== null && typeof value === "object" && !Array.i
|
|
|
38186
38190
|
var scalar = (value, max) => typeof value === "string" && value.length > 0 && value.trim() === value && Buffer.byteLength(value, "utf8") <= max && !/[\u0000-\u001f\u007f]/u.test(value);
|
|
38187
38191
|
var remotePluginIdentifier = (value) => typeof value === "string" && /^[A-Za-z0-9_~-]{1,1024}$/.test(value);
|
|
38188
38192
|
var absolutePath2 = (value) => scalar(value, MAX_PATH_BYTES) && isAbsolute5(value);
|
|
38193
|
+
function projectPluginSource(source) {
|
|
38194
|
+
if (!object2(source))
|
|
38195
|
+
return {};
|
|
38196
|
+
if (source.type === "remote")
|
|
38197
|
+
return { sourceType: "remote" };
|
|
38198
|
+
const optionalText = (value) => value === undefined || value === null || scalar(value, MAX_PATH_BYTES);
|
|
38199
|
+
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;
|
|
38200
|
+
return valid ? { sourceType: source.type, sourceSha256: hashNativeJsonControls(JSON.stringify(source)), ...source.type === "local" ? { sourcePath: source.path } : {} } : {};
|
|
38201
|
+
}
|
|
38189
38202
|
function projectCodexNativeSkillCatalog(response, cwd) {
|
|
38190
38203
|
if (!absolutePath2(cwd) || !object2(response) || !Array.isArray(response.data) || response.data.length !== 1)
|
|
38191
38204
|
refuse2();
|
|
@@ -38215,7 +38228,10 @@ function projectCodexInstalledPlugins(response) {
|
|
|
38215
38228
|
plugins.push({
|
|
38216
38229
|
...value,
|
|
38217
38230
|
marketplace: marketplace.name,
|
|
38218
|
-
sourceType:
|
|
38231
|
+
sourceType: undefined,
|
|
38232
|
+
sourceSha256: undefined,
|
|
38233
|
+
sourcePath: undefined,
|
|
38234
|
+
...projectPluginSource(value.source)
|
|
38219
38235
|
});
|
|
38220
38236
|
}
|
|
38221
38237
|
}
|
|
@@ -38226,7 +38242,7 @@ function projectCodexInstalledPluginEntries(value) {
|
|
|
38226
38242
|
refuse2();
|
|
38227
38243
|
const ids = new Set;
|
|
38228
38244
|
return value.map((item) => {
|
|
38229
|
-
if (!object2(item) || !scalar(item.id, MAX_PLUGIN_ID_BYTES) || !scalar(item.name, MAX_NAME_BYTES) || typeof item.installed !== "boolean" || typeof item.enabled !== "boolean" || item.localVersion !== null && !scalar(item.localVersion, MAX_NAME_BYTES) || item.remotePluginId !== undefined && item.remotePluginId !== null && !remotePluginIdentifier(item.remotePluginId) || item.sourceType !== undefined && item.sourceType !== "
|
|
38245
|
+
if (!object2(item) || !scalar(item.id, MAX_PLUGIN_ID_BYTES) || !scalar(item.name, MAX_NAME_BYTES) || typeof item.installed !== "boolean" || typeof item.enabled !== "boolean" || item.localVersion !== null && !scalar(item.localVersion, MAX_NAME_BYTES) || item.remotePluginId !== undefined && item.remotePluginId !== null && !remotePluginIdentifier(item.remotePluginId) || item.sourceType !== undefined && !["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) || normalize(item.sourcePath) !== item.sourcePath || item.sourceSha256 !== hashNativeJsonControls(JSON.stringify({ type: "local", path: item.sourcePath })) : item.sourcePath !== undefined))
|
|
38230
38246
|
refuse2();
|
|
38231
38247
|
const at = item.id.lastIndexOf("@");
|
|
38232
38248
|
if (at < 1 || item.id.slice(0, at) !== item.name || at === item.id.length - 1 || ids.has(item.id))
|
|
@@ -38238,7 +38254,9 @@ function projectCodexInstalledPluginEntries(value) {
|
|
|
38238
38254
|
installed: item.installed,
|
|
38239
38255
|
enabled: item.enabled,
|
|
38240
38256
|
localVersion: item.localVersion ?? null,
|
|
38241
|
-
...item.sourceType ===
|
|
38257
|
+
...item.sourceType === undefined ? {} : { sourceType: item.sourceType },
|
|
38258
|
+
...item.sourceSha256 === undefined ? {} : { sourceSha256: item.sourceSha256 },
|
|
38259
|
+
...item.sourcePath === undefined ? {} : { sourcePath: item.sourcePath },
|
|
38242
38260
|
...item.remotePluginId == null ? {} : { remotePluginId: item.remotePluginId }
|
|
38243
38261
|
};
|
|
38244
38262
|
});
|
|
@@ -38359,27 +38377,62 @@ function mcpControls(path, read) {
|
|
|
38359
38377
|
const object3 = (v) => Boolean(v && typeof v === "object" && !Array.isArray(v));
|
|
38360
38378
|
const textField = (v, empty = false) => typeof v === "string" && (empty || Boolean(v.trim())) && Buffer.byteLength(v) <= 16384 && !/[\x00-\x1f\x7f]/.test(v);
|
|
38361
38379
|
const envName = (v) => typeof v === "string" && /^[A-Za-z_][A-Za-z0-9_]{0,255}$/.test(v);
|
|
38380
|
+
const optional = (v, valid) => v === undefined || v === null || valid(v);
|
|
38381
|
+
const stringList = (v) => Array.isArray(v) && v.length <= 256 && v.every((item) => textField(item));
|
|
38382
|
+
const approval = (v) => ["auto", "prompt", "writes", "approve"].includes(v);
|
|
38383
|
+
const duration = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0;
|
|
38384
|
+
const positiveInteger = (v) => Number.isSafeInteger(v) && v > 0;
|
|
38385
|
+
const fields = [
|
|
38386
|
+
"command",
|
|
38387
|
+
"args",
|
|
38388
|
+
"cwd",
|
|
38389
|
+
"env",
|
|
38390
|
+
"env_vars",
|
|
38391
|
+
"enabled",
|
|
38392
|
+
"required",
|
|
38393
|
+
"environment_id",
|
|
38394
|
+
"startup_readiness",
|
|
38395
|
+
"supports_parallel_tool_calls",
|
|
38396
|
+
"tool_input_schema_max_bytes",
|
|
38397
|
+
"startup_timeout_sec",
|
|
38398
|
+
"startup_timeout_ms",
|
|
38399
|
+
"tool_timeout_sec",
|
|
38400
|
+
"default_tools_approval_mode",
|
|
38401
|
+
"enabled_tools",
|
|
38402
|
+
"disabled_tools",
|
|
38403
|
+
"omit_tools_from",
|
|
38404
|
+
"tools",
|
|
38405
|
+
"name"
|
|
38406
|
+
];
|
|
38362
38407
|
if (!object3(value) || Object.keys(value).length !== 1 || !object3(value.mcpServers))
|
|
38363
38408
|
refuse3();
|
|
38364
38409
|
const servers = Object.entries(value.mcpServers);
|
|
38365
38410
|
if (!servers.length || servers.length > 256)
|
|
38366
38411
|
refuse3();
|
|
38367
38412
|
for (const [name, server] of servers) {
|
|
38368
|
-
if (!identifier3(name) || !object3(server) || !Object.keys(server).every((key) =>
|
|
38413
|
+
if (!identifier3(name) || !object3(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) => object3(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))
|
|
38369
38414
|
refuse3();
|
|
38370
|
-
if (server.env_vars !== undefined) {
|
|
38415
|
+
if (server.env_vars !== undefined && server.env_vars !== null) {
|
|
38371
38416
|
if (!Array.isArray(server.env_vars) || server.env_vars.length > 256)
|
|
38372
38417
|
refuse3();
|
|
38373
38418
|
const names = server.env_vars.map((entry) => {
|
|
38374
38419
|
if (envName(entry))
|
|
38375
38420
|
return entry;
|
|
38376
|
-
if (!object3(entry) || !Object.keys(entry).every((key) => ["name", "source"].includes(key)) || !envName(entry.name) || entry.source
|
|
38421
|
+
if (!object3(entry) || !Object.keys(entry).every((key) => ["name", "source"].includes(key)) || !envName(entry.name) || !optional(entry.source, (v) => v === "local"))
|
|
38377
38422
|
refuse3();
|
|
38378
38423
|
return entry.name;
|
|
38379
38424
|
});
|
|
38380
38425
|
if (new Set(names).size !== names.length)
|
|
38381
38426
|
refuse3();
|
|
38382
38427
|
}
|
|
38428
|
+
if (server.tools !== undefined && server.tools !== null) {
|
|
38429
|
+
if (!object3(server.tools) || Object.keys(server.tools).length > 256)
|
|
38430
|
+
refuse3();
|
|
38431
|
+
for (const [tool, config] of Object.entries(server.tools)) {
|
|
38432
|
+
if (!textField(tool) || !object3(config) || !Object.keys(config).every((key) => ["approval_mode", "output_token_limit"].includes(key)) || !optional(config.approval_mode, approval) || !optional(config.output_token_limit, positiveInteger))
|
|
38433
|
+
refuse3();
|
|
38434
|
+
}
|
|
38435
|
+
}
|
|
38383
38436
|
}
|
|
38384
38437
|
return sha2562;
|
|
38385
38438
|
}
|
|
@@ -38416,7 +38469,7 @@ function rootControls(root, read) {
|
|
|
38416
38469
|
const appSha256 = present ? appControls(app, read) : undefined;
|
|
38417
38470
|
return { namespace: manifest.name, manifestSha256, ...appSha256 ? { appSha256 } : {}, ...mcpSha256 ? { mcpSha256 } : {} };
|
|
38418
38471
|
}
|
|
38419
|
-
function
|
|
38472
|
+
function documentIdentity(document, cache, read) {
|
|
38420
38473
|
if (!document.startsWith(cache + sep2) || !document.endsWith(sep2 + "SKILL.md"))
|
|
38421
38474
|
refuse3();
|
|
38422
38475
|
const text = read(document);
|
|
@@ -38444,11 +38497,33 @@ function identity(document, cache, read) {
|
|
|
38444
38497
|
const path = join10(root, ".codex-plugin", "plugin.json");
|
|
38445
38498
|
if (!lstatSync6(path, { throwIfNoEntry: false }))
|
|
38446
38499
|
continue;
|
|
38447
|
-
const
|
|
38448
|
-
|
|
38500
|
+
const manifestFile = lstatSync6(path);
|
|
38501
|
+
if (!lstatSync6(join10(root, ".codex-plugin")).isDirectory() || !manifestFile.isFile() || manifestFile.size > 1024 * 1024)
|
|
38502
|
+
refuse3();
|
|
38503
|
+
let manifest;
|
|
38504
|
+
try {
|
|
38505
|
+
const text2 = read(path);
|
|
38506
|
+
hashNativeJsonControls(text2);
|
|
38507
|
+
manifest = JSON.parse(text2);
|
|
38508
|
+
} catch {
|
|
38509
|
+
refuse3();
|
|
38510
|
+
}
|
|
38511
|
+
if (!manifest || typeof manifest !== "object" || Array.isArray(manifest) || !identifier3(manifest.name))
|
|
38512
|
+
refuse3();
|
|
38513
|
+
const declaredVersion = manifest.version === undefined ? "" : typeof manifest.version === "string" ? manifest.version.trim() : null;
|
|
38514
|
+
if (declaredVersion === null || (declaredVersion ? declaredVersion !== basename3(root) : basename3(root) !== CODEX_DEFAULT_AGENT_PLUGIN_VERSION))
|
|
38515
|
+
refuse3();
|
|
38516
|
+
return { name: `${manifest.name}:${front.name}`, namespace: manifest.name, pluginParent: dirname5(root), root };
|
|
38449
38517
|
}
|
|
38450
38518
|
refuse3();
|
|
38451
38519
|
}
|
|
38520
|
+
function identity(document, cache, read) {
|
|
38521
|
+
const parsed = documentIdentity(document, cache, read);
|
|
38522
|
+
const controls = rootControls(parsed.root, read);
|
|
38523
|
+
if (controls.namespace !== parsed.namespace)
|
|
38524
|
+
refuse3();
|
|
38525
|
+
return { name: parsed.name, pluginParent: parsed.pluginParent, ...controls };
|
|
38526
|
+
}
|
|
38452
38527
|
function reviewedCodexPluginCapabilitiesUnchanged(cache, controls, read) {
|
|
38453
38528
|
if (!Array.isArray(controls) || controls.length > 4096)
|
|
38454
38529
|
return false;
|
|
@@ -38486,11 +38561,13 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache, controls, read) {
|
|
|
38486
38561
|
return false;
|
|
38487
38562
|
}
|
|
38488
38563
|
}
|
|
38489
|
-
function
|
|
38564
|
+
function reviewCodexPluginControls(catalog, documents, cache, cwd, read, rules, pluginSettings) {
|
|
38490
38565
|
if (!supportsCodexNativeCapability(catalog?.version, "qualified-skill-catalog") || catalog.cwd !== cwd)
|
|
38491
38566
|
refuse3();
|
|
38492
38567
|
const skills = projectCodexNativeSkillCatalog({ data: [{ cwd, errors: [], skills: catalog.skills }] }, cwd);
|
|
38493
|
-
const allowed = new Set(documents), result = [];
|
|
38568
|
+
const allowed = new Set(documents), result = [], inertDocuments = new Set;
|
|
38569
|
+
const inactivePlugins = new Map;
|
|
38570
|
+
const sourceInputs = new Map;
|
|
38494
38571
|
let installedPlugins;
|
|
38495
38572
|
try {
|
|
38496
38573
|
installedPlugins = projectCodexInstalledPluginEntries(catalog.plugins ?? []);
|
|
@@ -38501,25 +38578,48 @@ function reviewCodexPluginSkillControls(catalog, documents, cache, cwd, read, ru
|
|
|
38501
38578
|
for (const document of candidates) {
|
|
38502
38579
|
if (!document.startsWith(cache + sep2))
|
|
38503
38580
|
continue;
|
|
38504
|
-
const
|
|
38505
|
-
if (
|
|
38581
|
+
const located = documentIdentity(document, cache, read);
|
|
38582
|
+
if (located.name === "skills-cli" || located.name.endsWith(":skills-cli"))
|
|
38506
38583
|
refuse3();
|
|
38507
|
-
const cacheParts = relative3(cache,
|
|
38584
|
+
const cacheParts = relative3(cache, located.pluginParent).split(sep2);
|
|
38508
38585
|
if (cacheParts.length !== 2 || cacheParts.some((part) => !identifier3(part)))
|
|
38509
38586
|
refuse3();
|
|
38510
38587
|
const [marketplace, pluginName] = cacheParts;
|
|
38511
|
-
if (pluginName !==
|
|
38588
|
+
if (pluginName !== located.namespace)
|
|
38512
38589
|
refuse3();
|
|
38513
38590
|
const expectedPluginId = `${pluginName}@${marketplace}`;
|
|
38514
38591
|
const listed = skills.filter((skill) => skill.path === document);
|
|
38515
38592
|
if (listed.length > 1)
|
|
38516
38593
|
refuse3();
|
|
38594
|
+
const installed = installedPlugins.filter((plugin) => plugin.id === expectedPluginId && plugin.name === pluginName);
|
|
38595
|
+
if (catalog.version === "codex-cli 0.160.0" && installed.length === 1 && installed[0].installed && installed[0].localVersion === basename3(located.root) && installed[0].sourceType === "local" && codexPluginSourceIsConfigControlled(installed[0])) {
|
|
38596
|
+
const plugin = installed[0], input = { pluginId: expectedPluginId, namespace: located.namespace, pluginParent: located.pluginParent, sourceRoot: plugin.sourcePath, sourceSha256: plugin.sourceSha256 };
|
|
38597
|
+
if (input.sourceRoot !== located.root && !input.sourceRoot.startsWith(cache + sep2) && (lstatSync6(input.sourceRoot, { throwIfNoEntry: false }) || documents.some((path) => path.startsWith(input.sourceRoot + sep2)))) {
|
|
38598
|
+
if (skills.some((skill) => skill.path === input.sourceRoot || skill.path.startsWith(input.sourceRoot + sep2)) || !sourceInputUnchanged(input, cache, read))
|
|
38599
|
+
refuse3();
|
|
38600
|
+
sourceInputs.set(expectedPluginId, input);
|
|
38601
|
+
}
|
|
38602
|
+
}
|
|
38603
|
+
const settings = pluginSettings && typeof pluginSettings === "object" && !Array.isArray(pluginSettings) ? pluginSettings : undefined;
|
|
38604
|
+
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) {
|
|
38605
|
+
if (!Array.isArray(rules))
|
|
38606
|
+
refuse3();
|
|
38607
|
+
const exactPathDeny = rules.some((rule) => rule?.path === document && rule?.enabled === false);
|
|
38608
|
+
if (!lstatSync6(document).isFile() || realpathSync5(document) !== document || realpathSync5(located.root) !== located.root || realpathSync5(located.pluginParent) !== located.pluginParent || realpathSync5(join10(located.root, ".codex-plugin/plugin.json")) !== join10(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: document, pluginId: expectedPluginId, enabled: true }, rules))
|
|
38609
|
+
refuse3();
|
|
38610
|
+
inertDocuments.add(document);
|
|
38611
|
+
const plugin = installed[0];
|
|
38612
|
+
inactivePlugins.set(expectedPluginId, { pluginId: expectedPluginId, namespace: located.namespace, pluginParent: located.pluginParent, sourceType: plugin.sourceType, sourceSha256: plugin.sourceSha256 });
|
|
38613
|
+
continue;
|
|
38614
|
+
}
|
|
38615
|
+
const parsed = { name: located.name, pluginParent: located.pluginParent, ...rootControls(located.root, read) };
|
|
38616
|
+
if (parsed.namespace !== located.namespace)
|
|
38617
|
+
refuse3();
|
|
38517
38618
|
let remotePluginId;
|
|
38518
38619
|
if (listed.length === 1) {
|
|
38519
38620
|
if (listed[0].name !== parsed.name || listed[0].pluginId !== expectedPluginId)
|
|
38520
38621
|
refuse3();
|
|
38521
38622
|
} else {
|
|
38522
|
-
const installed = installedPlugins.filter((plugin2) => plugin2.id === expectedPluginId && plugin2.name === pluginName);
|
|
38523
38623
|
if (installed.length !== 1 || !installed[0].installed || !installed[0].enabled)
|
|
38524
38624
|
refuse3();
|
|
38525
38625
|
const plugin = installed[0];
|
|
@@ -38537,9 +38637,48 @@ function reviewCodexPluginSkillControls(catalog, documents, cache, cwd, read, ru
|
|
|
38537
38637
|
}
|
|
38538
38638
|
result.push({ ...parsed, pluginId: expectedPluginId, ...remotePluginId ? { remotePluginId } : {} });
|
|
38539
38639
|
}
|
|
38540
|
-
if (!result.length && documents.some((document) => document.startsWith(cache + sep2)) || new Set(result.map((item) => item.name)).size !== result.length)
|
|
38640
|
+
if (!result.length && documents.some((document) => document.startsWith(cache + sep2) && !inertDocuments.has(document)) || new Set(result.map((item) => item.name)).size !== result.length)
|
|
38541
38641
|
refuse3();
|
|
38542
|
-
return result;
|
|
38642
|
+
return { skills: result, inactivePlugins: [...inactivePlugins.values()], sourceInputs: [...sourceInputs.values()] };
|
|
38643
|
+
}
|
|
38644
|
+
function sourceInputUnchanged(input, cache, read) {
|
|
38645
|
+
try {
|
|
38646
|
+
const parts = relative3(cache, input.pluginParent).split(sep2);
|
|
38647
|
+
if (parts.length !== 2 || parts.some((part) => !identifier3(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 })) || resolve4(input.sourceRoot) !== input.sourceRoot || !lstatSync6(input.sourceRoot).isDirectory() || realpathSync5(input.sourceRoot) !== input.sourceRoot || input.sourceRoot === cache || input.sourceRoot.startsWith(cache + sep2) || cache.startsWith(input.sourceRoot + sep2))
|
|
38648
|
+
return false;
|
|
38649
|
+
const path = join10(input.sourceRoot, ".codex-plugin/plugin.json"), stat = lstatSync6(path);
|
|
38650
|
+
if (!stat.isFile() || stat.size > 1024 * 1024 || realpathSync5(path) !== path)
|
|
38651
|
+
return false;
|
|
38652
|
+
const text = read(path);
|
|
38653
|
+
hashNativeJsonControls(text);
|
|
38654
|
+
const manifest = JSON.parse(text);
|
|
38655
|
+
return Boolean(manifest && typeof manifest === "object" && !Array.isArray(manifest) && manifest.name === input.namespace);
|
|
38656
|
+
} catch {
|
|
38657
|
+
return false;
|
|
38658
|
+
}
|
|
38659
|
+
}
|
|
38660
|
+
function reviewedCodexPluginSourceRoots(cache, inputs, read) {
|
|
38661
|
+
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, cache, read)))
|
|
38662
|
+
refuse3();
|
|
38663
|
+
const roots = inputs.map((input) => input.sourceRoot);
|
|
38664
|
+
if (roots.some((root) => roots.some((other) => root !== other && root.startsWith(other + sep2))))
|
|
38665
|
+
refuse3();
|
|
38666
|
+
return roots;
|
|
38667
|
+
}
|
|
38668
|
+
function isReviewedCodexPluginInactive(document, cache, controls, pluginSettings, rules, read) {
|
|
38669
|
+
if (!Array.isArray(controls) || controls.length > 4096 || !pluginSettings || typeof pluginSettings !== "object" || Array.isArray(pluginSettings) || !Array.isArray(rules))
|
|
38670
|
+
return false;
|
|
38671
|
+
try {
|
|
38672
|
+
const parsed = documentIdentity(document, cache, read), matches = controls.filter((control2) => control2.pluginParent === parsed.pluginParent && control2.namespace === parsed.namespace);
|
|
38673
|
+
if (matches.length !== 1 || !lstatSync6(document).isFile() || realpathSync5(document) !== document || realpathSync5(parsed.root) !== parsed.root || realpathSync5(parsed.pluginParent) !== parsed.pluginParent || realpathSync5(join10(parsed.root, ".codex-plugin/plugin.json")) !== join10(parsed.root, ".codex-plugin/plugin.json"))
|
|
38674
|
+
return false;
|
|
38675
|
+
const control = matches[0], parts = relative3(cache, parsed.pluginParent).split(sep2);
|
|
38676
|
+
if (parts.length !== 2 || parts.some((part) => !identifier3(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)
|
|
38677
|
+
return false;
|
|
38678
|
+
return !rules.some((rule) => (rule?.path === document || typeof rule?.name === "string" && rule.name.trim() === parsed.name) && rule?.enabled !== false);
|
|
38679
|
+
} catch {
|
|
38680
|
+
return false;
|
|
38681
|
+
}
|
|
38543
38682
|
}
|
|
38544
38683
|
function isReviewedCodexPluginSkillDisabled(document, cache, controls, rules, read) {
|
|
38545
38684
|
if (!document.startsWith(cache + sep2) || !Array.isArray(controls) || controls.length > 4096)
|
|
@@ -38915,6 +39054,18 @@ function assertAgentPolicyCollections(policy) {
|
|
|
38915
39054
|
if (control.appSha256 !== undefined)
|
|
38916
39055
|
requireBound(typeof control.appSha256 === "string" && /^[a-f0-9]{64}$/.test(control.appSha256));
|
|
38917
39056
|
}
|
|
39057
|
+
if (bridge.codexInactivePlugins !== undefined) {
|
|
39058
|
+
const controls = array(bridge.codexInactivePlugins, 4096), ids = new Set;
|
|
39059
|
+
requireBound(controls.length === 0 || object3(bridge.codexPluginSkillReview) && bridge.codexPluginSkillReview.version === "codex-cli 0.160.0" && typeof bridge.codexPluginSkillReview.catalogSha256 === "string" && /^[a-f0-9]{64}$/.test(bridge.codexPluginSkillReview.catalogSha256));
|
|
39060
|
+
for (const control of controls) {
|
|
39061
|
+
requireBound(object3(control) && Object.keys(control).every((key) => ["pluginId", "namespace", "pluginParent", "sourceType", "sourceSha256"].includes(key)));
|
|
39062
|
+
text(control.pluginId, 1024);
|
|
39063
|
+
text(control.namespace, 64);
|
|
39064
|
+
text(control.pluginParent);
|
|
39065
|
+
requireBound(!ids.has(control.pluginId) && isAbsolute6(control.pluginParent) && resolve5(control.pluginParent) === control.pluginParent && ["local", "git", "npm"].includes(control.sourceType) && typeof control.sourceSha256 === "string" && /^[a-f0-9]{64}$/.test(control.sourceSha256));
|
|
39066
|
+
ids.add(control.pluginId);
|
|
39067
|
+
}
|
|
39068
|
+
}
|
|
38918
39069
|
if (bridge.disabledBuiltins !== undefined)
|
|
38919
39070
|
for (const builtin of array(bridge.disabledBuiltins, AGENT_POLICY_LIMITS.builtinNames)) {
|
|
38920
39071
|
requireBound(object3(builtin));
|
|
@@ -38927,6 +39078,25 @@ function assertAgentPolicyCollections(policy) {
|
|
|
38927
39078
|
text(agent, 128);
|
|
38928
39079
|
requireBound(object3(value));
|
|
38929
39080
|
text(value.agent, 128);
|
|
39081
|
+
if (value.codexInstallationInputs !== undefined) {
|
|
39082
|
+
const proof = record2(value.codexInstallationInputs, 4), inputs = array(proof.plugins, 4096), ids = new Set;
|
|
39083
|
+
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 && object3(bridge.codexPluginSkillReview) && bridge.codexPluginSkillReview.version === proof.version && bridge.codexPluginSkillReview.catalogSha256 === proof.catalogSha256);
|
|
39084
|
+
for (const input of inputs) {
|
|
39085
|
+
requireBound(object3(input) && Object.keys(input).every((key) => ["pluginId", "namespace", "pluginParent", "sourceRoot", "sourceSha256"].includes(key)));
|
|
39086
|
+
text(input.pluginId, 1024);
|
|
39087
|
+
text(input.namespace, 64);
|
|
39088
|
+
text(input.pluginParent);
|
|
39089
|
+
text(input.sourceRoot);
|
|
39090
|
+
requireBound(!ids.has(input.pluginId) && [input.pluginParent, input.sourceRoot].every((path) => isAbsolute6(path) && resolve5(path) === path) && typeof input.sourceSha256 === "string" && /^[a-f0-9]{64}$/.test(input.sourceSha256));
|
|
39091
|
+
ids.add(input.pluginId);
|
|
39092
|
+
}
|
|
39093
|
+
if (proof.directories !== undefined)
|
|
39094
|
+
for (const directory of array(proof.directories, AGENT_POLICY_LIMITS.discoveryDirectories)) {
|
|
39095
|
+
requireBound(object3(directory));
|
|
39096
|
+
text(directory.path);
|
|
39097
|
+
requireBound(directory.sha256 === null || typeof directory.sha256 === "string" && /^[a-f0-9]{64}$/.test(directory.sha256));
|
|
39098
|
+
}
|
|
39099
|
+
}
|
|
38930
39100
|
for (const root of array(value.roots, AGENT_POLICY_LIMITS.discoveryRoots))
|
|
38931
39101
|
text(root);
|
|
38932
39102
|
for (const source of array(value.sources, AGENT_POLICY_LIMITS.discoverySources)) {
|
|
@@ -39369,7 +39539,7 @@ function safe(path) {
|
|
|
39369
39539
|
function same(before, after) {
|
|
39370
39540
|
return Boolean(after && after.isDirectory() && before.dev === after.dev && before.ino === after.ino && before.mtimeMs === after.mtimeMs && before.ctimeMs === after.ctimeMs);
|
|
39371
39541
|
}
|
|
39372
|
-
function capture(path, budget) {
|
|
39542
|
+
function capture(path, budget, excludedRoots) {
|
|
39373
39543
|
safe(path);
|
|
39374
39544
|
const root = lstatSync10(path, { throwIfNoEntry: false });
|
|
39375
39545
|
if (!root)
|
|
@@ -39398,7 +39568,7 @@ function capture(path, budget) {
|
|
|
39398
39568
|
budget.bytes += Buffer.byteLength(row);
|
|
39399
39569
|
need4(budget.bytes <= AGENT_POLICY_LIMITS.discoveryDirectoryBytes, "Native discovery directory metadata limit exceeded");
|
|
39400
39570
|
hash2.update(row);
|
|
39401
|
-
if (stat.isDirectory())
|
|
39571
|
+
if (stat.isDirectory() && !excludedRoots.includes(child))
|
|
39402
39572
|
walk2(child, childRelative, stat, depth + 1);
|
|
39403
39573
|
}
|
|
39404
39574
|
need4(same(before, lstatSync10(current, { throwIfNoEntry: false })), "Native discovery directory changed while reading");
|
|
@@ -39407,16 +39577,18 @@ function capture(path, budget) {
|
|
|
39407
39577
|
safe(path);
|
|
39408
39578
|
return { path, sha256: hash2.digest("hex") };
|
|
39409
39579
|
}
|
|
39410
|
-
function captureDiscoveryDirectories(paths) {
|
|
39580
|
+
function captureDiscoveryDirectories(paths, excludedRoots = []) {
|
|
39411
39581
|
need4(Array.isArray(paths) && paths.length <= AGENT_POLICY_LIMITS.discoveryDirectories && new Set(paths).size === paths.length, "Invalid native discovery directory collection");
|
|
39412
39582
|
const budget = { entries: 0, bytes: 0 };
|
|
39413
|
-
|
|
39583
|
+
for (const root of excludedRoots)
|
|
39584
|
+
safe(root);
|
|
39585
|
+
return paths.map((path) => capture(path, budget, excludedRoots));
|
|
39414
39586
|
}
|
|
39415
|
-
function verifyDiscoveryDirectories(directories) {
|
|
39587
|
+
function verifyDiscoveryDirectories(directories, excludedRoots = []) {
|
|
39416
39588
|
need4(Array.isArray(directories) && directories.length <= AGENT_POLICY_LIMITS.discoveryDirectories, "Invalid native discovery directory collection");
|
|
39417
39589
|
for (const directory of directories)
|
|
39418
39590
|
need4(directory && typeof directory === "object" && (directory.sha256 === null || typeof directory.sha256 === "string" && /^[a-f0-9]{64}$/.test(directory.sha256)), "Invalid native discovery directory digest");
|
|
39419
|
-
const current = captureDiscoveryDirectories(directories.map((directory) => directory.path));
|
|
39591
|
+
const current = captureDiscoveryDirectories(directories.map((directory) => directory.path), excludedRoots);
|
|
39420
39592
|
for (let i = 0;i < directories.length; i++)
|
|
39421
39593
|
need4(current[i].sha256 === directories[i].sha256, `Native discovery directory membership changed; run skills hook install with a fresh discovery review: ${directories[i].path}`);
|
|
39422
39594
|
}
|
|
@@ -41503,8 +41675,16 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
41503
41675
|
throw new Error("Invalid native discovery binding");
|
|
41504
41676
|
if (binding.agent === "hermes" && !binding.directories?.length)
|
|
41505
41677
|
throw new Error("Hermes discovery requires directory membership coverage; run skills hook install with a fresh discovery review");
|
|
41506
|
-
|
|
41507
|
-
|
|
41678
|
+
const installationRoots = codexInstallationRoots(binding);
|
|
41679
|
+
const installationInput = (path) => installationRoots.some((root2) => path === root2 || path.startsWith(root2 + sep4));
|
|
41680
|
+
if (binding.directories !== undefined) {
|
|
41681
|
+
const projected2 = binding.codexInstallationInputs?.directories ?? [];
|
|
41682
|
+
const ancestors2 = binding.directories.filter((directory) => installationRoots.some((root2) => root2.startsWith(directory.path + sep4)));
|
|
41683
|
+
if (projected2.length !== ancestors2.length || projected2.some((directory) => !ancestors2.some((original) => original.path === directory.path)))
|
|
41684
|
+
throw new Error("Missing installation input directory projection");
|
|
41685
|
+
verifyDiscoveryDirectories(binding.directories.filter((directory) => !installationInput(directory.path) && !ancestors2.includes(directory)));
|
|
41686
|
+
verifyDiscoveryDirectories(projected2, installationRoots);
|
|
41687
|
+
}
|
|
41508
41688
|
const budget = discoveryByteBudget();
|
|
41509
41689
|
for (const source of binding.sources) {
|
|
41510
41690
|
assertMarketplaceBinding(binding, source);
|
|
@@ -41514,6 +41694,10 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
41514
41694
|
throw new Error("Invalid native discovery projection");
|
|
41515
41695
|
if (source.sha256 !== null && !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
41516
41696
|
throw new Error("Invalid native discovery digest");
|
|
41697
|
+
if (installationInput(source.path)) {
|
|
41698
|
+
safe4(source.path);
|
|
41699
|
+
continue;
|
|
41700
|
+
}
|
|
41517
41701
|
const current = projected(source, undefined, budget);
|
|
41518
41702
|
if (current !== source.sha256 && !verifiesCodexHookDiscoverySource(binding, source, current, codexRecovery))
|
|
41519
41703
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
@@ -41521,6 +41705,27 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
41521
41705
|
for (const root2 of binding.roots)
|
|
41522
41706
|
safe4(root2);
|
|
41523
41707
|
}
|
|
41708
|
+
function codexInstallationRoots(binding) {
|
|
41709
|
+
const proof = binding.codexInstallationInputs;
|
|
41710
|
+
if (proof === undefined)
|
|
41711
|
+
return [];
|
|
41712
|
+
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)
|
|
41713
|
+
throw new Error("Invalid native installation input proof");
|
|
41714
|
+
const cache = dirname14(dirname14(proof.plugins[0].pluginParent));
|
|
41715
|
+
const config = join21(dirname14(dirname14(cache)), "config.toml"), home = dirname14(dirname14(dirname14(cache)));
|
|
41716
|
+
const configSource = binding.sources.find((source) => source.path === config && source.sha256 !== null && (!source.format || source.format === "toml" && source.fields?.includes("plugins")));
|
|
41717
|
+
const nativeRoots = NATIVE_SKILL_ROOTS.filter(([agent]) => agent === "codex").map(([, path]) => join21(home, path));
|
|
41718
|
+
if (!configSource || proof.plugins.some((input) => nativeRoots.some((root2) => root2 === input.sourceRoot || root2.startsWith(input.sourceRoot + sep4) || input.sourceRoot.startsWith(root2 + sep4)) || binding.sources.some((source) => basename7(source.path) === "config.toml" && (source.path === input.sourceRoot || source.path.startsWith(input.sourceRoot + sep4)))))
|
|
41719
|
+
throw new Error("Native installation input overlaps configuration or loading roots");
|
|
41720
|
+
if (proof.plugins.some((input) => dirname14(dirname14(input.pluginParent)) !== cache || !binding.sources.some((source) => source.path === join21(input.sourceRoot, ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined)))
|
|
41721
|
+
throw new Error("Missing native installation input source witness");
|
|
41722
|
+
return reviewedCodexPluginSourceRoots(cache, proof.plugins, (path) => {
|
|
41723
|
+
const text2 = read2(path);
|
|
41724
|
+
if (text2 === null)
|
|
41725
|
+
throw new Error("Missing native installation input");
|
|
41726
|
+
return text2;
|
|
41727
|
+
});
|
|
41728
|
+
}
|
|
41524
41729
|
function assertMarketplaceBinding(binding, source) {
|
|
41525
41730
|
if ((source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2") && (binding.agent !== "codex" || binding.method !== "reviewed" || basename7(source.path) !== "config.toml"))
|
|
41526
41731
|
throw new Error("Codex settings witnesses require explicit reviewed Codex configuration");
|
|
@@ -41531,8 +41736,11 @@ function assertMarketplaceBinding(binding, source) {
|
|
|
41531
41736
|
}
|
|
41532
41737
|
function rebindAgentDiscovery(binding, changes) {
|
|
41533
41738
|
const budget = discoveryByteBudget();
|
|
41739
|
+
const installationRoots = codexInstallationRoots(binding);
|
|
41534
41740
|
return { ...binding, sources: binding.sources.map((source) => {
|
|
41535
41741
|
assertMarketplaceBinding(binding, source);
|
|
41742
|
+
if (!changes.has(source.path) && installationRoots.some((root2) => source.path.startsWith(root2 + sep4)))
|
|
41743
|
+
return source;
|
|
41536
41744
|
const sha2562 = projected(source, changes, budget);
|
|
41537
41745
|
if (!changes.has(source.path) && sha2562 !== source.sha256)
|
|
41538
41746
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
@@ -42140,10 +42348,75 @@ function disableCodexBundledSkills(text2) {
|
|
|
42140
42348
|
// src/lib/agent-integration.ts
|
|
42141
42349
|
var sha4 = (data) => createHash18("sha256").update(data).digest("hex");
|
|
42142
42350
|
var ROOTS = NATIVE_SKILL_ROOTS;
|
|
42351
|
+
function hasNoDarwinAcl(fd) {
|
|
42352
|
+
try {
|
|
42353
|
+
const { dlopen, read: read3 } = __require("bun:ffi");
|
|
42354
|
+
const library = dlopen("/usr/lib/libSystem.B.dylib", {
|
|
42355
|
+
acl_get_fd: { args: ["i32"], returns: "ptr" },
|
|
42356
|
+
acl_free: { args: ["ptr"], returns: "i32" },
|
|
42357
|
+
__error: { args: [], returns: "ptr" }
|
|
42358
|
+
});
|
|
42359
|
+
try {
|
|
42360
|
+
const errno = library.symbols.__error();
|
|
42361
|
+
if (!errno)
|
|
42362
|
+
return false;
|
|
42363
|
+
const acl = library.symbols.acl_get_fd(fd);
|
|
42364
|
+
if (acl) {
|
|
42365
|
+
library.symbols.acl_free(acl);
|
|
42366
|
+
return false;
|
|
42367
|
+
}
|
|
42368
|
+
return (acl === null || acl === 0) && read3.i32(errno) === 2;
|
|
42369
|
+
} finally {
|
|
42370
|
+
library.close();
|
|
42371
|
+
}
|
|
42372
|
+
} catch {
|
|
42373
|
+
return false;
|
|
42374
|
+
}
|
|
42375
|
+
}
|
|
42376
|
+
function isSystemRootAlias(path) {
|
|
42377
|
+
if (process.platform !== "darwin" || !["/var", "/tmp", "/etc"].includes(path))
|
|
42378
|
+
return false;
|
|
42379
|
+
const target = `/private${path}`, link = `private${path}`;
|
|
42380
|
+
const identity4 = (stat2) => `${stat2.dev}:${stat2.ino}:${stat2.ctimeNs}:${stat2.uid}:${stat2.mode}`;
|
|
42381
|
+
try {
|
|
42382
|
+
const before = lstatSync19(path, { bigint: true });
|
|
42383
|
+
if (!before.isSymbolicLink() || before.uid !== 0n || readlinkSync4(path) !== link)
|
|
42384
|
+
return false;
|
|
42385
|
+
const directories = ["/", "/private", target].map((directory) => {
|
|
42386
|
+
const stat2 = lstatSync19(directory, { bigint: true });
|
|
42387
|
+
if (!stat2.isDirectory() || stat2.uid !== 0n)
|
|
42388
|
+
throw new Error("Untrusted system alias directory");
|
|
42389
|
+
if (directory !== "/private/tmp") {
|
|
42390
|
+
if ((stat2.mode & 0o022n) !== 0n)
|
|
42391
|
+
throw new Error("Writable system alias directory");
|
|
42392
|
+
} else if ((stat2.mode & 0o1000n) === 0n)
|
|
42393
|
+
throw new Error("Unprotected system temporary directory");
|
|
42394
|
+
const fd = openSync16(directory, constants12.O_RDONLY | constants12.O_DIRECTORY | constants12.O_NOFOLLOW);
|
|
42395
|
+
try {
|
|
42396
|
+
if (identity4(fstatSync16(fd, { bigint: true })) !== identity4(stat2) || !hasNoDarwinAcl(fd) || identity4(fstatSync16(fd, { bigint: true })) !== identity4(stat2))
|
|
42397
|
+
throw new Error("Unverified system alias directory ACL");
|
|
42398
|
+
} finally {
|
|
42399
|
+
closeSync16(fd);
|
|
42400
|
+
}
|
|
42401
|
+
return { directory, identity: identity4(stat2) };
|
|
42402
|
+
});
|
|
42403
|
+
return realpathSync7(path) === target && readlinkSync4(path) === link && identity4(lstatSync19(path, { bigint: true })) === identity4(before) && directories.every((item) => identity4(lstatSync19(item.directory, { bigint: true })) === item.identity);
|
|
42404
|
+
} catch {
|
|
42405
|
+
return false;
|
|
42406
|
+
}
|
|
42407
|
+
}
|
|
42408
|
+
function canonicalSystemPath(path) {
|
|
42409
|
+
const absolute = resolve15(path), root2 = `/${absolute.split(sep5)[1]}`;
|
|
42410
|
+
if (process.platform !== "darwin" || !["/var", "/tmp", "/etc"].includes(root2) || !lstatSync19(root2, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
42411
|
+
return absolute;
|
|
42412
|
+
if (!isSystemRootAlias(root2))
|
|
42413
|
+
throw new Error(`Refusing symlink path: ${root2}`);
|
|
42414
|
+
return `/private${absolute}`;
|
|
42415
|
+
}
|
|
42143
42416
|
function assertSafePath(path) {
|
|
42144
42417
|
let cursor = resolve15(path);
|
|
42145
42418
|
while (true) {
|
|
42146
|
-
if (lstatSync19(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
42419
|
+
if (lstatSync19(cursor, { throwIfNoEntry: false })?.isSymbolicLink() && !isSystemRootAlias(cursor))
|
|
42147
42420
|
throw new Error(`Refusing symlink path: ${cursor}`);
|
|
42148
42421
|
const parent = dirname15(cursor);
|
|
42149
42422
|
if (parent === cursor)
|
|
@@ -42179,7 +42452,7 @@ function rootAliases(home, allowed = false) {
|
|
|
42179
42452
|
return result;
|
|
42180
42453
|
}
|
|
42181
42454
|
function canonicalAgentPath(path, aliases) {
|
|
42182
|
-
const absolute =
|
|
42455
|
+
const absolute = canonicalSystemPath(path), binding = aliases.find((item) => absolute === item.alias || absolute.startsWith(item.alias + sep5));
|
|
42183
42456
|
return binding ? join22(binding.target, relative4(binding.alias, absolute)) : absolute;
|
|
42184
42457
|
}
|
|
42185
42458
|
function disabledCodexSkillPaths(config, aliases) {
|
|
@@ -42277,17 +42550,19 @@ function selectNativeMigrationTargets(inventory, manifest) {
|
|
|
42277
42550
|
const identities = new Set;
|
|
42278
42551
|
const selected = [];
|
|
42279
42552
|
for (const target of manifest.targets) {
|
|
42280
|
-
|
|
42281
|
-
|
|
42553
|
+
if (!isAbsolute17(target.projectRoot) || resolve15(target.projectRoot) !== target.projectRoot)
|
|
42554
|
+
throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
|
|
42555
|
+
const projectRoot = canonicalSystemPath(target.projectRoot), normalized = relative4(projectRoot, resolve15(projectRoot, target.path));
|
|
42556
|
+
if (!existsSync6(projectRoot) || !lstatSync19(projectRoot).isDirectory())
|
|
42282
42557
|
throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
|
|
42283
42558
|
assertSafePath(projectRoot);
|
|
42284
42559
|
if (isAbsolute17(target.path) || target.path.includes("\\") || target.path.includes("\x00") || !normalized || normalized === ".." || normalized.startsWith(`..${sep5}`) || normalized !== target.path || !/^[0-9a-f]{64}$/.test(target.treeSha256))
|
|
42285
42560
|
throw new Error(`Invalid native migration target: ${target.path}`);
|
|
42286
|
-
const identity4 = `${target.agent}\x00${projectRoot}\x00${normalized}`;
|
|
42561
|
+
const identity4 = `${target.agent}\x00${canonicalSystemPath(projectRoot)}\x00${normalized}`;
|
|
42287
42562
|
if (identities.has(identity4))
|
|
42288
42563
|
throw new Error(`Duplicate native migration target: ${target.path}`);
|
|
42289
42564
|
identities.add(identity4);
|
|
42290
|
-
const expected = resolve15(target.projectRoot, target.path);
|
|
42565
|
+
const expected = canonicalSystemPath(resolve15(target.projectRoot, target.path));
|
|
42291
42566
|
const matches = inventory.filter((entry2) => entry2.agent === target.agent && resolve15(entry2.path) === expected);
|
|
42292
42567
|
if (matches.length !== 1)
|
|
42293
42568
|
throw new Error(`Native migration target was not found exactly once: ${target.agent} ${target.projectRoot}/${target.path}`);
|
|
@@ -42303,7 +42578,7 @@ function selectNativeMigrationTargets(inventory, manifest) {
|
|
|
42303
42578
|
function projectAncestorDirectories(projects) {
|
|
42304
42579
|
const directories = new Set;
|
|
42305
42580
|
for (const project of projects) {
|
|
42306
|
-
for (let path =
|
|
42581
|
+
for (let path = canonicalSystemPath(project), depth = 0;; depth++) {
|
|
42307
42582
|
if (depth >= 100)
|
|
42308
42583
|
throw new Error("NATIVE_SKILL_DRIFT: project ancestor discovery limit exceeded");
|
|
42309
42584
|
directories.add(path);
|
|
@@ -42316,11 +42591,13 @@ function projectAncestorDirectories(projects) {
|
|
|
42316
42591
|
return [...directories];
|
|
42317
42592
|
}
|
|
42318
42593
|
function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
42594
|
+
home = canonicalSystemPath(home);
|
|
42319
42595
|
if (options.reviewedCacheAlias !== undefined && (!options.includeVendor || !isAbsolute17(options.reviewedCacheAlias) || resolve15(options.reviewedCacheAlias) !== options.reviewedCacheAlias))
|
|
42320
42596
|
throw new Error("A reviewed cache alias requires vendor inventory and an exact absolute path");
|
|
42321
42597
|
if (options.disabledVendorPaths?.some((path) => !isAbsolute17(path) || resolve15(path) !== path))
|
|
42322
42598
|
throw new Error("Disabled vendor paths must be exact absolute paths");
|
|
42323
|
-
const
|
|
42599
|
+
const reviewedCacheAlias = options.reviewedCacheAlias === undefined ? undefined : canonicalSystemPath(options.reviewedCacheAlias);
|
|
42600
|
+
const disabledVendorPaths = new Set((options.disabledVendorPaths ?? []).map(canonicalSystemPath));
|
|
42324
42601
|
const aliases = rootAliases(home, options.allowRootAliases);
|
|
42325
42602
|
const selectedAgents = options.agents ? new Set(options.agents) : undefined;
|
|
42326
42603
|
const includesAgent = (agent) => !selectedAgents || selectedAgents.has(agent);
|
|
@@ -42331,6 +42608,9 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
42331
42608
|
for (const [agent, path] of rootDefinitions)
|
|
42332
42609
|
roots.push([agent, canonicalAgentPath(join22(project, path), aliases)]);
|
|
42333
42610
|
}
|
|
42611
|
+
const installationInputs = options.codexInstallationInputRoots ?? [];
|
|
42612
|
+
if (installationInputs.some((input) => resolve15(input) !== input || realpathSync7(input) !== input || roots.some(([agent, path]) => agent === "codex" && (path === input || path.startsWith(input + sep5) || input.startsWith(path + sep5)))))
|
|
42613
|
+
throw new Error("Native installation input overlaps an unconditional skill-loading root");
|
|
42334
42614
|
const entries = [], seen = new Set;
|
|
42335
42615
|
const cacheScans = new Map, maxAliasProofEntries = 1e4;
|
|
42336
42616
|
let discoveryEntries = 0, discoveryPathBytes = 0;
|
|
@@ -42343,8 +42623,11 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
42343
42623
|
}
|
|
42344
42624
|
let reviewedCacheAliasFound = false;
|
|
42345
42625
|
function verifiedSiblingCacheAlias(agent, path, parent) {
|
|
42346
|
-
const link = readlinkSync4(path),
|
|
42347
|
-
if (
|
|
42626
|
+
const link = readlinkSync4(path), lexicalTarget = resolve15(parent, link);
|
|
42627
|
+
if (isAbsolute17(link) ? link !== lexicalTarget : dirname15(link) !== ".")
|
|
42628
|
+
return false;
|
|
42629
|
+
const target = canonicalSystemPath(lexicalTarget);
|
|
42630
|
+
if (dirname15(target) !== parent)
|
|
42348
42631
|
return false;
|
|
42349
42632
|
if (!lstatSync19(target, { throwIfNoEntry: false })?.isDirectory())
|
|
42350
42633
|
return false;
|
|
@@ -42353,20 +42636,22 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
42353
42636
|
return false;
|
|
42354
42637
|
if (scan.hasSkills) {
|
|
42355
42638
|
const targetSkills = entries.filter((entry) => entry.agent === agent && entry.vendor && (entry.path === target || entry.path.startsWith(target + sep5)));
|
|
42356
|
-
if (path ===
|
|
42639
|
+
if (path === reviewedCacheAlias && targetSkills.length > 0)
|
|
42357
42640
|
reviewedCacheAliasFound = true;
|
|
42358
42641
|
if (agent === "codex" && targetSkills.length > 0 && targetSkills.every((entry) => disabledVendorPaths.has(entry.path) || options.disabledVendorSkill?.(entry) === true))
|
|
42359
42642
|
return true;
|
|
42360
|
-
if (path !==
|
|
42643
|
+
if (path !== reviewedCacheAlias)
|
|
42361
42644
|
return false;
|
|
42362
42645
|
}
|
|
42363
42646
|
return true;
|
|
42364
42647
|
}
|
|
42365
|
-
function visit2(agent, path, vendor = false, depth = 0, pluginCache = false, admitted = false) {
|
|
42648
|
+
function visit2(agent, path, vendor = false, depth = 0, pluginCache = false, admitted = false, configuredRoot = false) {
|
|
42366
42649
|
if (!admitted)
|
|
42367
42650
|
admit(path);
|
|
42368
42651
|
const scan = { complete: true, hasSkills: false, entries: 1 };
|
|
42369
42652
|
assertSafePath(path);
|
|
42653
|
+
if (configuredRoot && agent === "codex" && installationInputs.includes(path))
|
|
42654
|
+
return scan;
|
|
42370
42655
|
if (!existsSync6(path))
|
|
42371
42656
|
return scan;
|
|
42372
42657
|
const stat2 = lstatSync19(path);
|
|
@@ -42422,7 +42707,7 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
42422
42707
|
continue;
|
|
42423
42708
|
}
|
|
42424
42709
|
}
|
|
42425
|
-
const childScan = visit2(agent, child, isVendor, depth + 1, pluginCache, true);
|
|
42710
|
+
const childScan = visit2(agent, child, isVendor, depth + 1, pluginCache, true, configuredRoot);
|
|
42426
42711
|
scan.complete &&= childScan.complete;
|
|
42427
42712
|
scan.hasSkills ||= childScan.hasSkills;
|
|
42428
42713
|
scan.entries += childScan.entries;
|
|
@@ -42431,10 +42716,10 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
42431
42716
|
cacheScans.set(path, scan);
|
|
42432
42717
|
return scan;
|
|
42433
42718
|
}
|
|
42434
|
-
function scanRoot(agent, path, vendor = false, pluginCache = false) {
|
|
42719
|
+
function scanRoot(agent, path, vendor = false, pluginCache = false, configuredRoot = false) {
|
|
42435
42720
|
if (agent === "hermes" || options.guardHermes && `${path}${sep5}`.includes(`${sep5}.agents${sep5}skills${sep5}`))
|
|
42436
42721
|
assertNoHermesLegacyShadow(path);
|
|
42437
|
-
if (!visit2(agent, path, vendor, 0, pluginCache).complete)
|
|
42722
|
+
if (!visit2(agent, path, vendor, 0, pluginCache, false, configuredRoot).complete)
|
|
42438
42723
|
throw new Error(`Native skill discovery limit exceeded; review this root before continuing: ${path}`);
|
|
42439
42724
|
}
|
|
42440
42725
|
for (const [agent, path] of roots)
|
|
@@ -42450,7 +42735,7 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
42450
42735
|
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 }))) : [];
|
|
42451
42736
|
for (const root2 of [...options.agentRoots ?? [], ...configured])
|
|
42452
42737
|
if (includesAgent(root2.agent))
|
|
42453
|
-
scanRoot(root2.agent, canonicalAgentPath(root2.path, aliases), true);
|
|
42738
|
+
scanRoot(root2.agent, canonicalAgentPath(root2.path, aliases), true, false, true);
|
|
42454
42739
|
if (options.reviewedCacheAlias !== undefined && !reviewedCacheAliasFound)
|
|
42455
42740
|
throw new Error("Reviewed cache alias was not an inventoried skill-containing sibling alias");
|
|
42456
42741
|
recheckRootAliases(aliases);
|
|
@@ -42590,6 +42875,11 @@ enabled = false
|
|
|
42590
42875
|
Bun.TOML.parse(result);
|
|
42591
42876
|
return result;
|
|
42592
42877
|
}
|
|
42878
|
+
function assertCodexInstallationInputs(home, projectDirs, inputs) {
|
|
42879
|
+
const nativeRoots = [home, ...projectAncestorDirectories(projectDirs)].flatMap((directory) => ROOTS.filter(([agent]) => agent === "codex").map(([, path]) => resolve15(directory, path)));
|
|
42880
|
+
if (inputs.some((input) => nativeRoots.some((root2) => root2 === input || root2.startsWith(input + sep5) || input.startsWith(root2 + sep5))))
|
|
42881
|
+
throw new Error("Native installation input overlaps an unconditional skill-loading root");
|
|
42882
|
+
}
|
|
42593
42883
|
function planAgentIntegration(options) {
|
|
42594
42884
|
const home = options.home ?? homedir3(), dataDir2 = options.dataDir ?? getDataDirReadOnly();
|
|
42595
42885
|
const aliases = rootAliases(home, options.allowRootAliases);
|
|
@@ -42628,11 +42918,16 @@ function planAgentIntegration(options) {
|
|
|
42628
42918
|
const codexConfig = options.agents.includes("codex") ? Bun.TOML.parse(readOptional(canonicalAgentPath(join22(home, ".codex", "config.toml"), aliases)) ?? "") : {};
|
|
42629
42919
|
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) });
|
|
42630
42920
|
const observedNativeSources = [];
|
|
42631
|
-
const
|
|
42921
|
+
const codexPluginControls = options.codexNativeCatalog ? reviewCodexPluginControls(options.codexNativeCatalog, nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor).map((entry) => join22(entry.path, "SKILL.md")), canonicalAgentPath(join22(home, ".codex/plugins/cache"), aliases), resolve15(options.projectDir ?? home), (path) => {
|
|
42632
42922
|
const bytes = readNativeBytes(path, 1024 * 1024);
|
|
42633
42923
|
observedNativeSources.push({ path, sha256: sha4(bytes) });
|
|
42634
42924
|
return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
42635
|
-
}, codexConfig.skills?.config ?? []) : policy.bridge?.codexPluginSkills ?? [];
|
|
42925
|
+
}, codexConfig.skills?.config ?? [], codexConfig.plugins) : { skills: policy.bridge?.codexPluginSkills ?? [], inactivePlugins: policy.bridge?.codexInactivePlugins ?? [], sourceInputs: policy.bridge?.discovery?.codex?.codexInstallationInputs?.plugins ?? [] };
|
|
42926
|
+
const codexPluginSkills = codexPluginControls.skills;
|
|
42927
|
+
const codexInactivePlugins = codexPluginControls.inactivePlugins;
|
|
42928
|
+
const codexDiscovery = discoveries.find((binding) => binding.agent === "codex");
|
|
42929
|
+
const codexPluginSourceInputs = codexPluginControls.sourceInputs.filter((input) => codexDiscovery?.method === "reviewed" && codexDiscovery.roots.some((root2) => root2 === input.sourceRoot || root2.startsWith(input.sourceRoot + sep5) || input.sourceRoot.startsWith(root2 + sep5)) && codexDiscovery.sources.some((source) => source.path === join22(input.sourceRoot, ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined));
|
|
42930
|
+
assertCodexInstallationInputs(home, [options.projectDir ?? home], codexPluginSourceInputs.map((input) => input.sourceRoot));
|
|
42636
42931
|
const changes = [];
|
|
42637
42932
|
for (const agent of [...new Set(options.agents)]) {
|
|
42638
42933
|
if (!INTEGRATION_AGENTS.includes(agent))
|
|
@@ -42697,7 +42992,16 @@ function planAgentIntegration(options) {
|
|
|
42697
42992
|
changes.push({ path: configPath, before: previous, after: next });
|
|
42698
42993
|
}
|
|
42699
42994
|
}
|
|
42700
|
-
const
|
|
42995
|
+
const codexPluginSkillReview = options.codexNativeCatalog ? { version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, catalogSha256: sha4(JSON.stringify({ version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, skills: projectCodexNativeSkillCatalog({ data: [{ cwd: options.codexNativeCatalog.cwd, errors: [], skills: options.codexNativeCatalog.skills }] }, options.codexNativeCatalog.cwd), ...options.codexNativeCatalog.plugins === undefined ? {} : { plugins: projectCodexInstalledPluginEntries(options.codexNativeCatalog.plugins) } })), configSha256: changes.find((change) => change.path === canonicalAgentPath(join22(home, ".codex/config.toml"), aliases))?.before === null ? null : sha4(readOptional(canonicalAgentPath(join22(home, ".codex/config.toml"), aliases)) ?? "") } : policy.bridge?.codexPluginSkillReview;
|
|
42996
|
+
const discoveryAfter = discoveries.map((binding) => {
|
|
42997
|
+
const rebound = rebindAgentDiscovery(binding, new Map(changes.map((change) => [change.path, change.after])));
|
|
42998
|
+
if (binding.agent !== "codex")
|
|
42999
|
+
return rebound;
|
|
43000
|
+
const { codexInstallationInputs: previousInputs, ...current } = rebound;
|
|
43001
|
+
const inputs = codexPluginSourceInputs.map((input) => input.sourceRoot);
|
|
43002
|
+
const directories = options.codexNativeCatalog || !previousInputs ? captureDiscoveryDirectories((binding.directories ?? []).filter((directory) => inputs.some((root2) => root2.startsWith(directory.path + sep5))).map((directory) => directory.path), inputs) : previousInputs.directories;
|
|
43003
|
+
return codexPluginSourceInputs.length ? { ...current, codexInstallationInputs: { version: "codex-cli 0.160.0", catalogSha256: codexPluginSkillReview.catalogSha256, plugins: codexPluginSourceInputs, ...directories?.length ? { directories } : {} } } : current;
|
|
43004
|
+
});
|
|
42701
43005
|
const nextPolicy = { ...policy, version: 1, loading: "cli", profileId, bridge: {
|
|
42702
43006
|
...policy.bridge,
|
|
42703
43007
|
version: CLI_BRIDGE_VERSION,
|
|
@@ -42710,7 +43014,7 @@ function planAgentIntegration(options) {
|
|
|
42710
43014
|
profiles: Object.fromEntries([...new Set([...priorAgents, ...options.agents])].sort().map((agent) => [agent, bindings.get(agent)?.profileId ?? policy.bridge?.profiles?.[agent] ?? policy.profileId])),
|
|
42711
43015
|
disabledBuiltins: options.agents.includes("codex") ? nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor && entry.path.startsWith(canonicalAgentPath(join22(home, ".codex", "skills", ".system"), aliases) + sep5)).map((entry) => ({ path: entry.path, hash: entry.hash })) : policy.bridge?.disabledBuiltins ?? [],
|
|
42712
43016
|
rootAliases: aliases,
|
|
42713
|
-
...
|
|
43017
|
+
...options.codexNativeCatalog || codexPluginSkills.length || codexInactivePlugins.length || codexPluginSourceInputs.length ? { codexPluginSkills, codexInactivePlugins, codexPluginSkillReview } : {},
|
|
42714
43018
|
discovery: { ...policy.bridge?.discovery, ...Object.fromEntries(discoveryAfter.map((binding) => [binding.agent, binding])) }
|
|
42715
43019
|
} };
|
|
42716
43020
|
const serializedPolicy = serializeManagedSkillPolicy(nextPolicy);
|
|
@@ -43201,7 +43505,12 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
|
|
|
43201
43505
|
throw new Error("NATIVE_SKILL_DRIFT: the Codex CLI bridge is disabled; run skills hook install");
|
|
43202
43506
|
if (agent === "codex" && !reviewedCodexPluginCapabilitiesUnchanged(canonicalAgentPath(join22(home, ".codex/plugins/cache"), aliases), binding.codexPluginSkills ?? [], (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024))))
|
|
43203
43507
|
throw new Error("NATIVE_SKILL_DRIFT: reviewed native plugin capability controls changed; run skills hook install with a fresh discovery review");
|
|
43204
|
-
const disabledPlugin = (entry) =>
|
|
43508
|
+
const disabledPlugin = (entry) => {
|
|
43509
|
+
if (agent !== "codex" || !entry.vendor)
|
|
43510
|
+
return false;
|
|
43511
|
+
const document2 = join22(entry.path, "SKILL.md"), cache = canonicalAgentPath(join22(home, ".codex/plugins/cache"), aliases), read3 = (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024));
|
|
43512
|
+
return isReviewedCodexPluginInactive(document2, cache, binding.codexInactivePlugins ?? [], codexConfig.plugins, codexConfig.skills?.config ?? [], read3) || isReviewedCodexPluginSkillDisabled(document2, cache, binding.codexPluginSkills ?? [], codexConfig.skills?.config, read3);
|
|
43513
|
+
};
|
|
43205
43514
|
const disabledPaths = new Set(disabledCodexSkillPaths(codexConfig, aliases));
|
|
43206
43515
|
const disabledVendorSkill = (entry) => {
|
|
43207
43516
|
if (agent !== "codex" || !entry.vendor)
|
|
@@ -43238,7 +43547,15 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
|
|
|
43238
43547
|
} catch (error) {
|
|
43239
43548
|
throw new Error(`NATIVE_SKILL_DRIFT: ${error.message}`);
|
|
43240
43549
|
}
|
|
43241
|
-
|
|
43550
|
+
let installationInputRoots = [];
|
|
43551
|
+
if (agent === "codex") {
|
|
43552
|
+
try {
|
|
43553
|
+
installationInputRoots = reviewedCodexPluginSourceRoots(canonicalAgentPath(join22(home, ".codex/plugins/cache"), aliases), discovery.codexInstallationInputs?.plugins ?? [], (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024)));
|
|
43554
|
+
} catch {
|
|
43555
|
+
throw new Error("NATIVE_SKILL_DRIFT: native installation input identity changed; review discovery and catalog");
|
|
43556
|
+
}
|
|
43557
|
+
}
|
|
43558
|
+
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 });
|
|
43242
43559
|
const unexpected = inventory.filter((entry) => visible(entry) && !entry.bridge && !disabledVendorSkill(entry));
|
|
43243
43560
|
if (unexpected.length) {
|
|
43244
43561
|
const paths = unexpected.slice(0, 3).map((entry) => {
|