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.mjs CHANGED
@@ -3,196 +3,178 @@
3
3
  // src/cli/index.ts
4
4
  import { Command } from "commander";
5
5
 
6
- // src/generators/cline.ts
6
+ // src/generators/claude.ts
7
7
  import { join } from "path";
8
- async function generateClineConfig(rules, config) {
9
- const sortedRules = rules.sort((a, b) => {
10
- if (a.frontmatter.priority !== b.frontmatter.priority) {
11
- return a.frontmatter.priority === "high" ? -1 : 1;
12
- }
13
- return a.filename.localeCompare(b.filename);
8
+ async function generateClaudeConfig(rules, config) {
9
+ const outputs = [];
10
+ const overviewRules = rules.filter((r) => r.frontmatter.ruleLevel === "overview");
11
+ const detailRules = rules.filter((r) => r.frontmatter.ruleLevel === "detail");
12
+ const claudeMdContent = generateClaudeMarkdown(overviewRules, detailRules);
13
+ outputs.push({
14
+ tool: "claude",
15
+ filepath: join(config.outputPaths.claude, "CLAUDE.md"),
16
+ content: claudeMdContent
14
17
  });
15
- const content = generateClineMarkdown(sortedRules);
16
- const filepath = join(config.outputPaths.cline, "01-ai-rules.md");
17
- return {
18
- tool: "cline",
19
- filepath,
20
- content
21
- };
18
+ for (const rule of detailRules) {
19
+ const memoryContent = generateMemoryFile(rule);
20
+ outputs.push({
21
+ tool: "claude",
22
+ filepath: join(config.outputPaths.claude, ".claude", "memories", `${rule.filename}.md`),
23
+ content: memoryContent
24
+ });
25
+ }
26
+ return outputs;
22
27
  }
23
- function generateClineMarkdown(rules) {
28
+ function generateClaudeMarkdown(overviewRules, detailRules) {
24
29
  const lines = [];
25
- lines.push("# Cline AI Assistant Rules");
26
- lines.push("");
27
- lines.push("Configuration rules for Cline AI Assistant. Generated from ai-rules configuration.");
28
- lines.push("");
29
- lines.push("These rules provide project-specific guidance for AI-assisted development.");
30
- lines.push("");
31
- const highPriorityRules = rules.filter((r) => r.frontmatter.priority === "high");
32
- const lowPriorityRules = rules.filter((r) => r.frontmatter.priority === "low");
33
- if (highPriorityRules.length > 0) {
34
- lines.push("## High Priority Guidelines");
35
- lines.push("");
36
- lines.push("These are critical rules that should always be followed:");
37
- lines.push("");
38
- for (const rule of highPriorityRules) {
39
- lines.push(...formatRuleForCline(rule));
30
+ if (detailRules.length > 0) {
31
+ for (const rule of detailRules) {
32
+ lines.push(`@${rule.filename}`);
40
33
  }
41
- }
42
- if (lowPriorityRules.length > 0) {
43
- lines.push("## Standard Guidelines");
44
- lines.push("");
45
- lines.push("These are recommended practices for this project:");
46
34
  lines.push("");
47
- for (const rule of lowPriorityRules) {
48
- lines.push(...formatRuleForCline(rule));
35
+ }
36
+ lines.push("# Claude Code Memory - Project Instructions");
37
+ lines.push("");
38
+ lines.push(
39
+ "Generated from rulesync configuration. These instructions guide Claude Code's behavior for this project."
40
+ );
41
+ lines.push("");
42
+ if (overviewRules.length > 0) {
43
+ for (const rule of overviewRules) {
44
+ lines.push(...formatRuleForClaude(rule));
49
45
  }
50
46
  }
51
47
  return lines.join("\n");
52
48
  }
53
- function formatRuleForCline(rule) {
49
+ function formatRuleForClaude(rule) {
54
50
  const lines = [];
55
51
  lines.push(`### ${rule.filename}`);
56
52
  lines.push("");
57
- lines.push(`**Description:** ${rule.frontmatter.description}`);
58
- lines.push("");
59
- if (rule.frontmatter.globs.length > 0) {
60
- lines.push(`**Applies to files:** ${rule.frontmatter.globs.join(", ")}`);
53
+ if (rule.frontmatter.description) {
54
+ lines.push(`**Description:** ${rule.frontmatter.description}`);
55
+ lines.push("");
56
+ }
57
+ if (rule.frontmatter.globs && rule.frontmatter.globs.length > 0) {
58
+ lines.push(`**File patterns:** ${rule.frontmatter.globs.join(", ")}`);
61
59
  lines.push("");
62
60
  }
63
- lines.push("**Guidelines:**");
64
- lines.push("");
65
61
  lines.push(rule.content);
66
62
  lines.push("");
67
- lines.push("---");
68
- lines.push("");
69
63
  return lines;
70
64
  }
71
-
72
- // src/generators/copilot.ts
73
- import { join as join2 } from "path";
74
- async function generateCopilotConfig(rules, config) {
75
- const sortedRules = rules.sort((a, b) => {
76
- if (a.frontmatter.priority !== b.frontmatter.priority) {
77
- return a.frontmatter.priority === "high" ? -1 : 1;
78
- }
79
- return a.filename.localeCompare(b.filename);
80
- });
81
- const content = generateCopilotMarkdown(sortedRules);
82
- const filepath = join2(config.outputPaths.copilot, "ai-rules.instructions.md");
83
- return {
84
- tool: "copilot",
85
- filepath,
86
- content
87
- };
88
- }
89
- function generateCopilotMarkdown(rules) {
65
+ function generateMemoryFile(rule) {
90
66
  const lines = [];
91
- lines.push("---");
92
- lines.push('description: "AI rules configuration for GitHub Copilot"');
93
- lines.push('applyTo: "**"');
94
- lines.push("---");
67
+ lines.push("Please also refer to the following files as needed:");
95
68
  lines.push("");
96
- lines.push("# GitHub Copilot Instructions");
69
+ lines.push("---");
97
70
  lines.push("");
98
- lines.push(
99
- "Generated from ai-rules configuration. These instructions guide GitHub Copilot's code suggestions."
100
- );
71
+ lines.push(`# ${rule.filename}`);
101
72
  lines.push("");
102
- const highPriorityRules = rules.filter((r) => r.frontmatter.priority === "high");
103
- const lowPriorityRules = rules.filter((r) => r.frontmatter.priority === "low");
104
- if (highPriorityRules.length > 0) {
105
- lines.push("## High Priority Rules");
73
+ if (rule.frontmatter.description) {
74
+ lines.push(`**Description:** ${rule.frontmatter.description}`);
106
75
  lines.push("");
107
- for (const rule of highPriorityRules) {
108
- lines.push(...formatRuleForCopilot(rule));
109
- }
110
76
  }
111
- if (lowPriorityRules.length > 0) {
112
- lines.push("## Standard Rules");
77
+ if (rule.frontmatter.globs && rule.frontmatter.globs.length > 0) {
78
+ lines.push(`**File patterns:** ${rule.frontmatter.globs.join(", ")}`);
113
79
  lines.push("");
114
- for (const rule of lowPriorityRules) {
115
- lines.push(...formatRuleForCopilot(rule));
116
- }
117
80
  }
81
+ lines.push(rule.content);
118
82
  return lines.join("\n");
119
83
  }
120
- function formatRuleForCopilot(rule) {
84
+
85
+ // src/generators/cline.ts
86
+ import { join as join2 } from "path";
87
+ async function generateClineConfig(rules, config) {
88
+ const outputs = [];
89
+ for (const rule of rules) {
90
+ const content = generateClineMarkdown(rule);
91
+ const filepath = join2(config.outputPaths.cline, `${rule.filename}.md`);
92
+ outputs.push({
93
+ tool: "cline",
94
+ filepath,
95
+ content
96
+ });
97
+ }
98
+ return outputs;
99
+ }
100
+ function generateClineMarkdown(rule) {
121
101
  const lines = [];
122
- lines.push(`### ${rule.filename}`);
123
- lines.push("");
124
- lines.push(`**Description:** ${rule.frontmatter.description}`);
102
+ lines.push(`# ${rule.frontmatter.description}`);
125
103
  lines.push("");
126
104
  if (rule.frontmatter.globs.length > 0) {
127
- lines.push(`**Applies to:** ${rule.frontmatter.globs.join(", ")}`);
105
+ lines.push(`**Applies to files:** ${rule.frontmatter.globs.join(", ")}`);
128
106
  lines.push("");
129
107
  }
130
108
  lines.push(rule.content);
131
- lines.push("");
132
- return lines;
109
+ return lines.join("\n");
133
110
  }
134
111
 
135
- // src/generators/cursor.ts
112
+ // src/generators/copilot.ts
136
113
  import { join as join3 } from "path";
137
- async function generateCursorConfig(rules, config) {
138
- const sortedRules = rules.sort((a, b) => {
139
- if (a.frontmatter.priority !== b.frontmatter.priority) {
140
- return a.frontmatter.priority === "high" ? -1 : 1;
141
- }
142
- return a.filename.localeCompare(b.filename);
143
- });
144
- const content = generateCursorMarkdown(sortedRules);
145
- const filepath = join3(config.outputPaths.cursor, "ai-rules.md");
146
- return {
147
- tool: "cursor",
148
- filepath,
149
- content
150
- };
114
+ async function generateCopilotConfig(rules, config) {
115
+ const outputs = [];
116
+ for (const rule of rules) {
117
+ const content = generateCopilotMarkdown(rule);
118
+ const baseFilename = rule.filename.replace(/\.md$/, "");
119
+ const filepath = join3(config.outputPaths.copilot, `${baseFilename}.instructions.md`);
120
+ outputs.push({
121
+ tool: "copilot",
122
+ filepath,
123
+ content
124
+ });
125
+ }
126
+ return outputs;
151
127
  }
152
- function generateCursorMarkdown(rules) {
128
+ function generateCopilotMarkdown(rule) {
153
129
  const lines = [];
154
130
  lines.push("---");
155
- lines.push("description: AI rules configuration for Cursor IDE");
156
- lines.push("alwaysApply: true");
131
+ lines.push(`description: "${rule.frontmatter.description}"`);
132
+ if (rule.frontmatter.globs.length > 0) {
133
+ lines.push(`applyTo: "${rule.frontmatter.globs.join(", ")}"`);
134
+ } else {
135
+ lines.push('applyTo: "**"');
136
+ }
157
137
  lines.push("---");
158
138
  lines.push("");
159
- lines.push("# Cursor IDE Rules");
160
- lines.push("");
161
- lines.push("These rules configure Cursor IDE's AI assistant behavior.");
162
- lines.push("");
139
+ lines.push(rule.content);
140
+ return lines.join("\n");
141
+ }
142
+
143
+ // src/generators/cursor.ts
144
+ import { join as join4 } from "path";
145
+ async function generateCursorConfig(rules, config) {
146
+ const outputs = [];
163
147
  for (const rule of rules) {
164
- lines.push(...formatRuleForCursor(rule));
148
+ const content = generateCursorMarkdown(rule);
149
+ const filepath = join4(config.outputPaths.cursor, `${rule.filename}.md`);
150
+ outputs.push({
151
+ tool: "cursor",
152
+ filepath,
153
+ content
154
+ });
165
155
  }
166
- return lines.join("\n");
156
+ return outputs;
167
157
  }
168
- function formatRuleForCursor(rule) {
158
+ function generateCursorMarkdown(rule) {
169
159
  const lines = [];
170
- const priorityBadge = rule.frontmatter.priority === "high" ? "\u{1F534} HIGH" : "\u{1F7E1} STANDARD";
171
160
  lines.push("---");
172
161
  lines.push(`description: ${rule.frontmatter.description}`);
173
162
  if (rule.frontmatter.globs.length > 0) {
174
163
  lines.push(`globs: [${rule.frontmatter.globs.map((g) => `"${g}"`).join(", ")}]`);
175
164
  }
176
- lines.push(`alwaysApply: ${rule.frontmatter.priority === "high"}`);
177
- lines.push("---");
178
- lines.push("");
179
- lines.push(`## ${rule.filename} ${priorityBadge}`);
180
- lines.push("");
181
- lines.push(`**Priority:** ${rule.frontmatter.priority.toUpperCase()}`);
182
- lines.push("");
183
- if (rule.frontmatter.globs.length > 0) {
184
- lines.push("**File Patterns:**");
185
- for (const glob of rule.frontmatter.globs) {
186
- lines.push(`- \`${glob}\``);
187
- }
188
- lines.push("");
165
+ let ruletype;
166
+ if (rule.frontmatter.ruleLevel === "overview") {
167
+ ruletype = "always";
168
+ } else if (rule.frontmatter.ruleLevel === "detail" && rule.frontmatter.globs.length === 0) {
169
+ ruletype = "agentrequested";
170
+ } else {
171
+ ruletype = "autoattached";
189
172
  }
190
- lines.push("**Rule:**");
191
- lines.push(rule.content);
192
- lines.push("");
173
+ lines.push(`ruletype: ${ruletype}`);
193
174
  lines.push("---");
194
175
  lines.push("");
195
- return lines;
176
+ lines.push(rule.content);
177
+ return lines.join("\n");
196
178
  }
197
179
 
198
180
  // src/utils/config.ts
@@ -202,10 +184,11 @@ function getDefaultConfig() {
202
184
  outputPaths: {
203
185
  copilot: ".github/instructions",
204
186
  cursor: ".cursor/rules",
205
- cline: ".clinerules"
187
+ cline: ".clinerules",
188
+ claude: "."
206
189
  },
207
190
  watchEnabled: false,
208
- defaultTargets: ["copilot", "cursor", "cline"]
191
+ defaultTargets: ["copilot", "cursor", "cline", "claude"]
209
192
  };
210
193
  }
211
194
  function resolveTargets(targets, config) {
@@ -216,8 +199,8 @@ function resolveTargets(targets, config) {
216
199
  }
217
200
 
218
201
  // src/utils/file.ts
219
- import { mkdir, readdir, readFile, stat, writeFile } from "fs/promises";
220
- import { dirname, join as join4 } from "path";
202
+ import { mkdir, readdir, readFile, rm, stat, writeFile } from "fs/promises";
203
+ import { dirname, join as join5 } from "path";
221
204
  async function ensureDir(dirPath) {
222
205
  try {
223
206
  await stat(dirPath);
@@ -235,7 +218,7 @@ async function writeFileContent(filepath, content) {
235
218
  async function findFiles(dir, extension = ".md") {
236
219
  try {
237
220
  const files = await readdir(dir);
238
- return files.filter((file) => file.endsWith(extension)).map((file) => join4(dir, file));
221
+ return files.filter((file) => file.endsWith(extension)).map((file) => join5(dir, file));
239
222
  } catch {
240
223
  return [];
241
224
  }
@@ -248,6 +231,15 @@ async function fileExists(filepath) {
248
231
  return false;
249
232
  }
250
233
  }
234
+ async function removeDirectory(dirPath) {
235
+ try {
236
+ if (await fileExists(dirPath)) {
237
+ await rm(dirPath, { recursive: true, force: true });
238
+ }
239
+ } catch (error) {
240
+ console.warn(`Failed to remove directory ${dirPath}:`, error);
241
+ }
242
+ }
251
243
 
252
244
  // src/core/generator.ts
253
245
  async function generateConfigurations(rules, config, targetTools) {
@@ -259,9 +251,9 @@ async function generateConfigurations(rules, config, targetTools) {
259
251
  console.warn(`No rules found for tool: ${tool}`);
260
252
  continue;
261
253
  }
262
- const output = await generateForTool(tool, relevantRules, config);
263
- if (output) {
264
- outputs.push(output);
254
+ const toolOutputs = await generateForTool(tool, relevantRules, config);
255
+ if (toolOutputs) {
256
+ outputs.push(...toolOutputs);
265
257
  }
266
258
  }
267
259
  return outputs;
@@ -280,6 +272,8 @@ async function generateForTool(tool, rules, config) {
280
272
  return generateCursorConfig(rules, config);
281
273
  case "cline":
282
274
  return generateClineConfig(rules, config);
275
+ case "claude":
276
+ return await generateClaudeConfig(rules, config);
283
277
  default:
284
278
  console.warn(`Unknown tool: ${tool}`);
285
279
  return null;
@@ -320,8 +314,8 @@ function validateFrontmatter(data, filepath) {
320
314
  throw new Error(`Invalid frontmatter in ${filepath}: must be an object`);
321
315
  }
322
316
  const obj = data;
323
- if (!obj.priority || !["high", "low"].includes(obj.priority)) {
324
- throw new Error(`Invalid priority in ${filepath}: must be "high" or "low"`);
317
+ if (!obj.ruleLevel || !["overview", "detail"].includes(obj.ruleLevel)) {
318
+ throw new Error(`Invalid ruleLevel in ${filepath}: must be "overview" or "detail"`);
325
319
  }
326
320
  if (!Array.isArray(obj.targets)) {
327
321
  throw new Error(`Invalid targets in ${filepath}: must be an array`);
@@ -358,6 +352,10 @@ async function validateRules(rules) {
358
352
  }
359
353
  filenames.add(rule.filename);
360
354
  }
355
+ const overviewRules = rules.filter((rule) => rule.frontmatter.ruleLevel === "overview");
356
+ if (overviewRules.length > 1) {
357
+ errors.push(`Multiple overview rules found: ${overviewRules.map((r) => r.filename).join(", ")}. Only one overview rule is allowed.`);
358
+ }
361
359
  for (const rule of rules) {
362
360
  const ruleValidation = await validateRule(rule);
363
361
  errors.push(...ruleValidation.errors);
@@ -411,6 +409,33 @@ async function generateCommand(options = {}) {
411
409
  if (options.verbose) {
412
410
  console.log(`Found ${rules.length} rule(s)`);
413
411
  }
412
+ if (options.delete) {
413
+ if (options.verbose) {
414
+ console.log("Deleting existing output directories...");
415
+ }
416
+ const targetTools = options.tools || config.defaultTargets;
417
+ const deleteTasks = [];
418
+ for (const tool of targetTools) {
419
+ switch (tool) {
420
+ case "copilot":
421
+ deleteTasks.push(removeDirectory(config.outputPaths.copilot));
422
+ break;
423
+ case "cursor":
424
+ deleteTasks.push(removeDirectory(config.outputPaths.cursor));
425
+ break;
426
+ case "cline":
427
+ deleteTasks.push(removeDirectory(config.outputPaths.cline));
428
+ break;
429
+ case "claude":
430
+ deleteTasks.push(removeDirectory(config.outputPaths.claude));
431
+ break;
432
+ }
433
+ }
434
+ await Promise.all(deleteTasks);
435
+ if (options.verbose) {
436
+ console.log("Deleted existing output directories");
437
+ }
438
+ }
414
439
  const outputs = await generateConfigurations(rules, config, options.tools);
415
440
  if (outputs.length === 0) {
416
441
  console.warn("\u26A0\uFE0F No configurations generated");
@@ -428,17 +453,57 @@ async function generateCommand(options = {}) {
428
453
  }
429
454
  }
430
455
 
456
+ // src/cli/commands/gitignore.ts
457
+ import { existsSync, readFileSync, writeFileSync } from "fs";
458
+ import { join as join6 } from "path";
459
+ var gitignoreCommand = async () => {
460
+ const gitignorePath = join6(process.cwd(), ".gitignore");
461
+ const rulesFilesToIgnore = [
462
+ "# Generated by rulesync - AI tool configuration files",
463
+ ".github/instructions/",
464
+ ".cursor/rules/",
465
+ ".clinerules/",
466
+ "CLAUDE.md"
467
+ ];
468
+ let gitignoreContent = "";
469
+ if (existsSync(gitignorePath)) {
470
+ gitignoreContent = readFileSync(gitignorePath, "utf-8");
471
+ }
472
+ const linesToAdd = [];
473
+ for (const rule of rulesFilesToIgnore) {
474
+ if (!gitignoreContent.includes(rule)) {
475
+ linesToAdd.push(rule);
476
+ }
477
+ }
478
+ if (linesToAdd.length === 0) {
479
+ console.log("\u2705 .gitignore\u306F\u65E2\u306B\u6700\u65B0\u3067\u3059");
480
+ return;
481
+ }
482
+ const newContent = gitignoreContent ? `${gitignoreContent.trimEnd()}
483
+
484
+ ${linesToAdd.join("\n")}
485
+ ` : `${linesToAdd.join("\n")}
486
+ `;
487
+ writeFileSync(gitignorePath, newContent);
488
+ console.log(`\u2705 .gitignore\u306B${linesToAdd.length}\u500B\u306E\u30EB\u30FC\u30EB\u3092\u8FFD\u52A0\u3057\u307E\u3057\u305F:`);
489
+ for (const line of linesToAdd) {
490
+ if (!line.startsWith("#")) {
491
+ console.log(` ${line}`);
492
+ }
493
+ }
494
+ };
495
+
431
496
  // src/cli/commands/init.ts
432
- import { join as join5 } from "path";
497
+ import { join as join7 } from "path";
433
498
  async function initCommand() {
434
499
  const aiRulesDir = ".rulesync";
435
- console.log("Initializing ai-rules...");
500
+ console.log("Initializing rulesync...");
436
501
  await ensureDir(aiRulesDir);
437
502
  await createSampleFiles(aiRulesDir);
438
- console.log("\u2705 ai-rules initialized successfully!");
503
+ console.log("\u2705 rulesync initialized successfully!");
439
504
  console.log("\nNext steps:");
440
505
  console.log("1. Edit rule files in .rulesync/");
441
- console.log("2. Run 'ai-rules generate' to create configuration files");
506
+ console.log("2. Run 'rulesync generate' to create configuration files");
442
507
  }
443
508
  async function createSampleFiles(aiRulesDir) {
444
509
  const sampleFiles = [
@@ -519,7 +584,7 @@ globs: ["src/**/*.ts"]
519
584
  }
520
585
  ];
521
586
  for (const file of sampleFiles) {
522
- const filepath = join5(aiRulesDir, file.filename);
587
+ const filepath = join7(aiRulesDir, file.filename);
523
588
  if (!await fileExists(filepath)) {
524
589
  await writeFileContent(filepath, file.content);
525
590
  console.log(`Created ${filepath}`);
@@ -534,10 +599,10 @@ async function statusCommand() {
534
599
  const config = getDefaultConfig();
535
600
  console.log("rulesync Status");
536
601
  console.log("===============");
537
- const aiRulesExists = await fileExists(config.aiRulesDir);
602
+ const rulesyncExists = await fileExists(config.aiRulesDir);
538
603
  console.log(`
539
- \u{1F4C1} .rulesync directory: ${aiRulesExists ? "\u2705 Found" : "\u274C Not found"}`);
540
- if (!aiRulesExists) {
604
+ \u{1F4C1} .rulesync directory: ${rulesyncExists ? "\u2705 Found" : "\u274C Not found"}`);
605
+ if (!rulesyncExists) {
541
606
  console.log("\n\u{1F4A1} Run 'rulesync init' to get started");
542
607
  return;
543
608
  }
@@ -580,7 +645,7 @@ async function statusCommand() {
580
645
  // src/cli/commands/validate.ts
581
646
  async function validateCommand() {
582
647
  const config = getDefaultConfig();
583
- console.log("Validating ai-rules configuration...");
648
+ console.log("Validating rulesync configuration...");
584
649
  if (!await fileExists(config.aiRulesDir)) {
585
650
  console.error("\u274C .rulesync directory not found. Run 'rulesync init' first.");
586
651
  process.exit(1);
@@ -588,7 +653,7 @@ async function validateCommand() {
588
653
  try {
589
654
  const rules = await parseRulesFromDirectory(config.aiRulesDir);
590
655
  if (rules.length === 0) {
591
- console.warn("\u26A0\uFE0F No rules found in .ai-rules directory");
656
+ console.warn("\u26A0\uFE0F No rules found in .rulesync directory");
592
657
  return;
593
658
  }
594
659
  console.log(`Found ${rules.length} rule(s), validating...`);
@@ -660,22 +725,25 @@ async function watchCommand() {
660
725
 
661
726
  // src/cli/index.ts
662
727
  var program = new Command();
663
- program.name("ai-rules").description("Unified AI rules management CLI tool").version("0.1.0");
664
- program.command("init").description("Initialize ai-rules in current directory").action(initCommand);
665
- 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) => {
728
+ program.name("rulesync").description("Unified AI rules management CLI tool").version("0.1.0");
729
+ program.command("init").description("Initialize rulesync in current directory").action(initCommand);
730
+ program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);
731
+ 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) => {
666
732
  const tools = [];
667
733
  if (options.copilot) tools.push("copilot");
668
734
  if (options.cursor) tools.push("cursor");
669
735
  if (options.cline) tools.push("cline");
736
+ if (options.claude) tools.push("claude");
670
737
  const generateOptions = {
671
- verbose: options.verbose
738
+ verbose: options.verbose,
739
+ delete: options.delete
672
740
  };
673
741
  if (tools.length > 0) {
674
742
  generateOptions.tools = tools;
675
743
  }
676
744
  await generateCommand(generateOptions);
677
745
  });
678
- program.command("validate").description("Validate ai-rules configuration").action(validateCommand);
679
- program.command("status").description("Show current status of ai-rules").action(statusCommand);
746
+ program.command("validate").description("Validate rulesync configuration").action(validateCommand);
747
+ program.command("status").description("Show current status of rulesync").action(statusCommand);
680
748
  program.command("watch").description("Watch for changes and auto-generate configurations").action(watchCommand);
681
749
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rulesync",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Unified AI rules management CLI tool that generates configuration files for various AI development tools",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",