rulesync 0.49.0 → 0.51.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 +3 -2
- package/README.md +90 -2
- package/dist/{augmentcode-KTXT5GMO.js → augmentcode-ICLQ2NEZ.js} +2 -2
- package/dist/{chunk-YVRWBSCK.js → chunk-4MZXYV5H.js} +1 -1
- package/dist/{chunk-XHNIEO22.js → chunk-AREA26HF.js} +1 -1
- package/dist/{chunk-MCADLVGY.js → chunk-FFW6TGCM.js} +1 -1
- package/dist/{chunk-QNHGYRJT.js → chunk-IXCMY24P.js} +1 -1
- package/dist/{chunk-6TAURCQP.js → chunk-OPZOVKIL.js} +1 -1
- package/dist/{chunk-R5HFWJ5L.js → chunk-QUJMXHNR.js} +1 -1
- package/dist/{chunk-6MFEIYHN.js → chunk-TTHBLXOB.js} +1 -1
- package/dist/{chunk-IBJGN3JQ.js → chunk-USKQYIZ2.js} +11 -3
- package/dist/chunk-Y26DXTAT.js +90 -0
- package/dist/{chunk-G5LLOIO4.js → chunk-Y2XH4E5R.js} +1 -1
- package/dist/{claudecode-OE4TSKPS.js → claudecode-SRXYHIJE.js} +2 -2
- package/dist/{cline-CWLQS5CV.js → cline-IJW27CUU.js} +2 -2
- package/dist/{copilot-PVZDRAU5.js → copilot-ARYIWVJ7.js} +2 -2
- package/dist/{cursor-ZZV7AY6H.js → cursor-FCS74IAH.js} +2 -2
- package/dist/{geminicli-RSXOWFEN.js → geminicli-VOPV6DXZ.js} +2 -2
- package/dist/index.cjs +1374 -549
- package/dist/index.js +1254 -484
- package/dist/junie-A2Y2WZI4.js +9 -0
- package/dist/{kiro-YRKVCDIQ.js → kiro-MHIK4UBV.js} +2 -2
- package/dist/{roo-HCRGELWQ.js → roo-VG4IUNTE.js} +2 -2
- package/package.json +17 -16
package/dist/index.cjs
CHANGED
|
@@ -27,12 +27,16 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
27
|
));
|
|
28
28
|
|
|
29
29
|
// src/types/tool-targets.ts
|
|
30
|
-
|
|
30
|
+
function isToolTarget(target) {
|
|
31
|
+
if (!target) return false;
|
|
32
|
+
return ALL_TOOL_TARGETS.some((validTarget) => validTarget === target);
|
|
33
|
+
}
|
|
34
|
+
var import_mini, ALL_TOOL_TARGETS, ToolTargetSchema, ToolTargetsSchema, WildcardTargetSchema, RulesyncTargetsSchema;
|
|
31
35
|
var init_tool_targets = __esm({
|
|
32
36
|
"src/types/tool-targets.ts"() {
|
|
33
37
|
"use strict";
|
|
34
38
|
import_mini = require("zod/mini");
|
|
35
|
-
|
|
39
|
+
ALL_TOOL_TARGETS = [
|
|
36
40
|
"augmentcode",
|
|
37
41
|
"augmentcode-legacy",
|
|
38
42
|
"copilot",
|
|
@@ -41,8 +45,10 @@ var init_tool_targets = __esm({
|
|
|
41
45
|
"claudecode",
|
|
42
46
|
"roo",
|
|
43
47
|
"geminicli",
|
|
44
|
-
"kiro"
|
|
45
|
-
|
|
48
|
+
"kiro",
|
|
49
|
+
"junie"
|
|
50
|
+
];
|
|
51
|
+
ToolTargetSchema = import_mini.z.enum(ALL_TOOL_TARGETS);
|
|
46
52
|
ToolTargetsSchema = import_mini.z.array(ToolTargetSchema);
|
|
47
53
|
WildcardTargetSchema = import_mini.z.tuple([import_mini.z.literal("*")]);
|
|
48
54
|
RulesyncTargetsSchema = import_mini.z.union([ToolTargetsSchema, WildcardTargetSchema]);
|
|
@@ -354,6 +360,58 @@ var init_geminicli = __esm({
|
|
|
354
360
|
}
|
|
355
361
|
});
|
|
356
362
|
|
|
363
|
+
// src/generators/mcp/junie.ts
|
|
364
|
+
function generateJunieMcp(config) {
|
|
365
|
+
const junieConfig = {
|
|
366
|
+
mcpServers: {}
|
|
367
|
+
};
|
|
368
|
+
for (const [serverName, server] of Object.entries(config.mcpServers)) {
|
|
369
|
+
if (!shouldIncludeServer(server, "junie")) continue;
|
|
370
|
+
const junieServer = {
|
|
371
|
+
name: serverName
|
|
372
|
+
};
|
|
373
|
+
if (server.command) {
|
|
374
|
+
junieServer.command = server.command;
|
|
375
|
+
if (server.args) junieServer.args = server.args;
|
|
376
|
+
} else if (server.url || server.httpUrl) {
|
|
377
|
+
if (server.httpUrl) {
|
|
378
|
+
junieServer.httpUrl = server.httpUrl;
|
|
379
|
+
} else if (server.url) {
|
|
380
|
+
junieServer.url = server.url;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
if (server.env) {
|
|
384
|
+
junieServer.env = server.env;
|
|
385
|
+
}
|
|
386
|
+
if (server.cwd) {
|
|
387
|
+
junieServer.workingDirectory = server.cwd;
|
|
388
|
+
}
|
|
389
|
+
if (server.timeout !== void 0) {
|
|
390
|
+
junieServer.timeout = server.timeout;
|
|
391
|
+
}
|
|
392
|
+
if (server.trust !== void 0) {
|
|
393
|
+
junieServer.trust = server.trust;
|
|
394
|
+
}
|
|
395
|
+
if (server.transport) {
|
|
396
|
+
if (String(server.transport) === "streamable-http") {
|
|
397
|
+
junieServer.transport = "http";
|
|
398
|
+
} else if (server.transport === "stdio" || server.transport === "http" || server.transport === "sse") {
|
|
399
|
+
junieServer.transport = server.transport;
|
|
400
|
+
}
|
|
401
|
+
} else if (server.command) {
|
|
402
|
+
junieServer.transport = "stdio";
|
|
403
|
+
}
|
|
404
|
+
junieConfig.mcpServers[serverName] = junieServer;
|
|
405
|
+
}
|
|
406
|
+
return JSON.stringify(junieConfig, null, 2);
|
|
407
|
+
}
|
|
408
|
+
var init_junie = __esm({
|
|
409
|
+
"src/generators/mcp/junie.ts"() {
|
|
410
|
+
"use strict";
|
|
411
|
+
init_mcp_helpers();
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
|
|
357
415
|
// src/generators/mcp/kiro.ts
|
|
358
416
|
function generateKiroMcp(config) {
|
|
359
417
|
const kiroConfig = {
|
|
@@ -478,19 +536,11 @@ function getDefaultConfig() {
|
|
|
478
536
|
claudecode: ".",
|
|
479
537
|
roo: ".roo/rules",
|
|
480
538
|
geminicli: ".gemini/memories",
|
|
481
|
-
kiro: ".kiro/steering"
|
|
539
|
+
kiro: ".kiro/steering",
|
|
540
|
+
junie: "."
|
|
482
541
|
},
|
|
483
542
|
watchEnabled: false,
|
|
484
|
-
defaultTargets:
|
|
485
|
-
"augmentcode",
|
|
486
|
-
"copilot",
|
|
487
|
-
"cursor",
|
|
488
|
-
"cline",
|
|
489
|
-
"claudecode",
|
|
490
|
-
"roo",
|
|
491
|
-
"geminicli",
|
|
492
|
-
"kiro"
|
|
493
|
-
]
|
|
543
|
+
defaultTargets: ALL_TOOL_TARGETS.filter((tool) => tool !== "augmentcode-legacy")
|
|
494
544
|
};
|
|
495
545
|
}
|
|
496
546
|
function resolveTargets(targets, config) {
|
|
@@ -537,174 +587,679 @@ async function addCommand(filename) {
|
|
|
537
587
|
}
|
|
538
588
|
}
|
|
539
589
|
|
|
540
|
-
// src/
|
|
541
|
-
var
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
)
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
)
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
)
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
590
|
+
// src/cli/commands/config.ts
|
|
591
|
+
var import_node_fs = require("fs");
|
|
592
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
593
|
+
|
|
594
|
+
// src/types/claudecode.ts
|
|
595
|
+
var import_mini2 = require("zod/mini");
|
|
596
|
+
var ClaudeSettingsSchema = import_mini2.z.looseObject({
|
|
597
|
+
permissions: import_mini2.z._default(
|
|
598
|
+
import_mini2.z.looseObject({
|
|
599
|
+
deny: import_mini2.z._default(import_mini2.z.array(import_mini2.z.string()), [])
|
|
600
|
+
}),
|
|
601
|
+
{ deny: [] }
|
|
602
|
+
)
|
|
603
|
+
});
|
|
604
|
+
|
|
605
|
+
// src/types/config.ts
|
|
606
|
+
var import_mini3 = require("zod/mini");
|
|
607
|
+
init_tool_targets();
|
|
608
|
+
var ConfigSchema = import_mini3.z.object({
|
|
609
|
+
aiRulesDir: import_mini3.z.string(),
|
|
610
|
+
outputPaths: import_mini3.z.record(ToolTargetSchema, import_mini3.z.string()),
|
|
611
|
+
watchEnabled: import_mini3.z.boolean(),
|
|
612
|
+
defaultTargets: ToolTargetsSchema
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
// src/types/config-options.ts
|
|
616
|
+
var import_mini4 = require("zod/mini");
|
|
617
|
+
init_tool_targets();
|
|
618
|
+
var OutputPathsSchema = import_mini4.z.object({
|
|
619
|
+
augmentcode: import_mini4.z.optional(import_mini4.z.string()),
|
|
620
|
+
"augmentcode-legacy": import_mini4.z.optional(import_mini4.z.string()),
|
|
621
|
+
copilot: import_mini4.z.optional(import_mini4.z.string()),
|
|
622
|
+
cursor: import_mini4.z.optional(import_mini4.z.string()),
|
|
623
|
+
cline: import_mini4.z.optional(import_mini4.z.string()),
|
|
624
|
+
claudecode: import_mini4.z.optional(import_mini4.z.string()),
|
|
625
|
+
roo: import_mini4.z.optional(import_mini4.z.string()),
|
|
626
|
+
geminicli: import_mini4.z.optional(import_mini4.z.string()),
|
|
627
|
+
kiro: import_mini4.z.optional(import_mini4.z.string()),
|
|
628
|
+
junie: import_mini4.z.optional(import_mini4.z.string())
|
|
629
|
+
});
|
|
630
|
+
var ConfigOptionsSchema = import_mini4.z.object({
|
|
631
|
+
aiRulesDir: import_mini4.z.optional(import_mini4.z.string()),
|
|
632
|
+
outputPaths: import_mini4.z.optional(OutputPathsSchema),
|
|
633
|
+
watchEnabled: import_mini4.z.optional(import_mini4.z.boolean()),
|
|
634
|
+
defaultTargets: import_mini4.z.optional(ToolTargetsSchema),
|
|
635
|
+
targets: import_mini4.z.optional(import_mini4.z.array(ToolTargetSchema)),
|
|
636
|
+
exclude: import_mini4.z.optional(import_mini4.z.array(ToolTargetSchema)),
|
|
637
|
+
verbose: import_mini4.z.optional(import_mini4.z.boolean()),
|
|
638
|
+
delete: import_mini4.z.optional(import_mini4.z.boolean()),
|
|
639
|
+
baseDir: import_mini4.z.optional(import_mini4.z.union([import_mini4.z.string(), import_mini4.z.array(import_mini4.z.string())])),
|
|
640
|
+
watch: import_mini4.z.optional(
|
|
641
|
+
import_mini4.z.object({
|
|
642
|
+
enabled: import_mini4.z.optional(import_mini4.z.boolean()),
|
|
643
|
+
interval: import_mini4.z.optional(import_mini4.z.number()),
|
|
644
|
+
ignore: import_mini4.z.optional(import_mini4.z.array(import_mini4.z.string()))
|
|
645
|
+
})
|
|
646
|
+
)
|
|
647
|
+
});
|
|
648
|
+
var MergedConfigSchema = import_mini4.z.object({
|
|
649
|
+
aiRulesDir: import_mini4.z.string(),
|
|
650
|
+
outputPaths: import_mini4.z.record(ToolTargetSchema, import_mini4.z.string()),
|
|
651
|
+
watchEnabled: import_mini4.z.boolean(),
|
|
652
|
+
defaultTargets: ToolTargetsSchema,
|
|
653
|
+
targets: import_mini4.z.optional(import_mini4.z.array(ToolTargetSchema)),
|
|
654
|
+
exclude: import_mini4.z.optional(import_mini4.z.array(ToolTargetSchema)),
|
|
655
|
+
verbose: import_mini4.z.optional(import_mini4.z.boolean()),
|
|
656
|
+
delete: import_mini4.z.optional(import_mini4.z.boolean()),
|
|
657
|
+
baseDir: import_mini4.z.optional(import_mini4.z.union([import_mini4.z.string(), import_mini4.z.array(import_mini4.z.string())])),
|
|
658
|
+
configPath: import_mini4.z.optional(import_mini4.z.string()),
|
|
659
|
+
watch: import_mini4.z.optional(
|
|
660
|
+
import_mini4.z.object({
|
|
661
|
+
enabled: import_mini4.z.optional(import_mini4.z.boolean()),
|
|
662
|
+
interval: import_mini4.z.optional(import_mini4.z.number()),
|
|
663
|
+
ignore: import_mini4.z.optional(import_mini4.z.array(import_mini4.z.string()))
|
|
664
|
+
})
|
|
665
|
+
)
|
|
666
|
+
});
|
|
667
|
+
|
|
668
|
+
// src/types/mcp.ts
|
|
669
|
+
var import_mini5 = require("zod/mini");
|
|
670
|
+
init_tool_targets();
|
|
671
|
+
var McpTransportTypeSchema = import_mini5.z.enum(["stdio", "sse", "http"]);
|
|
672
|
+
var McpServerBaseSchema = import_mini5.z.object({
|
|
673
|
+
command: import_mini5.z.optional(import_mini5.z.string()),
|
|
674
|
+
args: import_mini5.z.optional(import_mini5.z.array(import_mini5.z.string())),
|
|
675
|
+
url: import_mini5.z.optional(import_mini5.z.string()),
|
|
676
|
+
httpUrl: import_mini5.z.optional(import_mini5.z.string()),
|
|
677
|
+
env: import_mini5.z.optional(import_mini5.z.record(import_mini5.z.string(), import_mini5.z.string())),
|
|
678
|
+
disabled: import_mini5.z.optional(import_mini5.z.boolean()),
|
|
679
|
+
networkTimeout: import_mini5.z.optional(import_mini5.z.number()),
|
|
680
|
+
timeout: import_mini5.z.optional(import_mini5.z.number()),
|
|
681
|
+
trust: import_mini5.z.optional(import_mini5.z.boolean()),
|
|
682
|
+
cwd: import_mini5.z.optional(import_mini5.z.string()),
|
|
683
|
+
transport: import_mini5.z.optional(McpTransportTypeSchema),
|
|
684
|
+
type: import_mini5.z.optional(import_mini5.z.enum(["sse", "streamable-http"])),
|
|
685
|
+
alwaysAllow: import_mini5.z.optional(import_mini5.z.array(import_mini5.z.string())),
|
|
686
|
+
tools: import_mini5.z.optional(import_mini5.z.array(import_mini5.z.string())),
|
|
687
|
+
kiroAutoApprove: import_mini5.z.optional(import_mini5.z.array(import_mini5.z.string())),
|
|
688
|
+
kiroAutoBlock: import_mini5.z.optional(import_mini5.z.array(import_mini5.z.string()))
|
|
689
|
+
});
|
|
690
|
+
var RulesyncMcpServerSchema = import_mini5.z.extend(McpServerBaseSchema, {
|
|
691
|
+
targets: import_mini5.z.optional(RulesyncTargetsSchema)
|
|
692
|
+
});
|
|
693
|
+
var McpConfigSchema = import_mini5.z.object({
|
|
694
|
+
mcpServers: import_mini5.z.record(import_mini5.z.string(), McpServerBaseSchema)
|
|
695
|
+
});
|
|
696
|
+
var RulesyncMcpConfigSchema = import_mini5.z.object({
|
|
697
|
+
mcpServers: import_mini5.z.record(import_mini5.z.string(), RulesyncMcpServerSchema)
|
|
698
|
+
});
|
|
699
|
+
|
|
700
|
+
// src/types/rules.ts
|
|
701
|
+
var import_mini6 = require("zod/mini");
|
|
702
|
+
init_tool_targets();
|
|
703
|
+
var RuleFrontmatterSchema = import_mini6.z.object({
|
|
704
|
+
root: import_mini6.z.boolean(),
|
|
705
|
+
targets: RulesyncTargetsSchema,
|
|
706
|
+
description: import_mini6.z.string(),
|
|
707
|
+
globs: import_mini6.z.array(import_mini6.z.string()),
|
|
708
|
+
cursorRuleType: import_mini6.z.optional(import_mini6.z.enum(["always", "manual", "specificFiles", "intelligently"])),
|
|
709
|
+
tags: import_mini6.z.optional(import_mini6.z.array(import_mini6.z.string()))
|
|
710
|
+
});
|
|
711
|
+
var ParsedRuleSchema = import_mini6.z.object({
|
|
712
|
+
frontmatter: RuleFrontmatterSchema,
|
|
713
|
+
content: import_mini6.z.string(),
|
|
714
|
+
filename: import_mini6.z.string(),
|
|
715
|
+
filepath: import_mini6.z.string()
|
|
716
|
+
});
|
|
717
|
+
var GeneratedOutputSchema = import_mini6.z.object({
|
|
718
|
+
tool: ToolTargetSchema,
|
|
719
|
+
filepath: import_mini6.z.string(),
|
|
720
|
+
content: import_mini6.z.string()
|
|
721
|
+
});
|
|
722
|
+
var GenerateOptionsSchema = import_mini6.z.object({
|
|
723
|
+
targetTools: import_mini6.z.optional(ToolTargetsSchema),
|
|
724
|
+
outputDir: import_mini6.z.optional(import_mini6.z.string()),
|
|
725
|
+
watch: import_mini6.z.optional(import_mini6.z.boolean())
|
|
726
|
+
});
|
|
727
|
+
|
|
728
|
+
// src/types/index.ts
|
|
729
|
+
init_tool_targets();
|
|
730
|
+
|
|
731
|
+
// src/utils/config-loader.ts
|
|
732
|
+
var import_c12 = require("c12");
|
|
733
|
+
var import_core = require("zod/v4/core");
|
|
734
|
+
var MODULE_NAME = "rulesync";
|
|
735
|
+
async function loadConfig(options = {}) {
|
|
736
|
+
const defaultConfig = getDefaultConfig();
|
|
737
|
+
if (options.noConfig) {
|
|
738
|
+
return {
|
|
739
|
+
config: defaultConfig,
|
|
740
|
+
isEmpty: true
|
|
741
|
+
};
|
|
653
742
|
}
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
patterns.push(glob);
|
|
682
|
-
}
|
|
743
|
+
try {
|
|
744
|
+
const loadOptions = {
|
|
745
|
+
name: MODULE_NAME,
|
|
746
|
+
cwd: options.cwd || process.cwd(),
|
|
747
|
+
rcFile: false,
|
|
748
|
+
// Disable rc file lookup
|
|
749
|
+
configFile: "rulesync",
|
|
750
|
+
// Will look for rulesync.jsonc, rulesync.ts, etc.
|
|
751
|
+
defaults: defaultConfig
|
|
752
|
+
};
|
|
753
|
+
if (options.configPath) {
|
|
754
|
+
loadOptions.configFile = options.configPath;
|
|
755
|
+
}
|
|
756
|
+
const { config, configFile } = await (0, import_c12.loadConfig)(loadOptions);
|
|
757
|
+
if (!config || Object.keys(config).length === 0) {
|
|
758
|
+
return {
|
|
759
|
+
config: defaultConfig,
|
|
760
|
+
isEmpty: true
|
|
761
|
+
};
|
|
762
|
+
}
|
|
763
|
+
try {
|
|
764
|
+
ConfigOptionsSchema.parse(config);
|
|
765
|
+
} catch (error) {
|
|
766
|
+
if (error instanceof import_core.$ZodError) {
|
|
767
|
+
const issues = error.issues.map((issue) => ` - ${issue.path.join(".")}: ${issue.message}`).join("\n");
|
|
768
|
+
throw new Error(`Invalid configuration in ${configFile}:
|
|
769
|
+
${issues}`);
|
|
683
770
|
}
|
|
771
|
+
throw error;
|
|
684
772
|
}
|
|
685
|
-
const
|
|
686
|
-
|
|
773
|
+
const processedConfig = postProcessConfig(config);
|
|
774
|
+
const result = {
|
|
775
|
+
config: processedConfig,
|
|
776
|
+
isEmpty: false
|
|
777
|
+
};
|
|
778
|
+
if (configFile) {
|
|
779
|
+
result.filepath = configFile;
|
|
780
|
+
}
|
|
781
|
+
return result;
|
|
782
|
+
} catch (error) {
|
|
783
|
+
throw new Error(
|
|
784
|
+
`Failed to load configuration: ${error instanceof Error ? error.message : String(error)}`
|
|
785
|
+
);
|
|
687
786
|
}
|
|
688
|
-
return patterns;
|
|
689
787
|
}
|
|
690
|
-
function
|
|
691
|
-
const
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
788
|
+
function postProcessConfig(config) {
|
|
789
|
+
const processed = { ...config };
|
|
790
|
+
if (processed.baseDir && !Array.isArray(processed.baseDir)) {
|
|
791
|
+
processed.baseDir = [processed.baseDir];
|
|
792
|
+
}
|
|
793
|
+
if (config.targets || config.exclude) {
|
|
794
|
+
const baseTargets = config.targets || processed.defaultTargets;
|
|
795
|
+
if (config.exclude && config.exclude.length > 0) {
|
|
796
|
+
processed.defaultTargets = baseTargets.filter(
|
|
797
|
+
(target) => config.exclude && !config.exclude.includes(target)
|
|
798
|
+
);
|
|
799
|
+
} else {
|
|
800
|
+
processed.defaultTargets = baseTargets;
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
return processed;
|
|
804
|
+
}
|
|
805
|
+
function generateMinimalConfig(options) {
|
|
806
|
+
if (!options || Object.keys(options).length === 0) {
|
|
807
|
+
return generateSampleConfig();
|
|
808
|
+
}
|
|
809
|
+
const lines = ["{"];
|
|
810
|
+
if (options.targets || options.exclude) {
|
|
811
|
+
lines.push(` // Available tools: ${ALL_TOOL_TARGETS.join(", ")}`);
|
|
812
|
+
}
|
|
813
|
+
if (options.targets) {
|
|
814
|
+
lines.push(` "targets": ${JSON.stringify(options.targets)}`);
|
|
815
|
+
}
|
|
816
|
+
if (options.exclude) {
|
|
817
|
+
const comma = lines.length > 1 ? "," : "";
|
|
818
|
+
if (comma) lines[lines.length - 1] += comma;
|
|
819
|
+
lines.push(` "exclude": ${JSON.stringify(options.exclude)}`);
|
|
820
|
+
}
|
|
821
|
+
if (options.aiRulesDir) {
|
|
822
|
+
const comma = lines.length > 1 ? "," : "";
|
|
823
|
+
if (comma) lines[lines.length - 1] += comma;
|
|
824
|
+
lines.push(` "aiRulesDir": "${options.aiRulesDir}"`);
|
|
825
|
+
}
|
|
826
|
+
if (options.outputPaths) {
|
|
827
|
+
const comma = lines.length > 1 ? "," : "";
|
|
828
|
+
if (comma) lines[lines.length - 1] += comma;
|
|
829
|
+
lines.push(
|
|
830
|
+
` "outputPaths": ${JSON.stringify(options.outputPaths, null, 4).split("\n").map((line, i) => i === 0 ? line : ` ${line}`).join("\n")}`
|
|
831
|
+
);
|
|
832
|
+
}
|
|
833
|
+
if (options.baseDir) {
|
|
834
|
+
const comma = lines.length > 1 ? "," : "";
|
|
835
|
+
if (comma) lines[lines.length - 1] += comma;
|
|
836
|
+
lines.push(` "baseDir": ${JSON.stringify(options.baseDir)}`);
|
|
837
|
+
}
|
|
838
|
+
if (options.delete !== void 0) {
|
|
839
|
+
const comma = lines.length > 1 ? "," : "";
|
|
840
|
+
if (comma) lines[lines.length - 1] += comma;
|
|
841
|
+
lines.push(` "delete": ${options.delete}`);
|
|
842
|
+
}
|
|
843
|
+
if (options.verbose !== void 0) {
|
|
844
|
+
const comma = lines.length > 1 ? "," : "";
|
|
845
|
+
if (comma) lines[lines.length - 1] += comma;
|
|
846
|
+
lines.push(` "verbose": ${options.verbose}`);
|
|
847
|
+
}
|
|
848
|
+
if (options.watch) {
|
|
849
|
+
const comma = lines.length > 1 ? "," : "";
|
|
850
|
+
if (comma) lines[lines.length - 1] += comma;
|
|
851
|
+
lines.push(
|
|
852
|
+
` "watch": ${JSON.stringify(options.watch, null, 4).split("\n").map((line, i) => i === 0 ? line : ` ${line}`).join("\n")}`
|
|
853
|
+
);
|
|
854
|
+
}
|
|
855
|
+
lines.push("}");
|
|
856
|
+
return lines.join("\n");
|
|
857
|
+
}
|
|
858
|
+
function generateSampleConfig(options) {
|
|
859
|
+
const targets = options?.targets || ALL_TOOL_TARGETS;
|
|
860
|
+
const excludeValue = options?.exclude ? JSON.stringify(options.exclude) : null;
|
|
861
|
+
const aiRulesDir = options?.aiRulesDir || null;
|
|
862
|
+
const baseDir = options?.baseDir || null;
|
|
863
|
+
const deleteFlag = options?.delete || false;
|
|
864
|
+
const verbose = options?.verbose !== void 0 ? options.verbose : true;
|
|
865
|
+
return `{
|
|
866
|
+
// List of tools to generate configurations for
|
|
867
|
+
// Available: ${ALL_TOOL_TARGETS.join(", ")}
|
|
868
|
+
"targets": ${JSON.stringify(targets)},
|
|
869
|
+
|
|
870
|
+
// Tools to exclude from generation (overrides targets)
|
|
871
|
+
${excludeValue ? `"exclude": ${excludeValue},` : '// "exclude": ["roo"],'}
|
|
872
|
+
${aiRulesDir ? `
|
|
873
|
+
// Directory containing AI rule files
|
|
874
|
+
"aiRulesDir": "${aiRulesDir}",` : ""}
|
|
875
|
+
|
|
876
|
+
// Custom output paths for specific tools
|
|
877
|
+
"outputPaths": {
|
|
878
|
+
"copilot": ".github/copilot-instructions.md"
|
|
879
|
+
},
|
|
880
|
+
${baseDir ? `
|
|
881
|
+
// Base directory for generation
|
|
882
|
+
"baseDir": "${baseDir}",` : `
|
|
883
|
+
// Base directory or directories for generation
|
|
884
|
+
// "baseDir": "./packages",
|
|
885
|
+
// "baseDir": ["./packages/frontend", "./packages/backend"],`}
|
|
886
|
+
|
|
887
|
+
// Delete existing files before generating
|
|
888
|
+
"delete": ${deleteFlag},
|
|
889
|
+
|
|
890
|
+
// Enable verbose output
|
|
891
|
+
"verbose": ${verbose},
|
|
892
|
+
|
|
893
|
+
// Watch configuration
|
|
894
|
+
"watch": {
|
|
895
|
+
"enabled": false,
|
|
896
|
+
"interval": 1000,
|
|
897
|
+
"ignore": ["node_modules/**", "dist/**"]
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
`;
|
|
901
|
+
}
|
|
902
|
+
function mergeWithCliOptions(config, cliOptions) {
|
|
903
|
+
const merged = { ...config };
|
|
904
|
+
if (cliOptions.verbose !== void 0) {
|
|
905
|
+
merged.verbose = cliOptions.verbose;
|
|
906
|
+
}
|
|
907
|
+
if (cliOptions.delete !== void 0) {
|
|
908
|
+
merged.delete = cliOptions.delete;
|
|
909
|
+
}
|
|
910
|
+
if (cliOptions.baseDirs && cliOptions.baseDirs.length > 0) {
|
|
911
|
+
merged.baseDir = cliOptions.baseDirs;
|
|
912
|
+
}
|
|
913
|
+
if (cliOptions.tools && cliOptions.tools.length > 0) {
|
|
914
|
+
merged.defaultTargets = cliOptions.tools;
|
|
915
|
+
merged.exclude = void 0;
|
|
916
|
+
}
|
|
917
|
+
return merged;
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
// src/utils/file.ts
|
|
921
|
+
var import_promises2 = require("fs/promises");
|
|
922
|
+
var import_node_path = require("path");
|
|
923
|
+
async function ensureDir(dirPath) {
|
|
924
|
+
try {
|
|
925
|
+
await (0, import_promises2.stat)(dirPath);
|
|
926
|
+
} catch {
|
|
927
|
+
await (0, import_promises2.mkdir)(dirPath, { recursive: true });
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
async function readFileContent(filepath) {
|
|
931
|
+
return (0, import_promises2.readFile)(filepath, "utf-8");
|
|
932
|
+
}
|
|
933
|
+
async function writeFileContent(filepath, content) {
|
|
934
|
+
await ensureDir((0, import_node_path.dirname)(filepath));
|
|
935
|
+
await (0, import_promises2.writeFile)(filepath, content, "utf-8");
|
|
936
|
+
}
|
|
937
|
+
async function fileExists(filepath) {
|
|
938
|
+
try {
|
|
939
|
+
await (0, import_promises2.stat)(filepath);
|
|
940
|
+
return true;
|
|
941
|
+
} catch {
|
|
942
|
+
return false;
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
async function findFiles(dir, extension = ".md") {
|
|
946
|
+
try {
|
|
947
|
+
const files = await (0, import_promises2.readdir)(dir);
|
|
948
|
+
return files.filter((file) => file.endsWith(extension)).map((file) => (0, import_node_path.join)(dir, file));
|
|
949
|
+
} catch {
|
|
950
|
+
return [];
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
async function removeDirectory(dirPath) {
|
|
954
|
+
const dangerousPaths = [".", "/", "~", "src", "node_modules"];
|
|
955
|
+
if (dangerousPaths.includes(dirPath) || dirPath === "") {
|
|
956
|
+
console.warn(`Skipping deletion of dangerous path: ${dirPath}`);
|
|
957
|
+
return;
|
|
958
|
+
}
|
|
959
|
+
try {
|
|
960
|
+
if (await fileExists(dirPath)) {
|
|
961
|
+
await (0, import_promises2.rm)(dirPath, { recursive: true, force: true });
|
|
962
|
+
}
|
|
963
|
+
} catch (error) {
|
|
964
|
+
console.warn(`Failed to remove directory ${dirPath}:`, error);
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
async function removeFile(filepath) {
|
|
968
|
+
try {
|
|
969
|
+
if (await fileExists(filepath)) {
|
|
970
|
+
await (0, import_promises2.rm)(filepath);
|
|
971
|
+
}
|
|
972
|
+
} catch (error) {
|
|
973
|
+
console.warn(`Failed to remove file ${filepath}:`, error);
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
async function removeClaudeGeneratedFiles() {
|
|
977
|
+
const filesToRemove = ["CLAUDE.md", ".claude/memories"];
|
|
978
|
+
for (const fileOrDir of filesToRemove) {
|
|
979
|
+
if (fileOrDir.endsWith("/memories")) {
|
|
980
|
+
await removeDirectory(fileOrDir);
|
|
981
|
+
} else {
|
|
982
|
+
await removeFile(fileOrDir);
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
// src/utils/rules.ts
|
|
988
|
+
function isToolSpecificRule(rule, targetTool) {
|
|
989
|
+
const filename = rule.filename;
|
|
990
|
+
const toolPatterns = {
|
|
991
|
+
"augmentcode-legacy": /^specification-augmentcode-legacy-/i,
|
|
992
|
+
augmentcode: /^specification-augmentcode-/i,
|
|
993
|
+
copilot: /^specification-copilot-/i,
|
|
994
|
+
cursor: /^specification-cursor-/i,
|
|
995
|
+
cline: /^specification-cline-/i,
|
|
996
|
+
claudecode: /^specification-claudecode-/i,
|
|
997
|
+
roo: /^specification-roo-/i,
|
|
998
|
+
geminicli: /^specification-geminicli-/i,
|
|
999
|
+
kiro: /^specification-kiro-/i
|
|
1000
|
+
};
|
|
1001
|
+
for (const [tool, pattern] of Object.entries(toolPatterns)) {
|
|
1002
|
+
if (pattern.test(filename)) {
|
|
1003
|
+
return tool === targetTool;
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
return true;
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
// src/cli/commands/config.ts
|
|
1010
|
+
async function configCommand(options = {}) {
|
|
1011
|
+
if (options.init) {
|
|
1012
|
+
await initConfig(options);
|
|
1013
|
+
return;
|
|
1014
|
+
}
|
|
1015
|
+
await showConfig();
|
|
1016
|
+
}
|
|
1017
|
+
async function showConfig() {
|
|
1018
|
+
console.log("Loading configuration...\n");
|
|
1019
|
+
try {
|
|
1020
|
+
const result = await loadConfig();
|
|
1021
|
+
if (result.isEmpty) {
|
|
1022
|
+
console.log("No configuration file found. Using default configuration.\n");
|
|
1023
|
+
} else {
|
|
1024
|
+
console.log(`Configuration loaded from: ${result.filepath}
|
|
1025
|
+
`);
|
|
1026
|
+
}
|
|
1027
|
+
console.log("Current configuration:");
|
|
1028
|
+
console.log("=====================");
|
|
1029
|
+
const config = result.config;
|
|
1030
|
+
console.log(`
|
|
1031
|
+
AI Rules Directory: ${config.aiRulesDir}`);
|
|
1032
|
+
console.log(`
|
|
1033
|
+
Default Targets: ${config.defaultTargets.join(", ")}`);
|
|
1034
|
+
if (config.exclude && config.exclude.length > 0) {
|
|
1035
|
+
console.log(`Excluded Targets: ${config.exclude.join(", ")}`);
|
|
1036
|
+
}
|
|
1037
|
+
console.log("\nOutput Paths:");
|
|
1038
|
+
for (const [tool, outputPath] of Object.entries(config.outputPaths)) {
|
|
1039
|
+
console.log(` ${tool}: ${outputPath}`);
|
|
1040
|
+
}
|
|
1041
|
+
if (config.baseDir) {
|
|
1042
|
+
const dirs = Array.isArray(config.baseDir) ? config.baseDir : [config.baseDir];
|
|
1043
|
+
console.log(`
|
|
1044
|
+
Base Directories: ${dirs.join(", ")}`);
|
|
1045
|
+
}
|
|
1046
|
+
console.log(`
|
|
1047
|
+
Verbose: ${config.verbose || false}`);
|
|
1048
|
+
console.log(`Delete before generate: ${config.delete || false}`);
|
|
1049
|
+
if (config.watch) {
|
|
1050
|
+
console.log("\nWatch Configuration:");
|
|
1051
|
+
console.log(` Enabled: ${config.watch.enabled || false}`);
|
|
1052
|
+
if (config.watch.interval) {
|
|
1053
|
+
console.log(` Interval: ${config.watch.interval}ms`);
|
|
1054
|
+
}
|
|
1055
|
+
if (config.watch.ignore && config.watch.ignore.length > 0) {
|
|
1056
|
+
console.log(` Ignore patterns: ${config.watch.ignore.join(", ")}`);
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
console.log("\nTip: Use 'rulesync config init' to create a configuration file.");
|
|
1060
|
+
} catch (error) {
|
|
1061
|
+
console.error(
|
|
1062
|
+
"\u274C Failed to load configuration:",
|
|
1063
|
+
error instanceof Error ? error.message : String(error)
|
|
1064
|
+
);
|
|
1065
|
+
process.exit(1);
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
var FORMAT_CONFIG = {
|
|
1069
|
+
jsonc: {
|
|
1070
|
+
filename: "rulesync.jsonc",
|
|
1071
|
+
generator: generateJsoncConfig
|
|
1072
|
+
},
|
|
1073
|
+
ts: {
|
|
1074
|
+
filename: "rulesync.ts",
|
|
1075
|
+
generator: generateTsConfig
|
|
1076
|
+
}
|
|
1077
|
+
};
|
|
1078
|
+
async function initConfig(options) {
|
|
1079
|
+
const validFormats = Object.keys(FORMAT_CONFIG);
|
|
1080
|
+
const selectedFormat = options.format || "jsonc";
|
|
1081
|
+
if (!validFormats.includes(selectedFormat)) {
|
|
1082
|
+
console.error(
|
|
1083
|
+
`\u274C Invalid format: ${selectedFormat}. Valid formats are: ${validFormats.join(", ")}`
|
|
1084
|
+
);
|
|
1085
|
+
process.exit(1);
|
|
1086
|
+
}
|
|
1087
|
+
const formatConfig = FORMAT_CONFIG[selectedFormat];
|
|
1088
|
+
const filename = formatConfig.filename;
|
|
1089
|
+
const configOptions = {};
|
|
1090
|
+
if (options.targets) {
|
|
1091
|
+
const targets = options.targets.split(",").map((t) => t.trim());
|
|
1092
|
+
const validTargets = [];
|
|
1093
|
+
for (const target of targets) {
|
|
1094
|
+
const result = ToolTargetSchema.safeParse(target);
|
|
1095
|
+
if (result.success) {
|
|
1096
|
+
validTargets.push(result.data);
|
|
1097
|
+
} else {
|
|
1098
|
+
console.error(`\u274C Invalid target: ${target}`);
|
|
1099
|
+
process.exit(1);
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
configOptions.targets = validTargets;
|
|
1103
|
+
}
|
|
1104
|
+
if (options.exclude) {
|
|
1105
|
+
const excludes = options.exclude.split(",").map((t) => t.trim());
|
|
1106
|
+
const validExcludes = [];
|
|
1107
|
+
for (const exclude of excludes) {
|
|
1108
|
+
const result = ToolTargetSchema.safeParse(exclude);
|
|
1109
|
+
if (result.success) {
|
|
1110
|
+
validExcludes.push(result.data);
|
|
1111
|
+
} else {
|
|
1112
|
+
console.error(`\u274C Invalid exclude target: ${exclude}`);
|
|
1113
|
+
process.exit(1);
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
configOptions.exclude = validExcludes;
|
|
1117
|
+
}
|
|
1118
|
+
if (options.aiRulesDir) {
|
|
1119
|
+
configOptions.aiRulesDir = options.aiRulesDir;
|
|
1120
|
+
}
|
|
1121
|
+
if (options.baseDir) {
|
|
1122
|
+
configOptions.baseDir = options.baseDir;
|
|
1123
|
+
}
|
|
1124
|
+
if (options.verbose !== void 0) {
|
|
1125
|
+
configOptions.verbose = options.verbose;
|
|
1126
|
+
}
|
|
1127
|
+
if (options.delete !== void 0) {
|
|
1128
|
+
configOptions.delete = options.delete;
|
|
1129
|
+
}
|
|
1130
|
+
const content = formatConfig.generator(configOptions);
|
|
1131
|
+
const filepath = import_node_path2.default.join(process.cwd(), filename);
|
|
1132
|
+
try {
|
|
1133
|
+
const fs2 = await import("fs/promises");
|
|
1134
|
+
await fs2.access(filepath);
|
|
1135
|
+
console.error(`\u274C Configuration file already exists: ${filepath}`);
|
|
1136
|
+
console.log("Remove the existing file or choose a different format.");
|
|
1137
|
+
process.exit(1);
|
|
1138
|
+
} catch {
|
|
1139
|
+
}
|
|
1140
|
+
try {
|
|
1141
|
+
(0, import_node_fs.writeFileSync)(filepath, content, "utf-8");
|
|
1142
|
+
console.log(`\u2705 Created configuration file: ${filepath}`);
|
|
1143
|
+
console.log("\nYou can now customize the configuration to fit your needs.");
|
|
1144
|
+
console.log("Run 'rulesync generate' to use the new configuration.");
|
|
1145
|
+
} catch (error) {
|
|
1146
|
+
console.error(
|
|
1147
|
+
`\u274C Failed to create configuration file: ${error instanceof Error ? error.message : String(error)}`
|
|
1148
|
+
);
|
|
1149
|
+
process.exit(1);
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
function generateJsoncConfig(options) {
|
|
1153
|
+
if (options && Object.keys(options).length > 0) {
|
|
1154
|
+
return generateMinimalConfig(options);
|
|
1155
|
+
}
|
|
1156
|
+
return generateSampleConfig(options);
|
|
1157
|
+
}
|
|
1158
|
+
function generateTsConfig(options) {
|
|
1159
|
+
if (!options || Object.keys(options).length === 0) {
|
|
1160
|
+
return `import type { ConfigOptions } from "rulesync";
|
|
1161
|
+
|
|
1162
|
+
const config: ConfigOptions = {
|
|
1163
|
+
// List of tools to generate configurations for
|
|
1164
|
+
// Available: ${ALL_TOOL_TARGETS.join(", ")}
|
|
1165
|
+
targets: ${JSON.stringify(ALL_TOOL_TARGETS)},
|
|
1166
|
+
|
|
1167
|
+
// Custom output paths for specific tools
|
|
1168
|
+
// outputPaths: {
|
|
1169
|
+
// copilot: ".github/copilot-instructions.md",
|
|
1170
|
+
// },
|
|
1171
|
+
|
|
1172
|
+
// Delete existing files before generating
|
|
1173
|
+
// delete: false,
|
|
1174
|
+
|
|
1175
|
+
// Enable verbose output
|
|
1176
|
+
verbose: true,
|
|
1177
|
+
};
|
|
1178
|
+
|
|
1179
|
+
export default config;`;
|
|
1180
|
+
}
|
|
1181
|
+
const configLines = [];
|
|
1182
|
+
if (options.targets) {
|
|
1183
|
+
configLines.push(` targets: ${JSON.stringify(options.targets)}`);
|
|
1184
|
+
}
|
|
1185
|
+
if (options.exclude) {
|
|
1186
|
+
configLines.push(` exclude: ${JSON.stringify(options.exclude)}`);
|
|
1187
|
+
}
|
|
1188
|
+
if (options.aiRulesDir) {
|
|
1189
|
+
configLines.push(` aiRulesDir: "${options.aiRulesDir}"`);
|
|
1190
|
+
}
|
|
1191
|
+
if (options.outputPaths) {
|
|
1192
|
+
const pathsStr = JSON.stringify(options.outputPaths, null, 4).split("\n").map((line, i) => i === 0 ? line : ` ${line}`).join("\n");
|
|
1193
|
+
configLines.push(` outputPaths: ${pathsStr}`);
|
|
1194
|
+
}
|
|
1195
|
+
if (options.baseDir) {
|
|
1196
|
+
configLines.push(` baseDir: ${JSON.stringify(options.baseDir)}`);
|
|
1197
|
+
}
|
|
1198
|
+
if (options.delete !== void 0) {
|
|
1199
|
+
configLines.push(` delete: ${options.delete}`);
|
|
1200
|
+
}
|
|
1201
|
+
if (options.verbose !== void 0) {
|
|
1202
|
+
configLines.push(` verbose: ${options.verbose}`);
|
|
1203
|
+
}
|
|
1204
|
+
if (options.watch) {
|
|
1205
|
+
const watchStr = JSON.stringify(options.watch, null, 4).split("\n").map((line, i) => i === 0 ? line : ` ${line}`).join("\n");
|
|
1206
|
+
configLines.push(` watch: ${watchStr}`);
|
|
1207
|
+
}
|
|
1208
|
+
const configContent = `import type { ConfigOptions } from "rulesync";
|
|
1209
|
+
|
|
1210
|
+
const config: ConfigOptions = {
|
|
1211
|
+
${configLines.join(",\n")},
|
|
1212
|
+
};
|
|
1213
|
+
|
|
1214
|
+
export default config;
|
|
1215
|
+
`;
|
|
1216
|
+
return configContent;
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
// src/cli/commands/generate.ts
|
|
1220
|
+
var import_node_path14 = require("path");
|
|
1221
|
+
|
|
1222
|
+
// src/generators/ignore/augmentcode.ts
|
|
1223
|
+
var import_node_path3 = require("path");
|
|
1224
|
+
|
|
1225
|
+
// src/generators/ignore/shared-helpers.ts
|
|
1226
|
+
function extractIgnorePatternsFromRules(rules) {
|
|
1227
|
+
const patterns = [];
|
|
1228
|
+
for (const rule of rules) {
|
|
1229
|
+
if (rule.frontmatter.globs && rule.frontmatter.globs.length > 0) {
|
|
1230
|
+
for (const glob of rule.frontmatter.globs) {
|
|
1231
|
+
if (shouldExcludeFromAI(glob)) {
|
|
1232
|
+
patterns.push(`# Exclude: ${rule.frontmatter.description}`);
|
|
1233
|
+
patterns.push(glob);
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
const contentPatterns = extractIgnorePatternsFromContent(rule.content);
|
|
1238
|
+
patterns.push(...contentPatterns);
|
|
1239
|
+
}
|
|
1240
|
+
return patterns;
|
|
1241
|
+
}
|
|
1242
|
+
function shouldExcludeFromAI(glob) {
|
|
1243
|
+
const excludePatterns = [
|
|
1244
|
+
// Large generated files that slow indexing
|
|
1245
|
+
"**/assets/generated/**",
|
|
1246
|
+
"**/public/build/**",
|
|
1247
|
+
// Test fixtures with potentially sensitive data
|
|
1248
|
+
"**/tests/fixtures/**",
|
|
1249
|
+
"**/test/fixtures/**",
|
|
1250
|
+
"**/*.fixture.*",
|
|
1251
|
+
// Build outputs that provide little value for AI context
|
|
700
1252
|
"**/dist/**",
|
|
701
1253
|
"**/build/**",
|
|
702
1254
|
"**/coverage/**",
|
|
703
1255
|
// Configuration that might contain sensitive data
|
|
704
1256
|
"**/config/production/**",
|
|
705
1257
|
"**/config/secrets/**",
|
|
1258
|
+
"**/config/prod/**",
|
|
706
1259
|
"**/deploy/prod/**",
|
|
707
|
-
|
|
1260
|
+
"**/*.prod.*",
|
|
1261
|
+
// Internal documentation that might be sensitive
|
|
1262
|
+
"**/internal/**",
|
|
708
1263
|
"**/internal-docs/**",
|
|
709
1264
|
"**/proprietary/**",
|
|
710
1265
|
"**/personal-notes/**",
|
|
@@ -716,11 +1271,17 @@ function shouldExcludeFromAugmentCode(glob) {
|
|
|
716
1271
|
return regex.test(glob);
|
|
717
1272
|
});
|
|
718
1273
|
}
|
|
719
|
-
function
|
|
1274
|
+
function extractIgnorePatternsFromContent(content) {
|
|
720
1275
|
const patterns = [];
|
|
721
1276
|
const lines = content.split("\n");
|
|
722
1277
|
for (const line of lines) {
|
|
723
1278
|
const trimmed = line.trim();
|
|
1279
|
+
if (trimmed.startsWith("# IGNORE:") || trimmed.startsWith("# aiignore:")) {
|
|
1280
|
+
const pattern = trimmed.replace(/^# (IGNORE|aiignore):\s*/, "").trim();
|
|
1281
|
+
if (pattern) {
|
|
1282
|
+
patterns.push(pattern);
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
724
1285
|
if (trimmed.startsWith("# AUGMENT_IGNORE:") || trimmed.startsWith("# augmentignore:")) {
|
|
725
1286
|
const pattern = trimmed.replace(/^# (AUGMENT_IGNORE|augmentignore):\s*/, "").trim();
|
|
726
1287
|
if (pattern) {
|
|
@@ -733,8 +1294,8 @@ function extractAugmentCodeIgnorePatternsFromContent(content) {
|
|
|
733
1294
|
patterns.push(`!${pattern}`);
|
|
734
1295
|
}
|
|
735
1296
|
}
|
|
736
|
-
if (trimmed.includes("
|
|
737
|
-
const matches = trimmed.match(/['"`]([^'"`]+\.(
|
|
1297
|
+
if (trimmed.includes("exclude") || trimmed.includes("ignore")) {
|
|
1298
|
+
const matches = trimmed.match(/['"`]([^'"`]+\.(log|tmp|cache|temp))['"`]/g);
|
|
738
1299
|
if (matches) {
|
|
739
1300
|
patterns.push(...matches.map((m) => m.replace(/['"`]/g, "")));
|
|
740
1301
|
}
|
|
@@ -742,14 +1303,330 @@ function extractAugmentCodeIgnorePatternsFromContent(content) {
|
|
|
742
1303
|
}
|
|
743
1304
|
return patterns;
|
|
744
1305
|
}
|
|
1306
|
+
function extractAugmentCodeIgnorePatternsFromContent(content) {
|
|
1307
|
+
const patterns = [];
|
|
1308
|
+
const lines = content.split("\n");
|
|
1309
|
+
for (const line of lines) {
|
|
1310
|
+
const trimmed = line.trim();
|
|
1311
|
+
if (trimmed.startsWith("# AUGMENT_IGNORE:") || trimmed.startsWith("# augmentignore:")) {
|
|
1312
|
+
const pattern = trimmed.replace(/^# (AUGMENT_IGNORE|augmentignore):\s*/, "").trim();
|
|
1313
|
+
if (pattern) {
|
|
1314
|
+
patterns.push(pattern);
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
if (trimmed.startsWith("# AUGMENT_INCLUDE:") || trimmed.startsWith("# augmentinclude:")) {
|
|
1318
|
+
const pattern = trimmed.replace(/^# (AUGMENT_INCLUDE|augmentinclude):\s*/, "").trim();
|
|
1319
|
+
if (pattern) {
|
|
1320
|
+
patterns.push(`!${pattern}`);
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
if (trimmed.includes("large file") || trimmed.includes("binary") || trimmed.includes("media")) {
|
|
1324
|
+
const regex = /['"`]([^'"`]+\.(mp4|avi|zip|tar\.gz|rar|pdf|doc|xlsx))['"`]/g;
|
|
1325
|
+
let match;
|
|
1326
|
+
while ((match = regex.exec(trimmed)) !== null) {
|
|
1327
|
+
if (match[1]) {
|
|
1328
|
+
patterns.push(match[1]);
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
return patterns;
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
// src/generators/ignore/augmentcode.ts
|
|
1337
|
+
async function generateAugmentCodeIgnoreFiles(rules, config, baseDir) {
|
|
1338
|
+
const outputs = [];
|
|
1339
|
+
const augmentignoreContent = generateAugmentignoreContent(rules);
|
|
1340
|
+
const outputPath = baseDir || process.cwd();
|
|
1341
|
+
const filepath = (0, import_node_path3.join)(outputPath, ".augmentignore");
|
|
1342
|
+
outputs.push({
|
|
1343
|
+
tool: "augmentcode",
|
|
1344
|
+
filepath,
|
|
1345
|
+
content: augmentignoreContent
|
|
1346
|
+
});
|
|
1347
|
+
return outputs;
|
|
1348
|
+
}
|
|
1349
|
+
function generateAugmentignoreContent(rules) {
|
|
1350
|
+
const lines = [
|
|
1351
|
+
"# Generated by rulesync - AugmentCode ignore patterns",
|
|
1352
|
+
"# AugmentCode uses a two-tier approach: .gitignore first, then .augmentignore",
|
|
1353
|
+
"# This file provides Augment-specific exclusions and re-inclusions",
|
|
1354
|
+
""
|
|
1355
|
+
];
|
|
1356
|
+
lines.push(
|
|
1357
|
+
"# Security and Secrets (critical exclusions)",
|
|
1358
|
+
"# Environment files",
|
|
1359
|
+
".env*",
|
|
1360
|
+
"",
|
|
1361
|
+
"# Private keys and certificates",
|
|
1362
|
+
"*.pem",
|
|
1363
|
+
"*.key",
|
|
1364
|
+
"*.p12",
|
|
1365
|
+
"*.crt",
|
|
1366
|
+
"*.der",
|
|
1367
|
+
"",
|
|
1368
|
+
"# SSH keys",
|
|
1369
|
+
"id_rsa*",
|
|
1370
|
+
"id_dsa*",
|
|
1371
|
+
"",
|
|
1372
|
+
"# AWS credentials",
|
|
1373
|
+
".aws/",
|
|
1374
|
+
"aws-exports.js",
|
|
1375
|
+
"",
|
|
1376
|
+
"# API keys and tokens",
|
|
1377
|
+
"**/apikeys/",
|
|
1378
|
+
"**/*_token*",
|
|
1379
|
+
"**/*_secret*",
|
|
1380
|
+
""
|
|
1381
|
+
);
|
|
1382
|
+
lines.push(
|
|
1383
|
+
"# Build Artifacts and Dependencies",
|
|
1384
|
+
"# Build outputs",
|
|
1385
|
+
"dist/",
|
|
1386
|
+
"build/",
|
|
1387
|
+
"out/",
|
|
1388
|
+
"target/",
|
|
1389
|
+
"",
|
|
1390
|
+
"# Dependencies",
|
|
1391
|
+
"node_modules/",
|
|
1392
|
+
"venv/",
|
|
1393
|
+
"*.egg-info/",
|
|
1394
|
+
"",
|
|
1395
|
+
"# Logs",
|
|
1396
|
+
"*.log",
|
|
1397
|
+
"logs/",
|
|
1398
|
+
"",
|
|
1399
|
+
"# Temporary files",
|
|
1400
|
+
"*.tmp",
|
|
1401
|
+
"*.swp",
|
|
1402
|
+
"*.swo",
|
|
1403
|
+
"*~",
|
|
1404
|
+
""
|
|
1405
|
+
);
|
|
1406
|
+
lines.push(
|
|
1407
|
+
"# Large Files and Media",
|
|
1408
|
+
"# Binary files",
|
|
1409
|
+
"*.jar",
|
|
1410
|
+
"*.png",
|
|
1411
|
+
"*.jpg",
|
|
1412
|
+
"*.jpeg",
|
|
1413
|
+
"*.gif",
|
|
1414
|
+
"*.mp4",
|
|
1415
|
+
"*.avi",
|
|
1416
|
+
"*.zip",
|
|
1417
|
+
"*.tar.gz",
|
|
1418
|
+
"*.rar",
|
|
1419
|
+
"",
|
|
1420
|
+
"# Database files",
|
|
1421
|
+
"*.sqlite",
|
|
1422
|
+
"*.db",
|
|
1423
|
+
"*.mdb",
|
|
1424
|
+
"",
|
|
1425
|
+
"# Data files",
|
|
1426
|
+
"*.csv",
|
|
1427
|
+
"*.tsv",
|
|
1428
|
+
"*.xlsx",
|
|
1429
|
+
""
|
|
1430
|
+
);
|
|
1431
|
+
lines.push(
|
|
1432
|
+
"# Performance Optimization",
|
|
1433
|
+
"# Exclude files that are too large for effective AI processing",
|
|
1434
|
+
"**/*.{mp4,avi,mov,mkv}",
|
|
1435
|
+
"**/*.{zip,tar,gz,rar}",
|
|
1436
|
+
"**/*.{pdf,doc,docx}",
|
|
1437
|
+
"**/logs/**/*.log",
|
|
1438
|
+
"",
|
|
1439
|
+
"# But include small configuration files",
|
|
1440
|
+
"!**/config.{json,yaml,yml}",
|
|
1441
|
+
""
|
|
1442
|
+
);
|
|
1443
|
+
const rulePatterns = extractIgnorePatternsFromRules(rules);
|
|
1444
|
+
const augmentPatterns = [];
|
|
1445
|
+
for (const rule of rules) {
|
|
1446
|
+
augmentPatterns.push(...extractAugmentCodeIgnorePatternsFromContent(rule.content));
|
|
1447
|
+
}
|
|
1448
|
+
const allPatterns = [...rulePatterns, ...augmentPatterns];
|
|
1449
|
+
if (allPatterns.length > 0) {
|
|
1450
|
+
lines.push("# Project-specific patterns from rulesync rules");
|
|
1451
|
+
lines.push(...allPatterns);
|
|
1452
|
+
lines.push("");
|
|
1453
|
+
}
|
|
1454
|
+
lines.push(
|
|
1455
|
+
"# Team Collaboration",
|
|
1456
|
+
"# Exclude personal IDE settings",
|
|
1457
|
+
".vscode/settings.json",
|
|
1458
|
+
".idea/workspace.xml",
|
|
1459
|
+
"",
|
|
1460
|
+
"# But include shared team settings",
|
|
1461
|
+
"!.vscode/extensions.json",
|
|
1462
|
+
"!.idea/codeStyles/",
|
|
1463
|
+
"",
|
|
1464
|
+
"# Exclude test fixtures with sensitive data",
|
|
1465
|
+
"tests/fixtures/real-data/**",
|
|
1466
|
+
"",
|
|
1467
|
+
"# Re-include important documentation",
|
|
1468
|
+
"!vendor/*/README.md",
|
|
1469
|
+
"!third-party/*/LICENSE",
|
|
1470
|
+
""
|
|
1471
|
+
);
|
|
1472
|
+
return lines.join("\n");
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
// src/generators/ignore/junie.ts
|
|
1476
|
+
var import_node_path4 = require("path");
|
|
1477
|
+
async function generateJunieIgnoreFiles(rules, config, baseDir) {
|
|
1478
|
+
const outputs = [];
|
|
1479
|
+
const aiignoreContent = generateAiignoreContent(rules);
|
|
1480
|
+
const outputPath = baseDir || process.cwd();
|
|
1481
|
+
const filepath = (0, import_node_path4.join)(outputPath, ".aiignore");
|
|
1482
|
+
outputs.push({
|
|
1483
|
+
tool: "junie",
|
|
1484
|
+
filepath,
|
|
1485
|
+
content: aiignoreContent
|
|
1486
|
+
});
|
|
1487
|
+
return outputs;
|
|
1488
|
+
}
|
|
1489
|
+
function generateAiignoreContent(rules) {
|
|
1490
|
+
const lines = [
|
|
1491
|
+
"# Generated by rulesync - JetBrains Junie AI ignore file",
|
|
1492
|
+
"# This file controls which files the AI can access automatically",
|
|
1493
|
+
"# AI must ask before reading or editing matched files/directories",
|
|
1494
|
+
"",
|
|
1495
|
+
"# \u2500\u2500\u2500\u2500\u2500 Source Control Metadata \u2500\u2500\u2500\u2500\u2500",
|
|
1496
|
+
".git/",
|
|
1497
|
+
".svn/",
|
|
1498
|
+
".hg/",
|
|
1499
|
+
".idea/",
|
|
1500
|
+
"*.iml",
|
|
1501
|
+
".vscode/settings.json",
|
|
1502
|
+
"",
|
|
1503
|
+
"# \u2500\u2500\u2500\u2500\u2500 Build Artifacts \u2500\u2500\u2500\u2500\u2500",
|
|
1504
|
+
"/out/",
|
|
1505
|
+
"/dist/",
|
|
1506
|
+
"/target/",
|
|
1507
|
+
"/build/",
|
|
1508
|
+
"*.class",
|
|
1509
|
+
"*.jar",
|
|
1510
|
+
"*.war",
|
|
1511
|
+
"",
|
|
1512
|
+
"# \u2500\u2500\u2500\u2500\u2500 Secrets & Credentials \u2500\u2500\u2500\u2500\u2500",
|
|
1513
|
+
"# Environment files",
|
|
1514
|
+
".env",
|
|
1515
|
+
".env.*",
|
|
1516
|
+
"!.env.example",
|
|
1517
|
+
"",
|
|
1518
|
+
"# Key material",
|
|
1519
|
+
"*.pem",
|
|
1520
|
+
"*.key",
|
|
1521
|
+
"*.crt",
|
|
1522
|
+
"*.p12",
|
|
1523
|
+
"*.pfx",
|
|
1524
|
+
"*.der",
|
|
1525
|
+
"id_rsa*",
|
|
1526
|
+
"id_dsa*",
|
|
1527
|
+
"*.ppk",
|
|
1528
|
+
"",
|
|
1529
|
+
"# Cloud and service configs",
|
|
1530
|
+
"aws-credentials.json",
|
|
1531
|
+
"gcp-service-account*.json",
|
|
1532
|
+
"azure-credentials.json",
|
|
1533
|
+
"secrets/**",
|
|
1534
|
+
"config/secrets/",
|
|
1535
|
+
"**/secrets/",
|
|
1536
|
+
"",
|
|
1537
|
+
"# Database credentials",
|
|
1538
|
+
"database.yml",
|
|
1539
|
+
"**/database/config.*",
|
|
1540
|
+
"",
|
|
1541
|
+
"# API keys and tokens",
|
|
1542
|
+
"**/apikeys/",
|
|
1543
|
+
"**/*_token*",
|
|
1544
|
+
"**/*_secret*",
|
|
1545
|
+
"**/*api_key*",
|
|
1546
|
+
"",
|
|
1547
|
+
"# \u2500\u2500\u2500\u2500\u2500 Infrastructure & Deployment \u2500\u2500\u2500\u2500\u2500",
|
|
1548
|
+
"# Terraform state",
|
|
1549
|
+
"*.tfstate",
|
|
1550
|
+
"*.tfstate.*",
|
|
1551
|
+
".terraform/",
|
|
1552
|
+
"",
|
|
1553
|
+
"# Kubernetes secrets",
|
|
1554
|
+
"**/k8s/**/secret*.yaml",
|
|
1555
|
+
"**/kubernetes/**/secret*.yaml",
|
|
1556
|
+
"",
|
|
1557
|
+
"# Docker secrets",
|
|
1558
|
+
"docker-compose.override.yml",
|
|
1559
|
+
"**/docker/secrets/",
|
|
1560
|
+
"",
|
|
1561
|
+
"# \u2500\u2500\u2500\u2500\u2500 Logs & Runtime Data \u2500\u2500\u2500\u2500\u2500",
|
|
1562
|
+
"*.log",
|
|
1563
|
+
"*.tmp",
|
|
1564
|
+
"*.cache",
|
|
1565
|
+
"logs/",
|
|
1566
|
+
"/var/log/",
|
|
1567
|
+
"coverage/",
|
|
1568
|
+
".nyc_output/",
|
|
1569
|
+
"",
|
|
1570
|
+
"# \u2500\u2500\u2500\u2500\u2500 Large Data Files \u2500\u2500\u2500\u2500\u2500",
|
|
1571
|
+
"*.csv",
|
|
1572
|
+
"*.xlsx",
|
|
1573
|
+
"*.sqlite",
|
|
1574
|
+
"*.db",
|
|
1575
|
+
"*.dump",
|
|
1576
|
+
"data/",
|
|
1577
|
+
"datasets/",
|
|
1578
|
+
"",
|
|
1579
|
+
"# \u2500\u2500\u2500\u2500\u2500 Node.js Specific \u2500\u2500\u2500\u2500\u2500",
|
|
1580
|
+
"node_modules/",
|
|
1581
|
+
".pnpm-store/",
|
|
1582
|
+
".yarn/",
|
|
1583
|
+
".next/",
|
|
1584
|
+
".nuxt/",
|
|
1585
|
+
".cache/",
|
|
1586
|
+
".parcel-cache/",
|
|
1587
|
+
"",
|
|
1588
|
+
"# \u2500\u2500\u2500\u2500\u2500 Python Specific \u2500\u2500\u2500\u2500\u2500",
|
|
1589
|
+
"__pycache__/",
|
|
1590
|
+
"*.pyc",
|
|
1591
|
+
"*.pyo",
|
|
1592
|
+
"*.pyd",
|
|
1593
|
+
".Python",
|
|
1594
|
+
"venv/",
|
|
1595
|
+
".venv/",
|
|
1596
|
+
"env/",
|
|
1597
|
+
".env/",
|
|
1598
|
+
"",
|
|
1599
|
+
"# \u2500\u2500\u2500\u2500\u2500 Java Specific \u2500\u2500\u2500\u2500\u2500",
|
|
1600
|
+
"*.class",
|
|
1601
|
+
"*.jar",
|
|
1602
|
+
"*.war",
|
|
1603
|
+
"target/",
|
|
1604
|
+
""
|
|
1605
|
+
];
|
|
1606
|
+
const rulePatterns = extractIgnorePatternsFromRules(rules);
|
|
1607
|
+
if (rulePatterns.length > 0) {
|
|
1608
|
+
lines.push("# \u2500\u2500\u2500\u2500\u2500 Project-specific exclusions from rulesync rules \u2500\u2500\u2500\u2500\u2500");
|
|
1609
|
+
lines.push(...rulePatterns);
|
|
1610
|
+
lines.push("");
|
|
1611
|
+
}
|
|
1612
|
+
lines.push(
|
|
1613
|
+
"# \u2500\u2500\u2500\u2500\u2500 Allow specific source files (uncomment as needed) \u2500\u2500\u2500\u2500\u2500",
|
|
1614
|
+
"# !src/**/*.ts",
|
|
1615
|
+
"# !src/**/*.js",
|
|
1616
|
+
"# !lib/**/*.py",
|
|
1617
|
+
"# !src/main/**/*.java",
|
|
1618
|
+
""
|
|
1619
|
+
);
|
|
1620
|
+
return lines.join("\n");
|
|
1621
|
+
}
|
|
745
1622
|
|
|
746
1623
|
// src/generators/ignore/kiro.ts
|
|
747
|
-
var
|
|
1624
|
+
var import_node_path5 = require("path");
|
|
748
1625
|
async function generateKiroIgnoreFiles(rules, config, baseDir) {
|
|
749
1626
|
const outputs = [];
|
|
750
|
-
const aiignoreContent =
|
|
1627
|
+
const aiignoreContent = generateAiignoreContent2(rules);
|
|
751
1628
|
const outputPath = baseDir || process.cwd();
|
|
752
|
-
const filepath = (0,
|
|
1629
|
+
const filepath = (0, import_node_path5.join)(outputPath, ".aiignore");
|
|
753
1630
|
outputs.push({
|
|
754
1631
|
tool: "kiro",
|
|
755
1632
|
filepath,
|
|
@@ -757,7 +1634,7 @@ async function generateKiroIgnoreFiles(rules, config, baseDir) {
|
|
|
757
1634
|
});
|
|
758
1635
|
return outputs;
|
|
759
1636
|
}
|
|
760
|
-
function
|
|
1637
|
+
function generateAiignoreContent2(rules) {
|
|
761
1638
|
const lines = [
|
|
762
1639
|
"# Generated by rulesync - Kiro AI-specific exclusions",
|
|
763
1640
|
"# This file excludes files that can be in Git but shouldn't be read by the AI",
|
|
@@ -786,162 +1663,33 @@ function generateAiignoreContent(rules) {
|
|
|
786
1663
|
"# Reinforce critical exclusions from .gitignore",
|
|
787
1664
|
"*.pem",
|
|
788
1665
|
"*.key",
|
|
789
|
-
".env*",
|
|
790
|
-
""
|
|
791
|
-
);
|
|
792
|
-
const rulePatterns =
|
|
793
|
-
if (rulePatterns.length > 0) {
|
|
794
|
-
lines.push("# Project-specific exclusions from rulesync rules");
|
|
795
|
-
lines.push(...rulePatterns);
|
|
796
|
-
lines.push("");
|
|
797
|
-
}
|
|
798
|
-
return lines.join("\n");
|
|
799
|
-
}
|
|
800
|
-
function extractIgnorePatternsFromRules2(rules) {
|
|
801
|
-
const patterns = [];
|
|
802
|
-
for (const rule of rules) {
|
|
803
|
-
if (rule.frontmatter.globs && rule.frontmatter.globs.length > 0) {
|
|
804
|
-
for (const glob of rule.frontmatter.globs) {
|
|
805
|
-
if (shouldExcludeFromAI(glob)) {
|
|
806
|
-
patterns.push(`# Exclude: ${rule.frontmatter.description}`);
|
|
807
|
-
patterns.push(glob);
|
|
808
|
-
}
|
|
809
|
-
}
|
|
810
|
-
}
|
|
811
|
-
const contentPatterns = extractIgnorePatternsFromContent(rule.content);
|
|
812
|
-
patterns.push(...contentPatterns);
|
|
813
|
-
}
|
|
814
|
-
return patterns;
|
|
815
|
-
}
|
|
816
|
-
function shouldExcludeFromAI(glob) {
|
|
817
|
-
const excludePatterns = [
|
|
818
|
-
// Test and fixture files that might be large or confusing
|
|
819
|
-
"**/test/fixtures/**",
|
|
820
|
-
"**/tests/fixtures/**",
|
|
821
|
-
"**/*.fixture.*",
|
|
822
|
-
// Build and generated files
|
|
823
|
-
"**/dist/**",
|
|
824
|
-
"**/build/**",
|
|
825
|
-
"**/coverage/**",
|
|
826
|
-
// Configuration that might contain sensitive data
|
|
827
|
-
"**/config/production/**",
|
|
828
|
-
"**/config/prod/**",
|
|
829
|
-
"**/*.prod.*",
|
|
830
|
-
// Documentation that might be sensitive
|
|
831
|
-
"**/internal/**",
|
|
832
|
-
"**/private/**",
|
|
833
|
-
"**/confidential/**"
|
|
834
|
-
];
|
|
835
|
-
return excludePatterns.some((pattern) => {
|
|
836
|
-
const regex = new RegExp(pattern.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*"));
|
|
837
|
-
return regex.test(glob);
|
|
838
|
-
});
|
|
839
|
-
}
|
|
840
|
-
function extractIgnorePatternsFromContent(content) {
|
|
841
|
-
const patterns = [];
|
|
842
|
-
const lines = content.split("\n");
|
|
843
|
-
for (const line of lines) {
|
|
844
|
-
const trimmed = line.trim();
|
|
845
|
-
if (trimmed.startsWith("# IGNORE:") || trimmed.startsWith("# aiignore:")) {
|
|
846
|
-
const pattern = trimmed.replace(/^# (IGNORE|aiignore):\s*/, "").trim();
|
|
847
|
-
if (pattern) {
|
|
848
|
-
patterns.push(pattern);
|
|
849
|
-
}
|
|
850
|
-
}
|
|
851
|
-
if (trimmed.includes("exclude") || trimmed.includes("ignore")) {
|
|
852
|
-
const matches = trimmed.match(/['"`]([^'"`]+\.(log|tmp|cache|temp))['"`]/g);
|
|
853
|
-
if (matches) {
|
|
854
|
-
patterns.push(...matches.map((m) => m.replace(/['"`]/g, "")));
|
|
855
|
-
}
|
|
856
|
-
}
|
|
1666
|
+
".env*",
|
|
1667
|
+
""
|
|
1668
|
+
);
|
|
1669
|
+
const rulePatterns = extractIgnorePatternsFromRules(rules);
|
|
1670
|
+
if (rulePatterns.length > 0) {
|
|
1671
|
+
lines.push("# Project-specific exclusions from rulesync rules");
|
|
1672
|
+
lines.push(...rulePatterns);
|
|
1673
|
+
lines.push("");
|
|
857
1674
|
}
|
|
858
|
-
return
|
|
1675
|
+
return lines.join("\n");
|
|
859
1676
|
}
|
|
860
1677
|
|
|
861
1678
|
// src/generators/rules/augmentcode.ts
|
|
862
|
-
var
|
|
1679
|
+
var import_node_path8 = require("path");
|
|
863
1680
|
|
|
864
1681
|
// src/generators/rules/shared-helpers.ts
|
|
865
|
-
var
|
|
1682
|
+
var import_node_path7 = require("path");
|
|
866
1683
|
|
|
867
1684
|
// src/utils/ignore.ts
|
|
868
|
-
var
|
|
1685
|
+
var import_node_path6 = require("path");
|
|
869
1686
|
var import_micromatch = __toESM(require("micromatch"), 1);
|
|
870
|
-
|
|
871
|
-
// src/utils/file.ts
|
|
872
|
-
var import_promises2 = require("fs/promises");
|
|
873
|
-
var import_node_path3 = require("path");
|
|
874
|
-
async function ensureDir(dirPath) {
|
|
875
|
-
try {
|
|
876
|
-
await (0, import_promises2.stat)(dirPath);
|
|
877
|
-
} catch {
|
|
878
|
-
await (0, import_promises2.mkdir)(dirPath, { recursive: true });
|
|
879
|
-
}
|
|
880
|
-
}
|
|
881
|
-
async function readFileContent(filepath) {
|
|
882
|
-
return (0, import_promises2.readFile)(filepath, "utf-8");
|
|
883
|
-
}
|
|
884
|
-
async function writeFileContent(filepath, content) {
|
|
885
|
-
await ensureDir((0, import_node_path3.dirname)(filepath));
|
|
886
|
-
await (0, import_promises2.writeFile)(filepath, content, "utf-8");
|
|
887
|
-
}
|
|
888
|
-
async function fileExists(filepath) {
|
|
889
|
-
try {
|
|
890
|
-
await (0, import_promises2.stat)(filepath);
|
|
891
|
-
return true;
|
|
892
|
-
} catch {
|
|
893
|
-
return false;
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
async function findFiles(dir, extension = ".md") {
|
|
897
|
-
try {
|
|
898
|
-
const files = await (0, import_promises2.readdir)(dir);
|
|
899
|
-
return files.filter((file) => file.endsWith(extension)).map((file) => (0, import_node_path3.join)(dir, file));
|
|
900
|
-
} catch {
|
|
901
|
-
return [];
|
|
902
|
-
}
|
|
903
|
-
}
|
|
904
|
-
async function removeDirectory(dirPath) {
|
|
905
|
-
const dangerousPaths = [".", "/", "~", "src", "node_modules"];
|
|
906
|
-
if (dangerousPaths.includes(dirPath) || dirPath === "") {
|
|
907
|
-
console.warn(`Skipping deletion of dangerous path: ${dirPath}`);
|
|
908
|
-
return;
|
|
909
|
-
}
|
|
910
|
-
try {
|
|
911
|
-
if (await fileExists(dirPath)) {
|
|
912
|
-
await (0, import_promises2.rm)(dirPath, { recursive: true, force: true });
|
|
913
|
-
}
|
|
914
|
-
} catch (error) {
|
|
915
|
-
console.warn(`Failed to remove directory ${dirPath}:`, error);
|
|
916
|
-
}
|
|
917
|
-
}
|
|
918
|
-
async function removeFile(filepath) {
|
|
919
|
-
try {
|
|
920
|
-
if (await fileExists(filepath)) {
|
|
921
|
-
await (0, import_promises2.rm)(filepath);
|
|
922
|
-
}
|
|
923
|
-
} catch (error) {
|
|
924
|
-
console.warn(`Failed to remove file ${filepath}:`, error);
|
|
925
|
-
}
|
|
926
|
-
}
|
|
927
|
-
async function removeClaudeGeneratedFiles() {
|
|
928
|
-
const filesToRemove = ["CLAUDE.md", ".claude/memories"];
|
|
929
|
-
for (const fileOrDir of filesToRemove) {
|
|
930
|
-
if (fileOrDir.endsWith("/memories")) {
|
|
931
|
-
await removeDirectory(fileOrDir);
|
|
932
|
-
} else {
|
|
933
|
-
await removeFile(fileOrDir);
|
|
934
|
-
}
|
|
935
|
-
}
|
|
936
|
-
}
|
|
937
|
-
|
|
938
|
-
// src/utils/ignore.ts
|
|
939
1687
|
var cachedIgnorePatterns = null;
|
|
940
1688
|
async function loadIgnorePatterns(baseDir = process.cwd()) {
|
|
941
1689
|
if (cachedIgnorePatterns) {
|
|
942
1690
|
return cachedIgnorePatterns;
|
|
943
1691
|
}
|
|
944
|
-
const ignorePath = (0,
|
|
1692
|
+
const ignorePath = (0, import_node_path6.join)(baseDir, ".rulesyncignore");
|
|
945
1693
|
if (!await fileExists(ignorePath)) {
|
|
946
1694
|
cachedIgnorePatterns = { patterns: [] };
|
|
947
1695
|
return cachedIgnorePatterns;
|
|
@@ -986,7 +1734,7 @@ function filterIgnoredFiles(files, ignorePatterns) {
|
|
|
986
1734
|
|
|
987
1735
|
// src/generators/rules/shared-helpers.ts
|
|
988
1736
|
function resolveOutputDir(config, tool, baseDir) {
|
|
989
|
-
return baseDir ? (0,
|
|
1737
|
+
return baseDir ? (0, import_node_path7.join)(baseDir, config.outputPaths[tool]) : config.outputPaths[tool];
|
|
990
1738
|
}
|
|
991
1739
|
function createOutputsArray() {
|
|
992
1740
|
return [];
|
|
@@ -995,7 +1743,7 @@ function addOutput(outputs, tool, config, baseDir, relativePath, content) {
|
|
|
995
1743
|
const outputDir = resolveOutputDir(config, tool, baseDir);
|
|
996
1744
|
outputs.push({
|
|
997
1745
|
tool,
|
|
998
|
-
filepath: (0,
|
|
1746
|
+
filepath: (0, import_node_path7.join)(outputDir, relativePath),
|
|
999
1747
|
content
|
|
1000
1748
|
});
|
|
1001
1749
|
}
|
|
@@ -1004,7 +1752,7 @@ async function generateRulesConfig(rules, config, generatorConfig, baseDir) {
|
|
|
1004
1752
|
for (const rule of rules) {
|
|
1005
1753
|
const content = generatorConfig.generateContent(rule);
|
|
1006
1754
|
const outputDir = resolveOutputDir(config, generatorConfig.tool, baseDir);
|
|
1007
|
-
const filepath = generatorConfig.pathResolver ? generatorConfig.pathResolver(rule, outputDir) : (0,
|
|
1755
|
+
const filepath = generatorConfig.pathResolver ? generatorConfig.pathResolver(rule, outputDir) : (0, import_node_path7.join)(outputDir, `${rule.filename}${generatorConfig.fileExtension}`);
|
|
1008
1756
|
outputs.push({
|
|
1009
1757
|
tool: generatorConfig.tool,
|
|
1010
1758
|
filepath,
|
|
@@ -1013,13 +1761,57 @@ async function generateRulesConfig(rules, config, generatorConfig, baseDir) {
|
|
|
1013
1761
|
}
|
|
1014
1762
|
const ignorePatterns = await loadIgnorePatterns(baseDir);
|
|
1015
1763
|
if (ignorePatterns.patterns.length > 0) {
|
|
1016
|
-
const ignorePath = baseDir ? (0,
|
|
1764
|
+
const ignorePath = baseDir ? (0, import_node_path7.join)(baseDir, generatorConfig.ignoreFileName) : generatorConfig.ignoreFileName;
|
|
1765
|
+
const ignoreContent = generateIgnoreFile(ignorePatterns.patterns, generatorConfig.tool);
|
|
1766
|
+
outputs.push({
|
|
1767
|
+
tool: generatorConfig.tool,
|
|
1768
|
+
filepath: ignorePath,
|
|
1769
|
+
content: ignoreContent
|
|
1770
|
+
});
|
|
1771
|
+
}
|
|
1772
|
+
return outputs;
|
|
1773
|
+
}
|
|
1774
|
+
async function generateComplexRules(rules, config, generatorConfig, baseDir) {
|
|
1775
|
+
const outputs = [];
|
|
1776
|
+
const rootRules = rules.filter((r) => r.frontmatter.root === true);
|
|
1777
|
+
const detailRules = rules.filter((r) => r.frontmatter.root === false);
|
|
1778
|
+
const rootRule = rootRules[0];
|
|
1779
|
+
if (generatorConfig.generateDetailContent && generatorConfig.detailSubDir) {
|
|
1780
|
+
for (const rule of detailRules) {
|
|
1781
|
+
const content = generatorConfig.generateDetailContent(rule);
|
|
1782
|
+
const filepath = baseDir ? (0, import_node_path7.join)(baseDir, generatorConfig.detailSubDir, `${rule.filename}.md`) : (0, import_node_path7.join)(generatorConfig.detailSubDir, `${rule.filename}.md`);
|
|
1783
|
+
outputs.push({
|
|
1784
|
+
tool: generatorConfig.tool,
|
|
1785
|
+
filepath,
|
|
1786
|
+
content
|
|
1787
|
+
});
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
if (generatorConfig.generateRootContent && generatorConfig.rootFilePath) {
|
|
1791
|
+
const rootContent = generatorConfig.generateRootContent(rootRule, detailRules, baseDir);
|
|
1792
|
+
const rootFilepath = baseDir ? (0, import_node_path7.join)(baseDir, generatorConfig.rootFilePath) : generatorConfig.rootFilePath;
|
|
1793
|
+
outputs.push({
|
|
1794
|
+
tool: generatorConfig.tool,
|
|
1795
|
+
filepath: rootFilepath,
|
|
1796
|
+
content: rootContent
|
|
1797
|
+
});
|
|
1798
|
+
}
|
|
1799
|
+
const ignorePatterns = await loadIgnorePatterns(baseDir);
|
|
1800
|
+
if (ignorePatterns.patterns.length > 0) {
|
|
1801
|
+
const ignorePath = baseDir ? (0, import_node_path7.join)(baseDir, generatorConfig.ignoreFileName) : generatorConfig.ignoreFileName;
|
|
1017
1802
|
const ignoreContent = generateIgnoreFile(ignorePatterns.patterns, generatorConfig.tool);
|
|
1018
1803
|
outputs.push({
|
|
1019
1804
|
tool: generatorConfig.tool,
|
|
1020
1805
|
filepath: ignorePath,
|
|
1021
1806
|
content: ignoreContent
|
|
1022
1807
|
});
|
|
1808
|
+
if (generatorConfig.updateAdditionalConfig) {
|
|
1809
|
+
const additionalOutputs = await generatorConfig.updateAdditionalConfig(
|
|
1810
|
+
ignorePatterns.patterns,
|
|
1811
|
+
baseDir
|
|
1812
|
+
);
|
|
1813
|
+
outputs.push(...additionalOutputs);
|
|
1814
|
+
}
|
|
1023
1815
|
}
|
|
1024
1816
|
return outputs;
|
|
1025
1817
|
}
|
|
@@ -1056,7 +1848,7 @@ async function generateAugmentcodeConfig(rules, config, baseDir) {
|
|
|
1056
1848
|
"augmentcode",
|
|
1057
1849
|
config,
|
|
1058
1850
|
baseDir,
|
|
1059
|
-
(0,
|
|
1851
|
+
(0, import_node_path8.join)(".augment", "rules", `${rule.filename}.md`),
|
|
1060
1852
|
generateRuleFile(rule)
|
|
1061
1853
|
);
|
|
1062
1854
|
});
|
|
@@ -1109,42 +1901,29 @@ function generateLegacyGuidelinesFile(allRules) {
|
|
|
1109
1901
|
}
|
|
1110
1902
|
|
|
1111
1903
|
// src/generators/rules/claudecode.ts
|
|
1112
|
-
var
|
|
1113
|
-
|
|
1114
|
-
// src/types/claudecode.ts
|
|
1115
|
-
var import_mini2 = require("zod/mini");
|
|
1116
|
-
var ClaudeSettingsSchema = import_mini2.z.looseObject({
|
|
1117
|
-
permissions: import_mini2.z._default(
|
|
1118
|
-
import_mini2.z.looseObject({
|
|
1119
|
-
deny: import_mini2.z._default(import_mini2.z.array(import_mini2.z.string()), [])
|
|
1120
|
-
}),
|
|
1121
|
-
{ deny: [] }
|
|
1122
|
-
)
|
|
1123
|
-
});
|
|
1124
|
-
|
|
1125
|
-
// src/generators/rules/claudecode.ts
|
|
1904
|
+
var import_node_path9 = require("path");
|
|
1126
1905
|
async function generateClaudecodeConfig(rules, config, baseDir) {
|
|
1127
1906
|
const outputs = [];
|
|
1128
1907
|
const rootRules = rules.filter((r) => r.frontmatter.root === true);
|
|
1129
1908
|
const detailRules = rules.filter((r) => r.frontmatter.root === false);
|
|
1130
1909
|
const claudeMdContent = generateClaudeMarkdown(rootRules, detailRules);
|
|
1131
|
-
const claudeOutputDir = baseDir ? (0,
|
|
1910
|
+
const claudeOutputDir = baseDir ? (0, import_node_path9.join)(baseDir, config.outputPaths.claudecode) : config.outputPaths.claudecode;
|
|
1132
1911
|
outputs.push({
|
|
1133
1912
|
tool: "claudecode",
|
|
1134
|
-
filepath: (0,
|
|
1913
|
+
filepath: (0, import_node_path9.join)(claudeOutputDir, "CLAUDE.md"),
|
|
1135
1914
|
content: claudeMdContent
|
|
1136
1915
|
});
|
|
1137
1916
|
for (const rule of detailRules) {
|
|
1138
1917
|
const memoryContent = generateMemoryFile(rule);
|
|
1139
1918
|
outputs.push({
|
|
1140
1919
|
tool: "claudecode",
|
|
1141
|
-
filepath: (0,
|
|
1920
|
+
filepath: (0, import_node_path9.join)(claudeOutputDir, ".claude", "memories", `${rule.filename}.md`),
|
|
1142
1921
|
content: memoryContent
|
|
1143
1922
|
});
|
|
1144
1923
|
}
|
|
1145
1924
|
const ignorePatterns = await loadIgnorePatterns(baseDir);
|
|
1146
1925
|
if (ignorePatterns.patterns.length > 0) {
|
|
1147
|
-
const settingsPath = baseDir ? (0,
|
|
1926
|
+
const settingsPath = baseDir ? (0, import_node_path9.join)(baseDir, ".claude", "settings.json") : (0, import_node_path9.join)(".claude", "settings.json");
|
|
1148
1927
|
await updateClaudeSettings(settingsPath, ignorePatterns.patterns);
|
|
1149
1928
|
}
|
|
1150
1929
|
return outputs;
|
|
@@ -1223,7 +2002,7 @@ async function generateClineConfig(rules, config, baseDir) {
|
|
|
1223
2002
|
}
|
|
1224
2003
|
|
|
1225
2004
|
// src/generators/rules/copilot.ts
|
|
1226
|
-
var
|
|
2005
|
+
var import_node_path10 = require("path");
|
|
1227
2006
|
async function generateCopilotConfig(rules, config, baseDir) {
|
|
1228
2007
|
return generateComplexRulesConfig(
|
|
1229
2008
|
rules,
|
|
@@ -1235,7 +2014,7 @@ async function generateCopilotConfig(rules, config, baseDir) {
|
|
|
1235
2014
|
generateContent: generateCopilotMarkdown,
|
|
1236
2015
|
getOutputPath: (rule, outputDir) => {
|
|
1237
2016
|
const baseFilename = rule.filename.replace(/\.md$/, "");
|
|
1238
|
-
return (0,
|
|
2017
|
+
return (0, import_node_path10.join)(outputDir, `${baseFilename}.instructions.md`);
|
|
1239
2018
|
}
|
|
1240
2019
|
},
|
|
1241
2020
|
baseDir
|
|
@@ -1256,7 +2035,7 @@ function generateCopilotMarkdown(rule) {
|
|
|
1256
2035
|
}
|
|
1257
2036
|
|
|
1258
2037
|
// src/generators/rules/cursor.ts
|
|
1259
|
-
var
|
|
2038
|
+
var import_node_path11 = require("path");
|
|
1260
2039
|
async function generateCursorConfig(rules, config, baseDir) {
|
|
1261
2040
|
return generateComplexRulesConfig(
|
|
1262
2041
|
rules,
|
|
@@ -1267,7 +2046,7 @@ async function generateCursorConfig(rules, config, baseDir) {
|
|
|
1267
2046
|
ignoreFileName: ".cursorignore",
|
|
1268
2047
|
generateContent: generateCursorMarkdown,
|
|
1269
2048
|
getOutputPath: (rule, outputDir) => {
|
|
1270
|
-
return (0,
|
|
2049
|
+
return (0, import_node_path11.join)(outputDir, `${rule.filename}.mdc`);
|
|
1271
2050
|
}
|
|
1272
2051
|
},
|
|
1273
2052
|
baseDir
|
|
@@ -1327,39 +2106,18 @@ function determineCursorRuleType(frontmatter) {
|
|
|
1327
2106
|
}
|
|
1328
2107
|
|
|
1329
2108
|
// src/generators/rules/geminicli.ts
|
|
1330
|
-
var import_node_path10 = require("path");
|
|
1331
2109
|
async function generateGeminiConfig(rules, config, baseDir) {
|
|
1332
|
-
const
|
|
1333
|
-
const rootRule = rules.find((rule) => rule.frontmatter.root === true);
|
|
1334
|
-
const memoryRules = rules.filter((rule) => rule.frontmatter.root === false);
|
|
1335
|
-
for (const rule of memoryRules) {
|
|
1336
|
-
const content = generateGeminiMemoryMarkdown(rule);
|
|
1337
|
-
const outputDir = baseDir ? (0, import_node_path10.join)(baseDir, config.outputPaths.geminicli) : config.outputPaths.geminicli;
|
|
1338
|
-
const filepath = (0, import_node_path10.join)(outputDir, `${rule.filename}.md`);
|
|
1339
|
-
outputs.push({
|
|
1340
|
-
tool: "geminicli",
|
|
1341
|
-
filepath,
|
|
1342
|
-
content
|
|
1343
|
-
});
|
|
1344
|
-
}
|
|
1345
|
-
const rootContent = generateGeminiRootMarkdown(rootRule, memoryRules, baseDir);
|
|
1346
|
-
const rootFilepath = baseDir ? (0, import_node_path10.join)(baseDir, "GEMINI.md") : "GEMINI.md";
|
|
1347
|
-
outputs.push({
|
|
2110
|
+
const generatorConfig = {
|
|
1348
2111
|
tool: "geminicli",
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
filepath: aiexcludePath,
|
|
1359
|
-
content: aiexcludeContent
|
|
1360
|
-
});
|
|
1361
|
-
}
|
|
1362
|
-
return outputs;
|
|
2112
|
+
fileExtension: ".md",
|
|
2113
|
+
ignoreFileName: ".aiexclude",
|
|
2114
|
+
generateContent: generateGeminiMemoryMarkdown,
|
|
2115
|
+
generateDetailContent: generateGeminiMemoryMarkdown,
|
|
2116
|
+
generateRootContent: generateGeminiRootMarkdown,
|
|
2117
|
+
rootFilePath: "GEMINI.md",
|
|
2118
|
+
detailSubDir: ".gemini/memories"
|
|
2119
|
+
};
|
|
2120
|
+
return generateComplexRules(rules, config, generatorConfig, baseDir);
|
|
1363
2121
|
}
|
|
1364
2122
|
function generateGeminiMemoryMarkdown(rule) {
|
|
1365
2123
|
return rule.content.trim();
|
|
@@ -1388,24 +2146,42 @@ function generateGeminiRootMarkdown(rootRule, memoryRules, _baseDir) {
|
|
|
1388
2146
|
}
|
|
1389
2147
|
return lines.join("\n");
|
|
1390
2148
|
}
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
"",
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
2149
|
+
|
|
2150
|
+
// src/generators/rules/junie.ts
|
|
2151
|
+
async function generateJunieConfig(rules, config, baseDir) {
|
|
2152
|
+
const generatorConfig = {
|
|
2153
|
+
tool: "junie",
|
|
2154
|
+
fileExtension: ".md",
|
|
2155
|
+
ignoreFileName: ".aiignore",
|
|
2156
|
+
generateContent: (rule) => rule.content.trim(),
|
|
2157
|
+
generateRootContent: generateGuidelinesMarkdown,
|
|
2158
|
+
rootFilePath: ".junie/guidelines.md"
|
|
2159
|
+
};
|
|
2160
|
+
return generateComplexRules(rules, config, generatorConfig, baseDir);
|
|
2161
|
+
}
|
|
2162
|
+
function generateGuidelinesMarkdown(rootRule, detailRules) {
|
|
2163
|
+
const lines = [];
|
|
2164
|
+
if (rootRule) {
|
|
2165
|
+
lines.push(rootRule.content);
|
|
2166
|
+
lines.push("");
|
|
2167
|
+
}
|
|
2168
|
+
if (detailRules.length > 0) {
|
|
2169
|
+
for (const rule of detailRules) {
|
|
2170
|
+
lines.push(rule.content);
|
|
2171
|
+
lines.push("");
|
|
2172
|
+
}
|
|
2173
|
+
}
|
|
2174
|
+
return lines.join("\n").trim();
|
|
1399
2175
|
}
|
|
1400
2176
|
|
|
1401
2177
|
// src/generators/rules/kiro.ts
|
|
1402
|
-
var
|
|
2178
|
+
var import_node_path12 = require("path");
|
|
1403
2179
|
async function generateKiroConfig(rules, config, baseDir) {
|
|
1404
2180
|
const outputs = [];
|
|
1405
2181
|
for (const rule of rules) {
|
|
1406
2182
|
const content = generateKiroMarkdown(rule);
|
|
1407
|
-
const outputDir = baseDir ? (0,
|
|
1408
|
-
const filepath = (0,
|
|
2183
|
+
const outputDir = baseDir ? (0, import_node_path12.join)(baseDir, config.outputPaths.kiro) : config.outputPaths.kiro;
|
|
2184
|
+
const filepath = (0, import_node_path12.join)(outputDir, `${rule.filename}.md`);
|
|
1409
2185
|
outputs.push({
|
|
1410
2186
|
tool: "kiro",
|
|
1411
2187
|
filepath,
|
|
@@ -1459,7 +2235,10 @@ async function generateConfigurations(rules, config, targetTools, baseDir) {
|
|
|
1459
2235
|
function filterRulesForTool(rules, tool, config) {
|
|
1460
2236
|
return rules.filter((rule) => {
|
|
1461
2237
|
const targets = resolveTargets(rule.frontmatter.targets, config);
|
|
1462
|
-
|
|
2238
|
+
if (!targets.includes(tool)) {
|
|
2239
|
+
return false;
|
|
2240
|
+
}
|
|
2241
|
+
return isToolSpecificRule(rule, tool);
|
|
1463
2242
|
});
|
|
1464
2243
|
}
|
|
1465
2244
|
async function generateForTool(tool, rules, config, baseDir) {
|
|
@@ -1490,6 +2269,11 @@ async function generateForTool(tool, rules, config, baseDir) {
|
|
|
1490
2269
|
return generateRooConfig(rules, config, baseDir);
|
|
1491
2270
|
case "geminicli":
|
|
1492
2271
|
return generateGeminiConfig(rules, config, baseDir);
|
|
2272
|
+
case "junie": {
|
|
2273
|
+
const junieRulesOutputs = await generateJunieConfig(rules, config, baseDir);
|
|
2274
|
+
const junieIgnoreOutputs = await generateJunieIgnoreFiles(rules, config, baseDir);
|
|
2275
|
+
return [...junieRulesOutputs, ...junieIgnoreOutputs];
|
|
2276
|
+
}
|
|
1493
2277
|
case "kiro": {
|
|
1494
2278
|
const kiroRulesOutputs = await generateKiroConfig(rules, config, baseDir);
|
|
1495
2279
|
const kiroIgnoreOutputs = await generateKiroIgnoreFiles(rules, config, baseDir);
|
|
@@ -1502,83 +2286,8 @@ async function generateForTool(tool, rules, config, baseDir) {
|
|
|
1502
2286
|
}
|
|
1503
2287
|
|
|
1504
2288
|
// src/core/parser.ts
|
|
1505
|
-
var
|
|
2289
|
+
var import_node_path13 = require("path");
|
|
1506
2290
|
var import_gray_matter = __toESM(require("gray-matter"), 1);
|
|
1507
|
-
|
|
1508
|
-
// src/types/config.ts
|
|
1509
|
-
var import_mini3 = require("zod/mini");
|
|
1510
|
-
init_tool_targets();
|
|
1511
|
-
var ConfigSchema = import_mini3.z.object({
|
|
1512
|
-
aiRulesDir: import_mini3.z.string(),
|
|
1513
|
-
outputPaths: import_mini3.z.record(ToolTargetSchema, import_mini3.z.string()),
|
|
1514
|
-
watchEnabled: import_mini3.z.boolean(),
|
|
1515
|
-
defaultTargets: ToolTargetsSchema
|
|
1516
|
-
});
|
|
1517
|
-
|
|
1518
|
-
// src/types/mcp.ts
|
|
1519
|
-
var import_mini4 = require("zod/mini");
|
|
1520
|
-
init_tool_targets();
|
|
1521
|
-
var McpTransportTypeSchema = import_mini4.z.enum(["stdio", "sse", "http"]);
|
|
1522
|
-
var McpServerBaseSchema = import_mini4.z.object({
|
|
1523
|
-
command: import_mini4.z.optional(import_mini4.z.string()),
|
|
1524
|
-
args: import_mini4.z.optional(import_mini4.z.array(import_mini4.z.string())),
|
|
1525
|
-
url: import_mini4.z.optional(import_mini4.z.string()),
|
|
1526
|
-
httpUrl: import_mini4.z.optional(import_mini4.z.string()),
|
|
1527
|
-
env: import_mini4.z.optional(import_mini4.z.record(import_mini4.z.string(), import_mini4.z.string())),
|
|
1528
|
-
disabled: import_mini4.z.optional(import_mini4.z.boolean()),
|
|
1529
|
-
networkTimeout: import_mini4.z.optional(import_mini4.z.number()),
|
|
1530
|
-
timeout: import_mini4.z.optional(import_mini4.z.number()),
|
|
1531
|
-
trust: import_mini4.z.optional(import_mini4.z.boolean()),
|
|
1532
|
-
cwd: import_mini4.z.optional(import_mini4.z.string()),
|
|
1533
|
-
transport: import_mini4.z.optional(McpTransportTypeSchema),
|
|
1534
|
-
type: import_mini4.z.optional(import_mini4.z.enum(["sse", "streamable-http"])),
|
|
1535
|
-
alwaysAllow: import_mini4.z.optional(import_mini4.z.array(import_mini4.z.string())),
|
|
1536
|
-
tools: import_mini4.z.optional(import_mini4.z.array(import_mini4.z.string())),
|
|
1537
|
-
kiroAutoApprove: import_mini4.z.optional(import_mini4.z.array(import_mini4.z.string())),
|
|
1538
|
-
kiroAutoBlock: import_mini4.z.optional(import_mini4.z.array(import_mini4.z.string()))
|
|
1539
|
-
});
|
|
1540
|
-
var RulesyncMcpServerSchema = import_mini4.z.extend(McpServerBaseSchema, {
|
|
1541
|
-
targets: import_mini4.z.optional(RulesyncTargetsSchema)
|
|
1542
|
-
});
|
|
1543
|
-
var McpConfigSchema = import_mini4.z.object({
|
|
1544
|
-
mcpServers: import_mini4.z.record(import_mini4.z.string(), McpServerBaseSchema)
|
|
1545
|
-
});
|
|
1546
|
-
var RulesyncMcpConfigSchema = import_mini4.z.object({
|
|
1547
|
-
mcpServers: import_mini4.z.record(import_mini4.z.string(), RulesyncMcpServerSchema)
|
|
1548
|
-
});
|
|
1549
|
-
|
|
1550
|
-
// src/types/rules.ts
|
|
1551
|
-
var import_mini5 = require("zod/mini");
|
|
1552
|
-
init_tool_targets();
|
|
1553
|
-
var RuleFrontmatterSchema = import_mini5.z.object({
|
|
1554
|
-
root: import_mini5.z.boolean(),
|
|
1555
|
-
targets: RulesyncTargetsSchema,
|
|
1556
|
-
description: import_mini5.z.string(),
|
|
1557
|
-
globs: import_mini5.z.array(import_mini5.z.string()),
|
|
1558
|
-
cursorRuleType: import_mini5.z.optional(import_mini5.z.enum(["always", "manual", "specificFiles", "intelligently"])),
|
|
1559
|
-
tags: import_mini5.z.optional(import_mini5.z.array(import_mini5.z.string()))
|
|
1560
|
-
});
|
|
1561
|
-
var ParsedRuleSchema = import_mini5.z.object({
|
|
1562
|
-
frontmatter: RuleFrontmatterSchema,
|
|
1563
|
-
content: import_mini5.z.string(),
|
|
1564
|
-
filename: import_mini5.z.string(),
|
|
1565
|
-
filepath: import_mini5.z.string()
|
|
1566
|
-
});
|
|
1567
|
-
var GeneratedOutputSchema = import_mini5.z.object({
|
|
1568
|
-
tool: ToolTargetSchema,
|
|
1569
|
-
filepath: import_mini5.z.string(),
|
|
1570
|
-
content: import_mini5.z.string()
|
|
1571
|
-
});
|
|
1572
|
-
var GenerateOptionsSchema = import_mini5.z.object({
|
|
1573
|
-
targetTools: import_mini5.z.optional(ToolTargetsSchema),
|
|
1574
|
-
outputDir: import_mini5.z.optional(import_mini5.z.string()),
|
|
1575
|
-
watch: import_mini5.z.optional(import_mini5.z.boolean())
|
|
1576
|
-
});
|
|
1577
|
-
|
|
1578
|
-
// src/types/index.ts
|
|
1579
|
-
init_tool_targets();
|
|
1580
|
-
|
|
1581
|
-
// src/core/parser.ts
|
|
1582
2291
|
async function parseRulesFromDirectory(aiRulesDir) {
|
|
1583
2292
|
const ignorePatterns = await loadIgnorePatterns();
|
|
1584
2293
|
const allRuleFiles = await findFiles(aiRulesDir, ".md");
|
|
@@ -1615,7 +2324,7 @@ async function parseRuleFile(filepath) {
|
|
|
1615
2324
|
const parsed = (0, import_gray_matter.default)(content);
|
|
1616
2325
|
try {
|
|
1617
2326
|
const frontmatter = RuleFrontmatterSchema.parse(parsed.data);
|
|
1618
|
-
const filename = (0,
|
|
2327
|
+
const filename = (0, import_node_path13.basename)(filepath, ".md");
|
|
1619
2328
|
return {
|
|
1620
2329
|
frontmatter,
|
|
1621
2330
|
content: parsed.content,
|
|
@@ -1680,7 +2389,7 @@ async function validateRule(rule) {
|
|
|
1680
2389
|
}
|
|
1681
2390
|
|
|
1682
2391
|
// src/core/mcp-generator.ts
|
|
1683
|
-
var
|
|
2392
|
+
var path4 = __toESM(require("path"), 1);
|
|
1684
2393
|
|
|
1685
2394
|
// src/generators/mcp/index.ts
|
|
1686
2395
|
init_augmentcode();
|
|
@@ -1689,14 +2398,15 @@ init_cline();
|
|
|
1689
2398
|
init_copilot();
|
|
1690
2399
|
init_cursor();
|
|
1691
2400
|
init_geminicli();
|
|
2401
|
+
init_junie();
|
|
1692
2402
|
init_kiro();
|
|
1693
2403
|
init_roo();
|
|
1694
2404
|
|
|
1695
2405
|
// src/core/mcp-parser.ts
|
|
1696
2406
|
var fs = __toESM(require("fs"), 1);
|
|
1697
|
-
var
|
|
2407
|
+
var path3 = __toESM(require("path"), 1);
|
|
1698
2408
|
function parseMcpConfig(projectRoot) {
|
|
1699
|
-
const mcpPath =
|
|
2409
|
+
const mcpPath = path3.join(projectRoot, ".rulesync", ".mcp.json");
|
|
1700
2410
|
if (!fs.existsSync(mcpPath)) {
|
|
1701
2411
|
return null;
|
|
1702
2412
|
}
|
|
@@ -1720,7 +2430,7 @@ function parseMcpConfig(projectRoot) {
|
|
|
1720
2430
|
}
|
|
1721
2431
|
|
|
1722
2432
|
// src/core/mcp-generator.ts
|
|
1723
|
-
async function generateMcpConfigs(projectRoot, baseDir) {
|
|
2433
|
+
async function generateMcpConfigs(projectRoot, baseDir, targetTools) {
|
|
1724
2434
|
const results = [];
|
|
1725
2435
|
const targetRoot = baseDir || projectRoot;
|
|
1726
2436
|
const config = parseMcpConfig(projectRoot);
|
|
@@ -1730,55 +2440,70 @@ async function generateMcpConfigs(projectRoot, baseDir) {
|
|
|
1730
2440
|
const generators = [
|
|
1731
2441
|
{
|
|
1732
2442
|
tool: "augmentcode-project",
|
|
1733
|
-
path:
|
|
2443
|
+
path: path4.join(targetRoot, ".mcp.json"),
|
|
1734
2444
|
generate: () => generateAugmentcodeMcp(config)
|
|
1735
2445
|
},
|
|
1736
2446
|
{
|
|
1737
2447
|
tool: "augmentcode-legacy-project",
|
|
1738
|
-
path:
|
|
2448
|
+
path: path4.join(targetRoot, ".mcp.json"),
|
|
1739
2449
|
generate: () => generateAugmentcodeMcp(config)
|
|
1740
2450
|
},
|
|
1741
2451
|
{
|
|
1742
2452
|
tool: "claude-project",
|
|
1743
|
-
path:
|
|
2453
|
+
path: path4.join(targetRoot, ".mcp.json"),
|
|
1744
2454
|
generate: () => generateClaudeMcp(config)
|
|
1745
2455
|
},
|
|
1746
2456
|
{
|
|
1747
2457
|
tool: "copilot-editor",
|
|
1748
|
-
path:
|
|
2458
|
+
path: path4.join(targetRoot, ".vscode", "mcp.json"),
|
|
1749
2459
|
generate: () => generateCopilotMcp(config, "editor")
|
|
1750
2460
|
},
|
|
1751
2461
|
{
|
|
1752
2462
|
tool: "cursor-project",
|
|
1753
|
-
path:
|
|
2463
|
+
path: path4.join(targetRoot, ".cursor", "mcp.json"),
|
|
1754
2464
|
generate: () => generateCursorMcp(config)
|
|
1755
2465
|
},
|
|
1756
2466
|
{
|
|
1757
2467
|
tool: "cline-project",
|
|
1758
|
-
path:
|
|
2468
|
+
path: path4.join(targetRoot, ".cline", "mcp.json"),
|
|
1759
2469
|
generate: () => generateClineMcp(config)
|
|
1760
2470
|
},
|
|
1761
2471
|
{
|
|
1762
2472
|
tool: "gemini-project",
|
|
1763
|
-
path:
|
|
2473
|
+
path: path4.join(targetRoot, ".gemini", "settings.json"),
|
|
1764
2474
|
generate: () => generateGeminiCliMcp(config)
|
|
1765
2475
|
},
|
|
2476
|
+
{
|
|
2477
|
+
tool: "junie-project",
|
|
2478
|
+
path: path4.join(targetRoot, ".junie", "mcp-config.json"),
|
|
2479
|
+
generate: () => generateJunieMcp(config)
|
|
2480
|
+
},
|
|
1766
2481
|
{
|
|
1767
2482
|
tool: "kiro-project",
|
|
1768
|
-
path:
|
|
2483
|
+
path: path4.join(targetRoot, ".kiro", "mcp.json"),
|
|
1769
2484
|
generate: () => generateKiroMcp(config)
|
|
1770
2485
|
},
|
|
1771
2486
|
{
|
|
1772
2487
|
tool: "roo-project",
|
|
1773
|
-
path:
|
|
2488
|
+
path: path4.join(targetRoot, ".roo", "mcp.json"),
|
|
1774
2489
|
generate: () => generateRooMcp(config)
|
|
1775
2490
|
}
|
|
1776
2491
|
];
|
|
1777
|
-
|
|
2492
|
+
const filteredGenerators = targetTools ? generators.filter((g) => {
|
|
2493
|
+
const baseTool = g.tool.split("-")[0];
|
|
2494
|
+
if (!isToolTarget(baseTool)) {
|
|
2495
|
+
return false;
|
|
2496
|
+
}
|
|
2497
|
+
if (baseTool === "augmentcode") {
|
|
2498
|
+
return targetTools.includes("augmentcode") || targetTools.includes("augmentcode-legacy");
|
|
2499
|
+
}
|
|
2500
|
+
return targetTools.includes(baseTool);
|
|
2501
|
+
}) : generators;
|
|
2502
|
+
for (const generator of filteredGenerators) {
|
|
1778
2503
|
try {
|
|
1779
2504
|
const content = generator.generate();
|
|
1780
2505
|
const parsed = JSON.parse(content);
|
|
1781
|
-
if (generator.tool.includes("augmentcode") || generator.tool.includes("claude") || generator.tool.includes("cline") || generator.tool.includes("cursor") || generator.tool.includes("gemini") || generator.tool.includes("kiro") || generator.tool.includes("roo")) {
|
|
2506
|
+
if (generator.tool.includes("augmentcode") || generator.tool.includes("claude") || generator.tool.includes("cline") || generator.tool.includes("cursor") || generator.tool.includes("gemini") || generator.tool.includes("junie") || generator.tool.includes("kiro") || generator.tool.includes("roo")) {
|
|
1782
2507
|
if (!parsed.mcpServers || Object.keys(parsed.mcpServers).length === 0) {
|
|
1783
2508
|
results.push({
|
|
1784
2509
|
tool: generator.tool,
|
|
@@ -1818,15 +2543,58 @@ async function generateMcpConfigs(projectRoot, baseDir) {
|
|
|
1818
2543
|
|
|
1819
2544
|
// src/cli/commands/generate.ts
|
|
1820
2545
|
async function generateCommand(options = {}) {
|
|
1821
|
-
const
|
|
1822
|
-
|
|
2546
|
+
const configLoaderOptions = {
|
|
2547
|
+
...options.config !== void 0 && { configPath: options.config },
|
|
2548
|
+
...options.noConfig !== void 0 && { noConfig: options.noConfig }
|
|
2549
|
+
};
|
|
2550
|
+
const configResult = await loadConfig(configLoaderOptions);
|
|
2551
|
+
const cliOptions = {
|
|
2552
|
+
...options.tools !== void 0 && { tools: options.tools },
|
|
2553
|
+
...options.verbose !== void 0 && { verbose: options.verbose },
|
|
2554
|
+
...options.delete !== void 0 && { delete: options.delete },
|
|
2555
|
+
...options.baseDirs !== void 0 && { baseDirs: options.baseDirs }
|
|
2556
|
+
};
|
|
2557
|
+
const config = mergeWithCliOptions(configResult.config, cliOptions);
|
|
2558
|
+
if (options.tools && options.tools.length > 0) {
|
|
2559
|
+
const configTargets = config.defaultTargets;
|
|
2560
|
+
const cliTools = options.tools;
|
|
2561
|
+
const cliToolsSet = new Set(cliTools);
|
|
2562
|
+
const configTargetsSet = new Set(configTargets);
|
|
2563
|
+
const notInConfig = cliTools.filter((tool) => !configTargetsSet.has(tool));
|
|
2564
|
+
const notInCli = configTargets.filter((tool) => !cliToolsSet.has(tool));
|
|
2565
|
+
if (notInConfig.length > 0 || notInCli.length > 0) {
|
|
2566
|
+
console.warn("\u26A0\uFE0F Warning: CLI tool selection differs from configuration!");
|
|
2567
|
+
console.warn(` Config targets: ${configTargets.join(", ")}`);
|
|
2568
|
+
console.warn(` CLI specified: ${cliTools.join(", ")}`);
|
|
2569
|
+
if (notInConfig.length > 0) {
|
|
2570
|
+
console.warn(` Tools specified but not in config: ${notInConfig.join(", ")}`);
|
|
2571
|
+
}
|
|
2572
|
+
if (notInCli.length > 0) {
|
|
2573
|
+
console.warn(` Tools in config but not specified: ${notInCli.join(", ")}`);
|
|
2574
|
+
}
|
|
2575
|
+
console.warn("\n The configuration file targets will be used.");
|
|
2576
|
+
console.warn(" To change targets, update your rulesync config file.");
|
|
2577
|
+
console.warn("");
|
|
2578
|
+
}
|
|
2579
|
+
}
|
|
2580
|
+
let baseDirs;
|
|
2581
|
+
if (config.baseDir) {
|
|
2582
|
+
baseDirs = Array.isArray(config.baseDir) ? config.baseDir : [config.baseDir];
|
|
2583
|
+
} else if (options.baseDirs) {
|
|
2584
|
+
baseDirs = options.baseDirs;
|
|
2585
|
+
} else {
|
|
2586
|
+
baseDirs = [process.cwd()];
|
|
2587
|
+
}
|
|
2588
|
+
if (config.verbose && configResult.filepath) {
|
|
2589
|
+
console.log(`Loaded configuration from: ${configResult.filepath}`);
|
|
2590
|
+
}
|
|
1823
2591
|
console.log("Generating configuration files...");
|
|
1824
2592
|
if (!await fileExists(config.aiRulesDir)) {
|
|
1825
2593
|
console.error("\u274C .rulesync directory not found. Run 'rulesync init' first.");
|
|
1826
2594
|
process.exit(1);
|
|
1827
2595
|
}
|
|
1828
2596
|
try {
|
|
1829
|
-
if (
|
|
2597
|
+
if (config.verbose) {
|
|
1830
2598
|
console.log(`Parsing rules from ${config.aiRulesDir}...`);
|
|
1831
2599
|
}
|
|
1832
2600
|
const rules = await parseRulesFromDirectory(config.aiRulesDir);
|
|
@@ -1834,18 +2602,26 @@ async function generateCommand(options = {}) {
|
|
|
1834
2602
|
console.warn("\u26A0\uFE0F No rules found in .rulesync directory");
|
|
1835
2603
|
return;
|
|
1836
2604
|
}
|
|
1837
|
-
if (
|
|
2605
|
+
if (config.verbose) {
|
|
1838
2606
|
console.log(`Found ${rules.length} rule(s)`);
|
|
1839
2607
|
console.log(`Base directories: ${baseDirs.join(", ")}`);
|
|
1840
2608
|
}
|
|
1841
|
-
if (
|
|
1842
|
-
if (
|
|
2609
|
+
if (config.delete) {
|
|
2610
|
+
if (config.verbose) {
|
|
1843
2611
|
console.log("Deleting existing output directories...");
|
|
1844
2612
|
}
|
|
1845
|
-
const targetTools =
|
|
2613
|
+
const targetTools = config.defaultTargets;
|
|
1846
2614
|
const deleteTasks = [];
|
|
1847
2615
|
for (const tool of targetTools) {
|
|
1848
2616
|
switch (tool) {
|
|
2617
|
+
case "augmentcode":
|
|
2618
|
+
deleteTasks.push(removeDirectory((0, import_node_path14.join)(".augment", "rules")));
|
|
2619
|
+
deleteTasks.push(removeDirectory((0, import_node_path14.join)(".augment", "ignore")));
|
|
2620
|
+
break;
|
|
2621
|
+
case "augmentcode-legacy":
|
|
2622
|
+
deleteTasks.push(removeClaudeGeneratedFiles());
|
|
2623
|
+
deleteTasks.push(removeDirectory((0, import_node_path14.join)(".augment", "ignore")));
|
|
2624
|
+
break;
|
|
1849
2625
|
case "copilot":
|
|
1850
2626
|
deleteTasks.push(removeDirectory(config.outputPaths.copilot));
|
|
1851
2627
|
break;
|
|
@@ -1870,19 +2646,19 @@ async function generateCommand(options = {}) {
|
|
|
1870
2646
|
}
|
|
1871
2647
|
}
|
|
1872
2648
|
await Promise.all(deleteTasks);
|
|
1873
|
-
if (
|
|
2649
|
+
if (config.verbose) {
|
|
1874
2650
|
console.log("Deleted existing output directories");
|
|
1875
2651
|
}
|
|
1876
2652
|
}
|
|
1877
2653
|
let totalOutputs = 0;
|
|
1878
2654
|
for (const baseDir of baseDirs) {
|
|
1879
|
-
if (
|
|
2655
|
+
if (config.verbose) {
|
|
1880
2656
|
console.log(`
|
|
1881
2657
|
Generating configurations for base directory: ${baseDir}`);
|
|
1882
2658
|
}
|
|
1883
|
-
const outputs = await generateConfigurations(rules, config,
|
|
2659
|
+
const outputs = await generateConfigurations(rules, config, config.defaultTargets, baseDir);
|
|
1884
2660
|
if (outputs.length === 0) {
|
|
1885
|
-
if (
|
|
2661
|
+
if (config.verbose) {
|
|
1886
2662
|
console.warn(`\u26A0\uFE0F No configurations generated for ${baseDir}`);
|
|
1887
2663
|
}
|
|
1888
2664
|
continue;
|
|
@@ -1897,17 +2673,18 @@ Generating configurations for base directory: ${baseDir}`);
|
|
|
1897
2673
|
console.warn("\u26A0\uFE0F No configurations generated");
|
|
1898
2674
|
return;
|
|
1899
2675
|
}
|
|
1900
|
-
if (
|
|
2676
|
+
if (config.verbose) {
|
|
1901
2677
|
console.log("\nGenerating MCP configurations...");
|
|
1902
2678
|
}
|
|
1903
2679
|
let totalMcpOutputs = 0;
|
|
1904
2680
|
for (const baseDir of baseDirs) {
|
|
1905
2681
|
const mcpResults = await generateMcpConfigs(
|
|
1906
2682
|
process.cwd(),
|
|
1907
|
-
baseDir === process.cwd() ? void 0 : baseDir
|
|
2683
|
+
baseDir === process.cwd() ? void 0 : baseDir,
|
|
2684
|
+
config.defaultTargets
|
|
1908
2685
|
);
|
|
1909
2686
|
if (mcpResults.length === 0) {
|
|
1910
|
-
if (
|
|
2687
|
+
if (config.verbose) {
|
|
1911
2688
|
console.log(`No MCP configuration found for ${baseDir}`);
|
|
1912
2689
|
}
|
|
1913
2690
|
continue;
|
|
@@ -1918,7 +2695,7 @@ Generating configurations for base directory: ${baseDir}`);
|
|
|
1918
2695
|
totalMcpOutputs++;
|
|
1919
2696
|
} else if (result.status === "error") {
|
|
1920
2697
|
console.error(`\u274C Failed to generate ${result.tool} MCP configuration: ${result.error}`);
|
|
1921
|
-
} else if (
|
|
2698
|
+
} else if (config.verbose && result.status === "skipped") {
|
|
1922
2699
|
console.log(`\u23ED\uFE0F Skipped ${result.tool} MCP configuration (no servers configured)`);
|
|
1923
2700
|
}
|
|
1924
2701
|
}
|
|
@@ -1937,10 +2714,10 @@ Generating configurations for base directory: ${baseDir}`);
|
|
|
1937
2714
|
}
|
|
1938
2715
|
|
|
1939
2716
|
// src/cli/commands/gitignore.ts
|
|
1940
|
-
var
|
|
1941
|
-
var
|
|
2717
|
+
var import_node_fs2 = require("fs");
|
|
2718
|
+
var import_node_path15 = require("path");
|
|
1942
2719
|
var gitignoreCommand = async () => {
|
|
1943
|
-
const gitignorePath = (0,
|
|
2720
|
+
const gitignorePath = (0, import_node_path15.join)(process.cwd(), ".gitignore");
|
|
1944
2721
|
const rulesFilesToIgnore = [
|
|
1945
2722
|
"# Generated by rulesync - AI tool configuration files",
|
|
1946
2723
|
"**/.github/copilot-instructions.md",
|
|
@@ -1962,6 +2739,8 @@ var gitignoreCommand = async () => {
|
|
|
1962
2739
|
"**/.kiro/steering/",
|
|
1963
2740
|
"**/.augment/rules/",
|
|
1964
2741
|
"**/.augment-guidelines",
|
|
2742
|
+
"**/.junie/guidelines.md",
|
|
2743
|
+
"**/.noai",
|
|
1965
2744
|
"**/.mcp.json",
|
|
1966
2745
|
"!.rulesync/.mcp.json",
|
|
1967
2746
|
"**/.cursor/mcp.json",
|
|
@@ -1971,8 +2750,8 @@ var gitignoreCommand = async () => {
|
|
|
1971
2750
|
"**/.roo/mcp.json"
|
|
1972
2751
|
];
|
|
1973
2752
|
let gitignoreContent = "";
|
|
1974
|
-
if ((0,
|
|
1975
|
-
gitignoreContent = (0,
|
|
2753
|
+
if ((0, import_node_fs2.existsSync)(gitignorePath)) {
|
|
2754
|
+
gitignoreContent = (0, import_node_fs2.readFileSync)(gitignorePath, "utf-8");
|
|
1976
2755
|
}
|
|
1977
2756
|
const linesToAdd = [];
|
|
1978
2757
|
for (const rule of rulesFilesToIgnore) {
|
|
@@ -1989,7 +2768,7 @@ var gitignoreCommand = async () => {
|
|
|
1989
2768
|
${linesToAdd.join("\n")}
|
|
1990
2769
|
` : `${linesToAdd.join("\n")}
|
|
1991
2770
|
`;
|
|
1992
|
-
(0,
|
|
2771
|
+
(0, import_node_fs2.writeFileSync)(gitignorePath, newContent);
|
|
1993
2772
|
console.log(`\u2705 Added ${linesToAdd.length} rules to .gitignore:`);
|
|
1994
2773
|
for (const line of linesToAdd) {
|
|
1995
2774
|
if (!line.startsWith("#")) {
|
|
@@ -1999,11 +2778,11 @@ ${linesToAdd.join("\n")}
|
|
|
1999
2778
|
};
|
|
2000
2779
|
|
|
2001
2780
|
// src/core/importer.ts
|
|
2002
|
-
var
|
|
2781
|
+
var import_node_path21 = require("path");
|
|
2003
2782
|
var import_gray_matter5 = __toESM(require("gray-matter"), 1);
|
|
2004
2783
|
|
|
2005
2784
|
// src/parsers/augmentcode.ts
|
|
2006
|
-
var
|
|
2785
|
+
var import_node_path16 = require("path");
|
|
2007
2786
|
var import_gray_matter2 = __toESM(require("gray-matter"), 1);
|
|
2008
2787
|
|
|
2009
2788
|
// src/utils/parser-helpers.ts
|
|
@@ -2044,7 +2823,7 @@ async function safeReadFile(operation, errorContext) {
|
|
|
2044
2823
|
// src/parsers/augmentcode.ts
|
|
2045
2824
|
async function parseAugmentcodeConfiguration(baseDir = process.cwd()) {
|
|
2046
2825
|
const result = createParseResult();
|
|
2047
|
-
const rulesDir = (0,
|
|
2826
|
+
const rulesDir = (0, import_node_path16.join)(baseDir, ".augment", "rules");
|
|
2048
2827
|
if (await fileExists(rulesDir)) {
|
|
2049
2828
|
const rulesResult = await parseAugmentRules(rulesDir);
|
|
2050
2829
|
addRules(result, rulesResult.rules);
|
|
@@ -2062,7 +2841,7 @@ async function parseAugmentRules(rulesDir) {
|
|
|
2062
2841
|
const files = await readdir2(rulesDir);
|
|
2063
2842
|
for (const file of files) {
|
|
2064
2843
|
if (file.endsWith(".md") || file.endsWith(".mdc")) {
|
|
2065
|
-
const filePath = (0,
|
|
2844
|
+
const filePath = (0, import_node_path16.join)(rulesDir, file);
|
|
2066
2845
|
try {
|
|
2067
2846
|
const rawContent = await readFileContent(filePath);
|
|
2068
2847
|
const parsed = (0, import_gray_matter2.default)(rawContent);
|
|
@@ -2071,7 +2850,7 @@ async function parseAugmentRules(rulesDir) {
|
|
|
2071
2850
|
const description = frontmatterData.description || "";
|
|
2072
2851
|
const tags = Array.isArray(frontmatterData.tags) ? frontmatterData.tags : void 0;
|
|
2073
2852
|
const isRoot = ruleType === "always";
|
|
2074
|
-
const filename = (0,
|
|
2853
|
+
const filename = (0, import_node_path16.basename)(file, file.endsWith(".mdc") ? ".mdc" : ".md");
|
|
2075
2854
|
const frontmatter = {
|
|
2076
2855
|
root: isRoot,
|
|
2077
2856
|
targets: ["augmentcode"],
|
|
@@ -2100,10 +2879,10 @@ async function parseAugmentRules(rulesDir) {
|
|
|
2100
2879
|
}
|
|
2101
2880
|
|
|
2102
2881
|
// src/parsers/augmentcode-legacy.ts
|
|
2103
|
-
var
|
|
2882
|
+
var import_node_path17 = require("path");
|
|
2104
2883
|
async function parseAugmentcodeLegacyConfiguration(baseDir = process.cwd()) {
|
|
2105
2884
|
const result = createParseResult();
|
|
2106
|
-
const guidelinesPath = (0,
|
|
2885
|
+
const guidelinesPath = (0, import_node_path17.join)(baseDir, ".augment-guidelines");
|
|
2107
2886
|
if (await fileExists(guidelinesPath)) {
|
|
2108
2887
|
const guidelinesResult = await parseAugmentGuidelines(guidelinesPath);
|
|
2109
2888
|
if (guidelinesResult.rule) {
|
|
@@ -2146,13 +2925,13 @@ async function parseAugmentGuidelines(guidelinesPath) {
|
|
|
2146
2925
|
}
|
|
2147
2926
|
|
|
2148
2927
|
// src/parsers/shared-helpers.ts
|
|
2149
|
-
var
|
|
2928
|
+
var import_node_path18 = require("path");
|
|
2150
2929
|
var import_gray_matter3 = __toESM(require("gray-matter"), 1);
|
|
2151
2930
|
async function parseConfigurationFiles(baseDir = process.cwd(), config) {
|
|
2152
2931
|
const errors = [];
|
|
2153
2932
|
const rules = [];
|
|
2154
2933
|
if (config.mainFile) {
|
|
2155
|
-
const mainFilePath = (0,
|
|
2934
|
+
const mainFilePath = (0, import_node_path18.join)(baseDir, config.mainFile.path);
|
|
2156
2935
|
if (await fileExists(mainFilePath)) {
|
|
2157
2936
|
try {
|
|
2158
2937
|
const rawContent = await readFileContent(mainFilePath);
|
|
@@ -2192,14 +2971,14 @@ async function parseConfigurationFiles(baseDir = process.cwd(), config) {
|
|
|
2192
2971
|
}
|
|
2193
2972
|
if (config.directories) {
|
|
2194
2973
|
for (const dirConfig of config.directories) {
|
|
2195
|
-
const dirPath = (0,
|
|
2974
|
+
const dirPath = (0, import_node_path18.join)(baseDir, dirConfig.directory);
|
|
2196
2975
|
if (await fileExists(dirPath)) {
|
|
2197
2976
|
try {
|
|
2198
2977
|
const { readdir: readdir2 } = await import("fs/promises");
|
|
2199
2978
|
const files = await readdir2(dirPath);
|
|
2200
2979
|
for (const file of files) {
|
|
2201
2980
|
if (file.endsWith(dirConfig.filePattern)) {
|
|
2202
|
-
const filePath = (0,
|
|
2981
|
+
const filePath = (0, import_node_path18.join)(dirPath, file);
|
|
2203
2982
|
try {
|
|
2204
2983
|
const rawContent = await readFileContent(filePath);
|
|
2205
2984
|
let content;
|
|
@@ -2247,7 +3026,7 @@ async function parseMemoryBasedConfiguration(baseDir = process.cwd(), config) {
|
|
|
2247
3026
|
const rules = [];
|
|
2248
3027
|
let ignorePatterns;
|
|
2249
3028
|
let mcpServers;
|
|
2250
|
-
const mainFilePath = (0,
|
|
3029
|
+
const mainFilePath = (0, import_node_path18.join)(baseDir, config.mainFileName);
|
|
2251
3030
|
if (!await fileExists(mainFilePath)) {
|
|
2252
3031
|
errors.push(`${config.mainFileName} file not found`);
|
|
2253
3032
|
return { rules, errors };
|
|
@@ -2258,12 +3037,12 @@ async function parseMemoryBasedConfiguration(baseDir = process.cwd(), config) {
|
|
|
2258
3037
|
if (mainRule) {
|
|
2259
3038
|
rules.push(mainRule);
|
|
2260
3039
|
}
|
|
2261
|
-
const memoryDir = (0,
|
|
3040
|
+
const memoryDir = (0, import_node_path18.join)(baseDir, config.memoryDirPath);
|
|
2262
3041
|
if (await fileExists(memoryDir)) {
|
|
2263
3042
|
const memoryRules = await parseMemoryFiles(memoryDir, config);
|
|
2264
3043
|
rules.push(...memoryRules);
|
|
2265
3044
|
}
|
|
2266
|
-
const settingsPath = (0,
|
|
3045
|
+
const settingsPath = (0, import_node_path18.join)(baseDir, config.settingsPath);
|
|
2267
3046
|
if (await fileExists(settingsPath)) {
|
|
2268
3047
|
const settingsResult = await parseSettingsFile(settingsPath, config.tool);
|
|
2269
3048
|
if (settingsResult.ignorePatterns) {
|
|
@@ -2275,7 +3054,7 @@ async function parseMemoryBasedConfiguration(baseDir = process.cwd(), config) {
|
|
|
2275
3054
|
errors.push(...settingsResult.errors);
|
|
2276
3055
|
}
|
|
2277
3056
|
if (config.additionalIgnoreFile) {
|
|
2278
|
-
const additionalIgnorePath = (0,
|
|
3057
|
+
const additionalIgnorePath = (0, import_node_path18.join)(baseDir, config.additionalIgnoreFile.path);
|
|
2279
3058
|
if (await fileExists(additionalIgnorePath)) {
|
|
2280
3059
|
const additionalPatterns = await config.additionalIgnoreFile.parser(additionalIgnorePath);
|
|
2281
3060
|
if (additionalPatterns.length > 0) {
|
|
@@ -2329,10 +3108,10 @@ async function parseMemoryFiles(memoryDir, config) {
|
|
|
2329
3108
|
const files = await readdir2(memoryDir);
|
|
2330
3109
|
for (const file of files) {
|
|
2331
3110
|
if (file.endsWith(".md")) {
|
|
2332
|
-
const filePath = (0,
|
|
3111
|
+
const filePath = (0, import_node_path18.join)(memoryDir, file);
|
|
2333
3112
|
const content = await readFileContent(filePath);
|
|
2334
3113
|
if (content.trim()) {
|
|
2335
|
-
const filename = (0,
|
|
3114
|
+
const filename = (0, import_node_path18.basename)(file, ".md");
|
|
2336
3115
|
const frontmatter = {
|
|
2337
3116
|
root: false,
|
|
2338
3117
|
targets: [config.tool],
|
|
@@ -2445,10 +3224,10 @@ async function parseCopilotConfiguration(baseDir = process.cwd()) {
|
|
|
2445
3224
|
}
|
|
2446
3225
|
|
|
2447
3226
|
// src/parsers/cursor.ts
|
|
2448
|
-
var
|
|
3227
|
+
var import_node_path19 = require("path");
|
|
2449
3228
|
var import_gray_matter4 = __toESM(require("gray-matter"), 1);
|
|
2450
3229
|
var import_js_yaml = require("js-yaml");
|
|
2451
|
-
var
|
|
3230
|
+
var import_mini7 = require("zod/mini");
|
|
2452
3231
|
var customMatterOptions = {
|
|
2453
3232
|
engines: {
|
|
2454
3233
|
yaml: {
|
|
@@ -2476,7 +3255,7 @@ var customMatterOptions = {
|
|
|
2476
3255
|
}
|
|
2477
3256
|
};
|
|
2478
3257
|
function convertCursorMdcFrontmatter(cursorFrontmatter, _filename) {
|
|
2479
|
-
const FrontmatterSchema =
|
|
3258
|
+
const FrontmatterSchema = import_mini7.z.record(import_mini7.z.string(), import_mini7.z.unknown());
|
|
2480
3259
|
const parseResult = FrontmatterSchema.safeParse(cursorFrontmatter);
|
|
2481
3260
|
if (!parseResult.success) {
|
|
2482
3261
|
return {
|
|
@@ -2570,7 +3349,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
2570
3349
|
const rules = [];
|
|
2571
3350
|
let ignorePatterns;
|
|
2572
3351
|
let mcpServers;
|
|
2573
|
-
const cursorFilePath = (0,
|
|
3352
|
+
const cursorFilePath = (0, import_node_path19.join)(baseDir, ".cursorrules");
|
|
2574
3353
|
if (await fileExists(cursorFilePath)) {
|
|
2575
3354
|
try {
|
|
2576
3355
|
const rawContent = await readFileContent(cursorFilePath);
|
|
@@ -2591,20 +3370,20 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
2591
3370
|
errors.push(`Failed to parse .cursorrules file: ${errorMessage}`);
|
|
2592
3371
|
}
|
|
2593
3372
|
}
|
|
2594
|
-
const cursorRulesDir = (0,
|
|
3373
|
+
const cursorRulesDir = (0, import_node_path19.join)(baseDir, ".cursor", "rules");
|
|
2595
3374
|
if (await fileExists(cursorRulesDir)) {
|
|
2596
3375
|
try {
|
|
2597
3376
|
const { readdir: readdir2 } = await import("fs/promises");
|
|
2598
3377
|
const files = await readdir2(cursorRulesDir);
|
|
2599
3378
|
for (const file of files) {
|
|
2600
3379
|
if (file.endsWith(".mdc")) {
|
|
2601
|
-
const filePath = (0,
|
|
3380
|
+
const filePath = (0, import_node_path19.join)(cursorRulesDir, file);
|
|
2602
3381
|
try {
|
|
2603
3382
|
const rawContent = await readFileContent(filePath);
|
|
2604
3383
|
const parsed = (0, import_gray_matter4.default)(rawContent, customMatterOptions);
|
|
2605
3384
|
const content = parsed.content.trim();
|
|
2606
3385
|
if (content) {
|
|
2607
|
-
const filename = (0,
|
|
3386
|
+
const filename = (0, import_node_path19.basename)(file, ".mdc");
|
|
2608
3387
|
const frontmatter = convertCursorMdcFrontmatter(parsed.data, filename);
|
|
2609
3388
|
rules.push({
|
|
2610
3389
|
frontmatter,
|
|
@@ -2627,7 +3406,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
2627
3406
|
if (rules.length === 0) {
|
|
2628
3407
|
errors.push("No Cursor configuration files found (.cursorrules or .cursor/rules/*.mdc)");
|
|
2629
3408
|
}
|
|
2630
|
-
const cursorIgnorePath = (0,
|
|
3409
|
+
const cursorIgnorePath = (0, import_node_path19.join)(baseDir, ".cursorignore");
|
|
2631
3410
|
if (await fileExists(cursorIgnorePath)) {
|
|
2632
3411
|
try {
|
|
2633
3412
|
const content = await readFileContent(cursorIgnorePath);
|
|
@@ -2640,7 +3419,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
2640
3419
|
errors.push(`Failed to parse .cursorignore: ${errorMessage}`);
|
|
2641
3420
|
}
|
|
2642
3421
|
}
|
|
2643
|
-
const cursorMcpPath = (0,
|
|
3422
|
+
const cursorMcpPath = (0, import_node_path19.join)(baseDir, ".cursor", "mcp.json");
|
|
2644
3423
|
if (await fileExists(cursorMcpPath)) {
|
|
2645
3424
|
try {
|
|
2646
3425
|
const content = await readFileContent(cursorMcpPath);
|
|
@@ -2688,6 +3467,42 @@ async function parseGeminiConfiguration(baseDir = process.cwd()) {
|
|
|
2688
3467
|
});
|
|
2689
3468
|
}
|
|
2690
3469
|
|
|
3470
|
+
// src/parsers/junie.ts
|
|
3471
|
+
var import_node_path20 = require("path");
|
|
3472
|
+
async function parseJunieConfiguration(baseDir = process.cwd()) {
|
|
3473
|
+
const errors = [];
|
|
3474
|
+
const rules = [];
|
|
3475
|
+
const guidelinesPath = (0, import_node_path20.join)(baseDir, ".junie", "guidelines.md");
|
|
3476
|
+
if (!await fileExists(guidelinesPath)) {
|
|
3477
|
+
errors.push(".junie/guidelines.md file not found");
|
|
3478
|
+
return { rules, errors };
|
|
3479
|
+
}
|
|
3480
|
+
try {
|
|
3481
|
+
const content = await readFileContent(guidelinesPath);
|
|
3482
|
+
if (content.trim()) {
|
|
3483
|
+
const frontmatter = {
|
|
3484
|
+
root: false,
|
|
3485
|
+
targets: ["junie"],
|
|
3486
|
+
description: "Junie project guidelines",
|
|
3487
|
+
globs: ["**/*"]
|
|
3488
|
+
};
|
|
3489
|
+
rules.push({
|
|
3490
|
+
frontmatter,
|
|
3491
|
+
content: content.trim(),
|
|
3492
|
+
filename: "junie-guidelines",
|
|
3493
|
+
filepath: guidelinesPath
|
|
3494
|
+
});
|
|
3495
|
+
}
|
|
3496
|
+
} catch (error) {
|
|
3497
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3498
|
+
errors.push(`Failed to parse .junie/guidelines.md: ${errorMessage}`);
|
|
3499
|
+
}
|
|
3500
|
+
if (rules.length === 0) {
|
|
3501
|
+
errors.push("No valid Junie configuration found");
|
|
3502
|
+
}
|
|
3503
|
+
return { rules, errors };
|
|
3504
|
+
}
|
|
3505
|
+
|
|
2691
3506
|
// src/parsers/roo.ts
|
|
2692
3507
|
async function parseRooConfiguration(baseDir = process.cwd()) {
|
|
2693
3508
|
return parseConfigurationFiles(baseDir, {
|
|
@@ -2774,6 +3589,12 @@ async function importConfiguration(options) {
|
|
|
2774
3589
|
mcpServers = geminiResult.mcpServers;
|
|
2775
3590
|
break;
|
|
2776
3591
|
}
|
|
3592
|
+
case "junie": {
|
|
3593
|
+
const junieResult = await parseJunieConfiguration(baseDir);
|
|
3594
|
+
rules = junieResult.rules;
|
|
3595
|
+
errors.push(...junieResult.errors);
|
|
3596
|
+
break;
|
|
3597
|
+
}
|
|
2777
3598
|
default:
|
|
2778
3599
|
errors.push(`Unsupported tool: ${tool}`);
|
|
2779
3600
|
return { success: false, rulesCreated: 0, errors };
|
|
@@ -2786,7 +3607,7 @@ async function importConfiguration(options) {
|
|
|
2786
3607
|
if (rules.length === 0 && !ignorePatterns && !mcpServers) {
|
|
2787
3608
|
return { success: false, rulesCreated: 0, errors };
|
|
2788
3609
|
}
|
|
2789
|
-
const rulesDirPath = (0,
|
|
3610
|
+
const rulesDirPath = (0, import_node_path21.join)(baseDir, rulesDir);
|
|
2790
3611
|
try {
|
|
2791
3612
|
const { mkdir: mkdir3 } = await import("fs/promises");
|
|
2792
3613
|
await mkdir3(rulesDirPath, { recursive: true });
|
|
@@ -2800,7 +3621,7 @@ async function importConfiguration(options) {
|
|
|
2800
3621
|
try {
|
|
2801
3622
|
const baseFilename = `${tool}__${rule.filename}`;
|
|
2802
3623
|
const filename = await generateUniqueFilename(rulesDirPath, baseFilename);
|
|
2803
|
-
const filePath = (0,
|
|
3624
|
+
const filePath = (0, import_node_path21.join)(rulesDirPath, `${filename}.md`);
|
|
2804
3625
|
const content = generateRuleFileContent(rule);
|
|
2805
3626
|
await writeFileContent(filePath, content);
|
|
2806
3627
|
rulesCreated++;
|
|
@@ -2815,7 +3636,7 @@ async function importConfiguration(options) {
|
|
|
2815
3636
|
let ignoreFileCreated = false;
|
|
2816
3637
|
if (ignorePatterns && ignorePatterns.length > 0) {
|
|
2817
3638
|
try {
|
|
2818
|
-
const rulesyncignorePath = (0,
|
|
3639
|
+
const rulesyncignorePath = (0, import_node_path21.join)(baseDir, ".rulesyncignore");
|
|
2819
3640
|
const ignoreContent = `${ignorePatterns.join("\n")}
|
|
2820
3641
|
`;
|
|
2821
3642
|
await writeFileContent(rulesyncignorePath, ignoreContent);
|
|
@@ -2831,7 +3652,7 @@ async function importConfiguration(options) {
|
|
|
2831
3652
|
let mcpFileCreated = false;
|
|
2832
3653
|
if (mcpServers && Object.keys(mcpServers).length > 0) {
|
|
2833
3654
|
try {
|
|
2834
|
-
const mcpPath = (0,
|
|
3655
|
+
const mcpPath = (0, import_node_path21.join)(baseDir, rulesDir, ".mcp.json");
|
|
2835
3656
|
const mcpContent = `${JSON.stringify({ mcpServers }, null, 2)}
|
|
2836
3657
|
`;
|
|
2837
3658
|
await writeFileContent(mcpPath, mcpContent);
|
|
@@ -2859,7 +3680,7 @@ function generateRuleFileContent(rule) {
|
|
|
2859
3680
|
async function generateUniqueFilename(rulesDir, baseFilename) {
|
|
2860
3681
|
let filename = baseFilename;
|
|
2861
3682
|
let counter = 1;
|
|
2862
|
-
while (await fileExists((0,
|
|
3683
|
+
while (await fileExists((0, import_node_path21.join)(rulesDir, `${filename}.md`))) {
|
|
2863
3684
|
filename = `${baseFilename}-${counter}`;
|
|
2864
3685
|
counter++;
|
|
2865
3686
|
}
|
|
@@ -2870,7 +3691,7 @@ async function generateUniqueFilename(rulesDir, baseFilename) {
|
|
|
2870
3691
|
async function importCommand(options = {}) {
|
|
2871
3692
|
const tools = [];
|
|
2872
3693
|
if (options.augmentcode) tools.push("augmentcode");
|
|
2873
|
-
if (options
|
|
3694
|
+
if (options["augmentcode-legacy"]) tools.push("augmentcode-legacy");
|
|
2874
3695
|
if (options.claudecode) tools.push("claudecode");
|
|
2875
3696
|
if (options.cursor) tools.push("cursor");
|
|
2876
3697
|
if (options.copilot) tools.push("copilot");
|
|
@@ -2879,7 +3700,7 @@ async function importCommand(options = {}) {
|
|
|
2879
3700
|
if (options.geminicli) tools.push("geminicli");
|
|
2880
3701
|
if (tools.length === 0) {
|
|
2881
3702
|
console.error(
|
|
2882
|
-
"\u274C Please specify one tool to import from (--augmentcode, --
|
|
3703
|
+
"\u274C Please specify one tool to import from (--augmentcode, --augmentcode-legacy, --claudecode, --cursor, --copilot, --cline, --roo, --geminicli)"
|
|
2883
3704
|
);
|
|
2884
3705
|
process.exit(1);
|
|
2885
3706
|
}
|
|
@@ -2926,7 +3747,7 @@ async function importCommand(options = {}) {
|
|
|
2926
3747
|
}
|
|
2927
3748
|
|
|
2928
3749
|
// src/cli/commands/init.ts
|
|
2929
|
-
var
|
|
3750
|
+
var import_node_path22 = require("path");
|
|
2930
3751
|
async function initCommand() {
|
|
2931
3752
|
const aiRulesDir = ".rulesync";
|
|
2932
3753
|
console.log("Initializing rulesync...");
|
|
@@ -2973,7 +3794,7 @@ globs: ["**/*"]
|
|
|
2973
3794
|
- Follow single responsibility principle
|
|
2974
3795
|
`
|
|
2975
3796
|
};
|
|
2976
|
-
const filepath = (0,
|
|
3797
|
+
const filepath = (0, import_node_path22.join)(aiRulesDir, sampleFile.filename);
|
|
2977
3798
|
if (!await fileExists(filepath)) {
|
|
2978
3799
|
await writeFileContent(filepath, sampleFile.content);
|
|
2979
3800
|
console.log(`Created ${filepath}`);
|
|
@@ -3087,11 +3908,11 @@ async function watchCommand() {
|
|
|
3087
3908
|
persistent: true
|
|
3088
3909
|
});
|
|
3089
3910
|
let isGenerating = false;
|
|
3090
|
-
const handleChange = async (
|
|
3911
|
+
const handleChange = async (path5) => {
|
|
3091
3912
|
if (isGenerating) return;
|
|
3092
3913
|
isGenerating = true;
|
|
3093
3914
|
console.log(`
|
|
3094
|
-
\u{1F4DD} Detected change in ${
|
|
3915
|
+
\u{1F4DD} Detected change in ${path5}`);
|
|
3095
3916
|
try {
|
|
3096
3917
|
await generateCommand({ verbose: false });
|
|
3097
3918
|
console.log("\u2705 Regenerated configuration files");
|
|
@@ -3101,10 +3922,10 @@ async function watchCommand() {
|
|
|
3101
3922
|
isGenerating = false;
|
|
3102
3923
|
}
|
|
3103
3924
|
};
|
|
3104
|
-
watcher.on("change", handleChange).on("add", handleChange).on("unlink", (
|
|
3925
|
+
watcher.on("change", handleChange).on("add", handleChange).on("unlink", (path5) => {
|
|
3105
3926
|
console.log(`
|
|
3106
|
-
\u{1F5D1}\uFE0F Removed ${
|
|
3107
|
-
handleChange(
|
|
3927
|
+
\u{1F5D1}\uFE0F Removed ${path5}`);
|
|
3928
|
+
handleChange(path5);
|
|
3108
3929
|
}).on("error", (error) => {
|
|
3109
3930
|
console.error("\u274C Watcher error:", error);
|
|
3110
3931
|
});
|
|
@@ -3117,28 +3938,31 @@ async function watchCommand() {
|
|
|
3117
3938
|
|
|
3118
3939
|
// src/cli/index.ts
|
|
3119
3940
|
var program = new import_commander.Command();
|
|
3120
|
-
program.name("rulesync").description("Unified AI rules management CLI tool").version("0.
|
|
3941
|
+
program.name("rulesync").description("Unified AI rules management CLI tool").version("0.51.0");
|
|
3121
3942
|
program.command("init").description("Initialize rulesync in current directory").action(initCommand);
|
|
3122
3943
|
program.command("add <filename>").description("Add a new rule file").action(addCommand);
|
|
3123
3944
|
program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);
|
|
3124
|
-
program.command("import").description("Import configurations from AI tools to rulesync format").option("--augmentcode", "Import from AugmentCode (.augment/rules/)").option("--
|
|
3125
|
-
program.command("generate").description("Generate configuration files for AI tools").option("--augmentcode", "Generate only for AugmentCode").option("--
|
|
3945
|
+
program.command("import").description("Import configurations from AI tools to rulesync format").option("--augmentcode", "Import from AugmentCode (.augment/rules/)").option("--augmentcode-legacy", "Import from AugmentCode legacy format (.augment-guidelines)").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("--junie", "Import from JetBrains Junie (.junie/guidelines.md)").option("-v, --verbose", "Verbose output").action(importCommand);
|
|
3946
|
+
program.command("generate").description("Generate configuration files for AI tools").option("--augmentcode", "Generate only for AugmentCode").option("--augmentcode-legacy", "Generate only for AugmentCode legacy format").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("--junie", "Generate only for JetBrains Junie").option("--kiro", "Generate only for Kiro IDE").option("--delete", "Delete all existing files in output directories before generating").option(
|
|
3126
3947
|
"-b, --base-dir <paths>",
|
|
3127
3948
|
"Base directories to generate files (comma-separated for multiple paths)"
|
|
3128
|
-
).option("-v, --verbose", "Verbose output").action(async (options) => {
|
|
3949
|
+
).option("-v, --verbose", "Verbose output").option("-c, --config <path>", "Path to configuration file").option("--no-config", "Disable configuration file loading").action(async (options) => {
|
|
3129
3950
|
const tools = [];
|
|
3130
3951
|
if (options.augmentcode) tools.push("augmentcode");
|
|
3131
|
-
if (options
|
|
3952
|
+
if (options["augmentcode-legacy"]) tools.push("augmentcode-legacy");
|
|
3132
3953
|
if (options.copilot) tools.push("copilot");
|
|
3133
3954
|
if (options.cursor) tools.push("cursor");
|
|
3134
3955
|
if (options.cline) tools.push("cline");
|
|
3135
3956
|
if (options.claudecode) tools.push("claudecode");
|
|
3136
3957
|
if (options.roo) tools.push("roo");
|
|
3137
3958
|
if (options.geminicli) tools.push("geminicli");
|
|
3959
|
+
if (options.junie) tools.push("junie");
|
|
3138
3960
|
if (options.kiro) tools.push("kiro");
|
|
3139
3961
|
const generateOptions = {
|
|
3140
3962
|
verbose: options.verbose,
|
|
3141
|
-
delete: options.delete
|
|
3963
|
+
delete: options.delete,
|
|
3964
|
+
config: options.config,
|
|
3965
|
+
noConfig: options.noConfig
|
|
3142
3966
|
};
|
|
3143
3967
|
if (tools.length > 0) {
|
|
3144
3968
|
generateOptions.tools = tools;
|
|
@@ -3151,4 +3975,5 @@ program.command("generate").description("Generate configuration files for AI too
|
|
|
3151
3975
|
program.command("validate").description("Validate rulesync configuration").action(validateCommand);
|
|
3152
3976
|
program.command("status").description("Show current status of rulesync").action(statusCommand);
|
|
3153
3977
|
program.command("watch").description("Watch for changes and auto-generate configurations").action(watchCommand);
|
|
3978
|
+
program.command("config").description("Show or initialize rulesync configuration").option("--init", "Initialize a new configuration file").option("--format <format>", "Configuration file format (jsonc, ts)", "jsonc").option("--targets <tools>", "Comma-separated list of tools to generate for").option("--exclude <tools>", "Comma-separated list of tools to exclude").option("--ai-rules-dir <dir>", "Directory containing AI rule files").option("--base-dir <path>", "Base directory for generation").option("--verbose", "Enable verbose output").option("--delete", "Delete existing files before generating").action(configCommand);
|
|
3154
3979
|
program.parse();
|