rulesync 0.2.0 → 0.4.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,196 +26,178 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
26
  // src/cli/index.ts
27
27
  var import_commander = require("commander");
28
28
 
29
- // src/generators/cline.ts
29
+ // src/generators/claude.ts
30
30
  var import_node_path = require("path");
31
- async function generateClineConfig(rules, config) {
32
- const sortedRules = rules.sort((a, b) => {
33
- if (a.frontmatter.priority !== b.frontmatter.priority) {
34
- return a.frontmatter.priority === "high" ? -1 : 1;
35
- }
36
- return a.filename.localeCompare(b.filename);
31
+ async function generateClaudeConfig(rules, config) {
32
+ const outputs = [];
33
+ const overviewRules = rules.filter((r) => r.frontmatter.ruleLevel === "overview");
34
+ const detailRules = rules.filter((r) => r.frontmatter.ruleLevel === "detail");
35
+ const claudeMdContent = generateClaudeMarkdown(overviewRules, detailRules);
36
+ outputs.push({
37
+ tool: "claude",
38
+ filepath: (0, import_node_path.join)(config.outputPaths.claude, "CLAUDE.md"),
39
+ content: claudeMdContent
37
40
  });
38
- const content = generateClineMarkdown(sortedRules);
39
- const filepath = (0, import_node_path.join)(config.outputPaths.cline, "01-ai-rules.md");
40
- return {
41
- tool: "cline",
42
- filepath,
43
- content
44
- };
41
+ for (const rule of detailRules) {
42
+ const memoryContent = generateMemoryFile(rule);
43
+ outputs.push({
44
+ tool: "claude",
45
+ filepath: (0, import_node_path.join)(config.outputPaths.claude, ".claude", "memories", `${rule.filename}.md`),
46
+ content: memoryContent
47
+ });
48
+ }
49
+ return outputs;
45
50
  }
46
- function generateClineMarkdown(rules) {
51
+ function generateClaudeMarkdown(overviewRules, detailRules) {
47
52
  const lines = [];
48
- lines.push("# Cline AI Assistant Rules");
49
- lines.push("");
50
- lines.push("Configuration rules for Cline AI Assistant. Generated from ai-rules configuration.");
51
- lines.push("");
52
- lines.push("These rules provide project-specific guidance for AI-assisted development.");
53
- lines.push("");
54
- const highPriorityRules = rules.filter((r) => r.frontmatter.priority === "high");
55
- const lowPriorityRules = rules.filter((r) => r.frontmatter.priority === "low");
56
- if (highPriorityRules.length > 0) {
57
- lines.push("## High Priority Guidelines");
58
- lines.push("");
59
- lines.push("These are critical rules that should always be followed:");
60
- lines.push("");
61
- for (const rule of highPriorityRules) {
62
- lines.push(...formatRuleForCline(rule));
53
+ if (detailRules.length > 0) {
54
+ for (const rule of detailRules) {
55
+ lines.push(`@${rule.filename}`);
63
56
  }
64
- }
65
- if (lowPriorityRules.length > 0) {
66
- lines.push("## Standard Guidelines");
67
57
  lines.push("");
68
- lines.push("These are recommended practices for this project:");
69
- lines.push("");
70
- for (const rule of lowPriorityRules) {
71
- lines.push(...formatRuleForCline(rule));
58
+ }
59
+ lines.push("# Claude Code Memory - Project Instructions");
60
+ lines.push("");
61
+ lines.push(
62
+ "Generated from rulesync configuration. These instructions guide Claude Code's behavior for this project."
63
+ );
64
+ lines.push("");
65
+ if (overviewRules.length > 0) {
66
+ for (const rule of overviewRules) {
67
+ lines.push(...formatRuleForClaude(rule));
72
68
  }
73
69
  }
74
70
  return lines.join("\n");
75
71
  }
76
- function formatRuleForCline(rule) {
72
+ function formatRuleForClaude(rule) {
77
73
  const lines = [];
78
74
  lines.push(`### ${rule.filename}`);
79
75
  lines.push("");
80
- lines.push(`**Description:** ${rule.frontmatter.description}`);
81
- lines.push("");
82
- if (rule.frontmatter.globs.length > 0) {
83
- lines.push(`**Applies to files:** ${rule.frontmatter.globs.join(", ")}`);
76
+ if (rule.frontmatter.description) {
77
+ lines.push(`**Description:** ${rule.frontmatter.description}`);
78
+ lines.push("");
79
+ }
80
+ if (rule.frontmatter.globs && rule.frontmatter.globs.length > 0) {
81
+ lines.push(`**File patterns:** ${rule.frontmatter.globs.join(", ")}`);
84
82
  lines.push("");
85
83
  }
86
- lines.push("**Guidelines:**");
87
- lines.push("");
88
84
  lines.push(rule.content);
89
85
  lines.push("");
90
- lines.push("---");
91
- lines.push("");
92
86
  return lines;
93
87
  }
94
-
95
- // src/generators/copilot.ts
96
- var import_node_path2 = require("path");
97
- async function generateCopilotConfig(rules, config) {
98
- const sortedRules = rules.sort((a, b) => {
99
- if (a.frontmatter.priority !== b.frontmatter.priority) {
100
- return a.frontmatter.priority === "high" ? -1 : 1;
101
- }
102
- return a.filename.localeCompare(b.filename);
103
- });
104
- const content = generateCopilotMarkdown(sortedRules);
105
- const filepath = (0, import_node_path2.join)(config.outputPaths.copilot, "ai-rules.instructions.md");
106
- return {
107
- tool: "copilot",
108
- filepath,
109
- content
110
- };
111
- }
112
- function generateCopilotMarkdown(rules) {
88
+ function generateMemoryFile(rule) {
113
89
  const lines = [];
114
- lines.push("---");
115
- lines.push('description: "AI rules configuration for GitHub Copilot"');
116
- lines.push('applyTo: "**"');
117
- lines.push("---");
90
+ lines.push("Please also refer to the following files as needed:");
118
91
  lines.push("");
119
- lines.push("# GitHub Copilot Instructions");
92
+ lines.push("---");
120
93
  lines.push("");
121
- lines.push(
122
- "Generated from ai-rules configuration. These instructions guide GitHub Copilot's code suggestions."
123
- );
94
+ lines.push(`# ${rule.filename}`);
124
95
  lines.push("");
125
- const highPriorityRules = rules.filter((r) => r.frontmatter.priority === "high");
126
- const lowPriorityRules = rules.filter((r) => r.frontmatter.priority === "low");
127
- if (highPriorityRules.length > 0) {
128
- lines.push("## High Priority Rules");
96
+ if (rule.frontmatter.description) {
97
+ lines.push(`**Description:** ${rule.frontmatter.description}`);
129
98
  lines.push("");
130
- for (const rule of highPriorityRules) {
131
- lines.push(...formatRuleForCopilot(rule));
132
- }
133
99
  }
134
- if (lowPriorityRules.length > 0) {
135
- lines.push("## Standard Rules");
100
+ if (rule.frontmatter.globs && rule.frontmatter.globs.length > 0) {
101
+ lines.push(`**File patterns:** ${rule.frontmatter.globs.join(", ")}`);
136
102
  lines.push("");
137
- for (const rule of lowPriorityRules) {
138
- lines.push(...formatRuleForCopilot(rule));
139
- }
140
103
  }
104
+ lines.push(rule.content);
141
105
  return lines.join("\n");
142
106
  }
143
- function formatRuleForCopilot(rule) {
107
+
108
+ // src/generators/cline.ts
109
+ var import_node_path2 = require("path");
110
+ async function generateClineConfig(rules, config) {
111
+ const outputs = [];
112
+ for (const rule of rules) {
113
+ const content = generateClineMarkdown(rule);
114
+ const filepath = (0, import_node_path2.join)(config.outputPaths.cline, `${rule.filename}.md`);
115
+ outputs.push({
116
+ tool: "cline",
117
+ filepath,
118
+ content
119
+ });
120
+ }
121
+ return outputs;
122
+ }
123
+ function generateClineMarkdown(rule) {
144
124
  const lines = [];
145
- lines.push(`### ${rule.filename}`);
146
- lines.push("");
147
- lines.push(`**Description:** ${rule.frontmatter.description}`);
125
+ lines.push(`# ${rule.frontmatter.description}`);
148
126
  lines.push("");
149
127
  if (rule.frontmatter.globs.length > 0) {
150
- lines.push(`**Applies to:** ${rule.frontmatter.globs.join(", ")}`);
128
+ lines.push(`**Applies to files:** ${rule.frontmatter.globs.join(", ")}`);
151
129
  lines.push("");
152
130
  }
153
131
  lines.push(rule.content);
154
- lines.push("");
155
- return lines;
132
+ return lines.join("\n");
156
133
  }
157
134
 
158
- // src/generators/cursor.ts
135
+ // src/generators/copilot.ts
159
136
  var import_node_path3 = require("path");
160
- async function generateCursorConfig(rules, config) {
161
- const sortedRules = rules.sort((a, b) => {
162
- if (a.frontmatter.priority !== b.frontmatter.priority) {
163
- return a.frontmatter.priority === "high" ? -1 : 1;
164
- }
165
- return a.filename.localeCompare(b.filename);
166
- });
167
- const content = generateCursorMarkdown(sortedRules);
168
- const filepath = (0, import_node_path3.join)(config.outputPaths.cursor, "ai-rules.md");
169
- return {
170
- tool: "cursor",
171
- filepath,
172
- content
173
- };
137
+ async function generateCopilotConfig(rules, config) {
138
+ const outputs = [];
139
+ for (const rule of rules) {
140
+ const content = generateCopilotMarkdown(rule);
141
+ const baseFilename = rule.filename.replace(/\.md$/, "");
142
+ const filepath = (0, import_node_path3.join)(config.outputPaths.copilot, `${baseFilename}.instructions.md`);
143
+ outputs.push({
144
+ tool: "copilot",
145
+ filepath,
146
+ content
147
+ });
148
+ }
149
+ return outputs;
174
150
  }
175
- function generateCursorMarkdown(rules) {
151
+ function generateCopilotMarkdown(rule) {
176
152
  const lines = [];
177
153
  lines.push("---");
178
- lines.push("description: AI rules configuration for Cursor IDE");
179
- lines.push("alwaysApply: true");
154
+ lines.push(`description: "${rule.frontmatter.description}"`);
155
+ if (rule.frontmatter.globs.length > 0) {
156
+ lines.push(`applyTo: "${rule.frontmatter.globs.join(", ")}"`);
157
+ } else {
158
+ lines.push('applyTo: "**"');
159
+ }
180
160
  lines.push("---");
181
161
  lines.push("");
182
- lines.push("# Cursor IDE Rules");
183
- lines.push("");
184
- lines.push("These rules configure Cursor IDE's AI assistant behavior.");
185
- lines.push("");
162
+ lines.push(rule.content);
163
+ return lines.join("\n");
164
+ }
165
+
166
+ // src/generators/cursor.ts
167
+ var import_node_path4 = require("path");
168
+ async function generateCursorConfig(rules, config) {
169
+ const outputs = [];
186
170
  for (const rule of rules) {
187
- lines.push(...formatRuleForCursor(rule));
171
+ const content = generateCursorMarkdown(rule);
172
+ const filepath = (0, import_node_path4.join)(config.outputPaths.cursor, `${rule.filename}.md`);
173
+ outputs.push({
174
+ tool: "cursor",
175
+ filepath,
176
+ content
177
+ });
188
178
  }
189
- return lines.join("\n");
179
+ return outputs;
190
180
  }
191
- function formatRuleForCursor(rule) {
181
+ function generateCursorMarkdown(rule) {
192
182
  const lines = [];
193
- const priorityBadge = rule.frontmatter.priority === "high" ? "\u{1F534} HIGH" : "\u{1F7E1} STANDARD";
194
183
  lines.push("---");
195
184
  lines.push(`description: ${rule.frontmatter.description}`);
196
185
  if (rule.frontmatter.globs.length > 0) {
197
186
  lines.push(`globs: [${rule.frontmatter.globs.map((g) => `"${g}"`).join(", ")}]`);
198
187
  }
199
- lines.push(`alwaysApply: ${rule.frontmatter.priority === "high"}`);
200
- lines.push("---");
201
- lines.push("");
202
- lines.push(`## ${rule.filename} ${priorityBadge}`);
203
- lines.push("");
204
- lines.push(`**Priority:** ${rule.frontmatter.priority.toUpperCase()}`);
205
- lines.push("");
206
- if (rule.frontmatter.globs.length > 0) {
207
- lines.push("**File Patterns:**");
208
- for (const glob of rule.frontmatter.globs) {
209
- lines.push(`- \`${glob}\``);
210
- }
211
- lines.push("");
188
+ let ruletype;
189
+ if (rule.frontmatter.ruleLevel === "overview") {
190
+ ruletype = "always";
191
+ } else if (rule.frontmatter.ruleLevel === "detail" && rule.frontmatter.globs.length === 0) {
192
+ ruletype = "agentrequested";
193
+ } else {
194
+ ruletype = "autoattached";
212
195
  }
213
- lines.push("**Rule:**");
214
- lines.push(rule.content);
215
- lines.push("");
196
+ lines.push(`ruletype: ${ruletype}`);
216
197
  lines.push("---");
217
198
  lines.push("");
218
- return lines;
199
+ lines.push(rule.content);
200
+ return lines.join("\n");
219
201
  }
220
202
 
221
203
  // src/utils/config.ts
@@ -225,10 +207,11 @@ function getDefaultConfig() {
225
207
  outputPaths: {
226
208
  copilot: ".github/instructions",
227
209
  cursor: ".cursor/rules",
228
- cline: ".clinerules"
210
+ cline: ".clinerules",
211
+ claude: "."
229
212
  },
230
213
  watchEnabled: false,
231
- defaultTargets: ["copilot", "cursor", "cline"]
214
+ defaultTargets: ["copilot", "cursor", "cline", "claude"]
232
215
  };
233
216
  }
234
217
  function resolveTargets(targets, config) {
@@ -240,7 +223,7 @@ function resolveTargets(targets, config) {
240
223
 
241
224
  // src/utils/file.ts
242
225
  var import_promises = require("fs/promises");
243
- var import_node_path4 = require("path");
226
+ var import_node_path5 = require("path");
244
227
  async function ensureDir(dirPath) {
245
228
  try {
246
229
  await (0, import_promises.stat)(dirPath);
@@ -252,13 +235,13 @@ async function readFileContent(filepath) {
252
235
  return (0, import_promises.readFile)(filepath, "utf-8");
253
236
  }
254
237
  async function writeFileContent(filepath, content) {
255
- await ensureDir((0, import_node_path4.dirname)(filepath));
238
+ await ensureDir((0, import_node_path5.dirname)(filepath));
256
239
  await (0, import_promises.writeFile)(filepath, content, "utf-8");
257
240
  }
258
241
  async function findFiles(dir, extension = ".md") {
259
242
  try {
260
243
  const files = await (0, import_promises.readdir)(dir);
261
- return files.filter((file) => file.endsWith(extension)).map((file) => (0, import_node_path4.join)(dir, file));
244
+ return files.filter((file) => file.endsWith(extension)).map((file) => (0, import_node_path5.join)(dir, file));
262
245
  } catch {
263
246
  return [];
264
247
  }
@@ -271,6 +254,15 @@ async function fileExists(filepath) {
271
254
  return false;
272
255
  }
273
256
  }
257
+ async function removeDirectory(dirPath) {
258
+ try {
259
+ if (await fileExists(dirPath)) {
260
+ await (0, import_promises.rm)(dirPath, { recursive: true, force: true });
261
+ }
262
+ } catch (error) {
263
+ console.warn(`Failed to remove directory ${dirPath}:`, error);
264
+ }
265
+ }
274
266
 
275
267
  // src/core/generator.ts
276
268
  async function generateConfigurations(rules, config, targetTools) {
@@ -282,9 +274,9 @@ async function generateConfigurations(rules, config, targetTools) {
282
274
  console.warn(`No rules found for tool: ${tool}`);
283
275
  continue;
284
276
  }
285
- const output = await generateForTool(tool, relevantRules, config);
286
- if (output) {
287
- outputs.push(output);
277
+ const toolOutputs = await generateForTool(tool, relevantRules, config);
278
+ if (toolOutputs) {
279
+ outputs.push(...toolOutputs);
288
280
  }
289
281
  }
290
282
  return outputs;
@@ -303,6 +295,8 @@ async function generateForTool(tool, rules, config) {
303
295
  return generateCursorConfig(rules, config);
304
296
  case "cline":
305
297
  return generateClineConfig(rules, config);
298
+ case "claude":
299
+ return await generateClaudeConfig(rules, config);
306
300
  default:
307
301
  console.warn(`Unknown tool: ${tool}`);
308
302
  return null;
@@ -310,7 +304,7 @@ async function generateForTool(tool, rules, config) {
310
304
  }
311
305
 
312
306
  // src/core/parser.ts
313
- var import_node_path5 = require("path");
307
+ var import_node_path6 = require("path");
314
308
  var import_gray_matter = __toESM(require("gray-matter"));
315
309
  async function parseRulesFromDirectory(aiRulesDir) {
316
310
  const ruleFiles = await findFiles(aiRulesDir);
@@ -330,7 +324,7 @@ async function parseRuleFile(filepath) {
330
324
  const parsed = (0, import_gray_matter.default)(content);
331
325
  validateFrontmatter(parsed.data, filepath);
332
326
  const frontmatter = parsed.data;
333
- const filename = (0, import_node_path5.basename)(filepath, ".md");
327
+ const filename = (0, import_node_path6.basename)(filepath, ".md");
334
328
  return {
335
329
  frontmatter,
336
330
  content: parsed.content,
@@ -343,8 +337,8 @@ function validateFrontmatter(data, filepath) {
343
337
  throw new Error(`Invalid frontmatter in ${filepath}: must be an object`);
344
338
  }
345
339
  const obj = data;
346
- if (!obj.priority || !["high", "low"].includes(obj.priority)) {
347
- throw new Error(`Invalid priority in ${filepath}: must be "high" or "low"`);
340
+ if (!obj.ruleLevel || !["overview", "detail"].includes(obj.ruleLevel)) {
341
+ throw new Error(`Invalid ruleLevel in ${filepath}: must be "overview" or "detail"`);
348
342
  }
349
343
  if (!Array.isArray(obj.targets)) {
350
344
  throw new Error(`Invalid targets in ${filepath}: must be an array`);
@@ -381,6 +375,10 @@ async function validateRules(rules) {
381
375
  }
382
376
  filenames.add(rule.filename);
383
377
  }
378
+ const overviewRules = rules.filter((rule) => rule.frontmatter.ruleLevel === "overview");
379
+ if (overviewRules.length > 1) {
380
+ errors.push(`Multiple overview rules found: ${overviewRules.map((r) => r.filename).join(", ")}. Only one overview rule is allowed.`);
381
+ }
384
382
  for (const rule of rules) {
385
383
  const ruleValidation = await validateRule(rule);
386
384
  errors.push(...ruleValidation.errors);
@@ -434,6 +432,33 @@ async function generateCommand(options = {}) {
434
432
  if (options.verbose) {
435
433
  console.log(`Found ${rules.length} rule(s)`);
436
434
  }
435
+ if (options.delete) {
436
+ if (options.verbose) {
437
+ console.log("Deleting existing output directories...");
438
+ }
439
+ const targetTools = options.tools || config.defaultTargets;
440
+ const deleteTasks = [];
441
+ for (const tool of targetTools) {
442
+ switch (tool) {
443
+ case "copilot":
444
+ deleteTasks.push(removeDirectory(config.outputPaths.copilot));
445
+ break;
446
+ case "cursor":
447
+ deleteTasks.push(removeDirectory(config.outputPaths.cursor));
448
+ break;
449
+ case "cline":
450
+ deleteTasks.push(removeDirectory(config.outputPaths.cline));
451
+ break;
452
+ case "claude":
453
+ deleteTasks.push(removeDirectory(config.outputPaths.claude));
454
+ break;
455
+ }
456
+ }
457
+ await Promise.all(deleteTasks);
458
+ if (options.verbose) {
459
+ console.log("Deleted existing output directories");
460
+ }
461
+ }
437
462
  const outputs = await generateConfigurations(rules, config, options.tools);
438
463
  if (outputs.length === 0) {
439
464
  console.warn("\u26A0\uFE0F No configurations generated");
@@ -451,17 +476,57 @@ async function generateCommand(options = {}) {
451
476
  }
452
477
  }
453
478
 
479
+ // src/cli/commands/gitignore.ts
480
+ var import_node_fs = require("fs");
481
+ var import_node_path7 = require("path");
482
+ var gitignoreCommand = async () => {
483
+ const gitignorePath = (0, import_node_path7.join)(process.cwd(), ".gitignore");
484
+ const rulesFilesToIgnore = [
485
+ "# Generated by rulesync - AI tool configuration files",
486
+ ".github/instructions/",
487
+ ".cursor/rules/",
488
+ ".clinerules/",
489
+ "CLAUDE.md"
490
+ ];
491
+ let gitignoreContent = "";
492
+ if ((0, import_node_fs.existsSync)(gitignorePath)) {
493
+ gitignoreContent = (0, import_node_fs.readFileSync)(gitignorePath, "utf-8");
494
+ }
495
+ const linesToAdd = [];
496
+ for (const rule of rulesFilesToIgnore) {
497
+ if (!gitignoreContent.includes(rule)) {
498
+ linesToAdd.push(rule);
499
+ }
500
+ }
501
+ if (linesToAdd.length === 0) {
502
+ console.log("\u2705 .gitignore\u306F\u65E2\u306B\u6700\u65B0\u3067\u3059");
503
+ return;
504
+ }
505
+ const newContent = gitignoreContent ? `${gitignoreContent.trimEnd()}
506
+
507
+ ${linesToAdd.join("\n")}
508
+ ` : `${linesToAdd.join("\n")}
509
+ `;
510
+ (0, import_node_fs.writeFileSync)(gitignorePath, newContent);
511
+ console.log(`\u2705 .gitignore\u306B${linesToAdd.length}\u500B\u306E\u30EB\u30FC\u30EB\u3092\u8FFD\u52A0\u3057\u307E\u3057\u305F:`);
512
+ for (const line of linesToAdd) {
513
+ if (!line.startsWith("#")) {
514
+ console.log(` ${line}`);
515
+ }
516
+ }
517
+ };
518
+
454
519
  // src/cli/commands/init.ts
455
- var import_node_path6 = require("path");
520
+ var import_node_path8 = require("path");
456
521
  async function initCommand() {
457
522
  const aiRulesDir = ".rulesync";
458
- console.log("Initializing ai-rules...");
523
+ console.log("Initializing rulesync...");
459
524
  await ensureDir(aiRulesDir);
460
525
  await createSampleFiles(aiRulesDir);
461
- console.log("\u2705 ai-rules initialized successfully!");
526
+ console.log("\u2705 rulesync initialized successfully!");
462
527
  console.log("\nNext steps:");
463
528
  console.log("1. Edit rule files in .rulesync/");
464
- console.log("2. Run 'ai-rules generate' to create configuration files");
529
+ console.log("2. Run 'rulesync generate' to create configuration files");
465
530
  }
466
531
  async function createSampleFiles(aiRulesDir) {
467
532
  const sampleFiles = [
@@ -542,7 +607,7 @@ globs: ["src/**/*.ts"]
542
607
  }
543
608
  ];
544
609
  for (const file of sampleFiles) {
545
- const filepath = (0, import_node_path6.join)(aiRulesDir, file.filename);
610
+ const filepath = (0, import_node_path8.join)(aiRulesDir, file.filename);
546
611
  if (!await fileExists(filepath)) {
547
612
  await writeFileContent(filepath, file.content);
548
613
  console.log(`Created ${filepath}`);
@@ -557,10 +622,10 @@ async function statusCommand() {
557
622
  const config = getDefaultConfig();
558
623
  console.log("rulesync Status");
559
624
  console.log("===============");
560
- const aiRulesExists = await fileExists(config.aiRulesDir);
625
+ const rulesyncExists = await fileExists(config.aiRulesDir);
561
626
  console.log(`
562
- \u{1F4C1} .rulesync directory: ${aiRulesExists ? "\u2705 Found" : "\u274C Not found"}`);
563
- if (!aiRulesExists) {
627
+ \u{1F4C1} .rulesync directory: ${rulesyncExists ? "\u2705 Found" : "\u274C Not found"}`);
628
+ if (!rulesyncExists) {
564
629
  console.log("\n\u{1F4A1} Run 'rulesync init' to get started");
565
630
  return;
566
631
  }
@@ -603,7 +668,7 @@ async function statusCommand() {
603
668
  // src/cli/commands/validate.ts
604
669
  async function validateCommand() {
605
670
  const config = getDefaultConfig();
606
- console.log("Validating ai-rules configuration...");
671
+ console.log("Validating rulesync configuration...");
607
672
  if (!await fileExists(config.aiRulesDir)) {
608
673
  console.error("\u274C .rulesync directory not found. Run 'rulesync init' first.");
609
674
  process.exit(1);
@@ -611,7 +676,7 @@ async function validateCommand() {
611
676
  try {
612
677
  const rules = await parseRulesFromDirectory(config.aiRulesDir);
613
678
  if (rules.length === 0) {
614
- console.warn("\u26A0\uFE0F No rules found in .ai-rules directory");
679
+ console.warn("\u26A0\uFE0F No rules found in .rulesync directory");
615
680
  return;
616
681
  }
617
682
  console.log(`Found ${rules.length} rule(s), validating...`);
@@ -683,22 +748,25 @@ async function watchCommand() {
683
748
 
684
749
  // src/cli/index.ts
685
750
  var program = new import_commander.Command();
686
- program.name("ai-rules").description("Unified AI rules management CLI tool").version("0.1.0");
687
- program.command("init").description("Initialize ai-rules in current directory").action(initCommand);
688
- program.command("generate").description("Generate configuration files for AI tools").option("--copilot", "Generate only for GitHub Copilot").option("--cursor", "Generate only for Cursor").option("--cline", "Generate only for Cline").option("-v, --verbose", "Verbose output").action(async (options) => {
751
+ program.name("rulesync").description("Unified AI rules management CLI tool").version("0.1.0");
752
+ program.command("init").description("Initialize rulesync in current directory").action(initCommand);
753
+ program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);
754
+ program.command("generate").description("Generate configuration files for AI tools").option("--copilot", "Generate only for GitHub Copilot").option("--cursor", "Generate only for Cursor").option("--cline", "Generate only for Cline").option("--claude", "Generate only for Claude Code").option("--delete", "Delete all existing files in output directories before generating").option("-v, --verbose", "Verbose output").action(async (options) => {
689
755
  const tools = [];
690
756
  if (options.copilot) tools.push("copilot");
691
757
  if (options.cursor) tools.push("cursor");
692
758
  if (options.cline) tools.push("cline");
759
+ if (options.claude) tools.push("claude");
693
760
  const generateOptions = {
694
- verbose: options.verbose
761
+ verbose: options.verbose,
762
+ delete: options.delete
695
763
  };
696
764
  if (tools.length > 0) {
697
765
  generateOptions.tools = tools;
698
766
  }
699
767
  await generateCommand(generateOptions);
700
768
  });
701
- program.command("validate").description("Validate ai-rules configuration").action(validateCommand);
702
- program.command("status").description("Show current status of ai-rules").action(statusCommand);
769
+ program.command("validate").description("Validate rulesync configuration").action(validateCommand);
770
+ program.command("status").description("Show current status of rulesync").action(statusCommand);
703
771
  program.command("watch").description("Watch for changes and auto-generate configurations").action(watchCommand);
704
772
  program.parse();