@hasna/skills 0.10.24 → 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 +11 -0
- package/bin/index.js +248 -35
- 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 +245 -35
- 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 +245 -35
- package/package.json +1 -1
|
@@ -9,10 +9,37 @@ export interface CodexPluginSkillControl {
|
|
|
9
9
|
mcpSha256?: string;
|
|
10
10
|
remotePluginId?: string;
|
|
11
11
|
}
|
|
12
|
+
/** A native nonremote installation disabled by the witnessed configuration.
|
|
13
|
+
* Its cache is inert; this makes no claim about reviewed hook capabilities. */
|
|
14
|
+
export interface CodexInactivePluginControl {
|
|
15
|
+
pluginId: string;
|
|
16
|
+
namespace: string;
|
|
17
|
+
pluginParent: string;
|
|
18
|
+
sourceType: "local" | "git" | "npm";
|
|
19
|
+
sourceSha256: string;
|
|
20
|
+
}
|
|
21
|
+
export interface CodexPluginSourceInput {
|
|
22
|
+
pluginId: string;
|
|
23
|
+
namespace: string;
|
|
24
|
+
pluginParent: string;
|
|
25
|
+
sourceRoot: string;
|
|
26
|
+
sourceSha256: string;
|
|
27
|
+
}
|
|
12
28
|
type Read = (path: string) => string;
|
|
13
29
|
/** Capability controls remain bound even after every native Skill body disappears. */
|
|
14
30
|
export declare function reviewedCodexPluginCapabilitiesUnchanged(cache: string, controls: CodexPluginSkillControl[], read: Read): boolean;
|
|
15
|
-
export declare function
|
|
31
|
+
export declare function reviewCodexPluginControls(catalog: CodexNativeSkillCatalog, documents: string[], cache: string, cwd: string, read: Read, rules: unknown, pluginSettings?: unknown): {
|
|
32
|
+
skills: CodexPluginSkillControl[];
|
|
33
|
+
inactivePlugins: CodexInactivePluginControl[];
|
|
34
|
+
sourceInputs: CodexPluginSourceInput[];
|
|
35
|
+
};
|
|
36
|
+
/** Validate installation-input roles before omitting them from runtime inventory.
|
|
37
|
+
* Discovery witnesses still cover the sources; migration inventory stays full. */
|
|
38
|
+
export declare function reviewedCodexPluginSourceRoots(cache: string, inputs: CodexPluginSourceInput[], read: Read): string[];
|
|
39
|
+
export declare function reviewCodexPluginSkillControls(catalog: CodexNativeSkillCatalog, documents: string[], cache: string, cwd: string, read: Read, rules: unknown, pluginSettings?: unknown): CodexPluginSkillControl[];
|
|
40
|
+
/** Cache refresh cannot reactivate a config-controlled disabled installation.
|
|
41
|
+
* The caller verifies discovery/config witnesses before consuming this result. */
|
|
42
|
+
export declare function isReviewedCodexPluginInactive(document: string, cache: string, controls: CodexInactivePluginControl[], pluginSettings: unknown, rules: unknown, read: Read): boolean;
|
|
16
43
|
export declare function isReviewedCodexPluginSkillDisabled(document: string, cache: string, controls: CodexPluginSkillControl[], rules: unknown, read: Read): boolean;
|
|
17
44
|
export declare function disableReviewedCodexPluginNames(text: string, controls: CodexPluginSkillControl[]): string;
|
|
18
45
|
export {};
|
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
|
});
|
|
@@ -38451,7 +38469,7 @@ function rootControls(root, read) {
|
|
|
38451
38469
|
const appSha256 = present ? appControls(app, read) : undefined;
|
|
38452
38470
|
return { namespace: manifest.name, manifestSha256, ...appSha256 ? { appSha256 } : {}, ...mcpSha256 ? { mcpSha256 } : {} };
|
|
38453
38471
|
}
|
|
38454
|
-
function
|
|
38472
|
+
function documentIdentity(document, cache, read) {
|
|
38455
38473
|
if (!document.startsWith(cache + sep2) || !document.endsWith(sep2 + "SKILL.md"))
|
|
38456
38474
|
refuse3();
|
|
38457
38475
|
const text = read(document);
|
|
@@ -38479,11 +38497,33 @@ function identity(document, cache, read) {
|
|
|
38479
38497
|
const path = join10(root, ".codex-plugin", "plugin.json");
|
|
38480
38498
|
if (!lstatSync6(path, { throwIfNoEntry: false }))
|
|
38481
38499
|
continue;
|
|
38482
|
-
const
|
|
38483
|
-
|
|
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 };
|
|
38484
38517
|
}
|
|
38485
38518
|
refuse3();
|
|
38486
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
|
+
}
|
|
38487
38527
|
function reviewedCodexPluginCapabilitiesUnchanged(cache, controls, read) {
|
|
38488
38528
|
if (!Array.isArray(controls) || controls.length > 4096)
|
|
38489
38529
|
return false;
|
|
@@ -38521,11 +38561,13 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache, controls, read) {
|
|
|
38521
38561
|
return false;
|
|
38522
38562
|
}
|
|
38523
38563
|
}
|
|
38524
|
-
function
|
|
38564
|
+
function reviewCodexPluginControls(catalog, documents, cache, cwd, read, rules, pluginSettings) {
|
|
38525
38565
|
if (!supportsCodexNativeCapability(catalog?.version, "qualified-skill-catalog") || catalog.cwd !== cwd)
|
|
38526
38566
|
refuse3();
|
|
38527
38567
|
const skills = projectCodexNativeSkillCatalog({ data: [{ cwd, errors: [], skills: catalog.skills }] }, cwd);
|
|
38528
|
-
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;
|
|
38529
38571
|
let installedPlugins;
|
|
38530
38572
|
try {
|
|
38531
38573
|
installedPlugins = projectCodexInstalledPluginEntries(catalog.plugins ?? []);
|
|
@@ -38536,25 +38578,48 @@ function reviewCodexPluginSkillControls(catalog, documents, cache, cwd, read, ru
|
|
|
38536
38578
|
for (const document of candidates) {
|
|
38537
38579
|
if (!document.startsWith(cache + sep2))
|
|
38538
38580
|
continue;
|
|
38539
|
-
const
|
|
38540
|
-
if (
|
|
38581
|
+
const located = documentIdentity(document, cache, read);
|
|
38582
|
+
if (located.name === "skills-cli" || located.name.endsWith(":skills-cli"))
|
|
38541
38583
|
refuse3();
|
|
38542
|
-
const cacheParts = relative3(cache,
|
|
38584
|
+
const cacheParts = relative3(cache, located.pluginParent).split(sep2);
|
|
38543
38585
|
if (cacheParts.length !== 2 || cacheParts.some((part) => !identifier3(part)))
|
|
38544
38586
|
refuse3();
|
|
38545
38587
|
const [marketplace, pluginName] = cacheParts;
|
|
38546
|
-
if (pluginName !==
|
|
38588
|
+
if (pluginName !== located.namespace)
|
|
38547
38589
|
refuse3();
|
|
38548
38590
|
const expectedPluginId = `${pluginName}@${marketplace}`;
|
|
38549
38591
|
const listed = skills.filter((skill) => skill.path === document);
|
|
38550
38592
|
if (listed.length > 1)
|
|
38551
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();
|
|
38552
38618
|
let remotePluginId;
|
|
38553
38619
|
if (listed.length === 1) {
|
|
38554
38620
|
if (listed[0].name !== parsed.name || listed[0].pluginId !== expectedPluginId)
|
|
38555
38621
|
refuse3();
|
|
38556
38622
|
} else {
|
|
38557
|
-
const installed = installedPlugins.filter((plugin2) => plugin2.id === expectedPluginId && plugin2.name === pluginName);
|
|
38558
38623
|
if (installed.length !== 1 || !installed[0].installed || !installed[0].enabled)
|
|
38559
38624
|
refuse3();
|
|
38560
38625
|
const plugin = installed[0];
|
|
@@ -38572,9 +38637,48 @@ function reviewCodexPluginSkillControls(catalog, documents, cache, cwd, read, ru
|
|
|
38572
38637
|
}
|
|
38573
38638
|
result.push({ ...parsed, pluginId: expectedPluginId, ...remotePluginId ? { remotePluginId } : {} });
|
|
38574
38639
|
}
|
|
38575
|
-
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)
|
|
38576
38641
|
refuse3();
|
|
38577
|
-
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
|
+
}
|
|
38578
38682
|
}
|
|
38579
38683
|
function isReviewedCodexPluginSkillDisabled(document, cache, controls, rules, read) {
|
|
38580
38684
|
if (!document.startsWith(cache + sep2) || !Array.isArray(controls) || controls.length > 4096)
|
|
@@ -38950,6 +39054,18 @@ function assertAgentPolicyCollections(policy) {
|
|
|
38950
39054
|
if (control.appSha256 !== undefined)
|
|
38951
39055
|
requireBound(typeof control.appSha256 === "string" && /^[a-f0-9]{64}$/.test(control.appSha256));
|
|
38952
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
|
+
}
|
|
38953
39069
|
if (bridge.disabledBuiltins !== undefined)
|
|
38954
39070
|
for (const builtin of array(bridge.disabledBuiltins, AGENT_POLICY_LIMITS.builtinNames)) {
|
|
38955
39071
|
requireBound(object3(builtin));
|
|
@@ -38962,6 +39078,25 @@ function assertAgentPolicyCollections(policy) {
|
|
|
38962
39078
|
text(agent, 128);
|
|
38963
39079
|
requireBound(object3(value));
|
|
38964
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
|
+
}
|
|
38965
39100
|
for (const root of array(value.roots, AGENT_POLICY_LIMITS.discoveryRoots))
|
|
38966
39101
|
text(root);
|
|
38967
39102
|
for (const source of array(value.sources, AGENT_POLICY_LIMITS.discoverySources)) {
|
|
@@ -39404,7 +39539,7 @@ function safe(path) {
|
|
|
39404
39539
|
function same(before, after) {
|
|
39405
39540
|
return Boolean(after && after.isDirectory() && before.dev === after.dev && before.ino === after.ino && before.mtimeMs === after.mtimeMs && before.ctimeMs === after.ctimeMs);
|
|
39406
39541
|
}
|
|
39407
|
-
function capture(path, budget) {
|
|
39542
|
+
function capture(path, budget, excludedRoots) {
|
|
39408
39543
|
safe(path);
|
|
39409
39544
|
const root = lstatSync10(path, { throwIfNoEntry: false });
|
|
39410
39545
|
if (!root)
|
|
@@ -39433,7 +39568,7 @@ function capture(path, budget) {
|
|
|
39433
39568
|
budget.bytes += Buffer.byteLength(row);
|
|
39434
39569
|
need4(budget.bytes <= AGENT_POLICY_LIMITS.discoveryDirectoryBytes, "Native discovery directory metadata limit exceeded");
|
|
39435
39570
|
hash2.update(row);
|
|
39436
|
-
if (stat.isDirectory())
|
|
39571
|
+
if (stat.isDirectory() && !excludedRoots.includes(child))
|
|
39437
39572
|
walk2(child, childRelative, stat, depth + 1);
|
|
39438
39573
|
}
|
|
39439
39574
|
need4(same(before, lstatSync10(current, { throwIfNoEntry: false })), "Native discovery directory changed while reading");
|
|
@@ -39442,16 +39577,18 @@ function capture(path, budget) {
|
|
|
39442
39577
|
safe(path);
|
|
39443
39578
|
return { path, sha256: hash2.digest("hex") };
|
|
39444
39579
|
}
|
|
39445
|
-
function captureDiscoveryDirectories(paths) {
|
|
39580
|
+
function captureDiscoveryDirectories(paths, excludedRoots = []) {
|
|
39446
39581
|
need4(Array.isArray(paths) && paths.length <= AGENT_POLICY_LIMITS.discoveryDirectories && new Set(paths).size === paths.length, "Invalid native discovery directory collection");
|
|
39447
39582
|
const budget = { entries: 0, bytes: 0 };
|
|
39448
|
-
|
|
39583
|
+
for (const root of excludedRoots)
|
|
39584
|
+
safe(root);
|
|
39585
|
+
return paths.map((path) => capture(path, budget, excludedRoots));
|
|
39449
39586
|
}
|
|
39450
|
-
function verifyDiscoveryDirectories(directories) {
|
|
39587
|
+
function verifyDiscoveryDirectories(directories, excludedRoots = []) {
|
|
39451
39588
|
need4(Array.isArray(directories) && directories.length <= AGENT_POLICY_LIMITS.discoveryDirectories, "Invalid native discovery directory collection");
|
|
39452
39589
|
for (const directory of directories)
|
|
39453
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");
|
|
39454
|
-
const current = captureDiscoveryDirectories(directories.map((directory) => directory.path));
|
|
39591
|
+
const current = captureDiscoveryDirectories(directories.map((directory) => directory.path), excludedRoots);
|
|
39455
39592
|
for (let i = 0;i < directories.length; i++)
|
|
39456
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}`);
|
|
39457
39594
|
}
|
|
@@ -41538,8 +41675,16 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
41538
41675
|
throw new Error("Invalid native discovery binding");
|
|
41539
41676
|
if (binding.agent === "hermes" && !binding.directories?.length)
|
|
41540
41677
|
throw new Error("Hermes discovery requires directory membership coverage; run skills hook install with a fresh discovery review");
|
|
41541
|
-
|
|
41542
|
-
|
|
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
|
+
}
|
|
41543
41688
|
const budget = discoveryByteBudget();
|
|
41544
41689
|
for (const source of binding.sources) {
|
|
41545
41690
|
assertMarketplaceBinding(binding, source);
|
|
@@ -41549,6 +41694,10 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
41549
41694
|
throw new Error("Invalid native discovery projection");
|
|
41550
41695
|
if (source.sha256 !== null && !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
41551
41696
|
throw new Error("Invalid native discovery digest");
|
|
41697
|
+
if (installationInput(source.path)) {
|
|
41698
|
+
safe4(source.path);
|
|
41699
|
+
continue;
|
|
41700
|
+
}
|
|
41552
41701
|
const current = projected(source, undefined, budget);
|
|
41553
41702
|
if (current !== source.sha256 && !verifiesCodexHookDiscoverySource(binding, source, current, codexRecovery))
|
|
41554
41703
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
@@ -41556,6 +41705,27 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
41556
41705
|
for (const root2 of binding.roots)
|
|
41557
41706
|
safe4(root2);
|
|
41558
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
|
+
}
|
|
41559
41729
|
function assertMarketplaceBinding(binding, source) {
|
|
41560
41730
|
if ((source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2") && (binding.agent !== "codex" || binding.method !== "reviewed" || basename7(source.path) !== "config.toml"))
|
|
41561
41731
|
throw new Error("Codex settings witnesses require explicit reviewed Codex configuration");
|
|
@@ -41566,8 +41736,11 @@ function assertMarketplaceBinding(binding, source) {
|
|
|
41566
41736
|
}
|
|
41567
41737
|
function rebindAgentDiscovery(binding, changes) {
|
|
41568
41738
|
const budget = discoveryByteBudget();
|
|
41739
|
+
const installationRoots = codexInstallationRoots(binding);
|
|
41569
41740
|
return { ...binding, sources: binding.sources.map((source) => {
|
|
41570
41741
|
assertMarketplaceBinding(binding, source);
|
|
41742
|
+
if (!changes.has(source.path) && installationRoots.some((root2) => source.path.startsWith(root2 + sep4)))
|
|
41743
|
+
return source;
|
|
41571
41744
|
const sha2562 = projected(source, changes, budget);
|
|
41572
41745
|
if (!changes.has(source.path) && sha2562 !== source.sha256)
|
|
41573
41746
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
@@ -42435,6 +42608,9 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
42435
42608
|
for (const [agent, path] of rootDefinitions)
|
|
42436
42609
|
roots.push([agent, canonicalAgentPath(join22(project, path), aliases)]);
|
|
42437
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");
|
|
42438
42614
|
const entries = [], seen = new Set;
|
|
42439
42615
|
const cacheScans = new Map, maxAliasProofEntries = 1e4;
|
|
42440
42616
|
let discoveryEntries = 0, discoveryPathBytes = 0;
|
|
@@ -42469,11 +42645,13 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
42469
42645
|
}
|
|
42470
42646
|
return true;
|
|
42471
42647
|
}
|
|
42472
|
-
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) {
|
|
42473
42649
|
if (!admitted)
|
|
42474
42650
|
admit(path);
|
|
42475
42651
|
const scan = { complete: true, hasSkills: false, entries: 1 };
|
|
42476
42652
|
assertSafePath(path);
|
|
42653
|
+
if (configuredRoot && agent === "codex" && installationInputs.includes(path))
|
|
42654
|
+
return scan;
|
|
42477
42655
|
if (!existsSync6(path))
|
|
42478
42656
|
return scan;
|
|
42479
42657
|
const stat2 = lstatSync19(path);
|
|
@@ -42529,7 +42707,7 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
42529
42707
|
continue;
|
|
42530
42708
|
}
|
|
42531
42709
|
}
|
|
42532
|
-
const childScan = visit2(agent, child, isVendor, depth + 1, pluginCache, true);
|
|
42710
|
+
const childScan = visit2(agent, child, isVendor, depth + 1, pluginCache, true, configuredRoot);
|
|
42533
42711
|
scan.complete &&= childScan.complete;
|
|
42534
42712
|
scan.hasSkills ||= childScan.hasSkills;
|
|
42535
42713
|
scan.entries += childScan.entries;
|
|
@@ -42538,10 +42716,10 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
42538
42716
|
cacheScans.set(path, scan);
|
|
42539
42717
|
return scan;
|
|
42540
42718
|
}
|
|
42541
|
-
function scanRoot(agent, path, vendor = false, pluginCache = false) {
|
|
42719
|
+
function scanRoot(agent, path, vendor = false, pluginCache = false, configuredRoot = false) {
|
|
42542
42720
|
if (agent === "hermes" || options.guardHermes && `${path}${sep5}`.includes(`${sep5}.agents${sep5}skills${sep5}`))
|
|
42543
42721
|
assertNoHermesLegacyShadow(path);
|
|
42544
|
-
if (!visit2(agent, path, vendor, 0, pluginCache).complete)
|
|
42722
|
+
if (!visit2(agent, path, vendor, 0, pluginCache, false, configuredRoot).complete)
|
|
42545
42723
|
throw new Error(`Native skill discovery limit exceeded; review this root before continuing: ${path}`);
|
|
42546
42724
|
}
|
|
42547
42725
|
for (const [agent, path] of roots)
|
|
@@ -42557,7 +42735,7 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
42557
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 }))) : [];
|
|
42558
42736
|
for (const root2 of [...options.agentRoots ?? [], ...configured])
|
|
42559
42737
|
if (includesAgent(root2.agent))
|
|
42560
|
-
scanRoot(root2.agent, canonicalAgentPath(root2.path, aliases), true);
|
|
42738
|
+
scanRoot(root2.agent, canonicalAgentPath(root2.path, aliases), true, false, true);
|
|
42561
42739
|
if (options.reviewedCacheAlias !== undefined && !reviewedCacheAliasFound)
|
|
42562
42740
|
throw new Error("Reviewed cache alias was not an inventoried skill-containing sibling alias");
|
|
42563
42741
|
recheckRootAliases(aliases);
|
|
@@ -42697,6 +42875,11 @@ enabled = false
|
|
|
42697
42875
|
Bun.TOML.parse(result);
|
|
42698
42876
|
return result;
|
|
42699
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
|
+
}
|
|
42700
42883
|
function planAgentIntegration(options) {
|
|
42701
42884
|
const home = options.home ?? homedir3(), dataDir2 = options.dataDir ?? getDataDirReadOnly();
|
|
42702
42885
|
const aliases = rootAliases(home, options.allowRootAliases);
|
|
@@ -42735,11 +42918,16 @@ function planAgentIntegration(options) {
|
|
|
42735
42918
|
const codexConfig = options.agents.includes("codex") ? Bun.TOML.parse(readOptional(canonicalAgentPath(join22(home, ".codex", "config.toml"), aliases)) ?? "") : {};
|
|
42736
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) });
|
|
42737
42920
|
const observedNativeSources = [];
|
|
42738
|
-
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) => {
|
|
42739
42922
|
const bytes = readNativeBytes(path, 1024 * 1024);
|
|
42740
42923
|
observedNativeSources.push({ path, sha256: sha4(bytes) });
|
|
42741
42924
|
return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
42742
|
-
}, 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));
|
|
42743
42931
|
const changes = [];
|
|
42744
42932
|
for (const agent of [...new Set(options.agents)]) {
|
|
42745
42933
|
if (!INTEGRATION_AGENTS.includes(agent))
|
|
@@ -42804,7 +42992,16 @@ function planAgentIntegration(options) {
|
|
|
42804
42992
|
changes.push({ path: configPath, before: previous, after: next });
|
|
42805
42993
|
}
|
|
42806
42994
|
}
|
|
42807
|
-
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
|
+
});
|
|
42808
43005
|
const nextPolicy = { ...policy, version: 1, loading: "cli", profileId, bridge: {
|
|
42809
43006
|
...policy.bridge,
|
|
42810
43007
|
version: CLI_BRIDGE_VERSION,
|
|
@@ -42817,7 +43014,7 @@ function planAgentIntegration(options) {
|
|
|
42817
43014
|
profiles: Object.fromEntries([...new Set([...priorAgents, ...options.agents])].sort().map((agent) => [agent, bindings.get(agent)?.profileId ?? policy.bridge?.profiles?.[agent] ?? policy.profileId])),
|
|
42818
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 ?? [],
|
|
42819
43016
|
rootAliases: aliases,
|
|
42820
|
-
...
|
|
43017
|
+
...options.codexNativeCatalog || codexPluginSkills.length || codexInactivePlugins.length || codexPluginSourceInputs.length ? { codexPluginSkills, codexInactivePlugins, codexPluginSkillReview } : {},
|
|
42821
43018
|
discovery: { ...policy.bridge?.discovery, ...Object.fromEntries(discoveryAfter.map((binding) => [binding.agent, binding])) }
|
|
42822
43019
|
} };
|
|
42823
43020
|
const serializedPolicy = serializeManagedSkillPolicy(nextPolicy);
|
|
@@ -43308,7 +43505,12 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
|
|
|
43308
43505
|
throw new Error("NATIVE_SKILL_DRIFT: the Codex CLI bridge is disabled; run skills hook install");
|
|
43309
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))))
|
|
43310
43507
|
throw new Error("NATIVE_SKILL_DRIFT: reviewed native plugin capability controls changed; run skills hook install with a fresh discovery review");
|
|
43311
|
-
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
|
+
};
|
|
43312
43514
|
const disabledPaths = new Set(disabledCodexSkillPaths(codexConfig, aliases));
|
|
43313
43515
|
const disabledVendorSkill = (entry) => {
|
|
43314
43516
|
if (agent !== "codex" || !entry.vendor)
|
|
@@ -43345,7 +43547,15 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
|
|
|
43345
43547
|
} catch (error) {
|
|
43346
43548
|
throw new Error(`NATIVE_SKILL_DRIFT: ${error.message}`);
|
|
43347
43549
|
}
|
|
43348
|
-
|
|
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 });
|
|
43349
43559
|
const unexpected = inventory.filter((entry) => visible(entry) && !entry.bridge && !disabledVendorSkill(entry));
|
|
43350
43560
|
if (unexpected.length) {
|
|
43351
43561
|
const paths = unexpected.slice(0, 3).map((entry) => {
|