@hasna/skills 0.10.92 → 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.
@@ -1,7 +1,12 @@
1
+ import { NativeDiscoveryUnresolved } from "./agent-discovery.js";
1
2
  export interface PortableAuthoringPathOptions {
2
3
  /** The account whose native discovery must remain free of authored payloads. */
3
4
  homeDir?: string;
4
5
  }
6
+ /** The authoring form of a native discovery refusal. Authoring commands take
7
+ * no --discovery-inputs option, so name the command that does, or say that a
8
+ * review does not resolve it. Names and paths only, never file content. */
9
+ export declare function portableAuthoringDiscoveryRefusal(error: NativeDiscoveryUnresolved, destination: string): string;
5
10
  /**
6
11
  * Refuse a write target that is, or physically aliases, an agent discovery
7
12
  * root. Read-only inventory and archive operations deliberately do not call
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Linux POSIX ACL absence check (SH-00084).
3
+ *
4
+ * Access ACLs change effective permissions independently of mode and group.
5
+ * The guarded writers do not copy ACLs, so they require verified absence on
6
+ * supported Linux/glibc. A default ACL initializes direct children at
7
+ * creation, not existing descendants: query it only for directories where the
8
+ * caller will create an object.
9
+ *
10
+ * Presence is queried only (size 0); no attribute value is read or copied.
11
+ *
12
+ * errno is thread-local and any later libc call on this thread, or a signal
13
+ * handler that does not preserve it, can overwrite it. The probe therefore:
14
+ * - resets errno before each query where the layer can write it,
15
+ * - reads it as the very next step after the call, with nothing allocated in
16
+ * between (the call returns an immediate number, not a BigInt, and errno is
17
+ * read with bun:ffi's read.i32, which allocates nothing),
18
+ * - re-queries a bounded number of times when the result is -1 with an errno
19
+ * other than the two "absent" answers, since a stray overwrite does not
20
+ * repeat while a genuine failure does. A persistent failure refuses.
21
+ * A result other than -1 (the attribute exists, or an anomalous value) always
22
+ * refuses at once and never depends on errno.
23
+ */
24
+ /** ENODATA on the asm-generic errno table (Linux x86_64 and aarch64). */
25
+ export declare const LINUX_ENODATA = 61;
26
+ /** EOPNOTSUPP, which glibc also names ENOTSUP, on the asm-generic table. */
27
+ export declare const LINUX_EOPNOTSUPP = 95;
28
+ /** Queries per attribute before an unexplained failure refuses. */
29
+ export declare const LINUX_ACL_QUERY_ATTEMPTS = 4;
30
+ /**
31
+ * Filesystems where an unsupported POSIX ACL attribute means the kernel
32
+ * enforces no ACL at all (support compiled out, or mounted with noacl), so
33
+ * mode and ownership are the whole access model. Network and FUSE filesystems
34
+ * (NFSv4, SMB, 9p, FUSE and others) also answer EOPNOTSUPP while enforcing
35
+ * their own ACLs or server-side access, so they stay unverified.
36
+ */
37
+ export declare const LINUX_ACL_FREE_WHEN_UNSUPPORTED: ReadonlySet<bigint>;
38
+ /** The raw operations, separable so tests can drive every errno path. */
39
+ export interface LinuxAclProbe {
40
+ /** process.arch of the running binary; only asm-generic errno tables are admitted. */
41
+ readonly arch: string;
42
+ /** Thread-local errno of the calling thread, or null when it cannot be located. */
43
+ readonly errno: {
44
+ get(): number;
45
+ set?(value: number): void;
46
+ } | null;
47
+ /** fgetxattr(fd, name, NULL, 0): the attribute size, or -1. */
48
+ fgetxattr(fd: number, attribute: string): number | bigint;
49
+ /** fstatfs(fd).f_type, or null when fstatfs fails. */
50
+ filesystemType(fd: number): bigint | null;
51
+ }
52
+ /** True only when every queried POSIX ACL attribute is verifiably absent. */
53
+ export declare function linuxAccessAclAbsent(probe: LinuxAclProbe, fd: number, creationParent: boolean): boolean;
54
+ /** Run with the glibc probe; any loading or ABI failure refuses (false). */
55
+ export declare function withGlibcAclProbe(use: (probe: LinuxAclProbe) => boolean): boolean;
@@ -49,7 +49,7 @@ var __require = import.meta.require;
49
49
  // src/runtime-prerequisites.ts
50
50
  import { isAbsolute as isAbsolute7 } from "path";
51
51
  // package.json
52
- var version = "0.10.92";
52
+ var version = "0.10.93";
53
53
  var package_default = {
54
54
  name: "@hasna/skills",
55
55
  version,
package/dist/sdk/index.js CHANGED
@@ -91998,7 +91998,7 @@ var init_event_sink = __esm(() => {
91998
91998
  init_dist();
91999
91999
  });
92000
92000
  // package.json
92001
- var version = "0.10.92";
92001
+ var version = "0.10.93";
92002
92002
  var package_default = {
92003
92003
  name: "@hasna/skills",
92004
92004
  version,
@@ -105659,6 +105659,19 @@ function discoveryRootUnresolved(agent, command, detail) {
105659
105659
  function isDiscoveryRootUnresolved(error) {
105660
105660
  return error instanceof Error && error.message.startsWith(`${DISCOVERY_ROOT_UNRESOLVED}: `);
105661
105661
  }
105662
+
105663
+ class NativeDiscoveryUnresolved extends Error {
105664
+ agent;
105665
+ detail;
105666
+ source;
105667
+ reviewable = false;
105668
+ constructor(agent, detail, source) {
105669
+ super(`Native discovery is unresolved (${agent}: ${detail}); provide a reviewed --discovery-inputs file`);
105670
+ this.agent = agent;
105671
+ this.detail = detail;
105672
+ this.source = source;
105673
+ }
105674
+ }
105662
105675
  var quotedPath = (path) => JSON.stringify(path).replace(/[^\x20-\x7e]/g, (character) => `\\u${character.charCodeAt(0).toString(16).padStart(4, "0")}`);
105663
105676
  var realpathOrNull = (path) => {
105664
105677
  try {
@@ -106754,8 +106767,8 @@ function resolveDiscovery(options, exclusion) {
106754
106767
  const configPath = exclusion?.nativeHome === undefined ? agentDiscoveryConfigPath(home, agent) : join34(nativeHome, agent === "codex" ? "config.toml" : "settings.json");
106755
106768
  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"]);
106756
106769
  const config = configText === null ? {} : agent === "hermes" ? parseHermesConfig(configText) : parseConfig(configText, configPath, agent === "codex");
106757
- const unresolved = (detail) => {
106758
- throw new Error(`Native discovery is unresolved (${agent}: ${detail}); provide a reviewed --discovery-inputs file`);
106770
+ const unresolved = (detail, source) => {
106771
+ throw new NativeDiscoveryUnresolved(agent, detail, source);
106759
106772
  };
106760
106773
  let opaqueClosureVerified = false;
106761
106774
  const verifyOpaqueClosure = (declarations) => {
@@ -106769,6 +106782,17 @@ function resolveDiscovery(options, exclusion) {
106769
106782
  verifyDiscovery(retained, undefined, undefined, undefined, exclusion?.narrowed, canonical9(configPath));
106770
106783
  opaqueClosureVerified = true;
106771
106784
  };
106785
+ const reviewRemedy = (source, check) => {
106786
+ try {
106787
+ check();
106788
+ } catch (error) {
106789
+ if (error instanceof NativeDiscoveryUnresolved) {
106790
+ error.reviewable = true;
106791
+ error.source ??= source;
106792
+ }
106793
+ throw error;
106794
+ }
106795
+ };
106772
106796
  if (exclusion) {
106773
106797
  if (configText !== null && agent !== "codex" && agent !== "hermes")
106774
106798
  parseNativeJsonObject(configText);
@@ -106840,7 +106864,7 @@ function resolveDiscovery(options, exclusion) {
106840
106864
  unresolved(`non-enumerable ${label} require a current settings review`);
106841
106865
  };
106842
106866
  if (hasHooks)
106843
- verifyCurrentOpaqueSettings("hooks");
106867
+ reviewRemedy(canonical9(configPath), () => verifyCurrentOpaqueSettings("hooks"));
106844
106868
  if (agent === "claude") {
106845
106869
  if (config.env !== undefined) {
106846
106870
  if (!object6(config.env) || Object.keys(config.env).length > 512)
@@ -106853,7 +106877,7 @@ function resolveDiscovery(options, exclusion) {
106853
106877
  if (hasFunctionHookEnvironment) {
106854
106878
  if (!["0", "1"].includes(config.env.CLAUDE_CODE_ENABLE_FUNCTION_HOOKS))
106855
106879
  unresolved("malformed Claude env.CLAUDE_CODE_ENABLE_FUNCTION_HOOKS flag");
106856
- verifyCurrentOpaqueSettings("function-hook environment controls");
106880
+ reviewRemedy(canonical9(configPath), () => verifyCurrentOpaqueSettings("function-hook environment controls"));
106857
106881
  }
106858
106882
  }
106859
106883
  if (config.pluginConfigs !== undefined) {
@@ -106880,7 +106904,7 @@ function resolveDiscovery(options, exclusion) {
106880
106904
  }
106881
106905
  hasPluginConfigs = Object.keys(config.pluginConfigs).length > 0;
106882
106906
  if (hasPluginConfigs)
106883
- verifyCurrentOpaqueSettings("plugin configurations");
106907
+ reviewRemedy(canonical9(configPath), () => verifyCurrentOpaqueSettings("plugin configurations"));
106884
106908
  }
106885
106909
  if (config.enabledPlugins !== undefined && !object6(config.enabledPlugins))
106886
106910
  unresolved("enabledPlugins must be an object");
@@ -106992,7 +107016,7 @@ function resolveDiscovery(options, exclusion) {
106992
107016
  if (Object.keys(config.enabledPlugins ?? config.plugins ?? config.extensions ?? {}).length > 512)
106993
107017
  unresolved("unbounded native registrations");
106994
107018
  if (hasHooks || hasPluginConfigs || hasFunctionHookEnvironment)
106995
- verifyOpaqueClosure([]);
107019
+ reviewRemedy(canonical9(configPath), () => verifyOpaqueClosure([]));
106996
107020
  }
106997
107021
  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))
106998
107022
  throw new Error("Invalid --discovery-inputs version or agents");
@@ -107245,40 +107269,41 @@ function resolveDiscovery(options, exclusion) {
107245
107269
  if (exclusion && Object.keys(manifest).some((key2) => /skill|plugin|hook|marketplace|extension|instruction/i.test(key2) && !["skills", "hooks"].includes(key2)))
107246
107270
  unresolved("unknown plugin discovery controls");
107247
107271
  const hooks = witness(join34(root2, "hooks/hooks.json"));
107248
- if (manifest.hooks !== undefined || hooks !== null) {
107249
- if (!exclusion || exclusion.retained?.method !== "reviewed")
107250
- unresolved("plugin hooks require a separate no-skill-injection review");
107251
- const required = [manifestPath, ...hooks !== null ? [join34(root2, "hooks/hooks.json")] : []];
107252
- const scoped2 = agent === "codex" && codex !== undefined ? [] : undefined;
107253
- if (manifest.hooks !== undefined) {
107254
- if (scoped2 && manifest.hooks && typeof manifest.hooks === "object" && !Array.isArray(manifest.hooks)) {
107255
- const inline = codexPluginHookHandlers(manifest.hooks);
107256
- if (!inline)
107257
- unresolved("unsupported inline plugin hooks");
107258
- scoped2.push(inline);
107259
- } else {
107260
- if (typeof manifest.hooks !== "string")
107261
- unresolved("unsupported plugin hooks target");
107262
- const hook = resolve27(root2, manifest.hooks);
107263
- if (!hook.startsWith(root2 + sep13))
107264
- unresolved("plugin hooks target escapes its root");
107265
- required.push(hook);
107266
- if (scoped2)
107267
- scoped2.push(readCodexHookDeclaration(witness(hook), hook));
107268
- }
107269
- }
107270
- if (scoped2 && hooks !== null)
107271
- scoped2.push(readCodexHookDeclaration(hooks, join34(root2, "hooks/hooks.json")));
107272
- for (const path of required) {
107273
- const saved = exclusion.retained.sources.filter((source) => source.path === canonical9(path) && source.sha256 !== null && source.format === undefined && source.fields === undefined);
107274
- if (saved.length ? saved.some((source) => projected(source, undefined, budget3) !== source.sha256) : !(scoped2 && reviewedInstalledCopy(root2, path, codex)))
107275
- unresolved("plugin hooks require current independently reviewed sources");
107276
- }
107277
- if (scoped2 && scoped2.every((item) => item !== null && item.commands === 0)) {
107278
- verifyCodexPluginHookClosure(root2, codex, codex.source, new Set(scoped2.flatMap((item) => [...item.servers])), required.map((path) => canonical9(path)));
107279
- } else
107280
- verifyOpaqueClosure(required.map((path) => canonical9(path)));
107281
- }
107272
+ if (manifest.hooks !== undefined || hooks !== null)
107273
+ reviewRemedy(canonical9(hooks !== null ? join34(root2, "hooks/hooks.json") : manifestPath), () => {
107274
+ if (!exclusion || exclusion.retained?.method !== "reviewed")
107275
+ unresolved("plugin hooks require a separate no-skill-injection review");
107276
+ const required = [manifestPath, ...hooks !== null ? [join34(root2, "hooks/hooks.json")] : []];
107277
+ const scoped2 = agent === "codex" && codex !== undefined ? [] : undefined;
107278
+ if (manifest.hooks !== undefined) {
107279
+ if (scoped2 && manifest.hooks && typeof manifest.hooks === "object" && !Array.isArray(manifest.hooks)) {
107280
+ const inline = codexPluginHookHandlers(manifest.hooks);
107281
+ if (!inline)
107282
+ unresolved("unsupported inline plugin hooks");
107283
+ scoped2.push(inline);
107284
+ } else {
107285
+ if (typeof manifest.hooks !== "string")
107286
+ unresolved("unsupported plugin hooks target");
107287
+ const hook = resolve27(root2, manifest.hooks);
107288
+ if (!hook.startsWith(root2 + sep13))
107289
+ unresolved("plugin hooks target escapes its root");
107290
+ required.push(hook);
107291
+ if (scoped2)
107292
+ scoped2.push(readCodexHookDeclaration(witness(hook), hook));
107293
+ }
107294
+ }
107295
+ if (scoped2 && hooks !== null)
107296
+ scoped2.push(readCodexHookDeclaration(hooks, join34(root2, "hooks/hooks.json")));
107297
+ for (const path of required) {
107298
+ const saved = exclusion.retained.sources.filter((source) => source.path === canonical9(path) && source.sha256 !== null && source.format === undefined && source.fields === undefined);
107299
+ if (saved.length ? saved.some((source) => projected(source, undefined, budget3) !== source.sha256) : !(scoped2 && reviewedInstalledCopy(root2, path, codex)))
107300
+ unresolved("plugin hooks require current independently reviewed sources", canonical9(path));
107301
+ }
107302
+ if (scoped2 && scoped2.every((item) => item !== null && item.commands === 0)) {
107303
+ verifyCodexPluginHookClosure(root2, codex, codex.source, new Set(scoped2.flatMap((item) => [...item.servers])), required.map((path) => canonical9(path)));
107304
+ } else
107305
+ verifyOpaqueClosure(required.map((path) => canonical9(path)));
107306
+ });
107282
107307
  const commands = join34(root2, "commands");
107283
107308
  safe6(commands);
107284
107309
  if (agent === "claude" && (manifest.commands !== undefined || lstatSync30(commands, { throwIfNoEntry: false })?.isDirectory() && entries(commands).length))
@@ -107902,6 +107927,82 @@ function assertPinnedLauncherRuntimeSafe(runtime) {
107902
107927
  }
107903
107928
  }
107904
107929
 
107930
+ // src/lib/linux-access-acl.ts
107931
+ var LINUX_ENODATA = 61;
107932
+ var LINUX_EOPNOTSUPP = 95;
107933
+ var LINUX_ACL_QUERY_ATTEMPTS = 4;
107934
+ var LINUX_ACL_FREE_WHEN_UNSUPPORTED = new Set([
107935
+ 0xef53n,
107936
+ 0x58465342n,
107937
+ 0x9123683en,
107938
+ 0x01021994n
107939
+ ]);
107940
+ function queryAttribute(probe2, errno, fd, attribute) {
107941
+ for (let attempt = 0;attempt < LINUX_ACL_QUERY_ATTEMPTS; attempt++) {
107942
+ errno.set?.(0);
107943
+ const result = probe2.fgetxattr(fd, attribute);
107944
+ const code = errno.get();
107945
+ if (result !== -1 && result !== -1n)
107946
+ return "present";
107947
+ if (code === LINUX_ENODATA)
107948
+ return "absent";
107949
+ if (code === LINUX_EOPNOTSUPP)
107950
+ return "unsupported";
107951
+ }
107952
+ return "unverified";
107953
+ }
107954
+ function linuxAccessAclAbsent(probe2, fd, creationParent) {
107955
+ if (probe2.arch !== "x64" && probe2.arch !== "arm64")
107956
+ return false;
107957
+ const errno = probe2.errno;
107958
+ if (!errno)
107959
+ return false;
107960
+ let unsupported = false;
107961
+ for (const attribute of ["system.posix_acl_access", ...creationParent ? ["system.posix_acl_default"] : []]) {
107962
+ const state = queryAttribute(probe2, errno, fd, attribute);
107963
+ if (state === "present" || state === "unverified")
107964
+ return false;
107965
+ if (state === "unsupported")
107966
+ unsupported = true;
107967
+ }
107968
+ if (!unsupported)
107969
+ return true;
107970
+ const type = probe2.filesystemType(fd);
107971
+ return type !== null && LINUX_ACL_FREE_WHEN_UNSUPPORTED.has(type);
107972
+ }
107973
+ function withGlibcAclProbe(use) {
107974
+ try {
107975
+ const { dlopen, ptr, read: read3, FFIType } = __require("bun:ffi");
107976
+ const library = dlopen("libc.so.6", {
107977
+ fgetxattr: { args: ["i32", "ptr", "ptr", "u64"], returns: FFIType.i64_fast },
107978
+ fstatfs: { args: ["i32", "ptr"], returns: "i32" },
107979
+ __errno_location: { args: [], returns: "ptr" }
107980
+ });
107981
+ try {
107982
+ const location = library.symbols.__errno_location();
107983
+ const names = new Map;
107984
+ return use({
107985
+ arch: process.arch,
107986
+ errno: location ? { get: () => read3.i32(location) } : null,
107987
+ fgetxattr: (fd, attribute) => {
107988
+ let name = names.get(attribute);
107989
+ if (!name)
107990
+ names.set(attribute, name = Buffer.from(attribute + "\x00"));
107991
+ return library.symbols.fgetxattr(fd, ptr(name), null, 0);
107992
+ },
107993
+ filesystemType: (fd) => {
107994
+ const statfs = new BigUint64Array(32);
107995
+ return library.symbols.fstatfs(fd, ptr(statfs)) === 0 ? statfs[0] : null;
107996
+ }
107997
+ });
107998
+ } finally {
107999
+ library.close();
108000
+ }
108001
+ } catch {
108002
+ return false;
108003
+ }
108004
+ }
108005
+
107905
108006
  // src/lib/agent-integration.ts
107906
108007
  var sha5 = (data) => createHash33("sha256").update(data).digest("hex");
107907
108008
  var ROOTS = NATIVE_SKILL_ROOTS;
@@ -108735,28 +108836,7 @@ function hookProjectionRefusal(reason2) {
108735
108836
  throw new Error(`CLAUDE_MANAGED_HOOK_${reason2}`);
108736
108837
  }
108737
108838
  function hasNoLinuxAccessAcl(fd, creationParent) {
108738
- try {
108739
- const { dlopen, read: read3, ptr } = __require("bun:ffi");
108740
- const library = dlopen("libc.so.6", {
108741
- fgetxattr: { args: ["i32", "ptr", "ptr", "u64"], returns: "i64" },
108742
- __errno_location: { args: [], returns: "ptr" }
108743
- });
108744
- try {
108745
- const errno = library.symbols.__errno_location();
108746
- if (!errno)
108747
- return false;
108748
- for (const attribute of ["system.posix_acl_access", ...creationParent ? ["system.posix_acl_default"] : []]) {
108749
- const name = Buffer.from(attribute + "\x00");
108750
- if (Number(library.symbols.fgetxattr(fd, ptr(name), null, 0)) !== -1 || read3.i32(errno) !== 61)
108751
- return false;
108752
- }
108753
- return true;
108754
- } finally {
108755
- library.close();
108756
- }
108757
- } catch {
108758
- return false;
108759
- }
108839
+ return withGlibcAclProbe((probe2) => linuxAccessAclAbsent(probe2, fd, creationParent));
108760
108840
  }
108761
108841
  function assertNativePathAcl(path, observed, options = {}) {
108762
108842
  if (process.platform !== "darwin" && process.platform !== "linux")
@@ -109697,7 +109777,7 @@ function planCodexPluginNameReconcile(request2) {
109697
109777
  pathDenies: [...pathDenies].sort(),
109698
109778
  ...discovery ? { discovery } : {}
109699
109779
  };
109700
- const plan = planAgentIntegration({ home, dataDir: dataDir2, projectDir, agents: ["codex"], codexNativeCatalog: catalog, codexReconcile: input });
109780
+ const plan = planAgentIntegration({ home, dataDir: dataDir2, projectDir, agents: ["codex"], codexNativeCatalog: catalog, codexReconcile: input, allowRootAliases: aliases.length > 0 });
109701
109781
  assertCodexReconcileScope(plan, { configPath, policyPath, prior, names, remoteIdentities, discovery: discovery ?? savedDiscovery });
109702
109782
  const configChange = plan.changes.find((change) => resolve28(change.path) === configPath);
109703
109783
  const plannedRules = configChange ? Bun.TOML.parse(configChange.after).skills?.config ?? [] : [];
@@ -111768,6 +111848,11 @@ function physicalPath(path) {
111768
111848
  }
111769
111849
  return resolve29(realpathSync15(cursor), ...suffix);
111770
111850
  }
111851
+ function portableAuthoringDiscoveryRefusal(error, destination) {
111852
+ const head = `Native discovery is unresolved (${error.agent}: ${error.detail}).${error.source ? ` Checked source: ${error.source}.` : ""}`;
111853
+ const review = `skills hook install --agent ${error.agent} --discovery-inputs <reviewed-file> --apply`;
111854
+ 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}.`;
111855
+ }
111771
111856
  function contains2(root2, path) {
111772
111857
  const boundary = root2.endsWith(sep16) ? root2 : root2 + sep16;
111773
111858
  return path === root2 || path.startsWith(boundary);
@@ -111868,11 +111953,18 @@ function assertPortableAuthoringPath(path, options = {}) {
111868
111953
  if (native) {
111869
111954
  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.`);
111870
111955
  }
111871
- const roots = configuredRoots(home, options.homeDir !== undefined);
111872
- for (const value of selected) {
111873
- if (physicalPath(value.path) === physicalPath(join38(home, `.${value.agent}`)))
111874
- continue;
111875
- roots.push(...resolveAgentDiscoveryExclusionRoots({ home, agent: value.agent, nativeHome: value.path, canonical: physicalPath, executable: null }));
111956
+ const roots = [];
111957
+ try {
111958
+ roots.push(...configuredRoots(home, options.homeDir !== undefined));
111959
+ for (const value of selected) {
111960
+ if (physicalPath(value.path) === physicalPath(join38(home, `.${value.agent}`)))
111961
+ continue;
111962
+ roots.push(...resolveAgentDiscoveryExclusionRoots({ home, agent: value.agent, nativeHome: value.path, canonical: physicalPath, executable: null }));
111963
+ }
111964
+ } catch (error) {
111965
+ if (error instanceof NativeDiscoveryUnresolved)
111966
+ throw new Error(portableAuthoringDiscoveryRefusal(error, lexical));
111967
+ throw error;
111876
111968
  }
111877
111969
  for (const root2 of roots) {
111878
111970
  if (candidates.some((candidate2) => [resolve29(root2), physicalPath(root2)].some((nativeRoot) => contains2(nativeRoot, candidate2) || contains2(candidate2, nativeRoot)))) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/skills",
3
- "version": "0.10.92",
3
+ "version": "0.10.93",
4
4
  "description": "Skills library for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {