rulesync 0.28.0 → 0.29.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/README.ja.md CHANGED
@@ -57,7 +57,7 @@ yarn global add rulesync
57
57
 
58
58
  1. **既存設定をインポート:**
59
59
  ```bash
60
- npx rulesync import --claude --cursor --copilot
60
+ npx rulesync import --claudecode --cursor --copilot
61
61
  ```
62
62
 
63
63
  2. **`.rulesync/`ディレクトリのインポートされたルールを確認・編集**
@@ -172,7 +172,7 @@ npx rulesync generate
172
172
  npx rulesync generate --copilot
173
173
  npx rulesync generate --cursor
174
174
  npx rulesync generate --cline
175
- npx rulesync generate --claude
175
+ npx rulesync generate --claudecode
176
176
  npx rulesync generate --roo
177
177
 
178
178
  # クリーンビルド(既存ファイルを最初に削除)
@@ -195,7 +195,7 @@ npx rulesync generate --base-dir ./apps/web,./apps/api,./packages/shared
195
195
 
196
196
  - `--delete`: 新しいファイルを作成する前に既存の生成済みファイルをすべて削除
197
197
  - `--verbose`: 生成プロセス中に詳細出力を表示
198
- - `--copilot`, `--cursor`, `--cline`, `--claude`, `--roo`: 指定されたツールのみ生成
198
+ - `--copilot`, `--cursor`, `--cline`, `--claudecode`, `--roo`: 指定されたツールのみ生成
199
199
  - `--base-dir <paths>`: 指定されたベースディレクトリに設定ファイルを生成(複数パスの場合はカンマ区切り)。異なるプロジェクトディレクトリにツール固有の設定を生成したいmonorepoセットアップに便利。
200
200
 
201
201
  ### 4. 既存設定のインポート
@@ -204,24 +204,24 @@ npx rulesync generate --base-dir ./apps/web,./apps/api,./packages/shared
204
204
 
205
205
  ```bash
206
206
  # 既存のAIツール設定からインポート
207
- npx rulesync import --claude # CLAUDE.mdからインポート
208
- npx rulesync import --cursor # .cursorrulesからインポート
209
- npx rulesync import --copilot # .github/copilot-instructions.mdからインポート
210
- npx rulesync import --cline # .cline/instructions.mdからインポート
211
- npx rulesync import --roo # .roo/instructions.mdからインポート
207
+ npx rulesync import --claudecode # CLAUDE.mdと.claude/memories/*.mdからインポート
208
+ npx rulesync import --cursor # .cursorrulesと.cursor/rules/*.mdからインポート
209
+ npx rulesync import --copilot # .github/copilot-instructions.mdと.github/instructions/*.instructions.mdからインポート
210
+ npx rulesync import --cline # .cline/instructions.mdからインポート
211
+ npx rulesync import --roo # .roo/instructions.mdからインポート
212
212
 
213
213
  # 複数のツールからインポート
214
- npx rulesync import --claude --cursor --copilot
214
+ npx rulesync import --claudecode --cursor --copilot
215
215
 
216
216
  # インポート時の詳細出力
217
- npx rulesync import --claude --verbose
217
+ npx rulesync import --claudecode --verbose
218
218
  ```
219
219
 
220
220
  importコマンドの動作:
221
221
  - 各AIツールの既存設定ファイルをパース
222
222
  - 適切なフロントマターを付けてrulesync形式に変換
223
223
  - インポートしたコンテンツで新しい`.rulesync/*.md`ファイルを作成
224
- - ファイル名の競合を避けるためツール固有のプレフィックスを使用(例:`claude__overview.md`)
224
+ - ファイル名の競合を避けるためツール固有のプレフィックスを使用(例:`claudecode__overview.md`)
225
225
  - 競合が発生した場合はユニークなファイル名を生成
226
226
 
227
227
  ### 5. その他のコマンド
package/README.md CHANGED
@@ -57,7 +57,7 @@ If you already have AI tool configurations, you can import them:
57
57
 
58
58
  1. **Import existing configurations:**
59
59
  ```bash
60
- npx rulesync import --claude --cursor --copilot
60
+ npx rulesync import --claudecode --cursor --copilot
61
61
  ```
62
62
 
63
63
  2. **Review and edit** the imported rules in `.rulesync/` directory
@@ -172,7 +172,7 @@ npx rulesync generate
172
172
  npx rulesync generate --copilot
173
173
  npx rulesync generate --cursor
174
174
  npx rulesync generate --cline
175
- npx rulesync generate --claude
175
+ npx rulesync generate --claudecode
176
176
  npx rulesync generate --roo
177
177
 
178
178
  # Clean build (delete existing files first)
@@ -195,7 +195,7 @@ npx rulesync generate --base-dir ./apps/web,./apps/api,./packages/shared
195
195
 
196
196
  - `--delete`: Remove all existing generated files before creating new ones
197
197
  - `--verbose`: Show detailed output during generation process
198
- - `--copilot`, `--cursor`, `--cline`, `--claude`, `--roo`: Generate only for specified tools
198
+ - `--copilot`, `--cursor`, `--cline`, `--claudecode`, `--roo`: Generate only for specified tools
199
199
  - `--base-dir <paths>`: Generate configuration files in specified base directories (comma-separated for multiple paths). Useful for monorepo setups where you want to generate tool-specific configurations in different project directories.
200
200
 
201
201
  ### 4. Import Existing Configurations
@@ -204,24 +204,24 @@ If you already have AI tool configurations in your project, you can import them
204
204
 
205
205
  ```bash
206
206
  # Import from existing AI tool configurations
207
- npx rulesync import --claude # Import from CLAUDE.md
208
- npx rulesync import --cursor # Import from .cursorrules
209
- npx rulesync import --copilot # Import from .github/copilot-instructions.md
210
- npx rulesync import --cline # Import from .cline/instructions.md
211
- npx rulesync import --roo # Import from .roo/instructions.md
207
+ npx rulesync import --claudecode # Import from CLAUDE.md and .claude/memories/*.md
208
+ npx rulesync import --cursor # Import from .cursorrules and .cursor/rules/*.md
209
+ npx rulesync import --copilot # Import from .github/copilot-instructions.md and .github/instructions/*.instructions.md
210
+ npx rulesync import --cline # Import from .cline/instructions.md
211
+ npx rulesync import --roo # Import from .roo/instructions.md
212
212
 
213
213
  # Import from multiple tools
214
- npx rulesync import --claude --cursor --copilot
214
+ npx rulesync import --claudecode --cursor --copilot
215
215
 
216
216
  # Verbose output during import
217
- npx rulesync import --claude --verbose
217
+ npx rulesync import --claudecode --verbose
218
218
  ```
219
219
 
220
220
  The import command will:
221
221
  - Parse existing configuration files from each AI tool
222
222
  - Convert them to rulesync format with appropriate frontmatter
223
223
  - Create new `.rulesync/*.md` files with imported content
224
- - Use tool-specific prefixes to avoid filename conflicts (e.g., `claude__overview.md`)
224
+ - Use tool-specific prefixes to avoid filename conflicts (e.g., `claudecode__overview.md`)
225
225
  - Generate unique filenames if conflicts occur
226
226
 
227
227
  ### 5. Other Commands
package/dist/index.js CHANGED
@@ -38,11 +38,11 @@ function getDefaultConfig() {
38
38
  copilot: ".github/instructions",
39
39
  cursor: ".cursor/rules",
40
40
  cline: ".clinerules",
41
- claude: ".",
41
+ claudecode: ".",
42
42
  roo: ".roo/rules"
43
43
  },
44
44
  watchEnabled: false,
45
- defaultTargets: ["copilot", "cursor", "cline", "claude", "roo"]
45
+ defaultTargets: ["copilot", "cursor", "cline", "claudecode", "roo"]
46
46
  };
47
47
  }
48
48
  function resolveTargets(targets, config) {
@@ -88,23 +88,23 @@ async function addCommand(filename) {
88
88
  }
89
89
  }
90
90
 
91
- // src/generators/claude.ts
91
+ // src/generators/claudecode.ts
92
92
  var import_node_path2 = require("path");
93
- async function generateClaudeConfig(rules, config, baseDir) {
93
+ async function generateClaudecodeConfig(rules, config, baseDir) {
94
94
  const outputs = [];
95
95
  const rootRules = rules.filter((r) => r.frontmatter.root === true);
96
96
  const detailRules = rules.filter((r) => r.frontmatter.root === false);
97
97
  const claudeMdContent = generateClaudeMarkdown(rootRules, detailRules);
98
- const claudeOutputDir = baseDir ? (0, import_node_path2.join)(baseDir, config.outputPaths.claude) : config.outputPaths.claude;
98
+ const claudeOutputDir = baseDir ? (0, import_node_path2.join)(baseDir, config.outputPaths.claudecode) : config.outputPaths.claudecode;
99
99
  outputs.push({
100
- tool: "claude",
100
+ tool: "claudecode",
101
101
  filepath: (0, import_node_path2.join)(claudeOutputDir, "CLAUDE.md"),
102
102
  content: claudeMdContent
103
103
  });
104
104
  for (const rule of detailRules) {
105
105
  const memoryContent = generateMemoryFile(rule);
106
106
  outputs.push({
107
- tool: "claude",
107
+ tool: "claudecode",
108
108
  filepath: (0, import_node_path2.join)(claudeOutputDir, ".claude", "memories", `${rule.filename}.md`),
109
109
  content: memoryContent
110
110
  });
@@ -350,8 +350,8 @@ async function generateForTool(tool, rules, config, baseDir) {
350
350
  return generateCursorConfig(rules, config, baseDir);
351
351
  case "cline":
352
352
  return generateClineConfig(rules, config, baseDir);
353
- case "claude":
354
- return await generateClaudeConfig(rules, config, baseDir);
353
+ case "claudecode":
354
+ return await generateClaudecodeConfig(rules, config, baseDir);
355
355
  case "roo":
356
356
  return generateRooConfig(rules, config, baseDir);
357
357
  default:
@@ -561,7 +561,7 @@ async function generateCommand(options = {}) {
561
561
  case "cline":
562
562
  deleteTasks.push(removeDirectory(config.outputPaths.cline));
563
563
  break;
564
- case "claude":
564
+ case "claudecode":
565
565
  deleteTasks.push(removeClaudeGeneratedFiles());
566
566
  break;
567
567
  case "roo":
@@ -658,9 +658,9 @@ ${linesToAdd.join("\n")}
658
658
 
659
659
  // src/core/importer.ts
660
660
  var import_node_path15 = require("path");
661
- var import_gray_matter2 = __toESM(require("gray-matter"));
661
+ var import_gray_matter4 = __toESM(require("gray-matter"));
662
662
 
663
- // src/parsers/claude.ts
663
+ // src/parsers/claudecode.ts
664
664
  var import_node_path10 = require("path");
665
665
  async function parseClaudeConfiguration(baseDir = process.cwd()) {
666
666
  const errors = [];
@@ -704,7 +704,7 @@ function parseClaudeMainFile(content, filepath) {
704
704
  }
705
705
  const frontmatter = {
706
706
  root: false,
707
- targets: ["claude"],
707
+ targets: ["claudecode"],
708
708
  description: "Main Claude Code configuration",
709
709
  globs: ["**/*"]
710
710
  };
@@ -728,7 +728,7 @@ async function parseClaudeMemoryFiles(memoryDir) {
728
728
  const filename = (0, import_node_path10.basename)(file, ".md");
729
729
  const frontmatter = {
730
730
  root: false,
731
- targets: ["claude"],
731
+ targets: ["claudecode"],
732
732
  description: `Memory file: ${filename}`,
733
733
  globs: ["**/*"]
734
734
  };
@@ -781,66 +781,147 @@ async function parseClineConfiguration(baseDir = process.cwd()) {
781
781
 
782
782
  // src/parsers/copilot.ts
783
783
  var import_node_path12 = require("path");
784
+ var import_gray_matter2 = __toESM(require("gray-matter"));
784
785
  async function parseCopilotConfiguration(baseDir = process.cwd()) {
785
786
  const errors = [];
786
787
  const rules = [];
787
788
  const copilotFilePath = (0, import_node_path12.join)(baseDir, ".github", "copilot-instructions.md");
788
- if (!await fileExists(copilotFilePath)) {
789
- errors.push(".github/copilot-instructions.md file not found");
790
- return { rules, errors };
789
+ if (await fileExists(copilotFilePath)) {
790
+ try {
791
+ const rawContent = await readFileContent(copilotFilePath);
792
+ const parsed = (0, import_gray_matter2.default)(rawContent);
793
+ const content = parsed.content.trim();
794
+ if (content) {
795
+ const frontmatter = {
796
+ root: false,
797
+ targets: ["copilot"],
798
+ description: "GitHub Copilot instructions",
799
+ globs: ["**/*"]
800
+ };
801
+ rules.push({
802
+ frontmatter,
803
+ content,
804
+ filename: "copilot-instructions",
805
+ filepath: copilotFilePath
806
+ });
807
+ }
808
+ } catch (error) {
809
+ const errorMessage = error instanceof Error ? error.message : String(error);
810
+ errors.push(`Failed to parse copilot-instructions.md: ${errorMessage}`);
811
+ }
791
812
  }
792
- try {
793
- const content = await readFileContent(copilotFilePath);
794
- if (content.trim()) {
795
- const frontmatter = {
796
- root: false,
797
- targets: ["copilot"],
798
- description: "GitHub Copilot instructions",
799
- globs: ["**/*"]
800
- };
801
- rules.push({
802
- frontmatter,
803
- content: content.trim(),
804
- filename: "copilot-instructions",
805
- filepath: copilotFilePath
806
- });
813
+ const instructionsDir = (0, import_node_path12.join)(baseDir, ".github", "instructions");
814
+ if (await fileExists(instructionsDir)) {
815
+ try {
816
+ const { readdir: readdir2 } = await import("fs/promises");
817
+ const files = await readdir2(instructionsDir);
818
+ for (const file of files) {
819
+ if (file.endsWith(".instructions.md")) {
820
+ const filePath = (0, import_node_path12.join)(instructionsDir, file);
821
+ const rawContent = await readFileContent(filePath);
822
+ const parsed = (0, import_gray_matter2.default)(rawContent);
823
+ const content = parsed.content.trim();
824
+ if (content) {
825
+ const filename = (0, import_node_path12.basename)(file, ".instructions.md");
826
+ const frontmatter = {
827
+ root: false,
828
+ targets: ["copilot"],
829
+ description: `Copilot instruction: ${filename}`,
830
+ globs: ["**/*"]
831
+ };
832
+ rules.push({
833
+ frontmatter,
834
+ content,
835
+ filename: `copilot-${filename}`,
836
+ filepath: filePath
837
+ });
838
+ }
839
+ }
840
+ }
841
+ } catch (error) {
842
+ const errorMessage = error instanceof Error ? error.message : String(error);
843
+ errors.push(`Failed to parse .github/instructions files: ${errorMessage}`);
807
844
  }
808
- } catch (error) {
809
- const errorMessage = error instanceof Error ? error.message : String(error);
810
- errors.push(`Failed to parse Copilot configuration: ${errorMessage}`);
845
+ }
846
+ if (rules.length === 0) {
847
+ errors.push(
848
+ "No Copilot configuration files found (.github/copilot-instructions.md or .github/instructions/*.instructions.md)"
849
+ );
811
850
  }
812
851
  return { rules, errors };
813
852
  }
814
853
 
815
854
  // src/parsers/cursor.ts
816
855
  var import_node_path13 = require("path");
856
+ var import_gray_matter3 = __toESM(require("gray-matter"));
817
857
  async function parseCursorConfiguration(baseDir = process.cwd()) {
818
858
  const errors = [];
819
859
  const rules = [];
820
860
  const cursorFilePath = (0, import_node_path13.join)(baseDir, ".cursorrules");
821
- if (!await fileExists(cursorFilePath)) {
822
- errors.push(".cursorrules file not found");
823
- return { rules, errors };
861
+ if (await fileExists(cursorFilePath)) {
862
+ try {
863
+ const rawContent = await readFileContent(cursorFilePath);
864
+ const parsed = (0, import_gray_matter3.default)(rawContent);
865
+ const content = parsed.content.trim();
866
+ if (content) {
867
+ const frontmatter = {
868
+ root: false,
869
+ targets: ["cursor"],
870
+ description: "Cursor IDE configuration rules",
871
+ globs: ["**/*"]
872
+ };
873
+ rules.push({
874
+ frontmatter,
875
+ content,
876
+ filename: "cursor-rules",
877
+ filepath: cursorFilePath
878
+ });
879
+ }
880
+ } catch (error) {
881
+ const errorMessage = error instanceof Error ? error.message : String(error);
882
+ errors.push(`Failed to parse .cursorrules file: ${errorMessage}`);
883
+ }
824
884
  }
825
- try {
826
- const content = await readFileContent(cursorFilePath);
827
- if (content.trim()) {
828
- const frontmatter = {
829
- root: false,
830
- targets: ["cursor"],
831
- description: "Cursor IDE configuration rules",
832
- globs: ["**/*"]
833
- };
834
- rules.push({
835
- frontmatter,
836
- content: content.trim(),
837
- filename: "cursor-rules",
838
- filepath: cursorFilePath
839
- });
885
+ const cursorRulesDir = (0, import_node_path13.join)(baseDir, ".cursor", "rules");
886
+ if (await fileExists(cursorRulesDir)) {
887
+ try {
888
+ const { readdir: readdir2 } = await import("fs/promises");
889
+ const files = await readdir2(cursorRulesDir);
890
+ for (const file of files) {
891
+ if (file.endsWith(".mdc")) {
892
+ const filePath = (0, import_node_path13.join)(cursorRulesDir, file);
893
+ try {
894
+ const rawContent = await readFileContent(filePath);
895
+ const parsed = (0, import_gray_matter3.default)(rawContent);
896
+ const content = parsed.content.trim();
897
+ if (content) {
898
+ const filename = (0, import_node_path13.basename)(file, ".mdc");
899
+ const frontmatter = {
900
+ root: false,
901
+ targets: ["cursor"],
902
+ description: `Cursor rule: ${filename}`,
903
+ globs: ["**/*"]
904
+ };
905
+ rules.push({
906
+ frontmatter,
907
+ content,
908
+ filename: `cursor-${filename}`,
909
+ filepath: filePath
910
+ });
911
+ }
912
+ } catch (error) {
913
+ const errorMessage = error instanceof Error ? error.message : String(error);
914
+ errors.push(`Failed to parse ${filePath}: ${errorMessage}`);
915
+ }
916
+ }
917
+ }
918
+ } catch (error) {
919
+ const errorMessage = error instanceof Error ? error.message : String(error);
920
+ errors.push(`Failed to parse .cursor/rules files: ${errorMessage}`);
840
921
  }
841
- } catch (error) {
842
- const errorMessage = error instanceof Error ? error.message : String(error);
843
- errors.push(`Failed to parse Cursor configuration: ${errorMessage}`);
922
+ }
923
+ if (rules.length === 0) {
924
+ errors.push("No Cursor configuration files found (.cursorrules or .cursor/rules/*.mdc)");
844
925
  }
845
926
  return { rules, errors };
846
927
  }
@@ -888,7 +969,7 @@ async function importConfiguration(options) {
888
969
  }
889
970
  try {
890
971
  switch (tool) {
891
- case "claude": {
972
+ case "claudecode": {
892
973
  const claudeResult = await parseClaudeConfiguration(baseDir);
893
974
  rules = claudeResult.rules;
894
975
  errors.push(...claudeResult.errors);
@@ -963,7 +1044,7 @@ async function importConfiguration(options) {
963
1044
  };
964
1045
  }
965
1046
  function generateRuleFileContent(rule) {
966
- const frontmatter = import_gray_matter2.default.stringify("", rule.frontmatter);
1047
+ const frontmatter = import_gray_matter4.default.stringify("", rule.frontmatter);
967
1048
  return frontmatter + rule.content;
968
1049
  }
969
1050
  async function generateUniqueFilename(rulesDir, baseFilename) {
@@ -979,14 +1060,14 @@ async function generateUniqueFilename(rulesDir, baseFilename) {
979
1060
  // src/cli/commands/import.ts
980
1061
  async function importCommand(options = {}) {
981
1062
  const tools = [];
982
- if (options.claude) tools.push("claude");
1063
+ if (options.claudecode) tools.push("claudecode");
983
1064
  if (options.cursor) tools.push("cursor");
984
1065
  if (options.copilot) tools.push("copilot");
985
1066
  if (options.cline) tools.push("cline");
986
1067
  if (options.roo) tools.push("roo");
987
1068
  if (tools.length === 0) {
988
1069
  console.error(
989
- "\u274C Please specify at least one tool to import from (--claude, --cursor, --copilot, --cline, --roo)"
1070
+ "\u274C Please specify at least one tool to import from (--claudecode, --cursor, --copilot, --cline, --roo)"
990
1071
  );
991
1072
  process.exit(1);
992
1073
  }
@@ -1197,7 +1278,7 @@ async function statusCommand() {
1197
1278
  const nonRootRules = rules.length - rootRules;
1198
1279
  console.log(` - Root rules: ${rootRules}`);
1199
1280
  console.log(` - Non-root rules: ${nonRootRules}`);
1200
- const targetCounts = { copilot: 0, cursor: 0, cline: 0, claude: 0, roo: 0 };
1281
+ const targetCounts = { copilot: 0, cursor: 0, cline: 0, claudecode: 0, roo: 0 };
1201
1282
  for (const rule of rules) {
1202
1283
  const targets = rule.frontmatter.targets[0] === "*" ? config.defaultTargets : rule.frontmatter.targets;
1203
1284
  for (const target of targets) {
@@ -1210,7 +1291,7 @@ async function statusCommand() {
1210
1291
  console.log(` - Copilot: ${targetCounts.copilot} rules`);
1211
1292
  console.log(` - Cursor: ${targetCounts.cursor} rules`);
1212
1293
  console.log(` - Cline: ${targetCounts.cline} rules`);
1213
- console.log(` - Claude: ${targetCounts.claude} rules`);
1294
+ console.log(` - Claude Code: ${targetCounts.claudecode} rules`);
1214
1295
  console.log(` - Roo: ${targetCounts.roo} rules`);
1215
1296
  }
1216
1297
  console.log("\n\u{1F4E4} Generated files:");
@@ -1309,12 +1390,12 @@ async function watchCommand() {
1309
1390
 
1310
1391
  // src/cli/index.ts
1311
1392
  var program = new import_commander.Command();
1312
- program.name("rulesync").description("Unified AI rules management CLI tool").version("0.28.0");
1393
+ program.name("rulesync").description("Unified AI rules management CLI tool").version("0.29.0");
1313
1394
  program.command("init").description("Initialize rulesync in current directory").action(initCommand);
1314
1395
  program.command("add <filename>").description("Add a new rule file").action(addCommand);
1315
1396
  program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);
1316
- program.command("import").description("Import configurations from AI tools to rulesync format").option("--claude", "Import from Claude Code (CLAUDE.md)").option("--cursor", "Import from Cursor (.cursorrules)").option("--copilot", "Import from GitHub Copilot (.github/copilot-instructions.md)").option("--cline", "Import from Cline (.cline/instructions.md)").option("--roo", "Import from Roo Code (.roo/instructions.md)").option("-v, --verbose", "Verbose output").action(importCommand);
1317
- 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("--roo", "Generate only for Roo Code").option("--delete", "Delete all existing files in output directories before generating").option(
1397
+ program.command("import").description("Import configurations from AI tools to rulesync format").option("--claudecode", "Import from Claude Code (CLAUDE.md)").option("--cursor", "Import from Cursor (.cursorrules)").option("--copilot", "Import from GitHub Copilot (.github/copilot-instructions.md)").option("--cline", "Import from Cline (.cline/instructions.md)").option("--roo", "Import from Roo Code (.roo/instructions.md)").option("-v, --verbose", "Verbose output").action(importCommand);
1398
+ 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("--claudecode", "Generate only for Claude Code").option("--roo", "Generate only for Roo Code").option("--delete", "Delete all existing files in output directories before generating").option(
1318
1399
  "-b, --base-dir <paths>",
1319
1400
  "Base directories to generate files (comma-separated for multiple paths)"
1320
1401
  ).option("-v, --verbose", "Verbose output").action(async (options) => {
@@ -1322,7 +1403,7 @@ program.command("generate").description("Generate configuration files for AI too
1322
1403
  if (options.copilot) tools.push("copilot");
1323
1404
  if (options.cursor) tools.push("cursor");
1324
1405
  if (options.cline) tools.push("cline");
1325
- if (options.claude) tools.push("claude");
1406
+ if (options.claudecode) tools.push("claudecode");
1326
1407
  if (options.roo) tools.push("roo");
1327
1408
  const generateOptions = {
1328
1409
  verbose: options.verbose,
package/dist/index.mjs CHANGED
@@ -15,11 +15,11 @@ function getDefaultConfig() {
15
15
  copilot: ".github/instructions",
16
16
  cursor: ".cursor/rules",
17
17
  cline: ".clinerules",
18
- claude: ".",
18
+ claudecode: ".",
19
19
  roo: ".roo/rules"
20
20
  },
21
21
  watchEnabled: false,
22
- defaultTargets: ["copilot", "cursor", "cline", "claude", "roo"]
22
+ defaultTargets: ["copilot", "cursor", "cline", "claudecode", "roo"]
23
23
  };
24
24
  }
25
25
  function resolveTargets(targets, config) {
@@ -65,23 +65,23 @@ async function addCommand(filename) {
65
65
  }
66
66
  }
67
67
 
68
- // src/generators/claude.ts
68
+ // src/generators/claudecode.ts
69
69
  import { join } from "path";
70
- async function generateClaudeConfig(rules, config, baseDir) {
70
+ async function generateClaudecodeConfig(rules, config, baseDir) {
71
71
  const outputs = [];
72
72
  const rootRules = rules.filter((r) => r.frontmatter.root === true);
73
73
  const detailRules = rules.filter((r) => r.frontmatter.root === false);
74
74
  const claudeMdContent = generateClaudeMarkdown(rootRules, detailRules);
75
- const claudeOutputDir = baseDir ? join(baseDir, config.outputPaths.claude) : config.outputPaths.claude;
75
+ const claudeOutputDir = baseDir ? join(baseDir, config.outputPaths.claudecode) : config.outputPaths.claudecode;
76
76
  outputs.push({
77
- tool: "claude",
77
+ tool: "claudecode",
78
78
  filepath: join(claudeOutputDir, "CLAUDE.md"),
79
79
  content: claudeMdContent
80
80
  });
81
81
  for (const rule of detailRules) {
82
82
  const memoryContent = generateMemoryFile(rule);
83
83
  outputs.push({
84
- tool: "claude",
84
+ tool: "claudecode",
85
85
  filepath: join(claudeOutputDir, ".claude", "memories", `${rule.filename}.md`),
86
86
  content: memoryContent
87
87
  });
@@ -327,8 +327,8 @@ async function generateForTool(tool, rules, config, baseDir) {
327
327
  return generateCursorConfig(rules, config, baseDir);
328
328
  case "cline":
329
329
  return generateClineConfig(rules, config, baseDir);
330
- case "claude":
331
- return await generateClaudeConfig(rules, config, baseDir);
330
+ case "claudecode":
331
+ return await generateClaudecodeConfig(rules, config, baseDir);
332
332
  case "roo":
333
333
  return generateRooConfig(rules, config, baseDir);
334
334
  default:
@@ -538,7 +538,7 @@ async function generateCommand(options = {}) {
538
538
  case "cline":
539
539
  deleteTasks.push(removeDirectory(config.outputPaths.cline));
540
540
  break;
541
- case "claude":
541
+ case "claudecode":
542
542
  deleteTasks.push(removeClaudeGeneratedFiles());
543
543
  break;
544
544
  case "roo":
@@ -635,9 +635,9 @@ ${linesToAdd.join("\n")}
635
635
 
636
636
  // src/core/importer.ts
637
637
  import { join as join13 } from "path";
638
- import matter2 from "gray-matter";
638
+ import matter4 from "gray-matter";
639
639
 
640
- // src/parsers/claude.ts
640
+ // src/parsers/claudecode.ts
641
641
  import { basename as basename2, join as join8 } from "path";
642
642
  async function parseClaudeConfiguration(baseDir = process.cwd()) {
643
643
  const errors = [];
@@ -681,7 +681,7 @@ function parseClaudeMainFile(content, filepath) {
681
681
  }
682
682
  const frontmatter = {
683
683
  root: false,
684
- targets: ["claude"],
684
+ targets: ["claudecode"],
685
685
  description: "Main Claude Code configuration",
686
686
  globs: ["**/*"]
687
687
  };
@@ -705,7 +705,7 @@ async function parseClaudeMemoryFiles(memoryDir) {
705
705
  const filename = basename2(file, ".md");
706
706
  const frontmatter = {
707
707
  root: false,
708
- targets: ["claude"],
708
+ targets: ["claudecode"],
709
709
  description: `Memory file: ${filename}`,
710
710
  globs: ["**/*"]
711
711
  };
@@ -757,67 +757,148 @@ async function parseClineConfiguration(baseDir = process.cwd()) {
757
757
  }
758
758
 
759
759
  // src/parsers/copilot.ts
760
- import { join as join10 } from "path";
760
+ import { basename as basename3, join as join10 } from "path";
761
+ import matter2 from "gray-matter";
761
762
  async function parseCopilotConfiguration(baseDir = process.cwd()) {
762
763
  const errors = [];
763
764
  const rules = [];
764
765
  const copilotFilePath = join10(baseDir, ".github", "copilot-instructions.md");
765
- if (!await fileExists(copilotFilePath)) {
766
- errors.push(".github/copilot-instructions.md file not found");
767
- return { rules, errors };
766
+ if (await fileExists(copilotFilePath)) {
767
+ try {
768
+ const rawContent = await readFileContent(copilotFilePath);
769
+ const parsed = matter2(rawContent);
770
+ const content = parsed.content.trim();
771
+ if (content) {
772
+ const frontmatter = {
773
+ root: false,
774
+ targets: ["copilot"],
775
+ description: "GitHub Copilot instructions",
776
+ globs: ["**/*"]
777
+ };
778
+ rules.push({
779
+ frontmatter,
780
+ content,
781
+ filename: "copilot-instructions",
782
+ filepath: copilotFilePath
783
+ });
784
+ }
785
+ } catch (error) {
786
+ const errorMessage = error instanceof Error ? error.message : String(error);
787
+ errors.push(`Failed to parse copilot-instructions.md: ${errorMessage}`);
788
+ }
768
789
  }
769
- try {
770
- const content = await readFileContent(copilotFilePath);
771
- if (content.trim()) {
772
- const frontmatter = {
773
- root: false,
774
- targets: ["copilot"],
775
- description: "GitHub Copilot instructions",
776
- globs: ["**/*"]
777
- };
778
- rules.push({
779
- frontmatter,
780
- content: content.trim(),
781
- filename: "copilot-instructions",
782
- filepath: copilotFilePath
783
- });
790
+ const instructionsDir = join10(baseDir, ".github", "instructions");
791
+ if (await fileExists(instructionsDir)) {
792
+ try {
793
+ const { readdir: readdir2 } = await import("fs/promises");
794
+ const files = await readdir2(instructionsDir);
795
+ for (const file of files) {
796
+ if (file.endsWith(".instructions.md")) {
797
+ const filePath = join10(instructionsDir, file);
798
+ const rawContent = await readFileContent(filePath);
799
+ const parsed = matter2(rawContent);
800
+ const content = parsed.content.trim();
801
+ if (content) {
802
+ const filename = basename3(file, ".instructions.md");
803
+ const frontmatter = {
804
+ root: false,
805
+ targets: ["copilot"],
806
+ description: `Copilot instruction: ${filename}`,
807
+ globs: ["**/*"]
808
+ };
809
+ rules.push({
810
+ frontmatter,
811
+ content,
812
+ filename: `copilot-${filename}`,
813
+ filepath: filePath
814
+ });
815
+ }
816
+ }
817
+ }
818
+ } catch (error) {
819
+ const errorMessage = error instanceof Error ? error.message : String(error);
820
+ errors.push(`Failed to parse .github/instructions files: ${errorMessage}`);
784
821
  }
785
- } catch (error) {
786
- const errorMessage = error instanceof Error ? error.message : String(error);
787
- errors.push(`Failed to parse Copilot configuration: ${errorMessage}`);
822
+ }
823
+ if (rules.length === 0) {
824
+ errors.push(
825
+ "No Copilot configuration files found (.github/copilot-instructions.md or .github/instructions/*.instructions.md)"
826
+ );
788
827
  }
789
828
  return { rules, errors };
790
829
  }
791
830
 
792
831
  // src/parsers/cursor.ts
793
- import { join as join11 } from "path";
832
+ import { basename as basename4, join as join11 } from "path";
833
+ import matter3 from "gray-matter";
794
834
  async function parseCursorConfiguration(baseDir = process.cwd()) {
795
835
  const errors = [];
796
836
  const rules = [];
797
837
  const cursorFilePath = join11(baseDir, ".cursorrules");
798
- if (!await fileExists(cursorFilePath)) {
799
- errors.push(".cursorrules file not found");
800
- return { rules, errors };
838
+ if (await fileExists(cursorFilePath)) {
839
+ try {
840
+ const rawContent = await readFileContent(cursorFilePath);
841
+ const parsed = matter3(rawContent);
842
+ const content = parsed.content.trim();
843
+ if (content) {
844
+ const frontmatter = {
845
+ root: false,
846
+ targets: ["cursor"],
847
+ description: "Cursor IDE configuration rules",
848
+ globs: ["**/*"]
849
+ };
850
+ rules.push({
851
+ frontmatter,
852
+ content,
853
+ filename: "cursor-rules",
854
+ filepath: cursorFilePath
855
+ });
856
+ }
857
+ } catch (error) {
858
+ const errorMessage = error instanceof Error ? error.message : String(error);
859
+ errors.push(`Failed to parse .cursorrules file: ${errorMessage}`);
860
+ }
801
861
  }
802
- try {
803
- const content = await readFileContent(cursorFilePath);
804
- if (content.trim()) {
805
- const frontmatter = {
806
- root: false,
807
- targets: ["cursor"],
808
- description: "Cursor IDE configuration rules",
809
- globs: ["**/*"]
810
- };
811
- rules.push({
812
- frontmatter,
813
- content: content.trim(),
814
- filename: "cursor-rules",
815
- filepath: cursorFilePath
816
- });
862
+ const cursorRulesDir = join11(baseDir, ".cursor", "rules");
863
+ if (await fileExists(cursorRulesDir)) {
864
+ try {
865
+ const { readdir: readdir2 } = await import("fs/promises");
866
+ const files = await readdir2(cursorRulesDir);
867
+ for (const file of files) {
868
+ if (file.endsWith(".mdc")) {
869
+ const filePath = join11(cursorRulesDir, file);
870
+ try {
871
+ const rawContent = await readFileContent(filePath);
872
+ const parsed = matter3(rawContent);
873
+ const content = parsed.content.trim();
874
+ if (content) {
875
+ const filename = basename4(file, ".mdc");
876
+ const frontmatter = {
877
+ root: false,
878
+ targets: ["cursor"],
879
+ description: `Cursor rule: ${filename}`,
880
+ globs: ["**/*"]
881
+ };
882
+ rules.push({
883
+ frontmatter,
884
+ content,
885
+ filename: `cursor-${filename}`,
886
+ filepath: filePath
887
+ });
888
+ }
889
+ } catch (error) {
890
+ const errorMessage = error instanceof Error ? error.message : String(error);
891
+ errors.push(`Failed to parse ${filePath}: ${errorMessage}`);
892
+ }
893
+ }
894
+ }
895
+ } catch (error) {
896
+ const errorMessage = error instanceof Error ? error.message : String(error);
897
+ errors.push(`Failed to parse .cursor/rules files: ${errorMessage}`);
817
898
  }
818
- } catch (error) {
819
- const errorMessage = error instanceof Error ? error.message : String(error);
820
- errors.push(`Failed to parse Cursor configuration: ${errorMessage}`);
899
+ }
900
+ if (rules.length === 0) {
901
+ errors.push("No Cursor configuration files found (.cursorrules or .cursor/rules/*.mdc)");
821
902
  }
822
903
  return { rules, errors };
823
904
  }
@@ -865,7 +946,7 @@ async function importConfiguration(options) {
865
946
  }
866
947
  try {
867
948
  switch (tool) {
868
- case "claude": {
949
+ case "claudecode": {
869
950
  const claudeResult = await parseClaudeConfiguration(baseDir);
870
951
  rules = claudeResult.rules;
871
952
  errors.push(...claudeResult.errors);
@@ -940,7 +1021,7 @@ async function importConfiguration(options) {
940
1021
  };
941
1022
  }
942
1023
  function generateRuleFileContent(rule) {
943
- const frontmatter = matter2.stringify("", rule.frontmatter);
1024
+ const frontmatter = matter4.stringify("", rule.frontmatter);
944
1025
  return frontmatter + rule.content;
945
1026
  }
946
1027
  async function generateUniqueFilename(rulesDir, baseFilename) {
@@ -956,14 +1037,14 @@ async function generateUniqueFilename(rulesDir, baseFilename) {
956
1037
  // src/cli/commands/import.ts
957
1038
  async function importCommand(options = {}) {
958
1039
  const tools = [];
959
- if (options.claude) tools.push("claude");
1040
+ if (options.claudecode) tools.push("claudecode");
960
1041
  if (options.cursor) tools.push("cursor");
961
1042
  if (options.copilot) tools.push("copilot");
962
1043
  if (options.cline) tools.push("cline");
963
1044
  if (options.roo) tools.push("roo");
964
1045
  if (tools.length === 0) {
965
1046
  console.error(
966
- "\u274C Please specify at least one tool to import from (--claude, --cursor, --copilot, --cline, --roo)"
1047
+ "\u274C Please specify at least one tool to import from (--claudecode, --cursor, --copilot, --cline, --roo)"
967
1048
  );
968
1049
  process.exit(1);
969
1050
  }
@@ -1174,7 +1255,7 @@ async function statusCommand() {
1174
1255
  const nonRootRules = rules.length - rootRules;
1175
1256
  console.log(` - Root rules: ${rootRules}`);
1176
1257
  console.log(` - Non-root rules: ${nonRootRules}`);
1177
- const targetCounts = { copilot: 0, cursor: 0, cline: 0, claude: 0, roo: 0 };
1258
+ const targetCounts = { copilot: 0, cursor: 0, cline: 0, claudecode: 0, roo: 0 };
1178
1259
  for (const rule of rules) {
1179
1260
  const targets = rule.frontmatter.targets[0] === "*" ? config.defaultTargets : rule.frontmatter.targets;
1180
1261
  for (const target of targets) {
@@ -1187,7 +1268,7 @@ async function statusCommand() {
1187
1268
  console.log(` - Copilot: ${targetCounts.copilot} rules`);
1188
1269
  console.log(` - Cursor: ${targetCounts.cursor} rules`);
1189
1270
  console.log(` - Cline: ${targetCounts.cline} rules`);
1190
- console.log(` - Claude: ${targetCounts.claude} rules`);
1271
+ console.log(` - Claude Code: ${targetCounts.claudecode} rules`);
1191
1272
  console.log(` - Roo: ${targetCounts.roo} rules`);
1192
1273
  }
1193
1274
  console.log("\n\u{1F4E4} Generated files:");
@@ -1286,12 +1367,12 @@ async function watchCommand() {
1286
1367
 
1287
1368
  // src/cli/index.ts
1288
1369
  var program = new Command();
1289
- program.name("rulesync").description("Unified AI rules management CLI tool").version("0.28.0");
1370
+ program.name("rulesync").description("Unified AI rules management CLI tool").version("0.29.0");
1290
1371
  program.command("init").description("Initialize rulesync in current directory").action(initCommand);
1291
1372
  program.command("add <filename>").description("Add a new rule file").action(addCommand);
1292
1373
  program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);
1293
- program.command("import").description("Import configurations from AI tools to rulesync format").option("--claude", "Import from Claude Code (CLAUDE.md)").option("--cursor", "Import from Cursor (.cursorrules)").option("--copilot", "Import from GitHub Copilot (.github/copilot-instructions.md)").option("--cline", "Import from Cline (.cline/instructions.md)").option("--roo", "Import from Roo Code (.roo/instructions.md)").option("-v, --verbose", "Verbose output").action(importCommand);
1294
- 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("--roo", "Generate only for Roo Code").option("--delete", "Delete all existing files in output directories before generating").option(
1374
+ program.command("import").description("Import configurations from AI tools to rulesync format").option("--claudecode", "Import from Claude Code (CLAUDE.md)").option("--cursor", "Import from Cursor (.cursorrules)").option("--copilot", "Import from GitHub Copilot (.github/copilot-instructions.md)").option("--cline", "Import from Cline (.cline/instructions.md)").option("--roo", "Import from Roo Code (.roo/instructions.md)").option("-v, --verbose", "Verbose output").action(importCommand);
1375
+ 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("--claudecode", "Generate only for Claude Code").option("--roo", "Generate only for Roo Code").option("--delete", "Delete all existing files in output directories before generating").option(
1295
1376
  "-b, --base-dir <paths>",
1296
1377
  "Base directories to generate files (comma-separated for multiple paths)"
1297
1378
  ).option("-v, --verbose", "Verbose output").action(async (options) => {
@@ -1299,7 +1380,7 @@ program.command("generate").description("Generate configuration files for AI too
1299
1380
  if (options.copilot) tools.push("copilot");
1300
1381
  if (options.cursor) tools.push("cursor");
1301
1382
  if (options.cline) tools.push("cline");
1302
- if (options.claude) tools.push("claude");
1383
+ if (options.claudecode) tools.push("claudecode");
1303
1384
  if (options.roo) tools.push("roo");
1304
1385
  const generateOptions = {
1305
1386
  verbose: options.verbose,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rulesync",
3
- "version": "0.28.0",
3
+ "version": "0.29.0",
4
4
  "description": "Unified AI rules management CLI tool that generates configuration files for various AI development tools",
5
5
  "keywords": [
6
6
  "ai",