rulesync 0.45.0 → 0.47.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 +368 -170
- package/dist/index.js +288 -140
- 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);
|
|
@@ -1386,9 +1581,9 @@ Generating configurations for base directory: ${baseDir}`);
|
|
|
1386
1581
|
|
|
1387
1582
|
// src/cli/commands/gitignore.ts
|
|
1388
1583
|
var import_node_fs = require("fs");
|
|
1389
|
-
var
|
|
1584
|
+
var import_node_path12 = require("path");
|
|
1390
1585
|
var gitignoreCommand = async () => {
|
|
1391
|
-
const gitignorePath = (0,
|
|
1586
|
+
const gitignorePath = (0, import_node_path12.join)(process.cwd(), ".gitignore");
|
|
1392
1587
|
const rulesFilesToIgnore = [
|
|
1393
1588
|
"# Generated by rulesync - AI tool configuration files",
|
|
1394
1589
|
"**/.github/copilot-instructions.md",
|
|
@@ -1405,6 +1600,8 @@ var gitignoreCommand = async () => {
|
|
|
1405
1600
|
"**/GEMINI.md",
|
|
1406
1601
|
"**/.gemini/memories/",
|
|
1407
1602
|
"**/.aiexclude",
|
|
1603
|
+
"**/.aiignore",
|
|
1604
|
+
"**/.kiro/steering/",
|
|
1408
1605
|
"**/.mcp.json",
|
|
1409
1606
|
"!.rulesync/.mcp.json",
|
|
1410
1607
|
"**/.cursor/mcp.json",
|
|
@@ -1442,17 +1639,17 @@ ${linesToAdd.join("\n")}
|
|
|
1442
1639
|
};
|
|
1443
1640
|
|
|
1444
1641
|
// src/core/importer.ts
|
|
1445
|
-
var
|
|
1642
|
+
var import_node_path19 = require("path");
|
|
1446
1643
|
var import_gray_matter4 = __toESM(require("gray-matter"), 1);
|
|
1447
1644
|
|
|
1448
1645
|
// src/parsers/claudecode.ts
|
|
1449
|
-
var
|
|
1646
|
+
var import_node_path13 = require("path");
|
|
1450
1647
|
async function parseClaudeConfiguration(baseDir = process.cwd()) {
|
|
1451
1648
|
const errors = [];
|
|
1452
1649
|
const rules = [];
|
|
1453
1650
|
let ignorePatterns;
|
|
1454
1651
|
let mcpServers;
|
|
1455
|
-
const claudeFilePath = (0,
|
|
1652
|
+
const claudeFilePath = (0, import_node_path13.join)(baseDir, "CLAUDE.md");
|
|
1456
1653
|
if (!await fileExists(claudeFilePath)) {
|
|
1457
1654
|
errors.push("CLAUDE.md file not found");
|
|
1458
1655
|
return { rules, errors };
|
|
@@ -1463,12 +1660,12 @@ async function parseClaudeConfiguration(baseDir = process.cwd()) {
|
|
|
1463
1660
|
if (mainRule) {
|
|
1464
1661
|
rules.push(mainRule);
|
|
1465
1662
|
}
|
|
1466
|
-
const memoryDir = (0,
|
|
1663
|
+
const memoryDir = (0, import_node_path13.join)(baseDir, ".claude", "memories");
|
|
1467
1664
|
if (await fileExists(memoryDir)) {
|
|
1468
1665
|
const memoryRules = await parseClaudeMemoryFiles(memoryDir);
|
|
1469
1666
|
rules.push(...memoryRules);
|
|
1470
1667
|
}
|
|
1471
|
-
const settingsPath = (0,
|
|
1668
|
+
const settingsPath = (0, import_node_path13.join)(baseDir, ".claude", "settings.json");
|
|
1472
1669
|
if (await fileExists(settingsPath)) {
|
|
1473
1670
|
const settingsResult = await parseClaudeSettings(settingsPath);
|
|
1474
1671
|
if (settingsResult.ignorePatterns) {
|
|
@@ -1525,10 +1722,10 @@ async function parseClaudeMemoryFiles(memoryDir) {
|
|
|
1525
1722
|
const files = await readdir2(memoryDir);
|
|
1526
1723
|
for (const file of files) {
|
|
1527
1724
|
if (file.endsWith(".md")) {
|
|
1528
|
-
const filePath = (0,
|
|
1725
|
+
const filePath = (0, import_node_path13.join)(memoryDir, file);
|
|
1529
1726
|
const content = await readFileContent(filePath);
|
|
1530
1727
|
if (content.trim()) {
|
|
1531
|
-
const filename = (0,
|
|
1728
|
+
const filename = (0, import_node_path13.basename)(file, ".md");
|
|
1532
1729
|
const frontmatter = {
|
|
1533
1730
|
root: false,
|
|
1534
1731
|
targets: ["claudecode"],
|
|
@@ -1588,11 +1785,11 @@ async function parseClaudeSettings(settingsPath) {
|
|
|
1588
1785
|
}
|
|
1589
1786
|
|
|
1590
1787
|
// src/parsers/cline.ts
|
|
1591
|
-
var
|
|
1788
|
+
var import_node_path14 = require("path");
|
|
1592
1789
|
async function parseClineConfiguration(baseDir = process.cwd()) {
|
|
1593
1790
|
const errors = [];
|
|
1594
1791
|
const rules = [];
|
|
1595
|
-
const clineFilePath = (0,
|
|
1792
|
+
const clineFilePath = (0, import_node_path14.join)(baseDir, ".cline", "instructions.md");
|
|
1596
1793
|
if (await fileExists(clineFilePath)) {
|
|
1597
1794
|
try {
|
|
1598
1795
|
const content = await readFileContent(clineFilePath);
|
|
@@ -1615,14 +1812,14 @@ async function parseClineConfiguration(baseDir = process.cwd()) {
|
|
|
1615
1812
|
errors.push(`Failed to parse .cline/instructions.md: ${errorMessage}`);
|
|
1616
1813
|
}
|
|
1617
1814
|
}
|
|
1618
|
-
const clinerulesDirPath = (0,
|
|
1815
|
+
const clinerulesDirPath = (0, import_node_path14.join)(baseDir, ".clinerules");
|
|
1619
1816
|
if (await fileExists(clinerulesDirPath)) {
|
|
1620
1817
|
try {
|
|
1621
1818
|
const { readdir: readdir2 } = await import("fs/promises");
|
|
1622
1819
|
const files = await readdir2(clinerulesDirPath);
|
|
1623
1820
|
for (const file of files) {
|
|
1624
1821
|
if (file.endsWith(".md")) {
|
|
1625
|
-
const filePath = (0,
|
|
1822
|
+
const filePath = (0, import_node_path14.join)(clinerulesDirPath, file);
|
|
1626
1823
|
try {
|
|
1627
1824
|
const content = await readFileContent(filePath);
|
|
1628
1825
|
if (content.trim()) {
|
|
@@ -1658,12 +1855,12 @@ async function parseClineConfiguration(baseDir = process.cwd()) {
|
|
|
1658
1855
|
}
|
|
1659
1856
|
|
|
1660
1857
|
// src/parsers/copilot.ts
|
|
1661
|
-
var
|
|
1858
|
+
var import_node_path15 = require("path");
|
|
1662
1859
|
var import_gray_matter2 = __toESM(require("gray-matter"), 1);
|
|
1663
1860
|
async function parseCopilotConfiguration(baseDir = process.cwd()) {
|
|
1664
1861
|
const errors = [];
|
|
1665
1862
|
const rules = [];
|
|
1666
|
-
const copilotFilePath = (0,
|
|
1863
|
+
const copilotFilePath = (0, import_node_path15.join)(baseDir, ".github", "copilot-instructions.md");
|
|
1667
1864
|
if (await fileExists(copilotFilePath)) {
|
|
1668
1865
|
try {
|
|
1669
1866
|
const rawContent = await readFileContent(copilotFilePath);
|
|
@@ -1688,19 +1885,19 @@ async function parseCopilotConfiguration(baseDir = process.cwd()) {
|
|
|
1688
1885
|
errors.push(`Failed to parse copilot-instructions.md: ${errorMessage}`);
|
|
1689
1886
|
}
|
|
1690
1887
|
}
|
|
1691
|
-
const instructionsDir = (0,
|
|
1888
|
+
const instructionsDir = (0, import_node_path15.join)(baseDir, ".github", "instructions");
|
|
1692
1889
|
if (await fileExists(instructionsDir)) {
|
|
1693
1890
|
try {
|
|
1694
1891
|
const { readdir: readdir2 } = await import("fs/promises");
|
|
1695
1892
|
const files = await readdir2(instructionsDir);
|
|
1696
1893
|
for (const file of files) {
|
|
1697
1894
|
if (file.endsWith(".instructions.md")) {
|
|
1698
|
-
const filePath = (0,
|
|
1895
|
+
const filePath = (0, import_node_path15.join)(instructionsDir, file);
|
|
1699
1896
|
const rawContent = await readFileContent(filePath);
|
|
1700
1897
|
const parsed = (0, import_gray_matter2.default)(rawContent);
|
|
1701
1898
|
const content = parsed.content.trim();
|
|
1702
1899
|
if (content) {
|
|
1703
|
-
const filename = (0,
|
|
1900
|
+
const filename = (0, import_node_path15.basename)(file, ".instructions.md");
|
|
1704
1901
|
const frontmatter = {
|
|
1705
1902
|
root: false,
|
|
1706
1903
|
targets: ["copilot"],
|
|
@@ -1730,10 +1927,10 @@ async function parseCopilotConfiguration(baseDir = process.cwd()) {
|
|
|
1730
1927
|
}
|
|
1731
1928
|
|
|
1732
1929
|
// src/parsers/cursor.ts
|
|
1733
|
-
var
|
|
1930
|
+
var import_node_path16 = require("path");
|
|
1734
1931
|
var import_gray_matter3 = __toESM(require("gray-matter"), 1);
|
|
1735
1932
|
var import_js_yaml = require("js-yaml");
|
|
1736
|
-
var
|
|
1933
|
+
var import_mini6 = require("zod/mini");
|
|
1737
1934
|
var customMatterOptions = {
|
|
1738
1935
|
engines: {
|
|
1739
1936
|
yaml: {
|
|
@@ -1761,7 +1958,7 @@ var customMatterOptions = {
|
|
|
1761
1958
|
}
|
|
1762
1959
|
};
|
|
1763
1960
|
function convertCursorMdcFrontmatter(cursorFrontmatter, _filename) {
|
|
1764
|
-
const FrontmatterSchema =
|
|
1961
|
+
const FrontmatterSchema = import_mini6.z.record(import_mini6.z.string(), import_mini6.z.unknown());
|
|
1765
1962
|
const parseResult = FrontmatterSchema.safeParse(cursorFrontmatter);
|
|
1766
1963
|
if (!parseResult.success) {
|
|
1767
1964
|
return {
|
|
@@ -1855,7 +2052,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
1855
2052
|
const rules = [];
|
|
1856
2053
|
let ignorePatterns;
|
|
1857
2054
|
let mcpServers;
|
|
1858
|
-
const cursorFilePath = (0,
|
|
2055
|
+
const cursorFilePath = (0, import_node_path16.join)(baseDir, ".cursorrules");
|
|
1859
2056
|
if (await fileExists(cursorFilePath)) {
|
|
1860
2057
|
try {
|
|
1861
2058
|
const rawContent = await readFileContent(cursorFilePath);
|
|
@@ -1876,20 +2073,20 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
1876
2073
|
errors.push(`Failed to parse .cursorrules file: ${errorMessage}`);
|
|
1877
2074
|
}
|
|
1878
2075
|
}
|
|
1879
|
-
const cursorRulesDir = (0,
|
|
2076
|
+
const cursorRulesDir = (0, import_node_path16.join)(baseDir, ".cursor", "rules");
|
|
1880
2077
|
if (await fileExists(cursorRulesDir)) {
|
|
1881
2078
|
try {
|
|
1882
2079
|
const { readdir: readdir2 } = await import("fs/promises");
|
|
1883
2080
|
const files = await readdir2(cursorRulesDir);
|
|
1884
2081
|
for (const file of files) {
|
|
1885
2082
|
if (file.endsWith(".mdc")) {
|
|
1886
|
-
const filePath = (0,
|
|
2083
|
+
const filePath = (0, import_node_path16.join)(cursorRulesDir, file);
|
|
1887
2084
|
try {
|
|
1888
2085
|
const rawContent = await readFileContent(filePath);
|
|
1889
2086
|
const parsed = (0, import_gray_matter3.default)(rawContent, customMatterOptions);
|
|
1890
2087
|
const content = parsed.content.trim();
|
|
1891
2088
|
if (content) {
|
|
1892
|
-
const filename = (0,
|
|
2089
|
+
const filename = (0, import_node_path16.basename)(file, ".mdc");
|
|
1893
2090
|
const frontmatter = convertCursorMdcFrontmatter(parsed.data, filename);
|
|
1894
2091
|
rules.push({
|
|
1895
2092
|
frontmatter,
|
|
@@ -1912,7 +2109,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
1912
2109
|
if (rules.length === 0) {
|
|
1913
2110
|
errors.push("No Cursor configuration files found (.cursorrules or .cursor/rules/*.mdc)");
|
|
1914
2111
|
}
|
|
1915
|
-
const cursorIgnorePath = (0,
|
|
2112
|
+
const cursorIgnorePath = (0, import_node_path16.join)(baseDir, ".cursorignore");
|
|
1916
2113
|
if (await fileExists(cursorIgnorePath)) {
|
|
1917
2114
|
try {
|
|
1918
2115
|
const content = await readFileContent(cursorIgnorePath);
|
|
@@ -1925,7 +2122,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
1925
2122
|
errors.push(`Failed to parse .cursorignore: ${errorMessage}`);
|
|
1926
2123
|
}
|
|
1927
2124
|
}
|
|
1928
|
-
const cursorMcpPath = (0,
|
|
2125
|
+
const cursorMcpPath = (0, import_node_path16.join)(baseDir, ".cursor", "mcp.json");
|
|
1929
2126
|
if (await fileExists(cursorMcpPath)) {
|
|
1930
2127
|
try {
|
|
1931
2128
|
const content = await readFileContent(cursorMcpPath);
|
|
@@ -1948,13 +2145,13 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
1948
2145
|
}
|
|
1949
2146
|
|
|
1950
2147
|
// src/parsers/geminicli.ts
|
|
1951
|
-
var
|
|
2148
|
+
var import_node_path17 = require("path");
|
|
1952
2149
|
async function parseGeminiConfiguration(baseDir = process.cwd()) {
|
|
1953
2150
|
const errors = [];
|
|
1954
2151
|
const rules = [];
|
|
1955
2152
|
let ignorePatterns;
|
|
1956
2153
|
let mcpServers;
|
|
1957
|
-
const geminiFilePath = (0,
|
|
2154
|
+
const geminiFilePath = (0, import_node_path17.join)(baseDir, "GEMINI.md");
|
|
1958
2155
|
if (!await fileExists(geminiFilePath)) {
|
|
1959
2156
|
errors.push("GEMINI.md file not found");
|
|
1960
2157
|
return { rules, errors };
|
|
@@ -1965,12 +2162,12 @@ async function parseGeminiConfiguration(baseDir = process.cwd()) {
|
|
|
1965
2162
|
if (mainRule) {
|
|
1966
2163
|
rules.push(mainRule);
|
|
1967
2164
|
}
|
|
1968
|
-
const memoryDir = (0,
|
|
2165
|
+
const memoryDir = (0, import_node_path17.join)(baseDir, ".gemini", "memories");
|
|
1969
2166
|
if (await fileExists(memoryDir)) {
|
|
1970
2167
|
const memoryRules = await parseGeminiMemoryFiles(memoryDir);
|
|
1971
2168
|
rules.push(...memoryRules);
|
|
1972
2169
|
}
|
|
1973
|
-
const settingsPath = (0,
|
|
2170
|
+
const settingsPath = (0, import_node_path17.join)(baseDir, ".gemini", "settings.json");
|
|
1974
2171
|
if (await fileExists(settingsPath)) {
|
|
1975
2172
|
const settingsResult = await parseGeminiSettings(settingsPath);
|
|
1976
2173
|
if (settingsResult.ignorePatterns) {
|
|
@@ -1981,7 +2178,7 @@ async function parseGeminiConfiguration(baseDir = process.cwd()) {
|
|
|
1981
2178
|
}
|
|
1982
2179
|
errors.push(...settingsResult.errors);
|
|
1983
2180
|
}
|
|
1984
|
-
const aiexcludePath = (0,
|
|
2181
|
+
const aiexcludePath = (0, import_node_path17.join)(baseDir, ".aiexclude");
|
|
1985
2182
|
if (await fileExists(aiexcludePath)) {
|
|
1986
2183
|
const aiexcludePatterns = await parseAiexclude(aiexcludePath);
|
|
1987
2184
|
if (aiexcludePatterns.length > 0) {
|
|
@@ -2034,10 +2231,10 @@ async function parseGeminiMemoryFiles(memoryDir) {
|
|
|
2034
2231
|
const files = await readdir2(memoryDir);
|
|
2035
2232
|
for (const file of files) {
|
|
2036
2233
|
if (file.endsWith(".md")) {
|
|
2037
|
-
const filePath = (0,
|
|
2234
|
+
const filePath = (0, import_node_path17.join)(memoryDir, file);
|
|
2038
2235
|
const content = await readFileContent(filePath);
|
|
2039
2236
|
if (content.trim()) {
|
|
2040
|
-
const filename = (0,
|
|
2237
|
+
const filename = (0, import_node_path17.basename)(file, ".md");
|
|
2041
2238
|
const frontmatter = {
|
|
2042
2239
|
root: false,
|
|
2043
2240
|
targets: ["geminicli"],
|
|
@@ -2087,11 +2284,11 @@ async function parseAiexclude(aiexcludePath) {
|
|
|
2087
2284
|
}
|
|
2088
2285
|
|
|
2089
2286
|
// src/parsers/roo.ts
|
|
2090
|
-
var
|
|
2287
|
+
var import_node_path18 = require("path");
|
|
2091
2288
|
async function parseRooConfiguration(baseDir = process.cwd()) {
|
|
2092
2289
|
const errors = [];
|
|
2093
2290
|
const rules = [];
|
|
2094
|
-
const rooFilePath = (0,
|
|
2291
|
+
const rooFilePath = (0, import_node_path18.join)(baseDir, ".roo", "instructions.md");
|
|
2095
2292
|
if (await fileExists(rooFilePath)) {
|
|
2096
2293
|
try {
|
|
2097
2294
|
const content = await readFileContent(rooFilePath);
|
|
@@ -2114,14 +2311,14 @@ async function parseRooConfiguration(baseDir = process.cwd()) {
|
|
|
2114
2311
|
errors.push(`Failed to parse .roo/instructions.md: ${errorMessage}`);
|
|
2115
2312
|
}
|
|
2116
2313
|
}
|
|
2117
|
-
const rooRulesDir = (0,
|
|
2314
|
+
const rooRulesDir = (0, import_node_path18.join)(baseDir, ".roo", "rules");
|
|
2118
2315
|
if (await fileExists(rooRulesDir)) {
|
|
2119
2316
|
try {
|
|
2120
2317
|
const { readdir: readdir2 } = await import("fs/promises");
|
|
2121
2318
|
const files = await readdir2(rooRulesDir);
|
|
2122
2319
|
for (const file of files) {
|
|
2123
2320
|
if (file.endsWith(".md")) {
|
|
2124
|
-
const filePath = (0,
|
|
2321
|
+
const filePath = (0, import_node_path18.join)(rooRulesDir, file);
|
|
2125
2322
|
try {
|
|
2126
2323
|
const content = await readFileContent(filePath);
|
|
2127
2324
|
if (content.trim()) {
|
|
@@ -2222,7 +2419,7 @@ async function importConfiguration(options) {
|
|
|
2222
2419
|
if (rules.length === 0 && !ignorePatterns && !mcpServers) {
|
|
2223
2420
|
return { success: false, rulesCreated: 0, errors };
|
|
2224
2421
|
}
|
|
2225
|
-
const rulesDirPath = (0,
|
|
2422
|
+
const rulesDirPath = (0, import_node_path19.join)(baseDir, rulesDir);
|
|
2226
2423
|
try {
|
|
2227
2424
|
const { mkdir: mkdir3 } = await import("fs/promises");
|
|
2228
2425
|
await mkdir3(rulesDirPath, { recursive: true });
|
|
@@ -2236,7 +2433,7 @@ async function importConfiguration(options) {
|
|
|
2236
2433
|
try {
|
|
2237
2434
|
const baseFilename = `${tool}__${rule.filename}`;
|
|
2238
2435
|
const filename = await generateUniqueFilename(rulesDirPath, baseFilename);
|
|
2239
|
-
const filePath = (0,
|
|
2436
|
+
const filePath = (0, import_node_path19.join)(rulesDirPath, `${filename}.md`);
|
|
2240
2437
|
const content = generateRuleFileContent(rule);
|
|
2241
2438
|
await writeFileContent(filePath, content);
|
|
2242
2439
|
rulesCreated++;
|
|
@@ -2251,7 +2448,7 @@ async function importConfiguration(options) {
|
|
|
2251
2448
|
let ignoreFileCreated = false;
|
|
2252
2449
|
if (ignorePatterns && ignorePatterns.length > 0) {
|
|
2253
2450
|
try {
|
|
2254
|
-
const rulesyncignorePath = (0,
|
|
2451
|
+
const rulesyncignorePath = (0, import_node_path19.join)(baseDir, ".rulesyncignore");
|
|
2255
2452
|
const ignoreContent = `${ignorePatterns.join("\n")}
|
|
2256
2453
|
`;
|
|
2257
2454
|
await writeFileContent(rulesyncignorePath, ignoreContent);
|
|
@@ -2267,7 +2464,7 @@ async function importConfiguration(options) {
|
|
|
2267
2464
|
let mcpFileCreated = false;
|
|
2268
2465
|
if (mcpServers && Object.keys(mcpServers).length > 0) {
|
|
2269
2466
|
try {
|
|
2270
|
-
const mcpPath = (0,
|
|
2467
|
+
const mcpPath = (0, import_node_path19.join)(baseDir, rulesDir, ".mcp.json");
|
|
2271
2468
|
const mcpContent = `${JSON.stringify({ mcpServers }, null, 2)}
|
|
2272
2469
|
`;
|
|
2273
2470
|
await writeFileContent(mcpPath, mcpContent);
|
|
@@ -2281,7 +2478,7 @@ async function importConfiguration(options) {
|
|
|
2281
2478
|
}
|
|
2282
2479
|
}
|
|
2283
2480
|
return {
|
|
2284
|
-
success: rulesCreated > 0 || ignoreFileCreated || mcpFileCreated,
|
|
2481
|
+
success: errors.length === 0 && (rulesCreated > 0 || ignoreFileCreated || mcpFileCreated),
|
|
2285
2482
|
rulesCreated,
|
|
2286
2483
|
errors,
|
|
2287
2484
|
ignoreFileCreated,
|
|
@@ -2295,7 +2492,7 @@ function generateRuleFileContent(rule) {
|
|
|
2295
2492
|
async function generateUniqueFilename(rulesDir, baseFilename) {
|
|
2296
2493
|
let filename = baseFilename;
|
|
2297
2494
|
let counter = 1;
|
|
2298
|
-
while (await fileExists((0,
|
|
2495
|
+
while (await fileExists((0, import_node_path19.join)(rulesDir, `${filename}.md`))) {
|
|
2299
2496
|
filename = `${baseFilename}-${counter}`;
|
|
2300
2497
|
counter++;
|
|
2301
2498
|
}
|
|
@@ -2360,7 +2557,7 @@ async function importCommand(options = {}) {
|
|
|
2360
2557
|
}
|
|
2361
2558
|
|
|
2362
2559
|
// src/cli/commands/init.ts
|
|
2363
|
-
var
|
|
2560
|
+
var import_node_path20 = require("path");
|
|
2364
2561
|
async function initCommand() {
|
|
2365
2562
|
const aiRulesDir = ".rulesync";
|
|
2366
2563
|
console.log("Initializing rulesync...");
|
|
@@ -2407,7 +2604,7 @@ globs: ["**/*"]
|
|
|
2407
2604
|
- Follow single responsibility principle
|
|
2408
2605
|
`
|
|
2409
2606
|
};
|
|
2410
|
-
const filepath = (0,
|
|
2607
|
+
const filepath = (0, import_node_path20.join)(aiRulesDir, sampleFile.filename);
|
|
2411
2608
|
if (!await fileExists(filepath)) {
|
|
2412
2609
|
await writeFileContent(filepath, sampleFile.content);
|
|
2413
2610
|
console.log(`Created ${filepath}`);
|
|
@@ -2551,12 +2748,12 @@ async function watchCommand() {
|
|
|
2551
2748
|
|
|
2552
2749
|
// src/cli/index.ts
|
|
2553
2750
|
var program = new import_commander.Command();
|
|
2554
|
-
program.name("rulesync").description("Unified AI rules management CLI tool").version("0.
|
|
2751
|
+
program.name("rulesync").description("Unified AI rules management CLI tool").version("0.47.0");
|
|
2555
2752
|
program.command("init").description("Initialize rulesync in current directory").action(initCommand);
|
|
2556
2753
|
program.command("add <filename>").description("Add a new rule file").action(addCommand);
|
|
2557
2754
|
program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);
|
|
2558
2755
|
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(
|
|
2756
|
+
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
2757
|
"-b, --base-dir <paths>",
|
|
2561
2758
|
"Base directories to generate files (comma-separated for multiple paths)"
|
|
2562
2759
|
).option("-v, --verbose", "Verbose output").action(async (options) => {
|
|
@@ -2567,6 +2764,7 @@ program.command("generate").description("Generate configuration files for AI too
|
|
|
2567
2764
|
if (options.claudecode) tools.push("claudecode");
|
|
2568
2765
|
if (options.roo) tools.push("roo");
|
|
2569
2766
|
if (options.geminicli) tools.push("geminicli");
|
|
2767
|
+
if (options.kiro) tools.push("kiro");
|
|
2570
2768
|
const generateOptions = {
|
|
2571
2769
|
verbose: options.verbose,
|
|
2572
2770
|
delete: options.delete
|