rulesync 9.5.0 → 9.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -97,7 +97,7 @@ The tables below show whether each tool supports a given feature (✅ = supporte
97
97
  | Takt | ✅ | | ✅ | ✅ | ✅ | ✅ | | ✅ |
98
98
  | Vibe Code | ✅ | ✅ | ✅ | | ✅ | ✅ | ✅ | ✅ |
99
99
  | Qwen Code | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
100
- | Reasonix | | | ✅ | ✅ | | | ✅ | ✅ |
100
+ | Reasonix || | ✅ | ✅ | || ✅ | ✅ |
101
101
  | Kiro ⚠️ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
102
102
  | Kiro CLI | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
103
103
  | Kiro IDE | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- const require_import = require("../import-DngV1i49.cjs");
2
+ const require_import = require("../import-DW-a1SJq.cjs");
3
3
  let commander = require("commander");
4
4
  let zod_mini = require("zod/mini");
5
5
  let node_path = require("node:path");
@@ -1563,12 +1563,13 @@ const gitignoreCommand = async (logger, options) => {
1563
1563
  const gitignorePath = (0, node_path.join)(process.cwd(), ".gitignore");
1564
1564
  const gitattributesPath = (0, node_path.join)(process.cwd(), ".gitattributes");
1565
1565
  const config = await require_import.ConfigResolver.resolve({});
1566
+ const resolvedEntries = resolveGitignoreEntries({
1567
+ targets: options?.targets,
1568
+ features: options?.features,
1569
+ logger
1570
+ });
1566
1571
  const { gitignore: gitignoreEntries, gitattributes: gitattributesEntries } = groupEntriesByDestination({
1567
- entries: resolveGitignoreEntries({
1568
- targets: options?.targets,
1569
- features: options?.features,
1570
- logger
1571
- }),
1572
+ entries: resolvedEntries,
1572
1573
  resolveDestination: (target, feature) => {
1573
1574
  if (feature === void 0 || feature === "general") return config.getGitignoreDestination(target);
1574
1575
  return config.getGitignoreDestination(target, feature);
@@ -2023,7 +2024,7 @@ function parseApmLock(content) {
2023
2024
  if (!content.trim()) return null;
2024
2025
  let loaded;
2025
2026
  try {
2026
- loaded = (0, js_yaml.load)(content);
2027
+ loaded = require_import.loadYaml(content);
2027
2028
  } catch {
2028
2029
  return null;
2029
2030
  }
@@ -2093,7 +2094,7 @@ async function apmManifestExists(projectRoot) {
2093
2094
  * or any dependency entry fails normalization.
2094
2095
  */
2095
2096
  function parseApmManifest(content) {
2096
- const loaded = (0, js_yaml.load)(content);
2097
+ const loaded = require_import.loadYaml(content);
2097
2098
  if (loaded === void 0 || loaded === null) return { dependencies: [] };
2098
2099
  const parsed = ApmManifestSchema.safeParse(loaded);
2099
2100
  if (!parsed.success) throw new Error(`Invalid apm.yml: ${parsed.error.message}`);
@@ -2562,11 +2563,14 @@ function injectSourceMetadata(params) {
2562
2563
  if (content.startsWith(`${FRONTMATTER_FENCE}\r\n`)) openFenceLen = 5;
2563
2564
  else if (content.startsWith(`${FRONTMATTER_FENCE}\n`)) openFenceLen = 4;
2564
2565
  else if (content === FRONTMATTER_FENCE) openFenceLen = 3;
2565
- else return `${FRONTMATTER_FENCE}\n${(0, js_yaml.dump)(provenance, {
2566
- noRefs: true,
2567
- lineWidth: -1,
2568
- sortKeys: false
2569
- })}${FRONTMATTER_FENCE}\n${content}`;
2566
+ else {
2567
+ const yaml = (0, js_yaml.dump)(provenance, {
2568
+ noRefs: true,
2569
+ lineWidth: -1,
2570
+ sortKeys: false
2571
+ });
2572
+ return `${FRONTMATTER_FENCE}\n${yaml}${FRONTMATTER_FENCE}\n${content}`;
2573
+ }
2570
2574
  const afterOpen = content.substring(openFenceLen);
2571
2575
  let fmBody;
2572
2576
  let rest;
@@ -2582,24 +2586,28 @@ function injectSourceMetadata(params) {
2582
2586
  }
2583
2587
  let loaded;
2584
2588
  try {
2585
- loaded = (0, js_yaml.load)(fmBody);
2589
+ loaded = require_import.loadYaml(fmBody);
2586
2590
  } catch {
2587
2591
  throw new Error("invalid frontmatter");
2588
2592
  }
2589
- if (loaded === null || loaded === void 0) return `${FRONTMATTER_FENCE}\n${(0, js_yaml.dump)(provenance, {
2590
- noRefs: true,
2591
- lineWidth: -1,
2592
- sortKeys: false
2593
- })}${FRONTMATTER_FENCE}\n${rest}`;
2593
+ if (loaded === null || loaded === void 0) {
2594
+ const yaml = (0, js_yaml.dump)(provenance, {
2595
+ noRefs: true,
2596
+ lineWidth: -1,
2597
+ sortKeys: false
2598
+ });
2599
+ return `${FRONTMATTER_FENCE}\n${yaml}${FRONTMATTER_FENCE}\n${rest}`;
2600
+ }
2594
2601
  if (typeof loaded !== "object" || Array.isArray(loaded)) throw new Error("invalid frontmatter");
2595
- return `${FRONTMATTER_FENCE}\n${(0, js_yaml.dump)({
2602
+ const yaml = (0, js_yaml.dump)({
2596
2603
  ...loaded,
2597
2604
  ...provenance
2598
2605
  }, {
2599
2606
  noRefs: true,
2600
2607
  lineWidth: -1,
2601
2608
  sortKeys: false
2602
- })}${FRONTMATTER_FENCE}\n${rest}`;
2609
+ });
2610
+ return `${FRONTMATTER_FENCE}\n${yaml}${FRONTMATTER_FENCE}\n${rest}`;
2603
2611
  }
2604
2612
  //#endregion
2605
2613
  //#region src/lib/gh/gh-lock.ts
@@ -2668,7 +2676,7 @@ function parseGhLock(content) {
2668
2676
  if (!content.trim()) return null;
2669
2677
  let loaded;
2670
2678
  try {
2671
- loaded = (0, js_yaml.load)(content);
2679
+ loaded = require_import.loadYaml(content);
2672
2680
  } catch {
2673
2681
  return null;
2674
2682
  }
@@ -3803,6 +3811,21 @@ function getFirstPathSeparatorIndex(path) {
3803
3811
  if (backslashIndex === -1) return slashIndex;
3804
3812
  return Math.min(slashIndex, backslashIndex);
3805
3813
  }
3814
+ /**
3815
+ * Decide whether a repository's root-level files should be installed as the
3816
+ * single requested skill (the "root fallback").
3817
+ *
3818
+ * A root fallback fires only when a single, non-wildcard skill was requested,
3819
+ * that skill's own directory is absent, and the repository root actually carries
3820
+ * a `SKILL.md`. Both the git transport (`groupRemoteFilesBySkillRoot`) and the
3821
+ * GitHub transport (`discoverGithubSkillDirs`) gate on these same conditions, so
3822
+ * the decision lives here to keep the two paths from drifting.
3823
+ */
3824
+ function shouldUseRootFallback(params) {
3825
+ const { skillFilter, isWildcard, hasRootSkillFile, hasRequestedSkillDir } = params;
3826
+ const [singleSkillName] = skillFilter;
3827
+ return !isWildcard && skillFilter.length === 1 && singleSkillName !== void 0 && hasRootSkillFile && !hasRequestedSkillDir;
3828
+ }
3806
3829
  function groupRemoteFilesBySkillRoot(params) {
3807
3830
  const { remoteFiles, skillFilter, isWildcard } = params;
3808
3831
  const grouped = /* @__PURE__ */ new Map();
@@ -3825,7 +3848,12 @@ function groupRemoteFilesBySkillRoot(params) {
3825
3848
  }
3826
3849
  const [singleSkillName] = skillFilter;
3827
3850
  const hasRootSkillFile = rootLevelFiles.some((file) => file.relativePath === require_import.SKILL_FILE_NAME);
3828
- if (!isWildcard && skillFilter.length === 1 && singleSkillName !== void 0 && hasRootSkillFile && !grouped.has(singleSkillName)) grouped.set(singleSkillName, rootLevelFiles);
3851
+ if (singleSkillName !== void 0 && shouldUseRootFallback({
3852
+ skillFilter,
3853
+ isWildcard,
3854
+ hasRootSkillFile,
3855
+ hasRequestedSkillDir: grouped.has(singleSkillName)
3856
+ })) grouped.set(singleSkillName, rootLevelFiles);
3829
3857
  return grouped;
3830
3858
  }
3831
3859
  /**
@@ -3962,7 +3990,12 @@ async function discoverGithubSkillDirs(params) {
3962
3990
  }));
3963
3991
  const [singleSkillName] = skillFilter;
3964
3992
  const hasRequestedSkillDir = singleSkillName !== void 0 && remoteSkillDirs.some((d) => d.name === singleSkillName);
3965
- if (!isWildcard && skillFilter.length === 1 && !hasRequestedSkillDir) {
3993
+ if (shouldUseRootFallback({
3994
+ skillFilter,
3995
+ isWildcard,
3996
+ hasRootSkillFile: entries.some((entry) => entry.type === "file" && entry.name === "SKILL.md"),
3997
+ hasRequestedSkillDir
3998
+ })) {
3966
3999
  const fallback = await fetchRootLevelFallbackSkill({
3967
4000
  entries,
3968
4001
  parsed,
@@ -6428,7 +6461,7 @@ function wrapCommand$1({ name, errorCode, handler, getVersion, loggerFactory = c
6428
6461
  }
6429
6462
  //#endregion
6430
6463
  //#region src/cli/index.ts
6431
- const getVersion = () => "9.5.0";
6464
+ const getVersion = () => "9.6.1";
6432
6465
  function wrapCommand(name, errorCode, handler) {
6433
6466
  return wrapCommand$1({
6434
6467
  name,
package/dist/cli/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import { $ as toPosixPath, A as RulesyncCommand, B as createTempDirectory, C as RulesyncHooks, Ct as RULESYNC_SKILLS_RELATIVE_DIR_PATH, D as CLAUDECODE_MEMORIES_DIR_NAME, Dt as ALL_FEATURES, E as CLAUDECODE_LOCAL_RULE_FILE_NAME, Et as formatError, F as ConsoleLogger, G as getFileSize, H as ensureDir, I as JsonLogger, J as listDirectoryFiles, K as getHomeDirectory, L as CLIError, M as stringifyFrontmatter, N as ConfigResolver, O as CLAUDECODE_SETTINGS_LOCAL_FILE_NAME, Ot as ALL_FEATURES_WITH_WILDCARD, P as findControlCharacter, Q as removeTempDirectory, R as ErrorCodes, S as HooksProcessor, St as RULESYNC_RULES_RELATIVE_DIR_PATH, T as CLAUDECODE_DIR, Tt as RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, U as fileExists, V as directoryExists, W as findFilesByGlobs, X as removeDirectory, Y as readFileContent, Z as removeFile, _ as RulesyncPermissions, _t as RULESYNC_MCP_SCHEMA_URL, a as convertFromTool, at as RULESYNC_AIIGNORE_FILE_NAME, b as IgnoreProcessor, bt as RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH, c as RulesyncRuleFrontmatterSchema, ct as RULESYNC_CONFIG_RELATIVE_FILE_PATH, d as RulesyncSubagentFrontmatterSchema, dt as RULESYNC_HOOKS_FILE_NAME, et as writeFileContent, f as SkillsProcessor, ft as RULESYNC_HOOKS_RELATIVE_FILE_PATH, g as SKILL_FILE_NAME$1, gt as RULESYNC_MCP_RELATIVE_FILE_PATH, h as RulesyncSkillFrontmatterSchema, ht as RULESYNC_MCP_FILE_NAME, i as getProcessorRegistryEntry, it as MAX_FILE_SIZE, j as RulesyncCommandFrontmatterSchema, k as CLAUDECODE_SKILLS_DIR_PATH, l as SubagentsProcessor, lt as RULESYNC_CONFIG_SCHEMA_URL, m as RulesyncSkill, mt as RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH, n as checkRulesyncDirExists, nt as ALL_TOOL_TARGETS_WITH_WILDCARD, o as RulesProcessor, ot as RULESYNC_AIIGNORE_RELATIVE_FILE_PATH, p as getLocalSkillDirNames, pt as RULESYNC_IGNORE_RELATIVE_FILE_PATH, q as isSymlink, r as generate, rt as ToolTargetSchema, s as RulesyncRule, st as RULESYNC_COMMANDS_RELATIVE_DIR_PATH, t as importFromTool, tt as ALL_TOOL_TARGETS, u as RulesyncSubagent, ut as RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH, v as McpProcessor, vt as RULESYNC_OVERVIEW_FILE_NAME, w as CommandsProcessor, wt as RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH, x as RulesyncIgnore, xt as RULESYNC_RELATIVE_DIR_PATH, y as RulesyncMcp, yt as RULESYNC_PERMISSIONS_FILE_NAME, z as checkPathTraversal } from "../import-BdJG1fyb.js";
2
+ import { $ as removeTempDirectory, A as RulesyncCommand, B as checkPathTraversal, C as RulesyncHooks, Ct as RULESYNC_RULES_RELATIVE_DIR_PATH, D as CLAUDECODE_MEMORIES_DIR_NAME, Dt as formatError, E as CLAUDECODE_LOCAL_RULE_FILE_NAME, Et as RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, F as findControlCharacter, G as findFilesByGlobs, H as directoryExists, I as ConsoleLogger, J as isSymlink, K as getFileSize, L as JsonLogger, M as stringifyFrontmatter, N as loadYaml, O as CLAUDECODE_SETTINGS_LOCAL_FILE_NAME, Ot as ALL_FEATURES, P as ConfigResolver, Q as removeFile, R as CLIError, S as HooksProcessor, St as RULESYNC_RELATIVE_DIR_PATH, T as CLAUDECODE_DIR, Tt as RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH, U as ensureDir, V as createTempDirectory, W as fileExists, X as readFileContent, Y as listDirectoryFiles, Z as removeDirectory, _ as RulesyncPermissions, _t as RULESYNC_MCP_RELATIVE_FILE_PATH, a as convertFromTool, at as MAX_FILE_SIZE, b as IgnoreProcessor, bt as RULESYNC_PERMISSIONS_FILE_NAME, c as RulesyncRuleFrontmatterSchema, ct as RULESYNC_COMMANDS_RELATIVE_DIR_PATH, d as RulesyncSubagentFrontmatterSchema, dt as RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH, et as toPosixPath, f as SkillsProcessor, ft as RULESYNC_HOOKS_FILE_NAME, g as SKILL_FILE_NAME$1, gt as RULESYNC_MCP_FILE_NAME, h as RulesyncSkillFrontmatterSchema, ht as RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH, i as getProcessorRegistryEntry, it as ToolTargetSchema, j as RulesyncCommandFrontmatterSchema, k as CLAUDECODE_SKILLS_DIR_PATH, kt as ALL_FEATURES_WITH_WILDCARD, l as SubagentsProcessor, lt as RULESYNC_CONFIG_RELATIVE_FILE_PATH, m as RulesyncSkill, mt as RULESYNC_IGNORE_RELATIVE_FILE_PATH, n as checkRulesyncDirExists, nt as ALL_TOOL_TARGETS, o as RulesProcessor, ot as RULESYNC_AIIGNORE_FILE_NAME, p as getLocalSkillDirNames, pt as RULESYNC_HOOKS_RELATIVE_FILE_PATH, q as getHomeDirectory, r as generate, rt as ALL_TOOL_TARGETS_WITH_WILDCARD, s as RulesyncRule, st as RULESYNC_AIIGNORE_RELATIVE_FILE_PATH, t as importFromTool, tt as writeFileContent, u as RulesyncSubagent, ut as RULESYNC_CONFIG_SCHEMA_URL, v as McpProcessor, vt as RULESYNC_MCP_SCHEMA_URL, w as CommandsProcessor, wt as RULESYNC_SKILLS_RELATIVE_DIR_PATH, x as RulesyncIgnore, xt as RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH, y as RulesyncMcp, yt as RULESYNC_OVERVIEW_FILE_NAME, z as ErrorCodes } from "../import-tTMN0WRi.js";
3
3
  import { Command } from "commander";
4
4
  import { nonnegative, optional, refine, z } from "zod/mini";
5
5
  import * as path$1 from "node:path";
6
6
  import { basename, dirname, isAbsolute, join, posix, relative, resolve, sep } from "node:path";
7
7
  import * as os$1 from "node:os";
8
8
  import { promisify } from "node:util";
9
- import { dump, load } from "js-yaml";
9
+ import { dump } from "js-yaml";
10
10
  import { Semaphore } from "es-toolkit/promise";
11
11
  import { RequestError } from "@octokit/request-error";
12
12
  import { Octokit } from "@octokit/rest";
@@ -1561,12 +1561,13 @@ const gitignoreCommand = async (logger, options) => {
1561
1561
  const gitignorePath = join(process.cwd(), ".gitignore");
1562
1562
  const gitattributesPath = join(process.cwd(), ".gitattributes");
1563
1563
  const config = await ConfigResolver.resolve({});
1564
+ const resolvedEntries = resolveGitignoreEntries({
1565
+ targets: options?.targets,
1566
+ features: options?.features,
1567
+ logger
1568
+ });
1564
1569
  const { gitignore: gitignoreEntries, gitattributes: gitattributesEntries } = groupEntriesByDestination({
1565
- entries: resolveGitignoreEntries({
1566
- targets: options?.targets,
1567
- features: options?.features,
1568
- logger
1569
- }),
1570
+ entries: resolvedEntries,
1570
1571
  resolveDestination: (target, feature) => {
1571
1572
  if (feature === void 0 || feature === "general") return config.getGitignoreDestination(target);
1572
1573
  return config.getGitignoreDestination(target, feature);
@@ -2021,7 +2022,7 @@ function parseApmLock(content) {
2021
2022
  if (!content.trim()) return null;
2022
2023
  let loaded;
2023
2024
  try {
2024
- loaded = load(content);
2025
+ loaded = loadYaml(content);
2025
2026
  } catch {
2026
2027
  return null;
2027
2028
  }
@@ -2091,7 +2092,7 @@ async function apmManifestExists(projectRoot) {
2091
2092
  * or any dependency entry fails normalization.
2092
2093
  */
2093
2094
  function parseApmManifest(content) {
2094
- const loaded = load(content);
2095
+ const loaded = loadYaml(content);
2095
2096
  if (loaded === void 0 || loaded === null) return { dependencies: [] };
2096
2097
  const parsed = ApmManifestSchema.safeParse(loaded);
2097
2098
  if (!parsed.success) throw new Error(`Invalid apm.yml: ${parsed.error.message}`);
@@ -2560,11 +2561,14 @@ function injectSourceMetadata(params) {
2560
2561
  if (content.startsWith(`${FRONTMATTER_FENCE}\r\n`)) openFenceLen = 5;
2561
2562
  else if (content.startsWith(`${FRONTMATTER_FENCE}\n`)) openFenceLen = 4;
2562
2563
  else if (content === FRONTMATTER_FENCE) openFenceLen = 3;
2563
- else return `${FRONTMATTER_FENCE}\n${dump(provenance, {
2564
- noRefs: true,
2565
- lineWidth: -1,
2566
- sortKeys: false
2567
- })}${FRONTMATTER_FENCE}\n${content}`;
2564
+ else {
2565
+ const yaml = dump(provenance, {
2566
+ noRefs: true,
2567
+ lineWidth: -1,
2568
+ sortKeys: false
2569
+ });
2570
+ return `${FRONTMATTER_FENCE}\n${yaml}${FRONTMATTER_FENCE}\n${content}`;
2571
+ }
2568
2572
  const afterOpen = content.substring(openFenceLen);
2569
2573
  let fmBody;
2570
2574
  let rest;
@@ -2580,24 +2584,28 @@ function injectSourceMetadata(params) {
2580
2584
  }
2581
2585
  let loaded;
2582
2586
  try {
2583
- loaded = load(fmBody);
2587
+ loaded = loadYaml(fmBody);
2584
2588
  } catch {
2585
2589
  throw new Error("invalid frontmatter");
2586
2590
  }
2587
- if (loaded === null || loaded === void 0) return `${FRONTMATTER_FENCE}\n${dump(provenance, {
2588
- noRefs: true,
2589
- lineWidth: -1,
2590
- sortKeys: false
2591
- })}${FRONTMATTER_FENCE}\n${rest}`;
2591
+ if (loaded === null || loaded === void 0) {
2592
+ const yaml = dump(provenance, {
2593
+ noRefs: true,
2594
+ lineWidth: -1,
2595
+ sortKeys: false
2596
+ });
2597
+ return `${FRONTMATTER_FENCE}\n${yaml}${FRONTMATTER_FENCE}\n${rest}`;
2598
+ }
2592
2599
  if (typeof loaded !== "object" || Array.isArray(loaded)) throw new Error("invalid frontmatter");
2593
- return `${FRONTMATTER_FENCE}\n${dump({
2600
+ const yaml = dump({
2594
2601
  ...loaded,
2595
2602
  ...provenance
2596
2603
  }, {
2597
2604
  noRefs: true,
2598
2605
  lineWidth: -1,
2599
2606
  sortKeys: false
2600
- })}${FRONTMATTER_FENCE}\n${rest}`;
2607
+ });
2608
+ return `${FRONTMATTER_FENCE}\n${yaml}${FRONTMATTER_FENCE}\n${rest}`;
2601
2609
  }
2602
2610
  //#endregion
2603
2611
  //#region src/lib/gh/gh-lock.ts
@@ -2666,7 +2674,7 @@ function parseGhLock(content) {
2666
2674
  if (!content.trim()) return null;
2667
2675
  let loaded;
2668
2676
  try {
2669
- loaded = load(content);
2677
+ loaded = loadYaml(content);
2670
2678
  } catch {
2671
2679
  return null;
2672
2680
  }
@@ -3801,6 +3809,21 @@ function getFirstPathSeparatorIndex(path) {
3801
3809
  if (backslashIndex === -1) return slashIndex;
3802
3810
  return Math.min(slashIndex, backslashIndex);
3803
3811
  }
3812
+ /**
3813
+ * Decide whether a repository's root-level files should be installed as the
3814
+ * single requested skill (the "root fallback").
3815
+ *
3816
+ * A root fallback fires only when a single, non-wildcard skill was requested,
3817
+ * that skill's own directory is absent, and the repository root actually carries
3818
+ * a `SKILL.md`. Both the git transport (`groupRemoteFilesBySkillRoot`) and the
3819
+ * GitHub transport (`discoverGithubSkillDirs`) gate on these same conditions, so
3820
+ * the decision lives here to keep the two paths from drifting.
3821
+ */
3822
+ function shouldUseRootFallback(params) {
3823
+ const { skillFilter, isWildcard, hasRootSkillFile, hasRequestedSkillDir } = params;
3824
+ const [singleSkillName] = skillFilter;
3825
+ return !isWildcard && skillFilter.length === 1 && singleSkillName !== void 0 && hasRootSkillFile && !hasRequestedSkillDir;
3826
+ }
3804
3827
  function groupRemoteFilesBySkillRoot(params) {
3805
3828
  const { remoteFiles, skillFilter, isWildcard } = params;
3806
3829
  const grouped = /* @__PURE__ */ new Map();
@@ -3823,7 +3846,12 @@ function groupRemoteFilesBySkillRoot(params) {
3823
3846
  }
3824
3847
  const [singleSkillName] = skillFilter;
3825
3848
  const hasRootSkillFile = rootLevelFiles.some((file) => file.relativePath === SKILL_FILE_NAME$1);
3826
- if (!isWildcard && skillFilter.length === 1 && singleSkillName !== void 0 && hasRootSkillFile && !grouped.has(singleSkillName)) grouped.set(singleSkillName, rootLevelFiles);
3849
+ if (singleSkillName !== void 0 && shouldUseRootFallback({
3850
+ skillFilter,
3851
+ isWildcard,
3852
+ hasRootSkillFile,
3853
+ hasRequestedSkillDir: grouped.has(singleSkillName)
3854
+ })) grouped.set(singleSkillName, rootLevelFiles);
3827
3855
  return grouped;
3828
3856
  }
3829
3857
  /**
@@ -3960,7 +3988,12 @@ async function discoverGithubSkillDirs(params) {
3960
3988
  }));
3961
3989
  const [singleSkillName] = skillFilter;
3962
3990
  const hasRequestedSkillDir = singleSkillName !== void 0 && remoteSkillDirs.some((d) => d.name === singleSkillName);
3963
- if (!isWildcard && skillFilter.length === 1 && !hasRequestedSkillDir) {
3991
+ if (shouldUseRootFallback({
3992
+ skillFilter,
3993
+ isWildcard,
3994
+ hasRootSkillFile: entries.some((entry) => entry.type === "file" && entry.name === "SKILL.md"),
3995
+ hasRequestedSkillDir
3996
+ })) {
3964
3997
  const fallback = await fetchRootLevelFallbackSkill({
3965
3998
  entries,
3966
3999
  parsed,
@@ -6426,7 +6459,7 @@ function wrapCommand$1({ name, errorCode, handler, getVersion, loggerFactory = c
6426
6459
  }
6427
6460
  //#endregion
6428
6461
  //#region src/cli/index.ts
6429
- const getVersion = () => "9.5.0";
6462
+ const getVersion = () => "9.6.1";
6430
6463
  function wrapCommand(name, errorCode, handler) {
6431
6464
  return wrapCommand$1({
6432
6465
  name,