@hasna/skills 0.10.91 → 0.10.93
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 +1051 -725
- package/bin/mcp.js +333 -46
- package/bin/migrate.js +1 -1
- package/bin/server.js +1 -1
- package/bin/worker.js +1 -1
- package/dist/cli/commands/portable-skills.d.ts +1 -0
- package/dist/index.js +381 -67
- package/dist/lib/agent-discovery.d.ts +27 -1
- package/dist/lib/authoring-path.d.ts +5 -0
- package/dist/lib/linux-access-acl.d.ts +55 -0
- package/dist/runtime-prerequisites.js +1 -1
- package/dist/sdk/index.js +671 -357
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -16369,7 +16369,7 @@ import { basename as basename15, dirname as dirname27, isAbsolute as isAbsolute2
|
|
|
16369
16369
|
import { homedir as homedir5 } from "os";
|
|
16370
16370
|
import { isAbsolute as isAbsolute25, join as join39, resolve as resolve25 } from "path";
|
|
16371
16371
|
// package.json
|
|
16372
|
-
var version = "0.10.
|
|
16372
|
+
var version = "0.10.93";
|
|
16373
16373
|
var package_default = {
|
|
16374
16374
|
name: "@hasna/skills",
|
|
16375
16375
|
version,
|
|
@@ -20802,6 +20802,82 @@ function assertPinnedLauncherRuntimeSafe(runtime) {
|
|
|
20802
20802
|
}
|
|
20803
20803
|
}
|
|
20804
20804
|
|
|
20805
|
+
// src/lib/linux-access-acl.ts
|
|
20806
|
+
var LINUX_ENODATA = 61;
|
|
20807
|
+
var LINUX_EOPNOTSUPP = 95;
|
|
20808
|
+
var LINUX_ACL_QUERY_ATTEMPTS = 4;
|
|
20809
|
+
var LINUX_ACL_FREE_WHEN_UNSUPPORTED = new Set([
|
|
20810
|
+
0xef53n,
|
|
20811
|
+
0x58465342n,
|
|
20812
|
+
0x9123683en,
|
|
20813
|
+
0x01021994n
|
|
20814
|
+
]);
|
|
20815
|
+
function queryAttribute(probe2, errno, fd, attribute) {
|
|
20816
|
+
for (let attempt = 0;attempt < LINUX_ACL_QUERY_ATTEMPTS; attempt++) {
|
|
20817
|
+
errno.set?.(0);
|
|
20818
|
+
const result = probe2.fgetxattr(fd, attribute);
|
|
20819
|
+
const code = errno.get();
|
|
20820
|
+
if (result !== -1 && result !== -1n)
|
|
20821
|
+
return "present";
|
|
20822
|
+
if (code === LINUX_ENODATA)
|
|
20823
|
+
return "absent";
|
|
20824
|
+
if (code === LINUX_EOPNOTSUPP)
|
|
20825
|
+
return "unsupported";
|
|
20826
|
+
}
|
|
20827
|
+
return "unverified";
|
|
20828
|
+
}
|
|
20829
|
+
function linuxAccessAclAbsent(probe2, fd, creationParent) {
|
|
20830
|
+
if (probe2.arch !== "x64" && probe2.arch !== "arm64")
|
|
20831
|
+
return false;
|
|
20832
|
+
const errno = probe2.errno;
|
|
20833
|
+
if (!errno)
|
|
20834
|
+
return false;
|
|
20835
|
+
let unsupported = false;
|
|
20836
|
+
for (const attribute of ["system.posix_acl_access", ...creationParent ? ["system.posix_acl_default"] : []]) {
|
|
20837
|
+
const state = queryAttribute(probe2, errno, fd, attribute);
|
|
20838
|
+
if (state === "present" || state === "unverified")
|
|
20839
|
+
return false;
|
|
20840
|
+
if (state === "unsupported")
|
|
20841
|
+
unsupported = true;
|
|
20842
|
+
}
|
|
20843
|
+
if (!unsupported)
|
|
20844
|
+
return true;
|
|
20845
|
+
const type = probe2.filesystemType(fd);
|
|
20846
|
+
return type !== null && LINUX_ACL_FREE_WHEN_UNSUPPORTED.has(type);
|
|
20847
|
+
}
|
|
20848
|
+
function withGlibcAclProbe(use) {
|
|
20849
|
+
try {
|
|
20850
|
+
const { dlopen, ptr, read: read2, FFIType } = __require("bun:ffi");
|
|
20851
|
+
const library = dlopen("libc.so.6", {
|
|
20852
|
+
fgetxattr: { args: ["i32", "ptr", "ptr", "u64"], returns: FFIType.i64_fast },
|
|
20853
|
+
fstatfs: { args: ["i32", "ptr"], returns: "i32" },
|
|
20854
|
+
__errno_location: { args: [], returns: "ptr" }
|
|
20855
|
+
});
|
|
20856
|
+
try {
|
|
20857
|
+
const location = library.symbols.__errno_location();
|
|
20858
|
+
const names = new Map;
|
|
20859
|
+
return use({
|
|
20860
|
+
arch: process.arch,
|
|
20861
|
+
errno: location ? { get: () => read2.i32(location) } : null,
|
|
20862
|
+
fgetxattr: (fd, attribute) => {
|
|
20863
|
+
let name = names.get(attribute);
|
|
20864
|
+
if (!name)
|
|
20865
|
+
names.set(attribute, name = Buffer.from(attribute + "\x00"));
|
|
20866
|
+
return library.symbols.fgetxattr(fd, ptr(name), null, 0);
|
|
20867
|
+
},
|
|
20868
|
+
filesystemType: (fd) => {
|
|
20869
|
+
const statfs = new BigUint64Array(32);
|
|
20870
|
+
return library.symbols.fstatfs(fd, ptr(statfs)) === 0 ? statfs[0] : null;
|
|
20871
|
+
}
|
|
20872
|
+
});
|
|
20873
|
+
} finally {
|
|
20874
|
+
library.close();
|
|
20875
|
+
}
|
|
20876
|
+
} catch {
|
|
20877
|
+
return false;
|
|
20878
|
+
}
|
|
20879
|
+
}
|
|
20880
|
+
|
|
20805
20881
|
// src/lib/retained-review-artifacts.ts
|
|
20806
20882
|
import { createHash as createHash29 } from "crypto";
|
|
20807
20883
|
import { constants as constants18, closeSync as closeSync17, fstatSync as fstatSync17, fsyncSync as fsyncSync6, lstatSync as lstatSync29, mkdirSync as mkdirSync8, openSync as openSync17, readSync as readSync12, writeSync as writeSync4 } from "fs";
|
|
@@ -21796,28 +21872,7 @@ function hookProjectionRefusal(reason2) {
|
|
|
21796
21872
|
throw new Error(`CLAUDE_MANAGED_HOOK_${reason2}`);
|
|
21797
21873
|
}
|
|
21798
21874
|
function hasNoLinuxAccessAcl(fd, creationParent) {
|
|
21799
|
-
|
|
21800
|
-
const { dlopen, read: read2, ptr } = __require("bun:ffi");
|
|
21801
|
-
const library = dlopen("libc.so.6", {
|
|
21802
|
-
fgetxattr: { args: ["i32", "ptr", "ptr", "u64"], returns: "i64" },
|
|
21803
|
-
__errno_location: { args: [], returns: "ptr" }
|
|
21804
|
-
});
|
|
21805
|
-
try {
|
|
21806
|
-
const errno = library.symbols.__errno_location();
|
|
21807
|
-
if (!errno)
|
|
21808
|
-
return false;
|
|
21809
|
-
for (const attribute of ["system.posix_acl_access", ...creationParent ? ["system.posix_acl_default"] : []]) {
|
|
21810
|
-
const name = Buffer.from(attribute + "\x00");
|
|
21811
|
-
if (Number(library.symbols.fgetxattr(fd, ptr(name), null, 0)) !== -1 || read2.i32(errno) !== 61)
|
|
21812
|
-
return false;
|
|
21813
|
-
}
|
|
21814
|
-
return true;
|
|
21815
|
-
} finally {
|
|
21816
|
-
library.close();
|
|
21817
|
-
}
|
|
21818
|
-
} catch {
|
|
21819
|
-
return false;
|
|
21820
|
-
}
|
|
21875
|
+
return withGlibcAclProbe((probe2) => linuxAccessAclAbsent(probe2, fd, creationParent));
|
|
21821
21876
|
}
|
|
21822
21877
|
function assertNativePathAcl(path, observed, options = {}) {
|
|
21823
21878
|
if (process.platform !== "darwin" && process.platform !== "linux")
|
|
@@ -22758,7 +22813,7 @@ function planCodexPluginNameReconcile(request) {
|
|
|
22758
22813
|
pathDenies: [...pathDenies].sort(),
|
|
22759
22814
|
...discovery ? { discovery } : {}
|
|
22760
22815
|
};
|
|
22761
|
-
const plan = planAgentIntegration({ home, dataDir: dataDir2, projectDir, agents: ["codex"], codexNativeCatalog: catalog, codexReconcile: input });
|
|
22816
|
+
const plan = planAgentIntegration({ home, dataDir: dataDir2, projectDir, agents: ["codex"], codexNativeCatalog: catalog, codexReconcile: input, allowRootAliases: aliases.length > 0 });
|
|
22762
22817
|
assertCodexReconcileScope(plan, { configPath, policyPath, prior, names, remoteIdentities, discovery: discovery ?? savedDiscovery });
|
|
22763
22818
|
const configChange = plan.changes.find((change) => resolve24(change.path) === configPath);
|
|
22764
22819
|
const plannedRules = configChange ? Bun.TOML.parse(configChange.after).skills?.config ?? [] : [];
|
|
@@ -25764,6 +25819,19 @@ function discoveryRootUnresolved(agent, command, detail) {
|
|
|
25764
25819
|
function isDiscoveryRootUnresolved(error) {
|
|
25765
25820
|
return error instanceof Error && error.message.startsWith(`${DISCOVERY_ROOT_UNRESOLVED}: `);
|
|
25766
25821
|
}
|
|
25822
|
+
|
|
25823
|
+
class NativeDiscoveryUnresolved extends Error {
|
|
25824
|
+
agent;
|
|
25825
|
+
detail;
|
|
25826
|
+
source;
|
|
25827
|
+
reviewable = false;
|
|
25828
|
+
constructor(agent, detail, source) {
|
|
25829
|
+
super(`Native discovery is unresolved (${agent}: ${detail}); provide a reviewed --discovery-inputs file`);
|
|
25830
|
+
this.agent = agent;
|
|
25831
|
+
this.detail = detail;
|
|
25832
|
+
this.source = source;
|
|
25833
|
+
}
|
|
25834
|
+
}
|
|
25767
25835
|
var quotedPath = (path) => JSON.stringify(path).replace(/[^\x20-\x7e]/g, (character) => `\\u${character.charCodeAt(0).toString(16).padStart(4, "0")}`);
|
|
25768
25836
|
var realpathOrNull = (path) => {
|
|
25769
25837
|
try {
|
|
@@ -26733,9 +26801,96 @@ function nativeDiscoveryAliasTargets(roots, home) {
|
|
|
26733
26801
|
}
|
|
26734
26802
|
return [...targets];
|
|
26735
26803
|
}
|
|
26804
|
+
function hooksAreManagedBridge(agent, hooks, managed) {
|
|
26805
|
+
const table = (value) => Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
26806
|
+
const exactKeys3 = (value, keys2) => Object.keys(value).sort().join("\x00") === [...keys2].sort().join("\x00");
|
|
26807
|
+
if (!table(hooks) || typeof managed.command !== "string" || !isAbsolute28(managed.command))
|
|
26808
|
+
return false;
|
|
26809
|
+
const events3 = agent === "gemini" ? ["BeforeAgent", "SessionStart", "BeforeTool"] : ["beforeSubmitPrompt", "sessionStart"];
|
|
26810
|
+
for (const [event, entries] of Object.entries(hooks)) {
|
|
26811
|
+
if (!events3.includes(event) || !Array.isArray(entries) || entries.length !== 1)
|
|
26812
|
+
return false;
|
|
26813
|
+
let expected;
|
|
26814
|
+
try {
|
|
26815
|
+
expected = renderAgentHookCommand(managed.command, agent, managed.profile, event);
|
|
26816
|
+
} catch {
|
|
26817
|
+
return false;
|
|
26818
|
+
}
|
|
26819
|
+
const entry = entries[0];
|
|
26820
|
+
if (!table(entry))
|
|
26821
|
+
return false;
|
|
26822
|
+
if (agent === "cursor") {
|
|
26823
|
+
if (!exactKeys3(entry, ["command", "timeout"]) || entry.timeout !== 15 || entry.command !== expected)
|
|
26824
|
+
return false;
|
|
26825
|
+
continue;
|
|
26826
|
+
}
|
|
26827
|
+
if (!exactKeys3(entry, event === "BeforeTool" ? ["hooks", "matcher"] : ["hooks"]) || event === "BeforeTool" && entry.matcher !== "activate_skill" || !Array.isArray(entry.hooks) || entry.hooks.length !== 1)
|
|
26828
|
+
return false;
|
|
26829
|
+
const hook = entry.hooks[0];
|
|
26830
|
+
if (!table(hook) || !exactKeys3(hook, ["command", "timeout", "type"]) || hook.type !== "command" || hook.timeout !== 15000 || hook.command !== expected)
|
|
26831
|
+
return false;
|
|
26832
|
+
}
|
|
26833
|
+
return true;
|
|
26834
|
+
}
|
|
26835
|
+
function sumiPluginLoadsOnlyBuiltins(text2) {
|
|
26836
|
+
for (const match of text2.matchAll(/\b(?:import|require)\s*\(\s*(.?)/g)) {
|
|
26837
|
+
const rest = text2.slice(match.index + match[0].length - match[1].length);
|
|
26838
|
+
if (!/^(['"])node:[A-Za-z0-9_/.-]+\1/.test(rest))
|
|
26839
|
+
return false;
|
|
26840
|
+
}
|
|
26841
|
+
for (const match of text2.matchAll(/\b(?:from|import)\s*(['"])([^'"]*)\1/g))
|
|
26842
|
+
if (!match[2].startsWith("node:"))
|
|
26843
|
+
return false;
|
|
26844
|
+
return true;
|
|
26845
|
+
}
|
|
26846
|
+
var CODEX_MARKETPLACE_TIMESTAMP = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,9})?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
26847
|
+
function codexRootFreeControls(config) {
|
|
26848
|
+
const table = (value) => Boolean(value && typeof value === "object" && !Array.isArray(value) && !(value instanceof Date));
|
|
26849
|
+
const adapted = [];
|
|
26850
|
+
const servers = config.mcp_servers;
|
|
26851
|
+
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)))
|
|
26852
|
+
adapted.push("mcp_servers");
|
|
26853
|
+
const agents = config.agents;
|
|
26854
|
+
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)))
|
|
26855
|
+
adapted.push("agents");
|
|
26856
|
+
return adapted;
|
|
26857
|
+
}
|
|
26858
|
+
var CODEX_HOOK_EVENTS = new Set(["PreToolUse", "PermissionRequest", "PostToolUse", "PreCompact", "PostCompact", "SessionStart", "SessionEnd", "UserPromptSubmit", "SubagentStart", "SubagentStop", "Stop", "Interrupt"]);
|
|
26859
|
+
function codexPluginHookHandlers(value) {
|
|
26860
|
+
const table = (item) => Boolean(item && typeof item === "object" && !Array.isArray(item));
|
|
26861
|
+
const identifier6 = (item) => typeof item === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(item);
|
|
26862
|
+
const text2 = (item) => typeof item === "string" && item.length <= AGENT_POLICY_LIMITS.pathCharacters && !item.includes("\x00");
|
|
26863
|
+
if (!table(value) || !Object.keys(value).every((key2) => key2 === "hooks" || key2 === "description") || value.description !== undefined && !text2(value.description) || !table(value.hooks) || Object.keys(value.hooks).length > 32)
|
|
26864
|
+
return null;
|
|
26865
|
+
const result = { commands: 0, servers: new Set };
|
|
26866
|
+
for (const [event, groups] of Object.entries(value.hooks)) {
|
|
26867
|
+
if (!CODEX_HOOK_EVENTS.has(event) || !Array.isArray(groups) || groups.length > 32)
|
|
26868
|
+
return null;
|
|
26869
|
+
for (const group of groups) {
|
|
26870
|
+
if (!table(group) || !Object.keys(group).every((key2) => key2 === "hooks" || key2 === "matcher") || group.matcher !== undefined && !text2(group.matcher) || !Array.isArray(group.hooks) || group.hooks.length > 32)
|
|
26871
|
+
return null;
|
|
26872
|
+
for (const handler of group.hooks) {
|
|
26873
|
+
if (!table(handler) || handler.timeout !== undefined && !(Number.isSafeInteger(handler.timeout) && handler.timeout >= 0) || handler.statusMessage !== undefined && !text2(handler.statusMessage))
|
|
26874
|
+
return null;
|
|
26875
|
+
if (handler.type === "command") {
|
|
26876
|
+
if (!text2(handler.command) || !handler.command || !Object.keys(handler).every((key2) => ["type", "command", "commandWindows", "command_windows", "timeout", "async", "statusMessage", "additionalContextLimit"].includes(key2)))
|
|
26877
|
+
return null;
|
|
26878
|
+
result.commands++;
|
|
26879
|
+
} else if (handler.type === "mcp_tool") {
|
|
26880
|
+
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)))
|
|
26881
|
+
return null;
|
|
26882
|
+
result.servers.add(handler.server);
|
|
26883
|
+
} else
|
|
26884
|
+
return null;
|
|
26885
|
+
}
|
|
26886
|
+
}
|
|
26887
|
+
}
|
|
26888
|
+
return result;
|
|
26889
|
+
}
|
|
26736
26890
|
function resolveDiscovery(options, exclusion) {
|
|
26737
26891
|
const canonical9 = options.canonical ?? resolve28, home = resolve28(options.home), agent = options.agent;
|
|
26738
26892
|
const sources = [], roots = new Set, builtinNames = [];
|
|
26893
|
+
const sumiLocalPluginTexts = new Map;
|
|
26739
26894
|
const budget3 = discoveryByteBudget();
|
|
26740
26895
|
let remainingEntries = AGENT_POLICY_LIMITS.discoveryDirectoryEntries;
|
|
26741
26896
|
const entries = (path) => {
|
|
@@ -26772,8 +26927,8 @@ function resolveDiscovery(options, exclusion) {
|
|
|
26772
26927
|
const configPath = exclusion?.nativeHome === undefined ? agentDiscoveryConfigPath(home, agent) : join41(nativeHome, agent === "codex" ? "config.toml" : "settings.json");
|
|
26773
26928
|
const configText = witness(configPath, agent === "hermes" ? "yaml" : agent === "codex" ? "toml" : "json", agent === "hermes" ? ["skills", "plugins", "hooks"] : agent === "claude" ? ["enabledPlugins", "extraKnownMarketplaces"] : agent === "codex" ? [...CODEX_DISCOVERY_PROJECTION_FIELDS] : agent === "gemini" ? ["skills", "extensions", "security"] : agent === "opencode" ? ["plugin", "skills"] : agent === "sumi" ? [...SUMI_DISCOVERY_PROJECTION_FIELDS] : ["version"]);
|
|
26774
26929
|
const config = configText === null ? {} : agent === "hermes" ? parseHermesConfig(configText) : parseConfig(configText, configPath, agent === "codex");
|
|
26775
|
-
const unresolved = (detail) => {
|
|
26776
|
-
throw new
|
|
26930
|
+
const unresolved = (detail, source) => {
|
|
26931
|
+
throw new NativeDiscoveryUnresolved(agent, detail, source);
|
|
26777
26932
|
};
|
|
26778
26933
|
let opaqueClosureVerified = false;
|
|
26779
26934
|
const verifyOpaqueClosure = (declarations) => {
|
|
@@ -26787,6 +26942,17 @@ function resolveDiscovery(options, exclusion) {
|
|
|
26787
26942
|
verifyDiscovery(retained, undefined, undefined, undefined, exclusion?.narrowed, canonical9(configPath));
|
|
26788
26943
|
opaqueClosureVerified = true;
|
|
26789
26944
|
};
|
|
26945
|
+
const reviewRemedy = (source, check) => {
|
|
26946
|
+
try {
|
|
26947
|
+
check();
|
|
26948
|
+
} catch (error) {
|
|
26949
|
+
if (error instanceof NativeDiscoveryUnresolved) {
|
|
26950
|
+
error.reviewable = true;
|
|
26951
|
+
error.source ??= source;
|
|
26952
|
+
}
|
|
26953
|
+
throw error;
|
|
26954
|
+
}
|
|
26955
|
+
};
|
|
26790
26956
|
if (exclusion) {
|
|
26791
26957
|
if (configText !== null && agent !== "codex" && agent !== "hermes")
|
|
26792
26958
|
parseNativeJsonObject(configText);
|
|
@@ -26812,12 +26978,38 @@ function resolveDiscovery(options, exclusion) {
|
|
|
26812
26978
|
const controls = agent === "claude" ? claudeDiscoveryControlKeys(configText ?? "{}") : agent === "codex" ? codexDiscoveryControlKeys(config) : Object.keys(config).filter((key2) => /skill|plugin|hook|marketplace|extension|instruction/i.test(key2));
|
|
26813
26979
|
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]";
|
|
26814
26980
|
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))}`);
|
|
26815
|
-
const
|
|
26981
|
+
const adapted = agent === "codex" ? codexRootFreeControls(config) : agent === "opencode" && Array.isArray(config.instructions) && config.instructions.length === 0 ? ["instructions"] : [];
|
|
26982
|
+
const unsupportedControls = controls.filter((key2) => !supported[agent].includes(key2) && !adapted.includes(key2));
|
|
26816
26983
|
if (unsupportedControls.length)
|
|
26817
26984
|
unsupportedFields(unsupportedControls, "");
|
|
26818
26985
|
if (config.hooks !== undefined && !object6(config.hooks))
|
|
26819
26986
|
unresolved("hooks must be an object");
|
|
26820
|
-
const
|
|
26987
|
+
const managedSupervisorOnly = () => {
|
|
26988
|
+
const supervisor = exclusion.managedHook?.supervisor;
|
|
26989
|
+
if (agent !== "hermes" || !supervisor || typeof supervisor.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(supervisor.sha256) || !object6(config.hooks))
|
|
26990
|
+
return false;
|
|
26991
|
+
let expected;
|
|
26992
|
+
try {
|
|
26993
|
+
expected = hermesHookDefinitions(supervisor);
|
|
26994
|
+
} catch {
|
|
26995
|
+
return false;
|
|
26996
|
+
}
|
|
26997
|
+
for (const [event, entries2] of Object.entries(config.hooks)) {
|
|
26998
|
+
const want = expected[event];
|
|
26999
|
+
if (!want || !Array.isArray(entries2) || entries2.length !== 1 || !object6(entries2[0]))
|
|
27000
|
+
return false;
|
|
27001
|
+
const entry = entries2[0];
|
|
27002
|
+
if (Object.keys(entry).sort().join("\x00") !== Object.keys(want).sort().join("\x00") || Object.keys(want).some((key2) => entry[key2] !== want[key2]))
|
|
27003
|
+
return false;
|
|
27004
|
+
}
|
|
27005
|
+
try {
|
|
27006
|
+
return hashRawDiscoveryFile(canonical9(supervisor.path), budget3) === supervisor.sha256;
|
|
27007
|
+
} catch {
|
|
27008
|
+
return false;
|
|
27009
|
+
}
|
|
27010
|
+
};
|
|
27011
|
+
const managedBridgeOnly = (agent === "gemini" || agent === "cursor") && exclusion.managedHook !== undefined && hooksAreManagedBridge(agent, config.hooks, exclusion.managedHook) || managedSupervisorOnly();
|
|
27012
|
+
const hasHooks = controls.includes("hooks") && config.hooks !== undefined && Object.keys(config.hooks).length > 0 && !managedBridgeOnly;
|
|
26821
27013
|
let hasPluginConfigs = false, hasFunctionHookEnvironment = false;
|
|
26822
27014
|
const verifyCurrentOpaqueSettings = (label) => {
|
|
26823
27015
|
const retained = exclusion.retained;
|
|
@@ -26832,7 +27024,7 @@ function resolveDiscovery(options, exclusion) {
|
|
|
26832
27024
|
unresolved(`non-enumerable ${label} require a current settings review`);
|
|
26833
27025
|
};
|
|
26834
27026
|
if (hasHooks)
|
|
26835
|
-
verifyCurrentOpaqueSettings("hooks");
|
|
27027
|
+
reviewRemedy(canonical9(configPath), () => verifyCurrentOpaqueSettings("hooks"));
|
|
26836
27028
|
if (agent === "claude") {
|
|
26837
27029
|
if (config.env !== undefined) {
|
|
26838
27030
|
if (!object6(config.env) || Object.keys(config.env).length > 512)
|
|
@@ -26845,7 +27037,7 @@ function resolveDiscovery(options, exclusion) {
|
|
|
26845
27037
|
if (hasFunctionHookEnvironment) {
|
|
26846
27038
|
if (!["0", "1"].includes(config.env.CLAUDE_CODE_ENABLE_FUNCTION_HOOKS))
|
|
26847
27039
|
unresolved("malformed Claude env.CLAUDE_CODE_ENABLE_FUNCTION_HOOKS flag");
|
|
26848
|
-
verifyCurrentOpaqueSettings("function-hook environment controls");
|
|
27040
|
+
reviewRemedy(canonical9(configPath), () => verifyCurrentOpaqueSettings("function-hook environment controls"));
|
|
26849
27041
|
}
|
|
26850
27042
|
}
|
|
26851
27043
|
if (config.pluginConfigs !== undefined) {
|
|
@@ -26872,7 +27064,7 @@ function resolveDiscovery(options, exclusion) {
|
|
|
26872
27064
|
}
|
|
26873
27065
|
hasPluginConfigs = Object.keys(config.pluginConfigs).length > 0;
|
|
26874
27066
|
if (hasPluginConfigs)
|
|
26875
|
-
verifyCurrentOpaqueSettings("plugin configurations");
|
|
27067
|
+
reviewRemedy(canonical9(configPath), () => verifyCurrentOpaqueSettings("plugin configurations"));
|
|
26876
27068
|
}
|
|
26877
27069
|
if (config.enabledPlugins !== undefined && !object6(config.enabledPlugins))
|
|
26878
27070
|
unresolved("enabledPlugins must be an object");
|
|
@@ -26922,7 +27114,9 @@ function resolveDiscovery(options, exclusion) {
|
|
|
26922
27114
|
unresolved("malformed Sumi plugins");
|
|
26923
27115
|
}
|
|
26924
27116
|
if (agent === "hermes" && config.skills !== undefined) {
|
|
26925
|
-
keys2(config.skills, ["external_dirs"], "Hermes skills");
|
|
27117
|
+
keys2(config.skills, ["external_dirs", "creation_nudge_interval"], "Hermes skills");
|
|
27118
|
+
if (config.skills.creation_nudge_interval !== undefined && !(Number.isSafeInteger(config.skills.creation_nudge_interval) && config.skills.creation_nudge_interval >= 0))
|
|
27119
|
+
unresolved("malformed Hermes skills creation_nudge_interval");
|
|
26926
27120
|
if (config.skills.external_dirs !== undefined)
|
|
26927
27121
|
paths(typeof config.skills.external_dirs === "string" ? [config.skills.external_dirs] : config.skills.external_dirs, "Hermes external directories");
|
|
26928
27122
|
}
|
|
@@ -26942,10 +27136,21 @@ function resolveDiscovery(options, exclusion) {
|
|
|
26942
27136
|
unresolved(`malformed Codex ${key2}`);
|
|
26943
27137
|
for (const value of Object.values(config.plugins ?? {}))
|
|
26944
27138
|
keys2(value, ["enabled"], "Codex plugin registration");
|
|
26945
|
-
for (const value of Object.values(config.marketplaces ?? {}))
|
|
26946
|
-
keys2(value, ["source_type", "source"], "Codex marketplace registration");
|
|
27139
|
+
for (const value of Object.values(config.marketplaces ?? {})) {
|
|
27140
|
+
keys2(value, ["source_type", "source", "last_updated"], "Codex marketplace registration");
|
|
27141
|
+
if (value.last_updated !== undefined && (typeof value.last_updated !== "string" || !CODEX_MARKETPLACE_TIMESTAMP.test(value.last_updated)))
|
|
27142
|
+
unresolved("malformed Codex marketplace refresh time");
|
|
27143
|
+
}
|
|
26947
27144
|
if (config.skills !== undefined)
|
|
26948
|
-
keys2(config.skills, ["config", "bundled"], "Codex skills");
|
|
27145
|
+
keys2(config.skills, ["config", "bundled", "native_allowed_paths"], "Codex skills");
|
|
27146
|
+
if (config.skills?.native_allowed_paths !== undefined) {
|
|
27147
|
+
for (const value of paths(config.skills.native_allowed_paths, "Codex native allowed skill paths")) {
|
|
27148
|
+
if (!isAbsolute28(value))
|
|
27149
|
+
unresolved("relative Codex native allowed skill path");
|
|
27150
|
+
const path = canonical9(value);
|
|
27151
|
+
roots.add(path.endsWith(`${sep15}SKILL.md`) ? dirname29(path) : path);
|
|
27152
|
+
}
|
|
27153
|
+
}
|
|
26949
27154
|
if (config.skills?.bundled !== undefined) {
|
|
26950
27155
|
keys2(config.skills.bundled, ["enabled"], "Codex bundled skills");
|
|
26951
27156
|
if (typeof config.skills.bundled.enabled !== "boolean")
|
|
@@ -26971,7 +27176,7 @@ function resolveDiscovery(options, exclusion) {
|
|
|
26971
27176
|
if (Object.keys(config.enabledPlugins ?? config.plugins ?? config.extensions ?? {}).length > 512)
|
|
26972
27177
|
unresolved("unbounded native registrations");
|
|
26973
27178
|
if (hasHooks || hasPluginConfigs || hasFunctionHookEnvironment)
|
|
26974
|
-
verifyOpaqueClosure([]);
|
|
27179
|
+
reviewRemedy(canonical9(configPath), () => verifyOpaqueClosure([]));
|
|
26975
27180
|
}
|
|
26976
27181
|
if (options.reviewed && (options.reviewed.version !== 1 || !Array.isArray(options.reviewed.agents) || options.reviewed.agents.some((item) => !item || typeof item !== "object") || new Set(options.reviewed.agents.map((item) => item.agent)).size !== options.reviewed.agents.length))
|
|
26977
27182
|
throw new Error("Invalid --discovery-inputs version or agents");
|
|
@@ -27003,7 +27208,9 @@ function resolveDiscovery(options, exclusion) {
|
|
|
27003
27208
|
const target = join41(path, name);
|
|
27004
27209
|
if (!lstatSync34(target).isFile())
|
|
27005
27210
|
unresolved("local plugin packages need a dedicated discovery adapter");
|
|
27006
|
-
witness(target);
|
|
27211
|
+
const text2 = witness(target);
|
|
27212
|
+
if (exclusion && text2 !== null)
|
|
27213
|
+
sumiLocalPluginTexts.set(canonical9(target), text2);
|
|
27007
27214
|
}
|
|
27008
27215
|
}
|
|
27009
27216
|
for (const root2 of roots) {
|
|
@@ -27137,38 +27344,126 @@ function resolveDiscovery(options, exclusion) {
|
|
|
27137
27344
|
const unique = combined.filter((source, index) => combined.findIndex((candidate2) => isDeepStrictEqual9(candidate2, source)) === index);
|
|
27138
27345
|
return { ...supplied, roots: [...new Set([...roots, ...supplied.roots])].sort(), sources: unique, ...agent === "gemini" ? { builtinNames } : {} };
|
|
27139
27346
|
}
|
|
27140
|
-
|
|
27347
|
+
const reviewedManifestAbsence = (root2, manifestPath) => {
|
|
27348
|
+
const retained = exclusion?.retained;
|
|
27349
|
+
if (agent !== "claude" || retained?.method !== "reviewed" || ![join41(root2, "skills"), root2].some((path) => retained.roots.includes(path)))
|
|
27350
|
+
return false;
|
|
27351
|
+
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);
|
|
27352
|
+
return saved.length > 0 && saved.every((source) => projected(source, undefined, budget3) === source.sha256);
|
|
27353
|
+
};
|
|
27354
|
+
const reviewedInstalledCopy = (root2, path, identity5) => {
|
|
27355
|
+
const retained = exclusion?.retained;
|
|
27356
|
+
if (agent !== "codex" || retained?.method !== "reviewed")
|
|
27357
|
+
return false;
|
|
27358
|
+
const inside = relative10(root2, canonical9(path));
|
|
27359
|
+
if (!inside || inside === ".." || inside.startsWith(`..${sep15}`) || isAbsolute28(inside))
|
|
27360
|
+
return false;
|
|
27361
|
+
const parent = canonical9(join41(nativeHome, "plugins/cache", identity5.marketplace, identity5.name));
|
|
27362
|
+
const current = hashRawDiscoveryFile(canonical9(path), budget3);
|
|
27363
|
+
if (current === null)
|
|
27364
|
+
return false;
|
|
27365
|
+
return retained.sources.some((source) => {
|
|
27366
|
+
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 + sep15))
|
|
27367
|
+
return false;
|
|
27368
|
+
const [version2, ...rest] = source.path.slice(parent.length + 1).split(sep15);
|
|
27369
|
+
return Boolean(version2) && version2 !== "." && version2 !== ".." && rest.join(sep15) === inside;
|
|
27370
|
+
});
|
|
27371
|
+
};
|
|
27372
|
+
const verifyCodexPluginHookClosure = (root2, identity5, marketplaceSource, servers, declarations) => {
|
|
27373
|
+
const retained = exclusion.retained;
|
|
27374
|
+
if (retained.codexSemanticCache || retained.codexInstallationInputs || retained.codexRetiredMaterializations)
|
|
27375
|
+
return verifyOpaqueClosure(declarations);
|
|
27376
|
+
const within2 = (base, path) => path === base || path.startsWith(base + sep15);
|
|
27377
|
+
const executables = [];
|
|
27378
|
+
for (const server of servers) {
|
|
27379
|
+
const row = config.mcp_servers?.[server];
|
|
27380
|
+
if (server === "codex_apps" || server === "_codex_apps" || !isCodexLocalStdioMcpServer(server, row))
|
|
27381
|
+
unresolved("plugin hook MCP server is not a configured local stdio server");
|
|
27382
|
+
for (const value of [row.command, ...row.args ?? []])
|
|
27383
|
+
for (const candidate2 of [value, value.slice(value.indexOf("=") + 1)]) {
|
|
27384
|
+
if (!isAbsolute28(candidate2) || /[\0$]/.test(candidate2) || executables.length >= AGENT_POLICY_LIMITS.discoveryRoots)
|
|
27385
|
+
continue;
|
|
27386
|
+
const path = canonical9(candidate2);
|
|
27387
|
+
if (lstatSync34(path, { throwIfNoEntry: false })?.isFile())
|
|
27388
|
+
executables.push(path);
|
|
27389
|
+
}
|
|
27390
|
+
}
|
|
27391
|
+
const cacheRoot = canonical9(join41(nativeHome, "plugins/cache"));
|
|
27392
|
+
const ownCache = canonical9(join41(nativeHome, "plugins/cache", identity5.marketplace, identity5.name));
|
|
27393
|
+
const ownCatalog = canonical9(join41(marketplaceSource, ".agents/plugins/marketplace.json"));
|
|
27394
|
+
const account = canonical9(home);
|
|
27395
|
+
const marketplaceRoots = Object.values(config.marketplaces ?? {}).filter((market) => market?.source_type === "local" && typeof market.source === "string" && isAbsolute28(market.source)).map((market) => canonical9(market.source)).filter((path) => !within2(path, account));
|
|
27396
|
+
const otherPlugin = (path) => !within2(root2, path) && !within2(ownCache, path) && path !== ownCatalog && !executables.includes(path) && (within2(cacheRoot, path) || marketplaceRoots.some((base) => within2(base, path)));
|
|
27397
|
+
const sources2 = retained.sources.filter((source) => source.path !== canonical9(configPath) && !otherPlugin(source.path));
|
|
27398
|
+
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)))
|
|
27399
|
+
return verifyOpaqueClosure(declarations);
|
|
27400
|
+
const declared = declarations.map((path) => relative10(root2, path));
|
|
27401
|
+
const declaration = (path) => declarations.includes(path) || path.startsWith(ownCache + sep15) && declared.includes(path.slice(ownCache.length + 1).split(sep15).slice(1).join(sep15));
|
|
27402
|
+
if (!sources2.some((source) => !declaration(source.path) && source.sha256 !== null))
|
|
27403
|
+
unresolved("opaque executable dependency closure is unavailable");
|
|
27404
|
+
for (const source of sources2)
|
|
27405
|
+
if (projected(source, undefined, budget3) !== source.sha256) {
|
|
27406
|
+
throw new NativeDiscoveryWitnessChange("input", source.path, `Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
27407
|
+
}
|
|
27408
|
+
verifyDiscoveryDirectories((retained.directories ?? []).filter((directory2) => !otherPlugin(directory2.path)));
|
|
27409
|
+
};
|
|
27410
|
+
const readCodexHookDeclaration = (text2, path) => {
|
|
27411
|
+
if (text2 === null)
|
|
27412
|
+
return null;
|
|
27413
|
+
try {
|
|
27414
|
+
return codexPluginHookHandlers(parseConfig(text2, path));
|
|
27415
|
+
} catch {
|
|
27416
|
+
return null;
|
|
27417
|
+
}
|
|
27418
|
+
};
|
|
27419
|
+
function plugin(root2, codex) {
|
|
27141
27420
|
root2 = canonical9(root2);
|
|
27142
27421
|
safe6(root2);
|
|
27143
27422
|
if (exclusion)
|
|
27144
27423
|
roots.add(root2);
|
|
27145
27424
|
const manifestPath = join41(root2, agent === "claude" ? ".claude-plugin/plugin.json" : ".codex-plugin/plugin.json");
|
|
27146
27425
|
const raw = witness(manifestPath, undefined, undefined, agent === "claude" ? "claude-plugin-manifest-v1" : undefined);
|
|
27147
|
-
if (raw === null)
|
|
27426
|
+
if (raw === null && !reviewedManifestAbsence(root2, manifestPath))
|
|
27148
27427
|
unresolved("plugin manifest missing");
|
|
27149
|
-
const manifest = parseConfig(raw, manifestPath);
|
|
27428
|
+
const manifest = raw === null ? {} : parseConfig(raw, manifestPath);
|
|
27150
27429
|
if (exclusion && Object.keys(manifest).some((key2) => /skill|plugin|hook|marketplace|extension|instruction/i.test(key2) && !["skills", "hooks"].includes(key2)))
|
|
27151
27430
|
unresolved("unknown plugin discovery controls");
|
|
27152
27431
|
const hooks = witness(join41(root2, "hooks/hooks.json"));
|
|
27153
|
-
if (manifest.hooks !== undefined || hooks !== null)
|
|
27154
|
-
|
|
27155
|
-
|
|
27156
|
-
|
|
27157
|
-
|
|
27158
|
-
|
|
27159
|
-
|
|
27160
|
-
|
|
27161
|
-
|
|
27162
|
-
|
|
27163
|
-
|
|
27164
|
-
|
|
27165
|
-
|
|
27166
|
-
|
|
27167
|
-
|
|
27168
|
-
|
|
27169
|
-
|
|
27170
|
-
|
|
27171
|
-
|
|
27432
|
+
if (manifest.hooks !== undefined || hooks !== null)
|
|
27433
|
+
reviewRemedy(canonical9(hooks !== null ? join41(root2, "hooks/hooks.json") : manifestPath), () => {
|
|
27434
|
+
if (!exclusion || exclusion.retained?.method !== "reviewed")
|
|
27435
|
+
unresolved("plugin hooks require a separate no-skill-injection review");
|
|
27436
|
+
const required = [manifestPath, ...hooks !== null ? [join41(root2, "hooks/hooks.json")] : []];
|
|
27437
|
+
const scoped2 = agent === "codex" && codex !== undefined ? [] : undefined;
|
|
27438
|
+
if (manifest.hooks !== undefined) {
|
|
27439
|
+
if (scoped2 && manifest.hooks && typeof manifest.hooks === "object" && !Array.isArray(manifest.hooks)) {
|
|
27440
|
+
const inline = codexPluginHookHandlers(manifest.hooks);
|
|
27441
|
+
if (!inline)
|
|
27442
|
+
unresolved("unsupported inline plugin hooks");
|
|
27443
|
+
scoped2.push(inline);
|
|
27444
|
+
} else {
|
|
27445
|
+
if (typeof manifest.hooks !== "string")
|
|
27446
|
+
unresolved("unsupported plugin hooks target");
|
|
27447
|
+
const hook = resolve28(root2, manifest.hooks);
|
|
27448
|
+
if (!hook.startsWith(root2 + sep15))
|
|
27449
|
+
unresolved("plugin hooks target escapes its root");
|
|
27450
|
+
required.push(hook);
|
|
27451
|
+
if (scoped2)
|
|
27452
|
+
scoped2.push(readCodexHookDeclaration(witness(hook), hook));
|
|
27453
|
+
}
|
|
27454
|
+
}
|
|
27455
|
+
if (scoped2 && hooks !== null)
|
|
27456
|
+
scoped2.push(readCodexHookDeclaration(hooks, join41(root2, "hooks/hooks.json")));
|
|
27457
|
+
for (const path of required) {
|
|
27458
|
+
const saved = exclusion.retained.sources.filter((source) => source.path === canonical9(path) && source.sha256 !== null && source.format === undefined && source.fields === undefined);
|
|
27459
|
+
if (saved.length ? saved.some((source) => projected(source, undefined, budget3) !== source.sha256) : !(scoped2 && reviewedInstalledCopy(root2, path, codex)))
|
|
27460
|
+
unresolved("plugin hooks require current independently reviewed sources", canonical9(path));
|
|
27461
|
+
}
|
|
27462
|
+
if (scoped2 && scoped2.every((item) => item !== null && item.commands === 0)) {
|
|
27463
|
+
verifyCodexPluginHookClosure(root2, codex, codex.source, new Set(scoped2.flatMap((item) => [...item.servers])), required.map((path) => canonical9(path)));
|
|
27464
|
+
} else
|
|
27465
|
+
verifyOpaqueClosure(required.map((path) => canonical9(path)));
|
|
27466
|
+
});
|
|
27172
27467
|
const commands = join41(root2, "commands");
|
|
27173
27468
|
safe6(commands);
|
|
27174
27469
|
if (agent === "claude" && (manifest.commands !== undefined || lstatSync34(commands, { throwIfNoEntry: false })?.isDirectory() && entries(commands).length))
|
|
@@ -27223,7 +27518,7 @@ function resolveDiscovery(options, exclusion) {
|
|
|
27223
27518
|
const catalog = parseConfig(catalogText, join41(market.source, ".agents/plugins/marketplace.json")), matches = Array.isArray(catalog.plugins) ? catalog.plugins.filter((item) => item.name === name) : [];
|
|
27224
27519
|
if (matches.length !== 1 || matches[0]?.source?.source !== "local" || typeof matches[0]?.source?.path !== "string")
|
|
27225
27520
|
unresolved("plugin catalog source is missing or ambiguous");
|
|
27226
|
-
plugin(resolve28(market.source, matches[0].source.path));
|
|
27521
|
+
plugin(resolve28(market.source, matches[0].source.path), exclusion ? { marketplace, name, source: market.source } : undefined);
|
|
27227
27522
|
}
|
|
27228
27523
|
} else if (agent === "opencode") {
|
|
27229
27524
|
if (witness(join41(home, ".config/opencode/opencode.jsonc")) !== null || witness(join41(home, ".config/opencode/config.json")) !== null)
|
|
@@ -27240,7 +27535,11 @@ function resolveDiscovery(options, exclusion) {
|
|
|
27240
27535
|
if (lstatSync34(localPlugins, { throwIfNoEntry: false }) && entries(localPlugins).some((name) => name !== "skills-cli.js"))
|
|
27241
27536
|
unresolved("additional local plugin hooks require review");
|
|
27242
27537
|
} else if (agent === "sumi") {
|
|
27243
|
-
|
|
27538
|
+
const pinnedLocalPlugin = (source) => {
|
|
27539
|
+
const retained = exclusion?.retained, text2 = sumiLocalPluginTexts.get(source.path);
|
|
27540
|
+
return retained?.method === "reviewed" && text2 !== undefined && sumiPluginLoadsOnlyBuiltins(text2) && 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);
|
|
27541
|
+
};
|
|
27542
|
+
if ((config.plugin?.length ?? 0) > 0 || (config.plugins?.length ?? 0) > 0 || sources.some((source) => source.path !== canonical9(configPath) && source.path !== canonical9(join41(sumiConfigDirectory(home), "sumi.jsonc")) && source.sha256 !== null && !pinnedLocalPlugin(source)))
|
|
27244
27543
|
unresolved("external or foreign local plugins require review");
|
|
27245
27544
|
} else if (agent === "hermes") {
|
|
27246
27545
|
for (const directory2 of [join41(home, ".hermes/plugins"), join41(home, ".hermes/hermes-agent")]) {
|
|
@@ -27303,6 +27602,11 @@ function physicalPath(path) {
|
|
|
27303
27602
|
}
|
|
27304
27603
|
return resolve29(realpathSync14(cursor), ...suffix);
|
|
27305
27604
|
}
|
|
27605
|
+
function portableAuthoringDiscoveryRefusal(error, destination) {
|
|
27606
|
+
const head = `Native discovery is unresolved (${error.agent}: ${error.detail}).${error.source ? ` Checked source: ${error.source}.` : ""}`;
|
|
27607
|
+
const review = `skills hook install --agent ${error.agent} --discovery-inputs <reviewed-file> --apply`;
|
|
27608
|
+
return error.reviewable ? `${head} Portable Skills authoring stays refused: an unreviewed ${error.agent} hook or plugin option could load skills written to ${destination}. This command takes no --discovery-inputs option; review the current ${error.agent} configuration with ${review}, then retry.` : `${head} Portable Skills authoring stays refused: Skills cannot list every skill root this ${error.agent} configuration registers, so it cannot rule out ${destination}. This command takes no --discovery-inputs option; correct that ${error.agent} configuration entry, then retry. Where a reviewed discovery binding covers it, record one with ${review}.`;
|
|
27609
|
+
}
|
|
27306
27610
|
function contains2(root2, path) {
|
|
27307
27611
|
const boundary = root2.endsWith(sep16) ? root2 : root2 + sep16;
|
|
27308
27612
|
return path === root2 || path.startsWith(boundary);
|
|
@@ -27348,7 +27652,10 @@ function configuredRoots(home, explicitHome) {
|
|
|
27348
27652
|
if (recorded && (!executable2 || executable2.target !== recorded.target || onPath && onPath.target !== recorded.target) || !executable2 && (binding.builtinNames?.length || binding.agent === "gemini" && binding.sources.some((source) => basename18(source.path) === "package.json"))) {
|
|
27349
27653
|
throw new Error("Native discovery runtime target is unresolved or changed");
|
|
27350
27654
|
}
|
|
27351
|
-
|
|
27655
|
+
const managedCommand = current.commands?.[agent], managedProfile = current.profiles?.[agent];
|
|
27656
|
+
const supervisor = current.supervisors?.[agent];
|
|
27657
|
+
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;
|
|
27658
|
+
roots.push(...resolveAgentDiscoveryExclusionRoots({ home, agent: binding.agent, canonical: physicalPath, retained: binding, executable: executable2, narrowed, ...managedHook ? { managedHook } : {} }));
|
|
27352
27659
|
}
|
|
27353
27660
|
};
|
|
27354
27661
|
if (homePolicy)
|
|
@@ -27400,11 +27707,18 @@ function assertPortableAuthoringPath(path, options = {}) {
|
|
|
27400
27707
|
if (native) {
|
|
27401
27708
|
throw new Error(`Refusing portable Skills authoring below native discovery root '${native}': ${lexical}. Set HASNA_SKILLS_DIR to a private authoring corpus outside native roots.`);
|
|
27402
27709
|
}
|
|
27403
|
-
const roots =
|
|
27404
|
-
|
|
27405
|
-
|
|
27406
|
-
|
|
27407
|
-
|
|
27710
|
+
const roots = [];
|
|
27711
|
+
try {
|
|
27712
|
+
roots.push(...configuredRoots(home, options.homeDir !== undefined));
|
|
27713
|
+
for (const value of selected) {
|
|
27714
|
+
if (physicalPath(value.path) === physicalPath(join42(home, `.${value.agent}`)))
|
|
27715
|
+
continue;
|
|
27716
|
+
roots.push(...resolveAgentDiscoveryExclusionRoots({ home, agent: value.agent, nativeHome: value.path, canonical: physicalPath, executable: null }));
|
|
27717
|
+
}
|
|
27718
|
+
} catch (error) {
|
|
27719
|
+
if (error instanceof NativeDiscoveryUnresolved)
|
|
27720
|
+
throw new Error(portableAuthoringDiscoveryRefusal(error, lexical));
|
|
27721
|
+
throw error;
|
|
27408
27722
|
}
|
|
27409
27723
|
for (const root2 of roots) {
|
|
27410
27724
|
if (candidates.some((candidate2) => [resolve29(root2), physicalPath(root2)].some((nativeRoot) => contains2(nativeRoot, candidate2) || contains2(candidate2, nativeRoot)))) {
|