rulesync 0.36.0 → 0.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -26,19 +26,78 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
26
  mod
27
27
  ));
28
28
 
29
+ // src/schemas/mcp.ts
30
+ var import_zod, ToolTargetSchema, WildcardTargetSchema, SpecificTargetsSchema, RulesyncTargetsSchema, McpTransportTypeSchema, McpServerBaseSchema, RulesyncMcpServerSchema;
31
+ var init_mcp = __esm({
32
+ "src/schemas/mcp.ts"() {
33
+ "use strict";
34
+ import_zod = require("zod");
35
+ ToolTargetSchema = import_zod.z.enum([
36
+ "copilot",
37
+ "cursor",
38
+ "cline",
39
+ "claudecode",
40
+ "claude",
41
+ "roo",
42
+ "geminicli"
43
+ ]);
44
+ WildcardTargetSchema = import_zod.z.tuple([import_zod.z.literal("*")]);
45
+ SpecificTargetsSchema = import_zod.z.array(ToolTargetSchema);
46
+ RulesyncTargetsSchema = import_zod.z.union([SpecificTargetsSchema, WildcardTargetSchema]);
47
+ McpTransportTypeSchema = import_zod.z.enum(["stdio", "sse", "http"]);
48
+ McpServerBaseSchema = import_zod.z.object({
49
+ command: import_zod.z.string().optional(),
50
+ args: import_zod.z.array(import_zod.z.string()).optional(),
51
+ url: import_zod.z.string().optional(),
52
+ httpUrl: import_zod.z.string().optional(),
53
+ env: import_zod.z.record(import_zod.z.string()).optional(),
54
+ disabled: import_zod.z.boolean().optional(),
55
+ networkTimeout: import_zod.z.number().optional(),
56
+ timeout: import_zod.z.number().optional(),
57
+ trust: import_zod.z.boolean().optional(),
58
+ cwd: import_zod.z.string().optional(),
59
+ transport: McpTransportTypeSchema.optional(),
60
+ type: import_zod.z.enum(["sse", "streamable-http"]).optional(),
61
+ alwaysAllow: import_zod.z.array(import_zod.z.string()).optional(),
62
+ tools: import_zod.z.array(import_zod.z.string()).optional()
63
+ });
64
+ RulesyncMcpServerSchema = McpServerBaseSchema.extend({
65
+ rulesyncTargets: RulesyncTargetsSchema.optional()
66
+ });
67
+ }
68
+ });
69
+
70
+ // src/utils/mcp-helpers.ts
71
+ function shouldIncludeServer(server, targetTool) {
72
+ if (!server.rulesyncTargets || server.rulesyncTargets.length === 0) {
73
+ return true;
74
+ }
75
+ const parsedTargets = RulesyncTargetsSchema.parse(server.rulesyncTargets);
76
+ if (parsedTargets.length === 1 && parsedTargets[0] === "*") {
77
+ return true;
78
+ }
79
+ const validatedTool = ToolTargetSchema.parse(targetTool);
80
+ for (const target of parsedTargets) {
81
+ if (target === validatedTool) {
82
+ return true;
83
+ }
84
+ }
85
+ return false;
86
+ }
87
+ var init_mcp_helpers = __esm({
88
+ "src/utils/mcp-helpers.ts"() {
89
+ "use strict";
90
+ init_mcp();
91
+ }
92
+ });
93
+
29
94
  // src/generators/mcp/claude.ts
30
95
  function generateClaudeMcp(config, _target) {
31
96
  const claudeSettings = {
32
97
  mcpServers: {}
33
98
  };
34
99
  const shouldInclude = (server) => {
35
- if (!server.rulesyncTargets || server.rulesyncTargets.length === 0) {
36
- return true;
37
- }
38
- if (server.rulesyncTargets.length === 1 && server.rulesyncTargets[0] === "*") {
39
- return true;
40
- }
41
- return server.rulesyncTargets.includes("claude");
100
+ return shouldIncludeServer(server, "claude");
42
101
  };
43
102
  for (const [serverName, server] of Object.entries(config.mcpServers)) {
44
103
  if (!shouldInclude(server)) continue;
@@ -67,6 +126,7 @@ function generateClaudeMcp(config, _target) {
67
126
  var init_claude = __esm({
68
127
  "src/generators/mcp/claude.ts"() {
69
128
  "use strict";
129
+ init_mcp_helpers();
70
130
  }
71
131
  });
72
132
 
@@ -76,10 +136,7 @@ function generateClineMcp(config, _target) {
76
136
  mcpServers: {}
77
137
  };
78
138
  const shouldInclude = (server) => {
79
- const targets = server.rulesyncTargets;
80
- if (!targets || targets.length === 0) return true;
81
- if (targets.length === 1 && targets[0] === "*") return true;
82
- return targets.includes("cline");
139
+ return shouldIncludeServer(server, "cline");
83
140
  };
84
141
  for (const [serverName, server] of Object.entries(config.mcpServers)) {
85
142
  if (!shouldInclude(server)) continue;
@@ -109,22 +166,17 @@ function generateClineMcp(config, _target) {
109
166
  var init_cline = __esm({
110
167
  "src/generators/mcp/cline.ts"() {
111
168
  "use strict";
169
+ init_mcp_helpers();
112
170
  }
113
171
  });
114
172
 
115
173
  // src/generators/mcp/copilot.ts
116
174
  function generateCopilotMcp(config, target) {
117
- const shouldInclude = (server) => {
118
- const targets = server.rulesyncTargets;
119
- if (!targets || targets.length === 0) return true;
120
- if (targets.length === 1 && targets[0] === "*") return true;
121
- return targets.includes("copilot");
122
- };
123
175
  const servers = {};
124
176
  const inputs = [];
125
177
  const inputMap = /* @__PURE__ */ new Map();
126
178
  for (const [serverName, server] of Object.entries(config.mcpServers)) {
127
- if (!shouldInclude(server)) continue;
179
+ if (!shouldIncludeServer(server, "copilot")) continue;
128
180
  const copilotServer = {};
129
181
  if (server.command) {
130
182
  copilotServer.command = server.command;
@@ -173,6 +225,7 @@ function generateCopilotMcp(config, target) {
173
225
  var init_copilot = __esm({
174
226
  "src/generators/mcp/copilot.ts"() {
175
227
  "use strict";
228
+ init_mcp_helpers();
176
229
  }
177
230
  });
178
231
 
@@ -181,14 +234,8 @@ function generateCursorMcp(config, _target) {
181
234
  const cursorConfig = {
182
235
  mcpServers: {}
183
236
  };
184
- const shouldInclude = (server) => {
185
- const targets = server.rulesyncTargets;
186
- if (!targets || targets.length === 0) return true;
187
- if (targets.length === 1 && targets[0] === "*") return true;
188
- return targets.includes("cursor");
189
- };
190
237
  for (const [serverName, server] of Object.entries(config.mcpServers)) {
191
- if (!shouldInclude(server)) continue;
238
+ if (!shouldIncludeServer(server, "cursor")) continue;
192
239
  const cursorServer = {};
193
240
  if (server.command) {
194
241
  cursorServer.command = server.command;
@@ -217,6 +264,7 @@ function generateCursorMcp(config, _target) {
217
264
  var init_cursor = __esm({
218
265
  "src/generators/mcp/cursor.ts"() {
219
266
  "use strict";
267
+ init_mcp_helpers();
220
268
  }
221
269
  });
222
270
 
@@ -225,14 +273,8 @@ function generateGeminiCliMcp(config, _target) {
225
273
  const geminiSettings = {
226
274
  mcpServers: {}
227
275
  };
228
- const shouldInclude = (server) => {
229
- const targets = server.rulesyncTargets;
230
- if (!targets || targets.length === 0) return true;
231
- if (targets.length === 1 && targets[0] === "*") return true;
232
- return targets.includes("geminicli");
233
- };
234
276
  for (const [serverName, server] of Object.entries(config.mcpServers)) {
235
- if (!shouldInclude(server)) continue;
277
+ if (!shouldIncludeServer(server, "geminicli")) continue;
236
278
  const geminiServer = {};
237
279
  if (server.command) {
238
280
  geminiServer.command = server.command;
@@ -267,6 +309,7 @@ function generateGeminiCliMcp(config, _target) {
267
309
  var init_geminicli = __esm({
268
310
  "src/generators/mcp/geminicli.ts"() {
269
311
  "use strict";
312
+ init_mcp_helpers();
270
313
  }
271
314
  });
272
315
 
@@ -275,14 +318,8 @@ function generateRooMcp(config, _target) {
275
318
  const rooConfig = {
276
319
  mcpServers: {}
277
320
  };
278
- const shouldInclude = (server) => {
279
- const targets = server.rulesyncTargets;
280
- if (!targets || targets.length === 0) return true;
281
- if (targets.length === 1 && targets[0] === "*") return true;
282
- return targets.includes("roo");
283
- };
284
321
  for (const [serverName, server] of Object.entries(config.mcpServers)) {
285
- if (!shouldInclude(server)) continue;
322
+ if (!shouldIncludeServer(server, "roo")) continue;
286
323
  const rooServer = {};
287
324
  if (server.command) {
288
325
  rooServer.command = server.command;
@@ -324,6 +361,7 @@ function generateRooMcp(config, _target) {
324
361
  var init_roo = __esm({
325
362
  "src/generators/mcp/roo.ts"() {
326
363
  "use strict";
364
+ init_mcp_helpers();
327
365
  }
328
366
  });
329
367
 
@@ -395,21 +433,47 @@ async function addCommand(filename) {
395
433
  }
396
434
 
397
435
  // src/generators/rules/claudecode.ts
398
- var import_node_path4 = require("path");
436
+ var import_node_path5 = require("path");
399
437
 
400
438
  // src/utils/file.ts
439
+ var import_promises3 = require("fs/promises");
440
+ var import_node_path4 = require("path");
441
+
442
+ // src/utils/file-ops.ts
401
443
  var import_promises2 = require("fs/promises");
402
- var import_node_path3 = require("path");
444
+ var import_node_path2 = require("path");
445
+ async function ensureDir(dirPath) {
446
+ try {
447
+ await (0, import_promises2.stat)(dirPath);
448
+ } catch {
449
+ await (0, import_promises2.mkdir)(dirPath, { recursive: true });
450
+ }
451
+ }
452
+ async function readFileContent(filepath) {
453
+ return (0, import_promises2.readFile)(filepath, "utf-8");
454
+ }
455
+ async function writeFileContent(filepath, content) {
456
+ await ensureDir((0, import_node_path2.dirname)(filepath));
457
+ await (0, import_promises2.writeFile)(filepath, content, "utf-8");
458
+ }
459
+ async function fileExists(filepath) {
460
+ try {
461
+ await (0, import_promises2.stat)(filepath);
462
+ return true;
463
+ } catch {
464
+ return false;
465
+ }
466
+ }
403
467
 
404
468
  // src/utils/ignore.ts
405
- var import_node_path2 = require("path");
469
+ var import_node_path3 = require("path");
406
470
  var import_micromatch = __toESM(require("micromatch"));
407
471
  var cachedIgnorePatterns = null;
408
472
  async function loadIgnorePatterns(baseDir = process.cwd()) {
409
473
  if (cachedIgnorePatterns) {
410
474
  return cachedIgnorePatterns;
411
475
  }
412
- const ignorePath = (0, import_node_path2.join)(baseDir, ".rulesyncignore");
476
+ const ignorePath = (0, import_node_path3.join)(baseDir, ".rulesyncignore");
413
477
  if (!await fileExists(ignorePath)) {
414
478
  cachedIgnorePatterns = { patterns: [] };
415
479
  return cachedIgnorePatterns;
@@ -453,24 +517,10 @@ function filterIgnoredFiles(files, ignorePatterns) {
453
517
  }
454
518
 
455
519
  // src/utils/file.ts
456
- async function ensureDir(dirPath) {
457
- try {
458
- await (0, import_promises2.stat)(dirPath);
459
- } catch {
460
- await (0, import_promises2.mkdir)(dirPath, { recursive: true });
461
- }
462
- }
463
- async function readFileContent(filepath) {
464
- return (0, import_promises2.readFile)(filepath, "utf-8");
465
- }
466
- async function writeFileContent(filepath, content) {
467
- await ensureDir((0, import_node_path3.dirname)(filepath));
468
- await (0, import_promises2.writeFile)(filepath, content, "utf-8");
469
- }
470
520
  async function findFiles(dir, extension = ".md", ignorePatterns) {
471
521
  try {
472
- const files = await (0, import_promises2.readdir)(dir);
473
- const filtered = files.filter((file) => file.endsWith(extension)).map((file) => (0, import_node_path3.join)(dir, file));
522
+ const files = await (0, import_promises3.readdir)(dir);
523
+ const filtered = files.filter((file) => file.endsWith(extension)).map((file) => (0, import_node_path4.join)(dir, file));
474
524
  if (ignorePatterns && ignorePatterns.length > 0) {
475
525
  return filterIgnoredFiles(filtered, ignorePatterns);
476
526
  }
@@ -479,14 +529,6 @@ async function findFiles(dir, extension = ".md", ignorePatterns) {
479
529
  return [];
480
530
  }
481
531
  }
482
- async function fileExists(filepath) {
483
- try {
484
- await (0, import_promises2.stat)(filepath);
485
- return true;
486
- } catch {
487
- return false;
488
- }
489
- }
490
532
  async function removeDirectory(dirPath) {
491
533
  const dangerousPaths = [".", "/", "~", "src", "node_modules"];
492
534
  if (dangerousPaths.includes(dirPath) || dirPath === "") {
@@ -495,7 +537,7 @@ async function removeDirectory(dirPath) {
495
537
  }
496
538
  try {
497
539
  if (await fileExists(dirPath)) {
498
- await (0, import_promises2.rm)(dirPath, { recursive: true, force: true });
540
+ await (0, import_promises3.rm)(dirPath, { recursive: true, force: true });
499
541
  }
500
542
  } catch (error) {
501
543
  console.warn(`Failed to remove directory ${dirPath}:`, error);
@@ -504,7 +546,7 @@ async function removeDirectory(dirPath) {
504
546
  async function removeFile(filepath) {
505
547
  try {
506
548
  if (await fileExists(filepath)) {
507
- await (0, import_promises2.rm)(filepath);
549
+ await (0, import_promises3.rm)(filepath);
508
550
  }
509
551
  } catch (error) {
510
552
  console.warn(`Failed to remove file ${filepath}:`, error);
@@ -527,23 +569,23 @@ async function generateClaudecodeConfig(rules, config, baseDir) {
527
569
  const rootRules = rules.filter((r) => r.frontmatter.root === true);
528
570
  const detailRules = rules.filter((r) => r.frontmatter.root === false);
529
571
  const claudeMdContent = generateClaudeMarkdown(rootRules, detailRules);
530
- const claudeOutputDir = baseDir ? (0, import_node_path4.join)(baseDir, config.outputPaths.claudecode) : config.outputPaths.claudecode;
572
+ const claudeOutputDir = baseDir ? (0, import_node_path5.join)(baseDir, config.outputPaths.claudecode) : config.outputPaths.claudecode;
531
573
  outputs.push({
532
574
  tool: "claudecode",
533
- filepath: (0, import_node_path4.join)(claudeOutputDir, "CLAUDE.md"),
575
+ filepath: (0, import_node_path5.join)(claudeOutputDir, "CLAUDE.md"),
534
576
  content: claudeMdContent
535
577
  });
536
578
  for (const rule of detailRules) {
537
579
  const memoryContent = generateMemoryFile(rule);
538
580
  outputs.push({
539
581
  tool: "claudecode",
540
- filepath: (0, import_node_path4.join)(claudeOutputDir, ".claude", "memories", `${rule.filename}.md`),
582
+ filepath: (0, import_node_path5.join)(claudeOutputDir, ".claude", "memories", `${rule.filename}.md`),
541
583
  content: memoryContent
542
584
  });
543
585
  }
544
586
  const ignorePatterns = await loadIgnorePatterns(baseDir);
545
587
  if (ignorePatterns.patterns.length > 0) {
546
- const settingsPath = baseDir ? (0, import_node_path4.join)(baseDir, ".claude", "settings.json") : (0, import_node_path4.join)(".claude", "settings.json");
588
+ const settingsPath = baseDir ? (0, import_node_path5.join)(baseDir, ".claude", "settings.json") : (0, import_node_path5.join)(".claude", "settings.json");
547
589
  await updateClaudeSettings(settingsPath, ignorePatterns.patterns);
548
590
  }
549
591
  return outputs;
@@ -580,39 +622,46 @@ async function updateClaudeSettings(settingsPath, ignorePatterns) {
580
622
  try {
581
623
  const content = await readFileContent(settingsPath);
582
624
  settings = JSON.parse(content);
583
- } catch (_error) {
625
+ } catch {
584
626
  console.warn(`Failed to parse existing ${settingsPath}, creating new settings`);
585
627
  settings = {};
586
628
  }
587
629
  }
588
- if (!settings.permissions) {
589
- settings.permissions = {};
630
+ if (typeof settings !== "object" || settings === null) {
631
+ settings = {};
590
632
  }
591
- if (!Array.isArray(settings.permissions.deny)) {
592
- settings.permissions.deny = [];
633
+ const settingsObj = settings;
634
+ if (!settingsObj.permissions || typeof settingsObj.permissions !== "object" || settingsObj.permissions === null) {
635
+ settingsObj.permissions = {};
636
+ }
637
+ const permissions = settingsObj.permissions;
638
+ if (!Array.isArray(permissions.deny)) {
639
+ permissions.deny = [];
593
640
  }
594
641
  const readDenyRules = ignorePatterns.map((pattern) => `Read(${pattern})`);
595
- settings.permissions.deny = settings.permissions.deny.filter((rule) => {
642
+ const denyArray = permissions.deny;
643
+ const filteredDeny = denyArray.filter((rule) => {
644
+ if (typeof rule !== "string") return false;
596
645
  if (!rule.startsWith("Read(")) return true;
597
646
  const match = rule.match(/^Read\((.*)\)$/);
598
647
  if (!match) return true;
599
648
  return !ignorePatterns.includes(match[1] ?? "");
600
649
  });
601
- settings.permissions.deny.push(...readDenyRules);
602
- settings.permissions.deny = [...new Set(settings.permissions.deny)];
603
- const jsonContent = JSON.stringify(settings, null, 2);
650
+ filteredDeny.push(...readDenyRules);
651
+ permissions.deny = [...new Set(filteredDeny)];
652
+ const jsonContent = JSON.stringify(settingsObj, null, 2);
604
653
  await writeFileContent(settingsPath, jsonContent);
605
654
  console.log(`\u2705 Updated Claude Code settings: ${settingsPath}`);
606
655
  }
607
656
 
608
657
  // src/generators/rules/cline.ts
609
- var import_node_path5 = require("path");
658
+ var import_node_path6 = require("path");
610
659
  async function generateClineConfig(rules, config, baseDir) {
611
660
  const outputs = [];
612
661
  for (const rule of rules) {
613
662
  const content = generateClineMarkdown(rule);
614
- const outputDir = baseDir ? (0, import_node_path5.join)(baseDir, config.outputPaths.cline) : config.outputPaths.cline;
615
- const filepath = (0, import_node_path5.join)(outputDir, `${rule.filename}.md`);
663
+ const outputDir = baseDir ? (0, import_node_path6.join)(baseDir, config.outputPaths.cline) : config.outputPaths.cline;
664
+ const filepath = (0, import_node_path6.join)(outputDir, `${rule.filename}.md`);
616
665
  outputs.push({
617
666
  tool: "cline",
618
667
  filepath,
@@ -621,7 +670,7 @@ async function generateClineConfig(rules, config, baseDir) {
621
670
  }
622
671
  const ignorePatterns = await loadIgnorePatterns(baseDir);
623
672
  if (ignorePatterns.patterns.length > 0) {
624
- const clineIgnorePath = baseDir ? (0, import_node_path5.join)(baseDir, ".clineignore") : ".clineignore";
673
+ const clineIgnorePath = baseDir ? (0, import_node_path6.join)(baseDir, ".clineignore") : ".clineignore";
625
674
  const clineIgnoreContent = generateClineIgnore(ignorePatterns.patterns);
626
675
  outputs.push({
627
676
  tool: "cline",
@@ -645,14 +694,14 @@ function generateClineIgnore(patterns) {
645
694
  }
646
695
 
647
696
  // src/generators/rules/copilot.ts
648
- var import_node_path6 = require("path");
697
+ var import_node_path7 = require("path");
649
698
  async function generateCopilotConfig(rules, config, baseDir) {
650
699
  const outputs = [];
651
700
  for (const rule of rules) {
652
701
  const content = generateCopilotMarkdown(rule);
653
702
  const baseFilename = rule.filename.replace(/\.md$/, "");
654
- const outputDir = baseDir ? (0, import_node_path6.join)(baseDir, config.outputPaths.copilot) : config.outputPaths.copilot;
655
- const filepath = (0, import_node_path6.join)(outputDir, `${baseFilename}.instructions.md`);
703
+ const outputDir = baseDir ? (0, import_node_path7.join)(baseDir, config.outputPaths.copilot) : config.outputPaths.copilot;
704
+ const filepath = (0, import_node_path7.join)(outputDir, `${baseFilename}.instructions.md`);
656
705
  outputs.push({
657
706
  tool: "copilot",
658
707
  filepath,
@@ -661,7 +710,7 @@ async function generateCopilotConfig(rules, config, baseDir) {
661
710
  }
662
711
  const ignorePatterns = await loadIgnorePatterns(baseDir);
663
712
  if (ignorePatterns.patterns.length > 0) {
664
- const copilotIgnorePath = baseDir ? (0, import_node_path6.join)(baseDir, ".copilotignore") : ".copilotignore";
713
+ const copilotIgnorePath = baseDir ? (0, import_node_path7.join)(baseDir, ".copilotignore") : ".copilotignore";
665
714
  const copilotIgnoreContent = generateCopilotIgnore(ignorePatterns.patterns);
666
715
  outputs.push({
667
716
  tool: "copilot",
@@ -697,13 +746,13 @@ function generateCopilotIgnore(patterns) {
697
746
  }
698
747
 
699
748
  // src/generators/rules/cursor.ts
700
- var import_node_path7 = require("path");
749
+ var import_node_path8 = require("path");
701
750
  async function generateCursorConfig(rules, config, baseDir) {
702
751
  const outputs = [];
703
752
  for (const rule of rules) {
704
753
  const content = generateCursorMarkdown(rule);
705
- const outputDir = baseDir ? (0, import_node_path7.join)(baseDir, config.outputPaths.cursor) : config.outputPaths.cursor;
706
- const filepath = (0, import_node_path7.join)(outputDir, `${rule.filename}.mdc`);
754
+ const outputDir = baseDir ? (0, import_node_path8.join)(baseDir, config.outputPaths.cursor) : config.outputPaths.cursor;
755
+ const filepath = (0, import_node_path8.join)(outputDir, `${rule.filename}.mdc`);
707
756
  outputs.push({
708
757
  tool: "cursor",
709
758
  filepath,
@@ -712,7 +761,7 @@ async function generateCursorConfig(rules, config, baseDir) {
712
761
  }
713
762
  const ignorePatterns = await loadIgnorePatterns(baseDir);
714
763
  if (ignorePatterns.patterns.length > 0) {
715
- const cursorIgnorePath = baseDir ? (0, import_node_path7.join)(baseDir, ".cursorignore") : ".cursorignore";
764
+ const cursorIgnorePath = baseDir ? (0, import_node_path8.join)(baseDir, ".cursorignore") : ".cursorignore";
716
765
  const cursorIgnoreContent = generateCursorIgnore(ignorePatterns.patterns);
717
766
  outputs.push({
718
767
  tool: "cursor",
@@ -753,15 +802,15 @@ function generateCursorIgnore(patterns) {
753
802
  }
754
803
 
755
804
  // src/generators/rules/geminicli.ts
756
- var import_node_path8 = require("path");
805
+ var import_node_path9 = require("path");
757
806
  async function generateGeminiConfig(rules, config, baseDir) {
758
807
  const outputs = [];
759
808
  const rootRule = rules.find((rule) => rule.frontmatter.root === true);
760
809
  const memoryRules = rules.filter((rule) => rule.frontmatter.root === false);
761
810
  for (const rule of memoryRules) {
762
811
  const content = generateGeminiMemoryMarkdown(rule);
763
- const outputDir = baseDir ? (0, import_node_path8.join)(baseDir, config.outputPaths.geminicli) : config.outputPaths.geminicli;
764
- const filepath = (0, import_node_path8.join)(outputDir, `${rule.filename}.md`);
812
+ const outputDir = baseDir ? (0, import_node_path9.join)(baseDir, config.outputPaths.geminicli) : config.outputPaths.geminicli;
813
+ const filepath = (0, import_node_path9.join)(outputDir, `${rule.filename}.md`);
765
814
  outputs.push({
766
815
  tool: "geminicli",
767
816
  filepath,
@@ -769,7 +818,7 @@ async function generateGeminiConfig(rules, config, baseDir) {
769
818
  });
770
819
  }
771
820
  const rootContent = generateGeminiRootMarkdown(rootRule, memoryRules, baseDir);
772
- const rootFilepath = baseDir ? (0, import_node_path8.join)(baseDir, "GEMINI.md") : "GEMINI.md";
821
+ const rootFilepath = baseDir ? (0, import_node_path9.join)(baseDir, "GEMINI.md") : "GEMINI.md";
773
822
  outputs.push({
774
823
  tool: "geminicli",
775
824
  filepath: rootFilepath,
@@ -777,7 +826,7 @@ async function generateGeminiConfig(rules, config, baseDir) {
777
826
  });
778
827
  const ignorePatterns = await loadIgnorePatterns(baseDir);
779
828
  if (ignorePatterns.patterns.length > 0) {
780
- const aiexcludePath = baseDir ? (0, import_node_path8.join)(baseDir, ".aiexclude") : ".aiexclude";
829
+ const aiexcludePath = baseDir ? (0, import_node_path9.join)(baseDir, ".aiexclude") : ".aiexclude";
781
830
  const aiexcludeContent = generateAiexclude(ignorePatterns.patterns);
782
831
  outputs.push({
783
832
  tool: "geminicli",
@@ -825,13 +874,13 @@ function generateAiexclude(patterns) {
825
874
  }
826
875
 
827
876
  // src/generators/rules/roo.ts
828
- var import_node_path9 = require("path");
877
+ var import_node_path10 = require("path");
829
878
  async function generateRooConfig(rules, config, baseDir) {
830
879
  const outputs = [];
831
880
  for (const rule of rules) {
832
881
  const content = generateRooMarkdown(rule);
833
- const outputDir = baseDir ? (0, import_node_path9.join)(baseDir, config.outputPaths.roo) : config.outputPaths.roo;
834
- const filepath = (0, import_node_path9.join)(outputDir, `${rule.filename}.md`);
882
+ const outputDir = baseDir ? (0, import_node_path10.join)(baseDir, config.outputPaths.roo) : config.outputPaths.roo;
883
+ const filepath = (0, import_node_path10.join)(outputDir, `${rule.filename}.md`);
835
884
  outputs.push({
836
885
  tool: "roo",
837
886
  filepath,
@@ -840,7 +889,7 @@ async function generateRooConfig(rules, config, baseDir) {
840
889
  }
841
890
  const ignorePatterns = await loadIgnorePatterns(baseDir);
842
891
  if (ignorePatterns.patterns.length > 0) {
843
- const rooIgnorePath = baseDir ? (0, import_node_path9.join)(baseDir, ".rooignore") : ".rooignore";
892
+ const rooIgnorePath = baseDir ? (0, import_node_path10.join)(baseDir, ".rooignore") : ".rooignore";
844
893
  const rooIgnoreContent = generateRooIgnore(ignorePatterns.patterns);
845
894
  outputs.push({
846
895
  tool: "roo",
@@ -913,7 +962,7 @@ async function generateForTool(tool, rules, config, baseDir) {
913
962
  }
914
963
 
915
964
  // src/core/parser.ts
916
- var import_node_path10 = require("path");
965
+ var import_node_path11 = require("path");
917
966
  var import_gray_matter = __toESM(require("gray-matter"));
918
967
  async function parseRulesFromDirectory(aiRulesDir) {
919
968
  const ignorePatterns = await loadIgnorePatterns();
@@ -950,7 +999,7 @@ async function parseRuleFile(filepath) {
950
999
  const parsed = (0, import_gray_matter.default)(content);
951
1000
  validateFrontmatter(parsed.data, filepath);
952
1001
  const frontmatter = parsed.data;
953
- const filename = (0, import_node_path10.basename)(filepath, ".md");
1002
+ const filename = (0, import_node_path11.basename)(filepath, ".md");
954
1003
  return {
955
1004
  frontmatter,
956
1005
  content: parsed.content,
@@ -1080,7 +1129,7 @@ async function validateRule(rule) {
1080
1129
 
1081
1130
  // src/core/mcp-generator.ts
1082
1131
  var import_node_os = __toESM(require("os"));
1083
- var import_node_path12 = __toESM(require("path"));
1132
+ var import_node_path13 = __toESM(require("path"));
1084
1133
 
1085
1134
  // src/generators/mcp/index.ts
1086
1135
  init_claude();
@@ -1092,9 +1141,9 @@ init_roo();
1092
1141
 
1093
1142
  // src/core/mcp-parser.ts
1094
1143
  var import_node_fs = __toESM(require("fs"));
1095
- var import_node_path11 = __toESM(require("path"));
1144
+ var import_node_path12 = __toESM(require("path"));
1096
1145
  function parseMcpConfig(projectRoot) {
1097
- const mcpPath = import_node_path11.default.join(projectRoot, ".rulesync", ".mcp.json");
1146
+ const mcpPath = import_node_path12.default.join(projectRoot, ".rulesync", ".mcp.json");
1098
1147
  if (!import_node_fs.default.existsSync(mcpPath)) {
1099
1148
  return null;
1100
1149
  }
@@ -1130,32 +1179,32 @@ async function generateMcpConfigs(projectRoot, baseDir) {
1130
1179
  const generators = [
1131
1180
  {
1132
1181
  tool: "claude-project",
1133
- path: import_node_path12.default.join(targetRoot, ".mcp.json"),
1182
+ path: import_node_path13.default.join(targetRoot, ".mcp.json"),
1134
1183
  generate: () => generateClaudeMcp(config, "project")
1135
1184
  },
1136
1185
  {
1137
1186
  tool: "copilot-editor",
1138
- path: import_node_path12.default.join(targetRoot, ".vscode", "mcp.json"),
1187
+ path: import_node_path13.default.join(targetRoot, ".vscode", "mcp.json"),
1139
1188
  generate: () => generateCopilotMcp(config, "editor")
1140
1189
  },
1141
1190
  {
1142
1191
  tool: "cursor-project",
1143
- path: import_node_path12.default.join(targetRoot, ".cursor", "mcp.json"),
1192
+ path: import_node_path13.default.join(targetRoot, ".cursor", "mcp.json"),
1144
1193
  generate: () => generateCursorMcp(config, "project")
1145
1194
  },
1146
1195
  {
1147
1196
  tool: "cline-project",
1148
- path: import_node_path12.default.join(targetRoot, ".cline", "mcp.json"),
1197
+ path: import_node_path13.default.join(targetRoot, ".cline", "mcp.json"),
1149
1198
  generate: () => generateClineMcp(config, "project")
1150
1199
  },
1151
1200
  {
1152
1201
  tool: "gemini-project",
1153
- path: import_node_path12.default.join(targetRoot, ".gemini", "settings.json"),
1202
+ path: import_node_path13.default.join(targetRoot, ".gemini", "settings.json"),
1154
1203
  generate: () => generateGeminiCliMcp(config, "project")
1155
1204
  },
1156
1205
  {
1157
1206
  tool: "roo-project",
1158
- path: import_node_path12.default.join(targetRoot, ".roo", "mcp.json"),
1207
+ path: import_node_path13.default.join(targetRoot, ".roo", "mcp.json"),
1159
1208
  generate: () => generateRooMcp(config, "project")
1160
1209
  }
1161
1210
  ];
@@ -1163,17 +1212,17 @@ async function generateMcpConfigs(projectRoot, baseDir) {
1163
1212
  generators.push(
1164
1213
  {
1165
1214
  tool: "claude-global",
1166
- path: import_node_path12.default.join(import_node_os.default.homedir(), ".claude", "settings.json"),
1215
+ path: import_node_path13.default.join(import_node_os.default.homedir(), ".claude", "settings.json"),
1167
1216
  generate: () => generateClaudeMcp(config, "global")
1168
1217
  },
1169
1218
  {
1170
1219
  tool: "cursor-global",
1171
- path: import_node_path12.default.join(import_node_os.default.homedir(), ".cursor", "mcp.json"),
1220
+ path: import_node_path13.default.join(import_node_os.default.homedir(), ".cursor", "mcp.json"),
1172
1221
  generate: () => generateCursorMcp(config, "global")
1173
1222
  },
1174
1223
  {
1175
1224
  tool: "gemini-global",
1176
- path: import_node_path12.default.join(import_node_os.default.homedir(), ".gemini", "settings.json"),
1225
+ path: import_node_path13.default.join(import_node_os.default.homedir(), ".gemini", "settings.json"),
1177
1226
  generate: () => generateGeminiCliMcp(config, "global")
1178
1227
  }
1179
1228
  );
@@ -1332,9 +1381,9 @@ Generating configurations for base directory: ${baseDir}`);
1332
1381
 
1333
1382
  // src/cli/commands/gitignore.ts
1334
1383
  var import_node_fs2 = require("fs");
1335
- var import_node_path13 = require("path");
1384
+ var import_node_path14 = require("path");
1336
1385
  var gitignoreCommand = async () => {
1337
- const gitignorePath = (0, import_node_path13.join)(process.cwd(), ".gitignore");
1386
+ const gitignorePath = (0, import_node_path14.join)(process.cwd(), ".gitignore");
1338
1387
  const rulesFilesToIgnore = [
1339
1388
  "# Generated by rulesync - AI tool configuration files",
1340
1389
  "**/.github/copilot-instructions.md",
@@ -1387,17 +1436,17 @@ ${linesToAdd.join("\n")}
1387
1436
  };
1388
1437
 
1389
1438
  // src/core/importer.ts
1390
- var import_node_path20 = require("path");
1439
+ var import_node_path21 = require("path");
1391
1440
  var import_gray_matter4 = __toESM(require("gray-matter"));
1392
1441
 
1393
1442
  // src/parsers/claudecode.ts
1394
- var import_node_path14 = require("path");
1443
+ var import_node_path15 = require("path");
1395
1444
  async function parseClaudeConfiguration(baseDir = process.cwd()) {
1396
1445
  const errors = [];
1397
1446
  const rules = [];
1398
1447
  let ignorePatterns;
1399
1448
  let mcpServers;
1400
- const claudeFilePath = (0, import_node_path14.join)(baseDir, "CLAUDE.md");
1449
+ const claudeFilePath = (0, import_node_path15.join)(baseDir, "CLAUDE.md");
1401
1450
  if (!await fileExists(claudeFilePath)) {
1402
1451
  errors.push("CLAUDE.md file not found");
1403
1452
  return { rules, errors };
@@ -1408,12 +1457,12 @@ async function parseClaudeConfiguration(baseDir = process.cwd()) {
1408
1457
  if (mainRule) {
1409
1458
  rules.push(mainRule);
1410
1459
  }
1411
- const memoryDir = (0, import_node_path14.join)(baseDir, ".claude", "memories");
1460
+ const memoryDir = (0, import_node_path15.join)(baseDir, ".claude", "memories");
1412
1461
  if (await fileExists(memoryDir)) {
1413
1462
  const memoryRules = await parseClaudeMemoryFiles(memoryDir);
1414
1463
  rules.push(...memoryRules);
1415
1464
  }
1416
- const settingsPath = (0, import_node_path14.join)(baseDir, ".claude", "settings.json");
1465
+ const settingsPath = (0, import_node_path15.join)(baseDir, ".claude", "settings.json");
1417
1466
  if (await fileExists(settingsPath)) {
1418
1467
  const settingsResult = await parseClaudeSettings(settingsPath);
1419
1468
  if (settingsResult.ignorePatterns) {
@@ -1470,10 +1519,10 @@ async function parseClaudeMemoryFiles(memoryDir) {
1470
1519
  const files = await readdir2(memoryDir);
1471
1520
  for (const file of files) {
1472
1521
  if (file.endsWith(".md")) {
1473
- const filePath = (0, import_node_path14.join)(memoryDir, file);
1522
+ const filePath = (0, import_node_path15.join)(memoryDir, file);
1474
1523
  const content = await readFileContent(filePath);
1475
1524
  if (content.trim()) {
1476
- const filename = (0, import_node_path14.basename)(file, ".md");
1525
+ const filename = (0, import_node_path15.basename)(file, ".md");
1477
1526
  const frontmatter = {
1478
1527
  root: false,
1479
1528
  targets: ["claudecode"],
@@ -1489,7 +1538,7 @@ async function parseClaudeMemoryFiles(memoryDir) {
1489
1538
  }
1490
1539
  }
1491
1540
  }
1492
- } catch (_error) {
1541
+ } catch {
1493
1542
  }
1494
1543
  return rules;
1495
1544
  }
@@ -1500,17 +1549,25 @@ async function parseClaudeSettings(settingsPath) {
1500
1549
  try {
1501
1550
  const content = await readFileContent(settingsPath);
1502
1551
  const settings = JSON.parse(content);
1503
- if (settings.permissions?.deny) {
1504
- const readPatterns = settings.permissions.deny.filter((rule) => rule.startsWith("Read(") && rule.endsWith(")")).map((rule) => {
1505
- const match = rule.match(/^Read\((.+)\)$/);
1506
- return match ? match[1] : null;
1507
- }).filter((pattern) => pattern !== null);
1508
- if (readPatterns.length > 0) {
1509
- ignorePatterns = readPatterns;
1552
+ if (typeof settings === "object" && settings !== null && "permissions" in settings) {
1553
+ const permissions = settings.permissions;
1554
+ if (permissions && "deny" in permissions && Array.isArray(permissions.deny)) {
1555
+ const readPatterns = permissions.deny.filter(
1556
+ (rule) => typeof rule === "string" && rule.startsWith("Read(") && rule.endsWith(")")
1557
+ ).map((rule) => {
1558
+ const match = rule.match(/^Read\((.+)\)$/);
1559
+ return match ? match[1] : null;
1560
+ }).filter((pattern) => pattern !== null);
1561
+ if (readPatterns.length > 0) {
1562
+ ignorePatterns = readPatterns;
1563
+ }
1510
1564
  }
1511
1565
  }
1512
- if (settings.mcpServers && Object.keys(settings.mcpServers).length > 0) {
1513
- mcpServers = settings.mcpServers;
1566
+ if (typeof settings === "object" && settings !== null && "mcpServers" in settings) {
1567
+ const servers = settings.mcpServers;
1568
+ if (servers && typeof servers === "object" && Object.keys(servers).length > 0) {
1569
+ mcpServers = servers;
1570
+ }
1514
1571
  }
1515
1572
  } catch (error) {
1516
1573
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -1524,11 +1581,11 @@ async function parseClaudeSettings(settingsPath) {
1524
1581
  }
1525
1582
 
1526
1583
  // src/parsers/cline.ts
1527
- var import_node_path15 = require("path");
1584
+ var import_node_path16 = require("path");
1528
1585
  async function parseClineConfiguration(baseDir = process.cwd()) {
1529
1586
  const errors = [];
1530
1587
  const rules = [];
1531
- const clineFilePath = (0, import_node_path15.join)(baseDir, ".cline", "instructions.md");
1588
+ const clineFilePath = (0, import_node_path16.join)(baseDir, ".cline", "instructions.md");
1532
1589
  if (await fileExists(clineFilePath)) {
1533
1590
  try {
1534
1591
  const content = await readFileContent(clineFilePath);
@@ -1551,14 +1608,14 @@ async function parseClineConfiguration(baseDir = process.cwd()) {
1551
1608
  errors.push(`Failed to parse .cline/instructions.md: ${errorMessage}`);
1552
1609
  }
1553
1610
  }
1554
- const clinerulesDirPath = (0, import_node_path15.join)(baseDir, ".clinerules");
1611
+ const clinerulesDirPath = (0, import_node_path16.join)(baseDir, ".clinerules");
1555
1612
  if (await fileExists(clinerulesDirPath)) {
1556
1613
  try {
1557
1614
  const { readdir: readdir2 } = await import("fs/promises");
1558
1615
  const files = await readdir2(clinerulesDirPath);
1559
1616
  for (const file of files) {
1560
1617
  if (file.endsWith(".md")) {
1561
- const filePath = (0, import_node_path15.join)(clinerulesDirPath, file);
1618
+ const filePath = (0, import_node_path16.join)(clinerulesDirPath, file);
1562
1619
  try {
1563
1620
  const content = await readFileContent(filePath);
1564
1621
  if (content.trim()) {
@@ -1594,12 +1651,12 @@ async function parseClineConfiguration(baseDir = process.cwd()) {
1594
1651
  }
1595
1652
 
1596
1653
  // src/parsers/copilot.ts
1597
- var import_node_path16 = require("path");
1654
+ var import_node_path17 = require("path");
1598
1655
  var import_gray_matter2 = __toESM(require("gray-matter"));
1599
1656
  async function parseCopilotConfiguration(baseDir = process.cwd()) {
1600
1657
  const errors = [];
1601
1658
  const rules = [];
1602
- const copilotFilePath = (0, import_node_path16.join)(baseDir, ".github", "copilot-instructions.md");
1659
+ const copilotFilePath = (0, import_node_path17.join)(baseDir, ".github", "copilot-instructions.md");
1603
1660
  if (await fileExists(copilotFilePath)) {
1604
1661
  try {
1605
1662
  const rawContent = await readFileContent(copilotFilePath);
@@ -1624,19 +1681,19 @@ async function parseCopilotConfiguration(baseDir = process.cwd()) {
1624
1681
  errors.push(`Failed to parse copilot-instructions.md: ${errorMessage}`);
1625
1682
  }
1626
1683
  }
1627
- const instructionsDir = (0, import_node_path16.join)(baseDir, ".github", "instructions");
1684
+ const instructionsDir = (0, import_node_path17.join)(baseDir, ".github", "instructions");
1628
1685
  if (await fileExists(instructionsDir)) {
1629
1686
  try {
1630
1687
  const { readdir: readdir2 } = await import("fs/promises");
1631
1688
  const files = await readdir2(instructionsDir);
1632
1689
  for (const file of files) {
1633
1690
  if (file.endsWith(".instructions.md")) {
1634
- const filePath = (0, import_node_path16.join)(instructionsDir, file);
1691
+ const filePath = (0, import_node_path17.join)(instructionsDir, file);
1635
1692
  const rawContent = await readFileContent(filePath);
1636
1693
  const parsed = (0, import_gray_matter2.default)(rawContent);
1637
1694
  const content = parsed.content.trim();
1638
1695
  if (content) {
1639
- const filename = (0, import_node_path16.basename)(file, ".instructions.md");
1696
+ const filename = (0, import_node_path17.basename)(file, ".instructions.md");
1640
1697
  const frontmatter = {
1641
1698
  root: false,
1642
1699
  targets: ["copilot"],
@@ -1666,19 +1723,19 @@ async function parseCopilotConfiguration(baseDir = process.cwd()) {
1666
1723
  }
1667
1724
 
1668
1725
  // src/parsers/cursor.ts
1669
- var import_node_path17 = require("path");
1726
+ var import_node_path18 = require("path");
1670
1727
  var import_gray_matter3 = __toESM(require("gray-matter"));
1671
- var import_js_yaml = __toESM(require("js-yaml"));
1728
+ var import_js_yaml = require("js-yaml");
1672
1729
  var customMatterOptions = {
1673
1730
  engines: {
1674
1731
  yaml: {
1675
1732
  parse: (str) => {
1676
1733
  try {
1677
1734
  const preprocessed = str.replace(/^(\s*globs:\s*)\*\s*$/gm, '$1"*"');
1678
- return import_js_yaml.default.load(preprocessed, { schema: import_js_yaml.default.DEFAULT_SCHEMA });
1735
+ return (0, import_js_yaml.load)(preprocessed, { schema: import_js_yaml.DEFAULT_SCHEMA });
1679
1736
  } catch (error) {
1680
1737
  try {
1681
- return import_js_yaml.default.load(str, { schema: import_js_yaml.default.FAILSAFE_SCHEMA });
1738
+ return (0, import_js_yaml.load)(str, { schema: import_js_yaml.FAILSAFE_SCHEMA });
1682
1739
  } catch {
1683
1740
  throw error;
1684
1741
  }
@@ -1692,7 +1749,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
1692
1749
  const rules = [];
1693
1750
  let ignorePatterns;
1694
1751
  let mcpServers;
1695
- const cursorFilePath = (0, import_node_path17.join)(baseDir, ".cursorrules");
1752
+ const cursorFilePath = (0, import_node_path18.join)(baseDir, ".cursorrules");
1696
1753
  if (await fileExists(cursorFilePath)) {
1697
1754
  try {
1698
1755
  const rawContent = await readFileContent(cursorFilePath);
@@ -1717,20 +1774,20 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
1717
1774
  errors.push(`Failed to parse .cursorrules file: ${errorMessage}`);
1718
1775
  }
1719
1776
  }
1720
- const cursorRulesDir = (0, import_node_path17.join)(baseDir, ".cursor", "rules");
1777
+ const cursorRulesDir = (0, import_node_path18.join)(baseDir, ".cursor", "rules");
1721
1778
  if (await fileExists(cursorRulesDir)) {
1722
1779
  try {
1723
1780
  const { readdir: readdir2 } = await import("fs/promises");
1724
1781
  const files = await readdir2(cursorRulesDir);
1725
1782
  for (const file of files) {
1726
1783
  if (file.endsWith(".mdc")) {
1727
- const filePath = (0, import_node_path17.join)(cursorRulesDir, file);
1784
+ const filePath = (0, import_node_path18.join)(cursorRulesDir, file);
1728
1785
  try {
1729
1786
  const rawContent = await readFileContent(filePath);
1730
1787
  const parsed = (0, import_gray_matter3.default)(rawContent, customMatterOptions);
1731
1788
  const content = parsed.content.trim();
1732
1789
  if (content) {
1733
- const filename = (0, import_node_path17.basename)(file, ".mdc");
1790
+ const filename = (0, import_node_path18.basename)(file, ".mdc");
1734
1791
  const frontmatter = {
1735
1792
  root: false,
1736
1793
  targets: ["cursor"],
@@ -1758,7 +1815,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
1758
1815
  if (rules.length === 0) {
1759
1816
  errors.push("No Cursor configuration files found (.cursorrules or .cursor/rules/*.mdc)");
1760
1817
  }
1761
- const cursorIgnorePath = (0, import_node_path17.join)(baseDir, ".cursorignore");
1818
+ const cursorIgnorePath = (0, import_node_path18.join)(baseDir, ".cursorignore");
1762
1819
  if (await fileExists(cursorIgnorePath)) {
1763
1820
  try {
1764
1821
  const content = await readFileContent(cursorIgnorePath);
@@ -1771,7 +1828,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
1771
1828
  errors.push(`Failed to parse .cursorignore: ${errorMessage}`);
1772
1829
  }
1773
1830
  }
1774
- const cursorMcpPath = (0, import_node_path17.join)(baseDir, ".cursor", "mcp.json");
1831
+ const cursorMcpPath = (0, import_node_path18.join)(baseDir, ".cursor", "mcp.json");
1775
1832
  if (await fileExists(cursorMcpPath)) {
1776
1833
  try {
1777
1834
  const content = await readFileContent(cursorMcpPath);
@@ -1793,13 +1850,13 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
1793
1850
  }
1794
1851
 
1795
1852
  // src/parsers/geminicli.ts
1796
- var import_node_path18 = require("path");
1853
+ var import_node_path19 = require("path");
1797
1854
  async function parseGeminiConfiguration(baseDir = process.cwd()) {
1798
1855
  const errors = [];
1799
1856
  const rules = [];
1800
1857
  let ignorePatterns;
1801
1858
  let mcpServers;
1802
- const geminiFilePath = (0, import_node_path18.join)(baseDir, "GEMINI.md");
1859
+ const geminiFilePath = (0, import_node_path19.join)(baseDir, "GEMINI.md");
1803
1860
  if (!await fileExists(geminiFilePath)) {
1804
1861
  errors.push("GEMINI.md file not found");
1805
1862
  return { rules, errors };
@@ -1810,12 +1867,12 @@ async function parseGeminiConfiguration(baseDir = process.cwd()) {
1810
1867
  if (mainRule) {
1811
1868
  rules.push(mainRule);
1812
1869
  }
1813
- const memoryDir = (0, import_node_path18.join)(baseDir, ".gemini", "memories");
1870
+ const memoryDir = (0, import_node_path19.join)(baseDir, ".gemini", "memories");
1814
1871
  if (await fileExists(memoryDir)) {
1815
1872
  const memoryRules = await parseGeminiMemoryFiles(memoryDir);
1816
1873
  rules.push(...memoryRules);
1817
1874
  }
1818
- const settingsPath = (0, import_node_path18.join)(baseDir, ".gemini", "settings.json");
1875
+ const settingsPath = (0, import_node_path19.join)(baseDir, ".gemini", "settings.json");
1819
1876
  if (await fileExists(settingsPath)) {
1820
1877
  const settingsResult = await parseGeminiSettings(settingsPath);
1821
1878
  if (settingsResult.ignorePatterns) {
@@ -1826,7 +1883,7 @@ async function parseGeminiConfiguration(baseDir = process.cwd()) {
1826
1883
  }
1827
1884
  errors.push(...settingsResult.errors);
1828
1885
  }
1829
- const aiexcludePath = (0, import_node_path18.join)(baseDir, ".aiexclude");
1886
+ const aiexcludePath = (0, import_node_path19.join)(baseDir, ".aiexclude");
1830
1887
  if (await fileExists(aiexcludePath)) {
1831
1888
  const aiexcludePatterns = await parseAiexclude(aiexcludePath);
1832
1889
  if (aiexcludePatterns.length > 0) {
@@ -1879,10 +1936,10 @@ async function parseGeminiMemoryFiles(memoryDir) {
1879
1936
  const files = await readdir2(memoryDir);
1880
1937
  for (const file of files) {
1881
1938
  if (file.endsWith(".md")) {
1882
- const filePath = (0, import_node_path18.join)(memoryDir, file);
1939
+ const filePath = (0, import_node_path19.join)(memoryDir, file);
1883
1940
  const content = await readFileContent(filePath);
1884
1941
  if (content.trim()) {
1885
- const filename = (0, import_node_path18.basename)(file, ".md");
1942
+ const filename = (0, import_node_path19.basename)(file, ".md");
1886
1943
  const frontmatter = {
1887
1944
  root: false,
1888
1945
  targets: ["geminicli"],
@@ -1898,7 +1955,7 @@ async function parseGeminiMemoryFiles(memoryDir) {
1898
1955
  }
1899
1956
  }
1900
1957
  }
1901
- } catch (_error) {
1958
+ } catch {
1902
1959
  }
1903
1960
  return rules;
1904
1961
  }
@@ -1925,17 +1982,17 @@ async function parseAiexclude(aiexcludePath) {
1925
1982
  const content = await readFileContent(aiexcludePath);
1926
1983
  const patterns = content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
1927
1984
  return patterns;
1928
- } catch (_error) {
1985
+ } catch {
1929
1986
  return [];
1930
1987
  }
1931
1988
  }
1932
1989
 
1933
1990
  // src/parsers/roo.ts
1934
- var import_node_path19 = require("path");
1991
+ var import_node_path20 = require("path");
1935
1992
  async function parseRooConfiguration(baseDir = process.cwd()) {
1936
1993
  const errors = [];
1937
1994
  const rules = [];
1938
- const rooFilePath = (0, import_node_path19.join)(baseDir, ".roo", "instructions.md");
1995
+ const rooFilePath = (0, import_node_path20.join)(baseDir, ".roo", "instructions.md");
1939
1996
  if (await fileExists(rooFilePath)) {
1940
1997
  try {
1941
1998
  const content = await readFileContent(rooFilePath);
@@ -1958,14 +2015,14 @@ async function parseRooConfiguration(baseDir = process.cwd()) {
1958
2015
  errors.push(`Failed to parse .roo/instructions.md: ${errorMessage}`);
1959
2016
  }
1960
2017
  }
1961
- const rooRulesDir = (0, import_node_path19.join)(baseDir, ".roo", "rules");
2018
+ const rooRulesDir = (0, import_node_path20.join)(baseDir, ".roo", "rules");
1962
2019
  if (await fileExists(rooRulesDir)) {
1963
2020
  try {
1964
2021
  const { readdir: readdir2 } = await import("fs/promises");
1965
2022
  const files = await readdir2(rooRulesDir);
1966
2023
  for (const file of files) {
1967
2024
  if (file.endsWith(".md")) {
1968
- const filePath = (0, import_node_path19.join)(rooRulesDir, file);
2025
+ const filePath = (0, import_node_path20.join)(rooRulesDir, file);
1969
2026
  try {
1970
2027
  const content = await readFileContent(filePath);
1971
2028
  if (content.trim()) {
@@ -2066,7 +2123,7 @@ async function importConfiguration(options) {
2066
2123
  if (rules.length === 0 && !ignorePatterns && !mcpServers) {
2067
2124
  return { success: false, rulesCreated: 0, errors };
2068
2125
  }
2069
- const rulesDirPath = (0, import_node_path20.join)(baseDir, rulesDir);
2126
+ const rulesDirPath = (0, import_node_path21.join)(baseDir, rulesDir);
2070
2127
  try {
2071
2128
  const { mkdir: mkdir3 } = await import("fs/promises");
2072
2129
  await mkdir3(rulesDirPath, { recursive: true });
@@ -2080,7 +2137,7 @@ async function importConfiguration(options) {
2080
2137
  try {
2081
2138
  const baseFilename = `${tool}__${rule.filename}`;
2082
2139
  const filename = await generateUniqueFilename(rulesDirPath, baseFilename);
2083
- const filePath = (0, import_node_path20.join)(rulesDirPath, `${filename}.md`);
2140
+ const filePath = (0, import_node_path21.join)(rulesDirPath, `${filename}.md`);
2084
2141
  const content = generateRuleFileContent(rule);
2085
2142
  await writeFileContent(filePath, content);
2086
2143
  rulesCreated++;
@@ -2095,7 +2152,7 @@ async function importConfiguration(options) {
2095
2152
  let ignoreFileCreated = false;
2096
2153
  if (ignorePatterns && ignorePatterns.length > 0) {
2097
2154
  try {
2098
- const rulesyncignorePath = (0, import_node_path20.join)(baseDir, ".rulesyncignore");
2155
+ const rulesyncignorePath = (0, import_node_path21.join)(baseDir, ".rulesyncignore");
2099
2156
  const ignoreContent = `${ignorePatterns.join("\n")}
2100
2157
  `;
2101
2158
  await writeFileContent(rulesyncignorePath, ignoreContent);
@@ -2111,7 +2168,7 @@ async function importConfiguration(options) {
2111
2168
  let mcpFileCreated = false;
2112
2169
  if (mcpServers && Object.keys(mcpServers).length > 0) {
2113
2170
  try {
2114
- const mcpPath = (0, import_node_path20.join)(baseDir, rulesDir, ".mcp.json");
2171
+ const mcpPath = (0, import_node_path21.join)(baseDir, rulesDir, ".mcp.json");
2115
2172
  const mcpContent = `${JSON.stringify({ mcpServers }, null, 2)}
2116
2173
  `;
2117
2174
  await writeFileContent(mcpPath, mcpContent);
@@ -2139,7 +2196,7 @@ function generateRuleFileContent(rule) {
2139
2196
  async function generateUniqueFilename(rulesDir, baseFilename) {
2140
2197
  let filename = baseFilename;
2141
2198
  let counter = 1;
2142
- while (await fileExists((0, import_node_path20.join)(rulesDir, `${filename}.md`))) {
2199
+ while (await fileExists((0, import_node_path21.join)(rulesDir, `${filename}.md`))) {
2143
2200
  filename = `${baseFilename}-${counter}`;
2144
2201
  counter++;
2145
2202
  }
@@ -2204,7 +2261,7 @@ async function importCommand(options = {}) {
2204
2261
  }
2205
2262
 
2206
2263
  // src/cli/commands/init.ts
2207
- var import_node_path21 = require("path");
2264
+ var import_node_path22 = require("path");
2208
2265
  async function initCommand() {
2209
2266
  const aiRulesDir = ".rulesync";
2210
2267
  console.log("Initializing rulesync...");
@@ -2334,7 +2391,7 @@ globs: ["src/api/**/*.ts", "src/services/**/*.ts", "src/models/**/*.ts"]
2334
2391
  }
2335
2392
  ];
2336
2393
  for (const file of sampleFiles) {
2337
- const filepath = (0, import_node_path21.join)(aiRulesDir, file.filename);
2394
+ const filepath = (0, import_node_path22.join)(aiRulesDir, file.filename);
2338
2395
  if (!await fileExists(filepath)) {
2339
2396
  await writeFileContent(filepath, file.content);
2340
2397
  console.log(`Created ${filepath}`);
@@ -2436,13 +2493,13 @@ async function validateCommand() {
2436
2493
  }
2437
2494
 
2438
2495
  // src/cli/commands/watch.ts
2439
- var import_chokidar = __toESM(require("chokidar"));
2496
+ var import_chokidar = require("chokidar");
2440
2497
  async function watchCommand() {
2441
2498
  const config = getDefaultConfig();
2442
2499
  console.log("\u{1F440} Watching for changes in .rulesync directory...");
2443
2500
  console.log("Press Ctrl+C to stop watching");
2444
2501
  await generateCommand({ verbose: false });
2445
- const watcher = import_chokidar.default.watch(`${config.aiRulesDir}/**/*.md`, {
2502
+ const watcher = (0, import_chokidar.watch)(`${config.aiRulesDir}/**/*.md`, {
2446
2503
  ignoreInitial: true,
2447
2504
  persistent: true
2448
2505
  });
@@ -2477,7 +2534,7 @@ async function watchCommand() {
2477
2534
 
2478
2535
  // src/cli/index.ts
2479
2536
  var program = new import_commander.Command();
2480
- program.name("rulesync").description("Unified AI rules management CLI tool").version("0.36.0");
2537
+ program.name("rulesync").description("Unified AI rules management CLI tool").version("0.37.0");
2481
2538
  program.command("init").description("Initialize rulesync in current directory").action(initCommand);
2482
2539
  program.command("add <filename>").description("Add a new rule file").action(addCommand);
2483
2540
  program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);