rulesync 0.36.0 → 0.37.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-UNTCJDMQ.mjs → chunk-2BYTQ4LL.mjs} +7 -13
- package/dist/{chunk-QHXMJZTJ.mjs → chunk-2CDVII2R.mjs} +6 -6
- package/dist/{chunk-QVPQ2X4L.mjs → chunk-3GVVX3G5.mjs} +11 -10
- package/dist/{chunk-SBYRCTWS.mjs → chunk-KZATM2CQ.mjs} +11 -10
- package/dist/{chunk-6PQ4APY4.mjs → chunk-PBOKMNYU.mjs} +6 -9
- package/dist/chunk-QQN5GTOV.mjs +56 -0
- package/dist/{chunk-YGXGGUBG.mjs → chunk-TKNVMYAC.mjs} +5 -7
- package/dist/{claude-O4SRX6VC.mjs → claude-2NLZ2CDE.mjs} +2 -1
- package/dist/{cline-H5JF2OPT.mjs → cline-HUXPTQP7.mjs} +2 -1
- package/dist/{copilot-GCIYHK4Q.mjs → copilot-376H5OXX.mjs} +2 -1
- package/dist/{cursor-N75OH6WS.mjs → cursor-XWLBQYWY.mjs} +2 -1
- package/dist/{geminicli-AGOQ32ZE.mjs → geminicli-EREPFSDP.mjs} +2 -1
- package/dist/index.js +235 -178
- package/dist/index.mjs +77 -57
- package/dist/{roo-V5YVC222.mjs → roo-YS23AEWJ.mjs} +2 -1
- package/package.json +22 -9
package/dist/index.js
CHANGED
|
@@ -26,19 +26,78 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
26
26
|
mod
|
|
27
27
|
));
|
|
28
28
|
|
|
29
|
+
// src/schemas/mcp.ts
|
|
30
|
+
var import_zod, ToolTargetSchema, WildcardTargetSchema, SpecificTargetsSchema, RulesyncTargetsSchema, McpTransportTypeSchema, McpServerBaseSchema, RulesyncMcpServerSchema;
|
|
31
|
+
var init_mcp = __esm({
|
|
32
|
+
"src/schemas/mcp.ts"() {
|
|
33
|
+
"use strict";
|
|
34
|
+
import_zod = require("zod");
|
|
35
|
+
ToolTargetSchema = import_zod.z.enum([
|
|
36
|
+
"copilot",
|
|
37
|
+
"cursor",
|
|
38
|
+
"cline",
|
|
39
|
+
"claudecode",
|
|
40
|
+
"claude",
|
|
41
|
+
"roo",
|
|
42
|
+
"geminicli"
|
|
43
|
+
]);
|
|
44
|
+
WildcardTargetSchema = import_zod.z.tuple([import_zod.z.literal("*")]);
|
|
45
|
+
SpecificTargetsSchema = import_zod.z.array(ToolTargetSchema);
|
|
46
|
+
RulesyncTargetsSchema = import_zod.z.union([SpecificTargetsSchema, WildcardTargetSchema]);
|
|
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
|
+
rulesyncTargets: RulesyncTargetsSchema.optional()
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// src/utils/mcp-helpers.ts
|
|
71
|
+
function shouldIncludeServer(server, targetTool) {
|
|
72
|
+
if (!server.rulesyncTargets || server.rulesyncTargets.length === 0) {
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
const parsedTargets = RulesyncTargetsSchema.parse(server.rulesyncTargets);
|
|
76
|
+
if (parsedTargets.length === 1 && parsedTargets[0] === "*") {
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
const validatedTool = ToolTargetSchema.parse(targetTool);
|
|
80
|
+
for (const target of parsedTargets) {
|
|
81
|
+
if (target === validatedTool) {
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
var init_mcp_helpers = __esm({
|
|
88
|
+
"src/utils/mcp-helpers.ts"() {
|
|
89
|
+
"use strict";
|
|
90
|
+
init_mcp();
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
29
94
|
// src/generators/mcp/claude.ts
|
|
30
95
|
function generateClaudeMcp(config, _target) {
|
|
31
96
|
const claudeSettings = {
|
|
32
97
|
mcpServers: {}
|
|
33
98
|
};
|
|
34
99
|
const shouldInclude = (server) => {
|
|
35
|
-
|
|
36
|
-
return true;
|
|
37
|
-
}
|
|
38
|
-
if (server.rulesyncTargets.length === 1 && server.rulesyncTargets[0] === "*") {
|
|
39
|
-
return true;
|
|
40
|
-
}
|
|
41
|
-
return server.rulesyncTargets.includes("claude");
|
|
100
|
+
return shouldIncludeServer(server, "claude");
|
|
42
101
|
};
|
|
43
102
|
for (const [serverName, server] of Object.entries(config.mcpServers)) {
|
|
44
103
|
if (!shouldInclude(server)) continue;
|
|
@@ -67,6 +126,7 @@ function generateClaudeMcp(config, _target) {
|
|
|
67
126
|
var init_claude = __esm({
|
|
68
127
|
"src/generators/mcp/claude.ts"() {
|
|
69
128
|
"use strict";
|
|
129
|
+
init_mcp_helpers();
|
|
70
130
|
}
|
|
71
131
|
});
|
|
72
132
|
|
|
@@ -76,10 +136,7 @@ function generateClineMcp(config, _target) {
|
|
|
76
136
|
mcpServers: {}
|
|
77
137
|
};
|
|
78
138
|
const shouldInclude = (server) => {
|
|
79
|
-
|
|
80
|
-
if (!targets || targets.length === 0) return true;
|
|
81
|
-
if (targets.length === 1 && targets[0] === "*") return true;
|
|
82
|
-
return targets.includes("cline");
|
|
139
|
+
return shouldIncludeServer(server, "cline");
|
|
83
140
|
};
|
|
84
141
|
for (const [serverName, server] of Object.entries(config.mcpServers)) {
|
|
85
142
|
if (!shouldInclude(server)) continue;
|
|
@@ -109,22 +166,17 @@ function generateClineMcp(config, _target) {
|
|
|
109
166
|
var init_cline = __esm({
|
|
110
167
|
"src/generators/mcp/cline.ts"() {
|
|
111
168
|
"use strict";
|
|
169
|
+
init_mcp_helpers();
|
|
112
170
|
}
|
|
113
171
|
});
|
|
114
172
|
|
|
115
173
|
// src/generators/mcp/copilot.ts
|
|
116
174
|
function generateCopilotMcp(config, target) {
|
|
117
|
-
const shouldInclude = (server) => {
|
|
118
|
-
const targets = server.rulesyncTargets;
|
|
119
|
-
if (!targets || targets.length === 0) return true;
|
|
120
|
-
if (targets.length === 1 && targets[0] === "*") return true;
|
|
121
|
-
return targets.includes("copilot");
|
|
122
|
-
};
|
|
123
175
|
const servers = {};
|
|
124
176
|
const inputs = [];
|
|
125
177
|
const inputMap = /* @__PURE__ */ new Map();
|
|
126
178
|
for (const [serverName, server] of Object.entries(config.mcpServers)) {
|
|
127
|
-
if (!
|
|
179
|
+
if (!shouldIncludeServer(server, "copilot")) continue;
|
|
128
180
|
const copilotServer = {};
|
|
129
181
|
if (server.command) {
|
|
130
182
|
copilotServer.command = server.command;
|
|
@@ -173,6 +225,7 @@ function generateCopilotMcp(config, target) {
|
|
|
173
225
|
var init_copilot = __esm({
|
|
174
226
|
"src/generators/mcp/copilot.ts"() {
|
|
175
227
|
"use strict";
|
|
228
|
+
init_mcp_helpers();
|
|
176
229
|
}
|
|
177
230
|
});
|
|
178
231
|
|
|
@@ -181,14 +234,8 @@ function generateCursorMcp(config, _target) {
|
|
|
181
234
|
const cursorConfig = {
|
|
182
235
|
mcpServers: {}
|
|
183
236
|
};
|
|
184
|
-
const shouldInclude = (server) => {
|
|
185
|
-
const targets = server.rulesyncTargets;
|
|
186
|
-
if (!targets || targets.length === 0) return true;
|
|
187
|
-
if (targets.length === 1 && targets[0] === "*") return true;
|
|
188
|
-
return targets.includes("cursor");
|
|
189
|
-
};
|
|
190
237
|
for (const [serverName, server] of Object.entries(config.mcpServers)) {
|
|
191
|
-
if (!
|
|
238
|
+
if (!shouldIncludeServer(server, "cursor")) continue;
|
|
192
239
|
const cursorServer = {};
|
|
193
240
|
if (server.command) {
|
|
194
241
|
cursorServer.command = server.command;
|
|
@@ -217,6 +264,7 @@ function generateCursorMcp(config, _target) {
|
|
|
217
264
|
var init_cursor = __esm({
|
|
218
265
|
"src/generators/mcp/cursor.ts"() {
|
|
219
266
|
"use strict";
|
|
267
|
+
init_mcp_helpers();
|
|
220
268
|
}
|
|
221
269
|
});
|
|
222
270
|
|
|
@@ -225,14 +273,8 @@ function generateGeminiCliMcp(config, _target) {
|
|
|
225
273
|
const geminiSettings = {
|
|
226
274
|
mcpServers: {}
|
|
227
275
|
};
|
|
228
|
-
const shouldInclude = (server) => {
|
|
229
|
-
const targets = server.rulesyncTargets;
|
|
230
|
-
if (!targets || targets.length === 0) return true;
|
|
231
|
-
if (targets.length === 1 && targets[0] === "*") return true;
|
|
232
|
-
return targets.includes("geminicli");
|
|
233
|
-
};
|
|
234
276
|
for (const [serverName, server] of Object.entries(config.mcpServers)) {
|
|
235
|
-
if (!
|
|
277
|
+
if (!shouldIncludeServer(server, "geminicli")) continue;
|
|
236
278
|
const geminiServer = {};
|
|
237
279
|
if (server.command) {
|
|
238
280
|
geminiServer.command = server.command;
|
|
@@ -267,6 +309,7 @@ function generateGeminiCliMcp(config, _target) {
|
|
|
267
309
|
var init_geminicli = __esm({
|
|
268
310
|
"src/generators/mcp/geminicli.ts"() {
|
|
269
311
|
"use strict";
|
|
312
|
+
init_mcp_helpers();
|
|
270
313
|
}
|
|
271
314
|
});
|
|
272
315
|
|
|
@@ -275,14 +318,8 @@ function generateRooMcp(config, _target) {
|
|
|
275
318
|
const rooConfig = {
|
|
276
319
|
mcpServers: {}
|
|
277
320
|
};
|
|
278
|
-
const shouldInclude = (server) => {
|
|
279
|
-
const targets = server.rulesyncTargets;
|
|
280
|
-
if (!targets || targets.length === 0) return true;
|
|
281
|
-
if (targets.length === 1 && targets[0] === "*") return true;
|
|
282
|
-
return targets.includes("roo");
|
|
283
|
-
};
|
|
284
321
|
for (const [serverName, server] of Object.entries(config.mcpServers)) {
|
|
285
|
-
if (!
|
|
322
|
+
if (!shouldIncludeServer(server, "roo")) continue;
|
|
286
323
|
const rooServer = {};
|
|
287
324
|
if (server.command) {
|
|
288
325
|
rooServer.command = server.command;
|
|
@@ -324,6 +361,7 @@ function generateRooMcp(config, _target) {
|
|
|
324
361
|
var init_roo = __esm({
|
|
325
362
|
"src/generators/mcp/roo.ts"() {
|
|
326
363
|
"use strict";
|
|
364
|
+
init_mcp_helpers();
|
|
327
365
|
}
|
|
328
366
|
});
|
|
329
367
|
|
|
@@ -395,21 +433,47 @@ async function addCommand(filename) {
|
|
|
395
433
|
}
|
|
396
434
|
|
|
397
435
|
// src/generators/rules/claudecode.ts
|
|
398
|
-
var
|
|
436
|
+
var import_node_path5 = require("path");
|
|
399
437
|
|
|
400
438
|
// src/utils/file.ts
|
|
439
|
+
var import_promises3 = require("fs/promises");
|
|
440
|
+
var import_node_path4 = require("path");
|
|
441
|
+
|
|
442
|
+
// src/utils/file-ops.ts
|
|
401
443
|
var import_promises2 = require("fs/promises");
|
|
402
|
-
var
|
|
444
|
+
var import_node_path2 = require("path");
|
|
445
|
+
async function ensureDir(dirPath) {
|
|
446
|
+
try {
|
|
447
|
+
await (0, import_promises2.stat)(dirPath);
|
|
448
|
+
} catch {
|
|
449
|
+
await (0, import_promises2.mkdir)(dirPath, { recursive: true });
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
async function readFileContent(filepath) {
|
|
453
|
+
return (0, import_promises2.readFile)(filepath, "utf-8");
|
|
454
|
+
}
|
|
455
|
+
async function writeFileContent(filepath, content) {
|
|
456
|
+
await ensureDir((0, import_node_path2.dirname)(filepath));
|
|
457
|
+
await (0, import_promises2.writeFile)(filepath, content, "utf-8");
|
|
458
|
+
}
|
|
459
|
+
async function fileExists(filepath) {
|
|
460
|
+
try {
|
|
461
|
+
await (0, import_promises2.stat)(filepath);
|
|
462
|
+
return true;
|
|
463
|
+
} catch {
|
|
464
|
+
return false;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
403
467
|
|
|
404
468
|
// src/utils/ignore.ts
|
|
405
|
-
var
|
|
469
|
+
var import_node_path3 = require("path");
|
|
406
470
|
var import_micromatch = __toESM(require("micromatch"));
|
|
407
471
|
var cachedIgnorePatterns = null;
|
|
408
472
|
async function loadIgnorePatterns(baseDir = process.cwd()) {
|
|
409
473
|
if (cachedIgnorePatterns) {
|
|
410
474
|
return cachedIgnorePatterns;
|
|
411
475
|
}
|
|
412
|
-
const ignorePath = (0,
|
|
476
|
+
const ignorePath = (0, import_node_path3.join)(baseDir, ".rulesyncignore");
|
|
413
477
|
if (!await fileExists(ignorePath)) {
|
|
414
478
|
cachedIgnorePatterns = { patterns: [] };
|
|
415
479
|
return cachedIgnorePatterns;
|
|
@@ -453,24 +517,10 @@ function filterIgnoredFiles(files, ignorePatterns) {
|
|
|
453
517
|
}
|
|
454
518
|
|
|
455
519
|
// src/utils/file.ts
|
|
456
|
-
async function ensureDir(dirPath) {
|
|
457
|
-
try {
|
|
458
|
-
await (0, import_promises2.stat)(dirPath);
|
|
459
|
-
} catch {
|
|
460
|
-
await (0, import_promises2.mkdir)(dirPath, { recursive: true });
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
async function readFileContent(filepath) {
|
|
464
|
-
return (0, import_promises2.readFile)(filepath, "utf-8");
|
|
465
|
-
}
|
|
466
|
-
async function writeFileContent(filepath, content) {
|
|
467
|
-
await ensureDir((0, import_node_path3.dirname)(filepath));
|
|
468
|
-
await (0, import_promises2.writeFile)(filepath, content, "utf-8");
|
|
469
|
-
}
|
|
470
520
|
async function findFiles(dir, extension = ".md", ignorePatterns) {
|
|
471
521
|
try {
|
|
472
|
-
const files = await (0,
|
|
473
|
-
const filtered = files.filter((file) => file.endsWith(extension)).map((file) => (0,
|
|
522
|
+
const files = await (0, import_promises3.readdir)(dir);
|
|
523
|
+
const filtered = files.filter((file) => file.endsWith(extension)).map((file) => (0, import_node_path4.join)(dir, file));
|
|
474
524
|
if (ignorePatterns && ignorePatterns.length > 0) {
|
|
475
525
|
return filterIgnoredFiles(filtered, ignorePatterns);
|
|
476
526
|
}
|
|
@@ -479,14 +529,6 @@ async function findFiles(dir, extension = ".md", ignorePatterns) {
|
|
|
479
529
|
return [];
|
|
480
530
|
}
|
|
481
531
|
}
|
|
482
|
-
async function fileExists(filepath) {
|
|
483
|
-
try {
|
|
484
|
-
await (0, import_promises2.stat)(filepath);
|
|
485
|
-
return true;
|
|
486
|
-
} catch {
|
|
487
|
-
return false;
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
532
|
async function removeDirectory(dirPath) {
|
|
491
533
|
const dangerousPaths = [".", "/", "~", "src", "node_modules"];
|
|
492
534
|
if (dangerousPaths.includes(dirPath) || dirPath === "") {
|
|
@@ -495,7 +537,7 @@ async function removeDirectory(dirPath) {
|
|
|
495
537
|
}
|
|
496
538
|
try {
|
|
497
539
|
if (await fileExists(dirPath)) {
|
|
498
|
-
await (0,
|
|
540
|
+
await (0, import_promises3.rm)(dirPath, { recursive: true, force: true });
|
|
499
541
|
}
|
|
500
542
|
} catch (error) {
|
|
501
543
|
console.warn(`Failed to remove directory ${dirPath}:`, error);
|
|
@@ -504,7 +546,7 @@ async function removeDirectory(dirPath) {
|
|
|
504
546
|
async function removeFile(filepath) {
|
|
505
547
|
try {
|
|
506
548
|
if (await fileExists(filepath)) {
|
|
507
|
-
await (0,
|
|
549
|
+
await (0, import_promises3.rm)(filepath);
|
|
508
550
|
}
|
|
509
551
|
} catch (error) {
|
|
510
552
|
console.warn(`Failed to remove file ${filepath}:`, error);
|
|
@@ -527,23 +569,23 @@ async function generateClaudecodeConfig(rules, config, baseDir) {
|
|
|
527
569
|
const rootRules = rules.filter((r) => r.frontmatter.root === true);
|
|
528
570
|
const detailRules = rules.filter((r) => r.frontmatter.root === false);
|
|
529
571
|
const claudeMdContent = generateClaudeMarkdown(rootRules, detailRules);
|
|
530
|
-
const claudeOutputDir = baseDir ? (0,
|
|
572
|
+
const claudeOutputDir = baseDir ? (0, import_node_path5.join)(baseDir, config.outputPaths.claudecode) : config.outputPaths.claudecode;
|
|
531
573
|
outputs.push({
|
|
532
574
|
tool: "claudecode",
|
|
533
|
-
filepath: (0,
|
|
575
|
+
filepath: (0, import_node_path5.join)(claudeOutputDir, "CLAUDE.md"),
|
|
534
576
|
content: claudeMdContent
|
|
535
577
|
});
|
|
536
578
|
for (const rule of detailRules) {
|
|
537
579
|
const memoryContent = generateMemoryFile(rule);
|
|
538
580
|
outputs.push({
|
|
539
581
|
tool: "claudecode",
|
|
540
|
-
filepath: (0,
|
|
582
|
+
filepath: (0, import_node_path5.join)(claudeOutputDir, ".claude", "memories", `${rule.filename}.md`),
|
|
541
583
|
content: memoryContent
|
|
542
584
|
});
|
|
543
585
|
}
|
|
544
586
|
const ignorePatterns = await loadIgnorePatterns(baseDir);
|
|
545
587
|
if (ignorePatterns.patterns.length > 0) {
|
|
546
|
-
const settingsPath = baseDir ? (0,
|
|
588
|
+
const settingsPath = baseDir ? (0, import_node_path5.join)(baseDir, ".claude", "settings.json") : (0, import_node_path5.join)(".claude", "settings.json");
|
|
547
589
|
await updateClaudeSettings(settingsPath, ignorePatterns.patterns);
|
|
548
590
|
}
|
|
549
591
|
return outputs;
|
|
@@ -580,39 +622,46 @@ async function updateClaudeSettings(settingsPath, ignorePatterns) {
|
|
|
580
622
|
try {
|
|
581
623
|
const content = await readFileContent(settingsPath);
|
|
582
624
|
settings = JSON.parse(content);
|
|
583
|
-
} catch
|
|
625
|
+
} catch {
|
|
584
626
|
console.warn(`Failed to parse existing ${settingsPath}, creating new settings`);
|
|
585
627
|
settings = {};
|
|
586
628
|
}
|
|
587
629
|
}
|
|
588
|
-
if (
|
|
589
|
-
settings
|
|
630
|
+
if (typeof settings !== "object" || settings === null) {
|
|
631
|
+
settings = {};
|
|
590
632
|
}
|
|
591
|
-
|
|
592
|
-
|
|
633
|
+
const settingsObj = settings;
|
|
634
|
+
if (!settingsObj.permissions || typeof settingsObj.permissions !== "object" || settingsObj.permissions === null) {
|
|
635
|
+
settingsObj.permissions = {};
|
|
636
|
+
}
|
|
637
|
+
const permissions = settingsObj.permissions;
|
|
638
|
+
if (!Array.isArray(permissions.deny)) {
|
|
639
|
+
permissions.deny = [];
|
|
593
640
|
}
|
|
594
641
|
const readDenyRules = ignorePatterns.map((pattern) => `Read(${pattern})`);
|
|
595
|
-
|
|
642
|
+
const denyArray = permissions.deny;
|
|
643
|
+
const filteredDeny = denyArray.filter((rule) => {
|
|
644
|
+
if (typeof rule !== "string") return false;
|
|
596
645
|
if (!rule.startsWith("Read(")) return true;
|
|
597
646
|
const match = rule.match(/^Read\((.*)\)$/);
|
|
598
647
|
if (!match) return true;
|
|
599
648
|
return !ignorePatterns.includes(match[1] ?? "");
|
|
600
649
|
});
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
const jsonContent = JSON.stringify(
|
|
650
|
+
filteredDeny.push(...readDenyRules);
|
|
651
|
+
permissions.deny = [...new Set(filteredDeny)];
|
|
652
|
+
const jsonContent = JSON.stringify(settingsObj, null, 2);
|
|
604
653
|
await writeFileContent(settingsPath, jsonContent);
|
|
605
654
|
console.log(`\u2705 Updated Claude Code settings: ${settingsPath}`);
|
|
606
655
|
}
|
|
607
656
|
|
|
608
657
|
// src/generators/rules/cline.ts
|
|
609
|
-
var
|
|
658
|
+
var import_node_path6 = require("path");
|
|
610
659
|
async function generateClineConfig(rules, config, baseDir) {
|
|
611
660
|
const outputs = [];
|
|
612
661
|
for (const rule of rules) {
|
|
613
662
|
const content = generateClineMarkdown(rule);
|
|
614
|
-
const outputDir = baseDir ? (0,
|
|
615
|
-
const filepath = (0,
|
|
663
|
+
const outputDir = baseDir ? (0, import_node_path6.join)(baseDir, config.outputPaths.cline) : config.outputPaths.cline;
|
|
664
|
+
const filepath = (0, import_node_path6.join)(outputDir, `${rule.filename}.md`);
|
|
616
665
|
outputs.push({
|
|
617
666
|
tool: "cline",
|
|
618
667
|
filepath,
|
|
@@ -621,7 +670,7 @@ async function generateClineConfig(rules, config, baseDir) {
|
|
|
621
670
|
}
|
|
622
671
|
const ignorePatterns = await loadIgnorePatterns(baseDir);
|
|
623
672
|
if (ignorePatterns.patterns.length > 0) {
|
|
624
|
-
const clineIgnorePath = baseDir ? (0,
|
|
673
|
+
const clineIgnorePath = baseDir ? (0, import_node_path6.join)(baseDir, ".clineignore") : ".clineignore";
|
|
625
674
|
const clineIgnoreContent = generateClineIgnore(ignorePatterns.patterns);
|
|
626
675
|
outputs.push({
|
|
627
676
|
tool: "cline",
|
|
@@ -645,14 +694,14 @@ function generateClineIgnore(patterns) {
|
|
|
645
694
|
}
|
|
646
695
|
|
|
647
696
|
// src/generators/rules/copilot.ts
|
|
648
|
-
var
|
|
697
|
+
var import_node_path7 = require("path");
|
|
649
698
|
async function generateCopilotConfig(rules, config, baseDir) {
|
|
650
699
|
const outputs = [];
|
|
651
700
|
for (const rule of rules) {
|
|
652
701
|
const content = generateCopilotMarkdown(rule);
|
|
653
702
|
const baseFilename = rule.filename.replace(/\.md$/, "");
|
|
654
|
-
const outputDir = baseDir ? (0,
|
|
655
|
-
const filepath = (0,
|
|
703
|
+
const outputDir = baseDir ? (0, import_node_path7.join)(baseDir, config.outputPaths.copilot) : config.outputPaths.copilot;
|
|
704
|
+
const filepath = (0, import_node_path7.join)(outputDir, `${baseFilename}.instructions.md`);
|
|
656
705
|
outputs.push({
|
|
657
706
|
tool: "copilot",
|
|
658
707
|
filepath,
|
|
@@ -661,7 +710,7 @@ async function generateCopilotConfig(rules, config, baseDir) {
|
|
|
661
710
|
}
|
|
662
711
|
const ignorePatterns = await loadIgnorePatterns(baseDir);
|
|
663
712
|
if (ignorePatterns.patterns.length > 0) {
|
|
664
|
-
const copilotIgnorePath = baseDir ? (0,
|
|
713
|
+
const copilotIgnorePath = baseDir ? (0, import_node_path7.join)(baseDir, ".copilotignore") : ".copilotignore";
|
|
665
714
|
const copilotIgnoreContent = generateCopilotIgnore(ignorePatterns.patterns);
|
|
666
715
|
outputs.push({
|
|
667
716
|
tool: "copilot",
|
|
@@ -697,13 +746,13 @@ function generateCopilotIgnore(patterns) {
|
|
|
697
746
|
}
|
|
698
747
|
|
|
699
748
|
// src/generators/rules/cursor.ts
|
|
700
|
-
var
|
|
749
|
+
var import_node_path8 = require("path");
|
|
701
750
|
async function generateCursorConfig(rules, config, baseDir) {
|
|
702
751
|
const outputs = [];
|
|
703
752
|
for (const rule of rules) {
|
|
704
753
|
const content = generateCursorMarkdown(rule);
|
|
705
|
-
const outputDir = baseDir ? (0,
|
|
706
|
-
const filepath = (0,
|
|
754
|
+
const outputDir = baseDir ? (0, import_node_path8.join)(baseDir, config.outputPaths.cursor) : config.outputPaths.cursor;
|
|
755
|
+
const filepath = (0, import_node_path8.join)(outputDir, `${rule.filename}.mdc`);
|
|
707
756
|
outputs.push({
|
|
708
757
|
tool: "cursor",
|
|
709
758
|
filepath,
|
|
@@ -712,7 +761,7 @@ async function generateCursorConfig(rules, config, baseDir) {
|
|
|
712
761
|
}
|
|
713
762
|
const ignorePatterns = await loadIgnorePatterns(baseDir);
|
|
714
763
|
if (ignorePatterns.patterns.length > 0) {
|
|
715
|
-
const cursorIgnorePath = baseDir ? (0,
|
|
764
|
+
const cursorIgnorePath = baseDir ? (0, import_node_path8.join)(baseDir, ".cursorignore") : ".cursorignore";
|
|
716
765
|
const cursorIgnoreContent = generateCursorIgnore(ignorePatterns.patterns);
|
|
717
766
|
outputs.push({
|
|
718
767
|
tool: "cursor",
|
|
@@ -753,15 +802,15 @@ function generateCursorIgnore(patterns) {
|
|
|
753
802
|
}
|
|
754
803
|
|
|
755
804
|
// src/generators/rules/geminicli.ts
|
|
756
|
-
var
|
|
805
|
+
var import_node_path9 = require("path");
|
|
757
806
|
async function generateGeminiConfig(rules, config, baseDir) {
|
|
758
807
|
const outputs = [];
|
|
759
808
|
const rootRule = rules.find((rule) => rule.frontmatter.root === true);
|
|
760
809
|
const memoryRules = rules.filter((rule) => rule.frontmatter.root === false);
|
|
761
810
|
for (const rule of memoryRules) {
|
|
762
811
|
const content = generateGeminiMemoryMarkdown(rule);
|
|
763
|
-
const outputDir = baseDir ? (0,
|
|
764
|
-
const filepath = (0,
|
|
812
|
+
const outputDir = baseDir ? (0, import_node_path9.join)(baseDir, config.outputPaths.geminicli) : config.outputPaths.geminicli;
|
|
813
|
+
const filepath = (0, import_node_path9.join)(outputDir, `${rule.filename}.md`);
|
|
765
814
|
outputs.push({
|
|
766
815
|
tool: "geminicli",
|
|
767
816
|
filepath,
|
|
@@ -769,7 +818,7 @@ async function generateGeminiConfig(rules, config, baseDir) {
|
|
|
769
818
|
});
|
|
770
819
|
}
|
|
771
820
|
const rootContent = generateGeminiRootMarkdown(rootRule, memoryRules, baseDir);
|
|
772
|
-
const rootFilepath = baseDir ? (0,
|
|
821
|
+
const rootFilepath = baseDir ? (0, import_node_path9.join)(baseDir, "GEMINI.md") : "GEMINI.md";
|
|
773
822
|
outputs.push({
|
|
774
823
|
tool: "geminicli",
|
|
775
824
|
filepath: rootFilepath,
|
|
@@ -777,7 +826,7 @@ async function generateGeminiConfig(rules, config, baseDir) {
|
|
|
777
826
|
});
|
|
778
827
|
const ignorePatterns = await loadIgnorePatterns(baseDir);
|
|
779
828
|
if (ignorePatterns.patterns.length > 0) {
|
|
780
|
-
const aiexcludePath = baseDir ? (0,
|
|
829
|
+
const aiexcludePath = baseDir ? (0, import_node_path9.join)(baseDir, ".aiexclude") : ".aiexclude";
|
|
781
830
|
const aiexcludeContent = generateAiexclude(ignorePatterns.patterns);
|
|
782
831
|
outputs.push({
|
|
783
832
|
tool: "geminicli",
|
|
@@ -825,13 +874,13 @@ function generateAiexclude(patterns) {
|
|
|
825
874
|
}
|
|
826
875
|
|
|
827
876
|
// src/generators/rules/roo.ts
|
|
828
|
-
var
|
|
877
|
+
var import_node_path10 = require("path");
|
|
829
878
|
async function generateRooConfig(rules, config, baseDir) {
|
|
830
879
|
const outputs = [];
|
|
831
880
|
for (const rule of rules) {
|
|
832
881
|
const content = generateRooMarkdown(rule);
|
|
833
|
-
const outputDir = baseDir ? (0,
|
|
834
|
-
const filepath = (0,
|
|
882
|
+
const outputDir = baseDir ? (0, import_node_path10.join)(baseDir, config.outputPaths.roo) : config.outputPaths.roo;
|
|
883
|
+
const filepath = (0, import_node_path10.join)(outputDir, `${rule.filename}.md`);
|
|
835
884
|
outputs.push({
|
|
836
885
|
tool: "roo",
|
|
837
886
|
filepath,
|
|
@@ -840,7 +889,7 @@ async function generateRooConfig(rules, config, baseDir) {
|
|
|
840
889
|
}
|
|
841
890
|
const ignorePatterns = await loadIgnorePatterns(baseDir);
|
|
842
891
|
if (ignorePatterns.patterns.length > 0) {
|
|
843
|
-
const rooIgnorePath = baseDir ? (0,
|
|
892
|
+
const rooIgnorePath = baseDir ? (0, import_node_path10.join)(baseDir, ".rooignore") : ".rooignore";
|
|
844
893
|
const rooIgnoreContent = generateRooIgnore(ignorePatterns.patterns);
|
|
845
894
|
outputs.push({
|
|
846
895
|
tool: "roo",
|
|
@@ -913,7 +962,7 @@ async function generateForTool(tool, rules, config, baseDir) {
|
|
|
913
962
|
}
|
|
914
963
|
|
|
915
964
|
// src/core/parser.ts
|
|
916
|
-
var
|
|
965
|
+
var import_node_path11 = require("path");
|
|
917
966
|
var import_gray_matter = __toESM(require("gray-matter"));
|
|
918
967
|
async function parseRulesFromDirectory(aiRulesDir) {
|
|
919
968
|
const ignorePatterns = await loadIgnorePatterns();
|
|
@@ -950,7 +999,7 @@ async function parseRuleFile(filepath) {
|
|
|
950
999
|
const parsed = (0, import_gray_matter.default)(content);
|
|
951
1000
|
validateFrontmatter(parsed.data, filepath);
|
|
952
1001
|
const frontmatter = parsed.data;
|
|
953
|
-
const filename = (0,
|
|
1002
|
+
const filename = (0, import_node_path11.basename)(filepath, ".md");
|
|
954
1003
|
return {
|
|
955
1004
|
frontmatter,
|
|
956
1005
|
content: parsed.content,
|
|
@@ -1080,7 +1129,7 @@ async function validateRule(rule) {
|
|
|
1080
1129
|
|
|
1081
1130
|
// src/core/mcp-generator.ts
|
|
1082
1131
|
var import_node_os = __toESM(require("os"));
|
|
1083
|
-
var
|
|
1132
|
+
var import_node_path13 = __toESM(require("path"));
|
|
1084
1133
|
|
|
1085
1134
|
// src/generators/mcp/index.ts
|
|
1086
1135
|
init_claude();
|
|
@@ -1092,9 +1141,9 @@ init_roo();
|
|
|
1092
1141
|
|
|
1093
1142
|
// src/core/mcp-parser.ts
|
|
1094
1143
|
var import_node_fs = __toESM(require("fs"));
|
|
1095
|
-
var
|
|
1144
|
+
var import_node_path12 = __toESM(require("path"));
|
|
1096
1145
|
function parseMcpConfig(projectRoot) {
|
|
1097
|
-
const mcpPath =
|
|
1146
|
+
const mcpPath = import_node_path12.default.join(projectRoot, ".rulesync", ".mcp.json");
|
|
1098
1147
|
if (!import_node_fs.default.existsSync(mcpPath)) {
|
|
1099
1148
|
return null;
|
|
1100
1149
|
}
|
|
@@ -1130,32 +1179,32 @@ async function generateMcpConfigs(projectRoot, baseDir) {
|
|
|
1130
1179
|
const generators = [
|
|
1131
1180
|
{
|
|
1132
1181
|
tool: "claude-project",
|
|
1133
|
-
path:
|
|
1182
|
+
path: import_node_path13.default.join(targetRoot, ".mcp.json"),
|
|
1134
1183
|
generate: () => generateClaudeMcp(config, "project")
|
|
1135
1184
|
},
|
|
1136
1185
|
{
|
|
1137
1186
|
tool: "copilot-editor",
|
|
1138
|
-
path:
|
|
1187
|
+
path: import_node_path13.default.join(targetRoot, ".vscode", "mcp.json"),
|
|
1139
1188
|
generate: () => generateCopilotMcp(config, "editor")
|
|
1140
1189
|
},
|
|
1141
1190
|
{
|
|
1142
1191
|
tool: "cursor-project",
|
|
1143
|
-
path:
|
|
1192
|
+
path: import_node_path13.default.join(targetRoot, ".cursor", "mcp.json"),
|
|
1144
1193
|
generate: () => generateCursorMcp(config, "project")
|
|
1145
1194
|
},
|
|
1146
1195
|
{
|
|
1147
1196
|
tool: "cline-project",
|
|
1148
|
-
path:
|
|
1197
|
+
path: import_node_path13.default.join(targetRoot, ".cline", "mcp.json"),
|
|
1149
1198
|
generate: () => generateClineMcp(config, "project")
|
|
1150
1199
|
},
|
|
1151
1200
|
{
|
|
1152
1201
|
tool: "gemini-project",
|
|
1153
|
-
path:
|
|
1202
|
+
path: import_node_path13.default.join(targetRoot, ".gemini", "settings.json"),
|
|
1154
1203
|
generate: () => generateGeminiCliMcp(config, "project")
|
|
1155
1204
|
},
|
|
1156
1205
|
{
|
|
1157
1206
|
tool: "roo-project",
|
|
1158
|
-
path:
|
|
1207
|
+
path: import_node_path13.default.join(targetRoot, ".roo", "mcp.json"),
|
|
1159
1208
|
generate: () => generateRooMcp(config, "project")
|
|
1160
1209
|
}
|
|
1161
1210
|
];
|
|
@@ -1163,17 +1212,17 @@ async function generateMcpConfigs(projectRoot, baseDir) {
|
|
|
1163
1212
|
generators.push(
|
|
1164
1213
|
{
|
|
1165
1214
|
tool: "claude-global",
|
|
1166
|
-
path:
|
|
1215
|
+
path: import_node_path13.default.join(import_node_os.default.homedir(), ".claude", "settings.json"),
|
|
1167
1216
|
generate: () => generateClaudeMcp(config, "global")
|
|
1168
1217
|
},
|
|
1169
1218
|
{
|
|
1170
1219
|
tool: "cursor-global",
|
|
1171
|
-
path:
|
|
1220
|
+
path: import_node_path13.default.join(import_node_os.default.homedir(), ".cursor", "mcp.json"),
|
|
1172
1221
|
generate: () => generateCursorMcp(config, "global")
|
|
1173
1222
|
},
|
|
1174
1223
|
{
|
|
1175
1224
|
tool: "gemini-global",
|
|
1176
|
-
path:
|
|
1225
|
+
path: import_node_path13.default.join(import_node_os.default.homedir(), ".gemini", "settings.json"),
|
|
1177
1226
|
generate: () => generateGeminiCliMcp(config, "global")
|
|
1178
1227
|
}
|
|
1179
1228
|
);
|
|
@@ -1332,9 +1381,9 @@ Generating configurations for base directory: ${baseDir}`);
|
|
|
1332
1381
|
|
|
1333
1382
|
// src/cli/commands/gitignore.ts
|
|
1334
1383
|
var import_node_fs2 = require("fs");
|
|
1335
|
-
var
|
|
1384
|
+
var import_node_path14 = require("path");
|
|
1336
1385
|
var gitignoreCommand = async () => {
|
|
1337
|
-
const gitignorePath = (0,
|
|
1386
|
+
const gitignorePath = (0, import_node_path14.join)(process.cwd(), ".gitignore");
|
|
1338
1387
|
const rulesFilesToIgnore = [
|
|
1339
1388
|
"# Generated by rulesync - AI tool configuration files",
|
|
1340
1389
|
"**/.github/copilot-instructions.md",
|
|
@@ -1387,17 +1436,17 @@ ${linesToAdd.join("\n")}
|
|
|
1387
1436
|
};
|
|
1388
1437
|
|
|
1389
1438
|
// src/core/importer.ts
|
|
1390
|
-
var
|
|
1439
|
+
var import_node_path21 = require("path");
|
|
1391
1440
|
var import_gray_matter4 = __toESM(require("gray-matter"));
|
|
1392
1441
|
|
|
1393
1442
|
// src/parsers/claudecode.ts
|
|
1394
|
-
var
|
|
1443
|
+
var import_node_path15 = require("path");
|
|
1395
1444
|
async function parseClaudeConfiguration(baseDir = process.cwd()) {
|
|
1396
1445
|
const errors = [];
|
|
1397
1446
|
const rules = [];
|
|
1398
1447
|
let ignorePatterns;
|
|
1399
1448
|
let mcpServers;
|
|
1400
|
-
const claudeFilePath = (0,
|
|
1449
|
+
const claudeFilePath = (0, import_node_path15.join)(baseDir, "CLAUDE.md");
|
|
1401
1450
|
if (!await fileExists(claudeFilePath)) {
|
|
1402
1451
|
errors.push("CLAUDE.md file not found");
|
|
1403
1452
|
return { rules, errors };
|
|
@@ -1408,12 +1457,12 @@ async function parseClaudeConfiguration(baseDir = process.cwd()) {
|
|
|
1408
1457
|
if (mainRule) {
|
|
1409
1458
|
rules.push(mainRule);
|
|
1410
1459
|
}
|
|
1411
|
-
const memoryDir = (0,
|
|
1460
|
+
const memoryDir = (0, import_node_path15.join)(baseDir, ".claude", "memories");
|
|
1412
1461
|
if (await fileExists(memoryDir)) {
|
|
1413
1462
|
const memoryRules = await parseClaudeMemoryFiles(memoryDir);
|
|
1414
1463
|
rules.push(...memoryRules);
|
|
1415
1464
|
}
|
|
1416
|
-
const settingsPath = (0,
|
|
1465
|
+
const settingsPath = (0, import_node_path15.join)(baseDir, ".claude", "settings.json");
|
|
1417
1466
|
if (await fileExists(settingsPath)) {
|
|
1418
1467
|
const settingsResult = await parseClaudeSettings(settingsPath);
|
|
1419
1468
|
if (settingsResult.ignorePatterns) {
|
|
@@ -1470,10 +1519,10 @@ async function parseClaudeMemoryFiles(memoryDir) {
|
|
|
1470
1519
|
const files = await readdir2(memoryDir);
|
|
1471
1520
|
for (const file of files) {
|
|
1472
1521
|
if (file.endsWith(".md")) {
|
|
1473
|
-
const filePath = (0,
|
|
1522
|
+
const filePath = (0, import_node_path15.join)(memoryDir, file);
|
|
1474
1523
|
const content = await readFileContent(filePath);
|
|
1475
1524
|
if (content.trim()) {
|
|
1476
|
-
const filename = (0,
|
|
1525
|
+
const filename = (0, import_node_path15.basename)(file, ".md");
|
|
1477
1526
|
const frontmatter = {
|
|
1478
1527
|
root: false,
|
|
1479
1528
|
targets: ["claudecode"],
|
|
@@ -1489,7 +1538,7 @@ async function parseClaudeMemoryFiles(memoryDir) {
|
|
|
1489
1538
|
}
|
|
1490
1539
|
}
|
|
1491
1540
|
}
|
|
1492
|
-
} catch
|
|
1541
|
+
} catch {
|
|
1493
1542
|
}
|
|
1494
1543
|
return rules;
|
|
1495
1544
|
}
|
|
@@ -1500,17 +1549,25 @@ async function parseClaudeSettings(settingsPath) {
|
|
|
1500
1549
|
try {
|
|
1501
1550
|
const content = await readFileContent(settingsPath);
|
|
1502
1551
|
const settings = JSON.parse(content);
|
|
1503
|
-
if (settings
|
|
1504
|
-
const
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1552
|
+
if (typeof settings === "object" && settings !== null && "permissions" in settings) {
|
|
1553
|
+
const permissions = settings.permissions;
|
|
1554
|
+
if (permissions && "deny" in permissions && Array.isArray(permissions.deny)) {
|
|
1555
|
+
const readPatterns = permissions.deny.filter(
|
|
1556
|
+
(rule) => typeof rule === "string" && rule.startsWith("Read(") && rule.endsWith(")")
|
|
1557
|
+
).map((rule) => {
|
|
1558
|
+
const match = rule.match(/^Read\((.+)\)$/);
|
|
1559
|
+
return match ? match[1] : null;
|
|
1560
|
+
}).filter((pattern) => pattern !== null);
|
|
1561
|
+
if (readPatterns.length > 0) {
|
|
1562
|
+
ignorePatterns = readPatterns;
|
|
1563
|
+
}
|
|
1510
1564
|
}
|
|
1511
1565
|
}
|
|
1512
|
-
if (settings
|
|
1513
|
-
|
|
1566
|
+
if (typeof settings === "object" && settings !== null && "mcpServers" in settings) {
|
|
1567
|
+
const servers = settings.mcpServers;
|
|
1568
|
+
if (servers && typeof servers === "object" && Object.keys(servers).length > 0) {
|
|
1569
|
+
mcpServers = servers;
|
|
1570
|
+
}
|
|
1514
1571
|
}
|
|
1515
1572
|
} catch (error) {
|
|
1516
1573
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -1524,11 +1581,11 @@ async function parseClaudeSettings(settingsPath) {
|
|
|
1524
1581
|
}
|
|
1525
1582
|
|
|
1526
1583
|
// src/parsers/cline.ts
|
|
1527
|
-
var
|
|
1584
|
+
var import_node_path16 = require("path");
|
|
1528
1585
|
async function parseClineConfiguration(baseDir = process.cwd()) {
|
|
1529
1586
|
const errors = [];
|
|
1530
1587
|
const rules = [];
|
|
1531
|
-
const clineFilePath = (0,
|
|
1588
|
+
const clineFilePath = (0, import_node_path16.join)(baseDir, ".cline", "instructions.md");
|
|
1532
1589
|
if (await fileExists(clineFilePath)) {
|
|
1533
1590
|
try {
|
|
1534
1591
|
const content = await readFileContent(clineFilePath);
|
|
@@ -1551,14 +1608,14 @@ async function parseClineConfiguration(baseDir = process.cwd()) {
|
|
|
1551
1608
|
errors.push(`Failed to parse .cline/instructions.md: ${errorMessage}`);
|
|
1552
1609
|
}
|
|
1553
1610
|
}
|
|
1554
|
-
const clinerulesDirPath = (0,
|
|
1611
|
+
const clinerulesDirPath = (0, import_node_path16.join)(baseDir, ".clinerules");
|
|
1555
1612
|
if (await fileExists(clinerulesDirPath)) {
|
|
1556
1613
|
try {
|
|
1557
1614
|
const { readdir: readdir2 } = await import("fs/promises");
|
|
1558
1615
|
const files = await readdir2(clinerulesDirPath);
|
|
1559
1616
|
for (const file of files) {
|
|
1560
1617
|
if (file.endsWith(".md")) {
|
|
1561
|
-
const filePath = (0,
|
|
1618
|
+
const filePath = (0, import_node_path16.join)(clinerulesDirPath, file);
|
|
1562
1619
|
try {
|
|
1563
1620
|
const content = await readFileContent(filePath);
|
|
1564
1621
|
if (content.trim()) {
|
|
@@ -1594,12 +1651,12 @@ async function parseClineConfiguration(baseDir = process.cwd()) {
|
|
|
1594
1651
|
}
|
|
1595
1652
|
|
|
1596
1653
|
// src/parsers/copilot.ts
|
|
1597
|
-
var
|
|
1654
|
+
var import_node_path17 = require("path");
|
|
1598
1655
|
var import_gray_matter2 = __toESM(require("gray-matter"));
|
|
1599
1656
|
async function parseCopilotConfiguration(baseDir = process.cwd()) {
|
|
1600
1657
|
const errors = [];
|
|
1601
1658
|
const rules = [];
|
|
1602
|
-
const copilotFilePath = (0,
|
|
1659
|
+
const copilotFilePath = (0, import_node_path17.join)(baseDir, ".github", "copilot-instructions.md");
|
|
1603
1660
|
if (await fileExists(copilotFilePath)) {
|
|
1604
1661
|
try {
|
|
1605
1662
|
const rawContent = await readFileContent(copilotFilePath);
|
|
@@ -1624,19 +1681,19 @@ async function parseCopilotConfiguration(baseDir = process.cwd()) {
|
|
|
1624
1681
|
errors.push(`Failed to parse copilot-instructions.md: ${errorMessage}`);
|
|
1625
1682
|
}
|
|
1626
1683
|
}
|
|
1627
|
-
const instructionsDir = (0,
|
|
1684
|
+
const instructionsDir = (0, import_node_path17.join)(baseDir, ".github", "instructions");
|
|
1628
1685
|
if (await fileExists(instructionsDir)) {
|
|
1629
1686
|
try {
|
|
1630
1687
|
const { readdir: readdir2 } = await import("fs/promises");
|
|
1631
1688
|
const files = await readdir2(instructionsDir);
|
|
1632
1689
|
for (const file of files) {
|
|
1633
1690
|
if (file.endsWith(".instructions.md")) {
|
|
1634
|
-
const filePath = (0,
|
|
1691
|
+
const filePath = (0, import_node_path17.join)(instructionsDir, file);
|
|
1635
1692
|
const rawContent = await readFileContent(filePath);
|
|
1636
1693
|
const parsed = (0, import_gray_matter2.default)(rawContent);
|
|
1637
1694
|
const content = parsed.content.trim();
|
|
1638
1695
|
if (content) {
|
|
1639
|
-
const filename = (0,
|
|
1696
|
+
const filename = (0, import_node_path17.basename)(file, ".instructions.md");
|
|
1640
1697
|
const frontmatter = {
|
|
1641
1698
|
root: false,
|
|
1642
1699
|
targets: ["copilot"],
|
|
@@ -1666,19 +1723,19 @@ async function parseCopilotConfiguration(baseDir = process.cwd()) {
|
|
|
1666
1723
|
}
|
|
1667
1724
|
|
|
1668
1725
|
// src/parsers/cursor.ts
|
|
1669
|
-
var
|
|
1726
|
+
var import_node_path18 = require("path");
|
|
1670
1727
|
var import_gray_matter3 = __toESM(require("gray-matter"));
|
|
1671
|
-
var import_js_yaml =
|
|
1728
|
+
var import_js_yaml = require("js-yaml");
|
|
1672
1729
|
var customMatterOptions = {
|
|
1673
1730
|
engines: {
|
|
1674
1731
|
yaml: {
|
|
1675
1732
|
parse: (str) => {
|
|
1676
1733
|
try {
|
|
1677
1734
|
const preprocessed = str.replace(/^(\s*globs:\s*)\*\s*$/gm, '$1"*"');
|
|
1678
|
-
return import_js_yaml.
|
|
1735
|
+
return (0, import_js_yaml.load)(preprocessed, { schema: import_js_yaml.DEFAULT_SCHEMA });
|
|
1679
1736
|
} catch (error) {
|
|
1680
1737
|
try {
|
|
1681
|
-
return import_js_yaml.
|
|
1738
|
+
return (0, import_js_yaml.load)(str, { schema: import_js_yaml.FAILSAFE_SCHEMA });
|
|
1682
1739
|
} catch {
|
|
1683
1740
|
throw error;
|
|
1684
1741
|
}
|
|
@@ -1692,7 +1749,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
1692
1749
|
const rules = [];
|
|
1693
1750
|
let ignorePatterns;
|
|
1694
1751
|
let mcpServers;
|
|
1695
|
-
const cursorFilePath = (0,
|
|
1752
|
+
const cursorFilePath = (0, import_node_path18.join)(baseDir, ".cursorrules");
|
|
1696
1753
|
if (await fileExists(cursorFilePath)) {
|
|
1697
1754
|
try {
|
|
1698
1755
|
const rawContent = await readFileContent(cursorFilePath);
|
|
@@ -1717,20 +1774,20 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
1717
1774
|
errors.push(`Failed to parse .cursorrules file: ${errorMessage}`);
|
|
1718
1775
|
}
|
|
1719
1776
|
}
|
|
1720
|
-
const cursorRulesDir = (0,
|
|
1777
|
+
const cursorRulesDir = (0, import_node_path18.join)(baseDir, ".cursor", "rules");
|
|
1721
1778
|
if (await fileExists(cursorRulesDir)) {
|
|
1722
1779
|
try {
|
|
1723
1780
|
const { readdir: readdir2 } = await import("fs/promises");
|
|
1724
1781
|
const files = await readdir2(cursorRulesDir);
|
|
1725
1782
|
for (const file of files) {
|
|
1726
1783
|
if (file.endsWith(".mdc")) {
|
|
1727
|
-
const filePath = (0,
|
|
1784
|
+
const filePath = (0, import_node_path18.join)(cursorRulesDir, file);
|
|
1728
1785
|
try {
|
|
1729
1786
|
const rawContent = await readFileContent(filePath);
|
|
1730
1787
|
const parsed = (0, import_gray_matter3.default)(rawContent, customMatterOptions);
|
|
1731
1788
|
const content = parsed.content.trim();
|
|
1732
1789
|
if (content) {
|
|
1733
|
-
const filename = (0,
|
|
1790
|
+
const filename = (0, import_node_path18.basename)(file, ".mdc");
|
|
1734
1791
|
const frontmatter = {
|
|
1735
1792
|
root: false,
|
|
1736
1793
|
targets: ["cursor"],
|
|
@@ -1758,7 +1815,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
1758
1815
|
if (rules.length === 0) {
|
|
1759
1816
|
errors.push("No Cursor configuration files found (.cursorrules or .cursor/rules/*.mdc)");
|
|
1760
1817
|
}
|
|
1761
|
-
const cursorIgnorePath = (0,
|
|
1818
|
+
const cursorIgnorePath = (0, import_node_path18.join)(baseDir, ".cursorignore");
|
|
1762
1819
|
if (await fileExists(cursorIgnorePath)) {
|
|
1763
1820
|
try {
|
|
1764
1821
|
const content = await readFileContent(cursorIgnorePath);
|
|
@@ -1771,7 +1828,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
1771
1828
|
errors.push(`Failed to parse .cursorignore: ${errorMessage}`);
|
|
1772
1829
|
}
|
|
1773
1830
|
}
|
|
1774
|
-
const cursorMcpPath = (0,
|
|
1831
|
+
const cursorMcpPath = (0, import_node_path18.join)(baseDir, ".cursor", "mcp.json");
|
|
1775
1832
|
if (await fileExists(cursorMcpPath)) {
|
|
1776
1833
|
try {
|
|
1777
1834
|
const content = await readFileContent(cursorMcpPath);
|
|
@@ -1793,13 +1850,13 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
1793
1850
|
}
|
|
1794
1851
|
|
|
1795
1852
|
// src/parsers/geminicli.ts
|
|
1796
|
-
var
|
|
1853
|
+
var import_node_path19 = require("path");
|
|
1797
1854
|
async function parseGeminiConfiguration(baseDir = process.cwd()) {
|
|
1798
1855
|
const errors = [];
|
|
1799
1856
|
const rules = [];
|
|
1800
1857
|
let ignorePatterns;
|
|
1801
1858
|
let mcpServers;
|
|
1802
|
-
const geminiFilePath = (0,
|
|
1859
|
+
const geminiFilePath = (0, import_node_path19.join)(baseDir, "GEMINI.md");
|
|
1803
1860
|
if (!await fileExists(geminiFilePath)) {
|
|
1804
1861
|
errors.push("GEMINI.md file not found");
|
|
1805
1862
|
return { rules, errors };
|
|
@@ -1810,12 +1867,12 @@ async function parseGeminiConfiguration(baseDir = process.cwd()) {
|
|
|
1810
1867
|
if (mainRule) {
|
|
1811
1868
|
rules.push(mainRule);
|
|
1812
1869
|
}
|
|
1813
|
-
const memoryDir = (0,
|
|
1870
|
+
const memoryDir = (0, import_node_path19.join)(baseDir, ".gemini", "memories");
|
|
1814
1871
|
if (await fileExists(memoryDir)) {
|
|
1815
1872
|
const memoryRules = await parseGeminiMemoryFiles(memoryDir);
|
|
1816
1873
|
rules.push(...memoryRules);
|
|
1817
1874
|
}
|
|
1818
|
-
const settingsPath = (0,
|
|
1875
|
+
const settingsPath = (0, import_node_path19.join)(baseDir, ".gemini", "settings.json");
|
|
1819
1876
|
if (await fileExists(settingsPath)) {
|
|
1820
1877
|
const settingsResult = await parseGeminiSettings(settingsPath);
|
|
1821
1878
|
if (settingsResult.ignorePatterns) {
|
|
@@ -1826,7 +1883,7 @@ async function parseGeminiConfiguration(baseDir = process.cwd()) {
|
|
|
1826
1883
|
}
|
|
1827
1884
|
errors.push(...settingsResult.errors);
|
|
1828
1885
|
}
|
|
1829
|
-
const aiexcludePath = (0,
|
|
1886
|
+
const aiexcludePath = (0, import_node_path19.join)(baseDir, ".aiexclude");
|
|
1830
1887
|
if (await fileExists(aiexcludePath)) {
|
|
1831
1888
|
const aiexcludePatterns = await parseAiexclude(aiexcludePath);
|
|
1832
1889
|
if (aiexcludePatterns.length > 0) {
|
|
@@ -1879,10 +1936,10 @@ async function parseGeminiMemoryFiles(memoryDir) {
|
|
|
1879
1936
|
const files = await readdir2(memoryDir);
|
|
1880
1937
|
for (const file of files) {
|
|
1881
1938
|
if (file.endsWith(".md")) {
|
|
1882
|
-
const filePath = (0,
|
|
1939
|
+
const filePath = (0, import_node_path19.join)(memoryDir, file);
|
|
1883
1940
|
const content = await readFileContent(filePath);
|
|
1884
1941
|
if (content.trim()) {
|
|
1885
|
-
const filename = (0,
|
|
1942
|
+
const filename = (0, import_node_path19.basename)(file, ".md");
|
|
1886
1943
|
const frontmatter = {
|
|
1887
1944
|
root: false,
|
|
1888
1945
|
targets: ["geminicli"],
|
|
@@ -1898,7 +1955,7 @@ async function parseGeminiMemoryFiles(memoryDir) {
|
|
|
1898
1955
|
}
|
|
1899
1956
|
}
|
|
1900
1957
|
}
|
|
1901
|
-
} catch
|
|
1958
|
+
} catch {
|
|
1902
1959
|
}
|
|
1903
1960
|
return rules;
|
|
1904
1961
|
}
|
|
@@ -1925,17 +1982,17 @@ async function parseAiexclude(aiexcludePath) {
|
|
|
1925
1982
|
const content = await readFileContent(aiexcludePath);
|
|
1926
1983
|
const patterns = content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
|
|
1927
1984
|
return patterns;
|
|
1928
|
-
} catch
|
|
1985
|
+
} catch {
|
|
1929
1986
|
return [];
|
|
1930
1987
|
}
|
|
1931
1988
|
}
|
|
1932
1989
|
|
|
1933
1990
|
// src/parsers/roo.ts
|
|
1934
|
-
var
|
|
1991
|
+
var import_node_path20 = require("path");
|
|
1935
1992
|
async function parseRooConfiguration(baseDir = process.cwd()) {
|
|
1936
1993
|
const errors = [];
|
|
1937
1994
|
const rules = [];
|
|
1938
|
-
const rooFilePath = (0,
|
|
1995
|
+
const rooFilePath = (0, import_node_path20.join)(baseDir, ".roo", "instructions.md");
|
|
1939
1996
|
if (await fileExists(rooFilePath)) {
|
|
1940
1997
|
try {
|
|
1941
1998
|
const content = await readFileContent(rooFilePath);
|
|
@@ -1958,14 +2015,14 @@ async function parseRooConfiguration(baseDir = process.cwd()) {
|
|
|
1958
2015
|
errors.push(`Failed to parse .roo/instructions.md: ${errorMessage}`);
|
|
1959
2016
|
}
|
|
1960
2017
|
}
|
|
1961
|
-
const rooRulesDir = (0,
|
|
2018
|
+
const rooRulesDir = (0, import_node_path20.join)(baseDir, ".roo", "rules");
|
|
1962
2019
|
if (await fileExists(rooRulesDir)) {
|
|
1963
2020
|
try {
|
|
1964
2021
|
const { readdir: readdir2 } = await import("fs/promises");
|
|
1965
2022
|
const files = await readdir2(rooRulesDir);
|
|
1966
2023
|
for (const file of files) {
|
|
1967
2024
|
if (file.endsWith(".md")) {
|
|
1968
|
-
const filePath = (0,
|
|
2025
|
+
const filePath = (0, import_node_path20.join)(rooRulesDir, file);
|
|
1969
2026
|
try {
|
|
1970
2027
|
const content = await readFileContent(filePath);
|
|
1971
2028
|
if (content.trim()) {
|
|
@@ -2066,7 +2123,7 @@ async function importConfiguration(options) {
|
|
|
2066
2123
|
if (rules.length === 0 && !ignorePatterns && !mcpServers) {
|
|
2067
2124
|
return { success: false, rulesCreated: 0, errors };
|
|
2068
2125
|
}
|
|
2069
|
-
const rulesDirPath = (0,
|
|
2126
|
+
const rulesDirPath = (0, import_node_path21.join)(baseDir, rulesDir);
|
|
2070
2127
|
try {
|
|
2071
2128
|
const { mkdir: mkdir3 } = await import("fs/promises");
|
|
2072
2129
|
await mkdir3(rulesDirPath, { recursive: true });
|
|
@@ -2080,7 +2137,7 @@ async function importConfiguration(options) {
|
|
|
2080
2137
|
try {
|
|
2081
2138
|
const baseFilename = `${tool}__${rule.filename}`;
|
|
2082
2139
|
const filename = await generateUniqueFilename(rulesDirPath, baseFilename);
|
|
2083
|
-
const filePath = (0,
|
|
2140
|
+
const filePath = (0, import_node_path21.join)(rulesDirPath, `${filename}.md`);
|
|
2084
2141
|
const content = generateRuleFileContent(rule);
|
|
2085
2142
|
await writeFileContent(filePath, content);
|
|
2086
2143
|
rulesCreated++;
|
|
@@ -2095,7 +2152,7 @@ async function importConfiguration(options) {
|
|
|
2095
2152
|
let ignoreFileCreated = false;
|
|
2096
2153
|
if (ignorePatterns && ignorePatterns.length > 0) {
|
|
2097
2154
|
try {
|
|
2098
|
-
const rulesyncignorePath = (0,
|
|
2155
|
+
const rulesyncignorePath = (0, import_node_path21.join)(baseDir, ".rulesyncignore");
|
|
2099
2156
|
const ignoreContent = `${ignorePatterns.join("\n")}
|
|
2100
2157
|
`;
|
|
2101
2158
|
await writeFileContent(rulesyncignorePath, ignoreContent);
|
|
@@ -2111,7 +2168,7 @@ async function importConfiguration(options) {
|
|
|
2111
2168
|
let mcpFileCreated = false;
|
|
2112
2169
|
if (mcpServers && Object.keys(mcpServers).length > 0) {
|
|
2113
2170
|
try {
|
|
2114
|
-
const mcpPath = (0,
|
|
2171
|
+
const mcpPath = (0, import_node_path21.join)(baseDir, rulesDir, ".mcp.json");
|
|
2115
2172
|
const mcpContent = `${JSON.stringify({ mcpServers }, null, 2)}
|
|
2116
2173
|
`;
|
|
2117
2174
|
await writeFileContent(mcpPath, mcpContent);
|
|
@@ -2139,7 +2196,7 @@ function generateRuleFileContent(rule) {
|
|
|
2139
2196
|
async function generateUniqueFilename(rulesDir, baseFilename) {
|
|
2140
2197
|
let filename = baseFilename;
|
|
2141
2198
|
let counter = 1;
|
|
2142
|
-
while (await fileExists((0,
|
|
2199
|
+
while (await fileExists((0, import_node_path21.join)(rulesDir, `${filename}.md`))) {
|
|
2143
2200
|
filename = `${baseFilename}-${counter}`;
|
|
2144
2201
|
counter++;
|
|
2145
2202
|
}
|
|
@@ -2204,7 +2261,7 @@ async function importCommand(options = {}) {
|
|
|
2204
2261
|
}
|
|
2205
2262
|
|
|
2206
2263
|
// src/cli/commands/init.ts
|
|
2207
|
-
var
|
|
2264
|
+
var import_node_path22 = require("path");
|
|
2208
2265
|
async function initCommand() {
|
|
2209
2266
|
const aiRulesDir = ".rulesync";
|
|
2210
2267
|
console.log("Initializing rulesync...");
|
|
@@ -2334,7 +2391,7 @@ globs: ["src/api/**/*.ts", "src/services/**/*.ts", "src/models/**/*.ts"]
|
|
|
2334
2391
|
}
|
|
2335
2392
|
];
|
|
2336
2393
|
for (const file of sampleFiles) {
|
|
2337
|
-
const filepath = (0,
|
|
2394
|
+
const filepath = (0, import_node_path22.join)(aiRulesDir, file.filename);
|
|
2338
2395
|
if (!await fileExists(filepath)) {
|
|
2339
2396
|
await writeFileContent(filepath, file.content);
|
|
2340
2397
|
console.log(`Created ${filepath}`);
|
|
@@ -2436,13 +2493,13 @@ async function validateCommand() {
|
|
|
2436
2493
|
}
|
|
2437
2494
|
|
|
2438
2495
|
// src/cli/commands/watch.ts
|
|
2439
|
-
var import_chokidar =
|
|
2496
|
+
var import_chokidar = require("chokidar");
|
|
2440
2497
|
async function watchCommand() {
|
|
2441
2498
|
const config = getDefaultConfig();
|
|
2442
2499
|
console.log("\u{1F440} Watching for changes in .rulesync directory...");
|
|
2443
2500
|
console.log("Press Ctrl+C to stop watching");
|
|
2444
2501
|
await generateCommand({ verbose: false });
|
|
2445
|
-
const watcher = import_chokidar.
|
|
2502
|
+
const watcher = (0, import_chokidar.watch)(`${config.aiRulesDir}/**/*.md`, {
|
|
2446
2503
|
ignoreInitial: true,
|
|
2447
2504
|
persistent: true
|
|
2448
2505
|
});
|
|
@@ -2477,7 +2534,7 @@ async function watchCommand() {
|
|
|
2477
2534
|
|
|
2478
2535
|
// src/cli/index.ts
|
|
2479
2536
|
var program = new import_commander.Command();
|
|
2480
|
-
program.name("rulesync").description("Unified AI rules management CLI tool").version("0.
|
|
2537
|
+
program.name("rulesync").description("Unified AI rules management CLI tool").version("0.37.0");
|
|
2481
2538
|
program.command("init").description("Initialize rulesync in current directory").action(initCommand);
|
|
2482
2539
|
program.command("add <filename>").description("Add a new rule file").action(addCommand);
|
|
2483
2540
|
program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);
|