rulesync 3.19.0 → 3.21.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 -15
  2. package/dist/index.cjs +1417 -802
  3. package/dist/index.js +1284 -669
  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,263 @@ 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/constants/rulesync-paths.ts
435
+ import { join as join2 } from "path";
436
+ var RULESYNC_CONFIG_RELATIVE_FILE_PATH = "rulesync.jsonc";
437
+ var RULESYNC_RELATIVE_DIR_PATH = ".rulesync";
438
+ var RULESYNC_RULES_RELATIVE_DIR_PATH = join2(RULESYNC_RELATIVE_DIR_PATH, "rules");
439
+ var RULESYNC_COMMANDS_RELATIVE_DIR_PATH = join2(RULESYNC_RELATIVE_DIR_PATH, "commands");
440
+ var RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH = join2(RULESYNC_RELATIVE_DIR_PATH, "subagents");
441
+ var RULESYNC_MCP_RELATIVE_FILE_PATH = join2(RULESYNC_RELATIVE_DIR_PATH, "mcp.json");
442
+ var RULESYNC_IGNORE_RELATIVE_FILE_PATH = ".rulesyncignore";
443
+ var RULESYNC_OVERVIEW_FILE_NAME = "overview.md";
444
+
445
+ // src/features/commands/commands-processor.ts
446
+ import { basename as basename11, join as join12 } from "path";
447
+ import { z as z10 } from "zod/mini";
448
+
192
449
  // src/types/feature-processor.ts
193
450
  var FeatureProcessor = class {
194
451
  baseDir;
@@ -219,8 +476,8 @@ var FeatureProcessor = class {
219
476
  }
220
477
  };
221
478
 
222
- // src/commands/agentsmd-command.ts
223
- import { basename as basename3, join as join3 } from "path";
479
+ // src/features/commands/agentsmd-command.ts
480
+ import { basename as basename3, join as join4 } from "path";
224
481
 
225
482
  // src/utils/frontmatter.ts
226
483
  import matter from "gray-matter";
@@ -271,12 +528,12 @@ function parseFrontmatter(content) {
271
528
  return { frontmatter, body };
272
529
  }
273
530
 
274
- // src/commands/simulated-command.ts
275
- import { basename as basename2, join as join2 } from "path";
276
- import { z as z2 } from "zod/mini";
531
+ // src/features/commands/simulated-command.ts
532
+ import { basename as basename2, join as join3 } from "path";
533
+ import { z as z4 } from "zod/mini";
277
534
 
278
535
  // src/types/ai-file.ts
279
- import path, { relative as relative2, resolve as resolve2 } from "path";
536
+ import path, { relative as relative2, resolve as resolve3 } from "path";
280
537
  var AiFile = class {
281
538
  /**
282
539
  * @example "."
@@ -332,8 +589,8 @@ var AiFile = class {
332
589
  }
333
590
  getFilePath() {
334
591
  const fullPath = path.join(this.baseDir, this.relativeDirPath, this.relativeFilePath);
335
- const resolvedFull = resolve2(fullPath);
336
- const resolvedBase = resolve2(this.baseDir);
592
+ const resolvedFull = resolve3(fullPath);
593
+ const resolvedBase = resolve3(this.baseDir);
337
594
  const rel = relative2(resolvedBase, resolvedFull);
338
595
  if (rel.startsWith("..") || path.isAbsolute(rel)) {
339
596
  throw new Error(
@@ -353,7 +610,7 @@ var AiFile = class {
353
610
  }
354
611
  };
355
612
 
356
- // src/commands/tool-command.ts
613
+ // src/features/commands/tool-command.ts
357
614
  var ToolCommand = class extends AiFile {
358
615
  static getSettablePaths() {
359
616
  throw new Error("Please implement this method in the subclass.");
@@ -423,9 +680,9 @@ var ToolCommand = class extends AiFile {
423
680
  }
424
681
  };
425
682
 
426
- // src/commands/simulated-command.ts
427
- var SimulatedCommandFrontmatterSchema = z2.object({
428
- description: z2.string()
683
+ // src/features/commands/simulated-command.ts
684
+ var SimulatedCommandFrontmatterSchema = z4.object({
685
+ description: z4.string()
429
686
  });
430
687
  var SimulatedCommand = class _SimulatedCommand extends ToolCommand {
431
688
  frontmatter;
@@ -435,7 +692,7 @@ var SimulatedCommand = class _SimulatedCommand extends ToolCommand {
435
692
  const result = SimulatedCommandFrontmatterSchema.safeParse(frontmatter);
436
693
  if (!result.success) {
437
694
  throw new Error(
438
- `Invalid frontmatter in ${join2(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
695
+ `Invalid frontmatter in ${join3(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
439
696
  );
440
697
  }
441
698
  }
@@ -485,7 +742,7 @@ var SimulatedCommand = class _SimulatedCommand extends ToolCommand {
485
742
  return {
486
743
  success: false,
487
744
  error: new Error(
488
- `Invalid frontmatter in ${join2(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
745
+ `Invalid frontmatter in ${join3(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
489
746
  )
490
747
  };
491
748
  }
@@ -495,7 +752,7 @@ var SimulatedCommand = class _SimulatedCommand extends ToolCommand {
495
752
  relativeFilePath,
496
753
  validate = true
497
754
  }) {
498
- const filePath = join2(
755
+ const filePath = join3(
499
756
  baseDir,
500
757
  _SimulatedCommand.getSettablePaths().relativeDirPath,
501
758
  relativeFilePath
@@ -517,11 +774,11 @@ var SimulatedCommand = class _SimulatedCommand extends ToolCommand {
517
774
  }
518
775
  };
519
776
 
520
- // src/commands/agentsmd-command.ts
777
+ // src/features/commands/agentsmd-command.ts
521
778
  var AgentsmdCommand = class _AgentsmdCommand extends SimulatedCommand {
522
779
  static getSettablePaths() {
523
780
  return {
524
- relativeDirPath: join3(".agents", "commands")
781
+ relativeDirPath: join4(".agents", "commands")
525
782
  };
526
783
  }
527
784
  static fromRulesyncCommand({
@@ -538,7 +795,7 @@ var AgentsmdCommand = class _AgentsmdCommand extends SimulatedCommand {
538
795
  relativeFilePath,
539
796
  validate = true
540
797
  }) {
541
- const filePath = join3(
798
+ const filePath = join4(
542
799
  baseDir,
543
800
  _AgentsmdCommand.getSettablePaths().relativeDirPath,
544
801
  relativeFilePath
@@ -566,13 +823,13 @@ var AgentsmdCommand = class _AgentsmdCommand extends SimulatedCommand {
566
823
  }
567
824
  };
568
825
 
569
- // src/commands/claudecode-command.ts
570
- import { basename as basename5, join as join5 } from "path";
571
- import { z as z5 } from "zod/mini";
826
+ // src/features/commands/claudecode-command.ts
827
+ import { basename as basename5, join as join6 } from "path";
828
+ import { z as z6 } from "zod/mini";
572
829
 
573
- // src/commands/rulesync-command.ts
574
- import { basename as basename4, join as join4 } from "path";
575
- import { z as z4 } from "zod/mini";
830
+ // src/features/commands/rulesync-command.ts
831
+ import { basename as basename4, join as join5 } from "path";
832
+ import { z as z5 } from "zod/mini";
576
833
 
577
834
  // src/types/rulesync-file.ts
578
835
  var RulesyncFile = class extends AiFile {
@@ -584,36 +841,10 @@ var RulesyncFile = class extends AiFile {
584
841
  }
585
842
  };
586
843
 
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({
844
+ // src/features/commands/rulesync-command.ts
845
+ var RulesyncCommandFrontmatterSchema = z5.object({
615
846
  targets: RulesyncTargetsSchema,
616
- description: z4.string()
847
+ description: z5.string()
617
848
  });
618
849
  var RulesyncCommand = class _RulesyncCommand extends RulesyncFile {
619
850
  frontmatter;
@@ -623,7 +854,7 @@ var RulesyncCommand = class _RulesyncCommand extends RulesyncFile {
623
854
  const result = RulesyncCommandFrontmatterSchema.safeParse(frontmatter);
624
855
  if (!result.success) {
625
856
  throw new Error(
626
- `Invalid frontmatter in ${join4(rest.baseDir ?? process.cwd(), rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
857
+ `Invalid frontmatter in ${join5(rest.baseDir ?? process.cwd(), rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
627
858
  );
628
859
  }
629
860
  }
@@ -636,7 +867,7 @@ var RulesyncCommand = class _RulesyncCommand extends RulesyncFile {
636
867
  }
637
868
  static getSettablePaths() {
638
869
  return {
639
- relativeDirPath: join4(".rulesync", "commands")
870
+ relativeDirPath: RULESYNC_COMMANDS_RELATIVE_DIR_PATH
640
871
  };
641
872
  }
642
873
  getFrontmatter() {
@@ -656,7 +887,7 @@ var RulesyncCommand = class _RulesyncCommand extends RulesyncFile {
656
887
  return {
657
888
  success: false,
658
889
  error: new Error(
659
- `Invalid frontmatter in ${join4(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
890
+ `Invalid frontmatter in ${join5(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
660
891
  )
661
892
  };
662
893
  }
@@ -664,9 +895,12 @@ var RulesyncCommand = class _RulesyncCommand extends RulesyncFile {
664
895
  static async fromFile({
665
896
  relativeFilePath
666
897
  }) {
667
- const fileContent = await readFileContent(
668
- join4(_RulesyncCommand.getSettablePaths().relativeDirPath, relativeFilePath)
898
+ const filePath = join5(
899
+ process.cwd(),
900
+ _RulesyncCommand.getSettablePaths().relativeDirPath,
901
+ relativeFilePath
669
902
  );
903
+ const fileContent = await readFileContent(filePath);
670
904
  const { frontmatter, body: content } = parseFrontmatter(fileContent);
671
905
  const result = RulesyncCommandFrontmatterSchema.safeParse(frontmatter);
672
906
  if (!result.success) {
@@ -684,9 +918,9 @@ var RulesyncCommand = class _RulesyncCommand extends RulesyncFile {
684
918
  }
685
919
  };
686
920
 
687
- // src/commands/claudecode-command.ts
688
- var ClaudecodeCommandFrontmatterSchema = z5.object({
689
- description: z5.string()
921
+ // src/features/commands/claudecode-command.ts
922
+ var ClaudecodeCommandFrontmatterSchema = z6.object({
923
+ description: z6.string()
690
924
  });
691
925
  var ClaudecodeCommand = class _ClaudecodeCommand extends ToolCommand {
692
926
  frontmatter;
@@ -696,7 +930,7 @@ var ClaudecodeCommand = class _ClaudecodeCommand extends ToolCommand {
696
930
  const result = ClaudecodeCommandFrontmatterSchema.safeParse(frontmatter);
697
931
  if (!result.success) {
698
932
  throw new Error(
699
- `Invalid frontmatter in ${join5(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
933
+ `Invalid frontmatter in ${join6(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
700
934
  );
701
935
  }
702
936
  }
@@ -709,7 +943,7 @@ var ClaudecodeCommand = class _ClaudecodeCommand extends ToolCommand {
709
943
  }
710
944
  static getSettablePaths(_options = {}) {
711
945
  return {
712
- relativeDirPath: join5(".claude", "commands")
946
+ relativeDirPath: join6(".claude", "commands")
713
947
  };
714
948
  }
715
949
  getBody() {
@@ -767,7 +1001,7 @@ var ClaudecodeCommand = class _ClaudecodeCommand extends ToolCommand {
767
1001
  return {
768
1002
  success: false,
769
1003
  error: new Error(
770
- `Invalid frontmatter in ${join5(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
1004
+ `Invalid frontmatter in ${join6(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
771
1005
  )
772
1006
  };
773
1007
  }
@@ -785,7 +1019,7 @@ var ClaudecodeCommand = class _ClaudecodeCommand extends ToolCommand {
785
1019
  global = false
786
1020
  }) {
787
1021
  const paths = this.getSettablePaths({ global });
788
- const filePath = join5(baseDir, paths.relativeDirPath, relativeFilePath);
1022
+ const filePath = join6(baseDir, paths.relativeDirPath, relativeFilePath);
789
1023
  const fileContent = await readFileContent(filePath);
790
1024
  const { frontmatter, body: content } = parseFrontmatter(fileContent);
791
1025
  const result = ClaudecodeCommandFrontmatterSchema.safeParse(frontmatter);
@@ -803,15 +1037,15 @@ var ClaudecodeCommand = class _ClaudecodeCommand extends ToolCommand {
803
1037
  }
804
1038
  };
805
1039
 
806
- // src/commands/codexcli-command.ts
807
- import { basename as basename6, join as join6 } from "path";
1040
+ // src/features/commands/codexcli-command.ts
1041
+ import { basename as basename6, join as join7 } from "path";
808
1042
  var CodexcliCommand = class _CodexcliCommand extends ToolCommand {
809
1043
  static getSettablePaths({ global } = {}) {
810
1044
  if (!global) {
811
1045
  throw new Error("CodexcliCommand only supports global mode. Please pass { global: true }.");
812
1046
  }
813
1047
  return {
814
- relativeDirPath: join6(".codex", "prompts")
1048
+ relativeDirPath: join7(".codex", "prompts")
815
1049
  };
816
1050
  }
817
1051
  toRulesyncCommand() {
@@ -864,7 +1098,7 @@ var CodexcliCommand = class _CodexcliCommand extends ToolCommand {
864
1098
  global = false
865
1099
  }) {
866
1100
  const paths = this.getSettablePaths({ global });
867
- const filePath = join6(baseDir, paths.relativeDirPath, relativeFilePath);
1101
+ const filePath = join7(baseDir, paths.relativeDirPath, relativeFilePath);
868
1102
  const fileContent = await readFileContent(filePath);
869
1103
  const { body: content } = parseFrontmatter(fileContent);
870
1104
  return new _CodexcliCommand({
@@ -877,12 +1111,12 @@ var CodexcliCommand = class _CodexcliCommand extends ToolCommand {
877
1111
  }
878
1112
  };
879
1113
 
880
- // src/commands/copilot-command.ts
881
- 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()
1114
+ // src/features/commands/copilot-command.ts
1115
+ import { basename as basename7, join as join8 } from "path";
1116
+ import { z as z7 } from "zod/mini";
1117
+ var CopilotCommandFrontmatterSchema = z7.object({
1118
+ mode: z7.literal("agent"),
1119
+ description: z7.string()
886
1120
  });
887
1121
  var CopilotCommand = class _CopilotCommand extends ToolCommand {
888
1122
  frontmatter;
@@ -892,7 +1126,7 @@ var CopilotCommand = class _CopilotCommand extends ToolCommand {
892
1126
  const result = CopilotCommandFrontmatterSchema.safeParse(frontmatter);
893
1127
  if (!result.success) {
894
1128
  throw new Error(
895
- `Invalid frontmatter in ${join7(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
1129
+ `Invalid frontmatter in ${join8(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
896
1130
  );
897
1131
  }
898
1132
  }
@@ -905,7 +1139,7 @@ var CopilotCommand = class _CopilotCommand extends ToolCommand {
905
1139
  }
906
1140
  static getSettablePaths() {
907
1141
  return {
908
- relativeDirPath: join7(".github", "prompts")
1142
+ relativeDirPath: join8(".github", "prompts")
909
1143
  };
910
1144
  }
911
1145
  getBody() {
@@ -942,7 +1176,7 @@ var CopilotCommand = class _CopilotCommand extends ToolCommand {
942
1176
  return {
943
1177
  success: false,
944
1178
  error: new Error(
945
- `Invalid frontmatter in ${join7(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
1179
+ `Invalid frontmatter in ${join8(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
946
1180
  )
947
1181
  };
948
1182
  }
@@ -976,7 +1210,7 @@ var CopilotCommand = class _CopilotCommand extends ToolCommand {
976
1210
  validate = true
977
1211
  }) {
978
1212
  const paths = this.getSettablePaths();
979
- const filePath = join7(baseDir, paths.relativeDirPath, relativeFilePath);
1213
+ const filePath = join8(baseDir, paths.relativeDirPath, relativeFilePath);
980
1214
  const fileContent = await readFileContent(filePath);
981
1215
  const { frontmatter, body: content } = parseFrontmatter(fileContent);
982
1216
  const result = CopilotCommandFrontmatterSchema.safeParse(frontmatter);
@@ -1000,12 +1234,12 @@ var CopilotCommand = class _CopilotCommand extends ToolCommand {
1000
1234
  }
1001
1235
  };
1002
1236
 
1003
- // src/commands/cursor-command.ts
1004
- import { basename as basename8, join as join8 } from "path";
1237
+ // src/features/commands/cursor-command.ts
1238
+ import { basename as basename8, join as join9 } from "path";
1005
1239
  var CursorCommand = class _CursorCommand extends ToolCommand {
1006
1240
  static getSettablePaths(_options = {}) {
1007
1241
  return {
1008
- relativeDirPath: join8(".cursor", "commands")
1242
+ relativeDirPath: join9(".cursor", "commands")
1009
1243
  };
1010
1244
  }
1011
1245
  toRulesyncCommand() {
@@ -1058,7 +1292,7 @@ var CursorCommand = class _CursorCommand extends ToolCommand {
1058
1292
  global = false
1059
1293
  }) {
1060
1294
  const paths = this.getSettablePaths({ global });
1061
- const filePath = join8(baseDir, paths.relativeDirPath, relativeFilePath);
1295
+ const filePath = join9(baseDir, paths.relativeDirPath, relativeFilePath);
1062
1296
  const fileContent = await readFileContent(filePath);
1063
1297
  const { body: content } = parseFrontmatter(fileContent);
1064
1298
  return new _CursorCommand({
@@ -1071,13 +1305,13 @@ var CursorCommand = class _CursorCommand extends ToolCommand {
1071
1305
  }
1072
1306
  };
1073
1307
 
1074
- // src/commands/geminicli-command.ts
1075
- import { basename as basename9, join as join9 } from "path";
1308
+ // src/features/commands/geminicli-command.ts
1309
+ import { basename as basename9, join as join10 } from "path";
1076
1310
  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()
1311
+ import { z as z8 } from "zod/mini";
1312
+ var GeminiCliCommandFrontmatterSchema = z8.object({
1313
+ description: z8.optional(z8.string()),
1314
+ prompt: z8.string()
1081
1315
  });
1082
1316
  var GeminiCliCommand = class _GeminiCliCommand extends ToolCommand {
1083
1317
  frontmatter;
@@ -1090,7 +1324,7 @@ var GeminiCliCommand = class _GeminiCliCommand extends ToolCommand {
1090
1324
  }
1091
1325
  static getSettablePaths(_options = {}) {
1092
1326
  return {
1093
- relativeDirPath: join9(".gemini", "commands")
1327
+ relativeDirPath: join10(".gemini", "commands")
1094
1328
  };
1095
1329
  }
1096
1330
  parseTomlContent(content) {
@@ -1167,7 +1401,7 @@ ${geminiFrontmatter.prompt}
1167
1401
  global = false
1168
1402
  }) {
1169
1403
  const paths = this.getSettablePaths({ global });
1170
- const filePath = join9(baseDir, paths.relativeDirPath, relativeFilePath);
1404
+ const filePath = join10(baseDir, paths.relativeDirPath, relativeFilePath);
1171
1405
  const fileContent = await readFileContent(filePath);
1172
1406
  return new _GeminiCliCommand({
1173
1407
  baseDir,
@@ -1193,19 +1427,19 @@ ${geminiFrontmatter.prompt}
1193
1427
  }
1194
1428
  };
1195
1429
 
1196
- // src/commands/roo-command.ts
1197
- 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())
1430
+ // src/features/commands/roo-command.ts
1431
+ import { basename as basename10, join as join11 } from "path";
1432
+ import { optional as optional2, z as z9 } from "zod/mini";
1433
+ var RooCommandFrontmatterSchema = z9.object({
1434
+ description: z9.string(),
1435
+ "argument-hint": optional2(z9.string())
1202
1436
  });
1203
1437
  var RooCommand = class _RooCommand extends ToolCommand {
1204
1438
  frontmatter;
1205
1439
  body;
1206
1440
  static getSettablePaths() {
1207
1441
  return {
1208
- relativeDirPath: join10(".roo", "commands")
1442
+ relativeDirPath: join11(".roo", "commands")
1209
1443
  };
1210
1444
  }
1211
1445
  constructor({ frontmatter, body, ...rest }) {
@@ -1213,7 +1447,7 @@ var RooCommand = class _RooCommand extends ToolCommand {
1213
1447
  const result = RooCommandFrontmatterSchema.safeParse(frontmatter);
1214
1448
  if (!result.success) {
1215
1449
  throw new Error(
1216
- `Invalid frontmatter in ${join10(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
1450
+ `Invalid frontmatter in ${join11(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
1217
1451
  );
1218
1452
  }
1219
1453
  }
@@ -1279,7 +1513,7 @@ var RooCommand = class _RooCommand extends ToolCommand {
1279
1513
  return {
1280
1514
  success: false,
1281
1515
  error: new Error(
1282
- `Invalid frontmatter in ${join10(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
1516
+ `Invalid frontmatter in ${join11(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
1283
1517
  )
1284
1518
  };
1285
1519
  }
@@ -1295,7 +1529,7 @@ var RooCommand = class _RooCommand extends ToolCommand {
1295
1529
  relativeFilePath,
1296
1530
  validate = true
1297
1531
  }) {
1298
- const filePath = join10(baseDir, _RooCommand.getSettablePaths().relativeDirPath, relativeFilePath);
1532
+ const filePath = join11(baseDir, _RooCommand.getSettablePaths().relativeDirPath, relativeFilePath);
1299
1533
  const fileContent = await readFileContent(filePath);
1300
1534
  const { frontmatter, body: content } = parseFrontmatter(fileContent);
1301
1535
  const result = RooCommandFrontmatterSchema.safeParse(frontmatter);
@@ -1314,7 +1548,7 @@ var RooCommand = class _RooCommand extends ToolCommand {
1314
1548
  }
1315
1549
  };
1316
1550
 
1317
- // src/commands/commands-processor.ts
1551
+ // src/features/commands/commands-processor.ts
1318
1552
  var commandsProcessorToolTargets = [
1319
1553
  "agentsmd",
1320
1554
  "claudecode",
@@ -1323,7 +1557,7 @@ var commandsProcessorToolTargets = [
1323
1557
  "copilot",
1324
1558
  "cursor"
1325
1559
  ];
1326
- var CommandsProcessorToolTargetSchema = z9.enum(
1560
+ var CommandsProcessorToolTargetSchema = z10.enum(
1327
1561
  // 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
1562
  commandsProcessorToolTargets.concat("codexcli")
1329
1563
  );
@@ -1441,7 +1675,7 @@ var CommandsProcessor = class extends FeatureProcessor {
1441
1675
  */
1442
1676
  async loadRulesyncFiles() {
1443
1677
  const rulesyncCommandPaths = await findFilesByGlobs(
1444
- join11(RulesyncCommand.getSettablePaths().relativeDirPath, "*.md")
1678
+ join12(RulesyncCommand.getSettablePaths().relativeDirPath, "*.md")
1445
1679
  );
1446
1680
  const rulesyncCommands = (await Promise.allSettled(
1447
1681
  rulesyncCommandPaths.map(
@@ -1484,7 +1718,7 @@ var CommandsProcessor = class extends FeatureProcessor {
1484
1718
  extension
1485
1719
  }) {
1486
1720
  const commandFilePaths = await findFilesByGlobs(
1487
- join11(this.baseDir, relativeDirPath, `*.${extension}`)
1721
+ join12(this.baseDir, relativeDirPath, `*.${extension}`)
1488
1722
  );
1489
1723
  const toolCommands = (await Promise.allSettled(
1490
1724
  commandFilePaths.map((path2) => {
@@ -1632,233 +1866,18 @@ var CommandsProcessor = class extends FeatureProcessor {
1632
1866
  }
1633
1867
  };
1634
1868
 
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
1869
+ // src/features/ignore/ignore-processor.ts
1851
1870
  import { z as z11 } from "zod/mini";
1852
1871
 
1853
- // src/ignore/amazonqcli-ignore.ts
1854
- import { join as join13 } from "path";
1872
+ // src/features/ignore/amazonqcli-ignore.ts
1873
+ import { join as join14 } from "path";
1855
1874
 
1856
1875
  // src/types/tool-file.ts
1857
1876
  var ToolFile = class extends AiFile {
1858
1877
  };
1859
1878
 
1860
- // src/ignore/rulesync-ignore.ts
1861
- import { join as join12 } from "path";
1879
+ // src/features/ignore/rulesync-ignore.ts
1880
+ import { join as join13 } from "path";
1862
1881
  var RulesyncIgnore = class _RulesyncIgnore extends RulesyncFile {
1863
1882
  validate() {
1864
1883
  return { success: true, error: null };
@@ -1866,12 +1885,12 @@ var RulesyncIgnore = class _RulesyncIgnore extends RulesyncFile {
1866
1885
  static getSettablePaths() {
1867
1886
  return {
1868
1887
  relativeDirPath: ".",
1869
- relativeFilePath: ".rulesyncignore"
1888
+ relativeFilePath: RULESYNC_IGNORE_RELATIVE_FILE_PATH
1870
1889
  };
1871
1890
  }
1872
1891
  static async fromFile() {
1873
1892
  const baseDir = process.cwd();
1874
- const filePath = join12(baseDir, this.getSettablePaths().relativeFilePath);
1893
+ const filePath = join13(baseDir, this.getSettablePaths().relativeFilePath);
1875
1894
  const fileContent = await readFileContent(filePath);
1876
1895
  return new _RulesyncIgnore({
1877
1896
  baseDir,
@@ -1882,7 +1901,7 @@ var RulesyncIgnore = class _RulesyncIgnore extends RulesyncFile {
1882
1901
  }
1883
1902
  };
1884
1903
 
1885
- // src/ignore/tool-ignore.ts
1904
+ // src/features/ignore/tool-ignore.ts
1886
1905
  var ToolIgnore = class extends ToolFile {
1887
1906
  patterns;
1888
1907
  constructor(params) {
@@ -1914,7 +1933,7 @@ var ToolIgnore = class extends ToolFile {
1914
1933
  return new RulesyncIgnore({
1915
1934
  baseDir: ".",
1916
1935
  relativeDirPath: ".",
1917
- relativeFilePath: ".rulesyncignore",
1936
+ relativeFilePath: RULESYNC_IGNORE_RELATIVE_FILE_PATH,
1918
1937
  fileContent: this.fileContent
1919
1938
  });
1920
1939
  }
@@ -1923,7 +1942,7 @@ var ToolIgnore = class extends ToolFile {
1923
1942
  }
1924
1943
  };
1925
1944
 
1926
- // src/ignore/amazonqcli-ignore.ts
1945
+ // src/features/ignore/amazonqcli-ignore.ts
1927
1946
  var AmazonqcliIgnore = class _AmazonqcliIgnore extends ToolIgnore {
1928
1947
  static getSettablePaths() {
1929
1948
  return {
@@ -1962,7 +1981,7 @@ var AmazonqcliIgnore = class _AmazonqcliIgnore extends ToolIgnore {
1962
1981
  validate = true
1963
1982
  }) {
1964
1983
  const fileContent = await readFileContent(
1965
- join13(
1984
+ join14(
1966
1985
  baseDir,
1967
1986
  this.getSettablePaths().relativeDirPath,
1968
1987
  this.getSettablePaths().relativeFilePath
@@ -1978,8 +1997,8 @@ var AmazonqcliIgnore = class _AmazonqcliIgnore extends ToolIgnore {
1978
1997
  }
1979
1998
  };
1980
1999
 
1981
- // src/ignore/augmentcode-ignore.ts
1982
- import { join as join14 } from "path";
2000
+ // src/features/ignore/augmentcode-ignore.ts
2001
+ import { join as join15 } from "path";
1983
2002
  var AugmentcodeIgnore = class _AugmentcodeIgnore extends ToolIgnore {
1984
2003
  static getSettablePaths() {
1985
2004
  return {
@@ -2017,7 +2036,7 @@ var AugmentcodeIgnore = class _AugmentcodeIgnore extends ToolIgnore {
2017
2036
  validate = true
2018
2037
  }) {
2019
2038
  const fileContent = await readFileContent(
2020
- join14(
2039
+ join15(
2021
2040
  baseDir,
2022
2041
  this.getSettablePaths().relativeDirPath,
2023
2042
  this.getSettablePaths().relativeFilePath
@@ -2033,8 +2052,8 @@ var AugmentcodeIgnore = class _AugmentcodeIgnore extends ToolIgnore {
2033
2052
  }
2034
2053
  };
2035
2054
 
2036
- // src/ignore/claudecode-ignore.ts
2037
- import { join as join15 } from "path";
2055
+ // src/features/ignore/claudecode-ignore.ts
2056
+ import { join as join16 } from "path";
2038
2057
  import { uniq } from "es-toolkit";
2039
2058
  var ClaudecodeIgnore = class _ClaudecodeIgnore extends ToolIgnore {
2040
2059
  constructor(params) {
@@ -2070,7 +2089,7 @@ var ClaudecodeIgnore = class _ClaudecodeIgnore extends ToolIgnore {
2070
2089
  const fileContent = rulesyncIgnore.getFileContent();
2071
2090
  const patterns = fileContent.split(/\r?\n|\r/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
2072
2091
  const deniedValues = patterns.map((pattern) => `Read(${pattern})`);
2073
- const filePath = join15(
2092
+ const filePath = join16(
2074
2093
  baseDir,
2075
2094
  this.getSettablePaths().relativeDirPath,
2076
2095
  this.getSettablePaths().relativeFilePath
@@ -2098,7 +2117,7 @@ var ClaudecodeIgnore = class _ClaudecodeIgnore extends ToolIgnore {
2098
2117
  validate = true
2099
2118
  }) {
2100
2119
  const fileContent = await readFileContent(
2101
- join15(
2120
+ join16(
2102
2121
  baseDir,
2103
2122
  this.getSettablePaths().relativeDirPath,
2104
2123
  this.getSettablePaths().relativeFilePath
@@ -2114,8 +2133,8 @@ var ClaudecodeIgnore = class _ClaudecodeIgnore extends ToolIgnore {
2114
2133
  }
2115
2134
  };
2116
2135
 
2117
- // src/ignore/cline-ignore.ts
2118
- import { join as join16 } from "path";
2136
+ // src/features/ignore/cline-ignore.ts
2137
+ import { join as join17 } from "path";
2119
2138
  var ClineIgnore = class _ClineIgnore extends ToolIgnore {
2120
2139
  static getSettablePaths() {
2121
2140
  return {
@@ -2152,7 +2171,7 @@ var ClineIgnore = class _ClineIgnore extends ToolIgnore {
2152
2171
  validate = true
2153
2172
  }) {
2154
2173
  const fileContent = await readFileContent(
2155
- join16(
2174
+ join17(
2156
2175
  baseDir,
2157
2176
  this.getSettablePaths().relativeDirPath,
2158
2177
  this.getSettablePaths().relativeFilePath
@@ -2168,8 +2187,8 @@ var ClineIgnore = class _ClineIgnore extends ToolIgnore {
2168
2187
  }
2169
2188
  };
2170
2189
 
2171
- // src/ignore/cursor-ignore.ts
2172
- import { join as join17 } from "path";
2190
+ // src/features/ignore/cursor-ignore.ts
2191
+ import { join as join18 } from "path";
2173
2192
  var CursorIgnore = class _CursorIgnore extends ToolIgnore {
2174
2193
  static getSettablePaths() {
2175
2194
  return {
@@ -2181,7 +2200,7 @@ var CursorIgnore = class _CursorIgnore extends ToolIgnore {
2181
2200
  return new RulesyncIgnore({
2182
2201
  baseDir: ".",
2183
2202
  relativeDirPath: ".",
2184
- relativeFilePath: ".rulesyncignore",
2203
+ relativeFilePath: RULESYNC_IGNORE_RELATIVE_FILE_PATH,
2185
2204
  fileContent: this.fileContent
2186
2205
  });
2187
2206
  }
@@ -2202,7 +2221,7 @@ var CursorIgnore = class _CursorIgnore extends ToolIgnore {
2202
2221
  validate = true
2203
2222
  }) {
2204
2223
  const fileContent = await readFileContent(
2205
- join17(
2224
+ join18(
2206
2225
  baseDir,
2207
2226
  this.getSettablePaths().relativeDirPath,
2208
2227
  this.getSettablePaths().relativeFilePath
@@ -2218,8 +2237,8 @@ var CursorIgnore = class _CursorIgnore extends ToolIgnore {
2218
2237
  }
2219
2238
  };
2220
2239
 
2221
- // src/ignore/geminicli-ignore.ts
2222
- import { join as join18 } from "path";
2240
+ // src/features/ignore/geminicli-ignore.ts
2241
+ import { join as join19 } from "path";
2223
2242
  var GeminiCliIgnore = class _GeminiCliIgnore extends ToolIgnore {
2224
2243
  static getSettablePaths() {
2225
2244
  return {
@@ -2246,7 +2265,7 @@ var GeminiCliIgnore = class _GeminiCliIgnore extends ToolIgnore {
2246
2265
  validate = true
2247
2266
  }) {
2248
2267
  const fileContent = await readFileContent(
2249
- join18(
2268
+ join19(
2250
2269
  baseDir,
2251
2270
  this.getSettablePaths().relativeDirPath,
2252
2271
  this.getSettablePaths().relativeFilePath
@@ -2262,8 +2281,8 @@ var GeminiCliIgnore = class _GeminiCliIgnore extends ToolIgnore {
2262
2281
  }
2263
2282
  };
2264
2283
 
2265
- // src/ignore/junie-ignore.ts
2266
- import { join as join19 } from "path";
2284
+ // src/features/ignore/junie-ignore.ts
2285
+ import { join as join20 } from "path";
2267
2286
  var JunieIgnore = class _JunieIgnore extends ToolIgnore {
2268
2287
  static getSettablePaths() {
2269
2288
  return {
@@ -2290,7 +2309,7 @@ var JunieIgnore = class _JunieIgnore extends ToolIgnore {
2290
2309
  validate = true
2291
2310
  }) {
2292
2311
  const fileContent = await readFileContent(
2293
- join19(
2312
+ join20(
2294
2313
  baseDir,
2295
2314
  this.getSettablePaths().relativeDirPath,
2296
2315
  this.getSettablePaths().relativeFilePath
@@ -2306,8 +2325,8 @@ var JunieIgnore = class _JunieIgnore extends ToolIgnore {
2306
2325
  }
2307
2326
  };
2308
2327
 
2309
- // src/ignore/kiro-ignore.ts
2310
- import { join as join20 } from "path";
2328
+ // src/features/ignore/kiro-ignore.ts
2329
+ import { join as join21 } from "path";
2311
2330
  var KiroIgnore = class _KiroIgnore extends ToolIgnore {
2312
2331
  static getSettablePaths() {
2313
2332
  return {
@@ -2334,7 +2353,7 @@ var KiroIgnore = class _KiroIgnore extends ToolIgnore {
2334
2353
  validate = true
2335
2354
  }) {
2336
2355
  const fileContent = await readFileContent(
2337
- join20(
2356
+ join21(
2338
2357
  baseDir,
2339
2358
  this.getSettablePaths().relativeDirPath,
2340
2359
  this.getSettablePaths().relativeFilePath
@@ -2350,8 +2369,8 @@ var KiroIgnore = class _KiroIgnore extends ToolIgnore {
2350
2369
  }
2351
2370
  };
2352
2371
 
2353
- // src/ignore/qwencode-ignore.ts
2354
- import { join as join21 } from "path";
2372
+ // src/features/ignore/qwencode-ignore.ts
2373
+ import { join as join22 } from "path";
2355
2374
  var QwencodeIgnore = class _QwencodeIgnore extends ToolIgnore {
2356
2375
  static getSettablePaths() {
2357
2376
  return {
@@ -2378,7 +2397,7 @@ var QwencodeIgnore = class _QwencodeIgnore extends ToolIgnore {
2378
2397
  validate = true
2379
2398
  }) {
2380
2399
  const fileContent = await readFileContent(
2381
- join21(
2400
+ join22(
2382
2401
  baseDir,
2383
2402
  this.getSettablePaths().relativeDirPath,
2384
2403
  this.getSettablePaths().relativeFilePath
@@ -2394,8 +2413,8 @@ var QwencodeIgnore = class _QwencodeIgnore extends ToolIgnore {
2394
2413
  }
2395
2414
  };
2396
2415
 
2397
- // src/ignore/roo-ignore.ts
2398
- import { join as join22 } from "path";
2416
+ // src/features/ignore/roo-ignore.ts
2417
+ import { join as join23 } from "path";
2399
2418
  var RooIgnore = class _RooIgnore extends ToolIgnore {
2400
2419
  static getSettablePaths() {
2401
2420
  return {
@@ -2422,7 +2441,7 @@ var RooIgnore = class _RooIgnore extends ToolIgnore {
2422
2441
  validate = true
2423
2442
  }) {
2424
2443
  const fileContent = await readFileContent(
2425
- join22(
2444
+ join23(
2426
2445
  baseDir,
2427
2446
  this.getSettablePaths().relativeDirPath,
2428
2447
  this.getSettablePaths().relativeFilePath
@@ -2438,8 +2457,8 @@ var RooIgnore = class _RooIgnore extends ToolIgnore {
2438
2457
  }
2439
2458
  };
2440
2459
 
2441
- // src/ignore/windsurf-ignore.ts
2442
- import { join as join23 } from "path";
2460
+ // src/features/ignore/windsurf-ignore.ts
2461
+ import { join as join24 } from "path";
2443
2462
  var WindsurfIgnore = class _WindsurfIgnore extends ToolIgnore {
2444
2463
  static getSettablePaths() {
2445
2464
  return {
@@ -2466,7 +2485,7 @@ var WindsurfIgnore = class _WindsurfIgnore extends ToolIgnore {
2466
2485
  validate = true
2467
2486
  }) {
2468
2487
  const fileContent = await readFileContent(
2469
- join23(
2488
+ join24(
2470
2489
  baseDir,
2471
2490
  this.getSettablePaths().relativeDirPath,
2472
2491
  this.getSettablePaths().relativeFilePath
@@ -2482,7 +2501,7 @@ var WindsurfIgnore = class _WindsurfIgnore extends ToolIgnore {
2482
2501
  }
2483
2502
  };
2484
2503
 
2485
- // src/ignore/ignore-processor.ts
2504
+ // src/features/ignore/ignore-processor.ts
2486
2505
  var ignoreProcessorToolTargets = [
2487
2506
  "amazonqcli",
2488
2507
  "augmentcode",
@@ -2583,7 +2602,7 @@ var IgnoreProcessor = class extends FeatureProcessor {
2583
2602
  (file) => file instanceof RulesyncIgnore
2584
2603
  );
2585
2604
  if (!rulesyncIgnore) {
2586
- throw new Error(`No .rulesyncignore found.`);
2605
+ throw new Error(`No ${RULESYNC_IGNORE_RELATIVE_FILE_PATH} found.`);
2587
2606
  }
2588
2607
  const toolIgnores = await Promise.all(
2589
2608
  [rulesyncIgnore].map(async (rulesyncIgnore2) => {
@@ -2670,14 +2689,14 @@ var IgnoreProcessor = class extends FeatureProcessor {
2670
2689
  }
2671
2690
  };
2672
2691
 
2673
- // src/mcp/mcp-processor.ts
2692
+ // src/features/mcp/mcp-processor.ts
2674
2693
  import { z as z13 } from "zod/mini";
2675
2694
 
2676
- // src/mcp/amazonqcli-mcp.ts
2677
- import { join as join25 } from "path";
2695
+ // src/features/mcp/amazonqcli-mcp.ts
2696
+ import { join as join26 } from "path";
2678
2697
 
2679
- // src/mcp/rulesync-mcp.ts
2680
- import { join as join24 } from "path";
2698
+ // src/features/mcp/rulesync-mcp.ts
2699
+ import { join as join25 } from "path";
2681
2700
  import { omit } from "es-toolkit/object";
2682
2701
  import { z as z12 } from "zod/mini";
2683
2702
  var McpTransportTypeSchema = z12.enum(["stdio", "sse", "http"]);
@@ -2728,11 +2747,11 @@ var RulesyncMcp = class _RulesyncMcp extends RulesyncFile {
2728
2747
  static getSettablePaths() {
2729
2748
  return {
2730
2749
  recommended: {
2731
- relativeDirPath: ".rulesync",
2750
+ relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
2732
2751
  relativeFilePath: "mcp.json"
2733
2752
  },
2734
2753
  legacy: {
2735
- relativeDirPath: ".rulesync",
2754
+ relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
2736
2755
  relativeFilePath: ".mcp.json"
2737
2756
  }
2738
2757
  };
@@ -2757,12 +2776,12 @@ var RulesyncMcp = class _RulesyncMcp extends RulesyncFile {
2757
2776
  }) {
2758
2777
  const baseDir = process.cwd();
2759
2778
  const paths = this.getSettablePaths();
2760
- const recommendedPath = join24(
2779
+ const recommendedPath = join25(
2761
2780
  baseDir,
2762
2781
  paths.recommended.relativeDirPath,
2763
2782
  paths.recommended.relativeFilePath
2764
2783
  );
2765
- const legacyPath = join24(baseDir, paths.legacy.relativeDirPath, paths.legacy.relativeFilePath);
2784
+ const legacyPath = join25(baseDir, paths.legacy.relativeDirPath, paths.legacy.relativeFilePath);
2766
2785
  if (await fileExists(recommendedPath)) {
2767
2786
  const fileContent2 = await readFileContent(recommendedPath);
2768
2787
  return new _RulesyncMcp({
@@ -2821,7 +2840,7 @@ var RulesyncMcp = class _RulesyncMcp extends RulesyncFile {
2821
2840
  }
2822
2841
  };
2823
2842
 
2824
- // src/mcp/tool-mcp.ts
2843
+ // src/features/mcp/tool-mcp.ts
2825
2844
  var ToolMcp = class extends ToolFile {
2826
2845
  constructor({ ...rest }) {
2827
2846
  super({
@@ -2847,7 +2866,7 @@ var ToolMcp = class extends ToolFile {
2847
2866
  } = {}) {
2848
2867
  return new RulesyncMcp({
2849
2868
  baseDir: this.baseDir,
2850
- relativeDirPath: ".rulesync",
2869
+ relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
2851
2870
  relativeFilePath: ".mcp.json",
2852
2871
  fileContent: fileContent ?? this.fileContent
2853
2872
  });
@@ -2860,7 +2879,7 @@ var ToolMcp = class extends ToolFile {
2860
2879
  }
2861
2880
  };
2862
2881
 
2863
- // src/mcp/amazonqcli-mcp.ts
2882
+ // src/features/mcp/amazonqcli-mcp.ts
2864
2883
  var AmazonqcliMcp = class _AmazonqcliMcp extends ToolMcp {
2865
2884
  json;
2866
2885
  constructor(params) {
@@ -2881,7 +2900,7 @@ var AmazonqcliMcp = class _AmazonqcliMcp extends ToolMcp {
2881
2900
  validate = true
2882
2901
  }) {
2883
2902
  const fileContent = await readFileContent(
2884
- join25(
2903
+ join26(
2885
2904
  baseDir,
2886
2905
  this.getSettablePaths().relativeDirPath,
2887
2906
  this.getSettablePaths().relativeFilePath
@@ -2916,11 +2935,11 @@ var AmazonqcliMcp = class _AmazonqcliMcp extends ToolMcp {
2916
2935
  }
2917
2936
  };
2918
2937
 
2919
- // src/mcp/claudecode-mcp.ts
2920
- import { join as join27 } from "path";
2938
+ // src/features/mcp/claudecode-mcp.ts
2939
+ import { join as join28 } from "path";
2921
2940
 
2922
- // src/mcp/modular-mcp.ts
2923
- import { join as join26 } from "path";
2941
+ // src/features/mcp/modular-mcp.ts
2942
+ import { join as join27 } from "path";
2924
2943
  var ModularMcp = class _ModularMcp extends AiFile {
2925
2944
  json;
2926
2945
  constructor(params) {
@@ -2975,7 +2994,7 @@ var ModularMcp = class _ModularMcp extends AiFile {
2975
2994
  args: [
2976
2995
  "-y",
2977
2996
  "@kimuson/modular-mcp",
2978
- join26(baseDir, paths.relativeDirPath, paths.relativeFilePath)
2997
+ join27(baseDir, paths.relativeDirPath, paths.relativeFilePath)
2979
2998
  ],
2980
2999
  env: {}
2981
3000
  }
@@ -3007,7 +3026,7 @@ var ModularMcp = class _ModularMcp extends AiFile {
3007
3026
  }
3008
3027
  };
3009
3028
 
3010
- // src/mcp/claudecode-mcp.ts
3029
+ // src/features/mcp/claudecode-mcp.ts
3011
3030
  var ClaudecodeMcp = class _ClaudecodeMcp extends ToolMcp {
3012
3031
  json;
3013
3032
  constructor(params) {
@@ -3036,7 +3055,7 @@ var ClaudecodeMcp = class _ClaudecodeMcp extends ToolMcp {
3036
3055
  }) {
3037
3056
  const paths = this.getSettablePaths({ global });
3038
3057
  const fileContent = await readOrInitializeFileContent(
3039
- join27(baseDir, paths.relativeDirPath, paths.relativeFilePath),
3058
+ join28(baseDir, paths.relativeDirPath, paths.relativeFilePath),
3040
3059
  JSON.stringify({ mcpServers: {} }, null, 2)
3041
3060
  );
3042
3061
  const json = JSON.parse(fileContent);
@@ -3058,7 +3077,7 @@ var ClaudecodeMcp = class _ClaudecodeMcp extends ToolMcp {
3058
3077
  }) {
3059
3078
  const paths = this.getSettablePaths({ global });
3060
3079
  const fileContent = await readOrInitializeFileContent(
3061
- join27(baseDir, paths.relativeDirPath, paths.relativeFilePath),
3080
+ join28(baseDir, paths.relativeDirPath, paths.relativeFilePath),
3062
3081
  JSON.stringify({ mcpServers: {} }, null, 2)
3063
3082
  );
3064
3083
  const json = JSON.parse(fileContent);
@@ -3088,8 +3107,8 @@ var ClaudecodeMcp = class _ClaudecodeMcp extends ToolMcp {
3088
3107
  }
3089
3108
  };
3090
3109
 
3091
- // src/mcp/cline-mcp.ts
3092
- import { join as join28 } from "path";
3110
+ // src/features/mcp/cline-mcp.ts
3111
+ import { join as join29 } from "path";
3093
3112
  var ClineMcp = class _ClineMcp extends ToolMcp {
3094
3113
  json;
3095
3114
  constructor(params) {
@@ -3110,7 +3129,7 @@ var ClineMcp = class _ClineMcp extends ToolMcp {
3110
3129
  validate = true
3111
3130
  }) {
3112
3131
  const fileContent = await readFileContent(
3113
- join28(
3132
+ join29(
3114
3133
  baseDir,
3115
3134
  this.getSettablePaths().relativeDirPath,
3116
3135
  this.getSettablePaths().relativeFilePath
@@ -3145,8 +3164,8 @@ var ClineMcp = class _ClineMcp extends ToolMcp {
3145
3164
  }
3146
3165
  };
3147
3166
 
3148
- // src/mcp/codexcli-mcp.ts
3149
- import { join as join29 } from "path";
3167
+ // src/features/mcp/codexcli-mcp.ts
3168
+ import { join as join30 } from "path";
3150
3169
  import * as smolToml from "smol-toml";
3151
3170
  var CodexcliMcp = class _CodexcliMcp extends ToolMcp {
3152
3171
  toml;
@@ -3182,7 +3201,7 @@ var CodexcliMcp = class _CodexcliMcp extends ToolMcp {
3182
3201
  }) {
3183
3202
  const paths = this.getSettablePaths({ global });
3184
3203
  const fileContent = await readFileContent(
3185
- join29(baseDir, paths.relativeDirPath, paths.relativeFilePath)
3204
+ join30(baseDir, paths.relativeDirPath, paths.relativeFilePath)
3186
3205
  );
3187
3206
  return new _CodexcliMcp({
3188
3207
  baseDir,
@@ -3199,7 +3218,7 @@ var CodexcliMcp = class _CodexcliMcp extends ToolMcp {
3199
3218
  global = false
3200
3219
  }) {
3201
3220
  const paths = this.getSettablePaths({ global });
3202
- const configTomlFilePath = join29(baseDir, paths.relativeDirPath, paths.relativeFilePath);
3221
+ const configTomlFilePath = join30(baseDir, paths.relativeDirPath, paths.relativeFilePath);
3203
3222
  const configTomlFileContent = await readOrInitializeFileContent(
3204
3223
  configTomlFilePath,
3205
3224
  smolToml.stringify({})
@@ -3219,7 +3238,7 @@ var CodexcliMcp = class _CodexcliMcp extends ToolMcp {
3219
3238
  toRulesyncMcp() {
3220
3239
  return new RulesyncMcp({
3221
3240
  baseDir: this.baseDir,
3222
- relativeDirPath: ".rulesync",
3241
+ relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
3223
3242
  relativeFilePath: ".mcp.json",
3224
3243
  fileContent: JSON.stringify({ mcpServers: this.toml.mcp_servers ?? {} }, null, 2)
3225
3244
  });
@@ -3239,8 +3258,8 @@ var CodexcliMcp = class _CodexcliMcp extends ToolMcp {
3239
3258
  }
3240
3259
  };
3241
3260
 
3242
- // src/mcp/copilot-mcp.ts
3243
- import { join as join30 } from "path";
3261
+ // src/features/mcp/copilot-mcp.ts
3262
+ import { join as join31 } from "path";
3244
3263
  var CopilotMcp = class _CopilotMcp extends ToolMcp {
3245
3264
  json;
3246
3265
  constructor(params) {
@@ -3261,7 +3280,7 @@ var CopilotMcp = class _CopilotMcp extends ToolMcp {
3261
3280
  validate = true
3262
3281
  }) {
3263
3282
  const fileContent = await readFileContent(
3264
- join30(
3283
+ join31(
3265
3284
  baseDir,
3266
3285
  this.getSettablePaths().relativeDirPath,
3267
3286
  this.getSettablePaths().relativeFilePath
@@ -3296,8 +3315,8 @@ var CopilotMcp = class _CopilotMcp extends ToolMcp {
3296
3315
  }
3297
3316
  };
3298
3317
 
3299
- // src/mcp/cursor-mcp.ts
3300
- import { join as join31 } from "path";
3318
+ // src/features/mcp/cursor-mcp.ts
3319
+ import { join as join32 } from "path";
3301
3320
  var CursorMcp = class _CursorMcp extends ToolMcp {
3302
3321
  json;
3303
3322
  constructor(params) {
@@ -3318,7 +3337,7 @@ var CursorMcp = class _CursorMcp extends ToolMcp {
3318
3337
  validate = true
3319
3338
  }) {
3320
3339
  const fileContent = await readFileContent(
3321
- join31(
3340
+ join32(
3322
3341
  baseDir,
3323
3342
  this.getSettablePaths().relativeDirPath,
3324
3343
  this.getSettablePaths().relativeFilePath
@@ -3364,8 +3383,8 @@ var CursorMcp = class _CursorMcp extends ToolMcp {
3364
3383
  }
3365
3384
  };
3366
3385
 
3367
- // src/mcp/geminicli-mcp.ts
3368
- import { join as join32 } from "path";
3386
+ // src/features/mcp/geminicli-mcp.ts
3387
+ import { join as join33 } from "path";
3369
3388
  var GeminiCliMcp = class _GeminiCliMcp extends ToolMcp {
3370
3389
  json;
3371
3390
  constructor(params) {
@@ -3394,7 +3413,7 @@ var GeminiCliMcp = class _GeminiCliMcp extends ToolMcp {
3394
3413
  }) {
3395
3414
  const paths = this.getSettablePaths({ global });
3396
3415
  const fileContent = await readOrInitializeFileContent(
3397
- join32(baseDir, paths.relativeDirPath, paths.relativeFilePath),
3416
+ join33(baseDir, paths.relativeDirPath, paths.relativeFilePath),
3398
3417
  JSON.stringify({ mcpServers: {} }, null, 2)
3399
3418
  );
3400
3419
  const json = JSON.parse(fileContent);
@@ -3415,7 +3434,7 @@ var GeminiCliMcp = class _GeminiCliMcp extends ToolMcp {
3415
3434
  }) {
3416
3435
  const paths = this.getSettablePaths({ global });
3417
3436
  const fileContent = await readOrInitializeFileContent(
3418
- join32(baseDir, paths.relativeDirPath, paths.relativeFilePath),
3437
+ join33(baseDir, paths.relativeDirPath, paths.relativeFilePath),
3419
3438
  JSON.stringify({ mcpServers: {} }, null, 2)
3420
3439
  );
3421
3440
  const json = JSON.parse(fileContent);
@@ -3438,8 +3457,8 @@ var GeminiCliMcp = class _GeminiCliMcp extends ToolMcp {
3438
3457
  }
3439
3458
  };
3440
3459
 
3441
- // src/mcp/roo-mcp.ts
3442
- import { join as join33 } from "path";
3460
+ // src/features/mcp/roo-mcp.ts
3461
+ import { join as join34 } from "path";
3443
3462
  var RooMcp = class _RooMcp extends ToolMcp {
3444
3463
  json;
3445
3464
  constructor(params) {
@@ -3460,7 +3479,7 @@ var RooMcp = class _RooMcp extends ToolMcp {
3460
3479
  validate = true
3461
3480
  }) {
3462
3481
  const fileContent = await readFileContent(
3463
- join33(
3482
+ join34(
3464
3483
  baseDir,
3465
3484
  this.getSettablePaths().relativeDirPath,
3466
3485
  this.getSettablePaths().relativeFilePath
@@ -3496,7 +3515,7 @@ var RooMcp = class _RooMcp extends ToolMcp {
3496
3515
  }
3497
3516
  };
3498
3517
 
3499
- // src/mcp/mcp-processor.ts
3518
+ // src/features/mcp/mcp-processor.ts
3500
3519
  var mcpProcessorToolTargets = [
3501
3520
  "amazonqcli",
3502
3521
  "claudecode",
@@ -3652,7 +3671,7 @@ var McpProcessor = class extends FeatureProcessor {
3652
3671
  (file) => file instanceof RulesyncMcp
3653
3672
  );
3654
3673
  if (!rulesyncMcp) {
3655
- throw new Error(`No .rulesync/mcp.json found.`);
3674
+ throw new Error(`No ${RULESYNC_MCP_RELATIVE_FILE_PATH} found.`);
3656
3675
  }
3657
3676
  const toolMcps = await Promise.all(
3658
3677
  [rulesyncMcp].map(async (rulesyncMcp2) => {
@@ -3742,19 +3761,19 @@ var McpProcessor = class extends FeatureProcessor {
3742
3761
  }
3743
3762
  };
3744
3763
 
3745
- // src/rules/rules-processor.ts
3746
- import { basename as basename17, join as join63 } from "path";
3764
+ // src/features/rules/rules-processor.ts
3765
+ import { basename as basename17, join as join64 } from "path";
3747
3766
  import { XMLBuilder } from "fast-xml-parser";
3748
3767
  import { z as z22 } from "zod/mini";
3749
3768
 
3750
- // src/subagents/agentsmd-subagent.ts
3751
- import { join as join35 } from "path";
3769
+ // src/features/subagents/agentsmd-subagent.ts
3770
+ import { join as join36 } from "path";
3752
3771
 
3753
- // src/subagents/simulated-subagent.ts
3754
- import { basename as basename12, join as join34 } from "path";
3772
+ // src/features/subagents/simulated-subagent.ts
3773
+ import { basename as basename12, join as join35 } from "path";
3755
3774
  import { z as z14 } from "zod/mini";
3756
3775
 
3757
- // src/subagents/tool-subagent.ts
3776
+ // src/features/subagents/tool-subagent.ts
3758
3777
  var ToolSubagent = class extends ToolFile {
3759
3778
  static getSettablePaths() {
3760
3779
  throw new Error("Please implement this method in the subclass.");
@@ -3786,7 +3805,7 @@ var ToolSubagent = class extends ToolFile {
3786
3805
  }
3787
3806
  };
3788
3807
 
3789
- // src/subagents/simulated-subagent.ts
3808
+ // src/features/subagents/simulated-subagent.ts
3790
3809
  var SimulatedSubagentFrontmatterSchema = z14.object({
3791
3810
  name: z14.string(),
3792
3811
  description: z14.string()
@@ -3799,7 +3818,7 @@ var SimulatedSubagent = class extends ToolSubagent {
3799
3818
  const result = SimulatedSubagentFrontmatterSchema.safeParse(frontmatter);
3800
3819
  if (!result.success) {
3801
3820
  throw new Error(
3802
- `Invalid frontmatter in ${join34(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
3821
+ `Invalid frontmatter in ${join35(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
3803
3822
  );
3804
3823
  }
3805
3824
  }
@@ -3850,7 +3869,7 @@ var SimulatedSubagent = class extends ToolSubagent {
3850
3869
  return {
3851
3870
  success: false,
3852
3871
  error: new Error(
3853
- `Invalid frontmatter in ${join34(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
3872
+ `Invalid frontmatter in ${join35(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
3854
3873
  )
3855
3874
  };
3856
3875
  }
@@ -3860,7 +3879,7 @@ var SimulatedSubagent = class extends ToolSubagent {
3860
3879
  relativeFilePath,
3861
3880
  validate = true
3862
3881
  }) {
3863
- const filePath = join34(baseDir, this.getSettablePaths().relativeDirPath, relativeFilePath);
3882
+ const filePath = join35(baseDir, this.getSettablePaths().relativeDirPath, relativeFilePath);
3864
3883
  const fileContent = await readFileContent(filePath);
3865
3884
  const { frontmatter, body: content } = parseFrontmatter(fileContent);
3866
3885
  const result = SimulatedSubagentFrontmatterSchema.safeParse(frontmatter);
@@ -3878,11 +3897,11 @@ var SimulatedSubagent = class extends ToolSubagent {
3878
3897
  }
3879
3898
  };
3880
3899
 
3881
- // src/subagents/agentsmd-subagent.ts
3900
+ // src/features/subagents/agentsmd-subagent.ts
3882
3901
  var AgentsmdSubagent = class _AgentsmdSubagent extends SimulatedSubagent {
3883
3902
  static getSettablePaths() {
3884
3903
  return {
3885
- relativeDirPath: join35(".agents", "subagents")
3904
+ relativeDirPath: join36(".agents", "subagents")
3886
3905
  };
3887
3906
  }
3888
3907
  static async fromFile(params) {
@@ -3901,12 +3920,12 @@ var AgentsmdSubagent = class _AgentsmdSubagent extends SimulatedSubagent {
3901
3920
  }
3902
3921
  };
3903
3922
 
3904
- // src/subagents/codexcli-subagent.ts
3905
- import { join as join36 } from "path";
3923
+ // src/features/subagents/codexcli-subagent.ts
3924
+ import { join as join37 } from "path";
3906
3925
  var CodexCliSubagent = class _CodexCliSubagent extends SimulatedSubagent {
3907
3926
  static getSettablePaths() {
3908
3927
  return {
3909
- relativeDirPath: join36(".codex", "subagents")
3928
+ relativeDirPath: join37(".codex", "subagents")
3910
3929
  };
3911
3930
  }
3912
3931
  static async fromFile(params) {
@@ -3925,12 +3944,12 @@ var CodexCliSubagent = class _CodexCliSubagent extends SimulatedSubagent {
3925
3944
  }
3926
3945
  };
3927
3946
 
3928
- // src/subagents/copilot-subagent.ts
3929
- import { join as join37 } from "path";
3947
+ // src/features/subagents/copilot-subagent.ts
3948
+ import { join as join38 } from "path";
3930
3949
  var CopilotSubagent = class _CopilotSubagent extends SimulatedSubagent {
3931
3950
  static getSettablePaths() {
3932
3951
  return {
3933
- relativeDirPath: join37(".github", "subagents")
3952
+ relativeDirPath: join38(".github", "subagents")
3934
3953
  };
3935
3954
  }
3936
3955
  static async fromFile(params) {
@@ -3949,12 +3968,12 @@ var CopilotSubagent = class _CopilotSubagent extends SimulatedSubagent {
3949
3968
  }
3950
3969
  };
3951
3970
 
3952
- // src/subagents/cursor-subagent.ts
3953
- import { join as join38 } from "path";
3971
+ // src/features/subagents/cursor-subagent.ts
3972
+ import { join as join39 } from "path";
3954
3973
  var CursorSubagent = class _CursorSubagent extends SimulatedSubagent {
3955
3974
  static getSettablePaths() {
3956
3975
  return {
3957
- relativeDirPath: join38(".cursor", "subagents")
3976
+ relativeDirPath: join39(".cursor", "subagents")
3958
3977
  };
3959
3978
  }
3960
3979
  static async fromFile(params) {
@@ -3973,12 +3992,12 @@ var CursorSubagent = class _CursorSubagent extends SimulatedSubagent {
3973
3992
  }
3974
3993
  };
3975
3994
 
3976
- // src/subagents/geminicli-subagent.ts
3977
- import { join as join39 } from "path";
3995
+ // src/features/subagents/geminicli-subagent.ts
3996
+ import { join as join40 } from "path";
3978
3997
  var GeminiCliSubagent = class _GeminiCliSubagent extends SimulatedSubagent {
3979
3998
  static getSettablePaths() {
3980
3999
  return {
3981
- relativeDirPath: join39(".gemini", "subagents")
4000
+ relativeDirPath: join40(".gemini", "subagents")
3982
4001
  };
3983
4002
  }
3984
4003
  static async fromFile(params) {
@@ -3997,12 +4016,12 @@ var GeminiCliSubagent = class _GeminiCliSubagent extends SimulatedSubagent {
3997
4016
  }
3998
4017
  };
3999
4018
 
4000
- // src/subagents/roo-subagent.ts
4001
- import { join as join40 } from "path";
4019
+ // src/features/subagents/roo-subagent.ts
4020
+ import { join as join41 } from "path";
4002
4021
  var RooSubagent = class _RooSubagent extends SimulatedSubagent {
4003
4022
  static getSettablePaths() {
4004
4023
  return {
4005
- relativeDirPath: join40(".roo", "subagents")
4024
+ relativeDirPath: join41(".roo", "subagents")
4006
4025
  };
4007
4026
  }
4008
4027
  static async fromFile(params) {
@@ -4021,16 +4040,16 @@ var RooSubagent = class _RooSubagent extends SimulatedSubagent {
4021
4040
  }
4022
4041
  };
4023
4042
 
4024
- // src/subagents/subagents-processor.ts
4025
- import { basename as basename14, join as join43 } from "path";
4043
+ // src/features/subagents/subagents-processor.ts
4044
+ import { basename as basename14, join as join44 } from "path";
4026
4045
  import { z as z17 } from "zod/mini";
4027
4046
 
4028
- // src/subagents/claudecode-subagent.ts
4029
- import { join as join42 } from "path";
4047
+ // src/features/subagents/claudecode-subagent.ts
4048
+ import { join as join43 } from "path";
4030
4049
  import { z as z16 } from "zod/mini";
4031
4050
 
4032
- // src/subagents/rulesync-subagent.ts
4033
- import { basename as basename13, join as join41 } from "path";
4051
+ // src/features/subagents/rulesync-subagent.ts
4052
+ import { basename as basename13, join as join42 } from "path";
4034
4053
  import { z as z15 } from "zod/mini";
4035
4054
  var RulesyncSubagentModelSchema = z15.enum(["opus", "sonnet", "haiku", "inherit"]);
4036
4055
  var RulesyncSubagentFrontmatterSchema = z15.object({
@@ -4051,19 +4070,20 @@ var RulesyncSubagent = class _RulesyncSubagent extends RulesyncFile {
4051
4070
  const result = RulesyncSubagentFrontmatterSchema.safeParse(frontmatter);
4052
4071
  if (!result.success) {
4053
4072
  throw new Error(
4054
- `Invalid frontmatter in ${join41(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
4073
+ `Invalid frontmatter in ${join42(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
4055
4074
  );
4056
4075
  }
4057
4076
  }
4058
4077
  super({
4059
- ...rest
4078
+ ...rest,
4079
+ fileContent: stringifyFrontmatter(body, frontmatter)
4060
4080
  });
4061
4081
  this.frontmatter = frontmatter;
4062
4082
  this.body = body;
4063
4083
  }
4064
4084
  static getSettablePaths() {
4065
4085
  return {
4066
- relativeDirPath: join41(".rulesync", "subagents")
4086
+ relativeDirPath: RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH
4067
4087
  };
4068
4088
  }
4069
4089
  getFrontmatter() {
@@ -4083,7 +4103,7 @@ var RulesyncSubagent = class _RulesyncSubagent extends RulesyncFile {
4083
4103
  return {
4084
4104
  success: false,
4085
4105
  error: new Error(
4086
- `Invalid frontmatter in ${join41(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
4106
+ `Invalid frontmatter in ${join42(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
4087
4107
  )
4088
4108
  };
4089
4109
  }
@@ -4092,7 +4112,7 @@ var RulesyncSubagent = class _RulesyncSubagent extends RulesyncFile {
4092
4112
  relativeFilePath
4093
4113
  }) {
4094
4114
  const fileContent = await readFileContent(
4095
- join41(process.cwd(), ".rulesync", "subagents", relativeFilePath)
4115
+ join42(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, relativeFilePath)
4096
4116
  );
4097
4117
  const { frontmatter, body: content } = parseFrontmatter(fileContent);
4098
4118
  const result = RulesyncSubagentFrontmatterSchema.safeParse(frontmatter);
@@ -4105,13 +4125,12 @@ var RulesyncSubagent = class _RulesyncSubagent extends RulesyncFile {
4105
4125
  relativeDirPath: this.getSettablePaths().relativeDirPath,
4106
4126
  relativeFilePath: filename,
4107
4127
  frontmatter: result.data,
4108
- body: content.trim(),
4109
- fileContent
4128
+ body: content.trim()
4110
4129
  });
4111
4130
  }
4112
4131
  };
4113
4132
 
4114
- // src/subagents/claudecode-subagent.ts
4133
+ // src/features/subagents/claudecode-subagent.ts
4115
4134
  var ClaudecodeSubagentFrontmatterSchema = z16.object({
4116
4135
  name: z16.string(),
4117
4136
  description: z16.string(),
@@ -4125,7 +4144,7 @@ var ClaudecodeSubagent = class _ClaudecodeSubagent extends ToolSubagent {
4125
4144
  const result = ClaudecodeSubagentFrontmatterSchema.safeParse(frontmatter);
4126
4145
  if (!result.success) {
4127
4146
  throw new Error(
4128
- `Invalid frontmatter in ${join42(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
4147
+ `Invalid frontmatter in ${join43(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
4129
4148
  );
4130
4149
  }
4131
4150
  }
@@ -4137,7 +4156,7 @@ var ClaudecodeSubagent = class _ClaudecodeSubagent extends ToolSubagent {
4137
4156
  }
4138
4157
  static getSettablePaths(_options = {}) {
4139
4158
  return {
4140
- relativeDirPath: join42(".claude", "agents")
4159
+ relativeDirPath: join43(".claude", "agents")
4141
4160
  };
4142
4161
  }
4143
4162
  getFrontmatter() {
@@ -4157,15 +4176,13 @@ var ClaudecodeSubagent = class _ClaudecodeSubagent extends ToolSubagent {
4157
4176
  }
4158
4177
  }
4159
4178
  };
4160
- const fileContent = stringifyFrontmatter(this.body, rulesyncFrontmatter);
4161
4179
  return new RulesyncSubagent({
4162
4180
  baseDir: ".",
4163
4181
  // RulesyncCommand baseDir is always the project root directory
4164
4182
  frontmatter: rulesyncFrontmatter,
4165
4183
  body: this.body,
4166
- relativeDirPath: join42(".rulesync", "subagents"),
4184
+ relativeDirPath: RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH,
4167
4185
  relativeFilePath: this.getRelativeFilePath(),
4168
- fileContent,
4169
4186
  validate: true
4170
4187
  });
4171
4188
  }
@@ -4205,7 +4222,7 @@ var ClaudecodeSubagent = class _ClaudecodeSubagent extends ToolSubagent {
4205
4222
  return {
4206
4223
  success: false,
4207
4224
  error: new Error(
4208
- `Invalid frontmatter in ${join42(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
4225
+ `Invalid frontmatter in ${join43(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
4209
4226
  )
4210
4227
  };
4211
4228
  }
@@ -4223,7 +4240,7 @@ var ClaudecodeSubagent = class _ClaudecodeSubagent extends ToolSubagent {
4223
4240
  global = false
4224
4241
  }) {
4225
4242
  const paths = this.getSettablePaths({ global });
4226
- const filePath = join42(baseDir, paths.relativeDirPath, relativeFilePath);
4243
+ const filePath = join43(baseDir, paths.relativeDirPath, relativeFilePath);
4227
4244
  const fileContent = await readFileContent(filePath);
4228
4245
  const { frontmatter, body: content } = parseFrontmatter(fileContent);
4229
4246
  const result = ClaudecodeSubagentFrontmatterSchema.safeParse(frontmatter);
@@ -4242,7 +4259,7 @@ var ClaudecodeSubagent = class _ClaudecodeSubagent extends ToolSubagent {
4242
4259
  }
4243
4260
  };
4244
4261
 
4245
- // src/subagents/subagents-processor.ts
4262
+ // src/features/subagents/subagents-processor.ts
4246
4263
  var subagentsProcessorToolTargets = [
4247
4264
  "agentsmd",
4248
4265
  "claudecode",
@@ -4377,7 +4394,7 @@ var SubagentsProcessor = class extends FeatureProcessor {
4377
4394
  * Load and parse rulesync subagent files from .rulesync/subagents/ directory
4378
4395
  */
4379
4396
  async loadRulesyncFiles() {
4380
- const subagentsDir = join43(this.baseDir, RulesyncSubagent.getSettablePaths().relativeDirPath);
4397
+ const subagentsDir = join44(this.baseDir, RulesyncSubagent.getSettablePaths().relativeDirPath);
4381
4398
  const dirExists = await directoryExists(subagentsDir);
4382
4399
  if (!dirExists) {
4383
4400
  logger.debug(`Rulesync subagents directory not found: ${subagentsDir}`);
@@ -4392,7 +4409,7 @@ var SubagentsProcessor = class extends FeatureProcessor {
4392
4409
  logger.info(`Found ${mdFiles.length} subagent files in ${subagentsDir}`);
4393
4410
  const rulesyncSubagents = [];
4394
4411
  for (const mdFile of mdFiles) {
4395
- const filepath = join43(subagentsDir, mdFile);
4412
+ const filepath = join44(subagentsDir, mdFile);
4396
4413
  try {
4397
4414
  const rulesyncSubagent = await RulesyncSubagent.fromFile({
4398
4415
  relativeFilePath: mdFile,
@@ -4511,7 +4528,7 @@ var SubagentsProcessor = class extends FeatureProcessor {
4511
4528
  relativeDirPath,
4512
4529
  fromFile
4513
4530
  }) {
4514
- const paths = await findFilesByGlobs(join43(this.baseDir, relativeDirPath, "*.md"));
4531
+ const paths = await findFilesByGlobs(join44(this.baseDir, relativeDirPath, "*.md"));
4515
4532
  const subagents = (await Promise.allSettled(paths.map((path2) => fromFile(basename14(path2))))).filter((r) => r.status === "fulfilled").map((r) => r.value);
4516
4533
  logger.info(`Successfully loaded ${subagents.length} ${relativeDirPath} subagents`);
4517
4534
  return subagents;
@@ -4538,14 +4555,14 @@ var SubagentsProcessor = class extends FeatureProcessor {
4538
4555
  }
4539
4556
  };
4540
4557
 
4541
- // src/rules/agentsmd-rule.ts
4542
- import { join as join46 } from "path";
4558
+ // src/features/rules/agentsmd-rule.ts
4559
+ import { join as join47 } from "path";
4543
4560
 
4544
- // src/rules/tool-rule.ts
4545
- import { join as join45 } from "path";
4561
+ // src/features/rules/tool-rule.ts
4562
+ import { join as join46 } from "path";
4546
4563
 
4547
- // src/rules/rulesync-rule.ts
4548
- import { basename as basename15, join as join44 } from "path";
4564
+ // src/features/rules/rulesync-rule.ts
4565
+ import { basename as basename15, join as join45 } from "path";
4549
4566
  import { z as z18 } from "zod/mini";
4550
4567
  var RulesyncRuleFrontmatterSchema = z18.object({
4551
4568
  root: z18.optional(z18.optional(z18.boolean())),
@@ -4574,7 +4591,7 @@ var RulesyncRule = class _RulesyncRule extends RulesyncFile {
4574
4591
  const result = RulesyncRuleFrontmatterSchema.safeParse(frontmatter);
4575
4592
  if (!result.success) {
4576
4593
  throw new Error(
4577
- `Invalid frontmatter in ${join44(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
4594
+ `Invalid frontmatter in ${join45(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
4578
4595
  );
4579
4596
  }
4580
4597
  }
@@ -4588,10 +4605,10 @@ var RulesyncRule = class _RulesyncRule extends RulesyncFile {
4588
4605
  static getSettablePaths() {
4589
4606
  return {
4590
4607
  recommended: {
4591
- relativeDirPath: join44(".rulesync", "rules")
4608
+ relativeDirPath: RULESYNC_RULES_RELATIVE_DIR_PATH
4592
4609
  },
4593
4610
  legacy: {
4594
- relativeDirPath: ".rulesync"
4611
+ relativeDirPath: RULESYNC_RELATIVE_DIR_PATH
4595
4612
  }
4596
4613
  };
4597
4614
  }
@@ -4609,7 +4626,7 @@ var RulesyncRule = class _RulesyncRule extends RulesyncFile {
4609
4626
  return {
4610
4627
  success: false,
4611
4628
  error: new Error(
4612
- `Invalid frontmatter in ${join44(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
4629
+ `Invalid frontmatter in ${join45(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
4613
4630
  )
4614
4631
  };
4615
4632
  }
@@ -4618,12 +4635,12 @@ var RulesyncRule = class _RulesyncRule extends RulesyncFile {
4618
4635
  relativeFilePath,
4619
4636
  validate = true
4620
4637
  }) {
4621
- const legacyPath = join44(
4638
+ const legacyPath = join45(
4622
4639
  process.cwd(),
4623
4640
  this.getSettablePaths().legacy.relativeDirPath,
4624
4641
  relativeFilePath
4625
4642
  );
4626
- const recommendedPath = join44(
4643
+ const recommendedPath = join45(
4627
4644
  this.getSettablePaths().recommended.relativeDirPath,
4628
4645
  relativeFilePath
4629
4646
  );
@@ -4656,7 +4673,7 @@ var RulesyncRule = class _RulesyncRule extends RulesyncFile {
4656
4673
  relativeFilePath,
4657
4674
  validate = true
4658
4675
  }) {
4659
- const filePath = join44(
4676
+ const filePath = join45(
4660
4677
  process.cwd(),
4661
4678
  this.getSettablePaths().recommended.relativeDirPath,
4662
4679
  relativeFilePath
@@ -4690,7 +4707,7 @@ var RulesyncRule = class _RulesyncRule extends RulesyncFile {
4690
4707
  }
4691
4708
  };
4692
4709
 
4693
- // src/rules/tool-rule.ts
4710
+ // src/features/rules/tool-rule.ts
4694
4711
  var ToolRule = class extends ToolFile {
4695
4712
  root;
4696
4713
  description;
@@ -4750,7 +4767,7 @@ var ToolRule = class extends ToolFile {
4750
4767
  rulesyncRule,
4751
4768
  validate = true,
4752
4769
  rootPath = { relativeDirPath: ".", relativeFilePath: "AGENTS.md" },
4753
- nonRootPath = { relativeDirPath: join45(".agents", "memories") }
4770
+ nonRootPath = { relativeDirPath: join46(".agents", "memories") }
4754
4771
  }) {
4755
4772
  const params = this.buildToolRuleParamsDefault({
4756
4773
  baseDir,
@@ -4761,17 +4778,16 @@ var ToolRule = class extends ToolFile {
4761
4778
  });
4762
4779
  const rulesyncFrontmatter = rulesyncRule.getFrontmatter();
4763
4780
  if (!rulesyncFrontmatter.root && rulesyncFrontmatter.agentsmd?.subprojectPath) {
4764
- params.relativeDirPath = join45(rulesyncFrontmatter.agentsmd.subprojectPath);
4781
+ params.relativeDirPath = join46(rulesyncFrontmatter.agentsmd.subprojectPath);
4765
4782
  params.relativeFilePath = "AGENTS.md";
4766
4783
  }
4767
4784
  return params;
4768
4785
  }
4769
4786
  toRulesyncRuleDefault() {
4770
4787
  return new RulesyncRule({
4771
- baseDir: ".",
4772
- // RulesyncRule baseDir is always the project root directory
4773
- relativeDirPath: join45(".rulesync", "rules"),
4774
- relativeFilePath: this.getRelativeFilePath(),
4788
+ baseDir: process.cwd(),
4789
+ relativeDirPath: RULESYNC_RULES_RELATIVE_DIR_PATH,
4790
+ relativeFilePath: this.isRoot() ? RULESYNC_OVERVIEW_FILE_NAME : this.getRelativeFilePath(),
4775
4791
  frontmatter: {
4776
4792
  root: this.isRoot(),
4777
4793
  targets: ["*"],
@@ -4811,7 +4827,7 @@ var ToolRule = class extends ToolFile {
4811
4827
  }
4812
4828
  };
4813
4829
 
4814
- // src/rules/agentsmd-rule.ts
4830
+ // src/features/rules/agentsmd-rule.ts
4815
4831
  var AgentsMdRule = class _AgentsMdRule extends ToolRule {
4816
4832
  constructor({ fileContent, root, ...rest }) {
4817
4833
  super({
@@ -4827,7 +4843,7 @@ var AgentsMdRule = class _AgentsMdRule extends ToolRule {
4827
4843
  relativeFilePath: "AGENTS.md"
4828
4844
  },
4829
4845
  nonRoot: {
4830
- relativeDirPath: join46(".agents", "memories")
4846
+ relativeDirPath: join47(".agents", "memories")
4831
4847
  }
4832
4848
  };
4833
4849
  }
@@ -4837,8 +4853,8 @@ var AgentsMdRule = class _AgentsMdRule extends ToolRule {
4837
4853
  validate = true
4838
4854
  }) {
4839
4855
  const isRoot = relativeFilePath === "AGENTS.md";
4840
- const relativePath = isRoot ? "AGENTS.md" : join46(".agents", "memories", relativeFilePath);
4841
- const fileContent = await readFileContent(join46(baseDir, relativePath));
4856
+ const relativePath = isRoot ? "AGENTS.md" : join47(".agents", "memories", relativeFilePath);
4857
+ const fileContent = await readFileContent(join47(baseDir, relativePath));
4842
4858
  return new _AgentsMdRule({
4843
4859
  baseDir,
4844
4860
  relativeDirPath: isRoot ? this.getSettablePaths().root.relativeDirPath : this.getSettablePaths().nonRoot.relativeDirPath,
@@ -4877,13 +4893,13 @@ var AgentsMdRule = class _AgentsMdRule extends ToolRule {
4877
4893
  }
4878
4894
  };
4879
4895
 
4880
- // src/rules/amazonqcli-rule.ts
4881
- import { join as join47 } from "path";
4896
+ // src/features/rules/amazonqcli-rule.ts
4897
+ import { join as join48 } from "path";
4882
4898
  var AmazonQCliRule = class _AmazonQCliRule extends ToolRule {
4883
4899
  static getSettablePaths() {
4884
4900
  return {
4885
4901
  nonRoot: {
4886
- relativeDirPath: join47(".amazonq", "rules")
4902
+ relativeDirPath: join48(".amazonq", "rules")
4887
4903
  }
4888
4904
  };
4889
4905
  }
@@ -4893,7 +4909,7 @@ var AmazonQCliRule = class _AmazonQCliRule extends ToolRule {
4893
4909
  validate = true
4894
4910
  }) {
4895
4911
  const fileContent = await readFileContent(
4896
- join47(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
4912
+ join48(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
4897
4913
  );
4898
4914
  return new _AmazonQCliRule({
4899
4915
  baseDir,
@@ -4932,8 +4948,8 @@ var AmazonQCliRule = class _AmazonQCliRule extends ToolRule {
4932
4948
  }
4933
4949
  };
4934
4950
 
4935
- // src/rules/augmentcode-legacy-rule.ts
4936
- import { join as join48 } from "path";
4951
+ // src/features/rules/augmentcode-legacy-rule.ts
4952
+ import { join as join49 } from "path";
4937
4953
  var AugmentcodeLegacyRule = class _AugmentcodeLegacyRule extends ToolRule {
4938
4954
  toRulesyncRule() {
4939
4955
  const rulesyncFrontmatter = {
@@ -4947,7 +4963,7 @@ var AugmentcodeLegacyRule = class _AugmentcodeLegacyRule extends ToolRule {
4947
4963
  // RulesyncRule baseDir is always the project root directory
4948
4964
  frontmatter: rulesyncFrontmatter,
4949
4965
  body: this.getFileContent(),
4950
- relativeDirPath: join48(".rulesync", "rules"),
4966
+ relativeDirPath: RULESYNC_RULES_RELATIVE_DIR_PATH,
4951
4967
  relativeFilePath: this.getRelativeFilePath(),
4952
4968
  validate: true
4953
4969
  });
@@ -4959,7 +4975,7 @@ var AugmentcodeLegacyRule = class _AugmentcodeLegacyRule extends ToolRule {
4959
4975
  relativeFilePath: ".augment-guidelines"
4960
4976
  },
4961
4977
  nonRoot: {
4962
- relativeDirPath: join48(".augment", "rules")
4978
+ relativeDirPath: join49(".augment", "rules")
4963
4979
  }
4964
4980
  };
4965
4981
  }
@@ -4994,8 +5010,8 @@ var AugmentcodeLegacyRule = class _AugmentcodeLegacyRule extends ToolRule {
4994
5010
  }) {
4995
5011
  const settablePaths = this.getSettablePaths();
4996
5012
  const isRoot = relativeFilePath === settablePaths.root.relativeFilePath;
4997
- const relativePath = isRoot ? settablePaths.root.relativeFilePath : join48(settablePaths.nonRoot.relativeDirPath, relativeFilePath);
4998
- const fileContent = await readFileContent(join48(baseDir, relativePath));
5013
+ const relativePath = isRoot ? settablePaths.root.relativeFilePath : join49(settablePaths.nonRoot.relativeDirPath, relativeFilePath);
5014
+ const fileContent = await readFileContent(join49(baseDir, relativePath));
4999
5015
  return new _AugmentcodeLegacyRule({
5000
5016
  baseDir,
5001
5017
  relativeDirPath: isRoot ? settablePaths.root.relativeDirPath : settablePaths.nonRoot.relativeDirPath,
@@ -5007,8 +5023,8 @@ var AugmentcodeLegacyRule = class _AugmentcodeLegacyRule extends ToolRule {
5007
5023
  }
5008
5024
  };
5009
5025
 
5010
- // src/rules/augmentcode-rule.ts
5011
- import { join as join49 } from "path";
5026
+ // src/features/rules/augmentcode-rule.ts
5027
+ import { join as join50 } from "path";
5012
5028
  var AugmentcodeRule = class _AugmentcodeRule extends ToolRule {
5013
5029
  toRulesyncRule() {
5014
5030
  return this.toRulesyncRuleDefault();
@@ -5016,7 +5032,7 @@ var AugmentcodeRule = class _AugmentcodeRule extends ToolRule {
5016
5032
  static getSettablePaths() {
5017
5033
  return {
5018
5034
  nonRoot: {
5019
- relativeDirPath: join49(".augment", "rules")
5035
+ relativeDirPath: join50(".augment", "rules")
5020
5036
  }
5021
5037
  };
5022
5038
  }
@@ -5040,7 +5056,7 @@ var AugmentcodeRule = class _AugmentcodeRule extends ToolRule {
5040
5056
  validate = true
5041
5057
  }) {
5042
5058
  const fileContent = await readFileContent(
5043
- join49(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
5059
+ join50(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
5044
5060
  );
5045
5061
  const { body: content } = parseFrontmatter(fileContent);
5046
5062
  return new _AugmentcodeRule({
@@ -5062,8 +5078,8 @@ var AugmentcodeRule = class _AugmentcodeRule extends ToolRule {
5062
5078
  }
5063
5079
  };
5064
5080
 
5065
- // src/rules/claudecode-rule.ts
5066
- import { join as join50 } from "path";
5081
+ // src/features/rules/claudecode-rule.ts
5082
+ import { join as join51 } from "path";
5067
5083
  var ClaudecodeRule = class _ClaudecodeRule extends ToolRule {
5068
5084
  static getSettablePaths({
5069
5085
  global
@@ -5082,7 +5098,7 @@ var ClaudecodeRule = class _ClaudecodeRule extends ToolRule {
5082
5098
  relativeFilePath: "CLAUDE.md"
5083
5099
  },
5084
5100
  nonRoot: {
5085
- relativeDirPath: join50(".claude", "memories")
5101
+ relativeDirPath: join51(".claude", "memories")
5086
5102
  }
5087
5103
  };
5088
5104
  }
@@ -5097,7 +5113,7 @@ var ClaudecodeRule = class _ClaudecodeRule extends ToolRule {
5097
5113
  if (isRoot) {
5098
5114
  const relativePath2 = paths.root.relativeFilePath;
5099
5115
  const fileContent2 = await readFileContent(
5100
- join50(baseDir, paths.root.relativeDirPath, relativePath2)
5116
+ join51(baseDir, paths.root.relativeDirPath, relativePath2)
5101
5117
  );
5102
5118
  return new _ClaudecodeRule({
5103
5119
  baseDir,
@@ -5111,8 +5127,8 @@ var ClaudecodeRule = class _ClaudecodeRule extends ToolRule {
5111
5127
  if (!paths.nonRoot) {
5112
5128
  throw new Error("nonRoot path is not set");
5113
5129
  }
5114
- const relativePath = join50(paths.nonRoot.relativeDirPath, relativeFilePath);
5115
- const fileContent = await readFileContent(join50(baseDir, relativePath));
5130
+ const relativePath = join51(paths.nonRoot.relativeDirPath, relativeFilePath);
5131
+ const fileContent = await readFileContent(join51(baseDir, relativePath));
5116
5132
  return new _ClaudecodeRule({
5117
5133
  baseDir,
5118
5134
  relativeDirPath: paths.nonRoot.relativeDirPath,
@@ -5153,8 +5169,8 @@ var ClaudecodeRule = class _ClaudecodeRule extends ToolRule {
5153
5169
  }
5154
5170
  };
5155
5171
 
5156
- // src/rules/cline-rule.ts
5157
- import { join as join51 } from "path";
5172
+ // src/features/rules/cline-rule.ts
5173
+ import { join as join52 } from "path";
5158
5174
  import { z as z19 } from "zod/mini";
5159
5175
  var ClineRuleFrontmatterSchema = z19.object({
5160
5176
  description: z19.string()
@@ -5199,7 +5215,7 @@ var ClineRule = class _ClineRule extends ToolRule {
5199
5215
  validate = true
5200
5216
  }) {
5201
5217
  const fileContent = await readFileContent(
5202
- join51(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
5218
+ join52(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
5203
5219
  );
5204
5220
  return new _ClineRule({
5205
5221
  baseDir,
@@ -5211,8 +5227,8 @@ var ClineRule = class _ClineRule extends ToolRule {
5211
5227
  }
5212
5228
  };
5213
5229
 
5214
- // src/rules/codexcli-rule.ts
5215
- import { join as join52 } from "path";
5230
+ // src/features/rules/codexcli-rule.ts
5231
+ import { join as join53 } from "path";
5216
5232
  var CodexcliRule = class _CodexcliRule extends ToolRule {
5217
5233
  static getSettablePaths({
5218
5234
  global
@@ -5231,7 +5247,7 @@ var CodexcliRule = class _CodexcliRule extends ToolRule {
5231
5247
  relativeFilePath: "AGENTS.md"
5232
5248
  },
5233
5249
  nonRoot: {
5234
- relativeDirPath: join52(".codex", "memories")
5250
+ relativeDirPath: join53(".codex", "memories")
5235
5251
  }
5236
5252
  };
5237
5253
  }
@@ -5246,7 +5262,7 @@ var CodexcliRule = class _CodexcliRule extends ToolRule {
5246
5262
  if (isRoot) {
5247
5263
  const relativePath2 = paths.root.relativeFilePath;
5248
5264
  const fileContent2 = await readFileContent(
5249
- join52(baseDir, paths.root.relativeDirPath, relativePath2)
5265
+ join53(baseDir, paths.root.relativeDirPath, relativePath2)
5250
5266
  );
5251
5267
  return new _CodexcliRule({
5252
5268
  baseDir,
@@ -5260,8 +5276,8 @@ var CodexcliRule = class _CodexcliRule extends ToolRule {
5260
5276
  if (!paths.nonRoot) {
5261
5277
  throw new Error("nonRoot path is not set");
5262
5278
  }
5263
- const relativePath = join52(paths.nonRoot.relativeDirPath, relativeFilePath);
5264
- const fileContent = await readFileContent(join52(baseDir, relativePath));
5279
+ const relativePath = join53(paths.nonRoot.relativeDirPath, relativeFilePath);
5280
+ const fileContent = await readFileContent(join53(baseDir, relativePath));
5265
5281
  return new _CodexcliRule({
5266
5282
  baseDir,
5267
5283
  relativeDirPath: paths.nonRoot.relativeDirPath,
@@ -5302,8 +5318,8 @@ var CodexcliRule = class _CodexcliRule extends ToolRule {
5302
5318
  }
5303
5319
  };
5304
5320
 
5305
- // src/rules/copilot-rule.ts
5306
- import { join as join53 } from "path";
5321
+ // src/features/rules/copilot-rule.ts
5322
+ import { join as join54 } from "path";
5307
5323
  import { z as z20 } from "zod/mini";
5308
5324
  var CopilotRuleFrontmatterSchema = z20.object({
5309
5325
  description: z20.optional(z20.string()),
@@ -5319,7 +5335,7 @@ var CopilotRule = class _CopilotRule extends ToolRule {
5319
5335
  relativeFilePath: "copilot-instructions.md"
5320
5336
  },
5321
5337
  nonRoot: {
5322
- relativeDirPath: join53(".github", "instructions")
5338
+ relativeDirPath: join54(".github", "instructions")
5323
5339
  }
5324
5340
  };
5325
5341
  }
@@ -5328,7 +5344,7 @@ var CopilotRule = class _CopilotRule extends ToolRule {
5328
5344
  const result = CopilotRuleFrontmatterSchema.safeParse(frontmatter);
5329
5345
  if (!result.success) {
5330
5346
  throw new Error(
5331
- `Invalid frontmatter in ${join53(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
5347
+ `Invalid frontmatter in ${join54(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
5332
5348
  );
5333
5349
  }
5334
5350
  }
@@ -5359,7 +5375,7 @@ var CopilotRule = class _CopilotRule extends ToolRule {
5359
5375
  baseDir: this.getBaseDir(),
5360
5376
  frontmatter: rulesyncFrontmatter,
5361
5377
  body: this.body,
5362
- relativeDirPath: join53(".rulesync", "rules"),
5378
+ relativeDirPath: RULESYNC_RULES_RELATIVE_DIR_PATH,
5363
5379
  relativeFilePath,
5364
5380
  validate: true
5365
5381
  });
@@ -5406,11 +5422,11 @@ var CopilotRule = class _CopilotRule extends ToolRule {
5406
5422
  validate = true
5407
5423
  }) {
5408
5424
  const isRoot = relativeFilePath === "copilot-instructions.md";
5409
- const relativePath = isRoot ? join53(
5425
+ const relativePath = isRoot ? join54(
5410
5426
  this.getSettablePaths().root.relativeDirPath,
5411
5427
  this.getSettablePaths().root.relativeFilePath
5412
- ) : join53(this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath);
5413
- const fileContent = await readFileContent(join53(baseDir, relativePath));
5428
+ ) : join54(this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath);
5429
+ const fileContent = await readFileContent(join54(baseDir, relativePath));
5414
5430
  if (isRoot) {
5415
5431
  return new _CopilotRule({
5416
5432
  baseDir,
@@ -5429,7 +5445,7 @@ var CopilotRule = class _CopilotRule extends ToolRule {
5429
5445
  const result = CopilotRuleFrontmatterSchema.safeParse(frontmatter);
5430
5446
  if (!result.success) {
5431
5447
  throw new Error(
5432
- `Invalid frontmatter in ${join53(baseDir, relativeFilePath)}: ${formatError(result.error)}`
5448
+ `Invalid frontmatter in ${join54(baseDir, relativeFilePath)}: ${formatError(result.error)}`
5433
5449
  );
5434
5450
  }
5435
5451
  return new _CopilotRule({
@@ -5453,7 +5469,7 @@ var CopilotRule = class _CopilotRule extends ToolRule {
5453
5469
  return {
5454
5470
  success: false,
5455
5471
  error: new Error(
5456
- `Invalid frontmatter in ${join53(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
5472
+ `Invalid frontmatter in ${join54(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
5457
5473
  )
5458
5474
  };
5459
5475
  }
@@ -5472,8 +5488,8 @@ var CopilotRule = class _CopilotRule extends ToolRule {
5472
5488
  }
5473
5489
  };
5474
5490
 
5475
- // src/rules/cursor-rule.ts
5476
- import { basename as basename16, join as join54 } from "path";
5491
+ // src/features/rules/cursor-rule.ts
5492
+ import { basename as basename16, join as join55 } from "path";
5477
5493
  import { z as z21 } from "zod/mini";
5478
5494
  var CursorRuleFrontmatterSchema = z21.object({
5479
5495
  description: z21.optional(z21.string()),
@@ -5486,7 +5502,7 @@ var CursorRule = class _CursorRule extends ToolRule {
5486
5502
  static getSettablePaths() {
5487
5503
  return {
5488
5504
  nonRoot: {
5489
- relativeDirPath: join54(".cursor", "rules")
5505
+ relativeDirPath: join55(".cursor", "rules")
5490
5506
  }
5491
5507
  };
5492
5508
  }
@@ -5495,7 +5511,7 @@ var CursorRule = class _CursorRule extends ToolRule {
5495
5511
  const result = CursorRuleFrontmatterSchema.safeParse(frontmatter);
5496
5512
  if (!result.success) {
5497
5513
  throw new Error(
5498
- `Invalid frontmatter in ${join54(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
5514
+ `Invalid frontmatter in ${join55(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
5499
5515
  );
5500
5516
  }
5501
5517
  }
@@ -5567,7 +5583,7 @@ var CursorRule = class _CursorRule extends ToolRule {
5567
5583
  return new RulesyncRule({
5568
5584
  frontmatter: rulesyncFrontmatter,
5569
5585
  body: this.body,
5570
- relativeDirPath: join54(".rulesync", "rules"),
5586
+ relativeDirPath: RULESYNC_RULES_RELATIVE_DIR_PATH,
5571
5587
  relativeFilePath: this.relativeFilePath.replace(/\.mdc$/, ".md"),
5572
5588
  validate: true
5573
5589
  });
@@ -5612,13 +5628,13 @@ var CursorRule = class _CursorRule extends ToolRule {
5612
5628
  validate = true
5613
5629
  }) {
5614
5630
  const fileContent = await readFileContent(
5615
- join54(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
5631
+ join55(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
5616
5632
  );
5617
5633
  const { frontmatter, body: content } = _CursorRule.parseCursorFrontmatter(fileContent);
5618
5634
  const result = CursorRuleFrontmatterSchema.safeParse(frontmatter);
5619
5635
  if (!result.success) {
5620
5636
  throw new Error(
5621
- `Invalid frontmatter in ${join54(baseDir, relativeFilePath)}: ${formatError(result.error)}`
5637
+ `Invalid frontmatter in ${join55(baseDir, relativeFilePath)}: ${formatError(result.error)}`
5622
5638
  );
5623
5639
  }
5624
5640
  return new _CursorRule({
@@ -5641,7 +5657,7 @@ var CursorRule = class _CursorRule extends ToolRule {
5641
5657
  return {
5642
5658
  success: false,
5643
5659
  error: new Error(
5644
- `Invalid frontmatter in ${join54(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
5660
+ `Invalid frontmatter in ${join55(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
5645
5661
  )
5646
5662
  };
5647
5663
  }
@@ -5660,8 +5676,8 @@ var CursorRule = class _CursorRule extends ToolRule {
5660
5676
  }
5661
5677
  };
5662
5678
 
5663
- // src/rules/geminicli-rule.ts
5664
- import { join as join55 } from "path";
5679
+ // src/features/rules/geminicli-rule.ts
5680
+ import { join as join56 } from "path";
5665
5681
  var GeminiCliRule = class _GeminiCliRule extends ToolRule {
5666
5682
  static getSettablePaths({
5667
5683
  global
@@ -5680,7 +5696,7 @@ var GeminiCliRule = class _GeminiCliRule extends ToolRule {
5680
5696
  relativeFilePath: "GEMINI.md"
5681
5697
  },
5682
5698
  nonRoot: {
5683
- relativeDirPath: join55(".gemini", "memories")
5699
+ relativeDirPath: join56(".gemini", "memories")
5684
5700
  }
5685
5701
  };
5686
5702
  }
@@ -5695,7 +5711,7 @@ var GeminiCliRule = class _GeminiCliRule extends ToolRule {
5695
5711
  if (isRoot) {
5696
5712
  const relativePath2 = paths.root.relativeFilePath;
5697
5713
  const fileContent2 = await readFileContent(
5698
- join55(baseDir, paths.root.relativeDirPath, relativePath2)
5714
+ join56(baseDir, paths.root.relativeDirPath, relativePath2)
5699
5715
  );
5700
5716
  return new _GeminiCliRule({
5701
5717
  baseDir,
@@ -5709,8 +5725,8 @@ var GeminiCliRule = class _GeminiCliRule extends ToolRule {
5709
5725
  if (!paths.nonRoot) {
5710
5726
  throw new Error("nonRoot path is not set");
5711
5727
  }
5712
- const relativePath = join55(paths.nonRoot.relativeDirPath, relativeFilePath);
5713
- const fileContent = await readFileContent(join55(baseDir, relativePath));
5728
+ const relativePath = join56(paths.nonRoot.relativeDirPath, relativeFilePath);
5729
+ const fileContent = await readFileContent(join56(baseDir, relativePath));
5714
5730
  return new _GeminiCliRule({
5715
5731
  baseDir,
5716
5732
  relativeDirPath: paths.nonRoot.relativeDirPath,
@@ -5751,8 +5767,8 @@ var GeminiCliRule = class _GeminiCliRule extends ToolRule {
5751
5767
  }
5752
5768
  };
5753
5769
 
5754
- // src/rules/junie-rule.ts
5755
- import { join as join56 } from "path";
5770
+ // src/features/rules/junie-rule.ts
5771
+ import { join as join57 } from "path";
5756
5772
  var JunieRule = class _JunieRule extends ToolRule {
5757
5773
  static getSettablePaths() {
5758
5774
  return {
@@ -5761,7 +5777,7 @@ var JunieRule = class _JunieRule extends ToolRule {
5761
5777
  relativeFilePath: "guidelines.md"
5762
5778
  },
5763
5779
  nonRoot: {
5764
- relativeDirPath: join56(".junie", "memories")
5780
+ relativeDirPath: join57(".junie", "memories")
5765
5781
  }
5766
5782
  };
5767
5783
  }
@@ -5771,8 +5787,8 @@ var JunieRule = class _JunieRule extends ToolRule {
5771
5787
  validate = true
5772
5788
  }) {
5773
5789
  const isRoot = relativeFilePath === "guidelines.md";
5774
- const relativePath = isRoot ? "guidelines.md" : join56(".junie", "memories", relativeFilePath);
5775
- const fileContent = await readFileContent(join56(baseDir, relativePath));
5790
+ const relativePath = isRoot ? "guidelines.md" : join57(".junie", "memories", relativeFilePath);
5791
+ const fileContent = await readFileContent(join57(baseDir, relativePath));
5776
5792
  return new _JunieRule({
5777
5793
  baseDir,
5778
5794
  relativeDirPath: isRoot ? this.getSettablePaths().root.relativeDirPath : this.getSettablePaths().nonRoot.relativeDirPath,
@@ -5811,13 +5827,13 @@ var JunieRule = class _JunieRule extends ToolRule {
5811
5827
  }
5812
5828
  };
5813
5829
 
5814
- // src/rules/kiro-rule.ts
5815
- import { join as join57 } from "path";
5830
+ // src/features/rules/kiro-rule.ts
5831
+ import { join as join58 } from "path";
5816
5832
  var KiroRule = class _KiroRule extends ToolRule {
5817
5833
  static getSettablePaths() {
5818
5834
  return {
5819
5835
  nonRoot: {
5820
- relativeDirPath: join57(".kiro", "steering")
5836
+ relativeDirPath: join58(".kiro", "steering")
5821
5837
  }
5822
5838
  };
5823
5839
  }
@@ -5827,7 +5843,7 @@ var KiroRule = class _KiroRule extends ToolRule {
5827
5843
  validate = true
5828
5844
  }) {
5829
5845
  const fileContent = await readFileContent(
5830
- join57(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
5846
+ join58(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
5831
5847
  );
5832
5848
  return new _KiroRule({
5833
5849
  baseDir,
@@ -5866,8 +5882,8 @@ var KiroRule = class _KiroRule extends ToolRule {
5866
5882
  }
5867
5883
  };
5868
5884
 
5869
- // src/rules/opencode-rule.ts
5870
- import { join as join58 } from "path";
5885
+ // src/features/rules/opencode-rule.ts
5886
+ import { join as join59 } from "path";
5871
5887
  var OpenCodeRule = class _OpenCodeRule extends ToolRule {
5872
5888
  static getSettablePaths() {
5873
5889
  return {
@@ -5876,7 +5892,7 @@ var OpenCodeRule = class _OpenCodeRule extends ToolRule {
5876
5892
  relativeFilePath: "AGENTS.md"
5877
5893
  },
5878
5894
  nonRoot: {
5879
- relativeDirPath: join58(".opencode", "memories")
5895
+ relativeDirPath: join59(".opencode", "memories")
5880
5896
  }
5881
5897
  };
5882
5898
  }
@@ -5886,8 +5902,8 @@ var OpenCodeRule = class _OpenCodeRule extends ToolRule {
5886
5902
  validate = true
5887
5903
  }) {
5888
5904
  const isRoot = relativeFilePath === "AGENTS.md";
5889
- const relativePath = isRoot ? "AGENTS.md" : join58(".opencode", "memories", relativeFilePath);
5890
- const fileContent = await readFileContent(join58(baseDir, relativePath));
5905
+ const relativePath = isRoot ? "AGENTS.md" : join59(".opencode", "memories", relativeFilePath);
5906
+ const fileContent = await readFileContent(join59(baseDir, relativePath));
5891
5907
  return new _OpenCodeRule({
5892
5908
  baseDir,
5893
5909
  relativeDirPath: isRoot ? this.getSettablePaths().root.relativeDirPath : this.getSettablePaths().nonRoot.relativeDirPath,
@@ -5926,8 +5942,8 @@ var OpenCodeRule = class _OpenCodeRule extends ToolRule {
5926
5942
  }
5927
5943
  };
5928
5944
 
5929
- // src/rules/qwencode-rule.ts
5930
- import { join as join59 } from "path";
5945
+ // src/features/rules/qwencode-rule.ts
5946
+ import { join as join60 } from "path";
5931
5947
  var QwencodeRule = class _QwencodeRule extends ToolRule {
5932
5948
  static getSettablePaths() {
5933
5949
  return {
@@ -5936,7 +5952,7 @@ var QwencodeRule = class _QwencodeRule extends ToolRule {
5936
5952
  relativeFilePath: "QWEN.md"
5937
5953
  },
5938
5954
  nonRoot: {
5939
- relativeDirPath: join59(".qwen", "memories")
5955
+ relativeDirPath: join60(".qwen", "memories")
5940
5956
  }
5941
5957
  };
5942
5958
  }
@@ -5946,8 +5962,8 @@ var QwencodeRule = class _QwencodeRule extends ToolRule {
5946
5962
  validate = true
5947
5963
  }) {
5948
5964
  const isRoot = relativeFilePath === "QWEN.md";
5949
- const relativePath = isRoot ? "QWEN.md" : join59(".qwen", "memories", relativeFilePath);
5950
- const fileContent = await readFileContent(join59(baseDir, relativePath));
5965
+ const relativePath = isRoot ? "QWEN.md" : join60(".qwen", "memories", relativeFilePath);
5966
+ const fileContent = await readFileContent(join60(baseDir, relativePath));
5951
5967
  return new _QwencodeRule({
5952
5968
  baseDir,
5953
5969
  relativeDirPath: isRoot ? this.getSettablePaths().root.relativeDirPath : this.getSettablePaths().nonRoot.relativeDirPath,
@@ -5983,13 +5999,13 @@ var QwencodeRule = class _QwencodeRule extends ToolRule {
5983
5999
  }
5984
6000
  };
5985
6001
 
5986
- // src/rules/roo-rule.ts
5987
- import { join as join60 } from "path";
6002
+ // src/features/rules/roo-rule.ts
6003
+ import { join as join61 } from "path";
5988
6004
  var RooRule = class _RooRule extends ToolRule {
5989
6005
  static getSettablePaths() {
5990
6006
  return {
5991
6007
  nonRoot: {
5992
- relativeDirPath: join60(".roo", "rules")
6008
+ relativeDirPath: join61(".roo", "rules")
5993
6009
  }
5994
6010
  };
5995
6011
  }
@@ -5999,7 +6015,7 @@ var RooRule = class _RooRule extends ToolRule {
5999
6015
  validate = true
6000
6016
  }) {
6001
6017
  const fileContent = await readFileContent(
6002
- join60(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
6018
+ join61(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
6003
6019
  );
6004
6020
  return new _RooRule({
6005
6021
  baseDir,
@@ -6053,8 +6069,8 @@ var RooRule = class _RooRule extends ToolRule {
6053
6069
  }
6054
6070
  };
6055
6071
 
6056
- // src/rules/warp-rule.ts
6057
- import { join as join61 } from "path";
6072
+ // src/features/rules/warp-rule.ts
6073
+ import { join as join62 } from "path";
6058
6074
  var WarpRule = class _WarpRule extends ToolRule {
6059
6075
  constructor({ fileContent, root, ...rest }) {
6060
6076
  super({
@@ -6070,7 +6086,7 @@ var WarpRule = class _WarpRule extends ToolRule {
6070
6086
  relativeFilePath: "WARP.md"
6071
6087
  },
6072
6088
  nonRoot: {
6073
- relativeDirPath: join61(".warp", "memories")
6089
+ relativeDirPath: join62(".warp", "memories")
6074
6090
  }
6075
6091
  };
6076
6092
  }
@@ -6080,8 +6096,8 @@ var WarpRule = class _WarpRule extends ToolRule {
6080
6096
  validate = true
6081
6097
  }) {
6082
6098
  const isRoot = relativeFilePath === this.getSettablePaths().root.relativeFilePath;
6083
- const relativePath = isRoot ? this.getSettablePaths().root.relativeFilePath : join61(this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath);
6084
- const fileContent = await readFileContent(join61(baseDir, relativePath));
6099
+ const relativePath = isRoot ? this.getSettablePaths().root.relativeFilePath : join62(this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath);
6100
+ const fileContent = await readFileContent(join62(baseDir, relativePath));
6085
6101
  return new _WarpRule({
6086
6102
  baseDir,
6087
6103
  relativeDirPath: isRoot ? this.getSettablePaths().root.relativeDirPath : ".warp",
@@ -6120,13 +6136,13 @@ var WarpRule = class _WarpRule extends ToolRule {
6120
6136
  }
6121
6137
  };
6122
6138
 
6123
- // src/rules/windsurf-rule.ts
6124
- import { join as join62 } from "path";
6139
+ // src/features/rules/windsurf-rule.ts
6140
+ import { join as join63 } from "path";
6125
6141
  var WindsurfRule = class _WindsurfRule extends ToolRule {
6126
6142
  static getSettablePaths() {
6127
6143
  return {
6128
6144
  nonRoot: {
6129
- relativeDirPath: join62(".windsurf", "rules")
6145
+ relativeDirPath: join63(".windsurf", "rules")
6130
6146
  }
6131
6147
  };
6132
6148
  }
@@ -6136,7 +6152,7 @@ var WindsurfRule = class _WindsurfRule extends ToolRule {
6136
6152
  validate = true
6137
6153
  }) {
6138
6154
  const fileContent = await readFileContent(
6139
- join62(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
6155
+ join63(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
6140
6156
  );
6141
6157
  return new _WindsurfRule({
6142
6158
  baseDir,
@@ -6174,7 +6190,7 @@ var WindsurfRule = class _WindsurfRule extends ToolRule {
6174
6190
  }
6175
6191
  };
6176
6192
 
6177
- // src/rules/rules-processor.ts
6193
+ // src/features/rules/rules-processor.ts
6178
6194
  var rulesProcessorToolTargets = [
6179
6195
  "agentsmd",
6180
6196
  "amazonqcli",
@@ -6536,7 +6552,7 @@ var RulesProcessor = class extends FeatureProcessor {
6536
6552
  * Load and parse rulesync rule files from .rulesync/rules/ directory
6537
6553
  */
6538
6554
  async loadRulesyncFiles() {
6539
- const files = await findFilesByGlobs(join63(".rulesync", "rules", "*.md"));
6555
+ const files = await findFilesByGlobs(join64(RULESYNC_RULES_RELATIVE_DIR_PATH, "*.md"));
6540
6556
  logger.debug(`Found ${files.length} rulesync files`);
6541
6557
  const rulesyncRules = await Promise.all(
6542
6558
  files.map((file) => RulesyncRule.fromFile({ relativeFilePath: basename17(file) }))
@@ -6557,7 +6573,7 @@ var RulesProcessor = class extends FeatureProcessor {
6557
6573
  return rulesyncRules;
6558
6574
  }
6559
6575
  async loadRulesyncFilesLegacy() {
6560
- const legacyFiles = await findFilesByGlobs(join63(".rulesync", "*.md"));
6576
+ const legacyFiles = await findFilesByGlobs(join64(RULESYNC_RELATIVE_DIR_PATH, "*.md"));
6561
6577
  logger.debug(`Found ${legacyFiles.length} legacy rulesync files`);
6562
6578
  return Promise.all(
6563
6579
  legacyFiles.map((file) => RulesyncRule.fromFileLegacy({ relativeFilePath: basename17(file) }))
@@ -6624,7 +6640,7 @@ var RulesProcessor = class extends FeatureProcessor {
6624
6640
  return [];
6625
6641
  }
6626
6642
  const rootFilePaths = await findFilesByGlobs(
6627
- join63(this.baseDir, root.relativeDirPath ?? ".", root.relativeFilePath)
6643
+ join64(this.baseDir, root.relativeDirPath ?? ".", root.relativeFilePath)
6628
6644
  );
6629
6645
  return await Promise.all(
6630
6646
  rootFilePaths.map(
@@ -6642,7 +6658,7 @@ var RulesProcessor = class extends FeatureProcessor {
6642
6658
  return [];
6643
6659
  }
6644
6660
  const nonRootFilePaths = await findFilesByGlobs(
6645
- join63(this.baseDir, nonRoot.relativeDirPath, `*.${nonRoot.extension}`)
6661
+ join64(this.baseDir, nonRoot.relativeDirPath, `*.${nonRoot.extension}`)
6646
6662
  );
6647
6663
  return await Promise.all(
6648
6664
  nonRootFilePaths.map(
@@ -7018,14 +7034,14 @@ s/<command> [arguments]
7018
7034
  This syntax employs a double slash (\`s/\`) to prevent conflicts with built-in slash commands.
7019
7035
  The \`s\` in \`s/\` stands for *simulate*. Because custom slash commands are not built-in, this syntax provides a pseudo way to invoke them.
7020
7036
 
7021
- When users call a custom slash command, you have to look for the markdown file, \`${join63(commands.relativeDirPath, "{command}.md")}\`, then execute the contents of that file as the block of operations.` : "";
7037
+ When users call a custom slash command, you have to look for the markdown file, \`${join64(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, "{command}.md")}\`, then execute the contents of that file as the block of operations.` : "";
7022
7038
  const subagentsSection = subagents ? `## Simulated Subagents
7023
7039
 
7024
7040
  Simulated subagents are specialized AI assistants that can be invoked to handle specific types of tasks. In this case, it can be appear something like custom slash commands simply. Simulated subagents can be called by custom slash commands.
7025
7041
 
7026
- When users call a simulated subagent, it will look for the corresponding markdown file, \`${join63(subagents.relativeDirPath, "{subagent}.md")}\`, and execute its contents as the block of operations.
7042
+ When users call a simulated subagent, it will look for the corresponding markdown file, \`${join64(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, "{subagent}.md")}\`, and execute its contents as the block of operations.
7027
7043
 
7028
- For example, if the user instructs \`Call planner subagent to plan the refactoring\`, you have to look for the markdown file, \`${join63(subagents.relativeDirPath, "planner.md")}\`, and execute its contents as the block of operations.` : "";
7044
+ For example, if the user instructs \`Call planner subagent to plan the refactoring\`, you have to look for the markdown file, \`${join64(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, "planner.md")}\`, and execute its contents as the block of operations.` : "";
7029
7045
  const result = [
7030
7046
  overview,
7031
7047
  ...this.simulateCommands && CommandsProcessor.getToolTargetsSimulated().includes(this.toolTarget) ? [commandsSection] : [],
@@ -7040,7 +7056,7 @@ async function generateCommand(options) {
7040
7056
  const config = await ConfigResolver.resolve(options);
7041
7057
  logger.setVerbose(config.getVerbose());
7042
7058
  logger.info("Generating files...");
7043
- if (!await fileExists(".rulesync")) {
7059
+ if (!await fileExists(RULESYNC_RELATIVE_DIR_PATH)) {
7044
7060
  logger.error("\u274C .rulesync directory not found. Run 'rulesync init' first.");
7045
7061
  process.exit(1);
7046
7062
  }
@@ -7239,9 +7255,9 @@ async function generateSubagents(config) {
7239
7255
  }
7240
7256
 
7241
7257
  // src/cli/commands/gitignore.ts
7242
- import { join as join64 } from "path";
7258
+ import { join as join65 } from "path";
7243
7259
  var gitignoreCommand = async () => {
7244
- const gitignorePath = join64(process.cwd(), ".gitignore");
7260
+ const gitignorePath = join65(process.cwd(), ".gitignore");
7245
7261
  const rulesFilesToIgnore = [
7246
7262
  "# Generated by rulesync - AI tool configuration files",
7247
7263
  // AGENTS.md
@@ -7482,24 +7498,26 @@ async function importSubagents(config, tool) {
7482
7498
  }
7483
7499
 
7484
7500
  // src/cli/commands/init.ts
7485
- import { join as join65 } from "path";
7501
+ import { join as join66 } from "path";
7486
7502
  async function initCommand() {
7487
7503
  logger.info("Initializing rulesync...");
7488
- await ensureDir(".rulesync");
7504
+ await ensureDir(RULESYNC_RELATIVE_DIR_PATH);
7489
7505
  await createSampleFiles();
7490
7506
  await createConfigFile();
7491
7507
  logger.success("rulesync initialized successfully!");
7492
7508
  logger.info("Next steps:");
7493
- logger.info(`1. Edit .rulesync/**/*.md, .rulesync/mcp.json and .rulesyncignore`);
7509
+ logger.info(
7510
+ `1. Edit ${RULESYNC_RELATIVE_DIR_PATH}/**/*.md, ${RULESYNC_MCP_RELATIVE_FILE_PATH} and ${RULESYNC_IGNORE_RELATIVE_FILE_PATH}`
7511
+ );
7494
7512
  logger.info("2. Run 'rulesync generate' to create configuration files");
7495
7513
  }
7496
7514
  async function createConfigFile() {
7497
- if (await fileExists("rulesync.jsonc")) {
7498
- logger.info("Skipped rulesync.jsonc (already exists)");
7515
+ if (await fileExists(RULESYNC_CONFIG_RELATIVE_FILE_PATH)) {
7516
+ logger.info(`Skipped ${RULESYNC_CONFIG_RELATIVE_FILE_PATH} (already exists)`);
7499
7517
  return;
7500
7518
  }
7501
7519
  await writeFileContent(
7502
- "rulesync.jsonc",
7520
+ RULESYNC_CONFIG_RELATIVE_FILE_PATH,
7503
7521
  JSON.stringify(
7504
7522
  {
7505
7523
  targets: ["copilot", "cursor", "claudecode", "codexcli"],
@@ -7516,11 +7534,11 @@ async function createConfigFile() {
7516
7534
  2
7517
7535
  )
7518
7536
  );
7519
- logger.success("Created rulesync.jsonc");
7537
+ logger.success(`Created ${RULESYNC_CONFIG_RELATIVE_FILE_PATH}`);
7520
7538
  }
7521
7539
  async function createSampleFiles() {
7522
7540
  const sampleRuleFile = {
7523
- filename: "overview.md",
7541
+ filename: RULESYNC_OVERVIEW_FILE_NAME,
7524
7542
  content: `---
7525
7543
  root: true
7526
7544
  targets: ["*"]
@@ -7643,14 +7661,14 @@ Attention, again, you are just the planner, so though you can read any files and
7643
7661
  await ensureDir(commandPaths.relativeDirPath);
7644
7662
  await ensureDir(subagentPaths.relativeDirPath);
7645
7663
  await ensureDir(ignorePaths.relativeDirPath);
7646
- const ruleFilepath = join65(rulePaths.recommended.relativeDirPath, sampleRuleFile.filename);
7664
+ const ruleFilepath = join66(rulePaths.recommended.relativeDirPath, sampleRuleFile.filename);
7647
7665
  if (!await fileExists(ruleFilepath)) {
7648
7666
  await writeFileContent(ruleFilepath, sampleRuleFile.content);
7649
7667
  logger.success(`Created ${ruleFilepath}`);
7650
7668
  } else {
7651
7669
  logger.info(`Skipped ${ruleFilepath} (already exists)`);
7652
7670
  }
7653
- const mcpFilepath = join65(
7671
+ const mcpFilepath = join66(
7654
7672
  mcpPaths.recommended.relativeDirPath,
7655
7673
  mcpPaths.recommended.relativeFilePath
7656
7674
  );
@@ -7660,21 +7678,21 @@ Attention, again, you are just the planner, so though you can read any files and
7660
7678
  } else {
7661
7679
  logger.info(`Skipped ${mcpFilepath} (already exists)`);
7662
7680
  }
7663
- const commandFilepath = join65(commandPaths.relativeDirPath, sampleCommandFile.filename);
7681
+ const commandFilepath = join66(commandPaths.relativeDirPath, sampleCommandFile.filename);
7664
7682
  if (!await fileExists(commandFilepath)) {
7665
7683
  await writeFileContent(commandFilepath, sampleCommandFile.content);
7666
7684
  logger.success(`Created ${commandFilepath}`);
7667
7685
  } else {
7668
7686
  logger.info(`Skipped ${commandFilepath} (already exists)`);
7669
7687
  }
7670
- const subagentFilepath = join65(subagentPaths.relativeDirPath, sampleSubagentFile.filename);
7688
+ const subagentFilepath = join66(subagentPaths.relativeDirPath, sampleSubagentFile.filename);
7671
7689
  if (!await fileExists(subagentFilepath)) {
7672
7690
  await writeFileContent(subagentFilepath, sampleSubagentFile.content);
7673
7691
  logger.success(`Created ${subagentFilepath}`);
7674
7692
  } else {
7675
7693
  logger.info(`Skipped ${subagentFilepath} (already exists)`);
7676
7694
  }
7677
- const ignoreFilepath = join65(ignorePaths.relativeDirPath, ignorePaths.relativeFilePath);
7695
+ const ignoreFilepath = join66(ignorePaths.relativeDirPath, ignorePaths.relativeFilePath);
7678
7696
  if (!await fileExists(ignoreFilepath)) {
7679
7697
  await writeFileContent(ignoreFilepath, sampleIgnoreFile.content);
7680
7698
  logger.success(`Created ${ignoreFilepath}`);
@@ -7684,31 +7702,408 @@ Attention, again, you are just the planner, so though you can read any files and
7684
7702
  }
7685
7703
 
7686
7704
  // src/cli/commands/mcp.ts
7687
- import { basename as basename18, join as join66 } from "path";
7688
7705
  import { FastMCP } from "fastmcp";
7706
+
7707
+ // src/mcp/commands.ts
7708
+ import { basename as basename18, join as join67 } from "path";
7689
7709
  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`);
7710
+ var maxCommandSizeBytes = 1024 * 1024;
7711
+ var maxCommandsCount = 1e3;
7712
+ async function listCommands() {
7713
+ const commandsDir = join67(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH);
7714
+ try {
7715
+ const files = await listDirectoryFiles(commandsDir);
7716
+ const mdFiles = files.filter((file) => file.endsWith(".md"));
7717
+ const commands = await Promise.all(
7718
+ mdFiles.map(async (file) => {
7719
+ try {
7720
+ const command = await RulesyncCommand.fromFile({
7721
+ relativeFilePath: file
7722
+ });
7723
+ const frontmatter = command.getFrontmatter();
7724
+ return {
7725
+ relativePathFromCwd: join67(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, file),
7726
+ frontmatter
7727
+ };
7728
+ } catch (error) {
7729
+ logger.error(`Failed to read command file ${file}: ${formatError(error)}`);
7730
+ return null;
7731
+ }
7732
+ })
7733
+ );
7734
+ return commands.filter((command) => command !== null);
7735
+ } catch (error) {
7736
+ logger.error(`Failed to read commands directory: ${formatError(error)}`);
7737
+ return [];
7738
+ }
7739
+ }
7740
+ async function getCommand({ relativePathFromCwd }) {
7741
+ checkPathTraversal({
7742
+ relativePath: relativePathFromCwd,
7743
+ intendedRootDir: process.cwd()
7744
+ });
7745
+ const filename = basename18(relativePathFromCwd);
7746
+ try {
7747
+ const command = await RulesyncCommand.fromFile({
7748
+ relativeFilePath: filename
7749
+ });
7750
+ return {
7751
+ relativePathFromCwd: join67(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),
7752
+ frontmatter: command.getFrontmatter(),
7753
+ body: command.getBody()
7754
+ };
7755
+ } catch (error) {
7756
+ throw new Error(`Failed to read command file ${relativePathFromCwd}: ${formatError(error)}`, {
7757
+ cause: error
7758
+ });
7759
+ }
7760
+ }
7761
+ async function putCommand({
7762
+ relativePathFromCwd,
7763
+ frontmatter,
7764
+ body
7765
+ }) {
7766
+ checkPathTraversal({
7767
+ relativePath: relativePathFromCwd,
7768
+ intendedRootDir: process.cwd()
7769
+ });
7770
+ const filename = basename18(relativePathFromCwd);
7771
+ const estimatedSize = JSON.stringify(frontmatter).length + body.length;
7772
+ if (estimatedSize > maxCommandSizeBytes) {
7773
+ throw new Error(
7774
+ `Command size ${estimatedSize} bytes exceeds maximum ${maxCommandSizeBytes} bytes (1MB)`
7775
+ );
7776
+ }
7777
+ try {
7778
+ const existingCommands = await listCommands();
7779
+ const isUpdate = existingCommands.some(
7780
+ (command2) => command2.relativePathFromCwd === join67(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename)
7781
+ );
7782
+ if (!isUpdate && existingCommands.length >= maxCommandsCount) {
7783
+ throw new Error(`Maximum number of commands (${maxCommandsCount}) reached`);
7784
+ }
7785
+ const fileContent = stringifyFrontmatter(body, frontmatter);
7786
+ const command = new RulesyncCommand({
7787
+ baseDir: process.cwd(),
7788
+ relativeDirPath: RULESYNC_COMMANDS_RELATIVE_DIR_PATH,
7789
+ relativeFilePath: filename,
7790
+ frontmatter,
7791
+ body,
7792
+ fileContent,
7793
+ validate: true
7794
+ });
7795
+ const commandsDir = join67(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH);
7796
+ await ensureDir(commandsDir);
7797
+ await writeFileContent(command.getFilePath(), command.getFileContent());
7798
+ return {
7799
+ relativePathFromCwd: join67(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),
7800
+ frontmatter: command.getFrontmatter(),
7801
+ body: command.getBody()
7802
+ };
7803
+ } catch (error) {
7804
+ throw new Error(`Failed to write command file ${relativePathFromCwd}: ${formatError(error)}`, {
7805
+ cause: error
7806
+ });
7807
+ }
7808
+ }
7809
+ async function deleteCommand({ relativePathFromCwd }) {
7810
+ checkPathTraversal({
7811
+ relativePath: relativePathFromCwd,
7812
+ intendedRootDir: process.cwd()
7813
+ });
7814
+ const filename = basename18(relativePathFromCwd);
7815
+ const fullPath = join67(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename);
7816
+ try {
7817
+ await removeFile(fullPath);
7818
+ return {
7819
+ relativePathFromCwd: join67(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename)
7820
+ };
7821
+ } catch (error) {
7822
+ throw new Error(`Failed to delete command file ${relativePathFromCwd}: ${formatError(error)}`, {
7823
+ cause: error
7824
+ });
7825
+ }
7826
+ }
7827
+ var commandToolSchemas = {
7828
+ listCommands: z23.object({}),
7829
+ getCommand: z23.object({
7830
+ relativePathFromCwd: z23.string()
7831
+ }),
7832
+ putCommand: z23.object({
7833
+ relativePathFromCwd: z23.string(),
7834
+ frontmatter: RulesyncCommandFrontmatterSchema,
7835
+ body: z23.string()
7836
+ }),
7837
+ deleteCommand: z23.object({
7838
+ relativePathFromCwd: z23.string()
7839
+ })
7840
+ };
7841
+ var commandTools = {
7842
+ listCommands: {
7843
+ name: "listCommands",
7844
+ description: `List all commands from ${join67(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
7845
+ parameters: commandToolSchemas.listCommands,
7846
+ execute: async () => {
7847
+ const commands = await listCommands();
7848
+ const output = { commands };
7849
+ return JSON.stringify(output, null, 2);
7850
+ }
7851
+ },
7852
+ getCommand: {
7853
+ name: "getCommand",
7854
+ description: "Get detailed information about a specific command. relativePathFromCwd parameter is required.",
7855
+ parameters: commandToolSchemas.getCommand,
7856
+ execute: async (args) => {
7857
+ const result = await getCommand({ relativePathFromCwd: args.relativePathFromCwd });
7858
+ return JSON.stringify(result, null, 2);
7859
+ }
7860
+ },
7861
+ putCommand: {
7862
+ name: "putCommand",
7863
+ description: "Create or update a command (upsert operation). relativePathFromCwd, frontmatter, and body parameters are required.",
7864
+ parameters: commandToolSchemas.putCommand,
7865
+ execute: async (args) => {
7866
+ const result = await putCommand({
7867
+ relativePathFromCwd: args.relativePathFromCwd,
7868
+ frontmatter: args.frontmatter,
7869
+ body: args.body
7870
+ });
7871
+ return JSON.stringify(result, null, 2);
7872
+ }
7873
+ },
7874
+ deleteCommand: {
7875
+ name: "deleteCommand",
7876
+ description: "Delete a command file. relativePathFromCwd parameter is required.",
7877
+ parameters: commandToolSchemas.deleteCommand,
7878
+ execute: async (args) => {
7879
+ const result = await deleteCommand({ relativePathFromCwd: args.relativePathFromCwd });
7880
+ return JSON.stringify(result, null, 2);
7881
+ }
7882
+ }
7883
+ };
7884
+
7885
+ // src/mcp/ignore.ts
7886
+ import { join as join68 } from "path";
7887
+ import { z as z24 } from "zod/mini";
7888
+ var maxIgnoreFileSizeBytes = 100 * 1024;
7889
+ async function getIgnoreFile() {
7890
+ const ignoreFilePath = join68(process.cwd(), RULESYNC_IGNORE_RELATIVE_FILE_PATH);
7891
+ try {
7892
+ const content = await readFileContent(ignoreFilePath);
7893
+ return {
7894
+ relativePathFromCwd: RULESYNC_IGNORE_RELATIVE_FILE_PATH,
7895
+ content
7896
+ };
7897
+ } catch (error) {
7898
+ throw new Error(`Failed to read .rulesyncignore file: ${formatError(error)}`, {
7899
+ cause: error
7900
+ });
7901
+ }
7902
+ }
7903
+ async function putIgnoreFile({ content }) {
7904
+ const ignoreFilePath = join68(process.cwd(), RULESYNC_IGNORE_RELATIVE_FILE_PATH);
7905
+ const contentSizeBytes = Buffer.byteLength(content, "utf8");
7906
+ if (contentSizeBytes > maxIgnoreFileSizeBytes) {
7907
+ throw new Error(
7908
+ `Ignore file size ${contentSizeBytes} bytes exceeds maximum ${maxIgnoreFileSizeBytes} bytes (100KB)`
7909
+ );
7910
+ }
7911
+ try {
7912
+ await ensureDir(process.cwd());
7913
+ await writeFileContent(ignoreFilePath, content);
7914
+ return {
7915
+ relativePathFromCwd: RULESYNC_IGNORE_RELATIVE_FILE_PATH,
7916
+ content
7917
+ };
7918
+ } catch (error) {
7919
+ throw new Error(`Failed to write .rulesyncignore file: ${formatError(error)}`, {
7920
+ cause: error
7921
+ });
7922
+ }
7923
+ }
7924
+ async function deleteIgnoreFile() {
7925
+ const ignoreFilePath = join68(process.cwd(), RULESYNC_IGNORE_RELATIVE_FILE_PATH);
7926
+ try {
7927
+ await removeFile(ignoreFilePath);
7928
+ return {
7929
+ relativePathFromCwd: RULESYNC_IGNORE_RELATIVE_FILE_PATH
7930
+ };
7931
+ } catch (error) {
7932
+ throw new Error(`Failed to delete .rulesyncignore file: ${formatError(error)}`, {
7933
+ cause: error
7934
+ });
7935
+ }
7936
+ }
7937
+ var ignoreToolSchemas = {
7938
+ getIgnoreFile: z24.object({}),
7939
+ putIgnoreFile: z24.object({
7940
+ content: z24.string()
7941
+ }),
7942
+ deleteIgnoreFile: z24.object({})
7943
+ };
7944
+ var ignoreTools = {
7945
+ getIgnoreFile: {
7946
+ name: "getIgnoreFile",
7947
+ description: "Get the content of the .rulesyncignore file from the project root.",
7948
+ parameters: ignoreToolSchemas.getIgnoreFile,
7949
+ execute: async () => {
7950
+ const result = await getIgnoreFile();
7951
+ return JSON.stringify(result, null, 2);
7952
+ }
7953
+ },
7954
+ putIgnoreFile: {
7955
+ name: "putIgnoreFile",
7956
+ description: "Create or update the .rulesyncignore file (upsert operation). content parameter is required.",
7957
+ parameters: ignoreToolSchemas.putIgnoreFile,
7958
+ execute: async (args) => {
7959
+ const result = await putIgnoreFile({ content: args.content });
7960
+ return JSON.stringify(result, null, 2);
7961
+ }
7962
+ },
7963
+ deleteIgnoreFile: {
7964
+ name: "deleteIgnoreFile",
7965
+ description: "Delete the .rulesyncignore file from the project root.",
7966
+ parameters: ignoreToolSchemas.deleteIgnoreFile,
7967
+ execute: async () => {
7968
+ const result = await deleteIgnoreFile();
7969
+ return JSON.stringify(result, null, 2);
7970
+ }
7697
7971
  }
7972
+ };
7973
+
7974
+ // src/mcp/mcp.ts
7975
+ import { join as join69 } from "path";
7976
+ import { z as z25 } from "zod/mini";
7977
+ var maxMcpSizeBytes = 1024 * 1024;
7978
+ async function getMcpFile() {
7698
7979
  try {
7699
- resolvePath(normalizedPath, process.cwd());
7980
+ const rulesyncMcp = await RulesyncMcp.fromFile({
7981
+ validate: true,
7982
+ modularMcp: false
7983
+ });
7984
+ const relativePathFromCwd = join69(
7985
+ rulesyncMcp.getRelativeDirPath(),
7986
+ rulesyncMcp.getRelativeFilePath()
7987
+ );
7988
+ return {
7989
+ relativePathFromCwd,
7990
+ content: rulesyncMcp.getFileContent()
7991
+ };
7700
7992
  } catch (error) {
7701
- throw new Error(`Path validation failed: ${formatError(error)}`, { cause: error });
7993
+ throw new Error(`Failed to read MCP file: ${formatError(error)}`, {
7994
+ cause: error
7995
+ });
7702
7996
  }
7703
- const filename = basename18(normalizedPath);
7704
- if (!/^[a-zA-Z0-9_-]+\.md$/.test(filename)) {
7997
+ }
7998
+ async function putMcpFile({ content }) {
7999
+ if (content.length > maxMcpSizeBytes) {
7705
8000
  throw new Error(
7706
- `Invalid filename: ${filename}. Must match pattern [a-zA-Z0-9_-]+.md (alphanumeric, hyphens, underscores only)`
8001
+ `MCP file size ${content.length} bytes exceeds maximum ${maxMcpSizeBytes} bytes (1MB)`
7707
8002
  );
7708
8003
  }
8004
+ try {
8005
+ JSON.parse(content);
8006
+ } catch (error) {
8007
+ throw new Error(`Invalid JSON format in MCP file: ${formatError(error)}`, {
8008
+ cause: error
8009
+ });
8010
+ }
8011
+ try {
8012
+ const baseDir = process.cwd();
8013
+ const paths = RulesyncMcp.getSettablePaths();
8014
+ const relativeDirPath = paths.recommended.relativeDirPath;
8015
+ const relativeFilePath = paths.recommended.relativeFilePath;
8016
+ const fullPath = join69(baseDir, relativeDirPath, relativeFilePath);
8017
+ const rulesyncMcp = new RulesyncMcp({
8018
+ baseDir,
8019
+ relativeDirPath,
8020
+ relativeFilePath,
8021
+ fileContent: content,
8022
+ validate: true,
8023
+ modularMcp: false
8024
+ });
8025
+ await ensureDir(join69(baseDir, relativeDirPath));
8026
+ await writeFileContent(fullPath, content);
8027
+ const relativePathFromCwd = join69(relativeDirPath, relativeFilePath);
8028
+ return {
8029
+ relativePathFromCwd,
8030
+ content: rulesyncMcp.getFileContent()
8031
+ };
8032
+ } catch (error) {
8033
+ throw new Error(`Failed to write MCP file: ${formatError(error)}`, {
8034
+ cause: error
8035
+ });
8036
+ }
7709
8037
  }
8038
+ async function deleteMcpFile() {
8039
+ try {
8040
+ const baseDir = process.cwd();
8041
+ const paths = RulesyncMcp.getSettablePaths();
8042
+ const recommendedPath = join69(
8043
+ baseDir,
8044
+ paths.recommended.relativeDirPath,
8045
+ paths.recommended.relativeFilePath
8046
+ );
8047
+ const legacyPath = join69(baseDir, paths.legacy.relativeDirPath, paths.legacy.relativeFilePath);
8048
+ await removeFile(recommendedPath);
8049
+ await removeFile(legacyPath);
8050
+ const relativePathFromCwd = join69(
8051
+ paths.recommended.relativeDirPath,
8052
+ paths.recommended.relativeFilePath
8053
+ );
8054
+ return {
8055
+ relativePathFromCwd
8056
+ };
8057
+ } catch (error) {
8058
+ throw new Error(`Failed to delete MCP file: ${formatError(error)}`, {
8059
+ cause: error
8060
+ });
8061
+ }
8062
+ }
8063
+ var mcpToolSchemas = {
8064
+ getMcpFile: z25.object({}),
8065
+ putMcpFile: z25.object({
8066
+ content: z25.string()
8067
+ }),
8068
+ deleteMcpFile: z25.object({})
8069
+ };
8070
+ var mcpTools = {
8071
+ getMcpFile: {
8072
+ name: "getMcpFile",
8073
+ description: `Get the MCP configuration file (${RULESYNC_MCP_RELATIVE_FILE_PATH}).`,
8074
+ parameters: mcpToolSchemas.getMcpFile,
8075
+ execute: async () => {
8076
+ const result = await getMcpFile();
8077
+ return JSON.stringify(result, null, 2);
8078
+ }
8079
+ },
8080
+ putMcpFile: {
8081
+ name: "putMcpFile",
8082
+ description: "Create or update the MCP configuration file (upsert operation). content parameter is required and must be valid JSON.",
8083
+ parameters: mcpToolSchemas.putMcpFile,
8084
+ execute: async (args) => {
8085
+ const result = await putMcpFile({ content: args.content });
8086
+ return JSON.stringify(result, null, 2);
8087
+ }
8088
+ },
8089
+ deleteMcpFile: {
8090
+ name: "deleteMcpFile",
8091
+ description: "Delete the MCP configuration file.",
8092
+ parameters: mcpToolSchemas.deleteMcpFile,
8093
+ execute: async () => {
8094
+ const result = await deleteMcpFile();
8095
+ return JSON.stringify(result, null, 2);
8096
+ }
8097
+ }
8098
+ };
8099
+
8100
+ // src/mcp/rules.ts
8101
+ import { basename as basename19, join as join70 } from "path";
8102
+ import { z as z26 } from "zod/mini";
8103
+ var maxRuleSizeBytes = 1024 * 1024;
8104
+ var maxRulesCount = 1e3;
7710
8105
  async function listRules() {
7711
- const rulesDir = join66(process.cwd(), ".rulesync", "rules");
8106
+ const rulesDir = join70(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH);
7712
8107
  try {
7713
8108
  const files = await listDirectoryFiles(rulesDir);
7714
8109
  const mdFiles = files.filter((file) => file.endsWith(".md"));
@@ -7721,7 +8116,7 @@ async function listRules() {
7721
8116
  });
7722
8117
  const frontmatter = rule.getFrontmatter();
7723
8118
  return {
7724
- relativePathFromCwd: join66(".rulesync", "rules", file),
8119
+ relativePathFromCwd: join70(RULESYNC_RULES_RELATIVE_DIR_PATH, file),
7725
8120
  frontmatter
7726
8121
  };
7727
8122
  } catch (error) {
@@ -7737,15 +8132,18 @@ async function listRules() {
7737
8132
  }
7738
8133
  }
7739
8134
  async function getRule({ relativePathFromCwd }) {
7740
- validateRulePath(relativePathFromCwd);
7741
- const filename = basename18(relativePathFromCwd);
8135
+ checkPathTraversal({
8136
+ relativePath: relativePathFromCwd,
8137
+ intendedRootDir: process.cwd()
8138
+ });
8139
+ const filename = basename19(relativePathFromCwd);
7742
8140
  try {
7743
8141
  const rule = await RulesyncRule.fromFile({
7744
8142
  relativeFilePath: filename,
7745
8143
  validate: true
7746
8144
  });
7747
8145
  return {
7748
- relativePathFromCwd: join66(".rulesync", "rules", filename),
8146
+ relativePathFromCwd: join70(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),
7749
8147
  frontmatter: rule.getFrontmatter(),
7750
8148
  body: rule.getBody()
7751
8149
  };
@@ -7760,35 +8158,38 @@ async function putRule({
7760
8158
  frontmatter,
7761
8159
  body
7762
8160
  }) {
7763
- validateRulePath(relativePathFromCwd);
7764
- const filename = basename18(relativePathFromCwd);
8161
+ checkPathTraversal({
8162
+ relativePath: relativePathFromCwd,
8163
+ intendedRootDir: process.cwd()
8164
+ });
8165
+ const filename = basename19(relativePathFromCwd);
7765
8166
  const estimatedSize = JSON.stringify(frontmatter).length + body.length;
7766
- if (estimatedSize > MAX_RULE_SIZE_BYTES) {
8167
+ if (estimatedSize > maxRuleSizeBytes) {
7767
8168
  throw new Error(
7768
- `Rule size ${estimatedSize} bytes exceeds maximum ${MAX_RULE_SIZE_BYTES} bytes (1MB)`
8169
+ `Rule size ${estimatedSize} bytes exceeds maximum ${maxRuleSizeBytes} bytes (1MB)`
7769
8170
  );
7770
8171
  }
7771
8172
  try {
7772
8173
  const existingRules = await listRules();
7773
8174
  const isUpdate = existingRules.some(
7774
- (rule2) => rule2.relativePathFromCwd === join66(".rulesync", "rules", filename)
8175
+ (rule2) => rule2.relativePathFromCwd === join70(RULESYNC_RULES_RELATIVE_DIR_PATH, filename)
7775
8176
  );
7776
- if (!isUpdate && existingRules.length >= MAX_RULES_COUNT) {
7777
- throw new Error(`Maximum number of rules (${MAX_RULES_COUNT}) reached`);
8177
+ if (!isUpdate && existingRules.length >= maxRulesCount) {
8178
+ throw new Error(`Maximum number of rules (${maxRulesCount}) reached`);
7778
8179
  }
7779
8180
  const rule = new RulesyncRule({
7780
8181
  baseDir: process.cwd(),
7781
- relativeDirPath: ".rulesync/rules",
8182
+ relativeDirPath: RULESYNC_RULES_RELATIVE_DIR_PATH,
7782
8183
  relativeFilePath: filename,
7783
8184
  frontmatter,
7784
8185
  body,
7785
8186
  validate: true
7786
8187
  });
7787
- const rulesDir = join66(process.cwd(), ".rulesync", "rules");
8188
+ const rulesDir = join70(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH);
7788
8189
  await ensureDir(rulesDir);
7789
8190
  await writeFileContent(rule.getFilePath(), rule.getFileContent());
7790
8191
  return {
7791
- relativePathFromCwd: join66(".rulesync", "rules", filename),
8192
+ relativePathFromCwd: join70(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),
7792
8193
  frontmatter: rule.getFrontmatter(),
7793
8194
  body: rule.getBody()
7794
8195
  };
@@ -7799,13 +8200,16 @@ async function putRule({
7799
8200
  }
7800
8201
  }
7801
8202
  async function deleteRule({ relativePathFromCwd }) {
7802
- validateRulePath(relativePathFromCwd);
7803
- const filename = basename18(relativePathFromCwd);
7804
- const fullPath = join66(process.cwd(), ".rulesync", "rules", filename);
8203
+ checkPathTraversal({
8204
+ relativePath: relativePathFromCwd,
8205
+ intendedRootDir: process.cwd()
8206
+ });
8207
+ const filename = basename19(relativePathFromCwd);
8208
+ const fullPath = join70(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH, filename);
7805
8209
  try {
7806
8210
  await removeFile(fullPath);
7807
8211
  return {
7808
- relativePathFromCwd: join66(".rulesync", "rules", filename)
8212
+ relativePathFromCwd: join70(RULESYNC_RULES_RELATIVE_DIR_PATH, filename)
7809
8213
  };
7810
8214
  } catch (error) {
7811
8215
  throw new Error(`Failed to delete rule file ${relativePathFromCwd}: ${formatError(error)}`, {
@@ -7813,42 +8217,44 @@ async function deleteRule({ relativePathFromCwd }) {
7813
8217
  });
7814
8218
  }
7815
8219
  }
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({
8220
+ var ruleToolSchemas = {
8221
+ listRules: z26.object({}),
8222
+ getRule: z26.object({
8223
+ relativePathFromCwd: z26.string()
8224
+ }),
8225
+ putRule: z26.object({
8226
+ relativePathFromCwd: z26.string(),
8227
+ frontmatter: RulesyncRuleFrontmatterSchema,
8228
+ body: z26.string()
8229
+ }),
8230
+ deleteRule: z26.object({
8231
+ relativePathFromCwd: z26.string()
8232
+ })
8233
+ };
8234
+ var ruleTools = {
8235
+ listRules: {
7824
8236
  name: "listRules",
7825
- description: "List all rules from .rulesync/rules/*.md with their frontmatter",
7826
- parameters: z23.object({}),
8237
+ description: `List all rules from ${join70(RULESYNC_RULES_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
8238
+ parameters: ruleToolSchemas.listRules,
7827
8239
  execute: async () => {
7828
8240
  const rules = await listRules();
7829
8241
  const output = { rules };
7830
8242
  return JSON.stringify(output, null, 2);
7831
8243
  }
7832
- });
7833
- server.addTool({
8244
+ },
8245
+ getRule: {
7834
8246
  name: "getRule",
7835
8247
  description: "Get detailed information about a specific rule. relativePathFromCwd parameter is required.",
7836
- parameters: z23.object({
7837
- relativePathFromCwd: z23.string()
7838
- }),
8248
+ parameters: ruleToolSchemas.getRule,
7839
8249
  execute: async (args) => {
7840
8250
  const result = await getRule({ relativePathFromCwd: args.relativePathFromCwd });
7841
8251
  return JSON.stringify(result, null, 2);
7842
8252
  }
7843
- });
7844
- server.addTool({
8253
+ },
8254
+ putRule: {
7845
8255
  name: "putRule",
7846
8256
  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
- }),
8257
+ parameters: ruleToolSchemas.putRule,
7852
8258
  execute: async (args) => {
7853
8259
  const result = await putRule({
7854
8260
  relativePathFromCwd: args.relativePathFromCwd,
@@ -7857,18 +8263,227 @@ async function mcpCommand({ version }) {
7857
8263
  });
7858
8264
  return JSON.stringify(result, null, 2);
7859
8265
  }
7860
- });
7861
- server.addTool({
8266
+ },
8267
+ deleteRule: {
7862
8268
  name: "deleteRule",
7863
8269
  description: "Delete a rule file. relativePathFromCwd parameter is required.",
7864
- parameters: z23.object({
7865
- relativePathFromCwd: z23.string()
7866
- }),
8270
+ parameters: ruleToolSchemas.deleteRule,
7867
8271
  execute: async (args) => {
7868
8272
  const result = await deleteRule({ relativePathFromCwd: args.relativePathFromCwd });
7869
8273
  return JSON.stringify(result, null, 2);
7870
8274
  }
8275
+ }
8276
+ };
8277
+
8278
+ // src/mcp/subagents.ts
8279
+ import { basename as basename20, join as join71 } from "path";
8280
+ import { z as z27 } from "zod/mini";
8281
+ var maxSubagentSizeBytes = 1024 * 1024;
8282
+ var maxSubagentsCount = 1e3;
8283
+ async function listSubagents() {
8284
+ const subagentsDir = join71(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH);
8285
+ try {
8286
+ const files = await listDirectoryFiles(subagentsDir);
8287
+ const mdFiles = files.filter((file) => file.endsWith(".md"));
8288
+ const subagents = await Promise.all(
8289
+ mdFiles.map(async (file) => {
8290
+ try {
8291
+ const subagent = await RulesyncSubagent.fromFile({
8292
+ relativeFilePath: file,
8293
+ validate: true
8294
+ });
8295
+ const frontmatter = subagent.getFrontmatter();
8296
+ return {
8297
+ relativePathFromCwd: join71(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, file),
8298
+ frontmatter
8299
+ };
8300
+ } catch (error) {
8301
+ logger.error(`Failed to read subagent file ${file}: ${formatError(error)}`);
8302
+ return null;
8303
+ }
8304
+ })
8305
+ );
8306
+ return subagents.filter(
8307
+ (subagent) => subagent !== null
8308
+ );
8309
+ } catch (error) {
8310
+ logger.error(`Failed to read subagents directory: ${formatError(error)}`);
8311
+ return [];
8312
+ }
8313
+ }
8314
+ async function getSubagent({ relativePathFromCwd }) {
8315
+ checkPathTraversal({
8316
+ relativePath: relativePathFromCwd,
8317
+ intendedRootDir: process.cwd()
8318
+ });
8319
+ const filename = basename20(relativePathFromCwd);
8320
+ try {
8321
+ const subagent = await RulesyncSubagent.fromFile({
8322
+ relativeFilePath: filename,
8323
+ validate: true
8324
+ });
8325
+ return {
8326
+ relativePathFromCwd: join71(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),
8327
+ frontmatter: subagent.getFrontmatter(),
8328
+ body: subagent.getBody()
8329
+ };
8330
+ } catch (error) {
8331
+ throw new Error(`Failed to read subagent file ${relativePathFromCwd}: ${formatError(error)}`, {
8332
+ cause: error
8333
+ });
8334
+ }
8335
+ }
8336
+ async function putSubagent({
8337
+ relativePathFromCwd,
8338
+ frontmatter,
8339
+ body
8340
+ }) {
8341
+ checkPathTraversal({
8342
+ relativePath: relativePathFromCwd,
8343
+ intendedRootDir: process.cwd()
8344
+ });
8345
+ const filename = basename20(relativePathFromCwd);
8346
+ const estimatedSize = JSON.stringify(frontmatter).length + body.length;
8347
+ if (estimatedSize > maxSubagentSizeBytes) {
8348
+ throw new Error(
8349
+ `Subagent size ${estimatedSize} bytes exceeds maximum ${maxSubagentSizeBytes} bytes (1MB)`
8350
+ );
8351
+ }
8352
+ try {
8353
+ const existingSubagents = await listSubagents();
8354
+ const isUpdate = existingSubagents.some(
8355
+ (subagent2) => subagent2.relativePathFromCwd === join71(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename)
8356
+ );
8357
+ if (!isUpdate && existingSubagents.length >= maxSubagentsCount) {
8358
+ throw new Error(`Maximum number of subagents (${maxSubagentsCount}) reached`);
8359
+ }
8360
+ const subagent = new RulesyncSubagent({
8361
+ baseDir: process.cwd(),
8362
+ relativeDirPath: RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH,
8363
+ relativeFilePath: filename,
8364
+ frontmatter,
8365
+ body,
8366
+ validate: true
8367
+ });
8368
+ const subagentsDir = join71(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH);
8369
+ await ensureDir(subagentsDir);
8370
+ await writeFileContent(subagent.getFilePath(), subagent.getFileContent());
8371
+ return {
8372
+ relativePathFromCwd: join71(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),
8373
+ frontmatter: subagent.getFrontmatter(),
8374
+ body: subagent.getBody()
8375
+ };
8376
+ } catch (error) {
8377
+ throw new Error(`Failed to write subagent file ${relativePathFromCwd}: ${formatError(error)}`, {
8378
+ cause: error
8379
+ });
8380
+ }
8381
+ }
8382
+ async function deleteSubagent({ relativePathFromCwd }) {
8383
+ checkPathTraversal({
8384
+ relativePath: relativePathFromCwd,
8385
+ intendedRootDir: process.cwd()
8386
+ });
8387
+ const filename = basename20(relativePathFromCwd);
8388
+ const fullPath = join71(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename);
8389
+ try {
8390
+ await removeFile(fullPath);
8391
+ return {
8392
+ relativePathFromCwd: join71(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename)
8393
+ };
8394
+ } catch (error) {
8395
+ throw new Error(
8396
+ `Failed to delete subagent file ${relativePathFromCwd}: ${formatError(error)}`,
8397
+ {
8398
+ cause: error
8399
+ }
8400
+ );
8401
+ }
8402
+ }
8403
+ var subagentToolSchemas = {
8404
+ listSubagents: z27.object({}),
8405
+ getSubagent: z27.object({
8406
+ relativePathFromCwd: z27.string()
8407
+ }),
8408
+ putSubagent: z27.object({
8409
+ relativePathFromCwd: z27.string(),
8410
+ frontmatter: RulesyncSubagentFrontmatterSchema,
8411
+ body: z27.string()
8412
+ }),
8413
+ deleteSubagent: z27.object({
8414
+ relativePathFromCwd: z27.string()
8415
+ })
8416
+ };
8417
+ var subagentTools = {
8418
+ listSubagents: {
8419
+ name: "listSubagents",
8420
+ description: `List all subagents from ${join71(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
8421
+ parameters: subagentToolSchemas.listSubagents,
8422
+ execute: async () => {
8423
+ const subagents = await listSubagents();
8424
+ const output = { subagents };
8425
+ return JSON.stringify(output, null, 2);
8426
+ }
8427
+ },
8428
+ getSubagent: {
8429
+ name: "getSubagent",
8430
+ description: "Get detailed information about a specific subagent. relativePathFromCwd parameter is required.",
8431
+ parameters: subagentToolSchemas.getSubagent,
8432
+ execute: async (args) => {
8433
+ const result = await getSubagent({ relativePathFromCwd: args.relativePathFromCwd });
8434
+ return JSON.stringify(result, null, 2);
8435
+ }
8436
+ },
8437
+ putSubagent: {
8438
+ name: "putSubagent",
8439
+ description: "Create or update a subagent (upsert operation). relativePathFromCwd, frontmatter, and body parameters are required.",
8440
+ parameters: subagentToolSchemas.putSubagent,
8441
+ execute: async (args) => {
8442
+ const result = await putSubagent({
8443
+ relativePathFromCwd: args.relativePathFromCwd,
8444
+ frontmatter: args.frontmatter,
8445
+ body: args.body
8446
+ });
8447
+ return JSON.stringify(result, null, 2);
8448
+ }
8449
+ },
8450
+ deleteSubagent: {
8451
+ name: "deleteSubagent",
8452
+ description: "Delete a subagent file. relativePathFromCwd parameter is required.",
8453
+ parameters: subagentToolSchemas.deleteSubagent,
8454
+ execute: async (args) => {
8455
+ const result = await deleteSubagent({ relativePathFromCwd: args.relativePathFromCwd });
8456
+ return JSON.stringify(result, null, 2);
8457
+ }
8458
+ }
8459
+ };
8460
+
8461
+ // src/cli/commands/mcp.ts
8462
+ async function mcpCommand({ version }) {
8463
+ const server = new FastMCP({
8464
+ name: "Rulesync MCP Server",
8465
+ // eslint-disable-next-line no-type-assertion/no-type-assertion
8466
+ version,
8467
+ 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
8468
  });
8469
+ server.addTool(ruleTools.listRules);
8470
+ server.addTool(ruleTools.getRule);
8471
+ server.addTool(ruleTools.putRule);
8472
+ server.addTool(ruleTools.deleteRule);
8473
+ server.addTool(commandTools.listCommands);
8474
+ server.addTool(commandTools.getCommand);
8475
+ server.addTool(commandTools.putCommand);
8476
+ server.addTool(commandTools.deleteCommand);
8477
+ server.addTool(subagentTools.listSubagents);
8478
+ server.addTool(subagentTools.getSubagent);
8479
+ server.addTool(subagentTools.putSubagent);
8480
+ server.addTool(subagentTools.deleteSubagent);
8481
+ server.addTool(ignoreTools.getIgnoreFile);
8482
+ server.addTool(ignoreTools.putIgnoreFile);
8483
+ server.addTool(ignoreTools.deleteIgnoreFile);
8484
+ server.addTool(mcpTools.getMcpFile);
8485
+ server.addTool(mcpTools.putMcpFile);
8486
+ server.addTool(mcpTools.deleteMcpFile);
7872
8487
  logger.info("Rulesync MCP server started via stdio");
7873
8488
  void server.start({
7874
8489
  transportType: "stdio"
@@ -7876,7 +8491,7 @@ async function mcpCommand({ version }) {
7876
8491
  }
7877
8492
 
7878
8493
  // src/cli/index.ts
7879
- var getVersion = () => "3.19.0";
8494
+ var getVersion = () => "3.21.0";
7880
8495
  var main = async () => {
7881
8496
  const program = new Command();
7882
8497
  const version = getVersion();