rulesync 0.42.0 → 0.44.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-HMMPZV7X.js → chunk-22GWBUIP.js} +15 -9
- package/dist/{chunk-X3FEMISQ.js → chunk-BD37M3ZH.js} +2 -2
- package/dist/{chunk-2SPL7QTK.js → chunk-DCSO5MY7.js} +2 -2
- package/dist/{chunk-D3YGI36J.js → chunk-FAZT3ILF.js} +8 -7
- package/dist/chunk-I5XVU7C6.js +38 -0
- package/dist/{chunk-3NRSCDLQ.js → chunk-PJUNIIF4.js} +7 -11
- package/dist/{chunk-SXEFNT27.js → chunk-ZORSPGDD.js} +1 -1
- package/dist/{claude-3YGZIO5F.js → claudecode-KSK2BEI7.js} +2 -2
- package/dist/{cline-ERYW7TOO.js → cline-T5YVGYBF.js} +2 -2
- package/dist/{copilot-NLSI3ID7.js → copilot-UDCWNUAH.js} +2 -2
- package/dist/{cursor-CX55HMO4.js → cursor-KPV6OVST.js} +2 -2
- package/dist/{geminicli-XHQR4RCQ.js → geminicli-2DC5F34J.js} +2 -2
- package/dist/index.cjs +271 -254
- package/dist/index.js +239 -206
- package/dist/{roo-OKE7XF3B.js → roo-DRA2SU4L.js} +2 -2
- package/package.json +12 -5
- package/dist/chunk-6YNGMPAL.js +0 -56
package/dist/index.cjs
CHANGED
|
@@ -26,44 +26,23 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
26
26
|
mod
|
|
27
27
|
));
|
|
28
28
|
|
|
29
|
-
// src/
|
|
30
|
-
var
|
|
31
|
-
var
|
|
32
|
-
"src/
|
|
29
|
+
// src/types/tool-targets.ts
|
|
30
|
+
var import_v4_mini, ToolTargetSchema, ToolTargetsSchema, WildcardTargetSchema, RulesyncTargetsSchema;
|
|
31
|
+
var init_tool_targets = __esm({
|
|
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",
|
|
39
39
|
"claudecode",
|
|
40
|
-
"claude",
|
|
41
40
|
"roo",
|
|
42
41
|
"geminicli"
|
|
43
42
|
]);
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
RulesyncTargetsSchema =
|
|
47
|
-
McpTransportTypeSchema = import_zod.z.enum(["stdio", "sse", "http"]);
|
|
48
|
-
McpServerBaseSchema = import_zod.z.object({
|
|
49
|
-
command: import_zod.z.string().optional(),
|
|
50
|
-
args: import_zod.z.array(import_zod.z.string()).optional(),
|
|
51
|
-
url: import_zod.z.string().optional(),
|
|
52
|
-
httpUrl: import_zod.z.string().optional(),
|
|
53
|
-
env: import_zod.z.record(import_zod.z.string()).optional(),
|
|
54
|
-
disabled: import_zod.z.boolean().optional(),
|
|
55
|
-
networkTimeout: import_zod.z.number().optional(),
|
|
56
|
-
timeout: import_zod.z.number().optional(),
|
|
57
|
-
trust: import_zod.z.boolean().optional(),
|
|
58
|
-
cwd: import_zod.z.string().optional(),
|
|
59
|
-
transport: McpTransportTypeSchema.optional(),
|
|
60
|
-
type: import_zod.z.enum(["sse", "streamable-http"]).optional(),
|
|
61
|
-
alwaysAllow: import_zod.z.array(import_zod.z.string()).optional(),
|
|
62
|
-
tools: import_zod.z.array(import_zod.z.string()).optional()
|
|
63
|
-
});
|
|
64
|
-
RulesyncMcpServerSchema = McpServerBaseSchema.extend({
|
|
65
|
-
targets: RulesyncTargetsSchema.optional()
|
|
66
|
-
});
|
|
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]);
|
|
67
46
|
}
|
|
68
47
|
});
|
|
69
48
|
|
|
@@ -87,17 +66,17 @@ function shouldIncludeServer(server, targetTool) {
|
|
|
87
66
|
var init_mcp_helpers = __esm({
|
|
88
67
|
"src/utils/mcp-helpers.ts"() {
|
|
89
68
|
"use strict";
|
|
90
|
-
|
|
69
|
+
init_tool_targets();
|
|
91
70
|
}
|
|
92
71
|
});
|
|
93
72
|
|
|
94
|
-
// src/generators/mcp/
|
|
73
|
+
// src/generators/mcp/claudecode.ts
|
|
95
74
|
function generateClaudeMcp(config) {
|
|
96
75
|
const claudeSettings = {
|
|
97
76
|
mcpServers: {}
|
|
98
77
|
};
|
|
99
78
|
const shouldInclude = (server) => {
|
|
100
|
-
return shouldIncludeServer(server, "
|
|
79
|
+
return shouldIncludeServer(server, "claudecode");
|
|
101
80
|
};
|
|
102
81
|
for (const [serverName, server] of Object.entries(config.mcpServers)) {
|
|
103
82
|
if (!shouldInclude(server)) continue;
|
|
@@ -119,12 +98,14 @@ function generateClaudeMcp(config) {
|
|
|
119
98
|
if (server.env) {
|
|
120
99
|
claudeServer.env = server.env;
|
|
121
100
|
}
|
|
122
|
-
claudeSettings.mcpServers
|
|
101
|
+
if (claudeSettings.mcpServers) {
|
|
102
|
+
claudeSettings.mcpServers[serverName] = claudeServer;
|
|
103
|
+
}
|
|
123
104
|
}
|
|
124
105
|
return JSON.stringify(claudeSettings, null, 2);
|
|
125
106
|
}
|
|
126
|
-
var
|
|
127
|
-
"src/generators/mcp/
|
|
107
|
+
var init_claudecode = __esm({
|
|
108
|
+
"src/generators/mcp/claudecode.ts"() {
|
|
128
109
|
"use strict";
|
|
129
110
|
init_mcp_helpers();
|
|
130
111
|
}
|
|
@@ -370,9 +351,10 @@ var import_commander = require("commander");
|
|
|
370
351
|
|
|
371
352
|
// src/cli/commands/add.ts
|
|
372
353
|
var import_promises = require("fs/promises");
|
|
373
|
-
var
|
|
354
|
+
var path = __toESM(require("path"), 1);
|
|
374
355
|
|
|
375
356
|
// src/utils/config.ts
|
|
357
|
+
init_tool_targets();
|
|
376
358
|
function getDefaultConfig() {
|
|
377
359
|
return {
|
|
378
360
|
aiRulesDir: ".rulesync",
|
|
@@ -381,19 +363,19 @@ function getDefaultConfig() {
|
|
|
381
363
|
cursor: ".cursor/rules",
|
|
382
364
|
cline: ".clinerules",
|
|
383
365
|
claudecode: ".",
|
|
384
|
-
claude: ".",
|
|
385
366
|
roo: ".roo/rules",
|
|
386
367
|
geminicli: ".gemini/memories"
|
|
387
368
|
},
|
|
388
369
|
watchEnabled: false,
|
|
389
|
-
defaultTargets: ["copilot", "cursor", "cline", "claudecode", "
|
|
370
|
+
defaultTargets: ["copilot", "cursor", "cline", "claudecode", "roo", "geminicli"]
|
|
390
371
|
};
|
|
391
372
|
}
|
|
392
373
|
function resolveTargets(targets, config) {
|
|
393
|
-
if (targets[0] === "*") {
|
|
374
|
+
if (targets.length === 1 && targets[0] === "*") {
|
|
394
375
|
return config.defaultTargets;
|
|
395
376
|
}
|
|
396
|
-
|
|
377
|
+
const validatedTargets = ToolTargetsSchema.parse(targets);
|
|
378
|
+
return validatedTargets;
|
|
397
379
|
}
|
|
398
380
|
|
|
399
381
|
// src/cli/commands/add.ts
|
|
@@ -418,7 +400,7 @@ async function addCommand(filename) {
|
|
|
418
400
|
const config = getDefaultConfig();
|
|
419
401
|
const sanitizedFilename = sanitizeFilename(filename);
|
|
420
402
|
const rulesDir = config.aiRulesDir;
|
|
421
|
-
const filePath =
|
|
403
|
+
const filePath = path.join(rulesDir, `${sanitizedFilename}.md`);
|
|
422
404
|
await (0, import_promises.mkdir)(rulesDir, { recursive: true });
|
|
423
405
|
const template = generateRuleTemplate(sanitizedFilename);
|
|
424
406
|
await (0, import_promises.writeFile)(filePath, template, "utf8");
|
|
@@ -433,15 +415,26 @@ async function addCommand(filename) {
|
|
|
433
415
|
}
|
|
434
416
|
|
|
435
417
|
// src/generators/rules/claudecode.ts
|
|
436
|
-
var
|
|
418
|
+
var import_node_path4 = require("path");
|
|
419
|
+
|
|
420
|
+
// src/types/claudecode.ts
|
|
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
|
+
)
|
|
429
|
+
});
|
|
437
430
|
|
|
438
431
|
// src/utils/file.ts
|
|
439
432
|
var import_promises3 = require("fs/promises");
|
|
440
|
-
var
|
|
433
|
+
var import_node_path3 = require("path");
|
|
441
434
|
|
|
442
435
|
// src/utils/file-ops.ts
|
|
443
436
|
var import_promises2 = require("fs/promises");
|
|
444
|
-
var
|
|
437
|
+
var import_node_path = require("path");
|
|
445
438
|
async function ensureDir(dirPath) {
|
|
446
439
|
try {
|
|
447
440
|
await (0, import_promises2.stat)(dirPath);
|
|
@@ -453,7 +446,7 @@ async function readFileContent(filepath) {
|
|
|
453
446
|
return (0, import_promises2.readFile)(filepath, "utf-8");
|
|
454
447
|
}
|
|
455
448
|
async function writeFileContent(filepath, content) {
|
|
456
|
-
await ensureDir((0,
|
|
449
|
+
await ensureDir((0, import_node_path.dirname)(filepath));
|
|
457
450
|
await (0, import_promises2.writeFile)(filepath, content, "utf-8");
|
|
458
451
|
}
|
|
459
452
|
async function fileExists(filepath) {
|
|
@@ -466,14 +459,14 @@ async function fileExists(filepath) {
|
|
|
466
459
|
}
|
|
467
460
|
|
|
468
461
|
// src/utils/ignore.ts
|
|
469
|
-
var
|
|
462
|
+
var import_node_path2 = require("path");
|
|
470
463
|
var import_micromatch = __toESM(require("micromatch"), 1);
|
|
471
464
|
var cachedIgnorePatterns = null;
|
|
472
465
|
async function loadIgnorePatterns(baseDir = process.cwd()) {
|
|
473
466
|
if (cachedIgnorePatterns) {
|
|
474
467
|
return cachedIgnorePatterns;
|
|
475
468
|
}
|
|
476
|
-
const ignorePath = (0,
|
|
469
|
+
const ignorePath = (0, import_node_path2.join)(baseDir, ".rulesyncignore");
|
|
477
470
|
if (!await fileExists(ignorePath)) {
|
|
478
471
|
cachedIgnorePatterns = { patterns: [] };
|
|
479
472
|
return cachedIgnorePatterns;
|
|
@@ -520,7 +513,7 @@ function filterIgnoredFiles(files, ignorePatterns) {
|
|
|
520
513
|
async function findFiles(dir, extension = ".md", ignorePatterns) {
|
|
521
514
|
try {
|
|
522
515
|
const files = await (0, import_promises3.readdir)(dir);
|
|
523
|
-
const filtered = files.filter((file) => file.endsWith(extension)).map((file) => (0,
|
|
516
|
+
const filtered = files.filter((file) => file.endsWith(extension)).map((file) => (0, import_node_path3.join)(dir, file));
|
|
524
517
|
if (ignorePatterns && ignorePatterns.length > 0) {
|
|
525
518
|
return filterIgnoredFiles(filtered, ignorePatterns);
|
|
526
519
|
}
|
|
@@ -569,23 +562,23 @@ async function generateClaudecodeConfig(rules, config, baseDir) {
|
|
|
569
562
|
const rootRules = rules.filter((r) => r.frontmatter.root === true);
|
|
570
563
|
const detailRules = rules.filter((r) => r.frontmatter.root === false);
|
|
571
564
|
const claudeMdContent = generateClaudeMarkdown(rootRules, detailRules);
|
|
572
|
-
const claudeOutputDir = baseDir ? (0,
|
|
565
|
+
const claudeOutputDir = baseDir ? (0, import_node_path4.join)(baseDir, config.outputPaths.claudecode) : config.outputPaths.claudecode;
|
|
573
566
|
outputs.push({
|
|
574
567
|
tool: "claudecode",
|
|
575
|
-
filepath: (0,
|
|
568
|
+
filepath: (0, import_node_path4.join)(claudeOutputDir, "CLAUDE.md"),
|
|
576
569
|
content: claudeMdContent
|
|
577
570
|
});
|
|
578
571
|
for (const rule of detailRules) {
|
|
579
572
|
const memoryContent = generateMemoryFile(rule);
|
|
580
573
|
outputs.push({
|
|
581
574
|
tool: "claudecode",
|
|
582
|
-
filepath: (0,
|
|
575
|
+
filepath: (0, import_node_path4.join)(claudeOutputDir, ".claude", "memories", `${rule.filename}.md`),
|
|
583
576
|
content: memoryContent
|
|
584
577
|
});
|
|
585
578
|
}
|
|
586
579
|
const ignorePatterns = await loadIgnorePatterns(baseDir);
|
|
587
580
|
if (ignorePatterns.patterns.length > 0) {
|
|
588
|
-
const settingsPath = baseDir ? (0,
|
|
581
|
+
const settingsPath = baseDir ? (0, import_node_path4.join)(baseDir, ".claude", "settings.json") : (0, import_node_path4.join)(".claude", "settings.json");
|
|
589
582
|
await updateClaudeSettings(settingsPath, ignorePatterns.patterns);
|
|
590
583
|
}
|
|
591
584
|
return outputs;
|
|
@@ -595,12 +588,10 @@ function generateClaudeMarkdown(rootRules, detailRules) {
|
|
|
595
588
|
if (detailRules.length > 0) {
|
|
596
589
|
lines.push("Please also reference the following documents as needed:");
|
|
597
590
|
lines.push("");
|
|
598
|
-
lines.push("| Document | Description | File Patterns |");
|
|
599
|
-
lines.push("|----------|-------------|---------------|");
|
|
600
591
|
for (const rule of detailRules) {
|
|
601
|
-
const globsText = rule.frontmatter.globs.length > 0 ? rule.frontmatter.globs.join(", ") : "
|
|
592
|
+
const globsText = rule.frontmatter.globs.length > 0 ? rule.frontmatter.globs.join(", ") : "";
|
|
602
593
|
lines.push(
|
|
603
|
-
|
|
594
|
+
`@.claude/memories/${rule.filename}.md ${rule.frontmatter.description} ${globsText}`.trim()
|
|
604
595
|
);
|
|
605
596
|
}
|
|
606
597
|
lines.push("");
|
|
@@ -617,51 +608,46 @@ function generateMemoryFile(rule) {
|
|
|
617
608
|
return rule.content.trim();
|
|
618
609
|
}
|
|
619
610
|
async function updateClaudeSettings(settingsPath, ignorePatterns) {
|
|
620
|
-
let
|
|
611
|
+
let rawSettings = {};
|
|
621
612
|
if (await fileExists(settingsPath)) {
|
|
622
613
|
try {
|
|
623
614
|
const content = await readFileContent(settingsPath);
|
|
624
|
-
|
|
615
|
+
rawSettings = JSON.parse(content);
|
|
625
616
|
} catch {
|
|
626
617
|
console.warn(`Failed to parse existing ${settingsPath}, creating new settings`);
|
|
627
|
-
|
|
618
|
+
rawSettings = {};
|
|
628
619
|
}
|
|
629
620
|
}
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
settingsObj.permissions = {};
|
|
621
|
+
const parseResult = ClaudeSettingsSchema.safeParse(rawSettings);
|
|
622
|
+
const settings = parseResult.success ? parseResult.data : ClaudeSettingsSchema.parse({});
|
|
623
|
+
const readDenyRules = ignorePatterns.map((pattern) => `Read(${pattern})`);
|
|
624
|
+
if (!settings.permissions) {
|
|
625
|
+
settings.permissions = { deny: [] };
|
|
636
626
|
}
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
permissions.deny = [];
|
|
627
|
+
if (!Array.isArray(settings.permissions.deny)) {
|
|
628
|
+
settings.permissions.deny = [];
|
|
640
629
|
}
|
|
641
|
-
const
|
|
642
|
-
const denyArray = permissions.deny;
|
|
643
|
-
const filteredDeny = denyArray.filter((rule) => {
|
|
644
|
-
if (typeof rule !== "string") return false;
|
|
630
|
+
const filteredDeny = settings.permissions.deny.filter((rule) => {
|
|
645
631
|
if (!rule.startsWith("Read(")) return true;
|
|
646
632
|
const match = rule.match(/^Read\((.*)\)$/);
|
|
647
633
|
if (!match) return true;
|
|
648
634
|
return !ignorePatterns.includes(match[1] ?? "");
|
|
649
635
|
});
|
|
650
636
|
filteredDeny.push(...readDenyRules);
|
|
651
|
-
permissions.deny =
|
|
652
|
-
const jsonContent = JSON.stringify(
|
|
637
|
+
settings.permissions.deny = Array.from(new Set(filteredDeny));
|
|
638
|
+
const jsonContent = JSON.stringify(settings, null, 2);
|
|
653
639
|
await writeFileContent(settingsPath, jsonContent);
|
|
654
640
|
console.log(`\u2705 Updated Claude Code settings: ${settingsPath}`);
|
|
655
641
|
}
|
|
656
642
|
|
|
657
643
|
// src/generators/rules/cline.ts
|
|
658
|
-
var
|
|
644
|
+
var import_node_path5 = require("path");
|
|
659
645
|
async function generateClineConfig(rules, config, baseDir) {
|
|
660
646
|
const outputs = [];
|
|
661
647
|
for (const rule of rules) {
|
|
662
648
|
const content = generateClineMarkdown(rule);
|
|
663
|
-
const outputDir = baseDir ? (0,
|
|
664
|
-
const filepath = (0,
|
|
649
|
+
const outputDir = baseDir ? (0, import_node_path5.join)(baseDir, config.outputPaths.cline) : config.outputPaths.cline;
|
|
650
|
+
const filepath = (0, import_node_path5.join)(outputDir, `${rule.filename}.md`);
|
|
665
651
|
outputs.push({
|
|
666
652
|
tool: "cline",
|
|
667
653
|
filepath,
|
|
@@ -670,7 +656,7 @@ async function generateClineConfig(rules, config, baseDir) {
|
|
|
670
656
|
}
|
|
671
657
|
const ignorePatterns = await loadIgnorePatterns(baseDir);
|
|
672
658
|
if (ignorePatterns.patterns.length > 0) {
|
|
673
|
-
const clineIgnorePath = baseDir ? (0,
|
|
659
|
+
const clineIgnorePath = baseDir ? (0, import_node_path5.join)(baseDir, ".clineignore") : ".clineignore";
|
|
674
660
|
const clineIgnoreContent = generateClineIgnore(ignorePatterns.patterns);
|
|
675
661
|
outputs.push({
|
|
676
662
|
tool: "cline",
|
|
@@ -694,14 +680,14 @@ function generateClineIgnore(patterns) {
|
|
|
694
680
|
}
|
|
695
681
|
|
|
696
682
|
// src/generators/rules/copilot.ts
|
|
697
|
-
var
|
|
683
|
+
var import_node_path6 = require("path");
|
|
698
684
|
async function generateCopilotConfig(rules, config, baseDir) {
|
|
699
685
|
const outputs = [];
|
|
700
686
|
for (const rule of rules) {
|
|
701
687
|
const content = generateCopilotMarkdown(rule);
|
|
702
688
|
const baseFilename = rule.filename.replace(/\.md$/, "");
|
|
703
|
-
const outputDir = baseDir ? (0,
|
|
704
|
-
const filepath = (0,
|
|
689
|
+
const outputDir = baseDir ? (0, import_node_path6.join)(baseDir, config.outputPaths.copilot) : config.outputPaths.copilot;
|
|
690
|
+
const filepath = (0, import_node_path6.join)(outputDir, `${baseFilename}.instructions.md`);
|
|
705
691
|
outputs.push({
|
|
706
692
|
tool: "copilot",
|
|
707
693
|
filepath,
|
|
@@ -710,7 +696,7 @@ async function generateCopilotConfig(rules, config, baseDir) {
|
|
|
710
696
|
}
|
|
711
697
|
const ignorePatterns = await loadIgnorePatterns(baseDir);
|
|
712
698
|
if (ignorePatterns.patterns.length > 0) {
|
|
713
|
-
const copilotIgnorePath = baseDir ? (0,
|
|
699
|
+
const copilotIgnorePath = baseDir ? (0, import_node_path6.join)(baseDir, ".copilotignore") : ".copilotignore";
|
|
714
700
|
const copilotIgnoreContent = generateCopilotIgnore(ignorePatterns.patterns);
|
|
715
701
|
outputs.push({
|
|
716
702
|
tool: "copilot",
|
|
@@ -746,13 +732,13 @@ function generateCopilotIgnore(patterns) {
|
|
|
746
732
|
}
|
|
747
733
|
|
|
748
734
|
// src/generators/rules/cursor.ts
|
|
749
|
-
var
|
|
735
|
+
var import_node_path7 = require("path");
|
|
750
736
|
async function generateCursorConfig(rules, config, baseDir) {
|
|
751
737
|
const outputs = [];
|
|
752
738
|
for (const rule of rules) {
|
|
753
739
|
const content = generateCursorMarkdown(rule);
|
|
754
|
-
const outputDir = baseDir ? (0,
|
|
755
|
-
const filepath = (0,
|
|
740
|
+
const outputDir = baseDir ? (0, import_node_path7.join)(baseDir, config.outputPaths.cursor) : config.outputPaths.cursor;
|
|
741
|
+
const filepath = (0, import_node_path7.join)(outputDir, `${rule.filename}.mdc`);
|
|
756
742
|
outputs.push({
|
|
757
743
|
tool: "cursor",
|
|
758
744
|
filepath,
|
|
@@ -761,7 +747,7 @@ async function generateCursorConfig(rules, config, baseDir) {
|
|
|
761
747
|
}
|
|
762
748
|
const ignorePatterns = await loadIgnorePatterns(baseDir);
|
|
763
749
|
if (ignorePatterns.patterns.length > 0) {
|
|
764
|
-
const cursorIgnorePath = baseDir ? (0,
|
|
750
|
+
const cursorIgnorePath = baseDir ? (0, import_node_path7.join)(baseDir, ".cursorignore") : ".cursorignore";
|
|
765
751
|
const cursorIgnoreContent = generateCursorIgnore(ignorePatterns.patterns);
|
|
766
752
|
outputs.push({
|
|
767
753
|
tool: "cursor",
|
|
@@ -834,15 +820,15 @@ function generateCursorIgnore(patterns) {
|
|
|
834
820
|
}
|
|
835
821
|
|
|
836
822
|
// src/generators/rules/geminicli.ts
|
|
837
|
-
var
|
|
823
|
+
var import_node_path8 = require("path");
|
|
838
824
|
async function generateGeminiConfig(rules, config, baseDir) {
|
|
839
825
|
const outputs = [];
|
|
840
826
|
const rootRule = rules.find((rule) => rule.frontmatter.root === true);
|
|
841
827
|
const memoryRules = rules.filter((rule) => rule.frontmatter.root === false);
|
|
842
828
|
for (const rule of memoryRules) {
|
|
843
829
|
const content = generateGeminiMemoryMarkdown(rule);
|
|
844
|
-
const outputDir = baseDir ? (0,
|
|
845
|
-
const filepath = (0,
|
|
830
|
+
const outputDir = baseDir ? (0, import_node_path8.join)(baseDir, config.outputPaths.geminicli) : config.outputPaths.geminicli;
|
|
831
|
+
const filepath = (0, import_node_path8.join)(outputDir, `${rule.filename}.md`);
|
|
846
832
|
outputs.push({
|
|
847
833
|
tool: "geminicli",
|
|
848
834
|
filepath,
|
|
@@ -850,7 +836,7 @@ async function generateGeminiConfig(rules, config, baseDir) {
|
|
|
850
836
|
});
|
|
851
837
|
}
|
|
852
838
|
const rootContent = generateGeminiRootMarkdown(rootRule, memoryRules, baseDir);
|
|
853
|
-
const rootFilepath = baseDir ? (0,
|
|
839
|
+
const rootFilepath = baseDir ? (0, import_node_path8.join)(baseDir, "GEMINI.md") : "GEMINI.md";
|
|
854
840
|
outputs.push({
|
|
855
841
|
tool: "geminicli",
|
|
856
842
|
filepath: rootFilepath,
|
|
@@ -858,7 +844,7 @@ async function generateGeminiConfig(rules, config, baseDir) {
|
|
|
858
844
|
});
|
|
859
845
|
const ignorePatterns = await loadIgnorePatterns(baseDir);
|
|
860
846
|
if (ignorePatterns.patterns.length > 0) {
|
|
861
|
-
const aiexcludePath = baseDir ? (0,
|
|
847
|
+
const aiexcludePath = baseDir ? (0, import_node_path8.join)(baseDir, ".aiexclude") : ".aiexclude";
|
|
862
848
|
const aiexcludeContent = generateAiexclude(ignorePatterns.patterns);
|
|
863
849
|
outputs.push({
|
|
864
850
|
tool: "geminicli",
|
|
@@ -906,13 +892,13 @@ function generateAiexclude(patterns) {
|
|
|
906
892
|
}
|
|
907
893
|
|
|
908
894
|
// src/generators/rules/roo.ts
|
|
909
|
-
var
|
|
895
|
+
var import_node_path9 = require("path");
|
|
910
896
|
async function generateRooConfig(rules, config, baseDir) {
|
|
911
897
|
const outputs = [];
|
|
912
898
|
for (const rule of rules) {
|
|
913
899
|
const content = generateRooMarkdown(rule);
|
|
914
|
-
const outputDir = baseDir ? (0,
|
|
915
|
-
const filepath = (0,
|
|
900
|
+
const outputDir = baseDir ? (0, import_node_path9.join)(baseDir, config.outputPaths.roo) : config.outputPaths.roo;
|
|
901
|
+
const filepath = (0, import_node_path9.join)(outputDir, `${rule.filename}.md`);
|
|
916
902
|
outputs.push({
|
|
917
903
|
tool: "roo",
|
|
918
904
|
filepath,
|
|
@@ -921,7 +907,7 @@ async function generateRooConfig(rules, config, baseDir) {
|
|
|
921
907
|
}
|
|
922
908
|
const ignorePatterns = await loadIgnorePatterns(baseDir);
|
|
923
909
|
if (ignorePatterns.patterns.length > 0) {
|
|
924
|
-
const rooIgnorePath = baseDir ? (0,
|
|
910
|
+
const rooIgnorePath = baseDir ? (0, import_node_path9.join)(baseDir, ".rooignore") : ".rooignore";
|
|
925
911
|
const rooIgnoreContent = generateRooIgnore(ignorePatterns.patterns);
|
|
926
912
|
outputs.push({
|
|
927
913
|
tool: "roo",
|
|
@@ -994,8 +980,80 @@ async function generateForTool(tool, rules, config, baseDir) {
|
|
|
994
980
|
}
|
|
995
981
|
|
|
996
982
|
// src/core/parser.ts
|
|
997
|
-
var
|
|
983
|
+
var import_node_path10 = require("path");
|
|
998
984
|
var import_gray_matter = __toESM(require("gray-matter"), 1);
|
|
985
|
+
|
|
986
|
+
// src/types/config.ts
|
|
987
|
+
var import_v4_mini3 = require("zod/v4-mini");
|
|
988
|
+
init_tool_targets();
|
|
989
|
+
var ConfigSchema = import_v4_mini3.z.object({
|
|
990
|
+
aiRulesDir: import_v4_mini3.z.string(),
|
|
991
|
+
outputPaths: import_v4_mini3.z.record(ToolTargetSchema, import_v4_mini3.z.string()),
|
|
992
|
+
watchEnabled: import_v4_mini3.z.boolean(),
|
|
993
|
+
defaultTargets: ToolTargetsSchema
|
|
994
|
+
});
|
|
995
|
+
|
|
996
|
+
// src/types/mcp.ts
|
|
997
|
+
var import_v4_mini4 = require("zod/v4-mini");
|
|
998
|
+
init_tool_targets();
|
|
999
|
+
var McpTransportTypeSchema = import_v4_mini4.z.enum(["stdio", "sse", "http"]);
|
|
1000
|
+
var McpServerBaseSchema = import_v4_mini4.z.object({
|
|
1001
|
+
command: import_v4_mini4.z.optional(import_v4_mini4.z.string()),
|
|
1002
|
+
args: import_v4_mini4.z.optional(import_v4_mini4.z.array(import_v4_mini4.z.string())),
|
|
1003
|
+
url: import_v4_mini4.z.optional(import_v4_mini4.z.string()),
|
|
1004
|
+
httpUrl: import_v4_mini4.z.optional(import_v4_mini4.z.string()),
|
|
1005
|
+
env: import_v4_mini4.z.optional(import_v4_mini4.z.record(import_v4_mini4.z.string(), import_v4_mini4.z.string())),
|
|
1006
|
+
disabled: import_v4_mini4.z.optional(import_v4_mini4.z.boolean()),
|
|
1007
|
+
networkTimeout: import_v4_mini4.z.optional(import_v4_mini4.z.number()),
|
|
1008
|
+
timeout: import_v4_mini4.z.optional(import_v4_mini4.z.number()),
|
|
1009
|
+
trust: import_v4_mini4.z.optional(import_v4_mini4.z.boolean()),
|
|
1010
|
+
cwd: import_v4_mini4.z.optional(import_v4_mini4.z.string()),
|
|
1011
|
+
transport: import_v4_mini4.z.optional(McpTransportTypeSchema),
|
|
1012
|
+
type: import_v4_mini4.z.optional(import_v4_mini4.z.enum(["sse", "streamable-http"])),
|
|
1013
|
+
alwaysAllow: import_v4_mini4.z.optional(import_v4_mini4.z.array(import_v4_mini4.z.string())),
|
|
1014
|
+
tools: import_v4_mini4.z.optional(import_v4_mini4.z.array(import_v4_mini4.z.string()))
|
|
1015
|
+
});
|
|
1016
|
+
var RulesyncMcpServerSchema = import_v4_mini4.z.extend(McpServerBaseSchema, {
|
|
1017
|
+
targets: import_v4_mini4.z.optional(RulesyncTargetsSchema)
|
|
1018
|
+
});
|
|
1019
|
+
var McpConfigSchema = import_v4_mini4.z.object({
|
|
1020
|
+
mcpServers: import_v4_mini4.z.record(import_v4_mini4.z.string(), McpServerBaseSchema)
|
|
1021
|
+
});
|
|
1022
|
+
var RulesyncMcpConfigSchema = import_v4_mini4.z.object({
|
|
1023
|
+
mcpServers: import_v4_mini4.z.record(import_v4_mini4.z.string(), RulesyncMcpServerSchema)
|
|
1024
|
+
});
|
|
1025
|
+
|
|
1026
|
+
// src/types/rules.ts
|
|
1027
|
+
var import_v4_mini5 = require("zod/v4-mini");
|
|
1028
|
+
init_tool_targets();
|
|
1029
|
+
var RuleFrontmatterSchema = import_v4_mini5.z.object({
|
|
1030
|
+
root: import_v4_mini5.z.boolean(),
|
|
1031
|
+
targets: RulesyncTargetsSchema,
|
|
1032
|
+
description: import_v4_mini5.z.string(),
|
|
1033
|
+
globs: import_v4_mini5.z.array(import_v4_mini5.z.string()),
|
|
1034
|
+
cursorRuleType: import_v4_mini5.z.optional(import_v4_mini5.z.enum(["always", "manual", "specificFiles", "intelligently"]))
|
|
1035
|
+
});
|
|
1036
|
+
var ParsedRuleSchema = import_v4_mini5.z.object({
|
|
1037
|
+
frontmatter: RuleFrontmatterSchema,
|
|
1038
|
+
content: import_v4_mini5.z.string(),
|
|
1039
|
+
filename: import_v4_mini5.z.string(),
|
|
1040
|
+
filepath: import_v4_mini5.z.string()
|
|
1041
|
+
});
|
|
1042
|
+
var GeneratedOutputSchema = import_v4_mini5.z.object({
|
|
1043
|
+
tool: ToolTargetSchema,
|
|
1044
|
+
filepath: import_v4_mini5.z.string(),
|
|
1045
|
+
content: import_v4_mini5.z.string()
|
|
1046
|
+
});
|
|
1047
|
+
var GenerateOptionsSchema = import_v4_mini5.z.object({
|
|
1048
|
+
targetTools: import_v4_mini5.z.optional(ToolTargetsSchema),
|
|
1049
|
+
outputDir: import_v4_mini5.z.optional(import_v4_mini5.z.string()),
|
|
1050
|
+
watch: import_v4_mini5.z.optional(import_v4_mini5.z.boolean())
|
|
1051
|
+
});
|
|
1052
|
+
|
|
1053
|
+
// src/types/index.ts
|
|
1054
|
+
init_tool_targets();
|
|
1055
|
+
|
|
1056
|
+
// src/core/parser.ts
|
|
999
1057
|
async function parseRulesFromDirectory(aiRulesDir) {
|
|
1000
1058
|
const ignorePatterns = await loadIgnorePatterns();
|
|
1001
1059
|
const ruleFiles = await findFiles(aiRulesDir, ".md", ignorePatterns.patterns);
|
|
@@ -1029,84 +1087,20 @@ ${errors.join("\n")}`);
|
|
|
1029
1087
|
async function parseRuleFile(filepath) {
|
|
1030
1088
|
const content = await readFileContent(filepath);
|
|
1031
1089
|
const parsed = (0, import_gray_matter.default)(content);
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
}
|
|
1042
|
-
function validateFrontmatter(data, filepath) {
|
|
1043
|
-
if (!data || typeof data !== "object") {
|
|
1044
|
-
if (!data) {
|
|
1045
|
-
throw new Error(
|
|
1046
|
-
`Missing frontmatter in ${filepath}: file must contain YAML frontmatter with required fields (root, targets, description, globs)`
|
|
1047
|
-
);
|
|
1048
|
-
}
|
|
1049
|
-
throw new Error(`Invalid frontmatter in ${filepath}: frontmatter must be a valid YAML object`);
|
|
1050
|
-
}
|
|
1051
|
-
const obj = data;
|
|
1052
|
-
if (Object.keys(obj).length === 0) {
|
|
1053
|
-
throw new Error(
|
|
1054
|
-
`Missing frontmatter in ${filepath}: file must contain YAML frontmatter with required fields (root, targets, description, globs)`
|
|
1055
|
-
);
|
|
1056
|
-
}
|
|
1057
|
-
if (obj.root === void 0) {
|
|
1058
|
-
throw new Error(`Missing required field "root" in ${filepath}: must be true or false`);
|
|
1059
|
-
}
|
|
1060
|
-
if (typeof obj.root !== "boolean") {
|
|
1061
|
-
throw new Error(
|
|
1062
|
-
`Invalid "root" field in ${filepath}: must be a boolean (true or false), got ${typeof obj.root}`
|
|
1063
|
-
);
|
|
1064
|
-
}
|
|
1065
|
-
if (obj.targets === void 0) {
|
|
1066
|
-
throw new Error(
|
|
1067
|
-
`Missing required field "targets" in ${filepath}: must be an array like ["*"] or ["copilot", "cursor"]`
|
|
1068
|
-
);
|
|
1069
|
-
}
|
|
1070
|
-
if (!Array.isArray(obj.targets)) {
|
|
1071
|
-
throw new Error(
|
|
1072
|
-
`Invalid "targets" field in ${filepath}: must be an array, got ${typeof obj.targets}`
|
|
1073
|
-
);
|
|
1074
|
-
}
|
|
1075
|
-
const validTargets = ["copilot", "cursor", "cline", "claudecode", "roo", "geminicli", "*"];
|
|
1076
|
-
for (const target of obj.targets) {
|
|
1077
|
-
if (typeof target !== "string" || !validTargets.includes(target)) {
|
|
1078
|
-
throw new Error(
|
|
1079
|
-
`Invalid target "${target}" in ${filepath}: must be one of ${validTargets.join(", ")}`
|
|
1080
|
-
);
|
|
1081
|
-
}
|
|
1082
|
-
}
|
|
1083
|
-
if (obj.description === void 0) {
|
|
1084
|
-
throw new Error(
|
|
1085
|
-
`Missing required field "description" in ${filepath}: must be a descriptive string`
|
|
1086
|
-
);
|
|
1087
|
-
}
|
|
1088
|
-
if (typeof obj.description !== "string") {
|
|
1089
|
-
throw new Error(
|
|
1090
|
-
`Invalid "description" field in ${filepath}: must be a string, got ${typeof obj.description}`
|
|
1091
|
-
);
|
|
1092
|
-
}
|
|
1093
|
-
if (obj.globs === void 0) {
|
|
1094
|
-
throw new Error(
|
|
1095
|
-
`Missing required field "globs" in ${filepath}: must be an array of file patterns like ["**/*.ts"]`
|
|
1096
|
-
);
|
|
1097
|
-
}
|
|
1098
|
-
if (!Array.isArray(obj.globs)) {
|
|
1090
|
+
try {
|
|
1091
|
+
const frontmatter = RuleFrontmatterSchema.parse(parsed.data);
|
|
1092
|
+
const filename = (0, import_node_path10.basename)(filepath, ".md");
|
|
1093
|
+
return {
|
|
1094
|
+
frontmatter,
|
|
1095
|
+
content: parsed.content,
|
|
1096
|
+
filename,
|
|
1097
|
+
filepath
|
|
1098
|
+
};
|
|
1099
|
+
} catch (error) {
|
|
1099
1100
|
throw new Error(
|
|
1100
|
-
`Invalid
|
|
1101
|
+
`Invalid frontmatter in ${filepath}: ${error instanceof Error ? error.message : String(error)}`
|
|
1101
1102
|
);
|
|
1102
1103
|
}
|
|
1103
|
-
for (const glob of obj.globs) {
|
|
1104
|
-
if (typeof glob !== "string") {
|
|
1105
|
-
throw new Error(
|
|
1106
|
-
`Invalid glob pattern in ${filepath}: all globs must be strings, got ${typeof glob}`
|
|
1107
|
-
);
|
|
1108
|
-
}
|
|
1109
|
-
}
|
|
1110
1104
|
}
|
|
1111
1105
|
|
|
1112
1106
|
// src/core/validator.ts
|
|
@@ -1160,10 +1154,10 @@ async function validateRule(rule) {
|
|
|
1160
1154
|
}
|
|
1161
1155
|
|
|
1162
1156
|
// src/core/mcp-generator.ts
|
|
1163
|
-
var
|
|
1157
|
+
var path3 = __toESM(require("path"), 1);
|
|
1164
1158
|
|
|
1165
1159
|
// src/generators/mcp/index.ts
|
|
1166
|
-
|
|
1160
|
+
init_claudecode();
|
|
1167
1161
|
init_cline();
|
|
1168
1162
|
init_copilot();
|
|
1169
1163
|
init_cursor();
|
|
@@ -1171,27 +1165,25 @@ init_geminicli();
|
|
|
1171
1165
|
init_roo();
|
|
1172
1166
|
|
|
1173
1167
|
// src/core/mcp-parser.ts
|
|
1174
|
-
var
|
|
1175
|
-
var
|
|
1168
|
+
var fs = __toESM(require("fs"), 1);
|
|
1169
|
+
var path2 = __toESM(require("path"), 1);
|
|
1176
1170
|
function parseMcpConfig(projectRoot) {
|
|
1177
|
-
const mcpPath =
|
|
1178
|
-
if (!
|
|
1171
|
+
const mcpPath = path2.join(projectRoot, ".rulesync", ".mcp.json");
|
|
1172
|
+
if (!fs.existsSync(mcpPath)) {
|
|
1179
1173
|
return null;
|
|
1180
1174
|
}
|
|
1181
1175
|
try {
|
|
1182
|
-
const content =
|
|
1176
|
+
const content = fs.readFileSync(mcpPath, "utf-8");
|
|
1183
1177
|
const rawConfig = JSON.parse(content);
|
|
1184
1178
|
if (rawConfig.servers && !rawConfig.mcpServers) {
|
|
1185
1179
|
rawConfig.mcpServers = rawConfig.servers;
|
|
1186
1180
|
delete rawConfig.servers;
|
|
1187
1181
|
}
|
|
1188
|
-
if (!rawConfig.mcpServers || typeof rawConfig.mcpServers !== "object") {
|
|
1189
|
-
throw new Error("Invalid mcp.json: 'mcpServers' field must be an object");
|
|
1190
|
-
}
|
|
1191
1182
|
if (rawConfig.tools) {
|
|
1192
1183
|
delete rawConfig.tools;
|
|
1193
1184
|
}
|
|
1194
|
-
|
|
1185
|
+
const validatedConfig = RulesyncMcpConfigSchema.parse(rawConfig);
|
|
1186
|
+
return validatedConfig;
|
|
1195
1187
|
} catch (error) {
|
|
1196
1188
|
throw new Error(
|
|
1197
1189
|
`Failed to parse mcp.json: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -1210,32 +1202,32 @@ async function generateMcpConfigs(projectRoot, baseDir) {
|
|
|
1210
1202
|
const generators = [
|
|
1211
1203
|
{
|
|
1212
1204
|
tool: "claude-project",
|
|
1213
|
-
path:
|
|
1205
|
+
path: path3.join(targetRoot, ".mcp.json"),
|
|
1214
1206
|
generate: () => generateClaudeMcp(config)
|
|
1215
1207
|
},
|
|
1216
1208
|
{
|
|
1217
1209
|
tool: "copilot-editor",
|
|
1218
|
-
path:
|
|
1210
|
+
path: path3.join(targetRoot, ".vscode", "mcp.json"),
|
|
1219
1211
|
generate: () => generateCopilotMcp(config, "editor")
|
|
1220
1212
|
},
|
|
1221
1213
|
{
|
|
1222
1214
|
tool: "cursor-project",
|
|
1223
|
-
path:
|
|
1215
|
+
path: path3.join(targetRoot, ".cursor", "mcp.json"),
|
|
1224
1216
|
generate: () => generateCursorMcp(config)
|
|
1225
1217
|
},
|
|
1226
1218
|
{
|
|
1227
1219
|
tool: "cline-project",
|
|
1228
|
-
path:
|
|
1220
|
+
path: path3.join(targetRoot, ".cline", "mcp.json"),
|
|
1229
1221
|
generate: () => generateClineMcp(config)
|
|
1230
1222
|
},
|
|
1231
1223
|
{
|
|
1232
1224
|
tool: "gemini-project",
|
|
1233
|
-
path:
|
|
1225
|
+
path: path3.join(targetRoot, ".gemini", "settings.json"),
|
|
1234
1226
|
generate: () => generateGeminiCliMcp(config)
|
|
1235
1227
|
},
|
|
1236
1228
|
{
|
|
1237
1229
|
tool: "roo-project",
|
|
1238
|
-
path:
|
|
1230
|
+
path: path3.join(targetRoot, ".roo", "mcp.json"),
|
|
1239
1231
|
generate: () => generateRooMcp(config)
|
|
1240
1232
|
}
|
|
1241
1233
|
];
|
|
@@ -1392,10 +1384,10 @@ Generating configurations for base directory: ${baseDir}`);
|
|
|
1392
1384
|
}
|
|
1393
1385
|
|
|
1394
1386
|
// src/cli/commands/gitignore.ts
|
|
1395
|
-
var
|
|
1396
|
-
var
|
|
1387
|
+
var import_node_fs = require("fs");
|
|
1388
|
+
var import_node_path11 = require("path");
|
|
1397
1389
|
var gitignoreCommand = async () => {
|
|
1398
|
-
const gitignorePath = (0,
|
|
1390
|
+
const gitignorePath = (0, import_node_path11.join)(process.cwd(), ".gitignore");
|
|
1399
1391
|
const rulesFilesToIgnore = [
|
|
1400
1392
|
"# Generated by rulesync - AI tool configuration files",
|
|
1401
1393
|
"**/.github/copilot-instructions.md",
|
|
@@ -1421,8 +1413,8 @@ var gitignoreCommand = async () => {
|
|
|
1421
1413
|
"**/.roo/mcp.json"
|
|
1422
1414
|
];
|
|
1423
1415
|
let gitignoreContent = "";
|
|
1424
|
-
if ((0,
|
|
1425
|
-
gitignoreContent = (0,
|
|
1416
|
+
if ((0, import_node_fs.existsSync)(gitignorePath)) {
|
|
1417
|
+
gitignoreContent = (0, import_node_fs.readFileSync)(gitignorePath, "utf-8");
|
|
1426
1418
|
}
|
|
1427
1419
|
const linesToAdd = [];
|
|
1428
1420
|
for (const rule of rulesFilesToIgnore) {
|
|
@@ -1439,7 +1431,7 @@ var gitignoreCommand = async () => {
|
|
|
1439
1431
|
${linesToAdd.join("\n")}
|
|
1440
1432
|
` : `${linesToAdd.join("\n")}
|
|
1441
1433
|
`;
|
|
1442
|
-
(0,
|
|
1434
|
+
(0, import_node_fs.writeFileSync)(gitignorePath, newContent);
|
|
1443
1435
|
console.log(`\u2705 Added ${linesToAdd.length} rules to .gitignore:`);
|
|
1444
1436
|
for (const line of linesToAdd) {
|
|
1445
1437
|
if (!line.startsWith("#")) {
|
|
@@ -1449,17 +1441,17 @@ ${linesToAdd.join("\n")}
|
|
|
1449
1441
|
};
|
|
1450
1442
|
|
|
1451
1443
|
// src/core/importer.ts
|
|
1452
|
-
var
|
|
1444
|
+
var import_node_path18 = require("path");
|
|
1453
1445
|
var import_gray_matter4 = __toESM(require("gray-matter"), 1);
|
|
1454
1446
|
|
|
1455
1447
|
// src/parsers/claudecode.ts
|
|
1456
|
-
var
|
|
1448
|
+
var import_node_path12 = require("path");
|
|
1457
1449
|
async function parseClaudeConfiguration(baseDir = process.cwd()) {
|
|
1458
1450
|
const errors = [];
|
|
1459
1451
|
const rules = [];
|
|
1460
1452
|
let ignorePatterns;
|
|
1461
1453
|
let mcpServers;
|
|
1462
|
-
const claudeFilePath = (0,
|
|
1454
|
+
const claudeFilePath = (0, import_node_path12.join)(baseDir, "CLAUDE.md");
|
|
1463
1455
|
if (!await fileExists(claudeFilePath)) {
|
|
1464
1456
|
errors.push("CLAUDE.md file not found");
|
|
1465
1457
|
return { rules, errors };
|
|
@@ -1470,12 +1462,12 @@ async function parseClaudeConfiguration(baseDir = process.cwd()) {
|
|
|
1470
1462
|
if (mainRule) {
|
|
1471
1463
|
rules.push(mainRule);
|
|
1472
1464
|
}
|
|
1473
|
-
const memoryDir = (0,
|
|
1465
|
+
const memoryDir = (0, import_node_path12.join)(baseDir, ".claude", "memories");
|
|
1474
1466
|
if (await fileExists(memoryDir)) {
|
|
1475
1467
|
const memoryRules = await parseClaudeMemoryFiles(memoryDir);
|
|
1476
1468
|
rules.push(...memoryRules);
|
|
1477
1469
|
}
|
|
1478
|
-
const settingsPath = (0,
|
|
1470
|
+
const settingsPath = (0, import_node_path12.join)(baseDir, ".claude", "settings.json");
|
|
1479
1471
|
if (await fileExists(settingsPath)) {
|
|
1480
1472
|
const settingsResult = await parseClaudeSettings(settingsPath);
|
|
1481
1473
|
if (settingsResult.ignorePatterns) {
|
|
@@ -1532,10 +1524,10 @@ async function parseClaudeMemoryFiles(memoryDir) {
|
|
|
1532
1524
|
const files = await readdir2(memoryDir);
|
|
1533
1525
|
for (const file of files) {
|
|
1534
1526
|
if (file.endsWith(".md")) {
|
|
1535
|
-
const filePath = (0,
|
|
1527
|
+
const filePath = (0, import_node_path12.join)(memoryDir, file);
|
|
1536
1528
|
const content = await readFileContent(filePath);
|
|
1537
1529
|
if (content.trim()) {
|
|
1538
|
-
const filename = (0,
|
|
1530
|
+
const filename = (0, import_node_path12.basename)(file, ".md");
|
|
1539
1531
|
const frontmatter = {
|
|
1540
1532
|
root: false,
|
|
1541
1533
|
targets: ["claudecode"],
|
|
@@ -1564,6 +1556,9 @@ async function parseClaudeSettings(settingsPath) {
|
|
|
1564
1556
|
const settings = JSON.parse(content);
|
|
1565
1557
|
if (typeof settings === "object" && settings !== null && "permissions" in settings) {
|
|
1566
1558
|
const permissions = settings.permissions;
|
|
1559
|
+
if (typeof permissions !== "object" || permissions === null) {
|
|
1560
|
+
return { ignorePatterns: [], errors: [] };
|
|
1561
|
+
}
|
|
1567
1562
|
if (permissions && "deny" in permissions && Array.isArray(permissions.deny)) {
|
|
1568
1563
|
const readPatterns = permissions.deny.filter(
|
|
1569
1564
|
(rule) => typeof rule === "string" && rule.startsWith("Read(") && rule.endsWith(")")
|
|
@@ -1576,11 +1571,9 @@ async function parseClaudeSettings(settingsPath) {
|
|
|
1576
1571
|
}
|
|
1577
1572
|
}
|
|
1578
1573
|
}
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
mcpServers = servers;
|
|
1583
|
-
}
|
|
1574
|
+
const parseResult = RulesyncMcpConfigSchema.safeParse(settings);
|
|
1575
|
+
if (parseResult.success && Object.keys(parseResult.data.mcpServers).length > 0) {
|
|
1576
|
+
mcpServers = parseResult.data.mcpServers;
|
|
1584
1577
|
}
|
|
1585
1578
|
} catch (error) {
|
|
1586
1579
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -1594,11 +1587,11 @@ async function parseClaudeSettings(settingsPath) {
|
|
|
1594
1587
|
}
|
|
1595
1588
|
|
|
1596
1589
|
// src/parsers/cline.ts
|
|
1597
|
-
var
|
|
1590
|
+
var import_node_path13 = require("path");
|
|
1598
1591
|
async function parseClineConfiguration(baseDir = process.cwd()) {
|
|
1599
1592
|
const errors = [];
|
|
1600
1593
|
const rules = [];
|
|
1601
|
-
const clineFilePath = (0,
|
|
1594
|
+
const clineFilePath = (0, import_node_path13.join)(baseDir, ".cline", "instructions.md");
|
|
1602
1595
|
if (await fileExists(clineFilePath)) {
|
|
1603
1596
|
try {
|
|
1604
1597
|
const content = await readFileContent(clineFilePath);
|
|
@@ -1621,14 +1614,14 @@ async function parseClineConfiguration(baseDir = process.cwd()) {
|
|
|
1621
1614
|
errors.push(`Failed to parse .cline/instructions.md: ${errorMessage}`);
|
|
1622
1615
|
}
|
|
1623
1616
|
}
|
|
1624
|
-
const clinerulesDirPath = (0,
|
|
1617
|
+
const clinerulesDirPath = (0, import_node_path13.join)(baseDir, ".clinerules");
|
|
1625
1618
|
if (await fileExists(clinerulesDirPath)) {
|
|
1626
1619
|
try {
|
|
1627
1620
|
const { readdir: readdir2 } = await import("fs/promises");
|
|
1628
1621
|
const files = await readdir2(clinerulesDirPath);
|
|
1629
1622
|
for (const file of files) {
|
|
1630
1623
|
if (file.endsWith(".md")) {
|
|
1631
|
-
const filePath = (0,
|
|
1624
|
+
const filePath = (0, import_node_path13.join)(clinerulesDirPath, file);
|
|
1632
1625
|
try {
|
|
1633
1626
|
const content = await readFileContent(filePath);
|
|
1634
1627
|
if (content.trim()) {
|
|
@@ -1664,12 +1657,12 @@ async function parseClineConfiguration(baseDir = process.cwd()) {
|
|
|
1664
1657
|
}
|
|
1665
1658
|
|
|
1666
1659
|
// src/parsers/copilot.ts
|
|
1667
|
-
var
|
|
1660
|
+
var import_node_path14 = require("path");
|
|
1668
1661
|
var import_gray_matter2 = __toESM(require("gray-matter"), 1);
|
|
1669
1662
|
async function parseCopilotConfiguration(baseDir = process.cwd()) {
|
|
1670
1663
|
const errors = [];
|
|
1671
1664
|
const rules = [];
|
|
1672
|
-
const copilotFilePath = (0,
|
|
1665
|
+
const copilotFilePath = (0, import_node_path14.join)(baseDir, ".github", "copilot-instructions.md");
|
|
1673
1666
|
if (await fileExists(copilotFilePath)) {
|
|
1674
1667
|
try {
|
|
1675
1668
|
const rawContent = await readFileContent(copilotFilePath);
|
|
@@ -1694,19 +1687,19 @@ async function parseCopilotConfiguration(baseDir = process.cwd()) {
|
|
|
1694
1687
|
errors.push(`Failed to parse copilot-instructions.md: ${errorMessage}`);
|
|
1695
1688
|
}
|
|
1696
1689
|
}
|
|
1697
|
-
const instructionsDir = (0,
|
|
1690
|
+
const instructionsDir = (0, import_node_path14.join)(baseDir, ".github", "instructions");
|
|
1698
1691
|
if (await fileExists(instructionsDir)) {
|
|
1699
1692
|
try {
|
|
1700
1693
|
const { readdir: readdir2 } = await import("fs/promises");
|
|
1701
1694
|
const files = await readdir2(instructionsDir);
|
|
1702
1695
|
for (const file of files) {
|
|
1703
1696
|
if (file.endsWith(".instructions.md")) {
|
|
1704
|
-
const filePath = (0,
|
|
1697
|
+
const filePath = (0, import_node_path14.join)(instructionsDir, file);
|
|
1705
1698
|
const rawContent = await readFileContent(filePath);
|
|
1706
1699
|
const parsed = (0, import_gray_matter2.default)(rawContent);
|
|
1707
1700
|
const content = parsed.content.trim();
|
|
1708
1701
|
if (content) {
|
|
1709
|
-
const filename = (0,
|
|
1702
|
+
const filename = (0, import_node_path14.basename)(file, ".instructions.md");
|
|
1710
1703
|
const frontmatter = {
|
|
1711
1704
|
root: false,
|
|
1712
1705
|
targets: ["copilot"],
|
|
@@ -1736,19 +1729,28 @@ async function parseCopilotConfiguration(baseDir = process.cwd()) {
|
|
|
1736
1729
|
}
|
|
1737
1730
|
|
|
1738
1731
|
// src/parsers/cursor.ts
|
|
1739
|
-
var
|
|
1732
|
+
var import_node_path15 = require("path");
|
|
1740
1733
|
var import_gray_matter3 = __toESM(require("gray-matter"), 1);
|
|
1741
1734
|
var import_js_yaml = require("js-yaml");
|
|
1735
|
+
var import_v4_mini6 = require("zod/v4-mini");
|
|
1742
1736
|
var customMatterOptions = {
|
|
1743
1737
|
engines: {
|
|
1744
1738
|
yaml: {
|
|
1745
1739
|
parse: (str) => {
|
|
1746
1740
|
try {
|
|
1747
|
-
|
|
1748
|
-
|
|
1741
|
+
const preprocessed = str.replace(/^(\s*globs:\s*)\*\s*$/gm, '$1"*"').replace(/^(\s*globs:\s*)([^\s"'[\n][^"'[\n]*?)(\s*)$/gm, '$1"$2"$3');
|
|
1742
|
+
const result = (0, import_js_yaml.load)(preprocessed, { schema: import_js_yaml.DEFAULT_SCHEMA });
|
|
1743
|
+
if (typeof result === "object" && result !== null) {
|
|
1744
|
+
return result;
|
|
1745
|
+
}
|
|
1746
|
+
throw new Error("Failed to parse YAML: result is not an object");
|
|
1749
1747
|
} catch (error) {
|
|
1750
1748
|
try {
|
|
1751
|
-
|
|
1749
|
+
const result = (0, import_js_yaml.load)(str, { schema: import_js_yaml.FAILSAFE_SCHEMA });
|
|
1750
|
+
if (typeof result === "object" && result !== null) {
|
|
1751
|
+
return result;
|
|
1752
|
+
}
|
|
1753
|
+
throw new Error("Failed to parse YAML: result is not an object");
|
|
1752
1754
|
} catch {
|
|
1753
1755
|
throw error;
|
|
1754
1756
|
}
|
|
@@ -1758,7 +1760,18 @@ var customMatterOptions = {
|
|
|
1758
1760
|
}
|
|
1759
1761
|
};
|
|
1760
1762
|
function convertCursorMdcFrontmatter(cursorFrontmatter, _filename) {
|
|
1761
|
-
const
|
|
1763
|
+
const FrontmatterSchema = import_v4_mini6.z.record(import_v4_mini6.z.string(), import_v4_mini6.z.unknown());
|
|
1764
|
+
const parseResult = FrontmatterSchema.safeParse(cursorFrontmatter);
|
|
1765
|
+
if (!parseResult.success) {
|
|
1766
|
+
return {
|
|
1767
|
+
root: false,
|
|
1768
|
+
targets: ["*"],
|
|
1769
|
+
description: "",
|
|
1770
|
+
globs: [],
|
|
1771
|
+
cursorRuleType: "manual"
|
|
1772
|
+
};
|
|
1773
|
+
}
|
|
1774
|
+
const frontmatter = parseResult.data;
|
|
1762
1775
|
const description = normalizeValue(frontmatter?.description);
|
|
1763
1776
|
const globs = normalizeGlobsValue(frontmatter?.globs);
|
|
1764
1777
|
const alwaysApply = frontmatter?.alwaysApply === true || frontmatter?.alwaysApply === "true";
|
|
@@ -1793,7 +1806,7 @@ function convertCursorMdcFrontmatter(cursorFrontmatter, _filename) {
|
|
|
1793
1806
|
return {
|
|
1794
1807
|
root: false,
|
|
1795
1808
|
targets: ["*"],
|
|
1796
|
-
description,
|
|
1809
|
+
description: description || "",
|
|
1797
1810
|
globs: [],
|
|
1798
1811
|
cursorRuleType: "intelligently"
|
|
1799
1812
|
};
|
|
@@ -1841,7 +1854,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
1841
1854
|
const rules = [];
|
|
1842
1855
|
let ignorePatterns;
|
|
1843
1856
|
let mcpServers;
|
|
1844
|
-
const cursorFilePath = (0,
|
|
1857
|
+
const cursorFilePath = (0, import_node_path15.join)(baseDir, ".cursorrules");
|
|
1845
1858
|
if (await fileExists(cursorFilePath)) {
|
|
1846
1859
|
try {
|
|
1847
1860
|
const rawContent = await readFileContent(cursorFilePath);
|
|
@@ -1862,20 +1875,20 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
1862
1875
|
errors.push(`Failed to parse .cursorrules file: ${errorMessage}`);
|
|
1863
1876
|
}
|
|
1864
1877
|
}
|
|
1865
|
-
const cursorRulesDir = (0,
|
|
1878
|
+
const cursorRulesDir = (0, import_node_path15.join)(baseDir, ".cursor", "rules");
|
|
1866
1879
|
if (await fileExists(cursorRulesDir)) {
|
|
1867
1880
|
try {
|
|
1868
1881
|
const { readdir: readdir2 } = await import("fs/promises");
|
|
1869
1882
|
const files = await readdir2(cursorRulesDir);
|
|
1870
1883
|
for (const file of files) {
|
|
1871
1884
|
if (file.endsWith(".mdc")) {
|
|
1872
|
-
const filePath = (0,
|
|
1885
|
+
const filePath = (0, import_node_path15.join)(cursorRulesDir, file);
|
|
1873
1886
|
try {
|
|
1874
1887
|
const rawContent = await readFileContent(filePath);
|
|
1875
1888
|
const parsed = (0, import_gray_matter3.default)(rawContent, customMatterOptions);
|
|
1876
1889
|
const content = parsed.content.trim();
|
|
1877
1890
|
if (content) {
|
|
1878
|
-
const filename = (0,
|
|
1891
|
+
const filename = (0, import_node_path15.basename)(file, ".mdc");
|
|
1879
1892
|
const frontmatter = convertCursorMdcFrontmatter(parsed.data, filename);
|
|
1880
1893
|
rules.push({
|
|
1881
1894
|
frontmatter,
|
|
@@ -1898,7 +1911,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
1898
1911
|
if (rules.length === 0) {
|
|
1899
1912
|
errors.push("No Cursor configuration files found (.cursorrules or .cursor/rules/*.mdc)");
|
|
1900
1913
|
}
|
|
1901
|
-
const cursorIgnorePath = (0,
|
|
1914
|
+
const cursorIgnorePath = (0, import_node_path15.join)(baseDir, ".cursorignore");
|
|
1902
1915
|
if (await fileExists(cursorIgnorePath)) {
|
|
1903
1916
|
try {
|
|
1904
1917
|
const content = await readFileContent(cursorIgnorePath);
|
|
@@ -1911,13 +1924,14 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
1911
1924
|
errors.push(`Failed to parse .cursorignore: ${errorMessage}`);
|
|
1912
1925
|
}
|
|
1913
1926
|
}
|
|
1914
|
-
const cursorMcpPath = (0,
|
|
1927
|
+
const cursorMcpPath = (0, import_node_path15.join)(baseDir, ".cursor", "mcp.json");
|
|
1915
1928
|
if (await fileExists(cursorMcpPath)) {
|
|
1916
1929
|
try {
|
|
1917
1930
|
const content = await readFileContent(cursorMcpPath);
|
|
1918
1931
|
const mcp = JSON.parse(content);
|
|
1919
|
-
|
|
1920
|
-
|
|
1932
|
+
const parseResult = RulesyncMcpConfigSchema.safeParse(mcp);
|
|
1933
|
+
if (parseResult.success && Object.keys(parseResult.data.mcpServers).length > 0) {
|
|
1934
|
+
mcpServers = parseResult.data.mcpServers;
|
|
1921
1935
|
}
|
|
1922
1936
|
} catch (error) {
|
|
1923
1937
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -1933,13 +1947,13 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
1933
1947
|
}
|
|
1934
1948
|
|
|
1935
1949
|
// src/parsers/geminicli.ts
|
|
1936
|
-
var
|
|
1950
|
+
var import_node_path16 = require("path");
|
|
1937
1951
|
async function parseGeminiConfiguration(baseDir = process.cwd()) {
|
|
1938
1952
|
const errors = [];
|
|
1939
1953
|
const rules = [];
|
|
1940
1954
|
let ignorePatterns;
|
|
1941
1955
|
let mcpServers;
|
|
1942
|
-
const geminiFilePath = (0,
|
|
1956
|
+
const geminiFilePath = (0, import_node_path16.join)(baseDir, "GEMINI.md");
|
|
1943
1957
|
if (!await fileExists(geminiFilePath)) {
|
|
1944
1958
|
errors.push("GEMINI.md file not found");
|
|
1945
1959
|
return { rules, errors };
|
|
@@ -1950,12 +1964,12 @@ async function parseGeminiConfiguration(baseDir = process.cwd()) {
|
|
|
1950
1964
|
if (mainRule) {
|
|
1951
1965
|
rules.push(mainRule);
|
|
1952
1966
|
}
|
|
1953
|
-
const memoryDir = (0,
|
|
1967
|
+
const memoryDir = (0, import_node_path16.join)(baseDir, ".gemini", "memories");
|
|
1954
1968
|
if (await fileExists(memoryDir)) {
|
|
1955
1969
|
const memoryRules = await parseGeminiMemoryFiles(memoryDir);
|
|
1956
1970
|
rules.push(...memoryRules);
|
|
1957
1971
|
}
|
|
1958
|
-
const settingsPath = (0,
|
|
1972
|
+
const settingsPath = (0, import_node_path16.join)(baseDir, ".gemini", "settings.json");
|
|
1959
1973
|
if (await fileExists(settingsPath)) {
|
|
1960
1974
|
const settingsResult = await parseGeminiSettings(settingsPath);
|
|
1961
1975
|
if (settingsResult.ignorePatterns) {
|
|
@@ -1966,7 +1980,7 @@ async function parseGeminiConfiguration(baseDir = process.cwd()) {
|
|
|
1966
1980
|
}
|
|
1967
1981
|
errors.push(...settingsResult.errors);
|
|
1968
1982
|
}
|
|
1969
|
-
const aiexcludePath = (0,
|
|
1983
|
+
const aiexcludePath = (0, import_node_path16.join)(baseDir, ".aiexclude");
|
|
1970
1984
|
if (await fileExists(aiexcludePath)) {
|
|
1971
1985
|
const aiexcludePatterns = await parseAiexclude(aiexcludePath);
|
|
1972
1986
|
if (aiexcludePatterns.length > 0) {
|
|
@@ -2019,10 +2033,10 @@ async function parseGeminiMemoryFiles(memoryDir) {
|
|
|
2019
2033
|
const files = await readdir2(memoryDir);
|
|
2020
2034
|
for (const file of files) {
|
|
2021
2035
|
if (file.endsWith(".md")) {
|
|
2022
|
-
const filePath = (0,
|
|
2036
|
+
const filePath = (0, import_node_path16.join)(memoryDir, file);
|
|
2023
2037
|
const content = await readFileContent(filePath);
|
|
2024
2038
|
if (content.trim()) {
|
|
2025
|
-
const filename = (0,
|
|
2039
|
+
const filename = (0, import_node_path16.basename)(file, ".md");
|
|
2026
2040
|
const frontmatter = {
|
|
2027
2041
|
root: false,
|
|
2028
2042
|
targets: ["geminicli"],
|
|
@@ -2048,8 +2062,9 @@ async function parseGeminiSettings(settingsPath) {
|
|
|
2048
2062
|
try {
|
|
2049
2063
|
const content = await readFileContent(settingsPath);
|
|
2050
2064
|
const settings = JSON.parse(content);
|
|
2051
|
-
|
|
2052
|
-
|
|
2065
|
+
const parseResult = RulesyncMcpConfigSchema.safeParse(settings);
|
|
2066
|
+
if (parseResult.success && Object.keys(parseResult.data.mcpServers).length > 0) {
|
|
2067
|
+
mcpServers = parseResult.data.mcpServers;
|
|
2053
2068
|
}
|
|
2054
2069
|
} catch (error) {
|
|
2055
2070
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -2071,11 +2086,11 @@ async function parseAiexclude(aiexcludePath) {
|
|
|
2071
2086
|
}
|
|
2072
2087
|
|
|
2073
2088
|
// src/parsers/roo.ts
|
|
2074
|
-
var
|
|
2089
|
+
var import_node_path17 = require("path");
|
|
2075
2090
|
async function parseRooConfiguration(baseDir = process.cwd()) {
|
|
2076
2091
|
const errors = [];
|
|
2077
2092
|
const rules = [];
|
|
2078
|
-
const rooFilePath = (0,
|
|
2093
|
+
const rooFilePath = (0, import_node_path17.join)(baseDir, ".roo", "instructions.md");
|
|
2079
2094
|
if (await fileExists(rooFilePath)) {
|
|
2080
2095
|
try {
|
|
2081
2096
|
const content = await readFileContent(rooFilePath);
|
|
@@ -2098,14 +2113,14 @@ async function parseRooConfiguration(baseDir = process.cwd()) {
|
|
|
2098
2113
|
errors.push(`Failed to parse .roo/instructions.md: ${errorMessage}`);
|
|
2099
2114
|
}
|
|
2100
2115
|
}
|
|
2101
|
-
const rooRulesDir = (0,
|
|
2116
|
+
const rooRulesDir = (0, import_node_path17.join)(baseDir, ".roo", "rules");
|
|
2102
2117
|
if (await fileExists(rooRulesDir)) {
|
|
2103
2118
|
try {
|
|
2104
2119
|
const { readdir: readdir2 } = await import("fs/promises");
|
|
2105
2120
|
const files = await readdir2(rooRulesDir);
|
|
2106
2121
|
for (const file of files) {
|
|
2107
2122
|
if (file.endsWith(".md")) {
|
|
2108
|
-
const filePath = (0,
|
|
2123
|
+
const filePath = (0, import_node_path17.join)(rooRulesDir, file);
|
|
2109
2124
|
try {
|
|
2110
2125
|
const content = await readFileContent(filePath);
|
|
2111
2126
|
if (content.trim()) {
|
|
@@ -2206,7 +2221,7 @@ async function importConfiguration(options) {
|
|
|
2206
2221
|
if (rules.length === 0 && !ignorePatterns && !mcpServers) {
|
|
2207
2222
|
return { success: false, rulesCreated: 0, errors };
|
|
2208
2223
|
}
|
|
2209
|
-
const rulesDirPath = (0,
|
|
2224
|
+
const rulesDirPath = (0, import_node_path18.join)(baseDir, rulesDir);
|
|
2210
2225
|
try {
|
|
2211
2226
|
const { mkdir: mkdir3 } = await import("fs/promises");
|
|
2212
2227
|
await mkdir3(rulesDirPath, { recursive: true });
|
|
@@ -2220,7 +2235,7 @@ async function importConfiguration(options) {
|
|
|
2220
2235
|
try {
|
|
2221
2236
|
const baseFilename = `${tool}__${rule.filename}`;
|
|
2222
2237
|
const filename = await generateUniqueFilename(rulesDirPath, baseFilename);
|
|
2223
|
-
const filePath = (0,
|
|
2238
|
+
const filePath = (0, import_node_path18.join)(rulesDirPath, `${filename}.md`);
|
|
2224
2239
|
const content = generateRuleFileContent(rule);
|
|
2225
2240
|
await writeFileContent(filePath, content);
|
|
2226
2241
|
rulesCreated++;
|
|
@@ -2235,7 +2250,7 @@ async function importConfiguration(options) {
|
|
|
2235
2250
|
let ignoreFileCreated = false;
|
|
2236
2251
|
if (ignorePatterns && ignorePatterns.length > 0) {
|
|
2237
2252
|
try {
|
|
2238
|
-
const rulesyncignorePath = (0,
|
|
2253
|
+
const rulesyncignorePath = (0, import_node_path18.join)(baseDir, ".rulesyncignore");
|
|
2239
2254
|
const ignoreContent = `${ignorePatterns.join("\n")}
|
|
2240
2255
|
`;
|
|
2241
2256
|
await writeFileContent(rulesyncignorePath, ignoreContent);
|
|
@@ -2251,7 +2266,7 @@ async function importConfiguration(options) {
|
|
|
2251
2266
|
let mcpFileCreated = false;
|
|
2252
2267
|
if (mcpServers && Object.keys(mcpServers).length > 0) {
|
|
2253
2268
|
try {
|
|
2254
|
-
const mcpPath = (0,
|
|
2269
|
+
const mcpPath = (0, import_node_path18.join)(baseDir, rulesDir, ".mcp.json");
|
|
2255
2270
|
const mcpContent = `${JSON.stringify({ mcpServers }, null, 2)}
|
|
2256
2271
|
`;
|
|
2257
2272
|
await writeFileContent(mcpPath, mcpContent);
|
|
@@ -2279,7 +2294,7 @@ function generateRuleFileContent(rule) {
|
|
|
2279
2294
|
async function generateUniqueFilename(rulesDir, baseFilename) {
|
|
2280
2295
|
let filename = baseFilename;
|
|
2281
2296
|
let counter = 1;
|
|
2282
|
-
while (await fileExists((0,
|
|
2297
|
+
while (await fileExists((0, import_node_path18.join)(rulesDir, `${filename}.md`))) {
|
|
2283
2298
|
filename = `${baseFilename}-${counter}`;
|
|
2284
2299
|
counter++;
|
|
2285
2300
|
}
|
|
@@ -2344,7 +2359,7 @@ async function importCommand(options = {}) {
|
|
|
2344
2359
|
}
|
|
2345
2360
|
|
|
2346
2361
|
// src/cli/commands/init.ts
|
|
2347
|
-
var
|
|
2362
|
+
var import_node_path19 = require("path");
|
|
2348
2363
|
async function initCommand() {
|
|
2349
2364
|
const aiRulesDir = ".rulesync";
|
|
2350
2365
|
console.log("Initializing rulesync...");
|
|
@@ -2474,7 +2489,7 @@ globs: ["src/api/**/*.ts", "src/services/**/*.ts", "src/models/**/*.ts"]
|
|
|
2474
2489
|
}
|
|
2475
2490
|
];
|
|
2476
2491
|
for (const file of sampleFiles) {
|
|
2477
|
-
const filepath = (0,
|
|
2492
|
+
const filepath = (0, import_node_path19.join)(aiRulesDir, file.filename);
|
|
2478
2493
|
if (!await fileExists(filepath)) {
|
|
2479
2494
|
await writeFileContent(filepath, file.content);
|
|
2480
2495
|
console.log(`Created ${filepath}`);
|
|
@@ -2509,9 +2524,11 @@ async function statusCommand() {
|
|
|
2509
2524
|
for (const rule of rules) {
|
|
2510
2525
|
const targets = rule.frontmatter.targets[0] === "*" ? config.defaultTargets : rule.frontmatter.targets;
|
|
2511
2526
|
for (const target of targets) {
|
|
2512
|
-
if (target
|
|
2513
|
-
|
|
2514
|
-
|
|
2527
|
+
if (target === "copilot") targetCounts.copilot++;
|
|
2528
|
+
else if (target === "cursor") targetCounts.cursor++;
|
|
2529
|
+
else if (target === "cline") targetCounts.cline++;
|
|
2530
|
+
else if (target === "claudecode") targetCounts.claudecode++;
|
|
2531
|
+
else if (target === "roo") targetCounts.roo++;
|
|
2515
2532
|
}
|
|
2516
2533
|
}
|
|
2517
2534
|
console.log("\n\u{1F3AF} Target tool coverage:");
|
|
@@ -2617,7 +2634,7 @@ async function watchCommand() {
|
|
|
2617
2634
|
|
|
2618
2635
|
// src/cli/index.ts
|
|
2619
2636
|
var program = new import_commander.Command();
|
|
2620
|
-
program.name("rulesync").description("Unified AI rules management CLI tool").version("0.
|
|
2637
|
+
program.name("rulesync").description("Unified AI rules management CLI tool").version("0.44.0");
|
|
2621
2638
|
program.command("init").description("Initialize rulesync in current directory").action(initCommand);
|
|
2622
2639
|
program.command("add <filename>").description("Add a new rule file").action(addCommand);
|
|
2623
2640
|
program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);
|