rulesync 0.60.0 → 0.62.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
@@ -35,11 +35,11 @@ function isToolTarget(target) {
35
35
  if (!target) return false;
36
36
  return ALL_TOOL_TARGETS.some((validTarget) => validTarget === target);
37
37
  }
38
- var import_mini, ALL_TOOL_TARGETS, ToolTargetSchema, ToolTargetsSchema, WildcardTargetSchema, RulesyncTargetsSchema;
38
+ var import_mini3, ALL_TOOL_TARGETS, ToolTargetSchema, ToolTargetsSchema, WildcardTargetSchema, RulesyncTargetsSchema;
39
39
  var init_tool_targets = __esm({
40
40
  "src/types/tool-targets.ts"() {
41
41
  "use strict";
42
- import_mini = require("zod/mini");
42
+ import_mini3 = require("zod/mini");
43
43
  ALL_TOOL_TARGETS = [
44
44
  "augmentcode",
45
45
  "augmentcode-legacy",
@@ -54,10 +54,10 @@ var init_tool_targets = __esm({
54
54
  "junie",
55
55
  "windsurf"
56
56
  ];
57
- ToolTargetSchema = import_mini.z.enum(ALL_TOOL_TARGETS);
58
- ToolTargetsSchema = import_mini.z.array(ToolTargetSchema);
59
- WildcardTargetSchema = import_mini.z.tuple([import_mini.z.literal("*")]);
60
- RulesyncTargetsSchema = import_mini.z.union([ToolTargetsSchema, WildcardTargetSchema]);
57
+ ToolTargetSchema = import_mini3.z.enum(ALL_TOOL_TARGETS);
58
+ ToolTargetsSchema = import_mini3.z.array(ToolTargetSchema);
59
+ WildcardTargetSchema = import_mini3.z.tuple([import_mini3.z.literal("*")]);
60
+ RulesyncTargetsSchema = import_mini3.z.union([ToolTargetsSchema, WildcardTargetSchema]);
61
61
  }
62
62
  });
63
63
 
@@ -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) {
@@ -247,7 +257,8 @@ function generateMcpConfigurationFilesFromRegistry(tool, mcpServers, baseDir = "
247
257
  return generateMcpConfigurationFiles(mcpServers, generatorConfig, baseDir);
248
258
  }
249
259
  function generateJunieMcpConfigurationFiles(mcpServers, baseDir = "") {
250
- const filepath = baseDir ? `${baseDir}/.junie/mcp-config.json` : ".junie/mcp-config.json";
260
+ const junieMcpPath = ".junie/mcp/mcp.json";
261
+ const filepath = baseDir ? `${baseDir}/${junieMcpPath}` : junieMcpPath;
251
262
  const config = {
252
263
  mcpServers: {}
253
264
  };
@@ -282,7 +293,7 @@ function generateJunieMcpConfigurationFiles(mcpServers, baseDir = "") {
282
293
  }
283
294
  ];
284
295
  }
285
- var serverTransforms, configWrappers, MCP_GENERATOR_REGISTRY;
296
+ var serverTransforms, configWrappers, MCP_GENERATOR_REGISTRY, cursorMcpGenerator, clineMcpGenerator;
286
297
  var init_shared_factory = __esm({
287
298
  "src/generators/mcp/shared-factory.ts"() {
288
299
  "use strict";
@@ -484,6 +495,8 @@ var init_shared_factory = __esm({
484
495
  configWrapper: configWrappers.mcpServers
485
496
  }
486
497
  };
498
+ cursorMcpGenerator = createMcpGenerator("cursor");
499
+ clineMcpGenerator = createMcpGenerator("cline");
487
500
  }
488
501
  });
489
502
 
@@ -512,16 +525,13 @@ __export(cline_exports, {
512
525
  generateClineMcp: () => generateClineMcp,
513
526
  generateClineMcpConfiguration: () => generateClineMcpConfiguration
514
527
  });
515
- function generateClineMcp(config) {
516
- return generateMcpFromRegistry("cline", config);
517
- }
518
- function generateClineMcpConfiguration(mcpServers, baseDir = "") {
519
- return generateMcpConfigurationFilesFromRegistry("cline", mcpServers, baseDir);
520
- }
528
+ var generateClineMcp, generateClineMcpConfiguration;
521
529
  var init_cline = __esm({
522
530
  "src/generators/mcp/cline.ts"() {
523
531
  "use strict";
524
532
  init_shared_factory();
533
+ generateClineMcp = clineMcpGenerator.generateMcp;
534
+ generateClineMcpConfiguration = clineMcpGenerator.generateMcpConfiguration;
525
535
  }
526
536
  });
527
537
 
@@ -759,16 +769,13 @@ __export(cursor_exports, {
759
769
  generateCursorMcp: () => generateCursorMcp,
760
770
  generateCursorMcpConfiguration: () => generateCursorMcpConfiguration
761
771
  });
762
- function generateCursorMcp(config) {
763
- return generateMcpFromRegistry("cursor", config);
764
- }
765
- function generateCursorMcpConfiguration(mcpServers, baseDir = "") {
766
- return generateMcpConfigurationFilesFromRegistry("cursor", mcpServers, baseDir);
767
- }
772
+ var generateCursorMcp, generateCursorMcpConfiguration;
768
773
  var init_cursor = __esm({
769
774
  "src/generators/mcp/cursor.ts"() {
770
775
  "use strict";
771
776
  init_shared_factory();
777
+ generateCursorMcp = cursorMcpGenerator.generateMcp;
778
+ generateCursorMcpConfiguration = cursorMcpGenerator.generateMcpConfiguration;
772
779
  }
773
780
  });
774
781
 
@@ -1049,92 +1056,25 @@ var import_commander = require("commander");
1049
1056
  var import_promises = require("fs/promises");
1050
1057
  var path = __toESM(require("path"), 1);
1051
1058
 
1052
- // src/utils/config.ts
1053
- init_tool_targets();
1054
- function getDefaultConfig() {
1055
- return {
1056
- aiRulesDir: ".rulesync",
1057
- outputPaths: {
1058
- augmentcode: ".",
1059
- "augmentcode-legacy": ".",
1060
- copilot: ".github/instructions",
1061
- cursor: ".cursor/rules",
1062
- cline: ".clinerules",
1063
- claudecode: ".",
1064
- codexcli: ".",
1065
- roo: ".roo/rules",
1066
- geminicli: ".gemini/memories",
1067
- kiro: ".kiro/steering",
1068
- junie: ".",
1069
- windsurf: "."
1070
- },
1071
- watchEnabled: false,
1072
- defaultTargets: ALL_TOOL_TARGETS.filter((tool) => tool !== "augmentcode-legacy")
1073
- };
1074
- }
1075
- function resolveTargets(targets, config) {
1076
- if (targets.length === 1 && targets[0] === "*") {
1077
- return config.defaultTargets;
1078
- }
1079
- const validatedTargets = ToolTargetsSchema.parse(targets);
1080
- return validatedTargets;
1081
- }
1082
-
1083
- // src/cli/commands/add.ts
1084
- function sanitizeFilename(filename) {
1085
- return filename.endsWith(".md") ? filename.slice(0, -3) : filename;
1086
- }
1087
- function generateRuleTemplate(filename) {
1088
- return `---
1089
- root: false
1090
- targets: ["*"]
1091
- description: "Rules for ${filename}"
1092
- globs: []
1093
- ---
1094
-
1095
- # ${filename.charAt(0).toUpperCase() + filename.slice(1)} Rules
1096
-
1097
- Add your rules here.
1098
- `;
1099
- }
1100
- async function addCommand(filename) {
1101
- try {
1102
- const config = getDefaultConfig();
1103
- const sanitizedFilename = sanitizeFilename(filename);
1104
- const rulesDir = config.aiRulesDir;
1105
- const filePath = path.join(rulesDir, `${sanitizedFilename}.md`);
1106
- await (0, import_promises.mkdir)(rulesDir, { recursive: true });
1107
- const template = generateRuleTemplate(sanitizedFilename);
1108
- await (0, import_promises.writeFile)(filePath, template, "utf8");
1109
- console.log(`\u2705 Created rule file: ${filePath}`);
1110
- console.log(`\u{1F4DD} Edit the file to customize your rules.`);
1111
- } catch (error) {
1112
- console.error(
1113
- `\u274C Failed to create rule file: ${error instanceof Error ? error.message : String(error)}`
1114
- );
1115
- process.exit(3);
1116
- }
1117
- }
1118
-
1119
- // src/cli/commands/config.ts
1120
- var import_node_fs = require("fs");
1121
- var import_node_path2 = __toESM(require("path"), 1);
1059
+ // src/utils/config-loader.ts
1060
+ var import_c12 = require("c12");
1061
+ var import_core = require("zod/v4/core");
1122
1062
 
1123
1063
  // src/types/claudecode.ts
1124
- var import_mini2 = require("zod/mini");
1125
- var ClaudeSettingsSchema = import_mini2.z.looseObject({
1126
- permissions: import_mini2.z._default(
1127
- import_mini2.z.looseObject({
1128
- deny: import_mini2.z._default(import_mini2.z.array(import_mini2.z.string()), [])
1064
+ var import_mini = require("zod/mini");
1065
+ var ClaudeSettingsSchema = import_mini.z.looseObject({
1066
+ permissions: import_mini.z._default(
1067
+ import_mini.z.looseObject({
1068
+ deny: import_mini.z._default(import_mini.z.array(import_mini.z.string()), [])
1129
1069
  }),
1130
1070
  { deny: [] }
1131
1071
  )
1132
1072
  });
1133
1073
 
1134
1074
  // src/types/commands.ts
1135
- var import_mini3 = require("zod/mini");
1136
- var CommandFrontmatterSchema = import_mini3.z.object({
1137
- description: import_mini3.z.optional(import_mini3.z.string())
1075
+ var import_mini2 = require("zod/mini");
1076
+ var CommandFrontmatterSchema = import_mini2.z.object({
1077
+ description: import_mini2.z.optional(import_mini2.z.string())
1138
1078
  });
1139
1079
 
1140
1080
  // src/types/config.ts
@@ -1146,7 +1086,8 @@ var ConfigSchema = import_mini4.z.object({
1146
1086
  watchEnabled: import_mini4.z.boolean(),
1147
1087
  defaultTargets: ToolTargetsSchema,
1148
1088
  claudecodeCommands: import_mini4.z.optional(import_mini4.z.string()),
1149
- geminicliCommands: import_mini4.z.optional(import_mini4.z.string())
1089
+ geminicliCommands: import_mini4.z.optional(import_mini4.z.string()),
1090
+ legacy: import_mini4.z.optional(import_mini4.z.boolean())
1150
1091
  });
1151
1092
 
1152
1093
  // src/types/config-options.ts
@@ -1176,6 +1117,7 @@ var ConfigOptionsSchema = import_mini5.z.object({
1176
1117
  verbose: import_mini5.z.optional(import_mini5.z.boolean()),
1177
1118
  delete: import_mini5.z.optional(import_mini5.z.boolean()),
1178
1119
  baseDir: import_mini5.z.optional(import_mini5.z.union([import_mini5.z.string(), import_mini5.z.array(import_mini5.z.string())])),
1120
+ legacy: import_mini5.z.optional(import_mini5.z.boolean()),
1179
1121
  watch: import_mini5.z.optional(
1180
1122
  import_mini5.z.object({
1181
1123
  enabled: import_mini5.z.optional(import_mini5.z.boolean()),
@@ -1195,6 +1137,7 @@ var MergedConfigSchema = import_mini5.z.object({
1195
1137
  delete: import_mini5.z.optional(import_mini5.z.boolean()),
1196
1138
  baseDir: import_mini5.z.optional(import_mini5.z.union([import_mini5.z.string(), import_mini5.z.array(import_mini5.z.string())])),
1197
1139
  configPath: import_mini5.z.optional(import_mini5.z.string()),
1140
+ legacy: import_mini5.z.optional(import_mini5.z.boolean()),
1198
1141
  watch: import_mini5.z.optional(
1199
1142
  import_mini5.z.object({
1200
1143
  enabled: import_mini5.z.optional(import_mini5.z.boolean()),
@@ -1250,13 +1193,6 @@ var RuleFrontmatterSchema = import_mini7.z.object({
1250
1193
  windsurfOutputFormat: import_mini7.z.optional(import_mini7.z.enum(["single-file", "directory"])),
1251
1194
  tags: import_mini7.z.optional(import_mini7.z.array(import_mini7.z.string()))
1252
1195
  });
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
1196
  var GeneratedOutputSchema = import_mini7.z.object({
1261
1197
  tool: ToolTargetSchema,
1262
1198
  filepath: import_mini7.z.string(),
@@ -1271,9 +1207,39 @@ var GenerateOptionsSchema = import_mini7.z.object({
1271
1207
  // src/types/index.ts
1272
1208
  init_tool_targets();
1273
1209
 
1210
+ // src/utils/config.ts
1211
+ init_tool_targets();
1212
+ function getDefaultConfig() {
1213
+ return {
1214
+ aiRulesDir: ".rulesync",
1215
+ outputPaths: {
1216
+ augmentcode: ".",
1217
+ "augmentcode-legacy": ".",
1218
+ copilot: ".github/instructions",
1219
+ cursor: ".cursor/rules",
1220
+ cline: ".clinerules",
1221
+ claudecode: ".",
1222
+ codexcli: ".",
1223
+ roo: ".roo/rules",
1224
+ geminicli: ".gemini/memories",
1225
+ kiro: ".kiro/steering",
1226
+ junie: ".",
1227
+ windsurf: "."
1228
+ },
1229
+ watchEnabled: false,
1230
+ defaultTargets: ALL_TOOL_TARGETS.filter((tool) => tool !== "augmentcode-legacy"),
1231
+ legacy: false
1232
+ };
1233
+ }
1234
+ function resolveTargets(targets, config) {
1235
+ if (targets.length === 1 && targets[0] === "*") {
1236
+ return config.defaultTargets;
1237
+ }
1238
+ const validatedTargets = ToolTargetsSchema.parse(targets);
1239
+ return validatedTargets;
1240
+ }
1241
+
1274
1242
  // src/utils/config-loader.ts
1275
- var import_c12 = require("c12");
1276
- var import_core = require("zod/v4/core");
1277
1243
  var MODULE_NAME = "rulesync";
1278
1244
  async function loadConfig(options = {}) {
1279
1245
  const defaultConfig = getDefaultConfig();
@@ -1460,6 +1426,49 @@ function mergeWithCliOptions(config, cliOptions) {
1460
1426
  return merged;
1461
1427
  }
1462
1428
 
1429
+ // src/cli/commands/add.ts
1430
+ function sanitizeFilename(filename) {
1431
+ return filename.endsWith(".md") ? filename.slice(0, -3) : filename;
1432
+ }
1433
+ function generateRuleTemplate(filename) {
1434
+ return `---
1435
+ root: false
1436
+ targets: ["*"]
1437
+ description: "Rules for ${filename}"
1438
+ globs: []
1439
+ ---
1440
+
1441
+ # ${filename.charAt(0).toUpperCase() + filename.slice(1)} Rules
1442
+
1443
+ Add your rules here.
1444
+ `;
1445
+ }
1446
+ async function addCommand(filename, options = {}) {
1447
+ try {
1448
+ const configResult = await loadConfig();
1449
+ const config = configResult.config;
1450
+ const sanitizedFilename = sanitizeFilename(filename);
1451
+ const aiRulesDir = config.aiRulesDir;
1452
+ const useLegacy = options.legacy ?? config.legacy ?? false;
1453
+ const rulesDir = useLegacy ? aiRulesDir : path.join(aiRulesDir, "rules");
1454
+ const filePath = path.join(rulesDir, `${sanitizedFilename}.md`);
1455
+ await (0, import_promises.mkdir)(rulesDir, { recursive: true });
1456
+ const template = generateRuleTemplate(sanitizedFilename);
1457
+ await (0, import_promises.writeFile)(filePath, template, "utf8");
1458
+ console.log(`\u2705 Created rule file: ${filePath}`);
1459
+ console.log(`\u{1F4DD} Edit the file to customize your rules.`);
1460
+ } catch (error) {
1461
+ console.error(
1462
+ `\u274C Failed to create rule file: ${error instanceof Error ? error.message : String(error)}`
1463
+ );
1464
+ process.exit(3);
1465
+ }
1466
+ }
1467
+
1468
+ // src/cli/commands/config.ts
1469
+ var import_node_fs = require("fs");
1470
+ var import_node_path2 = __toESM(require("path"), 1);
1471
+
1463
1472
  // src/utils/error.ts
1464
1473
  function getErrorMessage(error) {
1465
1474
  return error instanceof Error ? error.message : String(error);
@@ -1526,6 +1535,19 @@ async function findFiles(dir, extension = ".md") {
1526
1535
  return [];
1527
1536
  }
1528
1537
  }
1538
+ async function findRuleFiles(aiRulesDir) {
1539
+ const rulesDir = (0, import_node_path.join)(aiRulesDir, "rules");
1540
+ const newLocationFiles = await findFiles(rulesDir, ".md");
1541
+ const legacyLocationFiles = await findFiles(aiRulesDir, ".md");
1542
+ const newLocationBasenames = new Set(
1543
+ newLocationFiles.map((file) => file.split("/").pop()?.replace(/\.md$/, ""))
1544
+ );
1545
+ const filteredLegacyFiles = legacyLocationFiles.filter((file) => {
1546
+ const basename6 = file.split("/").pop()?.replace(/\.md$/, "");
1547
+ return !newLocationBasenames.has(basename6);
1548
+ });
1549
+ return [...newLocationFiles, ...filteredLegacyFiles];
1550
+ }
1529
1551
  async function removeDirectory(dirPath) {
1530
1552
  const dangerousPaths = [".", "/", "~", "src", "node_modules"];
1531
1553
  if (dangerousPaths.includes(dirPath) || dirPath === "") {
@@ -1560,6 +1582,50 @@ async function removeClaudeGeneratedFiles() {
1560
1582
  }
1561
1583
  }
1562
1584
 
1585
+ // src/utils/logger.ts
1586
+ var import_consola = require("consola");
1587
+ var Logger = class {
1588
+ _verbose = false;
1589
+ console = import_consola.consola.withDefaults({
1590
+ tag: "rulesync"
1591
+ });
1592
+ setVerbose(verbose) {
1593
+ this._verbose = verbose;
1594
+ }
1595
+ get verbose() {
1596
+ return this._verbose;
1597
+ }
1598
+ // Regular log (always shown, regardless of verbose)
1599
+ log(message, ...args) {
1600
+ this.console.log(message, ...args);
1601
+ }
1602
+ // Info level (shown only in verbose mode)
1603
+ info(message, ...args) {
1604
+ if (this._verbose) {
1605
+ this.console.info(message, ...args);
1606
+ }
1607
+ }
1608
+ // Success (always shown)
1609
+ success(message, ...args) {
1610
+ this.console.success(message, ...args);
1611
+ }
1612
+ // Warning (always shown)
1613
+ warn(message, ...args) {
1614
+ this.console.warn(message, ...args);
1615
+ }
1616
+ // Error (always shown)
1617
+ error(message, ...args) {
1618
+ this.console.error(message, ...args);
1619
+ }
1620
+ // Debug level (shown only in verbose mode)
1621
+ debug(message, ...args) {
1622
+ if (this._verbose) {
1623
+ this.console.debug(message, ...args);
1624
+ }
1625
+ }
1626
+ };
1627
+ var logger = new Logger();
1628
+
1563
1629
  // src/cli/commands/config.ts
1564
1630
  async function configCommand(options = {}) {
1565
1631
  if (options.init) {
@@ -1569,50 +1635,50 @@ async function configCommand(options = {}) {
1569
1635
  await showConfig();
1570
1636
  }
1571
1637
  async function showConfig() {
1572
- console.log("Loading configuration...\n");
1638
+ logger.log("Loading configuration...\n");
1573
1639
  try {
1574
1640
  const result = await loadConfig();
1575
1641
  if (result.isEmpty) {
1576
- console.log("No configuration file found. Using default configuration.\n");
1642
+ logger.log("No configuration file found. Using default configuration.\n");
1577
1643
  } else {
1578
- console.log(`Configuration loaded from: ${result.filepath}
1644
+ logger.log(`Configuration loaded from: ${result.filepath}
1579
1645
  `);
1580
1646
  }
1581
- console.log("Current configuration:");
1582
- console.log("=====================");
1647
+ logger.log("Current configuration:");
1648
+ logger.log("=====================");
1583
1649
  const config = result.config;
1584
- console.log(`
1650
+ logger.log(`
1585
1651
  AI Rules Directory: ${config.aiRulesDir}`);
1586
- console.log(`
1652
+ logger.log(`
1587
1653
  Default Targets: ${config.defaultTargets.join(", ")}`);
1588
1654
  if (config.exclude && config.exclude.length > 0) {
1589
- console.log(`Excluded Targets: ${config.exclude.join(", ")}`);
1655
+ logger.log(`Excluded Targets: ${config.exclude.join(", ")}`);
1590
1656
  }
1591
- console.log("\nOutput Paths:");
1657
+ logger.log("\nOutput Paths:");
1592
1658
  for (const [tool, outputPath] of Object.entries(config.outputPaths)) {
1593
- console.log(` ${tool}: ${outputPath}`);
1659
+ logger.log(` ${tool}: ${outputPath}`);
1594
1660
  }
1595
1661
  if (config.baseDir) {
1596
1662
  const dirs = Array.isArray(config.baseDir) ? config.baseDir : [config.baseDir];
1597
- console.log(`
1663
+ logger.log(`
1598
1664
  Base Directories: ${dirs.join(", ")}`);
1599
1665
  }
1600
- console.log(`
1666
+ logger.log(`
1601
1667
  Verbose: ${config.verbose || false}`);
1602
- console.log(`Delete before generate: ${config.delete || false}`);
1668
+ logger.log(`Delete before generate: ${config.delete || false}`);
1603
1669
  if (config.watch) {
1604
- console.log("\nWatch Configuration:");
1605
- console.log(` Enabled: ${config.watch.enabled || false}`);
1670
+ logger.log("\nWatch Configuration:");
1671
+ logger.log(` Enabled: ${config.watch.enabled || false}`);
1606
1672
  if (config.watch.interval) {
1607
- console.log(` Interval: ${config.watch.interval}ms`);
1673
+ logger.log(` Interval: ${config.watch.interval}ms`);
1608
1674
  }
1609
1675
  if (config.watch.ignore && config.watch.ignore.length > 0) {
1610
- console.log(` Ignore patterns: ${config.watch.ignore.join(", ")}`);
1676
+ logger.log(` Ignore patterns: ${config.watch.ignore.join(", ")}`);
1611
1677
  }
1612
1678
  }
1613
- console.log("\nTip: Use 'rulesync config init' to create a configuration file.");
1679
+ logger.log("\nTip: Use 'rulesync config init' to create a configuration file.");
1614
1680
  } catch (error) {
1615
- console.error(
1681
+ logger.error(
1616
1682
  "\u274C Failed to load configuration:",
1617
1683
  error instanceof Error ? error.message : String(error)
1618
1684
  );
@@ -1633,7 +1699,7 @@ async function initConfig(options) {
1633
1699
  const validFormats = Object.keys(FORMAT_CONFIG);
1634
1700
  const selectedFormat = options.format || "jsonc";
1635
1701
  if (!validFormats.includes(selectedFormat)) {
1636
- console.error(
1702
+ logger.error(
1637
1703
  `\u274C Invalid format: ${selectedFormat}. Valid formats are: ${validFormats.join(", ")}`
1638
1704
  );
1639
1705
  process.exit(1);
@@ -1649,7 +1715,7 @@ async function initConfig(options) {
1649
1715
  if (result.success) {
1650
1716
  validTargets.push(result.data);
1651
1717
  } else {
1652
- console.error(`\u274C Invalid target: ${target}`);
1718
+ logger.error(`\u274C Invalid target: ${target}`);
1653
1719
  process.exit(1);
1654
1720
  }
1655
1721
  }
@@ -1663,7 +1729,7 @@ async function initConfig(options) {
1663
1729
  if (result.success) {
1664
1730
  validExcludes.push(result.data);
1665
1731
  } else {
1666
- console.error(`\u274C Invalid exclude target: ${exclude}`);
1732
+ logger.error(`\u274C Invalid exclude target: ${exclude}`);
1667
1733
  process.exit(1);
1668
1734
  }
1669
1735
  }
@@ -1686,18 +1752,18 @@ async function initConfig(options) {
1686
1752
  try {
1687
1753
  const fs2 = await import("fs/promises");
1688
1754
  await fs2.access(filepath);
1689
- console.error(`\u274C Configuration file already exists: ${filepath}`);
1690
- console.log("Remove the existing file or choose a different format.");
1755
+ logger.error(`\u274C Configuration file already exists: ${filepath}`);
1756
+ logger.log("Remove the existing file or choose a different format.");
1691
1757
  process.exit(1);
1692
1758
  } catch {
1693
1759
  }
1694
1760
  try {
1695
1761
  (0, import_node_fs.writeFileSync)(filepath, content, "utf-8");
1696
- console.log(`\u2705 Created configuration file: ${filepath}`);
1697
- console.log("\nYou can now customize the configuration to fit your needs.");
1698
- console.log("Run 'rulesync generate' to use the new configuration.");
1762
+ logger.success(`Created configuration file: ${filepath}`);
1763
+ logger.log("\nYou can now customize the configuration to fit your needs.");
1764
+ logger.log("Run 'rulesync generate' to use the new configuration.");
1699
1765
  } catch (error) {
1700
- console.error(
1766
+ logger.error(
1701
1767
  `\u274C Failed to create configuration file: ${error instanceof Error ? error.message : String(error)}`
1702
1768
  );
1703
1769
  process.exit(1);
@@ -1771,10 +1837,10 @@ export default config;
1771
1837
  }
1772
1838
 
1773
1839
  // src/cli/commands/generate.ts
1774
- var import_node_path14 = require("path");
1840
+ var import_node_path15 = require("path");
1775
1841
 
1776
1842
  // src/core/command-generator.ts
1777
- var import_node_path6 = require("path");
1843
+ var import_node_path7 = require("path");
1778
1844
 
1779
1845
  // src/generators/commands/claudecode.ts
1780
1846
  var import_node_path3 = require("path");
@@ -1830,12 +1896,6 @@ var GeminiCliCommandGenerator = class {
1830
1896
  let converted = content;
1831
1897
  converted = converted.replace(/\$ARGUMENTS/g, "{{args}}");
1832
1898
  converted = converted.replace(/!`([^`]+)`/g, "!{$1}");
1833
- const atSyntaxMatches = converted.match(/@[^\s]+/g);
1834
- if (atSyntaxMatches) {
1835
- console.warn(
1836
- `\u26A0\uFE0F Warning: @ syntax found (${atSyntaxMatches.join(", ")}). Gemini CLI does not support file content injection. Consider using shell commands or remove these references.`
1837
- );
1838
- }
1839
1899
  return converted.trim();
1840
1900
  }
1841
1901
  escapeTomlString(str) {
@@ -1843,17 +1903,44 @@ var GeminiCliCommandGenerator = class {
1843
1903
  }
1844
1904
  };
1845
1905
 
1906
+ // src/generators/commands/roo.ts
1907
+ var import_node_path5 = require("path");
1908
+ var RooCommandGenerator = class {
1909
+ generate(command, outputDir) {
1910
+ const filepath = this.getOutputPath(command.filename, outputDir);
1911
+ const frontmatter = ["---"];
1912
+ if (command.frontmatter.description) {
1913
+ frontmatter.push(`description: ${command.frontmatter.description}`);
1914
+ }
1915
+ frontmatter.push("---");
1916
+ const content = `${frontmatter.join("\n")}
1917
+
1918
+ ${command.content.trim()}
1919
+ `;
1920
+ return {
1921
+ tool: "roo",
1922
+ filepath,
1923
+ content
1924
+ };
1925
+ }
1926
+ getOutputPath(filename, baseDir) {
1927
+ const flattenedName = filename.replace(/\//g, "-");
1928
+ return (0, import_node_path5.join)(baseDir, ".roo", "commands", `${flattenedName}.md`);
1929
+ }
1930
+ };
1931
+
1846
1932
  // src/generators/commands/index.ts
1847
1933
  var commandGenerators = {
1848
1934
  claudecode: new ClaudeCodeCommandGenerator(),
1849
- geminicli: new GeminiCliCommandGenerator()
1935
+ geminicli: new GeminiCliCommandGenerator(),
1936
+ roo: new RooCommandGenerator()
1850
1937
  };
1851
1938
  function getCommandGenerator(tool) {
1852
1939
  return commandGenerators[tool];
1853
1940
  }
1854
1941
 
1855
1942
  // src/core/command-parser.ts
1856
- var import_node_path5 = require("path");
1943
+ var import_node_path6 = require("path");
1857
1944
  var import_gray_matter = __toESM(require("gray-matter"), 1);
1858
1945
  async function parseCommandsFromDirectory(commandsDir) {
1859
1946
  const commandFiles = await findFiles(commandsDir, ".md");
@@ -1879,7 +1966,7 @@ async function parseCommandFile(filepath) {
1879
1966
  const parsed = (0, import_gray_matter.default)(content);
1880
1967
  try {
1881
1968
  const validatedData = CommandFrontmatterSchema.parse(parsed.data);
1882
- const filename = (0, import_node_path5.basename)(filepath, ".md");
1969
+ const filename = (0, import_node_path6.basename)(filepath, ".md");
1883
1970
  return {
1884
1971
  frontmatter: {
1885
1972
  description: validatedData.description
@@ -1897,7 +1984,7 @@ async function parseCommandFile(filepath) {
1897
1984
 
1898
1985
  // src/core/command-generator.ts
1899
1986
  async function generateCommands(projectRoot, baseDir, targets) {
1900
- const commandsDir = (0, import_node_path6.join)(projectRoot, ".rulesync", "commands");
1987
+ const commandsDir = (0, import_node_path7.join)(projectRoot, ".rulesync", "commands");
1901
1988
  if (!await fileExists(commandsDir)) {
1902
1989
  return [];
1903
1990
  }
@@ -1907,7 +1994,9 @@ async function generateCommands(projectRoot, baseDir, targets) {
1907
1994
  }
1908
1995
  const outputs = [];
1909
1996
  const outputDir = baseDir || projectRoot;
1910
- const supportedTargets = targets.filter((target) => ["claudecode", "geminicli"].includes(target));
1997
+ const supportedTargets = targets.filter(
1998
+ (target) => ["claudecode", "geminicli", "roo"].includes(target)
1999
+ );
1911
2000
  for (const target of supportedTargets) {
1912
2001
  const generator = getCommandGenerator(target);
1913
2002
  if (!generator) {
@@ -1929,58 +2018,81 @@ async function generateCommands(projectRoot, baseDir, targets) {
1929
2018
  }
1930
2019
 
1931
2020
  // src/generators/ignore/shared-factory.ts
1932
- var import_node_path7 = require("path");
2021
+ var import_node_path8 = require("path");
1933
2022
 
1934
2023
  // src/generators/ignore/shared-helpers.ts
1935
2024
  function extractIgnorePatternsFromRules(rules) {
1936
2025
  const patterns = [];
1937
2026
  for (const rule of rules) {
1938
2027
  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
- }
2028
+ const sensitiveGlobs = rule.frontmatter.globs.filter(shouldExcludeFromAI);
2029
+ if (sensitiveGlobs.length > 0) {
2030
+ patterns.push(`# Exclude: ${rule.frontmatter.description}`);
2031
+ patterns.push(...sensitiveGlobs);
1944
2032
  }
1945
2033
  }
1946
- const contentPatterns = extractIgnorePatternsFromContent(rule.content);
2034
+ const contentPatterns = extractBasicIgnorePatternsFromContent(rule.content);
1947
2035
  patterns.push(...contentPatterns);
1948
2036
  }
1949
2037
  return patterns;
1950
2038
  }
1951
2039
  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
2040
+ const sensitivePatterns = [
2041
+ // Security-related patterns
2042
+ "**/secret**",
2043
+ "**/credential**",
2044
+ "**/token**",
2045
+ "**/key**",
2046
+ "**/password**",
2047
+ "**/auth**",
2048
+ "**/private**",
2049
+ "**/confidential**",
2050
+ "**/internal**",
2051
+ "**/internal-docs/**",
2052
+ "**/admin**",
2053
+ // Configuration patterns that might contain secrets
2054
+ "**/config/prod**",
2055
+ "**/config/production**",
2056
+ "**/config/secret**",
2057
+ "**/config/secrets/**",
2058
+ "**/env/**",
2059
+ "**/.env**",
2060
+ // Build and deployment patterns
1961
2061
  "**/dist/**",
1962
2062
  "**/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/**"
2063
+ "**/target/**",
2064
+ "**/out/**",
2065
+ "**/node_modules/**",
2066
+ // Data and media patterns
2067
+ "**/data/**",
2068
+ "**/dataset**",
2069
+ "**/backup**",
2070
+ "**/logs/**",
2071
+ "**/log/**",
2072
+ "**/temp/**",
2073
+ "**/tmp/**",
2074
+ "**/cache/**",
2075
+ // Test fixtures that might contain sensitive data
2076
+ "**/test/fixtures/**",
2077
+ "**/test**/fixture**",
2078
+ "**/test**/mock**",
2079
+ "**/test**/data/**",
2080
+ // Database and infrastructure
2081
+ "**/*.sqlite",
2082
+ "**/*.db",
2083
+ "**/*.dump",
2084
+ // Production files
2085
+ "**/*.prod.json",
2086
+ "**/*.production.*"
1977
2087
  ];
1978
- return excludePatterns.some((pattern) => {
1979
- const regex = new RegExp(pattern.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*"));
1980
- return regex.test(glob);
2088
+ const lowerGlob = glob.toLowerCase();
2089
+ return sensitivePatterns.some((pattern) => {
2090
+ const regexPattern = pattern.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*").replace(/\?/g, ".");
2091
+ const regex = new RegExp(`^${regexPattern}$`, "i");
2092
+ return regex.test(lowerGlob);
1981
2093
  });
1982
2094
  }
1983
- function extractIgnorePatternsFromContent(content) {
2095
+ function extractBasicIgnorePatternsFromContent(content) {
1984
2096
  const patterns = [];
1985
2097
  const lines = content.split("\n");
1986
2098
  for (const line of lines) {
@@ -1991,24 +2103,6 @@ function extractIgnorePatternsFromContent(content) {
1991
2103
  patterns.push(pattern);
1992
2104
  }
1993
2105
  }
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
2106
  }
2013
2107
  return patterns;
2014
2108
  }
@@ -2047,7 +2141,7 @@ function generateIgnoreFile(rules, config, ignoreConfig, baseDir) {
2047
2141
  const outputs = [];
2048
2142
  const content = generateIgnoreContent(rules, ignoreConfig);
2049
2143
  const outputPath = baseDir || process.cwd();
2050
- const filepath = (0, import_node_path7.join)(outputPath, ignoreConfig.filename);
2144
+ const filepath = (0, import_node_path8.join)(outputPath, ignoreConfig.filename);
2051
2145
  outputs.push({
2052
2146
  tool: ignoreConfig.tool,
2053
2147
  filepath,
@@ -2635,20 +2729,20 @@ function generateWindsurfIgnore(rules, config, baseDir) {
2635
2729
  }
2636
2730
 
2637
2731
  // src/generators/rules/augmentcode.ts
2638
- var import_node_path10 = require("path");
2732
+ var import_node_path11 = require("path");
2639
2733
 
2640
2734
  // src/generators/rules/shared-helpers.ts
2641
- var import_node_path9 = require("path");
2735
+ var import_node_path10 = require("path");
2642
2736
 
2643
2737
  // src/utils/ignore.ts
2644
- var import_node_path8 = require("path");
2738
+ var import_node_path9 = require("path");
2645
2739
  var import_micromatch = __toESM(require("micromatch"), 1);
2646
2740
  var cachedIgnorePatterns = null;
2647
2741
  async function loadIgnorePatterns(baseDir = process.cwd()) {
2648
2742
  if (cachedIgnorePatterns) {
2649
2743
  return cachedIgnorePatterns;
2650
2744
  }
2651
- const ignorePath = (0, import_node_path8.join)(baseDir, ".rulesyncignore");
2745
+ const ignorePath = (0, import_node_path9.join)(baseDir, ".rulesyncignore");
2652
2746
  if (!await fileExists(ignorePath)) {
2653
2747
  cachedIgnorePatterns = { patterns: [] };
2654
2748
  return cachedIgnorePatterns;
@@ -2702,7 +2796,7 @@ function addOutput(outputs, tool, config, baseDir, relativePath, content) {
2702
2796
  const outputDir = resolveOutputDir(config, tool, baseDir);
2703
2797
  outputs.push({
2704
2798
  tool,
2705
- filepath: (0, import_node_path9.join)(outputDir, relativePath),
2799
+ filepath: (0, import_node_path10.join)(outputDir, relativePath),
2706
2800
  content
2707
2801
  });
2708
2802
  }
@@ -2711,7 +2805,7 @@ async function generateRulesConfig(rules, config, generatorConfig, baseDir) {
2711
2805
  for (const rule of rules) {
2712
2806
  const content = generatorConfig.generateContent(rule);
2713
2807
  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}`);
2808
+ const filepath = generatorConfig.pathResolver ? generatorConfig.pathResolver(rule, outputDir) : (0, import_node_path10.join)(outputDir, `${rule.filename}${generatorConfig.fileExtension}`);
2715
2809
  outputs.push({
2716
2810
  tool: generatorConfig.tool,
2717
2811
  filepath,
@@ -2739,7 +2833,7 @@ async function generateComplexRules(rules, config, generatorConfig, baseDir) {
2739
2833
  for (const rule of detailRules) {
2740
2834
  const content = generatorConfig.generateDetailContent(rule);
2741
2835
  const filepath = resolvePath(
2742
- (0, import_node_path9.join)(generatorConfig.detailSubDir, `${rule.filename}.md`),
2836
+ (0, import_node_path10.join)(generatorConfig.detailSubDir, `${rule.filename}.md`),
2743
2837
  baseDir
2744
2838
  );
2745
2839
  outputs.push({
@@ -2802,7 +2896,7 @@ async function generateAugmentcodeConfig(rules, config, baseDir) {
2802
2896
  "augmentcode",
2803
2897
  config,
2804
2898
  baseDir,
2805
- (0, import_node_path10.join)(".augment", "rules", `${rule.filename}.md`),
2899
+ (0, import_node_path11.join)(".augment", "rules", `${rule.filename}.md`),
2806
2900
  generateRuleFile(rule)
2807
2901
  );
2808
2902
  });
@@ -2855,7 +2949,7 @@ function generateLegacyGuidelinesFile(allRules) {
2855
2949
  }
2856
2950
 
2857
2951
  // src/generators/rules/claudecode.ts
2858
- var import_node_path11 = require("path");
2952
+ var import_node_path12 = require("path");
2859
2953
  async function generateClaudecodeConfig(rules, config, baseDir) {
2860
2954
  const generatorConfig = {
2861
2955
  tool: "claudecode",
@@ -2867,7 +2961,7 @@ async function generateClaudecodeConfig(rules, config, baseDir) {
2867
2961
  generateDetailContent: generateMemoryFile,
2868
2962
  detailSubDir: ".claude/memories",
2869
2963
  updateAdditionalConfig: async (ignorePatterns, baseDir2) => {
2870
- const settingsPath = resolvePath((0, import_node_path11.join)(".claude", "settings.json"), baseDir2);
2964
+ const settingsPath = resolvePath((0, import_node_path12.join)(".claude", "settings.json"), baseDir2);
2871
2965
  await updateClaudeSettings(settingsPath, ignorePatterns);
2872
2966
  return [];
2873
2967
  }
@@ -2931,7 +3025,7 @@ async function updateClaudeSettings(settingsPath, ignorePatterns) {
2931
3025
  }
2932
3026
 
2933
3027
  // src/generators/rules/generator-registry.ts
2934
- var import_node_path12 = require("path");
3028
+ var import_node_path13 = require("path");
2935
3029
  function determineCursorRuleType(frontmatter) {
2936
3030
  if (frontmatter.cursorRuleType) {
2937
3031
  return frontmatter.cursorRuleType;
@@ -3011,7 +3105,7 @@ var GENERATOR_REGISTRY = {
3011
3105
  },
3012
3106
  pathResolver: (rule, outputDir) => {
3013
3107
  const baseFilename = rule.filename.replace(/\.md$/, "");
3014
- return (0, import_node_path12.join)(outputDir, `${baseFilename}.instructions.md`);
3108
+ return (0, import_node_path13.join)(outputDir, `${baseFilename}.instructions.md`);
3015
3109
  }
3016
3110
  },
3017
3111
  cursor: {
@@ -3051,7 +3145,7 @@ var GENERATOR_REGISTRY = {
3051
3145
  return lines.join("\n");
3052
3146
  },
3053
3147
  pathResolver: (rule, outputDir) => {
3054
- return (0, import_node_path12.join)(outputDir, `${rule.filename}.mdc`);
3148
+ return (0, import_node_path13.join)(outputDir, `${rule.filename}.mdc`);
3055
3149
  }
3056
3150
  },
3057
3151
  codexcli: {
@@ -3087,10 +3181,10 @@ var GENERATOR_REGISTRY = {
3087
3181
  pathResolver: (rule, outputDir) => {
3088
3182
  const outputFormat = rule.frontmatter.windsurfOutputFormat || "directory";
3089
3183
  if (outputFormat === "single-file") {
3090
- return (0, import_node_path12.join)(outputDir, ".windsurf-rules");
3184
+ return (0, import_node_path13.join)(outputDir, ".windsurf-rules");
3091
3185
  } else {
3092
- const rulesDir = (0, import_node_path12.join)(outputDir, ".windsurf", "rules");
3093
- return (0, import_node_path12.join)(rulesDir, `${rule.filename}.md`);
3186
+ const rulesDir = (0, import_node_path13.join)(outputDir, ".windsurf", "rules");
3187
+ return (0, import_node_path13.join)(rulesDir, `${rule.filename}.md`);
3094
3188
  }
3095
3189
  }
3096
3190
  },
@@ -3181,10 +3275,18 @@ async function generateFromRegistry(tool, rules, config, baseDir) {
3181
3275
  }
3182
3276
  }
3183
3277
 
3184
- // src/generators/rules/cline.ts
3185
- async function generateClineConfig(rules, config, baseDir) {
3186
- return generateFromRegistry("cline", rules, config, baseDir);
3278
+ // src/generators/rules/generator-factory.ts
3279
+ function createSimpleGenerator(toolName) {
3280
+ return async function(rules, config, baseDir) {
3281
+ return generateFromRegistry(toolName, rules, config, baseDir);
3282
+ };
3187
3283
  }
3284
+ var generateCursorConfig = createSimpleGenerator("cursor");
3285
+ var generateClineConfig = createSimpleGenerator("cline");
3286
+ var generateCopilotConfig = createSimpleGenerator("copilot");
3287
+ var generateWindsurfConfig = createSimpleGenerator("windsurf");
3288
+ var generateKiroConfig = createSimpleGenerator("kiro");
3289
+ var generateRooConfig = createSimpleGenerator("roo");
3188
3290
 
3189
3291
  // src/generators/rules/codexcli.ts
3190
3292
  async function generateCodexConfig(rules, config, baseDir) {
@@ -3231,16 +3333,6 @@ function generateConcatenatedCodexContent(rules) {
3231
3333
  return sections.join("\n\n---\n\n");
3232
3334
  }
3233
3335
 
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
3336
  // src/generators/rules/geminicli.ts
3245
3337
  async function generateGeminiConfig(rules, config, baseDir) {
3246
3338
  const generatorConfig = {
@@ -3310,21 +3402,6 @@ function generateGuidelinesMarkdown(rootRule, detailRules) {
3310
3402
  return lines.join("\n").trim();
3311
3403
  }
3312
3404
 
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
3405
  // src/core/generator.ts
3329
3406
  async function generateConfigurations(rules, config, targetTools, baseDir) {
3330
3407
  const outputs = createOutputsArray();
@@ -3409,11 +3486,11 @@ async function generateForTool(tool, rules, config, baseDir) {
3409
3486
  }
3410
3487
 
3411
3488
  // src/core/parser.ts
3412
- var import_node_path13 = require("path");
3489
+ var import_node_path14 = require("path");
3413
3490
  var import_gray_matter2 = __toESM(require("gray-matter"), 1);
3414
3491
  async function parseRulesFromDirectory(aiRulesDir) {
3415
3492
  const ignorePatterns = await loadIgnorePatterns();
3416
- const allRuleFiles = await findFiles(aiRulesDir, ".md");
3493
+ const allRuleFiles = await findRuleFiles(aiRulesDir);
3417
3494
  const ruleFiles = filterIgnoredFiles(allRuleFiles, ignorePatterns.patterns);
3418
3495
  const rules = [];
3419
3496
  const errors = [];
@@ -3463,7 +3540,7 @@ async function parseRuleFile(filepath) {
3463
3540
  },
3464
3541
  ...validatedData.tags !== void 0 && { tags: validatedData.tags }
3465
3542
  };
3466
- const filename = (0, import_node_path13.basename)(filepath, ".md");
3543
+ const filename = (0, import_node_path14.basename)(filepath, ".md");
3467
3544
  return {
3468
3545
  frontmatter,
3469
3546
  content: parsed.content,
@@ -3632,6 +3709,7 @@ async function generateCommand(options = {}) {
3632
3709
  ...options.baseDirs !== void 0 && { baseDirs: options.baseDirs }
3633
3710
  };
3634
3711
  const config = mergeWithCliOptions(configResult.config, cliOptions);
3712
+ logger.setVerbose(config.verbose || false);
3635
3713
  if (options.tools && options.tools.length > 0) {
3636
3714
  const configTargets = config.defaultTargets;
3637
3715
  const cliTools = options.tools;
@@ -3640,18 +3718,18 @@ async function generateCommand(options = {}) {
3640
3718
  const notInConfig = cliTools.filter((tool) => !configTargetsSet.has(tool));
3641
3719
  const notInCli = configTargets.filter((tool) => !cliToolsSet.has(tool));
3642
3720
  if (notInConfig.length > 0 || notInCli.length > 0) {
3643
- console.warn("\u26A0\uFE0F Warning: CLI tool selection differs from configuration!");
3644
- console.warn(` Config targets: ${configTargets.join(", ")}`);
3645
- console.warn(` CLI specified: ${cliTools.join(", ")}`);
3721
+ logger.warn("\u26A0\uFE0F Warning: CLI tool selection differs from configuration!");
3722
+ logger.warn(` Config targets: ${configTargets.join(", ")}`);
3723
+ logger.warn(` CLI specified: ${cliTools.join(", ")}`);
3646
3724
  if (notInConfig.length > 0) {
3647
- console.warn(` Tools specified but not in config: ${notInConfig.join(", ")}`);
3725
+ logger.warn(` Tools specified but not in config: ${notInConfig.join(", ")}`);
3648
3726
  }
3649
3727
  if (notInCli.length > 0) {
3650
- console.warn(` Tools in config but not specified: ${notInCli.join(", ")}`);
3728
+ logger.warn(` Tools in config but not specified: ${notInCli.join(", ")}`);
3651
3729
  }
3652
- console.warn("\n The configuration file targets will be used.");
3653
- console.warn(" To change targets, update your rulesync config file.");
3654
- console.warn("");
3730
+ logger.warn("\n The configuration file targets will be used.");
3731
+ logger.warn(" To change targets, update your rulesync config file.");
3732
+ logger.warn("");
3655
3733
  }
3656
3734
  }
3657
3735
  let baseDirs;
@@ -3662,42 +3740,46 @@ async function generateCommand(options = {}) {
3662
3740
  } else {
3663
3741
  baseDirs = [process.cwd()];
3664
3742
  }
3665
- if (config.verbose && configResult.filepath) {
3666
- console.log(`Loaded configuration from: ${configResult.filepath}`);
3667
- }
3668
- console.log("Generating configuration files...");
3743
+ logger.info(`Loaded configuration from: ${configResult.filepath}`);
3744
+ logger.log("Generating configuration files...");
3669
3745
  if (!await fileExists(config.aiRulesDir)) {
3670
- console.error("\u274C .rulesync directory not found. Run 'rulesync init' first.");
3746
+ logger.error("\u274C .rulesync directory not found. Run 'rulesync init' first.");
3671
3747
  process.exit(1);
3672
3748
  }
3673
3749
  try {
3674
- if (config.verbose) {
3675
- console.log(`Parsing rules from ${config.aiRulesDir}...`);
3676
- }
3750
+ logger.info(`Parsing rules from ${config.aiRulesDir}...`);
3677
3751
  const rules = await parseRulesFromDirectory(config.aiRulesDir);
3678
3752
  if (rules.length === 0) {
3679
- console.warn("\u26A0\uFE0F No rules found in .rulesync directory");
3753
+ logger.warn("\u26A0\uFE0F No rules found in .rulesync directory");
3680
3754
  return;
3681
3755
  }
3682
- if (config.verbose) {
3683
- console.log(`Found ${rules.length} rule(s)`);
3684
- console.log(`Base directories: ${baseDirs.join(", ")}`);
3685
- }
3756
+ logger.info(`Found ${rules.length} rule(s)`);
3757
+ logger.info(`Base directories: ${baseDirs.join(", ")}`);
3686
3758
  if (config.delete) {
3687
- if (config.verbose) {
3688
- console.log("Deleting existing output directories...");
3689
- }
3759
+ logger.info("Deleting existing output directories...");
3690
3760
  const targetTools = config.defaultTargets;
3691
3761
  const deleteTasks = [];
3762
+ const commandsDir = (0, import_node_path15.join)(config.aiRulesDir, "commands");
3763
+ const hasCommands = await fileExists(commandsDir);
3764
+ let hasCommandFiles = false;
3765
+ if (hasCommands) {
3766
+ const { readdir: readdir2 } = await import("fs/promises");
3767
+ try {
3768
+ const files = await readdir2(commandsDir);
3769
+ hasCommandFiles = files.some((file) => file.endsWith(".md"));
3770
+ } catch {
3771
+ hasCommandFiles = false;
3772
+ }
3773
+ }
3692
3774
  for (const tool of targetTools) {
3693
3775
  switch (tool) {
3694
3776
  case "augmentcode":
3695
- deleteTasks.push(removeDirectory((0, import_node_path14.join)(".augment", "rules")));
3696
- deleteTasks.push(removeDirectory((0, import_node_path14.join)(".augment", "ignore")));
3777
+ deleteTasks.push(removeDirectory((0, import_node_path15.join)(".augment", "rules")));
3778
+ deleteTasks.push(removeDirectory((0, import_node_path15.join)(".augment", "ignore")));
3697
3779
  break;
3698
3780
  case "augmentcode-legacy":
3699
3781
  deleteTasks.push(removeClaudeGeneratedFiles());
3700
- deleteTasks.push(removeDirectory((0, import_node_path14.join)(".augment", "ignore")));
3782
+ deleteTasks.push(removeDirectory((0, import_node_path15.join)(".augment", "ignore")));
3701
3783
  break;
3702
3784
  case "copilot":
3703
3785
  deleteTasks.push(removeDirectory(config.outputPaths.copilot));
@@ -3710,14 +3792,21 @@ async function generateCommand(options = {}) {
3710
3792
  break;
3711
3793
  case "claudecode":
3712
3794
  deleteTasks.push(removeClaudeGeneratedFiles());
3713
- deleteTasks.push(removeDirectory((0, import_node_path14.join)(".claude", "commands")));
3795
+ if (hasCommandFiles) {
3796
+ deleteTasks.push(removeDirectory((0, import_node_path15.join)(".claude", "commands")));
3797
+ }
3714
3798
  break;
3715
3799
  case "roo":
3716
3800
  deleteTasks.push(removeDirectory(config.outputPaths.roo));
3801
+ if (hasCommandFiles) {
3802
+ deleteTasks.push(removeDirectory((0, import_node_path15.join)(".roo", "commands")));
3803
+ }
3717
3804
  break;
3718
3805
  case "geminicli":
3719
3806
  deleteTasks.push(removeDirectory(config.outputPaths.geminicli));
3720
- deleteTasks.push(removeDirectory((0, import_node_path14.join)(".gemini", "commands")));
3807
+ if (hasCommandFiles) {
3808
+ deleteTasks.push(removeDirectory((0, import_node_path15.join)(".gemini", "commands")));
3809
+ }
3721
3810
  break;
3722
3811
  case "kiro":
3723
3812
  deleteTasks.push(removeDirectory(config.outputPaths.kiro));
@@ -3728,44 +3817,34 @@ async function generateCommand(options = {}) {
3728
3817
  }
3729
3818
  }
3730
3819
  await Promise.all(deleteTasks);
3731
- if (config.verbose) {
3732
- console.log("Deleted existing output directories");
3733
- }
3820
+ logger.info("Deleted existing output directories");
3734
3821
  }
3735
3822
  let totalOutputs = 0;
3736
3823
  for (const baseDir of baseDirs) {
3737
- if (config.verbose) {
3738
- console.log(`
3824
+ logger.info(`
3739
3825
  Generating configurations for base directory: ${baseDir}`);
3740
- }
3741
3826
  const outputs = await generateConfigurations(rules, config, config.defaultTargets, baseDir);
3742
3827
  if (outputs.length === 0) {
3743
- if (config.verbose) {
3744
- console.warn(`\u26A0\uFE0F No configurations generated for ${baseDir}`);
3745
- }
3828
+ logger.warn(`\u26A0\uFE0F No configurations generated for ${baseDir}`);
3746
3829
  continue;
3747
3830
  }
3748
3831
  for (const output of outputs) {
3749
3832
  await writeFileContent(output.filepath, output.content);
3750
- console.log(`\u2705 Generated ${output.tool} configuration: ${output.filepath}`);
3833
+ logger.success(`Generated ${output.tool} configuration: ${output.filepath}`);
3751
3834
  }
3752
3835
  totalOutputs += outputs.length;
3753
3836
  }
3754
3837
  if (totalOutputs === 0) {
3755
- console.warn("\u26A0\uFE0F No configurations generated");
3838
+ logger.warn("\u26A0\uFE0F No configurations generated");
3756
3839
  return;
3757
3840
  }
3758
- if (config.verbose) {
3759
- console.log("\nGenerating MCP configurations...");
3760
- }
3841
+ logger.info("\nGenerating MCP configurations...");
3761
3842
  let totalMcpOutputs = 0;
3762
3843
  for (const baseDir of baseDirs) {
3763
3844
  try {
3764
3845
  const mcpConfig = parseMcpConfig(process.cwd());
3765
3846
  if (!mcpConfig || !mcpConfig.mcpServers || Object.keys(mcpConfig.mcpServers).length === 0) {
3766
- if (config.verbose) {
3767
- console.log(`No MCP configuration found for ${baseDir}`);
3768
- }
3847
+ logger.info(`No MCP configuration found for ${baseDir}`);
3769
3848
  continue;
3770
3849
  }
3771
3850
  const mcpResults = await generateMcpConfigurations(
@@ -3774,27 +3853,21 @@ Generating configurations for base directory: ${baseDir}`);
3774
3853
  config.defaultTargets
3775
3854
  );
3776
3855
  if (mcpResults.length === 0) {
3777
- if (config.verbose) {
3778
- console.log(`No MCP configurations generated for ${baseDir}`);
3779
- }
3856
+ logger.info(`No MCP configurations generated for ${baseDir}`);
3780
3857
  continue;
3781
3858
  }
3782
3859
  for (const result of mcpResults) {
3783
3860
  await writeFileContent(result.filepath, result.content);
3784
- console.log(`\u2705 Generated ${result.tool} MCP configuration: ${result.filepath}`);
3861
+ logger.success(`Generated ${result.tool} MCP configuration: ${result.filepath}`);
3785
3862
  totalMcpOutputs++;
3786
3863
  }
3787
3864
  } catch (error) {
3788
- if (config.verbose) {
3789
- console.error(
3790
- `\u274C Failed to generate MCP configurations: ${error instanceof Error ? error.message : String(error)}`
3791
- );
3792
- }
3865
+ logger.error(
3866
+ `\u274C Failed to generate MCP configurations: ${error instanceof Error ? error.message : String(error)}`
3867
+ );
3793
3868
  }
3794
3869
  }
3795
- if (config.verbose) {
3796
- console.log("\nGenerating command files...");
3797
- }
3870
+ logger.info("\nGenerating command files...");
3798
3871
  let totalCommandOutputs = 0;
3799
3872
  for (const baseDir of baseDirs) {
3800
3873
  const commandResults = await generateCommands(
@@ -3803,14 +3876,12 @@ Generating configurations for base directory: ${baseDir}`);
3803
3876
  config.defaultTargets
3804
3877
  );
3805
3878
  if (commandResults.length === 0) {
3806
- if (config.verbose) {
3807
- console.log(`No commands found for ${baseDir}`);
3808
- }
3879
+ logger.info(`No commands found for ${baseDir}`);
3809
3880
  continue;
3810
3881
  }
3811
3882
  for (const result of commandResults) {
3812
3883
  await writeFileContent(result.filepath, result.content);
3813
- console.log(`\u2705 Generated ${result.tool} command: ${result.filepath}`);
3884
+ logger.success(`Generated ${result.tool} command: ${result.filepath}`);
3814
3885
  totalCommandOutputs++;
3815
3886
  }
3816
3887
  }
@@ -3820,22 +3891,22 @@ Generating configurations for base directory: ${baseDir}`);
3820
3891
  if (totalOutputs > 0) parts.push(`${totalOutputs} configurations`);
3821
3892
  if (totalMcpOutputs > 0) parts.push(`${totalMcpOutputs} MCP configurations`);
3822
3893
  if (totalCommandOutputs > 0) parts.push(`${totalCommandOutputs} commands`);
3823
- console.log(
3894
+ logger.success(
3824
3895
  `
3825
3896
  \u{1F389} All done! Generated ${totalGenerated} file(s) total (${parts.join(" + ")})`
3826
3897
  );
3827
3898
  }
3828
3899
  } catch (error) {
3829
- console.error("\u274C Failed to generate configurations:", error);
3900
+ logger.error("\u274C Failed to generate configurations:", error);
3830
3901
  process.exit(1);
3831
3902
  }
3832
3903
  }
3833
3904
 
3834
3905
  // src/cli/commands/gitignore.ts
3835
3906
  var import_node_fs2 = require("fs");
3836
- var import_node_path15 = require("path");
3907
+ var import_node_path16 = require("path");
3837
3908
  var gitignoreCommand = async () => {
3838
- const gitignorePath = (0, import_node_path15.join)(process.cwd(), ".gitignore");
3909
+ const gitignorePath = (0, import_node_path16.join)(process.cwd(), ".gitignore");
3839
3910
  const rulesFilesToIgnore = [
3840
3911
  "# Generated by rulesync - AI tool configuration files",
3841
3912
  "**/.github/copilot-instructions.md",
@@ -3901,11 +3972,11 @@ ${linesToAdd.join("\n")}
3901
3972
  };
3902
3973
 
3903
3974
  // src/core/importer.ts
3904
- var import_node_path22 = require("path");
3975
+ var import_node_path23 = require("path");
3905
3976
  var import_gray_matter7 = __toESM(require("gray-matter"), 1);
3906
3977
 
3907
3978
  // src/parsers/augmentcode.ts
3908
- var import_node_path16 = require("path");
3979
+ var import_node_path17 = require("path");
3909
3980
  var import_gray_matter3 = __toESM(require("gray-matter"), 1);
3910
3981
 
3911
3982
  // src/utils/parser-helpers.ts
@@ -3954,7 +4025,7 @@ async function parseAugmentcodeLegacyConfiguration(baseDir = process.cwd()) {
3954
4025
  async function parseUnifiedAugmentcode(baseDir, config) {
3955
4026
  const result = createParseResult();
3956
4027
  if (config.rulesDir) {
3957
- const rulesDir = (0, import_node_path16.join)(baseDir, config.rulesDir);
4028
+ const rulesDir = (0, import_node_path17.join)(baseDir, config.rulesDir);
3958
4029
  if (await fileExists(rulesDir)) {
3959
4030
  const rulesResult = await parseAugmentRules(rulesDir, config);
3960
4031
  addRules(result, rulesResult.rules);
@@ -3967,7 +4038,7 @@ async function parseUnifiedAugmentcode(baseDir, config) {
3967
4038
  }
3968
4039
  }
3969
4040
  if (config.legacyFilePath) {
3970
- const legacyPath = (0, import_node_path16.join)(baseDir, config.legacyFilePath);
4041
+ const legacyPath = (0, import_node_path17.join)(baseDir, config.legacyFilePath);
3971
4042
  if (await fileExists(legacyPath)) {
3972
4043
  const legacyResult = await parseAugmentGuidelines(legacyPath, config);
3973
4044
  if (legacyResult.rule) {
@@ -3991,7 +4062,7 @@ async function parseAugmentRules(rulesDir, config) {
3991
4062
  const files = await readdir2(rulesDir);
3992
4063
  for (const file of files) {
3993
4064
  if (file.endsWith(".md") || file.endsWith(".mdc")) {
3994
- const filePath = (0, import_node_path16.join)(rulesDir, file);
4065
+ const filePath = (0, import_node_path17.join)(rulesDir, file);
3995
4066
  try {
3996
4067
  const rawContent = await readFileContent(filePath);
3997
4068
  const parsed = (0, import_gray_matter3.default)(rawContent);
@@ -4000,7 +4071,7 @@ async function parseAugmentRules(rulesDir, config) {
4000
4071
  const description = frontmatterData.description || "";
4001
4072
  const tags = Array.isArray(frontmatterData.tags) ? frontmatterData.tags : void 0;
4002
4073
  const isRoot = ruleType === "always";
4003
- const filename = (0, import_node_path16.basename)(file, file.endsWith(".mdc") ? ".mdc" : ".md");
4074
+ const filename = (0, import_node_path17.basename)(file, file.endsWith(".mdc") ? ".mdc" : ".md");
4004
4075
  const frontmatter = {
4005
4076
  root: isRoot,
4006
4077
  targets: [config.targetName],
@@ -4058,7 +4129,7 @@ async function parseAugmentGuidelines(guidelinesPath, config) {
4058
4129
  }
4059
4130
 
4060
4131
  // src/parsers/shared-helpers.ts
4061
- var import_node_path17 = require("path");
4132
+ var import_node_path18 = require("path");
4062
4133
  var import_gray_matter4 = __toESM(require("gray-matter"), 1);
4063
4134
  async function parseConfigurationFiles(baseDir = process.cwd(), config) {
4064
4135
  const errors = [];
@@ -4114,7 +4185,7 @@ async function parseConfigurationFiles(baseDir = process.cwd(), config) {
4114
4185
  const files = await readdir2(dirPath);
4115
4186
  for (const file of files) {
4116
4187
  if (file.endsWith(dirConfig.filePattern)) {
4117
- const filePath = (0, import_node_path17.join)(dirPath, file);
4188
+ const filePath = (0, import_node_path18.join)(dirPath, file);
4118
4189
  const fileResult = await safeAsyncOperation(async () => {
4119
4190
  const rawContent = await readFileContent(filePath);
4120
4191
  let content;
@@ -4259,10 +4330,10 @@ async function parseMemoryFiles(memoryDir, config) {
4259
4330
  const files = await readdir2(memoryDir);
4260
4331
  for (const file of files) {
4261
4332
  if (file.endsWith(".md")) {
4262
- const filePath = (0, import_node_path17.join)(memoryDir, file);
4333
+ const filePath = (0, import_node_path18.join)(memoryDir, file);
4263
4334
  const content = await readFileContent(filePath);
4264
4335
  if (content.trim()) {
4265
- const filename = (0, import_node_path17.basename)(file, ".md");
4336
+ const filename = (0, import_node_path18.basename)(file, ".md");
4266
4337
  const frontmatter = {
4267
4338
  root: false,
4268
4339
  targets: [config.tool],
@@ -4289,10 +4360,10 @@ async function parseCommandsFiles(commandsDir, config) {
4289
4360
  const files = await readdir2(commandsDir);
4290
4361
  for (const file of files) {
4291
4362
  if (file.endsWith(".md")) {
4292
- const filePath = (0, import_node_path17.join)(commandsDir, file);
4363
+ const filePath = (0, import_node_path18.join)(commandsDir, file);
4293
4364
  const content = await readFileContent(filePath);
4294
4365
  if (content.trim()) {
4295
- const filename = (0, import_node_path17.basename)(file, ".md");
4366
+ const filename = (0, import_node_path18.basename)(file, ".md");
4296
4367
  let frontmatter;
4297
4368
  let ruleContent;
4298
4369
  try {
@@ -4403,7 +4474,7 @@ async function parseClineConfiguration(baseDir = process.cwd()) {
4403
4474
  }
4404
4475
 
4405
4476
  // src/parsers/codexcli.ts
4406
- var import_node_path18 = require("path");
4477
+ var import_node_path19 = require("path");
4407
4478
 
4408
4479
  // src/parsers/copilot.ts
4409
4480
  async function parseCopilotConfiguration(baseDir = process.cwd()) {
@@ -4426,7 +4497,7 @@ async function parseCopilotConfiguration(baseDir = process.cwd()) {
4426
4497
  }
4427
4498
 
4428
4499
  // src/parsers/cursor.ts
4429
- var import_node_path19 = require("path");
4500
+ var import_node_path20 = require("path");
4430
4501
  var import_gray_matter5 = __toESM(require("gray-matter"), 1);
4431
4502
  var import_js_yaml = require("js-yaml");
4432
4503
  var import_mini8 = require("zod/mini");
@@ -4551,7 +4622,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
4551
4622
  const rules = [];
4552
4623
  let ignorePatterns;
4553
4624
  let mcpServers;
4554
- const cursorFilePath = (0, import_node_path19.join)(baseDir, ".cursorrules");
4625
+ const cursorFilePath = (0, import_node_path20.join)(baseDir, ".cursorrules");
4555
4626
  if (await fileExists(cursorFilePath)) {
4556
4627
  try {
4557
4628
  const rawContent = await readFileContent(cursorFilePath);
@@ -4572,20 +4643,20 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
4572
4643
  errors.push(`Failed to parse .cursorrules file: ${errorMessage}`);
4573
4644
  }
4574
4645
  }
4575
- const cursorRulesDir = (0, import_node_path19.join)(baseDir, ".cursor", "rules");
4646
+ const cursorRulesDir = (0, import_node_path20.join)(baseDir, ".cursor", "rules");
4576
4647
  if (await fileExists(cursorRulesDir)) {
4577
4648
  try {
4578
4649
  const { readdir: readdir2 } = await import("fs/promises");
4579
4650
  const files = await readdir2(cursorRulesDir);
4580
4651
  for (const file of files) {
4581
4652
  if (file.endsWith(".mdc")) {
4582
- const filePath = (0, import_node_path19.join)(cursorRulesDir, file);
4653
+ const filePath = (0, import_node_path20.join)(cursorRulesDir, file);
4583
4654
  try {
4584
4655
  const rawContent = await readFileContent(filePath);
4585
4656
  const parsed = (0, import_gray_matter5.default)(rawContent, customMatterOptions);
4586
4657
  const content = parsed.content.trim();
4587
4658
  if (content) {
4588
- const filename = (0, import_node_path19.basename)(file, ".mdc");
4659
+ const filename = (0, import_node_path20.basename)(file, ".mdc");
4589
4660
  const frontmatter = convertCursorMdcFrontmatter(parsed.data, filename);
4590
4661
  rules.push({
4591
4662
  frontmatter,
@@ -4608,7 +4679,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
4608
4679
  if (rules.length === 0) {
4609
4680
  errors.push("No Cursor configuration files found (.cursorrules or .cursor/rules/*.mdc)");
4610
4681
  }
4611
- const cursorIgnorePath = (0, import_node_path19.join)(baseDir, ".cursorignore");
4682
+ const cursorIgnorePath = (0, import_node_path20.join)(baseDir, ".cursorignore");
4612
4683
  if (await fileExists(cursorIgnorePath)) {
4613
4684
  try {
4614
4685
  const content = await readFileContent(cursorIgnorePath);
@@ -4621,7 +4692,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
4621
4692
  errors.push(`Failed to parse .cursorignore: ${errorMessage}`);
4622
4693
  }
4623
4694
  }
4624
- const cursorMcpPath = (0, import_node_path19.join)(baseDir, ".cursor", "mcp.json");
4695
+ const cursorMcpPath = (0, import_node_path20.join)(baseDir, ".cursor", "mcp.json");
4625
4696
  if (await fileExists(cursorMcpPath)) {
4626
4697
  try {
4627
4698
  const content = await readFileContent(cursorMcpPath);
@@ -4671,11 +4742,11 @@ async function parseGeminiConfiguration(baseDir = process.cwd()) {
4671
4742
  }
4672
4743
 
4673
4744
  // src/parsers/junie.ts
4674
- var import_node_path20 = require("path");
4745
+ var import_node_path21 = require("path");
4675
4746
  async function parseJunieConfiguration(baseDir = process.cwd()) {
4676
4747
  const errors = [];
4677
4748
  const rules = [];
4678
- const guidelinesPath = (0, import_node_path20.join)(baseDir, ".junie", "guidelines.md");
4749
+ const guidelinesPath = (0, import_node_path21.join)(baseDir, ".junie", "guidelines.md");
4679
4750
  if (!await fileExists(guidelinesPath)) {
4680
4751
  errors.push(".junie/guidelines.md file not found");
4681
4752
  return { rules, errors };
@@ -4728,12 +4799,18 @@ async function parseRooConfiguration(baseDir = process.cwd()) {
4728
4799
 
4729
4800
  // src/parsers/windsurf.ts
4730
4801
  var import_promises3 = require("fs/promises");
4731
- var import_node_path21 = require("path");
4802
+ var import_node_path22 = require("path");
4732
4803
  var import_gray_matter6 = __toESM(require("gray-matter"), 1);
4733
4804
 
4734
4805
  // src/core/importer.ts
4735
4806
  async function importConfiguration(options) {
4736
- const { tool, baseDir = process.cwd(), rulesDir = ".rulesync", verbose = false } = options;
4807
+ const {
4808
+ tool,
4809
+ baseDir = process.cwd(),
4810
+ rulesDir = ".rulesync",
4811
+ verbose = false,
4812
+ useLegacyLocation = false
4813
+ } = options;
4737
4814
  const errors = [];
4738
4815
  let rules = [];
4739
4816
  let ignorePatterns;
@@ -4815,7 +4892,7 @@ async function importConfiguration(options) {
4815
4892
  if (rules.length === 0 && !ignorePatterns && !mcpServers) {
4816
4893
  return { success: false, rulesCreated: 0, errors };
4817
4894
  }
4818
- const rulesDirPath = (0, import_node_path22.join)(baseDir, rulesDir);
4895
+ const rulesDirPath = (0, import_node_path23.join)(baseDir, rulesDir);
4819
4896
  try {
4820
4897
  const { mkdir: mkdir3 } = await import("fs/promises");
4821
4898
  await mkdir3(rulesDirPath, { recursive: true });
@@ -4830,11 +4907,17 @@ async function importConfiguration(options) {
4830
4907
  const baseFilename = rule.filename;
4831
4908
  let targetDir = rulesDirPath;
4832
4909
  if (rule.type === "command") {
4833
- targetDir = (0, import_node_path22.join)(rulesDirPath, "commands");
4910
+ targetDir = (0, import_node_path23.join)(rulesDirPath, "commands");
4834
4911
  const { mkdir: mkdir3 } = await import("fs/promises");
4835
4912
  await mkdir3(targetDir, { recursive: true });
4913
+ } else {
4914
+ if (!useLegacyLocation) {
4915
+ targetDir = (0, import_node_path23.join)(rulesDirPath, "rules");
4916
+ const { mkdir: mkdir3 } = await import("fs/promises");
4917
+ await mkdir3(targetDir, { recursive: true });
4918
+ }
4836
4919
  }
4837
- const filePath = (0, import_node_path22.join)(targetDir, `${baseFilename}.md`);
4920
+ const filePath = (0, import_node_path23.join)(targetDir, `${baseFilename}.md`);
4838
4921
  const content = generateRuleFileContent(rule);
4839
4922
  await writeFileContent(filePath, content);
4840
4923
  rulesCreated++;
@@ -4849,7 +4932,7 @@ async function importConfiguration(options) {
4849
4932
  let ignoreFileCreated = false;
4850
4933
  if (ignorePatterns && ignorePatterns.length > 0) {
4851
4934
  try {
4852
- const rulesyncignorePath = (0, import_node_path22.join)(baseDir, ".rulesyncignore");
4935
+ const rulesyncignorePath = (0, import_node_path23.join)(baseDir, ".rulesyncignore");
4853
4936
  const ignoreContent = `${ignorePatterns.join("\n")}
4854
4937
  `;
4855
4938
  await writeFileContent(rulesyncignorePath, ignoreContent);
@@ -4865,7 +4948,7 @@ async function importConfiguration(options) {
4865
4948
  let mcpFileCreated = false;
4866
4949
  if (mcpServers && Object.keys(mcpServers).length > 0) {
4867
4950
  try {
4868
- const mcpPath = (0, import_node_path22.join)(baseDir, rulesDir, ".mcp.json");
4951
+ const mcpPath = (0, import_node_path23.join)(baseDir, rulesDir, ".mcp.json");
4869
4952
  const mcpContent = `${JSON.stringify({ mcpServers }, null, 2)}
4870
4953
  `;
4871
4954
  await writeFileContent(mcpPath, mcpContent);
@@ -4901,6 +4984,7 @@ function generateRuleFileContent(rule) {
4901
4984
 
4902
4985
  // src/cli/commands/import.ts
4903
4986
  async function importCommand(options = {}) {
4987
+ logger.setVerbose(options.verbose || false);
4904
4988
  const tools = [];
4905
4989
  if (options.augmentcode) tools.push("augmentcode");
4906
4990
  if (options["augmentcode-legacy"]) tools.push("augmentcode-legacy");
@@ -4911,66 +4995,74 @@ async function importCommand(options = {}) {
4911
4995
  if (options.roo) tools.push("roo");
4912
4996
  if (options.geminicli) tools.push("geminicli");
4913
4997
  if (tools.length === 0) {
4914
- console.error(
4998
+ logger.error(
4915
4999
  "\u274C Please specify one tool to import from (--augmentcode, --augmentcode-legacy, --claudecode, --cursor, --copilot, --cline, --roo, --geminicli)"
4916
5000
  );
4917
5001
  process.exit(1);
4918
5002
  }
4919
5003
  if (tools.length > 1) {
4920
- console.error(
5004
+ logger.error(
4921
5005
  "\u274C Only one tool can be specified at a time. Please run the import command separately for each tool."
4922
5006
  );
4923
5007
  process.exit(1);
4924
5008
  }
4925
5009
  const tool = tools[0];
4926
5010
  if (!tool) {
4927
- console.error("Error: No tool specified");
5011
+ logger.error("Error: No tool specified");
4928
5012
  process.exit(1);
4929
5013
  }
4930
- console.log(`Importing configuration files from ${tool}...`);
5014
+ logger.log(`Importing configuration files from ${tool}...`);
4931
5015
  try {
4932
5016
  const result = await importConfiguration({
4933
5017
  tool,
4934
- verbose: options.verbose ?? false
5018
+ verbose: options.verbose ?? false,
5019
+ useLegacyLocation: options.legacy ?? false
4935
5020
  });
4936
5021
  if (result.success) {
4937
- console.log(`\u2705 Imported ${result.rulesCreated} rule(s) from ${tool}`);
5022
+ logger.success(`Imported ${result.rulesCreated} rule(s) from ${tool}`);
4938
5023
  if (result.ignoreFileCreated) {
4939
- console.log("\u2705 Created .rulesyncignore file from ignore patterns");
5024
+ logger.success("Created .rulesyncignore file from ignore patterns");
4940
5025
  }
4941
5026
  if (result.mcpFileCreated) {
4942
- console.log("\u2705 Created .rulesync/.mcp.json file from MCP configuration");
5027
+ logger.success("Created .rulesync/.mcp.json file from MCP configuration");
4943
5028
  }
4944
- console.log("You can now run 'rulesync generate' to create tool-specific configurations.");
5029
+ logger.log("You can now run 'rulesync generate' to create tool-specific configurations.");
4945
5030
  } else if (result.errors.length > 0) {
4946
- console.warn(`\u26A0\uFE0F Failed to import from ${tool}: ${result.errors[0]}`);
4947
- if (options.verbose && result.errors.length > 1) {
4948
- console.log("\nDetailed errors:");
5031
+ logger.warn(`\u26A0\uFE0F Failed to import from ${tool}: ${result.errors[0]}`);
5032
+ if (result.errors.length > 1) {
5033
+ logger.info("\nDetailed errors:");
4949
5034
  for (const error of result.errors) {
4950
- console.log(` - ${error}`);
5035
+ logger.info(` - ${error}`);
4951
5036
  }
4952
5037
  }
4953
5038
  }
4954
5039
  } catch (error) {
4955
5040
  const errorMessage = error instanceof Error ? error.message : String(error);
4956
- console.error(`\u274C Error importing from ${tool}: ${errorMessage}`);
5041
+ logger.error(`\u274C Error importing from ${tool}: ${errorMessage}`);
4957
5042
  process.exit(1);
4958
5043
  }
4959
5044
  }
4960
5045
 
4961
5046
  // src/cli/commands/init.ts
4962
- var import_node_path23 = require("path");
4963
- async function initCommand() {
4964
- const aiRulesDir = ".rulesync";
5047
+ var import_node_path24 = require("path");
5048
+ async function initCommand(options = {}) {
5049
+ const configResult = await loadConfig();
5050
+ const config = configResult.config;
5051
+ const aiRulesDir = config.aiRulesDir;
4965
5052
  console.log("Initializing rulesync...");
4966
5053
  await ensureDir(aiRulesDir);
4967
- await createSampleFiles(aiRulesDir);
5054
+ const useLegacy = options.legacy ?? config.legacy ?? false;
5055
+ const rulesDir = useLegacy ? aiRulesDir : (0, import_node_path24.join)(aiRulesDir, "rules");
5056
+ if (!useLegacy) {
5057
+ await ensureDir(rulesDir);
5058
+ }
5059
+ await createSampleFiles(rulesDir);
4968
5060
  console.log("\u2705 rulesync initialized successfully!");
4969
5061
  console.log("\nNext steps:");
4970
- console.log("1. Edit rule files in .rulesync/");
5062
+ console.log(`1. Edit rule files in ${rulesDir}/`);
4971
5063
  console.log("2. Run 'rulesync generate' to create configuration files");
4972
5064
  }
4973
- async function createSampleFiles(aiRulesDir) {
5065
+ async function createSampleFiles(rulesDir) {
4974
5066
  const sampleFile = {
4975
5067
  filename: "overview.md",
4976
5068
  content: `---
@@ -5006,7 +5098,7 @@ globs: ["**/*"]
5006
5098
  - Follow single responsibility principle
5007
5099
  `
5008
5100
  };
5009
- const filepath = (0, import_node_path23.join)(aiRulesDir, sampleFile.filename);
5101
+ const filepath = (0, import_node_path24.join)(rulesDir, sampleFile.filename);
5010
5102
  if (!await fileExists(filepath)) {
5011
5103
  await writeFileContent(filepath, sampleFile.content);
5012
5104
  console.log(`Created ${filepath}`);
@@ -5150,12 +5242,12 @@ async function watchCommand() {
5150
5242
 
5151
5243
  // src/cli/index.ts
5152
5244
  var program = new import_commander.Command();
5153
- program.name("rulesync").description("Unified AI rules management CLI tool").version("0.60.0");
5154
- program.command("init").description("Initialize rulesync in current directory").action(initCommand);
5155
- program.command("add <filename>").description("Add a new rule file").action(addCommand);
5245
+ program.name("rulesync").description("Unified AI rules management CLI tool").version("0.62.0");
5246
+ program.command("init").description("Initialize rulesync in current directory").option("--legacy", "Use legacy file location (.rulesync/*.md instead of .rulesync/rules/*.md)").action(initCommand);
5247
+ program.command("add <filename>").description("Add a new rule file").option("--legacy", "Use legacy file location (.rulesync/*.md instead of .rulesync/rules/*.md)").action(addCommand);
5156
5248
  program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);
5157
- 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(
5249
+ 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").option("--legacy", "Use legacy file location (.rulesync/*.md instead of .rulesync/rules/*.md)").action(importCommand);
5250
+ 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
5251
  "-b, --base-dir <paths>",
5160
5252
  "Base directories to generate files (comma-separated for multiple paths)"
5161
5253
  ).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 +5263,7 @@ program.command("generate").description("Generate configuration files for AI too
5171
5263
  if (options.geminicli) tools.push("geminicli");
5172
5264
  if (options.junie) tools.push("junie");
5173
5265
  if (options.kiro) tools.push("kiro");
5266
+ if (options.windsurf) tools.push("windsurf");
5174
5267
  const generateOptions = {
5175
5268
  verbose: options.verbose,
5176
5269
  delete: options.delete,