rulesync 0.64.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 +7 -1
- package/dist/{amazonqcli-WVGYACHI.js → amazonqcli-MW7XTVPN.js} +2 -2
- package/dist/{augmentcode-DTHPPXWO.js → augmentcode-WCZCL7VR.js} +2 -2
- package/dist/{chunk-KKWJVA56.js → chunk-4NWMCTN5.js} +1 -1
- package/dist/{chunk-DMTCLQ4T.js → chunk-6AXPFPKI.js} +1 -1
- package/dist/{chunk-EID75W45.js → chunk-6SLEITCQ.js} +1 -1
- package/dist/{chunk-YPJW7Z5M.js → chunk-DM2B7XUB.js} +1 -1
- package/dist/{chunk-JX55DU6Y.js → chunk-FL5BF6JM.js} +1 -1
- package/dist/{chunk-TBXG53FV.js → chunk-GIAQWZQ4.js} +1 -1
- package/dist/{chunk-E2J3UBBK.js → chunk-I4NVS7GE.js} +1 -1
- package/dist/{chunk-6LSN7HSJ.js → chunk-JXOLLTNV.js} +14 -1
- package/dist/{chunk-HHJIL3YZ.js → chunk-LTWEI4PW.js} +1 -1
- package/dist/{chunk-LYVES5YR.js → chunk-M2AUM37M.js} +1 -0
- package/dist/{chunk-4NAQ5HL4.js → chunk-N6DASHJL.js} +1 -1
- package/dist/chunk-TX2CE4RR.js +17 -0
- package/dist/{chunk-TQOL7OKY.js → chunk-UGY5ALND.js} +1 -1
- package/dist/{chunk-LURFNGH4.js → chunk-VRWNZTGW.js} +1 -1
- package/dist/{chunk-FVPZQEWP.js → chunk-YC2BC7Z2.js} +1 -1
- package/dist/{claudecode-SSYLLUXX.js → claudecode-RZSJPPBU.js} +3 -3
- package/dist/{cline-5EUGKNZ6.js → cline-JTWWBQQ4.js} +3 -3
- package/dist/{codexcli-IGM2ADYK.js → codexcli-ATMFGRJR.js} +3 -3
- package/dist/{copilot-HSQO7ZCJ.js → copilot-H3CLGKDP.js} +2 -2
- package/dist/{cursor-ZB3XNGBK.js → cursor-ZUN5RZU6.js} +3 -3
- package/dist/{geminicli-FNRKH5GX.js → geminicli-Q5HPIQCU.js} +3 -3
- package/dist/index.cjs +297 -111
- package/dist/index.js +286 -133
- package/dist/{junie-3YGOSOGF.js → junie-JCLVC3MI.js} +3 -3
- package/dist/{kiro-B6WZNLY4.js → kiro-CNF6433S.js} +2 -2
- package/dist/{opencode-SZETJ62M.js → opencode-EBS3CED2.js} +2 -2
- package/dist/qwencode-JIT6KW7E.js +10 -0
- package/dist/{roo-KLTWVAKE.js → roo-KBTRH4TZ.js} +3 -3
- package/dist/{windsurf-IZEKUAID.js → windsurf-ZAAWL6JJ.js} +3 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import "./chunk-
|
|
3
|
-
import "./chunk-
|
|
4
|
-
import "./chunk-
|
|
5
|
-
import "./chunk-
|
|
6
|
-
import "./chunk-
|
|
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";
|
|
7
8
|
import {
|
|
8
9
|
ensureDir,
|
|
9
10
|
fileExists,
|
|
@@ -15,33 +16,25 @@ import {
|
|
|
15
16
|
removeDirectory,
|
|
16
17
|
resolvePath,
|
|
17
18
|
writeFileContent
|
|
18
|
-
} from "./chunk-
|
|
19
|
-
import "./chunk-
|
|
20
|
-
import "./chunk-
|
|
21
|
-
import "./chunk-
|
|
22
|
-
import "./chunk-
|
|
23
|
-
import "./chunk-
|
|
24
|
-
import "./chunk-
|
|
25
|
-
import "./chunk-
|
|
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";
|
|
26
27
|
import {
|
|
27
28
|
ALL_TOOL_TARGETS,
|
|
28
29
|
RulesyncTargetsSchema,
|
|
29
30
|
ToolTargetSchema,
|
|
30
31
|
ToolTargetsSchema,
|
|
31
32
|
isToolTarget
|
|
32
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-M2AUM37M.js";
|
|
33
34
|
|
|
34
35
|
// src/cli/index.ts
|
|
35
36
|
import { Command } from "commander";
|
|
36
37
|
|
|
37
|
-
// src/cli/commands/add.ts
|
|
38
|
-
import { mkdir, writeFile } from "fs/promises";
|
|
39
|
-
import * as path from "path";
|
|
40
|
-
|
|
41
|
-
// src/utils/config-loader.ts
|
|
42
|
-
import { loadConfig as loadC12Config } from "c12";
|
|
43
|
-
import { $ZodError } from "zod/v4/core";
|
|
44
|
-
|
|
45
38
|
// src/types/claudecode.ts
|
|
46
39
|
import { z } from "zod/mini";
|
|
47
40
|
var ClaudeSettingsSchema = z.looseObject({
|
|
@@ -91,6 +84,7 @@ var OutputPathsSchema = z4.object({
|
|
|
91
84
|
claudecode: z4.optional(z4.string()),
|
|
92
85
|
codexcli: z4.optional(z4.string()),
|
|
93
86
|
opencode: z4.optional(z4.string()),
|
|
87
|
+
qwencode: z4.optional(z4.string()),
|
|
94
88
|
roo: z4.optional(z4.string()),
|
|
95
89
|
geminicli: z4.optional(z4.string()),
|
|
96
90
|
kiro: z4.optional(z4.string()),
|
|
@@ -187,6 +181,14 @@ var GenerateOptionsSchema = z6.object({
|
|
|
187
181
|
watch: z6.optional(z6.boolean())
|
|
188
182
|
});
|
|
189
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
|
+
|
|
190
192
|
// src/utils/config.ts
|
|
191
193
|
function getDefaultConfig() {
|
|
192
194
|
return {
|
|
@@ -201,6 +203,7 @@ function getDefaultConfig() {
|
|
|
201
203
|
claudecode: ".",
|
|
202
204
|
codexcli: ".",
|
|
203
205
|
opencode: ".",
|
|
206
|
+
qwencode: ".qwen/memories",
|
|
204
207
|
roo: ".roo/rules",
|
|
205
208
|
geminicli: ".gemini/memories",
|
|
206
209
|
kiro: ".kiro/steering",
|
|
@@ -691,7 +694,7 @@ export default config;
|
|
|
691
694
|
}
|
|
692
695
|
|
|
693
696
|
// src/cli/commands/generate.ts
|
|
694
|
-
import { join as
|
|
697
|
+
import { join as join13 } from "path";
|
|
695
698
|
|
|
696
699
|
// src/core/command-generator.ts
|
|
697
700
|
import { join as join3 } from "path";
|
|
@@ -1661,23 +1664,84 @@ async function generateKiroIgnoreFiles(rules, config, baseDir) {
|
|
|
1661
1664
|
return generateIgnoreFile(rules, config, ignoreConfigs.kiro, baseDir);
|
|
1662
1665
|
}
|
|
1663
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
|
+
|
|
1664
1728
|
// src/generators/ignore/windsurf.ts
|
|
1665
1729
|
function generateWindsurfIgnore(rules, config, baseDir) {
|
|
1666
1730
|
return generateIgnoreFile(rules, config, ignoreConfigs.windsurf, baseDir);
|
|
1667
1731
|
}
|
|
1668
1732
|
|
|
1669
1733
|
// src/generators/rules/shared-helpers.ts
|
|
1670
|
-
import { join as
|
|
1734
|
+
import { join as join7 } from "path";
|
|
1671
1735
|
|
|
1672
1736
|
// src/utils/ignore.ts
|
|
1673
|
-
import { join as
|
|
1737
|
+
import { join as join6 } from "path";
|
|
1674
1738
|
import micromatch from "micromatch";
|
|
1675
1739
|
var cachedIgnorePatterns = null;
|
|
1676
1740
|
async function loadIgnorePatterns(baseDir = process.cwd()) {
|
|
1677
1741
|
if (cachedIgnorePatterns) {
|
|
1678
1742
|
return cachedIgnorePatterns;
|
|
1679
1743
|
}
|
|
1680
|
-
const ignorePath =
|
|
1744
|
+
const ignorePath = join6(baseDir, ".rulesyncignore");
|
|
1681
1745
|
if (!await fileExists(ignorePath)) {
|
|
1682
1746
|
cachedIgnorePatterns = { patterns: [] };
|
|
1683
1747
|
return cachedIgnorePatterns;
|
|
@@ -1731,7 +1795,7 @@ function addOutput(outputs, tool, config, baseDir, relativePath, content) {
|
|
|
1731
1795
|
const outputDir = resolveOutputDir(config, tool, baseDir);
|
|
1732
1796
|
outputs.push({
|
|
1733
1797
|
tool,
|
|
1734
|
-
filepath:
|
|
1798
|
+
filepath: join7(outputDir, relativePath),
|
|
1735
1799
|
content
|
|
1736
1800
|
});
|
|
1737
1801
|
}
|
|
@@ -1740,7 +1804,7 @@ async function generateRulesConfig(rules, config, generatorConfig, baseDir) {
|
|
|
1740
1804
|
for (const rule of rules) {
|
|
1741
1805
|
const content = generatorConfig.generateContent(rule);
|
|
1742
1806
|
const outputDir = resolveOutputDir(config, generatorConfig.tool, baseDir);
|
|
1743
|
-
const filepath = generatorConfig.pathResolver ? generatorConfig.pathResolver(rule, outputDir) :
|
|
1807
|
+
const filepath = generatorConfig.pathResolver ? generatorConfig.pathResolver(rule, outputDir) : join7(outputDir, `${rule.filename}${generatorConfig.fileExtension}`);
|
|
1744
1808
|
outputs.push({
|
|
1745
1809
|
tool: generatorConfig.tool,
|
|
1746
1810
|
filepath,
|
|
@@ -1768,7 +1832,7 @@ async function generateComplexRules(rules, config, generatorConfig, baseDir) {
|
|
|
1768
1832
|
for (const rule of detailRules) {
|
|
1769
1833
|
const content = generatorConfig.generateDetailContent(rule);
|
|
1770
1834
|
const filepath = resolvePath(
|
|
1771
|
-
|
|
1835
|
+
join7(generatorConfig.detailSubDir, `${rule.filename}.md`),
|
|
1772
1836
|
baseDir
|
|
1773
1837
|
);
|
|
1774
1838
|
outputs.push({
|
|
@@ -1876,7 +1940,7 @@ function generateRuleFile(rule) {
|
|
|
1876
1940
|
}
|
|
1877
1941
|
|
|
1878
1942
|
// src/generators/rules/augmentcode.ts
|
|
1879
|
-
import { join as
|
|
1943
|
+
import { join as join8 } from "path";
|
|
1880
1944
|
async function generateAugmentcodeConfig(rules, config, baseDir) {
|
|
1881
1945
|
const outputs = createOutputsArray();
|
|
1882
1946
|
rules.forEach((rule) => {
|
|
@@ -1885,7 +1949,7 @@ async function generateAugmentcodeConfig(rules, config, baseDir) {
|
|
|
1885
1949
|
"augmentcode",
|
|
1886
1950
|
config,
|
|
1887
1951
|
baseDir,
|
|
1888
|
-
|
|
1952
|
+
join8(".augment", "rules", `${rule.filename}.md`),
|
|
1889
1953
|
generateRuleFile2(rule)
|
|
1890
1954
|
);
|
|
1891
1955
|
});
|
|
@@ -1938,7 +2002,7 @@ function generateLegacyGuidelinesFile(allRules) {
|
|
|
1938
2002
|
}
|
|
1939
2003
|
|
|
1940
2004
|
// src/generators/rules/claudecode.ts
|
|
1941
|
-
import { join as
|
|
2005
|
+
import { join as join9 } from "path";
|
|
1942
2006
|
async function generateClaudecodeConfig(rules, config, baseDir) {
|
|
1943
2007
|
const generatorConfig = {
|
|
1944
2008
|
tool: "claudecode",
|
|
@@ -1950,7 +2014,7 @@ async function generateClaudecodeConfig(rules, config, baseDir) {
|
|
|
1950
2014
|
generateDetailContent: generateMemoryFile,
|
|
1951
2015
|
detailSubDir: ".claude/memories",
|
|
1952
2016
|
updateAdditionalConfig: async (ignorePatterns, baseDir2) => {
|
|
1953
|
-
const settingsPath = resolvePath(
|
|
2017
|
+
const settingsPath = resolvePath(join9(".claude", "settings.json"), baseDir2);
|
|
1954
2018
|
await updateClaudeSettings(settingsPath, ignorePatterns);
|
|
1955
2019
|
return [];
|
|
1956
2020
|
}
|
|
@@ -2014,7 +2078,7 @@ async function updateClaudeSettings(settingsPath, ignorePatterns) {
|
|
|
2014
2078
|
}
|
|
2015
2079
|
|
|
2016
2080
|
// src/generators/rules/generator-registry.ts
|
|
2017
|
-
import { join as
|
|
2081
|
+
import { join as join10 } from "path";
|
|
2018
2082
|
function determineCursorRuleType(frontmatter) {
|
|
2019
2083
|
if (frontmatter.cursorRuleType) {
|
|
2020
2084
|
return frontmatter.cursorRuleType;
|
|
@@ -2110,7 +2174,7 @@ var GENERATOR_REGISTRY = {
|
|
|
2110
2174
|
},
|
|
2111
2175
|
pathResolver: (rule, outputDir) => {
|
|
2112
2176
|
const baseFilename = rule.filename.replace(/\.md$/, "");
|
|
2113
|
-
return
|
|
2177
|
+
return join10(outputDir, `${baseFilename}.instructions.md`);
|
|
2114
2178
|
}
|
|
2115
2179
|
},
|
|
2116
2180
|
cursor: {
|
|
@@ -2150,7 +2214,7 @@ var GENERATOR_REGISTRY = {
|
|
|
2150
2214
|
return lines.join("\n");
|
|
2151
2215
|
},
|
|
2152
2216
|
pathResolver: (rule, outputDir) => {
|
|
2153
|
-
return
|
|
2217
|
+
return join10(outputDir, `${rule.filename}.mdc`);
|
|
2154
2218
|
}
|
|
2155
2219
|
},
|
|
2156
2220
|
codexcli: {
|
|
@@ -2186,10 +2250,10 @@ var GENERATOR_REGISTRY = {
|
|
|
2186
2250
|
pathResolver: (rule, outputDir) => {
|
|
2187
2251
|
const outputFormat = rule.frontmatter.windsurfOutputFormat || "directory";
|
|
2188
2252
|
if (outputFormat === "single-file") {
|
|
2189
|
-
return
|
|
2253
|
+
return join10(outputDir, ".windsurf-rules");
|
|
2190
2254
|
} else {
|
|
2191
|
-
const rulesDir =
|
|
2192
|
-
return
|
|
2255
|
+
const rulesDir = join10(outputDir, ".windsurf", "rules");
|
|
2256
|
+
return join10(rulesDir, `${rule.filename}.md`);
|
|
2193
2257
|
}
|
|
2194
2258
|
}
|
|
2195
2259
|
},
|
|
@@ -2252,6 +2316,22 @@ var GENERATOR_REGISTRY = {
|
|
|
2252
2316
|
const lines = [];
|
|
2253
2317
|
if (rule.frontmatter.description) {
|
|
2254
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}
|
|
2255
2335
|
`);
|
|
2256
2336
|
}
|
|
2257
2337
|
lines.push(rule.content.trim());
|
|
@@ -2308,6 +2388,7 @@ var generateCopilotConfig = createSimpleGenerator("copilot");
|
|
|
2308
2388
|
var generateWindsurfConfig = createSimpleGenerator("windsurf");
|
|
2309
2389
|
var generateKiroConfig = createSimpleGenerator("kiro");
|
|
2310
2390
|
var generateRooConfig = createSimpleGenerator("roo");
|
|
2391
|
+
var generateQwencodeConfig = createSimpleGenerator("qwencode");
|
|
2311
2392
|
|
|
2312
2393
|
// src/utils/xml-document-generator.ts
|
|
2313
2394
|
import { XMLBuilder } from "fast-xml-parser";
|
|
@@ -2469,6 +2550,30 @@ function generateOpenCodeRootMarkdown(rootRule, memoryRules, _baseDir) {
|
|
|
2469
2550
|
});
|
|
2470
2551
|
}
|
|
2471
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
|
+
|
|
2472
2577
|
// src/core/generator.ts
|
|
2473
2578
|
async function generateConfigurations(rules, config, targetTools, baseDir) {
|
|
2474
2579
|
const outputs = createOutputsArray();
|
|
@@ -2543,6 +2648,11 @@ async function generateForTool(tool, rules, config, baseDir) {
|
|
|
2543
2648
|
}
|
|
2544
2649
|
case "opencode":
|
|
2545
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
|
+
}
|
|
2546
2656
|
case "windsurf": {
|
|
2547
2657
|
const windsurfRulesOutputs = await generateWindsurfConfig(rules, config, baseDir);
|
|
2548
2658
|
const windsurfIgnoreOutputs = await generateWindsurfIgnore(rules, config, baseDir);
|
|
@@ -2719,6 +2829,7 @@ async function generateMcpConfigurations(mcpConfig, baseDir, targetTools) {
|
|
|
2719
2829
|
claudecode: ".",
|
|
2720
2830
|
codexcli: ".",
|
|
2721
2831
|
opencode: ".",
|
|
2832
|
+
qwencode: ".qwen/memories",
|
|
2722
2833
|
roo: ".roo/rules",
|
|
2723
2834
|
geminicli: ".gemini/memories",
|
|
2724
2835
|
kiro: ".kiro/steering",
|
|
@@ -2728,41 +2839,45 @@ async function generateMcpConfigurations(mcpConfig, baseDir, targetTools) {
|
|
|
2728
2839
|
watchEnabled: false,
|
|
2729
2840
|
defaultTargets: []
|
|
2730
2841
|
};
|
|
2731
|
-
const results = await (await import("./amazonqcli-
|
|
2842
|
+
const results = await (await import("./amazonqcli-MW7XTVPN.js")).generateAmazonqcliMcp(
|
|
2732
2843
|
servers,
|
|
2733
2844
|
config,
|
|
2734
2845
|
dir
|
|
2735
2846
|
);
|
|
2736
2847
|
return results.map((result) => ({ filepath: result.filepath, content: result.content }));
|
|
2737
2848
|
},
|
|
2738
|
-
augmentcode: async (servers, dir) => (await import("./augmentcode-
|
|
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(
|
|
2739
2854
|
servers,
|
|
2740
2855
|
dir
|
|
2741
2856
|
),
|
|
2742
|
-
|
|
2857
|
+
claudecode: async (servers, dir) => (await import("./claudecode-RZSJPPBU.js")).generateClaudeMcpConfiguration(
|
|
2743
2858
|
servers,
|
|
2744
2859
|
dir
|
|
2745
2860
|
),
|
|
2746
|
-
|
|
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(
|
|
2747
2866
|
servers,
|
|
2748
2867
|
dir
|
|
2749
2868
|
),
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
cline: async (servers, dir) => (await import("./cline-5EUGKNZ6.js")).generateClineMcpConfiguration(servers, dir),
|
|
2753
|
-
codexcli: async (servers, dir) => (await import("./codexcli-IGM2ADYK.js")).generateCodexMcpConfiguration(servers, dir),
|
|
2754
|
-
opencode: async (servers, dir) => (await import("./opencode-SZETJ62M.js")).generateOpenCodeMcpConfiguration(
|
|
2869
|
+
roo: async (servers, dir) => (await import("./roo-KBTRH4TZ.js")).generateRooMcpConfiguration(servers, dir),
|
|
2870
|
+
geminicli: async (servers, dir) => (await import("./geminicli-Q5HPIQCU.js")).generateGeminiCliMcpConfiguration(
|
|
2755
2871
|
servers,
|
|
2756
2872
|
dir
|
|
2757
2873
|
),
|
|
2758
|
-
|
|
2759
|
-
|
|
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(
|
|
2760
2877
|
servers,
|
|
2761
2878
|
dir
|
|
2762
2879
|
),
|
|
2763
|
-
|
|
2764
|
-
junie: async (servers, dir) => (await import("./junie-3YGOSOGF.js")).generateJunieMcpConfiguration(servers, dir),
|
|
2765
|
-
windsurf: async (servers, dir) => (await import("./windsurf-IZEKUAID.js")).generateWindsurfMcpConfiguration(
|
|
2880
|
+
windsurf: async (servers, dir) => (await import("./windsurf-ZAAWL6JJ.js")).generateWindsurfMcpConfiguration(
|
|
2766
2881
|
servers,
|
|
2767
2882
|
dir
|
|
2768
2883
|
)
|
|
@@ -2791,35 +2906,40 @@ async function generateCommand(options = {}) {
|
|
|
2791
2906
|
};
|
|
2792
2907
|
const configResult = await loadConfig(configLoaderOptions);
|
|
2793
2908
|
const cliOptions = {
|
|
2794
|
-
|
|
2909
|
+
tools: options.tools,
|
|
2795
2910
|
...options.verbose !== void 0 && { verbose: options.verbose },
|
|
2796
2911
|
...options.delete !== void 0 && { delete: options.delete },
|
|
2797
2912
|
...options.baseDirs !== void 0 && { baseDirs: options.baseDirs }
|
|
2798
2913
|
};
|
|
2799
2914
|
const config = mergeWithCliOptions(configResult.config, cliOptions);
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
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);
|
|
2822
2941
|
}
|
|
2942
|
+
logger.setVerbose(config.verbose || false);
|
|
2823
2943
|
let baseDirs;
|
|
2824
2944
|
if (config.baseDir) {
|
|
2825
2945
|
baseDirs = Array.isArray(config.baseDir) ? config.baseDir : [config.baseDir];
|
|
@@ -2847,7 +2967,7 @@ async function generateCommand(options = {}) {
|
|
|
2847
2967
|
logger.info("Deleting existing output directories...");
|
|
2848
2968
|
const targetTools = config.defaultTargets;
|
|
2849
2969
|
const deleteTasks = [];
|
|
2850
|
-
const commandsDir =
|
|
2970
|
+
const commandsDir = join13(config.aiRulesDir, "commands");
|
|
2851
2971
|
const hasCommands = await fileExists(commandsDir);
|
|
2852
2972
|
let hasCommandFiles = false;
|
|
2853
2973
|
if (hasCommands) {
|
|
@@ -2862,12 +2982,12 @@ async function generateCommand(options = {}) {
|
|
|
2862
2982
|
for (const tool of targetTools) {
|
|
2863
2983
|
switch (tool) {
|
|
2864
2984
|
case "augmentcode":
|
|
2865
|
-
deleteTasks.push(removeDirectory(
|
|
2866
|
-
deleteTasks.push(removeDirectory(
|
|
2985
|
+
deleteTasks.push(removeDirectory(join13(".augment", "rules")));
|
|
2986
|
+
deleteTasks.push(removeDirectory(join13(".augment", "ignore")));
|
|
2867
2987
|
break;
|
|
2868
2988
|
case "augmentcode-legacy":
|
|
2869
2989
|
deleteTasks.push(removeClaudeGeneratedFiles());
|
|
2870
|
-
deleteTasks.push(removeDirectory(
|
|
2990
|
+
deleteTasks.push(removeDirectory(join13(".augment", "ignore")));
|
|
2871
2991
|
break;
|
|
2872
2992
|
case "copilot":
|
|
2873
2993
|
deleteTasks.push(removeDirectory(config.outputPaths.copilot));
|
|
@@ -2881,19 +3001,19 @@ async function generateCommand(options = {}) {
|
|
|
2881
3001
|
case "claudecode":
|
|
2882
3002
|
deleteTasks.push(removeClaudeGeneratedFiles());
|
|
2883
3003
|
if (hasCommandFiles) {
|
|
2884
|
-
deleteTasks.push(removeDirectory(
|
|
3004
|
+
deleteTasks.push(removeDirectory(join13(".claude", "commands")));
|
|
2885
3005
|
}
|
|
2886
3006
|
break;
|
|
2887
3007
|
case "roo":
|
|
2888
3008
|
deleteTasks.push(removeDirectory(config.outputPaths.roo));
|
|
2889
3009
|
if (hasCommandFiles) {
|
|
2890
|
-
deleteTasks.push(removeDirectory(
|
|
3010
|
+
deleteTasks.push(removeDirectory(join13(".roo", "commands")));
|
|
2891
3011
|
}
|
|
2892
3012
|
break;
|
|
2893
3013
|
case "geminicli":
|
|
2894
3014
|
deleteTasks.push(removeDirectory(config.outputPaths.geminicli));
|
|
2895
3015
|
if (hasCommandFiles) {
|
|
2896
|
-
deleteTasks.push(removeDirectory(
|
|
3016
|
+
deleteTasks.push(removeDirectory(join13(".gemini", "commands")));
|
|
2897
3017
|
}
|
|
2898
3018
|
break;
|
|
2899
3019
|
case "kiro":
|
|
@@ -2902,6 +3022,9 @@ async function generateCommand(options = {}) {
|
|
|
2902
3022
|
case "opencode":
|
|
2903
3023
|
deleteTasks.push(removeDirectory(config.outputPaths.opencode));
|
|
2904
3024
|
break;
|
|
3025
|
+
case "qwencode":
|
|
3026
|
+
deleteTasks.push(removeDirectory(config.outputPaths.qwencode));
|
|
3027
|
+
break;
|
|
2905
3028
|
case "windsurf":
|
|
2906
3029
|
deleteTasks.push(removeDirectory(config.outputPaths.windsurf));
|
|
2907
3030
|
break;
|
|
@@ -2995,9 +3118,9 @@ Generating configurations for base directory: ${baseDir}`);
|
|
|
2995
3118
|
|
|
2996
3119
|
// src/cli/commands/gitignore.ts
|
|
2997
3120
|
import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
2998
|
-
import { join as
|
|
3121
|
+
import { join as join14 } from "path";
|
|
2999
3122
|
var gitignoreCommand = async () => {
|
|
3000
|
-
const gitignorePath =
|
|
3123
|
+
const gitignorePath = join14(process.cwd(), ".gitignore");
|
|
3001
3124
|
const rulesFilesToIgnore = [
|
|
3002
3125
|
"# Generated by rulesync - AI tool configuration files",
|
|
3003
3126
|
"**/.amazonq/rules/",
|
|
@@ -3019,6 +3142,8 @@ var gitignoreCommand = async () => {
|
|
|
3019
3142
|
"**/GEMINI.md",
|
|
3020
3143
|
"**/.gemini/memories/",
|
|
3021
3144
|
"**/.gemini/commands/",
|
|
3145
|
+
"**/QWEN.md",
|
|
3146
|
+
"**/.qwen/memories/",
|
|
3022
3147
|
"**/.aiexclude",
|
|
3023
3148
|
"**/.aiignore",
|
|
3024
3149
|
"**/.augmentignore",
|
|
@@ -3037,6 +3162,7 @@ var gitignoreCommand = async () => {
|
|
|
3037
3162
|
"**/.vscode/mcp.json",
|
|
3038
3163
|
"**/.codex/mcp-config.json",
|
|
3039
3164
|
"**/.gemini/settings.json",
|
|
3165
|
+
"**/.qwen/settings.json",
|
|
3040
3166
|
"**/.roo/mcp.json"
|
|
3041
3167
|
];
|
|
3042
3168
|
let gitignoreContent = "";
|
|
@@ -3068,11 +3194,11 @@ ${linesToAdd.join("\n")}
|
|
|
3068
3194
|
};
|
|
3069
3195
|
|
|
3070
3196
|
// src/core/importer.ts
|
|
3071
|
-
import { join as
|
|
3197
|
+
import { join as join21 } from "path";
|
|
3072
3198
|
import matter2 from "gray-matter";
|
|
3073
3199
|
|
|
3074
3200
|
// src/parsers/shared-helpers.ts
|
|
3075
|
-
import { basename as basename3, join as
|
|
3201
|
+
import { basename as basename3, join as join15 } from "path";
|
|
3076
3202
|
async function parseConfigurationFiles(baseDir = process.cwd(), config) {
|
|
3077
3203
|
const errors = [];
|
|
3078
3204
|
const rules = [];
|
|
@@ -3129,7 +3255,7 @@ async function parseConfigurationFiles(baseDir = process.cwd(), config) {
|
|
|
3129
3255
|
const files = await readdir(dirPath);
|
|
3130
3256
|
for (const file of files) {
|
|
3131
3257
|
if (file.endsWith(dirConfig.filePattern)) {
|
|
3132
|
-
const filePath =
|
|
3258
|
+
const filePath = join15(dirPath, file);
|
|
3133
3259
|
const fileResult = await safeAsyncOperation(async () => {
|
|
3134
3260
|
const rawContent = await readFileContent(filePath);
|
|
3135
3261
|
let content;
|
|
@@ -3280,7 +3406,7 @@ async function parseMemoryFiles(memoryDir, config) {
|
|
|
3280
3406
|
const files = await readdir(memoryDir);
|
|
3281
3407
|
for (const file of files) {
|
|
3282
3408
|
if (file.endsWith(".md")) {
|
|
3283
|
-
const filePath =
|
|
3409
|
+
const filePath = join15(memoryDir, file);
|
|
3284
3410
|
const content = await readFileContent(filePath);
|
|
3285
3411
|
if (content.trim()) {
|
|
3286
3412
|
const filename = basename3(file, ".md");
|
|
@@ -3310,7 +3436,7 @@ async function parseCommandsFiles(commandsDir, config) {
|
|
|
3310
3436
|
const files = await readdir(commandsDir);
|
|
3311
3437
|
for (const file of files) {
|
|
3312
3438
|
if (file.endsWith(".md")) {
|
|
3313
|
-
const filePath =
|
|
3439
|
+
const filePath = join15(commandsDir, file);
|
|
3314
3440
|
const content = await readFileContent(filePath);
|
|
3315
3441
|
if (content.trim()) {
|
|
3316
3442
|
const filename = basename3(file, ".md");
|
|
@@ -3402,7 +3528,7 @@ async function parseAmazonqcliConfiguration(baseDir = process.cwd()) {
|
|
|
3402
3528
|
}
|
|
3403
3529
|
|
|
3404
3530
|
// src/parsers/augmentcode.ts
|
|
3405
|
-
import { basename as basename4, join as
|
|
3531
|
+
import { basename as basename4, join as join16 } from "path";
|
|
3406
3532
|
|
|
3407
3533
|
// src/utils/parser-helpers.ts
|
|
3408
3534
|
function createParseResult() {
|
|
@@ -3450,7 +3576,7 @@ async function parseAugmentcodeLegacyConfiguration(baseDir = process.cwd()) {
|
|
|
3450
3576
|
async function parseUnifiedAugmentcode(baseDir, config) {
|
|
3451
3577
|
const result = createParseResult();
|
|
3452
3578
|
if (config.rulesDir) {
|
|
3453
|
-
const rulesDir =
|
|
3579
|
+
const rulesDir = join16(baseDir, config.rulesDir);
|
|
3454
3580
|
if (await fileExists(rulesDir)) {
|
|
3455
3581
|
const rulesResult = await parseAugmentRules(rulesDir, config);
|
|
3456
3582
|
addRules(result, rulesResult.rules);
|
|
@@ -3463,7 +3589,7 @@ async function parseUnifiedAugmentcode(baseDir, config) {
|
|
|
3463
3589
|
}
|
|
3464
3590
|
}
|
|
3465
3591
|
if (config.legacyFilePath) {
|
|
3466
|
-
const legacyPath =
|
|
3592
|
+
const legacyPath = join16(baseDir, config.legacyFilePath);
|
|
3467
3593
|
if (await fileExists(legacyPath)) {
|
|
3468
3594
|
const legacyResult = await parseAugmentGuidelines(legacyPath, config);
|
|
3469
3595
|
if (legacyResult.rule) {
|
|
@@ -3487,7 +3613,7 @@ async function parseAugmentRules(rulesDir, config) {
|
|
|
3487
3613
|
const files = await readdir(rulesDir);
|
|
3488
3614
|
for (const file of files) {
|
|
3489
3615
|
if (file.endsWith(".md") || file.endsWith(".mdc")) {
|
|
3490
|
-
const filePath =
|
|
3616
|
+
const filePath = join16(rulesDir, file);
|
|
3491
3617
|
try {
|
|
3492
3618
|
const rawContent = await readFileContent(filePath);
|
|
3493
3619
|
const parsed = parseFrontmatter(rawContent);
|
|
@@ -3587,7 +3713,7 @@ async function parseClineConfiguration(baseDir = process.cwd()) {
|
|
|
3587
3713
|
}
|
|
3588
3714
|
|
|
3589
3715
|
// src/parsers/codexcli.ts
|
|
3590
|
-
import { join as
|
|
3716
|
+
import { join as join17 } from "path";
|
|
3591
3717
|
|
|
3592
3718
|
// src/parsers/copilot.ts
|
|
3593
3719
|
async function parseCopilotConfiguration(baseDir = process.cwd()) {
|
|
@@ -3610,7 +3736,7 @@ async function parseCopilotConfiguration(baseDir = process.cwd()) {
|
|
|
3610
3736
|
}
|
|
3611
3737
|
|
|
3612
3738
|
// src/parsers/cursor.ts
|
|
3613
|
-
import { basename as basename5, join as
|
|
3739
|
+
import { basename as basename5, join as join18 } from "path";
|
|
3614
3740
|
import { DEFAULT_SCHEMA, FAILSAFE_SCHEMA, load } from "js-yaml";
|
|
3615
3741
|
import { z as z7 } from "zod/mini";
|
|
3616
3742
|
var customMatterOptions = {
|
|
@@ -3734,7 +3860,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
3734
3860
|
const rules = [];
|
|
3735
3861
|
let ignorePatterns;
|
|
3736
3862
|
let mcpServers;
|
|
3737
|
-
const cursorFilePath =
|
|
3863
|
+
const cursorFilePath = join18(baseDir, ".cursorrules");
|
|
3738
3864
|
if (await fileExists(cursorFilePath)) {
|
|
3739
3865
|
try {
|
|
3740
3866
|
const rawContent = await readFileContent(cursorFilePath);
|
|
@@ -3755,14 +3881,14 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
3755
3881
|
errors.push(`Failed to parse .cursorrules file: ${errorMessage}`);
|
|
3756
3882
|
}
|
|
3757
3883
|
}
|
|
3758
|
-
const cursorRulesDir =
|
|
3884
|
+
const cursorRulesDir = join18(baseDir, ".cursor", "rules");
|
|
3759
3885
|
if (await fileExists(cursorRulesDir)) {
|
|
3760
3886
|
try {
|
|
3761
3887
|
const { readdir } = await import("fs/promises");
|
|
3762
3888
|
const files = await readdir(cursorRulesDir);
|
|
3763
3889
|
for (const file of files) {
|
|
3764
3890
|
if (file.endsWith(".mdc")) {
|
|
3765
|
-
const filePath =
|
|
3891
|
+
const filePath = join18(cursorRulesDir, file);
|
|
3766
3892
|
try {
|
|
3767
3893
|
const rawContent = await readFileContent(filePath);
|
|
3768
3894
|
const parsed = parseFrontmatter(rawContent, { matterOptions: customMatterOptions });
|
|
@@ -3791,7 +3917,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
3791
3917
|
if (rules.length === 0) {
|
|
3792
3918
|
errors.push("No Cursor configuration files found (.cursorrules or .cursor/rules/*.mdc)");
|
|
3793
3919
|
}
|
|
3794
|
-
const cursorIgnorePath =
|
|
3920
|
+
const cursorIgnorePath = join18(baseDir, ".cursorignore");
|
|
3795
3921
|
if (await fileExists(cursorIgnorePath)) {
|
|
3796
3922
|
try {
|
|
3797
3923
|
const content = await readFileContent(cursorIgnorePath);
|
|
@@ -3804,7 +3930,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
3804
3930
|
errors.push(`Failed to parse .cursorignore: ${errorMessage}`);
|
|
3805
3931
|
}
|
|
3806
3932
|
}
|
|
3807
|
-
const cursorMcpPath =
|
|
3933
|
+
const cursorMcpPath = join18(baseDir, ".cursor", "mcp.json");
|
|
3808
3934
|
if (await fileExists(cursorMcpPath)) {
|
|
3809
3935
|
try {
|
|
3810
3936
|
const content = await readFileContent(cursorMcpPath);
|
|
@@ -3854,11 +3980,11 @@ async function parseGeminiConfiguration(baseDir = process.cwd()) {
|
|
|
3854
3980
|
}
|
|
3855
3981
|
|
|
3856
3982
|
// src/parsers/junie.ts
|
|
3857
|
-
import { join as
|
|
3983
|
+
import { join as join19 } from "path";
|
|
3858
3984
|
async function parseJunieConfiguration(baseDir = process.cwd()) {
|
|
3859
3985
|
const errors = [];
|
|
3860
3986
|
const rules = [];
|
|
3861
|
-
const guidelinesPath =
|
|
3987
|
+
const guidelinesPath = join19(baseDir, ".junie", "guidelines.md");
|
|
3862
3988
|
if (!await fileExists(guidelinesPath)) {
|
|
3863
3989
|
errors.push(".junie/guidelines.md file not found");
|
|
3864
3990
|
return { rules, errors };
|
|
@@ -3915,6 +4041,22 @@ async function parseOpenCodeConfiguration(baseDir = process.cwd()) {
|
|
|
3915
4041
|
});
|
|
3916
4042
|
}
|
|
3917
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
|
+
|
|
3918
4060
|
// src/parsers/roo.ts
|
|
3919
4061
|
async function parseRooConfiguration(baseDir = process.cwd()) {
|
|
3920
4062
|
return parseConfigurationFiles(baseDir, {
|
|
@@ -3937,7 +4079,7 @@ async function parseRooConfiguration(baseDir = process.cwd()) {
|
|
|
3937
4079
|
|
|
3938
4080
|
// src/parsers/windsurf.ts
|
|
3939
4081
|
import { readFile } from "fs/promises";
|
|
3940
|
-
import { join as
|
|
4082
|
+
import { join as join20 } from "path";
|
|
3941
4083
|
|
|
3942
4084
|
// src/core/importer.ts
|
|
3943
4085
|
async function importConfiguration(options) {
|
|
@@ -4032,6 +4174,13 @@ async function importConfiguration(options) {
|
|
|
4032
4174
|
mcpServers = opencodeResult.mcpServers;
|
|
4033
4175
|
break;
|
|
4034
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
|
+
}
|
|
4035
4184
|
default:
|
|
4036
4185
|
errors.push(`Unsupported tool: ${tool}`);
|
|
4037
4186
|
return { success: false, rulesCreated: 0, errors };
|
|
@@ -4044,7 +4193,7 @@ async function importConfiguration(options) {
|
|
|
4044
4193
|
if (rules.length === 0 && !ignorePatterns && !mcpServers) {
|
|
4045
4194
|
return { success: false, rulesCreated: 0, errors };
|
|
4046
4195
|
}
|
|
4047
|
-
const rulesDirPath =
|
|
4196
|
+
const rulesDirPath = join21(baseDir, rulesDir);
|
|
4048
4197
|
try {
|
|
4049
4198
|
const { mkdir: mkdir2 } = await import("fs/promises");
|
|
4050
4199
|
await mkdir2(rulesDirPath, { recursive: true });
|
|
@@ -4059,17 +4208,17 @@ async function importConfiguration(options) {
|
|
|
4059
4208
|
const baseFilename = rule.filename;
|
|
4060
4209
|
let targetDir = rulesDirPath;
|
|
4061
4210
|
if (rule.type === "command") {
|
|
4062
|
-
targetDir =
|
|
4211
|
+
targetDir = join21(rulesDirPath, "commands");
|
|
4063
4212
|
const { mkdir: mkdir2 } = await import("fs/promises");
|
|
4064
4213
|
await mkdir2(targetDir, { recursive: true });
|
|
4065
4214
|
} else {
|
|
4066
4215
|
if (!useLegacyLocation) {
|
|
4067
|
-
targetDir =
|
|
4216
|
+
targetDir = join21(rulesDirPath, "rules");
|
|
4068
4217
|
const { mkdir: mkdir2 } = await import("fs/promises");
|
|
4069
4218
|
await mkdir2(targetDir, { recursive: true });
|
|
4070
4219
|
}
|
|
4071
4220
|
}
|
|
4072
|
-
const filePath =
|
|
4221
|
+
const filePath = join21(targetDir, `${baseFilename}.md`);
|
|
4073
4222
|
const content = generateRuleFileContent(rule);
|
|
4074
4223
|
await writeFileContent(filePath, content);
|
|
4075
4224
|
rulesCreated++;
|
|
@@ -4084,7 +4233,7 @@ async function importConfiguration(options) {
|
|
|
4084
4233
|
let ignoreFileCreated = false;
|
|
4085
4234
|
if (ignorePatterns && ignorePatterns.length > 0) {
|
|
4086
4235
|
try {
|
|
4087
|
-
const rulesyncignorePath =
|
|
4236
|
+
const rulesyncignorePath = join21(baseDir, ".rulesyncignore");
|
|
4088
4237
|
const ignoreContent = `${ignorePatterns.join("\n")}
|
|
4089
4238
|
`;
|
|
4090
4239
|
await writeFileContent(rulesyncignorePath, ignoreContent);
|
|
@@ -4100,7 +4249,7 @@ async function importConfiguration(options) {
|
|
|
4100
4249
|
let mcpFileCreated = false;
|
|
4101
4250
|
if (mcpServers && Object.keys(mcpServers).length > 0) {
|
|
4102
4251
|
try {
|
|
4103
|
-
const mcpPath =
|
|
4252
|
+
const mcpPath = join21(baseDir, rulesDir, ".mcp.json");
|
|
4104
4253
|
const mcpContent = `${JSON.stringify({ mcpServers }, null, 2)}
|
|
4105
4254
|
`;
|
|
4106
4255
|
await writeFileContent(mcpPath, mcpContent);
|
|
@@ -4147,10 +4296,11 @@ async function importCommand(options = {}) {
|
|
|
4147
4296
|
if (options.cline) tools.push("cline");
|
|
4148
4297
|
if (options.roo) tools.push("roo");
|
|
4149
4298
|
if (options.geminicli) tools.push("geminicli");
|
|
4299
|
+
if (options.qwencode) tools.push("qwencode");
|
|
4150
4300
|
if (options.opencode) tools.push("opencode");
|
|
4151
4301
|
if (tools.length === 0) {
|
|
4152
4302
|
logger.error(
|
|
4153
|
-
"\u274C Please specify one tool to import from (--amazonqcli, --augmentcode, --augmentcode-legacy, --claudecode, --cursor, --copilot, --cline, --roo, --geminicli, --opencode)"
|
|
4303
|
+
"\u274C Please specify one tool to import from (--amazonqcli, --augmentcode, --augmentcode-legacy, --claudecode, --cursor, --copilot, --cline, --roo, --geminicli, --qwencode, --opencode)"
|
|
4154
4304
|
);
|
|
4155
4305
|
process.exit(1);
|
|
4156
4306
|
}
|
|
@@ -4198,7 +4348,7 @@ async function importCommand(options = {}) {
|
|
|
4198
4348
|
}
|
|
4199
4349
|
|
|
4200
4350
|
// src/cli/commands/init.ts
|
|
4201
|
-
import { join as
|
|
4351
|
+
import { join as join22 } from "path";
|
|
4202
4352
|
async function initCommand(options = {}) {
|
|
4203
4353
|
const configResult = await loadConfig();
|
|
4204
4354
|
const config = configResult.config;
|
|
@@ -4206,7 +4356,7 @@ async function initCommand(options = {}) {
|
|
|
4206
4356
|
logger.log("Initializing rulesync...");
|
|
4207
4357
|
await ensureDir(aiRulesDir);
|
|
4208
4358
|
const useLegacy = options.legacy ?? config.legacy ?? false;
|
|
4209
|
-
const rulesDir = useLegacy ? aiRulesDir :
|
|
4359
|
+
const rulesDir = useLegacy ? aiRulesDir : join22(aiRulesDir, "rules");
|
|
4210
4360
|
if (!useLegacy) {
|
|
4211
4361
|
await ensureDir(rulesDir);
|
|
4212
4362
|
}
|
|
@@ -4252,7 +4402,7 @@ globs: ["**/*"]
|
|
|
4252
4402
|
- Follow single responsibility principle
|
|
4253
4403
|
`
|
|
4254
4404
|
};
|
|
4255
|
-
const filepath =
|
|
4405
|
+
const filepath = join22(rulesDir, sampleFile.filename);
|
|
4256
4406
|
if (!await fileExists(filepath)) {
|
|
4257
4407
|
await writeFileContent(filepath, sampleFile.content);
|
|
4258
4408
|
logger.success(`Created ${filepath}`);
|
|
@@ -4396,38 +4546,41 @@ async function watchCommand() {
|
|
|
4396
4546
|
|
|
4397
4547
|
// src/cli/index.ts
|
|
4398
4548
|
var program = new Command();
|
|
4399
|
-
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");
|
|
4400
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);
|
|
4401
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);
|
|
4402
4552
|
program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);
|
|
4403
|
-
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("--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);
|
|
4404
|
-
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("--opencode", "Generate only for OpenCode").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(
|
|
4405
4555
|
"-b, --base-dir <paths>",
|
|
4406
4556
|
"Base directories to generate files (comma-separated for multiple paths)"
|
|
4407
4557
|
).option("-v, --verbose", "Verbose output").option("-c, --config <path>", "Path to configuration file").option("--no-config", "Disable configuration file loading").action(async (options) => {
|
|
4408
4558
|
const tools = [];
|
|
4409
|
-
if (options.
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
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
|
+
}
|
|
4422
4577
|
const generateOptions = {
|
|
4423
4578
|
verbose: options.verbose,
|
|
4579
|
+
tools: tools.length > 0 ? tools : void 0,
|
|
4424
4580
|
delete: options.delete,
|
|
4425
4581
|
config: options.config,
|
|
4426
4582
|
noConfig: options.noConfig
|
|
4427
4583
|
};
|
|
4428
|
-
if (tools.length > 0) {
|
|
4429
|
-
generateOptions.tools = tools;
|
|
4430
|
-
}
|
|
4431
4584
|
if (options.baseDir) {
|
|
4432
4585
|
generateOptions.baseDirs = options.baseDir.split(",").map((dir) => dir.trim()).filter((dir) => dir.length > 0);
|
|
4433
4586
|
}
|