@hasna/skills 0.10.91 → 0.10.92
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/THIRD_PARTY_NOTICES +1 -1
- package/bin/index.js +247 -24
- package/bin/mcp.js +263 -24
- package/bin/migrate.js +1 -1
- package/bin/server.js +1 -1
- package/bin/worker.js +1 -1
- package/dist/index.js +245 -23
- package/dist/lib/agent-discovery.d.ts +14 -1
- package/dist/runtime-prerequisites.js +1 -1
- package/dist/sdk/index.js +497 -275
- package/package.json +1 -1
package/THIRD_PARTY_NOTICES
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
THIRD-PARTY SOFTWARE NOTICES
|
|
2
2
|
|
|
3
|
-
@hasna/skills 0.10.
|
|
3
|
+
@hasna/skills 0.10.92 bundles the 80 third-party packages below into its bin/ and dist/ files.
|
|
4
4
|
Each is listed with its licence and the licence and notice text it ships with.
|
|
5
5
|
|
|
6
6
|
================================================================================
|
package/bin/index.js
CHANGED
|
@@ -36888,7 +36888,7 @@ var package_default;
|
|
|
36888
36888
|
var init_package = __esm(() => {
|
|
36889
36889
|
package_default = {
|
|
36890
36890
|
name: "@hasna/skills",
|
|
36891
|
-
version: "0.10.
|
|
36891
|
+
version: "0.10.92",
|
|
36892
36892
|
description: "Skills library for AI coding agents",
|
|
36893
36893
|
type: "module",
|
|
36894
36894
|
bin: {
|
|
@@ -65872,9 +65872,94 @@ function nativeDiscoveryAliasTargets(roots, home) {
|
|
|
65872
65872
|
}
|
|
65873
65873
|
return [...targets];
|
|
65874
65874
|
}
|
|
65875
|
+
function hooksAreManagedBridge(agent, hooks, managed) {
|
|
65876
|
+
const table = (value) => Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
65877
|
+
const exactKeys4 = (value, keys3) => Object.keys(value).sort().join("\x00") === [...keys3].sort().join("\x00");
|
|
65878
|
+
if (!table(hooks) || typeof managed.command !== "string" || !isAbsolute30(managed.command))
|
|
65879
|
+
return false;
|
|
65880
|
+
const events3 = agent === "gemini" ? ["BeforeAgent", "SessionStart", "BeforeTool"] : ["beforeSubmitPrompt", "sessionStart"];
|
|
65881
|
+
for (const [event, entries] of Object.entries(hooks)) {
|
|
65882
|
+
if (!events3.includes(event) || !Array.isArray(entries) || entries.length !== 1)
|
|
65883
|
+
return false;
|
|
65884
|
+
let expected;
|
|
65885
|
+
try {
|
|
65886
|
+
expected = renderAgentHookCommand(managed.command, agent, managed.profile, event);
|
|
65887
|
+
} catch {
|
|
65888
|
+
return false;
|
|
65889
|
+
}
|
|
65890
|
+
const entry = entries[0];
|
|
65891
|
+
if (!table(entry))
|
|
65892
|
+
return false;
|
|
65893
|
+
if (agent === "cursor") {
|
|
65894
|
+
if (!exactKeys4(entry, ["command", "timeout"]) || entry.timeout !== 15 || entry.command !== expected)
|
|
65895
|
+
return false;
|
|
65896
|
+
continue;
|
|
65897
|
+
}
|
|
65898
|
+
if (!exactKeys4(entry, event === "BeforeTool" ? ["hooks", "matcher"] : ["hooks"]) || event === "BeforeTool" && entry.matcher !== "activate_skill" || !Array.isArray(entry.hooks) || entry.hooks.length !== 1)
|
|
65899
|
+
return false;
|
|
65900
|
+
const hook = entry.hooks[0];
|
|
65901
|
+
if (!table(hook) || !exactKeys4(hook, ["command", "timeout", "type"]) || hook.type !== "command" || hook.timeout !== 15000 || hook.command !== expected)
|
|
65902
|
+
return false;
|
|
65903
|
+
}
|
|
65904
|
+
return true;
|
|
65905
|
+
}
|
|
65906
|
+
function sumiPluginLoadsOnlyBuiltins(text3) {
|
|
65907
|
+
for (const match of text3.matchAll(/\b(?:import|require)\s*\(\s*(.?)/g)) {
|
|
65908
|
+
const rest2 = text3.slice(match.index + match[0].length - match[1].length);
|
|
65909
|
+
if (!/^(['"])node:[A-Za-z0-9_/.-]+\1/.test(rest2))
|
|
65910
|
+
return false;
|
|
65911
|
+
}
|
|
65912
|
+
for (const match of text3.matchAll(/\b(?:from|import)\s*(['"])([^'"]*)\1/g))
|
|
65913
|
+
if (!match[2].startsWith("node:"))
|
|
65914
|
+
return false;
|
|
65915
|
+
return true;
|
|
65916
|
+
}
|
|
65917
|
+
function codexRootFreeControls(config) {
|
|
65918
|
+
const table = (value) => Boolean(value && typeof value === "object" && !Array.isArray(value) && !(value instanceof Date));
|
|
65919
|
+
const adapted = [];
|
|
65920
|
+
const servers = config.mcp_servers;
|
|
65921
|
+
if (table(servers) && Object.keys(servers).length <= AGENT_POLICY_LIMITS.discoveryRoots && Object.entries(servers).every(([name, row]) => name !== "codex_apps" && name !== "_codex_apps" && isCodexLocalStdioMcpServer(name, row)))
|
|
65922
|
+
adapted.push("mcp_servers");
|
|
65923
|
+
const agents = config.agents;
|
|
65924
|
+
if (table(agents) && Object.keys(agents).length <= AGENT_POLICY_LIMITS.fields && Object.values(agents).every((value) => typeof value === "boolean" || typeof value === "number" && Number.isFinite(value)))
|
|
65925
|
+
adapted.push("agents");
|
|
65926
|
+
return adapted;
|
|
65927
|
+
}
|
|
65928
|
+
function codexPluginHookHandlers(value) {
|
|
65929
|
+
const table = (item) => Boolean(item && typeof item === "object" && !Array.isArray(item));
|
|
65930
|
+
const identifier6 = (item) => typeof item === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(item);
|
|
65931
|
+
const text3 = (item) => typeof item === "string" && item.length <= AGENT_POLICY_LIMITS.pathCharacters && !item.includes("\x00");
|
|
65932
|
+
if (!table(value) || !Object.keys(value).every((key2) => key2 === "hooks" || key2 === "description") || value.description !== undefined && !text3(value.description) || !table(value.hooks) || Object.keys(value.hooks).length > 32)
|
|
65933
|
+
return null;
|
|
65934
|
+
const result2 = { commands: 0, servers: new Set };
|
|
65935
|
+
for (const [event, groups] of Object.entries(value.hooks)) {
|
|
65936
|
+
if (!CODEX_HOOK_EVENTS.has(event) || !Array.isArray(groups) || groups.length > 32)
|
|
65937
|
+
return null;
|
|
65938
|
+
for (const group of groups) {
|
|
65939
|
+
if (!table(group) || !Object.keys(group).every((key2) => key2 === "hooks" || key2 === "matcher") || group.matcher !== undefined && !text3(group.matcher) || !Array.isArray(group.hooks) || group.hooks.length > 32)
|
|
65940
|
+
return null;
|
|
65941
|
+
for (const handler of group.hooks) {
|
|
65942
|
+
if (!table(handler) || handler.timeout !== undefined && !(Number.isSafeInteger(handler.timeout) && handler.timeout >= 0) || handler.statusMessage !== undefined && !text3(handler.statusMessage))
|
|
65943
|
+
return null;
|
|
65944
|
+
if (handler.type === "command") {
|
|
65945
|
+
if (!text3(handler.command) || !handler.command || !Object.keys(handler).every((key2) => ["type", "command", "commandWindows", "command_windows", "timeout", "async", "statusMessage", "additionalContextLimit"].includes(key2)))
|
|
65946
|
+
return null;
|
|
65947
|
+
result2.commands++;
|
|
65948
|
+
} else if (handler.type === "mcp_tool") {
|
|
65949
|
+
if (!identifier6(handler.server) || !identifier6(handler.tool) || handler.input !== undefined && !table(handler.input) || !Object.keys(handler).every((key2) => ["type", "server", "tool", "input", "timeout", "statusMessage"].includes(key2)))
|
|
65950
|
+
return null;
|
|
65951
|
+
result2.servers.add(handler.server);
|
|
65952
|
+
} else
|
|
65953
|
+
return null;
|
|
65954
|
+
}
|
|
65955
|
+
}
|
|
65956
|
+
}
|
|
65957
|
+
return result2;
|
|
65958
|
+
}
|
|
65875
65959
|
function resolveDiscovery(options, exclusion) {
|
|
65876
65960
|
const canonical9 = options.canonical ?? resolve29, home = resolve29(options.home), agent = options.agent;
|
|
65877
65961
|
const sources = [], roots = new Set, builtinNames = [];
|
|
65962
|
+
const sumiLocalPluginTexts = new Map;
|
|
65878
65963
|
const budget3 = discoveryByteBudget();
|
|
65879
65964
|
let remainingEntries = AGENT_POLICY_LIMITS.discoveryDirectoryEntries;
|
|
65880
65965
|
const entries = (path) => {
|
|
@@ -65951,12 +66036,38 @@ function resolveDiscovery(options, exclusion) {
|
|
|
65951
66036
|
const controls = agent === "claude" ? claudeDiscoveryControlKeys(configText ?? "{}") : agent === "codex" ? codexDiscoveryControlKeys(config) : Object.keys(config).filter((key2) => /skill|plugin|hook|marketplace|extension|instruction/i.test(key2));
|
|
65952
66037
|
const fieldKey = (key2) => /^[A-Za-z_$][A-Za-z0-9_$.-]{0,22}$/.test(key2) && !/(?:sk|rk|pk)_(?:live|test)_|whsec_/i.test(key2) ? JSON.stringify(key2) : "[withheld field key]";
|
|
65953
66038
|
const unsupportedFields = (names, label) => unresolved(`unknown discovery controls have no root-exclusion adapter for ${label}${names.slice(0, 8).map(fieldKey).join(", ")}${names.length > 8 ? ", additional keys withheld" : ""} in ${quotedPath(canonical9(configPath))}`);
|
|
65954
|
-
const
|
|
66039
|
+
const adapted = agent === "codex" ? codexRootFreeControls(config) : agent === "opencode" && Array.isArray(config.instructions) && config.instructions.length === 0 ? ["instructions"] : [];
|
|
66040
|
+
const unsupportedControls = controls.filter((key2) => !supported[agent].includes(key2) && !adapted.includes(key2));
|
|
65955
66041
|
if (unsupportedControls.length)
|
|
65956
66042
|
unsupportedFields(unsupportedControls, "");
|
|
65957
66043
|
if (config.hooks !== undefined && !object6(config.hooks))
|
|
65958
66044
|
unresolved("hooks must be an object");
|
|
65959
|
-
const
|
|
66045
|
+
const managedSupervisorOnly = () => {
|
|
66046
|
+
const supervisor = exclusion.managedHook?.supervisor;
|
|
66047
|
+
if (agent !== "hermes" || !supervisor || typeof supervisor.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(supervisor.sha256) || !object6(config.hooks))
|
|
66048
|
+
return false;
|
|
66049
|
+
let expected;
|
|
66050
|
+
try {
|
|
66051
|
+
expected = hermesHookDefinitions(supervisor);
|
|
66052
|
+
} catch {
|
|
66053
|
+
return false;
|
|
66054
|
+
}
|
|
66055
|
+
for (const [event, entries2] of Object.entries(config.hooks)) {
|
|
66056
|
+
const want = expected[event];
|
|
66057
|
+
if (!want || !Array.isArray(entries2) || entries2.length !== 1 || !object6(entries2[0]))
|
|
66058
|
+
return false;
|
|
66059
|
+
const entry = entries2[0];
|
|
66060
|
+
if (Object.keys(entry).sort().join("\x00") !== Object.keys(want).sort().join("\x00") || Object.keys(want).some((key2) => entry[key2] !== want[key2]))
|
|
66061
|
+
return false;
|
|
66062
|
+
}
|
|
66063
|
+
try {
|
|
66064
|
+
return hashRawDiscoveryFile(canonical9(supervisor.path), budget3) === supervisor.sha256;
|
|
66065
|
+
} catch {
|
|
66066
|
+
return false;
|
|
66067
|
+
}
|
|
66068
|
+
};
|
|
66069
|
+
const managedBridgeOnly = (agent === "gemini" || agent === "cursor") && exclusion.managedHook !== undefined && hooksAreManagedBridge(agent, config.hooks, exclusion.managedHook) || managedSupervisorOnly();
|
|
66070
|
+
const hasHooks = controls.includes("hooks") && config.hooks !== undefined && Object.keys(config.hooks).length > 0 && !managedBridgeOnly;
|
|
65960
66071
|
let hasPluginConfigs = false, hasFunctionHookEnvironment = false;
|
|
65961
66072
|
const verifyCurrentOpaqueSettings = (label) => {
|
|
65962
66073
|
const retained = exclusion.retained;
|
|
@@ -66061,7 +66172,9 @@ function resolveDiscovery(options, exclusion) {
|
|
|
66061
66172
|
unresolved("malformed Sumi plugins");
|
|
66062
66173
|
}
|
|
66063
66174
|
if (agent === "hermes" && config.skills !== undefined) {
|
|
66064
|
-
keys3(config.skills, ["external_dirs"], "Hermes skills");
|
|
66175
|
+
keys3(config.skills, ["external_dirs", "creation_nudge_interval"], "Hermes skills");
|
|
66176
|
+
if (config.skills.creation_nudge_interval !== undefined && !(Number.isSafeInteger(config.skills.creation_nudge_interval) && config.skills.creation_nudge_interval >= 0))
|
|
66177
|
+
unresolved("malformed Hermes skills creation_nudge_interval");
|
|
66065
66178
|
if (config.skills.external_dirs !== undefined)
|
|
66066
66179
|
paths(typeof config.skills.external_dirs === "string" ? [config.skills.external_dirs] : config.skills.external_dirs, "Hermes external directories");
|
|
66067
66180
|
}
|
|
@@ -66081,10 +66194,21 @@ function resolveDiscovery(options, exclusion) {
|
|
|
66081
66194
|
unresolved(`malformed Codex ${key2}`);
|
|
66082
66195
|
for (const value of Object.values(config.plugins ?? {}))
|
|
66083
66196
|
keys3(value, ["enabled"], "Codex plugin registration");
|
|
66084
|
-
for (const value of Object.values(config.marketplaces ?? {}))
|
|
66085
|
-
keys3(value, ["source_type", "source"], "Codex marketplace registration");
|
|
66197
|
+
for (const value of Object.values(config.marketplaces ?? {})) {
|
|
66198
|
+
keys3(value, ["source_type", "source", "last_updated"], "Codex marketplace registration");
|
|
66199
|
+
if (value.last_updated !== undefined && (typeof value.last_updated !== "string" || !CODEX_MARKETPLACE_TIMESTAMP.test(value.last_updated)))
|
|
66200
|
+
unresolved("malformed Codex marketplace refresh time");
|
|
66201
|
+
}
|
|
66086
66202
|
if (config.skills !== undefined)
|
|
66087
|
-
keys3(config.skills, ["config", "bundled"], "Codex skills");
|
|
66203
|
+
keys3(config.skills, ["config", "bundled", "native_allowed_paths"], "Codex skills");
|
|
66204
|
+
if (config.skills?.native_allowed_paths !== undefined) {
|
|
66205
|
+
for (const value of paths(config.skills.native_allowed_paths, "Codex native allowed skill paths")) {
|
|
66206
|
+
if (!isAbsolute30(value))
|
|
66207
|
+
unresolved("relative Codex native allowed skill path");
|
|
66208
|
+
const path = canonical9(value);
|
|
66209
|
+
roots.add(path.endsWith(`${sep14}SKILL.md`) ? dirname29(path) : path);
|
|
66210
|
+
}
|
|
66211
|
+
}
|
|
66088
66212
|
if (config.skills?.bundled !== undefined) {
|
|
66089
66213
|
keys3(config.skills.bundled, ["enabled"], "Codex bundled skills");
|
|
66090
66214
|
if (typeof config.skills.bundled.enabled !== "boolean")
|
|
@@ -66142,7 +66266,9 @@ function resolveDiscovery(options, exclusion) {
|
|
|
66142
66266
|
const target = join46(path, name);
|
|
66143
66267
|
if (!lstatSync35(target).isFile())
|
|
66144
66268
|
unresolved("local plugin packages need a dedicated discovery adapter");
|
|
66145
|
-
witness(target);
|
|
66269
|
+
const text3 = witness(target);
|
|
66270
|
+
if (exclusion && text3 !== null)
|
|
66271
|
+
sumiLocalPluginTexts.set(canonical9(target), text3);
|
|
66146
66272
|
}
|
|
66147
66273
|
}
|
|
66148
66274
|
for (const root2 of roots) {
|
|
@@ -66276,16 +66402,88 @@ function resolveDiscovery(options, exclusion) {
|
|
|
66276
66402
|
const unique = combined.filter((source, index) => combined.findIndex((candidate2) => isDeepStrictEqual15(candidate2, source)) === index);
|
|
66277
66403
|
return { ...supplied, roots: [...new Set([...roots, ...supplied.roots])].sort(), sources: unique, ...agent === "gemini" ? { builtinNames } : {} };
|
|
66278
66404
|
}
|
|
66279
|
-
|
|
66405
|
+
const reviewedManifestAbsence = (root2, manifestPath) => {
|
|
66406
|
+
const retained = exclusion?.retained;
|
|
66407
|
+
if (agent !== "claude" || retained?.method !== "reviewed" || ![join46(root2, "skills"), root2].some((path) => retained.roots.includes(path)))
|
|
66408
|
+
return false;
|
|
66409
|
+
const saved = retained.sources.filter((source) => source.path === canonical9(manifestPath) && source.hashMode === "path-bytes" && source.sha256 !== null && source.format === undefined && source.fields === undefined && source.managedPlugins === undefined);
|
|
66410
|
+
return saved.length > 0 && saved.every((source) => projected(source, undefined, budget3) === source.sha256);
|
|
66411
|
+
};
|
|
66412
|
+
const reviewedInstalledCopy = (root2, path, identity6) => {
|
|
66413
|
+
const retained = exclusion?.retained;
|
|
66414
|
+
if (agent !== "codex" || retained?.method !== "reviewed")
|
|
66415
|
+
return false;
|
|
66416
|
+
const inside = relative9(root2, canonical9(path));
|
|
66417
|
+
if (!inside || inside === ".." || inside.startsWith(`..${sep14}`) || isAbsolute30(inside))
|
|
66418
|
+
return false;
|
|
66419
|
+
const parent = canonical9(join46(nativeHome, "plugins/cache", identity6.marketplace, identity6.name));
|
|
66420
|
+
const current = hashRawDiscoveryFile(canonical9(path), budget3);
|
|
66421
|
+
if (current === null)
|
|
66422
|
+
return false;
|
|
66423
|
+
return retained.sources.some((source) => {
|
|
66424
|
+
if (source.sha256 !== current || source.format !== undefined || source.fields !== undefined || ![undefined, "bytes"].includes(source.hashMode) || source.managedPlugins !== undefined || source.reviewArtifact !== undefined || !source.path.startsWith(parent + sep14))
|
|
66425
|
+
return false;
|
|
66426
|
+
const [version, ...rest2] = source.path.slice(parent.length + 1).split(sep14);
|
|
66427
|
+
return Boolean(version) && version !== "." && version !== ".." && rest2.join(sep14) === inside;
|
|
66428
|
+
});
|
|
66429
|
+
};
|
|
66430
|
+
const verifyCodexPluginHookClosure = (root2, identity6, marketplaceSource, servers, declarations) => {
|
|
66431
|
+
const retained = exclusion.retained;
|
|
66432
|
+
if (retained.codexSemanticCache || retained.codexInstallationInputs || retained.codexRetiredMaterializations)
|
|
66433
|
+
return verifyOpaqueClosure(declarations);
|
|
66434
|
+
const within2 = (base2, path) => path === base2 || path.startsWith(base2 + sep14);
|
|
66435
|
+
const executables = [];
|
|
66436
|
+
for (const server of servers) {
|
|
66437
|
+
const row = config.mcp_servers?.[server];
|
|
66438
|
+
if (server === "codex_apps" || server === "_codex_apps" || !isCodexLocalStdioMcpServer(server, row))
|
|
66439
|
+
unresolved("plugin hook MCP server is not a configured local stdio server");
|
|
66440
|
+
for (const value of [row.command, ...row.args ?? []])
|
|
66441
|
+
for (const candidate2 of [value, value.slice(value.indexOf("=") + 1)]) {
|
|
66442
|
+
if (!isAbsolute30(candidate2) || /[\0$]/.test(candidate2) || executables.length >= AGENT_POLICY_LIMITS.discoveryRoots)
|
|
66443
|
+
continue;
|
|
66444
|
+
const path = canonical9(candidate2);
|
|
66445
|
+
if (lstatSync35(path, { throwIfNoEntry: false })?.isFile())
|
|
66446
|
+
executables.push(path);
|
|
66447
|
+
}
|
|
66448
|
+
}
|
|
66449
|
+
const cacheRoot = canonical9(join46(nativeHome, "plugins/cache"));
|
|
66450
|
+
const ownCache = canonical9(join46(nativeHome, "plugins/cache", identity6.marketplace, identity6.name));
|
|
66451
|
+
const ownCatalog = canonical9(join46(marketplaceSource, ".agents/plugins/marketplace.json"));
|
|
66452
|
+
const account = canonical9(home);
|
|
66453
|
+
const marketplaceRoots = Object.values(config.marketplaces ?? {}).filter((market) => market?.source_type === "local" && typeof market.source === "string" && isAbsolute30(market.source)).map((market) => canonical9(market.source)).filter((path) => !within2(path, account));
|
|
66454
|
+
const otherPlugin = (path) => !within2(root2, path) && !within2(ownCache, path) && path !== ownCatalog && !executables.includes(path) && (within2(cacheRoot, path) || marketplaceRoots.some((base2) => within2(base2, path)));
|
|
66455
|
+
const sources2 = retained.sources.filter((source) => source.path !== canonical9(configPath) && !otherPlugin(source.path));
|
|
66456
|
+
if (sources2.some((source) => source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || source.reviewArtifact !== undefined || ![undefined, "bytes", "path-bytes", "executable-v1"].includes(source.hashMode)))
|
|
66457
|
+
return verifyOpaqueClosure(declarations);
|
|
66458
|
+
const declared = declarations.map((path) => relative9(root2, path));
|
|
66459
|
+
const declaration = (path) => declarations.includes(path) || path.startsWith(ownCache + sep14) && declared.includes(path.slice(ownCache.length + 1).split(sep14).slice(1).join(sep14));
|
|
66460
|
+
if (!sources2.some((source) => !declaration(source.path) && source.sha256 !== null))
|
|
66461
|
+
unresolved("opaque executable dependency closure is unavailable");
|
|
66462
|
+
for (const source of sources2)
|
|
66463
|
+
if (projected(source, undefined, budget3) !== source.sha256) {
|
|
66464
|
+
throw new NativeDiscoveryWitnessChange("input", source.path, `Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
66465
|
+
}
|
|
66466
|
+
verifyDiscoveryDirectories((retained.directories ?? []).filter((directory2) => !otherPlugin(directory2.path)));
|
|
66467
|
+
};
|
|
66468
|
+
const readCodexHookDeclaration = (text3, path) => {
|
|
66469
|
+
if (text3 === null)
|
|
66470
|
+
return null;
|
|
66471
|
+
try {
|
|
66472
|
+
return codexPluginHookHandlers(parseConfig(text3, path));
|
|
66473
|
+
} catch {
|
|
66474
|
+
return null;
|
|
66475
|
+
}
|
|
66476
|
+
};
|
|
66477
|
+
function plugin(root2, codex) {
|
|
66280
66478
|
root2 = canonical9(root2);
|
|
66281
66479
|
safe6(root2);
|
|
66282
66480
|
if (exclusion)
|
|
66283
66481
|
roots.add(root2);
|
|
66284
66482
|
const manifestPath = join46(root2, agent === "claude" ? ".claude-plugin/plugin.json" : ".codex-plugin/plugin.json");
|
|
66285
66483
|
const raw = witness(manifestPath, undefined, undefined, agent === "claude" ? "claude-plugin-manifest-v1" : undefined);
|
|
66286
|
-
if (raw === null)
|
|
66484
|
+
if (raw === null && !reviewedManifestAbsence(root2, manifestPath))
|
|
66287
66485
|
unresolved("plugin manifest missing");
|
|
66288
|
-
const manifest = parseConfig(raw, manifestPath);
|
|
66486
|
+
const manifest = raw === null ? {} : parseConfig(raw, manifestPath);
|
|
66289
66487
|
if (exclusion && Object.keys(manifest).some((key2) => /skill|plugin|hook|marketplace|extension|instruction/i.test(key2) && !["skills", "hooks"].includes(key2)))
|
|
66290
66488
|
unresolved("unknown plugin discovery controls");
|
|
66291
66489
|
const hooks = witness(join46(root2, "hooks/hooks.json"));
|
|
@@ -66293,20 +66491,35 @@ function resolveDiscovery(options, exclusion) {
|
|
|
66293
66491
|
if (!exclusion || exclusion.retained?.method !== "reviewed")
|
|
66294
66492
|
unresolved("plugin hooks require a separate no-skill-injection review");
|
|
66295
66493
|
const required = [manifestPath, ...hooks !== null ? [join46(root2, "hooks/hooks.json")] : []];
|
|
66494
|
+
const scoped2 = agent === "codex" && codex !== undefined ? [] : undefined;
|
|
66296
66495
|
if (manifest.hooks !== undefined) {
|
|
66297
|
-
if (typeof manifest.hooks
|
|
66298
|
-
|
|
66299
|
-
|
|
66300
|
-
|
|
66301
|
-
|
|
66302
|
-
|
|
66303
|
-
|
|
66496
|
+
if (scoped2 && manifest.hooks && typeof manifest.hooks === "object" && !Array.isArray(manifest.hooks)) {
|
|
66497
|
+
const inline = codexPluginHookHandlers(manifest.hooks);
|
|
66498
|
+
if (!inline)
|
|
66499
|
+
unresolved("unsupported inline plugin hooks");
|
|
66500
|
+
scoped2.push(inline);
|
|
66501
|
+
} else {
|
|
66502
|
+
if (typeof manifest.hooks !== "string")
|
|
66503
|
+
unresolved("unsupported plugin hooks target");
|
|
66504
|
+
const hook = resolve29(root2, manifest.hooks);
|
|
66505
|
+
if (!hook.startsWith(root2 + sep14))
|
|
66506
|
+
unresolved("plugin hooks target escapes its root");
|
|
66507
|
+
required.push(hook);
|
|
66508
|
+
if (scoped2)
|
|
66509
|
+
scoped2.push(readCodexHookDeclaration(witness(hook), hook));
|
|
66510
|
+
}
|
|
66511
|
+
}
|
|
66512
|
+
if (scoped2 && hooks !== null)
|
|
66513
|
+
scoped2.push(readCodexHookDeclaration(hooks, join46(root2, "hooks/hooks.json")));
|
|
66304
66514
|
for (const path of required) {
|
|
66305
66515
|
const saved = exclusion.retained.sources.filter((source) => source.path === canonical9(path) && source.sha256 !== null && source.format === undefined && source.fields === undefined);
|
|
66306
|
-
if (
|
|
66516
|
+
if (saved.length ? saved.some((source) => projected(source, undefined, budget3) !== source.sha256) : !(scoped2 && reviewedInstalledCopy(root2, path, codex)))
|
|
66307
66517
|
unresolved("plugin hooks require current independently reviewed sources");
|
|
66308
66518
|
}
|
|
66309
|
-
|
|
66519
|
+
if (scoped2 && scoped2.every((item) => item !== null && item.commands === 0)) {
|
|
66520
|
+
verifyCodexPluginHookClosure(root2, codex, codex.source, new Set(scoped2.flatMap((item) => [...item.servers])), required.map((path) => canonical9(path)));
|
|
66521
|
+
} else
|
|
66522
|
+
verifyOpaqueClosure(required.map((path) => canonical9(path)));
|
|
66310
66523
|
}
|
|
66311
66524
|
const commands = join46(root2, "commands");
|
|
66312
66525
|
safe6(commands);
|
|
@@ -66362,7 +66575,7 @@ function resolveDiscovery(options, exclusion) {
|
|
|
66362
66575
|
const catalog = parseConfig(catalogText, join46(market.source, ".agents/plugins/marketplace.json")), matches2 = Array.isArray(catalog.plugins) ? catalog.plugins.filter((item) => item.name === name) : [];
|
|
66363
66576
|
if (matches2.length !== 1 || matches2[0]?.source?.source !== "local" || typeof matches2[0]?.source?.path !== "string")
|
|
66364
66577
|
unresolved("plugin catalog source is missing or ambiguous");
|
|
66365
|
-
plugin(resolve29(market.source, matches2[0].source.path));
|
|
66578
|
+
plugin(resolve29(market.source, matches2[0].source.path), exclusion ? { marketplace, name, source: market.source } : undefined);
|
|
66366
66579
|
}
|
|
66367
66580
|
} else if (agent === "opencode") {
|
|
66368
66581
|
if (witness(join46(home, ".config/opencode/opencode.jsonc")) !== null || witness(join46(home, ".config/opencode/config.json")) !== null)
|
|
@@ -66379,7 +66592,11 @@ function resolveDiscovery(options, exclusion) {
|
|
|
66379
66592
|
if (lstatSync35(localPlugins, { throwIfNoEntry: false }) && entries(localPlugins).some((name) => name !== "skills-cli.js"))
|
|
66380
66593
|
unresolved("additional local plugin hooks require review");
|
|
66381
66594
|
} else if (agent === "sumi") {
|
|
66382
|
-
|
|
66595
|
+
const pinnedLocalPlugin = (source) => {
|
|
66596
|
+
const retained = exclusion?.retained, text3 = sumiLocalPluginTexts.get(source.path);
|
|
66597
|
+
return retained?.method === "reviewed" && text3 !== undefined && sumiPluginLoadsOnlyBuiltins(text3) && retained.sources.some((saved) => saved.path === source.path && saved.sha256 === source.sha256 && saved.sha256 !== null && [undefined, "bytes"].includes(saved.hashMode) && saved.format === undefined && saved.fields === undefined && saved.managedPlugins === undefined && saved.reviewArtifact === undefined);
|
|
66598
|
+
};
|
|
66599
|
+
if ((config.plugin?.length ?? 0) > 0 || (config.plugins?.length ?? 0) > 0 || sources.some((source) => source.path !== canonical9(configPath) && source.path !== canonical9(join46(sumiConfigDirectory(home), "sumi.jsonc")) && source.sha256 !== null && !pinnedLocalPlugin(source)))
|
|
66383
66600
|
unresolved("external or foreign local plugins require review");
|
|
66384
66601
|
} else if (agent === "hermes") {
|
|
66385
66602
|
for (const directory2 of [join46(home, ".hermes/plugins"), join46(home, ".hermes/hermes-agent")]) {
|
|
@@ -66419,11 +66636,12 @@ var DISCOVERY_RUNTIME_COMMANDS, DISCOVERY_ROOT_UNRESOLVED = "DISCOVERY_ROOT_UNRE
|
|
|
66419
66636
|
} catch {
|
|
66420
66637
|
return null;
|
|
66421
66638
|
}
|
|
66422
|
-
}, digest2 = (text3) => createHash33("sha256").update(text3).digest("hex"), CLAUDE_CONTROL_WITNESS_MODES, CLAUDE_CONTROL_FILES, ADOPTABLE_SETTINGS_MATCHES, CLAUDE_PROJECT_DISCOVERY_KEYS;
|
|
66639
|
+
}, digest2 = (text3) => createHash33("sha256").update(text3).digest("hex"), CLAUDE_CONTROL_WITNESS_MODES, CLAUDE_CONTROL_FILES, ADOPTABLE_SETTINGS_MATCHES, CLAUDE_PROJECT_DISCOVERY_KEYS, CODEX_MARKETPLACE_TIMESTAMP, CODEX_HOOK_EVENTS;
|
|
66423
66640
|
var init_agent_discovery = __esm(() => {
|
|
66424
66641
|
init_sumi_settings_witness();
|
|
66425
66642
|
init_agent_policy_limits();
|
|
66426
66643
|
init_agent_hermes();
|
|
66644
|
+
init_agent_adapters();
|
|
66427
66645
|
init_agent_discovery_directories();
|
|
66428
66646
|
init_agent_discovery_bytes();
|
|
66429
66647
|
init_plugin_projection_store();
|
|
@@ -66453,6 +66671,8 @@ var init_agent_discovery = __esm(() => {
|
|
|
66453
66671
|
CLAUDE_CONTROL_FILES = new Set(["settings.json", "settings.local.json", "installed_plugins.json", "known_marketplaces.json"]);
|
|
66454
66672
|
ADOPTABLE_SETTINGS_MATCHES = Object.freeze(["exact", "screen-reader-receipt"]);
|
|
66455
66673
|
CLAUDE_PROJECT_DISCOVERY_KEYS = Object.freeze(["enabledPlugins", "extraKnownMarketplaces", "additionalMarketplaces", "skillOverrides"]);
|
|
66674
|
+
CODEX_MARKETPLACE_TIMESTAMP = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,9})?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
66675
|
+
CODEX_HOOK_EVENTS = new Set(["PreToolUse", "PermissionRequest", "PostToolUse", "PreCompact", "PostCompact", "SessionStart", "SessionEnd", "UserPromptSubmit", "SubagentStart", "SubagentStop", "Stop", "Interrupt"]);
|
|
66456
66676
|
});
|
|
66457
66677
|
|
|
66458
66678
|
// src/lib/authoring-path.ts
|
|
@@ -66530,7 +66750,10 @@ function configuredRoots(home, explicitHome) {
|
|
|
66530
66750
|
if (recorded && (!executable2 || executable2.target !== recorded.target || onPath && onPath.target !== recorded.target) || !executable2 && (binding.builtinNames?.length || binding.agent === "gemini" && binding.sources.some((source) => basename19(source.path) === "package.json"))) {
|
|
66531
66751
|
throw new Error("Native discovery runtime target is unresolved or changed");
|
|
66532
66752
|
}
|
|
66533
|
-
|
|
66753
|
+
const managedCommand = current.commands?.[agent], managedProfile = current.profiles?.[agent];
|
|
66754
|
+
const supervisor = current.supervisors?.[agent];
|
|
66755
|
+
const managedHook = (binding.agent === "gemini" || binding.agent === "cursor") && typeof managedCommand === "string" && typeof managedProfile === "string" ? { command: managedCommand, profile: managedProfile } : binding.agent === "hermes" && typeof managedCommand === "string" && typeof managedProfile === "string" && supervisor && typeof supervisor === "object" && typeof supervisor.path === "string" && typeof supervisor.runtime === "string" && typeof supervisor.sha256 === "string" ? { command: managedCommand, profile: managedProfile, supervisor: { path: supervisor.path, runtime: supervisor.runtime, sha256: supervisor.sha256 } } : undefined;
|
|
66756
|
+
roots.push(...resolveAgentDiscoveryExclusionRoots({ home, agent: binding.agent, canonical: physicalPath, retained: binding, executable: executable2, narrowed, ...managedHook ? { managedHook } : {} }));
|
|
66534
66757
|
}
|
|
66535
66758
|
};
|
|
66536
66759
|
if (homePolicy)
|