rulesync 7.4.0 → 7.5.0

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.
@@ -605,7 +605,7 @@ import { intersection } from "es-toolkit";
605
605
  import { join as join109 } from "path";
606
606
 
607
607
  // src/features/commands/commands-processor.ts
608
- import { basename as basename16, join as join19 } from "path";
608
+ import { basename as basename2, join as join19, relative as relative3 } from "path";
609
609
  import { z as z12 } from "zod/mini";
610
610
 
611
611
  // src/types/feature-processor.ts
@@ -671,7 +671,7 @@ var FeatureProcessor = class {
671
671
  };
672
672
 
673
673
  // src/features/commands/agentsmd-command.ts
674
- import { basename as basename2, join as join5 } from "path";
674
+ import { join as join5 } from "path";
675
675
 
676
676
  // src/utils/frontmatter.ts
677
677
  import matter from "gray-matter";
@@ -724,7 +724,7 @@ function parseFrontmatter(content) {
724
724
  }
725
725
 
726
726
  // src/features/commands/simulated-command.ts
727
- import { basename, join as join4 } from "path";
727
+ import { join as join4 } from "path";
728
728
  import { z as z4 } from "zod/mini";
729
729
 
730
730
  // src/types/ai-file.ts
@@ -972,7 +972,7 @@ var SimulatedCommand = class _SimulatedCommand extends ToolCommand {
972
972
  return {
973
973
  baseDir,
974
974
  relativeDirPath: _SimulatedCommand.getSettablePaths().relativeDirPath,
975
- relativeFilePath: basename(relativeFilePath),
975
+ relativeFilePath,
976
976
  frontmatter: result.data,
977
977
  body: content.trim(),
978
978
  validate
@@ -1029,7 +1029,7 @@ var AgentsmdCommand = class _AgentsmdCommand extends SimulatedCommand {
1029
1029
  return new _AgentsmdCommand({
1030
1030
  baseDir,
1031
1031
  relativeDirPath: _AgentsmdCommand.getSettablePaths().relativeDirPath,
1032
- relativeFilePath: basename2(relativeFilePath),
1032
+ relativeFilePath,
1033
1033
  frontmatter: result.data,
1034
1034
  body: content.trim(),
1035
1035
  validate
@@ -1053,7 +1053,7 @@ var AgentsmdCommand = class _AgentsmdCommand extends SimulatedCommand {
1053
1053
  };
1054
1054
 
1055
1055
  // src/features/commands/antigravity-command.ts
1056
- import { basename as basename4, join as join7 } from "path";
1056
+ import { basename, join as join7 } from "path";
1057
1057
  import { z as z6 } from "zod/mini";
1058
1058
 
1059
1059
  // src/utils/type-guards.ts
@@ -1062,7 +1062,7 @@ function isRecord(value) {
1062
1062
  }
1063
1063
 
1064
1064
  // src/features/commands/rulesync-command.ts
1065
- import { basename as basename3, join as join6 } from "path";
1065
+ import { join as join6 } from "path";
1066
1066
  import { z as z5 } from "zod/mini";
1067
1067
 
1068
1068
  // src/types/rulesync-file.ts
@@ -1106,6 +1106,16 @@ var RulesyncCommand = class _RulesyncCommand extends RulesyncFile {
1106
1106
  getBody() {
1107
1107
  return this.body;
1108
1108
  }
1109
+ withRelativeFilePath(newRelativeFilePath) {
1110
+ return new _RulesyncCommand({
1111
+ baseDir: this.getBaseDir(),
1112
+ relativeDirPath: this.getRelativeDirPath(),
1113
+ relativeFilePath: newRelativeFilePath,
1114
+ frontmatter: this.getFrontmatter(),
1115
+ body: this.getBody(),
1116
+ fileContent: this.getFileContent()
1117
+ });
1118
+ }
1109
1119
  validate() {
1110
1120
  if (!this.frontmatter) {
1111
1121
  return { success: true, error: null };
@@ -1136,11 +1146,10 @@ var RulesyncCommand = class _RulesyncCommand extends RulesyncFile {
1136
1146
  if (!result.success) {
1137
1147
  throw new Error(`Invalid frontmatter in ${relativeFilePath}: ${formatError(result.error)}`);
1138
1148
  }
1139
- const filename = basename3(relativeFilePath);
1140
1149
  return new _RulesyncCommand({
1141
1150
  baseDir: process.cwd(),
1142
1151
  relativeDirPath: _RulesyncCommand.getSettablePaths().relativeDirPath,
1143
- relativeFilePath: filename,
1152
+ relativeFilePath,
1144
1153
  frontmatter: result.data,
1145
1154
  body: content.trim(),
1146
1155
  fileContent
@@ -1255,7 +1264,7 @@ ${body}${turboDirective}`;
1255
1264
  const antigravityTrigger = antigravityConfig && typeof antigravityConfig.trigger === "string" ? antigravityConfig.trigger : void 0;
1256
1265
  const rootTrigger = typeof rulesyncFrontmatter.trigger === "string" ? rulesyncFrontmatter.trigger : void 0;
1257
1266
  const bodyTriggerMatch = rulesyncCommand.getBody().match(/trigger:\s*(\/[\w-]+)/);
1258
- const filenameTrigger = `/${basename4(rulesyncCommand.getRelativeFilePath(), ".md")}`;
1267
+ const filenameTrigger = `/${basename(rulesyncCommand.getRelativeFilePath(), ".md")}`;
1259
1268
  return antigravityTrigger || rootTrigger || (bodyTriggerMatch ? bodyTriggerMatch[1] : void 0) || filenameTrigger;
1260
1269
  }
1261
1270
  validate() {
@@ -1299,7 +1308,7 @@ ${body}${turboDirective}`;
1299
1308
  return new _AntigravityCommand({
1300
1309
  baseDir,
1301
1310
  relativeDirPath: _AntigravityCommand.getSettablePaths().relativeDirPath,
1302
- relativeFilePath: basename4(relativeFilePath),
1311
+ relativeFilePath,
1303
1312
  frontmatter: result.data,
1304
1313
  body: content.trim(),
1305
1314
  fileContent,
@@ -1324,7 +1333,7 @@ ${body}${turboDirective}`;
1324
1333
  };
1325
1334
 
1326
1335
  // src/features/commands/claudecode-command.ts
1327
- import { basename as basename5, join as join8 } from "path";
1336
+ import { join as join8 } from "path";
1328
1337
  import { z as z7 } from "zod/mini";
1329
1338
  var ClaudecodeCommandFrontmatterSchema = z7.looseObject({
1330
1339
  description: z7.string(),
@@ -1445,7 +1454,7 @@ var ClaudecodeCommand = class _ClaudecodeCommand extends ToolCommand {
1445
1454
  return new _ClaudecodeCommand({
1446
1455
  baseDir,
1447
1456
  relativeDirPath: paths.relativeDirPath,
1448
- relativeFilePath: basename5(relativeFilePath),
1457
+ relativeFilePath,
1449
1458
  frontmatter: result.data,
1450
1459
  body: content.trim(),
1451
1460
  validate
@@ -1468,7 +1477,7 @@ var ClaudecodeCommand = class _ClaudecodeCommand extends ToolCommand {
1468
1477
  };
1469
1478
 
1470
1479
  // src/features/commands/cline-command.ts
1471
- import { basename as basename6, join as join9 } from "path";
1480
+ import { join as join9 } from "path";
1472
1481
  var ClineCommand = class _ClineCommand extends ToolCommand {
1473
1482
  static getSettablePaths({ global } = {}) {
1474
1483
  if (global) {
@@ -1535,7 +1544,7 @@ var ClineCommand = class _ClineCommand extends ToolCommand {
1535
1544
  return new _ClineCommand({
1536
1545
  baseDir,
1537
1546
  relativeDirPath: paths.relativeDirPath,
1538
- relativeFilePath: basename6(relativeFilePath),
1547
+ relativeFilePath,
1539
1548
  fileContent: content.trim(),
1540
1549
  validate
1541
1550
  });
@@ -1556,7 +1565,7 @@ var ClineCommand = class _ClineCommand extends ToolCommand {
1556
1565
  };
1557
1566
 
1558
1567
  // src/features/commands/codexcli-command.ts
1559
- import { basename as basename7, join as join10 } from "path";
1568
+ import { join as join10 } from "path";
1560
1569
  var CodexcliCommand = class _CodexcliCommand extends ToolCommand {
1561
1570
  static getSettablePaths({ global } = {}) {
1562
1571
  if (!global) {
@@ -1622,7 +1631,7 @@ var CodexcliCommand = class _CodexcliCommand extends ToolCommand {
1622
1631
  return new _CodexcliCommand({
1623
1632
  baseDir,
1624
1633
  relativeDirPath: paths.relativeDirPath,
1625
- relativeFilePath: basename7(relativeFilePath),
1634
+ relativeFilePath,
1626
1635
  fileContent: content.trim(),
1627
1636
  validate
1628
1637
  });
@@ -1643,7 +1652,7 @@ var CodexcliCommand = class _CodexcliCommand extends ToolCommand {
1643
1652
  };
1644
1653
 
1645
1654
  // src/features/commands/copilot-command.ts
1646
- import { basename as basename8, join as join11 } from "path";
1655
+ import { join as join11 } from "path";
1647
1656
  import { z as z8 } from "zod/mini";
1648
1657
  var CopilotCommandFrontmatterSchema = z8.looseObject({
1649
1658
  mode: z8.optional(z8.string()),
@@ -1755,7 +1764,7 @@ var CopilotCommand = class _CopilotCommand extends ToolCommand {
1755
1764
  return new _CopilotCommand({
1756
1765
  baseDir,
1757
1766
  relativeDirPath: paths.relativeDirPath,
1758
- relativeFilePath: basename8(relativeFilePath),
1767
+ relativeFilePath,
1759
1768
  frontmatter: result.data,
1760
1769
  body: content.trim(),
1761
1770
  validate
@@ -1784,7 +1793,7 @@ var CopilotCommand = class _CopilotCommand extends ToolCommand {
1784
1793
  };
1785
1794
 
1786
1795
  // src/features/commands/cursor-command.ts
1787
- import { basename as basename9, join as join12 } from "path";
1796
+ import { join as join12 } from "path";
1788
1797
  var CursorCommand = class _CursorCommand extends ToolCommand {
1789
1798
  static getSettablePaths(_options = {}) {
1790
1799
  return {
@@ -1847,7 +1856,7 @@ var CursorCommand = class _CursorCommand extends ToolCommand {
1847
1856
  return new _CursorCommand({
1848
1857
  baseDir,
1849
1858
  relativeDirPath: paths.relativeDirPath,
1850
- relativeFilePath: basename9(relativeFilePath),
1859
+ relativeFilePath,
1851
1860
  fileContent: content.trim(),
1852
1861
  validate
1853
1862
  });
@@ -1868,7 +1877,7 @@ var CursorCommand = class _CursorCommand extends ToolCommand {
1868
1877
  };
1869
1878
 
1870
1879
  // src/features/commands/factorydroid-command.ts
1871
- import { basename as basename10, join as join13 } from "path";
1880
+ import { join as join13 } from "path";
1872
1881
  var FactorydroidCommand = class _FactorydroidCommand extends SimulatedCommand {
1873
1882
  static getSettablePaths(_options) {
1874
1883
  return {
@@ -1902,7 +1911,7 @@ var FactorydroidCommand = class _FactorydroidCommand extends SimulatedCommand {
1902
1911
  return new _FactorydroidCommand({
1903
1912
  baseDir,
1904
1913
  relativeDirPath: paths.relativeDirPath,
1905
- relativeFilePath: basename10(relativeFilePath),
1914
+ relativeFilePath,
1906
1915
  frontmatter: result.data,
1907
1916
  body: content.trim(),
1908
1917
  validate
@@ -1926,7 +1935,7 @@ var FactorydroidCommand = class _FactorydroidCommand extends SimulatedCommand {
1926
1935
  };
1927
1936
 
1928
1937
  // src/features/commands/geminicli-command.ts
1929
- import { basename as basename11, join as join14 } from "path";
1938
+ import { join as join14 } from "path";
1930
1939
  import { parse as parseToml } from "smol-toml";
1931
1940
  import { z as z9 } from "zod/mini";
1932
1941
  var GeminiCliCommandFrontmatterSchema = z9.looseObject({
@@ -2034,7 +2043,7 @@ ${geminiFrontmatter.prompt}
2034
2043
  return new _GeminiCliCommand({
2035
2044
  baseDir,
2036
2045
  relativeDirPath: paths.relativeDirPath,
2037
- relativeFilePath: basename11(relativeFilePath),
2046
+ relativeFilePath,
2038
2047
  fileContent,
2039
2048
  validate
2040
2049
  });
@@ -2071,7 +2080,7 @@ prompt = ""`;
2071
2080
  };
2072
2081
 
2073
2082
  // src/features/commands/kilo-command.ts
2074
- import { basename as basename12, join as join15 } from "path";
2083
+ import { join as join15 } from "path";
2075
2084
  var KiloCommand = class _KiloCommand extends ToolCommand {
2076
2085
  static getSettablePaths(_options = {}) {
2077
2086
  return {
@@ -2131,7 +2140,7 @@ var KiloCommand = class _KiloCommand extends ToolCommand {
2131
2140
  return new _KiloCommand({
2132
2141
  baseDir,
2133
2142
  relativeDirPath: paths.relativeDirPath,
2134
- relativeFilePath: basename12(relativeFilePath),
2143
+ relativeFilePath,
2135
2144
  fileContent: content.trim(),
2136
2145
  validate
2137
2146
  });
@@ -2152,7 +2161,7 @@ var KiloCommand = class _KiloCommand extends ToolCommand {
2152
2161
  };
2153
2162
 
2154
2163
  // src/features/commands/kiro-command.ts
2155
- import { basename as basename13, join as join16 } from "path";
2164
+ import { join as join16 } from "path";
2156
2165
  var KiroCommand = class _KiroCommand extends ToolCommand {
2157
2166
  static getSettablePaths(_options = {}) {
2158
2167
  return {
@@ -2212,7 +2221,7 @@ var KiroCommand = class _KiroCommand extends ToolCommand {
2212
2221
  return new _KiroCommand({
2213
2222
  baseDir,
2214
2223
  relativeDirPath: paths.relativeDirPath,
2215
- relativeFilePath: basename13(relativeFilePath),
2224
+ relativeFilePath,
2216
2225
  fileContent: content.trim(),
2217
2226
  validate
2218
2227
  });
@@ -2233,7 +2242,7 @@ var KiroCommand = class _KiroCommand extends ToolCommand {
2233
2242
  };
2234
2243
 
2235
2244
  // src/features/commands/opencode-command.ts
2236
- import { basename as basename14, join as join17 } from "path";
2245
+ import { join as join17 } from "path";
2237
2246
  import { optional as optional2, z as z10 } from "zod/mini";
2238
2247
  var OpenCodeCommandFrontmatterSchema = z10.looseObject({
2239
2248
  description: z10.string(),
@@ -2344,7 +2353,7 @@ var OpenCodeCommand = class _OpenCodeCommand extends ToolCommand {
2344
2353
  return new _OpenCodeCommand({
2345
2354
  baseDir,
2346
2355
  relativeDirPath: paths.relativeDirPath,
2347
- relativeFilePath: basename14(relativeFilePath),
2356
+ relativeFilePath,
2348
2357
  frontmatter: result.data,
2349
2358
  body: content.trim(),
2350
2359
  validate
@@ -2373,7 +2382,7 @@ var OpenCodeCommand = class _OpenCodeCommand extends ToolCommand {
2373
2382
  };
2374
2383
 
2375
2384
  // src/features/commands/roo-command.ts
2376
- import { basename as basename15, join as join18 } from "path";
2385
+ import { join as join18 } from "path";
2377
2386
  import { optional as optional3, z as z11 } from "zod/mini";
2378
2387
  var RooCommandFrontmatterSchema = z11.looseObject({
2379
2388
  description: z11.string(),
@@ -2489,7 +2498,7 @@ var RooCommand = class _RooCommand extends ToolCommand {
2489
2498
  return new _RooCommand({
2490
2499
  baseDir,
2491
2500
  relativeDirPath: _RooCommand.getSettablePaths().relativeDirPath,
2492
- relativeFilePath: basename15(relativeFilePath),
2501
+ relativeFilePath,
2493
2502
  frontmatter: result.data,
2494
2503
  body: content.trim(),
2495
2504
  fileContent,
@@ -2536,42 +2545,78 @@ var toolCommandFactories = /* @__PURE__ */ new Map([
2536
2545
  "agentsmd",
2537
2546
  {
2538
2547
  class: AgentsmdCommand,
2539
- meta: { extension: "md", supportsProject: true, supportsGlobal: false, isSimulated: true }
2548
+ meta: {
2549
+ extension: "md",
2550
+ supportsProject: true,
2551
+ supportsGlobal: false,
2552
+ isSimulated: true,
2553
+ supportsSubdirectory: false
2554
+ }
2540
2555
  }
2541
2556
  ],
2542
2557
  [
2543
2558
  "antigravity",
2544
2559
  {
2545
2560
  class: AntigravityCommand,
2546
- meta: { extension: "md", supportsProject: true, supportsGlobal: false, isSimulated: false }
2561
+ meta: {
2562
+ extension: "md",
2563
+ supportsProject: true,
2564
+ supportsGlobal: false,
2565
+ isSimulated: false,
2566
+ supportsSubdirectory: false
2567
+ }
2547
2568
  }
2548
2569
  ],
2549
2570
  [
2550
2571
  "claudecode",
2551
2572
  {
2552
2573
  class: ClaudecodeCommand,
2553
- meta: { extension: "md", supportsProject: true, supportsGlobal: true, isSimulated: false }
2574
+ meta: {
2575
+ extension: "md",
2576
+ supportsProject: true,
2577
+ supportsGlobal: true,
2578
+ isSimulated: false,
2579
+ supportsSubdirectory: true
2580
+ }
2554
2581
  }
2555
2582
  ],
2556
2583
  [
2557
2584
  "claudecode-legacy",
2558
2585
  {
2559
2586
  class: ClaudecodeCommand,
2560
- meta: { extension: "md", supportsProject: true, supportsGlobal: true, isSimulated: false }
2587
+ meta: {
2588
+ extension: "md",
2589
+ supportsProject: true,
2590
+ supportsGlobal: true,
2591
+ isSimulated: false,
2592
+ supportsSubdirectory: true
2593
+ }
2561
2594
  }
2562
2595
  ],
2563
2596
  [
2564
2597
  "cline",
2565
2598
  {
2566
2599
  class: ClineCommand,
2567
- meta: { extension: "md", supportsProject: true, supportsGlobal: true, isSimulated: false }
2600
+ meta: {
2601
+ extension: "md",
2602
+ supportsProject: true,
2603
+ supportsGlobal: true,
2604
+ isSimulated: false,
2605
+ supportsSubdirectory: false
2606
+ }
2568
2607
  }
2569
2608
  ],
2570
2609
  [
2571
2610
  "codexcli",
2572
2611
  {
2573
2612
  class: CodexcliCommand,
2574
- meta: { extension: "md", supportsProject: false, supportsGlobal: true, isSimulated: false }
2613
+ meta: {
2614
+ extension: "md",
2615
+ supportsProject: false,
2616
+ supportsGlobal: true,
2617
+ isSimulated: false,
2618
+ supportsSubdirectory: false
2619
+ }
2575
2620
  }
2576
2621
  ],
2577
2622
  [
@@ -2582,7 +2627,8 @@ var toolCommandFactories = /* @__PURE__ */ new Map([
2582
2627
  extension: "prompt.md",
2583
2628
  supportsProject: true,
2584
2629
  supportsGlobal: false,
2585
- isSimulated: false
2630
+ isSimulated: false,
2631
+ supportsSubdirectory: false
2586
2632
  }
2587
2633
  }
2588
2634
  ],
@@ -2590,49 +2636,91 @@ var toolCommandFactories = /* @__PURE__ */ new Map([
2590
2636
  "cursor",
2591
2637
  {
2592
2638
  class: CursorCommand,
2593
- meta: { extension: "md", supportsProject: true, supportsGlobal: true, isSimulated: false }
2639
+ meta: {
2640
+ extension: "md",
2641
+ supportsProject: true,
2642
+ supportsGlobal: true,
2643
+ isSimulated: false,
2644
+ supportsSubdirectory: false
2645
+ }
2594
2646
  }
2595
2647
  ],
2596
2648
  [
2597
2649
  "factorydroid",
2598
2650
  {
2599
2651
  class: FactorydroidCommand,
2600
- meta: { extension: "md", supportsProject: true, supportsGlobal: true, isSimulated: true }
2652
+ meta: {
2653
+ extension: "md",
2654
+ supportsProject: true,
2655
+ supportsGlobal: true,
2656
+ isSimulated: true,
2657
+ supportsSubdirectory: false
2658
+ }
2601
2659
  }
2602
2660
  ],
2603
2661
  [
2604
2662
  "geminicli",
2605
2663
  {
2606
2664
  class: GeminiCliCommand,
2607
- meta: { extension: "toml", supportsProject: true, supportsGlobal: true, isSimulated: false }
2665
+ meta: {
2666
+ extension: "toml",
2667
+ supportsProject: true,
2668
+ supportsGlobal: true,
2669
+ isSimulated: false,
2670
+ supportsSubdirectory: true
2671
+ }
2608
2672
  }
2609
2673
  ],
2610
2674
  [
2611
2675
  "kilo",
2612
2676
  {
2613
2677
  class: KiloCommand,
2614
- meta: { extension: "md", supportsProject: true, supportsGlobal: true, isSimulated: false }
2678
+ meta: {
2679
+ extension: "md",
2680
+ supportsProject: true,
2681
+ supportsGlobal: true,
2682
+ isSimulated: false,
2683
+ supportsSubdirectory: false
2684
+ }
2615
2685
  }
2616
2686
  ],
2617
2687
  [
2618
2688
  "kiro",
2619
2689
  {
2620
2690
  class: KiroCommand,
2621
- meta: { extension: "md", supportsProject: true, supportsGlobal: false, isSimulated: false }
2691
+ meta: {
2692
+ extension: "md",
2693
+ supportsProject: true,
2694
+ supportsGlobal: false,
2695
+ isSimulated: false,
2696
+ supportsSubdirectory: false
2697
+ }
2622
2698
  }
2623
2699
  ],
2624
2700
  [
2625
2701
  "opencode",
2626
2702
  {
2627
2703
  class: OpenCodeCommand,
2628
- meta: { extension: "md", supportsProject: true, supportsGlobal: true, isSimulated: false }
2704
+ meta: {
2705
+ extension: "md",
2706
+ supportsProject: true,
2707
+ supportsGlobal: true,
2708
+ isSimulated: false,
2709
+ supportsSubdirectory: true
2710
+ }
2629
2711
  }
2630
2712
  ],
2631
2713
  [
2632
2714
  "roo",
2633
2715
  {
2634
2716
  class: RooCommand,
2635
- meta: { extension: "md", supportsProject: true, supportsGlobal: false, isSimulated: false }
2717
+ meta: {
2718
+ extension: "md",
2719
+ supportsProject: true,
2720
+ supportsGlobal: false,
2721
+ isSimulated: false,
2722
+ supportsSubdirectory: true
2723
+ }
2636
2724
  }
2637
2725
  ]
2638
2726
  ]);
@@ -2685,13 +2773,27 @@ var CommandsProcessor = class extends FeatureProcessor {
2685
2773
  (file) => file instanceof RulesyncCommand
2686
2774
  );
2687
2775
  const factory = this.getFactory(this.toolTarget);
2776
+ const flattenedPathOrigins = /* @__PURE__ */ new Map();
2688
2777
  const toolCommands = rulesyncCommands.map((rulesyncCommand) => {
2689
2778
  if (!factory.class.isTargetedByRulesyncCommand(rulesyncCommand)) {
2690
2779
  return null;
2691
2780
  }
2781
+ const originalRelativePath = rulesyncCommand.getRelativeFilePath();
2782
+ const commandToConvert = factory.meta.supportsSubdirectory ? rulesyncCommand : this.flattenRelativeFilePath(rulesyncCommand);
2783
+ if (!factory.meta.supportsSubdirectory) {
2784
+ const flattenedPath = commandToConvert.getRelativeFilePath();
2785
+ const firstOrigin = flattenedPathOrigins.get(flattenedPath);
2786
+ if (firstOrigin && firstOrigin !== originalRelativePath) {
2787
+ logger.warn(
2788
+ `Command path collision detected while flattening for ${this.toolTarget}: "${firstOrigin}" and "${originalRelativePath}" both map to "${flattenedPath}". The later command will overwrite the earlier one.`
2789
+ );
2790
+ } else if (!firstOrigin) {
2791
+ flattenedPathOrigins.set(flattenedPath, originalRelativePath);
2792
+ }
2793
+ }
2692
2794
  return factory.class.fromRulesyncCommand({
2693
2795
  baseDir: this.baseDir,
2694
- rulesyncCommand,
2796
+ rulesyncCommand: commandToConvert,
2695
2797
  global: this.global
2696
2798
  });
2697
2799
  }).filter((command) => command !== null);
@@ -2706,17 +2808,26 @@ var CommandsProcessor = class extends FeatureProcessor {
2706
2808
  });
2707
2809
  return rulesyncCommands;
2708
2810
  }
2811
+ flattenRelativeFilePath(rulesyncCommand) {
2812
+ const flatPath = basename2(rulesyncCommand.getRelativeFilePath());
2813
+ if (flatPath === rulesyncCommand.getRelativeFilePath()) return rulesyncCommand;
2814
+ return rulesyncCommand.withRelativeFilePath(flatPath);
2815
+ }
2816
+ safeRelativePath(basePath, fullPath) {
2817
+ const rel = relative3(basePath, fullPath);
2818
+ checkPathTraversal({ relativePath: rel, intendedRootDir: basePath });
2819
+ return rel;
2820
+ }
2709
2821
  /**
2710
2822
  * Implementation of abstract method from FeatureProcessor
2711
2823
  * Load and parse rulesync command files from .rulesync/commands/ directory
2712
2824
  */
2713
2825
  async loadRulesyncFiles() {
2714
- const rulesyncCommandPaths = await findFilesByGlobs(
2715
- join19(RulesyncCommand.getSettablePaths().relativeDirPath, "*.md")
2716
- );
2826
+ const basePath = RulesyncCommand.getSettablePaths().relativeDirPath;
2827
+ const rulesyncCommandPaths = await findFilesByGlobs(join19(basePath, "**", "*.md"));
2717
2828
  const rulesyncCommands = await Promise.all(
2718
2829
  rulesyncCommandPaths.map(
2719
- (path3) => RulesyncCommand.fromFile({ relativeFilePath: basename16(path3) })
2830
+ (path3) => RulesyncCommand.fromFile({ relativeFilePath: this.safeRelativePath(basePath, path3) })
2720
2831
  )
2721
2832
  );
2722
2833
  logger.debug(`Successfully loaded ${rulesyncCommands.length} rulesync commands`);
@@ -2731,15 +2842,15 @@ var CommandsProcessor = class extends FeatureProcessor {
2731
2842
  } = {}) {
2732
2843
  const factory = this.getFactory(this.toolTarget);
2733
2844
  const paths = factory.class.getSettablePaths({ global: this.global });
2734
- const commandFilePaths = await findFilesByGlobs(
2735
- join19(this.baseDir, paths.relativeDirPath, `*.${factory.meta.extension}`)
2736
- );
2845
+ const baseDirFull = join19(this.baseDir, paths.relativeDirPath);
2846
+ const globPattern = factory.meta.supportsSubdirectory ? join19(baseDirFull, "**", `*.${factory.meta.extension}`) : join19(baseDirFull, `*.${factory.meta.extension}`);
2847
+ const commandFilePaths = await findFilesByGlobs(globPattern);
2737
2848
  if (forDeletion) {
2738
2849
  const toolCommands2 = commandFilePaths.map(
2739
2850
  (path3) => factory.class.forDeletion({
2740
2851
  baseDir: this.baseDir,
2741
2852
  relativeDirPath: paths.relativeDirPath,
2742
- relativeFilePath: basename16(path3),
2853
+ relativeFilePath: this.safeRelativePath(baseDirFull, path3),
2743
2854
  global: this.global
2744
2855
  })
2745
2856
  ).filter((cmd) => cmd.isDeletable());
@@ -2750,7 +2861,7 @@ var CommandsProcessor = class extends FeatureProcessor {
2750
2861
  commandFilePaths.map(
2751
2862
  (path3) => factory.class.fromFile({
2752
2863
  baseDir: this.baseDir,
2753
- relativeFilePath: basename16(path3),
2864
+ relativeFilePath: this.safeRelativePath(baseDirFull, path3),
2754
2865
  global: this.global
2755
2866
  })
2756
2867
  )
@@ -6670,7 +6781,7 @@ var McpProcessor = class extends FeatureProcessor {
6670
6781
 
6671
6782
  // src/features/rules/rules-processor.ts
6672
6783
  import { encode } from "@toon-format/toon";
6673
- import { basename as basename24, join as join108, relative as relative4 } from "path";
6784
+ import { basename as basename10, join as join108, relative as relative5 } from "path";
6674
6785
  import { z as z49 } from "zod/mini";
6675
6786
 
6676
6787
  // src/constants/general.ts
@@ -6687,7 +6798,7 @@ import { z as z20 } from "zod/mini";
6687
6798
  import { join as join52 } from "path";
6688
6799
 
6689
6800
  // src/types/ai-dir.ts
6690
- import path2, { basename as basename17, join as join51, relative as relative3, resolve as resolve4 } from "path";
6801
+ import path2, { basename as basename3, join as join51, relative as relative4, resolve as resolve4 } from "path";
6691
6802
  var AiDir = class {
6692
6803
  /**
6693
6804
  * @example "."
@@ -6747,7 +6858,7 @@ var AiDir = class {
6747
6858
  const fullPath = path2.join(this.baseDir, this.relativeDirPath, this.dirName);
6748
6859
  const resolvedFull = resolve4(fullPath);
6749
6860
  const resolvedBase = resolve4(this.baseDir);
6750
- const rel = relative3(resolvedBase, resolvedFull);
6861
+ const rel = relative4(resolvedBase, resolvedFull);
6751
6862
  if (rel.startsWith("..") || path2.isAbsolute(rel)) {
6752
6863
  throw new Error(
6753
6864
  `Path traversal detected: Final path escapes baseDir. baseDir="${this.baseDir}", relativeDirPath="${this.relativeDirPath}", dirName="${this.dirName}"`
@@ -6784,12 +6895,12 @@ var AiDir = class {
6784
6895
  const dirPath = join51(baseDir, relativeDirPath, dirName);
6785
6896
  const glob = join51(dirPath, "**", "*");
6786
6897
  const filePaths = await findFilesByGlobs(glob, { type: "file" });
6787
- const filteredPaths = filePaths.filter((filePath) => basename17(filePath) !== excludeFileName);
6898
+ const filteredPaths = filePaths.filter((filePath) => basename3(filePath) !== excludeFileName);
6788
6899
  const files = await Promise.all(
6789
6900
  filteredPaths.map(async (filePath) => {
6790
6901
  const fileBuffer = await readFileBuffer(filePath);
6791
6902
  return {
6792
- relativeFilePathToDirPath: relative3(dirPath, filePath),
6903
+ relativeFilePathToDirPath: relative4(dirPath, filePath),
6793
6904
  fileBuffer
6794
6905
  };
6795
6906
  })
@@ -7139,7 +7250,7 @@ var FactorydroidSkill = class _FactorydroidSkill extends SimulatedSkill {
7139
7250
  };
7140
7251
 
7141
7252
  // src/features/skills/skills-processor.ts
7142
- import { basename as basename19, join as join71 } from "path";
7253
+ import { basename as basename5, join as join71 } from "path";
7143
7254
  import { z as z34 } from "zod/mini";
7144
7255
 
7145
7256
  // src/types/dir-feature-processor.ts
@@ -9346,7 +9457,7 @@ var RooSkill = class _RooSkill extends ToolSkill {
9346
9457
  };
9347
9458
 
9348
9459
  // src/features/skills/skills-utils.ts
9349
- import { basename as basename18, join as join70 } from "path";
9460
+ import { basename as basename4, join as join70 } from "path";
9350
9461
  async function getLocalSkillDirNames(baseDir) {
9351
9462
  const skillsDir = join70(baseDir, RULESYNC_SKILLS_RELATIVE_DIR_PATH);
9352
9463
  const names = /* @__PURE__ */ new Set();
@@ -9355,8 +9466,8 @@ async function getLocalSkillDirNames(baseDir) {
9355
9466
  }
9356
9467
  const dirPaths = await findFilesByGlobs(join70(skillsDir, "*"), { type: "dir" });
9357
9468
  for (const dirPath of dirPaths) {
9358
- const name = basename18(dirPath);
9359
- if (name === basename18(RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH)) continue;
9469
+ const name = basename4(dirPath);
9470
+ if (name === basename4(RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH)) continue;
9360
9471
  names.add(name);
9361
9472
  }
9362
9473
  return names;
@@ -9578,7 +9689,7 @@ var SkillsProcessor = class extends DirFeatureProcessor {
9578
9689
  let curatedSkills = [];
9579
9690
  if (await directoryExists(curatedDirPath)) {
9580
9691
  const curatedDirPaths = await findFilesByGlobs(join71(curatedDirPath, "*"), { type: "dir" });
9581
- const curatedDirNames = curatedDirPaths.map((path3) => basename19(path3));
9692
+ const curatedDirNames = curatedDirPaths.map((path3) => basename5(path3));
9582
9693
  const nonConflicting = curatedDirNames.filter((name) => {
9583
9694
  if (localSkillNames.has(name)) {
9584
9695
  logger.debug(`Skipping curated skill "${name}": local skill takes precedence.`);
@@ -9613,7 +9724,7 @@ var SkillsProcessor = class extends DirFeatureProcessor {
9613
9724
  const paths = factory.class.getSettablePaths({ global: this.global });
9614
9725
  const skillsDirPath = join71(this.baseDir, paths.relativeDirPath);
9615
9726
  const dirPaths = await findFilesByGlobs(join71(skillsDirPath, "*"), { type: "dir" });
9616
- const dirNames = dirPaths.map((path3) => basename19(path3));
9727
+ const dirNames = dirPaths.map((path3) => basename5(path3));
9617
9728
  const toolSkills = await Promise.all(
9618
9729
  dirNames.map(
9619
9730
  (dirName) => factory.class.fromDir({
@@ -9631,7 +9742,7 @@ var SkillsProcessor = class extends DirFeatureProcessor {
9631
9742
  const paths = factory.class.getSettablePaths({ global: this.global });
9632
9743
  const skillsDirPath = join71(this.baseDir, paths.relativeDirPath);
9633
9744
  const dirPaths = await findFilesByGlobs(join71(skillsDirPath, "*"), { type: "dir" });
9634
- const dirNames = dirPaths.map((path3) => basename19(path3));
9745
+ const dirNames = dirPaths.map((path3) => basename5(path3));
9635
9746
  const toolSkills = dirNames.map(
9636
9747
  (dirName) => factory.class.forDeletion({
9637
9748
  baseDir: this.baseDir,
@@ -9695,7 +9806,7 @@ var SkillsProcessor = class extends DirFeatureProcessor {
9695
9806
  import { join as join73 } from "path";
9696
9807
 
9697
9808
  // src/features/subagents/simulated-subagent.ts
9698
- import { basename as basename20, join as join72 } from "path";
9809
+ import { basename as basename6, join as join72 } from "path";
9699
9810
  import { z as z35 } from "zod/mini";
9700
9811
 
9701
9812
  // src/features/subagents/tool-subagent.ts
@@ -9822,7 +9933,7 @@ var SimulatedSubagent = class extends ToolSubagent {
9822
9933
  return {
9823
9934
  baseDir,
9824
9935
  relativeDirPath: this.getSettablePaths().relativeDirPath,
9825
- relativeFilePath: basename20(relativeFilePath),
9936
+ relativeFilePath: basename6(relativeFilePath),
9826
9937
  frontmatter: result.data,
9827
9938
  body: content.trim(),
9828
9939
  validate
@@ -9979,7 +10090,7 @@ var RooSubagent = class _RooSubagent extends SimulatedSubagent {
9979
10090
  };
9980
10091
 
9981
10092
  // src/features/subagents/subagents-processor.ts
9982
- import { basename as basename23, join as join84 } from "path";
10093
+ import { basename as basename9, join as join84 } from "path";
9983
10094
  import { z as z42 } from "zod/mini";
9984
10095
 
9985
10096
  // src/features/subagents/claudecode-subagent.ts
@@ -9987,7 +10098,7 @@ import { join as join79 } from "path";
9987
10098
  import { z as z37 } from "zod/mini";
9988
10099
 
9989
10100
  // src/features/subagents/rulesync-subagent.ts
9990
- import { basename as basename21, join as join78 } from "path";
10101
+ import { basename as basename7, join as join78 } from "path";
9991
10102
  import { z as z36 } from "zod/mini";
9992
10103
  var RulesyncSubagentFrontmatterSchema = z36.looseObject({
9993
10104
  targets: z36._default(RulesyncTargetsSchema, ["*"]),
@@ -10050,7 +10161,7 @@ var RulesyncSubagent = class _RulesyncSubagent extends RulesyncFile {
10050
10161
  if (!result.success) {
10051
10162
  throw new Error(`Invalid frontmatter in ${relativeFilePath}: ${formatError(result.error)}`);
10052
10163
  }
10053
- const filename = basename21(relativeFilePath);
10164
+ const filename = basename7(relativeFilePath);
10054
10165
  return new _RulesyncSubagent({
10055
10166
  baseDir: process.cwd(),
10056
10167
  relativeDirPath: this.getSettablePaths().relativeDirPath,
@@ -10669,7 +10780,7 @@ var KiroSubagent = class _KiroSubagent extends ToolSubagent {
10669
10780
  };
10670
10781
 
10671
10782
  // src/features/subagents/opencode-subagent.ts
10672
- import { basename as basename22, join as join83 } from "path";
10783
+ import { basename as basename8, join as join83 } from "path";
10673
10784
  import { z as z41 } from "zod/mini";
10674
10785
  var OpenCodeSubagentFrontmatterSchema = z41.looseObject({
10675
10786
  description: z41.string(),
@@ -10711,7 +10822,7 @@ var OpenCodeSubagent = class _OpenCodeSubagent extends ToolSubagent {
10711
10822
  const { description, mode, name, ...opencodeSection } = this.frontmatter;
10712
10823
  const rulesyncFrontmatter = {
10713
10824
  targets: ["*"],
10714
- name: name ?? basename22(this.getRelativeFilePath(), ".md"),
10825
+ name: name ?? basename8(this.getRelativeFilePath(), ".md"),
10715
10826
  description,
10716
10827
  opencode: { mode, ...opencodeSection }
10717
10828
  };
@@ -11044,7 +11155,7 @@ var SubagentsProcessor = class extends FeatureProcessor {
11044
11155
  (path3) => factory.class.forDeletion({
11045
11156
  baseDir: this.baseDir,
11046
11157
  relativeDirPath: paths.relativeDirPath,
11047
- relativeFilePath: basename23(path3),
11158
+ relativeFilePath: basename9(path3),
11048
11159
  global: this.global
11049
11160
  })
11050
11161
  ).filter((subagent) => subagent.isDeletable());
@@ -11057,7 +11168,7 @@ var SubagentsProcessor = class extends FeatureProcessor {
11057
11168
  subagentFilePaths.map(
11058
11169
  (path3) => factory.class.fromFile({
11059
11170
  baseDir: this.baseDir,
11060
- relativeFilePath: basename23(path3),
11171
+ relativeFilePath: basename9(path3),
11061
11172
  global: this.global
11062
11173
  })
11063
11174
  )
@@ -14284,7 +14395,7 @@ var RulesProcessor = class extends FeatureProcessor {
14284
14395
  logger.debug(`Found ${files.length} rulesync files`);
14285
14396
  const rulesyncRules = await Promise.all(
14286
14397
  files.map((file) => {
14287
- const relativeFilePath = relative4(rulesyncBaseDir, file);
14398
+ const relativeFilePath = relative5(rulesyncBaseDir, file);
14288
14399
  checkPathTraversal({
14289
14400
  relativePath: relativeFilePath,
14290
14401
  intendedRootDir: rulesyncBaseDir
@@ -14358,7 +14469,7 @@ var RulesProcessor = class extends FeatureProcessor {
14358
14469
  (filePath) => factory.class.forDeletion({
14359
14470
  baseDir: this.baseDir,
14360
14471
  relativeDirPath: settablePaths.root?.relativeDirPath ?? ".",
14361
- relativeFilePath: basename24(filePath),
14472
+ relativeFilePath: basename10(filePath),
14362
14473
  global: this.global
14363
14474
  })
14364
14475
  ).filter((rule) => rule.isDeletable());
@@ -14367,7 +14478,7 @@ var RulesProcessor = class extends FeatureProcessor {
14367
14478
  rootFilePaths.map(
14368
14479
  (filePath) => factory.class.fromFile({
14369
14480
  baseDir: this.baseDir,
14370
- relativeFilePath: basename24(filePath),
14481
+ relativeFilePath: basename10(filePath),
14371
14482
  global: this.global
14372
14483
  })
14373
14484
  )
@@ -14391,7 +14502,7 @@ var RulesProcessor = class extends FeatureProcessor {
14391
14502
  (filePath) => factory.class.forDeletion({
14392
14503
  baseDir: this.baseDir,
14393
14504
  relativeDirPath: settablePaths.root?.relativeDirPath ?? ".",
14394
- relativeFilePath: basename24(filePath),
14505
+ relativeFilePath: basename10(filePath),
14395
14506
  global: this.global
14396
14507
  })
14397
14508
  ).filter((rule) => rule.isDeletable());
@@ -14407,7 +14518,7 @@ var RulesProcessor = class extends FeatureProcessor {
14407
14518
  );
14408
14519
  if (forDeletion) {
14409
14520
  return nonRootFilePaths.map((filePath) => {
14410
- const relativeFilePath = relative4(nonRootBaseDir, filePath);
14521
+ const relativeFilePath = relative5(nonRootBaseDir, filePath);
14411
14522
  checkPathTraversal({
14412
14523
  relativePath: relativeFilePath,
14413
14524
  intendedRootDir: nonRootBaseDir
@@ -14422,7 +14533,7 @@ var RulesProcessor = class extends FeatureProcessor {
14422
14533
  }
14423
14534
  return await Promise.all(
14424
14535
  nonRootFilePaths.map((filePath) => {
14425
- const relativeFilePath = relative4(nonRootBaseDir, filePath);
14536
+ const relativeFilePath = relative5(nonRootBaseDir, filePath);
14426
14537
  checkPathTraversal({
14427
14538
  relativePath: relativeFilePath,
14428
14539
  intendedRootDir: nonRootBaseDir