rulesync 0.63.0 → 0.65.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.md +21 -3
- package/dist/amazonqcli-MW7XTVPN.js +9 -0
- package/dist/{augmentcode-HIZIQG2W.js → augmentcode-WCZCL7VR.js} +2 -2
- package/dist/{chunk-KUGTKMNW.js → chunk-4NWMCTN5.js} +5 -2
- package/dist/chunk-6AXPFPKI.js +17 -0
- package/dist/{chunk-LXTA7DBA.js → chunk-6SLEITCQ.js} +1 -1
- package/dist/chunk-DM2B7XUB.js +210 -0
- package/dist/{chunk-UEAYL4NT.js → chunk-FL5BF6JM.js} +1 -1
- package/dist/{chunk-4PSTOKKD.js → chunk-GIAQWZQ4.js} +1 -1
- package/dist/{chunk-YTU3SCQO.js → chunk-I4NVS7GE.js} +9 -3
- package/dist/{chunk-GQTMTBX4.js → chunk-JXOLLTNV.js} +89 -4
- package/dist/{chunk-NETSYSMD.js → chunk-LTWEI4PW.js} +1 -1
- package/dist/{chunk-AUUSMVCT.js → chunk-M2AUM37M.js} +3 -0
- package/dist/{chunk-M7NL7G7A.js → chunk-N6DASHJL.js} +1 -1
- package/dist/chunk-TX2CE4RR.js +17 -0
- package/dist/{chunk-2CW2KFB3.js → chunk-UGY5ALND.js} +1 -1
- package/dist/chunk-VRWNZTGW.js +17 -0
- package/dist/{chunk-U4PLVMCG.js → chunk-YC2BC7Z2.js} +1 -1
- package/dist/{claudecode-YTEFACCT.js → claudecode-RZSJPPBU.js} +3 -3
- package/dist/{cline-CKNUDEA3.js → cline-JTWWBQQ4.js} +3 -3
- package/dist/{codexcli-7SDGYI7D.js → codexcli-ATMFGRJR.js} +3 -3
- package/dist/{copilot-MOR3HHJX.js → copilot-H3CLGKDP.js} +2 -2
- package/dist/{cursor-YJGH7W24.js → cursor-ZUN5RZU6.js} +3 -3
- package/dist/{geminicli-E7KZTZ2G.js → geminicli-Q5HPIQCU.js} +3 -3
- package/dist/index.cjs +1213 -619
- package/dist/index.js +806 -488
- package/dist/{junie-5LEQU4BO.js → junie-JCLVC3MI.js} +3 -3
- package/dist/{kiro-YDHXY2MA.js → kiro-CNF6433S.js} +2 -2
- package/dist/opencode-EBS3CED2.js +17 -0
- package/dist/qwencode-JIT6KW7E.js +10 -0
- package/dist/{roo-L3QTTIPO.js → roo-KBTRH4TZ.js} +3 -2
- package/dist/{windsurf-4P6HEUBV.js → windsurf-ZAAWL6JJ.js} +3 -3
- package/package.json +2 -1
- package/dist/chunk-MDYDKNXQ.js +0 -61
- package/dist/chunk-PCATT4UZ.js +0 -78
package/dist/index.js
CHANGED
|
@@ -1,35 +1,40 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import "./chunk-
|
|
3
|
-
import "./chunk-
|
|
4
|
-
import "./chunk-
|
|
5
|
-
import "./chunk-
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
2
|
+
import "./chunk-6AXPFPKI.js";
|
|
3
|
+
import "./chunk-N6DASHJL.js";
|
|
4
|
+
import "./chunk-6SLEITCQ.js";
|
|
5
|
+
import "./chunk-TX2CE4RR.js";
|
|
6
|
+
import "./chunk-VRWNZTGW.js";
|
|
7
|
+
import "./chunk-LTWEI4PW.js";
|
|
8
|
+
import {
|
|
9
|
+
ensureDir,
|
|
10
|
+
fileExists,
|
|
11
|
+
findFiles,
|
|
12
|
+
findRuleFiles,
|
|
13
|
+
logger,
|
|
14
|
+
readFileContent,
|
|
15
|
+
removeClaudeGeneratedFiles,
|
|
16
|
+
removeDirectory,
|
|
17
|
+
resolvePath,
|
|
18
|
+
writeFileContent
|
|
19
|
+
} from "./chunk-DM2B7XUB.js";
|
|
20
|
+
import "./chunk-I4NVS7GE.js";
|
|
21
|
+
import "./chunk-YC2BC7Z2.js";
|
|
22
|
+
import "./chunk-FL5BF6JM.js";
|
|
23
|
+
import "./chunk-UGY5ALND.js";
|
|
24
|
+
import "./chunk-4NWMCTN5.js";
|
|
25
|
+
import "./chunk-GIAQWZQ4.js";
|
|
26
|
+
import "./chunk-JXOLLTNV.js";
|
|
14
27
|
import {
|
|
15
28
|
ALL_TOOL_TARGETS,
|
|
16
29
|
RulesyncTargetsSchema,
|
|
17
30
|
ToolTargetSchema,
|
|
18
31
|
ToolTargetsSchema,
|
|
19
32
|
isToolTarget
|
|
20
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-M2AUM37M.js";
|
|
21
34
|
|
|
22
35
|
// src/cli/index.ts
|
|
23
36
|
import { Command } from "commander";
|
|
24
37
|
|
|
25
|
-
// src/cli/commands/add.ts
|
|
26
|
-
import { mkdir, writeFile } from "fs/promises";
|
|
27
|
-
import * as path from "path";
|
|
28
|
-
|
|
29
|
-
// src/utils/config-loader.ts
|
|
30
|
-
import { loadConfig as loadC12Config } from "c12";
|
|
31
|
-
import { $ZodError } from "zod/v4/core";
|
|
32
|
-
|
|
33
38
|
// src/types/claudecode.ts
|
|
34
39
|
import { z } from "zod/mini";
|
|
35
40
|
var ClaudeSettingsSchema = z.looseObject({
|
|
@@ -70,6 +75,7 @@ var ConfigSchema = z3.object({
|
|
|
70
75
|
// src/types/config-options.ts
|
|
71
76
|
import { z as z4 } from "zod/mini";
|
|
72
77
|
var OutputPathsSchema = z4.object({
|
|
78
|
+
amazonqcli: z4.optional(z4.string()),
|
|
73
79
|
augmentcode: z4.optional(z4.string()),
|
|
74
80
|
"augmentcode-legacy": z4.optional(z4.string()),
|
|
75
81
|
copilot: z4.optional(z4.string()),
|
|
@@ -77,6 +83,8 @@ var OutputPathsSchema = z4.object({
|
|
|
77
83
|
cline: z4.optional(z4.string()),
|
|
78
84
|
claudecode: z4.optional(z4.string()),
|
|
79
85
|
codexcli: z4.optional(z4.string()),
|
|
86
|
+
opencode: z4.optional(z4.string()),
|
|
87
|
+
qwencode: z4.optional(z4.string()),
|
|
80
88
|
roo: z4.optional(z4.string()),
|
|
81
89
|
geminicli: z4.optional(z4.string()),
|
|
82
90
|
kiro: z4.optional(z4.string()),
|
|
@@ -127,7 +135,7 @@ var MergedConfigSchema = z4.object({
|
|
|
127
135
|
import { z as z5 } from "zod/mini";
|
|
128
136
|
var McpTransportTypeSchema = z5.enum(["stdio", "sse", "http"]);
|
|
129
137
|
var McpServerBaseSchema = z5.object({
|
|
130
|
-
command: z5.optional(z5.string()),
|
|
138
|
+
command: z5.optional(z5.union([z5.string(), z5.array(z5.string())])),
|
|
131
139
|
args: z5.optional(z5.array(z5.string())),
|
|
132
140
|
url: z5.optional(z5.string()),
|
|
133
141
|
httpUrl: z5.optional(z5.string()),
|
|
@@ -173,11 +181,20 @@ var GenerateOptionsSchema = z6.object({
|
|
|
173
181
|
watch: z6.optional(z6.boolean())
|
|
174
182
|
});
|
|
175
183
|
|
|
184
|
+
// src/cli/commands/add.ts
|
|
185
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
186
|
+
import * as path from "path";
|
|
187
|
+
|
|
188
|
+
// src/utils/config-loader.ts
|
|
189
|
+
import { loadConfig as loadC12Config } from "c12";
|
|
190
|
+
import { $ZodError } from "zod/v4/core";
|
|
191
|
+
|
|
176
192
|
// src/utils/config.ts
|
|
177
193
|
function getDefaultConfig() {
|
|
178
194
|
return {
|
|
179
195
|
aiRulesDir: ".rulesync",
|
|
180
196
|
outputPaths: {
|
|
197
|
+
amazonqcli: ".amazonq/rules",
|
|
181
198
|
augmentcode: ".",
|
|
182
199
|
"augmentcode-legacy": ".",
|
|
183
200
|
copilot: ".github/instructions",
|
|
@@ -185,6 +202,8 @@ function getDefaultConfig() {
|
|
|
185
202
|
cline: ".clinerules",
|
|
186
203
|
claudecode: ".",
|
|
187
204
|
codexcli: ".",
|
|
205
|
+
opencode: ".",
|
|
206
|
+
qwencode: ".qwen/memories",
|
|
188
207
|
roo: ".roo/rules",
|
|
189
208
|
geminicli: ".gemini/memories",
|
|
190
209
|
kiro: ".kiro/steering",
|
|
@@ -391,50 +410,6 @@ function mergeWithCliOptions(config, cliOptions) {
|
|
|
391
410
|
return merged;
|
|
392
411
|
}
|
|
393
412
|
|
|
394
|
-
// src/utils/logger.ts
|
|
395
|
-
import { consola } from "consola";
|
|
396
|
-
var Logger = class {
|
|
397
|
-
_verbose = false;
|
|
398
|
-
console = consola.withDefaults({
|
|
399
|
-
tag: "rulesync"
|
|
400
|
-
});
|
|
401
|
-
setVerbose(verbose) {
|
|
402
|
-
this._verbose = verbose;
|
|
403
|
-
}
|
|
404
|
-
get verbose() {
|
|
405
|
-
return this._verbose;
|
|
406
|
-
}
|
|
407
|
-
// Regular log (always shown, regardless of verbose)
|
|
408
|
-
log(message, ...args) {
|
|
409
|
-
this.console.log(message, ...args);
|
|
410
|
-
}
|
|
411
|
-
// Info level (shown only in verbose mode)
|
|
412
|
-
info(message, ...args) {
|
|
413
|
-
if (this._verbose) {
|
|
414
|
-
this.console.info(message, ...args);
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
// Success (always shown)
|
|
418
|
-
success(message, ...args) {
|
|
419
|
-
this.console.success(message, ...args);
|
|
420
|
-
}
|
|
421
|
-
// Warning (always shown)
|
|
422
|
-
warn(message, ...args) {
|
|
423
|
-
this.console.warn(message, ...args);
|
|
424
|
-
}
|
|
425
|
-
// Error (always shown)
|
|
426
|
-
error(message, ...args) {
|
|
427
|
-
this.console.error(message, ...args);
|
|
428
|
-
}
|
|
429
|
-
// Debug level (shown only in verbose mode)
|
|
430
|
-
debug(message, ...args) {
|
|
431
|
-
if (this._verbose) {
|
|
432
|
-
this.console.debug(message, ...args);
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
};
|
|
436
|
-
var logger = new Logger();
|
|
437
|
-
|
|
438
413
|
// src/cli/commands/add.ts
|
|
439
414
|
function sanitizeFilename(filename) {
|
|
440
415
|
return filename.endsWith(".md") ? filename.slice(0, -3) : filename;
|
|
@@ -508,89 +483,6 @@ async function safeAsyncOperation(operation, errorContext) {
|
|
|
508
483
|
}
|
|
509
484
|
}
|
|
510
485
|
|
|
511
|
-
// src/utils/file.ts
|
|
512
|
-
import { mkdir as mkdir2, readdir, readFile, rm, stat, writeFile as writeFile2 } from "fs/promises";
|
|
513
|
-
import { dirname, join as join2 } from "path";
|
|
514
|
-
async function ensureDir(dirPath) {
|
|
515
|
-
try {
|
|
516
|
-
await stat(dirPath);
|
|
517
|
-
} catch {
|
|
518
|
-
await mkdir2(dirPath, { recursive: true });
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
function resolvePath(relativePath, baseDir) {
|
|
522
|
-
return baseDir ? join2(baseDir, relativePath) : relativePath;
|
|
523
|
-
}
|
|
524
|
-
async function readFileContent(filepath) {
|
|
525
|
-
return readFile(filepath, "utf-8");
|
|
526
|
-
}
|
|
527
|
-
async function writeFileContent(filepath, content) {
|
|
528
|
-
await ensureDir(dirname(filepath));
|
|
529
|
-
await writeFile2(filepath, content, "utf-8");
|
|
530
|
-
}
|
|
531
|
-
async function fileExists(filepath) {
|
|
532
|
-
try {
|
|
533
|
-
await stat(filepath);
|
|
534
|
-
return true;
|
|
535
|
-
} catch {
|
|
536
|
-
return false;
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
async function findFiles(dir, extension = ".md") {
|
|
540
|
-
try {
|
|
541
|
-
const files = await readdir(dir);
|
|
542
|
-
return files.filter((file) => file.endsWith(extension)).map((file) => join2(dir, file));
|
|
543
|
-
} catch {
|
|
544
|
-
return [];
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
async function findRuleFiles(aiRulesDir) {
|
|
548
|
-
const rulesDir = join2(aiRulesDir, "rules");
|
|
549
|
-
const newLocationFiles = await findFiles(rulesDir, ".md");
|
|
550
|
-
const legacyLocationFiles = await findFiles(aiRulesDir, ".md");
|
|
551
|
-
const newLocationBasenames = new Set(
|
|
552
|
-
newLocationFiles.map((file) => file.split("/").pop()?.replace(/\.md$/, ""))
|
|
553
|
-
);
|
|
554
|
-
const filteredLegacyFiles = legacyLocationFiles.filter((file) => {
|
|
555
|
-
const basename6 = file.split("/").pop()?.replace(/\.md$/, "");
|
|
556
|
-
return !newLocationBasenames.has(basename6);
|
|
557
|
-
});
|
|
558
|
-
return [...newLocationFiles, ...filteredLegacyFiles];
|
|
559
|
-
}
|
|
560
|
-
async function removeDirectory(dirPath) {
|
|
561
|
-
const dangerousPaths = [".", "/", "~", "src", "node_modules"];
|
|
562
|
-
if (dangerousPaths.includes(dirPath) || dirPath === "") {
|
|
563
|
-
logger.warn(`Skipping deletion of dangerous path: ${dirPath}`);
|
|
564
|
-
return;
|
|
565
|
-
}
|
|
566
|
-
try {
|
|
567
|
-
if (await fileExists(dirPath)) {
|
|
568
|
-
await rm(dirPath, { recursive: true, force: true });
|
|
569
|
-
}
|
|
570
|
-
} catch (error) {
|
|
571
|
-
logger.warn(`Failed to remove directory ${dirPath}:`, error);
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
async function removeFile(filepath) {
|
|
575
|
-
try {
|
|
576
|
-
if (await fileExists(filepath)) {
|
|
577
|
-
await rm(filepath);
|
|
578
|
-
}
|
|
579
|
-
} catch (error) {
|
|
580
|
-
logger.warn(`Failed to remove file ${filepath}:`, error);
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
async function removeClaudeGeneratedFiles() {
|
|
584
|
-
const filesToRemove = ["CLAUDE.md", ".claude/memories"];
|
|
585
|
-
for (const fileOrDir of filesToRemove) {
|
|
586
|
-
if (fileOrDir.endsWith("/memories")) {
|
|
587
|
-
await removeDirectory(fileOrDir);
|
|
588
|
-
} else {
|
|
589
|
-
await removeFile(fileOrDir);
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
|
|
594
486
|
// src/cli/commands/config.ts
|
|
595
487
|
async function configCommand(options = {}) {
|
|
596
488
|
if (options.init) {
|
|
@@ -805,22 +697,22 @@ export default config;
|
|
|
805
697
|
import { join as join13 } from "path";
|
|
806
698
|
|
|
807
699
|
// src/core/command-generator.ts
|
|
808
|
-
import { join as
|
|
700
|
+
import { join as join3 } from "path";
|
|
809
701
|
|
|
810
702
|
// src/utils/command-generators.ts
|
|
811
|
-
import { join as
|
|
812
|
-
function generateYamlFrontmatter(command, options
|
|
813
|
-
const
|
|
814
|
-
if (options
|
|
815
|
-
|
|
703
|
+
import { join as join2 } from "path";
|
|
704
|
+
function generateYamlFrontmatter(command, options) {
|
|
705
|
+
const frontmatterLines = ["---"];
|
|
706
|
+
if (options?.includeDescription && command.frontmatter.description) {
|
|
707
|
+
frontmatterLines.push(`description: ${command.frontmatter.description}`);
|
|
816
708
|
}
|
|
817
|
-
if (options
|
|
709
|
+
if (options?.additionalFields) {
|
|
818
710
|
for (const field of options.additionalFields) {
|
|
819
|
-
|
|
711
|
+
frontmatterLines.push(`${field.key}: ${field.value}`);
|
|
820
712
|
}
|
|
821
713
|
}
|
|
822
|
-
|
|
823
|
-
return
|
|
714
|
+
frontmatterLines.push("---");
|
|
715
|
+
return frontmatterLines;
|
|
824
716
|
}
|
|
825
717
|
function buildCommandContent(command, frontmatterOptions) {
|
|
826
718
|
const frontmatter = generateYamlFrontmatter(command, frontmatterOptions);
|
|
@@ -831,12 +723,12 @@ ${command.content.trim()}
|
|
|
831
723
|
}
|
|
832
724
|
function getFlattenedCommandPath(filename, baseDir, subdir) {
|
|
833
725
|
const flattenedName = filename.replace(/\//g, "-");
|
|
834
|
-
return
|
|
726
|
+
return join2(baseDir, subdir, `${flattenedName}.md`);
|
|
835
727
|
}
|
|
836
728
|
function getHierarchicalCommandPath(filename, baseDir, subdir, extension = "md") {
|
|
837
729
|
const nameWithoutExt = filename.replace(/\.[^/.]+$/, "");
|
|
838
730
|
const fileWithExt = `${nameWithoutExt}.${extension}`;
|
|
839
|
-
return
|
|
731
|
+
return join2(baseDir, subdir, fileWithExt);
|
|
840
732
|
}
|
|
841
733
|
function escapeTomlString(str) {
|
|
842
734
|
return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
|
|
@@ -859,26 +751,75 @@ var syntaxConverters = {
|
|
|
859
751
|
}
|
|
860
752
|
};
|
|
861
753
|
|
|
862
|
-
// src/generators/commands/
|
|
863
|
-
var
|
|
754
|
+
// src/generators/commands/base.ts
|
|
755
|
+
var BaseCommandGenerator = class {
|
|
756
|
+
/**
|
|
757
|
+
* Generate command output for the specified tool
|
|
758
|
+
*/
|
|
864
759
|
generate(command, outputDir) {
|
|
865
760
|
const filepath = this.getOutputPath(command.filename, outputDir);
|
|
866
|
-
const content =
|
|
761
|
+
const content = this.processContent(command);
|
|
867
762
|
return {
|
|
868
|
-
tool:
|
|
763
|
+
tool: this.getToolName(),
|
|
869
764
|
filepath,
|
|
870
765
|
content
|
|
871
766
|
};
|
|
872
767
|
}
|
|
768
|
+
/**
|
|
769
|
+
* Get the output path for the command file
|
|
770
|
+
* Override this method if custom path logic is needed
|
|
771
|
+
*/
|
|
873
772
|
getOutputPath(filename, baseDir) {
|
|
874
|
-
|
|
773
|
+
if (this.supportsHierarchy()) {
|
|
774
|
+
return getHierarchicalCommandPath(
|
|
775
|
+
filename,
|
|
776
|
+
baseDir,
|
|
777
|
+
this.getCommandsDirectory(),
|
|
778
|
+
this.getFileExtension()
|
|
779
|
+
);
|
|
780
|
+
} else {
|
|
781
|
+
return getFlattenedCommandPath(filename, baseDir, this.getCommandsDirectory());
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
/**
|
|
785
|
+
* Whether this tool supports hierarchical directory structure
|
|
786
|
+
* Override to return true for tools that support nested commands
|
|
787
|
+
*/
|
|
788
|
+
supportsHierarchy() {
|
|
789
|
+
return false;
|
|
790
|
+
}
|
|
791
|
+
/**
|
|
792
|
+
* Get file extension for the target tool
|
|
793
|
+
* Override if tool uses different extension than .md
|
|
794
|
+
*/
|
|
795
|
+
getFileExtension() {
|
|
796
|
+
return "md";
|
|
797
|
+
}
|
|
798
|
+
};
|
|
799
|
+
|
|
800
|
+
// src/generators/commands/claudecode.ts
|
|
801
|
+
var ClaudeCodeCommandGenerator = class extends BaseCommandGenerator {
|
|
802
|
+
getToolName() {
|
|
803
|
+
return "claudecode";
|
|
804
|
+
}
|
|
805
|
+
getCommandsDirectory() {
|
|
806
|
+
return ".claude/commands";
|
|
807
|
+
}
|
|
808
|
+
processContent(command) {
|
|
809
|
+
return buildCommandContent(command, { includeDescription: true });
|
|
875
810
|
}
|
|
811
|
+
// Uses flattened structure by default (supportsHierarchy returns false)
|
|
876
812
|
};
|
|
877
813
|
|
|
878
814
|
// src/generators/commands/geminicli.ts
|
|
879
|
-
var GeminiCliCommandGenerator = class {
|
|
880
|
-
|
|
881
|
-
|
|
815
|
+
var GeminiCliCommandGenerator = class extends BaseCommandGenerator {
|
|
816
|
+
getToolName() {
|
|
817
|
+
return "geminicli";
|
|
818
|
+
}
|
|
819
|
+
getCommandsDirectory() {
|
|
820
|
+
return ".gemini/commands";
|
|
821
|
+
}
|
|
822
|
+
processContent(command) {
|
|
882
823
|
const convertedContent = syntaxConverters.toGeminiCli(command.content);
|
|
883
824
|
const tomlLines = [];
|
|
884
825
|
if (command.frontmatter.description) {
|
|
@@ -886,32 +827,28 @@ var GeminiCliCommandGenerator = class {
|
|
|
886
827
|
tomlLines.push("");
|
|
887
828
|
}
|
|
888
829
|
tomlLines.push(`prompt = """${convertedContent}"""`);
|
|
889
|
-
|
|
890
|
-
return {
|
|
891
|
-
tool: "geminicli",
|
|
892
|
-
filepath,
|
|
893
|
-
content
|
|
894
|
-
};
|
|
830
|
+
return tomlLines.join("\n") + "\n";
|
|
895
831
|
}
|
|
896
|
-
|
|
897
|
-
return
|
|
832
|
+
supportsHierarchy() {
|
|
833
|
+
return true;
|
|
834
|
+
}
|
|
835
|
+
getFileExtension() {
|
|
836
|
+
return "toml";
|
|
898
837
|
}
|
|
899
838
|
};
|
|
900
839
|
|
|
901
840
|
// src/generators/commands/roo.ts
|
|
902
|
-
var RooCommandGenerator = class {
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
const content = buildCommandContent(command);
|
|
906
|
-
return {
|
|
907
|
-
tool: "roo",
|
|
908
|
-
filepath,
|
|
909
|
-
content
|
|
910
|
-
};
|
|
841
|
+
var RooCommandGenerator = class extends BaseCommandGenerator {
|
|
842
|
+
getToolName() {
|
|
843
|
+
return "roo";
|
|
911
844
|
}
|
|
912
|
-
|
|
913
|
-
return
|
|
845
|
+
getCommandsDirectory() {
|
|
846
|
+
return ".roo/commands";
|
|
914
847
|
}
|
|
848
|
+
processContent(command) {
|
|
849
|
+
return buildCommandContent(command, { includeDescription: true });
|
|
850
|
+
}
|
|
851
|
+
// Uses flattened structure by default (supportsHierarchy returns false)
|
|
915
852
|
};
|
|
916
853
|
|
|
917
854
|
// src/generators/commands/index.ts
|
|
@@ -988,7 +925,7 @@ async function parseCommandFile(filepath) {
|
|
|
988
925
|
|
|
989
926
|
// src/core/command-generator.ts
|
|
990
927
|
async function generateCommands(projectRoot, baseDir, targets) {
|
|
991
|
-
const commandsDir =
|
|
928
|
+
const commandsDir = join3(projectRoot, ".rulesync", "commands");
|
|
992
929
|
if (!await fileExists(commandsDir)) {
|
|
993
930
|
return [];
|
|
994
931
|
}
|
|
@@ -1022,7 +959,7 @@ async function generateCommands(projectRoot, baseDir, targets) {
|
|
|
1022
959
|
}
|
|
1023
960
|
|
|
1024
961
|
// src/generators/ignore/shared-factory.ts
|
|
1025
|
-
import { join as
|
|
962
|
+
import { join as join4 } from "path";
|
|
1026
963
|
|
|
1027
964
|
// src/generators/ignore/shared-helpers.ts
|
|
1028
965
|
function extractIgnorePatternsFromRules(rules) {
|
|
@@ -1145,7 +1082,7 @@ function generateIgnoreFile(rules, config, ignoreConfig, baseDir) {
|
|
|
1145
1082
|
const outputs = [];
|
|
1146
1083
|
const content = generateIgnoreContent(rules, ignoreConfig);
|
|
1147
1084
|
const outputPath = baseDir || process.cwd();
|
|
1148
|
-
const filepath =
|
|
1085
|
+
const filepath = join4(outputPath, ignoreConfig.filename);
|
|
1149
1086
|
outputs.push({
|
|
1150
1087
|
tool: ignoreConfig.tool,
|
|
1151
1088
|
filepath,
|
|
@@ -1727,14 +1664,72 @@ async function generateKiroIgnoreFiles(rules, config, baseDir) {
|
|
|
1727
1664
|
return generateIgnoreFile(rules, config, ignoreConfigs.kiro, baseDir);
|
|
1728
1665
|
}
|
|
1729
1666
|
|
|
1667
|
+
// src/generators/ignore/qwencode.ts
|
|
1668
|
+
import { join as join5 } from "path";
|
|
1669
|
+
function extractQwenCodeFileFilteringPatterns(content) {
|
|
1670
|
+
const filtering = {};
|
|
1671
|
+
const configBlocks = content.match(/```(?:json|javascript)\s*\n([\s\S]*?)\n```/g);
|
|
1672
|
+
if (configBlocks) {
|
|
1673
|
+
for (const block of configBlocks) {
|
|
1674
|
+
try {
|
|
1675
|
+
const jsonContent = block.replace(/```(?:json|javascript)\s*\n/, "").replace(/\n```$/, "");
|
|
1676
|
+
const parsed = JSON.parse(jsonContent);
|
|
1677
|
+
if (parsed.fileFiltering) {
|
|
1678
|
+
Object.assign(filtering, parsed.fileFiltering);
|
|
1679
|
+
}
|
|
1680
|
+
} catch {
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
if (content.includes("respectGitIgnore")) {
|
|
1685
|
+
if (content.includes("respectGitIgnore: false") || content.includes('"respectGitIgnore": false')) {
|
|
1686
|
+
filtering.respectGitIgnore = false;
|
|
1687
|
+
} else {
|
|
1688
|
+
filtering.respectGitIgnore = true;
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
if (content.includes("enableRecursiveFileSearch")) {
|
|
1692
|
+
if (content.includes("enableRecursiveFileSearch: false") || content.includes('"enableRecursiveFileSearch": false')) {
|
|
1693
|
+
filtering.enableRecursiveFileSearch = false;
|
|
1694
|
+
} else {
|
|
1695
|
+
filtering.enableRecursiveFileSearch = true;
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
return Object.keys(filtering).length > 0 ? filtering : void 0;
|
|
1699
|
+
}
|
|
1700
|
+
function generateQwenCodeConfiguration(rules) {
|
|
1701
|
+
const config = {};
|
|
1702
|
+
config.fileFiltering = {
|
|
1703
|
+
respectGitIgnore: true,
|
|
1704
|
+
enableRecursiveFileSearch: true
|
|
1705
|
+
};
|
|
1706
|
+
for (const rule of rules) {
|
|
1707
|
+
const ruleFiltering = extractQwenCodeFileFilteringPatterns(rule.content);
|
|
1708
|
+
if (ruleFiltering) {
|
|
1709
|
+
Object.assign(config.fileFiltering, ruleFiltering);
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
return config;
|
|
1713
|
+
}
|
|
1714
|
+
async function generateQwenCodeIgnoreFiles(rules, config, baseDir) {
|
|
1715
|
+
const outputs = [];
|
|
1716
|
+
const outputPath = baseDir || process.cwd();
|
|
1717
|
+
const qwenConfig = generateQwenCodeConfiguration(rules);
|
|
1718
|
+
const settingsPath = join5(outputPath, ".qwen", "settings.json");
|
|
1719
|
+
outputs.push({
|
|
1720
|
+
tool: "qwencode",
|
|
1721
|
+
filepath: settingsPath,
|
|
1722
|
+
content: `${JSON.stringify(qwenConfig, null, 2)}
|
|
1723
|
+
`
|
|
1724
|
+
});
|
|
1725
|
+
return outputs;
|
|
1726
|
+
}
|
|
1727
|
+
|
|
1730
1728
|
// src/generators/ignore/windsurf.ts
|
|
1731
1729
|
function generateWindsurfIgnore(rules, config, baseDir) {
|
|
1732
1730
|
return generateIgnoreFile(rules, config, ignoreConfigs.windsurf, baseDir);
|
|
1733
1731
|
}
|
|
1734
1732
|
|
|
1735
|
-
// src/generators/rules/augmentcode.ts
|
|
1736
|
-
import { join as join8 } from "path";
|
|
1737
|
-
|
|
1738
1733
|
// src/generators/rules/shared-helpers.ts
|
|
1739
1734
|
import { join as join7 } from "path";
|
|
1740
1735
|
|
|
@@ -1891,7 +1886,61 @@ function generateIgnoreFile2(patterns, tool) {
|
|
|
1891
1886
|
return lines.join("\n");
|
|
1892
1887
|
}
|
|
1893
1888
|
|
|
1889
|
+
// src/generators/rules/amazonqcli.ts
|
|
1890
|
+
async function generateAmazonqcliConfig(rules, config, baseDir) {
|
|
1891
|
+
const generatorConfig = {
|
|
1892
|
+
tool: "amazonqcli",
|
|
1893
|
+
fileExtension: ".md",
|
|
1894
|
+
generateContent: generateRuleFile,
|
|
1895
|
+
generateRootContent: generateMainRulesFile,
|
|
1896
|
+
rootFilePath: ".amazonq/rules/main.md",
|
|
1897
|
+
generateDetailContent: generateRuleFile,
|
|
1898
|
+
detailSubDir: ".amazonq/rules"
|
|
1899
|
+
};
|
|
1900
|
+
return generateComplexRules(rules, config, generatorConfig, baseDir);
|
|
1901
|
+
}
|
|
1902
|
+
function generateMainRulesFile(rootRule, detailRules) {
|
|
1903
|
+
const lines = [];
|
|
1904
|
+
if (detailRules.length > 0) {
|
|
1905
|
+
lines.push("# Amazon Q Developer CLI Project Rules");
|
|
1906
|
+
lines.push("");
|
|
1907
|
+
lines.push("This file contains the main project rules. See also:");
|
|
1908
|
+
lines.push("");
|
|
1909
|
+
for (const rule of detailRules) {
|
|
1910
|
+
lines.push(`- ${rule.filename}.md: ${rule.frontmatter.description}`);
|
|
1911
|
+
}
|
|
1912
|
+
lines.push("");
|
|
1913
|
+
}
|
|
1914
|
+
if (rootRule) {
|
|
1915
|
+
if (detailRules.length > 0) {
|
|
1916
|
+
lines.push("## Overview");
|
|
1917
|
+
lines.push("");
|
|
1918
|
+
}
|
|
1919
|
+
lines.push(rootRule.content);
|
|
1920
|
+
lines.push("");
|
|
1921
|
+
} else if (detailRules.length === 0) {
|
|
1922
|
+
lines.push("# Amazon Q Developer CLI Project Rules");
|
|
1923
|
+
lines.push("");
|
|
1924
|
+
lines.push("This file contains project-specific rules and context for Amazon Q Developer CLI.");
|
|
1925
|
+
lines.push("");
|
|
1926
|
+
lines.push("## Development Standards");
|
|
1927
|
+
lines.push("");
|
|
1928
|
+
lines.push("Add your project-specific development standards here.");
|
|
1929
|
+
lines.push("");
|
|
1930
|
+
}
|
|
1931
|
+
return lines.join("\n").trim() + "\n";
|
|
1932
|
+
}
|
|
1933
|
+
function generateRuleFile(rule) {
|
|
1934
|
+
const lines = [];
|
|
1935
|
+
lines.push(`# ${rule.frontmatter.description || rule.filename}`);
|
|
1936
|
+
lines.push("");
|
|
1937
|
+
lines.push(rule.content.trim());
|
|
1938
|
+
lines.push("");
|
|
1939
|
+
return lines.join("\n");
|
|
1940
|
+
}
|
|
1941
|
+
|
|
1894
1942
|
// src/generators/rules/augmentcode.ts
|
|
1943
|
+
import { join as join8 } from "path";
|
|
1895
1944
|
async function generateAugmentcodeConfig(rules, config, baseDir) {
|
|
1896
1945
|
const outputs = createOutputsArray();
|
|
1897
1946
|
rules.forEach((rule) => {
|
|
@@ -1901,12 +1950,12 @@ async function generateAugmentcodeConfig(rules, config, baseDir) {
|
|
|
1901
1950
|
config,
|
|
1902
1951
|
baseDir,
|
|
1903
1952
|
join8(".augment", "rules", `${rule.filename}.md`),
|
|
1904
|
-
|
|
1953
|
+
generateRuleFile2(rule)
|
|
1905
1954
|
);
|
|
1906
1955
|
});
|
|
1907
1956
|
return outputs;
|
|
1908
1957
|
}
|
|
1909
|
-
function
|
|
1958
|
+
function generateRuleFile2(rule) {
|
|
1910
1959
|
const lines = [];
|
|
1911
1960
|
lines.push("---");
|
|
1912
1961
|
let ruleType = "manual";
|
|
@@ -2053,6 +2102,22 @@ function determineCursorRuleType(frontmatter) {
|
|
|
2053
2102
|
}
|
|
2054
2103
|
var GENERATOR_REGISTRY = {
|
|
2055
2104
|
// Simple generators - generate one file per rule
|
|
2105
|
+
amazonqcli: {
|
|
2106
|
+
type: "complex",
|
|
2107
|
+
tool: "amazonqcli",
|
|
2108
|
+
fileExtension: ".md",
|
|
2109
|
+
// ignoreFileName omitted - Amazon Q CLI doesn't have native ignore file support yet
|
|
2110
|
+
generateContent: (rule) => {
|
|
2111
|
+
const lines = [];
|
|
2112
|
+
if (rule.frontmatter.description) {
|
|
2113
|
+
lines.push(`# ${rule.frontmatter.description}
|
|
2114
|
+
`);
|
|
2115
|
+
}
|
|
2116
|
+
lines.push(rule.content.trim());
|
|
2117
|
+
return lines.join("\n");
|
|
2118
|
+
}
|
|
2119
|
+
// Complex generation handled by existing generator
|
|
2120
|
+
},
|
|
2056
2121
|
cline: {
|
|
2057
2122
|
type: "simple",
|
|
2058
2123
|
tool: "cline",
|
|
@@ -2219,6 +2284,22 @@ var GENERATOR_REGISTRY = {
|
|
|
2219
2284
|
const lines = [];
|
|
2220
2285
|
if (rule.frontmatter.description) {
|
|
2221
2286
|
lines.push(`# ${rule.frontmatter.description}
|
|
2287
|
+
`);
|
|
2288
|
+
}
|
|
2289
|
+
lines.push(rule.content.trim());
|
|
2290
|
+
return lines.join("\n");
|
|
2291
|
+
}
|
|
2292
|
+
// Complex generation handled by existing generator
|
|
2293
|
+
},
|
|
2294
|
+
opencode: {
|
|
2295
|
+
type: "complex",
|
|
2296
|
+
tool: "opencode",
|
|
2297
|
+
fileExtension: ".md",
|
|
2298
|
+
// ignoreFileName omitted - OpenCode doesn't use dedicated ignore files
|
|
2299
|
+
generateContent: (rule) => {
|
|
2300
|
+
const lines = [];
|
|
2301
|
+
if (rule.frontmatter.description) {
|
|
2302
|
+
lines.push(`# ${rule.frontmatter.description}
|
|
2222
2303
|
`);
|
|
2223
2304
|
}
|
|
2224
2305
|
lines.push(rule.content.trim());
|
|
@@ -2235,6 +2316,22 @@ var GENERATOR_REGISTRY = {
|
|
|
2235
2316
|
const lines = [];
|
|
2236
2317
|
if (rule.frontmatter.description) {
|
|
2237
2318
|
lines.push(`# ${rule.frontmatter.description}
|
|
2319
|
+
`);
|
|
2320
|
+
}
|
|
2321
|
+
lines.push(rule.content.trim());
|
|
2322
|
+
return lines.join("\n");
|
|
2323
|
+
}
|
|
2324
|
+
// Complex generation handled by existing generator
|
|
2325
|
+
},
|
|
2326
|
+
qwencode: {
|
|
2327
|
+
type: "complex",
|
|
2328
|
+
tool: "qwencode",
|
|
2329
|
+
fileExtension: ".md",
|
|
2330
|
+
// ignoreFileName omitted - Qwen Code uses git-aware filtering instead of dedicated ignore files
|
|
2331
|
+
generateContent: (rule) => {
|
|
2332
|
+
const lines = [];
|
|
2333
|
+
if (rule.frontmatter.description) {
|
|
2334
|
+
lines.push(`# ${rule.frontmatter.description}
|
|
2238
2335
|
`);
|
|
2239
2336
|
}
|
|
2240
2337
|
lines.push(rule.content.trim());
|
|
@@ -2261,8 +2358,8 @@ async function generateFromRegistry(tool, rules, config, baseDir) {
|
|
|
2261
2358
|
const enhancedConfig = {
|
|
2262
2359
|
tool: generatorConfig.tool,
|
|
2263
2360
|
fileExtension: generatorConfig.fileExtension,
|
|
2264
|
-
ignoreFileName: generatorConfig.ignoreFileName,
|
|
2265
2361
|
generateContent: generatorConfig.generateContent,
|
|
2362
|
+
...generatorConfig.ignoreFileName && { ignoreFileName: generatorConfig.ignoreFileName },
|
|
2266
2363
|
...generatorConfig.generateRootContent && {
|
|
2267
2364
|
generateRootContent: generatorConfig.generateRootContent
|
|
2268
2365
|
},
|
|
@@ -2291,53 +2388,94 @@ var generateCopilotConfig = createSimpleGenerator("copilot");
|
|
|
2291
2388
|
var generateWindsurfConfig = createSimpleGenerator("windsurf");
|
|
2292
2389
|
var generateKiroConfig = createSimpleGenerator("kiro");
|
|
2293
2390
|
var generateRooConfig = createSimpleGenerator("roo");
|
|
2391
|
+
var generateQwencodeConfig = createSimpleGenerator("qwencode");
|
|
2294
2392
|
|
|
2295
|
-
// src/
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
const
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
content: ignoreContent
|
|
2393
|
+
// src/utils/xml-document-generator.ts
|
|
2394
|
+
import { XMLBuilder } from "fast-xml-parser";
|
|
2395
|
+
function generateRootMarkdownWithXmlDocs(rootRule, memoryRules, config) {
|
|
2396
|
+
const lines = [];
|
|
2397
|
+
if (memoryRules.length > 0) {
|
|
2398
|
+
lines.push(
|
|
2399
|
+
"Please also reference the following documents as needed. In this case, `@` stands for the project root directory."
|
|
2400
|
+
);
|
|
2401
|
+
lines.push("");
|
|
2402
|
+
const documentsData = {
|
|
2403
|
+
Documents: {
|
|
2404
|
+
Document: memoryRules.map((rule) => {
|
|
2405
|
+
const relativePath = `@${config.memorySubDir}/${rule.filename}.md`;
|
|
2406
|
+
const document = {
|
|
2407
|
+
Path: relativePath,
|
|
2408
|
+
Description: rule.frontmatter.description
|
|
2409
|
+
};
|
|
2410
|
+
if (rule.frontmatter.globs.length > 0) {
|
|
2411
|
+
document.FilePatterns = rule.frontmatter.globs.join(", ");
|
|
2412
|
+
}
|
|
2413
|
+
return document;
|
|
2414
|
+
})
|
|
2415
|
+
}
|
|
2416
|
+
};
|
|
2417
|
+
const builder = new XMLBuilder({
|
|
2418
|
+
format: true,
|
|
2419
|
+
ignoreAttributes: false,
|
|
2420
|
+
suppressEmptyNode: false
|
|
2324
2421
|
});
|
|
2422
|
+
const xmlContent = builder.build(documentsData);
|
|
2423
|
+
lines.push(xmlContent);
|
|
2424
|
+
lines.push("");
|
|
2425
|
+
lines.push("");
|
|
2325
2426
|
}
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
if (!content) {
|
|
2333
|
-
continue;
|
|
2334
|
-
}
|
|
2335
|
-
sections.push(content);
|
|
2427
|
+
if (rootRule) {
|
|
2428
|
+
lines.push(rootRule.content.trim());
|
|
2429
|
+
} else if (memoryRules.length === 0) {
|
|
2430
|
+
lines.push(`# ${config.fallbackTitle}`);
|
|
2431
|
+
lines.push("");
|
|
2432
|
+
lines.push("No configuration rules have been defined yet.");
|
|
2336
2433
|
}
|
|
2337
|
-
return
|
|
2434
|
+
return lines.join("\n");
|
|
2338
2435
|
}
|
|
2339
2436
|
|
|
2340
|
-
// src/generators/rules/
|
|
2437
|
+
// src/generators/rules/codexcli.ts
|
|
2438
|
+
async function generateCodexConfig(rules, config, baseDir) {
|
|
2439
|
+
const outputs = [];
|
|
2440
|
+
const nonEmptyRules = rules.filter((rule) => rule.content.trim().length > 0);
|
|
2441
|
+
if (nonEmptyRules.length > 0) {
|
|
2442
|
+
const generatorConfig = {
|
|
2443
|
+
tool: "codexcli",
|
|
2444
|
+
fileExtension: ".md",
|
|
2445
|
+
ignoreFileName: ".codexignore",
|
|
2446
|
+
generateContent: generateCodexMemoryMarkdown,
|
|
2447
|
+
generateDetailContent: generateCodexMemoryMarkdown,
|
|
2448
|
+
generateRootContent: generateCodexRootMarkdown,
|
|
2449
|
+
rootFilePath: "AGENTS.md",
|
|
2450
|
+
detailSubDir: ".codex/memories"
|
|
2451
|
+
};
|
|
2452
|
+
const ruleOutputs = await generateComplexRules(nonEmptyRules, config, generatorConfig, baseDir);
|
|
2453
|
+
outputs.push(...ruleOutputs);
|
|
2454
|
+
} else {
|
|
2455
|
+
const ignorePatterns = await loadIgnorePatterns(baseDir);
|
|
2456
|
+
if (ignorePatterns.patterns.length > 0) {
|
|
2457
|
+
const ignorePath = resolvePath(".codexignore", baseDir);
|
|
2458
|
+
const ignoreContent = generateIgnoreFile2(ignorePatterns.patterns, "codexcli");
|
|
2459
|
+
outputs.push({
|
|
2460
|
+
tool: "codexcli",
|
|
2461
|
+
filepath: ignorePath,
|
|
2462
|
+
content: ignoreContent
|
|
2463
|
+
});
|
|
2464
|
+
}
|
|
2465
|
+
}
|
|
2466
|
+
return outputs;
|
|
2467
|
+
}
|
|
2468
|
+
function generateCodexMemoryMarkdown(rule) {
|
|
2469
|
+
return rule.content.trim();
|
|
2470
|
+
}
|
|
2471
|
+
function generateCodexRootMarkdown(rootRule, memoryRules, _baseDir) {
|
|
2472
|
+
return generateRootMarkdownWithXmlDocs(rootRule, memoryRules, {
|
|
2473
|
+
memorySubDir: ".codex/memories",
|
|
2474
|
+
fallbackTitle: "OpenAI Codex CLI Configuration"
|
|
2475
|
+
});
|
|
2476
|
+
}
|
|
2477
|
+
|
|
2478
|
+
// src/generators/rules/geminicli.ts
|
|
2341
2479
|
async function generateGeminiConfig(rules, config, baseDir) {
|
|
2342
2480
|
const generatorConfig = {
|
|
2343
2481
|
tool: "geminicli",
|
|
@@ -2355,28 +2493,10 @@ function generateGeminiMemoryMarkdown(rule) {
|
|
|
2355
2493
|
return rule.content.trim();
|
|
2356
2494
|
}
|
|
2357
2495
|
function generateGeminiRootMarkdown(rootRule, memoryRules, _baseDir) {
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
lines.push("| Document | Description | File Patterns |");
|
|
2363
|
-
lines.push("|----------|-------------|---------------|");
|
|
2364
|
-
for (const rule of memoryRules) {
|
|
2365
|
-
const relativePath = `@.gemini/memories/${rule.filename}.md`;
|
|
2366
|
-
const filePatterns = rule.frontmatter.globs.length > 0 ? rule.frontmatter.globs.join(", ") : "-";
|
|
2367
|
-
lines.push(`| ${relativePath} | ${rule.frontmatter.description} | ${filePatterns} |`);
|
|
2368
|
-
}
|
|
2369
|
-
lines.push("");
|
|
2370
|
-
lines.push("");
|
|
2371
|
-
}
|
|
2372
|
-
if (rootRule) {
|
|
2373
|
-
lines.push(rootRule.content.trim());
|
|
2374
|
-
} else if (memoryRules.length === 0) {
|
|
2375
|
-
lines.push("# Gemini CLI Configuration");
|
|
2376
|
-
lines.push("");
|
|
2377
|
-
lines.push("No configuration rules have been defined yet.");
|
|
2378
|
-
}
|
|
2379
|
-
return lines.join("\n");
|
|
2496
|
+
return generateRootMarkdownWithXmlDocs(rootRule, memoryRules, {
|
|
2497
|
+
memorySubDir: ".gemini/memories",
|
|
2498
|
+
fallbackTitle: "Gemini CLI Configuration"
|
|
2499
|
+
});
|
|
2380
2500
|
}
|
|
2381
2501
|
|
|
2382
2502
|
// src/generators/rules/junie.ts
|
|
@@ -2406,6 +2526,54 @@ function generateGuidelinesMarkdown(rootRule, detailRules) {
|
|
|
2406
2526
|
return lines.join("\n").trim();
|
|
2407
2527
|
}
|
|
2408
2528
|
|
|
2529
|
+
// src/generators/rules/opencode.ts
|
|
2530
|
+
async function generateOpenCodeConfig(rules, config, baseDir) {
|
|
2531
|
+
const generatorConfig = {
|
|
2532
|
+
tool: "opencode",
|
|
2533
|
+
fileExtension: ".md",
|
|
2534
|
+
// ignoreFileName omitted - OpenCode doesn't use dedicated ignore files
|
|
2535
|
+
generateContent: generateOpenCodeMarkdown,
|
|
2536
|
+
generateDetailContent: generateOpenCodeMarkdown,
|
|
2537
|
+
generateRootContent: generateOpenCodeRootMarkdown,
|
|
2538
|
+
rootFilePath: "AGENTS.md",
|
|
2539
|
+
detailSubDir: ".opencode/memories"
|
|
2540
|
+
};
|
|
2541
|
+
return generateComplexRules(rules, config, generatorConfig, baseDir);
|
|
2542
|
+
}
|
|
2543
|
+
function generateOpenCodeMarkdown(rule) {
|
|
2544
|
+
return rule.content.trim();
|
|
2545
|
+
}
|
|
2546
|
+
function generateOpenCodeRootMarkdown(rootRule, memoryRules, _baseDir) {
|
|
2547
|
+
return generateRootMarkdownWithXmlDocs(rootRule, memoryRules, {
|
|
2548
|
+
memorySubDir: ".opencode/memories",
|
|
2549
|
+
fallbackTitle: "OpenCode Configuration"
|
|
2550
|
+
});
|
|
2551
|
+
}
|
|
2552
|
+
|
|
2553
|
+
// src/generators/rules/qwencode.ts
|
|
2554
|
+
async function generateQwencodeConfig2(rules, config, baseDir) {
|
|
2555
|
+
const generatorConfig = {
|
|
2556
|
+
tool: "qwencode",
|
|
2557
|
+
fileExtension: ".md",
|
|
2558
|
+
// ignoreFileName omitted - Qwen Code uses git-aware filtering instead of dedicated ignore files
|
|
2559
|
+
generateContent: generateQwenMemoryMarkdown,
|
|
2560
|
+
generateDetailContent: generateQwenMemoryMarkdown,
|
|
2561
|
+
generateRootContent: generateQwenRootMarkdown,
|
|
2562
|
+
rootFilePath: "QWEN.md",
|
|
2563
|
+
detailSubDir: ".qwen/memories"
|
|
2564
|
+
};
|
|
2565
|
+
return generateComplexRules(rules, config, generatorConfig, baseDir);
|
|
2566
|
+
}
|
|
2567
|
+
function generateQwenMemoryMarkdown(rule) {
|
|
2568
|
+
return rule.content.trim();
|
|
2569
|
+
}
|
|
2570
|
+
function generateQwenRootMarkdown(rootRule, memoryRules, _baseDir) {
|
|
2571
|
+
return generateRootMarkdownWithXmlDocs(rootRule, memoryRules, {
|
|
2572
|
+
memorySubDir: ".qwen/memories",
|
|
2573
|
+
fallbackTitle: "Qwen Code Configuration"
|
|
2574
|
+
});
|
|
2575
|
+
}
|
|
2576
|
+
|
|
2409
2577
|
// src/core/generator.ts
|
|
2410
2578
|
async function generateConfigurations(rules, config, targetTools, baseDir) {
|
|
2411
2579
|
const outputs = createOutputsArray();
|
|
@@ -2438,6 +2606,8 @@ function filterRulesForTool(rules, tool, config) {
|
|
|
2438
2606
|
}
|
|
2439
2607
|
async function generateForTool(tool, rules, config, baseDir) {
|
|
2440
2608
|
switch (tool) {
|
|
2609
|
+
case "amazonqcli":
|
|
2610
|
+
return await generateAmazonqcliConfig(rules, config, baseDir);
|
|
2441
2611
|
case "augmentcode": {
|
|
2442
2612
|
const augmentRulesOutputs = await generateAugmentcodeConfig(rules, config, baseDir);
|
|
2443
2613
|
const augmentIgnoreOutputs = await generateAugmentCodeIgnoreFiles(rules, config, baseDir);
|
|
@@ -2476,6 +2646,13 @@ async function generateForTool(tool, rules, config, baseDir) {
|
|
|
2476
2646
|
const kiroIgnoreOutputs = await generateKiroIgnoreFiles(rules, config, baseDir);
|
|
2477
2647
|
return [...kiroRulesOutputs, ...kiroIgnoreOutputs];
|
|
2478
2648
|
}
|
|
2649
|
+
case "opencode":
|
|
2650
|
+
return generateOpenCodeConfig(rules, config, baseDir);
|
|
2651
|
+
case "qwencode": {
|
|
2652
|
+
const qwenRulesOutputs = await generateQwencodeConfig2(rules, config, baseDir);
|
|
2653
|
+
const qwenIgnoreOutputs = await generateQwenCodeIgnoreFiles(rules, config, baseDir);
|
|
2654
|
+
return [...qwenRulesOutputs, ...qwenIgnoreOutputs];
|
|
2655
|
+
}
|
|
2479
2656
|
case "windsurf": {
|
|
2480
2657
|
const windsurfRulesOutputs = await generateWindsurfConfig(rules, config, baseDir);
|
|
2481
2658
|
const windsurfIgnoreOutputs = await generateWindsurfIgnore(rules, config, baseDir);
|
|
@@ -2639,30 +2816,68 @@ function parseMcpConfig(projectRoot) {
|
|
|
2639
2816
|
async function generateMcpConfigurations(mcpConfig, baseDir, targetTools) {
|
|
2640
2817
|
const outputs = [];
|
|
2641
2818
|
const toolMap = {
|
|
2642
|
-
|
|
2819
|
+
amazonqcli: async (servers, dir) => {
|
|
2820
|
+
const config = {
|
|
2821
|
+
aiRulesDir: ".rulesync",
|
|
2822
|
+
outputPaths: {
|
|
2823
|
+
amazonqcli: ".amazonq/rules",
|
|
2824
|
+
augmentcode: ".",
|
|
2825
|
+
"augmentcode-legacy": ".",
|
|
2826
|
+
copilot: ".github/instructions",
|
|
2827
|
+
cursor: ".cursor/rules",
|
|
2828
|
+
cline: ".clinerules",
|
|
2829
|
+
claudecode: ".",
|
|
2830
|
+
codexcli: ".",
|
|
2831
|
+
opencode: ".",
|
|
2832
|
+
qwencode: ".qwen/memories",
|
|
2833
|
+
roo: ".roo/rules",
|
|
2834
|
+
geminicli: ".gemini/memories",
|
|
2835
|
+
kiro: ".kiro/steering",
|
|
2836
|
+
junie: ".",
|
|
2837
|
+
windsurf: "."
|
|
2838
|
+
},
|
|
2839
|
+
watchEnabled: false,
|
|
2840
|
+
defaultTargets: []
|
|
2841
|
+
};
|
|
2842
|
+
const results = await (await import("./amazonqcli-MW7XTVPN.js")).generateAmazonqcliMcp(
|
|
2843
|
+
servers,
|
|
2844
|
+
config,
|
|
2845
|
+
dir
|
|
2846
|
+
);
|
|
2847
|
+
return results.map((result) => ({ filepath: result.filepath, content: result.content }));
|
|
2848
|
+
},
|
|
2849
|
+
augmentcode: async (servers, dir) => (await import("./augmentcode-WCZCL7VR.js")).generateAugmentcodeMcpConfiguration(
|
|
2850
|
+
servers,
|
|
2851
|
+
dir
|
|
2852
|
+
),
|
|
2853
|
+
"augmentcode-legacy": async (servers, dir) => (await import("./augmentcode-WCZCL7VR.js")).generateAugmentcodeMcpConfiguration(
|
|
2854
|
+
servers,
|
|
2855
|
+
dir
|
|
2856
|
+
),
|
|
2857
|
+
claudecode: async (servers, dir) => (await import("./claudecode-RZSJPPBU.js")).generateClaudeMcpConfiguration(
|
|
2643
2858
|
servers,
|
|
2644
2859
|
dir
|
|
2645
2860
|
),
|
|
2646
|
-
|
|
2861
|
+
copilot: async (servers, dir) => (await import("./copilot-H3CLGKDP.js")).generateCopilotMcpConfiguration(servers, dir),
|
|
2862
|
+
cursor: async (servers, dir) => (await import("./cursor-ZUN5RZU6.js")).generateCursorMcpConfiguration(servers, dir),
|
|
2863
|
+
cline: async (servers, dir) => (await import("./cline-JTWWBQQ4.js")).generateClineMcpConfiguration(servers, dir),
|
|
2864
|
+
codexcli: async (servers, dir) => (await import("./codexcli-ATMFGRJR.js")).generateCodexMcpConfiguration(servers, dir),
|
|
2865
|
+
opencode: async (servers, dir) => (await import("./opencode-EBS3CED2.js")).generateOpenCodeMcpConfiguration(
|
|
2647
2866
|
servers,
|
|
2648
2867
|
dir
|
|
2649
2868
|
),
|
|
2650
|
-
|
|
2869
|
+
roo: async (servers, dir) => (await import("./roo-KBTRH4TZ.js")).generateRooMcpConfiguration(servers, dir),
|
|
2870
|
+
geminicli: async (servers, dir) => (await import("./geminicli-Q5HPIQCU.js")).generateGeminiCliMcpConfiguration(
|
|
2651
2871
|
servers,
|
|
2652
2872
|
dir
|
|
2653
2873
|
),
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
codexcli: async (servers, dir) => (await import("./codexcli-7SDGYI7D.js")).generateCodexMcpConfiguration(servers, dir),
|
|
2658
|
-
roo: async (servers, dir) => (await import("./roo-L3QTTIPO.js")).generateRooMcpConfiguration(servers, dir),
|
|
2659
|
-
geminicli: async (servers, dir) => (await import("./geminicli-E7KZTZ2G.js")).generateGeminiCliMcpConfiguration(
|
|
2874
|
+
kiro: async (servers, dir) => (await import("./kiro-CNF6433S.js")).generateKiroMcpConfiguration(servers, dir),
|
|
2875
|
+
junie: async (servers, dir) => (await import("./junie-JCLVC3MI.js")).generateJunieMcpConfiguration(servers, dir),
|
|
2876
|
+
qwencode: async (servers, dir) => (await import("./qwencode-JIT6KW7E.js")).generateQwenCodeMcpConfiguration(
|
|
2660
2877
|
servers,
|
|
2661
2878
|
dir
|
|
2662
2879
|
),
|
|
2663
|
-
|
|
2664
|
-
junie: async (servers, dir) => (await import("./junie-5LEQU4BO.js")).generateJunieMcpConfiguration(servers, dir),
|
|
2665
|
-
windsurf: async (servers, dir) => (await import("./windsurf-4P6HEUBV.js")).generateWindsurfMcpConfiguration(
|
|
2880
|
+
windsurf: async (servers, dir) => (await import("./windsurf-ZAAWL6JJ.js")).generateWindsurfMcpConfiguration(
|
|
2666
2881
|
servers,
|
|
2667
2882
|
dir
|
|
2668
2883
|
)
|
|
@@ -2691,35 +2906,40 @@ async function generateCommand(options = {}) {
|
|
|
2691
2906
|
};
|
|
2692
2907
|
const configResult = await loadConfig(configLoaderOptions);
|
|
2693
2908
|
const cliOptions = {
|
|
2694
|
-
|
|
2909
|
+
tools: options.tools,
|
|
2695
2910
|
...options.verbose !== void 0 && { verbose: options.verbose },
|
|
2696
2911
|
...options.delete !== void 0 && { delete: options.delete },
|
|
2697
2912
|
...options.baseDirs !== void 0 && { baseDirs: options.baseDirs }
|
|
2698
2913
|
};
|
|
2699
2914
|
const config = mergeWithCliOptions(configResult.config, cliOptions);
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2915
|
+
if (!config.defaultTargets || config.defaultTargets.length === 0) {
|
|
2916
|
+
const errorMessage = `\u274C Error: At least one tool must be specified.
|
|
2917
|
+
|
|
2918
|
+
Available tools:
|
|
2919
|
+
--augmentcode Generate for AugmentCode
|
|
2920
|
+
--augmentcode-legacy Generate for AugmentCode legacy format
|
|
2921
|
+
--copilot Generate for GitHub Copilot
|
|
2922
|
+
--cursor Generate for Cursor
|
|
2923
|
+
--cline Generate for Cline
|
|
2924
|
+
--codexcli Generate for OpenAI Codex CLI
|
|
2925
|
+
--claudecode Generate for Claude Code
|
|
2926
|
+
--roo Generate for Roo Code
|
|
2927
|
+
--geminicli Generate for Gemini CLI
|
|
2928
|
+
--junie Generate for JetBrains Junie
|
|
2929
|
+
--qwencode Generate for Qwen Code
|
|
2930
|
+
--kiro Generate for Kiro IDE
|
|
2931
|
+
--opencode Generate for OpenCode
|
|
2932
|
+
--windsurf Generate for Windsurf
|
|
2933
|
+
|
|
2934
|
+
Example:
|
|
2935
|
+
rulesync generate --copilot --cursor
|
|
2936
|
+
|
|
2937
|
+
Or specify tools in rulesync.jsonc:
|
|
2938
|
+
"tools": ["copilot", "cursor"]`;
|
|
2939
|
+
logger.error(errorMessage);
|
|
2940
|
+
process.exit(1);
|
|
2722
2941
|
}
|
|
2942
|
+
logger.setVerbose(config.verbose || false);
|
|
2723
2943
|
let baseDirs;
|
|
2724
2944
|
if (config.baseDir) {
|
|
2725
2945
|
baseDirs = Array.isArray(config.baseDir) ? config.baseDir : [config.baseDir];
|
|
@@ -2751,9 +2971,9 @@ async function generateCommand(options = {}) {
|
|
|
2751
2971
|
const hasCommands = await fileExists(commandsDir);
|
|
2752
2972
|
let hasCommandFiles = false;
|
|
2753
2973
|
if (hasCommands) {
|
|
2754
|
-
const { readdir
|
|
2974
|
+
const { readdir } = await import("fs/promises");
|
|
2755
2975
|
try {
|
|
2756
|
-
const files = await
|
|
2976
|
+
const files = await readdir(commandsDir);
|
|
2757
2977
|
hasCommandFiles = files.some((file) => file.endsWith(".md"));
|
|
2758
2978
|
} catch {
|
|
2759
2979
|
hasCommandFiles = false;
|
|
@@ -2799,6 +3019,12 @@ async function generateCommand(options = {}) {
|
|
|
2799
3019
|
case "kiro":
|
|
2800
3020
|
deleteTasks.push(removeDirectory(config.outputPaths.kiro));
|
|
2801
3021
|
break;
|
|
3022
|
+
case "opencode":
|
|
3023
|
+
deleteTasks.push(removeDirectory(config.outputPaths.opencode));
|
|
3024
|
+
break;
|
|
3025
|
+
case "qwencode":
|
|
3026
|
+
deleteTasks.push(removeDirectory(config.outputPaths.qwencode));
|
|
3027
|
+
break;
|
|
2802
3028
|
case "windsurf":
|
|
2803
3029
|
deleteTasks.push(removeDirectory(config.outputPaths.windsurf));
|
|
2804
3030
|
break;
|
|
@@ -2897,6 +3123,8 @@ var gitignoreCommand = async () => {
|
|
|
2897
3123
|
const gitignorePath = join14(process.cwd(), ".gitignore");
|
|
2898
3124
|
const rulesFilesToIgnore = [
|
|
2899
3125
|
"# Generated by rulesync - AI tool configuration files",
|
|
3126
|
+
"**/.amazonq/rules/",
|
|
3127
|
+
"**/.amazonq/mcp.json",
|
|
2900
3128
|
"**/.github/copilot-instructions.md",
|
|
2901
3129
|
"**/.github/instructions/",
|
|
2902
3130
|
"**/.cursor/rules/",
|
|
@@ -2914,6 +3142,8 @@ var gitignoreCommand = async () => {
|
|
|
2914
3142
|
"**/GEMINI.md",
|
|
2915
3143
|
"**/.gemini/memories/",
|
|
2916
3144
|
"**/.gemini/commands/",
|
|
3145
|
+
"**/QWEN.md",
|
|
3146
|
+
"**/.qwen/memories/",
|
|
2917
3147
|
"**/.aiexclude",
|
|
2918
3148
|
"**/.aiignore",
|
|
2919
3149
|
"**/.augmentignore",
|
|
@@ -2922,6 +3152,9 @@ var gitignoreCommand = async () => {
|
|
|
2922
3152
|
"**/.augment-guidelines",
|
|
2923
3153
|
"**/.junie/guidelines.md",
|
|
2924
3154
|
"**/.noai",
|
|
3155
|
+
"**/.opencode/memories/",
|
|
3156
|
+
"**/.opencode/commands/",
|
|
3157
|
+
"**/opencode.json",
|
|
2925
3158
|
"**/.mcp.json",
|
|
2926
3159
|
"!.rulesync/.mcp.json",
|
|
2927
3160
|
"**/.cursor/mcp.json",
|
|
@@ -2929,6 +3162,7 @@ var gitignoreCommand = async () => {
|
|
|
2929
3162
|
"**/.vscode/mcp.json",
|
|
2930
3163
|
"**/.codex/mcp-config.json",
|
|
2931
3164
|
"**/.gemini/settings.json",
|
|
3165
|
+
"**/.qwen/settings.json",
|
|
2932
3166
|
"**/.roo/mcp.json"
|
|
2933
3167
|
];
|
|
2934
3168
|
let gitignoreContent = "";
|
|
@@ -2963,159 +3197,8 @@ ${linesToAdd.join("\n")}
|
|
|
2963
3197
|
import { join as join21 } from "path";
|
|
2964
3198
|
import matter2 from "gray-matter";
|
|
2965
3199
|
|
|
2966
|
-
// src/parsers/augmentcode.ts
|
|
2967
|
-
import { basename as basename3, join as join15 } from "path";
|
|
2968
|
-
|
|
2969
|
-
// src/utils/parser-helpers.ts
|
|
2970
|
-
function createParseResult() {
|
|
2971
|
-
return { rules: [], errors: [] };
|
|
2972
|
-
}
|
|
2973
|
-
function addError(result, error) {
|
|
2974
|
-
result.errors.push(error);
|
|
2975
|
-
}
|
|
2976
|
-
function addRule(result, rule) {
|
|
2977
|
-
if (!result.rules) {
|
|
2978
|
-
result.rules = [];
|
|
2979
|
-
}
|
|
2980
|
-
result.rules.push(rule);
|
|
2981
|
-
}
|
|
2982
|
-
function addRules(result, rules) {
|
|
2983
|
-
if (!result.rules) {
|
|
2984
|
-
result.rules = [];
|
|
2985
|
-
}
|
|
2986
|
-
result.rules.push(...rules);
|
|
2987
|
-
}
|
|
2988
|
-
async function safeReadFile(operation, errorContext) {
|
|
2989
|
-
try {
|
|
2990
|
-
const result = await operation();
|
|
2991
|
-
return createSuccessResult(result);
|
|
2992
|
-
} catch (error) {
|
|
2993
|
-
return createErrorResult(error, errorContext);
|
|
2994
|
-
}
|
|
2995
|
-
}
|
|
2996
|
-
|
|
2997
|
-
// src/parsers/augmentcode.ts
|
|
2998
|
-
async function parseAugmentcodeConfiguration(baseDir = process.cwd()) {
|
|
2999
|
-
return parseUnifiedAugmentcode(baseDir, {
|
|
3000
|
-
rulesDir: ".augment/rules",
|
|
3001
|
-
targetName: "augmentcode",
|
|
3002
|
-
filenamePrefix: "augmentcode"
|
|
3003
|
-
});
|
|
3004
|
-
}
|
|
3005
|
-
async function parseAugmentcodeLegacyConfiguration(baseDir = process.cwd()) {
|
|
3006
|
-
return parseUnifiedAugmentcode(baseDir, {
|
|
3007
|
-
legacyFilePath: ".augment-guidelines",
|
|
3008
|
-
targetName: "augmentcode-legacy",
|
|
3009
|
-
filenamePrefix: "augmentcode-legacy"
|
|
3010
|
-
});
|
|
3011
|
-
}
|
|
3012
|
-
async function parseUnifiedAugmentcode(baseDir, config) {
|
|
3013
|
-
const result = createParseResult();
|
|
3014
|
-
if (config.rulesDir) {
|
|
3015
|
-
const rulesDir = join15(baseDir, config.rulesDir);
|
|
3016
|
-
if (await fileExists(rulesDir)) {
|
|
3017
|
-
const rulesResult = await parseAugmentRules(rulesDir, config);
|
|
3018
|
-
addRules(result, rulesResult.rules);
|
|
3019
|
-
result.errors.push(...rulesResult.errors);
|
|
3020
|
-
} else {
|
|
3021
|
-
addError(
|
|
3022
|
-
result,
|
|
3023
|
-
`No AugmentCode configuration found. Expected ${config.rulesDir} directory.`
|
|
3024
|
-
);
|
|
3025
|
-
}
|
|
3026
|
-
}
|
|
3027
|
-
if (config.legacyFilePath) {
|
|
3028
|
-
const legacyPath = join15(baseDir, config.legacyFilePath);
|
|
3029
|
-
if (await fileExists(legacyPath)) {
|
|
3030
|
-
const legacyResult = await parseAugmentGuidelines(legacyPath, config);
|
|
3031
|
-
if (legacyResult.rule) {
|
|
3032
|
-
addRule(result, legacyResult.rule);
|
|
3033
|
-
}
|
|
3034
|
-
result.errors.push(...legacyResult.errors);
|
|
3035
|
-
} else {
|
|
3036
|
-
addError(
|
|
3037
|
-
result,
|
|
3038
|
-
`No AugmentCode legacy configuration found. Expected ${config.legacyFilePath} file.`
|
|
3039
|
-
);
|
|
3040
|
-
}
|
|
3041
|
-
}
|
|
3042
|
-
return { rules: result.rules || [], errors: result.errors };
|
|
3043
|
-
}
|
|
3044
|
-
async function parseAugmentRules(rulesDir, config) {
|
|
3045
|
-
const rules = [];
|
|
3046
|
-
const errors = [];
|
|
3047
|
-
try {
|
|
3048
|
-
const { readdir: readdir2 } = await import("fs/promises");
|
|
3049
|
-
const files = await readdir2(rulesDir);
|
|
3050
|
-
for (const file of files) {
|
|
3051
|
-
if (file.endsWith(".md") || file.endsWith(".mdc")) {
|
|
3052
|
-
const filePath = join15(rulesDir, file);
|
|
3053
|
-
try {
|
|
3054
|
-
const rawContent = await readFileContent(filePath);
|
|
3055
|
-
const parsed = parseFrontmatter(rawContent);
|
|
3056
|
-
const ruleType = extractStringField(parsed.data, "type", "manual");
|
|
3057
|
-
const description = extractStringField(parsed.data, "description", "");
|
|
3058
|
-
const tags = extractArrayField(parsed.data, "tags");
|
|
3059
|
-
const isRoot = ruleType === "always";
|
|
3060
|
-
const filename = basename3(file, file.endsWith(".mdc") ? ".mdc" : ".md");
|
|
3061
|
-
const frontmatter = {
|
|
3062
|
-
root: isRoot,
|
|
3063
|
-
targets: [config.targetName],
|
|
3064
|
-
description,
|
|
3065
|
-
globs: ["**/*"],
|
|
3066
|
-
// AugmentCode doesn't use specific globs in the same way
|
|
3067
|
-
...tags.length > 0 && { tags }
|
|
3068
|
-
};
|
|
3069
|
-
rules.push({
|
|
3070
|
-
frontmatter,
|
|
3071
|
-
content: parsed.content.trim(),
|
|
3072
|
-
filename: `${config.filenamePrefix}-${ruleType}-${filename}`,
|
|
3073
|
-
filepath: filePath
|
|
3074
|
-
});
|
|
3075
|
-
} catch (error) {
|
|
3076
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3077
|
-
errors.push(`Failed to parse ${filePath}: ${errorMessage}`);
|
|
3078
|
-
}
|
|
3079
|
-
}
|
|
3080
|
-
}
|
|
3081
|
-
} catch (error) {
|
|
3082
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3083
|
-
errors.push(`Failed to read ${config.rulesDir || rulesDir} directory: ${errorMessage}`);
|
|
3084
|
-
}
|
|
3085
|
-
return { rules, errors };
|
|
3086
|
-
}
|
|
3087
|
-
async function parseAugmentGuidelines(guidelinesPath, config) {
|
|
3088
|
-
const parseResult = await safeReadFile(
|
|
3089
|
-
async () => {
|
|
3090
|
-
const content = await readFileContent(guidelinesPath);
|
|
3091
|
-
if (content.trim()) {
|
|
3092
|
-
const frontmatter = {
|
|
3093
|
-
root: true,
|
|
3094
|
-
// Legacy guidelines become root rules
|
|
3095
|
-
targets: [config.targetName],
|
|
3096
|
-
description: "Legacy AugmentCode guidelines",
|
|
3097
|
-
globs: ["**/*"]
|
|
3098
|
-
};
|
|
3099
|
-
return {
|
|
3100
|
-
frontmatter,
|
|
3101
|
-
content: content.trim(),
|
|
3102
|
-
filename: `${config.filenamePrefix}-guidelines`,
|
|
3103
|
-
filepath: guidelinesPath
|
|
3104
|
-
};
|
|
3105
|
-
}
|
|
3106
|
-
return null;
|
|
3107
|
-
},
|
|
3108
|
-
`Failed to parse ${config.legacyFilePath || guidelinesPath}`
|
|
3109
|
-
);
|
|
3110
|
-
if (parseResult.success) {
|
|
3111
|
-
return { rule: parseResult.result || null, errors: [] };
|
|
3112
|
-
} else {
|
|
3113
|
-
return { rule: null, errors: [parseResult.error || "Unknown error"] };
|
|
3114
|
-
}
|
|
3115
|
-
}
|
|
3116
|
-
|
|
3117
3200
|
// src/parsers/shared-helpers.ts
|
|
3118
|
-
import { basename as
|
|
3201
|
+
import { basename as basename3, join as join15 } from "path";
|
|
3119
3202
|
async function parseConfigurationFiles(baseDir = process.cwd(), config) {
|
|
3120
3203
|
const errors = [];
|
|
3121
3204
|
const rules = [];
|
|
@@ -3168,11 +3251,11 @@ async function parseConfigurationFiles(baseDir = process.cwd(), config) {
|
|
|
3168
3251
|
const dirPath = resolvePath(dirConfig.directory, baseDir);
|
|
3169
3252
|
if (await fileExists(dirPath)) {
|
|
3170
3253
|
const result = await safeAsyncOperation(async () => {
|
|
3171
|
-
const { readdir
|
|
3172
|
-
const files = await
|
|
3254
|
+
const { readdir } = await import("fs/promises");
|
|
3255
|
+
const files = await readdir(dirPath);
|
|
3173
3256
|
for (const file of files) {
|
|
3174
3257
|
if (file.endsWith(dirConfig.filePattern)) {
|
|
3175
|
-
const filePath =
|
|
3258
|
+
const filePath = join15(dirPath, file);
|
|
3176
3259
|
const fileResult = await safeAsyncOperation(async () => {
|
|
3177
3260
|
const rawContent = await readFileContent(filePath);
|
|
3178
3261
|
let content;
|
|
@@ -3319,14 +3402,14 @@ function parseMainFile(content, filepath, config) {
|
|
|
3319
3402
|
async function parseMemoryFiles(memoryDir, config) {
|
|
3320
3403
|
const rules = [];
|
|
3321
3404
|
try {
|
|
3322
|
-
const { readdir
|
|
3323
|
-
const files = await
|
|
3405
|
+
const { readdir } = await import("fs/promises");
|
|
3406
|
+
const files = await readdir(memoryDir);
|
|
3324
3407
|
for (const file of files) {
|
|
3325
3408
|
if (file.endsWith(".md")) {
|
|
3326
|
-
const filePath =
|
|
3409
|
+
const filePath = join15(memoryDir, file);
|
|
3327
3410
|
const content = await readFileContent(filePath);
|
|
3328
3411
|
if (content.trim()) {
|
|
3329
|
-
const filename =
|
|
3412
|
+
const filename = basename3(file, ".md");
|
|
3330
3413
|
const frontmatter = {
|
|
3331
3414
|
root: false,
|
|
3332
3415
|
targets: [config.tool],
|
|
@@ -3349,14 +3432,14 @@ async function parseMemoryFiles(memoryDir, config) {
|
|
|
3349
3432
|
async function parseCommandsFiles(commandsDir, config) {
|
|
3350
3433
|
const rules = [];
|
|
3351
3434
|
try {
|
|
3352
|
-
const { readdir
|
|
3353
|
-
const files = await
|
|
3435
|
+
const { readdir } = await import("fs/promises");
|
|
3436
|
+
const files = await readdir(commandsDir);
|
|
3354
3437
|
for (const file of files) {
|
|
3355
3438
|
if (file.endsWith(".md")) {
|
|
3356
|
-
const filePath =
|
|
3439
|
+
const filePath = join15(commandsDir, file);
|
|
3357
3440
|
const content = await readFileContent(filePath);
|
|
3358
3441
|
if (content.trim()) {
|
|
3359
|
-
const filename =
|
|
3442
|
+
const filename = basename3(file, ".md");
|
|
3360
3443
|
let frontmatter;
|
|
3361
3444
|
let ruleContent;
|
|
3362
3445
|
try {
|
|
@@ -3431,6 +3514,170 @@ async function parseSettingsFile(settingsPath, tool) {
|
|
|
3431
3514
|
};
|
|
3432
3515
|
}
|
|
3433
3516
|
|
|
3517
|
+
// src/parsers/amazonqcli.ts
|
|
3518
|
+
async function parseAmazonqcliConfiguration(baseDir = process.cwd()) {
|
|
3519
|
+
return parseMemoryBasedConfiguration(baseDir, {
|
|
3520
|
+
tool: "amazonqcli",
|
|
3521
|
+
mainFileName: ".amazonq/rules/main.md",
|
|
3522
|
+
memoryDirPath: ".amazonq/rules",
|
|
3523
|
+
settingsPath: ".amazonq/mcp.json",
|
|
3524
|
+
mainDescription: "Main Amazon Q Developer CLI configuration",
|
|
3525
|
+
memoryDescription: "Amazon Q rule",
|
|
3526
|
+
filenamePrefix: "amazonq"
|
|
3527
|
+
});
|
|
3528
|
+
}
|
|
3529
|
+
|
|
3530
|
+
// src/parsers/augmentcode.ts
|
|
3531
|
+
import { basename as basename4, join as join16 } from "path";
|
|
3532
|
+
|
|
3533
|
+
// src/utils/parser-helpers.ts
|
|
3534
|
+
function createParseResult() {
|
|
3535
|
+
return { rules: [], errors: [] };
|
|
3536
|
+
}
|
|
3537
|
+
function addError(result, error) {
|
|
3538
|
+
result.errors.push(error);
|
|
3539
|
+
}
|
|
3540
|
+
function addRule(result, rule) {
|
|
3541
|
+
if (!result.rules) {
|
|
3542
|
+
result.rules = [];
|
|
3543
|
+
}
|
|
3544
|
+
result.rules.push(rule);
|
|
3545
|
+
}
|
|
3546
|
+
function addRules(result, rules) {
|
|
3547
|
+
if (!result.rules) {
|
|
3548
|
+
result.rules = [];
|
|
3549
|
+
}
|
|
3550
|
+
result.rules.push(...rules);
|
|
3551
|
+
}
|
|
3552
|
+
async function safeReadFile(operation, errorContext) {
|
|
3553
|
+
try {
|
|
3554
|
+
const result = await operation();
|
|
3555
|
+
return createSuccessResult(result);
|
|
3556
|
+
} catch (error) {
|
|
3557
|
+
return createErrorResult(error, errorContext);
|
|
3558
|
+
}
|
|
3559
|
+
}
|
|
3560
|
+
|
|
3561
|
+
// src/parsers/augmentcode.ts
|
|
3562
|
+
async function parseAugmentcodeConfiguration(baseDir = process.cwd()) {
|
|
3563
|
+
return parseUnifiedAugmentcode(baseDir, {
|
|
3564
|
+
rulesDir: ".augment/rules",
|
|
3565
|
+
targetName: "augmentcode",
|
|
3566
|
+
filenamePrefix: "augmentcode"
|
|
3567
|
+
});
|
|
3568
|
+
}
|
|
3569
|
+
async function parseAugmentcodeLegacyConfiguration(baseDir = process.cwd()) {
|
|
3570
|
+
return parseUnifiedAugmentcode(baseDir, {
|
|
3571
|
+
legacyFilePath: ".augment-guidelines",
|
|
3572
|
+
targetName: "augmentcode-legacy",
|
|
3573
|
+
filenamePrefix: "augmentcode-legacy"
|
|
3574
|
+
});
|
|
3575
|
+
}
|
|
3576
|
+
async function parseUnifiedAugmentcode(baseDir, config) {
|
|
3577
|
+
const result = createParseResult();
|
|
3578
|
+
if (config.rulesDir) {
|
|
3579
|
+
const rulesDir = join16(baseDir, config.rulesDir);
|
|
3580
|
+
if (await fileExists(rulesDir)) {
|
|
3581
|
+
const rulesResult = await parseAugmentRules(rulesDir, config);
|
|
3582
|
+
addRules(result, rulesResult.rules);
|
|
3583
|
+
result.errors.push(...rulesResult.errors);
|
|
3584
|
+
} else {
|
|
3585
|
+
addError(
|
|
3586
|
+
result,
|
|
3587
|
+
`No AugmentCode configuration found. Expected ${config.rulesDir} directory.`
|
|
3588
|
+
);
|
|
3589
|
+
}
|
|
3590
|
+
}
|
|
3591
|
+
if (config.legacyFilePath) {
|
|
3592
|
+
const legacyPath = join16(baseDir, config.legacyFilePath);
|
|
3593
|
+
if (await fileExists(legacyPath)) {
|
|
3594
|
+
const legacyResult = await parseAugmentGuidelines(legacyPath, config);
|
|
3595
|
+
if (legacyResult.rule) {
|
|
3596
|
+
addRule(result, legacyResult.rule);
|
|
3597
|
+
}
|
|
3598
|
+
result.errors.push(...legacyResult.errors);
|
|
3599
|
+
} else {
|
|
3600
|
+
addError(
|
|
3601
|
+
result,
|
|
3602
|
+
`No AugmentCode legacy configuration found. Expected ${config.legacyFilePath} file.`
|
|
3603
|
+
);
|
|
3604
|
+
}
|
|
3605
|
+
}
|
|
3606
|
+
return { rules: result.rules || [], errors: result.errors };
|
|
3607
|
+
}
|
|
3608
|
+
async function parseAugmentRules(rulesDir, config) {
|
|
3609
|
+
const rules = [];
|
|
3610
|
+
const errors = [];
|
|
3611
|
+
try {
|
|
3612
|
+
const { readdir } = await import("fs/promises");
|
|
3613
|
+
const files = await readdir(rulesDir);
|
|
3614
|
+
for (const file of files) {
|
|
3615
|
+
if (file.endsWith(".md") || file.endsWith(".mdc")) {
|
|
3616
|
+
const filePath = join16(rulesDir, file);
|
|
3617
|
+
try {
|
|
3618
|
+
const rawContent = await readFileContent(filePath);
|
|
3619
|
+
const parsed = parseFrontmatter(rawContent);
|
|
3620
|
+
const ruleType = extractStringField(parsed.data, "type", "manual");
|
|
3621
|
+
const description = extractStringField(parsed.data, "description", "");
|
|
3622
|
+
const tags = extractArrayField(parsed.data, "tags");
|
|
3623
|
+
const isRoot = ruleType === "always";
|
|
3624
|
+
const filename = basename4(file, file.endsWith(".mdc") ? ".mdc" : ".md");
|
|
3625
|
+
const frontmatter = {
|
|
3626
|
+
root: isRoot,
|
|
3627
|
+
targets: [config.targetName],
|
|
3628
|
+
description,
|
|
3629
|
+
globs: ["**/*"],
|
|
3630
|
+
// AugmentCode doesn't use specific globs in the same way
|
|
3631
|
+
...tags.length > 0 && { tags }
|
|
3632
|
+
};
|
|
3633
|
+
rules.push({
|
|
3634
|
+
frontmatter,
|
|
3635
|
+
content: parsed.content.trim(),
|
|
3636
|
+
filename: `${config.filenamePrefix}-${ruleType}-${filename}`,
|
|
3637
|
+
filepath: filePath
|
|
3638
|
+
});
|
|
3639
|
+
} catch (error) {
|
|
3640
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3641
|
+
errors.push(`Failed to parse ${filePath}: ${errorMessage}`);
|
|
3642
|
+
}
|
|
3643
|
+
}
|
|
3644
|
+
}
|
|
3645
|
+
} catch (error) {
|
|
3646
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3647
|
+
errors.push(`Failed to read ${config.rulesDir || rulesDir} directory: ${errorMessage}`);
|
|
3648
|
+
}
|
|
3649
|
+
return { rules, errors };
|
|
3650
|
+
}
|
|
3651
|
+
async function parseAugmentGuidelines(guidelinesPath, config) {
|
|
3652
|
+
const parseResult = await safeReadFile(
|
|
3653
|
+
async () => {
|
|
3654
|
+
const content = await readFileContent(guidelinesPath);
|
|
3655
|
+
if (content.trim()) {
|
|
3656
|
+
const frontmatter = {
|
|
3657
|
+
root: true,
|
|
3658
|
+
// Legacy guidelines become root rules
|
|
3659
|
+
targets: [config.targetName],
|
|
3660
|
+
description: "Legacy AugmentCode guidelines",
|
|
3661
|
+
globs: ["**/*"]
|
|
3662
|
+
};
|
|
3663
|
+
return {
|
|
3664
|
+
frontmatter,
|
|
3665
|
+
content: content.trim(),
|
|
3666
|
+
filename: `${config.filenamePrefix}-guidelines`,
|
|
3667
|
+
filepath: guidelinesPath
|
|
3668
|
+
};
|
|
3669
|
+
}
|
|
3670
|
+
return null;
|
|
3671
|
+
},
|
|
3672
|
+
`Failed to parse ${config.legacyFilePath || guidelinesPath}`
|
|
3673
|
+
);
|
|
3674
|
+
if (parseResult.success) {
|
|
3675
|
+
return { rule: parseResult.result || null, errors: [] };
|
|
3676
|
+
} else {
|
|
3677
|
+
return { rule: null, errors: [parseResult.error || "Unknown error"] };
|
|
3678
|
+
}
|
|
3679
|
+
}
|
|
3680
|
+
|
|
3434
3681
|
// src/parsers/claudecode.ts
|
|
3435
3682
|
async function parseClaudeConfiguration(baseDir = process.cwd()) {
|
|
3436
3683
|
return parseMemoryBasedConfiguration(baseDir, {
|
|
@@ -3637,8 +3884,8 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
3637
3884
|
const cursorRulesDir = join18(baseDir, ".cursor", "rules");
|
|
3638
3885
|
if (await fileExists(cursorRulesDir)) {
|
|
3639
3886
|
try {
|
|
3640
|
-
const { readdir
|
|
3641
|
-
const files = await
|
|
3887
|
+
const { readdir } = await import("fs/promises");
|
|
3888
|
+
const files = await readdir(cursorRulesDir);
|
|
3642
3889
|
for (const file of files) {
|
|
3643
3890
|
if (file.endsWith(".mdc")) {
|
|
3644
3891
|
const filePath = join18(cursorRulesDir, file);
|
|
@@ -3768,6 +4015,48 @@ async function parseJunieConfiguration(baseDir = process.cwd()) {
|
|
|
3768
4015
|
return { rules, errors };
|
|
3769
4016
|
}
|
|
3770
4017
|
|
|
4018
|
+
// src/parsers/opencode.ts
|
|
4019
|
+
async function parseOpCodeIgnore(opcodeignorePath) {
|
|
4020
|
+
try {
|
|
4021
|
+
const content = await readFileContent(opcodeignorePath);
|
|
4022
|
+
const patterns = content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
|
|
4023
|
+
return patterns;
|
|
4024
|
+
} catch {
|
|
4025
|
+
return [];
|
|
4026
|
+
}
|
|
4027
|
+
}
|
|
4028
|
+
async function parseOpenCodeConfiguration(baseDir = process.cwd()) {
|
|
4029
|
+
return parseMemoryBasedConfiguration(baseDir, {
|
|
4030
|
+
tool: "opencode",
|
|
4031
|
+
mainFileName: "AGENTS.md",
|
|
4032
|
+
memoryDirPath: ".opencode/memories",
|
|
4033
|
+
settingsPath: "opencode.json",
|
|
4034
|
+
mainDescription: "Main OpenCode configuration",
|
|
4035
|
+
memoryDescription: "Memory file",
|
|
4036
|
+
filenamePrefix: "opencode",
|
|
4037
|
+
additionalIgnoreFile: {
|
|
4038
|
+
path: ".opcodeignore",
|
|
4039
|
+
parser: parseOpCodeIgnore
|
|
4040
|
+
}
|
|
4041
|
+
});
|
|
4042
|
+
}
|
|
4043
|
+
|
|
4044
|
+
// src/parsers/qwencode.ts
|
|
4045
|
+
async function parseQwenConfiguration(baseDir = process.cwd()) {
|
|
4046
|
+
return parseMemoryBasedConfiguration(baseDir, {
|
|
4047
|
+
tool: "qwencode",
|
|
4048
|
+
mainFileName: "QWEN.md",
|
|
4049
|
+
memoryDirPath: ".qwen/memories",
|
|
4050
|
+
settingsPath: ".qwen/settings.json",
|
|
4051
|
+
mainDescription: "Main Qwen Code configuration",
|
|
4052
|
+
memoryDescription: "Memory file",
|
|
4053
|
+
filenamePrefix: "qwen",
|
|
4054
|
+
// Qwen Code uses git-aware filtering instead of dedicated ignore files
|
|
4055
|
+
// additionalIgnoreFile is omitted
|
|
4056
|
+
commandsDirPath: ".qwen/commands"
|
|
4057
|
+
});
|
|
4058
|
+
}
|
|
4059
|
+
|
|
3771
4060
|
// src/parsers/roo.ts
|
|
3772
4061
|
async function parseRooConfiguration(baseDir = process.cwd()) {
|
|
3773
4062
|
return parseConfigurationFiles(baseDir, {
|
|
@@ -3789,7 +4078,7 @@ async function parseRooConfiguration(baseDir = process.cwd()) {
|
|
|
3789
4078
|
}
|
|
3790
4079
|
|
|
3791
4080
|
// src/parsers/windsurf.ts
|
|
3792
|
-
import { readFile
|
|
4081
|
+
import { readFile } from "fs/promises";
|
|
3793
4082
|
import { join as join20 } from "path";
|
|
3794
4083
|
|
|
3795
4084
|
// src/core/importer.ts
|
|
@@ -3810,6 +4099,13 @@ async function importConfiguration(options) {
|
|
|
3810
4099
|
}
|
|
3811
4100
|
try {
|
|
3812
4101
|
switch (tool) {
|
|
4102
|
+
case "amazonqcli": {
|
|
4103
|
+
const amazonqResult = await parseAmazonqcliConfiguration(baseDir);
|
|
4104
|
+
rules = amazonqResult.rules;
|
|
4105
|
+
errors.push(...amazonqResult.errors);
|
|
4106
|
+
mcpServers = amazonqResult.mcpServers;
|
|
4107
|
+
break;
|
|
4108
|
+
}
|
|
3813
4109
|
case "augmentcode": {
|
|
3814
4110
|
const augmentResult = await parseAugmentcodeConfiguration(baseDir);
|
|
3815
4111
|
rules = augmentResult.rules;
|
|
@@ -3870,6 +4166,21 @@ async function importConfiguration(options) {
|
|
|
3870
4166
|
errors.push(...junieResult.errors);
|
|
3871
4167
|
break;
|
|
3872
4168
|
}
|
|
4169
|
+
case "opencode": {
|
|
4170
|
+
const opencodeResult = await parseOpenCodeConfiguration(baseDir);
|
|
4171
|
+
rules = opencodeResult.rules;
|
|
4172
|
+
errors.push(...opencodeResult.errors);
|
|
4173
|
+
ignorePatterns = opencodeResult.ignorePatterns;
|
|
4174
|
+
mcpServers = opencodeResult.mcpServers;
|
|
4175
|
+
break;
|
|
4176
|
+
}
|
|
4177
|
+
case "qwencode": {
|
|
4178
|
+
const qwenResult = await parseQwenConfiguration(baseDir);
|
|
4179
|
+
rules = qwenResult.rules;
|
|
4180
|
+
errors.push(...qwenResult.errors);
|
|
4181
|
+
mcpServers = qwenResult.mcpServers;
|
|
4182
|
+
break;
|
|
4183
|
+
}
|
|
3873
4184
|
default:
|
|
3874
4185
|
errors.push(`Unsupported tool: ${tool}`);
|
|
3875
4186
|
return { success: false, rulesCreated: 0, errors };
|
|
@@ -3884,8 +4195,8 @@ async function importConfiguration(options) {
|
|
|
3884
4195
|
}
|
|
3885
4196
|
const rulesDirPath = join21(baseDir, rulesDir);
|
|
3886
4197
|
try {
|
|
3887
|
-
const { mkdir:
|
|
3888
|
-
await
|
|
4198
|
+
const { mkdir: mkdir2 } = await import("fs/promises");
|
|
4199
|
+
await mkdir2(rulesDirPath, { recursive: true });
|
|
3889
4200
|
} catch (error) {
|
|
3890
4201
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3891
4202
|
errors.push(`Failed to create rules directory: ${errorMessage}`);
|
|
@@ -3898,13 +4209,13 @@ async function importConfiguration(options) {
|
|
|
3898
4209
|
let targetDir = rulesDirPath;
|
|
3899
4210
|
if (rule.type === "command") {
|
|
3900
4211
|
targetDir = join21(rulesDirPath, "commands");
|
|
3901
|
-
const { mkdir:
|
|
3902
|
-
await
|
|
4212
|
+
const { mkdir: mkdir2 } = await import("fs/promises");
|
|
4213
|
+
await mkdir2(targetDir, { recursive: true });
|
|
3903
4214
|
} else {
|
|
3904
4215
|
if (!useLegacyLocation) {
|
|
3905
4216
|
targetDir = join21(rulesDirPath, "rules");
|
|
3906
|
-
const { mkdir:
|
|
3907
|
-
await
|
|
4217
|
+
const { mkdir: mkdir2 } = await import("fs/promises");
|
|
4218
|
+
await mkdir2(targetDir, { recursive: true });
|
|
3908
4219
|
}
|
|
3909
4220
|
}
|
|
3910
4221
|
const filePath = join21(targetDir, `${baseFilename}.md`);
|
|
@@ -3976,6 +4287,7 @@ function generateRuleFileContent(rule) {
|
|
|
3976
4287
|
async function importCommand(options = {}) {
|
|
3977
4288
|
logger.setVerbose(options.verbose || false);
|
|
3978
4289
|
const tools = [];
|
|
4290
|
+
if (options.amazonqcli) tools.push("amazonqcli");
|
|
3979
4291
|
if (options.augmentcode) tools.push("augmentcode");
|
|
3980
4292
|
if (options["augmentcode-legacy"]) tools.push("augmentcode-legacy");
|
|
3981
4293
|
if (options.claudecode) tools.push("claudecode");
|
|
@@ -3984,9 +4296,11 @@ async function importCommand(options = {}) {
|
|
|
3984
4296
|
if (options.cline) tools.push("cline");
|
|
3985
4297
|
if (options.roo) tools.push("roo");
|
|
3986
4298
|
if (options.geminicli) tools.push("geminicli");
|
|
4299
|
+
if (options.qwencode) tools.push("qwencode");
|
|
4300
|
+
if (options.opencode) tools.push("opencode");
|
|
3987
4301
|
if (tools.length === 0) {
|
|
3988
4302
|
logger.error(
|
|
3989
|
-
"\u274C Please specify one tool to import from (--augmentcode, --augmentcode-legacy, --claudecode, --cursor, --copilot, --cline, --roo, --geminicli)"
|
|
4303
|
+
"\u274C Please specify one tool to import from (--amazonqcli, --augmentcode, --augmentcode-legacy, --claudecode, --cursor, --copilot, --cline, --roo, --geminicli, --qwencode, --opencode)"
|
|
3990
4304
|
);
|
|
3991
4305
|
process.exit(1);
|
|
3992
4306
|
}
|
|
@@ -4232,37 +4546,41 @@ async function watchCommand() {
|
|
|
4232
4546
|
|
|
4233
4547
|
// src/cli/index.ts
|
|
4234
4548
|
var program = new Command();
|
|
4235
|
-
program.name("rulesync").description("Unified AI rules management CLI tool").version("0.
|
|
4549
|
+
program.name("rulesync").description("Unified AI rules management CLI tool").version("0.65.0");
|
|
4236
4550
|
program.command("init").description("Initialize rulesync in current directory").option("--legacy", "Use legacy file location (.rulesync/*.md instead of .rulesync/rules/*.md)").action(initCommand);
|
|
4237
4551
|
program.command("add <filename>").description("Add a new rule file").option("--legacy", "Use legacy file location (.rulesync/*.md instead of .rulesync/rules/*.md)").action(addCommand);
|
|
4238
4552
|
program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);
|
|
4239
|
-
program.command("import").description("Import configurations from AI tools to rulesync format").option("--augmentcode", "Import from AugmentCode (.augment/rules/)").option("--augmentcode-legacy", "Import from AugmentCode legacy format (.augment-guidelines)").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("--geminicli", "Import from Gemini CLI (GEMINI.md)").option("--junie", "Import from JetBrains Junie (.junie/guidelines.md)").option("-v, --verbose", "Verbose output").option("--legacy", "Use legacy file location (.rulesync/*.md instead of .rulesync/rules/*.md)").action(importCommand);
|
|
4240
|
-
program.command("generate").description("Generate configuration files for AI tools").option("--augmentcode", "Generate only for AugmentCode").option("--augmentcode-legacy", "Generate only for AugmentCode legacy format").option("--copilot", "Generate only for GitHub Copilot").option("--cursor", "Generate only for Cursor").option("--cline", "Generate only for Cline").option("--codexcli", "Generate only for OpenAI Codex CLI").option("--claudecode", "Generate only for Claude Code").option("--roo", "Generate only for Roo Code").option("--geminicli", "Generate only for Gemini CLI").option("--junie", "Generate only for JetBrains Junie").option("--kiro", "Generate only for Kiro IDE").option("--windsurf", "Generate only for Windsurf").option("--delete", "Delete all existing files in output directories before generating").option(
|
|
4553
|
+
program.command("import").description("Import configurations from AI tools to rulesync format").option("--augmentcode", "Import from AugmentCode (.augment/rules/)").option("--augmentcode-legacy", "Import from AugmentCode legacy format (.augment-guidelines)").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("--geminicli", "Import from Gemini CLI (GEMINI.md)").option("--junie", "Import from JetBrains Junie (.junie/guidelines.md)").option("--qwencode", "Import from Qwen Code (QWEN.md)").option("--opencode", "Import from OpenCode (AGENTS.md)").option("-v, --verbose", "Verbose output").option("--legacy", "Use legacy file location (.rulesync/*.md instead of .rulesync/rules/*.md)").action(importCommand);
|
|
4554
|
+
program.command("generate").description("Generate configuration files for AI tools").option("--all", "Generate for all supported AI tools").option("--augmentcode", "Generate only for AugmentCode").option("--augmentcode-legacy", "Generate only for AugmentCode legacy format").option("--copilot", "Generate only for GitHub Copilot").option("--cursor", "Generate only for Cursor").option("--cline", "Generate only for Cline").option("--codexcli", "Generate only for OpenAI Codex CLI").option("--claudecode", "Generate only for Claude Code").option("--roo", "Generate only for Roo Code").option("--geminicli", "Generate only for Gemini CLI").option("--junie", "Generate only for JetBrains Junie").option("--qwencode", "Generate only for Qwen Code").option("--kiro", "Generate only for Kiro IDE").option("--opencode", "Generate only for OpenCode").option("--windsurf", "Generate only for Windsurf").option("--delete", "Delete all existing files in output directories before generating").option(
|
|
4241
4555
|
"-b, --base-dir <paths>",
|
|
4242
4556
|
"Base directories to generate files (comma-separated for multiple paths)"
|
|
4243
4557
|
).option("-v, --verbose", "Verbose output").option("-c, --config <path>", "Path to configuration file").option("--no-config", "Disable configuration file loading").action(async (options) => {
|
|
4244
4558
|
const tools = [];
|
|
4245
|
-
if (options.
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4559
|
+
if (options.all) {
|
|
4560
|
+
tools.push(...ALL_TOOL_TARGETS);
|
|
4561
|
+
} else {
|
|
4562
|
+
if (options.augmentcode) tools.push("augmentcode");
|
|
4563
|
+
if (options["augmentcode-legacy"]) tools.push("augmentcode-legacy");
|
|
4564
|
+
if (options.copilot) tools.push("copilot");
|
|
4565
|
+
if (options.cursor) tools.push("cursor");
|
|
4566
|
+
if (options.cline) tools.push("cline");
|
|
4567
|
+
if (options.codexcli) tools.push("codexcli");
|
|
4568
|
+
if (options.claudecode) tools.push("claudecode");
|
|
4569
|
+
if (options.roo) tools.push("roo");
|
|
4570
|
+
if (options.geminicli) tools.push("geminicli");
|
|
4571
|
+
if (options.junie) tools.push("junie");
|
|
4572
|
+
if (options.qwencode) tools.push("qwencode");
|
|
4573
|
+
if (options.kiro) tools.push("kiro");
|
|
4574
|
+
if (options.opencode) tools.push("opencode");
|
|
4575
|
+
if (options.windsurf) tools.push("windsurf");
|
|
4576
|
+
}
|
|
4257
4577
|
const generateOptions = {
|
|
4258
4578
|
verbose: options.verbose,
|
|
4579
|
+
tools: tools.length > 0 ? tools : void 0,
|
|
4259
4580
|
delete: options.delete,
|
|
4260
4581
|
config: options.config,
|
|
4261
4582
|
noConfig: options.noConfig
|
|
4262
4583
|
};
|
|
4263
|
-
if (tools.length > 0) {
|
|
4264
|
-
generateOptions.tools = tools;
|
|
4265
|
-
}
|
|
4266
4584
|
if (options.baseDir) {
|
|
4267
4585
|
generateOptions.baseDirs = options.baseDir.split(",").map((dir) => dir.trim()).filter((dir) => dir.length > 0);
|
|
4268
4586
|
}
|