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 +11 -11
- package/README.md +11 -11
- package/dist/index.js +147 -66
- package/dist/index.mjs +149 -68
- package/package.json +1 -1
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 --
|
|
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 --
|
|
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`, `--
|
|
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 --
|
|
208
|
-
npx rulesync import --cursor
|
|
209
|
-
npx rulesync import --copilot
|
|
210
|
-
npx rulesync import --cline
|
|
211
|
-
npx rulesync import --roo
|
|
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 --
|
|
214
|
+
npx rulesync import --claudecode --cursor --copilot
|
|
215
215
|
|
|
216
216
|
# インポート時の詳細出力
|
|
217
|
-
npx rulesync import --
|
|
217
|
+
npx rulesync import --claudecode --verbose
|
|
218
218
|
```
|
|
219
219
|
|
|
220
220
|
importコマンドの動作:
|
|
221
221
|
- 各AIツールの既存設定ファイルをパース
|
|
222
222
|
- 適切なフロントマターを付けてrulesync形式に変換
|
|
223
223
|
- インポートしたコンテンツで新しい`.rulesync/*.md`ファイルを作成
|
|
224
|
-
- ファイル名の競合を避けるためツール固有のプレフィックスを使用(例:`
|
|
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 --
|
|
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 --
|
|
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`, `--
|
|
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 --
|
|
208
|
-
npx rulesync import --cursor
|
|
209
|
-
npx rulesync import --copilot
|
|
210
|
-
npx rulesync import --cline
|
|
211
|
-
npx rulesync import --roo
|
|
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 --
|
|
214
|
+
npx rulesync import --claudecode --cursor --copilot
|
|
215
215
|
|
|
216
216
|
# Verbose output during import
|
|
217
|
-
npx rulesync import --
|
|
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., `
|
|
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
|
-
|
|
41
|
+
claudecode: ".",
|
|
42
42
|
roo: ".roo/rules"
|
|
43
43
|
},
|
|
44
44
|
watchEnabled: false,
|
|
45
|
-
defaultTargets: ["copilot", "cursor", "cline", "
|
|
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/
|
|
91
|
+
// src/generators/claudecode.ts
|
|
92
92
|
var import_node_path2 = require("path");
|
|
93
|
-
async function
|
|
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.
|
|
98
|
+
const claudeOutputDir = baseDir ? (0, import_node_path2.join)(baseDir, config.outputPaths.claudecode) : config.outputPaths.claudecode;
|
|
99
99
|
outputs.push({
|
|
100
|
-
tool: "
|
|
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: "
|
|
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 "
|
|
354
|
-
return await
|
|
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 "
|
|
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
|
|
661
|
+
var import_gray_matter4 = __toESM(require("gray-matter"));
|
|
662
662
|
|
|
663
|
-
// src/parsers/
|
|
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: ["
|
|
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: ["
|
|
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 (
|
|
789
|
-
|
|
790
|
-
|
|
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
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
const
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
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
|
-
}
|
|
809
|
-
|
|
810
|
-
errors.push(
|
|
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 (
|
|
822
|
-
|
|
823
|
-
|
|
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
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
const
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
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
|
-
}
|
|
842
|
-
|
|
843
|
-
errors.push(
|
|
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 "
|
|
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 =
|
|
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.
|
|
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 (--
|
|
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,
|
|
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.
|
|
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.
|
|
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("--
|
|
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("--
|
|
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.
|
|
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
|
-
|
|
18
|
+
claudecode: ".",
|
|
19
19
|
roo: ".roo/rules"
|
|
20
20
|
},
|
|
21
21
|
watchEnabled: false,
|
|
22
|
-
defaultTargets: ["copilot", "cursor", "cline", "
|
|
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/
|
|
68
|
+
// src/generators/claudecode.ts
|
|
69
69
|
import { join } from "path";
|
|
70
|
-
async function
|
|
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.
|
|
75
|
+
const claudeOutputDir = baseDir ? join(baseDir, config.outputPaths.claudecode) : config.outputPaths.claudecode;
|
|
76
76
|
outputs.push({
|
|
77
|
-
tool: "
|
|
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: "
|
|
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 "
|
|
331
|
-
return await
|
|
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 "
|
|
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
|
|
638
|
+
import matter4 from "gray-matter";
|
|
639
639
|
|
|
640
|
-
// src/parsers/
|
|
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: ["
|
|
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: ["
|
|
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 (
|
|
766
|
-
|
|
767
|
-
|
|
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
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
const
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
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
|
-
}
|
|
786
|
-
|
|
787
|
-
errors.push(
|
|
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 (
|
|
799
|
-
|
|
800
|
-
|
|
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
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
const
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
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
|
-
}
|
|
819
|
-
|
|
820
|
-
errors.push(
|
|
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 "
|
|
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 =
|
|
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.
|
|
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 (--
|
|
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,
|
|
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.
|
|
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.
|
|
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("--
|
|
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("--
|
|
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.
|
|
1383
|
+
if (options.claudecode) tools.push("claudecode");
|
|
1303
1384
|
if (options.roo) tools.push("roo");
|
|
1304
1385
|
const generateOptions = {
|
|
1305
1386
|
verbose: options.verbose,
|