rulesync 3.19.0 → 3.20.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 (4) hide show
  1. package/README.md +52 -0
  2. package/dist/index.cjs +1218 -615
  3. package/dist/index.js +1060 -457
  4. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -84,9 +84,9 @@ var logger = new Logger();
84
84
  // src/cli/commands/generate.ts
85
85
  import { intersection } from "es-toolkit";
86
86
 
87
- // src/commands/commands-processor.ts
88
- import { basename as basename11, join as join11 } from "path";
89
- import { z as z9 } from "zod/mini";
87
+ // src/config/config-resolver.ts
88
+ import { resolve as resolve2 } from "path";
89
+ import { parse as parseJsonc } from "jsonc-parser";
90
90
 
91
91
  // src/utils/file.ts
92
92
  import { globSync } from "fs";
@@ -109,14 +109,24 @@ async function readOrInitializeFileContent(filePath, initialContent = "") {
109
109
  return initialContent;
110
110
  }
111
111
  }
112
- function resolvePath(relativePath, baseDir) {
113
- if (!baseDir) return relativePath;
114
- const resolved = resolve(baseDir, relativePath);
115
- const rel = relative(baseDir, resolved);
112
+ function checkPathTraversal({
113
+ relativePath,
114
+ intendedRootDir
115
+ }) {
116
+ const segments = relativePath.split(/[/\\]/);
117
+ if (segments.includes("..")) {
118
+ throw new Error(`Path traversal detected: ${relativePath}`);
119
+ }
120
+ const resolved = resolve(intendedRootDir, relativePath);
121
+ const rel = relative(intendedRootDir, resolved);
116
122
  if (rel.startsWith("..") || resolve(resolved) !== resolved) {
117
123
  throw new Error(`Path traversal detected: ${relativePath}`);
118
124
  }
119
- return resolved;
125
+ }
126
+ function resolvePath(relativePath, baseDir) {
127
+ if (!baseDir) return relativePath;
128
+ checkPathTraversal({ relativePath, intendedRootDir: baseDir });
129
+ return resolve(baseDir, relativePath);
120
130
  }
121
131
  async function directoryExists(dirPath) {
122
132
  try {
@@ -179,16 +189,252 @@ function validateBaseDir(baseDir) {
179
189
  if (baseDir.trim() === "") {
180
190
  throw new Error("baseDir cannot be an empty string");
181
191
  }
182
- if (baseDir.includes("..")) {
183
- throw new Error(`baseDir cannot contain directory traversal (..): ${baseDir}`);
192
+ checkPathTraversal({ relativePath: baseDir, intendedRootDir: process.cwd() });
193
+ }
194
+
195
+ // src/config/config.ts
196
+ import { optional, z as z3 } from "zod/mini";
197
+
198
+ // src/types/tool-targets.ts
199
+ import { z as z2 } from "zod/mini";
200
+ var ALL_TOOL_TARGETS = [
201
+ "agentsmd",
202
+ "amazonqcli",
203
+ "augmentcode",
204
+ "augmentcode-legacy",
205
+ "copilot",
206
+ "cursor",
207
+ "cline",
208
+ "claudecode",
209
+ "codexcli",
210
+ "opencode",
211
+ "qwencode",
212
+ "roo",
213
+ "geminicli",
214
+ "kiro",
215
+ "junie",
216
+ "warp",
217
+ "windsurf"
218
+ ];
219
+ var ALL_TOOL_TARGETS_WITH_WILDCARD = [...ALL_TOOL_TARGETS, "*"];
220
+ var ToolTargetSchema = z2.enum(ALL_TOOL_TARGETS);
221
+ var ToolTargetsSchema = z2.array(ToolTargetSchema);
222
+ var RulesyncTargetsSchema = z2.array(z2.enum(ALL_TOOL_TARGETS_WITH_WILDCARD));
223
+
224
+ // src/config/config.ts
225
+ var ConfigParamsSchema = z3.object({
226
+ baseDirs: z3.array(z3.string()),
227
+ targets: RulesyncTargetsSchema,
228
+ features: RulesyncFeaturesSchema,
229
+ verbose: z3.boolean(),
230
+ delete: z3.boolean(),
231
+ // New non-experimental options
232
+ global: optional(z3.boolean()),
233
+ simulatedCommands: optional(z3.boolean()),
234
+ simulatedSubagents: optional(z3.boolean()),
235
+ modularMcp: optional(z3.boolean()),
236
+ // Deprecated experimental options (for backward compatibility)
237
+ experimentalGlobal: optional(z3.boolean()),
238
+ experimentalSimulateCommands: optional(z3.boolean()),
239
+ experimentalSimulateSubagents: optional(z3.boolean())
240
+ });
241
+ var PartialConfigParamsSchema = z3.partial(ConfigParamsSchema);
242
+ var RequiredConfigParamsSchema = z3.required(ConfigParamsSchema);
243
+ var Config = class {
244
+ baseDirs;
245
+ targets;
246
+ features;
247
+ verbose;
248
+ delete;
249
+ global;
250
+ simulatedCommands;
251
+ simulatedSubagents;
252
+ modularMcp;
253
+ constructor({
254
+ baseDirs,
255
+ targets,
256
+ features,
257
+ verbose,
258
+ delete: isDelete,
259
+ global,
260
+ simulatedCommands,
261
+ simulatedSubagents,
262
+ modularMcp,
263
+ experimentalGlobal,
264
+ experimentalSimulateCommands,
265
+ experimentalSimulateSubagents
266
+ }) {
267
+ this.baseDirs = baseDirs;
268
+ this.targets = targets;
269
+ this.features = features;
270
+ this.verbose = verbose;
271
+ this.delete = isDelete;
272
+ this.global = global ?? experimentalGlobal ?? false;
273
+ this.simulatedCommands = simulatedCommands ?? experimentalSimulateCommands ?? false;
274
+ this.simulatedSubagents = simulatedSubagents ?? experimentalSimulateSubagents ?? false;
275
+ this.modularMcp = modularMcp ?? false;
276
+ }
277
+ getBaseDirs() {
278
+ return this.baseDirs;
279
+ }
280
+ getTargets() {
281
+ if (this.targets.includes("*")) {
282
+ return [...ALL_TOOL_TARGETS];
283
+ }
284
+ return this.targets.filter((target) => target !== "*");
285
+ }
286
+ getFeatures() {
287
+ if (this.features.includes("*")) {
288
+ return [...ALL_FEATURES];
289
+ }
290
+ return this.features.filter((feature) => feature !== "*");
291
+ }
292
+ getVerbose() {
293
+ return this.verbose;
294
+ }
295
+ getDelete() {
296
+ return this.delete;
297
+ }
298
+ getGlobal() {
299
+ return this.global;
300
+ }
301
+ getSimulatedCommands() {
302
+ return this.simulatedCommands;
303
+ }
304
+ getSimulatedSubagents() {
305
+ return this.simulatedSubagents;
306
+ }
307
+ getModularMcp() {
308
+ return this.modularMcp;
309
+ }
310
+ // Deprecated getters for backward compatibility
311
+ /** @deprecated Use getGlobal() instead */
312
+ getExperimentalGlobal() {
313
+ return this.global;
314
+ }
315
+ /** @deprecated Use getSimulatedCommands() instead */
316
+ getExperimentalSimulateCommands() {
317
+ return this.simulatedCommands;
318
+ }
319
+ /** @deprecated Use getSimulatedSubagents() instead */
320
+ getExperimentalSimulateSubagents() {
321
+ return this.simulatedSubagents;
322
+ }
323
+ };
324
+
325
+ // src/config/config-resolver.ts
326
+ var defaults = {
327
+ targets: ["agentsmd"],
328
+ features: ["rules"],
329
+ verbose: false,
330
+ delete: false,
331
+ baseDirs: [process.cwd()],
332
+ configPath: "rulesync.jsonc",
333
+ global: false,
334
+ simulatedCommands: false,
335
+ simulatedSubagents: false,
336
+ modularMcp: false,
337
+ experimentalGlobal: false,
338
+ experimentalSimulateCommands: false,
339
+ experimentalSimulateSubagents: false
340
+ };
341
+ var ConfigResolver = class {
342
+ static async resolve({
343
+ targets,
344
+ features,
345
+ verbose,
346
+ delete: isDelete,
347
+ baseDirs,
348
+ configPath = defaults.configPath,
349
+ global,
350
+ simulatedCommands,
351
+ simulatedSubagents,
352
+ modularMcp,
353
+ experimentalGlobal,
354
+ experimentalSimulateCommands,
355
+ experimentalSimulateSubagents
356
+ }) {
357
+ const validatedConfigPath = resolvePath(configPath, process.cwd());
358
+ let configByFile = {};
359
+ if (await fileExists(validatedConfigPath)) {
360
+ try {
361
+ const fileContent = await readFileContent(validatedConfigPath);
362
+ const jsonData = parseJsonc(fileContent);
363
+ configByFile = PartialConfigParamsSchema.parse(jsonData);
364
+ } catch (error) {
365
+ logger.error(`Failed to load config file: ${formatError(error)}`);
366
+ throw error;
367
+ }
368
+ }
369
+ const deprecatedGlobal = experimentalGlobal ?? configByFile.experimentalGlobal;
370
+ const deprecatedCommands = experimentalSimulateCommands ?? configByFile.experimentalSimulateCommands;
371
+ const deprecatedSubagents = experimentalSimulateSubagents ?? configByFile.experimentalSimulateSubagents;
372
+ if (deprecatedGlobal !== void 0) {
373
+ warnDeprecatedOptions({ experimentalGlobal: deprecatedGlobal });
374
+ }
375
+ if (deprecatedCommands !== void 0) {
376
+ warnDeprecatedOptions({ experimentalSimulateCommands: deprecatedCommands });
377
+ }
378
+ if (deprecatedSubagents !== void 0) {
379
+ warnDeprecatedOptions({ experimentalSimulateSubagents: deprecatedSubagents });
380
+ }
381
+ const resolvedGlobal = global ?? configByFile.global ?? experimentalGlobal ?? configByFile.experimentalGlobal ?? defaults.global;
382
+ const resolvedSimulatedCommands = simulatedCommands ?? configByFile.simulatedCommands ?? experimentalSimulateCommands ?? configByFile.experimentalSimulateCommands ?? defaults.simulatedCommands;
383
+ const resolvedSimulatedSubagents = simulatedSubagents ?? configByFile.simulatedSubagents ?? experimentalSimulateSubagents ?? configByFile.experimentalSimulateSubagents ?? defaults.simulatedSubagents;
384
+ const configParams = {
385
+ targets: targets ?? configByFile.targets ?? defaults.targets,
386
+ features: features ?? configByFile.features ?? defaults.features,
387
+ verbose: verbose ?? configByFile.verbose ?? defaults.verbose,
388
+ delete: isDelete ?? configByFile.delete ?? defaults.delete,
389
+ baseDirs: getBaseDirsInLightOfGlobal({
390
+ baseDirs: baseDirs ?? configByFile.baseDirs ?? defaults.baseDirs,
391
+ global: resolvedGlobal
392
+ }),
393
+ global: resolvedGlobal,
394
+ simulatedCommands: resolvedSimulatedCommands,
395
+ simulatedSubagents: resolvedSimulatedSubagents,
396
+ modularMcp: modularMcp ?? configByFile.modularMcp ?? defaults.modularMcp
397
+ };
398
+ return new Config(configParams);
399
+ }
400
+ };
401
+ function warnDeprecatedOptions({
402
+ experimentalGlobal,
403
+ experimentalSimulateCommands,
404
+ experimentalSimulateSubagents
405
+ }) {
406
+ if (experimentalGlobal !== void 0) {
407
+ logger.warn("'experimentalGlobal' option is deprecated. Please use 'global' instead.");
408
+ }
409
+ if (experimentalSimulateCommands !== void 0) {
410
+ logger.warn(
411
+ "'experimentalSimulateCommands' option is deprecated. Please use 'simulatedCommands' instead."
412
+ );
413
+ }
414
+ if (experimentalSimulateSubagents !== void 0) {
415
+ logger.warn(
416
+ "'experimentalSimulateSubagents' option is deprecated. Please use 'simulatedSubagents' instead."
417
+ );
184
418
  }
185
- const normalized = resolve(baseDir);
186
- const rel = relative(process.cwd(), normalized);
187
- if (rel.startsWith("..")) {
188
- throw new Error(`baseDir cannot contain directory traversal (..): ${baseDir}`);
419
+ }
420
+ function getBaseDirsInLightOfGlobal({
421
+ baseDirs,
422
+ global
423
+ }) {
424
+ if (global) {
425
+ return [getHomeDirectory()];
189
426
  }
427
+ const resolvedBaseDirs = baseDirs.map((baseDir) => resolve2(baseDir));
428
+ resolvedBaseDirs.forEach((baseDir) => {
429
+ validateBaseDir(baseDir);
430
+ });
431
+ return resolvedBaseDirs;
190
432
  }
191
433
 
434
+ // src/features/commands/commands-processor.ts
435
+ import { basename as basename11, join as join11 } from "path";
436
+ import { z as z10 } from "zod/mini";
437
+
192
438
  // src/types/feature-processor.ts
193
439
  var FeatureProcessor = class {
194
440
  baseDir;
@@ -219,7 +465,7 @@ var FeatureProcessor = class {
219
465
  }
220
466
  };
221
467
 
222
- // src/commands/agentsmd-command.ts
468
+ // src/features/commands/agentsmd-command.ts
223
469
  import { basename as basename3, join as join3 } from "path";
224
470
 
225
471
  // src/utils/frontmatter.ts
@@ -271,12 +517,12 @@ function parseFrontmatter(content) {
271
517
  return { frontmatter, body };
272
518
  }
273
519
 
274
- // src/commands/simulated-command.ts
520
+ // src/features/commands/simulated-command.ts
275
521
  import { basename as basename2, join as join2 } from "path";
276
- import { z as z2 } from "zod/mini";
522
+ import { z as z4 } from "zod/mini";
277
523
 
278
524
  // src/types/ai-file.ts
279
- import path, { relative as relative2, resolve as resolve2 } from "path";
525
+ import path, { relative as relative2, resolve as resolve3 } from "path";
280
526
  var AiFile = class {
281
527
  /**
282
528
  * @example "."
@@ -332,8 +578,8 @@ var AiFile = class {
332
578
  }
333
579
  getFilePath() {
334
580
  const fullPath = path.join(this.baseDir, this.relativeDirPath, this.relativeFilePath);
335
- const resolvedFull = resolve2(fullPath);
336
- const resolvedBase = resolve2(this.baseDir);
581
+ const resolvedFull = resolve3(fullPath);
582
+ const resolvedBase = resolve3(this.baseDir);
337
583
  const rel = relative2(resolvedBase, resolvedFull);
338
584
  if (rel.startsWith("..") || path.isAbsolute(rel)) {
339
585
  throw new Error(
@@ -353,7 +599,7 @@ var AiFile = class {
353
599
  }
354
600
  };
355
601
 
356
- // src/commands/tool-command.ts
602
+ // src/features/commands/tool-command.ts
357
603
  var ToolCommand = class extends AiFile {
358
604
  static getSettablePaths() {
359
605
  throw new Error("Please implement this method in the subclass.");
@@ -423,9 +669,9 @@ var ToolCommand = class extends AiFile {
423
669
  }
424
670
  };
425
671
 
426
- // src/commands/simulated-command.ts
427
- var SimulatedCommandFrontmatterSchema = z2.object({
428
- description: z2.string()
672
+ // src/features/commands/simulated-command.ts
673
+ var SimulatedCommandFrontmatterSchema = z4.object({
674
+ description: z4.string()
429
675
  });
430
676
  var SimulatedCommand = class _SimulatedCommand extends ToolCommand {
431
677
  frontmatter;
@@ -517,7 +763,7 @@ var SimulatedCommand = class _SimulatedCommand extends ToolCommand {
517
763
  }
518
764
  };
519
765
 
520
- // src/commands/agentsmd-command.ts
766
+ // src/features/commands/agentsmd-command.ts
521
767
  var AgentsmdCommand = class _AgentsmdCommand extends SimulatedCommand {
522
768
  static getSettablePaths() {
523
769
  return {
@@ -566,13 +812,13 @@ var AgentsmdCommand = class _AgentsmdCommand extends SimulatedCommand {
566
812
  }
567
813
  };
568
814
 
569
- // src/commands/claudecode-command.ts
815
+ // src/features/commands/claudecode-command.ts
570
816
  import { basename as basename5, join as join5 } from "path";
571
- import { z as z5 } from "zod/mini";
817
+ import { z as z6 } from "zod/mini";
572
818
 
573
- // src/commands/rulesync-command.ts
819
+ // src/features/commands/rulesync-command.ts
574
820
  import { basename as basename4, join as join4 } from "path";
575
- import { z as z4 } from "zod/mini";
821
+ import { z as z5 } from "zod/mini";
576
822
 
577
823
  // src/types/rulesync-file.ts
578
824
  var RulesyncFile = class extends AiFile {
@@ -584,36 +830,10 @@ var RulesyncFile = class extends AiFile {
584
830
  }
585
831
  };
586
832
 
587
- // src/types/tool-targets.ts
588
- import { z as z3 } from "zod/mini";
589
- var ALL_TOOL_TARGETS = [
590
- "agentsmd",
591
- "amazonqcli",
592
- "augmentcode",
593
- "augmentcode-legacy",
594
- "copilot",
595
- "cursor",
596
- "cline",
597
- "claudecode",
598
- "codexcli",
599
- "opencode",
600
- "qwencode",
601
- "roo",
602
- "geminicli",
603
- "kiro",
604
- "junie",
605
- "warp",
606
- "windsurf"
607
- ];
608
- var ALL_TOOL_TARGETS_WITH_WILDCARD = [...ALL_TOOL_TARGETS, "*"];
609
- var ToolTargetSchema = z3.enum(ALL_TOOL_TARGETS);
610
- var ToolTargetsSchema = z3.array(ToolTargetSchema);
611
- var RulesyncTargetsSchema = z3.array(z3.enum(ALL_TOOL_TARGETS_WITH_WILDCARD));
612
-
613
- // src/commands/rulesync-command.ts
614
- var RulesyncCommandFrontmatterSchema = z4.object({
833
+ // src/features/commands/rulesync-command.ts
834
+ var RulesyncCommandFrontmatterSchema = z5.object({
615
835
  targets: RulesyncTargetsSchema,
616
- description: z4.string()
836
+ description: z5.string()
617
837
  });
618
838
  var RulesyncCommand = class _RulesyncCommand extends RulesyncFile {
619
839
  frontmatter;
@@ -664,9 +884,12 @@ var RulesyncCommand = class _RulesyncCommand extends RulesyncFile {
664
884
  static async fromFile({
665
885
  relativeFilePath
666
886
  }) {
667
- const fileContent = await readFileContent(
668
- join4(_RulesyncCommand.getSettablePaths().relativeDirPath, relativeFilePath)
887
+ const filePath = join4(
888
+ process.cwd(),
889
+ _RulesyncCommand.getSettablePaths().relativeDirPath,
890
+ relativeFilePath
669
891
  );
892
+ const fileContent = await readFileContent(filePath);
670
893
  const { frontmatter, body: content } = parseFrontmatter(fileContent);
671
894
  const result = RulesyncCommandFrontmatterSchema.safeParse(frontmatter);
672
895
  if (!result.success) {
@@ -684,9 +907,9 @@ var RulesyncCommand = class _RulesyncCommand extends RulesyncFile {
684
907
  }
685
908
  };
686
909
 
687
- // src/commands/claudecode-command.ts
688
- var ClaudecodeCommandFrontmatterSchema = z5.object({
689
- description: z5.string()
910
+ // src/features/commands/claudecode-command.ts
911
+ var ClaudecodeCommandFrontmatterSchema = z6.object({
912
+ description: z6.string()
690
913
  });
691
914
  var ClaudecodeCommand = class _ClaudecodeCommand extends ToolCommand {
692
915
  frontmatter;
@@ -803,7 +1026,7 @@ var ClaudecodeCommand = class _ClaudecodeCommand extends ToolCommand {
803
1026
  }
804
1027
  };
805
1028
 
806
- // src/commands/codexcli-command.ts
1029
+ // src/features/commands/codexcli-command.ts
807
1030
  import { basename as basename6, join as join6 } from "path";
808
1031
  var CodexcliCommand = class _CodexcliCommand extends ToolCommand {
809
1032
  static getSettablePaths({ global } = {}) {
@@ -877,12 +1100,12 @@ var CodexcliCommand = class _CodexcliCommand extends ToolCommand {
877
1100
  }
878
1101
  };
879
1102
 
880
- // src/commands/copilot-command.ts
1103
+ // src/features/commands/copilot-command.ts
881
1104
  import { basename as basename7, join as join7 } from "path";
882
- import { z as z6 } from "zod/mini";
883
- var CopilotCommandFrontmatterSchema = z6.object({
884
- mode: z6.literal("agent"),
885
- description: z6.string()
1105
+ import { z as z7 } from "zod/mini";
1106
+ var CopilotCommandFrontmatterSchema = z7.object({
1107
+ mode: z7.literal("agent"),
1108
+ description: z7.string()
886
1109
  });
887
1110
  var CopilotCommand = class _CopilotCommand extends ToolCommand {
888
1111
  frontmatter;
@@ -1000,7 +1223,7 @@ var CopilotCommand = class _CopilotCommand extends ToolCommand {
1000
1223
  }
1001
1224
  };
1002
1225
 
1003
- // src/commands/cursor-command.ts
1226
+ // src/features/commands/cursor-command.ts
1004
1227
  import { basename as basename8, join as join8 } from "path";
1005
1228
  var CursorCommand = class _CursorCommand extends ToolCommand {
1006
1229
  static getSettablePaths(_options = {}) {
@@ -1071,13 +1294,13 @@ var CursorCommand = class _CursorCommand extends ToolCommand {
1071
1294
  }
1072
1295
  };
1073
1296
 
1074
- // src/commands/geminicli-command.ts
1297
+ // src/features/commands/geminicli-command.ts
1075
1298
  import { basename as basename9, join as join9 } from "path";
1076
1299
  import { parse as parseToml } from "smol-toml";
1077
- import { z as z7 } from "zod/mini";
1078
- var GeminiCliCommandFrontmatterSchema = z7.object({
1079
- description: z7.optional(z7.string()),
1080
- prompt: z7.string()
1300
+ import { z as z8 } from "zod/mini";
1301
+ var GeminiCliCommandFrontmatterSchema = z8.object({
1302
+ description: z8.optional(z8.string()),
1303
+ prompt: z8.string()
1081
1304
  });
1082
1305
  var GeminiCliCommand = class _GeminiCliCommand extends ToolCommand {
1083
1306
  frontmatter;
@@ -1193,12 +1416,12 @@ ${geminiFrontmatter.prompt}
1193
1416
  }
1194
1417
  };
1195
1418
 
1196
- // src/commands/roo-command.ts
1419
+ // src/features/commands/roo-command.ts
1197
1420
  import { basename as basename10, join as join10 } from "path";
1198
- import { optional, z as z8 } from "zod/mini";
1199
- var RooCommandFrontmatterSchema = z8.object({
1200
- description: z8.string(),
1201
- "argument-hint": optional(z8.string())
1421
+ import { optional as optional2, z as z9 } from "zod/mini";
1422
+ var RooCommandFrontmatterSchema = z9.object({
1423
+ description: z9.string(),
1424
+ "argument-hint": optional2(z9.string())
1202
1425
  });
1203
1426
  var RooCommand = class _RooCommand extends ToolCommand {
1204
1427
  frontmatter;
@@ -1314,7 +1537,7 @@ var RooCommand = class _RooCommand extends ToolCommand {
1314
1537
  }
1315
1538
  };
1316
1539
 
1317
- // src/commands/commands-processor.ts
1540
+ // src/features/commands/commands-processor.ts
1318
1541
  var commandsProcessorToolTargets = [
1319
1542
  "agentsmd",
1320
1543
  "claudecode",
@@ -1323,7 +1546,7 @@ var commandsProcessorToolTargets = [
1323
1546
  "copilot",
1324
1547
  "cursor"
1325
1548
  ];
1326
- var CommandsProcessorToolTargetSchema = z9.enum(
1549
+ var CommandsProcessorToolTargetSchema = z10.enum(
1327
1550
  // codexcli is not in the list of tool targets but we add it here because it is a valid tool target for global mode generation
1328
1551
  commandsProcessorToolTargets.concat("codexcli")
1329
1552
  );
@@ -1632,232 +1855,17 @@ var CommandsProcessor = class extends FeatureProcessor {
1632
1855
  }
1633
1856
  };
1634
1857
 
1635
- // src/config/config-resolver.ts
1636
- import { resolve as resolve3 } from "path";
1637
- import { parse as parseJsonc } from "jsonc-parser";
1638
-
1639
- // src/config/config.ts
1640
- import { optional as optional2, z as z10 } from "zod/mini";
1641
- var ConfigParamsSchema = z10.object({
1642
- baseDirs: z10.array(z10.string()),
1643
- targets: RulesyncTargetsSchema,
1644
- features: RulesyncFeaturesSchema,
1645
- verbose: z10.boolean(),
1646
- delete: z10.boolean(),
1647
- // New non-experimental options
1648
- global: optional2(z10.boolean()),
1649
- simulatedCommands: optional2(z10.boolean()),
1650
- simulatedSubagents: optional2(z10.boolean()),
1651
- modularMcp: optional2(z10.boolean()),
1652
- // Deprecated experimental options (for backward compatibility)
1653
- experimentalGlobal: optional2(z10.boolean()),
1654
- experimentalSimulateCommands: optional2(z10.boolean()),
1655
- experimentalSimulateSubagents: optional2(z10.boolean())
1656
- });
1657
- var PartialConfigParamsSchema = z10.partial(ConfigParamsSchema);
1658
- var RequiredConfigParamsSchema = z10.required(ConfigParamsSchema);
1659
- var Config = class {
1660
- baseDirs;
1661
- targets;
1662
- features;
1663
- verbose;
1664
- delete;
1665
- global;
1666
- simulatedCommands;
1667
- simulatedSubagents;
1668
- modularMcp;
1669
- constructor({
1670
- baseDirs,
1671
- targets,
1672
- features,
1673
- verbose,
1674
- delete: isDelete,
1675
- global,
1676
- simulatedCommands,
1677
- simulatedSubagents,
1678
- modularMcp,
1679
- experimentalGlobal,
1680
- experimentalSimulateCommands,
1681
- experimentalSimulateSubagents
1682
- }) {
1683
- this.baseDirs = baseDirs;
1684
- this.targets = targets;
1685
- this.features = features;
1686
- this.verbose = verbose;
1687
- this.delete = isDelete;
1688
- this.global = global ?? experimentalGlobal ?? false;
1689
- this.simulatedCommands = simulatedCommands ?? experimentalSimulateCommands ?? false;
1690
- this.simulatedSubagents = simulatedSubagents ?? experimentalSimulateSubagents ?? false;
1691
- this.modularMcp = modularMcp ?? false;
1692
- }
1693
- getBaseDirs() {
1694
- return this.baseDirs;
1695
- }
1696
- getTargets() {
1697
- if (this.targets.includes("*")) {
1698
- return [...ALL_TOOL_TARGETS];
1699
- }
1700
- return this.targets.filter((target) => target !== "*");
1701
- }
1702
- getFeatures() {
1703
- if (this.features.includes("*")) {
1704
- return [...ALL_FEATURES];
1705
- }
1706
- return this.features.filter((feature) => feature !== "*");
1707
- }
1708
- getVerbose() {
1709
- return this.verbose;
1710
- }
1711
- getDelete() {
1712
- return this.delete;
1713
- }
1714
- getGlobal() {
1715
- return this.global;
1716
- }
1717
- getSimulatedCommands() {
1718
- return this.simulatedCommands;
1719
- }
1720
- getSimulatedSubagents() {
1721
- return this.simulatedSubagents;
1722
- }
1723
- getModularMcp() {
1724
- return this.modularMcp;
1725
- }
1726
- // Deprecated getters for backward compatibility
1727
- /** @deprecated Use getGlobal() instead */
1728
- getExperimentalGlobal() {
1729
- return this.global;
1730
- }
1731
- /** @deprecated Use getSimulatedCommands() instead */
1732
- getExperimentalSimulateCommands() {
1733
- return this.simulatedCommands;
1734
- }
1735
- /** @deprecated Use getSimulatedSubagents() instead */
1736
- getExperimentalSimulateSubagents() {
1737
- return this.simulatedSubagents;
1738
- }
1739
- };
1740
-
1741
- // src/config/config-resolver.ts
1742
- var defaults = {
1743
- targets: ["agentsmd"],
1744
- features: ["rules"],
1745
- verbose: false,
1746
- delete: false,
1747
- baseDirs: [process.cwd()],
1748
- configPath: "rulesync.jsonc",
1749
- global: false,
1750
- simulatedCommands: false,
1751
- simulatedSubagents: false,
1752
- modularMcp: false,
1753
- experimentalGlobal: false,
1754
- experimentalSimulateCommands: false,
1755
- experimentalSimulateSubagents: false
1756
- };
1757
- var ConfigResolver = class {
1758
- static async resolve({
1759
- targets,
1760
- features,
1761
- verbose,
1762
- delete: isDelete,
1763
- baseDirs,
1764
- configPath = defaults.configPath,
1765
- global,
1766
- simulatedCommands,
1767
- simulatedSubagents,
1768
- modularMcp,
1769
- experimentalGlobal,
1770
- experimentalSimulateCommands,
1771
- experimentalSimulateSubagents
1772
- }) {
1773
- const validatedConfigPath = resolvePath(configPath, process.cwd());
1774
- let configByFile = {};
1775
- if (await fileExists(validatedConfigPath)) {
1776
- try {
1777
- const fileContent = await readFileContent(validatedConfigPath);
1778
- const jsonData = parseJsonc(fileContent);
1779
- configByFile = PartialConfigParamsSchema.parse(jsonData);
1780
- } catch (error) {
1781
- logger.error(`Failed to load config file: ${formatError(error)}`);
1782
- throw error;
1783
- }
1784
- }
1785
- const deprecatedGlobal = experimentalGlobal ?? configByFile.experimentalGlobal;
1786
- const deprecatedCommands = experimentalSimulateCommands ?? configByFile.experimentalSimulateCommands;
1787
- const deprecatedSubagents = experimentalSimulateSubagents ?? configByFile.experimentalSimulateSubagents;
1788
- if (deprecatedGlobal !== void 0) {
1789
- warnDeprecatedOptions({ experimentalGlobal: deprecatedGlobal });
1790
- }
1791
- if (deprecatedCommands !== void 0) {
1792
- warnDeprecatedOptions({ experimentalSimulateCommands: deprecatedCommands });
1793
- }
1794
- if (deprecatedSubagents !== void 0) {
1795
- warnDeprecatedOptions({ experimentalSimulateSubagents: deprecatedSubagents });
1796
- }
1797
- const resolvedGlobal = global ?? configByFile.global ?? experimentalGlobal ?? configByFile.experimentalGlobal ?? defaults.global;
1798
- const resolvedSimulatedCommands = simulatedCommands ?? configByFile.simulatedCommands ?? experimentalSimulateCommands ?? configByFile.experimentalSimulateCommands ?? defaults.simulatedCommands;
1799
- const resolvedSimulatedSubagents = simulatedSubagents ?? configByFile.simulatedSubagents ?? experimentalSimulateSubagents ?? configByFile.experimentalSimulateSubagents ?? defaults.simulatedSubagents;
1800
- const configParams = {
1801
- targets: targets ?? configByFile.targets ?? defaults.targets,
1802
- features: features ?? configByFile.features ?? defaults.features,
1803
- verbose: verbose ?? configByFile.verbose ?? defaults.verbose,
1804
- delete: isDelete ?? configByFile.delete ?? defaults.delete,
1805
- baseDirs: getBaseDirsInLightOfGlobal({
1806
- baseDirs: baseDirs ?? configByFile.baseDirs ?? defaults.baseDirs,
1807
- global: resolvedGlobal
1808
- }),
1809
- global: resolvedGlobal,
1810
- simulatedCommands: resolvedSimulatedCommands,
1811
- simulatedSubagents: resolvedSimulatedSubagents,
1812
- modularMcp: modularMcp ?? configByFile.modularMcp ?? defaults.modularMcp
1813
- };
1814
- return new Config(configParams);
1815
- }
1816
- };
1817
- function warnDeprecatedOptions({
1818
- experimentalGlobal,
1819
- experimentalSimulateCommands,
1820
- experimentalSimulateSubagents
1821
- }) {
1822
- if (experimentalGlobal !== void 0) {
1823
- logger.warn("'experimentalGlobal' option is deprecated. Please use 'global' instead.");
1824
- }
1825
- if (experimentalSimulateCommands !== void 0) {
1826
- logger.warn(
1827
- "'experimentalSimulateCommands' option is deprecated. Please use 'simulatedCommands' instead."
1828
- );
1829
- }
1830
- if (experimentalSimulateSubagents !== void 0) {
1831
- logger.warn(
1832
- "'experimentalSimulateSubagents' option is deprecated. Please use 'simulatedSubagents' instead."
1833
- );
1834
- }
1835
- }
1836
- function getBaseDirsInLightOfGlobal({
1837
- baseDirs,
1838
- global
1839
- }) {
1840
- if (global) {
1841
- return [getHomeDirectory()];
1842
- }
1843
- const resolvedBaseDirs = baseDirs.map((baseDir) => resolve3(baseDir));
1844
- resolvedBaseDirs.forEach((baseDir) => {
1845
- validateBaseDir(baseDir);
1846
- });
1847
- return resolvedBaseDirs;
1848
- }
1849
-
1850
- // src/ignore/ignore-processor.ts
1858
+ // src/features/ignore/ignore-processor.ts
1851
1859
  import { z as z11 } from "zod/mini";
1852
1860
 
1853
- // src/ignore/amazonqcli-ignore.ts
1861
+ // src/features/ignore/amazonqcli-ignore.ts
1854
1862
  import { join as join13 } from "path";
1855
1863
 
1856
1864
  // src/types/tool-file.ts
1857
1865
  var ToolFile = class extends AiFile {
1858
1866
  };
1859
1867
 
1860
- // src/ignore/rulesync-ignore.ts
1868
+ // src/features/ignore/rulesync-ignore.ts
1861
1869
  import { join as join12 } from "path";
1862
1870
  var RulesyncIgnore = class _RulesyncIgnore extends RulesyncFile {
1863
1871
  validate() {
@@ -1882,7 +1890,7 @@ var RulesyncIgnore = class _RulesyncIgnore extends RulesyncFile {
1882
1890
  }
1883
1891
  };
1884
1892
 
1885
- // src/ignore/tool-ignore.ts
1893
+ // src/features/ignore/tool-ignore.ts
1886
1894
  var ToolIgnore = class extends ToolFile {
1887
1895
  patterns;
1888
1896
  constructor(params) {
@@ -1923,7 +1931,7 @@ var ToolIgnore = class extends ToolFile {
1923
1931
  }
1924
1932
  };
1925
1933
 
1926
- // src/ignore/amazonqcli-ignore.ts
1934
+ // src/features/ignore/amazonqcli-ignore.ts
1927
1935
  var AmazonqcliIgnore = class _AmazonqcliIgnore extends ToolIgnore {
1928
1936
  static getSettablePaths() {
1929
1937
  return {
@@ -1978,7 +1986,7 @@ var AmazonqcliIgnore = class _AmazonqcliIgnore extends ToolIgnore {
1978
1986
  }
1979
1987
  };
1980
1988
 
1981
- // src/ignore/augmentcode-ignore.ts
1989
+ // src/features/ignore/augmentcode-ignore.ts
1982
1990
  import { join as join14 } from "path";
1983
1991
  var AugmentcodeIgnore = class _AugmentcodeIgnore extends ToolIgnore {
1984
1992
  static getSettablePaths() {
@@ -2033,7 +2041,7 @@ var AugmentcodeIgnore = class _AugmentcodeIgnore extends ToolIgnore {
2033
2041
  }
2034
2042
  };
2035
2043
 
2036
- // src/ignore/claudecode-ignore.ts
2044
+ // src/features/ignore/claudecode-ignore.ts
2037
2045
  import { join as join15 } from "path";
2038
2046
  import { uniq } from "es-toolkit";
2039
2047
  var ClaudecodeIgnore = class _ClaudecodeIgnore extends ToolIgnore {
@@ -2114,7 +2122,7 @@ var ClaudecodeIgnore = class _ClaudecodeIgnore extends ToolIgnore {
2114
2122
  }
2115
2123
  };
2116
2124
 
2117
- // src/ignore/cline-ignore.ts
2125
+ // src/features/ignore/cline-ignore.ts
2118
2126
  import { join as join16 } from "path";
2119
2127
  var ClineIgnore = class _ClineIgnore extends ToolIgnore {
2120
2128
  static getSettablePaths() {
@@ -2168,7 +2176,7 @@ var ClineIgnore = class _ClineIgnore extends ToolIgnore {
2168
2176
  }
2169
2177
  };
2170
2178
 
2171
- // src/ignore/cursor-ignore.ts
2179
+ // src/features/ignore/cursor-ignore.ts
2172
2180
  import { join as join17 } from "path";
2173
2181
  var CursorIgnore = class _CursorIgnore extends ToolIgnore {
2174
2182
  static getSettablePaths() {
@@ -2218,7 +2226,7 @@ var CursorIgnore = class _CursorIgnore extends ToolIgnore {
2218
2226
  }
2219
2227
  };
2220
2228
 
2221
- // src/ignore/geminicli-ignore.ts
2229
+ // src/features/ignore/geminicli-ignore.ts
2222
2230
  import { join as join18 } from "path";
2223
2231
  var GeminiCliIgnore = class _GeminiCliIgnore extends ToolIgnore {
2224
2232
  static getSettablePaths() {
@@ -2262,7 +2270,7 @@ var GeminiCliIgnore = class _GeminiCliIgnore extends ToolIgnore {
2262
2270
  }
2263
2271
  };
2264
2272
 
2265
- // src/ignore/junie-ignore.ts
2273
+ // src/features/ignore/junie-ignore.ts
2266
2274
  import { join as join19 } from "path";
2267
2275
  var JunieIgnore = class _JunieIgnore extends ToolIgnore {
2268
2276
  static getSettablePaths() {
@@ -2306,7 +2314,7 @@ var JunieIgnore = class _JunieIgnore extends ToolIgnore {
2306
2314
  }
2307
2315
  };
2308
2316
 
2309
- // src/ignore/kiro-ignore.ts
2317
+ // src/features/ignore/kiro-ignore.ts
2310
2318
  import { join as join20 } from "path";
2311
2319
  var KiroIgnore = class _KiroIgnore extends ToolIgnore {
2312
2320
  static getSettablePaths() {
@@ -2350,7 +2358,7 @@ var KiroIgnore = class _KiroIgnore extends ToolIgnore {
2350
2358
  }
2351
2359
  };
2352
2360
 
2353
- // src/ignore/qwencode-ignore.ts
2361
+ // src/features/ignore/qwencode-ignore.ts
2354
2362
  import { join as join21 } from "path";
2355
2363
  var QwencodeIgnore = class _QwencodeIgnore extends ToolIgnore {
2356
2364
  static getSettablePaths() {
@@ -2394,7 +2402,7 @@ var QwencodeIgnore = class _QwencodeIgnore extends ToolIgnore {
2394
2402
  }
2395
2403
  };
2396
2404
 
2397
- // src/ignore/roo-ignore.ts
2405
+ // src/features/ignore/roo-ignore.ts
2398
2406
  import { join as join22 } from "path";
2399
2407
  var RooIgnore = class _RooIgnore extends ToolIgnore {
2400
2408
  static getSettablePaths() {
@@ -2438,7 +2446,7 @@ var RooIgnore = class _RooIgnore extends ToolIgnore {
2438
2446
  }
2439
2447
  };
2440
2448
 
2441
- // src/ignore/windsurf-ignore.ts
2449
+ // src/features/ignore/windsurf-ignore.ts
2442
2450
  import { join as join23 } from "path";
2443
2451
  var WindsurfIgnore = class _WindsurfIgnore extends ToolIgnore {
2444
2452
  static getSettablePaths() {
@@ -2482,7 +2490,7 @@ var WindsurfIgnore = class _WindsurfIgnore extends ToolIgnore {
2482
2490
  }
2483
2491
  };
2484
2492
 
2485
- // src/ignore/ignore-processor.ts
2493
+ // src/features/ignore/ignore-processor.ts
2486
2494
  var ignoreProcessorToolTargets = [
2487
2495
  "amazonqcli",
2488
2496
  "augmentcode",
@@ -2670,13 +2678,13 @@ var IgnoreProcessor = class extends FeatureProcessor {
2670
2678
  }
2671
2679
  };
2672
2680
 
2673
- // src/mcp/mcp-processor.ts
2681
+ // src/features/mcp/mcp-processor.ts
2674
2682
  import { z as z13 } from "zod/mini";
2675
2683
 
2676
- // src/mcp/amazonqcli-mcp.ts
2684
+ // src/features/mcp/amazonqcli-mcp.ts
2677
2685
  import { join as join25 } from "path";
2678
2686
 
2679
- // src/mcp/rulesync-mcp.ts
2687
+ // src/features/mcp/rulesync-mcp.ts
2680
2688
  import { join as join24 } from "path";
2681
2689
  import { omit } from "es-toolkit/object";
2682
2690
  import { z as z12 } from "zod/mini";
@@ -2821,7 +2829,7 @@ var RulesyncMcp = class _RulesyncMcp extends RulesyncFile {
2821
2829
  }
2822
2830
  };
2823
2831
 
2824
- // src/mcp/tool-mcp.ts
2832
+ // src/features/mcp/tool-mcp.ts
2825
2833
  var ToolMcp = class extends ToolFile {
2826
2834
  constructor({ ...rest }) {
2827
2835
  super({
@@ -2860,7 +2868,7 @@ var ToolMcp = class extends ToolFile {
2860
2868
  }
2861
2869
  };
2862
2870
 
2863
- // src/mcp/amazonqcli-mcp.ts
2871
+ // src/features/mcp/amazonqcli-mcp.ts
2864
2872
  var AmazonqcliMcp = class _AmazonqcliMcp extends ToolMcp {
2865
2873
  json;
2866
2874
  constructor(params) {
@@ -2916,10 +2924,10 @@ var AmazonqcliMcp = class _AmazonqcliMcp extends ToolMcp {
2916
2924
  }
2917
2925
  };
2918
2926
 
2919
- // src/mcp/claudecode-mcp.ts
2927
+ // src/features/mcp/claudecode-mcp.ts
2920
2928
  import { join as join27 } from "path";
2921
2929
 
2922
- // src/mcp/modular-mcp.ts
2930
+ // src/features/mcp/modular-mcp.ts
2923
2931
  import { join as join26 } from "path";
2924
2932
  var ModularMcp = class _ModularMcp extends AiFile {
2925
2933
  json;
@@ -3007,7 +3015,7 @@ var ModularMcp = class _ModularMcp extends AiFile {
3007
3015
  }
3008
3016
  };
3009
3017
 
3010
- // src/mcp/claudecode-mcp.ts
3018
+ // src/features/mcp/claudecode-mcp.ts
3011
3019
  var ClaudecodeMcp = class _ClaudecodeMcp extends ToolMcp {
3012
3020
  json;
3013
3021
  constructor(params) {
@@ -3088,7 +3096,7 @@ var ClaudecodeMcp = class _ClaudecodeMcp extends ToolMcp {
3088
3096
  }
3089
3097
  };
3090
3098
 
3091
- // src/mcp/cline-mcp.ts
3099
+ // src/features/mcp/cline-mcp.ts
3092
3100
  import { join as join28 } from "path";
3093
3101
  var ClineMcp = class _ClineMcp extends ToolMcp {
3094
3102
  json;
@@ -3145,7 +3153,7 @@ var ClineMcp = class _ClineMcp extends ToolMcp {
3145
3153
  }
3146
3154
  };
3147
3155
 
3148
- // src/mcp/codexcli-mcp.ts
3156
+ // src/features/mcp/codexcli-mcp.ts
3149
3157
  import { join as join29 } from "path";
3150
3158
  import * as smolToml from "smol-toml";
3151
3159
  var CodexcliMcp = class _CodexcliMcp extends ToolMcp {
@@ -3239,7 +3247,7 @@ var CodexcliMcp = class _CodexcliMcp extends ToolMcp {
3239
3247
  }
3240
3248
  };
3241
3249
 
3242
- // src/mcp/copilot-mcp.ts
3250
+ // src/features/mcp/copilot-mcp.ts
3243
3251
  import { join as join30 } from "path";
3244
3252
  var CopilotMcp = class _CopilotMcp extends ToolMcp {
3245
3253
  json;
@@ -3296,7 +3304,7 @@ var CopilotMcp = class _CopilotMcp extends ToolMcp {
3296
3304
  }
3297
3305
  };
3298
3306
 
3299
- // src/mcp/cursor-mcp.ts
3307
+ // src/features/mcp/cursor-mcp.ts
3300
3308
  import { join as join31 } from "path";
3301
3309
  var CursorMcp = class _CursorMcp extends ToolMcp {
3302
3310
  json;
@@ -3364,7 +3372,7 @@ var CursorMcp = class _CursorMcp extends ToolMcp {
3364
3372
  }
3365
3373
  };
3366
3374
 
3367
- // src/mcp/geminicli-mcp.ts
3375
+ // src/features/mcp/geminicli-mcp.ts
3368
3376
  import { join as join32 } from "path";
3369
3377
  var GeminiCliMcp = class _GeminiCliMcp extends ToolMcp {
3370
3378
  json;
@@ -3438,7 +3446,7 @@ var GeminiCliMcp = class _GeminiCliMcp extends ToolMcp {
3438
3446
  }
3439
3447
  };
3440
3448
 
3441
- // src/mcp/roo-mcp.ts
3449
+ // src/features/mcp/roo-mcp.ts
3442
3450
  import { join as join33 } from "path";
3443
3451
  var RooMcp = class _RooMcp extends ToolMcp {
3444
3452
  json;
@@ -3496,7 +3504,7 @@ var RooMcp = class _RooMcp extends ToolMcp {
3496
3504
  }
3497
3505
  };
3498
3506
 
3499
- // src/mcp/mcp-processor.ts
3507
+ // src/features/mcp/mcp-processor.ts
3500
3508
  var mcpProcessorToolTargets = [
3501
3509
  "amazonqcli",
3502
3510
  "claudecode",
@@ -3742,19 +3750,19 @@ var McpProcessor = class extends FeatureProcessor {
3742
3750
  }
3743
3751
  };
3744
3752
 
3745
- // src/rules/rules-processor.ts
3753
+ // src/features/rules/rules-processor.ts
3746
3754
  import { basename as basename17, join as join63 } from "path";
3747
3755
  import { XMLBuilder } from "fast-xml-parser";
3748
3756
  import { z as z22 } from "zod/mini";
3749
3757
 
3750
- // src/subagents/agentsmd-subagent.ts
3758
+ // src/features/subagents/agentsmd-subagent.ts
3751
3759
  import { join as join35 } from "path";
3752
3760
 
3753
- // src/subagents/simulated-subagent.ts
3761
+ // src/features/subagents/simulated-subagent.ts
3754
3762
  import { basename as basename12, join as join34 } from "path";
3755
3763
  import { z as z14 } from "zod/mini";
3756
3764
 
3757
- // src/subagents/tool-subagent.ts
3765
+ // src/features/subagents/tool-subagent.ts
3758
3766
  var ToolSubagent = class extends ToolFile {
3759
3767
  static getSettablePaths() {
3760
3768
  throw new Error("Please implement this method in the subclass.");
@@ -3786,7 +3794,7 @@ var ToolSubagent = class extends ToolFile {
3786
3794
  }
3787
3795
  };
3788
3796
 
3789
- // src/subagents/simulated-subagent.ts
3797
+ // src/features/subagents/simulated-subagent.ts
3790
3798
  var SimulatedSubagentFrontmatterSchema = z14.object({
3791
3799
  name: z14.string(),
3792
3800
  description: z14.string()
@@ -3878,7 +3886,7 @@ var SimulatedSubagent = class extends ToolSubagent {
3878
3886
  }
3879
3887
  };
3880
3888
 
3881
- // src/subagents/agentsmd-subagent.ts
3889
+ // src/features/subagents/agentsmd-subagent.ts
3882
3890
  var AgentsmdSubagent = class _AgentsmdSubagent extends SimulatedSubagent {
3883
3891
  static getSettablePaths() {
3884
3892
  return {
@@ -3901,7 +3909,7 @@ var AgentsmdSubagent = class _AgentsmdSubagent extends SimulatedSubagent {
3901
3909
  }
3902
3910
  };
3903
3911
 
3904
- // src/subagents/codexcli-subagent.ts
3912
+ // src/features/subagents/codexcli-subagent.ts
3905
3913
  import { join as join36 } from "path";
3906
3914
  var CodexCliSubagent = class _CodexCliSubagent extends SimulatedSubagent {
3907
3915
  static getSettablePaths() {
@@ -3925,7 +3933,7 @@ var CodexCliSubagent = class _CodexCliSubagent extends SimulatedSubagent {
3925
3933
  }
3926
3934
  };
3927
3935
 
3928
- // src/subagents/copilot-subagent.ts
3936
+ // src/features/subagents/copilot-subagent.ts
3929
3937
  import { join as join37 } from "path";
3930
3938
  var CopilotSubagent = class _CopilotSubagent extends SimulatedSubagent {
3931
3939
  static getSettablePaths() {
@@ -3949,7 +3957,7 @@ var CopilotSubagent = class _CopilotSubagent extends SimulatedSubagent {
3949
3957
  }
3950
3958
  };
3951
3959
 
3952
- // src/subagents/cursor-subagent.ts
3960
+ // src/features/subagents/cursor-subagent.ts
3953
3961
  import { join as join38 } from "path";
3954
3962
  var CursorSubagent = class _CursorSubagent extends SimulatedSubagent {
3955
3963
  static getSettablePaths() {
@@ -3973,7 +3981,7 @@ var CursorSubagent = class _CursorSubagent extends SimulatedSubagent {
3973
3981
  }
3974
3982
  };
3975
3983
 
3976
- // src/subagents/geminicli-subagent.ts
3984
+ // src/features/subagents/geminicli-subagent.ts
3977
3985
  import { join as join39 } from "path";
3978
3986
  var GeminiCliSubagent = class _GeminiCliSubagent extends SimulatedSubagent {
3979
3987
  static getSettablePaths() {
@@ -3997,7 +4005,7 @@ var GeminiCliSubagent = class _GeminiCliSubagent extends SimulatedSubagent {
3997
4005
  }
3998
4006
  };
3999
4007
 
4000
- // src/subagents/roo-subagent.ts
4008
+ // src/features/subagents/roo-subagent.ts
4001
4009
  import { join as join40 } from "path";
4002
4010
  var RooSubagent = class _RooSubagent extends SimulatedSubagent {
4003
4011
  static getSettablePaths() {
@@ -4021,15 +4029,15 @@ var RooSubagent = class _RooSubagent extends SimulatedSubagent {
4021
4029
  }
4022
4030
  };
4023
4031
 
4024
- // src/subagents/subagents-processor.ts
4032
+ // src/features/subagents/subagents-processor.ts
4025
4033
  import { basename as basename14, join as join43 } from "path";
4026
4034
  import { z as z17 } from "zod/mini";
4027
4035
 
4028
- // src/subagents/claudecode-subagent.ts
4036
+ // src/features/subagents/claudecode-subagent.ts
4029
4037
  import { join as join42 } from "path";
4030
4038
  import { z as z16 } from "zod/mini";
4031
4039
 
4032
- // src/subagents/rulesync-subagent.ts
4040
+ // src/features/subagents/rulesync-subagent.ts
4033
4041
  import { basename as basename13, join as join41 } from "path";
4034
4042
  import { z as z15 } from "zod/mini";
4035
4043
  var RulesyncSubagentModelSchema = z15.enum(["opus", "sonnet", "haiku", "inherit"]);
@@ -4056,7 +4064,8 @@ var RulesyncSubagent = class _RulesyncSubagent extends RulesyncFile {
4056
4064
  }
4057
4065
  }
4058
4066
  super({
4059
- ...rest
4067
+ ...rest,
4068
+ fileContent: stringifyFrontmatter(body, frontmatter)
4060
4069
  });
4061
4070
  this.frontmatter = frontmatter;
4062
4071
  this.body = body;
@@ -4105,13 +4114,12 @@ var RulesyncSubagent = class _RulesyncSubagent extends RulesyncFile {
4105
4114
  relativeDirPath: this.getSettablePaths().relativeDirPath,
4106
4115
  relativeFilePath: filename,
4107
4116
  frontmatter: result.data,
4108
- body: content.trim(),
4109
- fileContent
4117
+ body: content.trim()
4110
4118
  });
4111
4119
  }
4112
4120
  };
4113
4121
 
4114
- // src/subagents/claudecode-subagent.ts
4122
+ // src/features/subagents/claudecode-subagent.ts
4115
4123
  var ClaudecodeSubagentFrontmatterSchema = z16.object({
4116
4124
  name: z16.string(),
4117
4125
  description: z16.string(),
@@ -4157,7 +4165,6 @@ var ClaudecodeSubagent = class _ClaudecodeSubagent extends ToolSubagent {
4157
4165
  }
4158
4166
  }
4159
4167
  };
4160
- const fileContent = stringifyFrontmatter(this.body, rulesyncFrontmatter);
4161
4168
  return new RulesyncSubagent({
4162
4169
  baseDir: ".",
4163
4170
  // RulesyncCommand baseDir is always the project root directory
@@ -4165,7 +4172,6 @@ var ClaudecodeSubagent = class _ClaudecodeSubagent extends ToolSubagent {
4165
4172
  body: this.body,
4166
4173
  relativeDirPath: join42(".rulesync", "subagents"),
4167
4174
  relativeFilePath: this.getRelativeFilePath(),
4168
- fileContent,
4169
4175
  validate: true
4170
4176
  });
4171
4177
  }
@@ -4242,7 +4248,7 @@ var ClaudecodeSubagent = class _ClaudecodeSubagent extends ToolSubagent {
4242
4248
  }
4243
4249
  };
4244
4250
 
4245
- // src/subagents/subagents-processor.ts
4251
+ // src/features/subagents/subagents-processor.ts
4246
4252
  var subagentsProcessorToolTargets = [
4247
4253
  "agentsmd",
4248
4254
  "claudecode",
@@ -4538,13 +4544,13 @@ var SubagentsProcessor = class extends FeatureProcessor {
4538
4544
  }
4539
4545
  };
4540
4546
 
4541
- // src/rules/agentsmd-rule.ts
4547
+ // src/features/rules/agentsmd-rule.ts
4542
4548
  import { join as join46 } from "path";
4543
4549
 
4544
- // src/rules/tool-rule.ts
4550
+ // src/features/rules/tool-rule.ts
4545
4551
  import { join as join45 } from "path";
4546
4552
 
4547
- // src/rules/rulesync-rule.ts
4553
+ // src/features/rules/rulesync-rule.ts
4548
4554
  import { basename as basename15, join as join44 } from "path";
4549
4555
  import { z as z18 } from "zod/mini";
4550
4556
  var RulesyncRuleFrontmatterSchema = z18.object({
@@ -4690,7 +4696,7 @@ var RulesyncRule = class _RulesyncRule extends RulesyncFile {
4690
4696
  }
4691
4697
  };
4692
4698
 
4693
- // src/rules/tool-rule.ts
4699
+ // src/features/rules/tool-rule.ts
4694
4700
  var ToolRule = class extends ToolFile {
4695
4701
  root;
4696
4702
  description;
@@ -4811,7 +4817,7 @@ var ToolRule = class extends ToolFile {
4811
4817
  }
4812
4818
  };
4813
4819
 
4814
- // src/rules/agentsmd-rule.ts
4820
+ // src/features/rules/agentsmd-rule.ts
4815
4821
  var AgentsMdRule = class _AgentsMdRule extends ToolRule {
4816
4822
  constructor({ fileContent, root, ...rest }) {
4817
4823
  super({
@@ -4877,7 +4883,7 @@ var AgentsMdRule = class _AgentsMdRule extends ToolRule {
4877
4883
  }
4878
4884
  };
4879
4885
 
4880
- // src/rules/amazonqcli-rule.ts
4886
+ // src/features/rules/amazonqcli-rule.ts
4881
4887
  import { join as join47 } from "path";
4882
4888
  var AmazonQCliRule = class _AmazonQCliRule extends ToolRule {
4883
4889
  static getSettablePaths() {
@@ -4932,7 +4938,7 @@ var AmazonQCliRule = class _AmazonQCliRule extends ToolRule {
4932
4938
  }
4933
4939
  };
4934
4940
 
4935
- // src/rules/augmentcode-legacy-rule.ts
4941
+ // src/features/rules/augmentcode-legacy-rule.ts
4936
4942
  import { join as join48 } from "path";
4937
4943
  var AugmentcodeLegacyRule = class _AugmentcodeLegacyRule extends ToolRule {
4938
4944
  toRulesyncRule() {
@@ -5007,7 +5013,7 @@ var AugmentcodeLegacyRule = class _AugmentcodeLegacyRule extends ToolRule {
5007
5013
  }
5008
5014
  };
5009
5015
 
5010
- // src/rules/augmentcode-rule.ts
5016
+ // src/features/rules/augmentcode-rule.ts
5011
5017
  import { join as join49 } from "path";
5012
5018
  var AugmentcodeRule = class _AugmentcodeRule extends ToolRule {
5013
5019
  toRulesyncRule() {
@@ -5062,7 +5068,7 @@ var AugmentcodeRule = class _AugmentcodeRule extends ToolRule {
5062
5068
  }
5063
5069
  };
5064
5070
 
5065
- // src/rules/claudecode-rule.ts
5071
+ // src/features/rules/claudecode-rule.ts
5066
5072
  import { join as join50 } from "path";
5067
5073
  var ClaudecodeRule = class _ClaudecodeRule extends ToolRule {
5068
5074
  static getSettablePaths({
@@ -5153,7 +5159,7 @@ var ClaudecodeRule = class _ClaudecodeRule extends ToolRule {
5153
5159
  }
5154
5160
  };
5155
5161
 
5156
- // src/rules/cline-rule.ts
5162
+ // src/features/rules/cline-rule.ts
5157
5163
  import { join as join51 } from "path";
5158
5164
  import { z as z19 } from "zod/mini";
5159
5165
  var ClineRuleFrontmatterSchema = z19.object({
@@ -5211,7 +5217,7 @@ var ClineRule = class _ClineRule extends ToolRule {
5211
5217
  }
5212
5218
  };
5213
5219
 
5214
- // src/rules/codexcli-rule.ts
5220
+ // src/features/rules/codexcli-rule.ts
5215
5221
  import { join as join52 } from "path";
5216
5222
  var CodexcliRule = class _CodexcliRule extends ToolRule {
5217
5223
  static getSettablePaths({
@@ -5302,7 +5308,7 @@ var CodexcliRule = class _CodexcliRule extends ToolRule {
5302
5308
  }
5303
5309
  };
5304
5310
 
5305
- // src/rules/copilot-rule.ts
5311
+ // src/features/rules/copilot-rule.ts
5306
5312
  import { join as join53 } from "path";
5307
5313
  import { z as z20 } from "zod/mini";
5308
5314
  var CopilotRuleFrontmatterSchema = z20.object({
@@ -5472,7 +5478,7 @@ var CopilotRule = class _CopilotRule extends ToolRule {
5472
5478
  }
5473
5479
  };
5474
5480
 
5475
- // src/rules/cursor-rule.ts
5481
+ // src/features/rules/cursor-rule.ts
5476
5482
  import { basename as basename16, join as join54 } from "path";
5477
5483
  import { z as z21 } from "zod/mini";
5478
5484
  var CursorRuleFrontmatterSchema = z21.object({
@@ -5660,7 +5666,7 @@ var CursorRule = class _CursorRule extends ToolRule {
5660
5666
  }
5661
5667
  };
5662
5668
 
5663
- // src/rules/geminicli-rule.ts
5669
+ // src/features/rules/geminicli-rule.ts
5664
5670
  import { join as join55 } from "path";
5665
5671
  var GeminiCliRule = class _GeminiCliRule extends ToolRule {
5666
5672
  static getSettablePaths({
@@ -5751,7 +5757,7 @@ var GeminiCliRule = class _GeminiCliRule extends ToolRule {
5751
5757
  }
5752
5758
  };
5753
5759
 
5754
- // src/rules/junie-rule.ts
5760
+ // src/features/rules/junie-rule.ts
5755
5761
  import { join as join56 } from "path";
5756
5762
  var JunieRule = class _JunieRule extends ToolRule {
5757
5763
  static getSettablePaths() {
@@ -5811,7 +5817,7 @@ var JunieRule = class _JunieRule extends ToolRule {
5811
5817
  }
5812
5818
  };
5813
5819
 
5814
- // src/rules/kiro-rule.ts
5820
+ // src/features/rules/kiro-rule.ts
5815
5821
  import { join as join57 } from "path";
5816
5822
  var KiroRule = class _KiroRule extends ToolRule {
5817
5823
  static getSettablePaths() {
@@ -5866,7 +5872,7 @@ var KiroRule = class _KiroRule extends ToolRule {
5866
5872
  }
5867
5873
  };
5868
5874
 
5869
- // src/rules/opencode-rule.ts
5875
+ // src/features/rules/opencode-rule.ts
5870
5876
  import { join as join58 } from "path";
5871
5877
  var OpenCodeRule = class _OpenCodeRule extends ToolRule {
5872
5878
  static getSettablePaths() {
@@ -5926,7 +5932,7 @@ var OpenCodeRule = class _OpenCodeRule extends ToolRule {
5926
5932
  }
5927
5933
  };
5928
5934
 
5929
- // src/rules/qwencode-rule.ts
5935
+ // src/features/rules/qwencode-rule.ts
5930
5936
  import { join as join59 } from "path";
5931
5937
  var QwencodeRule = class _QwencodeRule extends ToolRule {
5932
5938
  static getSettablePaths() {
@@ -5983,7 +5989,7 @@ var QwencodeRule = class _QwencodeRule extends ToolRule {
5983
5989
  }
5984
5990
  };
5985
5991
 
5986
- // src/rules/roo-rule.ts
5992
+ // src/features/rules/roo-rule.ts
5987
5993
  import { join as join60 } from "path";
5988
5994
  var RooRule = class _RooRule extends ToolRule {
5989
5995
  static getSettablePaths() {
@@ -6053,7 +6059,7 @@ var RooRule = class _RooRule extends ToolRule {
6053
6059
  }
6054
6060
  };
6055
6061
 
6056
- // src/rules/warp-rule.ts
6062
+ // src/features/rules/warp-rule.ts
6057
6063
  import { join as join61 } from "path";
6058
6064
  var WarpRule = class _WarpRule extends ToolRule {
6059
6065
  constructor({ fileContent, root, ...rest }) {
@@ -6120,7 +6126,7 @@ var WarpRule = class _WarpRule extends ToolRule {
6120
6126
  }
6121
6127
  };
6122
6128
 
6123
- // src/rules/windsurf-rule.ts
6129
+ // src/features/rules/windsurf-rule.ts
6124
6130
  import { join as join62 } from "path";
6125
6131
  var WindsurfRule = class _WindsurfRule extends ToolRule {
6126
6132
  static getSettablePaths() {
@@ -6174,7 +6180,7 @@ var WindsurfRule = class _WindsurfRule extends ToolRule {
6174
6180
  }
6175
6181
  };
6176
6182
 
6177
- // src/rules/rules-processor.ts
6183
+ // src/features/rules/rules-processor.ts
6178
6184
  var rulesProcessorToolTargets = [
6179
6185
  "agentsmd",
6180
6186
  "amazonqcli",
@@ -7684,111 +7690,494 @@ Attention, again, you are just the planner, so though you can read any files and
7684
7690
  }
7685
7691
 
7686
7692
  // src/cli/commands/mcp.ts
7687
- import { basename as basename18, join as join66 } from "path";
7688
7693
  import { FastMCP } from "fastmcp";
7694
+
7695
+ // src/mcp/commands.ts
7696
+ import { basename as basename18, join as join66 } from "path";
7689
7697
  import { z as z23 } from "zod/mini";
7690
- var MAX_RULE_SIZE_BYTES = 1024 * 1024;
7691
- var MAX_RULES_COUNT = 1e3;
7692
- var RULES_DIR_PREFIX = ".rulesync/rules";
7693
- function validateRulePath(relativePathFromCwd) {
7694
- const normalizedPath = relativePathFromCwd.replace(/\\/g, "/");
7695
- if (!normalizedPath.startsWith(`${RULES_DIR_PREFIX}/`)) {
7696
- throw new Error(`Invalid rule path: must be within ${RULES_DIR_PREFIX}/ directory`);
7697
- }
7698
- try {
7699
- resolvePath(normalizedPath, process.cwd());
7700
- } catch (error) {
7701
- throw new Error(`Path validation failed: ${formatError(error)}`, { cause: error });
7702
- }
7703
- const filename = basename18(normalizedPath);
7704
- if (!/^[a-zA-Z0-9_-]+\.md$/.test(filename)) {
7705
- throw new Error(
7706
- `Invalid filename: ${filename}. Must match pattern [a-zA-Z0-9_-]+.md (alphanumeric, hyphens, underscores only)`
7707
- );
7708
- }
7709
- }
7710
- async function listRules() {
7711
- const rulesDir = join66(process.cwd(), ".rulesync", "rules");
7698
+ var maxCommandSizeBytes = 1024 * 1024;
7699
+ var maxCommandsCount = 1e3;
7700
+ async function listCommands() {
7701
+ const commandsDir = join66(process.cwd(), ".rulesync", "commands");
7712
7702
  try {
7713
- const files = await listDirectoryFiles(rulesDir);
7703
+ const files = await listDirectoryFiles(commandsDir);
7714
7704
  const mdFiles = files.filter((file) => file.endsWith(".md"));
7715
- const rules = await Promise.all(
7705
+ const commands = await Promise.all(
7716
7706
  mdFiles.map(async (file) => {
7717
7707
  try {
7718
- const rule = await RulesyncRule.fromFile({
7719
- relativeFilePath: file,
7720
- validate: true
7708
+ const command = await RulesyncCommand.fromFile({
7709
+ relativeFilePath: file
7721
7710
  });
7722
- const frontmatter = rule.getFrontmatter();
7711
+ const frontmatter = command.getFrontmatter();
7723
7712
  return {
7724
- relativePathFromCwd: join66(".rulesync", "rules", file),
7713
+ relativePathFromCwd: join66(".rulesync", "commands", file),
7725
7714
  frontmatter
7726
7715
  };
7727
7716
  } catch (error) {
7728
- logger.error(`Failed to read rule file ${file}: ${formatError(error)}`);
7717
+ logger.error(`Failed to read command file ${file}: ${formatError(error)}`);
7729
7718
  return null;
7730
7719
  }
7731
7720
  })
7732
7721
  );
7733
- return rules.filter((rule) => rule !== null);
7722
+ return commands.filter((command) => command !== null);
7734
7723
  } catch (error) {
7735
- logger.error(`Failed to read rules directory: ${formatError(error)}`);
7724
+ logger.error(`Failed to read commands directory: ${formatError(error)}`);
7736
7725
  return [];
7737
7726
  }
7738
7727
  }
7739
- async function getRule({ relativePathFromCwd }) {
7740
- validateRulePath(relativePathFromCwd);
7728
+ async function getCommand({ relativePathFromCwd }) {
7729
+ checkPathTraversal({
7730
+ relativePath: relativePathFromCwd,
7731
+ intendedRootDir: process.cwd()
7732
+ });
7741
7733
  const filename = basename18(relativePathFromCwd);
7742
7734
  try {
7743
- const rule = await RulesyncRule.fromFile({
7744
- relativeFilePath: filename,
7745
- validate: true
7735
+ const command = await RulesyncCommand.fromFile({
7736
+ relativeFilePath: filename
7746
7737
  });
7747
7738
  return {
7748
- relativePathFromCwd: join66(".rulesync", "rules", filename),
7749
- frontmatter: rule.getFrontmatter(),
7750
- body: rule.getBody()
7739
+ relativePathFromCwd: join66(".rulesync", "commands", filename),
7740
+ frontmatter: command.getFrontmatter(),
7741
+ body: command.getBody()
7751
7742
  };
7752
7743
  } catch (error) {
7753
- throw new Error(`Failed to read rule file ${relativePathFromCwd}: ${formatError(error)}`, {
7744
+ throw new Error(`Failed to read command file ${relativePathFromCwd}: ${formatError(error)}`, {
7754
7745
  cause: error
7755
7746
  });
7756
7747
  }
7757
7748
  }
7758
- async function putRule({
7749
+ async function putCommand({
7759
7750
  relativePathFromCwd,
7760
7751
  frontmatter,
7761
7752
  body
7762
7753
  }) {
7763
- validateRulePath(relativePathFromCwd);
7754
+ checkPathTraversal({
7755
+ relativePath: relativePathFromCwd,
7756
+ intendedRootDir: process.cwd()
7757
+ });
7764
7758
  const filename = basename18(relativePathFromCwd);
7765
7759
  const estimatedSize = JSON.stringify(frontmatter).length + body.length;
7766
- if (estimatedSize > MAX_RULE_SIZE_BYTES) {
7760
+ if (estimatedSize > maxCommandSizeBytes) {
7767
7761
  throw new Error(
7768
- `Rule size ${estimatedSize} bytes exceeds maximum ${MAX_RULE_SIZE_BYTES} bytes (1MB)`
7762
+ `Command size ${estimatedSize} bytes exceeds maximum ${maxCommandSizeBytes} bytes (1MB)`
7769
7763
  );
7770
7764
  }
7771
7765
  try {
7772
- const existingRules = await listRules();
7773
- const isUpdate = existingRules.some(
7774
- (rule2) => rule2.relativePathFromCwd === join66(".rulesync", "rules", filename)
7766
+ const existingCommands = await listCommands();
7767
+ const isUpdate = existingCommands.some(
7768
+ (command2) => command2.relativePathFromCwd === join66(".rulesync", "commands", filename)
7775
7769
  );
7776
- if (!isUpdate && existingRules.length >= MAX_RULES_COUNT) {
7777
- throw new Error(`Maximum number of rules (${MAX_RULES_COUNT}) reached`);
7770
+ if (!isUpdate && existingCommands.length >= maxCommandsCount) {
7771
+ throw new Error(`Maximum number of commands (${maxCommandsCount}) reached`);
7772
+ }
7773
+ const fileContent = stringifyFrontmatter(body, frontmatter);
7774
+ const command = new RulesyncCommand({
7775
+ baseDir: process.cwd(),
7776
+ relativeDirPath: join66(".rulesync", "commands"),
7777
+ relativeFilePath: filename,
7778
+ frontmatter,
7779
+ body,
7780
+ fileContent,
7781
+ validate: true
7782
+ });
7783
+ const commandsDir = join66(process.cwd(), ".rulesync", "commands");
7784
+ await ensureDir(commandsDir);
7785
+ await writeFileContent(command.getFilePath(), command.getFileContent());
7786
+ return {
7787
+ relativePathFromCwd: join66(".rulesync", "commands", filename),
7788
+ frontmatter: command.getFrontmatter(),
7789
+ body: command.getBody()
7790
+ };
7791
+ } catch (error) {
7792
+ throw new Error(`Failed to write command file ${relativePathFromCwd}: ${formatError(error)}`, {
7793
+ cause: error
7794
+ });
7795
+ }
7796
+ }
7797
+ async function deleteCommand({ relativePathFromCwd }) {
7798
+ checkPathTraversal({
7799
+ relativePath: relativePathFromCwd,
7800
+ intendedRootDir: process.cwd()
7801
+ });
7802
+ const filename = basename18(relativePathFromCwd);
7803
+ const fullPath = join66(process.cwd(), ".rulesync", "commands", filename);
7804
+ try {
7805
+ await removeFile(fullPath);
7806
+ return {
7807
+ relativePathFromCwd: join66(".rulesync", "commands", filename)
7808
+ };
7809
+ } catch (error) {
7810
+ throw new Error(`Failed to delete command file ${relativePathFromCwd}: ${formatError(error)}`, {
7811
+ cause: error
7812
+ });
7813
+ }
7814
+ }
7815
+ var commandToolSchemas = {
7816
+ listCommands: z23.object({}),
7817
+ getCommand: z23.object({
7818
+ relativePathFromCwd: z23.string()
7819
+ }),
7820
+ putCommand: z23.object({
7821
+ relativePathFromCwd: z23.string(),
7822
+ frontmatter: RulesyncCommandFrontmatterSchema,
7823
+ body: z23.string()
7824
+ }),
7825
+ deleteCommand: z23.object({
7826
+ relativePathFromCwd: z23.string()
7827
+ })
7828
+ };
7829
+ var commandTools = {
7830
+ listCommands: {
7831
+ name: "listCommands",
7832
+ description: `List all commands from ${join66(".rulesync", "commands", "*.md")} with their frontmatter.`,
7833
+ parameters: commandToolSchemas.listCommands,
7834
+ execute: async () => {
7835
+ const commands = await listCommands();
7836
+ const output = { commands };
7837
+ return JSON.stringify(output, null, 2);
7838
+ }
7839
+ },
7840
+ getCommand: {
7841
+ name: "getCommand",
7842
+ description: "Get detailed information about a specific command. relativePathFromCwd parameter is required.",
7843
+ parameters: commandToolSchemas.getCommand,
7844
+ execute: async (args) => {
7845
+ const result = await getCommand({ relativePathFromCwd: args.relativePathFromCwd });
7846
+ return JSON.stringify(result, null, 2);
7847
+ }
7848
+ },
7849
+ putCommand: {
7850
+ name: "putCommand",
7851
+ description: "Create or update a command (upsert operation). relativePathFromCwd, frontmatter, and body parameters are required.",
7852
+ parameters: commandToolSchemas.putCommand,
7853
+ execute: async (args) => {
7854
+ const result = await putCommand({
7855
+ relativePathFromCwd: args.relativePathFromCwd,
7856
+ frontmatter: args.frontmatter,
7857
+ body: args.body
7858
+ });
7859
+ return JSON.stringify(result, null, 2);
7860
+ }
7861
+ },
7862
+ deleteCommand: {
7863
+ name: "deleteCommand",
7864
+ description: "Delete a command file. relativePathFromCwd parameter is required.",
7865
+ parameters: commandToolSchemas.deleteCommand,
7866
+ execute: async (args) => {
7867
+ const result = await deleteCommand({ relativePathFromCwd: args.relativePathFromCwd });
7868
+ return JSON.stringify(result, null, 2);
7869
+ }
7870
+ }
7871
+ };
7872
+
7873
+ // src/mcp/ignore.ts
7874
+ import { join as join67 } from "path";
7875
+ import { z as z24 } from "zod/mini";
7876
+ var maxIgnoreFileSizeBytes = 100 * 1024;
7877
+ async function getIgnoreFile() {
7878
+ const ignoreFilePath = join67(process.cwd(), ".rulesyncignore");
7879
+ try {
7880
+ const content = await readFileContent(ignoreFilePath);
7881
+ return {
7882
+ relativePathFromCwd: ".rulesyncignore",
7883
+ content
7884
+ };
7885
+ } catch (error) {
7886
+ throw new Error(`Failed to read .rulesyncignore file: ${formatError(error)}`, {
7887
+ cause: error
7888
+ });
7889
+ }
7890
+ }
7891
+ async function putIgnoreFile({ content }) {
7892
+ const ignoreFilePath = join67(process.cwd(), ".rulesyncignore");
7893
+ const contentSizeBytes = Buffer.byteLength(content, "utf8");
7894
+ if (contentSizeBytes > maxIgnoreFileSizeBytes) {
7895
+ throw new Error(
7896
+ `Ignore file size ${contentSizeBytes} bytes exceeds maximum ${maxIgnoreFileSizeBytes} bytes (100KB)`
7897
+ );
7898
+ }
7899
+ try {
7900
+ await ensureDir(process.cwd());
7901
+ await writeFileContent(ignoreFilePath, content);
7902
+ return {
7903
+ relativePathFromCwd: ".rulesyncignore",
7904
+ content
7905
+ };
7906
+ } catch (error) {
7907
+ throw new Error(`Failed to write .rulesyncignore file: ${formatError(error)}`, {
7908
+ cause: error
7909
+ });
7910
+ }
7911
+ }
7912
+ async function deleteIgnoreFile() {
7913
+ const ignoreFilePath = join67(process.cwd(), ".rulesyncignore");
7914
+ try {
7915
+ await removeFile(ignoreFilePath);
7916
+ return {
7917
+ relativePathFromCwd: ".rulesyncignore"
7918
+ };
7919
+ } catch (error) {
7920
+ throw new Error(`Failed to delete .rulesyncignore file: ${formatError(error)}`, {
7921
+ cause: error
7922
+ });
7923
+ }
7924
+ }
7925
+ var ignoreToolSchemas = {
7926
+ getIgnoreFile: z24.object({}),
7927
+ putIgnoreFile: z24.object({
7928
+ content: z24.string()
7929
+ }),
7930
+ deleteIgnoreFile: z24.object({})
7931
+ };
7932
+ var ignoreTools = {
7933
+ getIgnoreFile: {
7934
+ name: "getIgnoreFile",
7935
+ description: "Get the content of the .rulesyncignore file from the project root.",
7936
+ parameters: ignoreToolSchemas.getIgnoreFile,
7937
+ execute: async () => {
7938
+ const result = await getIgnoreFile();
7939
+ return JSON.stringify(result, null, 2);
7940
+ }
7941
+ },
7942
+ putIgnoreFile: {
7943
+ name: "putIgnoreFile",
7944
+ description: "Create or update the .rulesyncignore file (upsert operation). content parameter is required.",
7945
+ parameters: ignoreToolSchemas.putIgnoreFile,
7946
+ execute: async (args) => {
7947
+ const result = await putIgnoreFile({ content: args.content });
7948
+ return JSON.stringify(result, null, 2);
7949
+ }
7950
+ },
7951
+ deleteIgnoreFile: {
7952
+ name: "deleteIgnoreFile",
7953
+ description: "Delete the .rulesyncignore file from the project root.",
7954
+ parameters: ignoreToolSchemas.deleteIgnoreFile,
7955
+ execute: async () => {
7956
+ const result = await deleteIgnoreFile();
7957
+ return JSON.stringify(result, null, 2);
7958
+ }
7959
+ }
7960
+ };
7961
+
7962
+ // src/mcp/mcp.ts
7963
+ import { join as join68 } from "path";
7964
+ import { z as z25 } from "zod/mini";
7965
+ var maxMcpSizeBytes = 1024 * 1024;
7966
+ async function getMcpFile() {
7967
+ try {
7968
+ const rulesyncMcp = await RulesyncMcp.fromFile({
7969
+ validate: true,
7970
+ modularMcp: false
7971
+ });
7972
+ const relativePathFromCwd = join68(
7973
+ rulesyncMcp.getRelativeDirPath(),
7974
+ rulesyncMcp.getRelativeFilePath()
7975
+ );
7976
+ return {
7977
+ relativePathFromCwd,
7978
+ content: rulesyncMcp.getFileContent()
7979
+ };
7980
+ } catch (error) {
7981
+ throw new Error(`Failed to read MCP file: ${formatError(error)}`, {
7982
+ cause: error
7983
+ });
7984
+ }
7985
+ }
7986
+ async function putMcpFile({ content }) {
7987
+ if (content.length > maxMcpSizeBytes) {
7988
+ throw new Error(
7989
+ `MCP file size ${content.length} bytes exceeds maximum ${maxMcpSizeBytes} bytes (1MB)`
7990
+ );
7991
+ }
7992
+ try {
7993
+ JSON.parse(content);
7994
+ } catch (error) {
7995
+ throw new Error(`Invalid JSON format in MCP file: ${formatError(error)}`, {
7996
+ cause: error
7997
+ });
7998
+ }
7999
+ try {
8000
+ const baseDir = process.cwd();
8001
+ const paths = RulesyncMcp.getSettablePaths();
8002
+ const relativeDirPath = paths.recommended.relativeDirPath;
8003
+ const relativeFilePath = paths.recommended.relativeFilePath;
8004
+ const fullPath = join68(baseDir, relativeDirPath, relativeFilePath);
8005
+ const rulesyncMcp = new RulesyncMcp({
8006
+ baseDir,
8007
+ relativeDirPath,
8008
+ relativeFilePath,
8009
+ fileContent: content,
8010
+ validate: true,
8011
+ modularMcp: false
8012
+ });
8013
+ await ensureDir(join68(baseDir, relativeDirPath));
8014
+ await writeFileContent(fullPath, content);
8015
+ const relativePathFromCwd = join68(relativeDirPath, relativeFilePath);
8016
+ return {
8017
+ relativePathFromCwd,
8018
+ content: rulesyncMcp.getFileContent()
8019
+ };
8020
+ } catch (error) {
8021
+ throw new Error(`Failed to write MCP file: ${formatError(error)}`, {
8022
+ cause: error
8023
+ });
8024
+ }
8025
+ }
8026
+ async function deleteMcpFile() {
8027
+ try {
8028
+ const baseDir = process.cwd();
8029
+ const paths = RulesyncMcp.getSettablePaths();
8030
+ const recommendedPath = join68(
8031
+ baseDir,
8032
+ paths.recommended.relativeDirPath,
8033
+ paths.recommended.relativeFilePath
8034
+ );
8035
+ const legacyPath = join68(baseDir, paths.legacy.relativeDirPath, paths.legacy.relativeFilePath);
8036
+ await removeFile(recommendedPath);
8037
+ await removeFile(legacyPath);
8038
+ const relativePathFromCwd = join68(
8039
+ paths.recommended.relativeDirPath,
8040
+ paths.recommended.relativeFilePath
8041
+ );
8042
+ return {
8043
+ relativePathFromCwd
8044
+ };
8045
+ } catch (error) {
8046
+ throw new Error(`Failed to delete MCP file: ${formatError(error)}`, {
8047
+ cause: error
8048
+ });
8049
+ }
8050
+ }
8051
+ var mcpToolSchemas = {
8052
+ getMcpFile: z25.object({}),
8053
+ putMcpFile: z25.object({
8054
+ content: z25.string()
8055
+ }),
8056
+ deleteMcpFile: z25.object({})
8057
+ };
8058
+ var mcpTools = {
8059
+ getMcpFile: {
8060
+ name: "getMcpFile",
8061
+ description: `Get the MCP configuration file (${join68(".rulesync", "mcp.json")}).`,
8062
+ parameters: mcpToolSchemas.getMcpFile,
8063
+ execute: async () => {
8064
+ const result = await getMcpFile();
8065
+ return JSON.stringify(result, null, 2);
8066
+ }
8067
+ },
8068
+ putMcpFile: {
8069
+ name: "putMcpFile",
8070
+ description: "Create or update the MCP configuration file (upsert operation). content parameter is required and must be valid JSON.",
8071
+ parameters: mcpToolSchemas.putMcpFile,
8072
+ execute: async (args) => {
8073
+ const result = await putMcpFile({ content: args.content });
8074
+ return JSON.stringify(result, null, 2);
8075
+ }
8076
+ },
8077
+ deleteMcpFile: {
8078
+ name: "deleteMcpFile",
8079
+ description: "Delete the MCP configuration file.",
8080
+ parameters: mcpToolSchemas.deleteMcpFile,
8081
+ execute: async () => {
8082
+ const result = await deleteMcpFile();
8083
+ return JSON.stringify(result, null, 2);
8084
+ }
8085
+ }
8086
+ };
8087
+
8088
+ // src/mcp/rules.ts
8089
+ import { basename as basename19, join as join69 } from "path";
8090
+ import { z as z26 } from "zod/mini";
8091
+ var maxRuleSizeBytes = 1024 * 1024;
8092
+ var maxRulesCount = 1e3;
8093
+ async function listRules() {
8094
+ const rulesDir = join69(process.cwd(), ".rulesync", "rules");
8095
+ try {
8096
+ const files = await listDirectoryFiles(rulesDir);
8097
+ const mdFiles = files.filter((file) => file.endsWith(".md"));
8098
+ const rules = await Promise.all(
8099
+ mdFiles.map(async (file) => {
8100
+ try {
8101
+ const rule = await RulesyncRule.fromFile({
8102
+ relativeFilePath: file,
8103
+ validate: true
8104
+ });
8105
+ const frontmatter = rule.getFrontmatter();
8106
+ return {
8107
+ relativePathFromCwd: join69(".rulesync", "rules", file),
8108
+ frontmatter
8109
+ };
8110
+ } catch (error) {
8111
+ logger.error(`Failed to read rule file ${file}: ${formatError(error)}`);
8112
+ return null;
8113
+ }
8114
+ })
8115
+ );
8116
+ return rules.filter((rule) => rule !== null);
8117
+ } catch (error) {
8118
+ logger.error(`Failed to read rules directory: ${formatError(error)}`);
8119
+ return [];
8120
+ }
8121
+ }
8122
+ async function getRule({ relativePathFromCwd }) {
8123
+ checkPathTraversal({
8124
+ relativePath: relativePathFromCwd,
8125
+ intendedRootDir: process.cwd()
8126
+ });
8127
+ const filename = basename19(relativePathFromCwd);
8128
+ try {
8129
+ const rule = await RulesyncRule.fromFile({
8130
+ relativeFilePath: filename,
8131
+ validate: true
8132
+ });
8133
+ return {
8134
+ relativePathFromCwd: join69(".rulesync", "rules", filename),
8135
+ frontmatter: rule.getFrontmatter(),
8136
+ body: rule.getBody()
8137
+ };
8138
+ } catch (error) {
8139
+ throw new Error(`Failed to read rule file ${relativePathFromCwd}: ${formatError(error)}`, {
8140
+ cause: error
8141
+ });
8142
+ }
8143
+ }
8144
+ async function putRule({
8145
+ relativePathFromCwd,
8146
+ frontmatter,
8147
+ body
8148
+ }) {
8149
+ checkPathTraversal({
8150
+ relativePath: relativePathFromCwd,
8151
+ intendedRootDir: process.cwd()
8152
+ });
8153
+ const filename = basename19(relativePathFromCwd);
8154
+ const estimatedSize = JSON.stringify(frontmatter).length + body.length;
8155
+ if (estimatedSize > maxRuleSizeBytes) {
8156
+ throw new Error(
8157
+ `Rule size ${estimatedSize} bytes exceeds maximum ${maxRuleSizeBytes} bytes (1MB)`
8158
+ );
8159
+ }
8160
+ try {
8161
+ const existingRules = await listRules();
8162
+ const isUpdate = existingRules.some(
8163
+ (rule2) => rule2.relativePathFromCwd === join69(".rulesync", "rules", filename)
8164
+ );
8165
+ if (!isUpdate && existingRules.length >= maxRulesCount) {
8166
+ throw new Error(`Maximum number of rules (${maxRulesCount}) reached`);
7778
8167
  }
7779
8168
  const rule = new RulesyncRule({
7780
8169
  baseDir: process.cwd(),
7781
- relativeDirPath: ".rulesync/rules",
8170
+ relativeDirPath: join69(".rulesync", "rules"),
7782
8171
  relativeFilePath: filename,
7783
8172
  frontmatter,
7784
8173
  body,
7785
8174
  validate: true
7786
8175
  });
7787
- const rulesDir = join66(process.cwd(), ".rulesync", "rules");
8176
+ const rulesDir = join69(process.cwd(), ".rulesync", "rules");
7788
8177
  await ensureDir(rulesDir);
7789
8178
  await writeFileContent(rule.getFilePath(), rule.getFileContent());
7790
8179
  return {
7791
- relativePathFromCwd: join66(".rulesync", "rules", filename),
8180
+ relativePathFromCwd: join69(".rulesync", "rules", filename),
7792
8181
  frontmatter: rule.getFrontmatter(),
7793
8182
  body: rule.getBody()
7794
8183
  };
@@ -7799,13 +8188,16 @@ async function putRule({
7799
8188
  }
7800
8189
  }
7801
8190
  async function deleteRule({ relativePathFromCwd }) {
7802
- validateRulePath(relativePathFromCwd);
7803
- const filename = basename18(relativePathFromCwd);
7804
- const fullPath = join66(process.cwd(), ".rulesync", "rules", filename);
8191
+ checkPathTraversal({
8192
+ relativePath: relativePathFromCwd,
8193
+ intendedRootDir: process.cwd()
8194
+ });
8195
+ const filename = basename19(relativePathFromCwd);
8196
+ const fullPath = join69(process.cwd(), ".rulesync", "rules", filename);
7805
8197
  try {
7806
8198
  await removeFile(fullPath);
7807
8199
  return {
7808
- relativePathFromCwd: join66(".rulesync", "rules", filename)
8200
+ relativePathFromCwd: join69(".rulesync", "rules", filename)
7809
8201
  };
7810
8202
  } catch (error) {
7811
8203
  throw new Error(`Failed to delete rule file ${relativePathFromCwd}: ${formatError(error)}`, {
@@ -7813,42 +8205,44 @@ async function deleteRule({ relativePathFromCwd }) {
7813
8205
  });
7814
8206
  }
7815
8207
  }
7816
- async function mcpCommand({ version }) {
7817
- const server = new FastMCP({
7818
- name: "rulesync-mcp-server",
7819
- // Type assertion is safe here because version comes from package.json which follows semver
7820
- // eslint-disable-next-line no-type-assertion/no-type-assertion
7821
- version
7822
- });
7823
- server.addTool({
8208
+ var ruleToolSchemas = {
8209
+ listRules: z26.object({}),
8210
+ getRule: z26.object({
8211
+ relativePathFromCwd: z26.string()
8212
+ }),
8213
+ putRule: z26.object({
8214
+ relativePathFromCwd: z26.string(),
8215
+ frontmatter: RulesyncRuleFrontmatterSchema,
8216
+ body: z26.string()
8217
+ }),
8218
+ deleteRule: z26.object({
8219
+ relativePathFromCwd: z26.string()
8220
+ })
8221
+ };
8222
+ var ruleTools = {
8223
+ listRules: {
7824
8224
  name: "listRules",
7825
- description: "List all rules from .rulesync/rules/*.md with their frontmatter",
7826
- parameters: z23.object({}),
8225
+ description: `List all rules from ${join69(".rulesync", "rules", "*.md")} with their frontmatter.`,
8226
+ parameters: ruleToolSchemas.listRules,
7827
8227
  execute: async () => {
7828
8228
  const rules = await listRules();
7829
8229
  const output = { rules };
7830
8230
  return JSON.stringify(output, null, 2);
7831
8231
  }
7832
- });
7833
- server.addTool({
8232
+ },
8233
+ getRule: {
7834
8234
  name: "getRule",
7835
8235
  description: "Get detailed information about a specific rule. relativePathFromCwd parameter is required.",
7836
- parameters: z23.object({
7837
- relativePathFromCwd: z23.string()
7838
- }),
8236
+ parameters: ruleToolSchemas.getRule,
7839
8237
  execute: async (args) => {
7840
8238
  const result = await getRule({ relativePathFromCwd: args.relativePathFromCwd });
7841
8239
  return JSON.stringify(result, null, 2);
7842
8240
  }
7843
- });
7844
- server.addTool({
8241
+ },
8242
+ putRule: {
7845
8243
  name: "putRule",
7846
8244
  description: "Create or update a rule (upsert operation). relativePathFromCwd, frontmatter, and body parameters are required.",
7847
- parameters: z23.object({
7848
- relativePathFromCwd: z23.string(),
7849
- frontmatter: RulesyncRuleFrontmatterSchema,
7850
- body: z23.string()
7851
- }),
8245
+ parameters: ruleToolSchemas.putRule,
7852
8246
  execute: async (args) => {
7853
8247
  const result = await putRule({
7854
8248
  relativePathFromCwd: args.relativePathFromCwd,
@@ -7857,18 +8251,227 @@ async function mcpCommand({ version }) {
7857
8251
  });
7858
8252
  return JSON.stringify(result, null, 2);
7859
8253
  }
7860
- });
7861
- server.addTool({
8254
+ },
8255
+ deleteRule: {
7862
8256
  name: "deleteRule",
7863
8257
  description: "Delete a rule file. relativePathFromCwd parameter is required.",
7864
- parameters: z23.object({
7865
- relativePathFromCwd: z23.string()
7866
- }),
8258
+ parameters: ruleToolSchemas.deleteRule,
7867
8259
  execute: async (args) => {
7868
8260
  const result = await deleteRule({ relativePathFromCwd: args.relativePathFromCwd });
7869
8261
  return JSON.stringify(result, null, 2);
7870
8262
  }
8263
+ }
8264
+ };
8265
+
8266
+ // src/mcp/subagents.ts
8267
+ import { basename as basename20, join as join70 } from "path";
8268
+ import { z as z27 } from "zod/mini";
8269
+ var maxSubagentSizeBytes = 1024 * 1024;
8270
+ var maxSubagentsCount = 1e3;
8271
+ async function listSubagents() {
8272
+ const subagentsDir = join70(process.cwd(), ".rulesync", "subagents");
8273
+ try {
8274
+ const files = await listDirectoryFiles(subagentsDir);
8275
+ const mdFiles = files.filter((file) => file.endsWith(".md"));
8276
+ const subagents = await Promise.all(
8277
+ mdFiles.map(async (file) => {
8278
+ try {
8279
+ const subagent = await RulesyncSubagent.fromFile({
8280
+ relativeFilePath: file,
8281
+ validate: true
8282
+ });
8283
+ const frontmatter = subagent.getFrontmatter();
8284
+ return {
8285
+ relativePathFromCwd: join70(".rulesync", "subagents", file),
8286
+ frontmatter
8287
+ };
8288
+ } catch (error) {
8289
+ logger.error(`Failed to read subagent file ${file}: ${formatError(error)}`);
8290
+ return null;
8291
+ }
8292
+ })
8293
+ );
8294
+ return subagents.filter(
8295
+ (subagent) => subagent !== null
8296
+ );
8297
+ } catch (error) {
8298
+ logger.error(`Failed to read subagents directory: ${formatError(error)}`);
8299
+ return [];
8300
+ }
8301
+ }
8302
+ async function getSubagent({ relativePathFromCwd }) {
8303
+ checkPathTraversal({
8304
+ relativePath: relativePathFromCwd,
8305
+ intendedRootDir: process.cwd()
8306
+ });
8307
+ const filename = basename20(relativePathFromCwd);
8308
+ try {
8309
+ const subagent = await RulesyncSubagent.fromFile({
8310
+ relativeFilePath: filename,
8311
+ validate: true
8312
+ });
8313
+ return {
8314
+ relativePathFromCwd: join70(".rulesync", "subagents", filename),
8315
+ frontmatter: subagent.getFrontmatter(),
8316
+ body: subagent.getBody()
8317
+ };
8318
+ } catch (error) {
8319
+ throw new Error(`Failed to read subagent file ${relativePathFromCwd}: ${formatError(error)}`, {
8320
+ cause: error
8321
+ });
8322
+ }
8323
+ }
8324
+ async function putSubagent({
8325
+ relativePathFromCwd,
8326
+ frontmatter,
8327
+ body
8328
+ }) {
8329
+ checkPathTraversal({
8330
+ relativePath: relativePathFromCwd,
8331
+ intendedRootDir: process.cwd()
8332
+ });
8333
+ const filename = basename20(relativePathFromCwd);
8334
+ const estimatedSize = JSON.stringify(frontmatter).length + body.length;
8335
+ if (estimatedSize > maxSubagentSizeBytes) {
8336
+ throw new Error(
8337
+ `Subagent size ${estimatedSize} bytes exceeds maximum ${maxSubagentSizeBytes} bytes (1MB)`
8338
+ );
8339
+ }
8340
+ try {
8341
+ const existingSubagents = await listSubagents();
8342
+ const isUpdate = existingSubagents.some(
8343
+ (subagent2) => subagent2.relativePathFromCwd === join70(".rulesync", "subagents", filename)
8344
+ );
8345
+ if (!isUpdate && existingSubagents.length >= maxSubagentsCount) {
8346
+ throw new Error(`Maximum number of subagents (${maxSubagentsCount}) reached`);
8347
+ }
8348
+ const subagent = new RulesyncSubagent({
8349
+ baseDir: process.cwd(),
8350
+ relativeDirPath: join70(".rulesync", "subagents"),
8351
+ relativeFilePath: filename,
8352
+ frontmatter,
8353
+ body,
8354
+ validate: true
8355
+ });
8356
+ const subagentsDir = join70(process.cwd(), ".rulesync", "subagents");
8357
+ await ensureDir(subagentsDir);
8358
+ await writeFileContent(subagent.getFilePath(), subagent.getFileContent());
8359
+ return {
8360
+ relativePathFromCwd: join70(".rulesync", "subagents", filename),
8361
+ frontmatter: subagent.getFrontmatter(),
8362
+ body: subagent.getBody()
8363
+ };
8364
+ } catch (error) {
8365
+ throw new Error(`Failed to write subagent file ${relativePathFromCwd}: ${formatError(error)}`, {
8366
+ cause: error
8367
+ });
8368
+ }
8369
+ }
8370
+ async function deleteSubagent({ relativePathFromCwd }) {
8371
+ checkPathTraversal({
8372
+ relativePath: relativePathFromCwd,
8373
+ intendedRootDir: process.cwd()
8374
+ });
8375
+ const filename = basename20(relativePathFromCwd);
8376
+ const fullPath = join70(process.cwd(), ".rulesync", "subagents", filename);
8377
+ try {
8378
+ await removeFile(fullPath);
8379
+ return {
8380
+ relativePathFromCwd: join70(".rulesync", "subagents", filename)
8381
+ };
8382
+ } catch (error) {
8383
+ throw new Error(
8384
+ `Failed to delete subagent file ${relativePathFromCwd}: ${formatError(error)}`,
8385
+ {
8386
+ cause: error
8387
+ }
8388
+ );
8389
+ }
8390
+ }
8391
+ var subagentToolSchemas = {
8392
+ listSubagents: z27.object({}),
8393
+ getSubagent: z27.object({
8394
+ relativePathFromCwd: z27.string()
8395
+ }),
8396
+ putSubagent: z27.object({
8397
+ relativePathFromCwd: z27.string(),
8398
+ frontmatter: RulesyncSubagentFrontmatterSchema,
8399
+ body: z27.string()
8400
+ }),
8401
+ deleteSubagent: z27.object({
8402
+ relativePathFromCwd: z27.string()
8403
+ })
8404
+ };
8405
+ var subagentTools = {
8406
+ listSubagents: {
8407
+ name: "listSubagents",
8408
+ description: `List all subagents from ${join70(".rulesync", "subagents", "*.md")} with their frontmatter.`,
8409
+ parameters: subagentToolSchemas.listSubagents,
8410
+ execute: async () => {
8411
+ const subagents = await listSubagents();
8412
+ const output = { subagents };
8413
+ return JSON.stringify(output, null, 2);
8414
+ }
8415
+ },
8416
+ getSubagent: {
8417
+ name: "getSubagent",
8418
+ description: "Get detailed information about a specific subagent. relativePathFromCwd parameter is required.",
8419
+ parameters: subagentToolSchemas.getSubagent,
8420
+ execute: async (args) => {
8421
+ const result = await getSubagent({ relativePathFromCwd: args.relativePathFromCwd });
8422
+ return JSON.stringify(result, null, 2);
8423
+ }
8424
+ },
8425
+ putSubagent: {
8426
+ name: "putSubagent",
8427
+ description: "Create or update a subagent (upsert operation). relativePathFromCwd, frontmatter, and body parameters are required.",
8428
+ parameters: subagentToolSchemas.putSubagent,
8429
+ execute: async (args) => {
8430
+ const result = await putSubagent({
8431
+ relativePathFromCwd: args.relativePathFromCwd,
8432
+ frontmatter: args.frontmatter,
8433
+ body: args.body
8434
+ });
8435
+ return JSON.stringify(result, null, 2);
8436
+ }
8437
+ },
8438
+ deleteSubagent: {
8439
+ name: "deleteSubagent",
8440
+ description: "Delete a subagent file. relativePathFromCwd parameter is required.",
8441
+ parameters: subagentToolSchemas.deleteSubagent,
8442
+ execute: async (args) => {
8443
+ const result = await deleteSubagent({ relativePathFromCwd: args.relativePathFromCwd });
8444
+ return JSON.stringify(result, null, 2);
8445
+ }
8446
+ }
8447
+ };
8448
+
8449
+ // src/cli/commands/mcp.ts
8450
+ async function mcpCommand({ version }) {
8451
+ const server = new FastMCP({
8452
+ name: "Rulesync MCP Server",
8453
+ // eslint-disable-next-line no-type-assertion/no-type-assertion
8454
+ version,
8455
+ instructions: "This server handles Rulesync files including rules, commands, MCP, ignore files, and subagents for any AI agents. It should be used when you need those files."
7871
8456
  });
8457
+ server.addTool(ruleTools.listRules);
8458
+ server.addTool(ruleTools.getRule);
8459
+ server.addTool(ruleTools.putRule);
8460
+ server.addTool(ruleTools.deleteRule);
8461
+ server.addTool(commandTools.listCommands);
8462
+ server.addTool(commandTools.getCommand);
8463
+ server.addTool(commandTools.putCommand);
8464
+ server.addTool(commandTools.deleteCommand);
8465
+ server.addTool(subagentTools.listSubagents);
8466
+ server.addTool(subagentTools.getSubagent);
8467
+ server.addTool(subagentTools.putSubagent);
8468
+ server.addTool(subagentTools.deleteSubagent);
8469
+ server.addTool(ignoreTools.getIgnoreFile);
8470
+ server.addTool(ignoreTools.putIgnoreFile);
8471
+ server.addTool(ignoreTools.deleteIgnoreFile);
8472
+ server.addTool(mcpTools.getMcpFile);
8473
+ server.addTool(mcpTools.putMcpFile);
8474
+ server.addTool(mcpTools.deleteMcpFile);
7872
8475
  logger.info("Rulesync MCP server started via stdio");
7873
8476
  void server.start({
7874
8477
  transportType: "stdio"
@@ -7876,7 +8479,7 @@ async function mcpCommand({ version }) {
7876
8479
  }
7877
8480
 
7878
8481
  // src/cli/index.ts
7879
- var getVersion = () => "3.19.0";
8482
+ var getVersion = () => "3.20.0";
7880
8483
  var main = async () => {
7881
8484
  const program = new Command();
7882
8485
  const version = getVersion();