rulesync 0.57.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 +171 -18
- package/README.md +67 -727
- package/dist/index.cjs +447 -212
- package/dist/index.js +447 -212
- 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:
|
|
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,7 +3084,7 @@ ${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
3089
|
const validatedData = RuleFrontmatterSchema.parse(parsed.data);
|
|
2946
3090
|
const frontmatter = {
|
|
@@ -2959,7 +3103,7 @@ async function parseRuleFile(filepath) {
|
|
|
2959
3103
|
},
|
|
2960
3104
|
...validatedData.tags !== void 0 && { tags: validatedData.tags }
|
|
2961
3105
|
};
|
|
2962
|
-
const filename = (0,
|
|
3106
|
+
const filename = (0, import_node_path13.basename)(filepath, ".md");
|
|
2963
3107
|
return {
|
|
2964
3108
|
frontmatter,
|
|
2965
3109
|
content: parsed.content,
|
|
@@ -3262,12 +3406,12 @@ async function generateCommand(options = {}) {
|
|
|
3262
3406
|
for (const tool of targetTools) {
|
|
3263
3407
|
switch (tool) {
|
|
3264
3408
|
case "augmentcode":
|
|
3265
|
-
deleteTasks.push(removeDirectory((0,
|
|
3266
|
-
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")));
|
|
3267
3411
|
break;
|
|
3268
3412
|
case "augmentcode-legacy":
|
|
3269
3413
|
deleteTasks.push(removeClaudeGeneratedFiles());
|
|
3270
|
-
deleteTasks.push(removeDirectory((0,
|
|
3414
|
+
deleteTasks.push(removeDirectory((0, import_node_path14.join)(".augment", "ignore")));
|
|
3271
3415
|
break;
|
|
3272
3416
|
case "copilot":
|
|
3273
3417
|
deleteTasks.push(removeDirectory(config.outputPaths.copilot));
|
|
@@ -3280,12 +3424,14 @@ async function generateCommand(options = {}) {
|
|
|
3280
3424
|
break;
|
|
3281
3425
|
case "claudecode":
|
|
3282
3426
|
deleteTasks.push(removeClaudeGeneratedFiles());
|
|
3427
|
+
deleteTasks.push(removeDirectory((0, import_node_path14.join)(".claude", "commands")));
|
|
3283
3428
|
break;
|
|
3284
3429
|
case "roo":
|
|
3285
3430
|
deleteTasks.push(removeDirectory(config.outputPaths.roo));
|
|
3286
3431
|
break;
|
|
3287
3432
|
case "geminicli":
|
|
3288
3433
|
deleteTasks.push(removeDirectory(config.outputPaths.geminicli));
|
|
3434
|
+
deleteTasks.push(removeDirectory((0, import_node_path14.join)(".gemini", "commands")));
|
|
3289
3435
|
break;
|
|
3290
3436
|
case "kiro":
|
|
3291
3437
|
deleteTasks.push(removeDirectory(config.outputPaths.kiro));
|
|
@@ -3350,11 +3496,37 @@ Generating configurations for base directory: ${baseDir}`);
|
|
|
3350
3496
|
}
|
|
3351
3497
|
}
|
|
3352
3498
|
}
|
|
3353
|
-
|
|
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;
|
|
3354
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`);
|
|
3355
3527
|
console.log(
|
|
3356
3528
|
`
|
|
3357
|
-
\u{1F389} All done! Generated ${totalGenerated} file(s) total (${
|
|
3529
|
+
\u{1F389} All done! Generated ${totalGenerated} file(s) total (${parts.join(" + ")})`
|
|
3358
3530
|
);
|
|
3359
3531
|
}
|
|
3360
3532
|
} catch (error) {
|
|
@@ -3365,9 +3537,9 @@ Generating configurations for base directory: ${baseDir}`);
|
|
|
3365
3537
|
|
|
3366
3538
|
// src/cli/commands/gitignore.ts
|
|
3367
3539
|
var import_node_fs2 = require("fs");
|
|
3368
|
-
var
|
|
3540
|
+
var import_node_path15 = require("path");
|
|
3369
3541
|
var gitignoreCommand = async () => {
|
|
3370
|
-
const gitignorePath = (0,
|
|
3542
|
+
const gitignorePath = (0, import_node_path15.join)(process.cwd(), ".gitignore");
|
|
3371
3543
|
const rulesFilesToIgnore = [
|
|
3372
3544
|
"# Generated by rulesync - AI tool configuration files",
|
|
3373
3545
|
"**/.github/copilot-instructions.md",
|
|
@@ -3378,6 +3550,7 @@ var gitignoreCommand = async () => {
|
|
|
3378
3550
|
"**/.clineignore",
|
|
3379
3551
|
"**/CLAUDE.md",
|
|
3380
3552
|
"**/.claude/memories/",
|
|
3553
|
+
"**/.claude/commands/",
|
|
3381
3554
|
"**/codex.md",
|
|
3382
3555
|
"**/.codexignore",
|
|
3383
3556
|
"**/.roo/rules/",
|
|
@@ -3385,6 +3558,7 @@ var gitignoreCommand = async () => {
|
|
|
3385
3558
|
"**/.copilotignore",
|
|
3386
3559
|
"**/GEMINI.md",
|
|
3387
3560
|
"**/.gemini/memories/",
|
|
3561
|
+
"**/.gemini/commands/",
|
|
3388
3562
|
"**/.aiexclude",
|
|
3389
3563
|
"**/.aiignore",
|
|
3390
3564
|
"**/.augmentignore",
|
|
@@ -3431,12 +3605,12 @@ ${linesToAdd.join("\n")}
|
|
|
3431
3605
|
};
|
|
3432
3606
|
|
|
3433
3607
|
// src/core/importer.ts
|
|
3434
|
-
var
|
|
3435
|
-
var
|
|
3608
|
+
var import_node_path22 = require("path");
|
|
3609
|
+
var import_gray_matter7 = __toESM(require("gray-matter"), 1);
|
|
3436
3610
|
|
|
3437
3611
|
// src/parsers/augmentcode.ts
|
|
3438
|
-
var
|
|
3439
|
-
var
|
|
3612
|
+
var import_node_path16 = require("path");
|
|
3613
|
+
var import_gray_matter3 = __toESM(require("gray-matter"), 1);
|
|
3440
3614
|
|
|
3441
3615
|
// src/utils/parser-helpers.ts
|
|
3442
3616
|
function createParseResult() {
|
|
@@ -3484,7 +3658,7 @@ async function parseAugmentcodeLegacyConfiguration(baseDir = process.cwd()) {
|
|
|
3484
3658
|
async function parseUnifiedAugmentcode(baseDir, config) {
|
|
3485
3659
|
const result = createParseResult();
|
|
3486
3660
|
if (config.rulesDir) {
|
|
3487
|
-
const rulesDir = (0,
|
|
3661
|
+
const rulesDir = (0, import_node_path16.join)(baseDir, config.rulesDir);
|
|
3488
3662
|
if (await fileExists(rulesDir)) {
|
|
3489
3663
|
const rulesResult = await parseAugmentRules(rulesDir, config);
|
|
3490
3664
|
addRules(result, rulesResult.rules);
|
|
@@ -3497,7 +3671,7 @@ async function parseUnifiedAugmentcode(baseDir, config) {
|
|
|
3497
3671
|
}
|
|
3498
3672
|
}
|
|
3499
3673
|
if (config.legacyFilePath) {
|
|
3500
|
-
const legacyPath = (0,
|
|
3674
|
+
const legacyPath = (0, import_node_path16.join)(baseDir, config.legacyFilePath);
|
|
3501
3675
|
if (await fileExists(legacyPath)) {
|
|
3502
3676
|
const legacyResult = await parseAugmentGuidelines(legacyPath, config);
|
|
3503
3677
|
if (legacyResult.rule) {
|
|
@@ -3521,16 +3695,16 @@ async function parseAugmentRules(rulesDir, config) {
|
|
|
3521
3695
|
const files = await readdir2(rulesDir);
|
|
3522
3696
|
for (const file of files) {
|
|
3523
3697
|
if (file.endsWith(".md") || file.endsWith(".mdc")) {
|
|
3524
|
-
const filePath = (0,
|
|
3698
|
+
const filePath = (0, import_node_path16.join)(rulesDir, file);
|
|
3525
3699
|
try {
|
|
3526
3700
|
const rawContent = await readFileContent(filePath);
|
|
3527
|
-
const parsed = (0,
|
|
3701
|
+
const parsed = (0, import_gray_matter3.default)(rawContent);
|
|
3528
3702
|
const frontmatterData = parsed.data;
|
|
3529
3703
|
const ruleType = frontmatterData.type || "manual";
|
|
3530
3704
|
const description = frontmatterData.description || "";
|
|
3531
3705
|
const tags = Array.isArray(frontmatterData.tags) ? frontmatterData.tags : void 0;
|
|
3532
3706
|
const isRoot = ruleType === "always";
|
|
3533
|
-
const filename = (0,
|
|
3707
|
+
const filename = (0, import_node_path16.basename)(file, file.endsWith(".mdc") ? ".mdc" : ".md");
|
|
3534
3708
|
const frontmatter = {
|
|
3535
3709
|
root: isRoot,
|
|
3536
3710
|
targets: [config.targetName],
|
|
@@ -3588,8 +3762,8 @@ async function parseAugmentGuidelines(guidelinesPath, config) {
|
|
|
3588
3762
|
}
|
|
3589
3763
|
|
|
3590
3764
|
// src/parsers/shared-helpers.ts
|
|
3591
|
-
var
|
|
3592
|
-
var
|
|
3765
|
+
var import_node_path17 = require("path");
|
|
3766
|
+
var import_gray_matter4 = __toESM(require("gray-matter"), 1);
|
|
3593
3767
|
async function parseConfigurationFiles(baseDir = process.cwd(), config) {
|
|
3594
3768
|
const errors = [];
|
|
3595
3769
|
const rules = [];
|
|
@@ -3602,7 +3776,7 @@ async function parseConfigurationFiles(baseDir = process.cwd(), config) {
|
|
|
3602
3776
|
let content;
|
|
3603
3777
|
let frontmatter;
|
|
3604
3778
|
if (mainFile.useFrontmatter) {
|
|
3605
|
-
const parsed = (0,
|
|
3779
|
+
const parsed = (0, import_gray_matter4.default)(rawContent);
|
|
3606
3780
|
content = parsed.content.trim();
|
|
3607
3781
|
const parsedFrontmatter = parsed.data;
|
|
3608
3782
|
frontmatter = {
|
|
@@ -3644,14 +3818,14 @@ async function parseConfigurationFiles(baseDir = process.cwd(), config) {
|
|
|
3644
3818
|
const files = await readdir2(dirPath);
|
|
3645
3819
|
for (const file of files) {
|
|
3646
3820
|
if (file.endsWith(dirConfig.filePattern)) {
|
|
3647
|
-
const filePath = (0,
|
|
3821
|
+
const filePath = (0, import_node_path17.join)(dirPath, file);
|
|
3648
3822
|
const fileResult = await safeAsyncOperation(async () => {
|
|
3649
3823
|
const rawContent = await readFileContent(filePath);
|
|
3650
3824
|
let content;
|
|
3651
3825
|
let frontmatter;
|
|
3652
3826
|
const filename = file.replace(new RegExp(`\\${dirConfig.filePattern}$`), "");
|
|
3653
3827
|
if (dirConfig.filePattern === ".instructions.md") {
|
|
3654
|
-
const parsed = (0,
|
|
3828
|
+
const parsed = (0, import_gray_matter4.default)(rawContent);
|
|
3655
3829
|
content = parsed.content.trim();
|
|
3656
3830
|
const parsedFrontmatter = parsed.data;
|
|
3657
3831
|
frontmatter = {
|
|
@@ -3717,6 +3891,13 @@ async function parseMemoryBasedConfiguration(baseDir = process.cwd(), config) {
|
|
|
3717
3891
|
const memoryRules = await parseMemoryFiles(memoryDir, config);
|
|
3718
3892
|
rules.push(...memoryRules);
|
|
3719
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
|
+
}
|
|
3720
3901
|
const settingsPath = resolvePath(config.settingsPath, baseDir);
|
|
3721
3902
|
if (await fileExists(settingsPath)) {
|
|
3722
3903
|
const settingsResult = await parseSettingsFile(settingsPath, config.tool);
|
|
@@ -3782,10 +3963,10 @@ async function parseMemoryFiles(memoryDir, config) {
|
|
|
3782
3963
|
const files = await readdir2(memoryDir);
|
|
3783
3964
|
for (const file of files) {
|
|
3784
3965
|
if (file.endsWith(".md")) {
|
|
3785
|
-
const filePath = (0,
|
|
3966
|
+
const filePath = (0, import_node_path17.join)(memoryDir, file);
|
|
3786
3967
|
const content = await readFileContent(filePath);
|
|
3787
3968
|
if (content.trim()) {
|
|
3788
|
-
const filename = (0,
|
|
3969
|
+
const filename = (0, import_node_path17.basename)(file, ".md");
|
|
3789
3970
|
const frontmatter = {
|
|
3790
3971
|
root: false,
|
|
3791
3972
|
targets: [config.tool],
|
|
@@ -3805,6 +3986,54 @@ async function parseMemoryFiles(memoryDir, config) {
|
|
|
3805
3986
|
}
|
|
3806
3987
|
return rules;
|
|
3807
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
|
+
}
|
|
3808
4037
|
async function parseSettingsFile(settingsPath, tool) {
|
|
3809
4038
|
const errors = [];
|
|
3810
4039
|
let ignorePatterns;
|
|
@@ -3852,7 +4081,8 @@ async function parseClaudeConfiguration(baseDir = process.cwd()) {
|
|
|
3852
4081
|
settingsPath: ".claude/settings.json",
|
|
3853
4082
|
mainDescription: "Main Claude Code configuration",
|
|
3854
4083
|
memoryDescription: "Memory file",
|
|
3855
|
-
filenamePrefix: "claude"
|
|
4084
|
+
filenamePrefix: "claude",
|
|
4085
|
+
commandsDirPath: ".claude/commands"
|
|
3856
4086
|
});
|
|
3857
4087
|
}
|
|
3858
4088
|
|
|
@@ -3877,7 +4107,7 @@ async function parseClineConfiguration(baseDir = process.cwd()) {
|
|
|
3877
4107
|
}
|
|
3878
4108
|
|
|
3879
4109
|
// src/parsers/codexcli.ts
|
|
3880
|
-
var
|
|
4110
|
+
var import_node_path18 = require("path");
|
|
3881
4111
|
|
|
3882
4112
|
// src/parsers/copilot.ts
|
|
3883
4113
|
async function parseCopilotConfiguration(baseDir = process.cwd()) {
|
|
@@ -3900,10 +4130,10 @@ async function parseCopilotConfiguration(baseDir = process.cwd()) {
|
|
|
3900
4130
|
}
|
|
3901
4131
|
|
|
3902
4132
|
// src/parsers/cursor.ts
|
|
3903
|
-
var
|
|
3904
|
-
var
|
|
4133
|
+
var import_node_path19 = require("path");
|
|
4134
|
+
var import_gray_matter5 = __toESM(require("gray-matter"), 1);
|
|
3905
4135
|
var import_js_yaml = require("js-yaml");
|
|
3906
|
-
var
|
|
4136
|
+
var import_mini8 = require("zod/mini");
|
|
3907
4137
|
var customMatterOptions = {
|
|
3908
4138
|
engines: {
|
|
3909
4139
|
yaml: {
|
|
@@ -3931,7 +4161,7 @@ var customMatterOptions = {
|
|
|
3931
4161
|
}
|
|
3932
4162
|
};
|
|
3933
4163
|
function convertCursorMdcFrontmatter(cursorFrontmatter, _filename) {
|
|
3934
|
-
const FrontmatterSchema =
|
|
4164
|
+
const FrontmatterSchema = import_mini8.z.record(import_mini8.z.string(), import_mini8.z.unknown());
|
|
3935
4165
|
const parseResult = FrontmatterSchema.safeParse(cursorFrontmatter);
|
|
3936
4166
|
if (!parseResult.success) {
|
|
3937
4167
|
return {
|
|
@@ -4025,11 +4255,11 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
4025
4255
|
const rules = [];
|
|
4026
4256
|
let ignorePatterns;
|
|
4027
4257
|
let mcpServers;
|
|
4028
|
-
const cursorFilePath = (0,
|
|
4258
|
+
const cursorFilePath = (0, import_node_path19.join)(baseDir, ".cursorrules");
|
|
4029
4259
|
if (await fileExists(cursorFilePath)) {
|
|
4030
4260
|
try {
|
|
4031
4261
|
const rawContent = await readFileContent(cursorFilePath);
|
|
4032
|
-
const parsed = (0,
|
|
4262
|
+
const parsed = (0, import_gray_matter5.default)(rawContent, customMatterOptions);
|
|
4033
4263
|
const content = parsed.content.trim();
|
|
4034
4264
|
if (content) {
|
|
4035
4265
|
const frontmatter = convertCursorMdcFrontmatter(parsed.data, "cursorrules");
|
|
@@ -4046,20 +4276,20 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
4046
4276
|
errors.push(`Failed to parse .cursorrules file: ${errorMessage}`);
|
|
4047
4277
|
}
|
|
4048
4278
|
}
|
|
4049
|
-
const cursorRulesDir = (0,
|
|
4279
|
+
const cursorRulesDir = (0, import_node_path19.join)(baseDir, ".cursor", "rules");
|
|
4050
4280
|
if (await fileExists(cursorRulesDir)) {
|
|
4051
4281
|
try {
|
|
4052
4282
|
const { readdir: readdir2 } = await import("fs/promises");
|
|
4053
4283
|
const files = await readdir2(cursorRulesDir);
|
|
4054
4284
|
for (const file of files) {
|
|
4055
4285
|
if (file.endsWith(".mdc")) {
|
|
4056
|
-
const filePath = (0,
|
|
4286
|
+
const filePath = (0, import_node_path19.join)(cursorRulesDir, file);
|
|
4057
4287
|
try {
|
|
4058
4288
|
const rawContent = await readFileContent(filePath);
|
|
4059
|
-
const parsed = (0,
|
|
4289
|
+
const parsed = (0, import_gray_matter5.default)(rawContent, customMatterOptions);
|
|
4060
4290
|
const content = parsed.content.trim();
|
|
4061
4291
|
if (content) {
|
|
4062
|
-
const filename = (0,
|
|
4292
|
+
const filename = (0, import_node_path19.basename)(file, ".mdc");
|
|
4063
4293
|
const frontmatter = convertCursorMdcFrontmatter(parsed.data, filename);
|
|
4064
4294
|
rules.push({
|
|
4065
4295
|
frontmatter,
|
|
@@ -4082,7 +4312,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
4082
4312
|
if (rules.length === 0) {
|
|
4083
4313
|
errors.push("No Cursor configuration files found (.cursorrules or .cursor/rules/*.mdc)");
|
|
4084
4314
|
}
|
|
4085
|
-
const cursorIgnorePath = (0,
|
|
4315
|
+
const cursorIgnorePath = (0, import_node_path19.join)(baseDir, ".cursorignore");
|
|
4086
4316
|
if (await fileExists(cursorIgnorePath)) {
|
|
4087
4317
|
try {
|
|
4088
4318
|
const content = await readFileContent(cursorIgnorePath);
|
|
@@ -4095,7 +4325,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
4095
4325
|
errors.push(`Failed to parse .cursorignore: ${errorMessage}`);
|
|
4096
4326
|
}
|
|
4097
4327
|
}
|
|
4098
|
-
const cursorMcpPath = (0,
|
|
4328
|
+
const cursorMcpPath = (0, import_node_path19.join)(baseDir, ".cursor", "mcp.json");
|
|
4099
4329
|
if (await fileExists(cursorMcpPath)) {
|
|
4100
4330
|
try {
|
|
4101
4331
|
const content = await readFileContent(cursorMcpPath);
|
|
@@ -4139,16 +4369,17 @@ async function parseGeminiConfiguration(baseDir = process.cwd()) {
|
|
|
4139
4369
|
additionalIgnoreFile: {
|
|
4140
4370
|
path: ".aiexclude",
|
|
4141
4371
|
parser: parseAiexclude
|
|
4142
|
-
}
|
|
4372
|
+
},
|
|
4373
|
+
commandsDirPath: ".gemini/commands"
|
|
4143
4374
|
});
|
|
4144
4375
|
}
|
|
4145
4376
|
|
|
4146
4377
|
// src/parsers/junie.ts
|
|
4147
|
-
var
|
|
4378
|
+
var import_node_path20 = require("path");
|
|
4148
4379
|
async function parseJunieConfiguration(baseDir = process.cwd()) {
|
|
4149
4380
|
const errors = [];
|
|
4150
4381
|
const rules = [];
|
|
4151
|
-
const guidelinesPath = (0,
|
|
4382
|
+
const guidelinesPath = (0, import_node_path20.join)(baseDir, ".junie", "guidelines.md");
|
|
4152
4383
|
if (!await fileExists(guidelinesPath)) {
|
|
4153
4384
|
errors.push(".junie/guidelines.md file not found");
|
|
4154
4385
|
return { rules, errors };
|
|
@@ -4201,8 +4432,8 @@ async function parseRooConfiguration(baseDir = process.cwd()) {
|
|
|
4201
4432
|
|
|
4202
4433
|
// src/parsers/windsurf.ts
|
|
4203
4434
|
var import_promises3 = require("fs/promises");
|
|
4204
|
-
var
|
|
4205
|
-
var
|
|
4435
|
+
var import_node_path21 = require("path");
|
|
4436
|
+
var import_gray_matter6 = __toESM(require("gray-matter"), 1);
|
|
4206
4437
|
|
|
4207
4438
|
// src/core/importer.ts
|
|
4208
4439
|
async function importConfiguration(options) {
|
|
@@ -4288,7 +4519,7 @@ async function importConfiguration(options) {
|
|
|
4288
4519
|
if (rules.length === 0 && !ignorePatterns && !mcpServers) {
|
|
4289
4520
|
return { success: false, rulesCreated: 0, errors };
|
|
4290
4521
|
}
|
|
4291
|
-
const rulesDirPath = (0,
|
|
4522
|
+
const rulesDirPath = (0, import_node_path22.join)(baseDir, rulesDir);
|
|
4292
4523
|
try {
|
|
4293
4524
|
const { mkdir: mkdir3 } = await import("fs/promises");
|
|
4294
4525
|
await mkdir3(rulesDirPath, { recursive: true });
|
|
@@ -4301,8 +4532,13 @@ async function importConfiguration(options) {
|
|
|
4301
4532
|
for (const rule of rules) {
|
|
4302
4533
|
try {
|
|
4303
4534
|
const baseFilename = rule.filename;
|
|
4304
|
-
|
|
4305
|
-
|
|
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`);
|
|
4306
4542
|
const content = generateRuleFileContent(rule);
|
|
4307
4543
|
await writeFileContent(filePath, content);
|
|
4308
4544
|
rulesCreated++;
|
|
@@ -4317,7 +4553,7 @@ async function importConfiguration(options) {
|
|
|
4317
4553
|
let ignoreFileCreated = false;
|
|
4318
4554
|
if (ignorePatterns && ignorePatterns.length > 0) {
|
|
4319
4555
|
try {
|
|
4320
|
-
const rulesyncignorePath = (0,
|
|
4556
|
+
const rulesyncignorePath = (0, import_node_path22.join)(baseDir, ".rulesyncignore");
|
|
4321
4557
|
const ignoreContent = `${ignorePatterns.join("\n")}
|
|
4322
4558
|
`;
|
|
4323
4559
|
await writeFileContent(rulesyncignorePath, ignoreContent);
|
|
@@ -4333,7 +4569,7 @@ async function importConfiguration(options) {
|
|
|
4333
4569
|
let mcpFileCreated = false;
|
|
4334
4570
|
if (mcpServers && Object.keys(mcpServers).length > 0) {
|
|
4335
4571
|
try {
|
|
4336
|
-
const mcpPath = (0,
|
|
4572
|
+
const mcpPath = (0, import_node_path22.join)(baseDir, rulesDir, ".mcp.json");
|
|
4337
4573
|
const mcpContent = `${JSON.stringify({ mcpServers }, null, 2)}
|
|
4338
4574
|
`;
|
|
4339
4575
|
await writeFileContent(mcpPath, mcpContent);
|
|
@@ -4355,17 +4591,16 @@ async function importConfiguration(options) {
|
|
|
4355
4591
|
};
|
|
4356
4592
|
}
|
|
4357
4593
|
function generateRuleFileContent(rule) {
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
filename = `${baseFilename}-${counter}`;
|
|
4366
|
-
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;
|
|
4367
4601
|
}
|
|
4368
|
-
|
|
4602
|
+
const frontmatter = import_gray_matter7.default.stringify("", rule.frontmatter);
|
|
4603
|
+
return frontmatter + rule.content;
|
|
4369
4604
|
}
|
|
4370
4605
|
|
|
4371
4606
|
// src/cli/commands/import.ts
|
|
@@ -4428,7 +4663,7 @@ async function importCommand(options = {}) {
|
|
|
4428
4663
|
}
|
|
4429
4664
|
|
|
4430
4665
|
// src/cli/commands/init.ts
|
|
4431
|
-
var
|
|
4666
|
+
var import_node_path23 = require("path");
|
|
4432
4667
|
async function initCommand() {
|
|
4433
4668
|
const aiRulesDir = ".rulesync";
|
|
4434
4669
|
console.log("Initializing rulesync...");
|
|
@@ -4475,7 +4710,7 @@ globs: ["**/*"]
|
|
|
4475
4710
|
- Follow single responsibility principle
|
|
4476
4711
|
`
|
|
4477
4712
|
};
|
|
4478
|
-
const filepath = (0,
|
|
4713
|
+
const filepath = (0, import_node_path23.join)(aiRulesDir, sampleFile.filename);
|
|
4479
4714
|
if (!await fileExists(filepath)) {
|
|
4480
4715
|
await writeFileContent(filepath, sampleFile.content);
|
|
4481
4716
|
console.log(`Created ${filepath}`);
|
|
@@ -4619,7 +4854,7 @@ async function watchCommand() {
|
|
|
4619
4854
|
|
|
4620
4855
|
// src/cli/index.ts
|
|
4621
4856
|
var program = new import_commander.Command();
|
|
4622
|
-
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");
|
|
4623
4858
|
program.command("init").description("Initialize rulesync in current directory").action(initCommand);
|
|
4624
4859
|
program.command("add <filename>").description("Add a new rule file").action(addCommand);
|
|
4625
4860
|
program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);
|