rulesync 0.55.0 → 0.57.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.ja.md +67 -5
  2. package/README.md +117 -18
  3. package/dist/{augmentcode-MJYD2Y4S.js → augmentcode-HIZIQG2W.js} +2 -2
  4. package/dist/chunk-7E4U4YAB.js +17 -0
  5. package/dist/{chunk-D7XQ4OHK.js → chunk-7UBF4OLN.js} +1 -1
  6. package/dist/{chunk-VI6SBYFB.js → chunk-AUUSMVCT.js} +2 -1
  7. package/dist/chunk-J3TBR5EP.js +292 -0
  8. package/dist/{chunk-OXKDEZJK.js → chunk-KUGTKMNW.js} +1 -1
  9. package/dist/{chunk-QVPD6ENS.js → chunk-LXTA7DBA.js} +1 -1
  10. package/dist/chunk-OA473EXZ.js +17 -0
  11. package/dist/{chunk-BEPSWIZC.js → chunk-PCATT4UZ.js} +1 -1
  12. package/dist/chunk-VKNCBVZF.js +17 -0
  13. package/dist/chunk-VNT6AHHO.js +17 -0
  14. package/dist/chunk-W2WU253H.js +17 -0
  15. package/dist/chunk-WAX2UANS.js +61 -0
  16. package/dist/{chunk-ORNO5MOO.js → chunk-YTU3SCQO.js} +1 -1
  17. package/dist/{claudecode-CKGUHLRR.js → claudecode-VVI2PTKI.js} +3 -3
  18. package/dist/{cline-Z5C656VR.js → cline-BJLFSLEB.js} +3 -3
  19. package/dist/{codexcli-VFUJKSIJ.js → codexcli-LKWQB3V3.js} +3 -3
  20. package/dist/{copilot-4WQS5TA7.js → copilot-MOR3HHJX.js} +2 -2
  21. package/dist/{cursor-HOB2F2V2.js → cursor-2BVUO64T.js} +3 -2
  22. package/dist/{geminicli-XTMQTIU2.js → geminicli-5YFMKRFL.js} +3 -2
  23. package/dist/index.cjs +553 -323
  24. package/dist/index.js +325 -168
  25. package/dist/{junie-AN6CR7DD.js → junie-5TDJPUXX.js} +3 -2
  26. package/dist/{kiro-PTUZOHQ2.js → kiro-YDHXY2MA.js} +2 -2
  27. package/dist/{roo-WOMS36KU.js → roo-L3QTTIPO.js} +2 -2
  28. package/dist/windsurf-PXDRIQ76.js +10 -0
  29. package/package.json +1 -1
  30. package/dist/chunk-3PHMFVXP.js +0 -66
  31. package/dist/chunk-OY6BYYIX.js +0 -63
  32. package/dist/chunk-PPAQWVXX.js +0 -94
  33. package/dist/chunk-TJKD6LEW.js +0 -90
  34. package/dist/chunk-UHANRG2O.js +0 -54
  35. package/dist/chunk-UZCJNUXO.js +0 -67
package/dist/index.cjs CHANGED
@@ -47,7 +47,8 @@ var init_tool_targets = __esm({
47
47
  "roo",
48
48
  "geminicli",
49
49
  "kiro",
50
- "junie"
50
+ "junie",
51
+ "windsurf"
51
52
  ];
52
53
  ToolTargetSchema = import_mini.z.enum(ALL_TOOL_TARGETS);
53
54
  ToolTargetsSchema = import_mini.z.array(ToolTargetSchema);
@@ -147,11 +148,72 @@ function generateMcpConfig(config, toolConfig) {
147
148
  const finalConfig = toolConfig.configWrapper(servers);
148
149
  return JSON.stringify(finalConfig, null, 2);
149
150
  }
150
- var configWrappers;
151
+ function generateMcpFromRegistry(tool, config) {
152
+ const generatorConfig = MCP_GENERATOR_REGISTRY[tool];
153
+ if (!generatorConfig) {
154
+ throw new Error(`No MCP generator configuration found for tool: ${tool}`);
155
+ }
156
+ return generateMcpConfig(config, generatorConfig);
157
+ }
158
+ var serverTransforms, configWrappers, MCP_GENERATOR_REGISTRY;
151
159
  var init_shared_factory = __esm({
152
160
  "src/generators/mcp/shared-factory.ts"() {
153
161
  "use strict";
154
162
  init_mcp_helpers();
163
+ serverTransforms = {
164
+ /**
165
+ * Basic server transformation (command, args, env, url handling)
166
+ */
167
+ basic: (server) => {
168
+ const result = {};
169
+ if (server.command) {
170
+ result.command = server.command;
171
+ if (server.args) result.args = server.args;
172
+ } else if (server.url || server.httpUrl) {
173
+ const url = server.httpUrl || server.url;
174
+ if (url) result.url = url;
175
+ }
176
+ if (server.env) {
177
+ result.env = server.env;
178
+ }
179
+ return result;
180
+ },
181
+ /**
182
+ * Extended server transformation (includes disabled, alwaysAllow, etc.)
183
+ */
184
+ extended: (server) => {
185
+ const result = serverTransforms.basic(server);
186
+ if (server.disabled !== void 0) {
187
+ result.disabled = server.disabled;
188
+ }
189
+ if (server.alwaysAllow) {
190
+ result.alwaysAllow = server.alwaysAllow;
191
+ }
192
+ if (server.networkTimeout !== void 0) {
193
+ result.networkTimeout = server.networkTimeout;
194
+ }
195
+ if (server.tools) {
196
+ result.tools = server.tools;
197
+ }
198
+ if (server.timeout !== void 0) {
199
+ result.timeout = server.timeout;
200
+ }
201
+ if (server.trust !== void 0) {
202
+ result.trust = server.trust;
203
+ }
204
+ if (server.headers) {
205
+ result.headers = server.headers;
206
+ }
207
+ return result;
208
+ },
209
+ /**
210
+ * Remove rulesync-specific properties from server config
211
+ */
212
+ cleanRulesyncProps: (server) => {
213
+ const { targets: _, transport: _transport, ...cleanServer } = server;
214
+ return { ...cleanServer };
215
+ }
216
+ };
155
217
  configWrappers = {
156
218
  /**
157
219
  * Standard mcpServers wrapper
@@ -166,37 +228,141 @@ var init_shared_factory = __esm({
166
228
  servers
167
229
  })
168
230
  };
231
+ MCP_GENERATOR_REGISTRY = {
232
+ claudecode: {
233
+ target: "claudecode",
234
+ configPaths: [".claude/settings.json"],
235
+ serverTransform: (server) => {
236
+ const claudeServer = {};
237
+ if (server.command) {
238
+ claudeServer.command = server.command;
239
+ if (server.args) claudeServer.args = server.args;
240
+ } else if (server.url || server.httpUrl) {
241
+ const url = server.httpUrl || server.url;
242
+ if (url) {
243
+ claudeServer.url = url;
244
+ }
245
+ if (server.httpUrl) {
246
+ claudeServer.transport = "http";
247
+ } else if (server.transport === "sse") {
248
+ claudeServer.transport = "sse";
249
+ }
250
+ }
251
+ if (server.env) {
252
+ claudeServer.env = server.env;
253
+ }
254
+ return claudeServer;
255
+ },
256
+ configWrapper: configWrappers.mcpServers
257
+ },
258
+ cursor: {
259
+ target: "cursor",
260
+ configPaths: [".cursor/mcp.json"],
261
+ serverTransform: (server) => {
262
+ const cursorServer = {};
263
+ if (server.command) {
264
+ cursorServer.command = server.command;
265
+ if (server.args) cursorServer.args = server.args;
266
+ } else if (server.url || server.httpUrl) {
267
+ const url = server.httpUrl || server.url;
268
+ if (url) {
269
+ cursorServer.url = url;
270
+ }
271
+ if (server.httpUrl || server.transport === "http") {
272
+ cursorServer.type = "streamable-http";
273
+ } else if (server.transport === "sse" || server.type === "sse") {
274
+ cursorServer.type = "sse";
275
+ }
276
+ }
277
+ if (server.env) {
278
+ cursorServer.env = server.env;
279
+ }
280
+ if (server.cwd) {
281
+ cursorServer.cwd = server.cwd;
282
+ }
283
+ return cursorServer;
284
+ },
285
+ configWrapper: configWrappers.mcpServers
286
+ },
287
+ windsurf: {
288
+ target: "windsurf",
289
+ configPaths: ["mcp_config.json"],
290
+ serverTransform: (server) => {
291
+ const windsurfServer = {};
292
+ if (server.command) {
293
+ windsurfServer.command = server.command;
294
+ if (server.args) windsurfServer.args = server.args;
295
+ } else if (server.url || server.httpUrl) {
296
+ const url = server.httpUrl || server.url;
297
+ if (url) {
298
+ windsurfServer.serverUrl = url;
299
+ }
300
+ }
301
+ if (server.env) {
302
+ windsurfServer.env = server.env;
303
+ }
304
+ if (server.cwd) {
305
+ windsurfServer.cwd = server.cwd;
306
+ }
307
+ return windsurfServer;
308
+ },
309
+ configWrapper: configWrappers.mcpServers
310
+ },
311
+ junie: {
312
+ target: "junie",
313
+ configPaths: [".junie/mcp-config.json"],
314
+ serverTransform: (server, serverName) => {
315
+ const junieServer = {
316
+ name: serverName
317
+ };
318
+ if (server.command) {
319
+ junieServer.command = server.command;
320
+ if (server.args) junieServer.args = server.args;
321
+ } else if (server.url || server.httpUrl) {
322
+ if (server.httpUrl) {
323
+ junieServer.httpUrl = server.httpUrl;
324
+ } else if (server.url) {
325
+ junieServer.url = server.url;
326
+ }
327
+ }
328
+ if (server.env) {
329
+ junieServer.env = server.env;
330
+ }
331
+ if (server.cwd) {
332
+ junieServer.workingDirectory = server.cwd;
333
+ }
334
+ if (server.timeout !== void 0) {
335
+ junieServer.timeout = server.timeout;
336
+ }
337
+ if (server.trust !== void 0) {
338
+ junieServer.trust = server.trust;
339
+ }
340
+ if (server.transport) {
341
+ if (String(server.transport) === "streamable-http") {
342
+ junieServer.transport = "http";
343
+ } else if (server.transport === "stdio" || server.transport === "http" || server.transport === "sse") {
344
+ junieServer.transport = server.transport;
345
+ }
346
+ } else if (server.command) {
347
+ junieServer.transport = "stdio";
348
+ }
349
+ return junieServer;
350
+ },
351
+ configWrapper: configWrappers.mcpServers
352
+ },
353
+ cline: {
354
+ target: "cline",
355
+ configPaths: [".cline/mcp.json"],
356
+ serverTransform: serverTransforms.extended,
357
+ configWrapper: configWrappers.mcpServers
358
+ }
359
+ };
169
360
  }
170
361
  });
171
362
 
172
363
  // src/generators/mcp/claudecode.ts
173
364
  function generateClaudeMcp(config) {
174
- return generateMcpConfig(config, {
175
- target: "claudecode",
176
- configPaths: [".claude/settings.json"],
177
- serverTransform: (server) => {
178
- const claudeServer = {};
179
- if (server.command) {
180
- claudeServer.command = server.command;
181
- if (server.args) claudeServer.args = server.args;
182
- } else if (server.url || server.httpUrl) {
183
- const url = server.httpUrl || server.url;
184
- if (url) {
185
- claudeServer.url = url;
186
- }
187
- if (server.httpUrl) {
188
- claudeServer.transport = "http";
189
- } else if (server.transport === "sse") {
190
- claudeServer.transport = "sse";
191
- }
192
- }
193
- if (server.env) {
194
- claudeServer.env = server.env;
195
- }
196
- return claudeServer;
197
- },
198
- configWrapper: configWrappers.mcpServers
199
- });
365
+ return generateMcpFromRegistry("claudecode", config);
200
366
  }
201
367
  var init_claudecode = __esm({
202
368
  "src/generators/mcp/claudecode.ts"() {
@@ -207,33 +373,7 @@ var init_claudecode = __esm({
207
373
 
208
374
  // src/generators/mcp/cline.ts
209
375
  function generateClineMcp(config) {
210
- return generateMcpConfig(config, {
211
- target: "cline",
212
- configPaths: [".cline/mcp.json"],
213
- serverTransform: (server) => {
214
- const clineServer = {};
215
- if (server.command) {
216
- clineServer.command = server.command;
217
- if (server.args) clineServer.args = server.args;
218
- } else if (server.url) {
219
- clineServer.url = server.url;
220
- }
221
- if (server.env) {
222
- clineServer.env = server.env;
223
- }
224
- if (server.disabled !== void 0) {
225
- clineServer.disabled = server.disabled;
226
- }
227
- if (server.alwaysAllow) {
228
- clineServer.alwaysAllow = server.alwaysAllow;
229
- }
230
- if (server.networkTimeout !== void 0) {
231
- clineServer.networkTimeout = server.networkTimeout;
232
- }
233
- return clineServer;
234
- },
235
- configWrapper: configWrappers.mcpServers
236
- });
376
+ return generateMcpFromRegistry("cline", config);
237
377
  }
238
378
  var init_cline = __esm({
239
379
  "src/generators/mcp/cline.ts"() {
@@ -370,137 +510,61 @@ var init_copilot = __esm({
370
510
 
371
511
  // src/generators/mcp/cursor.ts
372
512
  function generateCursorMcp(config) {
373
- const cursorConfig = {
374
- mcpServers: {}
375
- };
376
- for (const [serverName, server] of Object.entries(config.mcpServers)) {
377
- if (!shouldIncludeServer(server, "cursor")) continue;
378
- const cursorServer = {};
379
- if (server.command) {
380
- cursorServer.command = server.command;
381
- if (server.args) cursorServer.args = server.args;
382
- } else if (server.url || server.httpUrl) {
383
- const url = server.httpUrl || server.url;
384
- if (url) {
385
- cursorServer.url = url;
386
- }
387
- if (server.httpUrl || server.transport === "http") {
388
- cursorServer.type = "streamable-http";
389
- } else if (server.transport === "sse" || server.type === "sse") {
390
- cursorServer.type = "sse";
391
- }
392
- }
393
- if (server.env) {
394
- cursorServer.env = server.env;
395
- }
396
- if (server.cwd) {
397
- cursorServer.cwd = server.cwd;
398
- }
399
- cursorConfig.mcpServers[serverName] = cursorServer;
400
- }
401
- return JSON.stringify(cursorConfig, null, 2);
513
+ return generateMcpFromRegistry("cursor", config);
402
514
  }
403
515
  var init_cursor = __esm({
404
516
  "src/generators/mcp/cursor.ts"() {
405
517
  "use strict";
406
- init_mcp_helpers();
518
+ init_shared_factory();
407
519
  }
408
520
  });
409
521
 
410
522
  // src/generators/mcp/geminicli.ts
411
523
  function generateGeminiCliMcp(config) {
412
- const geminiSettings = {
413
- mcpServers: {}
414
- };
415
- for (const [serverName, server] of Object.entries(config.mcpServers)) {
416
- if (!shouldIncludeServer(server, "geminicli")) continue;
417
- const geminiServer = {};
418
- if (server.command) {
419
- geminiServer.command = server.command;
420
- if (server.args) geminiServer.args = server.args;
421
- } else if (server.url || server.httpUrl) {
422
- if (server.httpUrl) {
423
- geminiServer.httpUrl = server.httpUrl;
424
- } else if (server.url) {
425
- geminiServer.url = server.url;
426
- }
427
- }
428
- if (server.env) {
429
- geminiServer.env = {};
430
- for (const [key, value] of Object.entries(server.env)) {
431
- if (value.startsWith("${") && value.endsWith("}")) {
432
- geminiServer.env[key] = value;
433
- } else {
434
- geminiServer.env[key] = `\${${value}}`;
524
+ return generateMcpConfig(config, {
525
+ target: "geminicli",
526
+ configPaths: [".gemini/settings.json"],
527
+ serverTransform: (server) => {
528
+ const geminiServer = {};
529
+ if (server.command) {
530
+ geminiServer.command = server.command;
531
+ if (server.args) geminiServer.args = server.args;
532
+ } else if (server.url || server.httpUrl) {
533
+ if (server.httpUrl) {
534
+ geminiServer.httpUrl = server.httpUrl;
535
+ } else if (server.url) {
536
+ geminiServer.url = server.url;
435
537
  }
436
538
  }
437
- }
438
- if (server.timeout !== void 0) {
439
- geminiServer.timeout = server.timeout;
440
- }
441
- if (server.trust !== void 0) {
442
- geminiServer.trust = server.trust;
443
- }
444
- geminiSettings.mcpServers[serverName] = geminiServer;
445
- }
446
- return JSON.stringify(geminiSettings, null, 2);
539
+ if (server.env) {
540
+ geminiServer.env = server.env;
541
+ }
542
+ if (server.timeout !== void 0) {
543
+ geminiServer.timeout = server.timeout;
544
+ }
545
+ if (server.trust !== void 0) {
546
+ geminiServer.trust = server.trust;
547
+ }
548
+ return geminiServer;
549
+ },
550
+ configWrapper: configWrappers.mcpServers
551
+ });
447
552
  }
448
553
  var init_geminicli = __esm({
449
554
  "src/generators/mcp/geminicli.ts"() {
450
555
  "use strict";
451
- init_mcp_helpers();
556
+ init_shared_factory();
452
557
  }
453
558
  });
454
559
 
455
560
  // src/generators/mcp/junie.ts
456
561
  function generateJunieMcp(config) {
457
- const junieConfig = {
458
- mcpServers: {}
459
- };
460
- for (const [serverName, server] of Object.entries(config.mcpServers)) {
461
- if (!shouldIncludeServer(server, "junie")) continue;
462
- const junieServer = {
463
- name: serverName
464
- };
465
- if (server.command) {
466
- junieServer.command = server.command;
467
- if (server.args) junieServer.args = server.args;
468
- } else if (server.url || server.httpUrl) {
469
- if (server.httpUrl) {
470
- junieServer.httpUrl = server.httpUrl;
471
- } else if (server.url) {
472
- junieServer.url = server.url;
473
- }
474
- }
475
- if (server.env) {
476
- junieServer.env = server.env;
477
- }
478
- if (server.cwd) {
479
- junieServer.workingDirectory = server.cwd;
480
- }
481
- if (server.timeout !== void 0) {
482
- junieServer.timeout = server.timeout;
483
- }
484
- if (server.trust !== void 0) {
485
- junieServer.trust = server.trust;
486
- }
487
- if (server.transport) {
488
- if (String(server.transport) === "streamable-http") {
489
- junieServer.transport = "http";
490
- } else if (server.transport === "stdio" || server.transport === "http" || server.transport === "sse") {
491
- junieServer.transport = server.transport;
492
- }
493
- } else if (server.command) {
494
- junieServer.transport = "stdio";
495
- }
496
- junieConfig.mcpServers[serverName] = junieServer;
497
- }
498
- return JSON.stringify(junieConfig, null, 2);
562
+ return generateMcpFromRegistry("junie", config);
499
563
  }
500
564
  var init_junie = __esm({
501
565
  "src/generators/mcp/junie.ts"() {
502
566
  "use strict";
503
- init_mcp_helpers();
567
+ init_shared_factory();
504
568
  }
505
569
  });
506
570
 
@@ -607,6 +671,17 @@ var init_roo = __esm({
607
671
  }
608
672
  });
609
673
 
674
+ // src/generators/mcp/windsurf.ts
675
+ function generateWindsurfMcp(config) {
676
+ return generateMcpFromRegistry("windsurf", config);
677
+ }
678
+ var init_windsurf = __esm({
679
+ "src/generators/mcp/windsurf.ts"() {
680
+ "use strict";
681
+ init_shared_factory();
682
+ }
683
+ });
684
+
610
685
  // src/cli/index.ts
611
686
  var import_commander = require("commander");
612
687
 
@@ -630,7 +705,8 @@ function getDefaultConfig() {
630
705
  roo: ".roo/rules",
631
706
  geminicli: ".gemini/memories",
632
707
  kiro: ".kiro/steering",
633
- junie: "."
708
+ junie: ".",
709
+ windsurf: "."
634
710
  },
635
711
  watchEnabled: false,
636
712
  defaultTargets: ALL_TOOL_TARGETS.filter((tool) => tool !== "augmentcode-legacy")
@@ -719,7 +795,8 @@ var OutputPathsSchema = import_mini4.z.object({
719
795
  roo: import_mini4.z.optional(import_mini4.z.string()),
720
796
  geminicli: import_mini4.z.optional(import_mini4.z.string()),
721
797
  kiro: import_mini4.z.optional(import_mini4.z.string()),
722
- junie: import_mini4.z.optional(import_mini4.z.string())
798
+ junie: import_mini4.z.optional(import_mini4.z.string()),
799
+ windsurf: import_mini4.z.optional(import_mini4.z.string())
723
800
  });
724
801
  var ConfigOptionsSchema = import_mini4.z.object({
725
802
  aiRulesDir: import_mini4.z.optional(import_mini4.z.string()),
@@ -796,11 +873,13 @@ var RulesyncMcpConfigSchema = import_mini5.z.object({
796
873
  var import_mini6 = require("zod/mini");
797
874
  init_tool_targets();
798
875
  var RuleFrontmatterSchema = import_mini6.z.object({
799
- root: import_mini6.z.boolean(),
800
- targets: RulesyncTargetsSchema,
801
- description: import_mini6.z.string(),
802
- globs: import_mini6.z.array(import_mini6.z.string()),
876
+ root: import_mini6.z.optional(import_mini6.z.boolean()),
877
+ targets: import_mini6.z.optional(RulesyncTargetsSchema),
878
+ description: import_mini6.z.optional(import_mini6.z.string()),
879
+ globs: import_mini6.z.optional(import_mini6.z.array(import_mini6.z.string())),
803
880
  cursorRuleType: import_mini6.z.optional(import_mini6.z.enum(["always", "manual", "specificFiles", "intelligently"])),
881
+ windsurfActivationMode: import_mini6.z.optional(import_mini6.z.enum(["always", "manual", "model-decision", "glob"])),
882
+ windsurfOutputFormat: import_mini6.z.optional(import_mini6.z.enum(["single-file", "directory"])),
804
883
  tags: import_mini6.z.optional(import_mini6.z.array(import_mini6.z.string()))
805
884
  });
806
885
  var ParsedRuleSchema = import_mini6.z.object({
@@ -1345,7 +1424,7 @@ export default config;
1345
1424
  }
1346
1425
 
1347
1426
  // src/cli/commands/generate.ts
1348
- var import_node_path12 = require("path");
1427
+ var import_node_path10 = require("path");
1349
1428
 
1350
1429
  // src/generators/ignore/shared-factory.ts
1351
1430
  var import_node_path3 = require("path");
@@ -1905,6 +1984,131 @@ var ignoreConfigs = {
1905
1984
  ],
1906
1985
  includeCommonPatterns: false,
1907
1986
  projectPatternsHeader: "# \u2500\u2500\u2500\u2500\u2500 Project-specific patterns from rulesync rules \u2500\u2500\u2500\u2500\u2500"
1987
+ },
1988
+ windsurf: {
1989
+ tool: "windsurf",
1990
+ filename: ".codeiumignore",
1991
+ header: [
1992
+ "# Generated by rulesync - Windsurf AI Code Editor ignore file",
1993
+ "# This file controls which files are excluded from Cascade AI analysis and context",
1994
+ "# Uses same syntax as .gitignore patterns",
1995
+ "# Note: Git-ignored files are automatically excluded by Windsurf"
1996
+ ],
1997
+ corePatterns: [
1998
+ "# \u2500\u2500\u2500\u2500\u2500 Security & Credentials (Critical) \u2500\u2500\u2500\u2500\u2500",
1999
+ "# Environment files",
2000
+ ".env*",
2001
+ "!.env.example",
2002
+ "",
2003
+ "# Private keys and certificates",
2004
+ "*.pem",
2005
+ "*.key",
2006
+ "*.crt",
2007
+ "*.p12",
2008
+ "*.pfx",
2009
+ "*.der",
2010
+ "",
2011
+ "# SSH keys",
2012
+ "id_rsa*",
2013
+ "id_dsa*",
2014
+ "*.ppk",
2015
+ "",
2016
+ "# API keys and tokens",
2017
+ "**/apikeys/",
2018
+ "**/*_token*",
2019
+ "**/*_secret*",
2020
+ "**/*api_key*",
2021
+ "",
2022
+ "# Cloud provider credentials",
2023
+ "aws-credentials.json",
2024
+ "gcp-service-account*.json",
2025
+ "azure-credentials.json",
2026
+ "",
2027
+ "# \u2500\u2500\u2500\u2500\u2500 Database & Configuration Files \u2500\u2500\u2500\u2500\u2500",
2028
+ "# Database files",
2029
+ "*.db",
2030
+ "*.sqlite",
2031
+ "*.sqlite3",
2032
+ "",
2033
+ "# Configuration files with secrets",
2034
+ "config/secrets/",
2035
+ "**/database.yml",
2036
+ "",
2037
+ "# \u2500\u2500\u2500\u2500\u2500 Build Artifacts & Dependencies \u2500\u2500\u2500\u2500\u2500",
2038
+ "# Build outputs",
2039
+ "dist/",
2040
+ "build/",
2041
+ "out/",
2042
+ "target/",
2043
+ "",
2044
+ "# Dependencies (already auto-excluded but reinforced)",
2045
+ "node_modules/",
2046
+ ".pnpm-store/",
2047
+ ".yarn/",
2048
+ "vendor/",
2049
+ "",
2050
+ "# \u2500\u2500\u2500\u2500\u2500 Cache & Temporary Files \u2500\u2500\u2500\u2500\u2500",
2051
+ "# Cache directories",
2052
+ ".cache/",
2053
+ ".parcel-cache/",
2054
+ ".next/cache/",
2055
+ "",
2056
+ "# Temporary files",
2057
+ "*.tmp",
2058
+ "*.swp",
2059
+ "*.swo",
2060
+ "*~",
2061
+ "",
2062
+ "# \u2500\u2500\u2500\u2500\u2500 Large Data Files \u2500\u2500\u2500\u2500\u2500",
2063
+ "# Data files",
2064
+ "*.csv",
2065
+ "*.xlsx",
2066
+ "*.json",
2067
+ "data/",
2068
+ "datasets/",
2069
+ "",
2070
+ "# Media files",
2071
+ "*.mp4",
2072
+ "*.avi",
2073
+ "*.mov",
2074
+ "*.png",
2075
+ "*.jpg",
2076
+ "*.jpeg",
2077
+ "*.gif",
2078
+ "",
2079
+ "# Archives",
2080
+ "*.zip",
2081
+ "*.tar.gz",
2082
+ "*.rar",
2083
+ "",
2084
+ "# \u2500\u2500\u2500\u2500\u2500 IDE & Editor Files \u2500\u2500\u2500\u2500\u2500",
2085
+ "# IDE settings (personal)",
2086
+ ".vscode/settings.json",
2087
+ ".idea/",
2088
+ "",
2089
+ "# Editor temporary files",
2090
+ "*.swp",
2091
+ "*.swo",
2092
+ "",
2093
+ "# \u2500\u2500\u2500\u2500\u2500 Test Coverage & Logs \u2500\u2500\u2500\u2500\u2500",
2094
+ "# Test coverage reports",
2095
+ "coverage/",
2096
+ ".nyc_output/",
2097
+ "",
2098
+ "# Logs",
2099
+ "*.log",
2100
+ "",
2101
+ "# \u2500\u2500\u2500\u2500\u2500 Re-include Important Files \u2500\u2500\u2500\u2500\u2500",
2102
+ "# Allow configuration examples",
2103
+ "!.env.example",
2104
+ "!config/*.example.*",
2105
+ "",
2106
+ "# Allow documentation",
2107
+ "!docs/**/*.md",
2108
+ "!README.md"
2109
+ ],
2110
+ includeCommonPatterns: false,
2111
+ projectPatternsHeader: "# \u2500\u2500\u2500\u2500\u2500 Project-specific patterns from rulesync rules \u2500\u2500\u2500\u2500\u2500"
1908
2112
  }
1909
2113
  };
1910
2114
 
@@ -1923,6 +2127,11 @@ async function generateKiroIgnoreFiles(rules, config, baseDir) {
1923
2127
  return generateIgnoreFile(rules, config, ignoreConfigs.kiro, baseDir);
1924
2128
  }
1925
2129
 
2130
+ // src/generators/ignore/windsurf.ts
2131
+ function generateWindsurfIgnore(rules, config, baseDir) {
2132
+ return generateIgnoreFile(rules, config, ignoreConfigs.windsurf, baseDir);
2133
+ }
2134
+
1926
2135
  // src/generators/rules/augmentcode.ts
1927
2136
  var import_node_path6 = require("path");
1928
2137
 
@@ -2079,16 +2288,6 @@ function generateIgnoreFile2(patterns, tool) {
2079
2288
  lines.push(...patterns);
2080
2289
  return lines.join("\n");
2081
2290
  }
2082
- async function generateComplexRulesConfig(rules, config, generatorConfig, baseDir) {
2083
- const unifiedConfig = {
2084
- tool: generatorConfig.tool,
2085
- fileExtension: generatorConfig.fileExtension,
2086
- ignoreFileName: generatorConfig.ignoreFileName,
2087
- generateContent: generatorConfig.generateContent,
2088
- pathResolver: generatorConfig.getOutputPath
2089
- };
2090
- return generateRulesConfig(rules, config, unifiedConfig, baseDir);
2091
- }
2092
2291
 
2093
2292
  // src/generators/rules/augmentcode.ts
2094
2293
  async function generateAugmentcodeConfig(rules, config, baseDir) {
@@ -2159,7 +2358,7 @@ async function generateClaudecodeConfig(rules, config, baseDir) {
2159
2358
  fileExtension: ".md",
2160
2359
  ignoreFileName: ".aiignore",
2161
2360
  generateContent: generateMemoryFile,
2162
- generateRootContent: (rootRule, detailRules) => generateClaudeMarkdown(rootRule ? [rootRule] : [], detailRules),
2361
+ generateRootContent: generateClaudeMarkdown,
2163
2362
  rootFilePath: "CLAUDE.md",
2164
2363
  generateDetailContent: generateMemoryFile,
2165
2364
  detailSubDir: ".claude/memories",
@@ -2171,7 +2370,7 @@ async function generateClaudecodeConfig(rules, config, baseDir) {
2171
2370
  };
2172
2371
  return generateComplexRules(rules, config, generatorConfig, baseDir);
2173
2372
  }
2174
- function generateClaudeMarkdown(rootRules, detailRules) {
2373
+ function generateClaudeMarkdown(rootRule, detailRules) {
2175
2374
  const lines = [];
2176
2375
  if (detailRules.length > 0) {
2177
2376
  lines.push("Please also reference the following documents as needed:");
@@ -2185,11 +2384,9 @@ function generateClaudeMarkdown(rootRules, detailRules) {
2185
2384
  }
2186
2385
  lines.push("");
2187
2386
  }
2188
- if (rootRules.length > 0) {
2189
- for (const rule of rootRules) {
2190
- lines.push(rule.content);
2191
- lines.push("");
2192
- }
2387
+ if (rootRule) {
2388
+ lines.push(rootRule.content);
2389
+ lines.push("");
2193
2390
  }
2194
2391
  return lines.join("\n");
2195
2392
  }
@@ -2231,6 +2428,27 @@ async function updateClaudeSettings(settingsPath, ignorePatterns) {
2231
2428
 
2232
2429
  // src/generators/rules/generator-registry.ts
2233
2430
  var import_node_path8 = require("path");
2431
+ function determineCursorRuleType(frontmatter) {
2432
+ if (frontmatter.cursorRuleType) {
2433
+ return frontmatter.cursorRuleType;
2434
+ }
2435
+ const isDescriptionEmpty = !frontmatter.description || frontmatter.description.trim() === "";
2436
+ const isGlobsEmpty = frontmatter.globs.length === 0;
2437
+ const isGlobsExactlyAllFiles = frontmatter.globs.length === 1 && frontmatter.globs[0] === "**/*";
2438
+ if (isGlobsExactlyAllFiles) {
2439
+ return "always";
2440
+ }
2441
+ if (isDescriptionEmpty && isGlobsEmpty) {
2442
+ return "manual";
2443
+ }
2444
+ if (isDescriptionEmpty && !isGlobsEmpty) {
2445
+ return "specificFiles";
2446
+ }
2447
+ if (!isDescriptionEmpty && isGlobsEmpty) {
2448
+ return "intelligently";
2449
+ }
2450
+ return "intelligently";
2451
+ }
2234
2452
  var GENERATOR_REGISTRY = {
2235
2453
  // Simple generators - generate one file per rule
2236
2454
  cline: {
@@ -2295,9 +2513,42 @@ var GENERATOR_REGISTRY = {
2295
2513
  cursor: {
2296
2514
  type: "simple",
2297
2515
  tool: "cursor",
2298
- fileExtension: ".md",
2516
+ fileExtension: ".mdc",
2299
2517
  ignoreFileName: ".cursorignore",
2300
- generateContent: (rule) => rule.content.trim()
2518
+ generateContent: (rule) => {
2519
+ const lines = [];
2520
+ const ruleType = determineCursorRuleType(rule.frontmatter);
2521
+ lines.push("---");
2522
+ switch (ruleType) {
2523
+ case "always":
2524
+ lines.push("description:");
2525
+ lines.push("globs:");
2526
+ lines.push("alwaysApply: true");
2527
+ break;
2528
+ case "manual":
2529
+ lines.push("description:");
2530
+ lines.push("globs:");
2531
+ lines.push("alwaysApply: false");
2532
+ break;
2533
+ case "specificFiles":
2534
+ lines.push("description:");
2535
+ lines.push(`globs: ${rule.frontmatter.globs.join(",")}`);
2536
+ lines.push("alwaysApply: false");
2537
+ break;
2538
+ case "intelligently":
2539
+ lines.push(`description: ${rule.frontmatter.description}`);
2540
+ lines.push("globs:");
2541
+ lines.push("alwaysApply: false");
2542
+ break;
2543
+ }
2544
+ lines.push("---");
2545
+ lines.push("");
2546
+ lines.push(rule.content);
2547
+ return lines.join("\n");
2548
+ },
2549
+ pathResolver: (rule, outputDir) => {
2550
+ return (0, import_node_path8.join)(outputDir, `${rule.filename}.mdc`);
2551
+ }
2301
2552
  },
2302
2553
  codexcli: {
2303
2554
  type: "simple",
@@ -2306,6 +2557,39 @@ var GENERATOR_REGISTRY = {
2306
2557
  ignoreFileName: ".codexignore",
2307
2558
  generateContent: (rule) => rule.content.trim()
2308
2559
  },
2560
+ windsurf: {
2561
+ type: "simple",
2562
+ tool: "windsurf",
2563
+ fileExtension: ".md",
2564
+ ignoreFileName: ".codeiumignore",
2565
+ generateContent: (rule) => {
2566
+ const lines = [];
2567
+ const activationMode = rule.frontmatter.windsurfActivationMode;
2568
+ const globPattern = rule.frontmatter.globs?.[0];
2569
+ if (activationMode || globPattern) {
2570
+ lines.push("---");
2571
+ if (activationMode) {
2572
+ lines.push(`activation: ${activationMode}`);
2573
+ }
2574
+ if (globPattern && activationMode === "glob") {
2575
+ lines.push(`pattern: "${globPattern}"`);
2576
+ }
2577
+ lines.push("---");
2578
+ lines.push("");
2579
+ }
2580
+ lines.push(rule.content.trim());
2581
+ return lines.join("\n");
2582
+ },
2583
+ pathResolver: (rule, outputDir) => {
2584
+ const outputFormat = rule.frontmatter.windsurfOutputFormat || "directory";
2585
+ if (outputFormat === "single-file") {
2586
+ return (0, import_node_path8.join)(outputDir, ".windsurf-rules");
2587
+ } else {
2588
+ const rulesDir = (0, import_node_path8.join)(outputDir, ".windsurf", "rules");
2589
+ return (0, import_node_path8.join)(rulesDir, `${rule.filename}.md`);
2590
+ }
2591
+ }
2592
+ },
2309
2593
  // Complex generators with root + detail pattern
2310
2594
  claudecode: {
2311
2595
  type: "complex",
@@ -2444,107 +2728,13 @@ function generateConcatenatedCodexContent(rules) {
2444
2728
  }
2445
2729
 
2446
2730
  // src/generators/rules/copilot.ts
2447
- var import_node_path9 = require("path");
2448
2731
  async function generateCopilotConfig(rules, config, baseDir) {
2449
- return generateComplexRulesConfig(
2450
- rules,
2451
- config,
2452
- {
2453
- tool: "copilot",
2454
- fileExtension: ".instructions.md",
2455
- ignoreFileName: ".copilotignore",
2456
- generateContent: generateCopilotMarkdown,
2457
- getOutputPath: (rule, outputDir) => {
2458
- const baseFilename = rule.filename.replace(/\.md$/, "");
2459
- return (0, import_node_path9.join)(outputDir, `${baseFilename}.instructions.md`);
2460
- }
2461
- },
2462
- baseDir
2463
- );
2464
- }
2465
- function generateCopilotMarkdown(rule) {
2466
- const lines = [];
2467
- lines.push("---");
2468
- lines.push(`description: "${rule.frontmatter.description}"`);
2469
- if (rule.frontmatter.globs.length > 0) {
2470
- lines.push(`applyTo: "${rule.frontmatter.globs.join(", ")}"`);
2471
- } else {
2472
- lines.push('applyTo: "**"');
2473
- }
2474
- lines.push("---");
2475
- lines.push(rule.content);
2476
- return lines.join("\n");
2732
+ return generateFromRegistry("copilot", rules, config, baseDir);
2477
2733
  }
2478
2734
 
2479
2735
  // src/generators/rules/cursor.ts
2480
- var import_node_path10 = require("path");
2481
2736
  async function generateCursorConfig(rules, config, baseDir) {
2482
- return generateComplexRulesConfig(
2483
- rules,
2484
- config,
2485
- {
2486
- tool: "cursor",
2487
- fileExtension: ".mdc",
2488
- ignoreFileName: ".cursorignore",
2489
- generateContent: generateCursorMarkdown,
2490
- getOutputPath: (rule, outputDir) => {
2491
- return (0, import_node_path10.join)(outputDir, `${rule.filename}.mdc`);
2492
- }
2493
- },
2494
- baseDir
2495
- );
2496
- }
2497
- function generateCursorMarkdown(rule) {
2498
- const lines = [];
2499
- const ruleType = determineCursorRuleType(rule.frontmatter);
2500
- lines.push("---");
2501
- switch (ruleType) {
2502
- case "always":
2503
- lines.push("description:");
2504
- lines.push("globs:");
2505
- lines.push("alwaysApply: true");
2506
- break;
2507
- case "manual":
2508
- lines.push("description:");
2509
- lines.push("globs:");
2510
- lines.push("alwaysApply: false");
2511
- break;
2512
- case "specificFiles":
2513
- lines.push("description:");
2514
- lines.push(`globs: ${rule.frontmatter.globs.join(",")}`);
2515
- lines.push("alwaysApply: false");
2516
- break;
2517
- case "intelligently":
2518
- lines.push(`description: ${rule.frontmatter.description}`);
2519
- lines.push("globs:");
2520
- lines.push("alwaysApply: false");
2521
- break;
2522
- }
2523
- lines.push("---");
2524
- lines.push("");
2525
- lines.push(rule.content);
2526
- return lines.join("\n");
2527
- }
2528
- function determineCursorRuleType(frontmatter) {
2529
- if (frontmatter.cursorRuleType) {
2530
- return frontmatter.cursorRuleType;
2531
- }
2532
- const isDescriptionEmpty = !frontmatter.description || frontmatter.description.trim() === "";
2533
- const isGlobsEmpty = frontmatter.globs.length === 0;
2534
- const isGlobsExactlyAllFiles = frontmatter.globs.length === 1 && frontmatter.globs[0] === "**/*";
2535
- if (isGlobsExactlyAllFiles) {
2536
- return "always";
2537
- }
2538
- if (isDescriptionEmpty && isGlobsEmpty) {
2539
- return "manual";
2540
- }
2541
- if (isDescriptionEmpty && !isGlobsEmpty) {
2542
- return "specificFiles";
2543
- }
2544
- if (!isDescriptionEmpty && isGlobsEmpty) {
2545
- return "intelligently";
2546
- }
2547
- return "intelligently";
2737
+ return generateFromRegistry("cursor", rules, config, baseDir);
2548
2738
  }
2549
2739
 
2550
2740
  // src/generators/rules/geminicli.ts
@@ -2626,6 +2816,11 @@ async function generateRooConfig(rules, config, baseDir) {
2626
2816
  return generateFromRegistry("roo", rules, config, baseDir);
2627
2817
  }
2628
2818
 
2819
+ // src/generators/rules/windsurf.ts
2820
+ async function generateWindsurfConfig(rules, config, baseDir) {
2821
+ return generateFromRegistry("windsurf", rules, config, baseDir);
2822
+ }
2823
+
2629
2824
  // src/core/generator.ts
2630
2825
  async function generateConfigurations(rules, config, targetTools, baseDir) {
2631
2826
  const outputs = createOutputsArray();
@@ -2698,6 +2893,11 @@ async function generateForTool(tool, rules, config, baseDir) {
2698
2893
  const kiroIgnoreOutputs = await generateKiroIgnoreFiles(rules, config, baseDir);
2699
2894
  return [...kiroRulesOutputs, ...kiroIgnoreOutputs];
2700
2895
  }
2896
+ case "windsurf": {
2897
+ const windsurfRulesOutputs = await generateWindsurfConfig(rules, config, baseDir);
2898
+ const windsurfIgnoreOutputs = await generateWindsurfIgnore(rules, config, baseDir);
2899
+ return [...windsurfRulesOutputs, ...windsurfIgnoreOutputs];
2900
+ }
2701
2901
  default:
2702
2902
  console.warn(`Unknown tool: ${tool}`);
2703
2903
  return null;
@@ -2705,7 +2905,7 @@ async function generateForTool(tool, rules, config, baseDir) {
2705
2905
  }
2706
2906
 
2707
2907
  // src/core/parser.ts
2708
- var import_node_path11 = require("path");
2908
+ var import_node_path9 = require("path");
2709
2909
  var import_gray_matter = __toESM(require("gray-matter"), 1);
2710
2910
  async function parseRulesFromDirectory(aiRulesDir) {
2711
2911
  const ignorePatterns = await loadIgnorePatterns();
@@ -2742,8 +2942,24 @@ async function parseRuleFile(filepath) {
2742
2942
  const content = await readFileContent(filepath);
2743
2943
  const parsed = (0, import_gray_matter.default)(content);
2744
2944
  try {
2745
- const frontmatter = RuleFrontmatterSchema.parse(parsed.data);
2746
- const filename = (0, import_node_path11.basename)(filepath, ".md");
2945
+ const validatedData = RuleFrontmatterSchema.parse(parsed.data);
2946
+ const frontmatter = {
2947
+ root: validatedData.root ?? false,
2948
+ targets: validatedData.targets ?? ["*"],
2949
+ description: validatedData.description ?? "",
2950
+ globs: validatedData.globs ?? [],
2951
+ ...validatedData.cursorRuleType !== void 0 && {
2952
+ cursorRuleType: validatedData.cursorRuleType
2953
+ },
2954
+ ...validatedData.windsurfActivationMode !== void 0 && {
2955
+ windsurfActivationMode: validatedData.windsurfActivationMode
2956
+ },
2957
+ ...validatedData.windsurfOutputFormat !== void 0 && {
2958
+ windsurfOutputFormat: validatedData.windsurfOutputFormat
2959
+ },
2960
+ ...validatedData.tags !== void 0 && { tags: validatedData.tags }
2961
+ };
2962
+ const filename = (0, import_node_path9.basename)(filepath, ".md");
2747
2963
  return {
2748
2964
  frontmatter,
2749
2965
  content: parsed.content,
@@ -2821,6 +3037,7 @@ init_geminicli();
2821
3037
  init_junie();
2822
3038
  init_kiro();
2823
3039
  init_roo();
3040
+ init_windsurf();
2824
3041
 
2825
3042
  // src/core/mcp-parser.ts
2826
3043
  var fs = __toESM(require("fs"), 1);
@@ -2912,6 +3129,11 @@ async function generateMcpConfigs(projectRoot, baseDir, targetTools) {
2912
3129
  tool: "roo-project",
2913
3130
  path: path4.join(targetRoot, ".roo", "mcp.json"),
2914
3131
  generate: () => generateRooMcp(config)
3132
+ },
3133
+ {
3134
+ tool: "windsurf-project",
3135
+ path: path4.join(targetRoot, "mcp_config.json"),
3136
+ generate: () => generateWindsurfMcp(config)
2915
3137
  }
2916
3138
  ];
2917
3139
  const filteredGenerators = targetTools ? generators.filter((g) => {
@@ -2928,7 +3150,7 @@ async function generateMcpConfigs(projectRoot, baseDir, targetTools) {
2928
3150
  try {
2929
3151
  const content = generator.generate();
2930
3152
  const parsed = JSON.parse(content);
2931
- if (generator.tool.includes("augmentcode") || generator.tool.includes("claude") || generator.tool.includes("cline") || generator.tool.includes("codexcli") || generator.tool.includes("cursor") || generator.tool.includes("gemini") || generator.tool.includes("junie") || generator.tool.includes("kiro") || generator.tool.includes("roo")) {
3153
+ if (generator.tool.includes("augmentcode") || generator.tool.includes("claude") || generator.tool.includes("cline") || generator.tool.includes("codexcli") || generator.tool.includes("cursor") || generator.tool.includes("gemini") || generator.tool.includes("junie") || generator.tool.includes("kiro") || generator.tool.includes("roo") || generator.tool.includes("windsurf")) {
2932
3154
  if (!parsed.mcpServers || Object.keys(parsed.mcpServers).length === 0) {
2933
3155
  results.push({
2934
3156
  tool: generator.tool,
@@ -3040,12 +3262,12 @@ async function generateCommand(options = {}) {
3040
3262
  for (const tool of targetTools) {
3041
3263
  switch (tool) {
3042
3264
  case "augmentcode":
3043
- deleteTasks.push(removeDirectory((0, import_node_path12.join)(".augment", "rules")));
3044
- deleteTasks.push(removeDirectory((0, import_node_path12.join)(".augment", "ignore")));
3265
+ deleteTasks.push(removeDirectory((0, import_node_path10.join)(".augment", "rules")));
3266
+ deleteTasks.push(removeDirectory((0, import_node_path10.join)(".augment", "ignore")));
3045
3267
  break;
3046
3268
  case "augmentcode-legacy":
3047
3269
  deleteTasks.push(removeClaudeGeneratedFiles());
3048
- deleteTasks.push(removeDirectory((0, import_node_path12.join)(".augment", "ignore")));
3270
+ deleteTasks.push(removeDirectory((0, import_node_path10.join)(".augment", "ignore")));
3049
3271
  break;
3050
3272
  case "copilot":
3051
3273
  deleteTasks.push(removeDirectory(config.outputPaths.copilot));
@@ -3068,6 +3290,9 @@ async function generateCommand(options = {}) {
3068
3290
  case "kiro":
3069
3291
  deleteTasks.push(removeDirectory(config.outputPaths.kiro));
3070
3292
  break;
3293
+ case "windsurf":
3294
+ deleteTasks.push(removeDirectory(config.outputPaths.windsurf));
3295
+ break;
3071
3296
  }
3072
3297
  }
3073
3298
  await Promise.all(deleteTasks);
@@ -3140,9 +3365,9 @@ Generating configurations for base directory: ${baseDir}`);
3140
3365
 
3141
3366
  // src/cli/commands/gitignore.ts
3142
3367
  var import_node_fs2 = require("fs");
3143
- var import_node_path13 = require("path");
3368
+ var import_node_path11 = require("path");
3144
3369
  var gitignoreCommand = async () => {
3145
- const gitignorePath = (0, import_node_path13.join)(process.cwd(), ".gitignore");
3370
+ const gitignorePath = (0, import_node_path11.join)(process.cwd(), ".gitignore");
3146
3371
  const rulesFilesToIgnore = [
3147
3372
  "# Generated by rulesync - AI tool configuration files",
3148
3373
  "**/.github/copilot-instructions.md",
@@ -3206,11 +3431,11 @@ ${linesToAdd.join("\n")}
3206
3431
  };
3207
3432
 
3208
3433
  // src/core/importer.ts
3209
- var import_node_path19 = require("path");
3210
- var import_gray_matter5 = __toESM(require("gray-matter"), 1);
3434
+ var import_node_path18 = require("path");
3435
+ var import_gray_matter6 = __toESM(require("gray-matter"), 1);
3211
3436
 
3212
3437
  // src/parsers/augmentcode.ts
3213
- var import_node_path14 = require("path");
3438
+ var import_node_path12 = require("path");
3214
3439
  var import_gray_matter2 = __toESM(require("gray-matter"), 1);
3215
3440
 
3216
3441
  // src/utils/parser-helpers.ts
@@ -3259,7 +3484,7 @@ async function parseAugmentcodeLegacyConfiguration(baseDir = process.cwd()) {
3259
3484
  async function parseUnifiedAugmentcode(baseDir, config) {
3260
3485
  const result = createParseResult();
3261
3486
  if (config.rulesDir) {
3262
- const rulesDir = (0, import_node_path14.join)(baseDir, config.rulesDir);
3487
+ const rulesDir = (0, import_node_path12.join)(baseDir, config.rulesDir);
3263
3488
  if (await fileExists(rulesDir)) {
3264
3489
  const rulesResult = await parseAugmentRules(rulesDir, config);
3265
3490
  addRules(result, rulesResult.rules);
@@ -3272,7 +3497,7 @@ async function parseUnifiedAugmentcode(baseDir, config) {
3272
3497
  }
3273
3498
  }
3274
3499
  if (config.legacyFilePath) {
3275
- const legacyPath = (0, import_node_path14.join)(baseDir, config.legacyFilePath);
3500
+ const legacyPath = (0, import_node_path12.join)(baseDir, config.legacyFilePath);
3276
3501
  if (await fileExists(legacyPath)) {
3277
3502
  const legacyResult = await parseAugmentGuidelines(legacyPath, config);
3278
3503
  if (legacyResult.rule) {
@@ -3296,7 +3521,7 @@ async function parseAugmentRules(rulesDir, config) {
3296
3521
  const files = await readdir2(rulesDir);
3297
3522
  for (const file of files) {
3298
3523
  if (file.endsWith(".md") || file.endsWith(".mdc")) {
3299
- const filePath = (0, import_node_path14.join)(rulesDir, file);
3524
+ const filePath = (0, import_node_path12.join)(rulesDir, file);
3300
3525
  try {
3301
3526
  const rawContent = await readFileContent(filePath);
3302
3527
  const parsed = (0, import_gray_matter2.default)(rawContent);
@@ -3305,7 +3530,7 @@ async function parseAugmentRules(rulesDir, config) {
3305
3530
  const description = frontmatterData.description || "";
3306
3531
  const tags = Array.isArray(frontmatterData.tags) ? frontmatterData.tags : void 0;
3307
3532
  const isRoot = ruleType === "always";
3308
- const filename = (0, import_node_path14.basename)(file, file.endsWith(".mdc") ? ".mdc" : ".md");
3533
+ const filename = (0, import_node_path12.basename)(file, file.endsWith(".mdc") ? ".mdc" : ".md");
3309
3534
  const frontmatter = {
3310
3535
  root: isRoot,
3311
3536
  targets: [config.targetName],
@@ -3363,7 +3588,7 @@ async function parseAugmentGuidelines(guidelinesPath, config) {
3363
3588
  }
3364
3589
 
3365
3590
  // src/parsers/shared-helpers.ts
3366
- var import_node_path15 = require("path");
3591
+ var import_node_path13 = require("path");
3367
3592
  var import_gray_matter3 = __toESM(require("gray-matter"), 1);
3368
3593
  async function parseConfigurationFiles(baseDir = process.cwd(), config) {
3369
3594
  const errors = [];
@@ -3419,7 +3644,7 @@ async function parseConfigurationFiles(baseDir = process.cwd(), config) {
3419
3644
  const files = await readdir2(dirPath);
3420
3645
  for (const file of files) {
3421
3646
  if (file.endsWith(dirConfig.filePattern)) {
3422
- const filePath = (0, import_node_path15.join)(dirPath, file);
3647
+ const filePath = (0, import_node_path13.join)(dirPath, file);
3423
3648
  const fileResult = await safeAsyncOperation(async () => {
3424
3649
  const rawContent = await readFileContent(filePath);
3425
3650
  let content;
@@ -3557,10 +3782,10 @@ async function parseMemoryFiles(memoryDir, config) {
3557
3782
  const files = await readdir2(memoryDir);
3558
3783
  for (const file of files) {
3559
3784
  if (file.endsWith(".md")) {
3560
- const filePath = (0, import_node_path15.join)(memoryDir, file);
3785
+ const filePath = (0, import_node_path13.join)(memoryDir, file);
3561
3786
  const content = await readFileContent(filePath);
3562
3787
  if (content.trim()) {
3563
- const filename = (0, import_node_path15.basename)(file, ".md");
3788
+ const filename = (0, import_node_path13.basename)(file, ".md");
3564
3789
  const frontmatter = {
3565
3790
  root: false,
3566
3791
  targets: [config.tool],
@@ -3652,7 +3877,7 @@ async function parseClineConfiguration(baseDir = process.cwd()) {
3652
3877
  }
3653
3878
 
3654
3879
  // src/parsers/codexcli.ts
3655
- var import_node_path16 = require("path");
3880
+ var import_node_path14 = require("path");
3656
3881
 
3657
3882
  // src/parsers/copilot.ts
3658
3883
  async function parseCopilotConfiguration(baseDir = process.cwd()) {
@@ -3675,7 +3900,7 @@ async function parseCopilotConfiguration(baseDir = process.cwd()) {
3675
3900
  }
3676
3901
 
3677
3902
  // src/parsers/cursor.ts
3678
- var import_node_path17 = require("path");
3903
+ var import_node_path15 = require("path");
3679
3904
  var import_gray_matter4 = __toESM(require("gray-matter"), 1);
3680
3905
  var import_js_yaml = require("js-yaml");
3681
3906
  var import_mini7 = require("zod/mini");
@@ -3800,7 +4025,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
3800
4025
  const rules = [];
3801
4026
  let ignorePatterns;
3802
4027
  let mcpServers;
3803
- const cursorFilePath = (0, import_node_path17.join)(baseDir, ".cursorrules");
4028
+ const cursorFilePath = (0, import_node_path15.join)(baseDir, ".cursorrules");
3804
4029
  if (await fileExists(cursorFilePath)) {
3805
4030
  try {
3806
4031
  const rawContent = await readFileContent(cursorFilePath);
@@ -3821,20 +4046,20 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
3821
4046
  errors.push(`Failed to parse .cursorrules file: ${errorMessage}`);
3822
4047
  }
3823
4048
  }
3824
- const cursorRulesDir = (0, import_node_path17.join)(baseDir, ".cursor", "rules");
4049
+ const cursorRulesDir = (0, import_node_path15.join)(baseDir, ".cursor", "rules");
3825
4050
  if (await fileExists(cursorRulesDir)) {
3826
4051
  try {
3827
4052
  const { readdir: readdir2 } = await import("fs/promises");
3828
4053
  const files = await readdir2(cursorRulesDir);
3829
4054
  for (const file of files) {
3830
4055
  if (file.endsWith(".mdc")) {
3831
- const filePath = (0, import_node_path17.join)(cursorRulesDir, file);
4056
+ const filePath = (0, import_node_path15.join)(cursorRulesDir, file);
3832
4057
  try {
3833
4058
  const rawContent = await readFileContent(filePath);
3834
4059
  const parsed = (0, import_gray_matter4.default)(rawContent, customMatterOptions);
3835
4060
  const content = parsed.content.trim();
3836
4061
  if (content) {
3837
- const filename = (0, import_node_path17.basename)(file, ".mdc");
4062
+ const filename = (0, import_node_path15.basename)(file, ".mdc");
3838
4063
  const frontmatter = convertCursorMdcFrontmatter(parsed.data, filename);
3839
4064
  rules.push({
3840
4065
  frontmatter,
@@ -3857,7 +4082,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
3857
4082
  if (rules.length === 0) {
3858
4083
  errors.push("No Cursor configuration files found (.cursorrules or .cursor/rules/*.mdc)");
3859
4084
  }
3860
- const cursorIgnorePath = (0, import_node_path17.join)(baseDir, ".cursorignore");
4085
+ const cursorIgnorePath = (0, import_node_path15.join)(baseDir, ".cursorignore");
3861
4086
  if (await fileExists(cursorIgnorePath)) {
3862
4087
  try {
3863
4088
  const content = await readFileContent(cursorIgnorePath);
@@ -3870,7 +4095,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
3870
4095
  errors.push(`Failed to parse .cursorignore: ${errorMessage}`);
3871
4096
  }
3872
4097
  }
3873
- const cursorMcpPath = (0, import_node_path17.join)(baseDir, ".cursor", "mcp.json");
4098
+ const cursorMcpPath = (0, import_node_path15.join)(baseDir, ".cursor", "mcp.json");
3874
4099
  if (await fileExists(cursorMcpPath)) {
3875
4100
  try {
3876
4101
  const content = await readFileContent(cursorMcpPath);
@@ -3919,11 +4144,11 @@ async function parseGeminiConfiguration(baseDir = process.cwd()) {
3919
4144
  }
3920
4145
 
3921
4146
  // src/parsers/junie.ts
3922
- var import_node_path18 = require("path");
4147
+ var import_node_path16 = require("path");
3923
4148
  async function parseJunieConfiguration(baseDir = process.cwd()) {
3924
4149
  const errors = [];
3925
4150
  const rules = [];
3926
- const guidelinesPath = (0, import_node_path18.join)(baseDir, ".junie", "guidelines.md");
4151
+ const guidelinesPath = (0, import_node_path16.join)(baseDir, ".junie", "guidelines.md");
3927
4152
  if (!await fileExists(guidelinesPath)) {
3928
4153
  errors.push(".junie/guidelines.md file not found");
3929
4154
  return { rules, errors };
@@ -3974,6 +4199,11 @@ async function parseRooConfiguration(baseDir = process.cwd()) {
3974
4199
  });
3975
4200
  }
3976
4201
 
4202
+ // src/parsers/windsurf.ts
4203
+ var import_promises3 = require("fs/promises");
4204
+ var import_node_path17 = require("path");
4205
+ var import_gray_matter5 = __toESM(require("gray-matter"), 1);
4206
+
3977
4207
  // src/core/importer.ts
3978
4208
  async function importConfiguration(options) {
3979
4209
  const { tool, baseDir = process.cwd(), rulesDir = ".rulesync", verbose = false } = options;
@@ -4058,7 +4288,7 @@ async function importConfiguration(options) {
4058
4288
  if (rules.length === 0 && !ignorePatterns && !mcpServers) {
4059
4289
  return { success: false, rulesCreated: 0, errors };
4060
4290
  }
4061
- const rulesDirPath = (0, import_node_path19.join)(baseDir, rulesDir);
4291
+ const rulesDirPath = (0, import_node_path18.join)(baseDir, rulesDir);
4062
4292
  try {
4063
4293
  const { mkdir: mkdir3 } = await import("fs/promises");
4064
4294
  await mkdir3(rulesDirPath, { recursive: true });
@@ -4072,7 +4302,7 @@ async function importConfiguration(options) {
4072
4302
  try {
4073
4303
  const baseFilename = rule.filename;
4074
4304
  const filename = await generateUniqueFilename(rulesDirPath, baseFilename);
4075
- const filePath = (0, import_node_path19.join)(rulesDirPath, `${filename}.md`);
4305
+ const filePath = (0, import_node_path18.join)(rulesDirPath, `${filename}.md`);
4076
4306
  const content = generateRuleFileContent(rule);
4077
4307
  await writeFileContent(filePath, content);
4078
4308
  rulesCreated++;
@@ -4087,7 +4317,7 @@ async function importConfiguration(options) {
4087
4317
  let ignoreFileCreated = false;
4088
4318
  if (ignorePatterns && ignorePatterns.length > 0) {
4089
4319
  try {
4090
- const rulesyncignorePath = (0, import_node_path19.join)(baseDir, ".rulesyncignore");
4320
+ const rulesyncignorePath = (0, import_node_path18.join)(baseDir, ".rulesyncignore");
4091
4321
  const ignoreContent = `${ignorePatterns.join("\n")}
4092
4322
  `;
4093
4323
  await writeFileContent(rulesyncignorePath, ignoreContent);
@@ -4103,7 +4333,7 @@ async function importConfiguration(options) {
4103
4333
  let mcpFileCreated = false;
4104
4334
  if (mcpServers && Object.keys(mcpServers).length > 0) {
4105
4335
  try {
4106
- const mcpPath = (0, import_node_path19.join)(baseDir, rulesDir, ".mcp.json");
4336
+ const mcpPath = (0, import_node_path18.join)(baseDir, rulesDir, ".mcp.json");
4107
4337
  const mcpContent = `${JSON.stringify({ mcpServers }, null, 2)}
4108
4338
  `;
4109
4339
  await writeFileContent(mcpPath, mcpContent);
@@ -4125,13 +4355,13 @@ async function importConfiguration(options) {
4125
4355
  };
4126
4356
  }
4127
4357
  function generateRuleFileContent(rule) {
4128
- const frontmatter = import_gray_matter5.default.stringify("", rule.frontmatter);
4358
+ const frontmatter = import_gray_matter6.default.stringify("", rule.frontmatter);
4129
4359
  return frontmatter + rule.content;
4130
4360
  }
4131
4361
  async function generateUniqueFilename(rulesDir, baseFilename) {
4132
4362
  let filename = baseFilename;
4133
4363
  let counter = 1;
4134
- while (await fileExists((0, import_node_path19.join)(rulesDir, `${filename}.md`))) {
4364
+ while (await fileExists((0, import_node_path18.join)(rulesDir, `${filename}.md`))) {
4135
4365
  filename = `${baseFilename}-${counter}`;
4136
4366
  counter++;
4137
4367
  }
@@ -4198,7 +4428,7 @@ async function importCommand(options = {}) {
4198
4428
  }
4199
4429
 
4200
4430
  // src/cli/commands/init.ts
4201
- var import_node_path20 = require("path");
4431
+ var import_node_path19 = require("path");
4202
4432
  async function initCommand() {
4203
4433
  const aiRulesDir = ".rulesync";
4204
4434
  console.log("Initializing rulesync...");
@@ -4245,7 +4475,7 @@ globs: ["**/*"]
4245
4475
  - Follow single responsibility principle
4246
4476
  `
4247
4477
  };
4248
- const filepath = (0, import_node_path20.join)(aiRulesDir, sampleFile.filename);
4478
+ const filepath = (0, import_node_path19.join)(aiRulesDir, sampleFile.filename);
4249
4479
  if (!await fileExists(filepath)) {
4250
4480
  await writeFileContent(filepath, sampleFile.content);
4251
4481
  console.log(`Created ${filepath}`);
@@ -4389,7 +4619,7 @@ async function watchCommand() {
4389
4619
 
4390
4620
  // src/cli/index.ts
4391
4621
  var program = new import_commander.Command();
4392
- program.name("rulesync").description("Unified AI rules management CLI tool").version("0.55.0");
4622
+ program.name("rulesync").description("Unified AI rules management CLI tool").version("0.57.0");
4393
4623
  program.command("init").description("Initialize rulesync in current directory").action(initCommand);
4394
4624
  program.command("add <filename>").description("Add a new rule file").action(addCommand);
4395
4625
  program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);