rulesync 0.55.0 → 0.56.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 +77 -6
  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 +532 -318
  24. package/dist/index.js +304 -163
  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()),
@@ -801,6 +878,8 @@ var RuleFrontmatterSchema = import_mini6.z.object({
801
878
  description: import_mini6.z.string(),
802
879
  globs: 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();
@@ -2743,7 +2943,7 @@ async function parseRuleFile(filepath) {
2743
2943
  const parsed = (0, import_gray_matter.default)(content);
2744
2944
  try {
2745
2945
  const frontmatter = RuleFrontmatterSchema.parse(parsed.data);
2746
- const filename = (0, import_node_path11.basename)(filepath, ".md");
2946
+ const filename = (0, import_node_path9.basename)(filepath, ".md");
2747
2947
  return {
2748
2948
  frontmatter,
2749
2949
  content: parsed.content,
@@ -2821,6 +3021,7 @@ init_geminicli();
2821
3021
  init_junie();
2822
3022
  init_kiro();
2823
3023
  init_roo();
3024
+ init_windsurf();
2824
3025
 
2825
3026
  // src/core/mcp-parser.ts
2826
3027
  var fs = __toESM(require("fs"), 1);
@@ -2912,6 +3113,11 @@ async function generateMcpConfigs(projectRoot, baseDir, targetTools) {
2912
3113
  tool: "roo-project",
2913
3114
  path: path4.join(targetRoot, ".roo", "mcp.json"),
2914
3115
  generate: () => generateRooMcp(config)
3116
+ },
3117
+ {
3118
+ tool: "windsurf-project",
3119
+ path: path4.join(targetRoot, "mcp_config.json"),
3120
+ generate: () => generateWindsurfMcp(config)
2915
3121
  }
2916
3122
  ];
2917
3123
  const filteredGenerators = targetTools ? generators.filter((g) => {
@@ -2928,7 +3134,7 @@ async function generateMcpConfigs(projectRoot, baseDir, targetTools) {
2928
3134
  try {
2929
3135
  const content = generator.generate();
2930
3136
  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")) {
3137
+ 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
3138
  if (!parsed.mcpServers || Object.keys(parsed.mcpServers).length === 0) {
2933
3139
  results.push({
2934
3140
  tool: generator.tool,
@@ -3040,12 +3246,12 @@ async function generateCommand(options = {}) {
3040
3246
  for (const tool of targetTools) {
3041
3247
  switch (tool) {
3042
3248
  case "augmentcode":
3043
- deleteTasks.push(removeDirectory((0, import_node_path12.join)(".augment", "rules")));
3044
- deleteTasks.push(removeDirectory((0, import_node_path12.join)(".augment", "ignore")));
3249
+ deleteTasks.push(removeDirectory((0, import_node_path10.join)(".augment", "rules")));
3250
+ deleteTasks.push(removeDirectory((0, import_node_path10.join)(".augment", "ignore")));
3045
3251
  break;
3046
3252
  case "augmentcode-legacy":
3047
3253
  deleteTasks.push(removeClaudeGeneratedFiles());
3048
- deleteTasks.push(removeDirectory((0, import_node_path12.join)(".augment", "ignore")));
3254
+ deleteTasks.push(removeDirectory((0, import_node_path10.join)(".augment", "ignore")));
3049
3255
  break;
3050
3256
  case "copilot":
3051
3257
  deleteTasks.push(removeDirectory(config.outputPaths.copilot));
@@ -3068,6 +3274,9 @@ async function generateCommand(options = {}) {
3068
3274
  case "kiro":
3069
3275
  deleteTasks.push(removeDirectory(config.outputPaths.kiro));
3070
3276
  break;
3277
+ case "windsurf":
3278
+ deleteTasks.push(removeDirectory(config.outputPaths.windsurf));
3279
+ break;
3071
3280
  }
3072
3281
  }
3073
3282
  await Promise.all(deleteTasks);
@@ -3140,9 +3349,9 @@ Generating configurations for base directory: ${baseDir}`);
3140
3349
 
3141
3350
  // src/cli/commands/gitignore.ts
3142
3351
  var import_node_fs2 = require("fs");
3143
- var import_node_path13 = require("path");
3352
+ var import_node_path11 = require("path");
3144
3353
  var gitignoreCommand = async () => {
3145
- const gitignorePath = (0, import_node_path13.join)(process.cwd(), ".gitignore");
3354
+ const gitignorePath = (0, import_node_path11.join)(process.cwd(), ".gitignore");
3146
3355
  const rulesFilesToIgnore = [
3147
3356
  "# Generated by rulesync - AI tool configuration files",
3148
3357
  "**/.github/copilot-instructions.md",
@@ -3206,11 +3415,11 @@ ${linesToAdd.join("\n")}
3206
3415
  };
3207
3416
 
3208
3417
  // src/core/importer.ts
3209
- var import_node_path19 = require("path");
3210
- var import_gray_matter5 = __toESM(require("gray-matter"), 1);
3418
+ var import_node_path18 = require("path");
3419
+ var import_gray_matter6 = __toESM(require("gray-matter"), 1);
3211
3420
 
3212
3421
  // src/parsers/augmentcode.ts
3213
- var import_node_path14 = require("path");
3422
+ var import_node_path12 = require("path");
3214
3423
  var import_gray_matter2 = __toESM(require("gray-matter"), 1);
3215
3424
 
3216
3425
  // src/utils/parser-helpers.ts
@@ -3259,7 +3468,7 @@ async function parseAugmentcodeLegacyConfiguration(baseDir = process.cwd()) {
3259
3468
  async function parseUnifiedAugmentcode(baseDir, config) {
3260
3469
  const result = createParseResult();
3261
3470
  if (config.rulesDir) {
3262
- const rulesDir = (0, import_node_path14.join)(baseDir, config.rulesDir);
3471
+ const rulesDir = (0, import_node_path12.join)(baseDir, config.rulesDir);
3263
3472
  if (await fileExists(rulesDir)) {
3264
3473
  const rulesResult = await parseAugmentRules(rulesDir, config);
3265
3474
  addRules(result, rulesResult.rules);
@@ -3272,7 +3481,7 @@ async function parseUnifiedAugmentcode(baseDir, config) {
3272
3481
  }
3273
3482
  }
3274
3483
  if (config.legacyFilePath) {
3275
- const legacyPath = (0, import_node_path14.join)(baseDir, config.legacyFilePath);
3484
+ const legacyPath = (0, import_node_path12.join)(baseDir, config.legacyFilePath);
3276
3485
  if (await fileExists(legacyPath)) {
3277
3486
  const legacyResult = await parseAugmentGuidelines(legacyPath, config);
3278
3487
  if (legacyResult.rule) {
@@ -3296,7 +3505,7 @@ async function parseAugmentRules(rulesDir, config) {
3296
3505
  const files = await readdir2(rulesDir);
3297
3506
  for (const file of files) {
3298
3507
  if (file.endsWith(".md") || file.endsWith(".mdc")) {
3299
- const filePath = (0, import_node_path14.join)(rulesDir, file);
3508
+ const filePath = (0, import_node_path12.join)(rulesDir, file);
3300
3509
  try {
3301
3510
  const rawContent = await readFileContent(filePath);
3302
3511
  const parsed = (0, import_gray_matter2.default)(rawContent);
@@ -3305,7 +3514,7 @@ async function parseAugmentRules(rulesDir, config) {
3305
3514
  const description = frontmatterData.description || "";
3306
3515
  const tags = Array.isArray(frontmatterData.tags) ? frontmatterData.tags : void 0;
3307
3516
  const isRoot = ruleType === "always";
3308
- const filename = (0, import_node_path14.basename)(file, file.endsWith(".mdc") ? ".mdc" : ".md");
3517
+ const filename = (0, import_node_path12.basename)(file, file.endsWith(".mdc") ? ".mdc" : ".md");
3309
3518
  const frontmatter = {
3310
3519
  root: isRoot,
3311
3520
  targets: [config.targetName],
@@ -3363,7 +3572,7 @@ async function parseAugmentGuidelines(guidelinesPath, config) {
3363
3572
  }
3364
3573
 
3365
3574
  // src/parsers/shared-helpers.ts
3366
- var import_node_path15 = require("path");
3575
+ var import_node_path13 = require("path");
3367
3576
  var import_gray_matter3 = __toESM(require("gray-matter"), 1);
3368
3577
  async function parseConfigurationFiles(baseDir = process.cwd(), config) {
3369
3578
  const errors = [];
@@ -3419,7 +3628,7 @@ async function parseConfigurationFiles(baseDir = process.cwd(), config) {
3419
3628
  const files = await readdir2(dirPath);
3420
3629
  for (const file of files) {
3421
3630
  if (file.endsWith(dirConfig.filePattern)) {
3422
- const filePath = (0, import_node_path15.join)(dirPath, file);
3631
+ const filePath = (0, import_node_path13.join)(dirPath, file);
3423
3632
  const fileResult = await safeAsyncOperation(async () => {
3424
3633
  const rawContent = await readFileContent(filePath);
3425
3634
  let content;
@@ -3557,10 +3766,10 @@ async function parseMemoryFiles(memoryDir, config) {
3557
3766
  const files = await readdir2(memoryDir);
3558
3767
  for (const file of files) {
3559
3768
  if (file.endsWith(".md")) {
3560
- const filePath = (0, import_node_path15.join)(memoryDir, file);
3769
+ const filePath = (0, import_node_path13.join)(memoryDir, file);
3561
3770
  const content = await readFileContent(filePath);
3562
3771
  if (content.trim()) {
3563
- const filename = (0, import_node_path15.basename)(file, ".md");
3772
+ const filename = (0, import_node_path13.basename)(file, ".md");
3564
3773
  const frontmatter = {
3565
3774
  root: false,
3566
3775
  targets: [config.tool],
@@ -3652,7 +3861,7 @@ async function parseClineConfiguration(baseDir = process.cwd()) {
3652
3861
  }
3653
3862
 
3654
3863
  // src/parsers/codexcli.ts
3655
- var import_node_path16 = require("path");
3864
+ var import_node_path14 = require("path");
3656
3865
 
3657
3866
  // src/parsers/copilot.ts
3658
3867
  async function parseCopilotConfiguration(baseDir = process.cwd()) {
@@ -3675,7 +3884,7 @@ async function parseCopilotConfiguration(baseDir = process.cwd()) {
3675
3884
  }
3676
3885
 
3677
3886
  // src/parsers/cursor.ts
3678
- var import_node_path17 = require("path");
3887
+ var import_node_path15 = require("path");
3679
3888
  var import_gray_matter4 = __toESM(require("gray-matter"), 1);
3680
3889
  var import_js_yaml = require("js-yaml");
3681
3890
  var import_mini7 = require("zod/mini");
@@ -3800,7 +4009,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
3800
4009
  const rules = [];
3801
4010
  let ignorePatterns;
3802
4011
  let mcpServers;
3803
- const cursorFilePath = (0, import_node_path17.join)(baseDir, ".cursorrules");
4012
+ const cursorFilePath = (0, import_node_path15.join)(baseDir, ".cursorrules");
3804
4013
  if (await fileExists(cursorFilePath)) {
3805
4014
  try {
3806
4015
  const rawContent = await readFileContent(cursorFilePath);
@@ -3821,20 +4030,20 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
3821
4030
  errors.push(`Failed to parse .cursorrules file: ${errorMessage}`);
3822
4031
  }
3823
4032
  }
3824
- const cursorRulesDir = (0, import_node_path17.join)(baseDir, ".cursor", "rules");
4033
+ const cursorRulesDir = (0, import_node_path15.join)(baseDir, ".cursor", "rules");
3825
4034
  if (await fileExists(cursorRulesDir)) {
3826
4035
  try {
3827
4036
  const { readdir: readdir2 } = await import("fs/promises");
3828
4037
  const files = await readdir2(cursorRulesDir);
3829
4038
  for (const file of files) {
3830
4039
  if (file.endsWith(".mdc")) {
3831
- const filePath = (0, import_node_path17.join)(cursorRulesDir, file);
4040
+ const filePath = (0, import_node_path15.join)(cursorRulesDir, file);
3832
4041
  try {
3833
4042
  const rawContent = await readFileContent(filePath);
3834
4043
  const parsed = (0, import_gray_matter4.default)(rawContent, customMatterOptions);
3835
4044
  const content = parsed.content.trim();
3836
4045
  if (content) {
3837
- const filename = (0, import_node_path17.basename)(file, ".mdc");
4046
+ const filename = (0, import_node_path15.basename)(file, ".mdc");
3838
4047
  const frontmatter = convertCursorMdcFrontmatter(parsed.data, filename);
3839
4048
  rules.push({
3840
4049
  frontmatter,
@@ -3857,7 +4066,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
3857
4066
  if (rules.length === 0) {
3858
4067
  errors.push("No Cursor configuration files found (.cursorrules or .cursor/rules/*.mdc)");
3859
4068
  }
3860
- const cursorIgnorePath = (0, import_node_path17.join)(baseDir, ".cursorignore");
4069
+ const cursorIgnorePath = (0, import_node_path15.join)(baseDir, ".cursorignore");
3861
4070
  if (await fileExists(cursorIgnorePath)) {
3862
4071
  try {
3863
4072
  const content = await readFileContent(cursorIgnorePath);
@@ -3870,7 +4079,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
3870
4079
  errors.push(`Failed to parse .cursorignore: ${errorMessage}`);
3871
4080
  }
3872
4081
  }
3873
- const cursorMcpPath = (0, import_node_path17.join)(baseDir, ".cursor", "mcp.json");
4082
+ const cursorMcpPath = (0, import_node_path15.join)(baseDir, ".cursor", "mcp.json");
3874
4083
  if (await fileExists(cursorMcpPath)) {
3875
4084
  try {
3876
4085
  const content = await readFileContent(cursorMcpPath);
@@ -3919,11 +4128,11 @@ async function parseGeminiConfiguration(baseDir = process.cwd()) {
3919
4128
  }
3920
4129
 
3921
4130
  // src/parsers/junie.ts
3922
- var import_node_path18 = require("path");
4131
+ var import_node_path16 = require("path");
3923
4132
  async function parseJunieConfiguration(baseDir = process.cwd()) {
3924
4133
  const errors = [];
3925
4134
  const rules = [];
3926
- const guidelinesPath = (0, import_node_path18.join)(baseDir, ".junie", "guidelines.md");
4135
+ const guidelinesPath = (0, import_node_path16.join)(baseDir, ".junie", "guidelines.md");
3927
4136
  if (!await fileExists(guidelinesPath)) {
3928
4137
  errors.push(".junie/guidelines.md file not found");
3929
4138
  return { rules, errors };
@@ -3974,6 +4183,11 @@ async function parseRooConfiguration(baseDir = process.cwd()) {
3974
4183
  });
3975
4184
  }
3976
4185
 
4186
+ // src/parsers/windsurf.ts
4187
+ var import_promises3 = require("fs/promises");
4188
+ var import_node_path17 = require("path");
4189
+ var import_gray_matter5 = __toESM(require("gray-matter"), 1);
4190
+
3977
4191
  // src/core/importer.ts
3978
4192
  async function importConfiguration(options) {
3979
4193
  const { tool, baseDir = process.cwd(), rulesDir = ".rulesync", verbose = false } = options;
@@ -4058,7 +4272,7 @@ async function importConfiguration(options) {
4058
4272
  if (rules.length === 0 && !ignorePatterns && !mcpServers) {
4059
4273
  return { success: false, rulesCreated: 0, errors };
4060
4274
  }
4061
- const rulesDirPath = (0, import_node_path19.join)(baseDir, rulesDir);
4275
+ const rulesDirPath = (0, import_node_path18.join)(baseDir, rulesDir);
4062
4276
  try {
4063
4277
  const { mkdir: mkdir3 } = await import("fs/promises");
4064
4278
  await mkdir3(rulesDirPath, { recursive: true });
@@ -4072,7 +4286,7 @@ async function importConfiguration(options) {
4072
4286
  try {
4073
4287
  const baseFilename = rule.filename;
4074
4288
  const filename = await generateUniqueFilename(rulesDirPath, baseFilename);
4075
- const filePath = (0, import_node_path19.join)(rulesDirPath, `${filename}.md`);
4289
+ const filePath = (0, import_node_path18.join)(rulesDirPath, `${filename}.md`);
4076
4290
  const content = generateRuleFileContent(rule);
4077
4291
  await writeFileContent(filePath, content);
4078
4292
  rulesCreated++;
@@ -4087,7 +4301,7 @@ async function importConfiguration(options) {
4087
4301
  let ignoreFileCreated = false;
4088
4302
  if (ignorePatterns && ignorePatterns.length > 0) {
4089
4303
  try {
4090
- const rulesyncignorePath = (0, import_node_path19.join)(baseDir, ".rulesyncignore");
4304
+ const rulesyncignorePath = (0, import_node_path18.join)(baseDir, ".rulesyncignore");
4091
4305
  const ignoreContent = `${ignorePatterns.join("\n")}
4092
4306
  `;
4093
4307
  await writeFileContent(rulesyncignorePath, ignoreContent);
@@ -4103,7 +4317,7 @@ async function importConfiguration(options) {
4103
4317
  let mcpFileCreated = false;
4104
4318
  if (mcpServers && Object.keys(mcpServers).length > 0) {
4105
4319
  try {
4106
- const mcpPath = (0, import_node_path19.join)(baseDir, rulesDir, ".mcp.json");
4320
+ const mcpPath = (0, import_node_path18.join)(baseDir, rulesDir, ".mcp.json");
4107
4321
  const mcpContent = `${JSON.stringify({ mcpServers }, null, 2)}
4108
4322
  `;
4109
4323
  await writeFileContent(mcpPath, mcpContent);
@@ -4125,13 +4339,13 @@ async function importConfiguration(options) {
4125
4339
  };
4126
4340
  }
4127
4341
  function generateRuleFileContent(rule) {
4128
- const frontmatter = import_gray_matter5.default.stringify("", rule.frontmatter);
4342
+ const frontmatter = import_gray_matter6.default.stringify("", rule.frontmatter);
4129
4343
  return frontmatter + rule.content;
4130
4344
  }
4131
4345
  async function generateUniqueFilename(rulesDir, baseFilename) {
4132
4346
  let filename = baseFilename;
4133
4347
  let counter = 1;
4134
- while (await fileExists((0, import_node_path19.join)(rulesDir, `${filename}.md`))) {
4348
+ while (await fileExists((0, import_node_path18.join)(rulesDir, `${filename}.md`))) {
4135
4349
  filename = `${baseFilename}-${counter}`;
4136
4350
  counter++;
4137
4351
  }
@@ -4198,7 +4412,7 @@ async function importCommand(options = {}) {
4198
4412
  }
4199
4413
 
4200
4414
  // src/cli/commands/init.ts
4201
- var import_node_path20 = require("path");
4415
+ var import_node_path19 = require("path");
4202
4416
  async function initCommand() {
4203
4417
  const aiRulesDir = ".rulesync";
4204
4418
  console.log("Initializing rulesync...");
@@ -4245,7 +4459,7 @@ globs: ["**/*"]
4245
4459
  - Follow single responsibility principle
4246
4460
  `
4247
4461
  };
4248
- const filepath = (0, import_node_path20.join)(aiRulesDir, sampleFile.filename);
4462
+ const filepath = (0, import_node_path19.join)(aiRulesDir, sampleFile.filename);
4249
4463
  if (!await fileExists(filepath)) {
4250
4464
  await writeFileContent(filepath, sampleFile.content);
4251
4465
  console.log(`Created ${filepath}`);
@@ -4389,7 +4603,7 @@ async function watchCommand() {
4389
4603
 
4390
4604
  // src/cli/index.ts
4391
4605
  var program = new import_commander.Command();
4392
- program.name("rulesync").description("Unified AI rules management CLI tool").version("0.55.0");
4606
+ program.name("rulesync").description("Unified AI rules management CLI tool").version("0.56.0");
4393
4607
  program.command("init").description("Initialize rulesync in current directory").action(initCommand);
4394
4608
  program.command("add <filename>").description("Add a new rule file").action(addCommand);
4395
4609
  program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);