rulesync 0.48.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 +8 -2
- package/README.md +95 -2
- package/dist/augmentcode-ICLQ2NEZ.js +9 -0
- package/dist/{chunk-OTCCHS7Q.js → chunk-4MZXYV5H.js} +1 -1
- package/dist/{chunk-BY6RI77W.js → chunk-AREA26HF.js} +1 -1
- package/dist/{chunk-L2JTXZZB.js → chunk-FFW6TGCM.js} +1 -1
- package/dist/{chunk-JWN6GRG6.js → chunk-IXCMY24P.js} +1 -1
- package/dist/chunk-OPZOVKIL.js +111 -0
- package/dist/{chunk-D365OP7N.js → chunk-QUJMXHNR.js} +1 -1
- package/dist/{chunk-7UVBAWYG.js → chunk-TTHBLXOB.js} +1 -1
- package/dist/{chunk-7ZIUEZZQ.js → chunk-USKQYIZ2.js} +13 -3
- package/dist/chunk-Y26DXTAT.js +90 -0
- package/dist/{chunk-P6KQZULZ.js → chunk-Y2XH4E5R.js} +1 -1
- package/dist/{claudecode-Y3GIXDUN.js → claudecode-SRXYHIJE.js} +2 -2
- package/dist/{cline-NS3OPXM2.js → cline-IJW27CUU.js} +2 -2
- package/dist/{copilot-QN2SC7Y2.js → copilot-ARYIWVJ7.js} +2 -2
- package/dist/{cursor-DV2IS7JF.js → cursor-FCS74IAH.js} +2 -2
- package/dist/{geminicli-MRYTLT2T.js → geminicli-VOPV6DXZ.js} +2 -2
- package/dist/index.cjs +2018 -829
- package/dist/index.js +1904 -827
- package/dist/junie-A2Y2WZI4.js +9 -0
- package/dist/{kiro-S5TSM7VW.js → kiro-MHIK4UBV.js} +2 -2
- package/dist/{roo-NWLD3YYN.js → roo-VG4IUNTE.js} +2 -2
- package/package.json +17 -16
package/dist/index.cjs
CHANGED
|
@@ -27,20 +27,28 @@ 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 = [
|
|
40
|
+
"augmentcode",
|
|
41
|
+
"augmentcode-legacy",
|
|
36
42
|
"copilot",
|
|
37
43
|
"cursor",
|
|
38
44
|
"cline",
|
|
39
45
|
"claudecode",
|
|
40
46
|
"roo",
|
|
41
47
|
"geminicli",
|
|
42
|
-
"kiro"
|
|
43
|
-
|
|
48
|
+
"kiro",
|
|
49
|
+
"junie"
|
|
50
|
+
];
|
|
51
|
+
ToolTargetSchema = import_mini.z.enum(ALL_TOOL_TARGETS);
|
|
44
52
|
ToolTargetsSchema = import_mini.z.array(ToolTargetSchema);
|
|
45
53
|
WildcardTargetSchema = import_mini.z.tuple([import_mini.z.literal("*")]);
|
|
46
54
|
RulesyncTargetsSchema = import_mini.z.union([ToolTargetsSchema, WildcardTargetSchema]);
|
|
@@ -71,6 +79,63 @@ var init_mcp_helpers = __esm({
|
|
|
71
79
|
}
|
|
72
80
|
});
|
|
73
81
|
|
|
82
|
+
// src/generators/mcp/augmentcode.ts
|
|
83
|
+
function generateAugmentcodeMcp(config) {
|
|
84
|
+
const augmentSettings = {
|
|
85
|
+
mcpServers: []
|
|
86
|
+
};
|
|
87
|
+
const shouldInclude = (server) => {
|
|
88
|
+
return shouldIncludeServer(server, "augmentcode");
|
|
89
|
+
};
|
|
90
|
+
for (const [serverName, server] of Object.entries(config.mcpServers)) {
|
|
91
|
+
if (!shouldInclude(server)) continue;
|
|
92
|
+
const augmentServer = {
|
|
93
|
+
name: serverName
|
|
94
|
+
};
|
|
95
|
+
if (server.command) {
|
|
96
|
+
augmentServer.command = server.command;
|
|
97
|
+
if (server.args) {
|
|
98
|
+
augmentServer.args = server.args;
|
|
99
|
+
}
|
|
100
|
+
} else if (server.url || server.httpUrl) {
|
|
101
|
+
const url = server.httpUrl || server.url;
|
|
102
|
+
if (url) {
|
|
103
|
+
augmentServer.url = url;
|
|
104
|
+
}
|
|
105
|
+
if (server.httpUrl || server.transport === "http") {
|
|
106
|
+
augmentServer.transport = "http";
|
|
107
|
+
} else if (server.transport === "sse") {
|
|
108
|
+
augmentServer.transport = "sse";
|
|
109
|
+
}
|
|
110
|
+
if (server.env) {
|
|
111
|
+
augmentServer.headers = server.env;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (server.env && server.command) {
|
|
115
|
+
augmentServer.env = server.env;
|
|
116
|
+
}
|
|
117
|
+
if (server.timeout) {
|
|
118
|
+
augmentServer.timeout = server.timeout;
|
|
119
|
+
}
|
|
120
|
+
if (server.disabled !== void 0) {
|
|
121
|
+
augmentServer.enabled = !server.disabled;
|
|
122
|
+
}
|
|
123
|
+
if (server.networkTimeout && server.networkTimeout > 0) {
|
|
124
|
+
augmentServer.retries = Math.max(1, Math.floor(server.networkTimeout / 3e4));
|
|
125
|
+
}
|
|
126
|
+
if (augmentSettings.mcpServers) {
|
|
127
|
+
augmentSettings.mcpServers.push(augmentServer);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return JSON.stringify(augmentSettings, null, 2);
|
|
131
|
+
}
|
|
132
|
+
var init_augmentcode = __esm({
|
|
133
|
+
"src/generators/mcp/augmentcode.ts"() {
|
|
134
|
+
"use strict";
|
|
135
|
+
init_mcp_helpers();
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
74
139
|
// src/generators/mcp/claudecode.ts
|
|
75
140
|
function generateClaudeMcp(config) {
|
|
76
141
|
const claudeSettings = {
|
|
@@ -295,6 +360,58 @@ var init_geminicli = __esm({
|
|
|
295
360
|
}
|
|
296
361
|
});
|
|
297
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
|
+
|
|
298
415
|
// src/generators/mcp/kiro.ts
|
|
299
416
|
function generateKiroMcp(config) {
|
|
300
417
|
const kiroConfig = {
|
|
@@ -411,16 +528,19 @@ function getDefaultConfig() {
|
|
|
411
528
|
return {
|
|
412
529
|
aiRulesDir: ".rulesync",
|
|
413
530
|
outputPaths: {
|
|
531
|
+
augmentcode: ".",
|
|
532
|
+
"augmentcode-legacy": ".",
|
|
414
533
|
copilot: ".github/instructions",
|
|
415
534
|
cursor: ".cursor/rules",
|
|
416
535
|
cline: ".clinerules",
|
|
417
536
|
claudecode: ".",
|
|
418
537
|
roo: ".roo/rules",
|
|
419
538
|
geminicli: ".gemini/memories",
|
|
420
|
-
kiro: ".kiro/steering"
|
|
539
|
+
kiro: ".kiro/steering",
|
|
540
|
+
junie: "."
|
|
421
541
|
},
|
|
422
542
|
watchEnabled: false,
|
|
423
|
-
defaultTargets:
|
|
543
|
+
defaultTargets: ALL_TOOL_TARGETS.filter((tool) => tool !== "augmentcode-legacy")
|
|
424
544
|
};
|
|
425
545
|
}
|
|
426
546
|
function resolveTargets(targets, config) {
|
|
@@ -467,123 +587,9 @@ async function addCommand(filename) {
|
|
|
467
587
|
}
|
|
468
588
|
}
|
|
469
589
|
|
|
470
|
-
// src/
|
|
471
|
-
var
|
|
472
|
-
|
|
473
|
-
const outputs = [];
|
|
474
|
-
const aiignoreContent = generateAiignoreContent(rules);
|
|
475
|
-
const outputPath = baseDir || process.cwd();
|
|
476
|
-
const filepath = (0, import_node_path.join)(outputPath, ".aiignore");
|
|
477
|
-
outputs.push({
|
|
478
|
-
tool: "kiro",
|
|
479
|
-
filepath,
|
|
480
|
-
content: aiignoreContent
|
|
481
|
-
});
|
|
482
|
-
return outputs;
|
|
483
|
-
}
|
|
484
|
-
function generateAiignoreContent(rules) {
|
|
485
|
-
const lines = [
|
|
486
|
-
"# Generated by rulesync - Kiro AI-specific exclusions",
|
|
487
|
-
"# This file excludes files that can be in Git but shouldn't be read by the AI",
|
|
488
|
-
""
|
|
489
|
-
];
|
|
490
|
-
lines.push(
|
|
491
|
-
"# Data files AI shouldn't process",
|
|
492
|
-
"*.csv",
|
|
493
|
-
"*.tsv",
|
|
494
|
-
"*.sqlite",
|
|
495
|
-
"*.db",
|
|
496
|
-
"",
|
|
497
|
-
"# Large binary files",
|
|
498
|
-
"*.zip",
|
|
499
|
-
"*.tar.gz",
|
|
500
|
-
"*.rar",
|
|
501
|
-
"",
|
|
502
|
-
"# Sensitive documentation",
|
|
503
|
-
"internal-docs/",
|
|
504
|
-
"confidential/",
|
|
505
|
-
"",
|
|
506
|
-
"# Test data that might confuse AI",
|
|
507
|
-
"test/fixtures/large-*.json",
|
|
508
|
-
"benchmark-results/",
|
|
509
|
-
"",
|
|
510
|
-
"# Reinforce critical exclusions from .gitignore",
|
|
511
|
-
"*.pem",
|
|
512
|
-
"*.key",
|
|
513
|
-
".env*",
|
|
514
|
-
""
|
|
515
|
-
);
|
|
516
|
-
const rulePatterns = extractIgnorePatternsFromRules(rules);
|
|
517
|
-
if (rulePatterns.length > 0) {
|
|
518
|
-
lines.push("# Project-specific exclusions from rulesync rules");
|
|
519
|
-
lines.push(...rulePatterns);
|
|
520
|
-
lines.push("");
|
|
521
|
-
}
|
|
522
|
-
return lines.join("\n");
|
|
523
|
-
}
|
|
524
|
-
function extractIgnorePatternsFromRules(rules) {
|
|
525
|
-
const patterns = [];
|
|
526
|
-
for (const rule of rules) {
|
|
527
|
-
if (rule.frontmatter.globs && rule.frontmatter.globs.length > 0) {
|
|
528
|
-
for (const glob of rule.frontmatter.globs) {
|
|
529
|
-
if (shouldExcludeFromAI(glob)) {
|
|
530
|
-
patterns.push(`# Exclude: ${rule.frontmatter.description}`);
|
|
531
|
-
patterns.push(glob);
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
const contentPatterns = extractIgnorePatternsFromContent(rule.content);
|
|
536
|
-
patterns.push(...contentPatterns);
|
|
537
|
-
}
|
|
538
|
-
return patterns;
|
|
539
|
-
}
|
|
540
|
-
function shouldExcludeFromAI(glob) {
|
|
541
|
-
const excludePatterns = [
|
|
542
|
-
// Test and fixture files that might be large or confusing
|
|
543
|
-
"**/test/fixtures/**",
|
|
544
|
-
"**/tests/fixtures/**",
|
|
545
|
-
"**/*.fixture.*",
|
|
546
|
-
// Build and generated files
|
|
547
|
-
"**/dist/**",
|
|
548
|
-
"**/build/**",
|
|
549
|
-
"**/coverage/**",
|
|
550
|
-
// Configuration that might contain sensitive data
|
|
551
|
-
"**/config/production/**",
|
|
552
|
-
"**/config/prod/**",
|
|
553
|
-
"**/*.prod.*",
|
|
554
|
-
// Documentation that might be sensitive
|
|
555
|
-
"**/internal/**",
|
|
556
|
-
"**/private/**",
|
|
557
|
-
"**/confidential/**"
|
|
558
|
-
];
|
|
559
|
-
return excludePatterns.some((pattern) => {
|
|
560
|
-
const regex = new RegExp(pattern.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*"));
|
|
561
|
-
return regex.test(glob);
|
|
562
|
-
});
|
|
563
|
-
}
|
|
564
|
-
function extractIgnorePatternsFromContent(content) {
|
|
565
|
-
const patterns = [];
|
|
566
|
-
const lines = content.split("\n");
|
|
567
|
-
for (const line of lines) {
|
|
568
|
-
const trimmed = line.trim();
|
|
569
|
-
if (trimmed.startsWith("# IGNORE:") || trimmed.startsWith("# aiignore:")) {
|
|
570
|
-
const pattern = trimmed.replace(/^# (IGNORE|aiignore):\s*/, "").trim();
|
|
571
|
-
if (pattern) {
|
|
572
|
-
patterns.push(pattern);
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
if (trimmed.includes("exclude") || trimmed.includes("ignore")) {
|
|
576
|
-
const matches = trimmed.match(/['"`]([^'"`]+\.(log|tmp|cache|temp))['"`]/g);
|
|
577
|
-
if (matches) {
|
|
578
|
-
patterns.push(...matches.map((m) => m.replace(/['"`]/g, "")));
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
return patterns;
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
// src/generators/rules/claudecode.ts
|
|
586
|
-
var import_node_path4 = require("path");
|
|
590
|
+
// src/cli/commands/config.ts
|
|
591
|
+
var import_node_fs = require("fs");
|
|
592
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
587
593
|
|
|
588
594
|
// src/types/claudecode.ts
|
|
589
595
|
var import_mini2 = require("zod/mini");
|
|
@@ -596,37 +602,352 @@ var ClaudeSettingsSchema = import_mini2.z.looseObject({
|
|
|
596
602
|
)
|
|
597
603
|
});
|
|
598
604
|
|
|
599
|
-
// src/
|
|
600
|
-
var
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
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
|
+
};
|
|
607
742
|
}
|
|
608
|
-
}
|
|
609
|
-
async function readFileContent(filepath) {
|
|
610
|
-
return (0, import_promises2.readFile)(filepath, "utf-8");
|
|
611
|
-
}
|
|
612
|
-
async function writeFileContent(filepath, content) {
|
|
613
|
-
await ensureDir((0, import_node_path2.dirname)(filepath));
|
|
614
|
-
await (0, import_promises2.writeFile)(filepath, content, "utf-8");
|
|
615
|
-
}
|
|
616
|
-
async function fileExists(filepath) {
|
|
617
743
|
try {
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
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}`);
|
|
770
|
+
}
|
|
771
|
+
throw error;
|
|
772
|
+
}
|
|
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
|
+
);
|
|
622
786
|
}
|
|
623
787
|
}
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
}
|
|
629
|
-
|
|
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 [];
|
|
630
951
|
}
|
|
631
952
|
}
|
|
632
953
|
async function removeDirectory(dirPath) {
|
|
@@ -663,15 +984,712 @@ async function removeClaudeGeneratedFiles() {
|
|
|
663
984
|
}
|
|
664
985
|
}
|
|
665
986
|
|
|
666
|
-
// src/utils/
|
|
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
|
|
667
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
|
|
1252
|
+
"**/dist/**",
|
|
1253
|
+
"**/build/**",
|
|
1254
|
+
"**/coverage/**",
|
|
1255
|
+
// Configuration that might contain sensitive data
|
|
1256
|
+
"**/config/production/**",
|
|
1257
|
+
"**/config/secrets/**",
|
|
1258
|
+
"**/config/prod/**",
|
|
1259
|
+
"**/deploy/prod/**",
|
|
1260
|
+
"**/*.prod.*",
|
|
1261
|
+
// Internal documentation that might be sensitive
|
|
1262
|
+
"**/internal/**",
|
|
1263
|
+
"**/internal-docs/**",
|
|
1264
|
+
"**/proprietary/**",
|
|
1265
|
+
"**/personal-notes/**",
|
|
1266
|
+
"**/private/**",
|
|
1267
|
+
"**/confidential/**"
|
|
1268
|
+
];
|
|
1269
|
+
return excludePatterns.some((pattern) => {
|
|
1270
|
+
const regex = new RegExp(pattern.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*"));
|
|
1271
|
+
return regex.test(glob);
|
|
1272
|
+
});
|
|
1273
|
+
}
|
|
1274
|
+
function extractIgnorePatternsFromContent(content) {
|
|
1275
|
+
const patterns = [];
|
|
1276
|
+
const lines = content.split("\n");
|
|
1277
|
+
for (const line of lines) {
|
|
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
|
+
}
|
|
1285
|
+
if (trimmed.startsWith("# AUGMENT_IGNORE:") || trimmed.startsWith("# augmentignore:")) {
|
|
1286
|
+
const pattern = trimmed.replace(/^# (AUGMENT_IGNORE|augmentignore):\s*/, "").trim();
|
|
1287
|
+
if (pattern) {
|
|
1288
|
+
patterns.push(pattern);
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
if (trimmed.startsWith("# AUGMENT_INCLUDE:") || trimmed.startsWith("# augmentinclude:")) {
|
|
1292
|
+
const pattern = trimmed.replace(/^# (AUGMENT_INCLUDE|augmentinclude):\s*/, "").trim();
|
|
1293
|
+
if (pattern) {
|
|
1294
|
+
patterns.push(`!${pattern}`);
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
if (trimmed.includes("exclude") || trimmed.includes("ignore")) {
|
|
1298
|
+
const matches = trimmed.match(/['"`]([^'"`]+\.(log|tmp|cache|temp))['"`]/g);
|
|
1299
|
+
if (matches) {
|
|
1300
|
+
patterns.push(...matches.map((m) => m.replace(/['"`]/g, "")));
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
return patterns;
|
|
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
|
+
}
|
|
1622
|
+
|
|
1623
|
+
// src/generators/ignore/kiro.ts
|
|
1624
|
+
var import_node_path5 = require("path");
|
|
1625
|
+
async function generateKiroIgnoreFiles(rules, config, baseDir) {
|
|
1626
|
+
const outputs = [];
|
|
1627
|
+
const aiignoreContent = generateAiignoreContent2(rules);
|
|
1628
|
+
const outputPath = baseDir || process.cwd();
|
|
1629
|
+
const filepath = (0, import_node_path5.join)(outputPath, ".aiignore");
|
|
1630
|
+
outputs.push({
|
|
1631
|
+
tool: "kiro",
|
|
1632
|
+
filepath,
|
|
1633
|
+
content: aiignoreContent
|
|
1634
|
+
});
|
|
1635
|
+
return outputs;
|
|
1636
|
+
}
|
|
1637
|
+
function generateAiignoreContent2(rules) {
|
|
1638
|
+
const lines = [
|
|
1639
|
+
"# Generated by rulesync - Kiro AI-specific exclusions",
|
|
1640
|
+
"# This file excludes files that can be in Git but shouldn't be read by the AI",
|
|
1641
|
+
""
|
|
1642
|
+
];
|
|
1643
|
+
lines.push(
|
|
1644
|
+
"# Data files AI shouldn't process",
|
|
1645
|
+
"*.csv",
|
|
1646
|
+
"*.tsv",
|
|
1647
|
+
"*.sqlite",
|
|
1648
|
+
"*.db",
|
|
1649
|
+
"",
|
|
1650
|
+
"# Large binary files",
|
|
1651
|
+
"*.zip",
|
|
1652
|
+
"*.tar.gz",
|
|
1653
|
+
"*.rar",
|
|
1654
|
+
"",
|
|
1655
|
+
"# Sensitive documentation",
|
|
1656
|
+
"internal-docs/",
|
|
1657
|
+
"confidential/",
|
|
1658
|
+
"",
|
|
1659
|
+
"# Test data that might confuse AI",
|
|
1660
|
+
"test/fixtures/large-*.json",
|
|
1661
|
+
"benchmark-results/",
|
|
1662
|
+
"",
|
|
1663
|
+
"# Reinforce critical exclusions from .gitignore",
|
|
1664
|
+
"*.pem",
|
|
1665
|
+
"*.key",
|
|
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("");
|
|
1674
|
+
}
|
|
1675
|
+
return lines.join("\n");
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1678
|
+
// src/generators/rules/augmentcode.ts
|
|
1679
|
+
var import_node_path8 = require("path");
|
|
1680
|
+
|
|
1681
|
+
// src/generators/rules/shared-helpers.ts
|
|
1682
|
+
var import_node_path7 = require("path");
|
|
1683
|
+
|
|
1684
|
+
// src/utils/ignore.ts
|
|
1685
|
+
var import_node_path6 = require("path");
|
|
668
1686
|
var import_micromatch = __toESM(require("micromatch"), 1);
|
|
669
1687
|
var cachedIgnorePatterns = null;
|
|
670
1688
|
async function loadIgnorePatterns(baseDir = process.cwd()) {
|
|
671
1689
|
if (cachedIgnorePatterns) {
|
|
672
1690
|
return cachedIgnorePatterns;
|
|
673
1691
|
}
|
|
674
|
-
const ignorePath = (0,
|
|
1692
|
+
const ignorePath = (0, import_node_path6.join)(baseDir, ".rulesyncignore");
|
|
675
1693
|
if (!await fileExists(ignorePath)) {
|
|
676
1694
|
cachedIgnorePatterns = { patterns: [] };
|
|
677
1695
|
return cachedIgnorePatterns;
|
|
@@ -714,29 +1732,198 @@ function filterIgnoredFiles(files, ignorePatterns) {
|
|
|
714
1732
|
return files.filter((file) => !isFileIgnored(file, ignorePatterns));
|
|
715
1733
|
}
|
|
716
1734
|
|
|
1735
|
+
// src/generators/rules/shared-helpers.ts
|
|
1736
|
+
function resolveOutputDir(config, tool, baseDir) {
|
|
1737
|
+
return baseDir ? (0, import_node_path7.join)(baseDir, config.outputPaths[tool]) : config.outputPaths[tool];
|
|
1738
|
+
}
|
|
1739
|
+
function createOutputsArray() {
|
|
1740
|
+
return [];
|
|
1741
|
+
}
|
|
1742
|
+
function addOutput(outputs, tool, config, baseDir, relativePath, content) {
|
|
1743
|
+
const outputDir = resolveOutputDir(config, tool, baseDir);
|
|
1744
|
+
outputs.push({
|
|
1745
|
+
tool,
|
|
1746
|
+
filepath: (0, import_node_path7.join)(outputDir, relativePath),
|
|
1747
|
+
content
|
|
1748
|
+
});
|
|
1749
|
+
}
|
|
1750
|
+
async function generateRulesConfig(rules, config, generatorConfig, baseDir) {
|
|
1751
|
+
const outputs = [];
|
|
1752
|
+
for (const rule of rules) {
|
|
1753
|
+
const content = generatorConfig.generateContent(rule);
|
|
1754
|
+
const outputDir = resolveOutputDir(config, generatorConfig.tool, baseDir);
|
|
1755
|
+
const filepath = generatorConfig.pathResolver ? generatorConfig.pathResolver(rule, outputDir) : (0, import_node_path7.join)(outputDir, `${rule.filename}${generatorConfig.fileExtension}`);
|
|
1756
|
+
outputs.push({
|
|
1757
|
+
tool: generatorConfig.tool,
|
|
1758
|
+
filepath,
|
|
1759
|
+
content
|
|
1760
|
+
});
|
|
1761
|
+
}
|
|
1762
|
+
const ignorePatterns = await loadIgnorePatterns(baseDir);
|
|
1763
|
+
if (ignorePatterns.patterns.length > 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;
|
|
1802
|
+
const ignoreContent = generateIgnoreFile(ignorePatterns.patterns, generatorConfig.tool);
|
|
1803
|
+
outputs.push({
|
|
1804
|
+
tool: generatorConfig.tool,
|
|
1805
|
+
filepath: ignorePath,
|
|
1806
|
+
content: ignoreContent
|
|
1807
|
+
});
|
|
1808
|
+
if (generatorConfig.updateAdditionalConfig) {
|
|
1809
|
+
const additionalOutputs = await generatorConfig.updateAdditionalConfig(
|
|
1810
|
+
ignorePatterns.patterns,
|
|
1811
|
+
baseDir
|
|
1812
|
+
);
|
|
1813
|
+
outputs.push(...additionalOutputs);
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
return outputs;
|
|
1817
|
+
}
|
|
1818
|
+
function generateIgnoreFile(patterns, tool) {
|
|
1819
|
+
const lines = [
|
|
1820
|
+
"# Generated by rulesync from .rulesyncignore",
|
|
1821
|
+
"# This file is automatically generated. Do not edit manually."
|
|
1822
|
+
];
|
|
1823
|
+
if (tool === "copilot") {
|
|
1824
|
+
lines.push("# Note: .copilotignore is not officially supported by GitHub Copilot.");
|
|
1825
|
+
lines.push("# This file is for use with community tools like copilotignore-vscode extension.");
|
|
1826
|
+
}
|
|
1827
|
+
lines.push("");
|
|
1828
|
+
lines.push(...patterns);
|
|
1829
|
+
return lines.join("\n");
|
|
1830
|
+
}
|
|
1831
|
+
async function generateComplexRulesConfig(rules, config, generatorConfig, baseDir) {
|
|
1832
|
+
const unifiedConfig = {
|
|
1833
|
+
tool: generatorConfig.tool,
|
|
1834
|
+
fileExtension: generatorConfig.fileExtension,
|
|
1835
|
+
ignoreFileName: generatorConfig.ignoreFileName,
|
|
1836
|
+
generateContent: generatorConfig.generateContent,
|
|
1837
|
+
pathResolver: generatorConfig.getOutputPath
|
|
1838
|
+
};
|
|
1839
|
+
return generateRulesConfig(rules, config, unifiedConfig, baseDir);
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
// src/generators/rules/augmentcode.ts
|
|
1843
|
+
async function generateAugmentcodeConfig(rules, config, baseDir) {
|
|
1844
|
+
const outputs = createOutputsArray();
|
|
1845
|
+
rules.forEach((rule) => {
|
|
1846
|
+
addOutput(
|
|
1847
|
+
outputs,
|
|
1848
|
+
"augmentcode",
|
|
1849
|
+
config,
|
|
1850
|
+
baseDir,
|
|
1851
|
+
(0, import_node_path8.join)(".augment", "rules", `${rule.filename}.md`),
|
|
1852
|
+
generateRuleFile(rule)
|
|
1853
|
+
);
|
|
1854
|
+
});
|
|
1855
|
+
return outputs;
|
|
1856
|
+
}
|
|
1857
|
+
function generateRuleFile(rule) {
|
|
1858
|
+
const lines = [];
|
|
1859
|
+
lines.push("---");
|
|
1860
|
+
let ruleType = "manual";
|
|
1861
|
+
let description = rule.frontmatter.description;
|
|
1862
|
+
if (rule.filename.endsWith("-always")) {
|
|
1863
|
+
ruleType = "always";
|
|
1864
|
+
description = "";
|
|
1865
|
+
} else if (rule.filename.endsWith("-auto")) {
|
|
1866
|
+
ruleType = "auto";
|
|
1867
|
+
}
|
|
1868
|
+
lines.push(`type: ${ruleType}`);
|
|
1869
|
+
lines.push(`description: "${description}"`);
|
|
1870
|
+
if (rule.frontmatter.tags && Array.isArray(rule.frontmatter.tags) && rule.frontmatter.tags.length > 0) {
|
|
1871
|
+
lines.push(`tags: [${rule.frontmatter.tags.map((tag) => `"${tag}"`).join(", ")}]`);
|
|
1872
|
+
}
|
|
1873
|
+
lines.push("---");
|
|
1874
|
+
lines.push("");
|
|
1875
|
+
lines.push(rule.content.trim());
|
|
1876
|
+
return lines.join("\n");
|
|
1877
|
+
}
|
|
1878
|
+
|
|
1879
|
+
// src/generators/rules/augmentcode-legacy.ts
|
|
1880
|
+
async function generateAugmentcodeLegacyConfig(rules, config, baseDir) {
|
|
1881
|
+
const outputs = createOutputsArray();
|
|
1882
|
+
if (rules.length > 0) {
|
|
1883
|
+
addOutput(
|
|
1884
|
+
outputs,
|
|
1885
|
+
"augmentcode-legacy",
|
|
1886
|
+
config,
|
|
1887
|
+
baseDir,
|
|
1888
|
+
".augment-guidelines",
|
|
1889
|
+
generateLegacyGuidelinesFile(rules)
|
|
1890
|
+
);
|
|
1891
|
+
}
|
|
1892
|
+
return outputs;
|
|
1893
|
+
}
|
|
1894
|
+
function generateLegacyGuidelinesFile(allRules) {
|
|
1895
|
+
const lines = [];
|
|
1896
|
+
for (const rule of allRules) {
|
|
1897
|
+
lines.push(rule.content.trim());
|
|
1898
|
+
lines.push("");
|
|
1899
|
+
}
|
|
1900
|
+
return lines.join("\n").trim();
|
|
1901
|
+
}
|
|
1902
|
+
|
|
717
1903
|
// src/generators/rules/claudecode.ts
|
|
1904
|
+
var import_node_path9 = require("path");
|
|
718
1905
|
async function generateClaudecodeConfig(rules, config, baseDir) {
|
|
719
1906
|
const outputs = [];
|
|
720
1907
|
const rootRules = rules.filter((r) => r.frontmatter.root === true);
|
|
721
1908
|
const detailRules = rules.filter((r) => r.frontmatter.root === false);
|
|
722
1909
|
const claudeMdContent = generateClaudeMarkdown(rootRules, detailRules);
|
|
723
|
-
const claudeOutputDir = baseDir ? (0,
|
|
1910
|
+
const claudeOutputDir = baseDir ? (0, import_node_path9.join)(baseDir, config.outputPaths.claudecode) : config.outputPaths.claudecode;
|
|
724
1911
|
outputs.push({
|
|
725
1912
|
tool: "claudecode",
|
|
726
|
-
filepath: (0,
|
|
1913
|
+
filepath: (0, import_node_path9.join)(claudeOutputDir, "CLAUDE.md"),
|
|
727
1914
|
content: claudeMdContent
|
|
728
1915
|
});
|
|
729
1916
|
for (const rule of detailRules) {
|
|
730
1917
|
const memoryContent = generateMemoryFile(rule);
|
|
731
1918
|
outputs.push({
|
|
732
1919
|
tool: "claudecode",
|
|
733
|
-
filepath: (0,
|
|
1920
|
+
filepath: (0, import_node_path9.join)(claudeOutputDir, ".claude", "memories", `${rule.filename}.md`),
|
|
734
1921
|
content: memoryContent
|
|
735
1922
|
});
|
|
736
1923
|
}
|
|
737
1924
|
const ignorePatterns = await loadIgnorePatterns(baseDir);
|
|
738
1925
|
if (ignorePatterns.patterns.length > 0) {
|
|
739
|
-
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");
|
|
740
1927
|
await updateClaudeSettings(settingsPath, ignorePatterns.patterns);
|
|
741
1928
|
}
|
|
742
1929
|
return outputs;
|
|
@@ -800,70 +1987,38 @@ async function updateClaudeSettings(settingsPath, ignorePatterns) {
|
|
|
800
1987
|
}
|
|
801
1988
|
|
|
802
1989
|
// src/generators/rules/cline.ts
|
|
803
|
-
var import_node_path5 = require("path");
|
|
804
1990
|
async function generateClineConfig(rules, config, baseDir) {
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
const filepath = (0, import_node_path5.join)(outputDir, `${rule.filename}.md`);
|
|
810
|
-
outputs.push({
|
|
811
|
-
tool: "cline",
|
|
812
|
-
filepath,
|
|
813
|
-
content
|
|
814
|
-
});
|
|
815
|
-
}
|
|
816
|
-
const ignorePatterns = await loadIgnorePatterns(baseDir);
|
|
817
|
-
if (ignorePatterns.patterns.length > 0) {
|
|
818
|
-
const clineIgnorePath = baseDir ? (0, import_node_path5.join)(baseDir, ".clineignore") : ".clineignore";
|
|
819
|
-
const clineIgnoreContent = generateClineIgnore(ignorePatterns.patterns);
|
|
820
|
-
outputs.push({
|
|
1991
|
+
return generateRulesConfig(
|
|
1992
|
+
rules,
|
|
1993
|
+
config,
|
|
1994
|
+
{
|
|
821
1995
|
tool: "cline",
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
];
|
|
838
|
-
return lines.join("\n");
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
// src/generators/rules/copilot.ts
|
|
842
|
-
var import_node_path6 = require("path");
|
|
843
|
-
async function generateCopilotConfig(rules, config, baseDir) {
|
|
844
|
-
const outputs = [];
|
|
845
|
-
for (const rule of rules) {
|
|
846
|
-
const content = generateCopilotMarkdown(rule);
|
|
847
|
-
const baseFilename = rule.filename.replace(/\.md$/, "");
|
|
848
|
-
const outputDir = baseDir ? (0, import_node_path6.join)(baseDir, config.outputPaths.copilot) : config.outputPaths.copilot;
|
|
849
|
-
const filepath = (0, import_node_path6.join)(outputDir, `${baseFilename}.instructions.md`);
|
|
850
|
-
outputs.push({
|
|
851
|
-
tool: "copilot",
|
|
852
|
-
filepath,
|
|
853
|
-
content
|
|
854
|
-
});
|
|
855
|
-
}
|
|
856
|
-
const ignorePatterns = await loadIgnorePatterns(baseDir);
|
|
857
|
-
if (ignorePatterns.patterns.length > 0) {
|
|
858
|
-
const copilotIgnorePath = baseDir ? (0, import_node_path6.join)(baseDir, ".copilotignore") : ".copilotignore";
|
|
859
|
-
const copilotIgnoreContent = generateCopilotIgnore(ignorePatterns.patterns);
|
|
860
|
-
outputs.push({
|
|
1996
|
+
fileExtension: ".md",
|
|
1997
|
+
ignoreFileName: ".clineignore",
|
|
1998
|
+
generateContent: (rule) => rule.content.trim()
|
|
1999
|
+
},
|
|
2000
|
+
baseDir
|
|
2001
|
+
);
|
|
2002
|
+
}
|
|
2003
|
+
|
|
2004
|
+
// src/generators/rules/copilot.ts
|
|
2005
|
+
var import_node_path10 = require("path");
|
|
2006
|
+
async function generateCopilotConfig(rules, config, baseDir) {
|
|
2007
|
+
return generateComplexRulesConfig(
|
|
2008
|
+
rules,
|
|
2009
|
+
config,
|
|
2010
|
+
{
|
|
861
2011
|
tool: "copilot",
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
2012
|
+
fileExtension: ".instructions.md",
|
|
2013
|
+
ignoreFileName: ".copilotignore",
|
|
2014
|
+
generateContent: generateCopilotMarkdown,
|
|
2015
|
+
getOutputPath: (rule, outputDir) => {
|
|
2016
|
+
const baseFilename = rule.filename.replace(/\.md$/, "");
|
|
2017
|
+
return (0, import_node_path10.join)(outputDir, `${baseFilename}.instructions.md`);
|
|
2018
|
+
}
|
|
2019
|
+
},
|
|
2020
|
+
baseDir
|
|
2021
|
+
);
|
|
867
2022
|
}
|
|
868
2023
|
function generateCopilotMarkdown(rule) {
|
|
869
2024
|
const lines = [];
|
|
@@ -878,43 +2033,24 @@ function generateCopilotMarkdown(rule) {
|
|
|
878
2033
|
lines.push(rule.content);
|
|
879
2034
|
return lines.join("\n");
|
|
880
2035
|
}
|
|
881
|
-
function generateCopilotIgnore(patterns) {
|
|
882
|
-
const lines = [
|
|
883
|
-
"# Generated by rulesync from .rulesyncignore",
|
|
884
|
-
"# This file is automatically generated. Do not edit manually.",
|
|
885
|
-
"# Note: .copilotignore is not officially supported by GitHub Copilot.",
|
|
886
|
-
"# This file is for use with community tools like copilotignore-vscode extension.",
|
|
887
|
-
"",
|
|
888
|
-
...patterns
|
|
889
|
-
];
|
|
890
|
-
return lines.join("\n");
|
|
891
|
-
}
|
|
892
2036
|
|
|
893
2037
|
// src/generators/rules/cursor.ts
|
|
894
|
-
var
|
|
2038
|
+
var import_node_path11 = require("path");
|
|
895
2039
|
async function generateCursorConfig(rules, config, baseDir) {
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
const filepath = (0, import_node_path7.join)(outputDir, `${rule.filename}.mdc`);
|
|
901
|
-
outputs.push({
|
|
902
|
-
tool: "cursor",
|
|
903
|
-
filepath,
|
|
904
|
-
content
|
|
905
|
-
});
|
|
906
|
-
}
|
|
907
|
-
const ignorePatterns = await loadIgnorePatterns(baseDir);
|
|
908
|
-
if (ignorePatterns.patterns.length > 0) {
|
|
909
|
-
const cursorIgnorePath = baseDir ? (0, import_node_path7.join)(baseDir, ".cursorignore") : ".cursorignore";
|
|
910
|
-
const cursorIgnoreContent = generateCursorIgnore(ignorePatterns.patterns);
|
|
911
|
-
outputs.push({
|
|
2040
|
+
return generateComplexRulesConfig(
|
|
2041
|
+
rules,
|
|
2042
|
+
config,
|
|
2043
|
+
{
|
|
912
2044
|
tool: "cursor",
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
2045
|
+
fileExtension: ".mdc",
|
|
2046
|
+
ignoreFileName: ".cursorignore",
|
|
2047
|
+
generateContent: generateCursorMarkdown,
|
|
2048
|
+
getOutputPath: (rule, outputDir) => {
|
|
2049
|
+
return (0, import_node_path11.join)(outputDir, `${rule.filename}.mdc`);
|
|
2050
|
+
}
|
|
2051
|
+
},
|
|
2052
|
+
baseDir
|
|
2053
|
+
);
|
|
918
2054
|
}
|
|
919
2055
|
function generateCursorMarkdown(rule) {
|
|
920
2056
|
const lines = [];
|
|
@@ -968,50 +2104,20 @@ function determineCursorRuleType(frontmatter) {
|
|
|
968
2104
|
}
|
|
969
2105
|
return "intelligently";
|
|
970
2106
|
}
|
|
971
|
-
function generateCursorIgnore(patterns) {
|
|
972
|
-
const lines = [
|
|
973
|
-
"# Generated by rulesync from .rulesyncignore",
|
|
974
|
-
"# This file is automatically generated. Do not edit manually.",
|
|
975
|
-
"",
|
|
976
|
-
...patterns
|
|
977
|
-
];
|
|
978
|
-
return lines.join("\n");
|
|
979
|
-
}
|
|
980
2107
|
|
|
981
2108
|
// src/generators/rules/geminicli.ts
|
|
982
|
-
var import_node_path8 = require("path");
|
|
983
2109
|
async function generateGeminiConfig(rules, config, baseDir) {
|
|
984
|
-
const
|
|
985
|
-
const rootRule = rules.find((rule) => rule.frontmatter.root === true);
|
|
986
|
-
const memoryRules = rules.filter((rule) => rule.frontmatter.root === false);
|
|
987
|
-
for (const rule of memoryRules) {
|
|
988
|
-
const content = generateGeminiMemoryMarkdown(rule);
|
|
989
|
-
const outputDir = baseDir ? (0, import_node_path8.join)(baseDir, config.outputPaths.geminicli) : config.outputPaths.geminicli;
|
|
990
|
-
const filepath = (0, import_node_path8.join)(outputDir, `${rule.filename}.md`);
|
|
991
|
-
outputs.push({
|
|
992
|
-
tool: "geminicli",
|
|
993
|
-
filepath,
|
|
994
|
-
content
|
|
995
|
-
});
|
|
996
|
-
}
|
|
997
|
-
const rootContent = generateGeminiRootMarkdown(rootRule, memoryRules, baseDir);
|
|
998
|
-
const rootFilepath = baseDir ? (0, import_node_path8.join)(baseDir, "GEMINI.md") : "GEMINI.md";
|
|
999
|
-
outputs.push({
|
|
2110
|
+
const generatorConfig = {
|
|
1000
2111
|
tool: "geminicli",
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
filepath: aiexcludePath,
|
|
1011
|
-
content: aiexcludeContent
|
|
1012
|
-
});
|
|
1013
|
-
}
|
|
1014
|
-
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);
|
|
1015
2121
|
}
|
|
1016
2122
|
function generateGeminiMemoryMarkdown(rule) {
|
|
1017
2123
|
return rule.content.trim();
|
|
@@ -1040,24 +2146,42 @@ function generateGeminiRootMarkdown(rootRule, memoryRules, _baseDir) {
|
|
|
1040
2146
|
}
|
|
1041
2147
|
return lines.join("\n");
|
|
1042
2148
|
}
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
"",
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
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();
|
|
1051
2175
|
}
|
|
1052
2176
|
|
|
1053
2177
|
// src/generators/rules/kiro.ts
|
|
1054
|
-
var
|
|
2178
|
+
var import_node_path12 = require("path");
|
|
1055
2179
|
async function generateKiroConfig(rules, config, baseDir) {
|
|
1056
2180
|
const outputs = [];
|
|
1057
2181
|
for (const rule of rules) {
|
|
1058
2182
|
const content = generateKiroMarkdown(rule);
|
|
1059
|
-
const outputDir = baseDir ? (0,
|
|
1060
|
-
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`);
|
|
1061
2185
|
outputs.push({
|
|
1062
2186
|
tool: "kiro",
|
|
1063
2187
|
filepath,
|
|
@@ -1071,47 +2195,23 @@ function generateKiroMarkdown(rule) {
|
|
|
1071
2195
|
}
|
|
1072
2196
|
|
|
1073
2197
|
// src/generators/rules/roo.ts
|
|
1074
|
-
var import_node_path10 = require("path");
|
|
1075
2198
|
async function generateRooConfig(rules, config, baseDir) {
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
const filepath = (0, import_node_path10.join)(outputDir, `${rule.filename}.md`);
|
|
1081
|
-
outputs.push({
|
|
1082
|
-
tool: "roo",
|
|
1083
|
-
filepath,
|
|
1084
|
-
content
|
|
1085
|
-
});
|
|
1086
|
-
}
|
|
1087
|
-
const ignorePatterns = await loadIgnorePatterns(baseDir);
|
|
1088
|
-
if (ignorePatterns.patterns.length > 0) {
|
|
1089
|
-
const rooIgnorePath = baseDir ? (0, import_node_path10.join)(baseDir, ".rooignore") : ".rooignore";
|
|
1090
|
-
const rooIgnoreContent = generateRooIgnore(ignorePatterns.patterns);
|
|
1091
|
-
outputs.push({
|
|
2199
|
+
return generateRulesConfig(
|
|
2200
|
+
rules,
|
|
2201
|
+
config,
|
|
2202
|
+
{
|
|
1092
2203
|
tool: "roo",
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
function generateRooMarkdown(rule) {
|
|
1100
|
-
return rule.content.trim();
|
|
1101
|
-
}
|
|
1102
|
-
function generateRooIgnore(patterns) {
|
|
1103
|
-
const lines = [
|
|
1104
|
-
"# Generated by rulesync from .rulesyncignore",
|
|
1105
|
-
"# This file is automatically generated. Do not edit manually.",
|
|
1106
|
-
"",
|
|
1107
|
-
...patterns
|
|
1108
|
-
];
|
|
1109
|
-
return lines.join("\n");
|
|
2204
|
+
fileExtension: ".md",
|
|
2205
|
+
ignoreFileName: ".rooignore",
|
|
2206
|
+
generateContent: (rule) => rule.content.trim()
|
|
2207
|
+
},
|
|
2208
|
+
baseDir
|
|
2209
|
+
);
|
|
1110
2210
|
}
|
|
1111
2211
|
|
|
1112
2212
|
// src/core/generator.ts
|
|
1113
2213
|
async function generateConfigurations(rules, config, targetTools, baseDir) {
|
|
1114
|
-
const outputs =
|
|
2214
|
+
const outputs = createOutputsArray();
|
|
1115
2215
|
const toolsToGenerate = targetTools || config.defaultTargets;
|
|
1116
2216
|
const rootFiles = rules.filter((rule) => rule.frontmatter.root === true);
|
|
1117
2217
|
if (rootFiles.length === 0) {
|
|
@@ -1135,11 +2235,28 @@ async function generateConfigurations(rules, config, targetTools, baseDir) {
|
|
|
1135
2235
|
function filterRulesForTool(rules, tool, config) {
|
|
1136
2236
|
return rules.filter((rule) => {
|
|
1137
2237
|
const targets = resolveTargets(rule.frontmatter.targets, config);
|
|
1138
|
-
|
|
2238
|
+
if (!targets.includes(tool)) {
|
|
2239
|
+
return false;
|
|
2240
|
+
}
|
|
2241
|
+
return isToolSpecificRule(rule, tool);
|
|
1139
2242
|
});
|
|
1140
2243
|
}
|
|
1141
2244
|
async function generateForTool(tool, rules, config, baseDir) {
|
|
1142
2245
|
switch (tool) {
|
|
2246
|
+
case "augmentcode": {
|
|
2247
|
+
const augmentRulesOutputs = await generateAugmentcodeConfig(rules, config, baseDir);
|
|
2248
|
+
const augmentIgnoreOutputs = await generateAugmentCodeIgnoreFiles(rules, config, baseDir);
|
|
2249
|
+
return [...augmentRulesOutputs, ...augmentIgnoreOutputs];
|
|
2250
|
+
}
|
|
2251
|
+
case "augmentcode-legacy": {
|
|
2252
|
+
const augmentLegacyRulesOutputs = await generateAugmentcodeLegacyConfig(
|
|
2253
|
+
rules,
|
|
2254
|
+
config,
|
|
2255
|
+
baseDir
|
|
2256
|
+
);
|
|
2257
|
+
const augmentIgnoreOutputs = await generateAugmentCodeIgnoreFiles(rules, config, baseDir);
|
|
2258
|
+
return [...augmentLegacyRulesOutputs, ...augmentIgnoreOutputs];
|
|
2259
|
+
}
|
|
1143
2260
|
case "copilot":
|
|
1144
2261
|
return generateCopilotConfig(rules, config, baseDir);
|
|
1145
2262
|
case "cursor":
|
|
@@ -1152,6 +2269,11 @@ async function generateForTool(tool, rules, config, baseDir) {
|
|
|
1152
2269
|
return generateRooConfig(rules, config, baseDir);
|
|
1153
2270
|
case "geminicli":
|
|
1154
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
|
+
}
|
|
1155
2277
|
case "kiro": {
|
|
1156
2278
|
const kiroRulesOutputs = await generateKiroConfig(rules, config, baseDir);
|
|
1157
2279
|
const kiroIgnoreOutputs = await generateKiroIgnoreFiles(rules, config, baseDir);
|
|
@@ -1164,82 +2286,8 @@ async function generateForTool(tool, rules, config, baseDir) {
|
|
|
1164
2286
|
}
|
|
1165
2287
|
|
|
1166
2288
|
// src/core/parser.ts
|
|
1167
|
-
var
|
|
2289
|
+
var import_node_path13 = require("path");
|
|
1168
2290
|
var import_gray_matter = __toESM(require("gray-matter"), 1);
|
|
1169
|
-
|
|
1170
|
-
// src/types/config.ts
|
|
1171
|
-
var import_mini3 = require("zod/mini");
|
|
1172
|
-
init_tool_targets();
|
|
1173
|
-
var ConfigSchema = import_mini3.z.object({
|
|
1174
|
-
aiRulesDir: import_mini3.z.string(),
|
|
1175
|
-
outputPaths: import_mini3.z.record(ToolTargetSchema, import_mini3.z.string()),
|
|
1176
|
-
watchEnabled: import_mini3.z.boolean(),
|
|
1177
|
-
defaultTargets: ToolTargetsSchema
|
|
1178
|
-
});
|
|
1179
|
-
|
|
1180
|
-
// src/types/mcp.ts
|
|
1181
|
-
var import_mini4 = require("zod/mini");
|
|
1182
|
-
init_tool_targets();
|
|
1183
|
-
var McpTransportTypeSchema = import_mini4.z.enum(["stdio", "sse", "http"]);
|
|
1184
|
-
var McpServerBaseSchema = import_mini4.z.object({
|
|
1185
|
-
command: import_mini4.z.optional(import_mini4.z.string()),
|
|
1186
|
-
args: import_mini4.z.optional(import_mini4.z.array(import_mini4.z.string())),
|
|
1187
|
-
url: import_mini4.z.optional(import_mini4.z.string()),
|
|
1188
|
-
httpUrl: import_mini4.z.optional(import_mini4.z.string()),
|
|
1189
|
-
env: import_mini4.z.optional(import_mini4.z.record(import_mini4.z.string(), import_mini4.z.string())),
|
|
1190
|
-
disabled: import_mini4.z.optional(import_mini4.z.boolean()),
|
|
1191
|
-
networkTimeout: import_mini4.z.optional(import_mini4.z.number()),
|
|
1192
|
-
timeout: import_mini4.z.optional(import_mini4.z.number()),
|
|
1193
|
-
trust: import_mini4.z.optional(import_mini4.z.boolean()),
|
|
1194
|
-
cwd: import_mini4.z.optional(import_mini4.z.string()),
|
|
1195
|
-
transport: import_mini4.z.optional(McpTransportTypeSchema),
|
|
1196
|
-
type: import_mini4.z.optional(import_mini4.z.enum(["sse", "streamable-http"])),
|
|
1197
|
-
alwaysAllow: import_mini4.z.optional(import_mini4.z.array(import_mini4.z.string())),
|
|
1198
|
-
tools: import_mini4.z.optional(import_mini4.z.array(import_mini4.z.string())),
|
|
1199
|
-
kiroAutoApprove: import_mini4.z.optional(import_mini4.z.array(import_mini4.z.string())),
|
|
1200
|
-
kiroAutoBlock: import_mini4.z.optional(import_mini4.z.array(import_mini4.z.string()))
|
|
1201
|
-
});
|
|
1202
|
-
var RulesyncMcpServerSchema = import_mini4.z.extend(McpServerBaseSchema, {
|
|
1203
|
-
targets: import_mini4.z.optional(RulesyncTargetsSchema)
|
|
1204
|
-
});
|
|
1205
|
-
var McpConfigSchema = import_mini4.z.object({
|
|
1206
|
-
mcpServers: import_mini4.z.record(import_mini4.z.string(), McpServerBaseSchema)
|
|
1207
|
-
});
|
|
1208
|
-
var RulesyncMcpConfigSchema = import_mini4.z.object({
|
|
1209
|
-
mcpServers: import_mini4.z.record(import_mini4.z.string(), RulesyncMcpServerSchema)
|
|
1210
|
-
});
|
|
1211
|
-
|
|
1212
|
-
// src/types/rules.ts
|
|
1213
|
-
var import_mini5 = require("zod/mini");
|
|
1214
|
-
init_tool_targets();
|
|
1215
|
-
var RuleFrontmatterSchema = import_mini5.z.object({
|
|
1216
|
-
root: import_mini5.z.boolean(),
|
|
1217
|
-
targets: RulesyncTargetsSchema,
|
|
1218
|
-
description: import_mini5.z.string(),
|
|
1219
|
-
globs: import_mini5.z.array(import_mini5.z.string()),
|
|
1220
|
-
cursorRuleType: import_mini5.z.optional(import_mini5.z.enum(["always", "manual", "specificFiles", "intelligently"]))
|
|
1221
|
-
});
|
|
1222
|
-
var ParsedRuleSchema = import_mini5.z.object({
|
|
1223
|
-
frontmatter: RuleFrontmatterSchema,
|
|
1224
|
-
content: import_mini5.z.string(),
|
|
1225
|
-
filename: import_mini5.z.string(),
|
|
1226
|
-
filepath: import_mini5.z.string()
|
|
1227
|
-
});
|
|
1228
|
-
var GeneratedOutputSchema = import_mini5.z.object({
|
|
1229
|
-
tool: ToolTargetSchema,
|
|
1230
|
-
filepath: import_mini5.z.string(),
|
|
1231
|
-
content: import_mini5.z.string()
|
|
1232
|
-
});
|
|
1233
|
-
var GenerateOptionsSchema = import_mini5.z.object({
|
|
1234
|
-
targetTools: import_mini5.z.optional(ToolTargetsSchema),
|
|
1235
|
-
outputDir: import_mini5.z.optional(import_mini5.z.string()),
|
|
1236
|
-
watch: import_mini5.z.optional(import_mini5.z.boolean())
|
|
1237
|
-
});
|
|
1238
|
-
|
|
1239
|
-
// src/types/index.ts
|
|
1240
|
-
init_tool_targets();
|
|
1241
|
-
|
|
1242
|
-
// src/core/parser.ts
|
|
1243
2291
|
async function parseRulesFromDirectory(aiRulesDir) {
|
|
1244
2292
|
const ignorePatterns = await loadIgnorePatterns();
|
|
1245
2293
|
const allRuleFiles = await findFiles(aiRulesDir, ".md");
|
|
@@ -1276,7 +2324,7 @@ async function parseRuleFile(filepath) {
|
|
|
1276
2324
|
const parsed = (0, import_gray_matter.default)(content);
|
|
1277
2325
|
try {
|
|
1278
2326
|
const frontmatter = RuleFrontmatterSchema.parse(parsed.data);
|
|
1279
|
-
const filename = (0,
|
|
2327
|
+
const filename = (0, import_node_path13.basename)(filepath, ".md");
|
|
1280
2328
|
return {
|
|
1281
2329
|
frontmatter,
|
|
1282
2330
|
content: parsed.content,
|
|
@@ -1341,22 +2389,24 @@ async function validateRule(rule) {
|
|
|
1341
2389
|
}
|
|
1342
2390
|
|
|
1343
2391
|
// src/core/mcp-generator.ts
|
|
1344
|
-
var
|
|
2392
|
+
var path4 = __toESM(require("path"), 1);
|
|
1345
2393
|
|
|
1346
2394
|
// src/generators/mcp/index.ts
|
|
2395
|
+
init_augmentcode();
|
|
1347
2396
|
init_claudecode();
|
|
1348
2397
|
init_cline();
|
|
1349
2398
|
init_copilot();
|
|
1350
2399
|
init_cursor();
|
|
1351
2400
|
init_geminicli();
|
|
2401
|
+
init_junie();
|
|
1352
2402
|
init_kiro();
|
|
1353
2403
|
init_roo();
|
|
1354
2404
|
|
|
1355
2405
|
// src/core/mcp-parser.ts
|
|
1356
2406
|
var fs = __toESM(require("fs"), 1);
|
|
1357
|
-
var
|
|
2407
|
+
var path3 = __toESM(require("path"), 1);
|
|
1358
2408
|
function parseMcpConfig(projectRoot) {
|
|
1359
|
-
const mcpPath =
|
|
2409
|
+
const mcpPath = path3.join(projectRoot, ".rulesync", ".mcp.json");
|
|
1360
2410
|
if (!fs.existsSync(mcpPath)) {
|
|
1361
2411
|
return null;
|
|
1362
2412
|
}
|
|
@@ -1380,7 +2430,7 @@ function parseMcpConfig(projectRoot) {
|
|
|
1380
2430
|
}
|
|
1381
2431
|
|
|
1382
2432
|
// src/core/mcp-generator.ts
|
|
1383
|
-
async function generateMcpConfigs(projectRoot, baseDir) {
|
|
2433
|
+
async function generateMcpConfigs(projectRoot, baseDir, targetTools) {
|
|
1384
2434
|
const results = [];
|
|
1385
2435
|
const targetRoot = baseDir || projectRoot;
|
|
1386
2436
|
const config = parseMcpConfig(projectRoot);
|
|
@@ -1388,47 +2438,72 @@ async function generateMcpConfigs(projectRoot, baseDir) {
|
|
|
1388
2438
|
return results;
|
|
1389
2439
|
}
|
|
1390
2440
|
const generators = [
|
|
2441
|
+
{
|
|
2442
|
+
tool: "augmentcode-project",
|
|
2443
|
+
path: path4.join(targetRoot, ".mcp.json"),
|
|
2444
|
+
generate: () => generateAugmentcodeMcp(config)
|
|
2445
|
+
},
|
|
2446
|
+
{
|
|
2447
|
+
tool: "augmentcode-legacy-project",
|
|
2448
|
+
path: path4.join(targetRoot, ".mcp.json"),
|
|
2449
|
+
generate: () => generateAugmentcodeMcp(config)
|
|
2450
|
+
},
|
|
1391
2451
|
{
|
|
1392
2452
|
tool: "claude-project",
|
|
1393
|
-
path:
|
|
2453
|
+
path: path4.join(targetRoot, ".mcp.json"),
|
|
1394
2454
|
generate: () => generateClaudeMcp(config)
|
|
1395
2455
|
},
|
|
1396
2456
|
{
|
|
1397
2457
|
tool: "copilot-editor",
|
|
1398
|
-
path:
|
|
2458
|
+
path: path4.join(targetRoot, ".vscode", "mcp.json"),
|
|
1399
2459
|
generate: () => generateCopilotMcp(config, "editor")
|
|
1400
2460
|
},
|
|
1401
2461
|
{
|
|
1402
2462
|
tool: "cursor-project",
|
|
1403
|
-
path:
|
|
2463
|
+
path: path4.join(targetRoot, ".cursor", "mcp.json"),
|
|
1404
2464
|
generate: () => generateCursorMcp(config)
|
|
1405
2465
|
},
|
|
1406
2466
|
{
|
|
1407
2467
|
tool: "cline-project",
|
|
1408
|
-
path:
|
|
2468
|
+
path: path4.join(targetRoot, ".cline", "mcp.json"),
|
|
1409
2469
|
generate: () => generateClineMcp(config)
|
|
1410
2470
|
},
|
|
1411
2471
|
{
|
|
1412
2472
|
tool: "gemini-project",
|
|
1413
|
-
path:
|
|
2473
|
+
path: path4.join(targetRoot, ".gemini", "settings.json"),
|
|
1414
2474
|
generate: () => generateGeminiCliMcp(config)
|
|
1415
2475
|
},
|
|
2476
|
+
{
|
|
2477
|
+
tool: "junie-project",
|
|
2478
|
+
path: path4.join(targetRoot, ".junie", "mcp-config.json"),
|
|
2479
|
+
generate: () => generateJunieMcp(config)
|
|
2480
|
+
},
|
|
1416
2481
|
{
|
|
1417
2482
|
tool: "kiro-project",
|
|
1418
|
-
path:
|
|
2483
|
+
path: path4.join(targetRoot, ".kiro", "mcp.json"),
|
|
1419
2484
|
generate: () => generateKiroMcp(config)
|
|
1420
2485
|
},
|
|
1421
2486
|
{
|
|
1422
2487
|
tool: "roo-project",
|
|
1423
|
-
path:
|
|
2488
|
+
path: path4.join(targetRoot, ".roo", "mcp.json"),
|
|
1424
2489
|
generate: () => generateRooMcp(config)
|
|
1425
2490
|
}
|
|
1426
2491
|
];
|
|
1427
|
-
|
|
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) {
|
|
1428
2503
|
try {
|
|
1429
2504
|
const content = generator.generate();
|
|
1430
2505
|
const parsed = JSON.parse(content);
|
|
1431
|
-
if (generator.tool.includes("claude") || generator.tool.includes("cline") || generator.tool.includes("cursor") || generator.tool.includes("gemini") || generator.tool.includes("kiro") || generator.tool.includes("roo")) {
|
|
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")) {
|
|
1432
2507
|
if (!parsed.mcpServers || Object.keys(parsed.mcpServers).length === 0) {
|
|
1433
2508
|
results.push({
|
|
1434
2509
|
tool: generator.tool,
|
|
@@ -1468,15 +2543,58 @@ async function generateMcpConfigs(projectRoot, baseDir) {
|
|
|
1468
2543
|
|
|
1469
2544
|
// src/cli/commands/generate.ts
|
|
1470
2545
|
async function generateCommand(options = {}) {
|
|
1471
|
-
const
|
|
1472
|
-
|
|
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
|
+
}
|
|
1473
2591
|
console.log("Generating configuration files...");
|
|
1474
2592
|
if (!await fileExists(config.aiRulesDir)) {
|
|
1475
2593
|
console.error("\u274C .rulesync directory not found. Run 'rulesync init' first.");
|
|
1476
2594
|
process.exit(1);
|
|
1477
2595
|
}
|
|
1478
2596
|
try {
|
|
1479
|
-
if (
|
|
2597
|
+
if (config.verbose) {
|
|
1480
2598
|
console.log(`Parsing rules from ${config.aiRulesDir}...`);
|
|
1481
2599
|
}
|
|
1482
2600
|
const rules = await parseRulesFromDirectory(config.aiRulesDir);
|
|
@@ -1484,18 +2602,26 @@ async function generateCommand(options = {}) {
|
|
|
1484
2602
|
console.warn("\u26A0\uFE0F No rules found in .rulesync directory");
|
|
1485
2603
|
return;
|
|
1486
2604
|
}
|
|
1487
|
-
if (
|
|
2605
|
+
if (config.verbose) {
|
|
1488
2606
|
console.log(`Found ${rules.length} rule(s)`);
|
|
1489
2607
|
console.log(`Base directories: ${baseDirs.join(", ")}`);
|
|
1490
2608
|
}
|
|
1491
|
-
if (
|
|
1492
|
-
if (
|
|
2609
|
+
if (config.delete) {
|
|
2610
|
+
if (config.verbose) {
|
|
1493
2611
|
console.log("Deleting existing output directories...");
|
|
1494
2612
|
}
|
|
1495
|
-
const targetTools =
|
|
2613
|
+
const targetTools = config.defaultTargets;
|
|
1496
2614
|
const deleteTasks = [];
|
|
1497
2615
|
for (const tool of targetTools) {
|
|
1498
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;
|
|
1499
2625
|
case "copilot":
|
|
1500
2626
|
deleteTasks.push(removeDirectory(config.outputPaths.copilot));
|
|
1501
2627
|
break;
|
|
@@ -1520,19 +2646,19 @@ async function generateCommand(options = {}) {
|
|
|
1520
2646
|
}
|
|
1521
2647
|
}
|
|
1522
2648
|
await Promise.all(deleteTasks);
|
|
1523
|
-
if (
|
|
2649
|
+
if (config.verbose) {
|
|
1524
2650
|
console.log("Deleted existing output directories");
|
|
1525
2651
|
}
|
|
1526
2652
|
}
|
|
1527
2653
|
let totalOutputs = 0;
|
|
1528
2654
|
for (const baseDir of baseDirs) {
|
|
1529
|
-
if (
|
|
2655
|
+
if (config.verbose) {
|
|
1530
2656
|
console.log(`
|
|
1531
2657
|
Generating configurations for base directory: ${baseDir}`);
|
|
1532
2658
|
}
|
|
1533
|
-
const outputs = await generateConfigurations(rules, config,
|
|
2659
|
+
const outputs = await generateConfigurations(rules, config, config.defaultTargets, baseDir);
|
|
1534
2660
|
if (outputs.length === 0) {
|
|
1535
|
-
if (
|
|
2661
|
+
if (config.verbose) {
|
|
1536
2662
|
console.warn(`\u26A0\uFE0F No configurations generated for ${baseDir}`);
|
|
1537
2663
|
}
|
|
1538
2664
|
continue;
|
|
@@ -1547,17 +2673,18 @@ Generating configurations for base directory: ${baseDir}`);
|
|
|
1547
2673
|
console.warn("\u26A0\uFE0F No configurations generated");
|
|
1548
2674
|
return;
|
|
1549
2675
|
}
|
|
1550
|
-
if (
|
|
2676
|
+
if (config.verbose) {
|
|
1551
2677
|
console.log("\nGenerating MCP configurations...");
|
|
1552
2678
|
}
|
|
1553
2679
|
let totalMcpOutputs = 0;
|
|
1554
2680
|
for (const baseDir of baseDirs) {
|
|
1555
2681
|
const mcpResults = await generateMcpConfigs(
|
|
1556
2682
|
process.cwd(),
|
|
1557
|
-
baseDir === process.cwd() ? void 0 : baseDir
|
|
2683
|
+
baseDir === process.cwd() ? void 0 : baseDir,
|
|
2684
|
+
config.defaultTargets
|
|
1558
2685
|
);
|
|
1559
2686
|
if (mcpResults.length === 0) {
|
|
1560
|
-
if (
|
|
2687
|
+
if (config.verbose) {
|
|
1561
2688
|
console.log(`No MCP configuration found for ${baseDir}`);
|
|
1562
2689
|
}
|
|
1563
2690
|
continue;
|
|
@@ -1568,7 +2695,7 @@ Generating configurations for base directory: ${baseDir}`);
|
|
|
1568
2695
|
totalMcpOutputs++;
|
|
1569
2696
|
} else if (result.status === "error") {
|
|
1570
2697
|
console.error(`\u274C Failed to generate ${result.tool} MCP configuration: ${result.error}`);
|
|
1571
|
-
} else if (
|
|
2698
|
+
} else if (config.verbose && result.status === "skipped") {
|
|
1572
2699
|
console.log(`\u23ED\uFE0F Skipped ${result.tool} MCP configuration (no servers configured)`);
|
|
1573
2700
|
}
|
|
1574
2701
|
}
|
|
@@ -1587,10 +2714,10 @@ Generating configurations for base directory: ${baseDir}`);
|
|
|
1587
2714
|
}
|
|
1588
2715
|
|
|
1589
2716
|
// src/cli/commands/gitignore.ts
|
|
1590
|
-
var
|
|
1591
|
-
var
|
|
2717
|
+
var import_node_fs2 = require("fs");
|
|
2718
|
+
var import_node_path15 = require("path");
|
|
1592
2719
|
var gitignoreCommand = async () => {
|
|
1593
|
-
const gitignorePath = (0,
|
|
2720
|
+
const gitignorePath = (0, import_node_path15.join)(process.cwd(), ".gitignore");
|
|
1594
2721
|
const rulesFilesToIgnore = [
|
|
1595
2722
|
"# Generated by rulesync - AI tool configuration files",
|
|
1596
2723
|
"**/.github/copilot-instructions.md",
|
|
@@ -1608,7 +2735,12 @@ var gitignoreCommand = async () => {
|
|
|
1608
2735
|
"**/.gemini/memories/",
|
|
1609
2736
|
"**/.aiexclude",
|
|
1610
2737
|
"**/.aiignore",
|
|
2738
|
+
"**/.augmentignore",
|
|
1611
2739
|
"**/.kiro/steering/",
|
|
2740
|
+
"**/.augment/rules/",
|
|
2741
|
+
"**/.augment-guidelines",
|
|
2742
|
+
"**/.junie/guidelines.md",
|
|
2743
|
+
"**/.noai",
|
|
1612
2744
|
"**/.mcp.json",
|
|
1613
2745
|
"!.rulesync/.mcp.json",
|
|
1614
2746
|
"**/.cursor/mcp.json",
|
|
@@ -1618,8 +2750,8 @@ var gitignoreCommand = async () => {
|
|
|
1618
2750
|
"**/.roo/mcp.json"
|
|
1619
2751
|
];
|
|
1620
2752
|
let gitignoreContent = "";
|
|
1621
|
-
if ((0,
|
|
1622
|
-
gitignoreContent = (0,
|
|
2753
|
+
if ((0, import_node_fs2.existsSync)(gitignorePath)) {
|
|
2754
|
+
gitignoreContent = (0, import_node_fs2.readFileSync)(gitignorePath, "utf-8");
|
|
1623
2755
|
}
|
|
1624
2756
|
const linesToAdd = [];
|
|
1625
2757
|
for (const rule of rulesFilesToIgnore) {
|
|
@@ -1636,45 +2768,283 @@ var gitignoreCommand = async () => {
|
|
|
1636
2768
|
${linesToAdd.join("\n")}
|
|
1637
2769
|
` : `${linesToAdd.join("\n")}
|
|
1638
2770
|
`;
|
|
1639
|
-
(0,
|
|
2771
|
+
(0, import_node_fs2.writeFileSync)(gitignorePath, newContent);
|
|
1640
2772
|
console.log(`\u2705 Added ${linesToAdd.length} rules to .gitignore:`);
|
|
1641
2773
|
for (const line of linesToAdd) {
|
|
1642
2774
|
if (!line.startsWith("#")) {
|
|
1643
2775
|
console.log(` ${line}`);
|
|
1644
2776
|
}
|
|
1645
2777
|
}
|
|
1646
|
-
};
|
|
1647
|
-
|
|
1648
|
-
// src/core/importer.ts
|
|
1649
|
-
var
|
|
1650
|
-
var
|
|
1651
|
-
|
|
1652
|
-
// src/parsers/
|
|
1653
|
-
var
|
|
1654
|
-
|
|
2778
|
+
};
|
|
2779
|
+
|
|
2780
|
+
// src/core/importer.ts
|
|
2781
|
+
var import_node_path21 = require("path");
|
|
2782
|
+
var import_gray_matter5 = __toESM(require("gray-matter"), 1);
|
|
2783
|
+
|
|
2784
|
+
// src/parsers/augmentcode.ts
|
|
2785
|
+
var import_node_path16 = require("path");
|
|
2786
|
+
var import_gray_matter2 = __toESM(require("gray-matter"), 1);
|
|
2787
|
+
|
|
2788
|
+
// src/utils/parser-helpers.ts
|
|
2789
|
+
function createParseResult() {
|
|
2790
|
+
return { rules: [], errors: [] };
|
|
2791
|
+
}
|
|
2792
|
+
function addError(result, error) {
|
|
2793
|
+
result.errors.push(error);
|
|
2794
|
+
}
|
|
2795
|
+
function addRule(result, rule) {
|
|
2796
|
+
if (!result.rules) {
|
|
2797
|
+
result.rules = [];
|
|
2798
|
+
}
|
|
2799
|
+
result.rules.push(rule);
|
|
2800
|
+
}
|
|
2801
|
+
function addRules(result, rules) {
|
|
2802
|
+
if (!result.rules) {
|
|
2803
|
+
result.rules = [];
|
|
2804
|
+
}
|
|
2805
|
+
result.rules.push(...rules);
|
|
2806
|
+
}
|
|
2807
|
+
function handleParseError(error, context) {
|
|
2808
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2809
|
+
return `${context}: ${errorMessage}`;
|
|
2810
|
+
}
|
|
2811
|
+
async function safeReadFile(operation, errorContext) {
|
|
2812
|
+
try {
|
|
2813
|
+
const result = await operation();
|
|
2814
|
+
return { success: true, result };
|
|
2815
|
+
} catch (error) {
|
|
2816
|
+
return {
|
|
2817
|
+
success: false,
|
|
2818
|
+
error: handleParseError(error, errorContext)
|
|
2819
|
+
};
|
|
2820
|
+
}
|
|
2821
|
+
}
|
|
2822
|
+
|
|
2823
|
+
// src/parsers/augmentcode.ts
|
|
2824
|
+
async function parseAugmentcodeConfiguration(baseDir = process.cwd()) {
|
|
2825
|
+
const result = createParseResult();
|
|
2826
|
+
const rulesDir = (0, import_node_path16.join)(baseDir, ".augment", "rules");
|
|
2827
|
+
if (await fileExists(rulesDir)) {
|
|
2828
|
+
const rulesResult = await parseAugmentRules(rulesDir);
|
|
2829
|
+
addRules(result, rulesResult.rules);
|
|
2830
|
+
result.errors.push(...rulesResult.errors);
|
|
2831
|
+
} else {
|
|
2832
|
+
addError(result, "No AugmentCode configuration found. Expected .augment/rules/ directory.");
|
|
2833
|
+
}
|
|
2834
|
+
return { rules: result.rules || [], errors: result.errors };
|
|
2835
|
+
}
|
|
2836
|
+
async function parseAugmentRules(rulesDir) {
|
|
2837
|
+
const rules = [];
|
|
2838
|
+
const errors = [];
|
|
2839
|
+
try {
|
|
2840
|
+
const { readdir: readdir2 } = await import("fs/promises");
|
|
2841
|
+
const files = await readdir2(rulesDir);
|
|
2842
|
+
for (const file of files) {
|
|
2843
|
+
if (file.endsWith(".md") || file.endsWith(".mdc")) {
|
|
2844
|
+
const filePath = (0, import_node_path16.join)(rulesDir, file);
|
|
2845
|
+
try {
|
|
2846
|
+
const rawContent = await readFileContent(filePath);
|
|
2847
|
+
const parsed = (0, import_gray_matter2.default)(rawContent);
|
|
2848
|
+
const frontmatterData = parsed.data;
|
|
2849
|
+
const ruleType = frontmatterData.type || "manual";
|
|
2850
|
+
const description = frontmatterData.description || "";
|
|
2851
|
+
const tags = Array.isArray(frontmatterData.tags) ? frontmatterData.tags : void 0;
|
|
2852
|
+
const isRoot = ruleType === "always";
|
|
2853
|
+
const filename = (0, import_node_path16.basename)(file, file.endsWith(".mdc") ? ".mdc" : ".md");
|
|
2854
|
+
const frontmatter = {
|
|
2855
|
+
root: isRoot,
|
|
2856
|
+
targets: ["augmentcode"],
|
|
2857
|
+
description,
|
|
2858
|
+
globs: ["**/*"],
|
|
2859
|
+
// AugmentCode doesn't use specific globs in the same way
|
|
2860
|
+
...tags && { tags }
|
|
2861
|
+
};
|
|
2862
|
+
rules.push({
|
|
2863
|
+
frontmatter,
|
|
2864
|
+
content: parsed.content.trim(),
|
|
2865
|
+
filename: `augmentcode-${ruleType}-${filename}`,
|
|
2866
|
+
filepath: filePath
|
|
2867
|
+
});
|
|
2868
|
+
} catch (error) {
|
|
2869
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2870
|
+
errors.push(`Failed to parse ${filePath}: ${errorMessage}`);
|
|
2871
|
+
}
|
|
2872
|
+
}
|
|
2873
|
+
}
|
|
2874
|
+
} catch (error) {
|
|
2875
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2876
|
+
errors.push(`Failed to read .augment/rules/ directory: ${errorMessage}`);
|
|
2877
|
+
}
|
|
2878
|
+
return { rules, errors };
|
|
2879
|
+
}
|
|
2880
|
+
|
|
2881
|
+
// src/parsers/augmentcode-legacy.ts
|
|
2882
|
+
var import_node_path17 = require("path");
|
|
2883
|
+
async function parseAugmentcodeLegacyConfiguration(baseDir = process.cwd()) {
|
|
2884
|
+
const result = createParseResult();
|
|
2885
|
+
const guidelinesPath = (0, import_node_path17.join)(baseDir, ".augment-guidelines");
|
|
2886
|
+
if (await fileExists(guidelinesPath)) {
|
|
2887
|
+
const guidelinesResult = await parseAugmentGuidelines(guidelinesPath);
|
|
2888
|
+
if (guidelinesResult.rule) {
|
|
2889
|
+
addRule(result, guidelinesResult.rule);
|
|
2890
|
+
}
|
|
2891
|
+
result.errors.push(...guidelinesResult.errors);
|
|
2892
|
+
} else {
|
|
2893
|
+
addError(
|
|
2894
|
+
result,
|
|
2895
|
+
"No AugmentCode legacy configuration found. Expected .augment-guidelines file."
|
|
2896
|
+
);
|
|
2897
|
+
}
|
|
2898
|
+
return { rules: result.rules || [], errors: result.errors };
|
|
2899
|
+
}
|
|
2900
|
+
async function parseAugmentGuidelines(guidelinesPath) {
|
|
2901
|
+
const parseResult = await safeReadFile(async () => {
|
|
2902
|
+
const content = await readFileContent(guidelinesPath);
|
|
2903
|
+
if (content.trim()) {
|
|
2904
|
+
const frontmatter = {
|
|
2905
|
+
root: true,
|
|
2906
|
+
// Legacy guidelines become root rules
|
|
2907
|
+
targets: ["augmentcode-legacy"],
|
|
2908
|
+
description: "Legacy AugmentCode guidelines",
|
|
2909
|
+
globs: ["**/*"]
|
|
2910
|
+
};
|
|
2911
|
+
return {
|
|
2912
|
+
frontmatter,
|
|
2913
|
+
content: content.trim(),
|
|
2914
|
+
filename: "augmentcode-legacy-guidelines",
|
|
2915
|
+
filepath: guidelinesPath
|
|
2916
|
+
};
|
|
2917
|
+
}
|
|
2918
|
+
return null;
|
|
2919
|
+
}, "Failed to parse .augment-guidelines");
|
|
2920
|
+
if (parseResult.success) {
|
|
2921
|
+
return { rule: parseResult.result || null, errors: [] };
|
|
2922
|
+
} else {
|
|
2923
|
+
return { rule: null, errors: [parseResult.error || "Unknown error"] };
|
|
2924
|
+
}
|
|
2925
|
+
}
|
|
2926
|
+
|
|
2927
|
+
// src/parsers/shared-helpers.ts
|
|
2928
|
+
var import_node_path18 = require("path");
|
|
2929
|
+
var import_gray_matter3 = __toESM(require("gray-matter"), 1);
|
|
2930
|
+
async function parseConfigurationFiles(baseDir = process.cwd(), config) {
|
|
2931
|
+
const errors = [];
|
|
2932
|
+
const rules = [];
|
|
2933
|
+
if (config.mainFile) {
|
|
2934
|
+
const mainFilePath = (0, import_node_path18.join)(baseDir, config.mainFile.path);
|
|
2935
|
+
if (await fileExists(mainFilePath)) {
|
|
2936
|
+
try {
|
|
2937
|
+
const rawContent = await readFileContent(mainFilePath);
|
|
2938
|
+
let content;
|
|
2939
|
+
let frontmatter;
|
|
2940
|
+
if (config.mainFile.useFrontmatter) {
|
|
2941
|
+
const parsed = (0, import_gray_matter3.default)(rawContent);
|
|
2942
|
+
content = parsed.content.trim();
|
|
2943
|
+
frontmatter = {
|
|
2944
|
+
root: false,
|
|
2945
|
+
targets: [config.tool],
|
|
2946
|
+
description: config.mainFile.description,
|
|
2947
|
+
globs: ["**/*"]
|
|
2948
|
+
};
|
|
2949
|
+
} else {
|
|
2950
|
+
content = rawContent.trim();
|
|
2951
|
+
frontmatter = {
|
|
2952
|
+
root: false,
|
|
2953
|
+
targets: [config.tool],
|
|
2954
|
+
description: config.mainFile.description,
|
|
2955
|
+
globs: ["**/*"]
|
|
2956
|
+
};
|
|
2957
|
+
}
|
|
2958
|
+
if (content) {
|
|
2959
|
+
rules.push({
|
|
2960
|
+
frontmatter,
|
|
2961
|
+
content,
|
|
2962
|
+
filename: `${config.tool}-instructions`,
|
|
2963
|
+
filepath: mainFilePath
|
|
2964
|
+
});
|
|
2965
|
+
}
|
|
2966
|
+
} catch (error) {
|
|
2967
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2968
|
+
errors.push(`Failed to parse ${config.mainFile.path}: ${errorMessage}`);
|
|
2969
|
+
}
|
|
2970
|
+
}
|
|
2971
|
+
}
|
|
2972
|
+
if (config.directories) {
|
|
2973
|
+
for (const dirConfig of config.directories) {
|
|
2974
|
+
const dirPath = (0, import_node_path18.join)(baseDir, dirConfig.directory);
|
|
2975
|
+
if (await fileExists(dirPath)) {
|
|
2976
|
+
try {
|
|
2977
|
+
const { readdir: readdir2 } = await import("fs/promises");
|
|
2978
|
+
const files = await readdir2(dirPath);
|
|
2979
|
+
for (const file of files) {
|
|
2980
|
+
if (file.endsWith(dirConfig.filePattern)) {
|
|
2981
|
+
const filePath = (0, import_node_path18.join)(dirPath, file);
|
|
2982
|
+
try {
|
|
2983
|
+
const rawContent = await readFileContent(filePath);
|
|
2984
|
+
let content;
|
|
2985
|
+
if (dirConfig.filePattern === ".instructions.md") {
|
|
2986
|
+
const parsed = (0, import_gray_matter3.default)(rawContent);
|
|
2987
|
+
content = parsed.content.trim();
|
|
2988
|
+
} else {
|
|
2989
|
+
content = rawContent.trim();
|
|
2990
|
+
}
|
|
2991
|
+
if (content) {
|
|
2992
|
+
const filename = file.replace(new RegExp(`\\${dirConfig.filePattern}$`), "");
|
|
2993
|
+
const frontmatter = {
|
|
2994
|
+
root: false,
|
|
2995
|
+
targets: [config.tool],
|
|
2996
|
+
description: `${dirConfig.description}: ${filename}`,
|
|
2997
|
+
globs: ["**/*"]
|
|
2998
|
+
};
|
|
2999
|
+
rules.push({
|
|
3000
|
+
frontmatter,
|
|
3001
|
+
content,
|
|
3002
|
+
filename: `${config.tool}-${filename}`,
|
|
3003
|
+
filepath: filePath
|
|
3004
|
+
});
|
|
3005
|
+
}
|
|
3006
|
+
} catch (error) {
|
|
3007
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3008
|
+
errors.push(`Failed to parse ${filePath}: ${errorMessage}`);
|
|
3009
|
+
}
|
|
3010
|
+
}
|
|
3011
|
+
}
|
|
3012
|
+
} catch (error) {
|
|
3013
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3014
|
+
errors.push(`Failed to parse ${dirConfig.directory} files: ${errorMessage}`);
|
|
3015
|
+
}
|
|
3016
|
+
}
|
|
3017
|
+
}
|
|
3018
|
+
}
|
|
3019
|
+
if (rules.length === 0) {
|
|
3020
|
+
errors.push(config.errorMessage);
|
|
3021
|
+
}
|
|
3022
|
+
return { rules, errors };
|
|
3023
|
+
}
|
|
3024
|
+
async function parseMemoryBasedConfiguration(baseDir = process.cwd(), config) {
|
|
1655
3025
|
const errors = [];
|
|
1656
3026
|
const rules = [];
|
|
1657
3027
|
let ignorePatterns;
|
|
1658
3028
|
let mcpServers;
|
|
1659
|
-
const
|
|
1660
|
-
if (!await fileExists(
|
|
1661
|
-
errors.push(
|
|
3029
|
+
const mainFilePath = (0, import_node_path18.join)(baseDir, config.mainFileName);
|
|
3030
|
+
if (!await fileExists(mainFilePath)) {
|
|
3031
|
+
errors.push(`${config.mainFileName} file not found`);
|
|
1662
3032
|
return { rules, errors };
|
|
1663
3033
|
}
|
|
1664
3034
|
try {
|
|
1665
|
-
const
|
|
1666
|
-
const mainRule =
|
|
3035
|
+
const mainContent = await readFileContent(mainFilePath);
|
|
3036
|
+
const mainRule = parseMainFile(mainContent, mainFilePath, config);
|
|
1667
3037
|
if (mainRule) {
|
|
1668
3038
|
rules.push(mainRule);
|
|
1669
3039
|
}
|
|
1670
|
-
const memoryDir = (0,
|
|
3040
|
+
const memoryDir = (0, import_node_path18.join)(baseDir, config.memoryDirPath);
|
|
1671
3041
|
if (await fileExists(memoryDir)) {
|
|
1672
|
-
const memoryRules = await
|
|
3042
|
+
const memoryRules = await parseMemoryFiles(memoryDir, config);
|
|
1673
3043
|
rules.push(...memoryRules);
|
|
1674
3044
|
}
|
|
1675
|
-
const settingsPath = (0,
|
|
3045
|
+
const settingsPath = (0, import_node_path18.join)(baseDir, config.settingsPath);
|
|
1676
3046
|
if (await fileExists(settingsPath)) {
|
|
1677
|
-
const settingsResult = await
|
|
3047
|
+
const settingsResult = await parseSettingsFile(settingsPath, config.tool);
|
|
1678
3048
|
if (settingsResult.ignorePatterns) {
|
|
1679
3049
|
ignorePatterns = settingsResult.ignorePatterns;
|
|
1680
3050
|
}
|
|
@@ -1683,9 +3053,18 @@ async function parseClaudeConfiguration(baseDir = process.cwd()) {
|
|
|
1683
3053
|
}
|
|
1684
3054
|
errors.push(...settingsResult.errors);
|
|
1685
3055
|
}
|
|
3056
|
+
if (config.additionalIgnoreFile) {
|
|
3057
|
+
const additionalIgnorePath = (0, import_node_path18.join)(baseDir, config.additionalIgnoreFile.path);
|
|
3058
|
+
if (await fileExists(additionalIgnorePath)) {
|
|
3059
|
+
const additionalPatterns = await config.additionalIgnoreFile.parser(additionalIgnorePath);
|
|
3060
|
+
if (additionalPatterns.length > 0) {
|
|
3061
|
+
ignorePatterns = ignorePatterns ? [...ignorePatterns, ...additionalPatterns] : additionalPatterns;
|
|
3062
|
+
}
|
|
3063
|
+
}
|
|
3064
|
+
}
|
|
1686
3065
|
} catch (error) {
|
|
1687
3066
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1688
|
-
errors.push(`Failed to parse
|
|
3067
|
+
errors.push(`Failed to parse ${config.tool} configuration: ${errorMessage}`);
|
|
1689
3068
|
}
|
|
1690
3069
|
return {
|
|
1691
3070
|
rules,
|
|
@@ -1694,7 +3073,7 @@ async function parseClaudeConfiguration(baseDir = process.cwd()) {
|
|
|
1694
3073
|
...mcpServers && { mcpServers }
|
|
1695
3074
|
};
|
|
1696
3075
|
}
|
|
1697
|
-
function
|
|
3076
|
+
function parseMainFile(content, filepath, config) {
|
|
1698
3077
|
const lines = content.split("\n");
|
|
1699
3078
|
let contentStartIndex = 0;
|
|
1700
3079
|
if (lines.some((line) => line.includes("| Document | Description | File Patterns |"))) {
|
|
@@ -1711,38 +3090,38 @@ function parseClaudeMainFile(content, filepath) {
|
|
|
1711
3090
|
}
|
|
1712
3091
|
const frontmatter = {
|
|
1713
3092
|
root: false,
|
|
1714
|
-
targets: [
|
|
1715
|
-
description:
|
|
3093
|
+
targets: [config.tool],
|
|
3094
|
+
description: config.mainDescription,
|
|
1716
3095
|
globs: ["**/*"]
|
|
1717
3096
|
};
|
|
1718
3097
|
return {
|
|
1719
3098
|
frontmatter,
|
|
1720
3099
|
content: mainContent,
|
|
1721
|
-
filename:
|
|
3100
|
+
filename: `${config.filenamePrefix}-main`,
|
|
1722
3101
|
filepath
|
|
1723
3102
|
};
|
|
1724
3103
|
}
|
|
1725
|
-
async function
|
|
3104
|
+
async function parseMemoryFiles(memoryDir, config) {
|
|
1726
3105
|
const rules = [];
|
|
1727
3106
|
try {
|
|
1728
3107
|
const { readdir: readdir2 } = await import("fs/promises");
|
|
1729
3108
|
const files = await readdir2(memoryDir);
|
|
1730
3109
|
for (const file of files) {
|
|
1731
3110
|
if (file.endsWith(".md")) {
|
|
1732
|
-
const filePath = (0,
|
|
3111
|
+
const filePath = (0, import_node_path18.join)(memoryDir, file);
|
|
1733
3112
|
const content = await readFileContent(filePath);
|
|
1734
3113
|
if (content.trim()) {
|
|
1735
|
-
const filename = (0,
|
|
3114
|
+
const filename = (0, import_node_path18.basename)(file, ".md");
|
|
1736
3115
|
const frontmatter = {
|
|
1737
3116
|
root: false,
|
|
1738
|
-
targets: [
|
|
1739
|
-
description:
|
|
3117
|
+
targets: [config.tool],
|
|
3118
|
+
description: `${config.memoryDescription}: ${filename}`,
|
|
1740
3119
|
globs: ["**/*"]
|
|
1741
3120
|
};
|
|
1742
3121
|
rules.push({
|
|
1743
3122
|
frontmatter,
|
|
1744
3123
|
content: content.trim(),
|
|
1745
|
-
filename:
|
|
3124
|
+
filename: `${config.filenamePrefix}-memory-${filename}`,
|
|
1746
3125
|
filepath: filePath
|
|
1747
3126
|
});
|
|
1748
3127
|
}
|
|
@@ -1752,14 +3131,14 @@ async function parseClaudeMemoryFiles(memoryDir) {
|
|
|
1752
3131
|
}
|
|
1753
3132
|
return rules;
|
|
1754
3133
|
}
|
|
1755
|
-
async function
|
|
3134
|
+
async function parseSettingsFile(settingsPath, tool) {
|
|
1756
3135
|
const errors = [];
|
|
1757
3136
|
let ignorePatterns;
|
|
1758
3137
|
let mcpServers;
|
|
1759
3138
|
try {
|
|
1760
3139
|
const content = await readFileContent(settingsPath);
|
|
1761
3140
|
const settings = JSON.parse(content);
|
|
1762
|
-
if (typeof settings === "object" && settings !== null && "permissions" in settings) {
|
|
3141
|
+
if (tool === "claudecode" && typeof settings === "object" && settings !== null && "permissions" in settings) {
|
|
1763
3142
|
const permissions = settings.permissions;
|
|
1764
3143
|
if (typeof permissions !== "object" || permissions === null) {
|
|
1765
3144
|
return { ignorePatterns: [], errors: [] };
|
|
@@ -1791,153 +3170,64 @@ async function parseClaudeSettings(settingsPath) {
|
|
|
1791
3170
|
};
|
|
1792
3171
|
}
|
|
1793
3172
|
|
|
3173
|
+
// src/parsers/claudecode.ts
|
|
3174
|
+
async function parseClaudeConfiguration(baseDir = process.cwd()) {
|
|
3175
|
+
return parseMemoryBasedConfiguration(baseDir, {
|
|
3176
|
+
tool: "claudecode",
|
|
3177
|
+
mainFileName: "CLAUDE.md",
|
|
3178
|
+
memoryDirPath: ".claude/memories",
|
|
3179
|
+
settingsPath: ".claude/settings.json",
|
|
3180
|
+
mainDescription: "Main Claude Code configuration",
|
|
3181
|
+
memoryDescription: "Memory file",
|
|
3182
|
+
filenamePrefix: "claude"
|
|
3183
|
+
});
|
|
3184
|
+
}
|
|
3185
|
+
|
|
1794
3186
|
// src/parsers/cline.ts
|
|
1795
|
-
var import_node_path14 = require("path");
|
|
1796
3187
|
async function parseClineConfiguration(baseDir = process.cwd()) {
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
};
|
|
1810
|
-
rules.push({
|
|
1811
|
-
frontmatter,
|
|
1812
|
-
content: content.trim(),
|
|
1813
|
-
filename: "cline-instructions",
|
|
1814
|
-
filepath: clineFilePath
|
|
1815
|
-
});
|
|
1816
|
-
}
|
|
1817
|
-
} catch (error) {
|
|
1818
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1819
|
-
errors.push(`Failed to parse .cline/instructions.md: ${errorMessage}`);
|
|
1820
|
-
}
|
|
1821
|
-
}
|
|
1822
|
-
const clinerulesDirPath = (0, import_node_path14.join)(baseDir, ".clinerules");
|
|
1823
|
-
if (await fileExists(clinerulesDirPath)) {
|
|
1824
|
-
try {
|
|
1825
|
-
const { readdir: readdir2 } = await import("fs/promises");
|
|
1826
|
-
const files = await readdir2(clinerulesDirPath);
|
|
1827
|
-
for (const file of files) {
|
|
1828
|
-
if (file.endsWith(".md")) {
|
|
1829
|
-
const filePath = (0, import_node_path14.join)(clinerulesDirPath, file);
|
|
1830
|
-
try {
|
|
1831
|
-
const content = await readFileContent(filePath);
|
|
1832
|
-
if (content.trim()) {
|
|
1833
|
-
const filename = file.replace(".md", "");
|
|
1834
|
-
const frontmatter = {
|
|
1835
|
-
root: false,
|
|
1836
|
-
targets: ["cline"],
|
|
1837
|
-
description: `Cline rule: ${filename}`,
|
|
1838
|
-
globs: ["**/*"]
|
|
1839
|
-
};
|
|
1840
|
-
rules.push({
|
|
1841
|
-
frontmatter,
|
|
1842
|
-
content: content.trim(),
|
|
1843
|
-
filename: `cline-${filename}`,
|
|
1844
|
-
filepath: filePath
|
|
1845
|
-
});
|
|
1846
|
-
}
|
|
1847
|
-
} catch (error) {
|
|
1848
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1849
|
-
errors.push(`Failed to parse ${filePath}: ${errorMessage}`);
|
|
1850
|
-
}
|
|
1851
|
-
}
|
|
3188
|
+
return parseConfigurationFiles(baseDir, {
|
|
3189
|
+
tool: "cline",
|
|
3190
|
+
mainFile: {
|
|
3191
|
+
path: ".cline/instructions.md",
|
|
3192
|
+
useFrontmatter: false,
|
|
3193
|
+
description: "Cline instructions"
|
|
3194
|
+
},
|
|
3195
|
+
directories: [
|
|
3196
|
+
{
|
|
3197
|
+
directory: ".clinerules",
|
|
3198
|
+
filePattern: ".md",
|
|
3199
|
+
description: "Cline rule"
|
|
1852
3200
|
}
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
}
|
|
1857
|
-
}
|
|
1858
|
-
if (rules.length === 0) {
|
|
1859
|
-
errors.push("No Cline configuration files found (.cline/instructions.md or .clinerules/*.md)");
|
|
1860
|
-
}
|
|
1861
|
-
return { rules, errors };
|
|
3201
|
+
],
|
|
3202
|
+
errorMessage: "No Cline configuration files found (.cline/instructions.md or .clinerules/*.md)"
|
|
3203
|
+
});
|
|
1862
3204
|
}
|
|
1863
3205
|
|
|
1864
3206
|
// src/parsers/copilot.ts
|
|
1865
|
-
var import_node_path15 = require("path");
|
|
1866
|
-
var import_gray_matter2 = __toESM(require("gray-matter"), 1);
|
|
1867
3207
|
async function parseCopilotConfiguration(baseDir = process.cwd()) {
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
description: "GitHub Copilot instructions",
|
|
1881
|
-
globs: ["**/*"]
|
|
1882
|
-
};
|
|
1883
|
-
rules.push({
|
|
1884
|
-
frontmatter,
|
|
1885
|
-
content,
|
|
1886
|
-
filename: "copilot-instructions",
|
|
1887
|
-
filepath: copilotFilePath
|
|
1888
|
-
});
|
|
1889
|
-
}
|
|
1890
|
-
} catch (error) {
|
|
1891
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1892
|
-
errors.push(`Failed to parse copilot-instructions.md: ${errorMessage}`);
|
|
1893
|
-
}
|
|
1894
|
-
}
|
|
1895
|
-
const instructionsDir = (0, import_node_path15.join)(baseDir, ".github", "instructions");
|
|
1896
|
-
if (await fileExists(instructionsDir)) {
|
|
1897
|
-
try {
|
|
1898
|
-
const { readdir: readdir2 } = await import("fs/promises");
|
|
1899
|
-
const files = await readdir2(instructionsDir);
|
|
1900
|
-
for (const file of files) {
|
|
1901
|
-
if (file.endsWith(".instructions.md")) {
|
|
1902
|
-
const filePath = (0, import_node_path15.join)(instructionsDir, file);
|
|
1903
|
-
const rawContent = await readFileContent(filePath);
|
|
1904
|
-
const parsed = (0, import_gray_matter2.default)(rawContent);
|
|
1905
|
-
const content = parsed.content.trim();
|
|
1906
|
-
if (content) {
|
|
1907
|
-
const filename = (0, import_node_path15.basename)(file, ".instructions.md");
|
|
1908
|
-
const frontmatter = {
|
|
1909
|
-
root: false,
|
|
1910
|
-
targets: ["copilot"],
|
|
1911
|
-
description: `Copilot instruction: ${filename}`,
|
|
1912
|
-
globs: ["**/*"]
|
|
1913
|
-
};
|
|
1914
|
-
rules.push({
|
|
1915
|
-
frontmatter,
|
|
1916
|
-
content,
|
|
1917
|
-
filename: `copilot-${filename}`,
|
|
1918
|
-
filepath: filePath
|
|
1919
|
-
});
|
|
1920
|
-
}
|
|
1921
|
-
}
|
|
3208
|
+
return parseConfigurationFiles(baseDir, {
|
|
3209
|
+
tool: "copilot",
|
|
3210
|
+
mainFile: {
|
|
3211
|
+
path: ".github/copilot-instructions.md",
|
|
3212
|
+
useFrontmatter: true,
|
|
3213
|
+
description: "GitHub Copilot instructions"
|
|
3214
|
+
},
|
|
3215
|
+
directories: [
|
|
3216
|
+
{
|
|
3217
|
+
directory: ".github/instructions",
|
|
3218
|
+
filePattern: ".instructions.md",
|
|
3219
|
+
description: "Copilot instruction"
|
|
1922
3220
|
}
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
}
|
|
1927
|
-
}
|
|
1928
|
-
if (rules.length === 0) {
|
|
1929
|
-
errors.push(
|
|
1930
|
-
"No Copilot configuration files found (.github/copilot-instructions.md or .github/instructions/*.instructions.md)"
|
|
1931
|
-
);
|
|
1932
|
-
}
|
|
1933
|
-
return { rules, errors };
|
|
3221
|
+
],
|
|
3222
|
+
errorMessage: "No Copilot configuration files found (.github/copilot-instructions.md or .github/instructions/*.instructions.md)"
|
|
3223
|
+
});
|
|
1934
3224
|
}
|
|
1935
3225
|
|
|
1936
3226
|
// src/parsers/cursor.ts
|
|
1937
|
-
var
|
|
1938
|
-
var
|
|
3227
|
+
var import_node_path19 = require("path");
|
|
3228
|
+
var import_gray_matter4 = __toESM(require("gray-matter"), 1);
|
|
1939
3229
|
var import_js_yaml = require("js-yaml");
|
|
1940
|
-
var
|
|
3230
|
+
var import_mini7 = require("zod/mini");
|
|
1941
3231
|
var customMatterOptions = {
|
|
1942
3232
|
engines: {
|
|
1943
3233
|
yaml: {
|
|
@@ -1965,7 +3255,7 @@ var customMatterOptions = {
|
|
|
1965
3255
|
}
|
|
1966
3256
|
};
|
|
1967
3257
|
function convertCursorMdcFrontmatter(cursorFrontmatter, _filename) {
|
|
1968
|
-
const FrontmatterSchema =
|
|
3258
|
+
const FrontmatterSchema = import_mini7.z.record(import_mini7.z.string(), import_mini7.z.unknown());
|
|
1969
3259
|
const parseResult = FrontmatterSchema.safeParse(cursorFrontmatter);
|
|
1970
3260
|
if (!parseResult.success) {
|
|
1971
3261
|
return {
|
|
@@ -2059,11 +3349,11 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
2059
3349
|
const rules = [];
|
|
2060
3350
|
let ignorePatterns;
|
|
2061
3351
|
let mcpServers;
|
|
2062
|
-
const cursorFilePath = (0,
|
|
3352
|
+
const cursorFilePath = (0, import_node_path19.join)(baseDir, ".cursorrules");
|
|
2063
3353
|
if (await fileExists(cursorFilePath)) {
|
|
2064
3354
|
try {
|
|
2065
3355
|
const rawContent = await readFileContent(cursorFilePath);
|
|
2066
|
-
const parsed = (0,
|
|
3356
|
+
const parsed = (0, import_gray_matter4.default)(rawContent, customMatterOptions);
|
|
2067
3357
|
const content = parsed.content.trim();
|
|
2068
3358
|
if (content) {
|
|
2069
3359
|
const frontmatter = convertCursorMdcFrontmatter(parsed.data, "cursorrules");
|
|
@@ -2080,20 +3370,20 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
2080
3370
|
errors.push(`Failed to parse .cursorrules file: ${errorMessage}`);
|
|
2081
3371
|
}
|
|
2082
3372
|
}
|
|
2083
|
-
const cursorRulesDir = (0,
|
|
3373
|
+
const cursorRulesDir = (0, import_node_path19.join)(baseDir, ".cursor", "rules");
|
|
2084
3374
|
if (await fileExists(cursorRulesDir)) {
|
|
2085
3375
|
try {
|
|
2086
3376
|
const { readdir: readdir2 } = await import("fs/promises");
|
|
2087
3377
|
const files = await readdir2(cursorRulesDir);
|
|
2088
3378
|
for (const file of files) {
|
|
2089
3379
|
if (file.endsWith(".mdc")) {
|
|
2090
|
-
const filePath = (0,
|
|
3380
|
+
const filePath = (0, import_node_path19.join)(cursorRulesDir, file);
|
|
2091
3381
|
try {
|
|
2092
3382
|
const rawContent = await readFileContent(filePath);
|
|
2093
|
-
const parsed = (0,
|
|
3383
|
+
const parsed = (0, import_gray_matter4.default)(rawContent, customMatterOptions);
|
|
2094
3384
|
const content = parsed.content.trim();
|
|
2095
3385
|
if (content) {
|
|
2096
|
-
const filename = (0,
|
|
3386
|
+
const filename = (0, import_node_path19.basename)(file, ".mdc");
|
|
2097
3387
|
const frontmatter = convertCursorMdcFrontmatter(parsed.data, filename);
|
|
2098
3388
|
rules.push({
|
|
2099
3389
|
frontmatter,
|
|
@@ -2116,7 +3406,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
2116
3406
|
if (rules.length === 0) {
|
|
2117
3407
|
errors.push("No Cursor configuration files found (.cursorrules or .cursor/rules/*.mdc)");
|
|
2118
3408
|
}
|
|
2119
|
-
const cursorIgnorePath = (0,
|
|
3409
|
+
const cursorIgnorePath = (0, import_node_path19.join)(baseDir, ".cursorignore");
|
|
2120
3410
|
if (await fileExists(cursorIgnorePath)) {
|
|
2121
3411
|
try {
|
|
2122
3412
|
const content = await readFileContent(cursorIgnorePath);
|
|
@@ -2129,7 +3419,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
2129
3419
|
errors.push(`Failed to parse .cursorignore: ${errorMessage}`);
|
|
2130
3420
|
}
|
|
2131
3421
|
}
|
|
2132
|
-
const cursorMcpPath = (0,
|
|
3422
|
+
const cursorMcpPath = (0, import_node_path19.join)(baseDir, ".cursor", "mcp.json");
|
|
2133
3423
|
if (await fileExists(cursorMcpPath)) {
|
|
2134
3424
|
try {
|
|
2135
3425
|
const content = await readFileContent(cursorMcpPath);
|
|
@@ -2152,134 +3442,6 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
2152
3442
|
}
|
|
2153
3443
|
|
|
2154
3444
|
// src/parsers/geminicli.ts
|
|
2155
|
-
var import_node_path17 = require("path");
|
|
2156
|
-
async function parseGeminiConfiguration(baseDir = process.cwd()) {
|
|
2157
|
-
const errors = [];
|
|
2158
|
-
const rules = [];
|
|
2159
|
-
let ignorePatterns;
|
|
2160
|
-
let mcpServers;
|
|
2161
|
-
const geminiFilePath = (0, import_node_path17.join)(baseDir, "GEMINI.md");
|
|
2162
|
-
if (!await fileExists(geminiFilePath)) {
|
|
2163
|
-
errors.push("GEMINI.md file not found");
|
|
2164
|
-
return { rules, errors };
|
|
2165
|
-
}
|
|
2166
|
-
try {
|
|
2167
|
-
const geminiContent = await readFileContent(geminiFilePath);
|
|
2168
|
-
const mainRule = parseGeminiMainFile(geminiContent, geminiFilePath);
|
|
2169
|
-
if (mainRule) {
|
|
2170
|
-
rules.push(mainRule);
|
|
2171
|
-
}
|
|
2172
|
-
const memoryDir = (0, import_node_path17.join)(baseDir, ".gemini", "memories");
|
|
2173
|
-
if (await fileExists(memoryDir)) {
|
|
2174
|
-
const memoryRules = await parseGeminiMemoryFiles(memoryDir);
|
|
2175
|
-
rules.push(...memoryRules);
|
|
2176
|
-
}
|
|
2177
|
-
const settingsPath = (0, import_node_path17.join)(baseDir, ".gemini", "settings.json");
|
|
2178
|
-
if (await fileExists(settingsPath)) {
|
|
2179
|
-
const settingsResult = await parseGeminiSettings(settingsPath);
|
|
2180
|
-
if (settingsResult.ignorePatterns) {
|
|
2181
|
-
ignorePatterns = settingsResult.ignorePatterns;
|
|
2182
|
-
}
|
|
2183
|
-
if (settingsResult.mcpServers) {
|
|
2184
|
-
mcpServers = settingsResult.mcpServers;
|
|
2185
|
-
}
|
|
2186
|
-
errors.push(...settingsResult.errors);
|
|
2187
|
-
}
|
|
2188
|
-
const aiexcludePath = (0, import_node_path17.join)(baseDir, ".aiexclude");
|
|
2189
|
-
if (await fileExists(aiexcludePath)) {
|
|
2190
|
-
const aiexcludePatterns = await parseAiexclude(aiexcludePath);
|
|
2191
|
-
if (aiexcludePatterns.length > 0) {
|
|
2192
|
-
ignorePatterns = ignorePatterns ? [...ignorePatterns, ...aiexcludePatterns] : aiexcludePatterns;
|
|
2193
|
-
}
|
|
2194
|
-
}
|
|
2195
|
-
} catch (error) {
|
|
2196
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2197
|
-
errors.push(`Failed to parse Gemini configuration: ${errorMessage}`);
|
|
2198
|
-
}
|
|
2199
|
-
return {
|
|
2200
|
-
rules,
|
|
2201
|
-
errors,
|
|
2202
|
-
...ignorePatterns && { ignorePatterns },
|
|
2203
|
-
...mcpServers && { mcpServers }
|
|
2204
|
-
};
|
|
2205
|
-
}
|
|
2206
|
-
function parseGeminiMainFile(content, filepath) {
|
|
2207
|
-
const lines = content.split("\n");
|
|
2208
|
-
let contentStartIndex = 0;
|
|
2209
|
-
if (lines.some((line) => line.includes("| Document | Description | File Patterns |"))) {
|
|
2210
|
-
const tableEndIndex = lines.findIndex(
|
|
2211
|
-
(line, index) => index > 0 && line.trim() === "" && lines[index - 1]?.includes("|") && !lines[index + 1]?.includes("|")
|
|
2212
|
-
);
|
|
2213
|
-
if (tableEndIndex !== -1) {
|
|
2214
|
-
contentStartIndex = tableEndIndex + 1;
|
|
2215
|
-
}
|
|
2216
|
-
}
|
|
2217
|
-
const mainContent = lines.slice(contentStartIndex).join("\n").trim();
|
|
2218
|
-
if (!mainContent) {
|
|
2219
|
-
return null;
|
|
2220
|
-
}
|
|
2221
|
-
const frontmatter = {
|
|
2222
|
-
root: false,
|
|
2223
|
-
targets: ["geminicli"],
|
|
2224
|
-
description: "Main Gemini CLI configuration",
|
|
2225
|
-
globs: ["**/*"]
|
|
2226
|
-
};
|
|
2227
|
-
return {
|
|
2228
|
-
frontmatter,
|
|
2229
|
-
content: mainContent,
|
|
2230
|
-
filename: "gemini-main",
|
|
2231
|
-
filepath
|
|
2232
|
-
};
|
|
2233
|
-
}
|
|
2234
|
-
async function parseGeminiMemoryFiles(memoryDir) {
|
|
2235
|
-
const rules = [];
|
|
2236
|
-
try {
|
|
2237
|
-
const { readdir: readdir2 } = await import("fs/promises");
|
|
2238
|
-
const files = await readdir2(memoryDir);
|
|
2239
|
-
for (const file of files) {
|
|
2240
|
-
if (file.endsWith(".md")) {
|
|
2241
|
-
const filePath = (0, import_node_path17.join)(memoryDir, file);
|
|
2242
|
-
const content = await readFileContent(filePath);
|
|
2243
|
-
if (content.trim()) {
|
|
2244
|
-
const filename = (0, import_node_path17.basename)(file, ".md");
|
|
2245
|
-
const frontmatter = {
|
|
2246
|
-
root: false,
|
|
2247
|
-
targets: ["geminicli"],
|
|
2248
|
-
description: `Memory file: ${filename}`,
|
|
2249
|
-
globs: ["**/*"]
|
|
2250
|
-
};
|
|
2251
|
-
rules.push({
|
|
2252
|
-
frontmatter,
|
|
2253
|
-
content: content.trim(),
|
|
2254
|
-
filename: `gemini-memory-${filename}`,
|
|
2255
|
-
filepath: filePath
|
|
2256
|
-
});
|
|
2257
|
-
}
|
|
2258
|
-
}
|
|
2259
|
-
}
|
|
2260
|
-
} catch {
|
|
2261
|
-
}
|
|
2262
|
-
return rules;
|
|
2263
|
-
}
|
|
2264
|
-
async function parseGeminiSettings(settingsPath) {
|
|
2265
|
-
const errors = [];
|
|
2266
|
-
let mcpServers;
|
|
2267
|
-
try {
|
|
2268
|
-
const content = await readFileContent(settingsPath);
|
|
2269
|
-
const settings = JSON.parse(content);
|
|
2270
|
-
const parseResult = RulesyncMcpConfigSchema.safeParse(settings);
|
|
2271
|
-
if (parseResult.success && Object.keys(parseResult.data.mcpServers).length > 0) {
|
|
2272
|
-
mcpServers = parseResult.data.mcpServers;
|
|
2273
|
-
}
|
|
2274
|
-
} catch (error) {
|
|
2275
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2276
|
-
errors.push(`Failed to parse settings.json: ${errorMessage}`);
|
|
2277
|
-
}
|
|
2278
|
-
return {
|
|
2279
|
-
errors,
|
|
2280
|
-
...mcpServers && { mcpServers }
|
|
2281
|
-
};
|
|
2282
|
-
}
|
|
2283
3445
|
async function parseAiexclude(aiexcludePath) {
|
|
2284
3446
|
try {
|
|
2285
3447
|
const content = await readFileContent(aiexcludePath);
|
|
@@ -2289,77 +3451,78 @@ async function parseAiexclude(aiexcludePath) {
|
|
|
2289
3451
|
return [];
|
|
2290
3452
|
}
|
|
2291
3453
|
}
|
|
3454
|
+
async function parseGeminiConfiguration(baseDir = process.cwd()) {
|
|
3455
|
+
return parseMemoryBasedConfiguration(baseDir, {
|
|
3456
|
+
tool: "geminicli",
|
|
3457
|
+
mainFileName: "GEMINI.md",
|
|
3458
|
+
memoryDirPath: ".gemini/memories",
|
|
3459
|
+
settingsPath: ".gemini/settings.json",
|
|
3460
|
+
mainDescription: "Main Gemini CLI configuration",
|
|
3461
|
+
memoryDescription: "Memory file",
|
|
3462
|
+
filenamePrefix: "gemini",
|
|
3463
|
+
additionalIgnoreFile: {
|
|
3464
|
+
path: ".aiexclude",
|
|
3465
|
+
parser: parseAiexclude
|
|
3466
|
+
}
|
|
3467
|
+
});
|
|
3468
|
+
}
|
|
2292
3469
|
|
|
2293
|
-
// src/parsers/
|
|
2294
|
-
var
|
|
2295
|
-
async function
|
|
3470
|
+
// src/parsers/junie.ts
|
|
3471
|
+
var import_node_path20 = require("path");
|
|
3472
|
+
async function parseJunieConfiguration(baseDir = process.cwd()) {
|
|
2296
3473
|
const errors = [];
|
|
2297
3474
|
const rules = [];
|
|
2298
|
-
const
|
|
2299
|
-
if (await fileExists(
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
if (content.trim()) {
|
|
2303
|
-
const frontmatter = {
|
|
2304
|
-
root: false,
|
|
2305
|
-
targets: ["roo"],
|
|
2306
|
-
description: "Roo Code instructions",
|
|
2307
|
-
globs: ["**/*"]
|
|
2308
|
-
};
|
|
2309
|
-
rules.push({
|
|
2310
|
-
frontmatter,
|
|
2311
|
-
content: content.trim(),
|
|
2312
|
-
filename: "roo-instructions",
|
|
2313
|
-
filepath: rooFilePath
|
|
2314
|
-
});
|
|
2315
|
-
}
|
|
2316
|
-
} catch (error) {
|
|
2317
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2318
|
-
errors.push(`Failed to parse .roo/instructions.md: ${errorMessage}`);
|
|
2319
|
-
}
|
|
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 };
|
|
2320
3479
|
}
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
const
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
description: `Roo rule: ${filename}`,
|
|
2337
|
-
globs: ["**/*"]
|
|
2338
|
-
};
|
|
2339
|
-
rules.push({
|
|
2340
|
-
frontmatter,
|
|
2341
|
-
content: content.trim(),
|
|
2342
|
-
filename: `roo-${filename}`,
|
|
2343
|
-
filepath: filePath
|
|
2344
|
-
});
|
|
2345
|
-
}
|
|
2346
|
-
} catch (error) {
|
|
2347
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2348
|
-
errors.push(`Failed to parse ${filePath}: ${errorMessage}`);
|
|
2349
|
-
}
|
|
2350
|
-
}
|
|
2351
|
-
}
|
|
2352
|
-
} catch (error) {
|
|
2353
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2354
|
-
errors.push(`Failed to parse .roo/rules files: ${errorMessage}`);
|
|
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
|
+
});
|
|
2355
3495
|
}
|
|
3496
|
+
} catch (error) {
|
|
3497
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3498
|
+
errors.push(`Failed to parse .junie/guidelines.md: ${errorMessage}`);
|
|
2356
3499
|
}
|
|
2357
3500
|
if (rules.length === 0) {
|
|
2358
|
-
errors.push("No
|
|
3501
|
+
errors.push("No valid Junie configuration found");
|
|
2359
3502
|
}
|
|
2360
3503
|
return { rules, errors };
|
|
2361
3504
|
}
|
|
2362
3505
|
|
|
3506
|
+
// src/parsers/roo.ts
|
|
3507
|
+
async function parseRooConfiguration(baseDir = process.cwd()) {
|
|
3508
|
+
return parseConfigurationFiles(baseDir, {
|
|
3509
|
+
tool: "roo",
|
|
3510
|
+
mainFile: {
|
|
3511
|
+
path: ".roo/instructions.md",
|
|
3512
|
+
useFrontmatter: false,
|
|
3513
|
+
description: "Roo Code instructions"
|
|
3514
|
+
},
|
|
3515
|
+
directories: [
|
|
3516
|
+
{
|
|
3517
|
+
directory: ".roo/rules",
|
|
3518
|
+
filePattern: ".md",
|
|
3519
|
+
description: "Roo rule"
|
|
3520
|
+
}
|
|
3521
|
+
],
|
|
3522
|
+
errorMessage: "No Roo Code configuration files found (.roo/instructions.md or .roo/rules/*.md)"
|
|
3523
|
+
});
|
|
3524
|
+
}
|
|
3525
|
+
|
|
2363
3526
|
// src/core/importer.ts
|
|
2364
3527
|
async function importConfiguration(options) {
|
|
2365
3528
|
const { tool, baseDir = process.cwd(), rulesDir = ".rulesync", verbose = false } = options;
|
|
@@ -2372,6 +3535,18 @@ async function importConfiguration(options) {
|
|
|
2372
3535
|
}
|
|
2373
3536
|
try {
|
|
2374
3537
|
switch (tool) {
|
|
3538
|
+
case "augmentcode": {
|
|
3539
|
+
const augmentResult = await parseAugmentcodeConfiguration(baseDir);
|
|
3540
|
+
rules = augmentResult.rules;
|
|
3541
|
+
errors.push(...augmentResult.errors);
|
|
3542
|
+
break;
|
|
3543
|
+
}
|
|
3544
|
+
case "augmentcode-legacy": {
|
|
3545
|
+
const augmentLegacyResult = await parseAugmentcodeLegacyConfiguration(baseDir);
|
|
3546
|
+
rules = augmentLegacyResult.rules;
|
|
3547
|
+
errors.push(...augmentLegacyResult.errors);
|
|
3548
|
+
break;
|
|
3549
|
+
}
|
|
2375
3550
|
case "claudecode": {
|
|
2376
3551
|
const claudeResult = await parseClaudeConfiguration(baseDir);
|
|
2377
3552
|
rules = claudeResult.rules;
|
|
@@ -2414,6 +3589,12 @@ async function importConfiguration(options) {
|
|
|
2414
3589
|
mcpServers = geminiResult.mcpServers;
|
|
2415
3590
|
break;
|
|
2416
3591
|
}
|
|
3592
|
+
case "junie": {
|
|
3593
|
+
const junieResult = await parseJunieConfiguration(baseDir);
|
|
3594
|
+
rules = junieResult.rules;
|
|
3595
|
+
errors.push(...junieResult.errors);
|
|
3596
|
+
break;
|
|
3597
|
+
}
|
|
2417
3598
|
default:
|
|
2418
3599
|
errors.push(`Unsupported tool: ${tool}`);
|
|
2419
3600
|
return { success: false, rulesCreated: 0, errors };
|
|
@@ -2426,7 +3607,7 @@ async function importConfiguration(options) {
|
|
|
2426
3607
|
if (rules.length === 0 && !ignorePatterns && !mcpServers) {
|
|
2427
3608
|
return { success: false, rulesCreated: 0, errors };
|
|
2428
3609
|
}
|
|
2429
|
-
const rulesDirPath = (0,
|
|
3610
|
+
const rulesDirPath = (0, import_node_path21.join)(baseDir, rulesDir);
|
|
2430
3611
|
try {
|
|
2431
3612
|
const { mkdir: mkdir3 } = await import("fs/promises");
|
|
2432
3613
|
await mkdir3(rulesDirPath, { recursive: true });
|
|
@@ -2440,7 +3621,7 @@ async function importConfiguration(options) {
|
|
|
2440
3621
|
try {
|
|
2441
3622
|
const baseFilename = `${tool}__${rule.filename}`;
|
|
2442
3623
|
const filename = await generateUniqueFilename(rulesDirPath, baseFilename);
|
|
2443
|
-
const filePath = (0,
|
|
3624
|
+
const filePath = (0, import_node_path21.join)(rulesDirPath, `${filename}.md`);
|
|
2444
3625
|
const content = generateRuleFileContent(rule);
|
|
2445
3626
|
await writeFileContent(filePath, content);
|
|
2446
3627
|
rulesCreated++;
|
|
@@ -2455,7 +3636,7 @@ async function importConfiguration(options) {
|
|
|
2455
3636
|
let ignoreFileCreated = false;
|
|
2456
3637
|
if (ignorePatterns && ignorePatterns.length > 0) {
|
|
2457
3638
|
try {
|
|
2458
|
-
const rulesyncignorePath = (0,
|
|
3639
|
+
const rulesyncignorePath = (0, import_node_path21.join)(baseDir, ".rulesyncignore");
|
|
2459
3640
|
const ignoreContent = `${ignorePatterns.join("\n")}
|
|
2460
3641
|
`;
|
|
2461
3642
|
await writeFileContent(rulesyncignorePath, ignoreContent);
|
|
@@ -2471,7 +3652,7 @@ async function importConfiguration(options) {
|
|
|
2471
3652
|
let mcpFileCreated = false;
|
|
2472
3653
|
if (mcpServers && Object.keys(mcpServers).length > 0) {
|
|
2473
3654
|
try {
|
|
2474
|
-
const mcpPath = (0,
|
|
3655
|
+
const mcpPath = (0, import_node_path21.join)(baseDir, rulesDir, ".mcp.json");
|
|
2475
3656
|
const mcpContent = `${JSON.stringify({ mcpServers }, null, 2)}
|
|
2476
3657
|
`;
|
|
2477
3658
|
await writeFileContent(mcpPath, mcpContent);
|
|
@@ -2493,13 +3674,13 @@ async function importConfiguration(options) {
|
|
|
2493
3674
|
};
|
|
2494
3675
|
}
|
|
2495
3676
|
function generateRuleFileContent(rule) {
|
|
2496
|
-
const frontmatter =
|
|
3677
|
+
const frontmatter = import_gray_matter5.default.stringify("", rule.frontmatter);
|
|
2497
3678
|
return frontmatter + rule.content;
|
|
2498
3679
|
}
|
|
2499
3680
|
async function generateUniqueFilename(rulesDir, baseFilename) {
|
|
2500
3681
|
let filename = baseFilename;
|
|
2501
3682
|
let counter = 1;
|
|
2502
|
-
while (await fileExists((0,
|
|
3683
|
+
while (await fileExists((0, import_node_path21.join)(rulesDir, `${filename}.md`))) {
|
|
2503
3684
|
filename = `${baseFilename}-${counter}`;
|
|
2504
3685
|
counter++;
|
|
2505
3686
|
}
|
|
@@ -2509,6 +3690,8 @@ async function generateUniqueFilename(rulesDir, baseFilename) {
|
|
|
2509
3690
|
// src/cli/commands/import.ts
|
|
2510
3691
|
async function importCommand(options = {}) {
|
|
2511
3692
|
const tools = [];
|
|
3693
|
+
if (options.augmentcode) tools.push("augmentcode");
|
|
3694
|
+
if (options["augmentcode-legacy"]) tools.push("augmentcode-legacy");
|
|
2512
3695
|
if (options.claudecode) tools.push("claudecode");
|
|
2513
3696
|
if (options.cursor) tools.push("cursor");
|
|
2514
3697
|
if (options.copilot) tools.push("copilot");
|
|
@@ -2517,7 +3700,7 @@ async function importCommand(options = {}) {
|
|
|
2517
3700
|
if (options.geminicli) tools.push("geminicli");
|
|
2518
3701
|
if (tools.length === 0) {
|
|
2519
3702
|
console.error(
|
|
2520
|
-
"\u274C Please specify one tool to import from (--claudecode, --cursor, --copilot, --cline, --roo, --geminicli)"
|
|
3703
|
+
"\u274C Please specify one tool to import from (--augmentcode, --augmentcode-legacy, --claudecode, --cursor, --copilot, --cline, --roo, --geminicli)"
|
|
2521
3704
|
);
|
|
2522
3705
|
process.exit(1);
|
|
2523
3706
|
}
|
|
@@ -2564,7 +3747,7 @@ async function importCommand(options = {}) {
|
|
|
2564
3747
|
}
|
|
2565
3748
|
|
|
2566
3749
|
// src/cli/commands/init.ts
|
|
2567
|
-
var
|
|
3750
|
+
var import_node_path22 = require("path");
|
|
2568
3751
|
async function initCommand() {
|
|
2569
3752
|
const aiRulesDir = ".rulesync";
|
|
2570
3753
|
console.log("Initializing rulesync...");
|
|
@@ -2611,7 +3794,7 @@ globs: ["**/*"]
|
|
|
2611
3794
|
- Follow single responsibility principle
|
|
2612
3795
|
`
|
|
2613
3796
|
};
|
|
2614
|
-
const filepath = (0,
|
|
3797
|
+
const filepath = (0, import_node_path22.join)(aiRulesDir, sampleFile.filename);
|
|
2615
3798
|
if (!await fileExists(filepath)) {
|
|
2616
3799
|
await writeFileContent(filepath, sampleFile.content);
|
|
2617
3800
|
console.log(`Created ${filepath}`);
|
|
@@ -2725,11 +3908,11 @@ async function watchCommand() {
|
|
|
2725
3908
|
persistent: true
|
|
2726
3909
|
});
|
|
2727
3910
|
let isGenerating = false;
|
|
2728
|
-
const handleChange = async (
|
|
3911
|
+
const handleChange = async (path5) => {
|
|
2729
3912
|
if (isGenerating) return;
|
|
2730
3913
|
isGenerating = true;
|
|
2731
3914
|
console.log(`
|
|
2732
|
-
\u{1F4DD} Detected change in ${
|
|
3915
|
+
\u{1F4DD} Detected change in ${path5}`);
|
|
2733
3916
|
try {
|
|
2734
3917
|
await generateCommand({ verbose: false });
|
|
2735
3918
|
console.log("\u2705 Regenerated configuration files");
|
|
@@ -2739,10 +3922,10 @@ async function watchCommand() {
|
|
|
2739
3922
|
isGenerating = false;
|
|
2740
3923
|
}
|
|
2741
3924
|
};
|
|
2742
|
-
watcher.on("change", handleChange).on("add", handleChange).on("unlink", (
|
|
3925
|
+
watcher.on("change", handleChange).on("add", handleChange).on("unlink", (path5) => {
|
|
2743
3926
|
console.log(`
|
|
2744
|
-
\u{1F5D1}\uFE0F Removed ${
|
|
2745
|
-
handleChange(
|
|
3927
|
+
\u{1F5D1}\uFE0F Removed ${path5}`);
|
|
3928
|
+
handleChange(path5);
|
|
2746
3929
|
}).on("error", (error) => {
|
|
2747
3930
|
console.error("\u274C Watcher error:", error);
|
|
2748
3931
|
});
|
|
@@ -2755,26 +3938,31 @@ async function watchCommand() {
|
|
|
2755
3938
|
|
|
2756
3939
|
// src/cli/index.ts
|
|
2757
3940
|
var program = new import_commander.Command();
|
|
2758
|
-
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");
|
|
2759
3942
|
program.command("init").description("Initialize rulesync in current directory").action(initCommand);
|
|
2760
3943
|
program.command("add <filename>").description("Add a new rule file").action(addCommand);
|
|
2761
3944
|
program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);
|
|
2762
|
-
program.command("import").description("Import configurations from AI tools to rulesync format").option("--claudecode", "Import from Claude Code (CLAUDE.md)").option("--cursor", "Import from Cursor (.cursorrules)").option("--copilot", "Import from GitHub Copilot (.github/copilot-instructions.md)").option("--cline", "Import from Cline (.cline/instructions.md)").option("--roo", "Import from Roo Code (.roo/instructions.md)").option("--geminicli", "Import from Gemini CLI (GEMINI.md)").option("-v, --verbose", "Verbose output").action(importCommand);
|
|
2763
|
-
program.command("generate").description("Generate configuration files for AI tools").option("--copilot", "Generate only for GitHub Copilot").option("--cursor", "Generate only for Cursor").option("--cline", "Generate only for Cline").option("--claudecode", "Generate only for Claude Code").option("--roo", "Generate only for Roo Code").option("--geminicli", "Generate only for Gemini CLI").option("--kiro", "Generate only for Kiro IDE").option("--delete", "Delete all existing files in output directories before generating").option(
|
|
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(
|
|
2764
3947
|
"-b, --base-dir <paths>",
|
|
2765
3948
|
"Base directories to generate files (comma-separated for multiple paths)"
|
|
2766
|
-
).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) => {
|
|
2767
3950
|
const tools = [];
|
|
3951
|
+
if (options.augmentcode) tools.push("augmentcode");
|
|
3952
|
+
if (options["augmentcode-legacy"]) tools.push("augmentcode-legacy");
|
|
2768
3953
|
if (options.copilot) tools.push("copilot");
|
|
2769
3954
|
if (options.cursor) tools.push("cursor");
|
|
2770
3955
|
if (options.cline) tools.push("cline");
|
|
2771
3956
|
if (options.claudecode) tools.push("claudecode");
|
|
2772
3957
|
if (options.roo) tools.push("roo");
|
|
2773
3958
|
if (options.geminicli) tools.push("geminicli");
|
|
3959
|
+
if (options.junie) tools.push("junie");
|
|
2774
3960
|
if (options.kiro) tools.push("kiro");
|
|
2775
3961
|
const generateOptions = {
|
|
2776
3962
|
verbose: options.verbose,
|
|
2777
|
-
delete: options.delete
|
|
3963
|
+
delete: options.delete,
|
|
3964
|
+
config: options.config,
|
|
3965
|
+
noConfig: options.noConfig
|
|
2778
3966
|
};
|
|
2779
3967
|
if (tools.length > 0) {
|
|
2780
3968
|
generateOptions.tools = tools;
|
|
@@ -2787,4 +3975,5 @@ program.command("generate").description("Generate configuration files for AI too
|
|
|
2787
3975
|
program.command("validate").description("Validate rulesync configuration").action(validateCommand);
|
|
2788
3976
|
program.command("status").description("Show current status of rulesync").action(statusCommand);
|
|
2789
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);
|
|
2790
3979
|
program.parse();
|