rulesync 0.43.0 → 0.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-B3627VQY.js → chunk-22GWBUIP.js} +9 -5
- package/dist/{chunk-XHRBWFGI.js → chunk-BD37M3ZH.js} +2 -2
- package/dist/{chunk-TCK42GOL.js → chunk-DCSO5MY7.js} +2 -2
- package/dist/{chunk-ZMAL5LIX.js → chunk-FAZT3ILF.js} +4 -8
- package/dist/{chunk-THWXK5Z2.js → chunk-I5XVU7C6.js} +4 -1
- package/dist/{chunk-RL3TE3EZ.js → chunk-PJUNIIF4.js} +4 -8
- package/dist/{chunk-2FR4Z37J.js → chunk-ZORSPGDD.js} +1 -1
- package/dist/{claudecode-ITHKV345.js → claudecode-KSK2BEI7.js} +2 -2
- package/dist/{cline-PKE6TYNJ.js → cline-T5YVGYBF.js} +2 -2
- package/dist/{copilot-5JP6D4NO.js → copilot-UDCWNUAH.js} +2 -2
- package/dist/{cursor-RHFDG6T2.js → cursor-KPV6OVST.js} +2 -2
- package/dist/{geminicli-B3FFO5WV.js → geminicli-2DC5F34J.js} +2 -2
- package/dist/index.cjs +163 -210
- package/dist/index.js +157 -209
- package/dist/{roo-UOTKEOH7.js → roo-DRA2SU4L.js} +2 -2
- package/package.json +12 -5
package/dist/index.cjs
CHANGED
|
@@ -27,12 +27,12 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
27
|
));
|
|
28
28
|
|
|
29
29
|
// src/types/tool-targets.ts
|
|
30
|
-
var
|
|
30
|
+
var import_v4_mini, ToolTargetSchema, ToolTargetsSchema, WildcardTargetSchema, RulesyncTargetsSchema;
|
|
31
31
|
var init_tool_targets = __esm({
|
|
32
32
|
"src/types/tool-targets.ts"() {
|
|
33
33
|
"use strict";
|
|
34
|
-
|
|
35
|
-
ToolTargetSchema =
|
|
34
|
+
import_v4_mini = require("zod/v4-mini");
|
|
35
|
+
ToolTargetSchema = import_v4_mini.z.enum([
|
|
36
36
|
"copilot",
|
|
37
37
|
"cursor",
|
|
38
38
|
"cline",
|
|
@@ -40,9 +40,9 @@ var init_tool_targets = __esm({
|
|
|
40
40
|
"roo",
|
|
41
41
|
"geminicli"
|
|
42
42
|
]);
|
|
43
|
-
ToolTargetsSchema =
|
|
44
|
-
WildcardTargetSchema =
|
|
45
|
-
RulesyncTargetsSchema =
|
|
43
|
+
ToolTargetsSchema = import_v4_mini.z.array(ToolTargetSchema);
|
|
44
|
+
WildcardTargetSchema = import_v4_mini.z.tuple([import_v4_mini.z.literal("*")]);
|
|
45
|
+
RulesyncTargetsSchema = import_v4_mini.z.union([ToolTargetsSchema, WildcardTargetSchema]);
|
|
46
46
|
}
|
|
47
47
|
});
|
|
48
48
|
|
|
@@ -98,7 +98,9 @@ function generateClaudeMcp(config) {
|
|
|
98
98
|
if (server.env) {
|
|
99
99
|
claudeServer.env = server.env;
|
|
100
100
|
}
|
|
101
|
-
claudeSettings.mcpServers
|
|
101
|
+
if (claudeSettings.mcpServers) {
|
|
102
|
+
claudeSettings.mcpServers[serverName] = claudeServer;
|
|
103
|
+
}
|
|
102
104
|
}
|
|
103
105
|
return JSON.stringify(claudeSettings, null, 2);
|
|
104
106
|
}
|
|
@@ -352,6 +354,7 @@ var import_promises = require("fs/promises");
|
|
|
352
354
|
var path = __toESM(require("path"), 1);
|
|
353
355
|
|
|
354
356
|
// src/utils/config.ts
|
|
357
|
+
init_tool_targets();
|
|
355
358
|
function getDefaultConfig() {
|
|
356
359
|
return {
|
|
357
360
|
aiRulesDir: ".rulesync",
|
|
@@ -368,10 +371,11 @@ function getDefaultConfig() {
|
|
|
368
371
|
};
|
|
369
372
|
}
|
|
370
373
|
function resolveTargets(targets, config) {
|
|
371
|
-
if (targets[0] === "*") {
|
|
374
|
+
if (targets.length === 1 && targets[0] === "*") {
|
|
372
375
|
return config.defaultTargets;
|
|
373
376
|
}
|
|
374
|
-
|
|
377
|
+
const validatedTargets = ToolTargetsSchema.parse(targets);
|
|
378
|
+
return validatedTargets;
|
|
375
379
|
}
|
|
376
380
|
|
|
377
381
|
// src/cli/commands/add.ts
|
|
@@ -414,11 +418,14 @@ async function addCommand(filename) {
|
|
|
414
418
|
var import_node_path4 = require("path");
|
|
415
419
|
|
|
416
420
|
// src/types/claudecode.ts
|
|
417
|
-
var
|
|
418
|
-
var ClaudeSettingsSchema =
|
|
419
|
-
permissions:
|
|
420
|
-
|
|
421
|
-
|
|
421
|
+
var import_v4_mini2 = require("zod/v4-mini");
|
|
422
|
+
var ClaudeSettingsSchema = import_v4_mini2.z.looseObject({
|
|
423
|
+
permissions: import_v4_mini2.z._default(
|
|
424
|
+
import_v4_mini2.z.looseObject({
|
|
425
|
+
deny: import_v4_mini2.z._default(import_v4_mini2.z.array(import_v4_mini2.z.string()), [])
|
|
426
|
+
}),
|
|
427
|
+
{ deny: [] }
|
|
428
|
+
)
|
|
422
429
|
});
|
|
423
430
|
|
|
424
431
|
// src/utils/file.ts
|
|
@@ -581,12 +588,11 @@ function generateClaudeMarkdown(rootRules, detailRules) {
|
|
|
581
588
|
if (detailRules.length > 0) {
|
|
582
589
|
lines.push("Please also reference the following documents as needed:");
|
|
583
590
|
lines.push("");
|
|
584
|
-
lines.push("| Document | Description | File Patterns |");
|
|
585
|
-
lines.push("|----------|-------------|---------------|");
|
|
586
591
|
for (const rule of detailRules) {
|
|
587
|
-
const
|
|
592
|
+
const escapedDescription = rule.frontmatter.description.replace(/"/g, '\\"');
|
|
593
|
+
const globsText = rule.frontmatter.globs.join(",");
|
|
588
594
|
lines.push(
|
|
589
|
-
|
|
595
|
+
`@.claude/memories/${rule.filename}.md description: "${escapedDescription}" globs: "${globsText}"`
|
|
590
596
|
);
|
|
591
597
|
}
|
|
592
598
|
lines.push("");
|
|
@@ -977,6 +983,78 @@ async function generateForTool(tool, rules, config, baseDir) {
|
|
|
977
983
|
// src/core/parser.ts
|
|
978
984
|
var import_node_path10 = require("path");
|
|
979
985
|
var import_gray_matter = __toESM(require("gray-matter"), 1);
|
|
986
|
+
|
|
987
|
+
// src/types/config.ts
|
|
988
|
+
var import_v4_mini3 = require("zod/v4-mini");
|
|
989
|
+
init_tool_targets();
|
|
990
|
+
var ConfigSchema = import_v4_mini3.z.object({
|
|
991
|
+
aiRulesDir: import_v4_mini3.z.string(),
|
|
992
|
+
outputPaths: import_v4_mini3.z.record(ToolTargetSchema, import_v4_mini3.z.string()),
|
|
993
|
+
watchEnabled: import_v4_mini3.z.boolean(),
|
|
994
|
+
defaultTargets: ToolTargetsSchema
|
|
995
|
+
});
|
|
996
|
+
|
|
997
|
+
// src/types/mcp.ts
|
|
998
|
+
var import_v4_mini4 = require("zod/v4-mini");
|
|
999
|
+
init_tool_targets();
|
|
1000
|
+
var McpTransportTypeSchema = import_v4_mini4.z.enum(["stdio", "sse", "http"]);
|
|
1001
|
+
var McpServerBaseSchema = import_v4_mini4.z.object({
|
|
1002
|
+
command: import_v4_mini4.z.optional(import_v4_mini4.z.string()),
|
|
1003
|
+
args: import_v4_mini4.z.optional(import_v4_mini4.z.array(import_v4_mini4.z.string())),
|
|
1004
|
+
url: import_v4_mini4.z.optional(import_v4_mini4.z.string()),
|
|
1005
|
+
httpUrl: import_v4_mini4.z.optional(import_v4_mini4.z.string()),
|
|
1006
|
+
env: import_v4_mini4.z.optional(import_v4_mini4.z.record(import_v4_mini4.z.string(), import_v4_mini4.z.string())),
|
|
1007
|
+
disabled: import_v4_mini4.z.optional(import_v4_mini4.z.boolean()),
|
|
1008
|
+
networkTimeout: import_v4_mini4.z.optional(import_v4_mini4.z.number()),
|
|
1009
|
+
timeout: import_v4_mini4.z.optional(import_v4_mini4.z.number()),
|
|
1010
|
+
trust: import_v4_mini4.z.optional(import_v4_mini4.z.boolean()),
|
|
1011
|
+
cwd: import_v4_mini4.z.optional(import_v4_mini4.z.string()),
|
|
1012
|
+
transport: import_v4_mini4.z.optional(McpTransportTypeSchema),
|
|
1013
|
+
type: import_v4_mini4.z.optional(import_v4_mini4.z.enum(["sse", "streamable-http"])),
|
|
1014
|
+
alwaysAllow: import_v4_mini4.z.optional(import_v4_mini4.z.array(import_v4_mini4.z.string())),
|
|
1015
|
+
tools: import_v4_mini4.z.optional(import_v4_mini4.z.array(import_v4_mini4.z.string()))
|
|
1016
|
+
});
|
|
1017
|
+
var RulesyncMcpServerSchema = import_v4_mini4.z.extend(McpServerBaseSchema, {
|
|
1018
|
+
targets: import_v4_mini4.z.optional(RulesyncTargetsSchema)
|
|
1019
|
+
});
|
|
1020
|
+
var McpConfigSchema = import_v4_mini4.z.object({
|
|
1021
|
+
mcpServers: import_v4_mini4.z.record(import_v4_mini4.z.string(), McpServerBaseSchema)
|
|
1022
|
+
});
|
|
1023
|
+
var RulesyncMcpConfigSchema = import_v4_mini4.z.object({
|
|
1024
|
+
mcpServers: import_v4_mini4.z.record(import_v4_mini4.z.string(), RulesyncMcpServerSchema)
|
|
1025
|
+
});
|
|
1026
|
+
|
|
1027
|
+
// src/types/rules.ts
|
|
1028
|
+
var import_v4_mini5 = require("zod/v4-mini");
|
|
1029
|
+
init_tool_targets();
|
|
1030
|
+
var RuleFrontmatterSchema = import_v4_mini5.z.object({
|
|
1031
|
+
root: import_v4_mini5.z.boolean(),
|
|
1032
|
+
targets: RulesyncTargetsSchema,
|
|
1033
|
+
description: import_v4_mini5.z.string(),
|
|
1034
|
+
globs: import_v4_mini5.z.array(import_v4_mini5.z.string()),
|
|
1035
|
+
cursorRuleType: import_v4_mini5.z.optional(import_v4_mini5.z.enum(["always", "manual", "specificFiles", "intelligently"]))
|
|
1036
|
+
});
|
|
1037
|
+
var ParsedRuleSchema = import_v4_mini5.z.object({
|
|
1038
|
+
frontmatter: RuleFrontmatterSchema,
|
|
1039
|
+
content: import_v4_mini5.z.string(),
|
|
1040
|
+
filename: import_v4_mini5.z.string(),
|
|
1041
|
+
filepath: import_v4_mini5.z.string()
|
|
1042
|
+
});
|
|
1043
|
+
var GeneratedOutputSchema = import_v4_mini5.z.object({
|
|
1044
|
+
tool: ToolTargetSchema,
|
|
1045
|
+
filepath: import_v4_mini5.z.string(),
|
|
1046
|
+
content: import_v4_mini5.z.string()
|
|
1047
|
+
});
|
|
1048
|
+
var GenerateOptionsSchema = import_v4_mini5.z.object({
|
|
1049
|
+
targetTools: import_v4_mini5.z.optional(ToolTargetsSchema),
|
|
1050
|
+
outputDir: import_v4_mini5.z.optional(import_v4_mini5.z.string()),
|
|
1051
|
+
watch: import_v4_mini5.z.optional(import_v4_mini5.z.boolean())
|
|
1052
|
+
});
|
|
1053
|
+
|
|
1054
|
+
// src/types/index.ts
|
|
1055
|
+
init_tool_targets();
|
|
1056
|
+
|
|
1057
|
+
// src/core/parser.ts
|
|
980
1058
|
async function parseRulesFromDirectory(aiRulesDir) {
|
|
981
1059
|
const ignorePatterns = await loadIgnorePatterns();
|
|
982
1060
|
const ruleFiles = await findFiles(aiRulesDir, ".md", ignorePatterns.patterns);
|
|
@@ -1010,84 +1088,20 @@ ${errors.join("\n")}`);
|
|
|
1010
1088
|
async function parseRuleFile(filepath) {
|
|
1011
1089
|
const content = await readFileContent(filepath);
|
|
1012
1090
|
const parsed = (0, import_gray_matter.default)(content);
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
}
|
|
1023
|
-
function validateFrontmatter(data, filepath) {
|
|
1024
|
-
if (!data || typeof data !== "object") {
|
|
1025
|
-
if (!data) {
|
|
1026
|
-
throw new Error(
|
|
1027
|
-
`Missing frontmatter in ${filepath}: file must contain YAML frontmatter with required fields (root, targets, description, globs)`
|
|
1028
|
-
);
|
|
1029
|
-
}
|
|
1030
|
-
throw new Error(`Invalid frontmatter in ${filepath}: frontmatter must be a valid YAML object`);
|
|
1031
|
-
}
|
|
1032
|
-
const obj = data;
|
|
1033
|
-
if (Object.keys(obj).length === 0) {
|
|
1034
|
-
throw new Error(
|
|
1035
|
-
`Missing frontmatter in ${filepath}: file must contain YAML frontmatter with required fields (root, targets, description, globs)`
|
|
1036
|
-
);
|
|
1037
|
-
}
|
|
1038
|
-
if (obj.root === void 0) {
|
|
1039
|
-
throw new Error(`Missing required field "root" in ${filepath}: must be true or false`);
|
|
1040
|
-
}
|
|
1041
|
-
if (typeof obj.root !== "boolean") {
|
|
1042
|
-
throw new Error(
|
|
1043
|
-
`Invalid "root" field in ${filepath}: must be a boolean (true or false), got ${typeof obj.root}`
|
|
1044
|
-
);
|
|
1045
|
-
}
|
|
1046
|
-
if (obj.targets === void 0) {
|
|
1047
|
-
throw new Error(
|
|
1048
|
-
`Missing required field "targets" in ${filepath}: must be an array like ["*"] or ["copilot", "cursor"]`
|
|
1049
|
-
);
|
|
1050
|
-
}
|
|
1051
|
-
if (!Array.isArray(obj.targets)) {
|
|
1052
|
-
throw new Error(
|
|
1053
|
-
`Invalid "targets" field in ${filepath}: must be an array, got ${typeof obj.targets}`
|
|
1054
|
-
);
|
|
1055
|
-
}
|
|
1056
|
-
const validTargets = ["copilot", "cursor", "cline", "claudecode", "roo", "geminicli", "*"];
|
|
1057
|
-
for (const target of obj.targets) {
|
|
1058
|
-
if (typeof target !== "string" || !validTargets.includes(target)) {
|
|
1059
|
-
throw new Error(
|
|
1060
|
-
`Invalid target "${target}" in ${filepath}: must be one of ${validTargets.join(", ")}`
|
|
1061
|
-
);
|
|
1062
|
-
}
|
|
1063
|
-
}
|
|
1064
|
-
if (obj.description === void 0) {
|
|
1065
|
-
throw new Error(
|
|
1066
|
-
`Missing required field "description" in ${filepath}: must be a descriptive string`
|
|
1067
|
-
);
|
|
1068
|
-
}
|
|
1069
|
-
if (typeof obj.description !== "string") {
|
|
1070
|
-
throw new Error(
|
|
1071
|
-
`Invalid "description" field in ${filepath}: must be a string, got ${typeof obj.description}`
|
|
1072
|
-
);
|
|
1073
|
-
}
|
|
1074
|
-
if (obj.globs === void 0) {
|
|
1075
|
-
throw new Error(
|
|
1076
|
-
`Missing required field "globs" in ${filepath}: must be an array of file patterns like ["**/*.ts"]`
|
|
1077
|
-
);
|
|
1078
|
-
}
|
|
1079
|
-
if (!Array.isArray(obj.globs)) {
|
|
1091
|
+
try {
|
|
1092
|
+
const frontmatter = RuleFrontmatterSchema.parse(parsed.data);
|
|
1093
|
+
const filename = (0, import_node_path10.basename)(filepath, ".md");
|
|
1094
|
+
return {
|
|
1095
|
+
frontmatter,
|
|
1096
|
+
content: parsed.content,
|
|
1097
|
+
filename,
|
|
1098
|
+
filepath
|
|
1099
|
+
};
|
|
1100
|
+
} catch (error) {
|
|
1080
1101
|
throw new Error(
|
|
1081
|
-
`Invalid
|
|
1102
|
+
`Invalid frontmatter in ${filepath}: ${error instanceof Error ? error.message : String(error)}`
|
|
1082
1103
|
);
|
|
1083
1104
|
}
|
|
1084
|
-
for (const glob of obj.globs) {
|
|
1085
|
-
if (typeof glob !== "string") {
|
|
1086
|
-
throw new Error(
|
|
1087
|
-
`Invalid glob pattern in ${filepath}: all globs must be strings, got ${typeof glob}`
|
|
1088
|
-
);
|
|
1089
|
-
}
|
|
1090
|
-
}
|
|
1091
1105
|
}
|
|
1092
1106
|
|
|
1093
1107
|
// src/core/validator.ts
|
|
@@ -1166,13 +1180,11 @@ function parseMcpConfig(projectRoot) {
|
|
|
1166
1180
|
rawConfig.mcpServers = rawConfig.servers;
|
|
1167
1181
|
delete rawConfig.servers;
|
|
1168
1182
|
}
|
|
1169
|
-
if (!rawConfig.mcpServers || typeof rawConfig.mcpServers !== "object") {
|
|
1170
|
-
throw new Error("Invalid mcp.json: 'mcpServers' field must be an object");
|
|
1171
|
-
}
|
|
1172
1183
|
if (rawConfig.tools) {
|
|
1173
1184
|
delete rawConfig.tools;
|
|
1174
1185
|
}
|
|
1175
|
-
|
|
1186
|
+
const validatedConfig = RulesyncMcpConfigSchema.parse(rawConfig);
|
|
1187
|
+
return validatedConfig;
|
|
1176
1188
|
} catch (error) {
|
|
1177
1189
|
throw new Error(
|
|
1178
1190
|
`Failed to parse mcp.json: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -1545,6 +1557,9 @@ async function parseClaudeSettings(settingsPath) {
|
|
|
1545
1557
|
const settings = JSON.parse(content);
|
|
1546
1558
|
if (typeof settings === "object" && settings !== null && "permissions" in settings) {
|
|
1547
1559
|
const permissions = settings.permissions;
|
|
1560
|
+
if (typeof permissions !== "object" || permissions === null) {
|
|
1561
|
+
return { ignorePatterns: [], errors: [] };
|
|
1562
|
+
}
|
|
1548
1563
|
if (permissions && "deny" in permissions && Array.isArray(permissions.deny)) {
|
|
1549
1564
|
const readPatterns = permissions.deny.filter(
|
|
1550
1565
|
(rule) => typeof rule === "string" && rule.startsWith("Read(") && rule.endsWith(")")
|
|
@@ -1557,11 +1572,9 @@ async function parseClaudeSettings(settingsPath) {
|
|
|
1557
1572
|
}
|
|
1558
1573
|
}
|
|
1559
1574
|
}
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
mcpServers = servers;
|
|
1564
|
-
}
|
|
1575
|
+
const parseResult = RulesyncMcpConfigSchema.safeParse(settings);
|
|
1576
|
+
if (parseResult.success && Object.keys(parseResult.data.mcpServers).length > 0) {
|
|
1577
|
+
mcpServers = parseResult.data.mcpServers;
|
|
1565
1578
|
}
|
|
1566
1579
|
} catch (error) {
|
|
1567
1580
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -1720,16 +1733,25 @@ async function parseCopilotConfiguration(baseDir = process.cwd()) {
|
|
|
1720
1733
|
var import_node_path15 = require("path");
|
|
1721
1734
|
var import_gray_matter3 = __toESM(require("gray-matter"), 1);
|
|
1722
1735
|
var import_js_yaml = require("js-yaml");
|
|
1736
|
+
var import_v4_mini6 = require("zod/v4-mini");
|
|
1723
1737
|
var customMatterOptions = {
|
|
1724
1738
|
engines: {
|
|
1725
1739
|
yaml: {
|
|
1726
1740
|
parse: (str) => {
|
|
1727
1741
|
try {
|
|
1728
|
-
|
|
1729
|
-
|
|
1742
|
+
const preprocessed = str.replace(/^(\s*globs:\s*)\*\s*$/gm, '$1"*"').replace(/^(\s*globs:\s*)([^\s"'[\n][^"'[\n]*?)(\s*)$/gm, '$1"$2"$3');
|
|
1743
|
+
const result = (0, import_js_yaml.load)(preprocessed, { schema: import_js_yaml.DEFAULT_SCHEMA });
|
|
1744
|
+
if (typeof result === "object" && result !== null) {
|
|
1745
|
+
return result;
|
|
1746
|
+
}
|
|
1747
|
+
throw new Error("Failed to parse YAML: result is not an object");
|
|
1730
1748
|
} catch (error) {
|
|
1731
1749
|
try {
|
|
1732
|
-
|
|
1750
|
+
const result = (0, import_js_yaml.load)(str, { schema: import_js_yaml.FAILSAFE_SCHEMA });
|
|
1751
|
+
if (typeof result === "object" && result !== null) {
|
|
1752
|
+
return result;
|
|
1753
|
+
}
|
|
1754
|
+
throw new Error("Failed to parse YAML: result is not an object");
|
|
1733
1755
|
} catch {
|
|
1734
1756
|
throw error;
|
|
1735
1757
|
}
|
|
@@ -1739,7 +1761,18 @@ var customMatterOptions = {
|
|
|
1739
1761
|
}
|
|
1740
1762
|
};
|
|
1741
1763
|
function convertCursorMdcFrontmatter(cursorFrontmatter, _filename) {
|
|
1742
|
-
const
|
|
1764
|
+
const FrontmatterSchema = import_v4_mini6.z.record(import_v4_mini6.z.string(), import_v4_mini6.z.unknown());
|
|
1765
|
+
const parseResult = FrontmatterSchema.safeParse(cursorFrontmatter);
|
|
1766
|
+
if (!parseResult.success) {
|
|
1767
|
+
return {
|
|
1768
|
+
root: false,
|
|
1769
|
+
targets: ["*"],
|
|
1770
|
+
description: "",
|
|
1771
|
+
globs: [],
|
|
1772
|
+
cursorRuleType: "manual"
|
|
1773
|
+
};
|
|
1774
|
+
}
|
|
1775
|
+
const frontmatter = parseResult.data;
|
|
1743
1776
|
const description = normalizeValue(frontmatter?.description);
|
|
1744
1777
|
const globs = normalizeGlobsValue(frontmatter?.globs);
|
|
1745
1778
|
const alwaysApply = frontmatter?.alwaysApply === true || frontmatter?.alwaysApply === "true";
|
|
@@ -1774,7 +1807,7 @@ function convertCursorMdcFrontmatter(cursorFrontmatter, _filename) {
|
|
|
1774
1807
|
return {
|
|
1775
1808
|
root: false,
|
|
1776
1809
|
targets: ["*"],
|
|
1777
|
-
description,
|
|
1810
|
+
description: description || "",
|
|
1778
1811
|
globs: [],
|
|
1779
1812
|
cursorRuleType: "intelligently"
|
|
1780
1813
|
};
|
|
@@ -1897,8 +1930,9 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
1897
1930
|
try {
|
|
1898
1931
|
const content = await readFileContent(cursorMcpPath);
|
|
1899
1932
|
const mcp = JSON.parse(content);
|
|
1900
|
-
|
|
1901
|
-
|
|
1933
|
+
const parseResult = RulesyncMcpConfigSchema.safeParse(mcp);
|
|
1934
|
+
if (parseResult.success && Object.keys(parseResult.data.mcpServers).length > 0) {
|
|
1935
|
+
mcpServers = parseResult.data.mcpServers;
|
|
1902
1936
|
}
|
|
1903
1937
|
} catch (error) {
|
|
1904
1938
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -2029,8 +2063,9 @@ async function parseGeminiSettings(settingsPath) {
|
|
|
2029
2063
|
try {
|
|
2030
2064
|
const content = await readFileContent(settingsPath);
|
|
2031
2065
|
const settings = JSON.parse(content);
|
|
2032
|
-
|
|
2033
|
-
|
|
2066
|
+
const parseResult = RulesyncMcpConfigSchema.safeParse(settings);
|
|
2067
|
+
if (parseResult.success && Object.keys(parseResult.data.mcpServers).length > 0) {
|
|
2068
|
+
mcpServers = parseResult.data.mcpServers;
|
|
2034
2069
|
}
|
|
2035
2070
|
} catch (error) {
|
|
2036
2071
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -2337,14 +2372,13 @@ async function initCommand() {
|
|
|
2337
2372
|
console.log("2. Run 'rulesync generate' to create configuration files");
|
|
2338
2373
|
}
|
|
2339
2374
|
async function createSampleFiles(aiRulesDir) {
|
|
2340
|
-
const
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
content: `---
|
|
2375
|
+
const sampleFile = {
|
|
2376
|
+
filename: "overview.md",
|
|
2377
|
+
content: `---
|
|
2344
2378
|
root: true
|
|
2345
2379
|
targets: ["*"]
|
|
2346
2380
|
description: "Project overview and general development guidelines"
|
|
2347
|
-
globs: ["
|
|
2381
|
+
globs: ["**/*"]
|
|
2348
2382
|
---
|
|
2349
2383
|
|
|
2350
2384
|
# Project Overview
|
|
@@ -2372,96 +2406,13 @@ globs: ["**/*.ts", "**/*.js", "**/*.tsx", "**/*.jsx"]
|
|
|
2372
2406
|
- Implement proper error handling
|
|
2373
2407
|
- Follow single responsibility principle
|
|
2374
2408
|
`
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
globs: ["src/components/**/*.tsx", "src/pages/**/*.tsx", "**/*.css", "**/*.scss"]
|
|
2383
|
-
---
|
|
2384
|
-
|
|
2385
|
-
# Frontend Development Rules
|
|
2386
|
-
|
|
2387
|
-
## React Components
|
|
2388
|
-
|
|
2389
|
-
- Use functional components with hooks
|
|
2390
|
-
- Follow PascalCase naming for components
|
|
2391
|
-
- Use TypeScript interfaces for props
|
|
2392
|
-
- Implement proper error boundaries
|
|
2393
|
-
|
|
2394
|
-
## Styling
|
|
2395
|
-
|
|
2396
|
-
- Use CSS modules or styled-components
|
|
2397
|
-
- Follow BEM methodology for CSS classes
|
|
2398
|
-
- Prefer flexbox and grid for layouts
|
|
2399
|
-
- Use semantic HTML elements
|
|
2400
|
-
|
|
2401
|
-
## State Management
|
|
2402
|
-
|
|
2403
|
-
- Use React hooks for local state
|
|
2404
|
-
- Consider Redux or Zustand for global state
|
|
2405
|
-
- Avoid prop drilling with context API
|
|
2406
|
-
- Keep state as close to where it's used as possible
|
|
2407
|
-
|
|
2408
|
-
## Performance
|
|
2409
|
-
|
|
2410
|
-
- Use React.memo for expensive components
|
|
2411
|
-
- Implement lazy loading for routes
|
|
2412
|
-
- Optimize images and assets
|
|
2413
|
-
- Use proper key props in lists
|
|
2414
|
-
`
|
|
2415
|
-
},
|
|
2416
|
-
{
|
|
2417
|
-
filename: "backend.md",
|
|
2418
|
-
content: `---
|
|
2419
|
-
root: false
|
|
2420
|
-
targets: ["*"]
|
|
2421
|
-
description: "Backend development rules and API guidelines"
|
|
2422
|
-
globs: ["src/api/**/*.ts", "src/services/**/*.ts", "src/models/**/*.ts"]
|
|
2423
|
-
---
|
|
2424
|
-
|
|
2425
|
-
# Backend Development Rules
|
|
2426
|
-
|
|
2427
|
-
## API Design
|
|
2428
|
-
|
|
2429
|
-
- Follow RESTful conventions
|
|
2430
|
-
- Use consistent HTTP status codes
|
|
2431
|
-
- Implement proper error handling with meaningful messages
|
|
2432
|
-
- Use API versioning when necessary
|
|
2433
|
-
|
|
2434
|
-
## Database
|
|
2435
|
-
|
|
2436
|
-
- Use proper indexing for performance
|
|
2437
|
-
- Implement database migrations
|
|
2438
|
-
- Follow naming conventions for tables and columns
|
|
2439
|
-
- Use transactions for data consistency
|
|
2440
|
-
|
|
2441
|
-
## Security
|
|
2442
|
-
|
|
2443
|
-
- Validate all input data
|
|
2444
|
-
- Use proper authentication and authorization
|
|
2445
|
-
- Implement rate limiting
|
|
2446
|
-
- Sanitize database queries to prevent SQL injection
|
|
2447
|
-
|
|
2448
|
-
## Code Organization
|
|
2449
|
-
|
|
2450
|
-
- Use service layer pattern
|
|
2451
|
-
- Implement proper logging
|
|
2452
|
-
- Use environment variables for configuration
|
|
2453
|
-
- Write comprehensive tests for business logic
|
|
2454
|
-
`
|
|
2455
|
-
}
|
|
2456
|
-
];
|
|
2457
|
-
for (const file of sampleFiles) {
|
|
2458
|
-
const filepath = (0, import_node_path19.join)(aiRulesDir, file.filename);
|
|
2459
|
-
if (!await fileExists(filepath)) {
|
|
2460
|
-
await writeFileContent(filepath, file.content);
|
|
2461
|
-
console.log(`Created ${filepath}`);
|
|
2462
|
-
} else {
|
|
2463
|
-
console.log(`Skipped ${filepath} (already exists)`);
|
|
2464
|
-
}
|
|
2409
|
+
};
|
|
2410
|
+
const filepath = (0, import_node_path19.join)(aiRulesDir, sampleFile.filename);
|
|
2411
|
+
if (!await fileExists(filepath)) {
|
|
2412
|
+
await writeFileContent(filepath, sampleFile.content);
|
|
2413
|
+
console.log(`Created ${filepath}`);
|
|
2414
|
+
} else {
|
|
2415
|
+
console.log(`Skipped ${filepath} (already exists)`);
|
|
2465
2416
|
}
|
|
2466
2417
|
}
|
|
2467
2418
|
|
|
@@ -2490,9 +2441,11 @@ async function statusCommand() {
|
|
|
2490
2441
|
for (const rule of rules) {
|
|
2491
2442
|
const targets = rule.frontmatter.targets[0] === "*" ? config.defaultTargets : rule.frontmatter.targets;
|
|
2492
2443
|
for (const target of targets) {
|
|
2493
|
-
if (target
|
|
2494
|
-
|
|
2495
|
-
|
|
2444
|
+
if (target === "copilot") targetCounts.copilot++;
|
|
2445
|
+
else if (target === "cursor") targetCounts.cursor++;
|
|
2446
|
+
else if (target === "cline") targetCounts.cline++;
|
|
2447
|
+
else if (target === "claudecode") targetCounts.claudecode++;
|
|
2448
|
+
else if (target === "roo") targetCounts.roo++;
|
|
2496
2449
|
}
|
|
2497
2450
|
}
|
|
2498
2451
|
console.log("\n\u{1F3AF} Target tool coverage:");
|
|
@@ -2598,7 +2551,7 @@ async function watchCommand() {
|
|
|
2598
2551
|
|
|
2599
2552
|
// src/cli/index.ts
|
|
2600
2553
|
var program = new import_commander.Command();
|
|
2601
|
-
program.name("rulesync").description("Unified AI rules management CLI tool").version("0.
|
|
2554
|
+
program.name("rulesync").description("Unified AI rules management CLI tool").version("0.45.0");
|
|
2602
2555
|
program.command("init").description("Initialize rulesync in current directory").action(initCommand);
|
|
2603
2556
|
program.command("add <filename>").description("Add a new rule file").action(addCommand);
|
|
2604
2557
|
program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);
|