rulesync 0.59.0 → 0.61.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.
package/dist/index.js CHANGED
@@ -1,16 +1,16 @@
1
1
  #!/usr/bin/env node
2
- import "./chunk-S3GB3VQK.js";
2
+ import "./chunk-U63N3YDS.js";
3
3
  import "./chunk-LXTA7DBA.js";
4
4
  import "./chunk-PCATT4UZ.js";
5
- import "./chunk-3YQ42A7G.js";
5
+ import "./chunk-ICMPPX55.js";
6
6
  import "./chunk-YTU3SCQO.js";
7
- import "./chunk-EG7LNNMW.js";
8
- import "./chunk-VYO76WDU.js";
9
- import "./chunk-DJWXF2WO.js";
7
+ import "./chunk-3ZLMXJTX.js";
8
+ import "./chunk-74TYZWHJ.js";
9
+ import "./chunk-C5LFJFPS.js";
10
10
  import "./chunk-KUGTKMNW.js";
11
- import "./chunk-LIV53UU5.js";
12
- import "./chunk-5SRMJNDW.js";
13
- import "./chunk-OCK47GE7.js";
11
+ import "./chunk-DA3XULAD.js";
12
+ import "./chunk-LRYVNLH5.js";
13
+ import "./chunk-2KYIOT5S.js";
14
14
  import {
15
15
  ALL_TOOL_TARGETS,
16
16
  RulesyncTargetsSchema,
@@ -222,13 +222,6 @@ var RuleFrontmatterSchema = z6.object({
222
222
  windsurfOutputFormat: z6.optional(z6.enum(["single-file", "directory"])),
223
223
  tags: z6.optional(z6.array(z6.string()))
224
224
  });
225
- var ParsedRuleSchema = z6.object({
226
- frontmatter: RuleFrontmatterSchema,
227
- content: z6.string(),
228
- filename: z6.string(),
229
- filepath: z6.string(),
230
- type: z6.optional(z6.enum(["rule", "command"]))
231
- });
232
225
  var GeneratedOutputSchema = z6.object({
233
226
  tool: ToolTargetSchema,
234
227
  filepath: z6.string(),
@@ -740,10 +733,10 @@ export default config;
740
733
  }
741
734
 
742
735
  // src/cli/commands/generate.ts
743
- import { join as join14 } from "path";
736
+ import { join as join15 } from "path";
744
737
 
745
738
  // src/core/command-generator.ts
746
- import { join as join5 } from "path";
739
+ import { join as join6 } from "path";
747
740
 
748
741
  // src/generators/commands/claudecode.ts
749
742
  import { join as join3 } from "path";
@@ -812,10 +805,37 @@ var GeminiCliCommandGenerator = class {
812
805
  }
813
806
  };
814
807
 
808
+ // src/generators/commands/roo.ts
809
+ import { join as join5 } from "path";
810
+ var RooCommandGenerator = class {
811
+ generate(command, outputDir) {
812
+ const filepath = this.getOutputPath(command.filename, outputDir);
813
+ const frontmatter = ["---"];
814
+ if (command.frontmatter.description) {
815
+ frontmatter.push(`description: ${command.frontmatter.description}`);
816
+ }
817
+ frontmatter.push("---");
818
+ const content = `${frontmatter.join("\n")}
819
+
820
+ ${command.content.trim()}
821
+ `;
822
+ return {
823
+ tool: "roo",
824
+ filepath,
825
+ content
826
+ };
827
+ }
828
+ getOutputPath(filename, baseDir) {
829
+ const flattenedName = filename.replace(/\//g, "-");
830
+ return join5(baseDir, ".roo", "commands", `${flattenedName}.md`);
831
+ }
832
+ };
833
+
815
834
  // src/generators/commands/index.ts
816
835
  var commandGenerators = {
817
836
  claudecode: new ClaudeCodeCommandGenerator(),
818
- geminicli: new GeminiCliCommandGenerator()
837
+ geminicli: new GeminiCliCommandGenerator(),
838
+ roo: new RooCommandGenerator()
819
839
  };
820
840
  function getCommandGenerator(tool) {
821
841
  return commandGenerators[tool];
@@ -866,7 +886,7 @@ async function parseCommandFile(filepath) {
866
886
 
867
887
  // src/core/command-generator.ts
868
888
  async function generateCommands(projectRoot, baseDir, targets) {
869
- const commandsDir = join5(projectRoot, ".rulesync", "commands");
889
+ const commandsDir = join6(projectRoot, ".rulesync", "commands");
870
890
  if (!await fileExists(commandsDir)) {
871
891
  return [];
872
892
  }
@@ -876,7 +896,9 @@ async function generateCommands(projectRoot, baseDir, targets) {
876
896
  }
877
897
  const outputs = [];
878
898
  const outputDir = baseDir || projectRoot;
879
- const supportedTargets = targets.filter((target) => ["claudecode", "geminicli"].includes(target));
899
+ const supportedTargets = targets.filter(
900
+ (target) => ["claudecode", "geminicli", "roo"].includes(target)
901
+ );
880
902
  for (const target of supportedTargets) {
881
903
  const generator = getCommandGenerator(target);
882
904
  if (!generator) {
@@ -898,58 +920,81 @@ async function generateCommands(projectRoot, baseDir, targets) {
898
920
  }
899
921
 
900
922
  // src/generators/ignore/shared-factory.ts
901
- import { join as join6 } from "path";
923
+ import { join as join7 } from "path";
902
924
 
903
925
  // src/generators/ignore/shared-helpers.ts
904
926
  function extractIgnorePatternsFromRules(rules) {
905
927
  const patterns = [];
906
928
  for (const rule of rules) {
907
929
  if (rule.frontmatter.globs && rule.frontmatter.globs.length > 0) {
908
- for (const glob of rule.frontmatter.globs) {
909
- if (shouldExcludeFromAI(glob)) {
910
- patterns.push(`# Exclude: ${rule.frontmatter.description}`);
911
- patterns.push(glob);
912
- }
930
+ const sensitiveGlobs = rule.frontmatter.globs.filter(shouldExcludeFromAI);
931
+ if (sensitiveGlobs.length > 0) {
932
+ patterns.push(`# Exclude: ${rule.frontmatter.description}`);
933
+ patterns.push(...sensitiveGlobs);
913
934
  }
914
935
  }
915
- const contentPatterns = extractIgnorePatternsFromContent(rule.content);
936
+ const contentPatterns = extractBasicIgnorePatternsFromContent(rule.content);
916
937
  patterns.push(...contentPatterns);
917
938
  }
918
939
  return patterns;
919
940
  }
920
941
  function shouldExcludeFromAI(glob) {
921
- const excludePatterns = [
922
- // Large generated files that slow indexing
923
- "**/assets/generated/**",
924
- "**/public/build/**",
925
- // Test fixtures with potentially sensitive data
926
- "**/tests/fixtures/**",
927
- "**/test/fixtures/**",
928
- "**/*.fixture.*",
929
- // Build outputs that provide little value for AI context
942
+ const sensitivePatterns = [
943
+ // Security-related patterns
944
+ "**/secret**",
945
+ "**/credential**",
946
+ "**/token**",
947
+ "**/key**",
948
+ "**/password**",
949
+ "**/auth**",
950
+ "**/private**",
951
+ "**/confidential**",
952
+ "**/internal**",
953
+ "**/internal-docs/**",
954
+ "**/admin**",
955
+ // Configuration patterns that might contain secrets
956
+ "**/config/prod**",
957
+ "**/config/production**",
958
+ "**/config/secret**",
959
+ "**/config/secrets/**",
960
+ "**/env/**",
961
+ "**/.env**",
962
+ // Build and deployment patterns
930
963
  "**/dist/**",
931
964
  "**/build/**",
932
- "**/coverage/**",
933
- // Configuration that might contain sensitive data
934
- "**/config/production/**",
935
- "**/config/secrets/**",
936
- "**/config/prod/**",
937
- "**/deploy/prod/**",
938
- "**/*.prod.*",
939
- // Internal documentation that might be sensitive
940
- "**/internal/**",
941
- "**/internal-docs/**",
942
- "**/proprietary/**",
943
- "**/personal-notes/**",
944
- "**/private/**",
945
- "**/confidential/**"
965
+ "**/target/**",
966
+ "**/out/**",
967
+ "**/node_modules/**",
968
+ // Data and media patterns
969
+ "**/data/**",
970
+ "**/dataset**",
971
+ "**/backup**",
972
+ "**/logs/**",
973
+ "**/log/**",
974
+ "**/temp/**",
975
+ "**/tmp/**",
976
+ "**/cache/**",
977
+ // Test fixtures that might contain sensitive data
978
+ "**/test/fixtures/**",
979
+ "**/test**/fixture**",
980
+ "**/test**/mock**",
981
+ "**/test**/data/**",
982
+ // Database and infrastructure
983
+ "**/*.sqlite",
984
+ "**/*.db",
985
+ "**/*.dump",
986
+ // Production files
987
+ "**/*.prod.json",
988
+ "**/*.production.*"
946
989
  ];
947
- return excludePatterns.some((pattern) => {
948
- const regex = new RegExp(pattern.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*"));
949
- return regex.test(glob);
990
+ const lowerGlob = glob.toLowerCase();
991
+ return sensitivePatterns.some((pattern) => {
992
+ const regexPattern = pattern.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*").replace(/\?/g, ".");
993
+ const regex = new RegExp(`^${regexPattern}$`, "i");
994
+ return regex.test(lowerGlob);
950
995
  });
951
996
  }
952
- function extractIgnorePatternsFromContent(content) {
997
+ function extractBasicIgnorePatternsFromContent(content) {
953
998
  const patterns = [];
954
999
  const lines = content.split("\n");
955
1000
  for (const line of lines) {
@@ -960,24 +1005,6 @@ function extractIgnorePatternsFromContent(content) {
960
1005
  patterns.push(pattern);
961
1006
  }
962
1007
  }
963
- if (trimmed.startsWith("# AUGMENT_IGNORE:") || trimmed.startsWith("# augmentignore:")) {
964
- const pattern = trimmed.replace(/^# (AUGMENT_IGNORE|augmentignore):\s*/, "").trim();
965
- if (pattern) {
966
- patterns.push(pattern);
967
- }
968
- }
969
- if (trimmed.startsWith("# AUGMENT_INCLUDE:") || trimmed.startsWith("# augmentinclude:")) {
970
- const pattern = trimmed.replace(/^# (AUGMENT_INCLUDE|augmentinclude):\s*/, "").trim();
971
- if (pattern) {
972
- patterns.push(`!${pattern}`);
973
- }
974
- }
975
- if (trimmed.includes("exclude") || trimmed.includes("ignore")) {
976
- const matches = trimmed.match(/['"`]([^'"`]+\.(log|tmp|cache|temp))['"`]/g);
977
- if (matches) {
978
- patterns.push(...matches.map((m) => m.replace(/['"`]/g, "")));
979
- }
980
- }
981
1008
  }
982
1009
  return patterns;
983
1010
  }
@@ -1016,7 +1043,7 @@ function generateIgnoreFile(rules, config, ignoreConfig, baseDir) {
1016
1043
  const outputs = [];
1017
1044
  const content = generateIgnoreContent(rules, ignoreConfig);
1018
1045
  const outputPath = baseDir || process.cwd();
1019
- const filepath = join6(outputPath, ignoreConfig.filename);
1046
+ const filepath = join7(outputPath, ignoreConfig.filename);
1020
1047
  outputs.push({
1021
1048
  tool: ignoreConfig.tool,
1022
1049
  filepath,
@@ -1604,20 +1631,20 @@ function generateWindsurfIgnore(rules, config, baseDir) {
1604
1631
  }
1605
1632
 
1606
1633
  // src/generators/rules/augmentcode.ts
1607
- import { join as join9 } from "path";
1634
+ import { join as join10 } from "path";
1608
1635
 
1609
1636
  // src/generators/rules/shared-helpers.ts
1610
- import { join as join8 } from "path";
1637
+ import { join as join9 } from "path";
1611
1638
 
1612
1639
  // src/utils/ignore.ts
1613
- import { join as join7 } from "path";
1640
+ import { join as join8 } from "path";
1614
1641
  import micromatch from "micromatch";
1615
1642
  var cachedIgnorePatterns = null;
1616
1643
  async function loadIgnorePatterns(baseDir = process.cwd()) {
1617
1644
  if (cachedIgnorePatterns) {
1618
1645
  return cachedIgnorePatterns;
1619
1646
  }
1620
- const ignorePath = join7(baseDir, ".rulesyncignore");
1647
+ const ignorePath = join8(baseDir, ".rulesyncignore");
1621
1648
  if (!await fileExists(ignorePath)) {
1622
1649
  cachedIgnorePatterns = { patterns: [] };
1623
1650
  return cachedIgnorePatterns;
@@ -1671,7 +1698,7 @@ function addOutput(outputs, tool, config, baseDir, relativePath, content) {
1671
1698
  const outputDir = resolveOutputDir(config, tool, baseDir);
1672
1699
  outputs.push({
1673
1700
  tool,
1674
- filepath: join8(outputDir, relativePath),
1701
+ filepath: join9(outputDir, relativePath),
1675
1702
  content
1676
1703
  });
1677
1704
  }
@@ -1680,7 +1707,7 @@ async function generateRulesConfig(rules, config, generatorConfig, baseDir) {
1680
1707
  for (const rule of rules) {
1681
1708
  const content = generatorConfig.generateContent(rule);
1682
1709
  const outputDir = resolveOutputDir(config, generatorConfig.tool, baseDir);
1683
- const filepath = generatorConfig.pathResolver ? generatorConfig.pathResolver(rule, outputDir) : join8(outputDir, `${rule.filename}${generatorConfig.fileExtension}`);
1710
+ const filepath = generatorConfig.pathResolver ? generatorConfig.pathResolver(rule, outputDir) : join9(outputDir, `${rule.filename}${generatorConfig.fileExtension}`);
1684
1711
  outputs.push({
1685
1712
  tool: generatorConfig.tool,
1686
1713
  filepath,
@@ -1708,7 +1735,7 @@ async function generateComplexRules(rules, config, generatorConfig, baseDir) {
1708
1735
  for (const rule of detailRules) {
1709
1736
  const content = generatorConfig.generateDetailContent(rule);
1710
1737
  const filepath = resolvePath(
1711
- join8(generatorConfig.detailSubDir, `${rule.filename}.md`),
1738
+ join9(generatorConfig.detailSubDir, `${rule.filename}.md`),
1712
1739
  baseDir
1713
1740
  );
1714
1741
  outputs.push({
@@ -1771,7 +1798,7 @@ async function generateAugmentcodeConfig(rules, config, baseDir) {
1771
1798
  "augmentcode",
1772
1799
  config,
1773
1800
  baseDir,
1774
- join9(".augment", "rules", `${rule.filename}.md`),
1801
+ join10(".augment", "rules", `${rule.filename}.md`),
1775
1802
  generateRuleFile(rule)
1776
1803
  );
1777
1804
  });
@@ -1824,7 +1851,7 @@ function generateLegacyGuidelinesFile(allRules) {
1824
1851
  }
1825
1852
 
1826
1853
  // src/generators/rules/claudecode.ts
1827
- import { join as join10 } from "path";
1854
+ import { join as join11 } from "path";
1828
1855
  async function generateClaudecodeConfig(rules, config, baseDir) {
1829
1856
  const generatorConfig = {
1830
1857
  tool: "claudecode",
@@ -1836,7 +1863,7 @@ async function generateClaudecodeConfig(rules, config, baseDir) {
1836
1863
  generateDetailContent: generateMemoryFile,
1837
1864
  detailSubDir: ".claude/memories",
1838
1865
  updateAdditionalConfig: async (ignorePatterns, baseDir2) => {
1839
- const settingsPath = resolvePath(join10(".claude", "settings.json"), baseDir2);
1866
+ const settingsPath = resolvePath(join11(".claude", "settings.json"), baseDir2);
1840
1867
  await updateClaudeSettings(settingsPath, ignorePatterns);
1841
1868
  return [];
1842
1869
  }
@@ -1900,7 +1927,7 @@ async function updateClaudeSettings(settingsPath, ignorePatterns) {
1900
1927
  }
1901
1928
 
1902
1929
  // src/generators/rules/generator-registry.ts
1903
- import { join as join11 } from "path";
1930
+ import { join as join12 } from "path";
1904
1931
  function determineCursorRuleType(frontmatter) {
1905
1932
  if (frontmatter.cursorRuleType) {
1906
1933
  return frontmatter.cursorRuleType;
@@ -1980,7 +2007,7 @@ var GENERATOR_REGISTRY = {
1980
2007
  },
1981
2008
  pathResolver: (rule, outputDir) => {
1982
2009
  const baseFilename = rule.filename.replace(/\.md$/, "");
1983
- return join11(outputDir, `${baseFilename}.instructions.md`);
2010
+ return join12(outputDir, `${baseFilename}.instructions.md`);
1984
2011
  }
1985
2012
  },
1986
2013
  cursor: {
@@ -2020,7 +2047,7 @@ var GENERATOR_REGISTRY = {
2020
2047
  return lines.join("\n");
2021
2048
  },
2022
2049
  pathResolver: (rule, outputDir) => {
2023
- return join11(outputDir, `${rule.filename}.mdc`);
2050
+ return join12(outputDir, `${rule.filename}.mdc`);
2024
2051
  }
2025
2052
  },
2026
2053
  codexcli: {
@@ -2056,10 +2083,10 @@ var GENERATOR_REGISTRY = {
2056
2083
  pathResolver: (rule, outputDir) => {
2057
2084
  const outputFormat = rule.frontmatter.windsurfOutputFormat || "directory";
2058
2085
  if (outputFormat === "single-file") {
2059
- return join11(outputDir, ".windsurf-rules");
2086
+ return join12(outputDir, ".windsurf-rules");
2060
2087
  } else {
2061
- const rulesDir = join11(outputDir, ".windsurf", "rules");
2062
- return join11(rulesDir, `${rule.filename}.md`);
2088
+ const rulesDir = join12(outputDir, ".windsurf", "rules");
2089
+ return join12(rulesDir, `${rule.filename}.md`);
2063
2090
  }
2064
2091
  }
2065
2092
  },
@@ -2150,10 +2177,18 @@ async function generateFromRegistry(tool, rules, config, baseDir) {
2150
2177
  }
2151
2178
  }
2152
2179
 
2153
- // src/generators/rules/cline.ts
2154
- async function generateClineConfig(rules, config, baseDir) {
2155
- return generateFromRegistry("cline", rules, config, baseDir);
2180
+ // src/generators/rules/generator-factory.ts
2181
+ function createSimpleGenerator(toolName) {
2182
+ return async function(rules, config, baseDir) {
2183
+ return generateFromRegistry(toolName, rules, config, baseDir);
2184
+ };
2156
2185
  }
2186
+ var generateCursorConfig = createSimpleGenerator("cursor");
2187
+ var generateClineConfig = createSimpleGenerator("cline");
2188
+ var generateCopilotConfig = createSimpleGenerator("copilot");
2189
+ var generateWindsurfConfig = createSimpleGenerator("windsurf");
2190
+ var generateKiroConfig = createSimpleGenerator("kiro");
2191
+ var generateRooConfig = createSimpleGenerator("roo");
2157
2192
 
2158
2193
  // src/generators/rules/codexcli.ts
2159
2194
  async function generateCodexConfig(rules, config, baseDir) {
@@ -2200,16 +2235,6 @@ function generateConcatenatedCodexContent(rules) {
2200
2235
  return sections.join("\n\n---\n\n");
2201
2236
  }
2202
2237
 
2203
- // src/generators/rules/copilot.ts
2204
- async function generateCopilotConfig(rules, config, baseDir) {
2205
- return generateFromRegistry("copilot", rules, config, baseDir);
2206
- }
2207
-
2208
- // src/generators/rules/cursor.ts
2209
- async function generateCursorConfig(rules, config, baseDir) {
2210
- return generateFromRegistry("cursor", rules, config, baseDir);
2211
- }
2212
-
2213
2238
  // src/generators/rules/geminicli.ts
2214
2239
  async function generateGeminiConfig(rules, config, baseDir) {
2215
2240
  const generatorConfig = {
@@ -2279,21 +2304,6 @@ function generateGuidelinesMarkdown(rootRule, detailRules) {
2279
2304
  return lines.join("\n").trim();
2280
2305
  }
2281
2306
 
2282
- // src/generators/rules/kiro.ts
2283
- async function generateKiroConfig(rules, config, baseDir) {
2284
- return generateFromRegistry("kiro", rules, config, baseDir);
2285
- }
2286
-
2287
- // src/generators/rules/roo.ts
2288
- async function generateRooConfig(rules, config, baseDir) {
2289
- return generateFromRegistry("roo", rules, config, baseDir);
2290
- }
2291
-
2292
- // src/generators/rules/windsurf.ts
2293
- async function generateWindsurfConfig(rules, config, baseDir) {
2294
- return generateFromRegistry("windsurf", rules, config, baseDir);
2295
- }
2296
-
2297
2307
  // src/core/generator.ts
2298
2308
  async function generateConfigurations(rules, config, targetTools, baseDir) {
2299
2309
  const outputs = createOutputsArray();
@@ -2538,22 +2548,22 @@ async function generateMcpConfigurations(mcpConfig, baseDir, targetTools) {
2538
2548
  servers,
2539
2549
  dir
2540
2550
  ),
2541
- claudecode: async (servers, dir) => (await import("./claudecode-CRSXMPS5.js")).generateClaudeMcpConfiguration(
2551
+ claudecode: async (servers, dir) => (await import("./claudecode-XKHMZT7R.js")).generateClaudeMcpConfiguration(
2542
2552
  servers,
2543
2553
  dir
2544
2554
  ),
2545
2555
  copilot: async (servers, dir) => (await import("./copilot-MOR3HHJX.js")).generateCopilotMcpConfiguration(servers, dir),
2546
- cursor: async (servers, dir) => (await import("./cursor-EXX2Q5MB.js")).generateCursorMcpConfiguration(servers, dir),
2547
- cline: async (servers, dir) => (await import("./cline-O67TEUFW.js")).generateClineMcpConfiguration(servers, dir),
2548
- codexcli: async (servers, dir) => (await import("./codexcli-S7VDKBI2.js")).generateCodexMcpConfiguration(servers, dir),
2556
+ cursor: async (servers, dir) => (await import("./cursor-WWHUW5AD.js")).generateCursorMcpConfiguration(servers, dir),
2557
+ cline: async (servers, dir) => (await import("./cline-FNWPJ7K4.js")).generateClineMcpConfiguration(servers, dir),
2558
+ codexcli: async (servers, dir) => (await import("./codexcli-FDFHY66P.js")).generateCodexMcpConfiguration(servers, dir),
2549
2559
  roo: async (servers, dir) => (await import("./roo-L3QTTIPO.js")).generateRooMcpConfiguration(servers, dir),
2550
- geminicli: async (servers, dir) => (await import("./geminicli-K3FKXDKP.js")).generateGeminiCliMcpConfiguration(
2560
+ geminicli: async (servers, dir) => (await import("./geminicli-7TIDQ62D.js")).generateGeminiCliMcpConfiguration(
2551
2561
  servers,
2552
2562
  dir
2553
2563
  ),
2554
2564
  kiro: async (servers, dir) => (await import("./kiro-YDHXY2MA.js")).generateKiroMcpConfiguration(servers, dir),
2555
- junie: async (servers, dir) => (await import("./junie-4SNWC452.js")).generateJunieMcpConfiguration(servers, dir),
2556
- windsurf: async (servers, dir) => (await import("./windsurf-NVCRKFHF.js")).generateWindsurfMcpConfiguration(
2565
+ junie: async (servers, dir) => (await import("./junie-VMNDWBNB.js")).generateJunieMcpConfiguration(servers, dir),
2566
+ windsurf: async (servers, dir) => (await import("./windsurf-KOSK4MZJ.js")).generateWindsurfMcpConfiguration(
2557
2567
  servers,
2558
2568
  dir
2559
2569
  )
@@ -2648,12 +2658,12 @@ async function generateCommand(options = {}) {
2648
2658
  for (const tool of targetTools) {
2649
2659
  switch (tool) {
2650
2660
  case "augmentcode":
2651
- deleteTasks.push(removeDirectory(join14(".augment", "rules")));
2652
- deleteTasks.push(removeDirectory(join14(".augment", "ignore")));
2661
+ deleteTasks.push(removeDirectory(join15(".augment", "rules")));
2662
+ deleteTasks.push(removeDirectory(join15(".augment", "ignore")));
2653
2663
  break;
2654
2664
  case "augmentcode-legacy":
2655
2665
  deleteTasks.push(removeClaudeGeneratedFiles());
2656
- deleteTasks.push(removeDirectory(join14(".augment", "ignore")));
2666
+ deleteTasks.push(removeDirectory(join15(".augment", "ignore")));
2657
2667
  break;
2658
2668
  case "copilot":
2659
2669
  deleteTasks.push(removeDirectory(config.outputPaths.copilot));
@@ -2666,14 +2676,15 @@ async function generateCommand(options = {}) {
2666
2676
  break;
2667
2677
  case "claudecode":
2668
2678
  deleteTasks.push(removeClaudeGeneratedFiles());
2669
- deleteTasks.push(removeDirectory(join14(".claude", "commands")));
2679
+ deleteTasks.push(removeDirectory(join15(".claude", "commands")));
2670
2680
  break;
2671
2681
  case "roo":
2672
2682
  deleteTasks.push(removeDirectory(config.outputPaths.roo));
2683
+ deleteTasks.push(removeDirectory(join15(".roo", "commands")));
2673
2684
  break;
2674
2685
  case "geminicli":
2675
2686
  deleteTasks.push(removeDirectory(config.outputPaths.geminicli));
2676
- deleteTasks.push(removeDirectory(join14(".gemini", "commands")));
2687
+ deleteTasks.push(removeDirectory(join15(".gemini", "commands")));
2677
2688
  break;
2678
2689
  case "kiro":
2679
2690
  deleteTasks.push(removeDirectory(config.outputPaths.kiro));
@@ -2789,9 +2800,9 @@ Generating configurations for base directory: ${baseDir}`);
2789
2800
 
2790
2801
  // src/cli/commands/gitignore.ts
2791
2802
  import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
2792
- import { join as join15 } from "path";
2803
+ import { join as join16 } from "path";
2793
2804
  var gitignoreCommand = async () => {
2794
- const gitignorePath = join15(process.cwd(), ".gitignore");
2805
+ const gitignorePath = join16(process.cwd(), ".gitignore");
2795
2806
  const rulesFilesToIgnore = [
2796
2807
  "# Generated by rulesync - AI tool configuration files",
2797
2808
  "**/.github/copilot-instructions.md",
@@ -2857,11 +2868,11 @@ ${linesToAdd.join("\n")}
2857
2868
  };
2858
2869
 
2859
2870
  // src/core/importer.ts
2860
- import { join as join22 } from "path";
2871
+ import { join as join23 } from "path";
2861
2872
  import matter7 from "gray-matter";
2862
2873
 
2863
2874
  // src/parsers/augmentcode.ts
2864
- import { basename as basename3, join as join16 } from "path";
2875
+ import { basename as basename3, join as join17 } from "path";
2865
2876
  import matter3 from "gray-matter";
2866
2877
 
2867
2878
  // src/utils/parser-helpers.ts
@@ -2910,7 +2921,7 @@ async function parseAugmentcodeLegacyConfiguration(baseDir = process.cwd()) {
2910
2921
  async function parseUnifiedAugmentcode(baseDir, config) {
2911
2922
  const result = createParseResult();
2912
2923
  if (config.rulesDir) {
2913
- const rulesDir = join16(baseDir, config.rulesDir);
2924
+ const rulesDir = join17(baseDir, config.rulesDir);
2914
2925
  if (await fileExists(rulesDir)) {
2915
2926
  const rulesResult = await parseAugmentRules(rulesDir, config);
2916
2927
  addRules(result, rulesResult.rules);
@@ -2923,7 +2934,7 @@ async function parseUnifiedAugmentcode(baseDir, config) {
2923
2934
  }
2924
2935
  }
2925
2936
  if (config.legacyFilePath) {
2926
- const legacyPath = join16(baseDir, config.legacyFilePath);
2937
+ const legacyPath = join17(baseDir, config.legacyFilePath);
2927
2938
  if (await fileExists(legacyPath)) {
2928
2939
  const legacyResult = await parseAugmentGuidelines(legacyPath, config);
2929
2940
  if (legacyResult.rule) {
@@ -2947,7 +2958,7 @@ async function parseAugmentRules(rulesDir, config) {
2947
2958
  const files = await readdir2(rulesDir);
2948
2959
  for (const file of files) {
2949
2960
  if (file.endsWith(".md") || file.endsWith(".mdc")) {
2950
- const filePath = join16(rulesDir, file);
2961
+ const filePath = join17(rulesDir, file);
2951
2962
  try {
2952
2963
  const rawContent = await readFileContent(filePath);
2953
2964
  const parsed = matter3(rawContent);
@@ -3014,7 +3025,7 @@ async function parseAugmentGuidelines(guidelinesPath, config) {
3014
3025
  }
3015
3026
 
3016
3027
  // src/parsers/shared-helpers.ts
3017
- import { basename as basename4, join as join17 } from "path";
3028
+ import { basename as basename4, join as join18 } from "path";
3018
3029
  import matter4 from "gray-matter";
3019
3030
  async function parseConfigurationFiles(baseDir = process.cwd(), config) {
3020
3031
  const errors = [];
@@ -3070,7 +3081,7 @@ async function parseConfigurationFiles(baseDir = process.cwd(), config) {
3070
3081
  const files = await readdir2(dirPath);
3071
3082
  for (const file of files) {
3072
3083
  if (file.endsWith(dirConfig.filePattern)) {
3073
- const filePath = join17(dirPath, file);
3084
+ const filePath = join18(dirPath, file);
3074
3085
  const fileResult = await safeAsyncOperation(async () => {
3075
3086
  const rawContent = await readFileContent(filePath);
3076
3087
  let content;
@@ -3215,7 +3226,7 @@ async function parseMemoryFiles(memoryDir, config) {
3215
3226
  const files = await readdir2(memoryDir);
3216
3227
  for (const file of files) {
3217
3228
  if (file.endsWith(".md")) {
3218
- const filePath = join17(memoryDir, file);
3229
+ const filePath = join18(memoryDir, file);
3219
3230
  const content = await readFileContent(filePath);
3220
3231
  if (content.trim()) {
3221
3232
  const filename = basename4(file, ".md");
@@ -3245,7 +3256,7 @@ async function parseCommandsFiles(commandsDir, config) {
3245
3256
  const files = await readdir2(commandsDir);
3246
3257
  for (const file of files) {
3247
3258
  if (file.endsWith(".md")) {
3248
- const filePath = join17(commandsDir, file);
3259
+ const filePath = join18(commandsDir, file);
3249
3260
  const content = await readFileContent(filePath);
3250
3261
  if (content.trim()) {
3251
3262
  const filename = basename4(file, ".md");
@@ -3359,7 +3370,7 @@ async function parseClineConfiguration(baseDir = process.cwd()) {
3359
3370
  }
3360
3371
 
3361
3372
  // src/parsers/codexcli.ts
3362
- import { join as join18 } from "path";
3373
+ import { join as join19 } from "path";
3363
3374
 
3364
3375
  // src/parsers/copilot.ts
3365
3376
  async function parseCopilotConfiguration(baseDir = process.cwd()) {
@@ -3382,7 +3393,7 @@ async function parseCopilotConfiguration(baseDir = process.cwd()) {
3382
3393
  }
3383
3394
 
3384
3395
  // src/parsers/cursor.ts
3385
- import { basename as basename5, join as join19 } from "path";
3396
+ import { basename as basename5, join as join20 } from "path";
3386
3397
  import matter5 from "gray-matter";
3387
3398
  import { DEFAULT_SCHEMA, FAILSAFE_SCHEMA, load } from "js-yaml";
3388
3399
  import { z as z7 } from "zod/mini";
@@ -3507,7 +3518,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
3507
3518
  const rules = [];
3508
3519
  let ignorePatterns;
3509
3520
  let mcpServers;
3510
- const cursorFilePath = join19(baseDir, ".cursorrules");
3521
+ const cursorFilePath = join20(baseDir, ".cursorrules");
3511
3522
  if (await fileExists(cursorFilePath)) {
3512
3523
  try {
3513
3524
  const rawContent = await readFileContent(cursorFilePath);
@@ -3528,14 +3539,14 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
3528
3539
  errors.push(`Failed to parse .cursorrules file: ${errorMessage}`);
3529
3540
  }
3530
3541
  }
3531
- const cursorRulesDir = join19(baseDir, ".cursor", "rules");
3542
+ const cursorRulesDir = join20(baseDir, ".cursor", "rules");
3532
3543
  if (await fileExists(cursorRulesDir)) {
3533
3544
  try {
3534
3545
  const { readdir: readdir2 } = await import("fs/promises");
3535
3546
  const files = await readdir2(cursorRulesDir);
3536
3547
  for (const file of files) {
3537
3548
  if (file.endsWith(".mdc")) {
3538
- const filePath = join19(cursorRulesDir, file);
3549
+ const filePath = join20(cursorRulesDir, file);
3539
3550
  try {
3540
3551
  const rawContent = await readFileContent(filePath);
3541
3552
  const parsed = matter5(rawContent, customMatterOptions);
@@ -3564,7 +3575,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
3564
3575
  if (rules.length === 0) {
3565
3576
  errors.push("No Cursor configuration files found (.cursorrules or .cursor/rules/*.mdc)");
3566
3577
  }
3567
- const cursorIgnorePath = join19(baseDir, ".cursorignore");
3578
+ const cursorIgnorePath = join20(baseDir, ".cursorignore");
3568
3579
  if (await fileExists(cursorIgnorePath)) {
3569
3580
  try {
3570
3581
  const content = await readFileContent(cursorIgnorePath);
@@ -3577,7 +3588,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
3577
3588
  errors.push(`Failed to parse .cursorignore: ${errorMessage}`);
3578
3589
  }
3579
3590
  }
3580
- const cursorMcpPath = join19(baseDir, ".cursor", "mcp.json");
3591
+ const cursorMcpPath = join20(baseDir, ".cursor", "mcp.json");
3581
3592
  if (await fileExists(cursorMcpPath)) {
3582
3593
  try {
3583
3594
  const content = await readFileContent(cursorMcpPath);
@@ -3627,11 +3638,11 @@ async function parseGeminiConfiguration(baseDir = process.cwd()) {
3627
3638
  }
3628
3639
 
3629
3640
  // src/parsers/junie.ts
3630
- import { join as join20 } from "path";
3641
+ import { join as join21 } from "path";
3631
3642
  async function parseJunieConfiguration(baseDir = process.cwd()) {
3632
3643
  const errors = [];
3633
3644
  const rules = [];
3634
- const guidelinesPath = join20(baseDir, ".junie", "guidelines.md");
3645
+ const guidelinesPath = join21(baseDir, ".junie", "guidelines.md");
3635
3646
  if (!await fileExists(guidelinesPath)) {
3636
3647
  errors.push(".junie/guidelines.md file not found");
3637
3648
  return { rules, errors };
@@ -3684,7 +3695,7 @@ async function parseRooConfiguration(baseDir = process.cwd()) {
3684
3695
 
3685
3696
  // src/parsers/windsurf.ts
3686
3697
  import { readFile as readFile2 } from "fs/promises";
3687
- import { join as join21 } from "path";
3698
+ import { join as join22 } from "path";
3688
3699
  import matter6 from "gray-matter";
3689
3700
 
3690
3701
  // src/core/importer.ts
@@ -3771,7 +3782,7 @@ async function importConfiguration(options) {
3771
3782
  if (rules.length === 0 && !ignorePatterns && !mcpServers) {
3772
3783
  return { success: false, rulesCreated: 0, errors };
3773
3784
  }
3774
- const rulesDirPath = join22(baseDir, rulesDir);
3785
+ const rulesDirPath = join23(baseDir, rulesDir);
3775
3786
  try {
3776
3787
  const { mkdir: mkdir3 } = await import("fs/promises");
3777
3788
  await mkdir3(rulesDirPath, { recursive: true });
@@ -3786,11 +3797,11 @@ async function importConfiguration(options) {
3786
3797
  const baseFilename = rule.filename;
3787
3798
  let targetDir = rulesDirPath;
3788
3799
  if (rule.type === "command") {
3789
- targetDir = join22(rulesDirPath, "commands");
3800
+ targetDir = join23(rulesDirPath, "commands");
3790
3801
  const { mkdir: mkdir3 } = await import("fs/promises");
3791
3802
  await mkdir3(targetDir, { recursive: true });
3792
3803
  }
3793
- const filePath = join22(targetDir, `${baseFilename}.md`);
3804
+ const filePath = join23(targetDir, `${baseFilename}.md`);
3794
3805
  const content = generateRuleFileContent(rule);
3795
3806
  await writeFileContent(filePath, content);
3796
3807
  rulesCreated++;
@@ -3805,7 +3816,7 @@ async function importConfiguration(options) {
3805
3816
  let ignoreFileCreated = false;
3806
3817
  if (ignorePatterns && ignorePatterns.length > 0) {
3807
3818
  try {
3808
- const rulesyncignorePath = join22(baseDir, ".rulesyncignore");
3819
+ const rulesyncignorePath = join23(baseDir, ".rulesyncignore");
3809
3820
  const ignoreContent = `${ignorePatterns.join("\n")}
3810
3821
  `;
3811
3822
  await writeFileContent(rulesyncignorePath, ignoreContent);
@@ -3821,7 +3832,7 @@ async function importConfiguration(options) {
3821
3832
  let mcpFileCreated = false;
3822
3833
  if (mcpServers && Object.keys(mcpServers).length > 0) {
3823
3834
  try {
3824
- const mcpPath = join22(baseDir, rulesDir, ".mcp.json");
3835
+ const mcpPath = join23(baseDir, rulesDir, ".mcp.json");
3825
3836
  const mcpContent = `${JSON.stringify({ mcpServers }, null, 2)}
3826
3837
  `;
3827
3838
  await writeFileContent(mcpPath, mcpContent);
@@ -3915,7 +3926,7 @@ async function importCommand(options = {}) {
3915
3926
  }
3916
3927
 
3917
3928
  // src/cli/commands/init.ts
3918
- import { join as join23 } from "path";
3929
+ import { join as join24 } from "path";
3919
3930
  async function initCommand() {
3920
3931
  const aiRulesDir = ".rulesync";
3921
3932
  console.log("Initializing rulesync...");
@@ -3962,7 +3973,7 @@ globs: ["**/*"]
3962
3973
  - Follow single responsibility principle
3963
3974
  `
3964
3975
  };
3965
- const filepath = join23(aiRulesDir, sampleFile.filename);
3976
+ const filepath = join24(aiRulesDir, sampleFile.filename);
3966
3977
  if (!await fileExists(filepath)) {
3967
3978
  await writeFileContent(filepath, sampleFile.content);
3968
3979
  console.log(`Created ${filepath}`);
@@ -4106,12 +4117,12 @@ async function watchCommand() {
4106
4117
 
4107
4118
  // src/cli/index.ts
4108
4119
  var program = new Command();
4109
- program.name("rulesync").description("Unified AI rules management CLI tool").version("0.59.0");
4120
+ program.name("rulesync").description("Unified AI rules management CLI tool").version("0.61.0");
4110
4121
  program.command("init").description("Initialize rulesync in current directory").action(initCommand);
4111
4122
  program.command("add <filename>").description("Add a new rule file").action(addCommand);
4112
4123
  program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);
4113
4124
  program.command("import").description("Import configurations from AI tools to rulesync format").option("--augmentcode", "Import from AugmentCode (.augment/rules/)").option("--augmentcode-legacy", "Import from AugmentCode legacy format (.augment-guidelines)").option("--claudecode", "Import from Claude Code (CLAUDE.md)").option("--cursor", "Import from Cursor (.cursorrules)").option("--copilot", "Import from GitHub Copilot (.github/copilot-instructions.md)").option("--cline", "Import from Cline (.cline/instructions.md)").option("--roo", "Import from Roo Code (.roo/instructions.md)").option("--geminicli", "Import from Gemini CLI (GEMINI.md)").option("--junie", "Import from JetBrains Junie (.junie/guidelines.md)").option("-v, --verbose", "Verbose output").action(importCommand);
4114
- program.command("generate").description("Generate configuration files for AI tools").option("--augmentcode", "Generate only for AugmentCode").option("--augmentcode-legacy", "Generate only for AugmentCode legacy format").option("--copilot", "Generate only for GitHub Copilot").option("--cursor", "Generate only for Cursor").option("--cline", "Generate only for Cline").option("--codexcli", "Generate only for OpenAI Codex CLI").option("--claudecode", "Generate only for Claude Code").option("--roo", "Generate only for Roo Code").option("--geminicli", "Generate only for Gemini CLI").option("--junie", "Generate only for JetBrains Junie").option("--kiro", "Generate only for Kiro IDE").option("--delete", "Delete all existing files in output directories before generating").option(
4125
+ program.command("generate").description("Generate configuration files for AI tools").option("--augmentcode", "Generate only for AugmentCode").option("--augmentcode-legacy", "Generate only for AugmentCode legacy format").option("--copilot", "Generate only for GitHub Copilot").option("--cursor", "Generate only for Cursor").option("--cline", "Generate only for Cline").option("--codexcli", "Generate only for OpenAI Codex CLI").option("--claudecode", "Generate only for Claude Code").option("--roo", "Generate only for Roo Code").option("--geminicli", "Generate only for Gemini CLI").option("--junie", "Generate only for JetBrains Junie").option("--kiro", "Generate only for Kiro IDE").option("--windsurf", "Generate only for Windsurf").option("--delete", "Delete all existing files in output directories before generating").option(
4115
4126
  "-b, --base-dir <paths>",
4116
4127
  "Base directories to generate files (comma-separated for multiple paths)"
4117
4128
  ).option("-v, --verbose", "Verbose output").option("-c, --config <path>", "Path to configuration file").option("--no-config", "Disable configuration file loading").action(async (options) => {
@@ -4127,6 +4138,7 @@ program.command("generate").description("Generate configuration files for AI too
4127
4138
  if (options.geminicli) tools.push("geminicli");
4128
4139
  if (options.junie) tools.push("junie");
4129
4140
  if (options.kiro) tools.push("kiro");
4141
+ if (options.windsurf) tools.push("windsurf");
4130
4142
  const generateOptions = {
4131
4143
  verbose: options.verbose,
4132
4144
  delete: options.delete,