rulesync 0.56.0 → 0.58.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +173 -20
- package/README.md +67 -699
- package/dist/index.cjs +464 -213
- package/dist/index.js +464 -213
- package/package.json +19 -19
package/dist/index.cjs
CHANGED
|
@@ -771,132 +771,141 @@ var ClaudeSettingsSchema = import_mini2.z.looseObject({
|
|
|
771
771
|
)
|
|
772
772
|
});
|
|
773
773
|
|
|
774
|
-
// src/types/
|
|
774
|
+
// src/types/commands.ts
|
|
775
775
|
var import_mini3 = require("zod/mini");
|
|
776
|
+
var CommandFrontmatterSchema = import_mini3.z.object({
|
|
777
|
+
description: import_mini3.z.optional(import_mini3.z.string())
|
|
778
|
+
});
|
|
779
|
+
|
|
780
|
+
// src/types/config.ts
|
|
781
|
+
var import_mini4 = require("zod/mini");
|
|
776
782
|
init_tool_targets();
|
|
777
|
-
var ConfigSchema =
|
|
778
|
-
aiRulesDir:
|
|
779
|
-
outputPaths:
|
|
780
|
-
watchEnabled:
|
|
781
|
-
defaultTargets: ToolTargetsSchema
|
|
783
|
+
var ConfigSchema = import_mini4.z.object({
|
|
784
|
+
aiRulesDir: import_mini4.z.string(),
|
|
785
|
+
outputPaths: import_mini4.z.record(ToolTargetSchema, import_mini4.z.string()),
|
|
786
|
+
watchEnabled: import_mini4.z.boolean(),
|
|
787
|
+
defaultTargets: ToolTargetsSchema,
|
|
788
|
+
claudecodeCommands: import_mini4.z.optional(import_mini4.z.string()),
|
|
789
|
+
geminicliCommands: import_mini4.z.optional(import_mini4.z.string())
|
|
782
790
|
});
|
|
783
791
|
|
|
784
792
|
// src/types/config-options.ts
|
|
785
|
-
var
|
|
793
|
+
var import_mini5 = require("zod/mini");
|
|
786
794
|
init_tool_targets();
|
|
787
|
-
var OutputPathsSchema =
|
|
788
|
-
augmentcode:
|
|
789
|
-
"augmentcode-legacy":
|
|
790
|
-
copilot:
|
|
791
|
-
cursor:
|
|
792
|
-
cline:
|
|
793
|
-
claudecode:
|
|
794
|
-
codexcli:
|
|
795
|
-
roo:
|
|
796
|
-
geminicli:
|
|
797
|
-
kiro:
|
|
798
|
-
junie:
|
|
799
|
-
windsurf:
|
|
795
|
+
var OutputPathsSchema = import_mini5.z.object({
|
|
796
|
+
augmentcode: import_mini5.z.optional(import_mini5.z.string()),
|
|
797
|
+
"augmentcode-legacy": import_mini5.z.optional(import_mini5.z.string()),
|
|
798
|
+
copilot: import_mini5.z.optional(import_mini5.z.string()),
|
|
799
|
+
cursor: import_mini5.z.optional(import_mini5.z.string()),
|
|
800
|
+
cline: import_mini5.z.optional(import_mini5.z.string()),
|
|
801
|
+
claudecode: import_mini5.z.optional(import_mini5.z.string()),
|
|
802
|
+
codexcli: import_mini5.z.optional(import_mini5.z.string()),
|
|
803
|
+
roo: import_mini5.z.optional(import_mini5.z.string()),
|
|
804
|
+
geminicli: import_mini5.z.optional(import_mini5.z.string()),
|
|
805
|
+
kiro: import_mini5.z.optional(import_mini5.z.string()),
|
|
806
|
+
junie: import_mini5.z.optional(import_mini5.z.string()),
|
|
807
|
+
windsurf: import_mini5.z.optional(import_mini5.z.string())
|
|
800
808
|
});
|
|
801
|
-
var ConfigOptionsSchema =
|
|
802
|
-
aiRulesDir:
|
|
803
|
-
outputPaths:
|
|
804
|
-
watchEnabled:
|
|
805
|
-
defaultTargets:
|
|
806
|
-
targets:
|
|
807
|
-
exclude:
|
|
808
|
-
verbose:
|
|
809
|
-
delete:
|
|
810
|
-
baseDir:
|
|
811
|
-
watch:
|
|
812
|
-
|
|
813
|
-
enabled:
|
|
814
|
-
interval:
|
|
815
|
-
ignore:
|
|
809
|
+
var ConfigOptionsSchema = import_mini5.z.object({
|
|
810
|
+
aiRulesDir: import_mini5.z.optional(import_mini5.z.string()),
|
|
811
|
+
outputPaths: import_mini5.z.optional(OutputPathsSchema),
|
|
812
|
+
watchEnabled: import_mini5.z.optional(import_mini5.z.boolean()),
|
|
813
|
+
defaultTargets: import_mini5.z.optional(ToolTargetsSchema),
|
|
814
|
+
targets: import_mini5.z.optional(import_mini5.z.array(ToolTargetSchema)),
|
|
815
|
+
exclude: import_mini5.z.optional(import_mini5.z.array(ToolTargetSchema)),
|
|
816
|
+
verbose: import_mini5.z.optional(import_mini5.z.boolean()),
|
|
817
|
+
delete: import_mini5.z.optional(import_mini5.z.boolean()),
|
|
818
|
+
baseDir: import_mini5.z.optional(import_mini5.z.union([import_mini5.z.string(), import_mini5.z.array(import_mini5.z.string())])),
|
|
819
|
+
watch: import_mini5.z.optional(
|
|
820
|
+
import_mini5.z.object({
|
|
821
|
+
enabled: import_mini5.z.optional(import_mini5.z.boolean()),
|
|
822
|
+
interval: import_mini5.z.optional(import_mini5.z.number()),
|
|
823
|
+
ignore: import_mini5.z.optional(import_mini5.z.array(import_mini5.z.string()))
|
|
816
824
|
})
|
|
817
825
|
)
|
|
818
826
|
});
|
|
819
|
-
var MergedConfigSchema =
|
|
820
|
-
aiRulesDir:
|
|
821
|
-
outputPaths:
|
|
822
|
-
watchEnabled:
|
|
827
|
+
var MergedConfigSchema = import_mini5.z.object({
|
|
828
|
+
aiRulesDir: import_mini5.z.string(),
|
|
829
|
+
outputPaths: import_mini5.z.record(ToolTargetSchema, import_mini5.z.string()),
|
|
830
|
+
watchEnabled: import_mini5.z.boolean(),
|
|
823
831
|
defaultTargets: ToolTargetsSchema,
|
|
824
|
-
targets:
|
|
825
|
-
exclude:
|
|
826
|
-
verbose:
|
|
827
|
-
delete:
|
|
828
|
-
baseDir:
|
|
829
|
-
configPath:
|
|
830
|
-
watch:
|
|
831
|
-
|
|
832
|
-
enabled:
|
|
833
|
-
interval:
|
|
834
|
-
ignore:
|
|
832
|
+
targets: import_mini5.z.optional(import_mini5.z.array(ToolTargetSchema)),
|
|
833
|
+
exclude: import_mini5.z.optional(import_mini5.z.array(ToolTargetSchema)),
|
|
834
|
+
verbose: import_mini5.z.optional(import_mini5.z.boolean()),
|
|
835
|
+
delete: import_mini5.z.optional(import_mini5.z.boolean()),
|
|
836
|
+
baseDir: import_mini5.z.optional(import_mini5.z.union([import_mini5.z.string(), import_mini5.z.array(import_mini5.z.string())])),
|
|
837
|
+
configPath: import_mini5.z.optional(import_mini5.z.string()),
|
|
838
|
+
watch: import_mini5.z.optional(
|
|
839
|
+
import_mini5.z.object({
|
|
840
|
+
enabled: import_mini5.z.optional(import_mini5.z.boolean()),
|
|
841
|
+
interval: import_mini5.z.optional(import_mini5.z.number()),
|
|
842
|
+
ignore: import_mini5.z.optional(import_mini5.z.array(import_mini5.z.string()))
|
|
835
843
|
})
|
|
836
844
|
)
|
|
837
845
|
});
|
|
838
846
|
|
|
839
847
|
// src/types/mcp.ts
|
|
840
|
-
var
|
|
848
|
+
var import_mini6 = require("zod/mini");
|
|
841
849
|
init_tool_targets();
|
|
842
|
-
var McpTransportTypeSchema =
|
|
843
|
-
var McpServerBaseSchema =
|
|
844
|
-
command:
|
|
845
|
-
args:
|
|
846
|
-
url:
|
|
847
|
-
httpUrl:
|
|
848
|
-
env:
|
|
849
|
-
disabled:
|
|
850
|
-
networkTimeout:
|
|
851
|
-
timeout:
|
|
852
|
-
trust:
|
|
853
|
-
cwd:
|
|
854
|
-
transport:
|
|
855
|
-
type:
|
|
856
|
-
alwaysAllow:
|
|
857
|
-
tools:
|
|
858
|
-
kiroAutoApprove:
|
|
859
|
-
kiroAutoBlock:
|
|
860
|
-
headers:
|
|
850
|
+
var McpTransportTypeSchema = import_mini6.z.enum(["stdio", "sse", "http"]);
|
|
851
|
+
var McpServerBaseSchema = import_mini6.z.object({
|
|
852
|
+
command: import_mini6.z.optional(import_mini6.z.string()),
|
|
853
|
+
args: import_mini6.z.optional(import_mini6.z.array(import_mini6.z.string())),
|
|
854
|
+
url: import_mini6.z.optional(import_mini6.z.string()),
|
|
855
|
+
httpUrl: import_mini6.z.optional(import_mini6.z.string()),
|
|
856
|
+
env: import_mini6.z.optional(import_mini6.z.record(import_mini6.z.string(), import_mini6.z.string())),
|
|
857
|
+
disabled: import_mini6.z.optional(import_mini6.z.boolean()),
|
|
858
|
+
networkTimeout: import_mini6.z.optional(import_mini6.z.number()),
|
|
859
|
+
timeout: import_mini6.z.optional(import_mini6.z.number()),
|
|
860
|
+
trust: import_mini6.z.optional(import_mini6.z.boolean()),
|
|
861
|
+
cwd: import_mini6.z.optional(import_mini6.z.string()),
|
|
862
|
+
transport: import_mini6.z.optional(McpTransportTypeSchema),
|
|
863
|
+
type: import_mini6.z.optional(import_mini6.z.enum(["sse", "streamable-http"])),
|
|
864
|
+
alwaysAllow: import_mini6.z.optional(import_mini6.z.array(import_mini6.z.string())),
|
|
865
|
+
tools: import_mini6.z.optional(import_mini6.z.array(import_mini6.z.string())),
|
|
866
|
+
kiroAutoApprove: import_mini6.z.optional(import_mini6.z.array(import_mini6.z.string())),
|
|
867
|
+
kiroAutoBlock: import_mini6.z.optional(import_mini6.z.array(import_mini6.z.string())),
|
|
868
|
+
headers: import_mini6.z.optional(import_mini6.z.record(import_mini6.z.string(), import_mini6.z.string()))
|
|
861
869
|
});
|
|
862
|
-
var RulesyncMcpServerSchema =
|
|
863
|
-
targets:
|
|
870
|
+
var RulesyncMcpServerSchema = import_mini6.z.extend(McpServerBaseSchema, {
|
|
871
|
+
targets: import_mini6.z.optional(RulesyncTargetsSchema)
|
|
864
872
|
});
|
|
865
|
-
var McpConfigSchema =
|
|
866
|
-
mcpServers:
|
|
873
|
+
var McpConfigSchema = import_mini6.z.object({
|
|
874
|
+
mcpServers: import_mini6.z.record(import_mini6.z.string(), McpServerBaseSchema)
|
|
867
875
|
});
|
|
868
|
-
var RulesyncMcpConfigSchema =
|
|
869
|
-
mcpServers:
|
|
876
|
+
var RulesyncMcpConfigSchema = import_mini6.z.object({
|
|
877
|
+
mcpServers: import_mini6.z.record(import_mini6.z.string(), RulesyncMcpServerSchema)
|
|
870
878
|
});
|
|
871
879
|
|
|
872
880
|
// src/types/rules.ts
|
|
873
|
-
var
|
|
881
|
+
var import_mini7 = require("zod/mini");
|
|
874
882
|
init_tool_targets();
|
|
875
|
-
var RuleFrontmatterSchema =
|
|
876
|
-
root:
|
|
877
|
-
targets: RulesyncTargetsSchema,
|
|
878
|
-
description:
|
|
879
|
-
globs:
|
|
880
|
-
cursorRuleType:
|
|
881
|
-
windsurfActivationMode:
|
|
882
|
-
windsurfOutputFormat:
|
|
883
|
-
tags:
|
|
883
|
+
var RuleFrontmatterSchema = import_mini7.z.object({
|
|
884
|
+
root: import_mini7.z.optional(import_mini7.z.boolean()),
|
|
885
|
+
targets: import_mini7.z.optional(RulesyncTargetsSchema),
|
|
886
|
+
description: import_mini7.z.optional(import_mini7.z.string()),
|
|
887
|
+
globs: import_mini7.z.optional(import_mini7.z.array(import_mini7.z.string())),
|
|
888
|
+
cursorRuleType: import_mini7.z.optional(import_mini7.z.enum(["always", "manual", "specificFiles", "intelligently"])),
|
|
889
|
+
windsurfActivationMode: import_mini7.z.optional(import_mini7.z.enum(["always", "manual", "model-decision", "glob"])),
|
|
890
|
+
windsurfOutputFormat: import_mini7.z.optional(import_mini7.z.enum(["single-file", "directory"])),
|
|
891
|
+
tags: import_mini7.z.optional(import_mini7.z.array(import_mini7.z.string()))
|
|
884
892
|
});
|
|
885
|
-
var ParsedRuleSchema =
|
|
893
|
+
var ParsedRuleSchema = import_mini7.z.object({
|
|
886
894
|
frontmatter: RuleFrontmatterSchema,
|
|
887
|
-
content:
|
|
888
|
-
filename:
|
|
889
|
-
filepath:
|
|
895
|
+
content: import_mini7.z.string(),
|
|
896
|
+
filename: import_mini7.z.string(),
|
|
897
|
+
filepath: import_mini7.z.string(),
|
|
898
|
+
type: import_mini7.z.optional(import_mini7.z.enum(["rule", "command"]))
|
|
890
899
|
});
|
|
891
|
-
var GeneratedOutputSchema =
|
|
900
|
+
var GeneratedOutputSchema = import_mini7.z.object({
|
|
892
901
|
tool: ToolTargetSchema,
|
|
893
|
-
filepath:
|
|
894
|
-
content:
|
|
902
|
+
filepath: import_mini7.z.string(),
|
|
903
|
+
content: import_mini7.z.string()
|
|
895
904
|
});
|
|
896
|
-
var GenerateOptionsSchema =
|
|
897
|
-
targetTools:
|
|
898
|
-
outputDir:
|
|
899
|
-
watch:
|
|
905
|
+
var GenerateOptionsSchema = import_mini7.z.object({
|
|
906
|
+
targetTools: import_mini7.z.optional(ToolTargetsSchema),
|
|
907
|
+
outputDir: import_mini7.z.optional(import_mini7.z.string()),
|
|
908
|
+
watch: import_mini7.z.optional(import_mini7.z.boolean())
|
|
900
909
|
});
|
|
901
910
|
|
|
902
911
|
// src/types/index.ts
|
|
@@ -1191,28 +1200,6 @@ async function removeClaudeGeneratedFiles() {
|
|
|
1191
1200
|
}
|
|
1192
1201
|
}
|
|
1193
1202
|
|
|
1194
|
-
// src/utils/rules.ts
|
|
1195
|
-
function isToolSpecificRule(rule, targetTool) {
|
|
1196
|
-
const filename = rule.filename;
|
|
1197
|
-
const toolPatterns = {
|
|
1198
|
-
"augmentcode-legacy": /^specification-augmentcode-legacy-/i,
|
|
1199
|
-
augmentcode: /^specification-augmentcode-/i,
|
|
1200
|
-
copilot: /^specification-copilot-/i,
|
|
1201
|
-
cursor: /^specification-cursor-/i,
|
|
1202
|
-
cline: /^specification-cline-/i,
|
|
1203
|
-
claudecode: /^specification-claudecode-/i,
|
|
1204
|
-
roo: /^specification-roo-/i,
|
|
1205
|
-
geminicli: /^specification-geminicli-/i,
|
|
1206
|
-
kiro: /^specification-kiro-/i
|
|
1207
|
-
};
|
|
1208
|
-
for (const [tool, pattern] of Object.entries(toolPatterns)) {
|
|
1209
|
-
if (pattern.test(filename)) {
|
|
1210
|
-
return tool === targetTool;
|
|
1211
|
-
}
|
|
1212
|
-
}
|
|
1213
|
-
return true;
|
|
1214
|
-
}
|
|
1215
|
-
|
|
1216
1203
|
// src/cli/commands/config.ts
|
|
1217
1204
|
async function configCommand(options = {}) {
|
|
1218
1205
|
if (options.init) {
|
|
@@ -1424,10 +1411,165 @@ export default config;
|
|
|
1424
1411
|
}
|
|
1425
1412
|
|
|
1426
1413
|
// src/cli/commands/generate.ts
|
|
1427
|
-
var
|
|
1414
|
+
var import_node_path14 = require("path");
|
|
1428
1415
|
|
|
1429
|
-
// src/
|
|
1416
|
+
// src/core/command-generator.ts
|
|
1417
|
+
var import_node_path6 = require("path");
|
|
1418
|
+
|
|
1419
|
+
// src/generators/commands/claudecode.ts
|
|
1430
1420
|
var import_node_path3 = require("path");
|
|
1421
|
+
var ClaudeCodeCommandGenerator = class {
|
|
1422
|
+
generate(command, outputDir) {
|
|
1423
|
+
const filepath = this.getOutputPath(command.filename, outputDir);
|
|
1424
|
+
const frontmatter = ["---"];
|
|
1425
|
+
if (command.frontmatter.description) {
|
|
1426
|
+
frontmatter.push(`description: ${command.frontmatter.description}`);
|
|
1427
|
+
}
|
|
1428
|
+
frontmatter.push("---");
|
|
1429
|
+
const content = `${frontmatter.join("\n")}
|
|
1430
|
+
|
|
1431
|
+
${command.content.trim()}
|
|
1432
|
+
`;
|
|
1433
|
+
return {
|
|
1434
|
+
tool: "claudecode",
|
|
1435
|
+
filepath,
|
|
1436
|
+
content
|
|
1437
|
+
};
|
|
1438
|
+
}
|
|
1439
|
+
getOutputPath(filename, baseDir) {
|
|
1440
|
+
const flattenedName = filename.replace(/\//g, "-");
|
|
1441
|
+
return (0, import_node_path3.join)(baseDir, ".claude", "commands", `${flattenedName}.md`);
|
|
1442
|
+
}
|
|
1443
|
+
};
|
|
1444
|
+
|
|
1445
|
+
// src/generators/commands/geminicli.ts
|
|
1446
|
+
var import_node_path4 = require("path");
|
|
1447
|
+
var GeminiCliCommandGenerator = class {
|
|
1448
|
+
generate(command, outputDir) {
|
|
1449
|
+
const filepath = this.getOutputPath(command.filename, outputDir);
|
|
1450
|
+
const convertedContent = this.convertSyntax(command.content);
|
|
1451
|
+
const tomlLines = [];
|
|
1452
|
+
if (command.frontmatter.description) {
|
|
1453
|
+
tomlLines.push(`description = "${this.escapeTomlString(command.frontmatter.description)}"`);
|
|
1454
|
+
tomlLines.push("");
|
|
1455
|
+
}
|
|
1456
|
+
tomlLines.push(`prompt = """${convertedContent}"""`);
|
|
1457
|
+
const content = tomlLines.join("\n") + "\n";
|
|
1458
|
+
return {
|
|
1459
|
+
tool: "geminicli",
|
|
1460
|
+
filepath,
|
|
1461
|
+
content
|
|
1462
|
+
};
|
|
1463
|
+
}
|
|
1464
|
+
getOutputPath(filename, baseDir) {
|
|
1465
|
+
const tomlFilename = filename.replace(/\.md$/, ".toml");
|
|
1466
|
+
const filenameWithExt = tomlFilename.endsWith(".toml") ? tomlFilename : `${tomlFilename}.toml`;
|
|
1467
|
+
return (0, import_node_path4.join)(baseDir, ".gemini", "commands", filenameWithExt);
|
|
1468
|
+
}
|
|
1469
|
+
convertSyntax(content) {
|
|
1470
|
+
let converted = content;
|
|
1471
|
+
converted = converted.replace(/\$ARGUMENTS/g, "{{args}}");
|
|
1472
|
+
converted = converted.replace(/!`([^`]+)`/g, "!{$1}");
|
|
1473
|
+
const atSyntaxMatches = converted.match(/@[^\s]+/g);
|
|
1474
|
+
if (atSyntaxMatches) {
|
|
1475
|
+
console.warn(
|
|
1476
|
+
`\u26A0\uFE0F Warning: @ syntax found (${atSyntaxMatches.join(", ")}). Gemini CLI does not support file content injection. Consider using shell commands or remove these references.`
|
|
1477
|
+
);
|
|
1478
|
+
}
|
|
1479
|
+
return converted.trim();
|
|
1480
|
+
}
|
|
1481
|
+
escapeTomlString(str) {
|
|
1482
|
+
return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
|
|
1483
|
+
}
|
|
1484
|
+
};
|
|
1485
|
+
|
|
1486
|
+
// src/generators/commands/index.ts
|
|
1487
|
+
var commandGenerators = {
|
|
1488
|
+
claudecode: new ClaudeCodeCommandGenerator(),
|
|
1489
|
+
geminicli: new GeminiCliCommandGenerator()
|
|
1490
|
+
};
|
|
1491
|
+
function getCommandGenerator(tool) {
|
|
1492
|
+
return commandGenerators[tool];
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
// src/core/command-parser.ts
|
|
1496
|
+
var import_node_path5 = require("path");
|
|
1497
|
+
var import_gray_matter = __toESM(require("gray-matter"), 1);
|
|
1498
|
+
async function parseCommandsFromDirectory(commandsDir) {
|
|
1499
|
+
const commandFiles = await findFiles(commandsDir, ".md");
|
|
1500
|
+
const commands = [];
|
|
1501
|
+
const errors = [];
|
|
1502
|
+
for (const filepath of commandFiles) {
|
|
1503
|
+
try {
|
|
1504
|
+
const command = await parseCommandFile(filepath);
|
|
1505
|
+
commands.push(command);
|
|
1506
|
+
} catch (error) {
|
|
1507
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1508
|
+
errors.push(`Failed to parse command file ${filepath}: ${errorMessage}`);
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
if (errors.length > 0) {
|
|
1512
|
+
console.warn(`\u26A0\uFE0F Command parsing errors:
|
|
1513
|
+
${errors.join("\n")}`);
|
|
1514
|
+
}
|
|
1515
|
+
return commands;
|
|
1516
|
+
}
|
|
1517
|
+
async function parseCommandFile(filepath) {
|
|
1518
|
+
const content = await readFileContent(filepath);
|
|
1519
|
+
const parsed = (0, import_gray_matter.default)(content);
|
|
1520
|
+
try {
|
|
1521
|
+
const validatedData = CommandFrontmatterSchema.parse(parsed.data);
|
|
1522
|
+
const filename = (0, import_node_path5.basename)(filepath, ".md");
|
|
1523
|
+
return {
|
|
1524
|
+
frontmatter: {
|
|
1525
|
+
description: validatedData.description
|
|
1526
|
+
},
|
|
1527
|
+
content: parsed.content,
|
|
1528
|
+
filename,
|
|
1529
|
+
filepath
|
|
1530
|
+
};
|
|
1531
|
+
} catch (error) {
|
|
1532
|
+
throw new Error(
|
|
1533
|
+
`Invalid frontmatter in ${filepath}: ${error instanceof Error ? error.message : String(error)}`
|
|
1534
|
+
);
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
// src/core/command-generator.ts
|
|
1539
|
+
async function generateCommands(projectRoot, baseDir, targets) {
|
|
1540
|
+
const commandsDir = (0, import_node_path6.join)(projectRoot, ".rulesync", "commands");
|
|
1541
|
+
if (!await fileExists(commandsDir)) {
|
|
1542
|
+
return [];
|
|
1543
|
+
}
|
|
1544
|
+
const commands = await parseCommandsFromDirectory(commandsDir);
|
|
1545
|
+
if (commands.length === 0) {
|
|
1546
|
+
return [];
|
|
1547
|
+
}
|
|
1548
|
+
const outputs = [];
|
|
1549
|
+
const outputDir = baseDir || projectRoot;
|
|
1550
|
+
const supportedTargets = targets.filter((target) => ["claudecode", "geminicli"].includes(target));
|
|
1551
|
+
for (const target of supportedTargets) {
|
|
1552
|
+
const generator = getCommandGenerator(target);
|
|
1553
|
+
if (!generator) {
|
|
1554
|
+
continue;
|
|
1555
|
+
}
|
|
1556
|
+
for (const command of commands) {
|
|
1557
|
+
try {
|
|
1558
|
+
const output = generator.generate(command, outputDir);
|
|
1559
|
+
outputs.push(output);
|
|
1560
|
+
} catch (error) {
|
|
1561
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1562
|
+
console.error(
|
|
1563
|
+
`\u274C Failed to generate ${target} command for ${command.filename}: ${errorMessage}`
|
|
1564
|
+
);
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
return outputs;
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
// src/generators/ignore/shared-factory.ts
|
|
1572
|
+
var import_node_path7 = require("path");
|
|
1431
1573
|
|
|
1432
1574
|
// src/generators/ignore/shared-helpers.ts
|
|
1433
1575
|
function extractIgnorePatternsFromRules(rules) {
|
|
@@ -1545,7 +1687,7 @@ function generateIgnoreFile(rules, config, ignoreConfig, baseDir) {
|
|
|
1545
1687
|
const outputs = [];
|
|
1546
1688
|
const content = generateIgnoreContent(rules, ignoreConfig);
|
|
1547
1689
|
const outputPath = baseDir || process.cwd();
|
|
1548
|
-
const filepath = (0,
|
|
1690
|
+
const filepath = (0, import_node_path7.join)(outputPath, ignoreConfig.filename);
|
|
1549
1691
|
outputs.push({
|
|
1550
1692
|
tool: ignoreConfig.tool,
|
|
1551
1693
|
filepath,
|
|
@@ -2133,20 +2275,20 @@ function generateWindsurfIgnore(rules, config, baseDir) {
|
|
|
2133
2275
|
}
|
|
2134
2276
|
|
|
2135
2277
|
// src/generators/rules/augmentcode.ts
|
|
2136
|
-
var
|
|
2278
|
+
var import_node_path10 = require("path");
|
|
2137
2279
|
|
|
2138
2280
|
// src/generators/rules/shared-helpers.ts
|
|
2139
|
-
var
|
|
2281
|
+
var import_node_path9 = require("path");
|
|
2140
2282
|
|
|
2141
2283
|
// src/utils/ignore.ts
|
|
2142
|
-
var
|
|
2284
|
+
var import_node_path8 = require("path");
|
|
2143
2285
|
var import_micromatch = __toESM(require("micromatch"), 1);
|
|
2144
2286
|
var cachedIgnorePatterns = null;
|
|
2145
2287
|
async function loadIgnorePatterns(baseDir = process.cwd()) {
|
|
2146
2288
|
if (cachedIgnorePatterns) {
|
|
2147
2289
|
return cachedIgnorePatterns;
|
|
2148
2290
|
}
|
|
2149
|
-
const ignorePath = (0,
|
|
2291
|
+
const ignorePath = (0, import_node_path8.join)(baseDir, ".rulesyncignore");
|
|
2150
2292
|
if (!await fileExists(ignorePath)) {
|
|
2151
2293
|
cachedIgnorePatterns = { patterns: [] };
|
|
2152
2294
|
return cachedIgnorePatterns;
|
|
@@ -2200,7 +2342,7 @@ function addOutput(outputs, tool, config, baseDir, relativePath, content) {
|
|
|
2200
2342
|
const outputDir = resolveOutputDir(config, tool, baseDir);
|
|
2201
2343
|
outputs.push({
|
|
2202
2344
|
tool,
|
|
2203
|
-
filepath: (0,
|
|
2345
|
+
filepath: (0, import_node_path9.join)(outputDir, relativePath),
|
|
2204
2346
|
content
|
|
2205
2347
|
});
|
|
2206
2348
|
}
|
|
@@ -2209,7 +2351,7 @@ async function generateRulesConfig(rules, config, generatorConfig, baseDir) {
|
|
|
2209
2351
|
for (const rule of rules) {
|
|
2210
2352
|
const content = generatorConfig.generateContent(rule);
|
|
2211
2353
|
const outputDir = resolveOutputDir(config, generatorConfig.tool, baseDir);
|
|
2212
|
-
const filepath = generatorConfig.pathResolver ? generatorConfig.pathResolver(rule, outputDir) : (0,
|
|
2354
|
+
const filepath = generatorConfig.pathResolver ? generatorConfig.pathResolver(rule, outputDir) : (0, import_node_path9.join)(outputDir, `${rule.filename}${generatorConfig.fileExtension}`);
|
|
2213
2355
|
outputs.push({
|
|
2214
2356
|
tool: generatorConfig.tool,
|
|
2215
2357
|
filepath,
|
|
@@ -2217,7 +2359,7 @@ async function generateRulesConfig(rules, config, generatorConfig, baseDir) {
|
|
|
2217
2359
|
});
|
|
2218
2360
|
}
|
|
2219
2361
|
const ignorePatterns = await loadIgnorePatterns(baseDir);
|
|
2220
|
-
if (ignorePatterns.patterns.length > 0) {
|
|
2362
|
+
if (ignorePatterns.patterns.length > 0 && generatorConfig.ignoreFileName) {
|
|
2221
2363
|
const ignorePath = resolvePath(generatorConfig.ignoreFileName, baseDir);
|
|
2222
2364
|
const ignoreContent = generateIgnoreFile2(ignorePatterns.patterns, generatorConfig.tool);
|
|
2223
2365
|
outputs.push({
|
|
@@ -2237,7 +2379,7 @@ async function generateComplexRules(rules, config, generatorConfig, baseDir) {
|
|
|
2237
2379
|
for (const rule of detailRules) {
|
|
2238
2380
|
const content = generatorConfig.generateDetailContent(rule);
|
|
2239
2381
|
const filepath = resolvePath(
|
|
2240
|
-
(0,
|
|
2382
|
+
(0, import_node_path9.join)(generatorConfig.detailSubDir, `${rule.filename}.md`),
|
|
2241
2383
|
baseDir
|
|
2242
2384
|
);
|
|
2243
2385
|
outputs.push({
|
|
@@ -2258,13 +2400,15 @@ async function generateComplexRules(rules, config, generatorConfig, baseDir) {
|
|
|
2258
2400
|
}
|
|
2259
2401
|
const ignorePatterns = await loadIgnorePatterns(baseDir);
|
|
2260
2402
|
if (ignorePatterns.patterns.length > 0) {
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2403
|
+
if (generatorConfig.ignoreFileName) {
|
|
2404
|
+
const ignorePath = resolvePath(generatorConfig.ignoreFileName, baseDir);
|
|
2405
|
+
const ignoreContent = generateIgnoreFile2(ignorePatterns.patterns, generatorConfig.tool);
|
|
2406
|
+
outputs.push({
|
|
2407
|
+
tool: generatorConfig.tool,
|
|
2408
|
+
filepath: ignorePath,
|
|
2409
|
+
content: ignoreContent
|
|
2410
|
+
});
|
|
2411
|
+
}
|
|
2268
2412
|
if (generatorConfig.updateAdditionalConfig) {
|
|
2269
2413
|
const additionalOutputs = await generatorConfig.updateAdditionalConfig(
|
|
2270
2414
|
ignorePatterns.patterns,
|
|
@@ -2298,7 +2442,7 @@ async function generateAugmentcodeConfig(rules, config, baseDir) {
|
|
|
2298
2442
|
"augmentcode",
|
|
2299
2443
|
config,
|
|
2300
2444
|
baseDir,
|
|
2301
|
-
(0,
|
|
2445
|
+
(0, import_node_path10.join)(".augment", "rules", `${rule.filename}.md`),
|
|
2302
2446
|
generateRuleFile(rule)
|
|
2303
2447
|
);
|
|
2304
2448
|
});
|
|
@@ -2351,19 +2495,19 @@ function generateLegacyGuidelinesFile(allRules) {
|
|
|
2351
2495
|
}
|
|
2352
2496
|
|
|
2353
2497
|
// src/generators/rules/claudecode.ts
|
|
2354
|
-
var
|
|
2498
|
+
var import_node_path11 = require("path");
|
|
2355
2499
|
async function generateClaudecodeConfig(rules, config, baseDir) {
|
|
2356
2500
|
const generatorConfig = {
|
|
2357
2501
|
tool: "claudecode",
|
|
2358
2502
|
fileExtension: ".md",
|
|
2359
|
-
ignoreFileName
|
|
2503
|
+
// ignoreFileName omitted - Claude Code uses settings.json permissions.deny instead of ignore files
|
|
2360
2504
|
generateContent: generateMemoryFile,
|
|
2361
2505
|
generateRootContent: generateClaudeMarkdown,
|
|
2362
2506
|
rootFilePath: "CLAUDE.md",
|
|
2363
2507
|
generateDetailContent: generateMemoryFile,
|
|
2364
2508
|
detailSubDir: ".claude/memories",
|
|
2365
2509
|
updateAdditionalConfig: async (ignorePatterns, baseDir2) => {
|
|
2366
|
-
const settingsPath = resolvePath((0,
|
|
2510
|
+
const settingsPath = resolvePath((0, import_node_path11.join)(".claude", "settings.json"), baseDir2);
|
|
2367
2511
|
await updateClaudeSettings(settingsPath, ignorePatterns);
|
|
2368
2512
|
return [];
|
|
2369
2513
|
}
|
|
@@ -2427,7 +2571,7 @@ async function updateClaudeSettings(settingsPath, ignorePatterns) {
|
|
|
2427
2571
|
}
|
|
2428
2572
|
|
|
2429
2573
|
// src/generators/rules/generator-registry.ts
|
|
2430
|
-
var
|
|
2574
|
+
var import_node_path12 = require("path");
|
|
2431
2575
|
function determineCursorRuleType(frontmatter) {
|
|
2432
2576
|
if (frontmatter.cursorRuleType) {
|
|
2433
2577
|
return frontmatter.cursorRuleType;
|
|
@@ -2507,7 +2651,7 @@ var GENERATOR_REGISTRY = {
|
|
|
2507
2651
|
},
|
|
2508
2652
|
pathResolver: (rule, outputDir) => {
|
|
2509
2653
|
const baseFilename = rule.filename.replace(/\.md$/, "");
|
|
2510
|
-
return (0,
|
|
2654
|
+
return (0, import_node_path12.join)(outputDir, `${baseFilename}.instructions.md`);
|
|
2511
2655
|
}
|
|
2512
2656
|
},
|
|
2513
2657
|
cursor: {
|
|
@@ -2547,7 +2691,7 @@ var GENERATOR_REGISTRY = {
|
|
|
2547
2691
|
return lines.join("\n");
|
|
2548
2692
|
},
|
|
2549
2693
|
pathResolver: (rule, outputDir) => {
|
|
2550
|
-
return (0,
|
|
2694
|
+
return (0, import_node_path12.join)(outputDir, `${rule.filename}.mdc`);
|
|
2551
2695
|
}
|
|
2552
2696
|
},
|
|
2553
2697
|
codexcli: {
|
|
@@ -2583,10 +2727,10 @@ var GENERATOR_REGISTRY = {
|
|
|
2583
2727
|
pathResolver: (rule, outputDir) => {
|
|
2584
2728
|
const outputFormat = rule.frontmatter.windsurfOutputFormat || "directory";
|
|
2585
2729
|
if (outputFormat === "single-file") {
|
|
2586
|
-
return (0,
|
|
2730
|
+
return (0, import_node_path12.join)(outputDir, ".windsurf-rules");
|
|
2587
2731
|
} else {
|
|
2588
|
-
const rulesDir = (0,
|
|
2589
|
-
return (0,
|
|
2732
|
+
const rulesDir = (0, import_node_path12.join)(outputDir, ".windsurf", "rules");
|
|
2733
|
+
return (0, import_node_path12.join)(rulesDir, `${rule.filename}.md`);
|
|
2590
2734
|
}
|
|
2591
2735
|
}
|
|
2592
2736
|
},
|
|
@@ -2850,7 +2994,7 @@ function filterRulesForTool(rules, tool, config) {
|
|
|
2850
2994
|
if (!targets.includes(tool)) {
|
|
2851
2995
|
return false;
|
|
2852
2996
|
}
|
|
2853
|
-
return
|
|
2997
|
+
return true;
|
|
2854
2998
|
});
|
|
2855
2999
|
}
|
|
2856
3000
|
async function generateForTool(tool, rules, config, baseDir) {
|
|
@@ -2905,8 +3049,8 @@ async function generateForTool(tool, rules, config, baseDir) {
|
|
|
2905
3049
|
}
|
|
2906
3050
|
|
|
2907
3051
|
// src/core/parser.ts
|
|
2908
|
-
var
|
|
2909
|
-
var
|
|
3052
|
+
var import_node_path13 = require("path");
|
|
3053
|
+
var import_gray_matter2 = __toESM(require("gray-matter"), 1);
|
|
2910
3054
|
async function parseRulesFromDirectory(aiRulesDir) {
|
|
2911
3055
|
const ignorePatterns = await loadIgnorePatterns();
|
|
2912
3056
|
const allRuleFiles = await findFiles(aiRulesDir, ".md");
|
|
@@ -2940,10 +3084,26 @@ ${errors.join("\n")}`);
|
|
|
2940
3084
|
}
|
|
2941
3085
|
async function parseRuleFile(filepath) {
|
|
2942
3086
|
const content = await readFileContent(filepath);
|
|
2943
|
-
const parsed = (0,
|
|
3087
|
+
const parsed = (0, import_gray_matter2.default)(content);
|
|
2944
3088
|
try {
|
|
2945
|
-
const
|
|
2946
|
-
const
|
|
3089
|
+
const validatedData = RuleFrontmatterSchema.parse(parsed.data);
|
|
3090
|
+
const frontmatter = {
|
|
3091
|
+
root: validatedData.root ?? false,
|
|
3092
|
+
targets: validatedData.targets ?? ["*"],
|
|
3093
|
+
description: validatedData.description ?? "",
|
|
3094
|
+
globs: validatedData.globs ?? [],
|
|
3095
|
+
...validatedData.cursorRuleType !== void 0 && {
|
|
3096
|
+
cursorRuleType: validatedData.cursorRuleType
|
|
3097
|
+
},
|
|
3098
|
+
...validatedData.windsurfActivationMode !== void 0 && {
|
|
3099
|
+
windsurfActivationMode: validatedData.windsurfActivationMode
|
|
3100
|
+
},
|
|
3101
|
+
...validatedData.windsurfOutputFormat !== void 0 && {
|
|
3102
|
+
windsurfOutputFormat: validatedData.windsurfOutputFormat
|
|
3103
|
+
},
|
|
3104
|
+
...validatedData.tags !== void 0 && { tags: validatedData.tags }
|
|
3105
|
+
};
|
|
3106
|
+
const filename = (0, import_node_path13.basename)(filepath, ".md");
|
|
2947
3107
|
return {
|
|
2948
3108
|
frontmatter,
|
|
2949
3109
|
content: parsed.content,
|
|
@@ -3246,12 +3406,12 @@ async function generateCommand(options = {}) {
|
|
|
3246
3406
|
for (const tool of targetTools) {
|
|
3247
3407
|
switch (tool) {
|
|
3248
3408
|
case "augmentcode":
|
|
3249
|
-
deleteTasks.push(removeDirectory((0,
|
|
3250
|
-
deleteTasks.push(removeDirectory((0,
|
|
3409
|
+
deleteTasks.push(removeDirectory((0, import_node_path14.join)(".augment", "rules")));
|
|
3410
|
+
deleteTasks.push(removeDirectory((0, import_node_path14.join)(".augment", "ignore")));
|
|
3251
3411
|
break;
|
|
3252
3412
|
case "augmentcode-legacy":
|
|
3253
3413
|
deleteTasks.push(removeClaudeGeneratedFiles());
|
|
3254
|
-
deleteTasks.push(removeDirectory((0,
|
|
3414
|
+
deleteTasks.push(removeDirectory((0, import_node_path14.join)(".augment", "ignore")));
|
|
3255
3415
|
break;
|
|
3256
3416
|
case "copilot":
|
|
3257
3417
|
deleteTasks.push(removeDirectory(config.outputPaths.copilot));
|
|
@@ -3264,12 +3424,14 @@ async function generateCommand(options = {}) {
|
|
|
3264
3424
|
break;
|
|
3265
3425
|
case "claudecode":
|
|
3266
3426
|
deleteTasks.push(removeClaudeGeneratedFiles());
|
|
3427
|
+
deleteTasks.push(removeDirectory((0, import_node_path14.join)(".claude", "commands")));
|
|
3267
3428
|
break;
|
|
3268
3429
|
case "roo":
|
|
3269
3430
|
deleteTasks.push(removeDirectory(config.outputPaths.roo));
|
|
3270
3431
|
break;
|
|
3271
3432
|
case "geminicli":
|
|
3272
3433
|
deleteTasks.push(removeDirectory(config.outputPaths.geminicli));
|
|
3434
|
+
deleteTasks.push(removeDirectory((0, import_node_path14.join)(".gemini", "commands")));
|
|
3273
3435
|
break;
|
|
3274
3436
|
case "kiro":
|
|
3275
3437
|
deleteTasks.push(removeDirectory(config.outputPaths.kiro));
|
|
@@ -3334,11 +3496,37 @@ Generating configurations for base directory: ${baseDir}`);
|
|
|
3334
3496
|
}
|
|
3335
3497
|
}
|
|
3336
3498
|
}
|
|
3337
|
-
|
|
3499
|
+
if (config.verbose) {
|
|
3500
|
+
console.log("\nGenerating command files...");
|
|
3501
|
+
}
|
|
3502
|
+
let totalCommandOutputs = 0;
|
|
3503
|
+
for (const baseDir of baseDirs) {
|
|
3504
|
+
const commandResults = await generateCommands(
|
|
3505
|
+
process.cwd(),
|
|
3506
|
+
baseDir === process.cwd() ? void 0 : baseDir,
|
|
3507
|
+
config.defaultTargets
|
|
3508
|
+
);
|
|
3509
|
+
if (commandResults.length === 0) {
|
|
3510
|
+
if (config.verbose) {
|
|
3511
|
+
console.log(`No commands found for ${baseDir}`);
|
|
3512
|
+
}
|
|
3513
|
+
continue;
|
|
3514
|
+
}
|
|
3515
|
+
for (const result of commandResults) {
|
|
3516
|
+
await writeFileContent(result.filepath, result.content);
|
|
3517
|
+
console.log(`\u2705 Generated ${result.tool} command: ${result.filepath}`);
|
|
3518
|
+
totalCommandOutputs++;
|
|
3519
|
+
}
|
|
3520
|
+
}
|
|
3521
|
+
const totalGenerated = totalOutputs + totalMcpOutputs + totalCommandOutputs;
|
|
3338
3522
|
if (totalGenerated > 0) {
|
|
3523
|
+
const parts = [];
|
|
3524
|
+
if (totalOutputs > 0) parts.push(`${totalOutputs} configurations`);
|
|
3525
|
+
if (totalMcpOutputs > 0) parts.push(`${totalMcpOutputs} MCP configurations`);
|
|
3526
|
+
if (totalCommandOutputs > 0) parts.push(`${totalCommandOutputs} commands`);
|
|
3339
3527
|
console.log(
|
|
3340
3528
|
`
|
|
3341
|
-
\u{1F389} All done! Generated ${totalGenerated} file(s) total (${
|
|
3529
|
+
\u{1F389} All done! Generated ${totalGenerated} file(s) total (${parts.join(" + ")})`
|
|
3342
3530
|
);
|
|
3343
3531
|
}
|
|
3344
3532
|
} catch (error) {
|
|
@@ -3349,9 +3537,9 @@ Generating configurations for base directory: ${baseDir}`);
|
|
|
3349
3537
|
|
|
3350
3538
|
// src/cli/commands/gitignore.ts
|
|
3351
3539
|
var import_node_fs2 = require("fs");
|
|
3352
|
-
var
|
|
3540
|
+
var import_node_path15 = require("path");
|
|
3353
3541
|
var gitignoreCommand = async () => {
|
|
3354
|
-
const gitignorePath = (0,
|
|
3542
|
+
const gitignorePath = (0, import_node_path15.join)(process.cwd(), ".gitignore");
|
|
3355
3543
|
const rulesFilesToIgnore = [
|
|
3356
3544
|
"# Generated by rulesync - AI tool configuration files",
|
|
3357
3545
|
"**/.github/copilot-instructions.md",
|
|
@@ -3362,6 +3550,7 @@ var gitignoreCommand = async () => {
|
|
|
3362
3550
|
"**/.clineignore",
|
|
3363
3551
|
"**/CLAUDE.md",
|
|
3364
3552
|
"**/.claude/memories/",
|
|
3553
|
+
"**/.claude/commands/",
|
|
3365
3554
|
"**/codex.md",
|
|
3366
3555
|
"**/.codexignore",
|
|
3367
3556
|
"**/.roo/rules/",
|
|
@@ -3369,6 +3558,7 @@ var gitignoreCommand = async () => {
|
|
|
3369
3558
|
"**/.copilotignore",
|
|
3370
3559
|
"**/GEMINI.md",
|
|
3371
3560
|
"**/.gemini/memories/",
|
|
3561
|
+
"**/.gemini/commands/",
|
|
3372
3562
|
"**/.aiexclude",
|
|
3373
3563
|
"**/.aiignore",
|
|
3374
3564
|
"**/.augmentignore",
|
|
@@ -3415,12 +3605,12 @@ ${linesToAdd.join("\n")}
|
|
|
3415
3605
|
};
|
|
3416
3606
|
|
|
3417
3607
|
// src/core/importer.ts
|
|
3418
|
-
var
|
|
3419
|
-
var
|
|
3608
|
+
var import_node_path22 = require("path");
|
|
3609
|
+
var import_gray_matter7 = __toESM(require("gray-matter"), 1);
|
|
3420
3610
|
|
|
3421
3611
|
// src/parsers/augmentcode.ts
|
|
3422
|
-
var
|
|
3423
|
-
var
|
|
3612
|
+
var import_node_path16 = require("path");
|
|
3613
|
+
var import_gray_matter3 = __toESM(require("gray-matter"), 1);
|
|
3424
3614
|
|
|
3425
3615
|
// src/utils/parser-helpers.ts
|
|
3426
3616
|
function createParseResult() {
|
|
@@ -3468,7 +3658,7 @@ async function parseAugmentcodeLegacyConfiguration(baseDir = process.cwd()) {
|
|
|
3468
3658
|
async function parseUnifiedAugmentcode(baseDir, config) {
|
|
3469
3659
|
const result = createParseResult();
|
|
3470
3660
|
if (config.rulesDir) {
|
|
3471
|
-
const rulesDir = (0,
|
|
3661
|
+
const rulesDir = (0, import_node_path16.join)(baseDir, config.rulesDir);
|
|
3472
3662
|
if (await fileExists(rulesDir)) {
|
|
3473
3663
|
const rulesResult = await parseAugmentRules(rulesDir, config);
|
|
3474
3664
|
addRules(result, rulesResult.rules);
|
|
@@ -3481,7 +3671,7 @@ async function parseUnifiedAugmentcode(baseDir, config) {
|
|
|
3481
3671
|
}
|
|
3482
3672
|
}
|
|
3483
3673
|
if (config.legacyFilePath) {
|
|
3484
|
-
const legacyPath = (0,
|
|
3674
|
+
const legacyPath = (0, import_node_path16.join)(baseDir, config.legacyFilePath);
|
|
3485
3675
|
if (await fileExists(legacyPath)) {
|
|
3486
3676
|
const legacyResult = await parseAugmentGuidelines(legacyPath, config);
|
|
3487
3677
|
if (legacyResult.rule) {
|
|
@@ -3505,16 +3695,16 @@ async function parseAugmentRules(rulesDir, config) {
|
|
|
3505
3695
|
const files = await readdir2(rulesDir);
|
|
3506
3696
|
for (const file of files) {
|
|
3507
3697
|
if (file.endsWith(".md") || file.endsWith(".mdc")) {
|
|
3508
|
-
const filePath = (0,
|
|
3698
|
+
const filePath = (0, import_node_path16.join)(rulesDir, file);
|
|
3509
3699
|
try {
|
|
3510
3700
|
const rawContent = await readFileContent(filePath);
|
|
3511
|
-
const parsed = (0,
|
|
3701
|
+
const parsed = (0, import_gray_matter3.default)(rawContent);
|
|
3512
3702
|
const frontmatterData = parsed.data;
|
|
3513
3703
|
const ruleType = frontmatterData.type || "manual";
|
|
3514
3704
|
const description = frontmatterData.description || "";
|
|
3515
3705
|
const tags = Array.isArray(frontmatterData.tags) ? frontmatterData.tags : void 0;
|
|
3516
3706
|
const isRoot = ruleType === "always";
|
|
3517
|
-
const filename = (0,
|
|
3707
|
+
const filename = (0, import_node_path16.basename)(file, file.endsWith(".mdc") ? ".mdc" : ".md");
|
|
3518
3708
|
const frontmatter = {
|
|
3519
3709
|
root: isRoot,
|
|
3520
3710
|
targets: [config.targetName],
|
|
@@ -3572,8 +3762,8 @@ async function parseAugmentGuidelines(guidelinesPath, config) {
|
|
|
3572
3762
|
}
|
|
3573
3763
|
|
|
3574
3764
|
// src/parsers/shared-helpers.ts
|
|
3575
|
-
var
|
|
3576
|
-
var
|
|
3765
|
+
var import_node_path17 = require("path");
|
|
3766
|
+
var import_gray_matter4 = __toESM(require("gray-matter"), 1);
|
|
3577
3767
|
async function parseConfigurationFiles(baseDir = process.cwd(), config) {
|
|
3578
3768
|
const errors = [];
|
|
3579
3769
|
const rules = [];
|
|
@@ -3586,7 +3776,7 @@ async function parseConfigurationFiles(baseDir = process.cwd(), config) {
|
|
|
3586
3776
|
let content;
|
|
3587
3777
|
let frontmatter;
|
|
3588
3778
|
if (mainFile.useFrontmatter) {
|
|
3589
|
-
const parsed = (0,
|
|
3779
|
+
const parsed = (0, import_gray_matter4.default)(rawContent);
|
|
3590
3780
|
content = parsed.content.trim();
|
|
3591
3781
|
const parsedFrontmatter = parsed.data;
|
|
3592
3782
|
frontmatter = {
|
|
@@ -3628,14 +3818,14 @@ async function parseConfigurationFiles(baseDir = process.cwd(), config) {
|
|
|
3628
3818
|
const files = await readdir2(dirPath);
|
|
3629
3819
|
for (const file of files) {
|
|
3630
3820
|
if (file.endsWith(dirConfig.filePattern)) {
|
|
3631
|
-
const filePath = (0,
|
|
3821
|
+
const filePath = (0, import_node_path17.join)(dirPath, file);
|
|
3632
3822
|
const fileResult = await safeAsyncOperation(async () => {
|
|
3633
3823
|
const rawContent = await readFileContent(filePath);
|
|
3634
3824
|
let content;
|
|
3635
3825
|
let frontmatter;
|
|
3636
3826
|
const filename = file.replace(new RegExp(`\\${dirConfig.filePattern}$`), "");
|
|
3637
3827
|
if (dirConfig.filePattern === ".instructions.md") {
|
|
3638
|
-
const parsed = (0,
|
|
3828
|
+
const parsed = (0, import_gray_matter4.default)(rawContent);
|
|
3639
3829
|
content = parsed.content.trim();
|
|
3640
3830
|
const parsedFrontmatter = parsed.data;
|
|
3641
3831
|
frontmatter = {
|
|
@@ -3701,6 +3891,13 @@ async function parseMemoryBasedConfiguration(baseDir = process.cwd(), config) {
|
|
|
3701
3891
|
const memoryRules = await parseMemoryFiles(memoryDir, config);
|
|
3702
3892
|
rules.push(...memoryRules);
|
|
3703
3893
|
}
|
|
3894
|
+
if (config.commandsDirPath) {
|
|
3895
|
+
const commandsDir = resolvePath(config.commandsDirPath, baseDir);
|
|
3896
|
+
if (await fileExists(commandsDir)) {
|
|
3897
|
+
const commandsRules = await parseCommandsFiles(commandsDir, config);
|
|
3898
|
+
rules.push(...commandsRules);
|
|
3899
|
+
}
|
|
3900
|
+
}
|
|
3704
3901
|
const settingsPath = resolvePath(config.settingsPath, baseDir);
|
|
3705
3902
|
if (await fileExists(settingsPath)) {
|
|
3706
3903
|
const settingsResult = await parseSettingsFile(settingsPath, config.tool);
|
|
@@ -3766,10 +3963,10 @@ async function parseMemoryFiles(memoryDir, config) {
|
|
|
3766
3963
|
const files = await readdir2(memoryDir);
|
|
3767
3964
|
for (const file of files) {
|
|
3768
3965
|
if (file.endsWith(".md")) {
|
|
3769
|
-
const filePath = (0,
|
|
3966
|
+
const filePath = (0, import_node_path17.join)(memoryDir, file);
|
|
3770
3967
|
const content = await readFileContent(filePath);
|
|
3771
3968
|
if (content.trim()) {
|
|
3772
|
-
const filename = (0,
|
|
3969
|
+
const filename = (0, import_node_path17.basename)(file, ".md");
|
|
3773
3970
|
const frontmatter = {
|
|
3774
3971
|
root: false,
|
|
3775
3972
|
targets: [config.tool],
|
|
@@ -3789,6 +3986,54 @@ async function parseMemoryFiles(memoryDir, config) {
|
|
|
3789
3986
|
}
|
|
3790
3987
|
return rules;
|
|
3791
3988
|
}
|
|
3989
|
+
async function parseCommandsFiles(commandsDir, config) {
|
|
3990
|
+
const rules = [];
|
|
3991
|
+
try {
|
|
3992
|
+
const { readdir: readdir2 } = await import("fs/promises");
|
|
3993
|
+
const files = await readdir2(commandsDir);
|
|
3994
|
+
for (const file of files) {
|
|
3995
|
+
if (file.endsWith(".md")) {
|
|
3996
|
+
const filePath = (0, import_node_path17.join)(commandsDir, file);
|
|
3997
|
+
const content = await readFileContent(filePath);
|
|
3998
|
+
if (content.trim()) {
|
|
3999
|
+
const filename = (0, import_node_path17.basename)(file, ".md");
|
|
4000
|
+
let frontmatter;
|
|
4001
|
+
let ruleContent;
|
|
4002
|
+
try {
|
|
4003
|
+
const parsed = (0, import_gray_matter4.default)(content);
|
|
4004
|
+
ruleContent = parsed.content.trim();
|
|
4005
|
+
const parsedFrontmatter = parsed.data;
|
|
4006
|
+
frontmatter = {
|
|
4007
|
+
root: false,
|
|
4008
|
+
targets: [config.tool],
|
|
4009
|
+
description: parsedFrontmatter.description || `Command: ${filename}`,
|
|
4010
|
+
globs: ["**/*"]
|
|
4011
|
+
};
|
|
4012
|
+
} catch {
|
|
4013
|
+
ruleContent = content.trim();
|
|
4014
|
+
frontmatter = {
|
|
4015
|
+
root: false,
|
|
4016
|
+
targets: [config.tool],
|
|
4017
|
+
description: `Command: ${filename}`,
|
|
4018
|
+
globs: ["**/*"]
|
|
4019
|
+
};
|
|
4020
|
+
}
|
|
4021
|
+
if (ruleContent) {
|
|
4022
|
+
rules.push({
|
|
4023
|
+
frontmatter,
|
|
4024
|
+
content: ruleContent,
|
|
4025
|
+
filename,
|
|
4026
|
+
filepath: filePath,
|
|
4027
|
+
type: "command"
|
|
4028
|
+
});
|
|
4029
|
+
}
|
|
4030
|
+
}
|
|
4031
|
+
}
|
|
4032
|
+
}
|
|
4033
|
+
} catch {
|
|
4034
|
+
}
|
|
4035
|
+
return rules;
|
|
4036
|
+
}
|
|
3792
4037
|
async function parseSettingsFile(settingsPath, tool) {
|
|
3793
4038
|
const errors = [];
|
|
3794
4039
|
let ignorePatterns;
|
|
@@ -3836,7 +4081,8 @@ async function parseClaudeConfiguration(baseDir = process.cwd()) {
|
|
|
3836
4081
|
settingsPath: ".claude/settings.json",
|
|
3837
4082
|
mainDescription: "Main Claude Code configuration",
|
|
3838
4083
|
memoryDescription: "Memory file",
|
|
3839
|
-
filenamePrefix: "claude"
|
|
4084
|
+
filenamePrefix: "claude",
|
|
4085
|
+
commandsDirPath: ".claude/commands"
|
|
3840
4086
|
});
|
|
3841
4087
|
}
|
|
3842
4088
|
|
|
@@ -3861,7 +4107,7 @@ async function parseClineConfiguration(baseDir = process.cwd()) {
|
|
|
3861
4107
|
}
|
|
3862
4108
|
|
|
3863
4109
|
// src/parsers/codexcli.ts
|
|
3864
|
-
var
|
|
4110
|
+
var import_node_path18 = require("path");
|
|
3865
4111
|
|
|
3866
4112
|
// src/parsers/copilot.ts
|
|
3867
4113
|
async function parseCopilotConfiguration(baseDir = process.cwd()) {
|
|
@@ -3884,10 +4130,10 @@ async function parseCopilotConfiguration(baseDir = process.cwd()) {
|
|
|
3884
4130
|
}
|
|
3885
4131
|
|
|
3886
4132
|
// src/parsers/cursor.ts
|
|
3887
|
-
var
|
|
3888
|
-
var
|
|
4133
|
+
var import_node_path19 = require("path");
|
|
4134
|
+
var import_gray_matter5 = __toESM(require("gray-matter"), 1);
|
|
3889
4135
|
var import_js_yaml = require("js-yaml");
|
|
3890
|
-
var
|
|
4136
|
+
var import_mini8 = require("zod/mini");
|
|
3891
4137
|
var customMatterOptions = {
|
|
3892
4138
|
engines: {
|
|
3893
4139
|
yaml: {
|
|
@@ -3915,7 +4161,7 @@ var customMatterOptions = {
|
|
|
3915
4161
|
}
|
|
3916
4162
|
};
|
|
3917
4163
|
function convertCursorMdcFrontmatter(cursorFrontmatter, _filename) {
|
|
3918
|
-
const FrontmatterSchema =
|
|
4164
|
+
const FrontmatterSchema = import_mini8.z.record(import_mini8.z.string(), import_mini8.z.unknown());
|
|
3919
4165
|
const parseResult = FrontmatterSchema.safeParse(cursorFrontmatter);
|
|
3920
4166
|
if (!parseResult.success) {
|
|
3921
4167
|
return {
|
|
@@ -4009,11 +4255,11 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
4009
4255
|
const rules = [];
|
|
4010
4256
|
let ignorePatterns;
|
|
4011
4257
|
let mcpServers;
|
|
4012
|
-
const cursorFilePath = (0,
|
|
4258
|
+
const cursorFilePath = (0, import_node_path19.join)(baseDir, ".cursorrules");
|
|
4013
4259
|
if (await fileExists(cursorFilePath)) {
|
|
4014
4260
|
try {
|
|
4015
4261
|
const rawContent = await readFileContent(cursorFilePath);
|
|
4016
|
-
const parsed = (0,
|
|
4262
|
+
const parsed = (0, import_gray_matter5.default)(rawContent, customMatterOptions);
|
|
4017
4263
|
const content = parsed.content.trim();
|
|
4018
4264
|
if (content) {
|
|
4019
4265
|
const frontmatter = convertCursorMdcFrontmatter(parsed.data, "cursorrules");
|
|
@@ -4030,20 +4276,20 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
4030
4276
|
errors.push(`Failed to parse .cursorrules file: ${errorMessage}`);
|
|
4031
4277
|
}
|
|
4032
4278
|
}
|
|
4033
|
-
const cursorRulesDir = (0,
|
|
4279
|
+
const cursorRulesDir = (0, import_node_path19.join)(baseDir, ".cursor", "rules");
|
|
4034
4280
|
if (await fileExists(cursorRulesDir)) {
|
|
4035
4281
|
try {
|
|
4036
4282
|
const { readdir: readdir2 } = await import("fs/promises");
|
|
4037
4283
|
const files = await readdir2(cursorRulesDir);
|
|
4038
4284
|
for (const file of files) {
|
|
4039
4285
|
if (file.endsWith(".mdc")) {
|
|
4040
|
-
const filePath = (0,
|
|
4286
|
+
const filePath = (0, import_node_path19.join)(cursorRulesDir, file);
|
|
4041
4287
|
try {
|
|
4042
4288
|
const rawContent = await readFileContent(filePath);
|
|
4043
|
-
const parsed = (0,
|
|
4289
|
+
const parsed = (0, import_gray_matter5.default)(rawContent, customMatterOptions);
|
|
4044
4290
|
const content = parsed.content.trim();
|
|
4045
4291
|
if (content) {
|
|
4046
|
-
const filename = (0,
|
|
4292
|
+
const filename = (0, import_node_path19.basename)(file, ".mdc");
|
|
4047
4293
|
const frontmatter = convertCursorMdcFrontmatter(parsed.data, filename);
|
|
4048
4294
|
rules.push({
|
|
4049
4295
|
frontmatter,
|
|
@@ -4066,7 +4312,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
4066
4312
|
if (rules.length === 0) {
|
|
4067
4313
|
errors.push("No Cursor configuration files found (.cursorrules or .cursor/rules/*.mdc)");
|
|
4068
4314
|
}
|
|
4069
|
-
const cursorIgnorePath = (0,
|
|
4315
|
+
const cursorIgnorePath = (0, import_node_path19.join)(baseDir, ".cursorignore");
|
|
4070
4316
|
if (await fileExists(cursorIgnorePath)) {
|
|
4071
4317
|
try {
|
|
4072
4318
|
const content = await readFileContent(cursorIgnorePath);
|
|
@@ -4079,7 +4325,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
4079
4325
|
errors.push(`Failed to parse .cursorignore: ${errorMessage}`);
|
|
4080
4326
|
}
|
|
4081
4327
|
}
|
|
4082
|
-
const cursorMcpPath = (0,
|
|
4328
|
+
const cursorMcpPath = (0, import_node_path19.join)(baseDir, ".cursor", "mcp.json");
|
|
4083
4329
|
if (await fileExists(cursorMcpPath)) {
|
|
4084
4330
|
try {
|
|
4085
4331
|
const content = await readFileContent(cursorMcpPath);
|
|
@@ -4123,16 +4369,17 @@ async function parseGeminiConfiguration(baseDir = process.cwd()) {
|
|
|
4123
4369
|
additionalIgnoreFile: {
|
|
4124
4370
|
path: ".aiexclude",
|
|
4125
4371
|
parser: parseAiexclude
|
|
4126
|
-
}
|
|
4372
|
+
},
|
|
4373
|
+
commandsDirPath: ".gemini/commands"
|
|
4127
4374
|
});
|
|
4128
4375
|
}
|
|
4129
4376
|
|
|
4130
4377
|
// src/parsers/junie.ts
|
|
4131
|
-
var
|
|
4378
|
+
var import_node_path20 = require("path");
|
|
4132
4379
|
async function parseJunieConfiguration(baseDir = process.cwd()) {
|
|
4133
4380
|
const errors = [];
|
|
4134
4381
|
const rules = [];
|
|
4135
|
-
const guidelinesPath = (0,
|
|
4382
|
+
const guidelinesPath = (0, import_node_path20.join)(baseDir, ".junie", "guidelines.md");
|
|
4136
4383
|
if (!await fileExists(guidelinesPath)) {
|
|
4137
4384
|
errors.push(".junie/guidelines.md file not found");
|
|
4138
4385
|
return { rules, errors };
|
|
@@ -4185,8 +4432,8 @@ async function parseRooConfiguration(baseDir = process.cwd()) {
|
|
|
4185
4432
|
|
|
4186
4433
|
// src/parsers/windsurf.ts
|
|
4187
4434
|
var import_promises3 = require("fs/promises");
|
|
4188
|
-
var
|
|
4189
|
-
var
|
|
4435
|
+
var import_node_path21 = require("path");
|
|
4436
|
+
var import_gray_matter6 = __toESM(require("gray-matter"), 1);
|
|
4190
4437
|
|
|
4191
4438
|
// src/core/importer.ts
|
|
4192
4439
|
async function importConfiguration(options) {
|
|
@@ -4272,7 +4519,7 @@ async function importConfiguration(options) {
|
|
|
4272
4519
|
if (rules.length === 0 && !ignorePatterns && !mcpServers) {
|
|
4273
4520
|
return { success: false, rulesCreated: 0, errors };
|
|
4274
4521
|
}
|
|
4275
|
-
const rulesDirPath = (0,
|
|
4522
|
+
const rulesDirPath = (0, import_node_path22.join)(baseDir, rulesDir);
|
|
4276
4523
|
try {
|
|
4277
4524
|
const { mkdir: mkdir3 } = await import("fs/promises");
|
|
4278
4525
|
await mkdir3(rulesDirPath, { recursive: true });
|
|
@@ -4285,8 +4532,13 @@ async function importConfiguration(options) {
|
|
|
4285
4532
|
for (const rule of rules) {
|
|
4286
4533
|
try {
|
|
4287
4534
|
const baseFilename = rule.filename;
|
|
4288
|
-
|
|
4289
|
-
|
|
4535
|
+
let targetDir = rulesDirPath;
|
|
4536
|
+
if (rule.type === "command") {
|
|
4537
|
+
targetDir = (0, import_node_path22.join)(rulesDirPath, "commands");
|
|
4538
|
+
const { mkdir: mkdir3 } = await import("fs/promises");
|
|
4539
|
+
await mkdir3(targetDir, { recursive: true });
|
|
4540
|
+
}
|
|
4541
|
+
const filePath = (0, import_node_path22.join)(targetDir, `${baseFilename}.md`);
|
|
4290
4542
|
const content = generateRuleFileContent(rule);
|
|
4291
4543
|
await writeFileContent(filePath, content);
|
|
4292
4544
|
rulesCreated++;
|
|
@@ -4301,7 +4553,7 @@ async function importConfiguration(options) {
|
|
|
4301
4553
|
let ignoreFileCreated = false;
|
|
4302
4554
|
if (ignorePatterns && ignorePatterns.length > 0) {
|
|
4303
4555
|
try {
|
|
4304
|
-
const rulesyncignorePath = (0,
|
|
4556
|
+
const rulesyncignorePath = (0, import_node_path22.join)(baseDir, ".rulesyncignore");
|
|
4305
4557
|
const ignoreContent = `${ignorePatterns.join("\n")}
|
|
4306
4558
|
`;
|
|
4307
4559
|
await writeFileContent(rulesyncignorePath, ignoreContent);
|
|
@@ -4317,7 +4569,7 @@ async function importConfiguration(options) {
|
|
|
4317
4569
|
let mcpFileCreated = false;
|
|
4318
4570
|
if (mcpServers && Object.keys(mcpServers).length > 0) {
|
|
4319
4571
|
try {
|
|
4320
|
-
const mcpPath = (0,
|
|
4572
|
+
const mcpPath = (0, import_node_path22.join)(baseDir, rulesDir, ".mcp.json");
|
|
4321
4573
|
const mcpContent = `${JSON.stringify({ mcpServers }, null, 2)}
|
|
4322
4574
|
`;
|
|
4323
4575
|
await writeFileContent(mcpPath, mcpContent);
|
|
@@ -4339,17 +4591,16 @@ async function importConfiguration(options) {
|
|
|
4339
4591
|
};
|
|
4340
4592
|
}
|
|
4341
4593
|
function generateRuleFileContent(rule) {
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
filename = `${baseFilename}-${counter}`;
|
|
4350
|
-
counter++;
|
|
4594
|
+
if (rule.type === "command") {
|
|
4595
|
+
const simplifiedFrontmatter = {
|
|
4596
|
+
description: rule.frontmatter.description,
|
|
4597
|
+
targets: rule.frontmatter.targets
|
|
4598
|
+
};
|
|
4599
|
+
const frontmatter2 = import_gray_matter7.default.stringify("", simplifiedFrontmatter);
|
|
4600
|
+
return frontmatter2 + rule.content;
|
|
4351
4601
|
}
|
|
4352
|
-
|
|
4602
|
+
const frontmatter = import_gray_matter7.default.stringify("", rule.frontmatter);
|
|
4603
|
+
return frontmatter + rule.content;
|
|
4353
4604
|
}
|
|
4354
4605
|
|
|
4355
4606
|
// src/cli/commands/import.ts
|
|
@@ -4412,7 +4663,7 @@ async function importCommand(options = {}) {
|
|
|
4412
4663
|
}
|
|
4413
4664
|
|
|
4414
4665
|
// src/cli/commands/init.ts
|
|
4415
|
-
var
|
|
4666
|
+
var import_node_path23 = require("path");
|
|
4416
4667
|
async function initCommand() {
|
|
4417
4668
|
const aiRulesDir = ".rulesync";
|
|
4418
4669
|
console.log("Initializing rulesync...");
|
|
@@ -4459,7 +4710,7 @@ globs: ["**/*"]
|
|
|
4459
4710
|
- Follow single responsibility principle
|
|
4460
4711
|
`
|
|
4461
4712
|
};
|
|
4462
|
-
const filepath = (0,
|
|
4713
|
+
const filepath = (0, import_node_path23.join)(aiRulesDir, sampleFile.filename);
|
|
4463
4714
|
if (!await fileExists(filepath)) {
|
|
4464
4715
|
await writeFileContent(filepath, sampleFile.content);
|
|
4465
4716
|
console.log(`Created ${filepath}`);
|
|
@@ -4603,7 +4854,7 @@ async function watchCommand() {
|
|
|
4603
4854
|
|
|
4604
4855
|
// src/cli/index.ts
|
|
4605
4856
|
var program = new import_commander.Command();
|
|
4606
|
-
program.name("rulesync").description("Unified AI rules management CLI tool").version("0.
|
|
4857
|
+
program.name("rulesync").description("Unified AI rules management CLI tool").version("0.58.0");
|
|
4607
4858
|
program.command("init").description("Initialize rulesync in current directory").action(initCommand);
|
|
4608
4859
|
program.command("add <filename>").description("Add a new rule file").action(addCommand);
|
|
4609
4860
|
program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);
|