rulesync 0.62.0 → 0.63.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +315 -273
- package/dist/index.js +297 -256
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -35,11 +35,11 @@ function isToolTarget(target) {
|
|
|
35
35
|
if (!target) return false;
|
|
36
36
|
return ALL_TOOL_TARGETS.some((validTarget) => validTarget === target);
|
|
37
37
|
}
|
|
38
|
-
var
|
|
38
|
+
var import_mini2, ALL_TOOL_TARGETS, ToolTargetSchema, ToolTargetsSchema, WildcardTargetSchema, RulesyncTargetsSchema;
|
|
39
39
|
var init_tool_targets = __esm({
|
|
40
40
|
"src/types/tool-targets.ts"() {
|
|
41
41
|
"use strict";
|
|
42
|
-
|
|
42
|
+
import_mini2 = require("zod/mini");
|
|
43
43
|
ALL_TOOL_TARGETS = [
|
|
44
44
|
"augmentcode",
|
|
45
45
|
"augmentcode-legacy",
|
|
@@ -54,10 +54,10 @@ var init_tool_targets = __esm({
|
|
|
54
54
|
"junie",
|
|
55
55
|
"windsurf"
|
|
56
56
|
];
|
|
57
|
-
ToolTargetSchema =
|
|
58
|
-
ToolTargetsSchema =
|
|
59
|
-
WildcardTargetSchema =
|
|
60
|
-
RulesyncTargetsSchema =
|
|
57
|
+
ToolTargetSchema = import_mini2.z.enum(ALL_TOOL_TARGETS);
|
|
58
|
+
ToolTargetsSchema = import_mini2.z.array(ToolTargetSchema);
|
|
59
|
+
WildcardTargetSchema = import_mini2.z.tuple([import_mini2.z.literal("*")]);
|
|
60
|
+
RulesyncTargetsSchema = import_mini2.z.union([ToolTargetsSchema, WildcardTargetSchema]);
|
|
61
61
|
}
|
|
62
62
|
});
|
|
63
63
|
|
|
@@ -1071,11 +1071,20 @@ var ClaudeSettingsSchema = import_mini.z.looseObject({
|
|
|
1071
1071
|
)
|
|
1072
1072
|
});
|
|
1073
1073
|
|
|
1074
|
-
// src/types/
|
|
1075
|
-
var
|
|
1076
|
-
|
|
1077
|
-
|
|
1074
|
+
// src/types/shared.ts
|
|
1075
|
+
var import_mini3 = require("zod/mini");
|
|
1076
|
+
init_tool_targets();
|
|
1077
|
+
var OutputSchema = import_mini3.z.object({
|
|
1078
|
+
tool: ToolTargetSchema,
|
|
1079
|
+
filepath: import_mini3.z.string(),
|
|
1080
|
+
content: import_mini3.z.string()
|
|
1078
1081
|
});
|
|
1082
|
+
var BaseFrontmatterSchema = import_mini3.z.object({
|
|
1083
|
+
description: import_mini3.z.optional(import_mini3.z.string())
|
|
1084
|
+
});
|
|
1085
|
+
|
|
1086
|
+
// src/types/commands.ts
|
|
1087
|
+
var CommandFrontmatterSchema = BaseFrontmatterSchema;
|
|
1079
1088
|
|
|
1080
1089
|
// src/types/config.ts
|
|
1081
1090
|
var import_mini4 = require("zod/mini");
|
|
@@ -1193,11 +1202,6 @@ var RuleFrontmatterSchema = import_mini7.z.object({
|
|
|
1193
1202
|
windsurfOutputFormat: import_mini7.z.optional(import_mini7.z.enum(["single-file", "directory"])),
|
|
1194
1203
|
tags: import_mini7.z.optional(import_mini7.z.array(import_mini7.z.string()))
|
|
1195
1204
|
});
|
|
1196
|
-
var GeneratedOutputSchema = import_mini7.z.object({
|
|
1197
|
-
tool: ToolTargetSchema,
|
|
1198
|
-
filepath: import_mini7.z.string(),
|
|
1199
|
-
content: import_mini7.z.string()
|
|
1200
|
-
});
|
|
1201
1205
|
var GenerateOptionsSchema = import_mini7.z.object({
|
|
1202
1206
|
targetTools: import_mini7.z.optional(ToolTargetsSchema),
|
|
1203
1207
|
outputDir: import_mini7.z.optional(import_mini7.z.string()),
|
|
@@ -1426,6 +1430,50 @@ function mergeWithCliOptions(config, cliOptions) {
|
|
|
1426
1430
|
return merged;
|
|
1427
1431
|
}
|
|
1428
1432
|
|
|
1433
|
+
// src/utils/logger.ts
|
|
1434
|
+
var import_consola = require("consola");
|
|
1435
|
+
var Logger = class {
|
|
1436
|
+
_verbose = false;
|
|
1437
|
+
console = import_consola.consola.withDefaults({
|
|
1438
|
+
tag: "rulesync"
|
|
1439
|
+
});
|
|
1440
|
+
setVerbose(verbose) {
|
|
1441
|
+
this._verbose = verbose;
|
|
1442
|
+
}
|
|
1443
|
+
get verbose() {
|
|
1444
|
+
return this._verbose;
|
|
1445
|
+
}
|
|
1446
|
+
// Regular log (always shown, regardless of verbose)
|
|
1447
|
+
log(message, ...args) {
|
|
1448
|
+
this.console.log(message, ...args);
|
|
1449
|
+
}
|
|
1450
|
+
// Info level (shown only in verbose mode)
|
|
1451
|
+
info(message, ...args) {
|
|
1452
|
+
if (this._verbose) {
|
|
1453
|
+
this.console.info(message, ...args);
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
// Success (always shown)
|
|
1457
|
+
success(message, ...args) {
|
|
1458
|
+
this.console.success(message, ...args);
|
|
1459
|
+
}
|
|
1460
|
+
// Warning (always shown)
|
|
1461
|
+
warn(message, ...args) {
|
|
1462
|
+
this.console.warn(message, ...args);
|
|
1463
|
+
}
|
|
1464
|
+
// Error (always shown)
|
|
1465
|
+
error(message, ...args) {
|
|
1466
|
+
this.console.error(message, ...args);
|
|
1467
|
+
}
|
|
1468
|
+
// Debug level (shown only in verbose mode)
|
|
1469
|
+
debug(message, ...args) {
|
|
1470
|
+
if (this._verbose) {
|
|
1471
|
+
this.console.debug(message, ...args);
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
};
|
|
1475
|
+
var logger = new Logger();
|
|
1476
|
+
|
|
1429
1477
|
// src/cli/commands/add.ts
|
|
1430
1478
|
function sanitizeFilename(filename) {
|
|
1431
1479
|
return filename.endsWith(".md") ? filename.slice(0, -3) : filename;
|
|
@@ -1455,11 +1503,11 @@ async function addCommand(filename, options = {}) {
|
|
|
1455
1503
|
await (0, import_promises.mkdir)(rulesDir, { recursive: true });
|
|
1456
1504
|
const template = generateRuleTemplate(sanitizedFilename);
|
|
1457
1505
|
await (0, import_promises.writeFile)(filePath, template, "utf8");
|
|
1458
|
-
|
|
1459
|
-
|
|
1506
|
+
logger.success(`Created rule file: ${filePath}`);
|
|
1507
|
+
logger.log(`\u{1F4DD} Edit the file to customize your rules.`);
|
|
1460
1508
|
} catch (error) {
|
|
1461
|
-
|
|
1462
|
-
|
|
1509
|
+
logger.error(
|
|
1510
|
+
`Failed to create rule file: ${error instanceof Error ? error.message : String(error)}`
|
|
1463
1511
|
);
|
|
1464
1512
|
process.exit(3);
|
|
1465
1513
|
}
|
|
@@ -1551,7 +1599,7 @@ async function findRuleFiles(aiRulesDir) {
|
|
|
1551
1599
|
async function removeDirectory(dirPath) {
|
|
1552
1600
|
const dangerousPaths = [".", "/", "~", "src", "node_modules"];
|
|
1553
1601
|
if (dangerousPaths.includes(dirPath) || dirPath === "") {
|
|
1554
|
-
|
|
1602
|
+
logger.warn(`Skipping deletion of dangerous path: ${dirPath}`);
|
|
1555
1603
|
return;
|
|
1556
1604
|
}
|
|
1557
1605
|
try {
|
|
@@ -1559,7 +1607,7 @@ async function removeDirectory(dirPath) {
|
|
|
1559
1607
|
await (0, import_promises2.rm)(dirPath, { recursive: true, force: true });
|
|
1560
1608
|
}
|
|
1561
1609
|
} catch (error) {
|
|
1562
|
-
|
|
1610
|
+
logger.warn(`Failed to remove directory ${dirPath}:`, error);
|
|
1563
1611
|
}
|
|
1564
1612
|
}
|
|
1565
1613
|
async function removeFile(filepath) {
|
|
@@ -1568,7 +1616,7 @@ async function removeFile(filepath) {
|
|
|
1568
1616
|
await (0, import_promises2.rm)(filepath);
|
|
1569
1617
|
}
|
|
1570
1618
|
} catch (error) {
|
|
1571
|
-
|
|
1619
|
+
logger.warn(`Failed to remove file ${filepath}:`, error);
|
|
1572
1620
|
}
|
|
1573
1621
|
}
|
|
1574
1622
|
async function removeClaudeGeneratedFiles() {
|
|
@@ -1582,50 +1630,6 @@ async function removeClaudeGeneratedFiles() {
|
|
|
1582
1630
|
}
|
|
1583
1631
|
}
|
|
1584
1632
|
|
|
1585
|
-
// src/utils/logger.ts
|
|
1586
|
-
var import_consola = require("consola");
|
|
1587
|
-
var Logger = class {
|
|
1588
|
-
_verbose = false;
|
|
1589
|
-
console = import_consola.consola.withDefaults({
|
|
1590
|
-
tag: "rulesync"
|
|
1591
|
-
});
|
|
1592
|
-
setVerbose(verbose) {
|
|
1593
|
-
this._verbose = verbose;
|
|
1594
|
-
}
|
|
1595
|
-
get verbose() {
|
|
1596
|
-
return this._verbose;
|
|
1597
|
-
}
|
|
1598
|
-
// Regular log (always shown, regardless of verbose)
|
|
1599
|
-
log(message, ...args) {
|
|
1600
|
-
this.console.log(message, ...args);
|
|
1601
|
-
}
|
|
1602
|
-
// Info level (shown only in verbose mode)
|
|
1603
|
-
info(message, ...args) {
|
|
1604
|
-
if (this._verbose) {
|
|
1605
|
-
this.console.info(message, ...args);
|
|
1606
|
-
}
|
|
1607
|
-
}
|
|
1608
|
-
// Success (always shown)
|
|
1609
|
-
success(message, ...args) {
|
|
1610
|
-
this.console.success(message, ...args);
|
|
1611
|
-
}
|
|
1612
|
-
// Warning (always shown)
|
|
1613
|
-
warn(message, ...args) {
|
|
1614
|
-
this.console.warn(message, ...args);
|
|
1615
|
-
}
|
|
1616
|
-
// Error (always shown)
|
|
1617
|
-
error(message, ...args) {
|
|
1618
|
-
this.console.error(message, ...args);
|
|
1619
|
-
}
|
|
1620
|
-
// Debug level (shown only in verbose mode)
|
|
1621
|
-
debug(message, ...args) {
|
|
1622
|
-
if (this._verbose) {
|
|
1623
|
-
this.console.debug(message, ...args);
|
|
1624
|
-
}
|
|
1625
|
-
}
|
|
1626
|
-
};
|
|
1627
|
-
var logger = new Logger();
|
|
1628
|
-
|
|
1629
1633
|
// src/cli/commands/config.ts
|
|
1630
1634
|
async function configCommand(options = {}) {
|
|
1631
1635
|
if (options.init) {
|
|
@@ -1837,25 +1841,68 @@ export default config;
|
|
|
1837
1841
|
}
|
|
1838
1842
|
|
|
1839
1843
|
// src/cli/commands/generate.ts
|
|
1840
|
-
var
|
|
1844
|
+
var import_node_path13 = require("path");
|
|
1841
1845
|
|
|
1842
1846
|
// src/core/command-generator.ts
|
|
1843
|
-
var
|
|
1847
|
+
var import_node_path5 = require("path");
|
|
1844
1848
|
|
|
1845
|
-
// src/generators
|
|
1849
|
+
// src/utils/command-generators.ts
|
|
1846
1850
|
var import_node_path3 = require("path");
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1851
|
+
function generateYamlFrontmatter(command, options = {}) {
|
|
1852
|
+
const frontmatter = ["---"];
|
|
1853
|
+
if (options.includeDescription !== false && command.frontmatter.description) {
|
|
1854
|
+
frontmatter.push(`description: ${command.frontmatter.description}`);
|
|
1855
|
+
}
|
|
1856
|
+
if (options.additionalFields) {
|
|
1857
|
+
for (const field of options.additionalFields) {
|
|
1858
|
+
frontmatter.push(`${field.key}: ${field.value}`);
|
|
1853
1859
|
}
|
|
1854
|
-
|
|
1855
|
-
|
|
1860
|
+
}
|
|
1861
|
+
frontmatter.push("---");
|
|
1862
|
+
return frontmatter;
|
|
1863
|
+
}
|
|
1864
|
+
function buildCommandContent(command, frontmatterOptions) {
|
|
1865
|
+
const frontmatter = generateYamlFrontmatter(command, frontmatterOptions);
|
|
1866
|
+
return `${frontmatter.join("\n")}
|
|
1856
1867
|
|
|
1857
1868
|
${command.content.trim()}
|
|
1858
1869
|
`;
|
|
1870
|
+
}
|
|
1871
|
+
function getFlattenedCommandPath(filename, baseDir, subdir) {
|
|
1872
|
+
const flattenedName = filename.replace(/\//g, "-");
|
|
1873
|
+
return (0, import_node_path3.join)(baseDir, subdir, `${flattenedName}.md`);
|
|
1874
|
+
}
|
|
1875
|
+
function getHierarchicalCommandPath(filename, baseDir, subdir, extension = "md") {
|
|
1876
|
+
const nameWithoutExt = filename.replace(/\.[^/.]+$/, "");
|
|
1877
|
+
const fileWithExt = `${nameWithoutExt}.${extension}`;
|
|
1878
|
+
return (0, import_node_path3.join)(baseDir, subdir, fileWithExt);
|
|
1879
|
+
}
|
|
1880
|
+
function escapeTomlString(str) {
|
|
1881
|
+
return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
|
|
1882
|
+
}
|
|
1883
|
+
var syntaxConverters = {
|
|
1884
|
+
/**
|
|
1885
|
+
* Convert Claude Code syntax to Gemini CLI syntax
|
|
1886
|
+
*/
|
|
1887
|
+
toGeminiCli(content) {
|
|
1888
|
+
let converted = content;
|
|
1889
|
+
converted = converted.replace(/\$ARGUMENTS/g, "{{args}}");
|
|
1890
|
+
converted = converted.replace(/!`([^`]+)`/g, "!{$1}");
|
|
1891
|
+
return converted.trim();
|
|
1892
|
+
},
|
|
1893
|
+
/**
|
|
1894
|
+
* Convert to Roo Code syntax (currently identical to Claude Code)
|
|
1895
|
+
*/
|
|
1896
|
+
toRooCode(content) {
|
|
1897
|
+
return content.trim();
|
|
1898
|
+
}
|
|
1899
|
+
};
|
|
1900
|
+
|
|
1901
|
+
// src/generators/commands/claudecode.ts
|
|
1902
|
+
var ClaudeCodeCommandGenerator = class {
|
|
1903
|
+
generate(command, outputDir) {
|
|
1904
|
+
const filepath = this.getOutputPath(command.filename, outputDir);
|
|
1905
|
+
const content = buildCommandContent(command);
|
|
1859
1906
|
return {
|
|
1860
1907
|
tool: "claudecode",
|
|
1861
1908
|
filepath,
|
|
@@ -1863,20 +1910,18 @@ ${command.content.trim()}
|
|
|
1863
1910
|
};
|
|
1864
1911
|
}
|
|
1865
1912
|
getOutputPath(filename, baseDir) {
|
|
1866
|
-
|
|
1867
|
-
return (0, import_node_path3.join)(baseDir, ".claude", "commands", `${flattenedName}.md`);
|
|
1913
|
+
return getFlattenedCommandPath(filename, baseDir, ".claude/commands");
|
|
1868
1914
|
}
|
|
1869
1915
|
};
|
|
1870
1916
|
|
|
1871
1917
|
// src/generators/commands/geminicli.ts
|
|
1872
|
-
var import_node_path4 = require("path");
|
|
1873
1918
|
var GeminiCliCommandGenerator = class {
|
|
1874
1919
|
generate(command, outputDir) {
|
|
1875
1920
|
const filepath = this.getOutputPath(command.filename, outputDir);
|
|
1876
|
-
const convertedContent =
|
|
1921
|
+
const convertedContent = syntaxConverters.toGeminiCli(command.content);
|
|
1877
1922
|
const tomlLines = [];
|
|
1878
1923
|
if (command.frontmatter.description) {
|
|
1879
|
-
tomlLines.push(`description = "${
|
|
1924
|
+
tomlLines.push(`description = "${escapeTomlString(command.frontmatter.description)}"`);
|
|
1880
1925
|
tomlLines.push("");
|
|
1881
1926
|
}
|
|
1882
1927
|
tomlLines.push(`prompt = """${convertedContent}"""`);
|
|
@@ -1888,35 +1933,15 @@ var GeminiCliCommandGenerator = class {
|
|
|
1888
1933
|
};
|
|
1889
1934
|
}
|
|
1890
1935
|
getOutputPath(filename, baseDir) {
|
|
1891
|
-
|
|
1892
|
-
const filenameWithExt = tomlFilename.endsWith(".toml") ? tomlFilename : `${tomlFilename}.toml`;
|
|
1893
|
-
return (0, import_node_path4.join)(baseDir, ".gemini", "commands", filenameWithExt);
|
|
1894
|
-
}
|
|
1895
|
-
convertSyntax(content) {
|
|
1896
|
-
let converted = content;
|
|
1897
|
-
converted = converted.replace(/\$ARGUMENTS/g, "{{args}}");
|
|
1898
|
-
converted = converted.replace(/!`([^`]+)`/g, "!{$1}");
|
|
1899
|
-
return converted.trim();
|
|
1900
|
-
}
|
|
1901
|
-
escapeTomlString(str) {
|
|
1902
|
-
return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
|
|
1936
|
+
return getHierarchicalCommandPath(filename, baseDir, ".gemini/commands", "toml");
|
|
1903
1937
|
}
|
|
1904
1938
|
};
|
|
1905
1939
|
|
|
1906
1940
|
// src/generators/commands/roo.ts
|
|
1907
|
-
var import_node_path5 = require("path");
|
|
1908
1941
|
var RooCommandGenerator = class {
|
|
1909
1942
|
generate(command, outputDir) {
|
|
1910
1943
|
const filepath = this.getOutputPath(command.filename, outputDir);
|
|
1911
|
-
const
|
|
1912
|
-
if (command.frontmatter.description) {
|
|
1913
|
-
frontmatter.push(`description: ${command.frontmatter.description}`);
|
|
1914
|
-
}
|
|
1915
|
-
frontmatter.push("---");
|
|
1916
|
-
const content = `${frontmatter.join("\n")}
|
|
1917
|
-
|
|
1918
|
-
${command.content.trim()}
|
|
1919
|
-
`;
|
|
1944
|
+
const content = buildCommandContent(command);
|
|
1920
1945
|
return {
|
|
1921
1946
|
tool: "roo",
|
|
1922
1947
|
filepath,
|
|
@@ -1924,8 +1949,7 @@ ${command.content.trim()}
|
|
|
1924
1949
|
};
|
|
1925
1950
|
}
|
|
1926
1951
|
getOutputPath(filename, baseDir) {
|
|
1927
|
-
|
|
1928
|
-
return (0, import_node_path5.join)(baseDir, ".roo", "commands", `${flattenedName}.md`);
|
|
1952
|
+
return getFlattenedCommandPath(filename, baseDir, ".roo/commands");
|
|
1929
1953
|
}
|
|
1930
1954
|
};
|
|
1931
1955
|
|
|
@@ -1940,8 +1964,27 @@ function getCommandGenerator(tool) {
|
|
|
1940
1964
|
}
|
|
1941
1965
|
|
|
1942
1966
|
// src/core/command-parser.ts
|
|
1943
|
-
var
|
|
1967
|
+
var import_node_path4 = require("path");
|
|
1968
|
+
|
|
1969
|
+
// src/utils/frontmatter.ts
|
|
1944
1970
|
var import_gray_matter = __toESM(require("gray-matter"), 1);
|
|
1971
|
+
function parseFrontmatter(content, options) {
|
|
1972
|
+
const parsed = (0, import_gray_matter.default)(content, options?.matterOptions);
|
|
1973
|
+
return {
|
|
1974
|
+
content: parsed.content.trim(),
|
|
1975
|
+
data: parsed.data || {}
|
|
1976
|
+
};
|
|
1977
|
+
}
|
|
1978
|
+
function extractArrayField(data, key, defaultValue = []) {
|
|
1979
|
+
const value = data[key];
|
|
1980
|
+
return Array.isArray(value) ? value : defaultValue;
|
|
1981
|
+
}
|
|
1982
|
+
function extractStringField(data, key, defaultValue) {
|
|
1983
|
+
const value = data[key];
|
|
1984
|
+
return typeof value === "string" ? value : defaultValue;
|
|
1985
|
+
}
|
|
1986
|
+
|
|
1987
|
+
// src/core/command-parser.ts
|
|
1945
1988
|
async function parseCommandsFromDirectory(commandsDir) {
|
|
1946
1989
|
const commandFiles = await findFiles(commandsDir, ".md");
|
|
1947
1990
|
const commands = [];
|
|
@@ -1956,17 +1999,17 @@ async function parseCommandsFromDirectory(commandsDir) {
|
|
|
1956
1999
|
}
|
|
1957
2000
|
}
|
|
1958
2001
|
if (errors.length > 0) {
|
|
1959
|
-
|
|
2002
|
+
logger.warn(`Command parsing errors:
|
|
1960
2003
|
${errors.join("\n")}`);
|
|
1961
2004
|
}
|
|
1962
2005
|
return commands;
|
|
1963
2006
|
}
|
|
1964
2007
|
async function parseCommandFile(filepath) {
|
|
1965
2008
|
const content = await readFileContent(filepath);
|
|
1966
|
-
const parsed = (
|
|
2009
|
+
const parsed = parseFrontmatter(content);
|
|
1967
2010
|
try {
|
|
1968
2011
|
const validatedData = CommandFrontmatterSchema.parse(parsed.data);
|
|
1969
|
-
const filename = (0,
|
|
2012
|
+
const filename = (0, import_node_path4.basename)(filepath, ".md");
|
|
1970
2013
|
return {
|
|
1971
2014
|
frontmatter: {
|
|
1972
2015
|
description: validatedData.description
|
|
@@ -1984,7 +2027,7 @@ async function parseCommandFile(filepath) {
|
|
|
1984
2027
|
|
|
1985
2028
|
// src/core/command-generator.ts
|
|
1986
2029
|
async function generateCommands(projectRoot, baseDir, targets) {
|
|
1987
|
-
const commandsDir = (0,
|
|
2030
|
+
const commandsDir = (0, import_node_path5.join)(projectRoot, ".rulesync", "commands");
|
|
1988
2031
|
if (!await fileExists(commandsDir)) {
|
|
1989
2032
|
return [];
|
|
1990
2033
|
}
|
|
@@ -2008,8 +2051,8 @@ async function generateCommands(projectRoot, baseDir, targets) {
|
|
|
2008
2051
|
outputs.push(output);
|
|
2009
2052
|
} catch (error) {
|
|
2010
2053
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2011
|
-
|
|
2012
|
-
|
|
2054
|
+
logger.error(
|
|
2055
|
+
`Failed to generate ${target} command for ${command.filename}: ${errorMessage}`
|
|
2013
2056
|
);
|
|
2014
2057
|
}
|
|
2015
2058
|
}
|
|
@@ -2018,7 +2061,7 @@ async function generateCommands(projectRoot, baseDir, targets) {
|
|
|
2018
2061
|
}
|
|
2019
2062
|
|
|
2020
2063
|
// src/generators/ignore/shared-factory.ts
|
|
2021
|
-
var
|
|
2064
|
+
var import_node_path6 = require("path");
|
|
2022
2065
|
|
|
2023
2066
|
// src/generators/ignore/shared-helpers.ts
|
|
2024
2067
|
function extractIgnorePatternsFromRules(rules) {
|
|
@@ -2141,7 +2184,7 @@ function generateIgnoreFile(rules, config, ignoreConfig, baseDir) {
|
|
|
2141
2184
|
const outputs = [];
|
|
2142
2185
|
const content = generateIgnoreContent(rules, ignoreConfig);
|
|
2143
2186
|
const outputPath = baseDir || process.cwd();
|
|
2144
|
-
const filepath = (0,
|
|
2187
|
+
const filepath = (0, import_node_path6.join)(outputPath, ignoreConfig.filename);
|
|
2145
2188
|
outputs.push({
|
|
2146
2189
|
tool: ignoreConfig.tool,
|
|
2147
2190
|
filepath,
|
|
@@ -2729,20 +2772,20 @@ function generateWindsurfIgnore(rules, config, baseDir) {
|
|
|
2729
2772
|
}
|
|
2730
2773
|
|
|
2731
2774
|
// src/generators/rules/augmentcode.ts
|
|
2732
|
-
var
|
|
2775
|
+
var import_node_path9 = require("path");
|
|
2733
2776
|
|
|
2734
2777
|
// src/generators/rules/shared-helpers.ts
|
|
2735
|
-
var
|
|
2778
|
+
var import_node_path8 = require("path");
|
|
2736
2779
|
|
|
2737
2780
|
// src/utils/ignore.ts
|
|
2738
|
-
var
|
|
2781
|
+
var import_node_path7 = require("path");
|
|
2739
2782
|
var import_micromatch = __toESM(require("micromatch"), 1);
|
|
2740
2783
|
var cachedIgnorePatterns = null;
|
|
2741
2784
|
async function loadIgnorePatterns(baseDir = process.cwd()) {
|
|
2742
2785
|
if (cachedIgnorePatterns) {
|
|
2743
2786
|
return cachedIgnorePatterns;
|
|
2744
2787
|
}
|
|
2745
|
-
const ignorePath = (0,
|
|
2788
|
+
const ignorePath = (0, import_node_path7.join)(baseDir, ".rulesyncignore");
|
|
2746
2789
|
if (!await fileExists(ignorePath)) {
|
|
2747
2790
|
cachedIgnorePatterns = { patterns: [] };
|
|
2748
2791
|
return cachedIgnorePatterns;
|
|
@@ -2753,7 +2796,7 @@ async function loadIgnorePatterns(baseDir = process.cwd()) {
|
|
|
2753
2796
|
cachedIgnorePatterns = { patterns };
|
|
2754
2797
|
return cachedIgnorePatterns;
|
|
2755
2798
|
} catch (error) {
|
|
2756
|
-
|
|
2799
|
+
logger.warn(`Failed to read .rulesyncignore: ${error}`);
|
|
2757
2800
|
cachedIgnorePatterns = { patterns: [] };
|
|
2758
2801
|
return cachedIgnorePatterns;
|
|
2759
2802
|
}
|
|
@@ -2796,7 +2839,7 @@ function addOutput(outputs, tool, config, baseDir, relativePath, content) {
|
|
|
2796
2839
|
const outputDir = resolveOutputDir(config, tool, baseDir);
|
|
2797
2840
|
outputs.push({
|
|
2798
2841
|
tool,
|
|
2799
|
-
filepath: (0,
|
|
2842
|
+
filepath: (0, import_node_path8.join)(outputDir, relativePath),
|
|
2800
2843
|
content
|
|
2801
2844
|
});
|
|
2802
2845
|
}
|
|
@@ -2805,7 +2848,7 @@ async function generateRulesConfig(rules, config, generatorConfig, baseDir) {
|
|
|
2805
2848
|
for (const rule of rules) {
|
|
2806
2849
|
const content = generatorConfig.generateContent(rule);
|
|
2807
2850
|
const outputDir = resolveOutputDir(config, generatorConfig.tool, baseDir);
|
|
2808
|
-
const filepath = generatorConfig.pathResolver ? generatorConfig.pathResolver(rule, outputDir) : (0,
|
|
2851
|
+
const filepath = generatorConfig.pathResolver ? generatorConfig.pathResolver(rule, outputDir) : (0, import_node_path8.join)(outputDir, `${rule.filename}${generatorConfig.fileExtension}`);
|
|
2809
2852
|
outputs.push({
|
|
2810
2853
|
tool: generatorConfig.tool,
|
|
2811
2854
|
filepath,
|
|
@@ -2833,7 +2876,7 @@ async function generateComplexRules(rules, config, generatorConfig, baseDir) {
|
|
|
2833
2876
|
for (const rule of detailRules) {
|
|
2834
2877
|
const content = generatorConfig.generateDetailContent(rule);
|
|
2835
2878
|
const filepath = resolvePath(
|
|
2836
|
-
(0,
|
|
2879
|
+
(0, import_node_path8.join)(generatorConfig.detailSubDir, `${rule.filename}.md`),
|
|
2837
2880
|
baseDir
|
|
2838
2881
|
);
|
|
2839
2882
|
outputs.push({
|
|
@@ -2896,7 +2939,7 @@ async function generateAugmentcodeConfig(rules, config, baseDir) {
|
|
|
2896
2939
|
"augmentcode",
|
|
2897
2940
|
config,
|
|
2898
2941
|
baseDir,
|
|
2899
|
-
(0,
|
|
2942
|
+
(0, import_node_path9.join)(".augment", "rules", `${rule.filename}.md`),
|
|
2900
2943
|
generateRuleFile(rule)
|
|
2901
2944
|
);
|
|
2902
2945
|
});
|
|
@@ -2949,7 +2992,7 @@ function generateLegacyGuidelinesFile(allRules) {
|
|
|
2949
2992
|
}
|
|
2950
2993
|
|
|
2951
2994
|
// src/generators/rules/claudecode.ts
|
|
2952
|
-
var
|
|
2995
|
+
var import_node_path10 = require("path");
|
|
2953
2996
|
async function generateClaudecodeConfig(rules, config, baseDir) {
|
|
2954
2997
|
const generatorConfig = {
|
|
2955
2998
|
tool: "claudecode",
|
|
@@ -2961,7 +3004,7 @@ async function generateClaudecodeConfig(rules, config, baseDir) {
|
|
|
2961
3004
|
generateDetailContent: generateMemoryFile,
|
|
2962
3005
|
detailSubDir: ".claude/memories",
|
|
2963
3006
|
updateAdditionalConfig: async (ignorePatterns, baseDir2) => {
|
|
2964
|
-
const settingsPath = resolvePath((0,
|
|
3007
|
+
const settingsPath = resolvePath((0, import_node_path10.join)(".claude", "settings.json"), baseDir2);
|
|
2965
3008
|
await updateClaudeSettings(settingsPath, ignorePatterns);
|
|
2966
3009
|
return [];
|
|
2967
3010
|
}
|
|
@@ -2998,7 +3041,7 @@ async function updateClaudeSettings(settingsPath, ignorePatterns) {
|
|
|
2998
3041
|
const content = await readFileContent(settingsPath);
|
|
2999
3042
|
rawSettings = JSON.parse(content);
|
|
3000
3043
|
} catch {
|
|
3001
|
-
|
|
3044
|
+
logger.warn(`Failed to parse existing ${settingsPath}, creating new settings`);
|
|
3002
3045
|
rawSettings = {};
|
|
3003
3046
|
}
|
|
3004
3047
|
}
|
|
@@ -3021,11 +3064,11 @@ async function updateClaudeSettings(settingsPath, ignorePatterns) {
|
|
|
3021
3064
|
settings.permissions.deny = Array.from(new Set(filteredDeny));
|
|
3022
3065
|
const jsonContent = JSON.stringify(settings, null, 2);
|
|
3023
3066
|
await writeFileContent(settingsPath, jsonContent);
|
|
3024
|
-
|
|
3067
|
+
logger.success(`Updated Claude Code settings: ${settingsPath}`);
|
|
3025
3068
|
}
|
|
3026
3069
|
|
|
3027
3070
|
// src/generators/rules/generator-registry.ts
|
|
3028
|
-
var
|
|
3071
|
+
var import_node_path11 = require("path");
|
|
3029
3072
|
function determineCursorRuleType(frontmatter) {
|
|
3030
3073
|
if (frontmatter.cursorRuleType) {
|
|
3031
3074
|
return frontmatter.cursorRuleType;
|
|
@@ -3105,7 +3148,7 @@ var GENERATOR_REGISTRY = {
|
|
|
3105
3148
|
},
|
|
3106
3149
|
pathResolver: (rule, outputDir) => {
|
|
3107
3150
|
const baseFilename = rule.filename.replace(/\.md$/, "");
|
|
3108
|
-
return (0,
|
|
3151
|
+
return (0, import_node_path11.join)(outputDir, `${baseFilename}.instructions.md`);
|
|
3109
3152
|
}
|
|
3110
3153
|
},
|
|
3111
3154
|
cursor: {
|
|
@@ -3145,7 +3188,7 @@ var GENERATOR_REGISTRY = {
|
|
|
3145
3188
|
return lines.join("\n");
|
|
3146
3189
|
},
|
|
3147
3190
|
pathResolver: (rule, outputDir) => {
|
|
3148
|
-
return (0,
|
|
3191
|
+
return (0, import_node_path11.join)(outputDir, `${rule.filename}.mdc`);
|
|
3149
3192
|
}
|
|
3150
3193
|
},
|
|
3151
3194
|
codexcli: {
|
|
@@ -3181,10 +3224,10 @@ var GENERATOR_REGISTRY = {
|
|
|
3181
3224
|
pathResolver: (rule, outputDir) => {
|
|
3182
3225
|
const outputFormat = rule.frontmatter.windsurfOutputFormat || "directory";
|
|
3183
3226
|
if (outputFormat === "single-file") {
|
|
3184
|
-
return (0,
|
|
3227
|
+
return (0, import_node_path11.join)(outputDir, ".windsurf-rules");
|
|
3185
3228
|
} else {
|
|
3186
|
-
const rulesDir = (0,
|
|
3187
|
-
return (0,
|
|
3229
|
+
const rulesDir = (0, import_node_path11.join)(outputDir, ".windsurf", "rules");
|
|
3230
|
+
return (0, import_node_path11.join)(rulesDir, `${rule.filename}.md`);
|
|
3188
3231
|
}
|
|
3189
3232
|
}
|
|
3190
3233
|
},
|
|
@@ -3302,7 +3345,7 @@ async function generateCodexConfig(rules, config, baseDir) {
|
|
|
3302
3345
|
const concatenatedContent = generateConcatenatedCodexContent(sortedRules);
|
|
3303
3346
|
if (concatenatedContent.trim()) {
|
|
3304
3347
|
const outputDir = resolveOutputDir(config, "codexcli", baseDir);
|
|
3305
|
-
const filepath = `${outputDir}/
|
|
3348
|
+
const filepath = `${outputDir}/AGENTS.md`;
|
|
3306
3349
|
outputs.push({
|
|
3307
3350
|
tool: "codexcli",
|
|
3308
3351
|
filepath,
|
|
@@ -3408,14 +3451,12 @@ async function generateConfigurations(rules, config, targetTools, baseDir) {
|
|
|
3408
3451
|
const toolsToGenerate = targetTools || config.defaultTargets;
|
|
3409
3452
|
const rootFiles = rules.filter((rule) => rule.frontmatter.root === true);
|
|
3410
3453
|
if (rootFiles.length === 0) {
|
|
3411
|
-
|
|
3412
|
-
"\u26A0\uFE0F Warning: No files with 'root: true' found. This may result in incomplete configurations."
|
|
3413
|
-
);
|
|
3454
|
+
logger.warn("No files with 'root: true' found. This may result in incomplete configurations.");
|
|
3414
3455
|
}
|
|
3415
3456
|
for (const tool of toolsToGenerate) {
|
|
3416
3457
|
const relevantRules = filterRulesForTool(rules, tool, config);
|
|
3417
3458
|
if (relevantRules.length === 0) {
|
|
3418
|
-
|
|
3459
|
+
logger.warn(`No rules found for tool: ${tool}`);
|
|
3419
3460
|
continue;
|
|
3420
3461
|
}
|
|
3421
3462
|
const toolOutputs = await generateForTool(tool, relevantRules, config, baseDir);
|
|
@@ -3480,14 +3521,13 @@ async function generateForTool(tool, rules, config, baseDir) {
|
|
|
3480
3521
|
return [...windsurfRulesOutputs, ...windsurfIgnoreOutputs];
|
|
3481
3522
|
}
|
|
3482
3523
|
default:
|
|
3483
|
-
|
|
3524
|
+
logger.warn(`Unknown tool: ${tool}`);
|
|
3484
3525
|
return null;
|
|
3485
3526
|
}
|
|
3486
3527
|
}
|
|
3487
3528
|
|
|
3488
3529
|
// src/core/parser.ts
|
|
3489
|
-
var
|
|
3490
|
-
var import_gray_matter2 = __toESM(require("gray-matter"), 1);
|
|
3530
|
+
var import_node_path12 = require("path");
|
|
3491
3531
|
async function parseRulesFromDirectory(aiRulesDir) {
|
|
3492
3532
|
const ignorePatterns = await loadIgnorePatterns();
|
|
3493
3533
|
const allRuleFiles = await findRuleFiles(aiRulesDir);
|
|
@@ -3495,7 +3535,7 @@ async function parseRulesFromDirectory(aiRulesDir) {
|
|
|
3495
3535
|
const rules = [];
|
|
3496
3536
|
const errors = [];
|
|
3497
3537
|
if (ignorePatterns.patterns.length > 0) {
|
|
3498
|
-
|
|
3538
|
+
logger.info(`Loaded ${ignorePatterns.patterns.length} ignore patterns from .rulesyncignore`);
|
|
3499
3539
|
}
|
|
3500
3540
|
for (const filepath of ruleFiles) {
|
|
3501
3541
|
try {
|
|
@@ -3521,7 +3561,7 @@ ${errors.join("\n")}`);
|
|
|
3521
3561
|
}
|
|
3522
3562
|
async function parseRuleFile(filepath) {
|
|
3523
3563
|
const content = await readFileContent(filepath);
|
|
3524
|
-
const parsed = (
|
|
3564
|
+
const parsed = parseFrontmatter(content);
|
|
3525
3565
|
try {
|
|
3526
3566
|
const validatedData = RuleFrontmatterSchema.parse(parsed.data);
|
|
3527
3567
|
const frontmatter = {
|
|
@@ -3540,7 +3580,7 @@ async function parseRuleFile(filepath) {
|
|
|
3540
3580
|
},
|
|
3541
3581
|
...validatedData.tags !== void 0 && { tags: validatedData.tags }
|
|
3542
3582
|
};
|
|
3543
|
-
const filename = (0,
|
|
3583
|
+
const filename = (0, import_node_path12.basename)(filepath, ".md");
|
|
3544
3584
|
return {
|
|
3545
3585
|
frontmatter,
|
|
3546
3586
|
content: parsed.content,
|
|
@@ -3759,7 +3799,7 @@ async function generateCommand(options = {}) {
|
|
|
3759
3799
|
logger.info("Deleting existing output directories...");
|
|
3760
3800
|
const targetTools = config.defaultTargets;
|
|
3761
3801
|
const deleteTasks = [];
|
|
3762
|
-
const commandsDir = (0,
|
|
3802
|
+
const commandsDir = (0, import_node_path13.join)(config.aiRulesDir, "commands");
|
|
3763
3803
|
const hasCommands = await fileExists(commandsDir);
|
|
3764
3804
|
let hasCommandFiles = false;
|
|
3765
3805
|
if (hasCommands) {
|
|
@@ -3774,12 +3814,12 @@ async function generateCommand(options = {}) {
|
|
|
3774
3814
|
for (const tool of targetTools) {
|
|
3775
3815
|
switch (tool) {
|
|
3776
3816
|
case "augmentcode":
|
|
3777
|
-
deleteTasks.push(removeDirectory((0,
|
|
3778
|
-
deleteTasks.push(removeDirectory((0,
|
|
3817
|
+
deleteTasks.push(removeDirectory((0, import_node_path13.join)(".augment", "rules")));
|
|
3818
|
+
deleteTasks.push(removeDirectory((0, import_node_path13.join)(".augment", "ignore")));
|
|
3779
3819
|
break;
|
|
3780
3820
|
case "augmentcode-legacy":
|
|
3781
3821
|
deleteTasks.push(removeClaudeGeneratedFiles());
|
|
3782
|
-
deleteTasks.push(removeDirectory((0,
|
|
3822
|
+
deleteTasks.push(removeDirectory((0, import_node_path13.join)(".augment", "ignore")));
|
|
3783
3823
|
break;
|
|
3784
3824
|
case "copilot":
|
|
3785
3825
|
deleteTasks.push(removeDirectory(config.outputPaths.copilot));
|
|
@@ -3793,19 +3833,19 @@ async function generateCommand(options = {}) {
|
|
|
3793
3833
|
case "claudecode":
|
|
3794
3834
|
deleteTasks.push(removeClaudeGeneratedFiles());
|
|
3795
3835
|
if (hasCommandFiles) {
|
|
3796
|
-
deleteTasks.push(removeDirectory((0,
|
|
3836
|
+
deleteTasks.push(removeDirectory((0, import_node_path13.join)(".claude", "commands")));
|
|
3797
3837
|
}
|
|
3798
3838
|
break;
|
|
3799
3839
|
case "roo":
|
|
3800
3840
|
deleteTasks.push(removeDirectory(config.outputPaths.roo));
|
|
3801
3841
|
if (hasCommandFiles) {
|
|
3802
|
-
deleteTasks.push(removeDirectory((0,
|
|
3842
|
+
deleteTasks.push(removeDirectory((0, import_node_path13.join)(".roo", "commands")));
|
|
3803
3843
|
}
|
|
3804
3844
|
break;
|
|
3805
3845
|
case "geminicli":
|
|
3806
3846
|
deleteTasks.push(removeDirectory(config.outputPaths.geminicli));
|
|
3807
3847
|
if (hasCommandFiles) {
|
|
3808
|
-
deleteTasks.push(removeDirectory((0,
|
|
3848
|
+
deleteTasks.push(removeDirectory((0, import_node_path13.join)(".gemini", "commands")));
|
|
3809
3849
|
}
|
|
3810
3850
|
break;
|
|
3811
3851
|
case "kiro":
|
|
@@ -3904,9 +3944,9 @@ Generating configurations for base directory: ${baseDir}`);
|
|
|
3904
3944
|
|
|
3905
3945
|
// src/cli/commands/gitignore.ts
|
|
3906
3946
|
var import_node_fs2 = require("fs");
|
|
3907
|
-
var
|
|
3947
|
+
var import_node_path14 = require("path");
|
|
3908
3948
|
var gitignoreCommand = async () => {
|
|
3909
|
-
const gitignorePath = (0,
|
|
3949
|
+
const gitignorePath = (0, import_node_path14.join)(process.cwd(), ".gitignore");
|
|
3910
3950
|
const rulesFilesToIgnore = [
|
|
3911
3951
|
"# Generated by rulesync - AI tool configuration files",
|
|
3912
3952
|
"**/.github/copilot-instructions.md",
|
|
@@ -3918,7 +3958,7 @@ var gitignoreCommand = async () => {
|
|
|
3918
3958
|
"**/CLAUDE.md",
|
|
3919
3959
|
"**/.claude/memories/",
|
|
3920
3960
|
"**/.claude/commands/",
|
|
3921
|
-
"**/
|
|
3961
|
+
"**/AGENTS.md",
|
|
3922
3962
|
"**/.codexignore",
|
|
3923
3963
|
"**/.roo/rules/",
|
|
3924
3964
|
"**/.rooignore",
|
|
@@ -3954,7 +3994,7 @@ var gitignoreCommand = async () => {
|
|
|
3954
3994
|
}
|
|
3955
3995
|
}
|
|
3956
3996
|
if (linesToAdd.length === 0) {
|
|
3957
|
-
|
|
3997
|
+
logger.success(".gitignore is already up to date");
|
|
3958
3998
|
return;
|
|
3959
3999
|
}
|
|
3960
4000
|
const newContent = gitignoreContent ? `${gitignoreContent.trimEnd()}
|
|
@@ -3963,21 +4003,20 @@ ${linesToAdd.join("\n")}
|
|
|
3963
4003
|
` : `${linesToAdd.join("\n")}
|
|
3964
4004
|
`;
|
|
3965
4005
|
(0, import_node_fs2.writeFileSync)(gitignorePath, newContent);
|
|
3966
|
-
|
|
4006
|
+
logger.success(`Added ${linesToAdd.length} rules to .gitignore:`);
|
|
3967
4007
|
for (const line of linesToAdd) {
|
|
3968
4008
|
if (!line.startsWith("#")) {
|
|
3969
|
-
|
|
4009
|
+
logger.log(` ${line}`);
|
|
3970
4010
|
}
|
|
3971
4011
|
}
|
|
3972
4012
|
};
|
|
3973
4013
|
|
|
3974
4014
|
// src/core/importer.ts
|
|
3975
|
-
var
|
|
3976
|
-
var
|
|
4015
|
+
var import_node_path21 = require("path");
|
|
4016
|
+
var import_gray_matter2 = __toESM(require("gray-matter"), 1);
|
|
3977
4017
|
|
|
3978
4018
|
// src/parsers/augmentcode.ts
|
|
3979
|
-
var
|
|
3980
|
-
var import_gray_matter3 = __toESM(require("gray-matter"), 1);
|
|
4019
|
+
var import_node_path15 = require("path");
|
|
3981
4020
|
|
|
3982
4021
|
// src/utils/parser-helpers.ts
|
|
3983
4022
|
function createParseResult() {
|
|
@@ -4025,7 +4064,7 @@ async function parseAugmentcodeLegacyConfiguration(baseDir = process.cwd()) {
|
|
|
4025
4064
|
async function parseUnifiedAugmentcode(baseDir, config) {
|
|
4026
4065
|
const result = createParseResult();
|
|
4027
4066
|
if (config.rulesDir) {
|
|
4028
|
-
const rulesDir = (0,
|
|
4067
|
+
const rulesDir = (0, import_node_path15.join)(baseDir, config.rulesDir);
|
|
4029
4068
|
if (await fileExists(rulesDir)) {
|
|
4030
4069
|
const rulesResult = await parseAugmentRules(rulesDir, config);
|
|
4031
4070
|
addRules(result, rulesResult.rules);
|
|
@@ -4038,7 +4077,7 @@ async function parseUnifiedAugmentcode(baseDir, config) {
|
|
|
4038
4077
|
}
|
|
4039
4078
|
}
|
|
4040
4079
|
if (config.legacyFilePath) {
|
|
4041
|
-
const legacyPath = (0,
|
|
4080
|
+
const legacyPath = (0, import_node_path15.join)(baseDir, config.legacyFilePath);
|
|
4042
4081
|
if (await fileExists(legacyPath)) {
|
|
4043
4082
|
const legacyResult = await parseAugmentGuidelines(legacyPath, config);
|
|
4044
4083
|
if (legacyResult.rule) {
|
|
@@ -4062,23 +4101,22 @@ async function parseAugmentRules(rulesDir, config) {
|
|
|
4062
4101
|
const files = await readdir2(rulesDir);
|
|
4063
4102
|
for (const file of files) {
|
|
4064
4103
|
if (file.endsWith(".md") || file.endsWith(".mdc")) {
|
|
4065
|
-
const filePath = (0,
|
|
4104
|
+
const filePath = (0, import_node_path15.join)(rulesDir, file);
|
|
4066
4105
|
try {
|
|
4067
4106
|
const rawContent = await readFileContent(filePath);
|
|
4068
|
-
const parsed = (
|
|
4069
|
-
const
|
|
4070
|
-
const
|
|
4071
|
-
const
|
|
4072
|
-
const tags = Array.isArray(frontmatterData.tags) ? frontmatterData.tags : void 0;
|
|
4107
|
+
const parsed = parseFrontmatter(rawContent);
|
|
4108
|
+
const ruleType = extractStringField(parsed.data, "type", "manual");
|
|
4109
|
+
const description = extractStringField(parsed.data, "description", "");
|
|
4110
|
+
const tags = extractArrayField(parsed.data, "tags");
|
|
4073
4111
|
const isRoot = ruleType === "always";
|
|
4074
|
-
const filename = (0,
|
|
4112
|
+
const filename = (0, import_node_path15.basename)(file, file.endsWith(".mdc") ? ".mdc" : ".md");
|
|
4075
4113
|
const frontmatter = {
|
|
4076
4114
|
root: isRoot,
|
|
4077
4115
|
targets: [config.targetName],
|
|
4078
4116
|
description,
|
|
4079
4117
|
globs: ["**/*"],
|
|
4080
4118
|
// AugmentCode doesn't use specific globs in the same way
|
|
4081
|
-
...tags && { tags }
|
|
4119
|
+
...tags.length > 0 && { tags }
|
|
4082
4120
|
};
|
|
4083
4121
|
rules.push({
|
|
4084
4122
|
frontmatter,
|
|
@@ -4129,8 +4167,7 @@ async function parseAugmentGuidelines(guidelinesPath, config) {
|
|
|
4129
4167
|
}
|
|
4130
4168
|
|
|
4131
4169
|
// src/parsers/shared-helpers.ts
|
|
4132
|
-
var
|
|
4133
|
-
var import_gray_matter4 = __toESM(require("gray-matter"), 1);
|
|
4170
|
+
var import_node_path16 = require("path");
|
|
4134
4171
|
async function parseConfigurationFiles(baseDir = process.cwd(), config) {
|
|
4135
4172
|
const errors = [];
|
|
4136
4173
|
const rules = [];
|
|
@@ -4143,16 +4180,18 @@ async function parseConfigurationFiles(baseDir = process.cwd(), config) {
|
|
|
4143
4180
|
let content;
|
|
4144
4181
|
let frontmatter;
|
|
4145
4182
|
if (mainFile.useFrontmatter) {
|
|
4146
|
-
const parsed = (
|
|
4147
|
-
content = parsed.content
|
|
4148
|
-
const parsedFrontmatter = parsed.data;
|
|
4183
|
+
const parsed = parseFrontmatter(rawContent);
|
|
4184
|
+
content = parsed.content;
|
|
4149
4185
|
frontmatter = {
|
|
4150
4186
|
root: mainFile.isRoot ?? false,
|
|
4151
4187
|
targets: [config.tool],
|
|
4152
|
-
description:
|
|
4153
|
-
globs:
|
|
4154
|
-
...parsedFrontmatter.tags && { tags: parsedFrontmatter.tags }
|
|
4188
|
+
description: extractStringField(parsed.data, "description", mainFile.description),
|
|
4189
|
+
globs: extractArrayField(parsed.data, "globs", ["**/*"])
|
|
4155
4190
|
};
|
|
4191
|
+
const tags = extractArrayField(parsed.data, "tags");
|
|
4192
|
+
if (tags.length > 0) {
|
|
4193
|
+
frontmatter.tags = tags;
|
|
4194
|
+
}
|
|
4156
4195
|
} else {
|
|
4157
4196
|
content = rawContent.trim();
|
|
4158
4197
|
frontmatter = {
|
|
@@ -4185,23 +4224,29 @@ async function parseConfigurationFiles(baseDir = process.cwd(), config) {
|
|
|
4185
4224
|
const files = await readdir2(dirPath);
|
|
4186
4225
|
for (const file of files) {
|
|
4187
4226
|
if (file.endsWith(dirConfig.filePattern)) {
|
|
4188
|
-
const filePath = (0,
|
|
4227
|
+
const filePath = (0, import_node_path16.join)(dirPath, file);
|
|
4189
4228
|
const fileResult = await safeAsyncOperation(async () => {
|
|
4190
4229
|
const rawContent = await readFileContent(filePath);
|
|
4191
4230
|
let content;
|
|
4192
4231
|
let frontmatter;
|
|
4193
4232
|
const filename = file.replace(new RegExp(`\\${dirConfig.filePattern}$`), "");
|
|
4194
4233
|
if (dirConfig.filePattern === ".instructions.md") {
|
|
4195
|
-
const parsed = (
|
|
4196
|
-
content = parsed.content
|
|
4197
|
-
const parsedFrontmatter = parsed.data;
|
|
4234
|
+
const parsed = parseFrontmatter(rawContent);
|
|
4235
|
+
content = parsed.content;
|
|
4198
4236
|
frontmatter = {
|
|
4199
4237
|
root: false,
|
|
4200
4238
|
targets: [config.tool],
|
|
4201
|
-
description:
|
|
4202
|
-
|
|
4203
|
-
|
|
4239
|
+
description: extractStringField(
|
|
4240
|
+
parsed.data,
|
|
4241
|
+
"description",
|
|
4242
|
+
`${dirConfig.description}: ${filename}`
|
|
4243
|
+
),
|
|
4244
|
+
globs: extractArrayField(parsed.data, "globs", ["**/*"])
|
|
4204
4245
|
};
|
|
4246
|
+
const tags = extractArrayField(parsed.data, "tags");
|
|
4247
|
+
if (tags.length > 0) {
|
|
4248
|
+
frontmatter.tags = tags;
|
|
4249
|
+
}
|
|
4205
4250
|
} else {
|
|
4206
4251
|
content = rawContent.trim();
|
|
4207
4252
|
frontmatter = {
|
|
@@ -4330,10 +4375,10 @@ async function parseMemoryFiles(memoryDir, config) {
|
|
|
4330
4375
|
const files = await readdir2(memoryDir);
|
|
4331
4376
|
for (const file of files) {
|
|
4332
4377
|
if (file.endsWith(".md")) {
|
|
4333
|
-
const filePath = (0,
|
|
4378
|
+
const filePath = (0, import_node_path16.join)(memoryDir, file);
|
|
4334
4379
|
const content = await readFileContent(filePath);
|
|
4335
4380
|
if (content.trim()) {
|
|
4336
|
-
const filename = (0,
|
|
4381
|
+
const filename = (0, import_node_path16.basename)(file, ".md");
|
|
4337
4382
|
const frontmatter = {
|
|
4338
4383
|
root: false,
|
|
4339
4384
|
targets: [config.tool],
|
|
@@ -4360,20 +4405,19 @@ async function parseCommandsFiles(commandsDir, config) {
|
|
|
4360
4405
|
const files = await readdir2(commandsDir);
|
|
4361
4406
|
for (const file of files) {
|
|
4362
4407
|
if (file.endsWith(".md")) {
|
|
4363
|
-
const filePath = (0,
|
|
4408
|
+
const filePath = (0, import_node_path16.join)(commandsDir, file);
|
|
4364
4409
|
const content = await readFileContent(filePath);
|
|
4365
4410
|
if (content.trim()) {
|
|
4366
|
-
const filename = (0,
|
|
4411
|
+
const filename = (0, import_node_path16.basename)(file, ".md");
|
|
4367
4412
|
let frontmatter;
|
|
4368
4413
|
let ruleContent;
|
|
4369
4414
|
try {
|
|
4370
|
-
const parsed = (
|
|
4371
|
-
ruleContent = parsed.content
|
|
4372
|
-
const parsedFrontmatter = parsed.data;
|
|
4415
|
+
const parsed = parseFrontmatter(content);
|
|
4416
|
+
ruleContent = parsed.content;
|
|
4373
4417
|
frontmatter = {
|
|
4374
4418
|
root: false,
|
|
4375
4419
|
targets: [config.tool],
|
|
4376
|
-
description:
|
|
4420
|
+
description: extractStringField(parsed.data, "description", `Command: ${filename}`),
|
|
4377
4421
|
globs: ["**/*"]
|
|
4378
4422
|
};
|
|
4379
4423
|
} catch {
|
|
@@ -4474,7 +4518,7 @@ async function parseClineConfiguration(baseDir = process.cwd()) {
|
|
|
4474
4518
|
}
|
|
4475
4519
|
|
|
4476
4520
|
// src/parsers/codexcli.ts
|
|
4477
|
-
var
|
|
4521
|
+
var import_node_path17 = require("path");
|
|
4478
4522
|
|
|
4479
4523
|
// src/parsers/copilot.ts
|
|
4480
4524
|
async function parseCopilotConfiguration(baseDir = process.cwd()) {
|
|
@@ -4497,8 +4541,7 @@ async function parseCopilotConfiguration(baseDir = process.cwd()) {
|
|
|
4497
4541
|
}
|
|
4498
4542
|
|
|
4499
4543
|
// src/parsers/cursor.ts
|
|
4500
|
-
var
|
|
4501
|
-
var import_gray_matter5 = __toESM(require("gray-matter"), 1);
|
|
4544
|
+
var import_node_path18 = require("path");
|
|
4502
4545
|
var import_js_yaml = require("js-yaml");
|
|
4503
4546
|
var import_mini8 = require("zod/mini");
|
|
4504
4547
|
var customMatterOptions = {
|
|
@@ -4622,12 +4665,12 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
4622
4665
|
const rules = [];
|
|
4623
4666
|
let ignorePatterns;
|
|
4624
4667
|
let mcpServers;
|
|
4625
|
-
const cursorFilePath = (0,
|
|
4668
|
+
const cursorFilePath = (0, import_node_path18.join)(baseDir, ".cursorrules");
|
|
4626
4669
|
if (await fileExists(cursorFilePath)) {
|
|
4627
4670
|
try {
|
|
4628
4671
|
const rawContent = await readFileContent(cursorFilePath);
|
|
4629
|
-
const parsed = (
|
|
4630
|
-
const content = parsed.content
|
|
4672
|
+
const parsed = parseFrontmatter(rawContent, { matterOptions: customMatterOptions });
|
|
4673
|
+
const content = parsed.content;
|
|
4631
4674
|
if (content) {
|
|
4632
4675
|
const frontmatter = convertCursorMdcFrontmatter(parsed.data, "cursorrules");
|
|
4633
4676
|
frontmatter.targets = ["cursor"];
|
|
@@ -4643,20 +4686,20 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
4643
4686
|
errors.push(`Failed to parse .cursorrules file: ${errorMessage}`);
|
|
4644
4687
|
}
|
|
4645
4688
|
}
|
|
4646
|
-
const cursorRulesDir = (0,
|
|
4689
|
+
const cursorRulesDir = (0, import_node_path18.join)(baseDir, ".cursor", "rules");
|
|
4647
4690
|
if (await fileExists(cursorRulesDir)) {
|
|
4648
4691
|
try {
|
|
4649
4692
|
const { readdir: readdir2 } = await import("fs/promises");
|
|
4650
4693
|
const files = await readdir2(cursorRulesDir);
|
|
4651
4694
|
for (const file of files) {
|
|
4652
4695
|
if (file.endsWith(".mdc")) {
|
|
4653
|
-
const filePath = (0,
|
|
4696
|
+
const filePath = (0, import_node_path18.join)(cursorRulesDir, file);
|
|
4654
4697
|
try {
|
|
4655
4698
|
const rawContent = await readFileContent(filePath);
|
|
4656
|
-
const parsed = (
|
|
4657
|
-
const content = parsed.content
|
|
4699
|
+
const parsed = parseFrontmatter(rawContent, { matterOptions: customMatterOptions });
|
|
4700
|
+
const content = parsed.content;
|
|
4658
4701
|
if (content) {
|
|
4659
|
-
const filename = (0,
|
|
4702
|
+
const filename = (0, import_node_path18.basename)(file, ".mdc");
|
|
4660
4703
|
const frontmatter = convertCursorMdcFrontmatter(parsed.data, filename);
|
|
4661
4704
|
rules.push({
|
|
4662
4705
|
frontmatter,
|
|
@@ -4679,7 +4722,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
4679
4722
|
if (rules.length === 0) {
|
|
4680
4723
|
errors.push("No Cursor configuration files found (.cursorrules or .cursor/rules/*.mdc)");
|
|
4681
4724
|
}
|
|
4682
|
-
const cursorIgnorePath = (0,
|
|
4725
|
+
const cursorIgnorePath = (0, import_node_path18.join)(baseDir, ".cursorignore");
|
|
4683
4726
|
if (await fileExists(cursorIgnorePath)) {
|
|
4684
4727
|
try {
|
|
4685
4728
|
const content = await readFileContent(cursorIgnorePath);
|
|
@@ -4692,7 +4735,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
4692
4735
|
errors.push(`Failed to parse .cursorignore: ${errorMessage}`);
|
|
4693
4736
|
}
|
|
4694
4737
|
}
|
|
4695
|
-
const cursorMcpPath = (0,
|
|
4738
|
+
const cursorMcpPath = (0, import_node_path18.join)(baseDir, ".cursor", "mcp.json");
|
|
4696
4739
|
if (await fileExists(cursorMcpPath)) {
|
|
4697
4740
|
try {
|
|
4698
4741
|
const content = await readFileContent(cursorMcpPath);
|
|
@@ -4742,11 +4785,11 @@ async function parseGeminiConfiguration(baseDir = process.cwd()) {
|
|
|
4742
4785
|
}
|
|
4743
4786
|
|
|
4744
4787
|
// src/parsers/junie.ts
|
|
4745
|
-
var
|
|
4788
|
+
var import_node_path19 = require("path");
|
|
4746
4789
|
async function parseJunieConfiguration(baseDir = process.cwd()) {
|
|
4747
4790
|
const errors = [];
|
|
4748
4791
|
const rules = [];
|
|
4749
|
-
const guidelinesPath = (0,
|
|
4792
|
+
const guidelinesPath = (0, import_node_path19.join)(baseDir, ".junie", "guidelines.md");
|
|
4750
4793
|
if (!await fileExists(guidelinesPath)) {
|
|
4751
4794
|
errors.push(".junie/guidelines.md file not found");
|
|
4752
4795
|
return { rules, errors };
|
|
@@ -4799,8 +4842,7 @@ async function parseRooConfiguration(baseDir = process.cwd()) {
|
|
|
4799
4842
|
|
|
4800
4843
|
// src/parsers/windsurf.ts
|
|
4801
4844
|
var import_promises3 = require("fs/promises");
|
|
4802
|
-
var
|
|
4803
|
-
var import_gray_matter6 = __toESM(require("gray-matter"), 1);
|
|
4845
|
+
var import_node_path20 = require("path");
|
|
4804
4846
|
|
|
4805
4847
|
// src/core/importer.ts
|
|
4806
4848
|
async function importConfiguration(options) {
|
|
@@ -4816,7 +4858,7 @@ async function importConfiguration(options) {
|
|
|
4816
4858
|
let ignorePatterns;
|
|
4817
4859
|
let mcpServers;
|
|
4818
4860
|
if (verbose) {
|
|
4819
|
-
|
|
4861
|
+
logger.log(`Importing ${tool} configuration from ${baseDir}...`);
|
|
4820
4862
|
}
|
|
4821
4863
|
try {
|
|
4822
4864
|
switch (tool) {
|
|
@@ -4892,7 +4934,7 @@ async function importConfiguration(options) {
|
|
|
4892
4934
|
if (rules.length === 0 && !ignorePatterns && !mcpServers) {
|
|
4893
4935
|
return { success: false, rulesCreated: 0, errors };
|
|
4894
4936
|
}
|
|
4895
|
-
const rulesDirPath = (0,
|
|
4937
|
+
const rulesDirPath = (0, import_node_path21.join)(baseDir, rulesDir);
|
|
4896
4938
|
try {
|
|
4897
4939
|
const { mkdir: mkdir3 } = await import("fs/promises");
|
|
4898
4940
|
await mkdir3(rulesDirPath, { recursive: true });
|
|
@@ -4907,22 +4949,22 @@ async function importConfiguration(options) {
|
|
|
4907
4949
|
const baseFilename = rule.filename;
|
|
4908
4950
|
let targetDir = rulesDirPath;
|
|
4909
4951
|
if (rule.type === "command") {
|
|
4910
|
-
targetDir = (0,
|
|
4952
|
+
targetDir = (0, import_node_path21.join)(rulesDirPath, "commands");
|
|
4911
4953
|
const { mkdir: mkdir3 } = await import("fs/promises");
|
|
4912
4954
|
await mkdir3(targetDir, { recursive: true });
|
|
4913
4955
|
} else {
|
|
4914
4956
|
if (!useLegacyLocation) {
|
|
4915
|
-
targetDir = (0,
|
|
4957
|
+
targetDir = (0, import_node_path21.join)(rulesDirPath, "rules");
|
|
4916
4958
|
const { mkdir: mkdir3 } = await import("fs/promises");
|
|
4917
4959
|
await mkdir3(targetDir, { recursive: true });
|
|
4918
4960
|
}
|
|
4919
4961
|
}
|
|
4920
|
-
const filePath = (0,
|
|
4962
|
+
const filePath = (0, import_node_path21.join)(targetDir, `${baseFilename}.md`);
|
|
4921
4963
|
const content = generateRuleFileContent(rule);
|
|
4922
4964
|
await writeFileContent(filePath, content);
|
|
4923
4965
|
rulesCreated++;
|
|
4924
4966
|
if (verbose) {
|
|
4925
|
-
|
|
4967
|
+
logger.success(`Created rule file: ${filePath}`);
|
|
4926
4968
|
}
|
|
4927
4969
|
} catch (error) {
|
|
4928
4970
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -4932,13 +4974,13 @@ async function importConfiguration(options) {
|
|
|
4932
4974
|
let ignoreFileCreated = false;
|
|
4933
4975
|
if (ignorePatterns && ignorePatterns.length > 0) {
|
|
4934
4976
|
try {
|
|
4935
|
-
const rulesyncignorePath = (0,
|
|
4977
|
+
const rulesyncignorePath = (0, import_node_path21.join)(baseDir, ".rulesyncignore");
|
|
4936
4978
|
const ignoreContent = `${ignorePatterns.join("\n")}
|
|
4937
4979
|
`;
|
|
4938
4980
|
await writeFileContent(rulesyncignorePath, ignoreContent);
|
|
4939
4981
|
ignoreFileCreated = true;
|
|
4940
4982
|
if (verbose) {
|
|
4941
|
-
|
|
4983
|
+
logger.success(`Created .rulesyncignore with ${ignorePatterns.length} patterns`);
|
|
4942
4984
|
}
|
|
4943
4985
|
} catch (error) {
|
|
4944
4986
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -4948,13 +4990,13 @@ async function importConfiguration(options) {
|
|
|
4948
4990
|
let mcpFileCreated = false;
|
|
4949
4991
|
if (mcpServers && Object.keys(mcpServers).length > 0) {
|
|
4950
4992
|
try {
|
|
4951
|
-
const mcpPath = (0,
|
|
4993
|
+
const mcpPath = (0, import_node_path21.join)(baseDir, rulesDir, ".mcp.json");
|
|
4952
4994
|
const mcpContent = `${JSON.stringify({ mcpServers }, null, 2)}
|
|
4953
4995
|
`;
|
|
4954
4996
|
await writeFileContent(mcpPath, mcpContent);
|
|
4955
4997
|
mcpFileCreated = true;
|
|
4956
4998
|
if (verbose) {
|
|
4957
|
-
|
|
4999
|
+
logger.success(`Created .mcp.json with ${Object.keys(mcpServers).length} servers`);
|
|
4958
5000
|
}
|
|
4959
5001
|
} catch (error) {
|
|
4960
5002
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -4975,10 +5017,10 @@ function generateRuleFileContent(rule) {
|
|
|
4975
5017
|
description: rule.frontmatter.description,
|
|
4976
5018
|
targets: rule.frontmatter.targets
|
|
4977
5019
|
};
|
|
4978
|
-
const frontmatter2 =
|
|
5020
|
+
const frontmatter2 = import_gray_matter2.default.stringify("", simplifiedFrontmatter);
|
|
4979
5021
|
return frontmatter2 + rule.content;
|
|
4980
5022
|
}
|
|
4981
|
-
const frontmatter =
|
|
5023
|
+
const frontmatter = import_gray_matter2.default.stringify("", rule.frontmatter);
|
|
4982
5024
|
return frontmatter + rule.content;
|
|
4983
5025
|
}
|
|
4984
5026
|
|
|
@@ -5044,23 +5086,23 @@ async function importCommand(options = {}) {
|
|
|
5044
5086
|
}
|
|
5045
5087
|
|
|
5046
5088
|
// src/cli/commands/init.ts
|
|
5047
|
-
var
|
|
5089
|
+
var import_node_path22 = require("path");
|
|
5048
5090
|
async function initCommand(options = {}) {
|
|
5049
5091
|
const configResult = await loadConfig();
|
|
5050
5092
|
const config = configResult.config;
|
|
5051
5093
|
const aiRulesDir = config.aiRulesDir;
|
|
5052
|
-
|
|
5094
|
+
logger.log("Initializing rulesync...");
|
|
5053
5095
|
await ensureDir(aiRulesDir);
|
|
5054
5096
|
const useLegacy = options.legacy ?? config.legacy ?? false;
|
|
5055
|
-
const rulesDir = useLegacy ? aiRulesDir : (0,
|
|
5097
|
+
const rulesDir = useLegacy ? aiRulesDir : (0, import_node_path22.join)(aiRulesDir, "rules");
|
|
5056
5098
|
if (!useLegacy) {
|
|
5057
5099
|
await ensureDir(rulesDir);
|
|
5058
5100
|
}
|
|
5059
5101
|
await createSampleFiles(rulesDir);
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5102
|
+
logger.success("rulesync initialized successfully!");
|
|
5103
|
+
logger.log("\nNext steps:");
|
|
5104
|
+
logger.log(`1. Edit rule files in ${rulesDir}/`);
|
|
5105
|
+
logger.log("2. Run 'rulesync generate' to create configuration files");
|
|
5064
5106
|
}
|
|
5065
5107
|
async function createSampleFiles(rulesDir) {
|
|
5066
5108
|
const sampleFile = {
|
|
@@ -5098,36 +5140,36 @@ globs: ["**/*"]
|
|
|
5098
5140
|
- Follow single responsibility principle
|
|
5099
5141
|
`
|
|
5100
5142
|
};
|
|
5101
|
-
const filepath = (0,
|
|
5143
|
+
const filepath = (0, import_node_path22.join)(rulesDir, sampleFile.filename);
|
|
5102
5144
|
if (!await fileExists(filepath)) {
|
|
5103
5145
|
await writeFileContent(filepath, sampleFile.content);
|
|
5104
|
-
|
|
5146
|
+
logger.success(`Created ${filepath}`);
|
|
5105
5147
|
} else {
|
|
5106
|
-
|
|
5148
|
+
logger.log(`Skipped ${filepath} (already exists)`);
|
|
5107
5149
|
}
|
|
5108
5150
|
}
|
|
5109
5151
|
|
|
5110
5152
|
// src/cli/commands/status.ts
|
|
5111
5153
|
async function statusCommand() {
|
|
5112
5154
|
const config = getDefaultConfig();
|
|
5113
|
-
|
|
5114
|
-
|
|
5155
|
+
logger.log("rulesync Status");
|
|
5156
|
+
logger.log("===============");
|
|
5115
5157
|
const rulesyncExists = await fileExists(config.aiRulesDir);
|
|
5116
|
-
|
|
5158
|
+
logger.log(`
|
|
5117
5159
|
\u{1F4C1} .rulesync directory: ${rulesyncExists ? "\u2705 Found" : "\u274C Not found"}`);
|
|
5118
5160
|
if (!rulesyncExists) {
|
|
5119
|
-
|
|
5161
|
+
logger.log("\n\u{1F4A1} Run 'rulesync init' to get started");
|
|
5120
5162
|
return;
|
|
5121
5163
|
}
|
|
5122
5164
|
try {
|
|
5123
5165
|
const rules = await parseRulesFromDirectory(config.aiRulesDir);
|
|
5124
|
-
|
|
5166
|
+
logger.log(`
|
|
5125
5167
|
\u{1F4CB} Rules: ${rules.length} total`);
|
|
5126
5168
|
if (rules.length > 0) {
|
|
5127
5169
|
const rootRules = rules.filter((r) => r.frontmatter.root).length;
|
|
5128
5170
|
const nonRootRules = rules.length - rootRules;
|
|
5129
|
-
|
|
5130
|
-
|
|
5171
|
+
logger.log(` - Root rules: ${rootRules}`);
|
|
5172
|
+
logger.log(` - Non-root rules: ${nonRootRules}`);
|
|
5131
5173
|
const targetCounts = { copilot: 0, cursor: 0, cline: 0, claudecode: 0, roo: 0 };
|
|
5132
5174
|
for (const rule of rules) {
|
|
5133
5175
|
const targets = rule.frontmatter.targets[0] === "*" ? config.defaultTargets : rule.frontmatter.targets;
|
|
@@ -5139,63 +5181,63 @@ async function statusCommand() {
|
|
|
5139
5181
|
else if (target === "roo") targetCounts.roo++;
|
|
5140
5182
|
}
|
|
5141
5183
|
}
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
}
|
|
5149
|
-
|
|
5184
|
+
logger.log("\n\u{1F3AF} Target tool coverage:");
|
|
5185
|
+
logger.log(` - Copilot: ${targetCounts.copilot} rules`);
|
|
5186
|
+
logger.log(` - Cursor: ${targetCounts.cursor} rules`);
|
|
5187
|
+
logger.log(` - Cline: ${targetCounts.cline} rules`);
|
|
5188
|
+
logger.log(` - Claude Code: ${targetCounts.claudecode} rules`);
|
|
5189
|
+
logger.log(` - Roo: ${targetCounts.roo} rules`);
|
|
5190
|
+
}
|
|
5191
|
+
logger.log("\n\u{1F4E4} Generated files:");
|
|
5150
5192
|
for (const [tool, outputPath] of Object.entries(config.outputPaths)) {
|
|
5151
5193
|
const outputExists = await fileExists(outputPath);
|
|
5152
|
-
|
|
5194
|
+
logger.log(` - ${tool}: ${outputExists ? "\u2705 Generated" : "\u274C Not found"}`);
|
|
5153
5195
|
}
|
|
5154
5196
|
if (rules.length > 0) {
|
|
5155
|
-
|
|
5197
|
+
logger.log("\n\u{1F4A1} Run 'rulesync generate' to update configuration files");
|
|
5156
5198
|
}
|
|
5157
5199
|
} catch (error) {
|
|
5158
|
-
|
|
5200
|
+
logger.error("\nFailed to get status:", error);
|
|
5159
5201
|
}
|
|
5160
5202
|
}
|
|
5161
5203
|
|
|
5162
5204
|
// src/cli/commands/validate.ts
|
|
5163
5205
|
async function validateCommand() {
|
|
5164
5206
|
const config = getDefaultConfig();
|
|
5165
|
-
|
|
5207
|
+
logger.log("Validating rulesync configuration...");
|
|
5166
5208
|
if (!await fileExists(config.aiRulesDir)) {
|
|
5167
|
-
|
|
5209
|
+
logger.error(".rulesync directory not found. Run 'rulesync init' first.");
|
|
5168
5210
|
process.exit(1);
|
|
5169
5211
|
}
|
|
5170
5212
|
try {
|
|
5171
5213
|
const rules = await parseRulesFromDirectory(config.aiRulesDir);
|
|
5172
5214
|
if (rules.length === 0) {
|
|
5173
|
-
|
|
5215
|
+
logger.warn("No rules found in .rulesync directory");
|
|
5174
5216
|
return;
|
|
5175
5217
|
}
|
|
5176
|
-
|
|
5218
|
+
logger.log(`Found ${rules.length} rule(s), validating...`);
|
|
5177
5219
|
const validation = await validateRules(rules);
|
|
5178
5220
|
if (validation.warnings.length > 0) {
|
|
5179
|
-
|
|
5221
|
+
logger.log("\n\u26A0\uFE0F Warnings:");
|
|
5180
5222
|
for (const warning of validation.warnings) {
|
|
5181
|
-
|
|
5223
|
+
logger.log(` - ${warning}`);
|
|
5182
5224
|
}
|
|
5183
5225
|
}
|
|
5184
5226
|
if (validation.errors.length > 0) {
|
|
5185
|
-
|
|
5227
|
+
logger.log("\nErrors:");
|
|
5186
5228
|
for (const error of validation.errors) {
|
|
5187
|
-
|
|
5229
|
+
logger.log(` - ${error}`);
|
|
5188
5230
|
}
|
|
5189
5231
|
}
|
|
5190
5232
|
if (validation.isValid) {
|
|
5191
|
-
|
|
5233
|
+
logger.success("\nAll rules are valid!");
|
|
5192
5234
|
} else {
|
|
5193
|
-
|
|
5194
|
-
|
|
5235
|
+
logger.log(`
|
|
5236
|
+
Validation failed with ${validation.errors.length} error(s)`);
|
|
5195
5237
|
process.exit(1);
|
|
5196
5238
|
}
|
|
5197
5239
|
} catch (error) {
|
|
5198
|
-
|
|
5240
|
+
logger.error("Failed to validate rules:", error);
|
|
5199
5241
|
process.exit(1);
|
|
5200
5242
|
}
|
|
5201
5243
|
}
|
|
@@ -5204,8 +5246,8 @@ async function validateCommand() {
|
|
|
5204
5246
|
var import_chokidar = require("chokidar");
|
|
5205
5247
|
async function watchCommand() {
|
|
5206
5248
|
const config = getDefaultConfig();
|
|
5207
|
-
|
|
5208
|
-
|
|
5249
|
+
logger.log("\u{1F440} Watching for changes in .rulesync directory...");
|
|
5250
|
+
logger.log("Press Ctrl+C to stop watching");
|
|
5209
5251
|
await generateCommand({ verbose: false });
|
|
5210
5252
|
const watcher = (0, import_chokidar.watch)(`${config.aiRulesDir}/**/*.md`, {
|
|
5211
5253
|
ignoreInitial: true,
|
|
@@ -5215,26 +5257,26 @@ async function watchCommand() {
|
|
|
5215
5257
|
const handleChange = async (path5) => {
|
|
5216
5258
|
if (isGenerating) return;
|
|
5217
5259
|
isGenerating = true;
|
|
5218
|
-
|
|
5260
|
+
logger.log(`
|
|
5219
5261
|
\u{1F4DD} Detected change in ${path5}`);
|
|
5220
5262
|
try {
|
|
5221
5263
|
await generateCommand({ verbose: false });
|
|
5222
|
-
|
|
5264
|
+
logger.success("Regenerated configuration files");
|
|
5223
5265
|
} catch (error) {
|
|
5224
|
-
|
|
5266
|
+
logger.error("Failed to regenerate:", error);
|
|
5225
5267
|
} finally {
|
|
5226
5268
|
isGenerating = false;
|
|
5227
5269
|
}
|
|
5228
5270
|
};
|
|
5229
5271
|
watcher.on("change", handleChange).on("add", handleChange).on("unlink", (path5) => {
|
|
5230
|
-
|
|
5272
|
+
logger.log(`
|
|
5231
5273
|
\u{1F5D1}\uFE0F Removed ${path5}`);
|
|
5232
5274
|
handleChange(path5);
|
|
5233
5275
|
}).on("error", (error) => {
|
|
5234
|
-
|
|
5276
|
+
logger.error("Watcher error:", error);
|
|
5235
5277
|
});
|
|
5236
5278
|
process.on("SIGINT", () => {
|
|
5237
|
-
|
|
5279
|
+
logger.log("\n\n\u{1F44B} Stopping watcher...");
|
|
5238
5280
|
watcher.close();
|
|
5239
5281
|
process.exit(0);
|
|
5240
5282
|
});
|
|
@@ -5242,7 +5284,7 @@ async function watchCommand() {
|
|
|
5242
5284
|
|
|
5243
5285
|
// src/cli/index.ts
|
|
5244
5286
|
var program = new import_commander.Command();
|
|
5245
|
-
program.name("rulesync").description("Unified AI rules management CLI tool").version("0.
|
|
5287
|
+
program.name("rulesync").description("Unified AI rules management CLI tool").version("0.63.0");
|
|
5246
5288
|
program.command("init").description("Initialize rulesync in current directory").option("--legacy", "Use legacy file location (.rulesync/*.md instead of .rulesync/rules/*.md)").action(initCommand);
|
|
5247
5289
|
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);
|
|
5248
5290
|
program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);
|