rulesync 0.63.0 → 0.65.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.
Files changed (35) hide show
  1. package/README.md +21 -3
  2. package/dist/amazonqcli-MW7XTVPN.js +9 -0
  3. package/dist/{augmentcode-HIZIQG2W.js → augmentcode-WCZCL7VR.js} +2 -2
  4. package/dist/{chunk-KUGTKMNW.js → chunk-4NWMCTN5.js} +5 -2
  5. package/dist/chunk-6AXPFPKI.js +17 -0
  6. package/dist/{chunk-LXTA7DBA.js → chunk-6SLEITCQ.js} +1 -1
  7. package/dist/chunk-DM2B7XUB.js +210 -0
  8. package/dist/{chunk-UEAYL4NT.js → chunk-FL5BF6JM.js} +1 -1
  9. package/dist/{chunk-4PSTOKKD.js → chunk-GIAQWZQ4.js} +1 -1
  10. package/dist/{chunk-YTU3SCQO.js → chunk-I4NVS7GE.js} +9 -3
  11. package/dist/{chunk-GQTMTBX4.js → chunk-JXOLLTNV.js} +89 -4
  12. package/dist/{chunk-NETSYSMD.js → chunk-LTWEI4PW.js} +1 -1
  13. package/dist/{chunk-AUUSMVCT.js → chunk-M2AUM37M.js} +3 -0
  14. package/dist/{chunk-M7NL7G7A.js → chunk-N6DASHJL.js} +1 -1
  15. package/dist/chunk-TX2CE4RR.js +17 -0
  16. package/dist/{chunk-2CW2KFB3.js → chunk-UGY5ALND.js} +1 -1
  17. package/dist/chunk-VRWNZTGW.js +17 -0
  18. package/dist/{chunk-U4PLVMCG.js → chunk-YC2BC7Z2.js} +1 -1
  19. package/dist/{claudecode-YTEFACCT.js → claudecode-RZSJPPBU.js} +3 -3
  20. package/dist/{cline-CKNUDEA3.js → cline-JTWWBQQ4.js} +3 -3
  21. package/dist/{codexcli-7SDGYI7D.js → codexcli-ATMFGRJR.js} +3 -3
  22. package/dist/{copilot-MOR3HHJX.js → copilot-H3CLGKDP.js} +2 -2
  23. package/dist/{cursor-YJGH7W24.js → cursor-ZUN5RZU6.js} +3 -3
  24. package/dist/{geminicli-E7KZTZ2G.js → geminicli-Q5HPIQCU.js} +3 -3
  25. package/dist/index.cjs +1213 -619
  26. package/dist/index.js +806 -488
  27. package/dist/{junie-5LEQU4BO.js → junie-JCLVC3MI.js} +3 -3
  28. package/dist/{kiro-YDHXY2MA.js → kiro-CNF6433S.js} +2 -2
  29. package/dist/opencode-EBS3CED2.js +17 -0
  30. package/dist/qwencode-JIT6KW7E.js +10 -0
  31. package/dist/{roo-L3QTTIPO.js → roo-KBTRH4TZ.js} +3 -2
  32. package/dist/{windsurf-4P6HEUBV.js → windsurf-ZAAWL6JJ.js} +3 -3
  33. package/package.json +2 -1
  34. package/dist/chunk-MDYDKNXQ.js +0 -61
  35. package/dist/chunk-PCATT4UZ.js +0 -78
package/dist/index.cjs CHANGED
@@ -41,6 +41,7 @@ var init_tool_targets = __esm({
41
41
  "use strict";
42
42
  import_mini2 = require("zod/mini");
43
43
  ALL_TOOL_TARGETS = [
44
+ "amazonqcli",
44
45
  "augmentcode",
45
46
  "augmentcode-legacy",
46
47
  "copilot",
@@ -48,6 +49,8 @@ var init_tool_targets = __esm({
48
49
  "cline",
49
50
  "claudecode",
50
51
  "codexcli",
52
+ "opencode",
53
+ "qwencode",
51
54
  "roo",
52
55
  "geminicli",
53
56
  "kiro",
@@ -61,6 +64,152 @@ var init_tool_targets = __esm({
61
64
  }
62
65
  });
63
66
 
67
+ // src/utils/logger.ts
68
+ var import_consola, Logger, logger;
69
+ var init_logger = __esm({
70
+ "src/utils/logger.ts"() {
71
+ "use strict";
72
+ import_consola = require("consola");
73
+ Logger = class {
74
+ _verbose = false;
75
+ console = import_consola.consola.withDefaults({
76
+ tag: "rulesync"
77
+ });
78
+ setVerbose(verbose) {
79
+ this._verbose = verbose;
80
+ }
81
+ get verbose() {
82
+ return this._verbose;
83
+ }
84
+ // Regular log (always shown, regardless of verbose)
85
+ log(message, ...args) {
86
+ this.console.log(message, ...args);
87
+ }
88
+ // Info level (shown only in verbose mode)
89
+ info(message, ...args) {
90
+ if (this._verbose) {
91
+ this.console.info(message, ...args);
92
+ }
93
+ }
94
+ // Success (always shown)
95
+ success(message, ...args) {
96
+ this.console.success(message, ...args);
97
+ }
98
+ // Warning (always shown)
99
+ warn(message, ...args) {
100
+ this.console.warn(message, ...args);
101
+ }
102
+ // Error (always shown)
103
+ error(message, ...args) {
104
+ this.console.error(message, ...args);
105
+ }
106
+ // Debug level (shown only in verbose mode)
107
+ debug(message, ...args) {
108
+ if (this._verbose) {
109
+ this.console.debug(message, ...args);
110
+ }
111
+ }
112
+ };
113
+ logger = new Logger();
114
+ }
115
+ });
116
+
117
+ // src/utils/file.ts
118
+ async function ensureDir(dirPath) {
119
+ try {
120
+ await (0, import_promises2.stat)(dirPath);
121
+ } catch {
122
+ await (0, import_promises2.mkdir)(dirPath, { recursive: true });
123
+ }
124
+ }
125
+ function resolvePath(relativePath, baseDir) {
126
+ if (!baseDir) return relativePath;
127
+ const resolved = (0, import_node_path.resolve)(baseDir, relativePath);
128
+ const rel = (0, import_node_path.relative)(baseDir, resolved);
129
+ if (rel.startsWith("..") || (0, import_node_path.resolve)(resolved) !== resolved) {
130
+ throw new Error(`Path traversal detected: ${relativePath}`);
131
+ }
132
+ return resolved;
133
+ }
134
+ async function readFileContent(filepath) {
135
+ return (0, import_promises2.readFile)(filepath, "utf-8");
136
+ }
137
+ async function writeFileContent(filepath, content) {
138
+ await ensureDir((0, import_node_path.dirname)(filepath));
139
+ await (0, import_promises2.writeFile)(filepath, content, "utf-8");
140
+ }
141
+ async function fileExists(filepath) {
142
+ try {
143
+ await (0, import_promises2.stat)(filepath);
144
+ return true;
145
+ } catch {
146
+ return false;
147
+ }
148
+ }
149
+ async function findFiles(dir, extension = ".md") {
150
+ try {
151
+ const files = await (0, import_promises2.readdir)(dir);
152
+ return files.filter((file) => file.endsWith(extension)).map((file) => (0, import_node_path.join)(dir, file));
153
+ } catch {
154
+ return [];
155
+ }
156
+ }
157
+ async function findRuleFiles(aiRulesDir) {
158
+ const rulesDir = (0, import_node_path.join)(aiRulesDir, "rules");
159
+ const newLocationFiles = await findFiles(rulesDir, ".md");
160
+ const legacyLocationFiles = await findFiles(aiRulesDir, ".md");
161
+ const newLocationBasenames = new Set(
162
+ newLocationFiles.map((file) => file.split("/").pop()?.replace(/\.md$/, ""))
163
+ );
164
+ const filteredLegacyFiles = legacyLocationFiles.filter((file) => {
165
+ const basename6 = file.split("/").pop()?.replace(/\.md$/, "");
166
+ return !newLocationBasenames.has(basename6);
167
+ });
168
+ return [...newLocationFiles, ...filteredLegacyFiles];
169
+ }
170
+ async function removeDirectory(dirPath) {
171
+ const dangerousPaths = [".", "/", "~", "src", "node_modules"];
172
+ if (dangerousPaths.includes(dirPath) || dirPath === "") {
173
+ logger.warn(`Skipping deletion of dangerous path: ${dirPath}`);
174
+ return;
175
+ }
176
+ try {
177
+ if (await fileExists(dirPath)) {
178
+ await (0, import_promises2.rm)(dirPath, { recursive: true, force: true });
179
+ }
180
+ } catch (error) {
181
+ logger.warn(`Failed to remove directory ${dirPath}:`, error);
182
+ }
183
+ }
184
+ async function removeFile(filepath) {
185
+ try {
186
+ if (await fileExists(filepath)) {
187
+ await (0, import_promises2.rm)(filepath);
188
+ }
189
+ } catch (error) {
190
+ logger.warn(`Failed to remove file ${filepath}:`, error);
191
+ }
192
+ }
193
+ async function removeClaudeGeneratedFiles() {
194
+ const filesToRemove = ["CLAUDE.md", ".claude/memories"];
195
+ for (const fileOrDir of filesToRemove) {
196
+ if (fileOrDir.endsWith("/memories")) {
197
+ await removeDirectory(fileOrDir);
198
+ } else {
199
+ await removeFile(fileOrDir);
200
+ }
201
+ }
202
+ }
203
+ var import_promises2, import_node_path;
204
+ var init_file = __esm({
205
+ "src/utils/file.ts"() {
206
+ "use strict";
207
+ import_promises2 = require("fs/promises");
208
+ import_node_path = require("path");
209
+ init_logger();
210
+ }
211
+ });
212
+
64
213
  // src/utils/mcp-helpers.ts
65
214
  function shouldIncludeServer(server, targetTool) {
66
215
  if (!server.targets || server.targets.length === 0) {
@@ -85,6 +234,75 @@ var init_mcp_helpers = __esm({
85
234
  }
86
235
  });
87
236
 
237
+ // src/generators/mcp/amazonqcli.ts
238
+ var amazonqcli_exports = {};
239
+ __export(amazonqcli_exports, {
240
+ generateAmazonqcliMcp: () => generateAmazonqcliMcp,
241
+ generateAmazonqcliMcpString: () => generateAmazonqcliMcpString
242
+ });
243
+ async function generateAmazonqcliMcp(mcpServers, config, baseDir) {
244
+ const outputs = [];
245
+ const configPaths = [
246
+ ".amazonq/mcp.json"
247
+ // Workspace configuration
248
+ // Note: Global configuration is ~/.aws/amazonq/mcp.json but is user-specific
249
+ // According to precautions.md, we should not create user-level files
250
+ ];
251
+ for (const configPath of configPaths) {
252
+ const filepath = resolvePath(configPath, baseDir);
253
+ const content = generateAmazonqcliMcpConfig({ mcpServers });
254
+ outputs.push({
255
+ tool: "amazonqcli",
256
+ filepath,
257
+ content
258
+ });
259
+ }
260
+ return outputs;
261
+ }
262
+ function generateAmazonqcliMcpString(config) {
263
+ return generateAmazonqcliMcpConfig(config);
264
+ }
265
+ function generateAmazonqcliMcpConfig(config) {
266
+ const servers = {};
267
+ for (const [serverName, server] of Object.entries(config.mcpServers)) {
268
+ if (!shouldIncludeServer(server, "amazonqcli")) {
269
+ continue;
270
+ }
271
+ const amazonqServer = {};
272
+ if (server.command) {
273
+ amazonqServer.command = server.command;
274
+ if (server.args) {
275
+ amazonqServer.args = server.args;
276
+ }
277
+ }
278
+ if (server.env) {
279
+ amazonqServer.env = server.env;
280
+ }
281
+ if (server.timeout !== void 0) {
282
+ amazonqServer.timeout = server.timeout;
283
+ }
284
+ if (server.disabled !== void 0) {
285
+ amazonqServer.disabled = server.disabled;
286
+ }
287
+ if (server.alwaysAllow) {
288
+ amazonqServer.autoApprove = server.alwaysAllow;
289
+ }
290
+ servers[serverName] = amazonqServer;
291
+ }
292
+ const finalConfig = {
293
+ mcpServers: servers
294
+ };
295
+ return `${JSON.stringify(finalConfig, null, 2)}
296
+ `;
297
+ }
298
+ var init_amazonqcli = __esm({
299
+ "src/generators/mcp/amazonqcli.ts"() {
300
+ "use strict";
301
+ init_file();
302
+ init_mcp_helpers();
303
+ }
304
+ });
305
+
88
306
  // src/generators/mcp/augmentcode.ts
89
307
  var augmentcode_exports = {};
90
308
  __export(augmentcode_exports, {
@@ -104,7 +322,10 @@ function generateAugmentcodeMcp(config) {
104
322
  name: serverName
105
323
  };
106
324
  if (server.command) {
107
- augmentServer.command = server.command;
325
+ const command = Array.isArray(server.command) ? server.command[0] : server.command;
326
+ if (command) {
327
+ augmentServer.command = command;
328
+ }
108
329
  if (server.args) {
109
330
  augmentServer.args = server.args;
110
331
  }
@@ -152,7 +373,10 @@ function generateAugmentcodeMcpConfiguration(mcpServers, baseDir = "") {
152
373
  const { targets: _, ...serverConfig } = server;
153
374
  const augmentServer = {};
154
375
  if (serverConfig.command) {
155
- augmentServer.command = serverConfig.command;
376
+ const command = Array.isArray(serverConfig.command) ? serverConfig.command[0] : serverConfig.command;
377
+ if (command) {
378
+ augmentServer.command = command;
379
+ }
156
380
  if (serverConfig.args) {
157
381
  augmentServer.args = serverConfig.args;
158
382
  }
@@ -199,6 +423,17 @@ var init_augmentcode = __esm({
199
423
  }
200
424
  });
201
425
 
426
+ // src/constants/schemas.ts
427
+ var SCHEMA_URLS;
428
+ var init_schemas = __esm({
429
+ "src/constants/schemas.ts"() {
430
+ "use strict";
431
+ SCHEMA_URLS = {
432
+ OPENCODE: "https://opencode.ai/config.json"
433
+ };
434
+ }
435
+ });
436
+
202
437
  // src/generators/mcp/shared-factory.ts
203
438
  function generateMcpConfig(config, toolConfig) {
204
439
  const servers = {};
@@ -248,7 +483,7 @@ function generateMcpConfigurationFilesFromRegistry(tool, mcpServers, baseDir = "
248
483
  if (tool === "junie") {
249
484
  return generateJunieMcpConfigurationFiles(mcpServers, baseDir);
250
485
  }
251
- const customTools = ["copilot", "augmentcode", "roo", "codexcli", "kiro", "geminicli"];
486
+ const customTools = ["copilot", "augmentcode", "codexcli", "kiro"];
252
487
  if (customTools.includes(tool)) {
253
488
  throw new Error(
254
489
  `Tool ${tool} uses custom configuration logic - use its specific generator function instead`
@@ -297,6 +532,7 @@ var serverTransforms, configWrappers, MCP_GENERATOR_REGISTRY, cursorMcpGenerator
297
532
  var init_shared_factory = __esm({
298
533
  "src/generators/mcp/shared-factory.ts"() {
299
534
  "use strict";
535
+ init_schemas();
300
536
  init_mcp_helpers();
301
537
  serverTransforms = {
302
538
  /**
@@ -307,7 +543,8 @@ var init_shared_factory = __esm({
307
543
  if (server.command) {
308
544
  result.command = server.command;
309
545
  if (server.args) result.args = server.args;
310
- } else if (server.url || server.httpUrl) {
546
+ }
547
+ if (server.url || server.httpUrl) {
311
548
  const url = server.httpUrl || server.url;
312
549
  if (url) result.url = url;
313
550
  }
@@ -316,6 +553,25 @@ var init_shared_factory = __esm({
316
553
  }
317
554
  return result;
318
555
  },
556
+ /**
557
+ * Roo-specific server transformation (preserves httpUrl, transport, type, etc.)
558
+ */
559
+ roo: (server) => {
560
+ const result = serverTransforms.extended(server);
561
+ if (server.httpUrl) {
562
+ if (!server.url) {
563
+ result.httpUrl = server.httpUrl;
564
+ delete result.url;
565
+ }
566
+ }
567
+ if (server.transport) {
568
+ result.transport = server.transport;
569
+ }
570
+ if (server.type) {
571
+ result.type = server.type;
572
+ }
573
+ return result;
574
+ },
319
575
  /**
320
576
  * Extended server transformation (includes disabled, alwaysAllow, etc.)
321
577
  */
@@ -367,6 +623,12 @@ var init_shared_factory = __esm({
367
623
  })
368
624
  };
369
625
  MCP_GENERATOR_REGISTRY = {
626
+ roo: {
627
+ target: "roo",
628
+ configPaths: [".roo/mcp.json"],
629
+ serverTransform: serverTransforms.roo,
630
+ configWrapper: configWrappers.mcpServers
631
+ },
370
632
  claudecode: {
371
633
  target: "claudecode",
372
634
  configPaths: [".mcp.json"],
@@ -493,6 +755,61 @@ var init_shared_factory = __esm({
493
755
  configPaths: [".cline/mcp.json"],
494
756
  serverTransform: serverTransforms.extended,
495
757
  configWrapper: configWrappers.mcpServers
758
+ },
759
+ geminicli: {
760
+ target: "geminicli",
761
+ configPaths: [".gemini/settings.json"],
762
+ serverTransform: (server) => {
763
+ const { targets: _, ...serverConfig } = server;
764
+ const geminiServer = { ...serverConfig };
765
+ if (server.env) {
766
+ geminiServer.env = server.env;
767
+ }
768
+ return geminiServer;
769
+ },
770
+ configWrapper: configWrappers.mcpServers
771
+ },
772
+ opencode: {
773
+ target: "opencode",
774
+ configPaths: ["opencode.json"],
775
+ serverTransform: (server) => {
776
+ const opencodeServer = {};
777
+ if (server.command) {
778
+ opencodeServer.type = "local";
779
+ opencodeServer.command = Array.isArray(server.command) ? server.command : [server.command];
780
+ if (server.args) opencodeServer.args = server.args;
781
+ if (server.env) opencodeServer.environment = server.env;
782
+ if (server.cwd) opencodeServer.cwd = server.cwd;
783
+ } else if (server.url || server.httpUrl) {
784
+ opencodeServer.type = "remote";
785
+ const url = server.httpUrl || server.url;
786
+ if (url) opencodeServer.url = url;
787
+ if (server.headers) opencodeServer.headers = server.headers;
788
+ }
789
+ if (server.disabled !== void 0) {
790
+ opencodeServer.enabled = !server.disabled;
791
+ } else {
792
+ opencodeServer.enabled = true;
793
+ }
794
+ return opencodeServer;
795
+ },
796
+ configWrapper: (servers) => ({
797
+ $schema: SCHEMA_URLS.OPENCODE,
798
+ mcp: servers
799
+ })
800
+ },
801
+ qwencode: {
802
+ target: "qwencode",
803
+ configPaths: [".qwen/settings.json"],
804
+ serverTransform: (server) => {
805
+ const { targets: _, ...serverConfig } = server;
806
+ const qwenServer = { ...serverConfig };
807
+ if (server.env) {
808
+ qwenServer.env = server.env;
809
+ }
810
+ return qwenServer;
811
+ },
812
+ configWrapper: configWrappers.mcpServers
496
813
  }
497
814
  };
498
815
  cursorMcpGenerator = createMcpGenerator("cursor");
@@ -696,7 +1013,10 @@ function generateCopilotMcp(config, target) {
696
1013
  if (!shouldIncludeServer(server, "copilot")) continue;
697
1014
  const copilotServer = {};
698
1015
  if (server.command) {
699
- copilotServer.command = server.command;
1016
+ const command = Array.isArray(server.command) ? server.command[0] : server.command;
1017
+ if (command) {
1018
+ copilotServer.command = command;
1019
+ }
700
1020
  if (server.args) copilotServer.args = server.args;
701
1021
  } else if (server.url || server.httpUrl) {
702
1022
  const url = server.httpUrl || server.url;
@@ -786,53 +1106,10 @@ __export(geminicli_exports, {
786
1106
  generateGeminiCliMcpConfiguration: () => generateGeminiCliMcpConfiguration
787
1107
  });
788
1108
  function generateGeminiCliMcp(config) {
789
- return generateMcpConfig(config, {
790
- target: "geminicli",
791
- configPaths: [".gemini/settings.json"],
792
- serverTransform: (server) => {
793
- const geminiServer = {};
794
- if (server.command) {
795
- geminiServer.command = server.command;
796
- if (server.args) geminiServer.args = server.args;
797
- } else if (server.url || server.httpUrl) {
798
- if (server.httpUrl) {
799
- geminiServer.httpUrl = server.httpUrl;
800
- } else if (server.url) {
801
- geminiServer.url = server.url;
802
- }
803
- }
804
- if (server.env) {
805
- geminiServer.env = server.env;
806
- }
807
- if (server.timeout !== void 0) {
808
- geminiServer.timeout = server.timeout;
809
- }
810
- if (server.trust !== void 0) {
811
- geminiServer.trust = server.trust;
812
- }
813
- return geminiServer;
814
- },
815
- configWrapper: configWrappers.mcpServers
816
- });
1109
+ return generateMcpFromRegistry("geminicli", config);
817
1110
  }
818
1111
  function generateGeminiCliMcpConfiguration(mcpServers, baseDir = "") {
819
- return generateMcpConfigurationFiles(
820
- mcpServers,
821
- {
822
- target: "geminicli",
823
- configPaths: [".gemini/settings.json"],
824
- serverTransform: (server) => {
825
- const { targets: _, ...serverConfig } = server;
826
- const geminiServer = { ...serverConfig };
827
- if (server.env) {
828
- geminiServer.env = server.env;
829
- }
830
- return geminiServer;
831
- },
832
- configWrapper: configWrappers.mcpServers
833
- },
834
- baseDir
835
- );
1112
+ return generateMcpConfigurationFilesFromRegistry("geminicli", mcpServers, baseDir);
836
1113
  }
837
1114
  var init_geminicli = __esm({
838
1115
  "src/generators/mcp/geminicli.ts"() {
@@ -949,6 +1226,25 @@ var init_kiro = __esm({
949
1226
  }
950
1227
  });
951
1228
 
1229
+ // src/generators/mcp/qwencode.ts
1230
+ var qwencode_exports = {};
1231
+ __export(qwencode_exports, {
1232
+ generateQwenCodeMcp: () => generateQwenCodeMcp,
1233
+ generateQwenCodeMcpConfiguration: () => generateQwenCodeMcpConfiguration
1234
+ });
1235
+ function generateQwenCodeMcp(config) {
1236
+ return generateMcpFromRegistry("qwencode", config);
1237
+ }
1238
+ function generateQwenCodeMcpConfiguration(mcpServers, baseDir = "") {
1239
+ return generateMcpConfigurationFilesFromRegistry("qwencode", mcpServers, baseDir);
1240
+ }
1241
+ var init_qwencode = __esm({
1242
+ "src/generators/mcp/qwencode.ts"() {
1243
+ "use strict";
1244
+ init_shared_factory();
1245
+ }
1246
+ });
1247
+
952
1248
  // src/generators/mcp/roo.ts
953
1249
  var roo_exports = {};
954
1250
  __export(roo_exports, {
@@ -956,77 +1252,15 @@ __export(roo_exports, {
956
1252
  generateRooMcpConfiguration: () => generateRooMcpConfiguration
957
1253
  });
958
1254
  function generateRooMcp(config) {
959
- const rooConfig = {
960
- mcpServers: {}
961
- };
962
- for (const [serverName, server] of Object.entries(config.mcpServers)) {
963
- if (!shouldIncludeServer(server, "roo")) continue;
964
- const rooServer = {};
965
- if (server.command) {
966
- rooServer.command = server.command;
967
- if (server.args) rooServer.args = server.args;
968
- } else if (server.url || server.httpUrl) {
969
- const url = server.httpUrl || server.url;
970
- if (url) {
971
- rooServer.url = url;
972
- }
973
- if (server.httpUrl || server.transport === "http") {
974
- rooServer.type = "streamable-http";
975
- } else if (server.transport === "sse" || server.type === "sse") {
976
- rooServer.type = "sse";
977
- }
978
- }
979
- if (server.env) {
980
- rooServer.env = {};
981
- for (const [key, value] of Object.entries(server.env)) {
982
- if (value.startsWith("${env:") && value.endsWith("}")) {
983
- rooServer.env[key] = value;
984
- } else {
985
- rooServer.env[key] = `\${env:${value}}`;
986
- }
987
- }
988
- }
989
- if (server.disabled !== void 0) {
990
- rooServer.disabled = server.disabled;
991
- }
992
- if (server.alwaysAllow) {
993
- rooServer.alwaysAllow = server.alwaysAllow;
994
- }
995
- if (server.networkTimeout !== void 0) {
996
- rooServer.networkTimeout = Math.max(3e4, Math.min(3e5, server.networkTimeout));
997
- }
998
- rooConfig.mcpServers[serverName] = rooServer;
999
- }
1000
- return JSON.stringify(rooConfig, null, 2);
1255
+ return generateMcpFromRegistry("roo", config);
1001
1256
  }
1002
1257
  function generateRooMcpConfiguration(mcpServers, baseDir = "") {
1003
- const filepath = baseDir ? `${baseDir}/.roo/mcp.json` : ".roo/mcp.json";
1004
- const config = {
1005
- mcpServers: {}
1006
- };
1007
- for (const [serverName, server] of Object.entries(mcpServers)) {
1008
- if (!shouldIncludeServer(server, "roo")) {
1009
- continue;
1010
- }
1011
- const { targets: _targets, ...serverConfig } = server;
1012
- const rooServer = { ...serverConfig };
1013
- if (serverConfig.httpUrl !== void 0 && serverConfig.url !== void 0) {
1014
- rooServer.url = serverConfig.httpUrl;
1015
- }
1016
- config.mcpServers[serverName] = rooServer;
1017
- }
1018
- return [
1019
- {
1020
- filepath,
1021
- content: `${JSON.stringify(config, null, 2)}
1022
- `
1023
- }
1024
- ];
1258
+ return generateMcpConfigurationFilesFromRegistry("roo", mcpServers, baseDir);
1025
1259
  }
1026
1260
  var init_roo = __esm({
1027
1261
  "src/generators/mcp/roo.ts"() {
1028
1262
  "use strict";
1029
- init_mcp_helpers();
1263
+ init_shared_factory();
1030
1264
  }
1031
1265
  });
1032
1266
 
@@ -1049,16 +1283,27 @@ var init_windsurf = __esm({
1049
1283
  }
1050
1284
  });
1051
1285
 
1052
- // src/cli/index.ts
1053
- var import_commander = require("commander");
1054
-
1055
- // src/cli/commands/add.ts
1056
- var import_promises = require("fs/promises");
1057
- var path = __toESM(require("path"), 1);
1058
-
1059
- // src/utils/config-loader.ts
1060
- var import_c12 = require("c12");
1061
- var import_core = require("zod/v4/core");
1286
+ // src/generators/mcp/opencode.ts
1287
+ var opencode_exports = {};
1288
+ __export(opencode_exports, {
1289
+ generateOpenCodeMcp: () => generateOpenCodeMcp,
1290
+ generateOpenCodeMcpConfiguration: () => generateOpenCodeMcpConfiguration
1291
+ });
1292
+ function generateOpenCodeMcp(config) {
1293
+ return generateMcpFromRegistry("opencode", config);
1294
+ }
1295
+ function generateOpenCodeMcpConfiguration(mcpServers, baseDir = "") {
1296
+ return generateMcpConfigurationFilesFromRegistry("opencode", mcpServers, baseDir);
1297
+ }
1298
+ var init_opencode = __esm({
1299
+ "src/generators/mcp/opencode.ts"() {
1300
+ "use strict";
1301
+ init_shared_factory();
1302
+ }
1303
+ });
1304
+
1305
+ // src/cli/index.ts
1306
+ var import_commander = require("commander");
1062
1307
 
1063
1308
  // src/types/claudecode.ts
1064
1309
  var import_mini = require("zod/mini");
@@ -1103,6 +1348,7 @@ var ConfigSchema = import_mini4.z.object({
1103
1348
  var import_mini5 = require("zod/mini");
1104
1349
  init_tool_targets();
1105
1350
  var OutputPathsSchema = import_mini5.z.object({
1351
+ amazonqcli: import_mini5.z.optional(import_mini5.z.string()),
1106
1352
  augmentcode: import_mini5.z.optional(import_mini5.z.string()),
1107
1353
  "augmentcode-legacy": import_mini5.z.optional(import_mini5.z.string()),
1108
1354
  copilot: import_mini5.z.optional(import_mini5.z.string()),
@@ -1110,6 +1356,8 @@ var OutputPathsSchema = import_mini5.z.object({
1110
1356
  cline: import_mini5.z.optional(import_mini5.z.string()),
1111
1357
  claudecode: import_mini5.z.optional(import_mini5.z.string()),
1112
1358
  codexcli: import_mini5.z.optional(import_mini5.z.string()),
1359
+ opencode: import_mini5.z.optional(import_mini5.z.string()),
1360
+ qwencode: import_mini5.z.optional(import_mini5.z.string()),
1113
1361
  roo: import_mini5.z.optional(import_mini5.z.string()),
1114
1362
  geminicli: import_mini5.z.optional(import_mini5.z.string()),
1115
1363
  kiro: import_mini5.z.optional(import_mini5.z.string()),
@@ -1161,7 +1409,7 @@ var import_mini6 = require("zod/mini");
1161
1409
  init_tool_targets();
1162
1410
  var McpTransportTypeSchema = import_mini6.z.enum(["stdio", "sse", "http"]);
1163
1411
  var McpServerBaseSchema = import_mini6.z.object({
1164
- command: import_mini6.z.optional(import_mini6.z.string()),
1412
+ command: import_mini6.z.optional(import_mini6.z.union([import_mini6.z.string(), import_mini6.z.array(import_mini6.z.string())])),
1165
1413
  args: import_mini6.z.optional(import_mini6.z.array(import_mini6.z.string())),
1166
1414
  url: import_mini6.z.optional(import_mini6.z.string()),
1167
1415
  httpUrl: import_mini6.z.optional(import_mini6.z.string()),
@@ -1211,12 +1459,21 @@ var GenerateOptionsSchema = import_mini7.z.object({
1211
1459
  // src/types/index.ts
1212
1460
  init_tool_targets();
1213
1461
 
1462
+ // src/cli/commands/add.ts
1463
+ var import_promises = require("fs/promises");
1464
+ var path = __toESM(require("path"), 1);
1465
+
1466
+ // src/utils/config-loader.ts
1467
+ var import_c12 = require("c12");
1468
+ var import_core = require("zod/v4/core");
1469
+
1214
1470
  // src/utils/config.ts
1215
1471
  init_tool_targets();
1216
1472
  function getDefaultConfig() {
1217
1473
  return {
1218
1474
  aiRulesDir: ".rulesync",
1219
1475
  outputPaths: {
1476
+ amazonqcli: ".amazonq/rules",
1220
1477
  augmentcode: ".",
1221
1478
  "augmentcode-legacy": ".",
1222
1479
  copilot: ".github/instructions",
@@ -1224,6 +1481,8 @@ function getDefaultConfig() {
1224
1481
  cline: ".clinerules",
1225
1482
  claudecode: ".",
1226
1483
  codexcli: ".",
1484
+ opencode: ".",
1485
+ qwencode: ".qwen/memories",
1227
1486
  roo: ".roo/rules",
1228
1487
  geminicli: ".gemini/memories",
1229
1488
  kiro: ".kiro/steering",
@@ -1430,51 +1689,8 @@ function mergeWithCliOptions(config, cliOptions) {
1430
1689
  return merged;
1431
1690
  }
1432
1691
 
1433
- // src/utils/logger.ts
1434
- var import_consola = require("consola");
1435
- var Logger = class {
1436
- _verbose = false;
1437
- console = import_consola.consola.withDefaults({
1438
- tag: "rulesync"
1439
- });
1440
- setVerbose(verbose) {
1441
- this._verbose = verbose;
1442
- }
1443
- get verbose() {
1444
- return this._verbose;
1445
- }
1446
- // Regular log (always shown, regardless of verbose)
1447
- log(message, ...args) {
1448
- this.console.log(message, ...args);
1449
- }
1450
- // Info level (shown only in verbose mode)
1451
- info(message, ...args) {
1452
- if (this._verbose) {
1453
- this.console.info(message, ...args);
1454
- }
1455
- }
1456
- // Success (always shown)
1457
- success(message, ...args) {
1458
- this.console.success(message, ...args);
1459
- }
1460
- // Warning (always shown)
1461
- warn(message, ...args) {
1462
- this.console.warn(message, ...args);
1463
- }
1464
- // Error (always shown)
1465
- error(message, ...args) {
1466
- this.console.error(message, ...args);
1467
- }
1468
- // Debug level (shown only in verbose mode)
1469
- debug(message, ...args) {
1470
- if (this._verbose) {
1471
- this.console.debug(message, ...args);
1472
- }
1473
- }
1474
- };
1475
- var logger = new Logger();
1476
-
1477
1692
  // src/cli/commands/add.ts
1693
+ init_logger();
1478
1694
  function sanitizeFilename(filename) {
1479
1695
  return filename.endsWith(".md") ? filename.slice(0, -3) : filename;
1480
1696
  }
@@ -1518,6 +1734,7 @@ var import_node_fs = require("fs");
1518
1734
  var import_node_path2 = __toESM(require("path"), 1);
1519
1735
 
1520
1736
  // src/utils/error.ts
1737
+ init_logger();
1521
1738
  function getErrorMessage(error) {
1522
1739
  return error instanceof Error ? error.message : String(error);
1523
1740
  }
@@ -1547,90 +1764,11 @@ async function safeAsyncOperation(operation, errorContext) {
1547
1764
  }
1548
1765
  }
1549
1766
 
1550
- // src/utils/file.ts
1551
- var import_promises2 = require("fs/promises");
1552
- var import_node_path = require("path");
1553
- async function ensureDir(dirPath) {
1554
- try {
1555
- await (0, import_promises2.stat)(dirPath);
1556
- } catch {
1557
- await (0, import_promises2.mkdir)(dirPath, { recursive: true });
1558
- }
1559
- }
1560
- function resolvePath(relativePath, baseDir) {
1561
- return baseDir ? (0, import_node_path.join)(baseDir, relativePath) : relativePath;
1562
- }
1563
- async function readFileContent(filepath) {
1564
- return (0, import_promises2.readFile)(filepath, "utf-8");
1565
- }
1566
- async function writeFileContent(filepath, content) {
1567
- await ensureDir((0, import_node_path.dirname)(filepath));
1568
- await (0, import_promises2.writeFile)(filepath, content, "utf-8");
1569
- }
1570
- async function fileExists(filepath) {
1571
- try {
1572
- await (0, import_promises2.stat)(filepath);
1573
- return true;
1574
- } catch {
1575
- return false;
1576
- }
1577
- }
1578
- async function findFiles(dir, extension = ".md") {
1579
- try {
1580
- const files = await (0, import_promises2.readdir)(dir);
1581
- return files.filter((file) => file.endsWith(extension)).map((file) => (0, import_node_path.join)(dir, file));
1582
- } catch {
1583
- return [];
1584
- }
1585
- }
1586
- async function findRuleFiles(aiRulesDir) {
1587
- const rulesDir = (0, import_node_path.join)(aiRulesDir, "rules");
1588
- const newLocationFiles = await findFiles(rulesDir, ".md");
1589
- const legacyLocationFiles = await findFiles(aiRulesDir, ".md");
1590
- const newLocationBasenames = new Set(
1591
- newLocationFiles.map((file) => file.split("/").pop()?.replace(/\.md$/, ""))
1592
- );
1593
- const filteredLegacyFiles = legacyLocationFiles.filter((file) => {
1594
- const basename6 = file.split("/").pop()?.replace(/\.md$/, "");
1595
- return !newLocationBasenames.has(basename6);
1596
- });
1597
- return [...newLocationFiles, ...filteredLegacyFiles];
1598
- }
1599
- async function removeDirectory(dirPath) {
1600
- const dangerousPaths = [".", "/", "~", "src", "node_modules"];
1601
- if (dangerousPaths.includes(dirPath) || dirPath === "") {
1602
- logger.warn(`Skipping deletion of dangerous path: ${dirPath}`);
1603
- return;
1604
- }
1605
- try {
1606
- if (await fileExists(dirPath)) {
1607
- await (0, import_promises2.rm)(dirPath, { recursive: true, force: true });
1608
- }
1609
- } catch (error) {
1610
- logger.warn(`Failed to remove directory ${dirPath}:`, error);
1611
- }
1612
- }
1613
- async function removeFile(filepath) {
1614
- try {
1615
- if (await fileExists(filepath)) {
1616
- await (0, import_promises2.rm)(filepath);
1617
- }
1618
- } catch (error) {
1619
- logger.warn(`Failed to remove file ${filepath}:`, error);
1620
- }
1621
- }
1622
- async function removeClaudeGeneratedFiles() {
1623
- const filesToRemove = ["CLAUDE.md", ".claude/memories"];
1624
- for (const fileOrDir of filesToRemove) {
1625
- if (fileOrDir.endsWith("/memories")) {
1626
- await removeDirectory(fileOrDir);
1627
- } else {
1628
- await removeFile(fileOrDir);
1629
- }
1630
- }
1631
- }
1767
+ // src/utils/index.ts
1768
+ init_file();
1632
1769
 
1633
1770
  // src/cli/commands/config.ts
1771
+ init_logger();
1634
1772
  async function configCommand(options = {}) {
1635
1773
  if (options.init) {
1636
1774
  await initConfig(options);
@@ -1841,25 +1979,25 @@ export default config;
1841
1979
  }
1842
1980
 
1843
1981
  // src/cli/commands/generate.ts
1844
- var import_node_path13 = require("path");
1982
+ var import_node_path14 = require("path");
1845
1983
 
1846
1984
  // src/core/command-generator.ts
1847
1985
  var import_node_path5 = require("path");
1848
1986
 
1849
1987
  // src/utils/command-generators.ts
1850
1988
  var import_node_path3 = require("path");
1851
- function generateYamlFrontmatter(command, options = {}) {
1852
- const frontmatter = ["---"];
1853
- if (options.includeDescription !== false && command.frontmatter.description) {
1854
- frontmatter.push(`description: ${command.frontmatter.description}`);
1989
+ function generateYamlFrontmatter(command, options) {
1990
+ const frontmatterLines = ["---"];
1991
+ if (options?.includeDescription && command.frontmatter.description) {
1992
+ frontmatterLines.push(`description: ${command.frontmatter.description}`);
1855
1993
  }
1856
- if (options.additionalFields) {
1994
+ if (options?.additionalFields) {
1857
1995
  for (const field of options.additionalFields) {
1858
- frontmatter.push(`${field.key}: ${field.value}`);
1996
+ frontmatterLines.push(`${field.key}: ${field.value}`);
1859
1997
  }
1860
1998
  }
1861
- frontmatter.push("---");
1862
- return frontmatter;
1999
+ frontmatterLines.push("---");
2000
+ return frontmatterLines;
1863
2001
  }
1864
2002
  function buildCommandContent(command, frontmatterOptions) {
1865
2003
  const frontmatter = generateYamlFrontmatter(command, frontmatterOptions);
@@ -1898,26 +2036,75 @@ var syntaxConverters = {
1898
2036
  }
1899
2037
  };
1900
2038
 
1901
- // src/generators/commands/claudecode.ts
1902
- var ClaudeCodeCommandGenerator = class {
2039
+ // src/generators/commands/base.ts
2040
+ var BaseCommandGenerator = class {
2041
+ /**
2042
+ * Generate command output for the specified tool
2043
+ */
1903
2044
  generate(command, outputDir) {
1904
2045
  const filepath = this.getOutputPath(command.filename, outputDir);
1905
- const content = buildCommandContent(command);
2046
+ const content = this.processContent(command);
1906
2047
  return {
1907
- tool: "claudecode",
2048
+ tool: this.getToolName(),
1908
2049
  filepath,
1909
2050
  content
1910
2051
  };
1911
2052
  }
2053
+ /**
2054
+ * Get the output path for the command file
2055
+ * Override this method if custom path logic is needed
2056
+ */
1912
2057
  getOutputPath(filename, baseDir) {
1913
- return getFlattenedCommandPath(filename, baseDir, ".claude/commands");
2058
+ if (this.supportsHierarchy()) {
2059
+ return getHierarchicalCommandPath(
2060
+ filename,
2061
+ baseDir,
2062
+ this.getCommandsDirectory(),
2063
+ this.getFileExtension()
2064
+ );
2065
+ } else {
2066
+ return getFlattenedCommandPath(filename, baseDir, this.getCommandsDirectory());
2067
+ }
2068
+ }
2069
+ /**
2070
+ * Whether this tool supports hierarchical directory structure
2071
+ * Override to return true for tools that support nested commands
2072
+ */
2073
+ supportsHierarchy() {
2074
+ return false;
1914
2075
  }
2076
+ /**
2077
+ * Get file extension for the target tool
2078
+ * Override if tool uses different extension than .md
2079
+ */
2080
+ getFileExtension() {
2081
+ return "md";
2082
+ }
2083
+ };
2084
+
2085
+ // src/generators/commands/claudecode.ts
2086
+ var ClaudeCodeCommandGenerator = class extends BaseCommandGenerator {
2087
+ getToolName() {
2088
+ return "claudecode";
2089
+ }
2090
+ getCommandsDirectory() {
2091
+ return ".claude/commands";
2092
+ }
2093
+ processContent(command) {
2094
+ return buildCommandContent(command, { includeDescription: true });
2095
+ }
2096
+ // Uses flattened structure by default (supportsHierarchy returns false)
1915
2097
  };
1916
2098
 
1917
2099
  // src/generators/commands/geminicli.ts
1918
- var GeminiCliCommandGenerator = class {
1919
- generate(command, outputDir) {
1920
- const filepath = this.getOutputPath(command.filename, outputDir);
2100
+ var GeminiCliCommandGenerator = class extends BaseCommandGenerator {
2101
+ getToolName() {
2102
+ return "geminicli";
2103
+ }
2104
+ getCommandsDirectory() {
2105
+ return ".gemini/commands";
2106
+ }
2107
+ processContent(command) {
1921
2108
  const convertedContent = syntaxConverters.toGeminiCli(command.content);
1922
2109
  const tomlLines = [];
1923
2110
  if (command.frontmatter.description) {
@@ -1925,32 +2112,28 @@ var GeminiCliCommandGenerator = class {
1925
2112
  tomlLines.push("");
1926
2113
  }
1927
2114
  tomlLines.push(`prompt = """${convertedContent}"""`);
1928
- const content = tomlLines.join("\n") + "\n";
1929
- return {
1930
- tool: "geminicli",
1931
- filepath,
1932
- content
1933
- };
2115
+ return tomlLines.join("\n") + "\n";
1934
2116
  }
1935
- getOutputPath(filename, baseDir) {
1936
- return getHierarchicalCommandPath(filename, baseDir, ".gemini/commands", "toml");
2117
+ supportsHierarchy() {
2118
+ return true;
2119
+ }
2120
+ getFileExtension() {
2121
+ return "toml";
1937
2122
  }
1938
2123
  };
1939
2124
 
1940
2125
  // src/generators/commands/roo.ts
1941
- var RooCommandGenerator = class {
1942
- generate(command, outputDir) {
1943
- const filepath = this.getOutputPath(command.filename, outputDir);
1944
- const content = buildCommandContent(command);
1945
- return {
1946
- tool: "roo",
1947
- filepath,
1948
- content
1949
- };
2126
+ var RooCommandGenerator = class extends BaseCommandGenerator {
2127
+ getToolName() {
2128
+ return "roo";
1950
2129
  }
1951
- getOutputPath(filename, baseDir) {
1952
- return getFlattenedCommandPath(filename, baseDir, ".roo/commands");
2130
+ getCommandsDirectory() {
2131
+ return ".roo/commands";
2132
+ }
2133
+ processContent(command) {
2134
+ return buildCommandContent(command, { includeDescription: true });
1953
2135
  }
2136
+ // Uses flattened structure by default (supportsHierarchy returns false)
1954
2137
  };
1955
2138
 
1956
2139
  // src/generators/commands/index.ts
@@ -1963,6 +2146,10 @@ function getCommandGenerator(tool) {
1963
2146
  return commandGenerators[tool];
1964
2147
  }
1965
2148
 
2149
+ // src/core/command-generator.ts
2150
+ init_file();
2151
+ init_logger();
2152
+
1966
2153
  // src/core/command-parser.ts
1967
2154
  var import_node_path4 = require("path");
1968
2155
 
@@ -1985,6 +2172,7 @@ function extractStringField(data, key, defaultValue) {
1985
2172
  }
1986
2173
 
1987
2174
  // src/core/command-parser.ts
2175
+ init_logger();
1988
2176
  async function parseCommandsFromDirectory(commandsDir) {
1989
2177
  const commandFiles = await findFiles(commandsDir, ".md");
1990
2178
  const commands = [];
@@ -2766,26 +2954,87 @@ async function generateKiroIgnoreFiles(rules, config, baseDir) {
2766
2954
  return generateIgnoreFile(rules, config, ignoreConfigs.kiro, baseDir);
2767
2955
  }
2768
2956
 
2957
+ // src/generators/ignore/qwencode.ts
2958
+ var import_node_path7 = require("path");
2959
+ function extractQwenCodeFileFilteringPatterns(content) {
2960
+ const filtering = {};
2961
+ const configBlocks = content.match(/```(?:json|javascript)\s*\n([\s\S]*?)\n```/g);
2962
+ if (configBlocks) {
2963
+ for (const block of configBlocks) {
2964
+ try {
2965
+ const jsonContent = block.replace(/```(?:json|javascript)\s*\n/, "").replace(/\n```$/, "");
2966
+ const parsed = JSON.parse(jsonContent);
2967
+ if (parsed.fileFiltering) {
2968
+ Object.assign(filtering, parsed.fileFiltering);
2969
+ }
2970
+ } catch {
2971
+ }
2972
+ }
2973
+ }
2974
+ if (content.includes("respectGitIgnore")) {
2975
+ if (content.includes("respectGitIgnore: false") || content.includes('"respectGitIgnore": false')) {
2976
+ filtering.respectGitIgnore = false;
2977
+ } else {
2978
+ filtering.respectGitIgnore = true;
2979
+ }
2980
+ }
2981
+ if (content.includes("enableRecursiveFileSearch")) {
2982
+ if (content.includes("enableRecursiveFileSearch: false") || content.includes('"enableRecursiveFileSearch": false')) {
2983
+ filtering.enableRecursiveFileSearch = false;
2984
+ } else {
2985
+ filtering.enableRecursiveFileSearch = true;
2986
+ }
2987
+ }
2988
+ return Object.keys(filtering).length > 0 ? filtering : void 0;
2989
+ }
2990
+ function generateQwenCodeConfiguration(rules) {
2991
+ const config = {};
2992
+ config.fileFiltering = {
2993
+ respectGitIgnore: true,
2994
+ enableRecursiveFileSearch: true
2995
+ };
2996
+ for (const rule of rules) {
2997
+ const ruleFiltering = extractQwenCodeFileFilteringPatterns(rule.content);
2998
+ if (ruleFiltering) {
2999
+ Object.assign(config.fileFiltering, ruleFiltering);
3000
+ }
3001
+ }
3002
+ return config;
3003
+ }
3004
+ async function generateQwenCodeIgnoreFiles(rules, config, baseDir) {
3005
+ const outputs = [];
3006
+ const outputPath = baseDir || process.cwd();
3007
+ const qwenConfig = generateQwenCodeConfiguration(rules);
3008
+ const settingsPath = (0, import_node_path7.join)(outputPath, ".qwen", "settings.json");
3009
+ outputs.push({
3010
+ tool: "qwencode",
3011
+ filepath: settingsPath,
3012
+ content: `${JSON.stringify(qwenConfig, null, 2)}
3013
+ `
3014
+ });
3015
+ return outputs;
3016
+ }
3017
+
2769
3018
  // src/generators/ignore/windsurf.ts
2770
3019
  function generateWindsurfIgnore(rules, config, baseDir) {
2771
3020
  return generateIgnoreFile(rules, config, ignoreConfigs.windsurf, baseDir);
2772
3021
  }
2773
3022
 
2774
- // src/generators/rules/augmentcode.ts
2775
- var import_node_path9 = require("path");
2776
-
2777
3023
  // src/generators/rules/shared-helpers.ts
2778
- var import_node_path8 = require("path");
3024
+ var import_node_path9 = require("path");
3025
+ init_file();
2779
3026
 
2780
3027
  // src/utils/ignore.ts
2781
- var import_node_path7 = require("path");
3028
+ var import_node_path8 = require("path");
2782
3029
  var import_micromatch = __toESM(require("micromatch"), 1);
3030
+ init_file();
3031
+ init_logger();
2783
3032
  var cachedIgnorePatterns = null;
2784
3033
  async function loadIgnorePatterns(baseDir = process.cwd()) {
2785
3034
  if (cachedIgnorePatterns) {
2786
3035
  return cachedIgnorePatterns;
2787
3036
  }
2788
- const ignorePath = (0, import_node_path7.join)(baseDir, ".rulesyncignore");
3037
+ const ignorePath = (0, import_node_path8.join)(baseDir, ".rulesyncignore");
2789
3038
  if (!await fileExists(ignorePath)) {
2790
3039
  cachedIgnorePatterns = { patterns: [] };
2791
3040
  return cachedIgnorePatterns;
@@ -2839,7 +3088,7 @@ function addOutput(outputs, tool, config, baseDir, relativePath, content) {
2839
3088
  const outputDir = resolveOutputDir(config, tool, baseDir);
2840
3089
  outputs.push({
2841
3090
  tool,
2842
- filepath: (0, import_node_path8.join)(outputDir, relativePath),
3091
+ filepath: (0, import_node_path9.join)(outputDir, relativePath),
2843
3092
  content
2844
3093
  });
2845
3094
  }
@@ -2848,7 +3097,7 @@ async function generateRulesConfig(rules, config, generatorConfig, baseDir) {
2848
3097
  for (const rule of rules) {
2849
3098
  const content = generatorConfig.generateContent(rule);
2850
3099
  const outputDir = resolveOutputDir(config, generatorConfig.tool, baseDir);
2851
- const filepath = generatorConfig.pathResolver ? generatorConfig.pathResolver(rule, outputDir) : (0, import_node_path8.join)(outputDir, `${rule.filename}${generatorConfig.fileExtension}`);
3100
+ const filepath = generatorConfig.pathResolver ? generatorConfig.pathResolver(rule, outputDir) : (0, import_node_path9.join)(outputDir, `${rule.filename}${generatorConfig.fileExtension}`);
2852
3101
  outputs.push({
2853
3102
  tool: generatorConfig.tool,
2854
3103
  filepath,
@@ -2876,7 +3125,7 @@ async function generateComplexRules(rules, config, generatorConfig, baseDir) {
2876
3125
  for (const rule of detailRules) {
2877
3126
  const content = generatorConfig.generateDetailContent(rule);
2878
3127
  const filepath = resolvePath(
2879
- (0, import_node_path8.join)(generatorConfig.detailSubDir, `${rule.filename}.md`),
3128
+ (0, import_node_path9.join)(generatorConfig.detailSubDir, `${rule.filename}.md`),
2880
3129
  baseDir
2881
3130
  );
2882
3131
  outputs.push({
@@ -2930,7 +3179,61 @@ function generateIgnoreFile2(patterns, tool) {
2930
3179
  return lines.join("\n");
2931
3180
  }
2932
3181
 
3182
+ // src/generators/rules/amazonqcli.ts
3183
+ async function generateAmazonqcliConfig(rules, config, baseDir) {
3184
+ const generatorConfig = {
3185
+ tool: "amazonqcli",
3186
+ fileExtension: ".md",
3187
+ generateContent: generateRuleFile,
3188
+ generateRootContent: generateMainRulesFile,
3189
+ rootFilePath: ".amazonq/rules/main.md",
3190
+ generateDetailContent: generateRuleFile,
3191
+ detailSubDir: ".amazonq/rules"
3192
+ };
3193
+ return generateComplexRules(rules, config, generatorConfig, baseDir);
3194
+ }
3195
+ function generateMainRulesFile(rootRule, detailRules) {
3196
+ const lines = [];
3197
+ if (detailRules.length > 0) {
3198
+ lines.push("# Amazon Q Developer CLI Project Rules");
3199
+ lines.push("");
3200
+ lines.push("This file contains the main project rules. See also:");
3201
+ lines.push("");
3202
+ for (const rule of detailRules) {
3203
+ lines.push(`- ${rule.filename}.md: ${rule.frontmatter.description}`);
3204
+ }
3205
+ lines.push("");
3206
+ }
3207
+ if (rootRule) {
3208
+ if (detailRules.length > 0) {
3209
+ lines.push("## Overview");
3210
+ lines.push("");
3211
+ }
3212
+ lines.push(rootRule.content);
3213
+ lines.push("");
3214
+ } else if (detailRules.length === 0) {
3215
+ lines.push("# Amazon Q Developer CLI Project Rules");
3216
+ lines.push("");
3217
+ lines.push("This file contains project-specific rules and context for Amazon Q Developer CLI.");
3218
+ lines.push("");
3219
+ lines.push("## Development Standards");
3220
+ lines.push("");
3221
+ lines.push("Add your project-specific development standards here.");
3222
+ lines.push("");
3223
+ }
3224
+ return lines.join("\n").trim() + "\n";
3225
+ }
3226
+ function generateRuleFile(rule) {
3227
+ const lines = [];
3228
+ lines.push(`# ${rule.frontmatter.description || rule.filename}`);
3229
+ lines.push("");
3230
+ lines.push(rule.content.trim());
3231
+ lines.push("");
3232
+ return lines.join("\n");
3233
+ }
3234
+
2933
3235
  // src/generators/rules/augmentcode.ts
3236
+ var import_node_path10 = require("path");
2934
3237
  async function generateAugmentcodeConfig(rules, config, baseDir) {
2935
3238
  const outputs = createOutputsArray();
2936
3239
  rules.forEach((rule) => {
@@ -2939,13 +3242,13 @@ async function generateAugmentcodeConfig(rules, config, baseDir) {
2939
3242
  "augmentcode",
2940
3243
  config,
2941
3244
  baseDir,
2942
- (0, import_node_path9.join)(".augment", "rules", `${rule.filename}.md`),
2943
- generateRuleFile(rule)
3245
+ (0, import_node_path10.join)(".augment", "rules", `${rule.filename}.md`),
3246
+ generateRuleFile2(rule)
2944
3247
  );
2945
3248
  });
2946
3249
  return outputs;
2947
3250
  }
2948
- function generateRuleFile(rule) {
3251
+ function generateRuleFile2(rule) {
2949
3252
  const lines = [];
2950
3253
  lines.push("---");
2951
3254
  let ruleType = "manual";
@@ -2992,7 +3295,9 @@ function generateLegacyGuidelinesFile(allRules) {
2992
3295
  }
2993
3296
 
2994
3297
  // src/generators/rules/claudecode.ts
2995
- var import_node_path10 = require("path");
3298
+ var import_node_path11 = require("path");
3299
+ init_file();
3300
+ init_logger();
2996
3301
  async function generateClaudecodeConfig(rules, config, baseDir) {
2997
3302
  const generatorConfig = {
2998
3303
  tool: "claudecode",
@@ -3004,7 +3309,7 @@ async function generateClaudecodeConfig(rules, config, baseDir) {
3004
3309
  generateDetailContent: generateMemoryFile,
3005
3310
  detailSubDir: ".claude/memories",
3006
3311
  updateAdditionalConfig: async (ignorePatterns, baseDir2) => {
3007
- const settingsPath = resolvePath((0, import_node_path10.join)(".claude", "settings.json"), baseDir2);
3312
+ const settingsPath = resolvePath((0, import_node_path11.join)(".claude", "settings.json"), baseDir2);
3008
3313
  await updateClaudeSettings(settingsPath, ignorePatterns);
3009
3314
  return [];
3010
3315
  }
@@ -3068,7 +3373,7 @@ async function updateClaudeSettings(settingsPath, ignorePatterns) {
3068
3373
  }
3069
3374
 
3070
3375
  // src/generators/rules/generator-registry.ts
3071
- var import_node_path11 = require("path");
3376
+ var import_node_path12 = require("path");
3072
3377
  function determineCursorRuleType(frontmatter) {
3073
3378
  if (frontmatter.cursorRuleType) {
3074
3379
  return frontmatter.cursorRuleType;
@@ -3092,6 +3397,22 @@ function determineCursorRuleType(frontmatter) {
3092
3397
  }
3093
3398
  var GENERATOR_REGISTRY = {
3094
3399
  // Simple generators - generate one file per rule
3400
+ amazonqcli: {
3401
+ type: "complex",
3402
+ tool: "amazonqcli",
3403
+ fileExtension: ".md",
3404
+ // ignoreFileName omitted - Amazon Q CLI doesn't have native ignore file support yet
3405
+ generateContent: (rule) => {
3406
+ const lines = [];
3407
+ if (rule.frontmatter.description) {
3408
+ lines.push(`# ${rule.frontmatter.description}
3409
+ `);
3410
+ }
3411
+ lines.push(rule.content.trim());
3412
+ return lines.join("\n");
3413
+ }
3414
+ // Complex generation handled by existing generator
3415
+ },
3095
3416
  cline: {
3096
3417
  type: "simple",
3097
3418
  tool: "cline",
@@ -3148,7 +3469,7 @@ var GENERATOR_REGISTRY = {
3148
3469
  },
3149
3470
  pathResolver: (rule, outputDir) => {
3150
3471
  const baseFilename = rule.filename.replace(/\.md$/, "");
3151
- return (0, import_node_path11.join)(outputDir, `${baseFilename}.instructions.md`);
3472
+ return (0, import_node_path12.join)(outputDir, `${baseFilename}.instructions.md`);
3152
3473
  }
3153
3474
  },
3154
3475
  cursor: {
@@ -3188,7 +3509,7 @@ var GENERATOR_REGISTRY = {
3188
3509
  return lines.join("\n");
3189
3510
  },
3190
3511
  pathResolver: (rule, outputDir) => {
3191
- return (0, import_node_path11.join)(outputDir, `${rule.filename}.mdc`);
3512
+ return (0, import_node_path12.join)(outputDir, `${rule.filename}.mdc`);
3192
3513
  }
3193
3514
  },
3194
3515
  codexcli: {
@@ -3224,10 +3545,10 @@ var GENERATOR_REGISTRY = {
3224
3545
  pathResolver: (rule, outputDir) => {
3225
3546
  const outputFormat = rule.frontmatter.windsurfOutputFormat || "directory";
3226
3547
  if (outputFormat === "single-file") {
3227
- return (0, import_node_path11.join)(outputDir, ".windsurf-rules");
3548
+ return (0, import_node_path12.join)(outputDir, ".windsurf-rules");
3228
3549
  } else {
3229
- const rulesDir = (0, import_node_path11.join)(outputDir, ".windsurf", "rules");
3230
- return (0, import_node_path11.join)(rulesDir, `${rule.filename}.md`);
3550
+ const rulesDir = (0, import_node_path12.join)(outputDir, ".windsurf", "rules");
3551
+ return (0, import_node_path12.join)(rulesDir, `${rule.filename}.md`);
3231
3552
  }
3232
3553
  }
3233
3554
  },
@@ -3258,6 +3579,22 @@ var GENERATOR_REGISTRY = {
3258
3579
  const lines = [];
3259
3580
  if (rule.frontmatter.description) {
3260
3581
  lines.push(`# ${rule.frontmatter.description}
3582
+ `);
3583
+ }
3584
+ lines.push(rule.content.trim());
3585
+ return lines.join("\n");
3586
+ }
3587
+ // Complex generation handled by existing generator
3588
+ },
3589
+ opencode: {
3590
+ type: "complex",
3591
+ tool: "opencode",
3592
+ fileExtension: ".md",
3593
+ // ignoreFileName omitted - OpenCode doesn't use dedicated ignore files
3594
+ generateContent: (rule) => {
3595
+ const lines = [];
3596
+ if (rule.frontmatter.description) {
3597
+ lines.push(`# ${rule.frontmatter.description}
3261
3598
  `);
3262
3599
  }
3263
3600
  lines.push(rule.content.trim());
@@ -3280,7 +3617,23 @@ var GENERATOR_REGISTRY = {
3280
3617
  return lines.join("\n");
3281
3618
  }
3282
3619
  // Complex generation handled by existing generator
3283
- }
3620
+ },
3621
+ qwencode: {
3622
+ type: "complex",
3623
+ tool: "qwencode",
3624
+ fileExtension: ".md",
3625
+ // ignoreFileName omitted - Qwen Code uses git-aware filtering instead of dedicated ignore files
3626
+ generateContent: (rule) => {
3627
+ const lines = [];
3628
+ if (rule.frontmatter.description) {
3629
+ lines.push(`# ${rule.frontmatter.description}
3630
+ `);
3631
+ }
3632
+ lines.push(rule.content.trim());
3633
+ return lines.join("\n");
3634
+ }
3635
+ // Complex generation handled by existing generator
3636
+ }
3284
3637
  };
3285
3638
  async function generateFromRegistry(tool, rules, config, baseDir) {
3286
3639
  const generatorConfig = GENERATOR_REGISTRY[tool];
@@ -3300,8 +3653,8 @@ async function generateFromRegistry(tool, rules, config, baseDir) {
3300
3653
  const enhancedConfig = {
3301
3654
  tool: generatorConfig.tool,
3302
3655
  fileExtension: generatorConfig.fileExtension,
3303
- ignoreFileName: generatorConfig.ignoreFileName,
3304
3656
  generateContent: generatorConfig.generateContent,
3657
+ ...generatorConfig.ignoreFileName && { ignoreFileName: generatorConfig.ignoreFileName },
3305
3658
  ...generatorConfig.generateRootContent && {
3306
3659
  generateRootContent: generatorConfig.generateRootContent
3307
3660
  },
@@ -3330,50 +3683,94 @@ var generateCopilotConfig = createSimpleGenerator("copilot");
3330
3683
  var generateWindsurfConfig = createSimpleGenerator("windsurf");
3331
3684
  var generateKiroConfig = createSimpleGenerator("kiro");
3332
3685
  var generateRooConfig = createSimpleGenerator("roo");
3686
+ var generateQwencodeConfig = createSimpleGenerator("qwencode");
3333
3687
 
3334
3688
  // src/generators/rules/codexcli.ts
3335
- async function generateCodexConfig(rules, config, baseDir) {
3336
- const outputs = [];
3337
- if (rules.length === 0) {
3338
- return outputs;
3339
- }
3340
- const sortedRules = [...rules].sort((a, b) => {
3341
- if (a.frontmatter.root === true && b.frontmatter.root !== true) return -1;
3342
- if (a.frontmatter.root !== true && b.frontmatter.root === true) return 1;
3343
- return 0;
3344
- });
3345
- const concatenatedContent = generateConcatenatedCodexContent(sortedRules);
3346
- if (concatenatedContent.trim()) {
3347
- const outputDir = resolveOutputDir(config, "codexcli", baseDir);
3348
- const filepath = `${outputDir}/AGENTS.md`;
3349
- outputs.push({
3350
- tool: "codexcli",
3351
- filepath,
3352
- content: concatenatedContent
3689
+ init_file();
3690
+
3691
+ // src/utils/xml-document-generator.ts
3692
+ var import_fast_xml_parser = require("fast-xml-parser");
3693
+ function generateRootMarkdownWithXmlDocs(rootRule, memoryRules, config) {
3694
+ const lines = [];
3695
+ if (memoryRules.length > 0) {
3696
+ lines.push(
3697
+ "Please also reference the following documents as needed. In this case, `@` stands for the project root directory."
3698
+ );
3699
+ lines.push("");
3700
+ const documentsData = {
3701
+ Documents: {
3702
+ Document: memoryRules.map((rule) => {
3703
+ const relativePath = `@${config.memorySubDir}/${rule.filename}.md`;
3704
+ const document = {
3705
+ Path: relativePath,
3706
+ Description: rule.frontmatter.description
3707
+ };
3708
+ if (rule.frontmatter.globs.length > 0) {
3709
+ document.FilePatterns = rule.frontmatter.globs.join(", ");
3710
+ }
3711
+ return document;
3712
+ })
3713
+ }
3714
+ };
3715
+ const builder = new import_fast_xml_parser.XMLBuilder({
3716
+ format: true,
3717
+ ignoreAttributes: false,
3718
+ suppressEmptyNode: false
3353
3719
  });
3720
+ const xmlContent = builder.build(documentsData);
3721
+ lines.push(xmlContent);
3722
+ lines.push("");
3723
+ lines.push("");
3354
3724
  }
3355
- const ignorePatterns = await loadIgnorePatterns(baseDir);
3356
- if (ignorePatterns.patterns.length > 0) {
3357
- const ignorePath = resolvePath(".codexignore", baseDir);
3358
- const ignoreContent = generateIgnoreFile2(ignorePatterns.patterns, "codexcli");
3359
- outputs.push({
3360
- tool: "codexcli",
3361
- filepath: ignorePath,
3362
- content: ignoreContent
3363
- });
3725
+ if (rootRule) {
3726
+ lines.push(rootRule.content.trim());
3727
+ } else if (memoryRules.length === 0) {
3728
+ lines.push(`# ${config.fallbackTitle}`);
3729
+ lines.push("");
3730
+ lines.push("No configuration rules have been defined yet.");
3364
3731
  }
3365
- return outputs;
3732
+ return lines.join("\n");
3366
3733
  }
3367
- function generateConcatenatedCodexContent(rules) {
3368
- const sections = [];
3369
- for (const rule of rules) {
3370
- const content = rule.content.trim();
3371
- if (!content) {
3372
- continue;
3734
+
3735
+ // src/generators/rules/codexcli.ts
3736
+ async function generateCodexConfig(rules, config, baseDir) {
3737
+ const outputs = [];
3738
+ const nonEmptyRules = rules.filter((rule) => rule.content.trim().length > 0);
3739
+ if (nonEmptyRules.length > 0) {
3740
+ const generatorConfig = {
3741
+ tool: "codexcli",
3742
+ fileExtension: ".md",
3743
+ ignoreFileName: ".codexignore",
3744
+ generateContent: generateCodexMemoryMarkdown,
3745
+ generateDetailContent: generateCodexMemoryMarkdown,
3746
+ generateRootContent: generateCodexRootMarkdown,
3747
+ rootFilePath: "AGENTS.md",
3748
+ detailSubDir: ".codex/memories"
3749
+ };
3750
+ const ruleOutputs = await generateComplexRules(nonEmptyRules, config, generatorConfig, baseDir);
3751
+ outputs.push(...ruleOutputs);
3752
+ } else {
3753
+ const ignorePatterns = await loadIgnorePatterns(baseDir);
3754
+ if (ignorePatterns.patterns.length > 0) {
3755
+ const ignorePath = resolvePath(".codexignore", baseDir);
3756
+ const ignoreContent = generateIgnoreFile2(ignorePatterns.patterns, "codexcli");
3757
+ outputs.push({
3758
+ tool: "codexcli",
3759
+ filepath: ignorePath,
3760
+ content: ignoreContent
3761
+ });
3373
3762
  }
3374
- sections.push(content);
3375
3763
  }
3376
- return sections.join("\n\n---\n\n");
3764
+ return outputs;
3765
+ }
3766
+ function generateCodexMemoryMarkdown(rule) {
3767
+ return rule.content.trim();
3768
+ }
3769
+ function generateCodexRootMarkdown(rootRule, memoryRules, _baseDir) {
3770
+ return generateRootMarkdownWithXmlDocs(rootRule, memoryRules, {
3771
+ memorySubDir: ".codex/memories",
3772
+ fallbackTitle: "OpenAI Codex CLI Configuration"
3773
+ });
3377
3774
  }
3378
3775
 
3379
3776
  // src/generators/rules/geminicli.ts
@@ -3394,28 +3791,10 @@ function generateGeminiMemoryMarkdown(rule) {
3394
3791
  return rule.content.trim();
3395
3792
  }
3396
3793
  function generateGeminiRootMarkdown(rootRule, memoryRules, _baseDir) {
3397
- const lines = [];
3398
- if (memoryRules.length > 0) {
3399
- lines.push("Please also reference the following documents as needed:");
3400
- lines.push("");
3401
- lines.push("| Document | Description | File Patterns |");
3402
- lines.push("|----------|-------------|---------------|");
3403
- for (const rule of memoryRules) {
3404
- const relativePath = `@.gemini/memories/${rule.filename}.md`;
3405
- const filePatterns = rule.frontmatter.globs.length > 0 ? rule.frontmatter.globs.join(", ") : "-";
3406
- lines.push(`| ${relativePath} | ${rule.frontmatter.description} | ${filePatterns} |`);
3407
- }
3408
- lines.push("");
3409
- lines.push("");
3410
- }
3411
- if (rootRule) {
3412
- lines.push(rootRule.content.trim());
3413
- } else if (memoryRules.length === 0) {
3414
- lines.push("# Gemini CLI Configuration");
3415
- lines.push("");
3416
- lines.push("No configuration rules have been defined yet.");
3417
- }
3418
- return lines.join("\n");
3794
+ return generateRootMarkdownWithXmlDocs(rootRule, memoryRules, {
3795
+ memorySubDir: ".gemini/memories",
3796
+ fallbackTitle: "Gemini CLI Configuration"
3797
+ });
3419
3798
  }
3420
3799
 
3421
3800
  // src/generators/rules/junie.ts
@@ -3445,7 +3824,56 @@ function generateGuidelinesMarkdown(rootRule, detailRules) {
3445
3824
  return lines.join("\n").trim();
3446
3825
  }
3447
3826
 
3827
+ // src/generators/rules/opencode.ts
3828
+ async function generateOpenCodeConfig(rules, config, baseDir) {
3829
+ const generatorConfig = {
3830
+ tool: "opencode",
3831
+ fileExtension: ".md",
3832
+ // ignoreFileName omitted - OpenCode doesn't use dedicated ignore files
3833
+ generateContent: generateOpenCodeMarkdown,
3834
+ generateDetailContent: generateOpenCodeMarkdown,
3835
+ generateRootContent: generateOpenCodeRootMarkdown,
3836
+ rootFilePath: "AGENTS.md",
3837
+ detailSubDir: ".opencode/memories"
3838
+ };
3839
+ return generateComplexRules(rules, config, generatorConfig, baseDir);
3840
+ }
3841
+ function generateOpenCodeMarkdown(rule) {
3842
+ return rule.content.trim();
3843
+ }
3844
+ function generateOpenCodeRootMarkdown(rootRule, memoryRules, _baseDir) {
3845
+ return generateRootMarkdownWithXmlDocs(rootRule, memoryRules, {
3846
+ memorySubDir: ".opencode/memories",
3847
+ fallbackTitle: "OpenCode Configuration"
3848
+ });
3849
+ }
3850
+
3851
+ // src/generators/rules/qwencode.ts
3852
+ async function generateQwencodeConfig2(rules, config, baseDir) {
3853
+ const generatorConfig = {
3854
+ tool: "qwencode",
3855
+ fileExtension: ".md",
3856
+ // ignoreFileName omitted - Qwen Code uses git-aware filtering instead of dedicated ignore files
3857
+ generateContent: generateQwenMemoryMarkdown,
3858
+ generateDetailContent: generateQwenMemoryMarkdown,
3859
+ generateRootContent: generateQwenRootMarkdown,
3860
+ rootFilePath: "QWEN.md",
3861
+ detailSubDir: ".qwen/memories"
3862
+ };
3863
+ return generateComplexRules(rules, config, generatorConfig, baseDir);
3864
+ }
3865
+ function generateQwenMemoryMarkdown(rule) {
3866
+ return rule.content.trim();
3867
+ }
3868
+ function generateQwenRootMarkdown(rootRule, memoryRules, _baseDir) {
3869
+ return generateRootMarkdownWithXmlDocs(rootRule, memoryRules, {
3870
+ memorySubDir: ".qwen/memories",
3871
+ fallbackTitle: "Qwen Code Configuration"
3872
+ });
3873
+ }
3874
+
3448
3875
  // src/core/generator.ts
3876
+ init_logger();
3449
3877
  async function generateConfigurations(rules, config, targetTools, baseDir) {
3450
3878
  const outputs = createOutputsArray();
3451
3879
  const toolsToGenerate = targetTools || config.defaultTargets;
@@ -3477,6 +3905,8 @@ function filterRulesForTool(rules, tool, config) {
3477
3905
  }
3478
3906
  async function generateForTool(tool, rules, config, baseDir) {
3479
3907
  switch (tool) {
3908
+ case "amazonqcli":
3909
+ return await generateAmazonqcliConfig(rules, config, baseDir);
3480
3910
  case "augmentcode": {
3481
3911
  const augmentRulesOutputs = await generateAugmentcodeConfig(rules, config, baseDir);
3482
3912
  const augmentIgnoreOutputs = await generateAugmentCodeIgnoreFiles(rules, config, baseDir);
@@ -3515,6 +3945,13 @@ async function generateForTool(tool, rules, config, baseDir) {
3515
3945
  const kiroIgnoreOutputs = await generateKiroIgnoreFiles(rules, config, baseDir);
3516
3946
  return [...kiroRulesOutputs, ...kiroIgnoreOutputs];
3517
3947
  }
3948
+ case "opencode":
3949
+ return generateOpenCodeConfig(rules, config, baseDir);
3950
+ case "qwencode": {
3951
+ const qwenRulesOutputs = await generateQwencodeConfig2(rules, config, baseDir);
3952
+ const qwenIgnoreOutputs = await generateQwenCodeIgnoreFiles(rules, config, baseDir);
3953
+ return [...qwenRulesOutputs, ...qwenIgnoreOutputs];
3954
+ }
3518
3955
  case "windsurf": {
3519
3956
  const windsurfRulesOutputs = await generateWindsurfConfig(rules, config, baseDir);
3520
3957
  const windsurfIgnoreOutputs = await generateWindsurfIgnore(rules, config, baseDir);
@@ -3527,7 +3964,8 @@ async function generateForTool(tool, rules, config, baseDir) {
3527
3964
  }
3528
3965
 
3529
3966
  // src/core/parser.ts
3530
- var import_node_path12 = require("path");
3967
+ var import_node_path13 = require("path");
3968
+ init_logger();
3531
3969
  async function parseRulesFromDirectory(aiRulesDir) {
3532
3970
  const ignorePatterns = await loadIgnorePatterns();
3533
3971
  const allRuleFiles = await findRuleFiles(aiRulesDir);
@@ -3580,7 +4018,7 @@ async function parseRuleFile(filepath) {
3580
4018
  },
3581
4019
  ...validatedData.tags !== void 0 && { tags: validatedData.tags }
3582
4020
  };
3583
- const filename = (0, import_node_path12.basename)(filepath, ".md");
4021
+ const filename = (0, import_node_path13.basename)(filepath, ".md");
3584
4022
  return {
3585
4023
  frontmatter,
3586
4024
  content: parsed.content,
@@ -3648,6 +4086,7 @@ async function validateRule(rule) {
3648
4086
  var path4 = __toESM(require("path"), 1);
3649
4087
 
3650
4088
  // src/generators/mcp/index.ts
4089
+ init_amazonqcli();
3651
4090
  init_augmentcode();
3652
4091
  init_claudecode();
3653
4092
  init_cline();
@@ -3657,9 +4096,13 @@ init_cursor();
3657
4096
  init_geminicli();
3658
4097
  init_junie();
3659
4098
  init_kiro();
4099
+ init_qwencode();
3660
4100
  init_roo();
3661
4101
  init_windsurf();
3662
4102
 
4103
+ // src/core/mcp-generator.ts
4104
+ init_file();
4105
+
3663
4106
  // src/core/mcp-parser.ts
3664
4107
  var fs = __toESM(require("fs"), 1);
3665
4108
  var path3 = __toESM(require("path"), 1);
@@ -3691,6 +4134,36 @@ function parseMcpConfig(projectRoot) {
3691
4134
  async function generateMcpConfigurations(mcpConfig, baseDir, targetTools) {
3692
4135
  const outputs = [];
3693
4136
  const toolMap = {
4137
+ amazonqcli: async (servers, dir) => {
4138
+ const config = {
4139
+ aiRulesDir: ".rulesync",
4140
+ outputPaths: {
4141
+ amazonqcli: ".amazonq/rules",
4142
+ augmentcode: ".",
4143
+ "augmentcode-legacy": ".",
4144
+ copilot: ".github/instructions",
4145
+ cursor: ".cursor/rules",
4146
+ cline: ".clinerules",
4147
+ claudecode: ".",
4148
+ codexcli: ".",
4149
+ opencode: ".",
4150
+ qwencode: ".qwen/memories",
4151
+ roo: ".roo/rules",
4152
+ geminicli: ".gemini/memories",
4153
+ kiro: ".kiro/steering",
4154
+ junie: ".",
4155
+ windsurf: "."
4156
+ },
4157
+ watchEnabled: false,
4158
+ defaultTargets: []
4159
+ };
4160
+ const results = await (await Promise.resolve().then(() => (init_amazonqcli(), amazonqcli_exports))).generateAmazonqcliMcp(
4161
+ servers,
4162
+ config,
4163
+ dir
4164
+ );
4165
+ return results.map((result) => ({ filepath: result.filepath, content: result.content }));
4166
+ },
3694
4167
  augmentcode: async (servers, dir) => (await Promise.resolve().then(() => (init_augmentcode(), augmentcode_exports))).generateAugmentcodeMcpConfiguration(
3695
4168
  servers,
3696
4169
  dir
@@ -3707,6 +4180,10 @@ async function generateMcpConfigurations(mcpConfig, baseDir, targetTools) {
3707
4180
  cursor: async (servers, dir) => (await Promise.resolve().then(() => (init_cursor(), cursor_exports))).generateCursorMcpConfiguration(servers, dir),
3708
4181
  cline: async (servers, dir) => (await Promise.resolve().then(() => (init_cline(), cline_exports))).generateClineMcpConfiguration(servers, dir),
3709
4182
  codexcli: async (servers, dir) => (await Promise.resolve().then(() => (init_codexcli(), codexcli_exports))).generateCodexMcpConfiguration(servers, dir),
4183
+ opencode: async (servers, dir) => (await Promise.resolve().then(() => (init_opencode(), opencode_exports))).generateOpenCodeMcpConfiguration(
4184
+ servers,
4185
+ dir
4186
+ ),
3710
4187
  roo: async (servers, dir) => (await Promise.resolve().then(() => (init_roo(), roo_exports))).generateRooMcpConfiguration(servers, dir),
3711
4188
  geminicli: async (servers, dir) => (await Promise.resolve().then(() => (init_geminicli(), geminicli_exports))).generateGeminiCliMcpConfiguration(
3712
4189
  servers,
@@ -3714,6 +4191,10 @@ async function generateMcpConfigurations(mcpConfig, baseDir, targetTools) {
3714
4191
  ),
3715
4192
  kiro: async (servers, dir) => (await Promise.resolve().then(() => (init_kiro(), kiro_exports))).generateKiroMcpConfiguration(servers, dir),
3716
4193
  junie: async (servers, dir) => (await Promise.resolve().then(() => (init_junie(), junie_exports))).generateJunieMcpConfiguration(servers, dir),
4194
+ qwencode: async (servers, dir) => (await Promise.resolve().then(() => (init_qwencode(), qwencode_exports))).generateQwenCodeMcpConfiguration(
4195
+ servers,
4196
+ dir
4197
+ ),
3717
4198
  windsurf: async (servers, dir) => (await Promise.resolve().then(() => (init_windsurf(), windsurf_exports))).generateWindsurfMcpConfiguration(
3718
4199
  servers,
3719
4200
  dir
@@ -3736,6 +4217,7 @@ async function generateMcpConfigurations(mcpConfig, baseDir, targetTools) {
3736
4217
  }
3737
4218
 
3738
4219
  // src/cli/commands/generate.ts
4220
+ init_logger();
3739
4221
  async function generateCommand(options = {}) {
3740
4222
  const configLoaderOptions = {
3741
4223
  ...options.config !== void 0 && { configPath: options.config },
@@ -3743,35 +4225,40 @@ async function generateCommand(options = {}) {
3743
4225
  };
3744
4226
  const configResult = await loadConfig(configLoaderOptions);
3745
4227
  const cliOptions = {
3746
- ...options.tools !== void 0 && { tools: options.tools },
4228
+ tools: options.tools,
3747
4229
  ...options.verbose !== void 0 && { verbose: options.verbose },
3748
4230
  ...options.delete !== void 0 && { delete: options.delete },
3749
4231
  ...options.baseDirs !== void 0 && { baseDirs: options.baseDirs }
3750
4232
  };
3751
4233
  const config = mergeWithCliOptions(configResult.config, cliOptions);
3752
- logger.setVerbose(config.verbose || false);
3753
- if (options.tools && options.tools.length > 0) {
3754
- const configTargets = config.defaultTargets;
3755
- const cliTools = options.tools;
3756
- const cliToolsSet = new Set(cliTools);
3757
- const configTargetsSet = new Set(configTargets);
3758
- const notInConfig = cliTools.filter((tool) => !configTargetsSet.has(tool));
3759
- const notInCli = configTargets.filter((tool) => !cliToolsSet.has(tool));
3760
- if (notInConfig.length > 0 || notInCli.length > 0) {
3761
- logger.warn("\u26A0\uFE0F Warning: CLI tool selection differs from configuration!");
3762
- logger.warn(` Config targets: ${configTargets.join(", ")}`);
3763
- logger.warn(` CLI specified: ${cliTools.join(", ")}`);
3764
- if (notInConfig.length > 0) {
3765
- logger.warn(` Tools specified but not in config: ${notInConfig.join(", ")}`);
3766
- }
3767
- if (notInCli.length > 0) {
3768
- logger.warn(` Tools in config but not specified: ${notInCli.join(", ")}`);
3769
- }
3770
- logger.warn("\n The configuration file targets will be used.");
3771
- logger.warn(" To change targets, update your rulesync config file.");
3772
- logger.warn("");
3773
- }
4234
+ if (!config.defaultTargets || config.defaultTargets.length === 0) {
4235
+ const errorMessage = `\u274C Error: At least one tool must be specified.
4236
+
4237
+ Available tools:
4238
+ --augmentcode Generate for AugmentCode
4239
+ --augmentcode-legacy Generate for AugmentCode legacy format
4240
+ --copilot Generate for GitHub Copilot
4241
+ --cursor Generate for Cursor
4242
+ --cline Generate for Cline
4243
+ --codexcli Generate for OpenAI Codex CLI
4244
+ --claudecode Generate for Claude Code
4245
+ --roo Generate for Roo Code
4246
+ --geminicli Generate for Gemini CLI
4247
+ --junie Generate for JetBrains Junie
4248
+ --qwencode Generate for Qwen Code
4249
+ --kiro Generate for Kiro IDE
4250
+ --opencode Generate for OpenCode
4251
+ --windsurf Generate for Windsurf
4252
+
4253
+ Example:
4254
+ rulesync generate --copilot --cursor
4255
+
4256
+ Or specify tools in rulesync.jsonc:
4257
+ "tools": ["copilot", "cursor"]`;
4258
+ logger.error(errorMessage);
4259
+ process.exit(1);
3774
4260
  }
4261
+ logger.setVerbose(config.verbose || false);
3775
4262
  let baseDirs;
3776
4263
  if (config.baseDir) {
3777
4264
  baseDirs = Array.isArray(config.baseDir) ? config.baseDir : [config.baseDir];
@@ -3799,7 +4286,7 @@ async function generateCommand(options = {}) {
3799
4286
  logger.info("Deleting existing output directories...");
3800
4287
  const targetTools = config.defaultTargets;
3801
4288
  const deleteTasks = [];
3802
- const commandsDir = (0, import_node_path13.join)(config.aiRulesDir, "commands");
4289
+ const commandsDir = (0, import_node_path14.join)(config.aiRulesDir, "commands");
3803
4290
  const hasCommands = await fileExists(commandsDir);
3804
4291
  let hasCommandFiles = false;
3805
4292
  if (hasCommands) {
@@ -3814,12 +4301,12 @@ async function generateCommand(options = {}) {
3814
4301
  for (const tool of targetTools) {
3815
4302
  switch (tool) {
3816
4303
  case "augmentcode":
3817
- deleteTasks.push(removeDirectory((0, import_node_path13.join)(".augment", "rules")));
3818
- deleteTasks.push(removeDirectory((0, import_node_path13.join)(".augment", "ignore")));
4304
+ deleteTasks.push(removeDirectory((0, import_node_path14.join)(".augment", "rules")));
4305
+ deleteTasks.push(removeDirectory((0, import_node_path14.join)(".augment", "ignore")));
3819
4306
  break;
3820
4307
  case "augmentcode-legacy":
3821
4308
  deleteTasks.push(removeClaudeGeneratedFiles());
3822
- deleteTasks.push(removeDirectory((0, import_node_path13.join)(".augment", "ignore")));
4309
+ deleteTasks.push(removeDirectory((0, import_node_path14.join)(".augment", "ignore")));
3823
4310
  break;
3824
4311
  case "copilot":
3825
4312
  deleteTasks.push(removeDirectory(config.outputPaths.copilot));
@@ -3833,24 +4320,30 @@ async function generateCommand(options = {}) {
3833
4320
  case "claudecode":
3834
4321
  deleteTasks.push(removeClaudeGeneratedFiles());
3835
4322
  if (hasCommandFiles) {
3836
- deleteTasks.push(removeDirectory((0, import_node_path13.join)(".claude", "commands")));
4323
+ deleteTasks.push(removeDirectory((0, import_node_path14.join)(".claude", "commands")));
3837
4324
  }
3838
4325
  break;
3839
4326
  case "roo":
3840
4327
  deleteTasks.push(removeDirectory(config.outputPaths.roo));
3841
4328
  if (hasCommandFiles) {
3842
- deleteTasks.push(removeDirectory((0, import_node_path13.join)(".roo", "commands")));
4329
+ deleteTasks.push(removeDirectory((0, import_node_path14.join)(".roo", "commands")));
3843
4330
  }
3844
4331
  break;
3845
4332
  case "geminicli":
3846
4333
  deleteTasks.push(removeDirectory(config.outputPaths.geminicli));
3847
4334
  if (hasCommandFiles) {
3848
- deleteTasks.push(removeDirectory((0, import_node_path13.join)(".gemini", "commands")));
4335
+ deleteTasks.push(removeDirectory((0, import_node_path14.join)(".gemini", "commands")));
3849
4336
  }
3850
4337
  break;
3851
4338
  case "kiro":
3852
4339
  deleteTasks.push(removeDirectory(config.outputPaths.kiro));
3853
4340
  break;
4341
+ case "opencode":
4342
+ deleteTasks.push(removeDirectory(config.outputPaths.opencode));
4343
+ break;
4344
+ case "qwencode":
4345
+ deleteTasks.push(removeDirectory(config.outputPaths.qwencode));
4346
+ break;
3854
4347
  case "windsurf":
3855
4348
  deleteTasks.push(removeDirectory(config.outputPaths.windsurf));
3856
4349
  break;
@@ -3944,11 +4437,14 @@ Generating configurations for base directory: ${baseDir}`);
3944
4437
 
3945
4438
  // src/cli/commands/gitignore.ts
3946
4439
  var import_node_fs2 = require("fs");
3947
- var import_node_path14 = require("path");
4440
+ var import_node_path15 = require("path");
4441
+ init_logger();
3948
4442
  var gitignoreCommand = async () => {
3949
- const gitignorePath = (0, import_node_path14.join)(process.cwd(), ".gitignore");
4443
+ const gitignorePath = (0, import_node_path15.join)(process.cwd(), ".gitignore");
3950
4444
  const rulesFilesToIgnore = [
3951
4445
  "# Generated by rulesync - AI tool configuration files",
4446
+ "**/.amazonq/rules/",
4447
+ "**/.amazonq/mcp.json",
3952
4448
  "**/.github/copilot-instructions.md",
3953
4449
  "**/.github/instructions/",
3954
4450
  "**/.cursor/rules/",
@@ -3966,6 +4462,8 @@ var gitignoreCommand = async () => {
3966
4462
  "**/GEMINI.md",
3967
4463
  "**/.gemini/memories/",
3968
4464
  "**/.gemini/commands/",
4465
+ "**/QWEN.md",
4466
+ "**/.qwen/memories/",
3969
4467
  "**/.aiexclude",
3970
4468
  "**/.aiignore",
3971
4469
  "**/.augmentignore",
@@ -3974,6 +4472,9 @@ var gitignoreCommand = async () => {
3974
4472
  "**/.augment-guidelines",
3975
4473
  "**/.junie/guidelines.md",
3976
4474
  "**/.noai",
4475
+ "**/.opencode/memories/",
4476
+ "**/.opencode/commands/",
4477
+ "**/opencode.json",
3977
4478
  "**/.mcp.json",
3978
4479
  "!.rulesync/.mcp.json",
3979
4480
  "**/.cursor/mcp.json",
@@ -3981,193 +4482,44 @@ var gitignoreCommand = async () => {
3981
4482
  "**/.vscode/mcp.json",
3982
4483
  "**/.codex/mcp-config.json",
3983
4484
  "**/.gemini/settings.json",
4485
+ "**/.qwen/settings.json",
3984
4486
  "**/.roo/mcp.json"
3985
4487
  ];
3986
4488
  let gitignoreContent = "";
3987
- if ((0, import_node_fs2.existsSync)(gitignorePath)) {
3988
- gitignoreContent = (0, import_node_fs2.readFileSync)(gitignorePath, "utf-8");
3989
- }
3990
- const linesToAdd = [];
3991
- for (const rule of rulesFilesToIgnore) {
3992
- if (!gitignoreContent.includes(rule)) {
3993
- linesToAdd.push(rule);
3994
- }
3995
- }
3996
- if (linesToAdd.length === 0) {
3997
- logger.success(".gitignore is already up to date");
3998
- return;
3999
- }
4000
- const newContent = gitignoreContent ? `${gitignoreContent.trimEnd()}
4001
-
4002
- ${linesToAdd.join("\n")}
4003
- ` : `${linesToAdd.join("\n")}
4004
- `;
4005
- (0, import_node_fs2.writeFileSync)(gitignorePath, newContent);
4006
- logger.success(`Added ${linesToAdd.length} rules to .gitignore:`);
4007
- for (const line of linesToAdd) {
4008
- if (!line.startsWith("#")) {
4009
- logger.log(` ${line}`);
4010
- }
4011
- }
4012
- };
4013
-
4014
- // src/core/importer.ts
4015
- var import_node_path21 = require("path");
4016
- var import_gray_matter2 = __toESM(require("gray-matter"), 1);
4017
-
4018
- // src/parsers/augmentcode.ts
4019
- var import_node_path15 = require("path");
4020
-
4021
- // src/utils/parser-helpers.ts
4022
- function createParseResult() {
4023
- return { rules: [], errors: [] };
4024
- }
4025
- function addError(result, error) {
4026
- result.errors.push(error);
4027
- }
4028
- function addRule(result, rule) {
4029
- if (!result.rules) {
4030
- result.rules = [];
4031
- }
4032
- result.rules.push(rule);
4033
- }
4034
- function addRules(result, rules) {
4035
- if (!result.rules) {
4036
- result.rules = [];
4037
- }
4038
- result.rules.push(...rules);
4039
- }
4040
- async function safeReadFile(operation, errorContext) {
4041
- try {
4042
- const result = await operation();
4043
- return createSuccessResult(result);
4044
- } catch (error) {
4045
- return createErrorResult(error, errorContext);
4046
- }
4047
- }
4048
-
4049
- // src/parsers/augmentcode.ts
4050
- async function parseAugmentcodeConfiguration(baseDir = process.cwd()) {
4051
- return parseUnifiedAugmentcode(baseDir, {
4052
- rulesDir: ".augment/rules",
4053
- targetName: "augmentcode",
4054
- filenamePrefix: "augmentcode"
4055
- });
4056
- }
4057
- async function parseAugmentcodeLegacyConfiguration(baseDir = process.cwd()) {
4058
- return parseUnifiedAugmentcode(baseDir, {
4059
- legacyFilePath: ".augment-guidelines",
4060
- targetName: "augmentcode-legacy",
4061
- filenamePrefix: "augmentcode-legacy"
4062
- });
4063
- }
4064
- async function parseUnifiedAugmentcode(baseDir, config) {
4065
- const result = createParseResult();
4066
- if (config.rulesDir) {
4067
- const rulesDir = (0, import_node_path15.join)(baseDir, config.rulesDir);
4068
- if (await fileExists(rulesDir)) {
4069
- const rulesResult = await parseAugmentRules(rulesDir, config);
4070
- addRules(result, rulesResult.rules);
4071
- result.errors.push(...rulesResult.errors);
4072
- } else {
4073
- addError(
4074
- result,
4075
- `No AugmentCode configuration found. Expected ${config.rulesDir} directory.`
4076
- );
4077
- }
4078
- }
4079
- if (config.legacyFilePath) {
4080
- const legacyPath = (0, import_node_path15.join)(baseDir, config.legacyFilePath);
4081
- if (await fileExists(legacyPath)) {
4082
- const legacyResult = await parseAugmentGuidelines(legacyPath, config);
4083
- if (legacyResult.rule) {
4084
- addRule(result, legacyResult.rule);
4085
- }
4086
- result.errors.push(...legacyResult.errors);
4087
- } else {
4088
- addError(
4089
- result,
4090
- `No AugmentCode legacy configuration found. Expected ${config.legacyFilePath} file.`
4091
- );
4092
- }
4093
- }
4094
- return { rules: result.rules || [], errors: result.errors };
4095
- }
4096
- async function parseAugmentRules(rulesDir, config) {
4097
- const rules = [];
4098
- const errors = [];
4099
- try {
4100
- const { readdir: readdir2 } = await import("fs/promises");
4101
- const files = await readdir2(rulesDir);
4102
- for (const file of files) {
4103
- if (file.endsWith(".md") || file.endsWith(".mdc")) {
4104
- const filePath = (0, import_node_path15.join)(rulesDir, file);
4105
- try {
4106
- const rawContent = await readFileContent(filePath);
4107
- const parsed = parseFrontmatter(rawContent);
4108
- const ruleType = extractStringField(parsed.data, "type", "manual");
4109
- const description = extractStringField(parsed.data, "description", "");
4110
- const tags = extractArrayField(parsed.data, "tags");
4111
- const isRoot = ruleType === "always";
4112
- const filename = (0, import_node_path15.basename)(file, file.endsWith(".mdc") ? ".mdc" : ".md");
4113
- const frontmatter = {
4114
- root: isRoot,
4115
- targets: [config.targetName],
4116
- description,
4117
- globs: ["**/*"],
4118
- // AugmentCode doesn't use specific globs in the same way
4119
- ...tags.length > 0 && { tags }
4120
- };
4121
- rules.push({
4122
- frontmatter,
4123
- content: parsed.content.trim(),
4124
- filename: `${config.filenamePrefix}-${ruleType}-${filename}`,
4125
- filepath: filePath
4126
- });
4127
- } catch (error) {
4128
- const errorMessage = error instanceof Error ? error.message : String(error);
4129
- errors.push(`Failed to parse ${filePath}: ${errorMessage}`);
4130
- }
4131
- }
4489
+ if ((0, import_node_fs2.existsSync)(gitignorePath)) {
4490
+ gitignoreContent = (0, import_node_fs2.readFileSync)(gitignorePath, "utf-8");
4491
+ }
4492
+ const linesToAdd = [];
4493
+ for (const rule of rulesFilesToIgnore) {
4494
+ if (!gitignoreContent.includes(rule)) {
4495
+ linesToAdd.push(rule);
4132
4496
  }
4133
- } catch (error) {
4134
- const errorMessage = error instanceof Error ? error.message : String(error);
4135
- errors.push(`Failed to read ${config.rulesDir || rulesDir} directory: ${errorMessage}`);
4136
4497
  }
4137
- return { rules, errors };
4138
- }
4139
- async function parseAugmentGuidelines(guidelinesPath, config) {
4140
- const parseResult = await safeReadFile(
4141
- async () => {
4142
- const content = await readFileContent(guidelinesPath);
4143
- if (content.trim()) {
4144
- const frontmatter = {
4145
- root: true,
4146
- // Legacy guidelines become root rules
4147
- targets: [config.targetName],
4148
- description: "Legacy AugmentCode guidelines",
4149
- globs: ["**/*"]
4150
- };
4151
- return {
4152
- frontmatter,
4153
- content: content.trim(),
4154
- filename: `${config.filenamePrefix}-guidelines`,
4155
- filepath: guidelinesPath
4156
- };
4157
- }
4158
- return null;
4159
- },
4160
- `Failed to parse ${config.legacyFilePath || guidelinesPath}`
4161
- );
4162
- if (parseResult.success) {
4163
- return { rule: parseResult.result || null, errors: [] };
4164
- } else {
4165
- return { rule: null, errors: [parseResult.error || "Unknown error"] };
4498
+ if (linesToAdd.length === 0) {
4499
+ logger.success(".gitignore is already up to date");
4500
+ return;
4166
4501
  }
4167
- }
4502
+ const newContent = gitignoreContent ? `${gitignoreContent.trimEnd()}
4503
+
4504
+ ${linesToAdd.join("\n")}
4505
+ ` : `${linesToAdd.join("\n")}
4506
+ `;
4507
+ (0, import_node_fs2.writeFileSync)(gitignorePath, newContent);
4508
+ logger.success(`Added ${linesToAdd.length} rules to .gitignore:`);
4509
+ for (const line of linesToAdd) {
4510
+ if (!line.startsWith("#")) {
4511
+ logger.log(` ${line}`);
4512
+ }
4513
+ }
4514
+ };
4515
+
4516
+ // src/core/importer.ts
4517
+ var import_node_path22 = require("path");
4518
+ var import_gray_matter2 = __toESM(require("gray-matter"), 1);
4168
4519
 
4169
4520
  // src/parsers/shared-helpers.ts
4170
4521
  var import_node_path16 = require("path");
4522
+ init_file();
4171
4523
  async function parseConfigurationFiles(baseDir = process.cwd(), config) {
4172
4524
  const errors = [];
4173
4525
  const rules = [];
@@ -4483,6 +4835,170 @@ async function parseSettingsFile(settingsPath, tool) {
4483
4835
  };
4484
4836
  }
4485
4837
 
4838
+ // src/parsers/amazonqcli.ts
4839
+ async function parseAmazonqcliConfiguration(baseDir = process.cwd()) {
4840
+ return parseMemoryBasedConfiguration(baseDir, {
4841
+ tool: "amazonqcli",
4842
+ mainFileName: ".amazonq/rules/main.md",
4843
+ memoryDirPath: ".amazonq/rules",
4844
+ settingsPath: ".amazonq/mcp.json",
4845
+ mainDescription: "Main Amazon Q Developer CLI configuration",
4846
+ memoryDescription: "Amazon Q rule",
4847
+ filenamePrefix: "amazonq"
4848
+ });
4849
+ }
4850
+
4851
+ // src/parsers/augmentcode.ts
4852
+ var import_node_path17 = require("path");
4853
+
4854
+ // src/utils/parser-helpers.ts
4855
+ function createParseResult() {
4856
+ return { rules: [], errors: [] };
4857
+ }
4858
+ function addError(result, error) {
4859
+ result.errors.push(error);
4860
+ }
4861
+ function addRule(result, rule) {
4862
+ if (!result.rules) {
4863
+ result.rules = [];
4864
+ }
4865
+ result.rules.push(rule);
4866
+ }
4867
+ function addRules(result, rules) {
4868
+ if (!result.rules) {
4869
+ result.rules = [];
4870
+ }
4871
+ result.rules.push(...rules);
4872
+ }
4873
+ async function safeReadFile(operation, errorContext) {
4874
+ try {
4875
+ const result = await operation();
4876
+ return createSuccessResult(result);
4877
+ } catch (error) {
4878
+ return createErrorResult(error, errorContext);
4879
+ }
4880
+ }
4881
+
4882
+ // src/parsers/augmentcode.ts
4883
+ async function parseAugmentcodeConfiguration(baseDir = process.cwd()) {
4884
+ return parseUnifiedAugmentcode(baseDir, {
4885
+ rulesDir: ".augment/rules",
4886
+ targetName: "augmentcode",
4887
+ filenamePrefix: "augmentcode"
4888
+ });
4889
+ }
4890
+ async function parseAugmentcodeLegacyConfiguration(baseDir = process.cwd()) {
4891
+ return parseUnifiedAugmentcode(baseDir, {
4892
+ legacyFilePath: ".augment-guidelines",
4893
+ targetName: "augmentcode-legacy",
4894
+ filenamePrefix: "augmentcode-legacy"
4895
+ });
4896
+ }
4897
+ async function parseUnifiedAugmentcode(baseDir, config) {
4898
+ const result = createParseResult();
4899
+ if (config.rulesDir) {
4900
+ const rulesDir = (0, import_node_path17.join)(baseDir, config.rulesDir);
4901
+ if (await fileExists(rulesDir)) {
4902
+ const rulesResult = await parseAugmentRules(rulesDir, config);
4903
+ addRules(result, rulesResult.rules);
4904
+ result.errors.push(...rulesResult.errors);
4905
+ } else {
4906
+ addError(
4907
+ result,
4908
+ `No AugmentCode configuration found. Expected ${config.rulesDir} directory.`
4909
+ );
4910
+ }
4911
+ }
4912
+ if (config.legacyFilePath) {
4913
+ const legacyPath = (0, import_node_path17.join)(baseDir, config.legacyFilePath);
4914
+ if (await fileExists(legacyPath)) {
4915
+ const legacyResult = await parseAugmentGuidelines(legacyPath, config);
4916
+ if (legacyResult.rule) {
4917
+ addRule(result, legacyResult.rule);
4918
+ }
4919
+ result.errors.push(...legacyResult.errors);
4920
+ } else {
4921
+ addError(
4922
+ result,
4923
+ `No AugmentCode legacy configuration found. Expected ${config.legacyFilePath} file.`
4924
+ );
4925
+ }
4926
+ }
4927
+ return { rules: result.rules || [], errors: result.errors };
4928
+ }
4929
+ async function parseAugmentRules(rulesDir, config) {
4930
+ const rules = [];
4931
+ const errors = [];
4932
+ try {
4933
+ const { readdir: readdir2 } = await import("fs/promises");
4934
+ const files = await readdir2(rulesDir);
4935
+ for (const file of files) {
4936
+ if (file.endsWith(".md") || file.endsWith(".mdc")) {
4937
+ const filePath = (0, import_node_path17.join)(rulesDir, file);
4938
+ try {
4939
+ const rawContent = await readFileContent(filePath);
4940
+ const parsed = parseFrontmatter(rawContent);
4941
+ const ruleType = extractStringField(parsed.data, "type", "manual");
4942
+ const description = extractStringField(parsed.data, "description", "");
4943
+ const tags = extractArrayField(parsed.data, "tags");
4944
+ const isRoot = ruleType === "always";
4945
+ const filename = (0, import_node_path17.basename)(file, file.endsWith(".mdc") ? ".mdc" : ".md");
4946
+ const frontmatter = {
4947
+ root: isRoot,
4948
+ targets: [config.targetName],
4949
+ description,
4950
+ globs: ["**/*"],
4951
+ // AugmentCode doesn't use specific globs in the same way
4952
+ ...tags.length > 0 && { tags }
4953
+ };
4954
+ rules.push({
4955
+ frontmatter,
4956
+ content: parsed.content.trim(),
4957
+ filename: `${config.filenamePrefix}-${ruleType}-${filename}`,
4958
+ filepath: filePath
4959
+ });
4960
+ } catch (error) {
4961
+ const errorMessage = error instanceof Error ? error.message : String(error);
4962
+ errors.push(`Failed to parse ${filePath}: ${errorMessage}`);
4963
+ }
4964
+ }
4965
+ }
4966
+ } catch (error) {
4967
+ const errorMessage = error instanceof Error ? error.message : String(error);
4968
+ errors.push(`Failed to read ${config.rulesDir || rulesDir} directory: ${errorMessage}`);
4969
+ }
4970
+ return { rules, errors };
4971
+ }
4972
+ async function parseAugmentGuidelines(guidelinesPath, config) {
4973
+ const parseResult = await safeReadFile(
4974
+ async () => {
4975
+ const content = await readFileContent(guidelinesPath);
4976
+ if (content.trim()) {
4977
+ const frontmatter = {
4978
+ root: true,
4979
+ // Legacy guidelines become root rules
4980
+ targets: [config.targetName],
4981
+ description: "Legacy AugmentCode guidelines",
4982
+ globs: ["**/*"]
4983
+ };
4984
+ return {
4985
+ frontmatter,
4986
+ content: content.trim(),
4987
+ filename: `${config.filenamePrefix}-guidelines`,
4988
+ filepath: guidelinesPath
4989
+ };
4990
+ }
4991
+ return null;
4992
+ },
4993
+ `Failed to parse ${config.legacyFilePath || guidelinesPath}`
4994
+ );
4995
+ if (parseResult.success) {
4996
+ return { rule: parseResult.result || null, errors: [] };
4997
+ } else {
4998
+ return { rule: null, errors: [parseResult.error || "Unknown error"] };
4999
+ }
5000
+ }
5001
+
4486
5002
  // src/parsers/claudecode.ts
4487
5003
  async function parseClaudeConfiguration(baseDir = process.cwd()) {
4488
5004
  return parseMemoryBasedConfiguration(baseDir, {
@@ -4518,7 +5034,7 @@ async function parseClineConfiguration(baseDir = process.cwd()) {
4518
5034
  }
4519
5035
 
4520
5036
  // src/parsers/codexcli.ts
4521
- var import_node_path17 = require("path");
5037
+ var import_node_path18 = require("path");
4522
5038
 
4523
5039
  // src/parsers/copilot.ts
4524
5040
  async function parseCopilotConfiguration(baseDir = process.cwd()) {
@@ -4541,7 +5057,7 @@ async function parseCopilotConfiguration(baseDir = process.cwd()) {
4541
5057
  }
4542
5058
 
4543
5059
  // src/parsers/cursor.ts
4544
- var import_node_path18 = require("path");
5060
+ var import_node_path19 = require("path");
4545
5061
  var import_js_yaml = require("js-yaml");
4546
5062
  var import_mini8 = require("zod/mini");
4547
5063
  var customMatterOptions = {
@@ -4665,7 +5181,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
4665
5181
  const rules = [];
4666
5182
  let ignorePatterns;
4667
5183
  let mcpServers;
4668
- const cursorFilePath = (0, import_node_path18.join)(baseDir, ".cursorrules");
5184
+ const cursorFilePath = (0, import_node_path19.join)(baseDir, ".cursorrules");
4669
5185
  if (await fileExists(cursorFilePath)) {
4670
5186
  try {
4671
5187
  const rawContent = await readFileContent(cursorFilePath);
@@ -4686,20 +5202,20 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
4686
5202
  errors.push(`Failed to parse .cursorrules file: ${errorMessage}`);
4687
5203
  }
4688
5204
  }
4689
- const cursorRulesDir = (0, import_node_path18.join)(baseDir, ".cursor", "rules");
5205
+ const cursorRulesDir = (0, import_node_path19.join)(baseDir, ".cursor", "rules");
4690
5206
  if (await fileExists(cursorRulesDir)) {
4691
5207
  try {
4692
5208
  const { readdir: readdir2 } = await import("fs/promises");
4693
5209
  const files = await readdir2(cursorRulesDir);
4694
5210
  for (const file of files) {
4695
5211
  if (file.endsWith(".mdc")) {
4696
- const filePath = (0, import_node_path18.join)(cursorRulesDir, file);
5212
+ const filePath = (0, import_node_path19.join)(cursorRulesDir, file);
4697
5213
  try {
4698
5214
  const rawContent = await readFileContent(filePath);
4699
5215
  const parsed = parseFrontmatter(rawContent, { matterOptions: customMatterOptions });
4700
5216
  const content = parsed.content;
4701
5217
  if (content) {
4702
- const filename = (0, import_node_path18.basename)(file, ".mdc");
5218
+ const filename = (0, import_node_path19.basename)(file, ".mdc");
4703
5219
  const frontmatter = convertCursorMdcFrontmatter(parsed.data, filename);
4704
5220
  rules.push({
4705
5221
  frontmatter,
@@ -4722,7 +5238,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
4722
5238
  if (rules.length === 0) {
4723
5239
  errors.push("No Cursor configuration files found (.cursorrules or .cursor/rules/*.mdc)");
4724
5240
  }
4725
- const cursorIgnorePath = (0, import_node_path18.join)(baseDir, ".cursorignore");
5241
+ const cursorIgnorePath = (0, import_node_path19.join)(baseDir, ".cursorignore");
4726
5242
  if (await fileExists(cursorIgnorePath)) {
4727
5243
  try {
4728
5244
  const content = await readFileContent(cursorIgnorePath);
@@ -4735,7 +5251,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
4735
5251
  errors.push(`Failed to parse .cursorignore: ${errorMessage}`);
4736
5252
  }
4737
5253
  }
4738
- const cursorMcpPath = (0, import_node_path18.join)(baseDir, ".cursor", "mcp.json");
5254
+ const cursorMcpPath = (0, import_node_path19.join)(baseDir, ".cursor", "mcp.json");
4739
5255
  if (await fileExists(cursorMcpPath)) {
4740
5256
  try {
4741
5257
  const content = await readFileContent(cursorMcpPath);
@@ -4785,11 +5301,11 @@ async function parseGeminiConfiguration(baseDir = process.cwd()) {
4785
5301
  }
4786
5302
 
4787
5303
  // src/parsers/junie.ts
4788
- var import_node_path19 = require("path");
5304
+ var import_node_path20 = require("path");
4789
5305
  async function parseJunieConfiguration(baseDir = process.cwd()) {
4790
5306
  const errors = [];
4791
5307
  const rules = [];
4792
- const guidelinesPath = (0, import_node_path19.join)(baseDir, ".junie", "guidelines.md");
5308
+ const guidelinesPath = (0, import_node_path20.join)(baseDir, ".junie", "guidelines.md");
4793
5309
  if (!await fileExists(guidelinesPath)) {
4794
5310
  errors.push(".junie/guidelines.md file not found");
4795
5311
  return { rules, errors };
@@ -4820,6 +5336,48 @@ async function parseJunieConfiguration(baseDir = process.cwd()) {
4820
5336
  return { rules, errors };
4821
5337
  }
4822
5338
 
5339
+ // src/parsers/opencode.ts
5340
+ async function parseOpCodeIgnore(opcodeignorePath) {
5341
+ try {
5342
+ const content = await readFileContent(opcodeignorePath);
5343
+ const patterns = content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
5344
+ return patterns;
5345
+ } catch {
5346
+ return [];
5347
+ }
5348
+ }
5349
+ async function parseOpenCodeConfiguration(baseDir = process.cwd()) {
5350
+ return parseMemoryBasedConfiguration(baseDir, {
5351
+ tool: "opencode",
5352
+ mainFileName: "AGENTS.md",
5353
+ memoryDirPath: ".opencode/memories",
5354
+ settingsPath: "opencode.json",
5355
+ mainDescription: "Main OpenCode configuration",
5356
+ memoryDescription: "Memory file",
5357
+ filenamePrefix: "opencode",
5358
+ additionalIgnoreFile: {
5359
+ path: ".opcodeignore",
5360
+ parser: parseOpCodeIgnore
5361
+ }
5362
+ });
5363
+ }
5364
+
5365
+ // src/parsers/qwencode.ts
5366
+ async function parseQwenConfiguration(baseDir = process.cwd()) {
5367
+ return parseMemoryBasedConfiguration(baseDir, {
5368
+ tool: "qwencode",
5369
+ mainFileName: "QWEN.md",
5370
+ memoryDirPath: ".qwen/memories",
5371
+ settingsPath: ".qwen/settings.json",
5372
+ mainDescription: "Main Qwen Code configuration",
5373
+ memoryDescription: "Memory file",
5374
+ filenamePrefix: "qwen",
5375
+ // Qwen Code uses git-aware filtering instead of dedicated ignore files
5376
+ // additionalIgnoreFile is omitted
5377
+ commandsDirPath: ".qwen/commands"
5378
+ });
5379
+ }
5380
+
4823
5381
  // src/parsers/roo.ts
4824
5382
  async function parseRooConfiguration(baseDir = process.cwd()) {
4825
5383
  return parseConfigurationFiles(baseDir, {
@@ -4842,9 +5400,11 @@ async function parseRooConfiguration(baseDir = process.cwd()) {
4842
5400
 
4843
5401
  // src/parsers/windsurf.ts
4844
5402
  var import_promises3 = require("fs/promises");
4845
- var import_node_path20 = require("path");
5403
+ var import_node_path21 = require("path");
5404
+ init_logger();
4846
5405
 
4847
5406
  // src/core/importer.ts
5407
+ init_logger();
4848
5408
  async function importConfiguration(options) {
4849
5409
  const {
4850
5410
  tool,
@@ -4862,6 +5422,13 @@ async function importConfiguration(options) {
4862
5422
  }
4863
5423
  try {
4864
5424
  switch (tool) {
5425
+ case "amazonqcli": {
5426
+ const amazonqResult = await parseAmazonqcliConfiguration(baseDir);
5427
+ rules = amazonqResult.rules;
5428
+ errors.push(...amazonqResult.errors);
5429
+ mcpServers = amazonqResult.mcpServers;
5430
+ break;
5431
+ }
4865
5432
  case "augmentcode": {
4866
5433
  const augmentResult = await parseAugmentcodeConfiguration(baseDir);
4867
5434
  rules = augmentResult.rules;
@@ -4922,6 +5489,21 @@ async function importConfiguration(options) {
4922
5489
  errors.push(...junieResult.errors);
4923
5490
  break;
4924
5491
  }
5492
+ case "opencode": {
5493
+ const opencodeResult = await parseOpenCodeConfiguration(baseDir);
5494
+ rules = opencodeResult.rules;
5495
+ errors.push(...opencodeResult.errors);
5496
+ ignorePatterns = opencodeResult.ignorePatterns;
5497
+ mcpServers = opencodeResult.mcpServers;
5498
+ break;
5499
+ }
5500
+ case "qwencode": {
5501
+ const qwenResult = await parseQwenConfiguration(baseDir);
5502
+ rules = qwenResult.rules;
5503
+ errors.push(...qwenResult.errors);
5504
+ mcpServers = qwenResult.mcpServers;
5505
+ break;
5506
+ }
4925
5507
  default:
4926
5508
  errors.push(`Unsupported tool: ${tool}`);
4927
5509
  return { success: false, rulesCreated: 0, errors };
@@ -4934,7 +5516,7 @@ async function importConfiguration(options) {
4934
5516
  if (rules.length === 0 && !ignorePatterns && !mcpServers) {
4935
5517
  return { success: false, rulesCreated: 0, errors };
4936
5518
  }
4937
- const rulesDirPath = (0, import_node_path21.join)(baseDir, rulesDir);
5519
+ const rulesDirPath = (0, import_node_path22.join)(baseDir, rulesDir);
4938
5520
  try {
4939
5521
  const { mkdir: mkdir3 } = await import("fs/promises");
4940
5522
  await mkdir3(rulesDirPath, { recursive: true });
@@ -4949,17 +5531,17 @@ async function importConfiguration(options) {
4949
5531
  const baseFilename = rule.filename;
4950
5532
  let targetDir = rulesDirPath;
4951
5533
  if (rule.type === "command") {
4952
- targetDir = (0, import_node_path21.join)(rulesDirPath, "commands");
5534
+ targetDir = (0, import_node_path22.join)(rulesDirPath, "commands");
4953
5535
  const { mkdir: mkdir3 } = await import("fs/promises");
4954
5536
  await mkdir3(targetDir, { recursive: true });
4955
5537
  } else {
4956
5538
  if (!useLegacyLocation) {
4957
- targetDir = (0, import_node_path21.join)(rulesDirPath, "rules");
5539
+ targetDir = (0, import_node_path22.join)(rulesDirPath, "rules");
4958
5540
  const { mkdir: mkdir3 } = await import("fs/promises");
4959
5541
  await mkdir3(targetDir, { recursive: true });
4960
5542
  }
4961
5543
  }
4962
- const filePath = (0, import_node_path21.join)(targetDir, `${baseFilename}.md`);
5544
+ const filePath = (0, import_node_path22.join)(targetDir, `${baseFilename}.md`);
4963
5545
  const content = generateRuleFileContent(rule);
4964
5546
  await writeFileContent(filePath, content);
4965
5547
  rulesCreated++;
@@ -4974,7 +5556,7 @@ async function importConfiguration(options) {
4974
5556
  let ignoreFileCreated = false;
4975
5557
  if (ignorePatterns && ignorePatterns.length > 0) {
4976
5558
  try {
4977
- const rulesyncignorePath = (0, import_node_path21.join)(baseDir, ".rulesyncignore");
5559
+ const rulesyncignorePath = (0, import_node_path22.join)(baseDir, ".rulesyncignore");
4978
5560
  const ignoreContent = `${ignorePatterns.join("\n")}
4979
5561
  `;
4980
5562
  await writeFileContent(rulesyncignorePath, ignoreContent);
@@ -4990,7 +5572,7 @@ async function importConfiguration(options) {
4990
5572
  let mcpFileCreated = false;
4991
5573
  if (mcpServers && Object.keys(mcpServers).length > 0) {
4992
5574
  try {
4993
- const mcpPath = (0, import_node_path21.join)(baseDir, rulesDir, ".mcp.json");
5575
+ const mcpPath = (0, import_node_path22.join)(baseDir, rulesDir, ".mcp.json");
4994
5576
  const mcpContent = `${JSON.stringify({ mcpServers }, null, 2)}
4995
5577
  `;
4996
5578
  await writeFileContent(mcpPath, mcpContent);
@@ -5025,9 +5607,11 @@ function generateRuleFileContent(rule) {
5025
5607
  }
5026
5608
 
5027
5609
  // src/cli/commands/import.ts
5610
+ init_logger();
5028
5611
  async function importCommand(options = {}) {
5029
5612
  logger.setVerbose(options.verbose || false);
5030
5613
  const tools = [];
5614
+ if (options.amazonqcli) tools.push("amazonqcli");
5031
5615
  if (options.augmentcode) tools.push("augmentcode");
5032
5616
  if (options["augmentcode-legacy"]) tools.push("augmentcode-legacy");
5033
5617
  if (options.claudecode) tools.push("claudecode");
@@ -5036,9 +5620,11 @@ async function importCommand(options = {}) {
5036
5620
  if (options.cline) tools.push("cline");
5037
5621
  if (options.roo) tools.push("roo");
5038
5622
  if (options.geminicli) tools.push("geminicli");
5623
+ if (options.qwencode) tools.push("qwencode");
5624
+ if (options.opencode) tools.push("opencode");
5039
5625
  if (tools.length === 0) {
5040
5626
  logger.error(
5041
- "\u274C Please specify one tool to import from (--augmentcode, --augmentcode-legacy, --claudecode, --cursor, --copilot, --cline, --roo, --geminicli)"
5627
+ "\u274C Please specify one tool to import from (--amazonqcli, --augmentcode, --augmentcode-legacy, --claudecode, --cursor, --copilot, --cline, --roo, --geminicli, --qwencode, --opencode)"
5042
5628
  );
5043
5629
  process.exit(1);
5044
5630
  }
@@ -5086,7 +5672,8 @@ async function importCommand(options = {}) {
5086
5672
  }
5087
5673
 
5088
5674
  // src/cli/commands/init.ts
5089
- var import_node_path22 = require("path");
5675
+ var import_node_path23 = require("path");
5676
+ init_logger();
5090
5677
  async function initCommand(options = {}) {
5091
5678
  const configResult = await loadConfig();
5092
5679
  const config = configResult.config;
@@ -5094,7 +5681,7 @@ async function initCommand(options = {}) {
5094
5681
  logger.log("Initializing rulesync...");
5095
5682
  await ensureDir(aiRulesDir);
5096
5683
  const useLegacy = options.legacy ?? config.legacy ?? false;
5097
- const rulesDir = useLegacy ? aiRulesDir : (0, import_node_path22.join)(aiRulesDir, "rules");
5684
+ const rulesDir = useLegacy ? aiRulesDir : (0, import_node_path23.join)(aiRulesDir, "rules");
5098
5685
  if (!useLegacy) {
5099
5686
  await ensureDir(rulesDir);
5100
5687
  }
@@ -5140,7 +5727,7 @@ globs: ["**/*"]
5140
5727
  - Follow single responsibility principle
5141
5728
  `
5142
5729
  };
5143
- const filepath = (0, import_node_path22.join)(rulesDir, sampleFile.filename);
5730
+ const filepath = (0, import_node_path23.join)(rulesDir, sampleFile.filename);
5144
5731
  if (!await fileExists(filepath)) {
5145
5732
  await writeFileContent(filepath, sampleFile.content);
5146
5733
  logger.success(`Created ${filepath}`);
@@ -5150,6 +5737,7 @@ globs: ["**/*"]
5150
5737
  }
5151
5738
 
5152
5739
  // src/cli/commands/status.ts
5740
+ init_logger();
5153
5741
  async function statusCommand() {
5154
5742
  const config = getDefaultConfig();
5155
5743
  logger.log("rulesync Status");
@@ -5202,6 +5790,7 @@ async function statusCommand() {
5202
5790
  }
5203
5791
 
5204
5792
  // src/cli/commands/validate.ts
5793
+ init_logger();
5205
5794
  async function validateCommand() {
5206
5795
  const config = getDefaultConfig();
5207
5796
  logger.log("Validating rulesync configuration...");
@@ -5244,6 +5833,7 @@ Validation failed with ${validation.errors.length} error(s)`);
5244
5833
 
5245
5834
  // src/cli/commands/watch.ts
5246
5835
  var import_chokidar = require("chokidar");
5836
+ init_logger();
5247
5837
  async function watchCommand() {
5248
5838
  const config = getDefaultConfig();
5249
5839
  logger.log("\u{1F440} Watching for changes in .rulesync directory...");
@@ -5284,37 +5874,41 @@ async function watchCommand() {
5284
5874
 
5285
5875
  // src/cli/index.ts
5286
5876
  var program = new import_commander.Command();
5287
- program.name("rulesync").description("Unified AI rules management CLI tool").version("0.63.0");
5877
+ program.name("rulesync").description("Unified AI rules management CLI tool").version("0.65.0");
5288
5878
  program.command("init").description("Initialize rulesync in current directory").option("--legacy", "Use legacy file location (.rulesync/*.md instead of .rulesync/rules/*.md)").action(initCommand);
5289
5879
  program.command("add <filename>").description("Add a new rule file").option("--legacy", "Use legacy file location (.rulesync/*.md instead of .rulesync/rules/*.md)").action(addCommand);
5290
5880
  program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);
5291
- 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").option("--legacy", "Use legacy file location (.rulesync/*.md instead of .rulesync/rules/*.md)").action(importCommand);
5292
- 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("--codexcli", "Generate only for OpenAI Codex CLI").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("--windsurf", "Generate only for Windsurf").option("--delete", "Delete all existing files in output directories before generating").option(
5881
+ 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("--qwencode", "Import from Qwen Code (QWEN.md)").option("--opencode", "Import from OpenCode (AGENTS.md)").option("-v, --verbose", "Verbose output").option("--legacy", "Use legacy file location (.rulesync/*.md instead of .rulesync/rules/*.md)").action(importCommand);
5882
+ program.command("generate").description("Generate configuration files for AI tools").option("--all", "Generate for all supported 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("--codexcli", "Generate only for OpenAI Codex CLI").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("--qwencode", "Generate only for Qwen Code").option("--kiro", "Generate only for Kiro IDE").option("--opencode", "Generate only for OpenCode").option("--windsurf", "Generate only for Windsurf").option("--delete", "Delete all existing files in output directories before generating").option(
5293
5883
  "-b, --base-dir <paths>",
5294
5884
  "Base directories to generate files (comma-separated for multiple paths)"
5295
5885
  ).option("-v, --verbose", "Verbose output").option("-c, --config <path>", "Path to configuration file").option("--no-config", "Disable configuration file loading").action(async (options) => {
5296
5886
  const tools = [];
5297
- if (options.augmentcode) tools.push("augmentcode");
5298
- if (options["augmentcode-legacy"]) tools.push("augmentcode-legacy");
5299
- if (options.copilot) tools.push("copilot");
5300
- if (options.cursor) tools.push("cursor");
5301
- if (options.cline) tools.push("cline");
5302
- if (options.codexcli) tools.push("codexcli");
5303
- if (options.claudecode) tools.push("claudecode");
5304
- if (options.roo) tools.push("roo");
5305
- if (options.geminicli) tools.push("geminicli");
5306
- if (options.junie) tools.push("junie");
5307
- if (options.kiro) tools.push("kiro");
5308
- if (options.windsurf) tools.push("windsurf");
5887
+ if (options.all) {
5888
+ tools.push(...ALL_TOOL_TARGETS);
5889
+ } else {
5890
+ if (options.augmentcode) tools.push("augmentcode");
5891
+ if (options["augmentcode-legacy"]) tools.push("augmentcode-legacy");
5892
+ if (options.copilot) tools.push("copilot");
5893
+ if (options.cursor) tools.push("cursor");
5894
+ if (options.cline) tools.push("cline");
5895
+ if (options.codexcli) tools.push("codexcli");
5896
+ if (options.claudecode) tools.push("claudecode");
5897
+ if (options.roo) tools.push("roo");
5898
+ if (options.geminicli) tools.push("geminicli");
5899
+ if (options.junie) tools.push("junie");
5900
+ if (options.qwencode) tools.push("qwencode");
5901
+ if (options.kiro) tools.push("kiro");
5902
+ if (options.opencode) tools.push("opencode");
5903
+ if (options.windsurf) tools.push("windsurf");
5904
+ }
5309
5905
  const generateOptions = {
5310
5906
  verbose: options.verbose,
5907
+ tools: tools.length > 0 ? tools : void 0,
5311
5908
  delete: options.delete,
5312
5909
  config: options.config,
5313
5910
  noConfig: options.noConfig
5314
5911
  };
5315
- if (tools.length > 0) {
5316
- generateOptions.tools = tools;
5317
- }
5318
5912
  if (options.baseDir) {
5319
5913
  generateOptions.baseDirs = options.baseDir.split(",").map((dir) => dir.trim()).filter((dir) => dir.length > 0);
5320
5914
  }