rulesync 0.41.0 → 0.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,30 +1,30 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  generateClaudeMcp
4
- } from "./chunk-CUKKFQFO.js";
4
+ } from "./chunk-B3627VQY.js";
5
5
  import {
6
6
  generateClineMcp
7
- } from "./chunk-XN7RGMJW.js";
7
+ } from "./chunk-XHRBWFGI.js";
8
8
  import {
9
9
  generateCopilotMcp
10
- } from "./chunk-SXEFNT27.js";
10
+ } from "./chunk-2FR4Z37J.js";
11
11
  import {
12
12
  generateCursorMcp
13
- } from "./chunk-4SFPBBIB.js";
13
+ } from "./chunk-ZMAL5LIX.js";
14
14
  import {
15
15
  generateGeminiCliMcp
16
- } from "./chunk-QR656A7R.js";
16
+ } from "./chunk-TCK42GOL.js";
17
17
  import {
18
18
  generateRooMcp
19
- } from "./chunk-PPX47BRK.js";
20
- import "./chunk-6YNGMPAL.js";
19
+ } from "./chunk-RL3TE3EZ.js";
20
+ import "./chunk-THWXK5Z2.js";
21
21
 
22
22
  // src/cli/index.ts
23
23
  import { Command } from "commander";
24
24
 
25
25
  // src/cli/commands/add.ts
26
26
  import { mkdir, writeFile } from "fs/promises";
27
- import path from "path";
27
+ import * as path from "path";
28
28
 
29
29
  // src/utils/config.ts
30
30
  function getDefaultConfig() {
@@ -35,12 +35,11 @@ function getDefaultConfig() {
35
35
  cursor: ".cursor/rules",
36
36
  cline: ".clinerules",
37
37
  claudecode: ".",
38
- claude: ".",
39
38
  roo: ".roo/rules",
40
39
  geminicli: ".gemini/memories"
41
40
  },
42
41
  watchEnabled: false,
43
- defaultTargets: ["copilot", "cursor", "cline", "claudecode", "claude", "roo", "geminicli"]
42
+ defaultTargets: ["copilot", "cursor", "cline", "claudecode", "roo", "geminicli"]
44
43
  };
45
44
  }
46
45
  function resolveTargets(targets, config) {
@@ -87,11 +86,19 @@ async function addCommand(filename) {
87
86
  }
88
87
 
89
88
  // src/generators/rules/claudecode.ts
90
- import { join as join3 } from "path";
89
+ import { join as join4 } from "path";
90
+
91
+ // src/types/claudecode.ts
92
+ import { z } from "zod/v4";
93
+ var ClaudeSettingsSchema = z.looseObject({
94
+ permissions: z.looseObject({
95
+ deny: z.array(z.string()).default([])
96
+ }).default({ deny: [] })
97
+ });
91
98
 
92
99
  // src/utils/file.ts
93
100
  import { readdir, rm } from "fs/promises";
94
- import { join as join2 } from "path";
101
+ import { join as join3 } from "path";
95
102
 
96
103
  // src/utils/file-ops.ts
97
104
  import { mkdir as mkdir2, readFile, stat, writeFile as writeFile2 } from "fs/promises";
@@ -120,14 +127,14 @@ async function fileExists(filepath) {
120
127
  }
121
128
 
122
129
  // src/utils/ignore.ts
123
- import { join } from "path";
130
+ import { join as join2 } from "path";
124
131
  import micromatch from "micromatch";
125
132
  var cachedIgnorePatterns = null;
126
133
  async function loadIgnorePatterns(baseDir = process.cwd()) {
127
134
  if (cachedIgnorePatterns) {
128
135
  return cachedIgnorePatterns;
129
136
  }
130
- const ignorePath = join(baseDir, ".rulesyncignore");
137
+ const ignorePath = join2(baseDir, ".rulesyncignore");
131
138
  if (!await fileExists(ignorePath)) {
132
139
  cachedIgnorePatterns = { patterns: [] };
133
140
  return cachedIgnorePatterns;
@@ -174,7 +181,7 @@ function filterIgnoredFiles(files, ignorePatterns) {
174
181
  async function findFiles(dir, extension = ".md", ignorePatterns) {
175
182
  try {
176
183
  const files = await readdir(dir);
177
- const filtered = files.filter((file) => file.endsWith(extension)).map((file) => join2(dir, file));
184
+ const filtered = files.filter((file) => file.endsWith(extension)).map((file) => join3(dir, file));
178
185
  if (ignorePatterns && ignorePatterns.length > 0) {
179
186
  return filterIgnoredFiles(filtered, ignorePatterns);
180
187
  }
@@ -223,23 +230,23 @@ async function generateClaudecodeConfig(rules, config, baseDir) {
223
230
  const rootRules = rules.filter((r) => r.frontmatter.root === true);
224
231
  const detailRules = rules.filter((r) => r.frontmatter.root === false);
225
232
  const claudeMdContent = generateClaudeMarkdown(rootRules, detailRules);
226
- const claudeOutputDir = baseDir ? join3(baseDir, config.outputPaths.claudecode) : config.outputPaths.claudecode;
233
+ const claudeOutputDir = baseDir ? join4(baseDir, config.outputPaths.claudecode) : config.outputPaths.claudecode;
227
234
  outputs.push({
228
235
  tool: "claudecode",
229
- filepath: join3(claudeOutputDir, "CLAUDE.md"),
236
+ filepath: join4(claudeOutputDir, "CLAUDE.md"),
230
237
  content: claudeMdContent
231
238
  });
232
239
  for (const rule of detailRules) {
233
240
  const memoryContent = generateMemoryFile(rule);
234
241
  outputs.push({
235
242
  tool: "claudecode",
236
- filepath: join3(claudeOutputDir, ".claude", "memories", `${rule.filename}.md`),
243
+ filepath: join4(claudeOutputDir, ".claude", "memories", `${rule.filename}.md`),
237
244
  content: memoryContent
238
245
  });
239
246
  }
240
247
  const ignorePatterns = await loadIgnorePatterns(baseDir);
241
248
  if (ignorePatterns.patterns.length > 0) {
242
- const settingsPath = baseDir ? join3(baseDir, ".claude", "settings.json") : join3(".claude", "settings.json");
249
+ const settingsPath = baseDir ? join4(baseDir, ".claude", "settings.json") : join4(".claude", "settings.json");
243
250
  await updateClaudeSettings(settingsPath, ignorePatterns.patterns);
244
251
  }
245
252
  return outputs;
@@ -271,51 +278,46 @@ function generateMemoryFile(rule) {
271
278
  return rule.content.trim();
272
279
  }
273
280
  async function updateClaudeSettings(settingsPath, ignorePatterns) {
274
- let settings = {};
281
+ let rawSettings = {};
275
282
  if (await fileExists(settingsPath)) {
276
283
  try {
277
284
  const content = await readFileContent(settingsPath);
278
- settings = JSON.parse(content);
285
+ rawSettings = JSON.parse(content);
279
286
  } catch {
280
287
  console.warn(`Failed to parse existing ${settingsPath}, creating new settings`);
281
- settings = {};
288
+ rawSettings = {};
282
289
  }
283
290
  }
284
- if (typeof settings !== "object" || settings === null) {
285
- settings = {};
286
- }
287
- const settingsObj = settings;
288
- if (!settingsObj.permissions || typeof settingsObj.permissions !== "object" || settingsObj.permissions === null) {
289
- settingsObj.permissions = {};
291
+ const parseResult = ClaudeSettingsSchema.safeParse(rawSettings);
292
+ const settings = parseResult.success ? parseResult.data : ClaudeSettingsSchema.parse({});
293
+ const readDenyRules = ignorePatterns.map((pattern) => `Read(${pattern})`);
294
+ if (!settings.permissions) {
295
+ settings.permissions = { deny: [] };
290
296
  }
291
- const permissions = settingsObj.permissions;
292
- if (!Array.isArray(permissions.deny)) {
293
- permissions.deny = [];
297
+ if (!Array.isArray(settings.permissions.deny)) {
298
+ settings.permissions.deny = [];
294
299
  }
295
- const readDenyRules = ignorePatterns.map((pattern) => `Read(${pattern})`);
296
- const denyArray = permissions.deny;
297
- const filteredDeny = denyArray.filter((rule) => {
298
- if (typeof rule !== "string") return false;
300
+ const filteredDeny = settings.permissions.deny.filter((rule) => {
299
301
  if (!rule.startsWith("Read(")) return true;
300
302
  const match = rule.match(/^Read\((.*)\)$/);
301
303
  if (!match) return true;
302
304
  return !ignorePatterns.includes(match[1] ?? "");
303
305
  });
304
306
  filteredDeny.push(...readDenyRules);
305
- permissions.deny = [...new Set(filteredDeny)];
306
- const jsonContent = JSON.stringify(settingsObj, null, 2);
307
+ settings.permissions.deny = Array.from(new Set(filteredDeny));
308
+ const jsonContent = JSON.stringify(settings, null, 2);
307
309
  await writeFileContent(settingsPath, jsonContent);
308
310
  console.log(`\u2705 Updated Claude Code settings: ${settingsPath}`);
309
311
  }
310
312
 
311
313
  // src/generators/rules/cline.ts
312
- import { join as join4 } from "path";
314
+ import { join as join5 } from "path";
313
315
  async function generateClineConfig(rules, config, baseDir) {
314
316
  const outputs = [];
315
317
  for (const rule of rules) {
316
318
  const content = generateClineMarkdown(rule);
317
- const outputDir = baseDir ? join4(baseDir, config.outputPaths.cline) : config.outputPaths.cline;
318
- const filepath = join4(outputDir, `${rule.filename}.md`);
319
+ const outputDir = baseDir ? join5(baseDir, config.outputPaths.cline) : config.outputPaths.cline;
320
+ const filepath = join5(outputDir, `${rule.filename}.md`);
319
321
  outputs.push({
320
322
  tool: "cline",
321
323
  filepath,
@@ -324,7 +326,7 @@ async function generateClineConfig(rules, config, baseDir) {
324
326
  }
325
327
  const ignorePatterns = await loadIgnorePatterns(baseDir);
326
328
  if (ignorePatterns.patterns.length > 0) {
327
- const clineIgnorePath = baseDir ? join4(baseDir, ".clineignore") : ".clineignore";
329
+ const clineIgnorePath = baseDir ? join5(baseDir, ".clineignore") : ".clineignore";
328
330
  const clineIgnoreContent = generateClineIgnore(ignorePatterns.patterns);
329
331
  outputs.push({
330
332
  tool: "cline",
@@ -348,14 +350,14 @@ function generateClineIgnore(patterns) {
348
350
  }
349
351
 
350
352
  // src/generators/rules/copilot.ts
351
- import { join as join5 } from "path";
353
+ import { join as join6 } from "path";
352
354
  async function generateCopilotConfig(rules, config, baseDir) {
353
355
  const outputs = [];
354
356
  for (const rule of rules) {
355
357
  const content = generateCopilotMarkdown(rule);
356
358
  const baseFilename = rule.filename.replace(/\.md$/, "");
357
- const outputDir = baseDir ? join5(baseDir, config.outputPaths.copilot) : config.outputPaths.copilot;
358
- const filepath = join5(outputDir, `${baseFilename}.instructions.md`);
359
+ const outputDir = baseDir ? join6(baseDir, config.outputPaths.copilot) : config.outputPaths.copilot;
360
+ const filepath = join6(outputDir, `${baseFilename}.instructions.md`);
359
361
  outputs.push({
360
362
  tool: "copilot",
361
363
  filepath,
@@ -364,7 +366,7 @@ async function generateCopilotConfig(rules, config, baseDir) {
364
366
  }
365
367
  const ignorePatterns = await loadIgnorePatterns(baseDir);
366
368
  if (ignorePatterns.patterns.length > 0) {
367
- const copilotIgnorePath = baseDir ? join5(baseDir, ".copilotignore") : ".copilotignore";
369
+ const copilotIgnorePath = baseDir ? join6(baseDir, ".copilotignore") : ".copilotignore";
368
370
  const copilotIgnoreContent = generateCopilotIgnore(ignorePatterns.patterns);
369
371
  outputs.push({
370
372
  tool: "copilot",
@@ -400,13 +402,13 @@ function generateCopilotIgnore(patterns) {
400
402
  }
401
403
 
402
404
  // src/generators/rules/cursor.ts
403
- import { join as join6 } from "path";
405
+ import { join as join7 } from "path";
404
406
  async function generateCursorConfig(rules, config, baseDir) {
405
407
  const outputs = [];
406
408
  for (const rule of rules) {
407
409
  const content = generateCursorMarkdown(rule);
408
- const outputDir = baseDir ? join6(baseDir, config.outputPaths.cursor) : config.outputPaths.cursor;
409
- const filepath = join6(outputDir, `${rule.filename}.mdc`);
410
+ const outputDir = baseDir ? join7(baseDir, config.outputPaths.cursor) : config.outputPaths.cursor;
411
+ const filepath = join7(outputDir, `${rule.filename}.mdc`);
410
412
  outputs.push({
411
413
  tool: "cursor",
412
414
  filepath,
@@ -415,7 +417,7 @@ async function generateCursorConfig(rules, config, baseDir) {
415
417
  }
416
418
  const ignorePatterns = await loadIgnorePatterns(baseDir);
417
419
  if (ignorePatterns.patterns.length > 0) {
418
- const cursorIgnorePath = baseDir ? join6(baseDir, ".cursorignore") : ".cursorignore";
420
+ const cursorIgnorePath = baseDir ? join7(baseDir, ".cursorignore") : ".cursorignore";
419
421
  const cursorIgnoreContent = generateCursorIgnore(ignorePatterns.patterns);
420
422
  outputs.push({
421
423
  tool: "cursor",
@@ -488,15 +490,15 @@ function generateCursorIgnore(patterns) {
488
490
  }
489
491
 
490
492
  // src/generators/rules/geminicli.ts
491
- import { join as join7 } from "path";
493
+ import { join as join8 } from "path";
492
494
  async function generateGeminiConfig(rules, config, baseDir) {
493
495
  const outputs = [];
494
496
  const rootRule = rules.find((rule) => rule.frontmatter.root === true);
495
497
  const memoryRules = rules.filter((rule) => rule.frontmatter.root === false);
496
498
  for (const rule of memoryRules) {
497
499
  const content = generateGeminiMemoryMarkdown(rule);
498
- const outputDir = baseDir ? join7(baseDir, config.outputPaths.geminicli) : config.outputPaths.geminicli;
499
- const filepath = join7(outputDir, `${rule.filename}.md`);
500
+ const outputDir = baseDir ? join8(baseDir, config.outputPaths.geminicli) : config.outputPaths.geminicli;
501
+ const filepath = join8(outputDir, `${rule.filename}.md`);
500
502
  outputs.push({
501
503
  tool: "geminicli",
502
504
  filepath,
@@ -504,7 +506,7 @@ async function generateGeminiConfig(rules, config, baseDir) {
504
506
  });
505
507
  }
506
508
  const rootContent = generateGeminiRootMarkdown(rootRule, memoryRules, baseDir);
507
- const rootFilepath = baseDir ? join7(baseDir, "GEMINI.md") : "GEMINI.md";
509
+ const rootFilepath = baseDir ? join8(baseDir, "GEMINI.md") : "GEMINI.md";
508
510
  outputs.push({
509
511
  tool: "geminicli",
510
512
  filepath: rootFilepath,
@@ -512,7 +514,7 @@ async function generateGeminiConfig(rules, config, baseDir) {
512
514
  });
513
515
  const ignorePatterns = await loadIgnorePatterns(baseDir);
514
516
  if (ignorePatterns.patterns.length > 0) {
515
- const aiexcludePath = baseDir ? join7(baseDir, ".aiexclude") : ".aiexclude";
517
+ const aiexcludePath = baseDir ? join8(baseDir, ".aiexclude") : ".aiexclude";
516
518
  const aiexcludeContent = generateAiexclude(ignorePatterns.patterns);
517
519
  outputs.push({
518
520
  tool: "geminicli",
@@ -560,13 +562,13 @@ function generateAiexclude(patterns) {
560
562
  }
561
563
 
562
564
  // src/generators/rules/roo.ts
563
- import { join as join8 } from "path";
565
+ import { join as join9 } from "path";
564
566
  async function generateRooConfig(rules, config, baseDir) {
565
567
  const outputs = [];
566
568
  for (const rule of rules) {
567
569
  const content = generateRooMarkdown(rule);
568
- const outputDir = baseDir ? join8(baseDir, config.outputPaths.roo) : config.outputPaths.roo;
569
- const filepath = join8(outputDir, `${rule.filename}.md`);
570
+ const outputDir = baseDir ? join9(baseDir, config.outputPaths.roo) : config.outputPaths.roo;
571
+ const filepath = join9(outputDir, `${rule.filename}.md`);
570
572
  outputs.push({
571
573
  tool: "roo",
572
574
  filepath,
@@ -575,7 +577,7 @@ async function generateRooConfig(rules, config, baseDir) {
575
577
  }
576
578
  const ignorePatterns = await loadIgnorePatterns(baseDir);
577
579
  if (ignorePatterns.patterns.length > 0) {
578
- const rooIgnorePath = baseDir ? join8(baseDir, ".rooignore") : ".rooignore";
580
+ const rooIgnorePath = baseDir ? join9(baseDir, ".rooignore") : ".rooignore";
579
581
  const rooIgnoreContent = generateRooIgnore(ignorePatterns.patterns);
580
582
  outputs.push({
581
583
  tool: "roo",
@@ -814,12 +816,11 @@ async function validateRule(rule) {
814
816
  }
815
817
 
816
818
  // src/core/mcp-generator.ts
817
- import os from "os";
818
- import path3 from "path";
819
+ import * as path3 from "path";
819
820
 
820
821
  // src/core/mcp-parser.ts
821
- import fs from "fs";
822
- import path2 from "path";
822
+ import * as fs from "fs";
823
+ import * as path2 from "path";
823
824
  function parseMcpConfig(projectRoot) {
824
825
  const mcpPath = path2.join(projectRoot, ".rulesync", ".mcp.json");
825
826
  if (!fs.existsSync(mcpPath)) {
@@ -858,7 +859,7 @@ async function generateMcpConfigs(projectRoot, baseDir) {
858
859
  {
859
860
  tool: "claude-project",
860
861
  path: path3.join(targetRoot, ".mcp.json"),
861
- generate: () => generateClaudeMcp(config, "project")
862
+ generate: () => generateClaudeMcp(config)
862
863
  },
863
864
  {
864
865
  tool: "copilot-editor",
@@ -868,43 +869,24 @@ async function generateMcpConfigs(projectRoot, baseDir) {
868
869
  {
869
870
  tool: "cursor-project",
870
871
  path: path3.join(targetRoot, ".cursor", "mcp.json"),
871
- generate: () => generateCursorMcp(config, "project")
872
+ generate: () => generateCursorMcp(config)
872
873
  },
873
874
  {
874
875
  tool: "cline-project",
875
876
  path: path3.join(targetRoot, ".cline", "mcp.json"),
876
- generate: () => generateClineMcp(config, "project")
877
+ generate: () => generateClineMcp(config)
877
878
  },
878
879
  {
879
880
  tool: "gemini-project",
880
881
  path: path3.join(targetRoot, ".gemini", "settings.json"),
881
- generate: () => generateGeminiCliMcp(config, "project")
882
+ generate: () => generateGeminiCliMcp(config)
882
883
  },
883
884
  {
884
885
  tool: "roo-project",
885
886
  path: path3.join(targetRoot, ".roo", "mcp.json"),
886
- generate: () => generateRooMcp(config, "project")
887
+ generate: () => generateRooMcp(config)
887
888
  }
888
889
  ];
889
- if (!baseDir) {
890
- generators.push(
891
- {
892
- tool: "claude-global",
893
- path: path3.join(os.homedir(), ".claude", "settings.json"),
894
- generate: () => generateClaudeMcp(config, "global")
895
- },
896
- {
897
- tool: "cursor-global",
898
- path: path3.join(os.homedir(), ".cursor", "mcp.json"),
899
- generate: () => generateCursorMcp(config, "global")
900
- },
901
- {
902
- tool: "gemini-global",
903
- path: path3.join(os.homedir(), ".gemini", "settings.json"),
904
- generate: () => generateGeminiCliMcp(config, "global")
905
- }
906
- );
907
- }
908
890
  for (const generator of generators) {
909
891
  try {
910
892
  const content = generator.generate();
@@ -1058,10 +1040,10 @@ Generating configurations for base directory: ${baseDir}`);
1058
1040
  }
1059
1041
 
1060
1042
  // src/cli/commands/gitignore.ts
1061
- import { existsSync, readFileSync, writeFileSync } from "fs";
1062
- import { join as join9 } from "path";
1043
+ import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync } from "fs";
1044
+ import { join as join12 } from "path";
1063
1045
  var gitignoreCommand = async () => {
1064
- const gitignorePath = join9(process.cwd(), ".gitignore");
1046
+ const gitignorePath = join12(process.cwd(), ".gitignore");
1065
1047
  const rulesFilesToIgnore = [
1066
1048
  "# Generated by rulesync - AI tool configuration files",
1067
1049
  "**/.github/copilot-instructions.md",
@@ -1087,8 +1069,8 @@ var gitignoreCommand = async () => {
1087
1069
  "**/.roo/mcp.json"
1088
1070
  ];
1089
1071
  let gitignoreContent = "";
1090
- if (existsSync(gitignorePath)) {
1091
- gitignoreContent = readFileSync(gitignorePath, "utf-8");
1072
+ if (existsSync2(gitignorePath)) {
1073
+ gitignoreContent = readFileSync2(gitignorePath, "utf-8");
1092
1074
  }
1093
1075
  const linesToAdd = [];
1094
1076
  for (const rule of rulesFilesToIgnore) {
@@ -1115,17 +1097,17 @@ ${linesToAdd.join("\n")}
1115
1097
  };
1116
1098
 
1117
1099
  // src/core/importer.ts
1118
- import { join as join16 } from "path";
1100
+ import { join as join19 } from "path";
1119
1101
  import matter4 from "gray-matter";
1120
1102
 
1121
1103
  // src/parsers/claudecode.ts
1122
- import { basename as basename2, join as join10 } from "path";
1104
+ import { basename as basename2, join as join13 } from "path";
1123
1105
  async function parseClaudeConfiguration(baseDir = process.cwd()) {
1124
1106
  const errors = [];
1125
1107
  const rules = [];
1126
1108
  let ignorePatterns;
1127
1109
  let mcpServers;
1128
- const claudeFilePath = join10(baseDir, "CLAUDE.md");
1110
+ const claudeFilePath = join13(baseDir, "CLAUDE.md");
1129
1111
  if (!await fileExists(claudeFilePath)) {
1130
1112
  errors.push("CLAUDE.md file not found");
1131
1113
  return { rules, errors };
@@ -1136,12 +1118,12 @@ async function parseClaudeConfiguration(baseDir = process.cwd()) {
1136
1118
  if (mainRule) {
1137
1119
  rules.push(mainRule);
1138
1120
  }
1139
- const memoryDir = join10(baseDir, ".claude", "memories");
1121
+ const memoryDir = join13(baseDir, ".claude", "memories");
1140
1122
  if (await fileExists(memoryDir)) {
1141
1123
  const memoryRules = await parseClaudeMemoryFiles(memoryDir);
1142
1124
  rules.push(...memoryRules);
1143
1125
  }
1144
- const settingsPath = join10(baseDir, ".claude", "settings.json");
1126
+ const settingsPath = join13(baseDir, ".claude", "settings.json");
1145
1127
  if (await fileExists(settingsPath)) {
1146
1128
  const settingsResult = await parseClaudeSettings(settingsPath);
1147
1129
  if (settingsResult.ignorePatterns) {
@@ -1198,7 +1180,7 @@ async function parseClaudeMemoryFiles(memoryDir) {
1198
1180
  const files = await readdir2(memoryDir);
1199
1181
  for (const file of files) {
1200
1182
  if (file.endsWith(".md")) {
1201
- const filePath = join10(memoryDir, file);
1183
+ const filePath = join13(memoryDir, file);
1202
1184
  const content = await readFileContent(filePath);
1203
1185
  if (content.trim()) {
1204
1186
  const filename = basename2(file, ".md");
@@ -1260,11 +1242,11 @@ async function parseClaudeSettings(settingsPath) {
1260
1242
  }
1261
1243
 
1262
1244
  // src/parsers/cline.ts
1263
- import { join as join11 } from "path";
1245
+ import { join as join14 } from "path";
1264
1246
  async function parseClineConfiguration(baseDir = process.cwd()) {
1265
1247
  const errors = [];
1266
1248
  const rules = [];
1267
- const clineFilePath = join11(baseDir, ".cline", "instructions.md");
1249
+ const clineFilePath = join14(baseDir, ".cline", "instructions.md");
1268
1250
  if (await fileExists(clineFilePath)) {
1269
1251
  try {
1270
1252
  const content = await readFileContent(clineFilePath);
@@ -1287,14 +1269,14 @@ async function parseClineConfiguration(baseDir = process.cwd()) {
1287
1269
  errors.push(`Failed to parse .cline/instructions.md: ${errorMessage}`);
1288
1270
  }
1289
1271
  }
1290
- const clinerulesDirPath = join11(baseDir, ".clinerules");
1272
+ const clinerulesDirPath = join14(baseDir, ".clinerules");
1291
1273
  if (await fileExists(clinerulesDirPath)) {
1292
1274
  try {
1293
1275
  const { readdir: readdir2 } = await import("fs/promises");
1294
1276
  const files = await readdir2(clinerulesDirPath);
1295
1277
  for (const file of files) {
1296
1278
  if (file.endsWith(".md")) {
1297
- const filePath = join11(clinerulesDirPath, file);
1279
+ const filePath = join14(clinerulesDirPath, file);
1298
1280
  try {
1299
1281
  const content = await readFileContent(filePath);
1300
1282
  if (content.trim()) {
@@ -1330,12 +1312,12 @@ async function parseClineConfiguration(baseDir = process.cwd()) {
1330
1312
  }
1331
1313
 
1332
1314
  // src/parsers/copilot.ts
1333
- import { basename as basename3, join as join12 } from "path";
1315
+ import { basename as basename3, join as join15 } from "path";
1334
1316
  import matter2 from "gray-matter";
1335
1317
  async function parseCopilotConfiguration(baseDir = process.cwd()) {
1336
1318
  const errors = [];
1337
1319
  const rules = [];
1338
- const copilotFilePath = join12(baseDir, ".github", "copilot-instructions.md");
1320
+ const copilotFilePath = join15(baseDir, ".github", "copilot-instructions.md");
1339
1321
  if (await fileExists(copilotFilePath)) {
1340
1322
  try {
1341
1323
  const rawContent = await readFileContent(copilotFilePath);
@@ -1360,14 +1342,14 @@ async function parseCopilotConfiguration(baseDir = process.cwd()) {
1360
1342
  errors.push(`Failed to parse copilot-instructions.md: ${errorMessage}`);
1361
1343
  }
1362
1344
  }
1363
- const instructionsDir = join12(baseDir, ".github", "instructions");
1345
+ const instructionsDir = join15(baseDir, ".github", "instructions");
1364
1346
  if (await fileExists(instructionsDir)) {
1365
1347
  try {
1366
1348
  const { readdir: readdir2 } = await import("fs/promises");
1367
1349
  const files = await readdir2(instructionsDir);
1368
1350
  for (const file of files) {
1369
1351
  if (file.endsWith(".instructions.md")) {
1370
- const filePath = join12(instructionsDir, file);
1352
+ const filePath = join15(instructionsDir, file);
1371
1353
  const rawContent = await readFileContent(filePath);
1372
1354
  const parsed = matter2(rawContent);
1373
1355
  const content = parsed.content.trim();
@@ -1402,7 +1384,7 @@ async function parseCopilotConfiguration(baseDir = process.cwd()) {
1402
1384
  }
1403
1385
 
1404
1386
  // src/parsers/cursor.ts
1405
- import { basename as basename4, join as join13 } from "path";
1387
+ import { basename as basename4, join as join16 } from "path";
1406
1388
  import matter3 from "gray-matter";
1407
1389
  import { DEFAULT_SCHEMA, FAILSAFE_SCHEMA, load } from "js-yaml";
1408
1390
  var customMatterOptions = {
@@ -1507,7 +1489,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
1507
1489
  const rules = [];
1508
1490
  let ignorePatterns;
1509
1491
  let mcpServers;
1510
- const cursorFilePath = join13(baseDir, ".cursorrules");
1492
+ const cursorFilePath = join16(baseDir, ".cursorrules");
1511
1493
  if (await fileExists(cursorFilePath)) {
1512
1494
  try {
1513
1495
  const rawContent = await readFileContent(cursorFilePath);
@@ -1528,14 +1510,14 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
1528
1510
  errors.push(`Failed to parse .cursorrules file: ${errorMessage}`);
1529
1511
  }
1530
1512
  }
1531
- const cursorRulesDir = join13(baseDir, ".cursor", "rules");
1513
+ const cursorRulesDir = join16(baseDir, ".cursor", "rules");
1532
1514
  if (await fileExists(cursorRulesDir)) {
1533
1515
  try {
1534
1516
  const { readdir: readdir2 } = await import("fs/promises");
1535
1517
  const files = await readdir2(cursorRulesDir);
1536
1518
  for (const file of files) {
1537
1519
  if (file.endsWith(".mdc")) {
1538
- const filePath = join13(cursorRulesDir, file);
1520
+ const filePath = join16(cursorRulesDir, file);
1539
1521
  try {
1540
1522
  const rawContent = await readFileContent(filePath);
1541
1523
  const parsed = matter3(rawContent, customMatterOptions);
@@ -1564,7 +1546,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
1564
1546
  if (rules.length === 0) {
1565
1547
  errors.push("No Cursor configuration files found (.cursorrules or .cursor/rules/*.mdc)");
1566
1548
  }
1567
- const cursorIgnorePath = join13(baseDir, ".cursorignore");
1549
+ const cursorIgnorePath = join16(baseDir, ".cursorignore");
1568
1550
  if (await fileExists(cursorIgnorePath)) {
1569
1551
  try {
1570
1552
  const content = await readFileContent(cursorIgnorePath);
@@ -1577,7 +1559,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
1577
1559
  errors.push(`Failed to parse .cursorignore: ${errorMessage}`);
1578
1560
  }
1579
1561
  }
1580
- const cursorMcpPath = join13(baseDir, ".cursor", "mcp.json");
1562
+ const cursorMcpPath = join16(baseDir, ".cursor", "mcp.json");
1581
1563
  if (await fileExists(cursorMcpPath)) {
1582
1564
  try {
1583
1565
  const content = await readFileContent(cursorMcpPath);
@@ -1599,13 +1581,13 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
1599
1581
  }
1600
1582
 
1601
1583
  // src/parsers/geminicli.ts
1602
- import { basename as basename5, join as join14 } from "path";
1584
+ import { basename as basename5, join as join17 } from "path";
1603
1585
  async function parseGeminiConfiguration(baseDir = process.cwd()) {
1604
1586
  const errors = [];
1605
1587
  const rules = [];
1606
1588
  let ignorePatterns;
1607
1589
  let mcpServers;
1608
- const geminiFilePath = join14(baseDir, "GEMINI.md");
1590
+ const geminiFilePath = join17(baseDir, "GEMINI.md");
1609
1591
  if (!await fileExists(geminiFilePath)) {
1610
1592
  errors.push("GEMINI.md file not found");
1611
1593
  return { rules, errors };
@@ -1616,12 +1598,12 @@ async function parseGeminiConfiguration(baseDir = process.cwd()) {
1616
1598
  if (mainRule) {
1617
1599
  rules.push(mainRule);
1618
1600
  }
1619
- const memoryDir = join14(baseDir, ".gemini", "memories");
1601
+ const memoryDir = join17(baseDir, ".gemini", "memories");
1620
1602
  if (await fileExists(memoryDir)) {
1621
1603
  const memoryRules = await parseGeminiMemoryFiles(memoryDir);
1622
1604
  rules.push(...memoryRules);
1623
1605
  }
1624
- const settingsPath = join14(baseDir, ".gemini", "settings.json");
1606
+ const settingsPath = join17(baseDir, ".gemini", "settings.json");
1625
1607
  if (await fileExists(settingsPath)) {
1626
1608
  const settingsResult = await parseGeminiSettings(settingsPath);
1627
1609
  if (settingsResult.ignorePatterns) {
@@ -1632,7 +1614,7 @@ async function parseGeminiConfiguration(baseDir = process.cwd()) {
1632
1614
  }
1633
1615
  errors.push(...settingsResult.errors);
1634
1616
  }
1635
- const aiexcludePath = join14(baseDir, ".aiexclude");
1617
+ const aiexcludePath = join17(baseDir, ".aiexclude");
1636
1618
  if (await fileExists(aiexcludePath)) {
1637
1619
  const aiexcludePatterns = await parseAiexclude(aiexcludePath);
1638
1620
  if (aiexcludePatterns.length > 0) {
@@ -1685,7 +1667,7 @@ async function parseGeminiMemoryFiles(memoryDir) {
1685
1667
  const files = await readdir2(memoryDir);
1686
1668
  for (const file of files) {
1687
1669
  if (file.endsWith(".md")) {
1688
- const filePath = join14(memoryDir, file);
1670
+ const filePath = join17(memoryDir, file);
1689
1671
  const content = await readFileContent(filePath);
1690
1672
  if (content.trim()) {
1691
1673
  const filename = basename5(file, ".md");
@@ -1737,11 +1719,11 @@ async function parseAiexclude(aiexcludePath) {
1737
1719
  }
1738
1720
 
1739
1721
  // src/parsers/roo.ts
1740
- import { join as join15 } from "path";
1722
+ import { join as join18 } from "path";
1741
1723
  async function parseRooConfiguration(baseDir = process.cwd()) {
1742
1724
  const errors = [];
1743
1725
  const rules = [];
1744
- const rooFilePath = join15(baseDir, ".roo", "instructions.md");
1726
+ const rooFilePath = join18(baseDir, ".roo", "instructions.md");
1745
1727
  if (await fileExists(rooFilePath)) {
1746
1728
  try {
1747
1729
  const content = await readFileContent(rooFilePath);
@@ -1764,14 +1746,14 @@ async function parseRooConfiguration(baseDir = process.cwd()) {
1764
1746
  errors.push(`Failed to parse .roo/instructions.md: ${errorMessage}`);
1765
1747
  }
1766
1748
  }
1767
- const rooRulesDir = join15(baseDir, ".roo", "rules");
1749
+ const rooRulesDir = join18(baseDir, ".roo", "rules");
1768
1750
  if (await fileExists(rooRulesDir)) {
1769
1751
  try {
1770
1752
  const { readdir: readdir2 } = await import("fs/promises");
1771
1753
  const files = await readdir2(rooRulesDir);
1772
1754
  for (const file of files) {
1773
1755
  if (file.endsWith(".md")) {
1774
- const filePath = join15(rooRulesDir, file);
1756
+ const filePath = join18(rooRulesDir, file);
1775
1757
  try {
1776
1758
  const content = await readFileContent(filePath);
1777
1759
  if (content.trim()) {
@@ -1872,7 +1854,7 @@ async function importConfiguration(options) {
1872
1854
  if (rules.length === 0 && !ignorePatterns && !mcpServers) {
1873
1855
  return { success: false, rulesCreated: 0, errors };
1874
1856
  }
1875
- const rulesDirPath = join16(baseDir, rulesDir);
1857
+ const rulesDirPath = join19(baseDir, rulesDir);
1876
1858
  try {
1877
1859
  const { mkdir: mkdir3 } = await import("fs/promises");
1878
1860
  await mkdir3(rulesDirPath, { recursive: true });
@@ -1886,7 +1868,7 @@ async function importConfiguration(options) {
1886
1868
  try {
1887
1869
  const baseFilename = `${tool}__${rule.filename}`;
1888
1870
  const filename = await generateUniqueFilename(rulesDirPath, baseFilename);
1889
- const filePath = join16(rulesDirPath, `${filename}.md`);
1871
+ const filePath = join19(rulesDirPath, `${filename}.md`);
1890
1872
  const content = generateRuleFileContent(rule);
1891
1873
  await writeFileContent(filePath, content);
1892
1874
  rulesCreated++;
@@ -1901,7 +1883,7 @@ async function importConfiguration(options) {
1901
1883
  let ignoreFileCreated = false;
1902
1884
  if (ignorePatterns && ignorePatterns.length > 0) {
1903
1885
  try {
1904
- const rulesyncignorePath = join16(baseDir, ".rulesyncignore");
1886
+ const rulesyncignorePath = join19(baseDir, ".rulesyncignore");
1905
1887
  const ignoreContent = `${ignorePatterns.join("\n")}
1906
1888
  `;
1907
1889
  await writeFileContent(rulesyncignorePath, ignoreContent);
@@ -1917,7 +1899,7 @@ async function importConfiguration(options) {
1917
1899
  let mcpFileCreated = false;
1918
1900
  if (mcpServers && Object.keys(mcpServers).length > 0) {
1919
1901
  try {
1920
- const mcpPath = join16(baseDir, rulesDir, ".mcp.json");
1902
+ const mcpPath = join19(baseDir, rulesDir, ".mcp.json");
1921
1903
  const mcpContent = `${JSON.stringify({ mcpServers }, null, 2)}
1922
1904
  `;
1923
1905
  await writeFileContent(mcpPath, mcpContent);
@@ -1945,7 +1927,7 @@ function generateRuleFileContent(rule) {
1945
1927
  async function generateUniqueFilename(rulesDir, baseFilename) {
1946
1928
  let filename = baseFilename;
1947
1929
  let counter = 1;
1948
- while (await fileExists(join16(rulesDir, `${filename}.md`))) {
1930
+ while (await fileExists(join19(rulesDir, `${filename}.md`))) {
1949
1931
  filename = `${baseFilename}-${counter}`;
1950
1932
  counter++;
1951
1933
  }
@@ -2010,7 +1992,7 @@ async function importCommand(options = {}) {
2010
1992
  }
2011
1993
 
2012
1994
  // src/cli/commands/init.ts
2013
- import { join as join17 } from "path";
1995
+ import { join as join20 } from "path";
2014
1996
  async function initCommand() {
2015
1997
  const aiRulesDir = ".rulesync";
2016
1998
  console.log("Initializing rulesync...");
@@ -2140,7 +2122,7 @@ globs: ["src/api/**/*.ts", "src/services/**/*.ts", "src/models/**/*.ts"]
2140
2122
  }
2141
2123
  ];
2142
2124
  for (const file of sampleFiles) {
2143
- const filepath = join17(aiRulesDir, file.filename);
2125
+ const filepath = join20(aiRulesDir, file.filename);
2144
2126
  if (!await fileExists(filepath)) {
2145
2127
  await writeFileContent(filepath, file.content);
2146
2128
  console.log(`Created ${filepath}`);
@@ -2283,7 +2265,7 @@ async function watchCommand() {
2283
2265
 
2284
2266
  // src/cli/index.ts
2285
2267
  var program = new Command();
2286
- program.name("rulesync").description("Unified AI rules management CLI tool").version("0.41.0");
2268
+ program.name("rulesync").description("Unified AI rules management CLI tool").version("0.43.0");
2287
2269
  program.command("init").description("Initialize rulesync in current directory").action(initCommand);
2288
2270
  program.command("add <filename>").description("Add a new rule file").action(addCommand);
2289
2271
  program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);