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.cjs CHANGED
@@ -230,6 +230,16 @@ function generateMcpFromRegistry(tool, config) {
230
230
  }
231
231
  return generateMcpConfig(config, generatorConfig);
232
232
  }
233
+ function createMcpGenerator(toolName) {
234
+ return {
235
+ generateMcp: (config) => {
236
+ return generateMcpFromRegistry(toolName, config);
237
+ },
238
+ generateMcpConfiguration: (mcpServers, baseDir = "") => {
239
+ return generateMcpConfigurationFilesFromRegistry(toolName, mcpServers, baseDir);
240
+ }
241
+ };
242
+ }
233
243
  function generateMcpConfigurationFilesFromRegistry(tool, mcpServers, baseDir = "") {
234
244
  const generatorConfig = MCP_GENERATOR_REGISTRY[tool];
235
245
  if (!generatorConfig) {
@@ -282,7 +292,7 @@ function generateJunieMcpConfigurationFiles(mcpServers, baseDir = "") {
282
292
  }
283
293
  ];
284
294
  }
285
- var serverTransforms, configWrappers, MCP_GENERATOR_REGISTRY;
295
+ var serverTransforms, configWrappers, MCP_GENERATOR_REGISTRY, cursorMcpGenerator, clineMcpGenerator;
286
296
  var init_shared_factory = __esm({
287
297
  "src/generators/mcp/shared-factory.ts"() {
288
298
  "use strict";
@@ -437,7 +447,7 @@ var init_shared_factory = __esm({
437
447
  },
438
448
  junie: {
439
449
  target: "junie",
440
- configPaths: [".junie/mcp-config.json"],
450
+ configPaths: [".junie/mcp/mcp.json"],
441
451
  serverTransform: (server, serverName) => {
442
452
  const junieServer = {
443
453
  name: serverName
@@ -484,6 +494,8 @@ var init_shared_factory = __esm({
484
494
  configWrapper: configWrappers.mcpServers
485
495
  }
486
496
  };
497
+ cursorMcpGenerator = createMcpGenerator("cursor");
498
+ clineMcpGenerator = createMcpGenerator("cline");
487
499
  }
488
500
  });
489
501
 
@@ -512,16 +524,13 @@ __export(cline_exports, {
512
524
  generateClineMcp: () => generateClineMcp,
513
525
  generateClineMcpConfiguration: () => generateClineMcpConfiguration
514
526
  });
515
- function generateClineMcp(config) {
516
- return generateMcpFromRegistry("cline", config);
517
- }
518
- function generateClineMcpConfiguration(mcpServers, baseDir = "") {
519
- return generateMcpConfigurationFilesFromRegistry("cline", mcpServers, baseDir);
520
- }
527
+ var generateClineMcp, generateClineMcpConfiguration;
521
528
  var init_cline = __esm({
522
529
  "src/generators/mcp/cline.ts"() {
523
530
  "use strict";
524
531
  init_shared_factory();
532
+ generateClineMcp = clineMcpGenerator.generateMcp;
533
+ generateClineMcpConfiguration = clineMcpGenerator.generateMcpConfiguration;
525
534
  }
526
535
  });
527
536
 
@@ -759,16 +768,13 @@ __export(cursor_exports, {
759
768
  generateCursorMcp: () => generateCursorMcp,
760
769
  generateCursorMcpConfiguration: () => generateCursorMcpConfiguration
761
770
  });
762
- function generateCursorMcp(config) {
763
- return generateMcpFromRegistry("cursor", config);
764
- }
765
- function generateCursorMcpConfiguration(mcpServers, baseDir = "") {
766
- return generateMcpConfigurationFilesFromRegistry("cursor", mcpServers, baseDir);
767
- }
771
+ var generateCursorMcp, generateCursorMcpConfiguration;
768
772
  var init_cursor = __esm({
769
773
  "src/generators/mcp/cursor.ts"() {
770
774
  "use strict";
771
775
  init_shared_factory();
776
+ generateCursorMcp = cursorMcpGenerator.generateMcp;
777
+ generateCursorMcpConfiguration = cursorMcpGenerator.generateMcpConfiguration;
772
778
  }
773
779
  });
774
780
 
@@ -1250,13 +1256,6 @@ var RuleFrontmatterSchema = import_mini7.z.object({
1250
1256
  windsurfOutputFormat: import_mini7.z.optional(import_mini7.z.enum(["single-file", "directory"])),
1251
1257
  tags: import_mini7.z.optional(import_mini7.z.array(import_mini7.z.string()))
1252
1258
  });
1253
- var ParsedRuleSchema = import_mini7.z.object({
1254
- frontmatter: RuleFrontmatterSchema,
1255
- content: import_mini7.z.string(),
1256
- filename: import_mini7.z.string(),
1257
- filepath: import_mini7.z.string(),
1258
- type: import_mini7.z.optional(import_mini7.z.enum(["rule", "command"]))
1259
- });
1260
1259
  var GeneratedOutputSchema = import_mini7.z.object({
1261
1260
  tool: ToolTargetSchema,
1262
1261
  filepath: import_mini7.z.string(),
@@ -1771,10 +1770,10 @@ export default config;
1771
1770
  }
1772
1771
 
1773
1772
  // src/cli/commands/generate.ts
1774
- var import_node_path14 = require("path");
1773
+ var import_node_path15 = require("path");
1775
1774
 
1776
1775
  // src/core/command-generator.ts
1777
- var import_node_path6 = require("path");
1776
+ var import_node_path7 = require("path");
1778
1777
 
1779
1778
  // src/generators/commands/claudecode.ts
1780
1779
  var import_node_path3 = require("path");
@@ -1843,17 +1842,44 @@ var GeminiCliCommandGenerator = class {
1843
1842
  }
1844
1843
  };
1845
1844
 
1845
+ // src/generators/commands/roo.ts
1846
+ var import_node_path5 = require("path");
1847
+ var RooCommandGenerator = class {
1848
+ generate(command, outputDir) {
1849
+ const filepath = this.getOutputPath(command.filename, outputDir);
1850
+ const frontmatter = ["---"];
1851
+ if (command.frontmatter.description) {
1852
+ frontmatter.push(`description: ${command.frontmatter.description}`);
1853
+ }
1854
+ frontmatter.push("---");
1855
+ const content = `${frontmatter.join("\n")}
1856
+
1857
+ ${command.content.trim()}
1858
+ `;
1859
+ return {
1860
+ tool: "roo",
1861
+ filepath,
1862
+ content
1863
+ };
1864
+ }
1865
+ getOutputPath(filename, baseDir) {
1866
+ const flattenedName = filename.replace(/\//g, "-");
1867
+ return (0, import_node_path5.join)(baseDir, ".roo", "commands", `${flattenedName}.md`);
1868
+ }
1869
+ };
1870
+
1846
1871
  // src/generators/commands/index.ts
1847
1872
  var commandGenerators = {
1848
1873
  claudecode: new ClaudeCodeCommandGenerator(),
1849
- geminicli: new GeminiCliCommandGenerator()
1874
+ geminicli: new GeminiCliCommandGenerator(),
1875
+ roo: new RooCommandGenerator()
1850
1876
  };
1851
1877
  function getCommandGenerator(tool) {
1852
1878
  return commandGenerators[tool];
1853
1879
  }
1854
1880
 
1855
1881
  // src/core/command-parser.ts
1856
- var import_node_path5 = require("path");
1882
+ var import_node_path6 = require("path");
1857
1883
  var import_gray_matter = __toESM(require("gray-matter"), 1);
1858
1884
  async function parseCommandsFromDirectory(commandsDir) {
1859
1885
  const commandFiles = await findFiles(commandsDir, ".md");
@@ -1879,7 +1905,7 @@ async function parseCommandFile(filepath) {
1879
1905
  const parsed = (0, import_gray_matter.default)(content);
1880
1906
  try {
1881
1907
  const validatedData = CommandFrontmatterSchema.parse(parsed.data);
1882
- const filename = (0, import_node_path5.basename)(filepath, ".md");
1908
+ const filename = (0, import_node_path6.basename)(filepath, ".md");
1883
1909
  return {
1884
1910
  frontmatter: {
1885
1911
  description: validatedData.description
@@ -1897,7 +1923,7 @@ async function parseCommandFile(filepath) {
1897
1923
 
1898
1924
  // src/core/command-generator.ts
1899
1925
  async function generateCommands(projectRoot, baseDir, targets) {
1900
- const commandsDir = (0, import_node_path6.join)(projectRoot, ".rulesync", "commands");
1926
+ const commandsDir = (0, import_node_path7.join)(projectRoot, ".rulesync", "commands");
1901
1927
  if (!await fileExists(commandsDir)) {
1902
1928
  return [];
1903
1929
  }
@@ -1907,7 +1933,9 @@ async function generateCommands(projectRoot, baseDir, targets) {
1907
1933
  }
1908
1934
  const outputs = [];
1909
1935
  const outputDir = baseDir || projectRoot;
1910
- const supportedTargets = targets.filter((target) => ["claudecode", "geminicli"].includes(target));
1936
+ const supportedTargets = targets.filter(
1937
+ (target) => ["claudecode", "geminicli", "roo"].includes(target)
1938
+ );
1911
1939
  for (const target of supportedTargets) {
1912
1940
  const generator = getCommandGenerator(target);
1913
1941
  if (!generator) {
@@ -1929,58 +1957,81 @@ async function generateCommands(projectRoot, baseDir, targets) {
1929
1957
  }
1930
1958
 
1931
1959
  // src/generators/ignore/shared-factory.ts
1932
- var import_node_path7 = require("path");
1960
+ var import_node_path8 = require("path");
1933
1961
 
1934
1962
  // src/generators/ignore/shared-helpers.ts
1935
1963
  function extractIgnorePatternsFromRules(rules) {
1936
1964
  const patterns = [];
1937
1965
  for (const rule of rules) {
1938
1966
  if (rule.frontmatter.globs && rule.frontmatter.globs.length > 0) {
1939
- for (const glob of rule.frontmatter.globs) {
1940
- if (shouldExcludeFromAI(glob)) {
1941
- patterns.push(`# Exclude: ${rule.frontmatter.description}`);
1942
- patterns.push(glob);
1943
- }
1967
+ const sensitiveGlobs = rule.frontmatter.globs.filter(shouldExcludeFromAI);
1968
+ if (sensitiveGlobs.length > 0) {
1969
+ patterns.push(`# Exclude: ${rule.frontmatter.description}`);
1970
+ patterns.push(...sensitiveGlobs);
1944
1971
  }
1945
1972
  }
1946
- const contentPatterns = extractIgnorePatternsFromContent(rule.content);
1973
+ const contentPatterns = extractBasicIgnorePatternsFromContent(rule.content);
1947
1974
  patterns.push(...contentPatterns);
1948
1975
  }
1949
1976
  return patterns;
1950
1977
  }
1951
1978
  function shouldExcludeFromAI(glob) {
1952
- const excludePatterns = [
1953
- // Large generated files that slow indexing
1954
- "**/assets/generated/**",
1955
- "**/public/build/**",
1956
- // Test fixtures with potentially sensitive data
1957
- "**/tests/fixtures/**",
1958
- "**/test/fixtures/**",
1959
- "**/*.fixture.*",
1960
- // Build outputs that provide little value for AI context
1979
+ const sensitivePatterns = [
1980
+ // Security-related patterns
1981
+ "**/secret**",
1982
+ "**/credential**",
1983
+ "**/token**",
1984
+ "**/key**",
1985
+ "**/password**",
1986
+ "**/auth**",
1987
+ "**/private**",
1988
+ "**/confidential**",
1989
+ "**/internal**",
1990
+ "**/internal-docs/**",
1991
+ "**/admin**",
1992
+ // Configuration patterns that might contain secrets
1993
+ "**/config/prod**",
1994
+ "**/config/production**",
1995
+ "**/config/secret**",
1996
+ "**/config/secrets/**",
1997
+ "**/env/**",
1998
+ "**/.env**",
1999
+ // Build and deployment patterns
1961
2000
  "**/dist/**",
1962
2001
  "**/build/**",
1963
- "**/coverage/**",
1964
- // Configuration that might contain sensitive data
1965
- "**/config/production/**",
1966
- "**/config/secrets/**",
1967
- "**/config/prod/**",
1968
- "**/deploy/prod/**",
1969
- "**/*.prod.*",
1970
- // Internal documentation that might be sensitive
1971
- "**/internal/**",
1972
- "**/internal-docs/**",
1973
- "**/proprietary/**",
1974
- "**/personal-notes/**",
1975
- "**/private/**",
1976
- "**/confidential/**"
2002
+ "**/target/**",
2003
+ "**/out/**",
2004
+ "**/node_modules/**",
2005
+ // Data and media patterns
2006
+ "**/data/**",
2007
+ "**/dataset**",
2008
+ "**/backup**",
2009
+ "**/logs/**",
2010
+ "**/log/**",
2011
+ "**/temp/**",
2012
+ "**/tmp/**",
2013
+ "**/cache/**",
2014
+ // Test fixtures that might contain sensitive data
2015
+ "**/test/fixtures/**",
2016
+ "**/test**/fixture**",
2017
+ "**/test**/mock**",
2018
+ "**/test**/data/**",
2019
+ // Database and infrastructure
2020
+ "**/*.sqlite",
2021
+ "**/*.db",
2022
+ "**/*.dump",
2023
+ // Production files
2024
+ "**/*.prod.json",
2025
+ "**/*.production.*"
1977
2026
  ];
1978
- return excludePatterns.some((pattern) => {
1979
- const regex = new RegExp(pattern.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*"));
1980
- return regex.test(glob);
2027
+ const lowerGlob = glob.toLowerCase();
2028
+ return sensitivePatterns.some((pattern) => {
2029
+ const regexPattern = pattern.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*").replace(/\?/g, ".");
2030
+ const regex = new RegExp(`^${regexPattern}$`, "i");
2031
+ return regex.test(lowerGlob);
1981
2032
  });
1982
2033
  }
1983
- function extractIgnorePatternsFromContent(content) {
2034
+ function extractBasicIgnorePatternsFromContent(content) {
1984
2035
  const patterns = [];
1985
2036
  const lines = content.split("\n");
1986
2037
  for (const line of lines) {
@@ -1991,24 +2042,6 @@ function extractIgnorePatternsFromContent(content) {
1991
2042
  patterns.push(pattern);
1992
2043
  }
1993
2044
  }
1994
- if (trimmed.startsWith("# AUGMENT_IGNORE:") || trimmed.startsWith("# augmentignore:")) {
1995
- const pattern = trimmed.replace(/^# (AUGMENT_IGNORE|augmentignore):\s*/, "").trim();
1996
- if (pattern) {
1997
- patterns.push(pattern);
1998
- }
1999
- }
2000
- if (trimmed.startsWith("# AUGMENT_INCLUDE:") || trimmed.startsWith("# augmentinclude:")) {
2001
- const pattern = trimmed.replace(/^# (AUGMENT_INCLUDE|augmentinclude):\s*/, "").trim();
2002
- if (pattern) {
2003
- patterns.push(`!${pattern}`);
2004
- }
2005
- }
2006
- if (trimmed.includes("exclude") || trimmed.includes("ignore")) {
2007
- const matches = trimmed.match(/['"`]([^'"`]+\.(log|tmp|cache|temp))['"`]/g);
2008
- if (matches) {
2009
- patterns.push(...matches.map((m) => m.replace(/['"`]/g, "")));
2010
- }
2011
- }
2012
2045
  }
2013
2046
  return patterns;
2014
2047
  }
@@ -2047,7 +2080,7 @@ function generateIgnoreFile(rules, config, ignoreConfig, baseDir) {
2047
2080
  const outputs = [];
2048
2081
  const content = generateIgnoreContent(rules, ignoreConfig);
2049
2082
  const outputPath = baseDir || process.cwd();
2050
- const filepath = (0, import_node_path7.join)(outputPath, ignoreConfig.filename);
2083
+ const filepath = (0, import_node_path8.join)(outputPath, ignoreConfig.filename);
2051
2084
  outputs.push({
2052
2085
  tool: ignoreConfig.tool,
2053
2086
  filepath,
@@ -2635,20 +2668,20 @@ function generateWindsurfIgnore(rules, config, baseDir) {
2635
2668
  }
2636
2669
 
2637
2670
  // src/generators/rules/augmentcode.ts
2638
- var import_node_path10 = require("path");
2671
+ var import_node_path11 = require("path");
2639
2672
 
2640
2673
  // src/generators/rules/shared-helpers.ts
2641
- var import_node_path9 = require("path");
2674
+ var import_node_path10 = require("path");
2642
2675
 
2643
2676
  // src/utils/ignore.ts
2644
- var import_node_path8 = require("path");
2677
+ var import_node_path9 = require("path");
2645
2678
  var import_micromatch = __toESM(require("micromatch"), 1);
2646
2679
  var cachedIgnorePatterns = null;
2647
2680
  async function loadIgnorePatterns(baseDir = process.cwd()) {
2648
2681
  if (cachedIgnorePatterns) {
2649
2682
  return cachedIgnorePatterns;
2650
2683
  }
2651
- const ignorePath = (0, import_node_path8.join)(baseDir, ".rulesyncignore");
2684
+ const ignorePath = (0, import_node_path9.join)(baseDir, ".rulesyncignore");
2652
2685
  if (!await fileExists(ignorePath)) {
2653
2686
  cachedIgnorePatterns = { patterns: [] };
2654
2687
  return cachedIgnorePatterns;
@@ -2702,7 +2735,7 @@ function addOutput(outputs, tool, config, baseDir, relativePath, content) {
2702
2735
  const outputDir = resolveOutputDir(config, tool, baseDir);
2703
2736
  outputs.push({
2704
2737
  tool,
2705
- filepath: (0, import_node_path9.join)(outputDir, relativePath),
2738
+ filepath: (0, import_node_path10.join)(outputDir, relativePath),
2706
2739
  content
2707
2740
  });
2708
2741
  }
@@ -2711,7 +2744,7 @@ async function generateRulesConfig(rules, config, generatorConfig, baseDir) {
2711
2744
  for (const rule of rules) {
2712
2745
  const content = generatorConfig.generateContent(rule);
2713
2746
  const outputDir = resolveOutputDir(config, generatorConfig.tool, baseDir);
2714
- const filepath = generatorConfig.pathResolver ? generatorConfig.pathResolver(rule, outputDir) : (0, import_node_path9.join)(outputDir, `${rule.filename}${generatorConfig.fileExtension}`);
2747
+ const filepath = generatorConfig.pathResolver ? generatorConfig.pathResolver(rule, outputDir) : (0, import_node_path10.join)(outputDir, `${rule.filename}${generatorConfig.fileExtension}`);
2715
2748
  outputs.push({
2716
2749
  tool: generatorConfig.tool,
2717
2750
  filepath,
@@ -2739,7 +2772,7 @@ async function generateComplexRules(rules, config, generatorConfig, baseDir) {
2739
2772
  for (const rule of detailRules) {
2740
2773
  const content = generatorConfig.generateDetailContent(rule);
2741
2774
  const filepath = resolvePath(
2742
- (0, import_node_path9.join)(generatorConfig.detailSubDir, `${rule.filename}.md`),
2775
+ (0, import_node_path10.join)(generatorConfig.detailSubDir, `${rule.filename}.md`),
2743
2776
  baseDir
2744
2777
  );
2745
2778
  outputs.push({
@@ -2802,7 +2835,7 @@ async function generateAugmentcodeConfig(rules, config, baseDir) {
2802
2835
  "augmentcode",
2803
2836
  config,
2804
2837
  baseDir,
2805
- (0, import_node_path10.join)(".augment", "rules", `${rule.filename}.md`),
2838
+ (0, import_node_path11.join)(".augment", "rules", `${rule.filename}.md`),
2806
2839
  generateRuleFile(rule)
2807
2840
  );
2808
2841
  });
@@ -2855,7 +2888,7 @@ function generateLegacyGuidelinesFile(allRules) {
2855
2888
  }
2856
2889
 
2857
2890
  // src/generators/rules/claudecode.ts
2858
- var import_node_path11 = require("path");
2891
+ var import_node_path12 = require("path");
2859
2892
  async function generateClaudecodeConfig(rules, config, baseDir) {
2860
2893
  const generatorConfig = {
2861
2894
  tool: "claudecode",
@@ -2867,7 +2900,7 @@ async function generateClaudecodeConfig(rules, config, baseDir) {
2867
2900
  generateDetailContent: generateMemoryFile,
2868
2901
  detailSubDir: ".claude/memories",
2869
2902
  updateAdditionalConfig: async (ignorePatterns, baseDir2) => {
2870
- const settingsPath = resolvePath((0, import_node_path11.join)(".claude", "settings.json"), baseDir2);
2903
+ const settingsPath = resolvePath((0, import_node_path12.join)(".claude", "settings.json"), baseDir2);
2871
2904
  await updateClaudeSettings(settingsPath, ignorePatterns);
2872
2905
  return [];
2873
2906
  }
@@ -2931,7 +2964,7 @@ async function updateClaudeSettings(settingsPath, ignorePatterns) {
2931
2964
  }
2932
2965
 
2933
2966
  // src/generators/rules/generator-registry.ts
2934
- var import_node_path12 = require("path");
2967
+ var import_node_path13 = require("path");
2935
2968
  function determineCursorRuleType(frontmatter) {
2936
2969
  if (frontmatter.cursorRuleType) {
2937
2970
  return frontmatter.cursorRuleType;
@@ -3011,7 +3044,7 @@ var GENERATOR_REGISTRY = {
3011
3044
  },
3012
3045
  pathResolver: (rule, outputDir) => {
3013
3046
  const baseFilename = rule.filename.replace(/\.md$/, "");
3014
- return (0, import_node_path12.join)(outputDir, `${baseFilename}.instructions.md`);
3047
+ return (0, import_node_path13.join)(outputDir, `${baseFilename}.instructions.md`);
3015
3048
  }
3016
3049
  },
3017
3050
  cursor: {
@@ -3051,7 +3084,7 @@ var GENERATOR_REGISTRY = {
3051
3084
  return lines.join("\n");
3052
3085
  },
3053
3086
  pathResolver: (rule, outputDir) => {
3054
- return (0, import_node_path12.join)(outputDir, `${rule.filename}.mdc`);
3087
+ return (0, import_node_path13.join)(outputDir, `${rule.filename}.mdc`);
3055
3088
  }
3056
3089
  },
3057
3090
  codexcli: {
@@ -3087,10 +3120,10 @@ var GENERATOR_REGISTRY = {
3087
3120
  pathResolver: (rule, outputDir) => {
3088
3121
  const outputFormat = rule.frontmatter.windsurfOutputFormat || "directory";
3089
3122
  if (outputFormat === "single-file") {
3090
- return (0, import_node_path12.join)(outputDir, ".windsurf-rules");
3123
+ return (0, import_node_path13.join)(outputDir, ".windsurf-rules");
3091
3124
  } else {
3092
- const rulesDir = (0, import_node_path12.join)(outputDir, ".windsurf", "rules");
3093
- return (0, import_node_path12.join)(rulesDir, `${rule.filename}.md`);
3125
+ const rulesDir = (0, import_node_path13.join)(outputDir, ".windsurf", "rules");
3126
+ return (0, import_node_path13.join)(rulesDir, `${rule.filename}.md`);
3094
3127
  }
3095
3128
  }
3096
3129
  },
@@ -3181,10 +3214,18 @@ async function generateFromRegistry(tool, rules, config, baseDir) {
3181
3214
  }
3182
3215
  }
3183
3216
 
3184
- // src/generators/rules/cline.ts
3185
- async function generateClineConfig(rules, config, baseDir) {
3186
- return generateFromRegistry("cline", rules, config, baseDir);
3217
+ // src/generators/rules/generator-factory.ts
3218
+ function createSimpleGenerator(toolName) {
3219
+ return async function(rules, config, baseDir) {
3220
+ return generateFromRegistry(toolName, rules, config, baseDir);
3221
+ };
3187
3222
  }
3223
+ var generateCursorConfig = createSimpleGenerator("cursor");
3224
+ var generateClineConfig = createSimpleGenerator("cline");
3225
+ var generateCopilotConfig = createSimpleGenerator("copilot");
3226
+ var generateWindsurfConfig = createSimpleGenerator("windsurf");
3227
+ var generateKiroConfig = createSimpleGenerator("kiro");
3228
+ var generateRooConfig = createSimpleGenerator("roo");
3188
3229
 
3189
3230
  // src/generators/rules/codexcli.ts
3190
3231
  async function generateCodexConfig(rules, config, baseDir) {
@@ -3231,16 +3272,6 @@ function generateConcatenatedCodexContent(rules) {
3231
3272
  return sections.join("\n\n---\n\n");
3232
3273
  }
3233
3274
 
3234
- // src/generators/rules/copilot.ts
3235
- async function generateCopilotConfig(rules, config, baseDir) {
3236
- return generateFromRegistry("copilot", rules, config, baseDir);
3237
- }
3238
-
3239
- // src/generators/rules/cursor.ts
3240
- async function generateCursorConfig(rules, config, baseDir) {
3241
- return generateFromRegistry("cursor", rules, config, baseDir);
3242
- }
3243
-
3244
3275
  // src/generators/rules/geminicli.ts
3245
3276
  async function generateGeminiConfig(rules, config, baseDir) {
3246
3277
  const generatorConfig = {
@@ -3310,21 +3341,6 @@ function generateGuidelinesMarkdown(rootRule, detailRules) {
3310
3341
  return lines.join("\n").trim();
3311
3342
  }
3312
3343
 
3313
- // src/generators/rules/kiro.ts
3314
- async function generateKiroConfig(rules, config, baseDir) {
3315
- return generateFromRegistry("kiro", rules, config, baseDir);
3316
- }
3317
-
3318
- // src/generators/rules/roo.ts
3319
- async function generateRooConfig(rules, config, baseDir) {
3320
- return generateFromRegistry("roo", rules, config, baseDir);
3321
- }
3322
-
3323
- // src/generators/rules/windsurf.ts
3324
- async function generateWindsurfConfig(rules, config, baseDir) {
3325
- return generateFromRegistry("windsurf", rules, config, baseDir);
3326
- }
3327
-
3328
3344
  // src/core/generator.ts
3329
3345
  async function generateConfigurations(rules, config, targetTools, baseDir) {
3330
3346
  const outputs = createOutputsArray();
@@ -3409,7 +3425,7 @@ async function generateForTool(tool, rules, config, baseDir) {
3409
3425
  }
3410
3426
 
3411
3427
  // src/core/parser.ts
3412
- var import_node_path13 = require("path");
3428
+ var import_node_path14 = require("path");
3413
3429
  var import_gray_matter2 = __toESM(require("gray-matter"), 1);
3414
3430
  async function parseRulesFromDirectory(aiRulesDir) {
3415
3431
  const ignorePatterns = await loadIgnorePatterns();
@@ -3463,7 +3479,7 @@ async function parseRuleFile(filepath) {
3463
3479
  },
3464
3480
  ...validatedData.tags !== void 0 && { tags: validatedData.tags }
3465
3481
  };
3466
- const filename = (0, import_node_path13.basename)(filepath, ".md");
3482
+ const filename = (0, import_node_path14.basename)(filepath, ".md");
3467
3483
  return {
3468
3484
  frontmatter,
3469
3485
  content: parsed.content,
@@ -3692,12 +3708,12 @@ async function generateCommand(options = {}) {
3692
3708
  for (const tool of targetTools) {
3693
3709
  switch (tool) {
3694
3710
  case "augmentcode":
3695
- deleteTasks.push(removeDirectory((0, import_node_path14.join)(".augment", "rules")));
3696
- deleteTasks.push(removeDirectory((0, import_node_path14.join)(".augment", "ignore")));
3711
+ deleteTasks.push(removeDirectory((0, import_node_path15.join)(".augment", "rules")));
3712
+ deleteTasks.push(removeDirectory((0, import_node_path15.join)(".augment", "ignore")));
3697
3713
  break;
3698
3714
  case "augmentcode-legacy":
3699
3715
  deleteTasks.push(removeClaudeGeneratedFiles());
3700
- deleteTasks.push(removeDirectory((0, import_node_path14.join)(".augment", "ignore")));
3716
+ deleteTasks.push(removeDirectory((0, import_node_path15.join)(".augment", "ignore")));
3701
3717
  break;
3702
3718
  case "copilot":
3703
3719
  deleteTasks.push(removeDirectory(config.outputPaths.copilot));
@@ -3710,14 +3726,15 @@ async function generateCommand(options = {}) {
3710
3726
  break;
3711
3727
  case "claudecode":
3712
3728
  deleteTasks.push(removeClaudeGeneratedFiles());
3713
- deleteTasks.push(removeDirectory((0, import_node_path14.join)(".claude", "commands")));
3729
+ deleteTasks.push(removeDirectory((0, import_node_path15.join)(".claude", "commands")));
3714
3730
  break;
3715
3731
  case "roo":
3716
3732
  deleteTasks.push(removeDirectory(config.outputPaths.roo));
3733
+ deleteTasks.push(removeDirectory((0, import_node_path15.join)(".roo", "commands")));
3717
3734
  break;
3718
3735
  case "geminicli":
3719
3736
  deleteTasks.push(removeDirectory(config.outputPaths.geminicli));
3720
- deleteTasks.push(removeDirectory((0, import_node_path14.join)(".gemini", "commands")));
3737
+ deleteTasks.push(removeDirectory((0, import_node_path15.join)(".gemini", "commands")));
3721
3738
  break;
3722
3739
  case "kiro":
3723
3740
  deleteTasks.push(removeDirectory(config.outputPaths.kiro));
@@ -3833,9 +3850,9 @@ Generating configurations for base directory: ${baseDir}`);
3833
3850
 
3834
3851
  // src/cli/commands/gitignore.ts
3835
3852
  var import_node_fs2 = require("fs");
3836
- var import_node_path15 = require("path");
3853
+ var import_node_path16 = require("path");
3837
3854
  var gitignoreCommand = async () => {
3838
- const gitignorePath = (0, import_node_path15.join)(process.cwd(), ".gitignore");
3855
+ const gitignorePath = (0, import_node_path16.join)(process.cwd(), ".gitignore");
3839
3856
  const rulesFilesToIgnore = [
3840
3857
  "# Generated by rulesync - AI tool configuration files",
3841
3858
  "**/.github/copilot-instructions.md",
@@ -3901,11 +3918,11 @@ ${linesToAdd.join("\n")}
3901
3918
  };
3902
3919
 
3903
3920
  // src/core/importer.ts
3904
- var import_node_path22 = require("path");
3921
+ var import_node_path23 = require("path");
3905
3922
  var import_gray_matter7 = __toESM(require("gray-matter"), 1);
3906
3923
 
3907
3924
  // src/parsers/augmentcode.ts
3908
- var import_node_path16 = require("path");
3925
+ var import_node_path17 = require("path");
3909
3926
  var import_gray_matter3 = __toESM(require("gray-matter"), 1);
3910
3927
 
3911
3928
  // src/utils/parser-helpers.ts
@@ -3954,7 +3971,7 @@ async function parseAugmentcodeLegacyConfiguration(baseDir = process.cwd()) {
3954
3971
  async function parseUnifiedAugmentcode(baseDir, config) {
3955
3972
  const result = createParseResult();
3956
3973
  if (config.rulesDir) {
3957
- const rulesDir = (0, import_node_path16.join)(baseDir, config.rulesDir);
3974
+ const rulesDir = (0, import_node_path17.join)(baseDir, config.rulesDir);
3958
3975
  if (await fileExists(rulesDir)) {
3959
3976
  const rulesResult = await parseAugmentRules(rulesDir, config);
3960
3977
  addRules(result, rulesResult.rules);
@@ -3967,7 +3984,7 @@ async function parseUnifiedAugmentcode(baseDir, config) {
3967
3984
  }
3968
3985
  }
3969
3986
  if (config.legacyFilePath) {
3970
- const legacyPath = (0, import_node_path16.join)(baseDir, config.legacyFilePath);
3987
+ const legacyPath = (0, import_node_path17.join)(baseDir, config.legacyFilePath);
3971
3988
  if (await fileExists(legacyPath)) {
3972
3989
  const legacyResult = await parseAugmentGuidelines(legacyPath, config);
3973
3990
  if (legacyResult.rule) {
@@ -3991,7 +4008,7 @@ async function parseAugmentRules(rulesDir, config) {
3991
4008
  const files = await readdir2(rulesDir);
3992
4009
  for (const file of files) {
3993
4010
  if (file.endsWith(".md") || file.endsWith(".mdc")) {
3994
- const filePath = (0, import_node_path16.join)(rulesDir, file);
4011
+ const filePath = (0, import_node_path17.join)(rulesDir, file);
3995
4012
  try {
3996
4013
  const rawContent = await readFileContent(filePath);
3997
4014
  const parsed = (0, import_gray_matter3.default)(rawContent);
@@ -4000,7 +4017,7 @@ async function parseAugmentRules(rulesDir, config) {
4000
4017
  const description = frontmatterData.description || "";
4001
4018
  const tags = Array.isArray(frontmatterData.tags) ? frontmatterData.tags : void 0;
4002
4019
  const isRoot = ruleType === "always";
4003
- const filename = (0, import_node_path16.basename)(file, file.endsWith(".mdc") ? ".mdc" : ".md");
4020
+ const filename = (0, import_node_path17.basename)(file, file.endsWith(".mdc") ? ".mdc" : ".md");
4004
4021
  const frontmatter = {
4005
4022
  root: isRoot,
4006
4023
  targets: [config.targetName],
@@ -4058,7 +4075,7 @@ async function parseAugmentGuidelines(guidelinesPath, config) {
4058
4075
  }
4059
4076
 
4060
4077
  // src/parsers/shared-helpers.ts
4061
- var import_node_path17 = require("path");
4078
+ var import_node_path18 = require("path");
4062
4079
  var import_gray_matter4 = __toESM(require("gray-matter"), 1);
4063
4080
  async function parseConfigurationFiles(baseDir = process.cwd(), config) {
4064
4081
  const errors = [];
@@ -4114,7 +4131,7 @@ async function parseConfigurationFiles(baseDir = process.cwd(), config) {
4114
4131
  const files = await readdir2(dirPath);
4115
4132
  for (const file of files) {
4116
4133
  if (file.endsWith(dirConfig.filePattern)) {
4117
- const filePath = (0, import_node_path17.join)(dirPath, file);
4134
+ const filePath = (0, import_node_path18.join)(dirPath, file);
4118
4135
  const fileResult = await safeAsyncOperation(async () => {
4119
4136
  const rawContent = await readFileContent(filePath);
4120
4137
  let content;
@@ -4259,10 +4276,10 @@ async function parseMemoryFiles(memoryDir, config) {
4259
4276
  const files = await readdir2(memoryDir);
4260
4277
  for (const file of files) {
4261
4278
  if (file.endsWith(".md")) {
4262
- const filePath = (0, import_node_path17.join)(memoryDir, file);
4279
+ const filePath = (0, import_node_path18.join)(memoryDir, file);
4263
4280
  const content = await readFileContent(filePath);
4264
4281
  if (content.trim()) {
4265
- const filename = (0, import_node_path17.basename)(file, ".md");
4282
+ const filename = (0, import_node_path18.basename)(file, ".md");
4266
4283
  const frontmatter = {
4267
4284
  root: false,
4268
4285
  targets: [config.tool],
@@ -4289,10 +4306,10 @@ async function parseCommandsFiles(commandsDir, config) {
4289
4306
  const files = await readdir2(commandsDir);
4290
4307
  for (const file of files) {
4291
4308
  if (file.endsWith(".md")) {
4292
- const filePath = (0, import_node_path17.join)(commandsDir, file);
4309
+ const filePath = (0, import_node_path18.join)(commandsDir, file);
4293
4310
  const content = await readFileContent(filePath);
4294
4311
  if (content.trim()) {
4295
- const filename = (0, import_node_path17.basename)(file, ".md");
4312
+ const filename = (0, import_node_path18.basename)(file, ".md");
4296
4313
  let frontmatter;
4297
4314
  let ruleContent;
4298
4315
  try {
@@ -4403,7 +4420,7 @@ async function parseClineConfiguration(baseDir = process.cwd()) {
4403
4420
  }
4404
4421
 
4405
4422
  // src/parsers/codexcli.ts
4406
- var import_node_path18 = require("path");
4423
+ var import_node_path19 = require("path");
4407
4424
 
4408
4425
  // src/parsers/copilot.ts
4409
4426
  async function parseCopilotConfiguration(baseDir = process.cwd()) {
@@ -4426,7 +4443,7 @@ async function parseCopilotConfiguration(baseDir = process.cwd()) {
4426
4443
  }
4427
4444
 
4428
4445
  // src/parsers/cursor.ts
4429
- var import_node_path19 = require("path");
4446
+ var import_node_path20 = require("path");
4430
4447
  var import_gray_matter5 = __toESM(require("gray-matter"), 1);
4431
4448
  var import_js_yaml = require("js-yaml");
4432
4449
  var import_mini8 = require("zod/mini");
@@ -4551,7 +4568,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
4551
4568
  const rules = [];
4552
4569
  let ignorePatterns;
4553
4570
  let mcpServers;
4554
- const cursorFilePath = (0, import_node_path19.join)(baseDir, ".cursorrules");
4571
+ const cursorFilePath = (0, import_node_path20.join)(baseDir, ".cursorrules");
4555
4572
  if (await fileExists(cursorFilePath)) {
4556
4573
  try {
4557
4574
  const rawContent = await readFileContent(cursorFilePath);
@@ -4572,20 +4589,20 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
4572
4589
  errors.push(`Failed to parse .cursorrules file: ${errorMessage}`);
4573
4590
  }
4574
4591
  }
4575
- const cursorRulesDir = (0, import_node_path19.join)(baseDir, ".cursor", "rules");
4592
+ const cursorRulesDir = (0, import_node_path20.join)(baseDir, ".cursor", "rules");
4576
4593
  if (await fileExists(cursorRulesDir)) {
4577
4594
  try {
4578
4595
  const { readdir: readdir2 } = await import("fs/promises");
4579
4596
  const files = await readdir2(cursorRulesDir);
4580
4597
  for (const file of files) {
4581
4598
  if (file.endsWith(".mdc")) {
4582
- const filePath = (0, import_node_path19.join)(cursorRulesDir, file);
4599
+ const filePath = (0, import_node_path20.join)(cursorRulesDir, file);
4583
4600
  try {
4584
4601
  const rawContent = await readFileContent(filePath);
4585
4602
  const parsed = (0, import_gray_matter5.default)(rawContent, customMatterOptions);
4586
4603
  const content = parsed.content.trim();
4587
4604
  if (content) {
4588
- const filename = (0, import_node_path19.basename)(file, ".mdc");
4605
+ const filename = (0, import_node_path20.basename)(file, ".mdc");
4589
4606
  const frontmatter = convertCursorMdcFrontmatter(parsed.data, filename);
4590
4607
  rules.push({
4591
4608
  frontmatter,
@@ -4608,7 +4625,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
4608
4625
  if (rules.length === 0) {
4609
4626
  errors.push("No Cursor configuration files found (.cursorrules or .cursor/rules/*.mdc)");
4610
4627
  }
4611
- const cursorIgnorePath = (0, import_node_path19.join)(baseDir, ".cursorignore");
4628
+ const cursorIgnorePath = (0, import_node_path20.join)(baseDir, ".cursorignore");
4612
4629
  if (await fileExists(cursorIgnorePath)) {
4613
4630
  try {
4614
4631
  const content = await readFileContent(cursorIgnorePath);
@@ -4621,7 +4638,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
4621
4638
  errors.push(`Failed to parse .cursorignore: ${errorMessage}`);
4622
4639
  }
4623
4640
  }
4624
- const cursorMcpPath = (0, import_node_path19.join)(baseDir, ".cursor", "mcp.json");
4641
+ const cursorMcpPath = (0, import_node_path20.join)(baseDir, ".cursor", "mcp.json");
4625
4642
  if (await fileExists(cursorMcpPath)) {
4626
4643
  try {
4627
4644
  const content = await readFileContent(cursorMcpPath);
@@ -4671,11 +4688,11 @@ async function parseGeminiConfiguration(baseDir = process.cwd()) {
4671
4688
  }
4672
4689
 
4673
4690
  // src/parsers/junie.ts
4674
- var import_node_path20 = require("path");
4691
+ var import_node_path21 = require("path");
4675
4692
  async function parseJunieConfiguration(baseDir = process.cwd()) {
4676
4693
  const errors = [];
4677
4694
  const rules = [];
4678
- const guidelinesPath = (0, import_node_path20.join)(baseDir, ".junie", "guidelines.md");
4695
+ const guidelinesPath = (0, import_node_path21.join)(baseDir, ".junie", "guidelines.md");
4679
4696
  if (!await fileExists(guidelinesPath)) {
4680
4697
  errors.push(".junie/guidelines.md file not found");
4681
4698
  return { rules, errors };
@@ -4728,7 +4745,7 @@ async function parseRooConfiguration(baseDir = process.cwd()) {
4728
4745
 
4729
4746
  // src/parsers/windsurf.ts
4730
4747
  var import_promises3 = require("fs/promises");
4731
- var import_node_path21 = require("path");
4748
+ var import_node_path22 = require("path");
4732
4749
  var import_gray_matter6 = __toESM(require("gray-matter"), 1);
4733
4750
 
4734
4751
  // src/core/importer.ts
@@ -4815,7 +4832,7 @@ async function importConfiguration(options) {
4815
4832
  if (rules.length === 0 && !ignorePatterns && !mcpServers) {
4816
4833
  return { success: false, rulesCreated: 0, errors };
4817
4834
  }
4818
- const rulesDirPath = (0, import_node_path22.join)(baseDir, rulesDir);
4835
+ const rulesDirPath = (0, import_node_path23.join)(baseDir, rulesDir);
4819
4836
  try {
4820
4837
  const { mkdir: mkdir3 } = await import("fs/promises");
4821
4838
  await mkdir3(rulesDirPath, { recursive: true });
@@ -4830,11 +4847,11 @@ async function importConfiguration(options) {
4830
4847
  const baseFilename = rule.filename;
4831
4848
  let targetDir = rulesDirPath;
4832
4849
  if (rule.type === "command") {
4833
- targetDir = (0, import_node_path22.join)(rulesDirPath, "commands");
4850
+ targetDir = (0, import_node_path23.join)(rulesDirPath, "commands");
4834
4851
  const { mkdir: mkdir3 } = await import("fs/promises");
4835
4852
  await mkdir3(targetDir, { recursive: true });
4836
4853
  }
4837
- const filePath = (0, import_node_path22.join)(targetDir, `${baseFilename}.md`);
4854
+ const filePath = (0, import_node_path23.join)(targetDir, `${baseFilename}.md`);
4838
4855
  const content = generateRuleFileContent(rule);
4839
4856
  await writeFileContent(filePath, content);
4840
4857
  rulesCreated++;
@@ -4849,7 +4866,7 @@ async function importConfiguration(options) {
4849
4866
  let ignoreFileCreated = false;
4850
4867
  if (ignorePatterns && ignorePatterns.length > 0) {
4851
4868
  try {
4852
- const rulesyncignorePath = (0, import_node_path22.join)(baseDir, ".rulesyncignore");
4869
+ const rulesyncignorePath = (0, import_node_path23.join)(baseDir, ".rulesyncignore");
4853
4870
  const ignoreContent = `${ignorePatterns.join("\n")}
4854
4871
  `;
4855
4872
  await writeFileContent(rulesyncignorePath, ignoreContent);
@@ -4865,7 +4882,7 @@ async function importConfiguration(options) {
4865
4882
  let mcpFileCreated = false;
4866
4883
  if (mcpServers && Object.keys(mcpServers).length > 0) {
4867
4884
  try {
4868
- const mcpPath = (0, import_node_path22.join)(baseDir, rulesDir, ".mcp.json");
4885
+ const mcpPath = (0, import_node_path23.join)(baseDir, rulesDir, ".mcp.json");
4869
4886
  const mcpContent = `${JSON.stringify({ mcpServers }, null, 2)}
4870
4887
  `;
4871
4888
  await writeFileContent(mcpPath, mcpContent);
@@ -4959,7 +4976,7 @@ async function importCommand(options = {}) {
4959
4976
  }
4960
4977
 
4961
4978
  // src/cli/commands/init.ts
4962
- var import_node_path23 = require("path");
4979
+ var import_node_path24 = require("path");
4963
4980
  async function initCommand() {
4964
4981
  const aiRulesDir = ".rulesync";
4965
4982
  console.log("Initializing rulesync...");
@@ -5006,7 +5023,7 @@ globs: ["**/*"]
5006
5023
  - Follow single responsibility principle
5007
5024
  `
5008
5025
  };
5009
- const filepath = (0, import_node_path23.join)(aiRulesDir, sampleFile.filename);
5026
+ const filepath = (0, import_node_path24.join)(aiRulesDir, sampleFile.filename);
5010
5027
  if (!await fileExists(filepath)) {
5011
5028
  await writeFileContent(filepath, sampleFile.content);
5012
5029
  console.log(`Created ${filepath}`);
@@ -5150,12 +5167,12 @@ async function watchCommand() {
5150
5167
 
5151
5168
  // src/cli/index.ts
5152
5169
  var program = new import_commander.Command();
5153
- program.name("rulesync").description("Unified AI rules management CLI tool").version("0.59.0");
5170
+ program.name("rulesync").description("Unified AI rules management CLI tool").version("0.61.0");
5154
5171
  program.command("init").description("Initialize rulesync in current directory").action(initCommand);
5155
5172
  program.command("add <filename>").description("Add a new rule file").action(addCommand);
5156
5173
  program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);
5157
5174
  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);
5158
- 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(
5175
+ 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(
5159
5176
  "-b, --base-dir <paths>",
5160
5177
  "Base directories to generate files (comma-separated for multiple paths)"
5161
5178
  ).option("-v, --verbose", "Verbose output").option("-c, --config <path>", "Path to configuration file").option("--no-config", "Disable configuration file loading").action(async (options) => {
@@ -5171,6 +5188,7 @@ program.command("generate").description("Generate configuration files for AI too
5171
5188
  if (options.geminicli) tools.push("geminicli");
5172
5189
  if (options.junie) tools.push("junie");
5173
5190
  if (options.kiro) tools.push("kiro");
5191
+ if (options.windsurf) tools.push("windsurf");
5174
5192
  const generateOptions = {
5175
5193
  verbose: options.verbose,
5176
5194
  delete: options.delete,