rulesync 0.44.0 → 0.47.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -27,22 +27,23 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
27
  ));
28
28
 
29
29
  // src/types/tool-targets.ts
30
- var import_v4_mini, ToolTargetSchema, ToolTargetsSchema, WildcardTargetSchema, RulesyncTargetsSchema;
30
+ var import_mini, ToolTargetSchema, ToolTargetsSchema, WildcardTargetSchema, RulesyncTargetsSchema;
31
31
  var init_tool_targets = __esm({
32
32
  "src/types/tool-targets.ts"() {
33
33
  "use strict";
34
- import_v4_mini = require("zod/v4-mini");
35
- ToolTargetSchema = import_v4_mini.z.enum([
34
+ import_mini = require("zod/mini");
35
+ ToolTargetSchema = import_mini.z.enum([
36
36
  "copilot",
37
37
  "cursor",
38
38
  "cline",
39
39
  "claudecode",
40
40
  "roo",
41
- "geminicli"
41
+ "geminicli",
42
+ "kiro"
42
43
  ]);
43
- ToolTargetsSchema = import_v4_mini.z.array(ToolTargetSchema);
44
- WildcardTargetSchema = import_v4_mini.z.tuple([import_v4_mini.z.literal("*")]);
45
- RulesyncTargetsSchema = import_v4_mini.z.union([ToolTargetsSchema, WildcardTargetSchema]);
44
+ ToolTargetsSchema = import_mini.z.array(ToolTargetSchema);
45
+ WildcardTargetSchema = import_mini.z.tuple([import_mini.z.literal("*")]);
46
+ RulesyncTargetsSchema = import_mini.z.union([ToolTargetsSchema, WildcardTargetSchema]);
46
47
  }
47
48
  });
48
49
 
@@ -294,6 +295,57 @@ var init_geminicli = __esm({
294
295
  }
295
296
  });
296
297
 
298
+ // src/generators/mcp/kiro.ts
299
+ function generateKiroMcp(config) {
300
+ const kiroConfig = {
301
+ mcpServers: {}
302
+ };
303
+ for (const [serverName, server] of Object.entries(config.mcpServers)) {
304
+ if (!shouldIncludeServer(server, "kiro")) continue;
305
+ const kiroServer = {};
306
+ if (server.command) {
307
+ kiroServer.command = server.command;
308
+ if (server.args) kiroServer.args = server.args;
309
+ } else if (server.url || server.httpUrl) {
310
+ const url = server.httpUrl || server.url;
311
+ if (url) {
312
+ kiroServer.url = url;
313
+ }
314
+ if (server.httpUrl || server.transport === "http") {
315
+ kiroServer.transport = "streamable-http";
316
+ } else if (server.transport === "sse" || server.type === "sse") {
317
+ kiroServer.transport = "sse";
318
+ }
319
+ }
320
+ if (server.env) {
321
+ kiroServer.env = server.env;
322
+ }
323
+ if (server.timeout) {
324
+ kiroServer.timeout = server.timeout;
325
+ }
326
+ if (server.disabled !== void 0) {
327
+ kiroServer.disabled = server.disabled;
328
+ }
329
+ if (server.transport) {
330
+ kiroServer.transport = server.transport;
331
+ }
332
+ if (server.kiroAutoApprove) {
333
+ kiroServer.autoApprove = server.kiroAutoApprove;
334
+ }
335
+ if (server.kiroAutoBlock) {
336
+ kiroServer.autoBlock = server.kiroAutoBlock;
337
+ }
338
+ kiroConfig.mcpServers[serverName] = kiroServer;
339
+ }
340
+ return JSON.stringify(kiroConfig, null, 2);
341
+ }
342
+ var init_kiro = __esm({
343
+ "src/generators/mcp/kiro.ts"() {
344
+ "use strict";
345
+ init_mcp_helpers();
346
+ }
347
+ });
348
+
297
349
  // src/generators/mcp/roo.ts
298
350
  function generateRooMcp(config) {
299
351
  const rooConfig = {
@@ -364,10 +416,11 @@ function getDefaultConfig() {
364
416
  cline: ".clinerules",
365
417
  claudecode: ".",
366
418
  roo: ".roo/rules",
367
- geminicli: ".gemini/memories"
419
+ geminicli: ".gemini/memories",
420
+ kiro: ".kiro/steering"
368
421
  },
369
422
  watchEnabled: false,
370
- defaultTargets: ["copilot", "cursor", "cline", "claudecode", "roo", "geminicli"]
423
+ defaultTargets: ["copilot", "cursor", "cline", "claudecode", "roo", "geminicli", "kiro"]
371
424
  };
372
425
  }
373
426
  function resolveTargets(targets, config) {
@@ -414,27 +467,138 @@ async function addCommand(filename) {
414
467
  }
415
468
  }
416
469
 
470
+ // src/generators/ignore/kiro.ts
471
+ var import_node_path = require("path");
472
+ async function generateKiroIgnoreFiles(rules, config, baseDir) {
473
+ const outputs = [];
474
+ const aiignoreContent = generateAiignoreContent(rules);
475
+ const outputPath = baseDir || process.cwd();
476
+ const filepath = (0, import_node_path.join)(outputPath, ".aiignore");
477
+ outputs.push({
478
+ tool: "kiro",
479
+ filepath,
480
+ content: aiignoreContent
481
+ });
482
+ return outputs;
483
+ }
484
+ function generateAiignoreContent(rules) {
485
+ const lines = [
486
+ "# Generated by rulesync - Kiro AI-specific exclusions",
487
+ "# This file excludes files that can be in Git but shouldn't be read by the AI",
488
+ ""
489
+ ];
490
+ lines.push(
491
+ "# Data files AI shouldn't process",
492
+ "*.csv",
493
+ "*.tsv",
494
+ "*.sqlite",
495
+ "*.db",
496
+ "",
497
+ "# Large binary files",
498
+ "*.zip",
499
+ "*.tar.gz",
500
+ "*.rar",
501
+ "",
502
+ "# Sensitive documentation",
503
+ "internal-docs/",
504
+ "confidential/",
505
+ "",
506
+ "# Test data that might confuse AI",
507
+ "test/fixtures/large-*.json",
508
+ "benchmark-results/",
509
+ "",
510
+ "# Reinforce critical exclusions from .gitignore",
511
+ "*.pem",
512
+ "*.key",
513
+ ".env*",
514
+ ""
515
+ );
516
+ const rulePatterns = extractIgnorePatternsFromRules(rules);
517
+ if (rulePatterns.length > 0) {
518
+ lines.push("# Project-specific exclusions from rulesync rules");
519
+ lines.push(...rulePatterns);
520
+ lines.push("");
521
+ }
522
+ return lines.join("\n");
523
+ }
524
+ function extractIgnorePatternsFromRules(rules) {
525
+ const patterns = [];
526
+ for (const rule of rules) {
527
+ if (rule.frontmatter.globs && rule.frontmatter.globs.length > 0) {
528
+ for (const glob of rule.frontmatter.globs) {
529
+ if (shouldExcludeFromAI(glob)) {
530
+ patterns.push(`# Exclude: ${rule.frontmatter.description}`);
531
+ patterns.push(glob);
532
+ }
533
+ }
534
+ }
535
+ const contentPatterns = extractIgnorePatternsFromContent(rule.content);
536
+ patterns.push(...contentPatterns);
537
+ }
538
+ return patterns;
539
+ }
540
+ function shouldExcludeFromAI(glob) {
541
+ const excludePatterns = [
542
+ // Test and fixture files that might be large or confusing
543
+ "**/test/fixtures/**",
544
+ "**/tests/fixtures/**",
545
+ "**/*.fixture.*",
546
+ // Build and generated files
547
+ "**/dist/**",
548
+ "**/build/**",
549
+ "**/coverage/**",
550
+ // Configuration that might contain sensitive data
551
+ "**/config/production/**",
552
+ "**/config/prod/**",
553
+ "**/*.prod.*",
554
+ // Documentation that might be sensitive
555
+ "**/internal/**",
556
+ "**/private/**",
557
+ "**/confidential/**"
558
+ ];
559
+ return excludePatterns.some((pattern) => {
560
+ const regex = new RegExp(pattern.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*"));
561
+ return regex.test(glob);
562
+ });
563
+ }
564
+ function extractIgnorePatternsFromContent(content) {
565
+ const patterns = [];
566
+ const lines = content.split("\n");
567
+ for (const line of lines) {
568
+ const trimmed = line.trim();
569
+ if (trimmed.startsWith("# IGNORE:") || trimmed.startsWith("# aiignore:")) {
570
+ const pattern = trimmed.replace(/^# (IGNORE|aiignore):\s*/, "").trim();
571
+ if (pattern) {
572
+ patterns.push(pattern);
573
+ }
574
+ }
575
+ if (trimmed.includes("exclude") || trimmed.includes("ignore")) {
576
+ const matches = trimmed.match(/['"`]([^'"`]+\.(log|tmp|cache|temp))['"`]/g);
577
+ if (matches) {
578
+ patterns.push(...matches.map((m) => m.replace(/['"`]/g, "")));
579
+ }
580
+ }
581
+ }
582
+ return patterns;
583
+ }
584
+
417
585
  // src/generators/rules/claudecode.ts
418
586
  var import_node_path4 = require("path");
419
587
 
420
588
  // src/types/claudecode.ts
421
- var import_v4_mini2 = require("zod/v4-mini");
422
- var ClaudeSettingsSchema = import_v4_mini2.z.looseObject({
423
- permissions: import_v4_mini2.z._default(
424
- import_v4_mini2.z.looseObject({
425
- deny: import_v4_mini2.z._default(import_v4_mini2.z.array(import_v4_mini2.z.string()), [])
589
+ var import_mini2 = require("zod/mini");
590
+ var ClaudeSettingsSchema = import_mini2.z.looseObject({
591
+ permissions: import_mini2.z._default(
592
+ import_mini2.z.looseObject({
593
+ deny: import_mini2.z._default(import_mini2.z.array(import_mini2.z.string()), [])
426
594
  }),
427
595
  { deny: [] }
428
596
  )
429
597
  });
430
598
 
431
599
  // src/utils/file.ts
432
- var import_promises3 = require("fs/promises");
433
- var import_node_path3 = require("path");
434
-
435
- // src/utils/file-ops.ts
436
600
  var import_promises2 = require("fs/promises");
437
- var import_node_path = require("path");
601
+ var import_node_path2 = require("path");
438
602
  async function ensureDir(dirPath) {
439
603
  try {
440
604
  await (0, import_promises2.stat)(dirPath);
@@ -446,7 +610,7 @@ async function readFileContent(filepath) {
446
610
  return (0, import_promises2.readFile)(filepath, "utf-8");
447
611
  }
448
612
  async function writeFileContent(filepath, content) {
449
- await ensureDir((0, import_node_path.dirname)(filepath));
613
+ await ensureDir((0, import_node_path2.dirname)(filepath));
450
614
  await (0, import_promises2.writeFile)(filepath, content, "utf-8");
451
615
  }
452
616
  async function fileExists(filepath) {
@@ -457,16 +621,57 @@ async function fileExists(filepath) {
457
621
  return false;
458
622
  }
459
623
  }
624
+ async function findFiles(dir, extension = ".md") {
625
+ try {
626
+ const files = await (0, import_promises2.readdir)(dir);
627
+ return files.filter((file) => file.endsWith(extension)).map((file) => (0, import_node_path2.join)(dir, file));
628
+ } catch {
629
+ return [];
630
+ }
631
+ }
632
+ async function removeDirectory(dirPath) {
633
+ const dangerousPaths = [".", "/", "~", "src", "node_modules"];
634
+ if (dangerousPaths.includes(dirPath) || dirPath === "") {
635
+ console.warn(`Skipping deletion of dangerous path: ${dirPath}`);
636
+ return;
637
+ }
638
+ try {
639
+ if (await fileExists(dirPath)) {
640
+ await (0, import_promises2.rm)(dirPath, { recursive: true, force: true });
641
+ }
642
+ } catch (error) {
643
+ console.warn(`Failed to remove directory ${dirPath}:`, error);
644
+ }
645
+ }
646
+ async function removeFile(filepath) {
647
+ try {
648
+ if (await fileExists(filepath)) {
649
+ await (0, import_promises2.rm)(filepath);
650
+ }
651
+ } catch (error) {
652
+ console.warn(`Failed to remove file ${filepath}:`, error);
653
+ }
654
+ }
655
+ async function removeClaudeGeneratedFiles() {
656
+ const filesToRemove = ["CLAUDE.md", ".claude/memories"];
657
+ for (const fileOrDir of filesToRemove) {
658
+ if (fileOrDir.endsWith("/memories")) {
659
+ await removeDirectory(fileOrDir);
660
+ } else {
661
+ await removeFile(fileOrDir);
662
+ }
663
+ }
664
+ }
460
665
 
461
666
  // src/utils/ignore.ts
462
- var import_node_path2 = require("path");
667
+ var import_node_path3 = require("path");
463
668
  var import_micromatch = __toESM(require("micromatch"), 1);
464
669
  var cachedIgnorePatterns = null;
465
670
  async function loadIgnorePatterns(baseDir = process.cwd()) {
466
671
  if (cachedIgnorePatterns) {
467
672
  return cachedIgnorePatterns;
468
673
  }
469
- const ignorePath = (0, import_node_path2.join)(baseDir, ".rulesyncignore");
674
+ const ignorePath = (0, import_node_path3.join)(baseDir, ".rulesyncignore");
470
675
  if (!await fileExists(ignorePath)) {
471
676
  cachedIgnorePatterns = { patterns: [] };
472
677
  return cachedIgnorePatterns;
@@ -509,53 +714,6 @@ function filterIgnoredFiles(files, ignorePatterns) {
509
714
  return files.filter((file) => !isFileIgnored(file, ignorePatterns));
510
715
  }
511
716
 
512
- // src/utils/file.ts
513
- async function findFiles(dir, extension = ".md", ignorePatterns) {
514
- try {
515
- const files = await (0, import_promises3.readdir)(dir);
516
- const filtered = files.filter((file) => file.endsWith(extension)).map((file) => (0, import_node_path3.join)(dir, file));
517
- if (ignorePatterns && ignorePatterns.length > 0) {
518
- return filterIgnoredFiles(filtered, ignorePatterns);
519
- }
520
- return filtered;
521
- } catch {
522
- return [];
523
- }
524
- }
525
- async function removeDirectory(dirPath) {
526
- const dangerousPaths = [".", "/", "~", "src", "node_modules"];
527
- if (dangerousPaths.includes(dirPath) || dirPath === "") {
528
- console.warn(`Skipping deletion of dangerous path: ${dirPath}`);
529
- return;
530
- }
531
- try {
532
- if (await fileExists(dirPath)) {
533
- await (0, import_promises3.rm)(dirPath, { recursive: true, force: true });
534
- }
535
- } catch (error) {
536
- console.warn(`Failed to remove directory ${dirPath}:`, error);
537
- }
538
- }
539
- async function removeFile(filepath) {
540
- try {
541
- if (await fileExists(filepath)) {
542
- await (0, import_promises3.rm)(filepath);
543
- }
544
- } catch (error) {
545
- console.warn(`Failed to remove file ${filepath}:`, error);
546
- }
547
- }
548
- async function removeClaudeGeneratedFiles() {
549
- const filesToRemove = ["CLAUDE.md", ".claude/memories"];
550
- for (const fileOrDir of filesToRemove) {
551
- if (fileOrDir.endsWith("/memories")) {
552
- await removeDirectory(fileOrDir);
553
- } else {
554
- await removeFile(fileOrDir);
555
- }
556
- }
557
- }
558
-
559
717
  // src/generators/rules/claudecode.ts
560
718
  async function generateClaudecodeConfig(rules, config, baseDir) {
561
719
  const outputs = [];
@@ -589,9 +747,10 @@ function generateClaudeMarkdown(rootRules, detailRules) {
589
747
  lines.push("Please also reference the following documents as needed:");
590
748
  lines.push("");
591
749
  for (const rule of detailRules) {
592
- const globsText = rule.frontmatter.globs.length > 0 ? rule.frontmatter.globs.join(", ") : "";
750
+ const escapedDescription = rule.frontmatter.description.replace(/"/g, '\\"');
751
+ const globsText = rule.frontmatter.globs.join(",");
593
752
  lines.push(
594
- `@.claude/memories/${rule.filename}.md ${rule.frontmatter.description} ${globsText}`.trim()
753
+ `@.claude/memories/${rule.filename}.md description: "${escapedDescription}" globs: "${globsText}"`
595
754
  );
596
755
  }
597
756
  lines.push("");
@@ -891,14 +1050,34 @@ function generateAiexclude(patterns) {
891
1050
  return lines.join("\n");
892
1051
  }
893
1052
 
894
- // src/generators/rules/roo.ts
1053
+ // src/generators/rules/kiro.ts
895
1054
  var import_node_path9 = require("path");
1055
+ async function generateKiroConfig(rules, config, baseDir) {
1056
+ const outputs = [];
1057
+ for (const rule of rules) {
1058
+ const content = generateKiroMarkdown(rule);
1059
+ const outputDir = baseDir ? (0, import_node_path9.join)(baseDir, config.outputPaths.kiro) : config.outputPaths.kiro;
1060
+ const filepath = (0, import_node_path9.join)(outputDir, `${rule.filename}.md`);
1061
+ outputs.push({
1062
+ tool: "kiro",
1063
+ filepath,
1064
+ content
1065
+ });
1066
+ }
1067
+ return outputs;
1068
+ }
1069
+ function generateKiroMarkdown(rule) {
1070
+ return rule.content.trim();
1071
+ }
1072
+
1073
+ // src/generators/rules/roo.ts
1074
+ var import_node_path10 = require("path");
896
1075
  async function generateRooConfig(rules, config, baseDir) {
897
1076
  const outputs = [];
898
1077
  for (const rule of rules) {
899
1078
  const content = generateRooMarkdown(rule);
900
- const outputDir = baseDir ? (0, import_node_path9.join)(baseDir, config.outputPaths.roo) : config.outputPaths.roo;
901
- const filepath = (0, import_node_path9.join)(outputDir, `${rule.filename}.md`);
1079
+ const outputDir = baseDir ? (0, import_node_path10.join)(baseDir, config.outputPaths.roo) : config.outputPaths.roo;
1080
+ const filepath = (0, import_node_path10.join)(outputDir, `${rule.filename}.md`);
902
1081
  outputs.push({
903
1082
  tool: "roo",
904
1083
  filepath,
@@ -907,7 +1086,7 @@ async function generateRooConfig(rules, config, baseDir) {
907
1086
  }
908
1087
  const ignorePatterns = await loadIgnorePatterns(baseDir);
909
1088
  if (ignorePatterns.patterns.length > 0) {
910
- const rooIgnorePath = baseDir ? (0, import_node_path9.join)(baseDir, ".rooignore") : ".rooignore";
1089
+ const rooIgnorePath = baseDir ? (0, import_node_path10.join)(baseDir, ".rooignore") : ".rooignore";
911
1090
  const rooIgnoreContent = generateRooIgnore(ignorePatterns.patterns);
912
1091
  outputs.push({
913
1092
  tool: "roo",
@@ -973,6 +1152,11 @@ async function generateForTool(tool, rules, config, baseDir) {
973
1152
  return generateRooConfig(rules, config, baseDir);
974
1153
  case "geminicli":
975
1154
  return generateGeminiConfig(rules, config, baseDir);
1155
+ case "kiro": {
1156
+ const kiroRulesOutputs = await generateKiroConfig(rules, config, baseDir);
1157
+ const kiroIgnoreOutputs = await generateKiroIgnoreFiles(rules, config, baseDir);
1158
+ return [...kiroRulesOutputs, ...kiroIgnoreOutputs];
1159
+ }
976
1160
  default:
977
1161
  console.warn(`Unknown tool: ${tool}`);
978
1162
  return null;
@@ -980,74 +1164,76 @@ async function generateForTool(tool, rules, config, baseDir) {
980
1164
  }
981
1165
 
982
1166
  // src/core/parser.ts
983
- var import_node_path10 = require("path");
1167
+ var import_node_path11 = require("path");
984
1168
  var import_gray_matter = __toESM(require("gray-matter"), 1);
985
1169
 
986
1170
  // src/types/config.ts
987
- var import_v4_mini3 = require("zod/v4-mini");
1171
+ var import_mini3 = require("zod/mini");
988
1172
  init_tool_targets();
989
- var ConfigSchema = import_v4_mini3.z.object({
990
- aiRulesDir: import_v4_mini3.z.string(),
991
- outputPaths: import_v4_mini3.z.record(ToolTargetSchema, import_v4_mini3.z.string()),
992
- watchEnabled: import_v4_mini3.z.boolean(),
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(),
993
1177
  defaultTargets: ToolTargetsSchema
994
1178
  });
995
1179
 
996
1180
  // src/types/mcp.ts
997
- var import_v4_mini4 = require("zod/v4-mini");
1181
+ var import_mini4 = require("zod/mini");
998
1182
  init_tool_targets();
999
- var McpTransportTypeSchema = import_v4_mini4.z.enum(["stdio", "sse", "http"]);
1000
- var McpServerBaseSchema = import_v4_mini4.z.object({
1001
- command: import_v4_mini4.z.optional(import_v4_mini4.z.string()),
1002
- args: import_v4_mini4.z.optional(import_v4_mini4.z.array(import_v4_mini4.z.string())),
1003
- url: import_v4_mini4.z.optional(import_v4_mini4.z.string()),
1004
- httpUrl: import_v4_mini4.z.optional(import_v4_mini4.z.string()),
1005
- env: import_v4_mini4.z.optional(import_v4_mini4.z.record(import_v4_mini4.z.string(), import_v4_mini4.z.string())),
1006
- disabled: import_v4_mini4.z.optional(import_v4_mini4.z.boolean()),
1007
- networkTimeout: import_v4_mini4.z.optional(import_v4_mini4.z.number()),
1008
- timeout: import_v4_mini4.z.optional(import_v4_mini4.z.number()),
1009
- trust: import_v4_mini4.z.optional(import_v4_mini4.z.boolean()),
1010
- cwd: import_v4_mini4.z.optional(import_v4_mini4.z.string()),
1011
- transport: import_v4_mini4.z.optional(McpTransportTypeSchema),
1012
- type: import_v4_mini4.z.optional(import_v4_mini4.z.enum(["sse", "streamable-http"])),
1013
- alwaysAllow: import_v4_mini4.z.optional(import_v4_mini4.z.array(import_v4_mini4.z.string())),
1014
- tools: import_v4_mini4.z.optional(import_v4_mini4.z.array(import_v4_mini4.z.string()))
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()))
1015
1201
  });
1016
- var RulesyncMcpServerSchema = import_v4_mini4.z.extend(McpServerBaseSchema, {
1017
- targets: import_v4_mini4.z.optional(RulesyncTargetsSchema)
1202
+ var RulesyncMcpServerSchema = import_mini4.z.extend(McpServerBaseSchema, {
1203
+ targets: import_mini4.z.optional(RulesyncTargetsSchema)
1018
1204
  });
1019
- var McpConfigSchema = import_v4_mini4.z.object({
1020
- mcpServers: import_v4_mini4.z.record(import_v4_mini4.z.string(), McpServerBaseSchema)
1205
+ var McpConfigSchema = import_mini4.z.object({
1206
+ mcpServers: import_mini4.z.record(import_mini4.z.string(), McpServerBaseSchema)
1021
1207
  });
1022
- var RulesyncMcpConfigSchema = import_v4_mini4.z.object({
1023
- mcpServers: import_v4_mini4.z.record(import_v4_mini4.z.string(), RulesyncMcpServerSchema)
1208
+ var RulesyncMcpConfigSchema = import_mini4.z.object({
1209
+ mcpServers: import_mini4.z.record(import_mini4.z.string(), RulesyncMcpServerSchema)
1024
1210
  });
1025
1211
 
1026
1212
  // src/types/rules.ts
1027
- var import_v4_mini5 = require("zod/v4-mini");
1213
+ var import_mini5 = require("zod/mini");
1028
1214
  init_tool_targets();
1029
- var RuleFrontmatterSchema = import_v4_mini5.z.object({
1030
- root: import_v4_mini5.z.boolean(),
1215
+ var RuleFrontmatterSchema = import_mini5.z.object({
1216
+ root: import_mini5.z.boolean(),
1031
1217
  targets: RulesyncTargetsSchema,
1032
- description: import_v4_mini5.z.string(),
1033
- globs: import_v4_mini5.z.array(import_v4_mini5.z.string()),
1034
- cursorRuleType: import_v4_mini5.z.optional(import_v4_mini5.z.enum(["always", "manual", "specificFiles", "intelligently"]))
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"]))
1035
1221
  });
1036
- var ParsedRuleSchema = import_v4_mini5.z.object({
1222
+ var ParsedRuleSchema = import_mini5.z.object({
1037
1223
  frontmatter: RuleFrontmatterSchema,
1038
- content: import_v4_mini5.z.string(),
1039
- filename: import_v4_mini5.z.string(),
1040
- filepath: import_v4_mini5.z.string()
1224
+ content: import_mini5.z.string(),
1225
+ filename: import_mini5.z.string(),
1226
+ filepath: import_mini5.z.string()
1041
1227
  });
1042
- var GeneratedOutputSchema = import_v4_mini5.z.object({
1228
+ var GeneratedOutputSchema = import_mini5.z.object({
1043
1229
  tool: ToolTargetSchema,
1044
- filepath: import_v4_mini5.z.string(),
1045
- content: import_v4_mini5.z.string()
1230
+ filepath: import_mini5.z.string(),
1231
+ content: import_mini5.z.string()
1046
1232
  });
1047
- var GenerateOptionsSchema = import_v4_mini5.z.object({
1048
- targetTools: import_v4_mini5.z.optional(ToolTargetsSchema),
1049
- outputDir: import_v4_mini5.z.optional(import_v4_mini5.z.string()),
1050
- watch: import_v4_mini5.z.optional(import_v4_mini5.z.boolean())
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())
1051
1237
  });
1052
1238
 
1053
1239
  // src/types/index.ts
@@ -1056,7 +1242,8 @@ init_tool_targets();
1056
1242
  // src/core/parser.ts
1057
1243
  async function parseRulesFromDirectory(aiRulesDir) {
1058
1244
  const ignorePatterns = await loadIgnorePatterns();
1059
- const ruleFiles = await findFiles(aiRulesDir, ".md", ignorePatterns.patterns);
1245
+ const allRuleFiles = await findFiles(aiRulesDir, ".md");
1246
+ const ruleFiles = filterIgnoredFiles(allRuleFiles, ignorePatterns.patterns);
1060
1247
  const rules = [];
1061
1248
  const errors = [];
1062
1249
  if (ignorePatterns.patterns.length > 0) {
@@ -1089,7 +1276,7 @@ async function parseRuleFile(filepath) {
1089
1276
  const parsed = (0, import_gray_matter.default)(content);
1090
1277
  try {
1091
1278
  const frontmatter = RuleFrontmatterSchema.parse(parsed.data);
1092
- const filename = (0, import_node_path10.basename)(filepath, ".md");
1279
+ const filename = (0, import_node_path11.basename)(filepath, ".md");
1093
1280
  return {
1094
1281
  frontmatter,
1095
1282
  content: parsed.content,
@@ -1162,6 +1349,7 @@ init_cline();
1162
1349
  init_copilot();
1163
1350
  init_cursor();
1164
1351
  init_geminicli();
1352
+ init_kiro();
1165
1353
  init_roo();
1166
1354
 
1167
1355
  // src/core/mcp-parser.ts
@@ -1225,6 +1413,11 @@ async function generateMcpConfigs(projectRoot, baseDir) {
1225
1413
  path: path3.join(targetRoot, ".gemini", "settings.json"),
1226
1414
  generate: () => generateGeminiCliMcp(config)
1227
1415
  },
1416
+ {
1417
+ tool: "kiro-project",
1418
+ path: path3.join(targetRoot, ".kiro", "mcp.json"),
1419
+ generate: () => generateKiroMcp(config)
1420
+ },
1228
1421
  {
1229
1422
  tool: "roo-project",
1230
1423
  path: path3.join(targetRoot, ".roo", "mcp.json"),
@@ -1235,7 +1428,7 @@ async function generateMcpConfigs(projectRoot, baseDir) {
1235
1428
  try {
1236
1429
  const content = generator.generate();
1237
1430
  const parsed = JSON.parse(content);
1238
- if (generator.tool.includes("claude") || generator.tool.includes("cline") || generator.tool.includes("cursor") || generator.tool.includes("gemini") || generator.tool.includes("roo")) {
1431
+ if (generator.tool.includes("claude") || generator.tool.includes("cline") || generator.tool.includes("cursor") || generator.tool.includes("gemini") || generator.tool.includes("kiro") || generator.tool.includes("roo")) {
1239
1432
  if (!parsed.mcpServers || Object.keys(parsed.mcpServers).length === 0) {
1240
1433
  results.push({
1241
1434
  tool: generator.tool,
@@ -1321,6 +1514,9 @@ async function generateCommand(options = {}) {
1321
1514
  case "geminicli":
1322
1515
  deleteTasks.push(removeDirectory(config.outputPaths.geminicli));
1323
1516
  break;
1517
+ case "kiro":
1518
+ deleteTasks.push(removeDirectory(config.outputPaths.kiro));
1519
+ break;
1324
1520
  }
1325
1521
  }
1326
1522
  await Promise.all(deleteTasks);
@@ -1385,9 +1581,9 @@ Generating configurations for base directory: ${baseDir}`);
1385
1581
 
1386
1582
  // src/cli/commands/gitignore.ts
1387
1583
  var import_node_fs = require("fs");
1388
- var import_node_path11 = require("path");
1584
+ var import_node_path12 = require("path");
1389
1585
  var gitignoreCommand = async () => {
1390
- const gitignorePath = (0, import_node_path11.join)(process.cwd(), ".gitignore");
1586
+ const gitignorePath = (0, import_node_path12.join)(process.cwd(), ".gitignore");
1391
1587
  const rulesFilesToIgnore = [
1392
1588
  "# Generated by rulesync - AI tool configuration files",
1393
1589
  "**/.github/copilot-instructions.md",
@@ -1404,6 +1600,8 @@ var gitignoreCommand = async () => {
1404
1600
  "**/GEMINI.md",
1405
1601
  "**/.gemini/memories/",
1406
1602
  "**/.aiexclude",
1603
+ "**/.aiignore",
1604
+ "**/.kiro/steering/",
1407
1605
  "**/.mcp.json",
1408
1606
  "!.rulesync/.mcp.json",
1409
1607
  "**/.cursor/mcp.json",
@@ -1441,17 +1639,17 @@ ${linesToAdd.join("\n")}
1441
1639
  };
1442
1640
 
1443
1641
  // src/core/importer.ts
1444
- var import_node_path18 = require("path");
1642
+ var import_node_path19 = require("path");
1445
1643
  var import_gray_matter4 = __toESM(require("gray-matter"), 1);
1446
1644
 
1447
1645
  // src/parsers/claudecode.ts
1448
- var import_node_path12 = require("path");
1646
+ var import_node_path13 = require("path");
1449
1647
  async function parseClaudeConfiguration(baseDir = process.cwd()) {
1450
1648
  const errors = [];
1451
1649
  const rules = [];
1452
1650
  let ignorePatterns;
1453
1651
  let mcpServers;
1454
- const claudeFilePath = (0, import_node_path12.join)(baseDir, "CLAUDE.md");
1652
+ const claudeFilePath = (0, import_node_path13.join)(baseDir, "CLAUDE.md");
1455
1653
  if (!await fileExists(claudeFilePath)) {
1456
1654
  errors.push("CLAUDE.md file not found");
1457
1655
  return { rules, errors };
@@ -1462,12 +1660,12 @@ async function parseClaudeConfiguration(baseDir = process.cwd()) {
1462
1660
  if (mainRule) {
1463
1661
  rules.push(mainRule);
1464
1662
  }
1465
- const memoryDir = (0, import_node_path12.join)(baseDir, ".claude", "memories");
1663
+ const memoryDir = (0, import_node_path13.join)(baseDir, ".claude", "memories");
1466
1664
  if (await fileExists(memoryDir)) {
1467
1665
  const memoryRules = await parseClaudeMemoryFiles(memoryDir);
1468
1666
  rules.push(...memoryRules);
1469
1667
  }
1470
- const settingsPath = (0, import_node_path12.join)(baseDir, ".claude", "settings.json");
1668
+ const settingsPath = (0, import_node_path13.join)(baseDir, ".claude", "settings.json");
1471
1669
  if (await fileExists(settingsPath)) {
1472
1670
  const settingsResult = await parseClaudeSettings(settingsPath);
1473
1671
  if (settingsResult.ignorePatterns) {
@@ -1524,10 +1722,10 @@ async function parseClaudeMemoryFiles(memoryDir) {
1524
1722
  const files = await readdir2(memoryDir);
1525
1723
  for (const file of files) {
1526
1724
  if (file.endsWith(".md")) {
1527
- const filePath = (0, import_node_path12.join)(memoryDir, file);
1725
+ const filePath = (0, import_node_path13.join)(memoryDir, file);
1528
1726
  const content = await readFileContent(filePath);
1529
1727
  if (content.trim()) {
1530
- const filename = (0, import_node_path12.basename)(file, ".md");
1728
+ const filename = (0, import_node_path13.basename)(file, ".md");
1531
1729
  const frontmatter = {
1532
1730
  root: false,
1533
1731
  targets: ["claudecode"],
@@ -1587,11 +1785,11 @@ async function parseClaudeSettings(settingsPath) {
1587
1785
  }
1588
1786
 
1589
1787
  // src/parsers/cline.ts
1590
- var import_node_path13 = require("path");
1788
+ var import_node_path14 = require("path");
1591
1789
  async function parseClineConfiguration(baseDir = process.cwd()) {
1592
1790
  const errors = [];
1593
1791
  const rules = [];
1594
- const clineFilePath = (0, import_node_path13.join)(baseDir, ".cline", "instructions.md");
1792
+ const clineFilePath = (0, import_node_path14.join)(baseDir, ".cline", "instructions.md");
1595
1793
  if (await fileExists(clineFilePath)) {
1596
1794
  try {
1597
1795
  const content = await readFileContent(clineFilePath);
@@ -1614,14 +1812,14 @@ async function parseClineConfiguration(baseDir = process.cwd()) {
1614
1812
  errors.push(`Failed to parse .cline/instructions.md: ${errorMessage}`);
1615
1813
  }
1616
1814
  }
1617
- const clinerulesDirPath = (0, import_node_path13.join)(baseDir, ".clinerules");
1815
+ const clinerulesDirPath = (0, import_node_path14.join)(baseDir, ".clinerules");
1618
1816
  if (await fileExists(clinerulesDirPath)) {
1619
1817
  try {
1620
1818
  const { readdir: readdir2 } = await import("fs/promises");
1621
1819
  const files = await readdir2(clinerulesDirPath);
1622
1820
  for (const file of files) {
1623
1821
  if (file.endsWith(".md")) {
1624
- const filePath = (0, import_node_path13.join)(clinerulesDirPath, file);
1822
+ const filePath = (0, import_node_path14.join)(clinerulesDirPath, file);
1625
1823
  try {
1626
1824
  const content = await readFileContent(filePath);
1627
1825
  if (content.trim()) {
@@ -1657,12 +1855,12 @@ async function parseClineConfiguration(baseDir = process.cwd()) {
1657
1855
  }
1658
1856
 
1659
1857
  // src/parsers/copilot.ts
1660
- var import_node_path14 = require("path");
1858
+ var import_node_path15 = require("path");
1661
1859
  var import_gray_matter2 = __toESM(require("gray-matter"), 1);
1662
1860
  async function parseCopilotConfiguration(baseDir = process.cwd()) {
1663
1861
  const errors = [];
1664
1862
  const rules = [];
1665
- const copilotFilePath = (0, import_node_path14.join)(baseDir, ".github", "copilot-instructions.md");
1863
+ const copilotFilePath = (0, import_node_path15.join)(baseDir, ".github", "copilot-instructions.md");
1666
1864
  if (await fileExists(copilotFilePath)) {
1667
1865
  try {
1668
1866
  const rawContent = await readFileContent(copilotFilePath);
@@ -1687,19 +1885,19 @@ async function parseCopilotConfiguration(baseDir = process.cwd()) {
1687
1885
  errors.push(`Failed to parse copilot-instructions.md: ${errorMessage}`);
1688
1886
  }
1689
1887
  }
1690
- const instructionsDir = (0, import_node_path14.join)(baseDir, ".github", "instructions");
1888
+ const instructionsDir = (0, import_node_path15.join)(baseDir, ".github", "instructions");
1691
1889
  if (await fileExists(instructionsDir)) {
1692
1890
  try {
1693
1891
  const { readdir: readdir2 } = await import("fs/promises");
1694
1892
  const files = await readdir2(instructionsDir);
1695
1893
  for (const file of files) {
1696
1894
  if (file.endsWith(".instructions.md")) {
1697
- const filePath = (0, import_node_path14.join)(instructionsDir, file);
1895
+ const filePath = (0, import_node_path15.join)(instructionsDir, file);
1698
1896
  const rawContent = await readFileContent(filePath);
1699
1897
  const parsed = (0, import_gray_matter2.default)(rawContent);
1700
1898
  const content = parsed.content.trim();
1701
1899
  if (content) {
1702
- const filename = (0, import_node_path14.basename)(file, ".instructions.md");
1900
+ const filename = (0, import_node_path15.basename)(file, ".instructions.md");
1703
1901
  const frontmatter = {
1704
1902
  root: false,
1705
1903
  targets: ["copilot"],
@@ -1729,10 +1927,10 @@ async function parseCopilotConfiguration(baseDir = process.cwd()) {
1729
1927
  }
1730
1928
 
1731
1929
  // src/parsers/cursor.ts
1732
- var import_node_path15 = require("path");
1930
+ var import_node_path16 = require("path");
1733
1931
  var import_gray_matter3 = __toESM(require("gray-matter"), 1);
1734
1932
  var import_js_yaml = require("js-yaml");
1735
- var import_v4_mini6 = require("zod/v4-mini");
1933
+ var import_mini6 = require("zod/mini");
1736
1934
  var customMatterOptions = {
1737
1935
  engines: {
1738
1936
  yaml: {
@@ -1760,7 +1958,7 @@ var customMatterOptions = {
1760
1958
  }
1761
1959
  };
1762
1960
  function convertCursorMdcFrontmatter(cursorFrontmatter, _filename) {
1763
- const FrontmatterSchema = import_v4_mini6.z.record(import_v4_mini6.z.string(), import_v4_mini6.z.unknown());
1961
+ const FrontmatterSchema = import_mini6.z.record(import_mini6.z.string(), import_mini6.z.unknown());
1764
1962
  const parseResult = FrontmatterSchema.safeParse(cursorFrontmatter);
1765
1963
  if (!parseResult.success) {
1766
1964
  return {
@@ -1854,7 +2052,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
1854
2052
  const rules = [];
1855
2053
  let ignorePatterns;
1856
2054
  let mcpServers;
1857
- const cursorFilePath = (0, import_node_path15.join)(baseDir, ".cursorrules");
2055
+ const cursorFilePath = (0, import_node_path16.join)(baseDir, ".cursorrules");
1858
2056
  if (await fileExists(cursorFilePath)) {
1859
2057
  try {
1860
2058
  const rawContent = await readFileContent(cursorFilePath);
@@ -1875,20 +2073,20 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
1875
2073
  errors.push(`Failed to parse .cursorrules file: ${errorMessage}`);
1876
2074
  }
1877
2075
  }
1878
- const cursorRulesDir = (0, import_node_path15.join)(baseDir, ".cursor", "rules");
2076
+ const cursorRulesDir = (0, import_node_path16.join)(baseDir, ".cursor", "rules");
1879
2077
  if (await fileExists(cursorRulesDir)) {
1880
2078
  try {
1881
2079
  const { readdir: readdir2 } = await import("fs/promises");
1882
2080
  const files = await readdir2(cursorRulesDir);
1883
2081
  for (const file of files) {
1884
2082
  if (file.endsWith(".mdc")) {
1885
- const filePath = (0, import_node_path15.join)(cursorRulesDir, file);
2083
+ const filePath = (0, import_node_path16.join)(cursorRulesDir, file);
1886
2084
  try {
1887
2085
  const rawContent = await readFileContent(filePath);
1888
2086
  const parsed = (0, import_gray_matter3.default)(rawContent, customMatterOptions);
1889
2087
  const content = parsed.content.trim();
1890
2088
  if (content) {
1891
- const filename = (0, import_node_path15.basename)(file, ".mdc");
2089
+ const filename = (0, import_node_path16.basename)(file, ".mdc");
1892
2090
  const frontmatter = convertCursorMdcFrontmatter(parsed.data, filename);
1893
2091
  rules.push({
1894
2092
  frontmatter,
@@ -1911,7 +2109,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
1911
2109
  if (rules.length === 0) {
1912
2110
  errors.push("No Cursor configuration files found (.cursorrules or .cursor/rules/*.mdc)");
1913
2111
  }
1914
- const cursorIgnorePath = (0, import_node_path15.join)(baseDir, ".cursorignore");
2112
+ const cursorIgnorePath = (0, import_node_path16.join)(baseDir, ".cursorignore");
1915
2113
  if (await fileExists(cursorIgnorePath)) {
1916
2114
  try {
1917
2115
  const content = await readFileContent(cursorIgnorePath);
@@ -1924,7 +2122,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
1924
2122
  errors.push(`Failed to parse .cursorignore: ${errorMessage}`);
1925
2123
  }
1926
2124
  }
1927
- const cursorMcpPath = (0, import_node_path15.join)(baseDir, ".cursor", "mcp.json");
2125
+ const cursorMcpPath = (0, import_node_path16.join)(baseDir, ".cursor", "mcp.json");
1928
2126
  if (await fileExists(cursorMcpPath)) {
1929
2127
  try {
1930
2128
  const content = await readFileContent(cursorMcpPath);
@@ -1947,13 +2145,13 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
1947
2145
  }
1948
2146
 
1949
2147
  // src/parsers/geminicli.ts
1950
- var import_node_path16 = require("path");
2148
+ var import_node_path17 = require("path");
1951
2149
  async function parseGeminiConfiguration(baseDir = process.cwd()) {
1952
2150
  const errors = [];
1953
2151
  const rules = [];
1954
2152
  let ignorePatterns;
1955
2153
  let mcpServers;
1956
- const geminiFilePath = (0, import_node_path16.join)(baseDir, "GEMINI.md");
2154
+ const geminiFilePath = (0, import_node_path17.join)(baseDir, "GEMINI.md");
1957
2155
  if (!await fileExists(geminiFilePath)) {
1958
2156
  errors.push("GEMINI.md file not found");
1959
2157
  return { rules, errors };
@@ -1964,12 +2162,12 @@ async function parseGeminiConfiguration(baseDir = process.cwd()) {
1964
2162
  if (mainRule) {
1965
2163
  rules.push(mainRule);
1966
2164
  }
1967
- const memoryDir = (0, import_node_path16.join)(baseDir, ".gemini", "memories");
2165
+ const memoryDir = (0, import_node_path17.join)(baseDir, ".gemini", "memories");
1968
2166
  if (await fileExists(memoryDir)) {
1969
2167
  const memoryRules = await parseGeminiMemoryFiles(memoryDir);
1970
2168
  rules.push(...memoryRules);
1971
2169
  }
1972
- const settingsPath = (0, import_node_path16.join)(baseDir, ".gemini", "settings.json");
2170
+ const settingsPath = (0, import_node_path17.join)(baseDir, ".gemini", "settings.json");
1973
2171
  if (await fileExists(settingsPath)) {
1974
2172
  const settingsResult = await parseGeminiSettings(settingsPath);
1975
2173
  if (settingsResult.ignorePatterns) {
@@ -1980,7 +2178,7 @@ async function parseGeminiConfiguration(baseDir = process.cwd()) {
1980
2178
  }
1981
2179
  errors.push(...settingsResult.errors);
1982
2180
  }
1983
- const aiexcludePath = (0, import_node_path16.join)(baseDir, ".aiexclude");
2181
+ const aiexcludePath = (0, import_node_path17.join)(baseDir, ".aiexclude");
1984
2182
  if (await fileExists(aiexcludePath)) {
1985
2183
  const aiexcludePatterns = await parseAiexclude(aiexcludePath);
1986
2184
  if (aiexcludePatterns.length > 0) {
@@ -2033,10 +2231,10 @@ async function parseGeminiMemoryFiles(memoryDir) {
2033
2231
  const files = await readdir2(memoryDir);
2034
2232
  for (const file of files) {
2035
2233
  if (file.endsWith(".md")) {
2036
- const filePath = (0, import_node_path16.join)(memoryDir, file);
2234
+ const filePath = (0, import_node_path17.join)(memoryDir, file);
2037
2235
  const content = await readFileContent(filePath);
2038
2236
  if (content.trim()) {
2039
- const filename = (0, import_node_path16.basename)(file, ".md");
2237
+ const filename = (0, import_node_path17.basename)(file, ".md");
2040
2238
  const frontmatter = {
2041
2239
  root: false,
2042
2240
  targets: ["geminicli"],
@@ -2086,11 +2284,11 @@ async function parseAiexclude(aiexcludePath) {
2086
2284
  }
2087
2285
 
2088
2286
  // src/parsers/roo.ts
2089
- var import_node_path17 = require("path");
2287
+ var import_node_path18 = require("path");
2090
2288
  async function parseRooConfiguration(baseDir = process.cwd()) {
2091
2289
  const errors = [];
2092
2290
  const rules = [];
2093
- const rooFilePath = (0, import_node_path17.join)(baseDir, ".roo", "instructions.md");
2291
+ const rooFilePath = (0, import_node_path18.join)(baseDir, ".roo", "instructions.md");
2094
2292
  if (await fileExists(rooFilePath)) {
2095
2293
  try {
2096
2294
  const content = await readFileContent(rooFilePath);
@@ -2113,14 +2311,14 @@ async function parseRooConfiguration(baseDir = process.cwd()) {
2113
2311
  errors.push(`Failed to parse .roo/instructions.md: ${errorMessage}`);
2114
2312
  }
2115
2313
  }
2116
- const rooRulesDir = (0, import_node_path17.join)(baseDir, ".roo", "rules");
2314
+ const rooRulesDir = (0, import_node_path18.join)(baseDir, ".roo", "rules");
2117
2315
  if (await fileExists(rooRulesDir)) {
2118
2316
  try {
2119
2317
  const { readdir: readdir2 } = await import("fs/promises");
2120
2318
  const files = await readdir2(rooRulesDir);
2121
2319
  for (const file of files) {
2122
2320
  if (file.endsWith(".md")) {
2123
- const filePath = (0, import_node_path17.join)(rooRulesDir, file);
2321
+ const filePath = (0, import_node_path18.join)(rooRulesDir, file);
2124
2322
  try {
2125
2323
  const content = await readFileContent(filePath);
2126
2324
  if (content.trim()) {
@@ -2221,7 +2419,7 @@ async function importConfiguration(options) {
2221
2419
  if (rules.length === 0 && !ignorePatterns && !mcpServers) {
2222
2420
  return { success: false, rulesCreated: 0, errors };
2223
2421
  }
2224
- const rulesDirPath = (0, import_node_path18.join)(baseDir, rulesDir);
2422
+ const rulesDirPath = (0, import_node_path19.join)(baseDir, rulesDir);
2225
2423
  try {
2226
2424
  const { mkdir: mkdir3 } = await import("fs/promises");
2227
2425
  await mkdir3(rulesDirPath, { recursive: true });
@@ -2235,7 +2433,7 @@ async function importConfiguration(options) {
2235
2433
  try {
2236
2434
  const baseFilename = `${tool}__${rule.filename}`;
2237
2435
  const filename = await generateUniqueFilename(rulesDirPath, baseFilename);
2238
- const filePath = (0, import_node_path18.join)(rulesDirPath, `${filename}.md`);
2436
+ const filePath = (0, import_node_path19.join)(rulesDirPath, `${filename}.md`);
2239
2437
  const content = generateRuleFileContent(rule);
2240
2438
  await writeFileContent(filePath, content);
2241
2439
  rulesCreated++;
@@ -2250,7 +2448,7 @@ async function importConfiguration(options) {
2250
2448
  let ignoreFileCreated = false;
2251
2449
  if (ignorePatterns && ignorePatterns.length > 0) {
2252
2450
  try {
2253
- const rulesyncignorePath = (0, import_node_path18.join)(baseDir, ".rulesyncignore");
2451
+ const rulesyncignorePath = (0, import_node_path19.join)(baseDir, ".rulesyncignore");
2254
2452
  const ignoreContent = `${ignorePatterns.join("\n")}
2255
2453
  `;
2256
2454
  await writeFileContent(rulesyncignorePath, ignoreContent);
@@ -2266,7 +2464,7 @@ async function importConfiguration(options) {
2266
2464
  let mcpFileCreated = false;
2267
2465
  if (mcpServers && Object.keys(mcpServers).length > 0) {
2268
2466
  try {
2269
- const mcpPath = (0, import_node_path18.join)(baseDir, rulesDir, ".mcp.json");
2467
+ const mcpPath = (0, import_node_path19.join)(baseDir, rulesDir, ".mcp.json");
2270
2468
  const mcpContent = `${JSON.stringify({ mcpServers }, null, 2)}
2271
2469
  `;
2272
2470
  await writeFileContent(mcpPath, mcpContent);
@@ -2280,7 +2478,7 @@ async function importConfiguration(options) {
2280
2478
  }
2281
2479
  }
2282
2480
  return {
2283
- success: rulesCreated > 0 || ignoreFileCreated || mcpFileCreated,
2481
+ success: errors.length === 0 && (rulesCreated > 0 || ignoreFileCreated || mcpFileCreated),
2284
2482
  rulesCreated,
2285
2483
  errors,
2286
2484
  ignoreFileCreated,
@@ -2294,7 +2492,7 @@ function generateRuleFileContent(rule) {
2294
2492
  async function generateUniqueFilename(rulesDir, baseFilename) {
2295
2493
  let filename = baseFilename;
2296
2494
  let counter = 1;
2297
- while (await fileExists((0, import_node_path18.join)(rulesDir, `${filename}.md`))) {
2495
+ while (await fileExists((0, import_node_path19.join)(rulesDir, `${filename}.md`))) {
2298
2496
  filename = `${baseFilename}-${counter}`;
2299
2497
  counter++;
2300
2498
  }
@@ -2359,7 +2557,7 @@ async function importCommand(options = {}) {
2359
2557
  }
2360
2558
 
2361
2559
  // src/cli/commands/init.ts
2362
- var import_node_path19 = require("path");
2560
+ var import_node_path20 = require("path");
2363
2561
  async function initCommand() {
2364
2562
  const aiRulesDir = ".rulesync";
2365
2563
  console.log("Initializing rulesync...");
@@ -2371,14 +2569,13 @@ async function initCommand() {
2371
2569
  console.log("2. Run 'rulesync generate' to create configuration files");
2372
2570
  }
2373
2571
  async function createSampleFiles(aiRulesDir) {
2374
- const sampleFiles = [
2375
- {
2376
- filename: "overview.md",
2377
- content: `---
2572
+ const sampleFile = {
2573
+ filename: "overview.md",
2574
+ content: `---
2378
2575
  root: true
2379
2576
  targets: ["*"]
2380
2577
  description: "Project overview and general development guidelines"
2381
- globs: ["**/*.ts", "**/*.js", "**/*.tsx", "**/*.jsx"]
2578
+ globs: ["**/*"]
2382
2579
  ---
2383
2580
 
2384
2581
  # Project Overview
@@ -2406,96 +2603,13 @@ globs: ["**/*.ts", "**/*.js", "**/*.tsx", "**/*.jsx"]
2406
2603
  - Implement proper error handling
2407
2604
  - Follow single responsibility principle
2408
2605
  `
2409
- },
2410
- {
2411
- filename: "frontend.md",
2412
- content: `---
2413
- root: false
2414
- targets: ["*"]
2415
- description: "Frontend development rules and best practices"
2416
- globs: ["src/components/**/*.tsx", "src/pages/**/*.tsx", "**/*.css", "**/*.scss"]
2417
- ---
2418
-
2419
- # Frontend Development Rules
2420
-
2421
- ## React Components
2422
-
2423
- - Use functional components with hooks
2424
- - Follow PascalCase naming for components
2425
- - Use TypeScript interfaces for props
2426
- - Implement proper error boundaries
2427
-
2428
- ## Styling
2429
-
2430
- - Use CSS modules or styled-components
2431
- - Follow BEM methodology for CSS classes
2432
- - Prefer flexbox and grid for layouts
2433
- - Use semantic HTML elements
2434
-
2435
- ## State Management
2436
-
2437
- - Use React hooks for local state
2438
- - Consider Redux or Zustand for global state
2439
- - Avoid prop drilling with context API
2440
- - Keep state as close to where it's used as possible
2441
-
2442
- ## Performance
2443
-
2444
- - Use React.memo for expensive components
2445
- - Implement lazy loading for routes
2446
- - Optimize images and assets
2447
- - Use proper key props in lists
2448
- `
2449
- },
2450
- {
2451
- filename: "backend.md",
2452
- content: `---
2453
- root: false
2454
- targets: ["*"]
2455
- description: "Backend development rules and API guidelines"
2456
- globs: ["src/api/**/*.ts", "src/services/**/*.ts", "src/models/**/*.ts"]
2457
- ---
2458
-
2459
- # Backend Development Rules
2460
-
2461
- ## API Design
2462
-
2463
- - Follow RESTful conventions
2464
- - Use consistent HTTP status codes
2465
- - Implement proper error handling with meaningful messages
2466
- - Use API versioning when necessary
2467
-
2468
- ## Database
2469
-
2470
- - Use proper indexing for performance
2471
- - Implement database migrations
2472
- - Follow naming conventions for tables and columns
2473
- - Use transactions for data consistency
2474
-
2475
- ## Security
2476
-
2477
- - Validate all input data
2478
- - Use proper authentication and authorization
2479
- - Implement rate limiting
2480
- - Sanitize database queries to prevent SQL injection
2481
-
2482
- ## Code Organization
2483
-
2484
- - Use service layer pattern
2485
- - Implement proper logging
2486
- - Use environment variables for configuration
2487
- - Write comprehensive tests for business logic
2488
- `
2489
- }
2490
- ];
2491
- for (const file of sampleFiles) {
2492
- const filepath = (0, import_node_path19.join)(aiRulesDir, file.filename);
2493
- if (!await fileExists(filepath)) {
2494
- await writeFileContent(filepath, file.content);
2495
- console.log(`Created ${filepath}`);
2496
- } else {
2497
- console.log(`Skipped ${filepath} (already exists)`);
2498
- }
2606
+ };
2607
+ const filepath = (0, import_node_path20.join)(aiRulesDir, sampleFile.filename);
2608
+ if (!await fileExists(filepath)) {
2609
+ await writeFileContent(filepath, sampleFile.content);
2610
+ console.log(`Created ${filepath}`);
2611
+ } else {
2612
+ console.log(`Skipped ${filepath} (already exists)`);
2499
2613
  }
2500
2614
  }
2501
2615
 
@@ -2634,12 +2748,12 @@ async function watchCommand() {
2634
2748
 
2635
2749
  // src/cli/index.ts
2636
2750
  var program = new import_commander.Command();
2637
- program.name("rulesync").description("Unified AI rules management CLI tool").version("0.44.0");
2751
+ program.name("rulesync").description("Unified AI rules management CLI tool").version("0.47.0");
2638
2752
  program.command("init").description("Initialize rulesync in current directory").action(initCommand);
2639
2753
  program.command("add <filename>").description("Add a new rule file").action(addCommand);
2640
2754
  program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);
2641
2755
  program.command("import").description("Import configurations from AI tools to rulesync format").option("--claudecode", "Import from Claude Code (CLAUDE.md)").option("--cursor", "Import from Cursor (.cursorrules)").option("--copilot", "Import from GitHub Copilot (.github/copilot-instructions.md)").option("--cline", "Import from Cline (.cline/instructions.md)").option("--roo", "Import from Roo Code (.roo/instructions.md)").option("--geminicli", "Import from Gemini CLI (GEMINI.md)").option("-v, --verbose", "Verbose output").action(importCommand);
2642
- program.command("generate").description("Generate configuration files for AI tools").option("--copilot", "Generate only for GitHub Copilot").option("--cursor", "Generate only for Cursor").option("--cline", "Generate only for Cline").option("--claudecode", "Generate only for Claude Code").option("--roo", "Generate only for Roo Code").option("--geminicli", "Generate only for Gemini CLI").option("--delete", "Delete all existing files in output directories before generating").option(
2756
+ program.command("generate").description("Generate configuration files for AI tools").option("--copilot", "Generate only for GitHub Copilot").option("--cursor", "Generate only for Cursor").option("--cline", "Generate only for Cline").option("--claudecode", "Generate only for Claude Code").option("--roo", "Generate only for Roo Code").option("--geminicli", "Generate only for Gemini CLI").option("--kiro", "Generate only for Kiro IDE").option("--delete", "Delete all existing files in output directories before generating").option(
2643
2757
  "-b, --base-dir <paths>",
2644
2758
  "Base directories to generate files (comma-separated for multiple paths)"
2645
2759
  ).option("-v, --verbose", "Verbose output").action(async (options) => {
@@ -2650,6 +2764,7 @@ program.command("generate").description("Generate configuration files for AI too
2650
2764
  if (options.claudecode) tools.push("claudecode");
2651
2765
  if (options.roo) tools.push("roo");
2652
2766
  if (options.geminicli) tools.push("geminicli");
2767
+ if (options.kiro) tools.push("kiro");
2653
2768
  const generateOptions = {
2654
2769
  verbose: options.verbose,
2655
2770
  delete: options.delete