rulesync 0.45.0 → 0.48.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +62 -2
- package/README.md +62 -2
- package/dist/{chunk-FAZT3ILF.js → chunk-7UVBAWYG.js} +1 -1
- package/dist/{chunk-I5XVU7C6.js → chunk-7ZIUEZZQ.js} +3 -2
- package/dist/{chunk-BD37M3ZH.js → chunk-BY6RI77W.js} +1 -1
- package/dist/chunk-D365OP7N.js +86 -0
- package/dist/{chunk-DCSO5MY7.js → chunk-JWN6GRG6.js} +1 -1
- package/dist/{chunk-PJUNIIF4.js → chunk-L2JTXZZB.js} +1 -1
- package/dist/{chunk-22GWBUIP.js → chunk-OTCCHS7Q.js} +1 -1
- package/dist/{chunk-ZORSPGDD.js → chunk-P6KQZULZ.js} +1 -1
- package/dist/{claudecode-KSK2BEI7.js → claudecode-Y3GIXDUN.js} +2 -2
- package/dist/{cline-T5YVGYBF.js → cline-NS3OPXM2.js} +2 -2
- package/dist/{copilot-UDCWNUAH.js → copilot-QN2SC7Y2.js} +2 -2
- package/dist/{cursor-KPV6OVST.js → cursor-DV2IS7JF.js} +2 -2
- package/dist/{geminicli-2DC5F34J.js → geminicli-MRYTLT2T.js} +2 -2
- package/dist/index.cjs +377 -172
- package/dist/index.js +297 -142
- package/dist/kiro-S5TSM7VW.js +9 -0
- package/dist/{roo-DRA2SU4L.js → roo-NWLD3YYN.js} +2 -2
- package/package.json +4 -3
package/dist/index.cjs
CHANGED
|
@@ -27,22 +27,23 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
27
|
));
|
|
28
28
|
|
|
29
29
|
// src/types/tool-targets.ts
|
|
30
|
-
var
|
|
30
|
+
var import_mini, ToolTargetSchema, ToolTargetsSchema, WildcardTargetSchema, RulesyncTargetsSchema;
|
|
31
31
|
var init_tool_targets = __esm({
|
|
32
32
|
"src/types/tool-targets.ts"() {
|
|
33
33
|
"use strict";
|
|
34
|
-
|
|
35
|
-
ToolTargetSchema =
|
|
34
|
+
import_mini = require("zod/mini");
|
|
35
|
+
ToolTargetSchema = import_mini.z.enum([
|
|
36
36
|
"copilot",
|
|
37
37
|
"cursor",
|
|
38
38
|
"cline",
|
|
39
39
|
"claudecode",
|
|
40
40
|
"roo",
|
|
41
|
-
"geminicli"
|
|
41
|
+
"geminicli",
|
|
42
|
+
"kiro"
|
|
42
43
|
]);
|
|
43
|
-
ToolTargetsSchema =
|
|
44
|
-
WildcardTargetSchema =
|
|
45
|
-
RulesyncTargetsSchema =
|
|
44
|
+
ToolTargetsSchema = import_mini.z.array(ToolTargetSchema);
|
|
45
|
+
WildcardTargetSchema = import_mini.z.tuple([import_mini.z.literal("*")]);
|
|
46
|
+
RulesyncTargetsSchema = import_mini.z.union([ToolTargetsSchema, WildcardTargetSchema]);
|
|
46
47
|
}
|
|
47
48
|
});
|
|
48
49
|
|
|
@@ -294,6 +295,57 @@ var init_geminicli = __esm({
|
|
|
294
295
|
}
|
|
295
296
|
});
|
|
296
297
|
|
|
298
|
+
// src/generators/mcp/kiro.ts
|
|
299
|
+
function generateKiroMcp(config) {
|
|
300
|
+
const kiroConfig = {
|
|
301
|
+
mcpServers: {}
|
|
302
|
+
};
|
|
303
|
+
for (const [serverName, server] of Object.entries(config.mcpServers)) {
|
|
304
|
+
if (!shouldIncludeServer(server, "kiro")) continue;
|
|
305
|
+
const kiroServer = {};
|
|
306
|
+
if (server.command) {
|
|
307
|
+
kiroServer.command = server.command;
|
|
308
|
+
if (server.args) kiroServer.args = server.args;
|
|
309
|
+
} else if (server.url || server.httpUrl) {
|
|
310
|
+
const url = server.httpUrl || server.url;
|
|
311
|
+
if (url) {
|
|
312
|
+
kiroServer.url = url;
|
|
313
|
+
}
|
|
314
|
+
if (server.httpUrl || server.transport === "http") {
|
|
315
|
+
kiroServer.transport = "streamable-http";
|
|
316
|
+
} else if (server.transport === "sse" || server.type === "sse") {
|
|
317
|
+
kiroServer.transport = "sse";
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
if (server.env) {
|
|
321
|
+
kiroServer.env = server.env;
|
|
322
|
+
}
|
|
323
|
+
if (server.timeout) {
|
|
324
|
+
kiroServer.timeout = server.timeout;
|
|
325
|
+
}
|
|
326
|
+
if (server.disabled !== void 0) {
|
|
327
|
+
kiroServer.disabled = server.disabled;
|
|
328
|
+
}
|
|
329
|
+
if (server.transport) {
|
|
330
|
+
kiroServer.transport = server.transport;
|
|
331
|
+
}
|
|
332
|
+
if (server.kiroAutoApprove) {
|
|
333
|
+
kiroServer.autoApprove = server.kiroAutoApprove;
|
|
334
|
+
}
|
|
335
|
+
if (server.kiroAutoBlock) {
|
|
336
|
+
kiroServer.autoBlock = server.kiroAutoBlock;
|
|
337
|
+
}
|
|
338
|
+
kiroConfig.mcpServers[serverName] = kiroServer;
|
|
339
|
+
}
|
|
340
|
+
return JSON.stringify(kiroConfig, null, 2);
|
|
341
|
+
}
|
|
342
|
+
var init_kiro = __esm({
|
|
343
|
+
"src/generators/mcp/kiro.ts"() {
|
|
344
|
+
"use strict";
|
|
345
|
+
init_mcp_helpers();
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
|
|
297
349
|
// src/generators/mcp/roo.ts
|
|
298
350
|
function generateRooMcp(config) {
|
|
299
351
|
const rooConfig = {
|
|
@@ -364,10 +416,11 @@ function getDefaultConfig() {
|
|
|
364
416
|
cline: ".clinerules",
|
|
365
417
|
claudecode: ".",
|
|
366
418
|
roo: ".roo/rules",
|
|
367
|
-
geminicli: ".gemini/memories"
|
|
419
|
+
geminicli: ".gemini/memories",
|
|
420
|
+
kiro: ".kiro/steering"
|
|
368
421
|
},
|
|
369
422
|
watchEnabled: false,
|
|
370
|
-
defaultTargets: ["copilot", "cursor", "cline", "claudecode", "roo", "geminicli"]
|
|
423
|
+
defaultTargets: ["copilot", "cursor", "cline", "claudecode", "roo", "geminicli", "kiro"]
|
|
371
424
|
};
|
|
372
425
|
}
|
|
373
426
|
function resolveTargets(targets, config) {
|
|
@@ -414,27 +467,138 @@ async function addCommand(filename) {
|
|
|
414
467
|
}
|
|
415
468
|
}
|
|
416
469
|
|
|
470
|
+
// src/generators/ignore/kiro.ts
|
|
471
|
+
var import_node_path = require("path");
|
|
472
|
+
async function generateKiroIgnoreFiles(rules, config, baseDir) {
|
|
473
|
+
const outputs = [];
|
|
474
|
+
const aiignoreContent = generateAiignoreContent(rules);
|
|
475
|
+
const outputPath = baseDir || process.cwd();
|
|
476
|
+
const filepath = (0, import_node_path.join)(outputPath, ".aiignore");
|
|
477
|
+
outputs.push({
|
|
478
|
+
tool: "kiro",
|
|
479
|
+
filepath,
|
|
480
|
+
content: aiignoreContent
|
|
481
|
+
});
|
|
482
|
+
return outputs;
|
|
483
|
+
}
|
|
484
|
+
function generateAiignoreContent(rules) {
|
|
485
|
+
const lines = [
|
|
486
|
+
"# Generated by rulesync - Kiro AI-specific exclusions",
|
|
487
|
+
"# This file excludes files that can be in Git but shouldn't be read by the AI",
|
|
488
|
+
""
|
|
489
|
+
];
|
|
490
|
+
lines.push(
|
|
491
|
+
"# Data files AI shouldn't process",
|
|
492
|
+
"*.csv",
|
|
493
|
+
"*.tsv",
|
|
494
|
+
"*.sqlite",
|
|
495
|
+
"*.db",
|
|
496
|
+
"",
|
|
497
|
+
"# Large binary files",
|
|
498
|
+
"*.zip",
|
|
499
|
+
"*.tar.gz",
|
|
500
|
+
"*.rar",
|
|
501
|
+
"",
|
|
502
|
+
"# Sensitive documentation",
|
|
503
|
+
"internal-docs/",
|
|
504
|
+
"confidential/",
|
|
505
|
+
"",
|
|
506
|
+
"# Test data that might confuse AI",
|
|
507
|
+
"test/fixtures/large-*.json",
|
|
508
|
+
"benchmark-results/",
|
|
509
|
+
"",
|
|
510
|
+
"# Reinforce critical exclusions from .gitignore",
|
|
511
|
+
"*.pem",
|
|
512
|
+
"*.key",
|
|
513
|
+
".env*",
|
|
514
|
+
""
|
|
515
|
+
);
|
|
516
|
+
const rulePatterns = extractIgnorePatternsFromRules(rules);
|
|
517
|
+
if (rulePatterns.length > 0) {
|
|
518
|
+
lines.push("# Project-specific exclusions from rulesync rules");
|
|
519
|
+
lines.push(...rulePatterns);
|
|
520
|
+
lines.push("");
|
|
521
|
+
}
|
|
522
|
+
return lines.join("\n");
|
|
523
|
+
}
|
|
524
|
+
function extractIgnorePatternsFromRules(rules) {
|
|
525
|
+
const patterns = [];
|
|
526
|
+
for (const rule of rules) {
|
|
527
|
+
if (rule.frontmatter.globs && rule.frontmatter.globs.length > 0) {
|
|
528
|
+
for (const glob of rule.frontmatter.globs) {
|
|
529
|
+
if (shouldExcludeFromAI(glob)) {
|
|
530
|
+
patterns.push(`# Exclude: ${rule.frontmatter.description}`);
|
|
531
|
+
patterns.push(glob);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
const contentPatterns = extractIgnorePatternsFromContent(rule.content);
|
|
536
|
+
patterns.push(...contentPatterns);
|
|
537
|
+
}
|
|
538
|
+
return patterns;
|
|
539
|
+
}
|
|
540
|
+
function shouldExcludeFromAI(glob) {
|
|
541
|
+
const excludePatterns = [
|
|
542
|
+
// Test and fixture files that might be large or confusing
|
|
543
|
+
"**/test/fixtures/**",
|
|
544
|
+
"**/tests/fixtures/**",
|
|
545
|
+
"**/*.fixture.*",
|
|
546
|
+
// Build and generated files
|
|
547
|
+
"**/dist/**",
|
|
548
|
+
"**/build/**",
|
|
549
|
+
"**/coverage/**",
|
|
550
|
+
// Configuration that might contain sensitive data
|
|
551
|
+
"**/config/production/**",
|
|
552
|
+
"**/config/prod/**",
|
|
553
|
+
"**/*.prod.*",
|
|
554
|
+
// Documentation that might be sensitive
|
|
555
|
+
"**/internal/**",
|
|
556
|
+
"**/private/**",
|
|
557
|
+
"**/confidential/**"
|
|
558
|
+
];
|
|
559
|
+
return excludePatterns.some((pattern) => {
|
|
560
|
+
const regex = new RegExp(pattern.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*"));
|
|
561
|
+
return regex.test(glob);
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
function extractIgnorePatternsFromContent(content) {
|
|
565
|
+
const patterns = [];
|
|
566
|
+
const lines = content.split("\n");
|
|
567
|
+
for (const line of lines) {
|
|
568
|
+
const trimmed = line.trim();
|
|
569
|
+
if (trimmed.startsWith("# IGNORE:") || trimmed.startsWith("# aiignore:")) {
|
|
570
|
+
const pattern = trimmed.replace(/^# (IGNORE|aiignore):\s*/, "").trim();
|
|
571
|
+
if (pattern) {
|
|
572
|
+
patterns.push(pattern);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
if (trimmed.includes("exclude") || trimmed.includes("ignore")) {
|
|
576
|
+
const matches = trimmed.match(/['"`]([^'"`]+\.(log|tmp|cache|temp))['"`]/g);
|
|
577
|
+
if (matches) {
|
|
578
|
+
patterns.push(...matches.map((m) => m.replace(/['"`]/g, "")));
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
return patterns;
|
|
583
|
+
}
|
|
584
|
+
|
|
417
585
|
// src/generators/rules/claudecode.ts
|
|
418
586
|
var import_node_path4 = require("path");
|
|
419
587
|
|
|
420
588
|
// src/types/claudecode.ts
|
|
421
|
-
var
|
|
422
|
-
var ClaudeSettingsSchema =
|
|
423
|
-
permissions:
|
|
424
|
-
|
|
425
|
-
deny:
|
|
589
|
+
var import_mini2 = require("zod/mini");
|
|
590
|
+
var ClaudeSettingsSchema = import_mini2.z.looseObject({
|
|
591
|
+
permissions: import_mini2.z._default(
|
|
592
|
+
import_mini2.z.looseObject({
|
|
593
|
+
deny: import_mini2.z._default(import_mini2.z.array(import_mini2.z.string()), [])
|
|
426
594
|
}),
|
|
427
595
|
{ deny: [] }
|
|
428
596
|
)
|
|
429
597
|
});
|
|
430
598
|
|
|
431
599
|
// src/utils/file.ts
|
|
432
|
-
var import_promises3 = require("fs/promises");
|
|
433
|
-
var import_node_path3 = require("path");
|
|
434
|
-
|
|
435
|
-
// src/utils/file-ops.ts
|
|
436
600
|
var import_promises2 = require("fs/promises");
|
|
437
|
-
var
|
|
601
|
+
var import_node_path2 = require("path");
|
|
438
602
|
async function ensureDir(dirPath) {
|
|
439
603
|
try {
|
|
440
604
|
await (0, import_promises2.stat)(dirPath);
|
|
@@ -446,7 +610,7 @@ async function readFileContent(filepath) {
|
|
|
446
610
|
return (0, import_promises2.readFile)(filepath, "utf-8");
|
|
447
611
|
}
|
|
448
612
|
async function writeFileContent(filepath, content) {
|
|
449
|
-
await ensureDir((0,
|
|
613
|
+
await ensureDir((0, import_node_path2.dirname)(filepath));
|
|
450
614
|
await (0, import_promises2.writeFile)(filepath, content, "utf-8");
|
|
451
615
|
}
|
|
452
616
|
async function fileExists(filepath) {
|
|
@@ -457,16 +621,57 @@ async function fileExists(filepath) {
|
|
|
457
621
|
return false;
|
|
458
622
|
}
|
|
459
623
|
}
|
|
624
|
+
async function findFiles(dir, extension = ".md") {
|
|
625
|
+
try {
|
|
626
|
+
const files = await (0, import_promises2.readdir)(dir);
|
|
627
|
+
return files.filter((file) => file.endsWith(extension)).map((file) => (0, import_node_path2.join)(dir, file));
|
|
628
|
+
} catch {
|
|
629
|
+
return [];
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
async function removeDirectory(dirPath) {
|
|
633
|
+
const dangerousPaths = [".", "/", "~", "src", "node_modules"];
|
|
634
|
+
if (dangerousPaths.includes(dirPath) || dirPath === "") {
|
|
635
|
+
console.warn(`Skipping deletion of dangerous path: ${dirPath}`);
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
try {
|
|
639
|
+
if (await fileExists(dirPath)) {
|
|
640
|
+
await (0, import_promises2.rm)(dirPath, { recursive: true, force: true });
|
|
641
|
+
}
|
|
642
|
+
} catch (error) {
|
|
643
|
+
console.warn(`Failed to remove directory ${dirPath}:`, error);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
async function removeFile(filepath) {
|
|
647
|
+
try {
|
|
648
|
+
if (await fileExists(filepath)) {
|
|
649
|
+
await (0, import_promises2.rm)(filepath);
|
|
650
|
+
}
|
|
651
|
+
} catch (error) {
|
|
652
|
+
console.warn(`Failed to remove file ${filepath}:`, error);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
async function removeClaudeGeneratedFiles() {
|
|
656
|
+
const filesToRemove = ["CLAUDE.md", ".claude/memories"];
|
|
657
|
+
for (const fileOrDir of filesToRemove) {
|
|
658
|
+
if (fileOrDir.endsWith("/memories")) {
|
|
659
|
+
await removeDirectory(fileOrDir);
|
|
660
|
+
} else {
|
|
661
|
+
await removeFile(fileOrDir);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
}
|
|
460
665
|
|
|
461
666
|
// src/utils/ignore.ts
|
|
462
|
-
var
|
|
667
|
+
var import_node_path3 = require("path");
|
|
463
668
|
var import_micromatch = __toESM(require("micromatch"), 1);
|
|
464
669
|
var cachedIgnorePatterns = null;
|
|
465
670
|
async function loadIgnorePatterns(baseDir = process.cwd()) {
|
|
466
671
|
if (cachedIgnorePatterns) {
|
|
467
672
|
return cachedIgnorePatterns;
|
|
468
673
|
}
|
|
469
|
-
const ignorePath = (0,
|
|
674
|
+
const ignorePath = (0, import_node_path3.join)(baseDir, ".rulesyncignore");
|
|
470
675
|
if (!await fileExists(ignorePath)) {
|
|
471
676
|
cachedIgnorePatterns = { patterns: [] };
|
|
472
677
|
return cachedIgnorePatterns;
|
|
@@ -509,53 +714,6 @@ function filterIgnoredFiles(files, ignorePatterns) {
|
|
|
509
714
|
return files.filter((file) => !isFileIgnored(file, ignorePatterns));
|
|
510
715
|
}
|
|
511
716
|
|
|
512
|
-
// src/utils/file.ts
|
|
513
|
-
async function findFiles(dir, extension = ".md", ignorePatterns) {
|
|
514
|
-
try {
|
|
515
|
-
const files = await (0, import_promises3.readdir)(dir);
|
|
516
|
-
const filtered = files.filter((file) => file.endsWith(extension)).map((file) => (0, import_node_path3.join)(dir, file));
|
|
517
|
-
if (ignorePatterns && ignorePatterns.length > 0) {
|
|
518
|
-
return filterIgnoredFiles(filtered, ignorePatterns);
|
|
519
|
-
}
|
|
520
|
-
return filtered;
|
|
521
|
-
} catch {
|
|
522
|
-
return [];
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
async function removeDirectory(dirPath) {
|
|
526
|
-
const dangerousPaths = [".", "/", "~", "src", "node_modules"];
|
|
527
|
-
if (dangerousPaths.includes(dirPath) || dirPath === "") {
|
|
528
|
-
console.warn(`Skipping deletion of dangerous path: ${dirPath}`);
|
|
529
|
-
return;
|
|
530
|
-
}
|
|
531
|
-
try {
|
|
532
|
-
if (await fileExists(dirPath)) {
|
|
533
|
-
await (0, import_promises3.rm)(dirPath, { recursive: true, force: true });
|
|
534
|
-
}
|
|
535
|
-
} catch (error) {
|
|
536
|
-
console.warn(`Failed to remove directory ${dirPath}:`, error);
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
async function removeFile(filepath) {
|
|
540
|
-
try {
|
|
541
|
-
if (await fileExists(filepath)) {
|
|
542
|
-
await (0, import_promises3.rm)(filepath);
|
|
543
|
-
}
|
|
544
|
-
} catch (error) {
|
|
545
|
-
console.warn(`Failed to remove file ${filepath}:`, error);
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
async function removeClaudeGeneratedFiles() {
|
|
549
|
-
const filesToRemove = ["CLAUDE.md", ".claude/memories"];
|
|
550
|
-
for (const fileOrDir of filesToRemove) {
|
|
551
|
-
if (fileOrDir.endsWith("/memories")) {
|
|
552
|
-
await removeDirectory(fileOrDir);
|
|
553
|
-
} else {
|
|
554
|
-
await removeFile(fileOrDir);
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
|
|
559
717
|
// src/generators/rules/claudecode.ts
|
|
560
718
|
async function generateClaudecodeConfig(rules, config, baseDir) {
|
|
561
719
|
const outputs = [];
|
|
@@ -892,14 +1050,34 @@ function generateAiexclude(patterns) {
|
|
|
892
1050
|
return lines.join("\n");
|
|
893
1051
|
}
|
|
894
1052
|
|
|
895
|
-
// src/generators/rules/
|
|
1053
|
+
// src/generators/rules/kiro.ts
|
|
896
1054
|
var import_node_path9 = require("path");
|
|
1055
|
+
async function generateKiroConfig(rules, config, baseDir) {
|
|
1056
|
+
const outputs = [];
|
|
1057
|
+
for (const rule of rules) {
|
|
1058
|
+
const content = generateKiroMarkdown(rule);
|
|
1059
|
+
const outputDir = baseDir ? (0, import_node_path9.join)(baseDir, config.outputPaths.kiro) : config.outputPaths.kiro;
|
|
1060
|
+
const filepath = (0, import_node_path9.join)(outputDir, `${rule.filename}.md`);
|
|
1061
|
+
outputs.push({
|
|
1062
|
+
tool: "kiro",
|
|
1063
|
+
filepath,
|
|
1064
|
+
content
|
|
1065
|
+
});
|
|
1066
|
+
}
|
|
1067
|
+
return outputs;
|
|
1068
|
+
}
|
|
1069
|
+
function generateKiroMarkdown(rule) {
|
|
1070
|
+
return rule.content.trim();
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
// src/generators/rules/roo.ts
|
|
1074
|
+
var import_node_path10 = require("path");
|
|
897
1075
|
async function generateRooConfig(rules, config, baseDir) {
|
|
898
1076
|
const outputs = [];
|
|
899
1077
|
for (const rule of rules) {
|
|
900
1078
|
const content = generateRooMarkdown(rule);
|
|
901
|
-
const outputDir = baseDir ? (0,
|
|
902
|
-
const filepath = (0,
|
|
1079
|
+
const outputDir = baseDir ? (0, import_node_path10.join)(baseDir, config.outputPaths.roo) : config.outputPaths.roo;
|
|
1080
|
+
const filepath = (0, import_node_path10.join)(outputDir, `${rule.filename}.md`);
|
|
903
1081
|
outputs.push({
|
|
904
1082
|
tool: "roo",
|
|
905
1083
|
filepath,
|
|
@@ -908,7 +1086,7 @@ async function generateRooConfig(rules, config, baseDir) {
|
|
|
908
1086
|
}
|
|
909
1087
|
const ignorePatterns = await loadIgnorePatterns(baseDir);
|
|
910
1088
|
if (ignorePatterns.patterns.length > 0) {
|
|
911
|
-
const rooIgnorePath = baseDir ? (0,
|
|
1089
|
+
const rooIgnorePath = baseDir ? (0, import_node_path10.join)(baseDir, ".rooignore") : ".rooignore";
|
|
912
1090
|
const rooIgnoreContent = generateRooIgnore(ignorePatterns.patterns);
|
|
913
1091
|
outputs.push({
|
|
914
1092
|
tool: "roo",
|
|
@@ -974,6 +1152,11 @@ async function generateForTool(tool, rules, config, baseDir) {
|
|
|
974
1152
|
return generateRooConfig(rules, config, baseDir);
|
|
975
1153
|
case "geminicli":
|
|
976
1154
|
return generateGeminiConfig(rules, config, baseDir);
|
|
1155
|
+
case "kiro": {
|
|
1156
|
+
const kiroRulesOutputs = await generateKiroConfig(rules, config, baseDir);
|
|
1157
|
+
const kiroIgnoreOutputs = await generateKiroIgnoreFiles(rules, config, baseDir);
|
|
1158
|
+
return [...kiroRulesOutputs, ...kiroIgnoreOutputs];
|
|
1159
|
+
}
|
|
977
1160
|
default:
|
|
978
1161
|
console.warn(`Unknown tool: ${tool}`);
|
|
979
1162
|
return null;
|
|
@@ -981,74 +1164,76 @@ async function generateForTool(tool, rules, config, baseDir) {
|
|
|
981
1164
|
}
|
|
982
1165
|
|
|
983
1166
|
// src/core/parser.ts
|
|
984
|
-
var
|
|
1167
|
+
var import_node_path11 = require("path");
|
|
985
1168
|
var import_gray_matter = __toESM(require("gray-matter"), 1);
|
|
986
1169
|
|
|
987
1170
|
// src/types/config.ts
|
|
988
|
-
var
|
|
1171
|
+
var import_mini3 = require("zod/mini");
|
|
989
1172
|
init_tool_targets();
|
|
990
|
-
var ConfigSchema =
|
|
991
|
-
aiRulesDir:
|
|
992
|
-
outputPaths:
|
|
993
|
-
watchEnabled:
|
|
1173
|
+
var ConfigSchema = import_mini3.z.object({
|
|
1174
|
+
aiRulesDir: import_mini3.z.string(),
|
|
1175
|
+
outputPaths: import_mini3.z.record(ToolTargetSchema, import_mini3.z.string()),
|
|
1176
|
+
watchEnabled: import_mini3.z.boolean(),
|
|
994
1177
|
defaultTargets: ToolTargetsSchema
|
|
995
1178
|
});
|
|
996
1179
|
|
|
997
1180
|
// src/types/mcp.ts
|
|
998
|
-
var
|
|
1181
|
+
var import_mini4 = require("zod/mini");
|
|
999
1182
|
init_tool_targets();
|
|
1000
|
-
var McpTransportTypeSchema =
|
|
1001
|
-
var McpServerBaseSchema =
|
|
1002
|
-
command:
|
|
1003
|
-
args:
|
|
1004
|
-
url:
|
|
1005
|
-
httpUrl:
|
|
1006
|
-
env:
|
|
1007
|
-
disabled:
|
|
1008
|
-
networkTimeout:
|
|
1009
|
-
timeout:
|
|
1010
|
-
trust:
|
|
1011
|
-
cwd:
|
|
1012
|
-
transport:
|
|
1013
|
-
type:
|
|
1014
|
-
alwaysAllow:
|
|
1015
|
-
tools:
|
|
1183
|
+
var McpTransportTypeSchema = import_mini4.z.enum(["stdio", "sse", "http"]);
|
|
1184
|
+
var McpServerBaseSchema = import_mini4.z.object({
|
|
1185
|
+
command: import_mini4.z.optional(import_mini4.z.string()),
|
|
1186
|
+
args: import_mini4.z.optional(import_mini4.z.array(import_mini4.z.string())),
|
|
1187
|
+
url: import_mini4.z.optional(import_mini4.z.string()),
|
|
1188
|
+
httpUrl: import_mini4.z.optional(import_mini4.z.string()),
|
|
1189
|
+
env: import_mini4.z.optional(import_mini4.z.record(import_mini4.z.string(), import_mini4.z.string())),
|
|
1190
|
+
disabled: import_mini4.z.optional(import_mini4.z.boolean()),
|
|
1191
|
+
networkTimeout: import_mini4.z.optional(import_mini4.z.number()),
|
|
1192
|
+
timeout: import_mini4.z.optional(import_mini4.z.number()),
|
|
1193
|
+
trust: import_mini4.z.optional(import_mini4.z.boolean()),
|
|
1194
|
+
cwd: import_mini4.z.optional(import_mini4.z.string()),
|
|
1195
|
+
transport: import_mini4.z.optional(McpTransportTypeSchema),
|
|
1196
|
+
type: import_mini4.z.optional(import_mini4.z.enum(["sse", "streamable-http"])),
|
|
1197
|
+
alwaysAllow: import_mini4.z.optional(import_mini4.z.array(import_mini4.z.string())),
|
|
1198
|
+
tools: import_mini4.z.optional(import_mini4.z.array(import_mini4.z.string())),
|
|
1199
|
+
kiroAutoApprove: import_mini4.z.optional(import_mini4.z.array(import_mini4.z.string())),
|
|
1200
|
+
kiroAutoBlock: import_mini4.z.optional(import_mini4.z.array(import_mini4.z.string()))
|
|
1016
1201
|
});
|
|
1017
|
-
var RulesyncMcpServerSchema =
|
|
1018
|
-
targets:
|
|
1202
|
+
var RulesyncMcpServerSchema = import_mini4.z.extend(McpServerBaseSchema, {
|
|
1203
|
+
targets: import_mini4.z.optional(RulesyncTargetsSchema)
|
|
1019
1204
|
});
|
|
1020
|
-
var McpConfigSchema =
|
|
1021
|
-
mcpServers:
|
|
1205
|
+
var McpConfigSchema = import_mini4.z.object({
|
|
1206
|
+
mcpServers: import_mini4.z.record(import_mini4.z.string(), McpServerBaseSchema)
|
|
1022
1207
|
});
|
|
1023
|
-
var RulesyncMcpConfigSchema =
|
|
1024
|
-
mcpServers:
|
|
1208
|
+
var RulesyncMcpConfigSchema = import_mini4.z.object({
|
|
1209
|
+
mcpServers: import_mini4.z.record(import_mini4.z.string(), RulesyncMcpServerSchema)
|
|
1025
1210
|
});
|
|
1026
1211
|
|
|
1027
1212
|
// src/types/rules.ts
|
|
1028
|
-
var
|
|
1213
|
+
var import_mini5 = require("zod/mini");
|
|
1029
1214
|
init_tool_targets();
|
|
1030
|
-
var RuleFrontmatterSchema =
|
|
1031
|
-
root:
|
|
1215
|
+
var RuleFrontmatterSchema = import_mini5.z.object({
|
|
1216
|
+
root: import_mini5.z.boolean(),
|
|
1032
1217
|
targets: RulesyncTargetsSchema,
|
|
1033
|
-
description:
|
|
1034
|
-
globs:
|
|
1035
|
-
cursorRuleType:
|
|
1218
|
+
description: import_mini5.z.string(),
|
|
1219
|
+
globs: import_mini5.z.array(import_mini5.z.string()),
|
|
1220
|
+
cursorRuleType: import_mini5.z.optional(import_mini5.z.enum(["always", "manual", "specificFiles", "intelligently"]))
|
|
1036
1221
|
});
|
|
1037
|
-
var ParsedRuleSchema =
|
|
1222
|
+
var ParsedRuleSchema = import_mini5.z.object({
|
|
1038
1223
|
frontmatter: RuleFrontmatterSchema,
|
|
1039
|
-
content:
|
|
1040
|
-
filename:
|
|
1041
|
-
filepath:
|
|
1224
|
+
content: import_mini5.z.string(),
|
|
1225
|
+
filename: import_mini5.z.string(),
|
|
1226
|
+
filepath: import_mini5.z.string()
|
|
1042
1227
|
});
|
|
1043
|
-
var GeneratedOutputSchema =
|
|
1228
|
+
var GeneratedOutputSchema = import_mini5.z.object({
|
|
1044
1229
|
tool: ToolTargetSchema,
|
|
1045
|
-
filepath:
|
|
1046
|
-
content:
|
|
1230
|
+
filepath: import_mini5.z.string(),
|
|
1231
|
+
content: import_mini5.z.string()
|
|
1047
1232
|
});
|
|
1048
|
-
var GenerateOptionsSchema =
|
|
1049
|
-
targetTools:
|
|
1050
|
-
outputDir:
|
|
1051
|
-
watch:
|
|
1233
|
+
var GenerateOptionsSchema = import_mini5.z.object({
|
|
1234
|
+
targetTools: import_mini5.z.optional(ToolTargetsSchema),
|
|
1235
|
+
outputDir: import_mini5.z.optional(import_mini5.z.string()),
|
|
1236
|
+
watch: import_mini5.z.optional(import_mini5.z.boolean())
|
|
1052
1237
|
});
|
|
1053
1238
|
|
|
1054
1239
|
// src/types/index.ts
|
|
@@ -1057,7 +1242,8 @@ init_tool_targets();
|
|
|
1057
1242
|
// src/core/parser.ts
|
|
1058
1243
|
async function parseRulesFromDirectory(aiRulesDir) {
|
|
1059
1244
|
const ignorePatterns = await loadIgnorePatterns();
|
|
1060
|
-
const
|
|
1245
|
+
const allRuleFiles = await findFiles(aiRulesDir, ".md");
|
|
1246
|
+
const ruleFiles = filterIgnoredFiles(allRuleFiles, ignorePatterns.patterns);
|
|
1061
1247
|
const rules = [];
|
|
1062
1248
|
const errors = [];
|
|
1063
1249
|
if (ignorePatterns.patterns.length > 0) {
|
|
@@ -1090,7 +1276,7 @@ async function parseRuleFile(filepath) {
|
|
|
1090
1276
|
const parsed = (0, import_gray_matter.default)(content);
|
|
1091
1277
|
try {
|
|
1092
1278
|
const frontmatter = RuleFrontmatterSchema.parse(parsed.data);
|
|
1093
|
-
const filename = (0,
|
|
1279
|
+
const filename = (0, import_node_path11.basename)(filepath, ".md");
|
|
1094
1280
|
return {
|
|
1095
1281
|
frontmatter,
|
|
1096
1282
|
content: parsed.content,
|
|
@@ -1163,6 +1349,7 @@ init_cline();
|
|
|
1163
1349
|
init_copilot();
|
|
1164
1350
|
init_cursor();
|
|
1165
1351
|
init_geminicli();
|
|
1352
|
+
init_kiro();
|
|
1166
1353
|
init_roo();
|
|
1167
1354
|
|
|
1168
1355
|
// src/core/mcp-parser.ts
|
|
@@ -1226,6 +1413,11 @@ async function generateMcpConfigs(projectRoot, baseDir) {
|
|
|
1226
1413
|
path: path3.join(targetRoot, ".gemini", "settings.json"),
|
|
1227
1414
|
generate: () => generateGeminiCliMcp(config)
|
|
1228
1415
|
},
|
|
1416
|
+
{
|
|
1417
|
+
tool: "kiro-project",
|
|
1418
|
+
path: path3.join(targetRoot, ".kiro", "mcp.json"),
|
|
1419
|
+
generate: () => generateKiroMcp(config)
|
|
1420
|
+
},
|
|
1229
1421
|
{
|
|
1230
1422
|
tool: "roo-project",
|
|
1231
1423
|
path: path3.join(targetRoot, ".roo", "mcp.json"),
|
|
@@ -1236,7 +1428,7 @@ async function generateMcpConfigs(projectRoot, baseDir) {
|
|
|
1236
1428
|
try {
|
|
1237
1429
|
const content = generator.generate();
|
|
1238
1430
|
const parsed = JSON.parse(content);
|
|
1239
|
-
if (generator.tool.includes("claude") || generator.tool.includes("cline") || generator.tool.includes("cursor") || generator.tool.includes("gemini") || generator.tool.includes("roo")) {
|
|
1431
|
+
if (generator.tool.includes("claude") || generator.tool.includes("cline") || generator.tool.includes("cursor") || generator.tool.includes("gemini") || generator.tool.includes("kiro") || generator.tool.includes("roo")) {
|
|
1240
1432
|
if (!parsed.mcpServers || Object.keys(parsed.mcpServers).length === 0) {
|
|
1241
1433
|
results.push({
|
|
1242
1434
|
tool: generator.tool,
|
|
@@ -1322,6 +1514,9 @@ async function generateCommand(options = {}) {
|
|
|
1322
1514
|
case "geminicli":
|
|
1323
1515
|
deleteTasks.push(removeDirectory(config.outputPaths.geminicli));
|
|
1324
1516
|
break;
|
|
1517
|
+
case "kiro":
|
|
1518
|
+
deleteTasks.push(removeDirectory(config.outputPaths.kiro));
|
|
1519
|
+
break;
|
|
1325
1520
|
}
|
|
1326
1521
|
}
|
|
1327
1522
|
await Promise.all(deleteTasks);
|
|
@@ -1352,11 +1547,10 @@ Generating configurations for base directory: ${baseDir}`);
|
|
|
1352
1547
|
console.warn("\u26A0\uFE0F No configurations generated");
|
|
1353
1548
|
return;
|
|
1354
1549
|
}
|
|
1355
|
-
console.log(`
|
|
1356
|
-
\u{1F389} Successfully generated ${totalOutputs} configuration file(s)!`);
|
|
1357
1550
|
if (options.verbose) {
|
|
1358
1551
|
console.log("\nGenerating MCP configurations...");
|
|
1359
1552
|
}
|
|
1553
|
+
let totalMcpOutputs = 0;
|
|
1360
1554
|
for (const baseDir of baseDirs) {
|
|
1361
1555
|
const mcpResults = await generateMcpConfigs(
|
|
1362
1556
|
process.cwd(),
|
|
@@ -1371,6 +1565,7 @@ Generating configurations for base directory: ${baseDir}`);
|
|
|
1371
1565
|
for (const result of mcpResults) {
|
|
1372
1566
|
if (result.status === "success") {
|
|
1373
1567
|
console.log(`\u2705 Generated ${result.tool} MCP configuration: ${result.path}`);
|
|
1568
|
+
totalMcpOutputs++;
|
|
1374
1569
|
} else if (result.status === "error") {
|
|
1375
1570
|
console.error(`\u274C Failed to generate ${result.tool} MCP configuration: ${result.error}`);
|
|
1376
1571
|
} else if (options.verbose && result.status === "skipped") {
|
|
@@ -1378,6 +1573,13 @@ Generating configurations for base directory: ${baseDir}`);
|
|
|
1378
1573
|
}
|
|
1379
1574
|
}
|
|
1380
1575
|
}
|
|
1576
|
+
const totalGenerated = totalOutputs + totalMcpOutputs;
|
|
1577
|
+
if (totalGenerated > 0) {
|
|
1578
|
+
console.log(
|
|
1579
|
+
`
|
|
1580
|
+
\u{1F389} All done! Generated ${totalGenerated} file(s) total (${totalOutputs} configurations + ${totalMcpOutputs} MCP configurations)`
|
|
1581
|
+
);
|
|
1582
|
+
}
|
|
1381
1583
|
} catch (error) {
|
|
1382
1584
|
console.error("\u274C Failed to generate configurations:", error);
|
|
1383
1585
|
process.exit(1);
|
|
@@ -1386,9 +1588,9 @@ Generating configurations for base directory: ${baseDir}`);
|
|
|
1386
1588
|
|
|
1387
1589
|
// src/cli/commands/gitignore.ts
|
|
1388
1590
|
var import_node_fs = require("fs");
|
|
1389
|
-
var
|
|
1591
|
+
var import_node_path12 = require("path");
|
|
1390
1592
|
var gitignoreCommand = async () => {
|
|
1391
|
-
const gitignorePath = (0,
|
|
1593
|
+
const gitignorePath = (0, import_node_path12.join)(process.cwd(), ".gitignore");
|
|
1392
1594
|
const rulesFilesToIgnore = [
|
|
1393
1595
|
"# Generated by rulesync - AI tool configuration files",
|
|
1394
1596
|
"**/.github/copilot-instructions.md",
|
|
@@ -1405,6 +1607,8 @@ var gitignoreCommand = async () => {
|
|
|
1405
1607
|
"**/GEMINI.md",
|
|
1406
1608
|
"**/.gemini/memories/",
|
|
1407
1609
|
"**/.aiexclude",
|
|
1610
|
+
"**/.aiignore",
|
|
1611
|
+
"**/.kiro/steering/",
|
|
1408
1612
|
"**/.mcp.json",
|
|
1409
1613
|
"!.rulesync/.mcp.json",
|
|
1410
1614
|
"**/.cursor/mcp.json",
|
|
@@ -1442,17 +1646,17 @@ ${linesToAdd.join("\n")}
|
|
|
1442
1646
|
};
|
|
1443
1647
|
|
|
1444
1648
|
// src/core/importer.ts
|
|
1445
|
-
var
|
|
1649
|
+
var import_node_path19 = require("path");
|
|
1446
1650
|
var import_gray_matter4 = __toESM(require("gray-matter"), 1);
|
|
1447
1651
|
|
|
1448
1652
|
// src/parsers/claudecode.ts
|
|
1449
|
-
var
|
|
1653
|
+
var import_node_path13 = require("path");
|
|
1450
1654
|
async function parseClaudeConfiguration(baseDir = process.cwd()) {
|
|
1451
1655
|
const errors = [];
|
|
1452
1656
|
const rules = [];
|
|
1453
1657
|
let ignorePatterns;
|
|
1454
1658
|
let mcpServers;
|
|
1455
|
-
const claudeFilePath = (0,
|
|
1659
|
+
const claudeFilePath = (0, import_node_path13.join)(baseDir, "CLAUDE.md");
|
|
1456
1660
|
if (!await fileExists(claudeFilePath)) {
|
|
1457
1661
|
errors.push("CLAUDE.md file not found");
|
|
1458
1662
|
return { rules, errors };
|
|
@@ -1463,12 +1667,12 @@ async function parseClaudeConfiguration(baseDir = process.cwd()) {
|
|
|
1463
1667
|
if (mainRule) {
|
|
1464
1668
|
rules.push(mainRule);
|
|
1465
1669
|
}
|
|
1466
|
-
const memoryDir = (0,
|
|
1670
|
+
const memoryDir = (0, import_node_path13.join)(baseDir, ".claude", "memories");
|
|
1467
1671
|
if (await fileExists(memoryDir)) {
|
|
1468
1672
|
const memoryRules = await parseClaudeMemoryFiles(memoryDir);
|
|
1469
1673
|
rules.push(...memoryRules);
|
|
1470
1674
|
}
|
|
1471
|
-
const settingsPath = (0,
|
|
1675
|
+
const settingsPath = (0, import_node_path13.join)(baseDir, ".claude", "settings.json");
|
|
1472
1676
|
if (await fileExists(settingsPath)) {
|
|
1473
1677
|
const settingsResult = await parseClaudeSettings(settingsPath);
|
|
1474
1678
|
if (settingsResult.ignorePatterns) {
|
|
@@ -1525,10 +1729,10 @@ async function parseClaudeMemoryFiles(memoryDir) {
|
|
|
1525
1729
|
const files = await readdir2(memoryDir);
|
|
1526
1730
|
for (const file of files) {
|
|
1527
1731
|
if (file.endsWith(".md")) {
|
|
1528
|
-
const filePath = (0,
|
|
1732
|
+
const filePath = (0, import_node_path13.join)(memoryDir, file);
|
|
1529
1733
|
const content = await readFileContent(filePath);
|
|
1530
1734
|
if (content.trim()) {
|
|
1531
|
-
const filename = (0,
|
|
1735
|
+
const filename = (0, import_node_path13.basename)(file, ".md");
|
|
1532
1736
|
const frontmatter = {
|
|
1533
1737
|
root: false,
|
|
1534
1738
|
targets: ["claudecode"],
|
|
@@ -1588,11 +1792,11 @@ async function parseClaudeSettings(settingsPath) {
|
|
|
1588
1792
|
}
|
|
1589
1793
|
|
|
1590
1794
|
// src/parsers/cline.ts
|
|
1591
|
-
var
|
|
1795
|
+
var import_node_path14 = require("path");
|
|
1592
1796
|
async function parseClineConfiguration(baseDir = process.cwd()) {
|
|
1593
1797
|
const errors = [];
|
|
1594
1798
|
const rules = [];
|
|
1595
|
-
const clineFilePath = (0,
|
|
1799
|
+
const clineFilePath = (0, import_node_path14.join)(baseDir, ".cline", "instructions.md");
|
|
1596
1800
|
if (await fileExists(clineFilePath)) {
|
|
1597
1801
|
try {
|
|
1598
1802
|
const content = await readFileContent(clineFilePath);
|
|
@@ -1615,14 +1819,14 @@ async function parseClineConfiguration(baseDir = process.cwd()) {
|
|
|
1615
1819
|
errors.push(`Failed to parse .cline/instructions.md: ${errorMessage}`);
|
|
1616
1820
|
}
|
|
1617
1821
|
}
|
|
1618
|
-
const clinerulesDirPath = (0,
|
|
1822
|
+
const clinerulesDirPath = (0, import_node_path14.join)(baseDir, ".clinerules");
|
|
1619
1823
|
if (await fileExists(clinerulesDirPath)) {
|
|
1620
1824
|
try {
|
|
1621
1825
|
const { readdir: readdir2 } = await import("fs/promises");
|
|
1622
1826
|
const files = await readdir2(clinerulesDirPath);
|
|
1623
1827
|
for (const file of files) {
|
|
1624
1828
|
if (file.endsWith(".md")) {
|
|
1625
|
-
const filePath = (0,
|
|
1829
|
+
const filePath = (0, import_node_path14.join)(clinerulesDirPath, file);
|
|
1626
1830
|
try {
|
|
1627
1831
|
const content = await readFileContent(filePath);
|
|
1628
1832
|
if (content.trim()) {
|
|
@@ -1658,12 +1862,12 @@ async function parseClineConfiguration(baseDir = process.cwd()) {
|
|
|
1658
1862
|
}
|
|
1659
1863
|
|
|
1660
1864
|
// src/parsers/copilot.ts
|
|
1661
|
-
var
|
|
1865
|
+
var import_node_path15 = require("path");
|
|
1662
1866
|
var import_gray_matter2 = __toESM(require("gray-matter"), 1);
|
|
1663
1867
|
async function parseCopilotConfiguration(baseDir = process.cwd()) {
|
|
1664
1868
|
const errors = [];
|
|
1665
1869
|
const rules = [];
|
|
1666
|
-
const copilotFilePath = (0,
|
|
1870
|
+
const copilotFilePath = (0, import_node_path15.join)(baseDir, ".github", "copilot-instructions.md");
|
|
1667
1871
|
if (await fileExists(copilotFilePath)) {
|
|
1668
1872
|
try {
|
|
1669
1873
|
const rawContent = await readFileContent(copilotFilePath);
|
|
@@ -1688,19 +1892,19 @@ async function parseCopilotConfiguration(baseDir = process.cwd()) {
|
|
|
1688
1892
|
errors.push(`Failed to parse copilot-instructions.md: ${errorMessage}`);
|
|
1689
1893
|
}
|
|
1690
1894
|
}
|
|
1691
|
-
const instructionsDir = (0,
|
|
1895
|
+
const instructionsDir = (0, import_node_path15.join)(baseDir, ".github", "instructions");
|
|
1692
1896
|
if (await fileExists(instructionsDir)) {
|
|
1693
1897
|
try {
|
|
1694
1898
|
const { readdir: readdir2 } = await import("fs/promises");
|
|
1695
1899
|
const files = await readdir2(instructionsDir);
|
|
1696
1900
|
for (const file of files) {
|
|
1697
1901
|
if (file.endsWith(".instructions.md")) {
|
|
1698
|
-
const filePath = (0,
|
|
1902
|
+
const filePath = (0, import_node_path15.join)(instructionsDir, file);
|
|
1699
1903
|
const rawContent = await readFileContent(filePath);
|
|
1700
1904
|
const parsed = (0, import_gray_matter2.default)(rawContent);
|
|
1701
1905
|
const content = parsed.content.trim();
|
|
1702
1906
|
if (content) {
|
|
1703
|
-
const filename = (0,
|
|
1907
|
+
const filename = (0, import_node_path15.basename)(file, ".instructions.md");
|
|
1704
1908
|
const frontmatter = {
|
|
1705
1909
|
root: false,
|
|
1706
1910
|
targets: ["copilot"],
|
|
@@ -1730,10 +1934,10 @@ async function parseCopilotConfiguration(baseDir = process.cwd()) {
|
|
|
1730
1934
|
}
|
|
1731
1935
|
|
|
1732
1936
|
// src/parsers/cursor.ts
|
|
1733
|
-
var
|
|
1937
|
+
var import_node_path16 = require("path");
|
|
1734
1938
|
var import_gray_matter3 = __toESM(require("gray-matter"), 1);
|
|
1735
1939
|
var import_js_yaml = require("js-yaml");
|
|
1736
|
-
var
|
|
1940
|
+
var import_mini6 = require("zod/mini");
|
|
1737
1941
|
var customMatterOptions = {
|
|
1738
1942
|
engines: {
|
|
1739
1943
|
yaml: {
|
|
@@ -1761,7 +1965,7 @@ var customMatterOptions = {
|
|
|
1761
1965
|
}
|
|
1762
1966
|
};
|
|
1763
1967
|
function convertCursorMdcFrontmatter(cursorFrontmatter, _filename) {
|
|
1764
|
-
const FrontmatterSchema =
|
|
1968
|
+
const FrontmatterSchema = import_mini6.z.record(import_mini6.z.string(), import_mini6.z.unknown());
|
|
1765
1969
|
const parseResult = FrontmatterSchema.safeParse(cursorFrontmatter);
|
|
1766
1970
|
if (!parseResult.success) {
|
|
1767
1971
|
return {
|
|
@@ -1855,7 +2059,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
1855
2059
|
const rules = [];
|
|
1856
2060
|
let ignorePatterns;
|
|
1857
2061
|
let mcpServers;
|
|
1858
|
-
const cursorFilePath = (0,
|
|
2062
|
+
const cursorFilePath = (0, import_node_path16.join)(baseDir, ".cursorrules");
|
|
1859
2063
|
if (await fileExists(cursorFilePath)) {
|
|
1860
2064
|
try {
|
|
1861
2065
|
const rawContent = await readFileContent(cursorFilePath);
|
|
@@ -1876,20 +2080,20 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
1876
2080
|
errors.push(`Failed to parse .cursorrules file: ${errorMessage}`);
|
|
1877
2081
|
}
|
|
1878
2082
|
}
|
|
1879
|
-
const cursorRulesDir = (0,
|
|
2083
|
+
const cursorRulesDir = (0, import_node_path16.join)(baseDir, ".cursor", "rules");
|
|
1880
2084
|
if (await fileExists(cursorRulesDir)) {
|
|
1881
2085
|
try {
|
|
1882
2086
|
const { readdir: readdir2 } = await import("fs/promises");
|
|
1883
2087
|
const files = await readdir2(cursorRulesDir);
|
|
1884
2088
|
for (const file of files) {
|
|
1885
2089
|
if (file.endsWith(".mdc")) {
|
|
1886
|
-
const filePath = (0,
|
|
2090
|
+
const filePath = (0, import_node_path16.join)(cursorRulesDir, file);
|
|
1887
2091
|
try {
|
|
1888
2092
|
const rawContent = await readFileContent(filePath);
|
|
1889
2093
|
const parsed = (0, import_gray_matter3.default)(rawContent, customMatterOptions);
|
|
1890
2094
|
const content = parsed.content.trim();
|
|
1891
2095
|
if (content) {
|
|
1892
|
-
const filename = (0,
|
|
2096
|
+
const filename = (0, import_node_path16.basename)(file, ".mdc");
|
|
1893
2097
|
const frontmatter = convertCursorMdcFrontmatter(parsed.data, filename);
|
|
1894
2098
|
rules.push({
|
|
1895
2099
|
frontmatter,
|
|
@@ -1912,7 +2116,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
1912
2116
|
if (rules.length === 0) {
|
|
1913
2117
|
errors.push("No Cursor configuration files found (.cursorrules or .cursor/rules/*.mdc)");
|
|
1914
2118
|
}
|
|
1915
|
-
const cursorIgnorePath = (0,
|
|
2119
|
+
const cursorIgnorePath = (0, import_node_path16.join)(baseDir, ".cursorignore");
|
|
1916
2120
|
if (await fileExists(cursorIgnorePath)) {
|
|
1917
2121
|
try {
|
|
1918
2122
|
const content = await readFileContent(cursorIgnorePath);
|
|
@@ -1925,7 +2129,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
1925
2129
|
errors.push(`Failed to parse .cursorignore: ${errorMessage}`);
|
|
1926
2130
|
}
|
|
1927
2131
|
}
|
|
1928
|
-
const cursorMcpPath = (0,
|
|
2132
|
+
const cursorMcpPath = (0, import_node_path16.join)(baseDir, ".cursor", "mcp.json");
|
|
1929
2133
|
if (await fileExists(cursorMcpPath)) {
|
|
1930
2134
|
try {
|
|
1931
2135
|
const content = await readFileContent(cursorMcpPath);
|
|
@@ -1948,13 +2152,13 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
1948
2152
|
}
|
|
1949
2153
|
|
|
1950
2154
|
// src/parsers/geminicli.ts
|
|
1951
|
-
var
|
|
2155
|
+
var import_node_path17 = require("path");
|
|
1952
2156
|
async function parseGeminiConfiguration(baseDir = process.cwd()) {
|
|
1953
2157
|
const errors = [];
|
|
1954
2158
|
const rules = [];
|
|
1955
2159
|
let ignorePatterns;
|
|
1956
2160
|
let mcpServers;
|
|
1957
|
-
const geminiFilePath = (0,
|
|
2161
|
+
const geminiFilePath = (0, import_node_path17.join)(baseDir, "GEMINI.md");
|
|
1958
2162
|
if (!await fileExists(geminiFilePath)) {
|
|
1959
2163
|
errors.push("GEMINI.md file not found");
|
|
1960
2164
|
return { rules, errors };
|
|
@@ -1965,12 +2169,12 @@ async function parseGeminiConfiguration(baseDir = process.cwd()) {
|
|
|
1965
2169
|
if (mainRule) {
|
|
1966
2170
|
rules.push(mainRule);
|
|
1967
2171
|
}
|
|
1968
|
-
const memoryDir = (0,
|
|
2172
|
+
const memoryDir = (0, import_node_path17.join)(baseDir, ".gemini", "memories");
|
|
1969
2173
|
if (await fileExists(memoryDir)) {
|
|
1970
2174
|
const memoryRules = await parseGeminiMemoryFiles(memoryDir);
|
|
1971
2175
|
rules.push(...memoryRules);
|
|
1972
2176
|
}
|
|
1973
|
-
const settingsPath = (0,
|
|
2177
|
+
const settingsPath = (0, import_node_path17.join)(baseDir, ".gemini", "settings.json");
|
|
1974
2178
|
if (await fileExists(settingsPath)) {
|
|
1975
2179
|
const settingsResult = await parseGeminiSettings(settingsPath);
|
|
1976
2180
|
if (settingsResult.ignorePatterns) {
|
|
@@ -1981,7 +2185,7 @@ async function parseGeminiConfiguration(baseDir = process.cwd()) {
|
|
|
1981
2185
|
}
|
|
1982
2186
|
errors.push(...settingsResult.errors);
|
|
1983
2187
|
}
|
|
1984
|
-
const aiexcludePath = (0,
|
|
2188
|
+
const aiexcludePath = (0, import_node_path17.join)(baseDir, ".aiexclude");
|
|
1985
2189
|
if (await fileExists(aiexcludePath)) {
|
|
1986
2190
|
const aiexcludePatterns = await parseAiexclude(aiexcludePath);
|
|
1987
2191
|
if (aiexcludePatterns.length > 0) {
|
|
@@ -2034,10 +2238,10 @@ async function parseGeminiMemoryFiles(memoryDir) {
|
|
|
2034
2238
|
const files = await readdir2(memoryDir);
|
|
2035
2239
|
for (const file of files) {
|
|
2036
2240
|
if (file.endsWith(".md")) {
|
|
2037
|
-
const filePath = (0,
|
|
2241
|
+
const filePath = (0, import_node_path17.join)(memoryDir, file);
|
|
2038
2242
|
const content = await readFileContent(filePath);
|
|
2039
2243
|
if (content.trim()) {
|
|
2040
|
-
const filename = (0,
|
|
2244
|
+
const filename = (0, import_node_path17.basename)(file, ".md");
|
|
2041
2245
|
const frontmatter = {
|
|
2042
2246
|
root: false,
|
|
2043
2247
|
targets: ["geminicli"],
|
|
@@ -2087,11 +2291,11 @@ async function parseAiexclude(aiexcludePath) {
|
|
|
2087
2291
|
}
|
|
2088
2292
|
|
|
2089
2293
|
// src/parsers/roo.ts
|
|
2090
|
-
var
|
|
2294
|
+
var import_node_path18 = require("path");
|
|
2091
2295
|
async function parseRooConfiguration(baseDir = process.cwd()) {
|
|
2092
2296
|
const errors = [];
|
|
2093
2297
|
const rules = [];
|
|
2094
|
-
const rooFilePath = (0,
|
|
2298
|
+
const rooFilePath = (0, import_node_path18.join)(baseDir, ".roo", "instructions.md");
|
|
2095
2299
|
if (await fileExists(rooFilePath)) {
|
|
2096
2300
|
try {
|
|
2097
2301
|
const content = await readFileContent(rooFilePath);
|
|
@@ -2114,14 +2318,14 @@ async function parseRooConfiguration(baseDir = process.cwd()) {
|
|
|
2114
2318
|
errors.push(`Failed to parse .roo/instructions.md: ${errorMessage}`);
|
|
2115
2319
|
}
|
|
2116
2320
|
}
|
|
2117
|
-
const rooRulesDir = (0,
|
|
2321
|
+
const rooRulesDir = (0, import_node_path18.join)(baseDir, ".roo", "rules");
|
|
2118
2322
|
if (await fileExists(rooRulesDir)) {
|
|
2119
2323
|
try {
|
|
2120
2324
|
const { readdir: readdir2 } = await import("fs/promises");
|
|
2121
2325
|
const files = await readdir2(rooRulesDir);
|
|
2122
2326
|
for (const file of files) {
|
|
2123
2327
|
if (file.endsWith(".md")) {
|
|
2124
|
-
const filePath = (0,
|
|
2328
|
+
const filePath = (0, import_node_path18.join)(rooRulesDir, file);
|
|
2125
2329
|
try {
|
|
2126
2330
|
const content = await readFileContent(filePath);
|
|
2127
2331
|
if (content.trim()) {
|
|
@@ -2222,7 +2426,7 @@ async function importConfiguration(options) {
|
|
|
2222
2426
|
if (rules.length === 0 && !ignorePatterns && !mcpServers) {
|
|
2223
2427
|
return { success: false, rulesCreated: 0, errors };
|
|
2224
2428
|
}
|
|
2225
|
-
const rulesDirPath = (0,
|
|
2429
|
+
const rulesDirPath = (0, import_node_path19.join)(baseDir, rulesDir);
|
|
2226
2430
|
try {
|
|
2227
2431
|
const { mkdir: mkdir3 } = await import("fs/promises");
|
|
2228
2432
|
await mkdir3(rulesDirPath, { recursive: true });
|
|
@@ -2236,7 +2440,7 @@ async function importConfiguration(options) {
|
|
|
2236
2440
|
try {
|
|
2237
2441
|
const baseFilename = `${tool}__${rule.filename}`;
|
|
2238
2442
|
const filename = await generateUniqueFilename(rulesDirPath, baseFilename);
|
|
2239
|
-
const filePath = (0,
|
|
2443
|
+
const filePath = (0, import_node_path19.join)(rulesDirPath, `${filename}.md`);
|
|
2240
2444
|
const content = generateRuleFileContent(rule);
|
|
2241
2445
|
await writeFileContent(filePath, content);
|
|
2242
2446
|
rulesCreated++;
|
|
@@ -2251,7 +2455,7 @@ async function importConfiguration(options) {
|
|
|
2251
2455
|
let ignoreFileCreated = false;
|
|
2252
2456
|
if (ignorePatterns && ignorePatterns.length > 0) {
|
|
2253
2457
|
try {
|
|
2254
|
-
const rulesyncignorePath = (0,
|
|
2458
|
+
const rulesyncignorePath = (0, import_node_path19.join)(baseDir, ".rulesyncignore");
|
|
2255
2459
|
const ignoreContent = `${ignorePatterns.join("\n")}
|
|
2256
2460
|
`;
|
|
2257
2461
|
await writeFileContent(rulesyncignorePath, ignoreContent);
|
|
@@ -2267,7 +2471,7 @@ async function importConfiguration(options) {
|
|
|
2267
2471
|
let mcpFileCreated = false;
|
|
2268
2472
|
if (mcpServers && Object.keys(mcpServers).length > 0) {
|
|
2269
2473
|
try {
|
|
2270
|
-
const mcpPath = (0,
|
|
2474
|
+
const mcpPath = (0, import_node_path19.join)(baseDir, rulesDir, ".mcp.json");
|
|
2271
2475
|
const mcpContent = `${JSON.stringify({ mcpServers }, null, 2)}
|
|
2272
2476
|
`;
|
|
2273
2477
|
await writeFileContent(mcpPath, mcpContent);
|
|
@@ -2281,7 +2485,7 @@ async function importConfiguration(options) {
|
|
|
2281
2485
|
}
|
|
2282
2486
|
}
|
|
2283
2487
|
return {
|
|
2284
|
-
success: rulesCreated > 0 || ignoreFileCreated || mcpFileCreated,
|
|
2488
|
+
success: errors.length === 0 && (rulesCreated > 0 || ignoreFileCreated || mcpFileCreated),
|
|
2285
2489
|
rulesCreated,
|
|
2286
2490
|
errors,
|
|
2287
2491
|
ignoreFileCreated,
|
|
@@ -2295,7 +2499,7 @@ function generateRuleFileContent(rule) {
|
|
|
2295
2499
|
async function generateUniqueFilename(rulesDir, baseFilename) {
|
|
2296
2500
|
let filename = baseFilename;
|
|
2297
2501
|
let counter = 1;
|
|
2298
|
-
while (await fileExists((0,
|
|
2502
|
+
while (await fileExists((0, import_node_path19.join)(rulesDir, `${filename}.md`))) {
|
|
2299
2503
|
filename = `${baseFilename}-${counter}`;
|
|
2300
2504
|
counter++;
|
|
2301
2505
|
}
|
|
@@ -2360,7 +2564,7 @@ async function importCommand(options = {}) {
|
|
|
2360
2564
|
}
|
|
2361
2565
|
|
|
2362
2566
|
// src/cli/commands/init.ts
|
|
2363
|
-
var
|
|
2567
|
+
var import_node_path20 = require("path");
|
|
2364
2568
|
async function initCommand() {
|
|
2365
2569
|
const aiRulesDir = ".rulesync";
|
|
2366
2570
|
console.log("Initializing rulesync...");
|
|
@@ -2407,7 +2611,7 @@ globs: ["**/*"]
|
|
|
2407
2611
|
- Follow single responsibility principle
|
|
2408
2612
|
`
|
|
2409
2613
|
};
|
|
2410
|
-
const filepath = (0,
|
|
2614
|
+
const filepath = (0, import_node_path20.join)(aiRulesDir, sampleFile.filename);
|
|
2411
2615
|
if (!await fileExists(filepath)) {
|
|
2412
2616
|
await writeFileContent(filepath, sampleFile.content);
|
|
2413
2617
|
console.log(`Created ${filepath}`);
|
|
@@ -2551,12 +2755,12 @@ async function watchCommand() {
|
|
|
2551
2755
|
|
|
2552
2756
|
// src/cli/index.ts
|
|
2553
2757
|
var program = new import_commander.Command();
|
|
2554
|
-
program.name("rulesync").description("Unified AI rules management CLI tool").version("0.
|
|
2758
|
+
program.name("rulesync").description("Unified AI rules management CLI tool").version("0.48.0");
|
|
2555
2759
|
program.command("init").description("Initialize rulesync in current directory").action(initCommand);
|
|
2556
2760
|
program.command("add <filename>").description("Add a new rule file").action(addCommand);
|
|
2557
2761
|
program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);
|
|
2558
2762
|
program.command("import").description("Import configurations from AI tools to rulesync format").option("--claudecode", "Import from Claude Code (CLAUDE.md)").option("--cursor", "Import from Cursor (.cursorrules)").option("--copilot", "Import from GitHub Copilot (.github/copilot-instructions.md)").option("--cline", "Import from Cline (.cline/instructions.md)").option("--roo", "Import from Roo Code (.roo/instructions.md)").option("--geminicli", "Import from Gemini CLI (GEMINI.md)").option("-v, --verbose", "Verbose output").action(importCommand);
|
|
2559
|
-
program.command("generate").description("Generate configuration files for AI tools").option("--copilot", "Generate only for GitHub Copilot").option("--cursor", "Generate only for Cursor").option("--cline", "Generate only for Cline").option("--claudecode", "Generate only for Claude Code").option("--roo", "Generate only for Roo Code").option("--geminicli", "Generate only for Gemini CLI").option("--delete", "Delete all existing files in output directories before generating").option(
|
|
2763
|
+
program.command("generate").description("Generate configuration files for AI tools").option("--copilot", "Generate only for GitHub Copilot").option("--cursor", "Generate only for Cursor").option("--cline", "Generate only for Cline").option("--claudecode", "Generate only for Claude Code").option("--roo", "Generate only for Roo Code").option("--geminicli", "Generate only for Gemini CLI").option("--kiro", "Generate only for Kiro IDE").option("--delete", "Delete all existing files in output directories before generating").option(
|
|
2560
2764
|
"-b, --base-dir <paths>",
|
|
2561
2765
|
"Base directories to generate files (comma-separated for multiple paths)"
|
|
2562
2766
|
).option("-v, --verbose", "Verbose output").action(async (options) => {
|
|
@@ -2567,6 +2771,7 @@ program.command("generate").description("Generate configuration files for AI too
|
|
|
2567
2771
|
if (options.claudecode) tools.push("claudecode");
|
|
2568
2772
|
if (options.roo) tools.push("roo");
|
|
2569
2773
|
if (options.geminicli) tools.push("geminicli");
|
|
2774
|
+
if (options.kiro) tools.push("kiro");
|
|
2570
2775
|
const generateOptions = {
|
|
2571
2776
|
verbose: options.verbose,
|
|
2572
2777
|
delete: options.delete
|