rulesync 0.75.0 → 0.76.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 +9 -5
  2. package/dist/index.cjs +1033 -907
  3. package/dist/index.js +1036 -910
  4. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -765,7 +765,7 @@ var import_node_path7 = require("path");
765
765
  var CopilotCommand = class _CopilotCommand extends SimulatedCommand {
766
766
  static getSettablePaths() {
767
767
  return {
768
- relativeDirPath: ".copilot/commands"
768
+ relativeDirPath: ".github/commands"
769
769
  };
770
770
  }
771
771
  static fromRulesyncCommand({
@@ -1323,6 +1323,9 @@ var CommandsProcessor = class extends FeatureProcessor {
1323
1323
  }
1324
1324
  return commandsProcessorToolTargets;
1325
1325
  }
1326
+ static getToolTargetsSimulated() {
1327
+ return commandsProcessorToolTargetsSimulated;
1328
+ }
1326
1329
  };
1327
1330
 
1328
1331
  // src/config/config-resolver.ts
@@ -2800,9 +2803,9 @@ var McpProcessor = class extends FeatureProcessor {
2800
2803
  };
2801
2804
 
2802
2805
  // src/rules/rules-processor.ts
2803
- var import_node_path50 = require("path");
2806
+ var import_node_path53 = require("path");
2804
2807
  var import_fast_xml_parser = require("fast-xml-parser");
2805
- var import_mini17 = require("zod/mini");
2808
+ var import_mini20 = require("zod/mini");
2806
2809
 
2807
2810
  // src/constants/paths.ts
2808
2811
  var import_node_path30 = require("path");
@@ -2960,7 +2963,7 @@ var CodexCliSubagent = class _CodexCliSubagent extends SimulatedSubagent {
2960
2963
  var CopilotSubagent = class _CopilotSubagent extends SimulatedSubagent {
2961
2964
  static getSettablePaths() {
2962
2965
  return {
2963
- relativeDirPath: ".copilot/subagents"
2966
+ relativeDirPath: ".github/subagents"
2964
2967
  };
2965
2968
  }
2966
2969
  static async fromFile(params) {
@@ -3002,187 +3005,684 @@ var CursorSubagent = class _CursorSubagent extends SimulatedSubagent {
3002
3005
  }
3003
3006
  };
3004
3007
 
3005
- // src/rules/agentsmd-rule.ts
3008
+ // src/subagents/geminicli-subagent.ts
3009
+ var GeminiCliSubagent = class _GeminiCliSubagent extends SimulatedSubagent {
3010
+ static getSettablePaths() {
3011
+ return {
3012
+ relativeDirPath: ".gemini/subagents"
3013
+ };
3014
+ }
3015
+ static async fromFile(params) {
3016
+ const baseParams = await this.fromFileDefault(params);
3017
+ return new _GeminiCliSubagent(baseParams);
3018
+ }
3019
+ static fromRulesyncSubagent(params) {
3020
+ const baseParams = this.fromRulesyncSubagentDefault(params);
3021
+ return new _GeminiCliSubagent(baseParams);
3022
+ }
3023
+ static isTargetedByRulesyncSubagent(rulesyncSubagent) {
3024
+ return this.isTargetedByRulesyncSubagentDefault({
3025
+ rulesyncSubagent,
3026
+ toolTarget: "geminicli"
3027
+ });
3028
+ }
3029
+ };
3030
+
3031
+ // src/subagents/roo-subagent.ts
3032
+ var RooSubagent = class _RooSubagent extends SimulatedSubagent {
3033
+ static getSettablePaths() {
3034
+ return {
3035
+ relativeDirPath: ".roo/subagents"
3036
+ };
3037
+ }
3038
+ static async fromFile(params) {
3039
+ const baseParams = await this.fromFileDefault(params);
3040
+ return new _RooSubagent(baseParams);
3041
+ }
3042
+ static fromRulesyncSubagent(params) {
3043
+ const baseParams = this.fromRulesyncSubagentDefault(params);
3044
+ return new _RooSubagent(baseParams);
3045
+ }
3046
+ static isTargetedByRulesyncSubagent(rulesyncSubagent) {
3047
+ return this.isTargetedByRulesyncSubagentDefault({
3048
+ rulesyncSubagent,
3049
+ toolTarget: "roo"
3050
+ });
3051
+ }
3052
+ };
3053
+
3054
+ // src/subagents/subagents-processor.ts
3055
+ var import_node_path34 = require("path");
3056
+ var import_mini15 = require("zod/mini");
3057
+
3058
+ // src/subagents/claudecode-subagent.ts
3006
3059
  var import_node_path33 = require("path");
3060
+ var import_mini14 = require("zod/mini");
3007
3061
 
3008
- // src/rules/rulesync-rule.ts
3062
+ // src/subagents/rulesync-subagent.ts
3009
3063
  var import_node_path32 = require("path");
3010
3064
  var import_mini13 = require("zod/mini");
3011
- var RulesyncRuleFrontmatterSchema = import_mini13.z.object({
3012
- root: import_mini13.z.optional(import_mini13.z.optional(import_mini13.z.boolean())),
3013
- targets: import_mini13.z.optional(RulesyncTargetsSchema),
3014
- description: import_mini13.z.optional(import_mini13.z.string()),
3015
- globs: import_mini13.z.optional(import_mini13.z.array(import_mini13.z.string())),
3016
- cursor: import_mini13.z.optional(
3065
+ var RulesyncSubagentModelSchema = import_mini13.z.enum(["opus", "sonnet", "haiku", "inherit"]);
3066
+ var RulesyncSubagentFrontmatterSchema = import_mini13.z.object({
3067
+ targets: RulesyncTargetsSchema,
3068
+ name: import_mini13.z.string(),
3069
+ description: import_mini13.z.string(),
3070
+ claudecode: import_mini13.z.optional(
3017
3071
  import_mini13.z.object({
3018
- alwaysApply: import_mini13.z.optional(import_mini13.z.boolean()),
3019
- description: import_mini13.z.optional(import_mini13.z.string()),
3020
- globs: import_mini13.z.optional(import_mini13.z.array(import_mini13.z.string()))
3072
+ model: RulesyncSubagentModelSchema
3021
3073
  })
3022
3074
  )
3023
3075
  });
3024
- var RulesyncRule = class _RulesyncRule extends RulesyncFile {
3076
+ var RulesyncSubagent = class _RulesyncSubagent extends RulesyncFile {
3025
3077
  frontmatter;
3026
3078
  body;
3027
3079
  constructor({ frontmatter, body, ...rest }) {
3028
3080
  if (rest.validate !== false) {
3029
- const result = RulesyncRuleFrontmatterSchema.safeParse(frontmatter);
3081
+ const result = RulesyncSubagentFrontmatterSchema.safeParse(frontmatter);
3030
3082
  if (!result.success) {
3031
3083
  throw result.error;
3032
3084
  }
3033
3085
  }
3034
3086
  super({
3035
- ...rest,
3036
- fileContent: stringifyFrontmatter(body, frontmatter)
3087
+ ...rest
3037
3088
  });
3038
3089
  this.frontmatter = frontmatter;
3039
3090
  this.body = body;
3040
3091
  }
3041
3092
  static getSettablePaths() {
3042
3093
  return {
3043
- recommended: {
3044
- relativeDirPath: ".rulesync/rules"
3045
- },
3046
- legacy: {
3047
- relativeDirPath: ".rulesync"
3048
- }
3094
+ relativeDirPath: ".rulesync/subagents"
3049
3095
  };
3050
3096
  }
3051
3097
  getFrontmatter() {
3052
3098
  return this.frontmatter;
3053
3099
  }
3100
+ getBody() {
3101
+ return this.body;
3102
+ }
3054
3103
  validate() {
3055
3104
  if (!this.frontmatter) {
3056
3105
  return { success: true, error: null };
3057
3106
  }
3058
- const result = RulesyncRuleFrontmatterSchema.safeParse(this.frontmatter);
3107
+ const result = RulesyncSubagentFrontmatterSchema.safeParse(this.frontmatter);
3059
3108
  if (result.success) {
3060
3109
  return { success: true, error: null };
3061
3110
  } else {
3062
3111
  return { success: false, error: result.error };
3063
3112
  }
3064
3113
  }
3065
- static async fromFileLegacy({
3066
- relativeFilePath,
3067
- validate = true
3114
+ static async fromFile({
3115
+ relativeFilePath
3068
3116
  }) {
3069
- const filePath = (0, import_node_path32.join)(this.getSettablePaths().legacy.relativeDirPath, relativeFilePath);
3070
- const fileContent = await readFileContent(filePath);
3117
+ const fileContent = await readFileContent((0, import_node_path32.join)(RULESYNC_SUBAGENTS_DIR, relativeFilePath));
3071
3118
  const { frontmatter, body: content } = parseFrontmatter(fileContent);
3072
- const result = RulesyncRuleFrontmatterSchema.safeParse(frontmatter);
3119
+ const result = RulesyncSubagentFrontmatterSchema.safeParse(frontmatter);
3073
3120
  if (!result.success) {
3074
- throw new Error(`Invalid frontmatter in ${filePath}: ${result.error.message}`);
3121
+ throw new Error(`Invalid frontmatter in ${relativeFilePath}: ${result.error.message}`);
3075
3122
  }
3076
- const validatedFrontmatter = {
3077
- root: result.data.root ?? false,
3078
- targets: result.data.targets ?? ["*"],
3079
- description: result.data.description ?? "",
3080
- globs: result.data.globs ?? [],
3081
- cursor: result.data.cursor
3082
- };
3083
- const filename = (0, import_node_path32.basename)(filePath);
3084
- return new _RulesyncRule({
3123
+ const filename = (0, import_node_path32.basename)(relativeFilePath);
3124
+ return new _RulesyncSubagent({
3085
3125
  baseDir: ".",
3086
- relativeDirPath: this.getSettablePaths().recommended.relativeDirPath,
3126
+ relativeDirPath: this.getSettablePaths().relativeDirPath,
3087
3127
  relativeFilePath: filename,
3088
- frontmatter: validatedFrontmatter,
3128
+ frontmatter: result.data,
3089
3129
  body: content.trim(),
3090
- validate
3130
+ fileContent
3091
3131
  });
3092
3132
  }
3093
- static async fromFile({
3094
- relativeFilePath,
3095
- validate = true
3096
- }) {
3097
- const filePath = (0, import_node_path32.join)(this.getSettablePaths().recommended.relativeDirPath, relativeFilePath);
3098
- const fileContent = await readFileContent(filePath);
3099
- const { frontmatter, body: content } = parseFrontmatter(fileContent);
3100
- const result = RulesyncRuleFrontmatterSchema.safeParse(frontmatter);
3101
- if (!result.success) {
3102
- throw new Error(`Invalid frontmatter in ${filePath}: ${result.error.message}`);
3133
+ };
3134
+
3135
+ // src/subagents/claudecode-subagent.ts
3136
+ var ClaudecodeSubagentFrontmatterSchema = import_mini14.z.object({
3137
+ name: import_mini14.z.string(),
3138
+ description: import_mini14.z.string(),
3139
+ model: import_mini14.z.optional(import_mini14.z.enum(["opus", "sonnet", "haiku", "inherit"]))
3140
+ });
3141
+ var ClaudecodeSubagent = class _ClaudecodeSubagent extends ToolSubagent {
3142
+ frontmatter;
3143
+ body;
3144
+ constructor({ frontmatter, body, ...rest }) {
3145
+ if (rest.validate !== false) {
3146
+ const result = ClaudecodeSubagentFrontmatterSchema.safeParse(frontmatter);
3147
+ if (!result.success) {
3148
+ throw result.error;
3149
+ }
3103
3150
  }
3104
- const validatedFrontmatter = {
3105
- root: result.data.root ?? false,
3106
- targets: result.data.targets ?? ["*"],
3107
- description: result.data.description ?? "",
3108
- globs: result.data.globs ?? [],
3109
- cursor: result.data.cursor
3110
- };
3111
- const filename = (0, import_node_path32.basename)(filePath);
3112
- return new _RulesyncRule({
3113
- baseDir: ".",
3114
- relativeDirPath: this.getSettablePaths().recommended.relativeDirPath,
3115
- relativeFilePath: filename,
3116
- frontmatter: validatedFrontmatter,
3117
- body: content.trim(),
3118
- validate
3151
+ super({
3152
+ ...rest
3119
3153
  });
3154
+ this.frontmatter = frontmatter;
3155
+ this.body = body;
3120
3156
  }
3121
- getBody() {
3122
- return this.body;
3157
+ static getSettablePaths() {
3158
+ return {
3159
+ relativeDirPath: ".claude/agents"
3160
+ };
3123
3161
  }
3124
- };
3125
-
3126
- // src/rules/tool-rule.ts
3127
- var ToolRule = class extends ToolFile {
3128
- root;
3129
- constructor({ root = false, ...rest }) {
3130
- super(rest);
3131
- this.root = root;
3162
+ getFrontmatter() {
3163
+ return this.frontmatter;
3132
3164
  }
3133
- static async fromFile(_params) {
3134
- throw new Error("Please implement this method in the subclass.");
3165
+ getBody() {
3166
+ return this.body;
3135
3167
  }
3136
- static fromRulesyncRule(_params) {
3137
- throw new Error("Please implement this method in the subclass.");
3168
+ toRulesyncSubagent() {
3169
+ const rulesyncFrontmatter = {
3170
+ targets: ["claudecode"],
3171
+ name: this.frontmatter.name,
3172
+ description: this.frontmatter.description,
3173
+ ...this.frontmatter.model && {
3174
+ claudecode: {
3175
+ model: this.frontmatter.model
3176
+ }
3177
+ }
3178
+ };
3179
+ const fileContent = stringifyFrontmatter(this.body, rulesyncFrontmatter);
3180
+ return new RulesyncSubagent({
3181
+ frontmatter: rulesyncFrontmatter,
3182
+ body: this.body,
3183
+ baseDir: this.baseDir,
3184
+ relativeDirPath: ".rulesync/subagents",
3185
+ relativeFilePath: this.getRelativeFilePath(),
3186
+ fileContent,
3187
+ validate: true
3188
+ });
3138
3189
  }
3139
- static buildToolRuleParamsDefault({
3190
+ static fromRulesyncSubagent({
3140
3191
  baseDir = ".",
3141
- rulesyncRule,
3142
- validate = true,
3143
- rootPath = { relativeDirPath: ".", relativeFilePath: "AGENTS.md" },
3144
- nonRootPath = { relativeDirPath: ".agents/memories" }
3192
+ rulesyncSubagent,
3193
+ validate = true
3145
3194
  }) {
3146
- const fileContent = rulesyncRule.getBody();
3147
- return {
3195
+ const rulesyncFrontmatter = rulesyncSubagent.getFrontmatter();
3196
+ const claudecodeFrontmatter = {
3197
+ name: rulesyncFrontmatter.name,
3198
+ description: rulesyncFrontmatter.description,
3199
+ model: rulesyncFrontmatter.claudecode?.model
3200
+ };
3201
+ const body = rulesyncSubagent.getBody();
3202
+ const fileContent = stringifyFrontmatter(body, claudecodeFrontmatter);
3203
+ return new _ClaudecodeSubagent({
3148
3204
  baseDir,
3149
- relativeDirPath: rulesyncRule.getFrontmatter().root ? rootPath.relativeDirPath : nonRootPath.relativeDirPath,
3150
- relativeFilePath: rulesyncRule.getFrontmatter().root ? rootPath.relativeFilePath : rulesyncRule.getRelativeFilePath(),
3205
+ frontmatter: claudecodeFrontmatter,
3206
+ body,
3207
+ relativeDirPath: ".claude/agents",
3208
+ relativeFilePath: rulesyncSubagent.getRelativeFilePath(),
3151
3209
  fileContent,
3152
- validate,
3153
- root: rulesyncRule.getFrontmatter().root ?? false
3154
- };
3155
- }
3156
- toRulesyncRuleDefault() {
3157
- return new RulesyncRule({
3158
- baseDir: this.getBaseDir(),
3159
- relativeDirPath: RULESYNC_RULES_DIR,
3160
- relativeFilePath: this.getRelativeFilePath(),
3161
- frontmatter: {
3162
- root: this.isRoot(),
3163
- targets: ["*"],
3164
- description: "",
3165
- globs: this.isRoot() ? ["**/*"] : []
3166
- },
3167
- body: this.getFileContent()
3210
+ validate
3168
3211
  });
3169
3212
  }
3170
- isRoot() {
3171
- return this.root;
3213
+ validate() {
3214
+ if (!this.frontmatter) {
3215
+ return { success: true, error: null };
3216
+ }
3217
+ const result = ClaudecodeSubagentFrontmatterSchema.safeParse(this.frontmatter);
3218
+ if (result.success) {
3219
+ return { success: true, error: null };
3220
+ } else {
3221
+ return { success: false, error: result.error };
3222
+ }
3172
3223
  }
3173
- static isTargetedByRulesyncRule(_rulesyncRule) {
3174
- throw new Error("Please implement this method in the subclass.");
3224
+ static isTargetedByRulesyncSubagent(rulesyncSubagent) {
3225
+ return this.isTargetedByRulesyncSubagentDefault({
3226
+ rulesyncSubagent,
3227
+ toolTarget: "claudecode"
3228
+ });
3175
3229
  }
3176
- static isTargetedByRulesyncRuleDefault({
3177
- rulesyncRule,
3178
- toolTarget
3230
+ static async fromFile({
3231
+ baseDir = ".",
3232
+ relativeFilePath,
3233
+ validate = true
3179
3234
  }) {
3180
- const targets = rulesyncRule.getFrontmatter().targets;
3181
- if (!targets) {
3182
- return true;
3235
+ const fileContent = await readFileContent((0, import_node_path33.join)(baseDir, ".claude/agents", relativeFilePath));
3236
+ const { frontmatter, body: content } = parseFrontmatter(fileContent);
3237
+ const result = ClaudecodeSubagentFrontmatterSchema.safeParse(frontmatter);
3238
+ if (!result.success) {
3239
+ throw new Error(`Invalid frontmatter in ${relativeFilePath}: ${result.error.message}`);
3183
3240
  }
3184
- if (targets.includes("*")) {
3185
- return true;
3241
+ return new _ClaudecodeSubagent({
3242
+ baseDir,
3243
+ relativeDirPath: ".claude/agents",
3244
+ relativeFilePath,
3245
+ frontmatter: result.data,
3246
+ body: content.trim(),
3247
+ fileContent,
3248
+ validate
3249
+ });
3250
+ }
3251
+ };
3252
+
3253
+ // src/subagents/subagents-processor.ts
3254
+ var subagentsProcessorToolTargets = [
3255
+ "claudecode",
3256
+ "copilot",
3257
+ "cursor",
3258
+ "codexcli",
3259
+ "geminicli",
3260
+ "roo"
3261
+ ];
3262
+ var subagentsProcessorToolTargetsSimulated = [
3263
+ "copilot",
3264
+ "cursor",
3265
+ "codexcli",
3266
+ "geminicli",
3267
+ "roo"
3268
+ ];
3269
+ var SubagentsProcessorToolTargetSchema = import_mini15.z.enum(subagentsProcessorToolTargets);
3270
+ var SubagentsProcessor = class extends FeatureProcessor {
3271
+ toolTarget;
3272
+ constructor({
3273
+ baseDir = ".",
3274
+ toolTarget
3275
+ }) {
3276
+ super({ baseDir });
3277
+ this.toolTarget = SubagentsProcessorToolTargetSchema.parse(toolTarget);
3278
+ }
3279
+ async convertRulesyncFilesToToolFiles(rulesyncFiles) {
3280
+ const rulesyncSubagents = rulesyncFiles.filter(
3281
+ (file) => file instanceof RulesyncSubagent
3282
+ );
3283
+ const toolSubagents = rulesyncSubagents.map((rulesyncSubagent) => {
3284
+ switch (this.toolTarget) {
3285
+ case "claudecode":
3286
+ if (!ClaudecodeSubagent.isTargetedByRulesyncSubagent(rulesyncSubagent)) {
3287
+ return null;
3288
+ }
3289
+ return ClaudecodeSubagent.fromRulesyncSubagent({
3290
+ baseDir: this.baseDir,
3291
+ relativeDirPath: RulesyncSubagent.getSettablePaths().relativeDirPath,
3292
+ rulesyncSubagent
3293
+ });
3294
+ case "copilot":
3295
+ if (!CopilotSubagent.isTargetedByRulesyncSubagent(rulesyncSubagent)) {
3296
+ return null;
3297
+ }
3298
+ return CopilotSubagent.fromRulesyncSubagent({
3299
+ baseDir: this.baseDir,
3300
+ relativeDirPath: RulesyncSubagent.getSettablePaths().relativeDirPath,
3301
+ rulesyncSubagent
3302
+ });
3303
+ case "cursor":
3304
+ if (!CursorSubagent.isTargetedByRulesyncSubagent(rulesyncSubagent)) {
3305
+ return null;
3306
+ }
3307
+ return CursorSubagent.fromRulesyncSubagent({
3308
+ baseDir: this.baseDir,
3309
+ relativeDirPath: RulesyncSubagent.getSettablePaths().relativeDirPath,
3310
+ rulesyncSubagent
3311
+ });
3312
+ case "codexcli":
3313
+ if (!CodexCliSubagent.isTargetedByRulesyncSubagent(rulesyncSubagent)) {
3314
+ return null;
3315
+ }
3316
+ return CodexCliSubagent.fromRulesyncSubagent({
3317
+ baseDir: this.baseDir,
3318
+ relativeDirPath: RulesyncSubagent.getSettablePaths().relativeDirPath,
3319
+ rulesyncSubagent
3320
+ });
3321
+ case "geminicli":
3322
+ if (!GeminiCliSubagent.isTargetedByRulesyncSubagent(rulesyncSubagent)) {
3323
+ return null;
3324
+ }
3325
+ return GeminiCliSubagent.fromRulesyncSubagent({
3326
+ baseDir: this.baseDir,
3327
+ relativeDirPath: RulesyncSubagent.getSettablePaths().relativeDirPath,
3328
+ rulesyncSubagent
3329
+ });
3330
+ case "roo":
3331
+ if (!RooSubagent.isTargetedByRulesyncSubagent(rulesyncSubagent)) {
3332
+ return null;
3333
+ }
3334
+ return RooSubagent.fromRulesyncSubagent({
3335
+ baseDir: this.baseDir,
3336
+ relativeDirPath: RulesyncSubagent.getSettablePaths().relativeDirPath,
3337
+ rulesyncSubagent
3338
+ });
3339
+ default:
3340
+ throw new Error(`Unsupported tool target: ${this.toolTarget}`);
3341
+ }
3342
+ }).filter((subagent) => subagent !== null);
3343
+ return toolSubagents;
3344
+ }
3345
+ async convertToolFilesToRulesyncFiles(toolFiles) {
3346
+ const toolSubagents = toolFiles.filter(
3347
+ (file) => file instanceof ToolSubagent
3348
+ );
3349
+ const rulesyncSubagents = [];
3350
+ for (const toolSubagent of toolSubagents) {
3351
+ if (toolSubagent instanceof SimulatedSubagent) {
3352
+ logger.debug(
3353
+ `Skipping simulated subagent conversion: ${toolSubagent.getRelativeFilePath()}`
3354
+ );
3355
+ continue;
3356
+ }
3357
+ rulesyncSubagents.push(toolSubagent.toRulesyncSubagent());
3358
+ }
3359
+ return rulesyncSubagents;
3360
+ }
3361
+ /**
3362
+ * Implementation of abstract method from Processor
3363
+ * Load and parse rulesync subagent files from .rulesync/subagents/ directory
3364
+ */
3365
+ async loadRulesyncFiles() {
3366
+ const subagentsDir = (0, import_node_path34.join)(this.baseDir, RulesyncSubagent.getSettablePaths().relativeDirPath);
3367
+ const dirExists = await directoryExists(subagentsDir);
3368
+ if (!dirExists) {
3369
+ logger.debug(`Rulesync subagents directory not found: ${subagentsDir}`);
3370
+ return [];
3371
+ }
3372
+ const entries = await listDirectoryFiles(subagentsDir);
3373
+ const mdFiles = entries.filter((file) => file.endsWith(".md"));
3374
+ if (mdFiles.length === 0) {
3375
+ logger.debug(`No markdown files found in rulesync subagents directory: ${subagentsDir}`);
3376
+ return [];
3377
+ }
3378
+ logger.info(`Found ${mdFiles.length} subagent files in ${subagentsDir}`);
3379
+ const rulesyncSubagents = [];
3380
+ for (const mdFile of mdFiles) {
3381
+ const filepath = (0, import_node_path34.join)(subagentsDir, mdFile);
3382
+ try {
3383
+ const rulesyncSubagent = await RulesyncSubagent.fromFile({
3384
+ relativeFilePath: mdFile,
3385
+ validate: true
3386
+ });
3387
+ rulesyncSubagents.push(rulesyncSubagent);
3388
+ logger.debug(`Successfully loaded subagent: ${mdFile}`);
3389
+ } catch (error) {
3390
+ logger.warn(`Failed to load subagent file ${filepath}:`, error);
3391
+ continue;
3392
+ }
3393
+ }
3394
+ if (rulesyncSubagents.length === 0) {
3395
+ logger.debug(`No valid subagents found in ${subagentsDir}`);
3396
+ return [];
3397
+ }
3398
+ logger.info(`Successfully loaded ${rulesyncSubagents.length} rulesync subagents`);
3399
+ return rulesyncSubagents;
3400
+ }
3401
+ /**
3402
+ * Implementation of abstract method from Processor
3403
+ * Load tool-specific subagent configurations and parse them into ToolSubagent instances
3404
+ */
3405
+ async loadToolFiles() {
3406
+ switch (this.toolTarget) {
3407
+ case "claudecode":
3408
+ return await this.loadClaudecodeSubagents();
3409
+ case "copilot":
3410
+ return await this.loadCopilotSubagents();
3411
+ case "cursor":
3412
+ return await this.loadCursorSubagents();
3413
+ case "codexcli":
3414
+ return await this.loadCodexCliSubagents();
3415
+ case "geminicli":
3416
+ return await this.loadGeminiCliSubagents();
3417
+ case "roo":
3418
+ return await this.loadRooSubagents();
3419
+ default:
3420
+ throw new Error(`Unsupported tool target: ${this.toolTarget}`);
3421
+ }
3422
+ }
3423
+ /**
3424
+ * Load Claude Code subagent configurations from .claude/agents/ directory
3425
+ */
3426
+ async loadClaudecodeSubagents() {
3427
+ return await this.loadToolSubagentsDefault({
3428
+ relativeDirPath: ClaudecodeSubagent.getSettablePaths().relativeDirPath,
3429
+ fromFile: (relativeFilePath) => ClaudecodeSubagent.fromFile({ relativeFilePath })
3430
+ });
3431
+ }
3432
+ /**
3433
+ * Load Copilot subagent configurations from .github/subagents/ directory
3434
+ */
3435
+ async loadCopilotSubagents() {
3436
+ return await this.loadToolSubagentsDefault({
3437
+ relativeDirPath: CopilotSubagent.getSettablePaths().relativeDirPath,
3438
+ fromFile: (relativeFilePath) => CopilotSubagent.fromFile({ relativeFilePath })
3439
+ });
3440
+ }
3441
+ /**
3442
+ * Load Cursor subagent configurations from .cursor/subagents/ directory
3443
+ */
3444
+ async loadCursorSubagents() {
3445
+ return await this.loadToolSubagentsDefault({
3446
+ relativeDirPath: CursorSubagent.getSettablePaths().relativeDirPath,
3447
+ fromFile: (relativeFilePath) => CursorSubagent.fromFile({ relativeFilePath })
3448
+ });
3449
+ }
3450
+ /**
3451
+ * Load CodexCli subagent configurations from .codex/subagents/ directory
3452
+ */
3453
+ async loadCodexCliSubagents() {
3454
+ return await this.loadToolSubagentsDefault({
3455
+ relativeDirPath: CodexCliSubagent.getSettablePaths().relativeDirPath,
3456
+ fromFile: (relativeFilePath) => CodexCliSubagent.fromFile({ relativeFilePath })
3457
+ });
3458
+ }
3459
+ /**
3460
+ * Load GeminiCli subagent configurations from .gemini/subagents/ directory
3461
+ */
3462
+ async loadGeminiCliSubagents() {
3463
+ return await this.loadToolSubagentsDefault({
3464
+ relativeDirPath: GeminiCliSubagent.getSettablePaths().relativeDirPath,
3465
+ fromFile: (relativeFilePath) => GeminiCliSubagent.fromFile({ relativeFilePath })
3466
+ });
3467
+ }
3468
+ /**
3469
+ * Load Roo subagent configurations from .roo/subagents/ directory
3470
+ */
3471
+ async loadRooSubagents() {
3472
+ return await this.loadToolSubagentsDefault({
3473
+ relativeDirPath: RooSubagent.getSettablePaths().relativeDirPath,
3474
+ fromFile: (relativeFilePath) => RooSubagent.fromFile({ relativeFilePath })
3475
+ });
3476
+ }
3477
+ async loadToolSubagentsDefault({
3478
+ relativeDirPath,
3479
+ fromFile
3480
+ }) {
3481
+ const paths = await findFilesByGlobs((0, import_node_path34.join)(this.baseDir, relativeDirPath, "*.md"));
3482
+ const subagents = (await Promise.allSettled(paths.map((path2) => fromFile((0, import_node_path34.basename)(path2))))).filter((r) => r.status === "fulfilled").map((r) => r.value);
3483
+ logger.info(`Successfully loaded ${subagents.length} ${relativeDirPath} subagents`);
3484
+ return subagents;
3485
+ }
3486
+ /**
3487
+ * Implementation of abstract method from FeatureProcessor
3488
+ * Return the tool targets that this processor supports
3489
+ */
3490
+ static getToolTargets({
3491
+ includeSimulated = false
3492
+ } = {}) {
3493
+ if (!includeSimulated) {
3494
+ return subagentsProcessorToolTargets.filter(
3495
+ (target) => !subagentsProcessorToolTargetsSimulated.includes(target)
3496
+ );
3497
+ }
3498
+ return subagentsProcessorToolTargets;
3499
+ }
3500
+ static getToolTargetsSimulated() {
3501
+ return subagentsProcessorToolTargetsSimulated;
3502
+ }
3503
+ };
3504
+
3505
+ // src/rules/agentsmd-rule.ts
3506
+ var import_node_path36 = require("path");
3507
+
3508
+ // src/rules/rulesync-rule.ts
3509
+ var import_node_path35 = require("path");
3510
+ var import_mini16 = require("zod/mini");
3511
+ var RulesyncRuleFrontmatterSchema = import_mini16.z.object({
3512
+ root: import_mini16.z.optional(import_mini16.z.optional(import_mini16.z.boolean())),
3513
+ targets: import_mini16.z.optional(RulesyncTargetsSchema),
3514
+ description: import_mini16.z.optional(import_mini16.z.string()),
3515
+ globs: import_mini16.z.optional(import_mini16.z.array(import_mini16.z.string())),
3516
+ cursor: import_mini16.z.optional(
3517
+ import_mini16.z.object({
3518
+ alwaysApply: import_mini16.z.optional(import_mini16.z.boolean()),
3519
+ description: import_mini16.z.optional(import_mini16.z.string()),
3520
+ globs: import_mini16.z.optional(import_mini16.z.array(import_mini16.z.string()))
3521
+ })
3522
+ )
3523
+ });
3524
+ var RulesyncRule = class _RulesyncRule extends RulesyncFile {
3525
+ frontmatter;
3526
+ body;
3527
+ constructor({ frontmatter, body, ...rest }) {
3528
+ if (rest.validate !== false) {
3529
+ const result = RulesyncRuleFrontmatterSchema.safeParse(frontmatter);
3530
+ if (!result.success) {
3531
+ throw result.error;
3532
+ }
3533
+ }
3534
+ super({
3535
+ ...rest,
3536
+ fileContent: stringifyFrontmatter(body, frontmatter)
3537
+ });
3538
+ this.frontmatter = frontmatter;
3539
+ this.body = body;
3540
+ }
3541
+ static getSettablePaths() {
3542
+ return {
3543
+ recommended: {
3544
+ relativeDirPath: ".rulesync/rules"
3545
+ },
3546
+ legacy: {
3547
+ relativeDirPath: ".rulesync"
3548
+ }
3549
+ };
3550
+ }
3551
+ getFrontmatter() {
3552
+ return this.frontmatter;
3553
+ }
3554
+ validate() {
3555
+ if (!this.frontmatter) {
3556
+ return { success: true, error: null };
3557
+ }
3558
+ const result = RulesyncRuleFrontmatterSchema.safeParse(this.frontmatter);
3559
+ if (result.success) {
3560
+ return { success: true, error: null };
3561
+ } else {
3562
+ return { success: false, error: result.error };
3563
+ }
3564
+ }
3565
+ static async fromFileLegacy({
3566
+ relativeFilePath,
3567
+ validate = true
3568
+ }) {
3569
+ const filePath = (0, import_node_path35.join)(this.getSettablePaths().legacy.relativeDirPath, relativeFilePath);
3570
+ const fileContent = await readFileContent(filePath);
3571
+ const { frontmatter, body: content } = parseFrontmatter(fileContent);
3572
+ const result = RulesyncRuleFrontmatterSchema.safeParse(frontmatter);
3573
+ if (!result.success) {
3574
+ throw new Error(`Invalid frontmatter in ${filePath}: ${result.error.message}`);
3575
+ }
3576
+ const validatedFrontmatter = {
3577
+ root: result.data.root ?? false,
3578
+ targets: result.data.targets ?? ["*"],
3579
+ description: result.data.description ?? "",
3580
+ globs: result.data.globs ?? [],
3581
+ cursor: result.data.cursor
3582
+ };
3583
+ const filename = (0, import_node_path35.basename)(filePath);
3584
+ return new _RulesyncRule({
3585
+ baseDir: ".",
3586
+ relativeDirPath: this.getSettablePaths().recommended.relativeDirPath,
3587
+ relativeFilePath: filename,
3588
+ frontmatter: validatedFrontmatter,
3589
+ body: content.trim(),
3590
+ validate
3591
+ });
3592
+ }
3593
+ static async fromFile({
3594
+ relativeFilePath,
3595
+ validate = true
3596
+ }) {
3597
+ const filePath = (0, import_node_path35.join)(this.getSettablePaths().recommended.relativeDirPath, relativeFilePath);
3598
+ const fileContent = await readFileContent(filePath);
3599
+ const { frontmatter, body: content } = parseFrontmatter(fileContent);
3600
+ const result = RulesyncRuleFrontmatterSchema.safeParse(frontmatter);
3601
+ if (!result.success) {
3602
+ throw new Error(`Invalid frontmatter in ${filePath}: ${result.error.message}`);
3603
+ }
3604
+ const validatedFrontmatter = {
3605
+ root: result.data.root ?? false,
3606
+ targets: result.data.targets ?? ["*"],
3607
+ description: result.data.description ?? "",
3608
+ globs: result.data.globs ?? [],
3609
+ cursor: result.data.cursor
3610
+ };
3611
+ const filename = (0, import_node_path35.basename)(filePath);
3612
+ return new _RulesyncRule({
3613
+ baseDir: ".",
3614
+ relativeDirPath: this.getSettablePaths().recommended.relativeDirPath,
3615
+ relativeFilePath: filename,
3616
+ frontmatter: validatedFrontmatter,
3617
+ body: content.trim(),
3618
+ validate
3619
+ });
3620
+ }
3621
+ getBody() {
3622
+ return this.body;
3623
+ }
3624
+ };
3625
+
3626
+ // src/rules/tool-rule.ts
3627
+ var ToolRule = class extends ToolFile {
3628
+ root;
3629
+ constructor({ root = false, ...rest }) {
3630
+ super(rest);
3631
+ this.root = root;
3632
+ }
3633
+ static async fromFile(_params) {
3634
+ throw new Error("Please implement this method in the subclass.");
3635
+ }
3636
+ static fromRulesyncRule(_params) {
3637
+ throw new Error("Please implement this method in the subclass.");
3638
+ }
3639
+ static buildToolRuleParamsDefault({
3640
+ baseDir = ".",
3641
+ rulesyncRule,
3642
+ validate = true,
3643
+ rootPath = { relativeDirPath: ".", relativeFilePath: "AGENTS.md" },
3644
+ nonRootPath = { relativeDirPath: ".agents/memories" }
3645
+ }) {
3646
+ const fileContent = rulesyncRule.getBody();
3647
+ return {
3648
+ baseDir,
3649
+ relativeDirPath: rulesyncRule.getFrontmatter().root ? rootPath.relativeDirPath : nonRootPath.relativeDirPath,
3650
+ relativeFilePath: rulesyncRule.getFrontmatter().root ? rootPath.relativeFilePath : rulesyncRule.getRelativeFilePath(),
3651
+ fileContent,
3652
+ validate,
3653
+ root: rulesyncRule.getFrontmatter().root ?? false
3654
+ };
3655
+ }
3656
+ toRulesyncRuleDefault() {
3657
+ return new RulesyncRule({
3658
+ baseDir: this.getBaseDir(),
3659
+ relativeDirPath: RULESYNC_RULES_DIR,
3660
+ relativeFilePath: this.getRelativeFilePath(),
3661
+ frontmatter: {
3662
+ root: this.isRoot(),
3663
+ targets: ["*"],
3664
+ description: "",
3665
+ globs: this.isRoot() ? ["**/*"] : []
3666
+ },
3667
+ body: this.getFileContent()
3668
+ });
3669
+ }
3670
+ isRoot() {
3671
+ return this.root;
3672
+ }
3673
+ static isTargetedByRulesyncRule(_rulesyncRule) {
3674
+ throw new Error("Please implement this method in the subclass.");
3675
+ }
3676
+ static isTargetedByRulesyncRuleDefault({
3677
+ rulesyncRule,
3678
+ toolTarget
3679
+ }) {
3680
+ const targets = rulesyncRule.getFrontmatter().targets;
3681
+ if (!targets) {
3682
+ return true;
3683
+ }
3684
+ if (targets.includes("*")) {
3685
+ return true;
3186
3686
  }
3187
3687
  if (targets.includes(toolTarget)) {
3188
3688
  return true;
@@ -3217,8 +3717,8 @@ var AgentsMdRule = class _AgentsMdRule extends ToolRule {
3217
3717
  validate = true
3218
3718
  }) {
3219
3719
  const isRoot = relativeFilePath === "AGENTS.md";
3220
- const relativePath = isRoot ? "AGENTS.md" : (0, import_node_path33.join)(".agents/memories", relativeFilePath);
3221
- const fileContent = await readFileContent((0, import_node_path33.join)(baseDir, relativePath));
3720
+ const relativePath = isRoot ? "AGENTS.md" : (0, import_node_path36.join)(".agents/memories", relativeFilePath);
3721
+ const fileContent = await readFileContent((0, import_node_path36.join)(baseDir, relativePath));
3222
3722
  return new _AgentsMdRule({
3223
3723
  baseDir,
3224
3724
  relativeDirPath: isRoot ? this.getSettablePaths().root.relativeDirPath : this.getSettablePaths().nonRoot.relativeDirPath,
@@ -3258,7 +3758,7 @@ var AgentsMdRule = class _AgentsMdRule extends ToolRule {
3258
3758
  };
3259
3759
 
3260
3760
  // src/rules/amazonqcli-rule.ts
3261
- var import_node_path34 = require("path");
3761
+ var import_node_path37 = require("path");
3262
3762
  var AmazonQCliRule = class _AmazonQCliRule extends ToolRule {
3263
3763
  static getSettablePaths() {
3264
3764
  return {
@@ -3273,7 +3773,7 @@ var AmazonQCliRule = class _AmazonQCliRule extends ToolRule {
3273
3773
  validate = true
3274
3774
  }) {
3275
3775
  const fileContent = await readFileContent(
3276
- (0, import_node_path34.join)(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
3776
+ (0, import_node_path37.join)(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
3277
3777
  );
3278
3778
  return new _AmazonQCliRule({
3279
3779
  baseDir,
@@ -3313,7 +3813,7 @@ var AmazonQCliRule = class _AmazonQCliRule extends ToolRule {
3313
3813
  };
3314
3814
 
3315
3815
  // src/rules/augmentcode-legacy-rule.ts
3316
- var import_node_path35 = require("path");
3816
+ var import_node_path38 = require("path");
3317
3817
  var AugmentcodeLegacyRule = class _AugmentcodeLegacyRule extends ToolRule {
3318
3818
  toRulesyncRule() {
3319
3819
  const rulesyncFrontmatter = {
@@ -3373,8 +3873,8 @@ var AugmentcodeLegacyRule = class _AugmentcodeLegacyRule extends ToolRule {
3373
3873
  }) {
3374
3874
  const settablePaths = this.getSettablePaths();
3375
3875
  const isRoot = relativeFilePath === settablePaths.root.relativeFilePath;
3376
- const relativePath = isRoot ? settablePaths.root.relativeFilePath : (0, import_node_path35.join)(settablePaths.nonRoot.relativeDirPath, relativeFilePath);
3377
- const fileContent = await readFileContent((0, import_node_path35.join)(baseDir, relativePath));
3876
+ const relativePath = isRoot ? settablePaths.root.relativeFilePath : (0, import_node_path38.join)(settablePaths.nonRoot.relativeDirPath, relativeFilePath);
3877
+ const fileContent = await readFileContent((0, import_node_path38.join)(baseDir, relativePath));
3378
3878
  return new _AugmentcodeLegacyRule({
3379
3879
  baseDir,
3380
3880
  relativeDirPath: isRoot ? settablePaths.root.relativeDirPath : settablePaths.nonRoot.relativeDirPath,
@@ -3387,7 +3887,7 @@ var AugmentcodeLegacyRule = class _AugmentcodeLegacyRule extends ToolRule {
3387
3887
  };
3388
3888
 
3389
3889
  // src/rules/augmentcode-rule.ts
3390
- var import_node_path36 = require("path");
3890
+ var import_node_path39 = require("path");
3391
3891
  var AugmentcodeRule = class _AugmentcodeRule extends ToolRule {
3392
3892
  toRulesyncRule() {
3393
3893
  return this.toRulesyncRuleDefault();
@@ -3419,7 +3919,7 @@ var AugmentcodeRule = class _AugmentcodeRule extends ToolRule {
3419
3919
  validate = true
3420
3920
  }) {
3421
3921
  const fileContent = await readFileContent(
3422
- (0, import_node_path36.join)(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
3922
+ (0, import_node_path39.join)(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
3423
3923
  );
3424
3924
  const { body: content } = parseFrontmatter(fileContent);
3425
3925
  return new _AugmentcodeRule({
@@ -3442,7 +3942,7 @@ var AugmentcodeRule = class _AugmentcodeRule extends ToolRule {
3442
3942
  };
3443
3943
 
3444
3944
  // src/rules/claudecode-rule.ts
3445
- var import_node_path37 = require("path");
3945
+ var import_node_path40 = require("path");
3446
3946
  var ClaudecodeRule = class _ClaudecodeRule extends ToolRule {
3447
3947
  static getSettablePaths() {
3448
3948
  return {
@@ -3461,8 +3961,8 @@ var ClaudecodeRule = class _ClaudecodeRule extends ToolRule {
3461
3961
  validate = true
3462
3962
  }) {
3463
3963
  const isRoot = relativeFilePath === this.getSettablePaths().root.relativeFilePath;
3464
- const relativePath = isRoot ? this.getSettablePaths().root.relativeFilePath : (0, import_node_path37.join)(this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath);
3465
- const fileContent = await readFileContent((0, import_node_path37.join)(baseDir, relativePath));
3964
+ const relativePath = isRoot ? this.getSettablePaths().root.relativeFilePath : (0, import_node_path40.join)(this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath);
3965
+ const fileContent = await readFileContent((0, import_node_path40.join)(baseDir, relativePath));
3466
3966
  return new _ClaudecodeRule({
3467
3967
  baseDir,
3468
3968
  relativeDirPath: isRoot ? this.getSettablePaths().root.relativeDirPath : this.getSettablePaths().nonRoot.relativeDirPath,
@@ -3502,10 +4002,10 @@ var ClaudecodeRule = class _ClaudecodeRule extends ToolRule {
3502
4002
  };
3503
4003
 
3504
4004
  // src/rules/cline-rule.ts
3505
- var import_node_path38 = require("path");
3506
- var import_mini14 = require("zod/mini");
3507
- var ClineRuleFrontmatterSchema = import_mini14.z.object({
3508
- description: import_mini14.z.string()
4005
+ var import_node_path41 = require("path");
4006
+ var import_mini17 = require("zod/mini");
4007
+ var ClineRuleFrontmatterSchema = import_mini17.z.object({
4008
+ description: import_mini17.z.string()
3509
4009
  });
3510
4010
  var ClineRule = class _ClineRule extends ToolRule {
3511
4011
  static getSettablePaths() {
@@ -3547,7 +4047,7 @@ var ClineRule = class _ClineRule extends ToolRule {
3547
4047
  validate = true
3548
4048
  }) {
3549
4049
  const fileContent = await readFileContent(
3550
- (0, import_node_path38.join)(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
4050
+ (0, import_node_path41.join)(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
3551
4051
  );
3552
4052
  return new _ClineRule({
3553
4053
  baseDir,
@@ -3560,7 +4060,7 @@ var ClineRule = class _ClineRule extends ToolRule {
3560
4060
  };
3561
4061
 
3562
4062
  // src/rules/codexcli-rule.ts
3563
- var import_node_path39 = require("path");
4063
+ var import_node_path42 = require("path");
3564
4064
  var CodexcliRule = class _CodexcliRule extends ToolRule {
3565
4065
  static getSettablePaths() {
3566
4066
  return {
@@ -3579,8 +4079,8 @@ var CodexcliRule = class _CodexcliRule extends ToolRule {
3579
4079
  validate = true
3580
4080
  }) {
3581
4081
  const isRoot = relativeFilePath === "AGENTS.md";
3582
- const relativePath = isRoot ? "AGENTS.md" : (0, import_node_path39.join)(this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath);
3583
- const fileContent = await readFileContent((0, import_node_path39.join)(baseDir, relativePath));
4082
+ const relativePath = isRoot ? "AGENTS.md" : (0, import_node_path42.join)(this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath);
4083
+ const fileContent = await readFileContent((0, import_node_path42.join)(baseDir, relativePath));
3584
4084
  return new _CodexcliRule({
3585
4085
  baseDir,
3586
4086
  relativeDirPath: isRoot ? this.getSettablePaths().root.relativeDirPath : this.getSettablePaths().nonRoot.relativeDirPath,
@@ -3620,11 +4120,11 @@ var CodexcliRule = class _CodexcliRule extends ToolRule {
3620
4120
  };
3621
4121
 
3622
4122
  // src/rules/copilot-rule.ts
3623
- var import_node_path40 = require("path");
3624
- var import_mini15 = require("zod/mini");
3625
- var CopilotRuleFrontmatterSchema = import_mini15.z.object({
3626
- description: import_mini15.z.optional(import_mini15.z.string()),
3627
- applyTo: import_mini15.z.optional(import_mini15.z.string())
4123
+ var import_node_path43 = require("path");
4124
+ var import_mini18 = require("zod/mini");
4125
+ var CopilotRuleFrontmatterSchema = import_mini18.z.object({
4126
+ description: import_mini18.z.optional(import_mini18.z.string()),
4127
+ applyTo: import_mini18.z.optional(import_mini18.z.string())
3628
4128
  });
3629
4129
  var CopilotRule = class _CopilotRule extends ToolRule {
3630
4130
  frontmatter;
@@ -3712,11 +4212,11 @@ var CopilotRule = class _CopilotRule extends ToolRule {
3712
4212
  validate = true
3713
4213
  }) {
3714
4214
  const isRoot = relativeFilePath === "copilot-instructions.md";
3715
- const relativePath = isRoot ? (0, import_node_path40.join)(
4215
+ const relativePath = isRoot ? (0, import_node_path43.join)(
3716
4216
  this.getSettablePaths().root.relativeDirPath,
3717
4217
  this.getSettablePaths().root.relativeFilePath
3718
- ) : (0, import_node_path40.join)(this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath);
3719
- const fileContent = await readFileContent((0, import_node_path40.join)(baseDir, relativePath));
4218
+ ) : (0, import_node_path43.join)(this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath);
4219
+ const fileContent = await readFileContent((0, import_node_path43.join)(baseDir, relativePath));
3720
4220
  if (isRoot) {
3721
4221
  return new _CopilotRule({
3722
4222
  baseDir,
@@ -3735,7 +4235,7 @@ var CopilotRule = class _CopilotRule extends ToolRule {
3735
4235
  const result = CopilotRuleFrontmatterSchema.safeParse(frontmatter);
3736
4236
  if (!result.success) {
3737
4237
  throw new Error(
3738
- `Invalid frontmatter in ${(0, import_node_path40.join)(baseDir, relativeFilePath)}: ${result.error.message}`
4238
+ `Invalid frontmatter in ${(0, import_node_path43.join)(baseDir, relativeFilePath)}: ${result.error.message}`
3739
4239
  );
3740
4240
  }
3741
4241
  return new _CopilotRule({
@@ -3774,12 +4274,12 @@ var CopilotRule = class _CopilotRule extends ToolRule {
3774
4274
  };
3775
4275
 
3776
4276
  // src/rules/cursor-rule.ts
3777
- var import_node_path41 = require("path");
3778
- var import_mini16 = require("zod/mini");
3779
- var CursorRuleFrontmatterSchema = import_mini16.z.object({
3780
- description: import_mini16.z.optional(import_mini16.z.string()),
3781
- globs: import_mini16.z.optional(import_mini16.z.string()),
3782
- alwaysApply: import_mini16.z.optional(import_mini16.z.boolean())
4277
+ var import_node_path44 = require("path");
4278
+ var import_mini19 = require("zod/mini");
4279
+ var CursorRuleFrontmatterSchema = import_mini19.z.object({
4280
+ description: import_mini19.z.optional(import_mini19.z.string()),
4281
+ globs: import_mini19.z.optional(import_mini19.z.string()),
4282
+ alwaysApply: import_mini19.z.optional(import_mini19.z.boolean())
3783
4283
  });
3784
4284
  var CursorRule = class _CursorRule extends ToolRule {
3785
4285
  frontmatter;
@@ -3904,19 +4404,19 @@ var CursorRule = class _CursorRule extends ToolRule {
3904
4404
  validate = true
3905
4405
  }) {
3906
4406
  const fileContent = await readFileContent(
3907
- (0, import_node_path41.join)(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
4407
+ (0, import_node_path44.join)(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
3908
4408
  );
3909
4409
  const { frontmatter, body: content } = _CursorRule.parseCursorFrontmatter(fileContent);
3910
4410
  const result = CursorRuleFrontmatterSchema.safeParse(frontmatter);
3911
4411
  if (!result.success) {
3912
4412
  throw new Error(
3913
- `Invalid frontmatter in ${(0, import_node_path41.join)(baseDir, relativeFilePath)}: ${result.error.message}`
4413
+ `Invalid frontmatter in ${(0, import_node_path44.join)(baseDir, relativeFilePath)}: ${result.error.message}`
3914
4414
  );
3915
4415
  }
3916
4416
  return new _CursorRule({
3917
4417
  baseDir,
3918
4418
  relativeDirPath: this.getSettablePaths().nonRoot.relativeDirPath,
3919
- relativeFilePath: (0, import_node_path41.basename)(relativeFilePath),
4419
+ relativeFilePath: (0, import_node_path44.basename)(relativeFilePath),
3920
4420
  frontmatter: result.data,
3921
4421
  body: content.trim(),
3922
4422
  validate
@@ -3948,7 +4448,7 @@ var CursorRule = class _CursorRule extends ToolRule {
3948
4448
  };
3949
4449
 
3950
4450
  // src/rules/geminicli-rule.ts
3951
- var import_node_path42 = require("path");
4451
+ var import_node_path45 = require("path");
3952
4452
  var GeminiCliRule = class _GeminiCliRule extends ToolRule {
3953
4453
  static getSettablePaths() {
3954
4454
  return {
@@ -3967,8 +4467,8 @@ var GeminiCliRule = class _GeminiCliRule extends ToolRule {
3967
4467
  validate = true
3968
4468
  }) {
3969
4469
  const isRoot = relativeFilePath === "GEMINI.md";
3970
- const relativePath = isRoot ? "GEMINI.md" : (0, import_node_path42.join)(".gemini/memories", relativeFilePath);
3971
- const fileContent = await readFileContent((0, import_node_path42.join)(baseDir, relativePath));
4470
+ const relativePath = isRoot ? "GEMINI.md" : (0, import_node_path45.join)(".gemini/memories", relativeFilePath);
4471
+ const fileContent = await readFileContent((0, import_node_path45.join)(baseDir, relativePath));
3972
4472
  return new _GeminiCliRule({
3973
4473
  baseDir,
3974
4474
  relativeDirPath: isRoot ? this.getSettablePaths().root.relativeDirPath : this.getSettablePaths().nonRoot.relativeDirPath,
@@ -4008,7 +4508,7 @@ var GeminiCliRule = class _GeminiCliRule extends ToolRule {
4008
4508
  };
4009
4509
 
4010
4510
  // src/rules/junie-rule.ts
4011
- var import_node_path43 = require("path");
4511
+ var import_node_path46 = require("path");
4012
4512
  var JunieRule = class _JunieRule extends ToolRule {
4013
4513
  static getSettablePaths() {
4014
4514
  return {
@@ -4027,8 +4527,8 @@ var JunieRule = class _JunieRule extends ToolRule {
4027
4527
  validate = true
4028
4528
  }) {
4029
4529
  const isRoot = relativeFilePath === "guidelines.md";
4030
- const relativePath = isRoot ? "guidelines.md" : (0, import_node_path43.join)(".junie/memories", relativeFilePath);
4031
- const fileContent = await readFileContent((0, import_node_path43.join)(baseDir, relativePath));
4530
+ const relativePath = isRoot ? "guidelines.md" : (0, import_node_path46.join)(".junie/memories", relativeFilePath);
4531
+ const fileContent = await readFileContent((0, import_node_path46.join)(baseDir, relativePath));
4032
4532
  return new _JunieRule({
4033
4533
  baseDir,
4034
4534
  relativeDirPath: isRoot ? this.getSettablePaths().root.relativeDirPath : this.getSettablePaths().nonRoot.relativeDirPath,
@@ -4068,7 +4568,7 @@ var JunieRule = class _JunieRule extends ToolRule {
4068
4568
  };
4069
4569
 
4070
4570
  // src/rules/kiro-rule.ts
4071
- var import_node_path44 = require("path");
4571
+ var import_node_path47 = require("path");
4072
4572
  var KiroRule = class _KiroRule extends ToolRule {
4073
4573
  static getSettablePaths() {
4074
4574
  return {
@@ -4083,7 +4583,7 @@ var KiroRule = class _KiroRule extends ToolRule {
4083
4583
  validate = true
4084
4584
  }) {
4085
4585
  const fileContent = await readFileContent(
4086
- (0, import_node_path44.join)(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
4586
+ (0, import_node_path47.join)(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
4087
4587
  );
4088
4588
  return new _KiroRule({
4089
4589
  baseDir,
@@ -4123,7 +4623,7 @@ var KiroRule = class _KiroRule extends ToolRule {
4123
4623
  };
4124
4624
 
4125
4625
  // src/rules/opencode-rule.ts
4126
- var import_node_path45 = require("path");
4626
+ var import_node_path48 = require("path");
4127
4627
  var OpenCodeRule = class _OpenCodeRule extends ToolRule {
4128
4628
  static getSettablePaths() {
4129
4629
  return {
@@ -4142,8 +4642,8 @@ var OpenCodeRule = class _OpenCodeRule extends ToolRule {
4142
4642
  validate = true
4143
4643
  }) {
4144
4644
  const isRoot = relativeFilePath === "AGENTS.md";
4145
- const relativePath = isRoot ? "AGENTS.md" : (0, import_node_path45.join)(".opencode/memories", relativeFilePath);
4146
- const fileContent = await readFileContent((0, import_node_path45.join)(baseDir, relativePath));
4645
+ const relativePath = isRoot ? "AGENTS.md" : (0, import_node_path48.join)(".opencode/memories", relativeFilePath);
4646
+ const fileContent = await readFileContent((0, import_node_path48.join)(baseDir, relativePath));
4147
4647
  return new _OpenCodeRule({
4148
4648
  baseDir,
4149
4649
  relativeDirPath: isRoot ? this.getSettablePaths().root.relativeDirPath : this.getSettablePaths().nonRoot.relativeDirPath,
@@ -4183,7 +4683,7 @@ var OpenCodeRule = class _OpenCodeRule extends ToolRule {
4183
4683
  };
4184
4684
 
4185
4685
  // src/rules/qwencode-rule.ts
4186
- var import_node_path46 = require("path");
4686
+ var import_node_path49 = require("path");
4187
4687
  var QwencodeRule = class _QwencodeRule extends ToolRule {
4188
4688
  static getSettablePaths() {
4189
4689
  return {
@@ -4202,8 +4702,8 @@ var QwencodeRule = class _QwencodeRule extends ToolRule {
4202
4702
  validate = true
4203
4703
  }) {
4204
4704
  const isRoot = relativeFilePath === "QWEN.md";
4205
- const relativePath = isRoot ? "QWEN.md" : (0, import_node_path46.join)(".qwen/memories", relativeFilePath);
4206
- const fileContent = await readFileContent((0, import_node_path46.join)(baseDir, relativePath));
4705
+ const relativePath = isRoot ? "QWEN.md" : (0, import_node_path49.join)(".qwen/memories", relativeFilePath);
4706
+ const fileContent = await readFileContent((0, import_node_path49.join)(baseDir, relativePath));
4207
4707
  return new _QwencodeRule({
4208
4708
  baseDir,
4209
4709
  relativeDirPath: isRoot ? this.getSettablePaths().root.relativeDirPath : this.getSettablePaths().nonRoot.relativeDirPath,
@@ -4240,7 +4740,7 @@ var QwencodeRule = class _QwencodeRule extends ToolRule {
4240
4740
  };
4241
4741
 
4242
4742
  // src/rules/roo-rule.ts
4243
- var import_node_path47 = require("path");
4743
+ var import_node_path50 = require("path");
4244
4744
  var RooRule = class _RooRule extends ToolRule {
4245
4745
  static getSettablePaths() {
4246
4746
  return {
@@ -4255,7 +4755,7 @@ var RooRule = class _RooRule extends ToolRule {
4255
4755
  validate = true
4256
4756
  }) {
4257
4757
  const fileContent = await readFileContent(
4258
- (0, import_node_path47.join)(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
4758
+ (0, import_node_path50.join)(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
4259
4759
  );
4260
4760
  return new _RooRule({
4261
4761
  baseDir,
@@ -4310,7 +4810,7 @@ var RooRule = class _RooRule extends ToolRule {
4310
4810
  };
4311
4811
 
4312
4812
  // src/rules/warp-rule.ts
4313
- var import_node_path48 = require("path");
4813
+ var import_node_path51 = require("path");
4314
4814
  var WarpRule = class _WarpRule extends ToolRule {
4315
4815
  constructor({ fileContent, root, ...rest }) {
4316
4816
  super({
@@ -4336,8 +4836,8 @@ var WarpRule = class _WarpRule extends ToolRule {
4336
4836
  validate = true
4337
4837
  }) {
4338
4838
  const isRoot = relativeFilePath === this.getSettablePaths().root.relativeFilePath;
4339
- const relativePath = isRoot ? this.getSettablePaths().root.relativeFilePath : (0, import_node_path48.join)(this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath);
4340
- const fileContent = await readFileContent((0, import_node_path48.join)(baseDir, relativePath));
4839
+ const relativePath = isRoot ? this.getSettablePaths().root.relativeFilePath : (0, import_node_path51.join)(this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath);
4840
+ const fileContent = await readFileContent((0, import_node_path51.join)(baseDir, relativePath));
4341
4841
  return new _WarpRule({
4342
4842
  baseDir,
4343
4843
  relativeDirPath: isRoot ? this.getSettablePaths().root.relativeDirPath : ".warp",
@@ -4377,7 +4877,7 @@ var WarpRule = class _WarpRule extends ToolRule {
4377
4877
  };
4378
4878
 
4379
4879
  // src/rules/windsurf-rule.ts
4380
- var import_node_path49 = require("path");
4880
+ var import_node_path52 = require("path");
4381
4881
  var WindsurfRule = class _WindsurfRule extends ToolRule {
4382
4882
  static getSettablePaths() {
4383
4883
  return {
@@ -4392,7 +4892,7 @@ var WindsurfRule = class _WindsurfRule extends ToolRule {
4392
4892
  validate = true
4393
4893
  }) {
4394
4894
  const fileContent = await readFileContent(
4395
- (0, import_node_path49.join)(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
4895
+ (0, import_node_path52.join)(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
4396
4896
  );
4397
4897
  return new _WindsurfRule({
4398
4898
  baseDir,
@@ -4450,7 +4950,7 @@ var rulesProcessorToolTargets = [
4450
4950
  "warp",
4451
4951
  "windsurf"
4452
4952
  ];
4453
- var RulesProcessorToolTargetSchema = import_mini17.z.enum(rulesProcessorToolTargets);
4953
+ var RulesProcessorToolTargetSchema = import_mini20.z.enum(rulesProcessorToolTargets);
4454
4954
  var RulesProcessor = class extends FeatureProcessor {
4455
4955
  toolTarget;
4456
4956
  simulateCommands;
@@ -4629,7 +5129,8 @@ var RulesProcessor = class extends FeatureProcessor {
4629
5129
  throw new Error(`Unsupported tool target: ${this.toolTarget}`);
4630
5130
  }
4631
5131
  }).filter((rule) => rule !== null);
4632
- if (this.toolTarget === "cursor" && (this.simulateCommands || this.simulateSubagents)) {
5132
+ const isSimulated = this.simulateCommands || this.simulateSubagents;
5133
+ if (isSimulated && this.toolTarget === "cursor") {
4633
5134
  toolRules.push(
4634
5135
  new CursorRule({
4635
5136
  baseDir: this.baseDir,
@@ -4648,6 +5149,22 @@ var RulesProcessor = class extends FeatureProcessor {
4648
5149
  })
4649
5150
  );
4650
5151
  }
5152
+ if (isSimulated && this.toolTarget === "roo") {
5153
+ toolRules.push(
5154
+ new RooRule({
5155
+ baseDir: this.baseDir,
5156
+ relativeDirPath: RooRule.getSettablePaths().nonRoot.relativeDirPath,
5157
+ relativeFilePath: "additional-conventions.md",
5158
+ fileContent: this.generateAdditionalConventionsSection({
5159
+ commands: { relativeDirPath: RooCommand.getSettablePaths().relativeDirPath },
5160
+ subagents: {
5161
+ relativeDirPath: RooSubagent.getSettablePaths().relativeDirPath
5162
+ }
5163
+ }),
5164
+ validate: true
5165
+ })
5166
+ );
5167
+ }
4651
5168
  const rootRuleIndex = toolRules.findIndex((rule) => rule.isRoot());
4652
5169
  if (rootRuleIndex === -1) {
4653
5170
  return toolRules;
@@ -4701,7 +5218,12 @@ var RulesProcessor = class extends FeatureProcessor {
4701
5218
  case "geminicli": {
4702
5219
  const rootRule = toolRules[rootRuleIndex];
4703
5220
  rootRule?.setFileContent(
4704
- this.generateXmlReferencesSection(toolRules) + rootRule.getFileContent()
5221
+ this.generateXmlReferencesSection(toolRules) + this.generateAdditionalConventionsSection({
5222
+ commands: { relativeDirPath: GeminiCliCommand.getSettablePaths().relativeDirPath },
5223
+ subagents: {
5224
+ relativeDirPath: GeminiCliSubagent.getSettablePaths().relativeDirPath
5225
+ }
5226
+ }) + rootRule.getFileContent()
4705
5227
  );
4706
5228
  return toolRules;
4707
5229
  }
@@ -4749,17 +5271,17 @@ var RulesProcessor = class extends FeatureProcessor {
4749
5271
  * Load and parse rulesync rule files from .rulesync/rules/ directory
4750
5272
  */
4751
5273
  async loadRulesyncFiles() {
4752
- const files = await findFilesByGlobs((0, import_node_path50.join)(RULESYNC_RULES_DIR, "*.md"));
5274
+ const files = await findFilesByGlobs((0, import_node_path53.join)(RULESYNC_RULES_DIR, "*.md"));
4753
5275
  logger.debug(`Found ${files.length} rulesync files`);
4754
5276
  return Promise.all(
4755
- files.map((file) => RulesyncRule.fromFile({ relativeFilePath: (0, import_node_path50.basename)(file) }))
5277
+ files.map((file) => RulesyncRule.fromFile({ relativeFilePath: (0, import_node_path53.basename)(file) }))
4756
5278
  );
4757
5279
  }
4758
5280
  async loadRulesyncFilesLegacy() {
4759
- const legacyFiles = await findFilesByGlobs((0, import_node_path50.join)(RULESYNC_RULES_DIR_LEGACY, "*.md"));
5281
+ const legacyFiles = await findFilesByGlobs((0, import_node_path53.join)(RULESYNC_RULES_DIR_LEGACY, "*.md"));
4760
5282
  logger.debug(`Found ${legacyFiles.length} legacy rulesync files`);
4761
5283
  return Promise.all(
4762
- legacyFiles.map((file) => RulesyncRule.fromFileLegacy({ relativeFilePath: (0, import_node_path50.basename)(file) }))
5284
+ legacyFiles.map((file) => RulesyncRule.fromFileLegacy({ relativeFilePath: (0, import_node_path53.basename)(file) }))
4763
5285
  );
4764
5286
  }
4765
5287
  /**
@@ -4820,803 +5342,405 @@ var RulesProcessor = class extends FeatureProcessor {
4820
5342
  return [];
4821
5343
  }
4822
5344
  const rootFilePaths = await findFilesByGlobs(
4823
- (0, import_node_path50.join)(this.baseDir, root.relativeDirPath ?? ".", root.relativeFilePath)
5345
+ (0, import_node_path53.join)(this.baseDir, root.relativeDirPath ?? ".", root.relativeFilePath)
4824
5346
  );
4825
5347
  return await Promise.all(
4826
5348
  rootFilePaths.map(
4827
5349
  (filePath) => root.fromFile({
4828
5350
  baseDir: this.baseDir,
4829
- relativeFilePath: (0, import_node_path50.basename)(filePath)
4830
- })
4831
- )
4832
- );
4833
- })();
4834
- logger.debug(`Found ${rootToolRules.length} root tool rule files`);
4835
- const nonRootToolRules = await (async () => {
4836
- if (!nonRoot) {
4837
- return [];
4838
- }
4839
- const nonRootFilePaths = await findFilesByGlobs(
4840
- (0, import_node_path50.join)(this.baseDir, nonRoot.relativeDirPath, `*.${nonRoot.extension}`)
4841
- );
4842
- return await Promise.all(
4843
- nonRootFilePaths.map(
4844
- (filePath) => nonRoot.fromFile({
4845
- baseDir: this.baseDir,
4846
- relativeFilePath: (0, import_node_path50.basename)(filePath)
5351
+ relativeFilePath: (0, import_node_path53.basename)(filePath)
4847
5352
  })
4848
5353
  )
4849
5354
  );
4850
5355
  })();
4851
- logger.debug(`Found ${nonRootToolRules.length} non-root tool rule files`);
4852
- return [...rootToolRules, ...nonRootToolRules];
4853
- }
4854
- /**
4855
- * Load AGENTS.md rule configuration
4856
- */
4857
- async loadAgentsmdRules() {
4858
- const settablePaths = AgentsMdRule.getSettablePaths();
4859
- return await this.loadToolRulesDefault({
4860
- root: {
4861
- relativeDirPath: settablePaths.root.relativeDirPath,
4862
- relativeFilePath: settablePaths.root.relativeFilePath,
4863
- fromFile: (params) => AgentsMdRule.fromFile(params)
4864
- },
4865
- nonRoot: {
4866
- relativeDirPath: settablePaths.nonRoot.relativeDirPath,
4867
- fromFile: (params) => AgentsMdRule.fromFile(params),
4868
- extension: "md"
4869
- }
4870
- });
4871
- }
4872
- async loadWarpRules() {
4873
- const settablePaths = WarpRule.getSettablePaths();
4874
- return await this.loadToolRulesDefault({
4875
- root: {
4876
- relativeDirPath: settablePaths.root.relativeDirPath,
4877
- relativeFilePath: settablePaths.root.relativeFilePath,
4878
- fromFile: (params) => WarpRule.fromFile(params)
4879
- },
4880
- nonRoot: {
4881
- relativeDirPath: settablePaths.nonRoot.relativeDirPath,
4882
- fromFile: (params) => WarpRule.fromFile(params),
4883
- extension: "md"
4884
- }
4885
- });
4886
- }
4887
- /**
4888
- * Load Amazon Q Developer CLI rule configurations from .amazonq/rules/ directory
4889
- */
4890
- async loadAmazonqcliRules() {
4891
- const settablePaths = AmazonQCliRule.getSettablePaths();
4892
- return await this.loadToolRulesDefault({
4893
- nonRoot: {
4894
- relativeDirPath: settablePaths.nonRoot.relativeDirPath,
4895
- fromFile: (params) => AmazonQCliRule.fromFile(params),
4896
- extension: "md"
4897
- }
4898
- });
4899
- }
4900
- /**
4901
- * Load AugmentCode rule configurations from .augment/rules/ directory
4902
- */
4903
- async loadAugmentcodeRules() {
4904
- const settablePaths = AugmentcodeRule.getSettablePaths();
4905
- return await this.loadToolRulesDefault({
4906
- nonRoot: {
4907
- relativeDirPath: settablePaths.nonRoot.relativeDirPath,
4908
- fromFile: (params) => AugmentcodeRule.fromFile(params),
4909
- extension: "md"
4910
- }
4911
- });
4912
- }
4913
- /**
4914
- * Load AugmentCode legacy rule configuration from .augment-guidelines file and .augment/rules/ directory
4915
- */
4916
- async loadAugmentcodeLegacyRules() {
4917
- const settablePaths = AugmentcodeLegacyRule.getSettablePaths();
4918
- return await this.loadToolRulesDefault({
4919
- root: {
4920
- relativeDirPath: settablePaths.root.relativeDirPath,
4921
- relativeFilePath: settablePaths.root.relativeFilePath,
4922
- fromFile: (params) => AugmentcodeLegacyRule.fromFile(params)
4923
- },
4924
- nonRoot: {
4925
- relativeDirPath: settablePaths.nonRoot.relativeDirPath,
4926
- fromFile: (params) => AugmentcodeLegacyRule.fromFile(params),
4927
- extension: "md"
4928
- }
4929
- });
4930
- }
4931
- /**
4932
- * Load Claude Code rule configuration from CLAUDE.md file
4933
- */
4934
- async loadClaudecodeRules() {
4935
- const settablePaths = ClaudecodeRule.getSettablePaths();
4936
- return await this.loadToolRulesDefault({
4937
- root: {
4938
- relativeDirPath: settablePaths.root.relativeDirPath,
4939
- relativeFilePath: settablePaths.root.relativeFilePath,
4940
- fromFile: (params) => ClaudecodeRule.fromFile(params)
4941
- },
4942
- nonRoot: {
4943
- relativeDirPath: settablePaths.nonRoot.relativeDirPath,
4944
- fromFile: (params) => ClaudecodeRule.fromFile(params),
4945
- extension: "md"
4946
- }
4947
- });
4948
- }
4949
- /**
4950
- * Load Cline rule configurations from .clinerules/ directory
4951
- */
4952
- async loadClineRules() {
4953
- const settablePaths = ClineRule.getSettablePaths();
4954
- return await this.loadToolRulesDefault({
4955
- nonRoot: {
4956
- relativeDirPath: settablePaths.nonRoot.relativeDirPath,
4957
- fromFile: (params) => ClineRule.fromFile(params),
4958
- extension: "md"
4959
- }
4960
- });
4961
- }
4962
- /**
4963
- * Load OpenAI Codex CLI rule configuration from AGENTS.md and .codex/memories/*.md files
4964
- */
4965
- async loadCodexcliRules() {
4966
- const settablePaths = CodexcliRule.getSettablePaths();
4967
- return await this.loadToolRulesDefault({
4968
- root: {
4969
- relativeDirPath: settablePaths.root.relativeDirPath,
4970
- relativeFilePath: settablePaths.root.relativeFilePath,
4971
- fromFile: (params) => CodexcliRule.fromFile(params)
4972
- },
4973
- nonRoot: {
4974
- relativeDirPath: settablePaths.nonRoot.relativeDirPath,
4975
- fromFile: (params) => CodexcliRule.fromFile(params),
4976
- extension: "md"
4977
- }
4978
- });
4979
- }
4980
- /**
4981
- * Load GitHub Copilot rule configuration from .github/copilot-instructions.md file
4982
- */
4983
- async loadCopilotRules() {
4984
- const settablePaths = CopilotRule.getSettablePaths();
4985
- return await this.loadToolRulesDefault({
4986
- root: {
4987
- relativeDirPath: settablePaths.root.relativeDirPath,
4988
- relativeFilePath: settablePaths.root.relativeFilePath,
4989
- fromFile: (params) => CopilotRule.fromFile(params)
4990
- },
4991
- nonRoot: {
4992
- relativeDirPath: settablePaths.nonRoot.relativeDirPath,
4993
- fromFile: (params) => CopilotRule.fromFile(params),
4994
- extension: "md"
4995
- }
4996
- });
4997
- }
4998
- /**
4999
- * Load Cursor rule configurations from .cursor/rules/ directory
5000
- */
5001
- async loadCursorRules() {
5002
- const settablePaths = CursorRule.getSettablePaths();
5003
- return await this.loadToolRulesDefault({
5004
- nonRoot: {
5005
- relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5006
- fromFile: (params) => CursorRule.fromFile(params),
5007
- extension: "mdc"
5008
- }
5009
- });
5010
- }
5011
- /**
5012
- * Load Gemini CLI rule configuration from GEMINI.md file
5013
- */
5014
- async loadGeminicliRules() {
5015
- const settablePaths = GeminiCliRule.getSettablePaths();
5016
- return await this.loadToolRulesDefault({
5017
- root: {
5018
- relativeDirPath: settablePaths.root.relativeDirPath,
5019
- relativeFilePath: settablePaths.root.relativeFilePath,
5020
- fromFile: (params) => GeminiCliRule.fromFile(params)
5021
- },
5022
- nonRoot: {
5023
- relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5024
- fromFile: (params) => GeminiCliRule.fromFile(params),
5025
- extension: "md"
5026
- }
5027
- });
5028
- }
5029
- /**
5030
- * Load JetBrains Junie rule configuration from .junie/guidelines.md file
5031
- */
5032
- async loadJunieRules() {
5033
- const settablePaths = JunieRule.getSettablePaths();
5034
- return await this.loadToolRulesDefault({
5035
- root: {
5036
- relativeDirPath: settablePaths.root.relativeDirPath,
5037
- relativeFilePath: settablePaths.root.relativeFilePath,
5038
- fromFile: (params) => JunieRule.fromFile(params)
5039
- },
5040
- nonRoot: {
5041
- relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5042
- fromFile: (params) => JunieRule.fromFile(params),
5043
- extension: "md"
5044
- }
5045
- });
5046
- }
5047
- /**
5048
- * Load Kiro rule configurations from .kiro/steering/ directory
5049
- */
5050
- async loadKiroRules() {
5051
- const settablePaths = KiroRule.getSettablePaths();
5052
- return await this.loadToolRulesDefault({
5053
- nonRoot: {
5054
- relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5055
- fromFile: (params) => KiroRule.fromFile(params),
5056
- extension: "md"
5356
+ logger.debug(`Found ${rootToolRules.length} root tool rule files`);
5357
+ const nonRootToolRules = await (async () => {
5358
+ if (!nonRoot) {
5359
+ return [];
5057
5360
  }
5058
- });
5361
+ const nonRootFilePaths = await findFilesByGlobs(
5362
+ (0, import_node_path53.join)(this.baseDir, nonRoot.relativeDirPath, `*.${nonRoot.extension}`)
5363
+ );
5364
+ return await Promise.all(
5365
+ nonRootFilePaths.map(
5366
+ (filePath) => nonRoot.fromFile({
5367
+ baseDir: this.baseDir,
5368
+ relativeFilePath: (0, import_node_path53.basename)(filePath)
5369
+ })
5370
+ )
5371
+ );
5372
+ })();
5373
+ logger.debug(`Found ${nonRootToolRules.length} non-root tool rule files`);
5374
+ return [...rootToolRules, ...nonRootToolRules];
5059
5375
  }
5060
5376
  /**
5061
- * Load OpenCode rule configuration from AGENTS.md file and .opencode/memories/*.md files
5377
+ * Load AGENTS.md rule configuration
5062
5378
  */
5063
- async loadOpencodeRules() {
5064
- const settablePaths = OpenCodeRule.getSettablePaths();
5379
+ async loadAgentsmdRules() {
5380
+ const settablePaths = AgentsMdRule.getSettablePaths();
5065
5381
  return await this.loadToolRulesDefault({
5066
5382
  root: {
5067
5383
  relativeDirPath: settablePaths.root.relativeDirPath,
5068
5384
  relativeFilePath: settablePaths.root.relativeFilePath,
5069
- fromFile: (params) => OpenCodeRule.fromFile(params)
5385
+ fromFile: (params) => AgentsMdRule.fromFile(params)
5070
5386
  },
5071
5387
  nonRoot: {
5072
5388
  relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5073
- fromFile: (params) => OpenCodeRule.fromFile(params),
5389
+ fromFile: (params) => AgentsMdRule.fromFile(params),
5074
5390
  extension: "md"
5075
5391
  }
5076
5392
  });
5077
5393
  }
5078
- /**
5079
- * Load Qwen Code rule configuration from QWEN.md file and .qwen/memories/*.md files
5080
- */
5081
- async loadQwencodeRules() {
5082
- const settablePaths = QwencodeRule.getSettablePaths();
5394
+ async loadWarpRules() {
5395
+ const settablePaths = WarpRule.getSettablePaths();
5083
5396
  return await this.loadToolRulesDefault({
5084
5397
  root: {
5085
5398
  relativeDirPath: settablePaths.root.relativeDirPath,
5086
5399
  relativeFilePath: settablePaths.root.relativeFilePath,
5087
- fromFile: (params) => QwencodeRule.fromFile(params)
5400
+ fromFile: (params) => WarpRule.fromFile(params)
5088
5401
  },
5089
5402
  nonRoot: {
5090
5403
  relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5091
- fromFile: (params) => QwencodeRule.fromFile(params),
5092
- extension: "md"
5093
- }
5094
- });
5095
- }
5096
- /**
5097
- * Load Roo Code rule configurations from .roo/rules/ directory
5098
- */
5099
- async loadRooRules() {
5100
- const settablePaths = RooRule.getSettablePaths();
5101
- return await this.loadToolRulesDefault({
5102
- nonRoot: {
5103
- relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5104
- fromFile: (params) => RooRule.fromFile(params),
5105
- extension: "md"
5106
- }
5107
- });
5108
- }
5109
- /**
5110
- * Load Windsurf rule configurations from .windsurf/rules/ directory
5111
- */
5112
- async loadWindsurfRules() {
5113
- const settablePaths = WindsurfRule.getSettablePaths();
5114
- return await this.loadToolRulesDefault({
5115
- nonRoot: {
5116
- relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5117
- fromFile: (params) => WindsurfRule.fromFile(params),
5404
+ fromFile: (params) => WarpRule.fromFile(params),
5118
5405
  extension: "md"
5119
5406
  }
5120
5407
  });
5121
5408
  }
5122
- /**
5123
- * Implementation of abstract method from FeatureProcessor
5124
- * Return the tool targets that this processor supports
5125
- */
5126
- static getToolTargets() {
5127
- return rulesProcessorToolTargets;
5128
- }
5129
- generateXmlReferencesSection(toolRules) {
5130
- const toolRulesWithoutRoot = toolRules.filter((rule) => !rule.isRoot());
5131
- if (toolRulesWithoutRoot.length === 0) {
5132
- return "";
5133
- }
5134
- const lines = [];
5135
- lines.push(
5136
- "Please also reference the following documents as needed. In this case, `@` stands for the project root directory."
5137
- );
5138
- lines.push("");
5139
- const documentsData = {
5140
- Documents: {
5141
- Document: toolRulesWithoutRoot.map((rule) => {
5142
- const rulesyncRule = rule.toRulesyncRule();
5143
- const frontmatter = rulesyncRule.getFrontmatter();
5144
- const relativePath = `@${rule.getRelativePathFromCwd()}`;
5145
- const document = {
5146
- Path: relativePath
5147
- };
5148
- if (frontmatter.description) {
5149
- document.Description = frontmatter.description;
5150
- }
5151
- if (frontmatter.globs && frontmatter.globs.length > 0) {
5152
- document.FilePatterns = frontmatter.globs.join(", ");
5153
- }
5154
- return document;
5155
- })
5156
- }
5157
- };
5158
- const builder = new import_fast_xml_parser.XMLBuilder({
5159
- format: true,
5160
- ignoreAttributes: false,
5161
- suppressEmptyNode: false
5162
- });
5163
- const xmlContent = builder.build(documentsData);
5164
- lines.push(xmlContent);
5165
- return lines.join("\n") + "\n";
5166
- }
5167
- generateReferencesSection(toolRules) {
5168
- const toolRulesWithoutRoot = toolRules.filter((rule) => !rule.isRoot());
5169
- if (toolRulesWithoutRoot.length === 0) {
5170
- return "";
5171
- }
5172
- const lines = [];
5173
- lines.push("Please also reference the following documents as needed:");
5174
- lines.push("");
5175
- for (const rule of toolRulesWithoutRoot) {
5176
- const rulesyncRule = rule.toRulesyncRule();
5177
- const frontmatter = rulesyncRule.getFrontmatter();
5178
- const escapedDescription = frontmatter.description?.replace(/"/g, '\\"');
5179
- const globsText = frontmatter.globs?.join(",");
5180
- lines.push(
5181
- `@${rule.getRelativePathFromCwd()} description: "${escapedDescription}" globs: "${globsText}"`
5182
- );
5183
- }
5184
- return lines.join("\n") + "\n";
5185
- }
5186
- generateAdditionalConventionsSection({
5187
- commands,
5188
- subagents
5189
- }) {
5190
- return `# Additional Conventions Beyond the Built-in Functions
5191
-
5192
- As this project's AI coding tool, you must follow the additional conventions below, in addition to the built-in functions.
5193
-
5194
- ${this.simulateCommands ? `## Simulated Custom Slash Commands
5195
-
5196
- Custom slash commands allow you to define frequently-used prompts as Markdown files that you can execute.
5197
-
5198
- ### Syntax
5199
-
5200
- Users can use following syntax to invoke a custom command.
5201
-
5202
- \`\`\`txt
5203
- s/<command> [arguments]
5204
- \`\`\`
5205
-
5206
- This syntax employs a double slash (\`s/\`) to prevent conflicts with built-in slash commands.
5207
- The \`s\` in \`s/\` stands for *simulate*. Because custom slash commands are not built-in, this syntax provides a pseudo way to invoke them.
5208
-
5209
- When users call a custom slash command, you have to look for the markdown file, \`${(0, import_node_path50.join)(commands.relativeDirPath, "{command}.md")}\`, then execute the contents of that file as the block of operations.` : ""}
5210
-
5211
- ${this.simulateSubagents ? `## Simulated Subagents
5212
-
5213
- 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 simulated custom slash commands simply. Simulated subagents can be called by simulated custom slash commands.
5214
-
5215
- When users call a simulated subagent, it will look for the corresponding markdown file, \`${(0, import_node_path50.join)(subagents.relativeDirPath, "{subagent}.md")}\`, and execute its contents as the block of operations.` : ""}`.trim();
5216
- }
5217
- };
5218
-
5219
- // src/subagents/subagents-processor.ts
5220
- var import_node_path53 = require("path");
5221
- var import_mini20 = require("zod/mini");
5222
-
5223
- // src/subagents/claudecode-subagent.ts
5224
- var import_node_path52 = require("path");
5225
- var import_mini19 = require("zod/mini");
5226
-
5227
- // src/subagents/rulesync-subagent.ts
5228
- var import_node_path51 = require("path");
5229
- var import_mini18 = require("zod/mini");
5230
- var RulesyncSubagentModelSchema = import_mini18.z.enum(["opus", "sonnet", "haiku", "inherit"]);
5231
- var RulesyncSubagentFrontmatterSchema = import_mini18.z.object({
5232
- targets: RulesyncTargetsSchema,
5233
- name: import_mini18.z.string(),
5234
- description: import_mini18.z.string(),
5235
- claudecode: import_mini18.z.optional(
5236
- import_mini18.z.object({
5237
- model: RulesyncSubagentModelSchema
5238
- })
5239
- )
5240
- });
5241
- var RulesyncSubagent = class _RulesyncSubagent extends RulesyncFile {
5242
- frontmatter;
5243
- body;
5244
- constructor({ frontmatter, body, ...rest }) {
5245
- if (rest.validate !== false) {
5246
- const result = RulesyncSubagentFrontmatterSchema.safeParse(frontmatter);
5247
- if (!result.success) {
5248
- throw result.error;
5249
- }
5250
- }
5251
- super({
5252
- ...rest
5253
- });
5254
- this.frontmatter = frontmatter;
5255
- this.body = body;
5256
- }
5257
- static getSettablePaths() {
5258
- return {
5259
- relativeDirPath: ".rulesync/subagents"
5260
- };
5261
- }
5262
- getFrontmatter() {
5263
- return this.frontmatter;
5264
- }
5265
- getBody() {
5266
- return this.body;
5267
- }
5268
- validate() {
5269
- if (!this.frontmatter) {
5270
- return { success: true, error: null };
5271
- }
5272
- const result = RulesyncSubagentFrontmatterSchema.safeParse(this.frontmatter);
5273
- if (result.success) {
5274
- return { success: true, error: null };
5275
- } else {
5276
- return { success: false, error: result.error };
5277
- }
5278
- }
5279
- static async fromFile({
5280
- relativeFilePath
5281
- }) {
5282
- const fileContent = await readFileContent((0, import_node_path51.join)(RULESYNC_SUBAGENTS_DIR, relativeFilePath));
5283
- const { frontmatter, body: content } = parseFrontmatter(fileContent);
5284
- const result = RulesyncSubagentFrontmatterSchema.safeParse(frontmatter);
5285
- if (!result.success) {
5286
- throw new Error(`Invalid frontmatter in ${relativeFilePath}: ${result.error.message}`);
5287
- }
5288
- const filename = (0, import_node_path51.basename)(relativeFilePath);
5289
- return new _RulesyncSubagent({
5290
- baseDir: ".",
5291
- relativeDirPath: this.getSettablePaths().relativeDirPath,
5292
- relativeFilePath: filename,
5293
- frontmatter: result.data,
5294
- body: content.trim(),
5295
- fileContent
5296
- });
5297
- }
5298
- };
5299
-
5300
- // src/subagents/claudecode-subagent.ts
5301
- var ClaudecodeSubagentFrontmatterSchema = import_mini19.z.object({
5302
- name: import_mini19.z.string(),
5303
- description: import_mini19.z.string(),
5304
- model: import_mini19.z.optional(import_mini19.z.enum(["opus", "sonnet", "haiku", "inherit"]))
5305
- });
5306
- var ClaudecodeSubagent = class _ClaudecodeSubagent extends ToolSubagent {
5307
- frontmatter;
5308
- body;
5309
- constructor({ frontmatter, body, ...rest }) {
5310
- if (rest.validate !== false) {
5311
- const result = ClaudecodeSubagentFrontmatterSchema.safeParse(frontmatter);
5312
- if (!result.success) {
5313
- throw result.error;
5314
- }
5315
- }
5316
- super({
5317
- ...rest
5318
- });
5319
- this.frontmatter = frontmatter;
5320
- this.body = body;
5321
- }
5322
- static getSettablePaths() {
5323
- return {
5324
- relativeDirPath: ".claude/agents"
5325
- };
5326
- }
5327
- getFrontmatter() {
5328
- return this.frontmatter;
5329
- }
5330
- getBody() {
5331
- return this.body;
5332
- }
5333
- toRulesyncSubagent() {
5334
- const rulesyncFrontmatter = {
5335
- targets: ["claudecode"],
5336
- name: this.frontmatter.name,
5337
- description: this.frontmatter.description,
5338
- ...this.frontmatter.model && {
5339
- claudecode: {
5340
- model: this.frontmatter.model
5341
- }
5409
+ /**
5410
+ * Load Amazon Q Developer CLI rule configurations from .amazonq/rules/ directory
5411
+ */
5412
+ async loadAmazonqcliRules() {
5413
+ const settablePaths = AmazonQCliRule.getSettablePaths();
5414
+ return await this.loadToolRulesDefault({
5415
+ nonRoot: {
5416
+ relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5417
+ fromFile: (params) => AmazonQCliRule.fromFile(params),
5418
+ extension: "md"
5342
5419
  }
5343
- };
5344
- const fileContent = stringifyFrontmatter(this.body, rulesyncFrontmatter);
5345
- return new RulesyncSubagent({
5346
- frontmatter: rulesyncFrontmatter,
5347
- body: this.body,
5348
- baseDir: this.baseDir,
5349
- relativeDirPath: ".rulesync/subagents",
5350
- relativeFilePath: this.getRelativeFilePath(),
5351
- fileContent,
5352
- validate: true
5353
5420
  });
5354
5421
  }
5355
- static fromRulesyncSubagent({
5356
- baseDir = ".",
5357
- rulesyncSubagent,
5358
- validate = true
5359
- }) {
5360
- const rulesyncFrontmatter = rulesyncSubagent.getFrontmatter();
5361
- const claudecodeFrontmatter = {
5362
- name: rulesyncFrontmatter.name,
5363
- description: rulesyncFrontmatter.description,
5364
- model: rulesyncFrontmatter.claudecode?.model
5365
- };
5366
- const body = rulesyncSubagent.getBody();
5367
- const fileContent = stringifyFrontmatter(body, claudecodeFrontmatter);
5368
- return new _ClaudecodeSubagent({
5369
- baseDir,
5370
- frontmatter: claudecodeFrontmatter,
5371
- body,
5372
- relativeDirPath: ".claude/agents",
5373
- relativeFilePath: rulesyncSubagent.getRelativeFilePath(),
5374
- fileContent,
5375
- validate
5422
+ /**
5423
+ * Load AugmentCode rule configurations from .augment/rules/ directory
5424
+ */
5425
+ async loadAugmentcodeRules() {
5426
+ const settablePaths = AugmentcodeRule.getSettablePaths();
5427
+ return await this.loadToolRulesDefault({
5428
+ nonRoot: {
5429
+ relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5430
+ fromFile: (params) => AugmentcodeRule.fromFile(params),
5431
+ extension: "md"
5432
+ }
5376
5433
  });
5377
5434
  }
5378
- validate() {
5379
- if (!this.frontmatter) {
5380
- return { success: true, error: null };
5381
- }
5382
- const result = ClaudecodeSubagentFrontmatterSchema.safeParse(this.frontmatter);
5383
- if (result.success) {
5384
- return { success: true, error: null };
5385
- } else {
5386
- return { success: false, error: result.error };
5387
- }
5435
+ /**
5436
+ * Load AugmentCode legacy rule configuration from .augment-guidelines file and .augment/rules/ directory
5437
+ */
5438
+ async loadAugmentcodeLegacyRules() {
5439
+ const settablePaths = AugmentcodeLegacyRule.getSettablePaths();
5440
+ return await this.loadToolRulesDefault({
5441
+ root: {
5442
+ relativeDirPath: settablePaths.root.relativeDirPath,
5443
+ relativeFilePath: settablePaths.root.relativeFilePath,
5444
+ fromFile: (params) => AugmentcodeLegacyRule.fromFile(params)
5445
+ },
5446
+ nonRoot: {
5447
+ relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5448
+ fromFile: (params) => AugmentcodeLegacyRule.fromFile(params),
5449
+ extension: "md"
5450
+ }
5451
+ });
5388
5452
  }
5389
- static isTargetedByRulesyncSubagent(rulesyncSubagent) {
5390
- return this.isTargetedByRulesyncSubagentDefault({
5391
- rulesyncSubagent,
5392
- toolTarget: "claudecode"
5453
+ /**
5454
+ * Load Claude Code rule configuration from CLAUDE.md file
5455
+ */
5456
+ async loadClaudecodeRules() {
5457
+ const settablePaths = ClaudecodeRule.getSettablePaths();
5458
+ return await this.loadToolRulesDefault({
5459
+ root: {
5460
+ relativeDirPath: settablePaths.root.relativeDirPath,
5461
+ relativeFilePath: settablePaths.root.relativeFilePath,
5462
+ fromFile: (params) => ClaudecodeRule.fromFile(params)
5463
+ },
5464
+ nonRoot: {
5465
+ relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5466
+ fromFile: (params) => ClaudecodeRule.fromFile(params),
5467
+ extension: "md"
5468
+ }
5393
5469
  });
5394
5470
  }
5395
- static async fromFile({
5396
- baseDir = ".",
5397
- relativeFilePath,
5398
- validate = true
5399
- }) {
5400
- const fileContent = await readFileContent((0, import_node_path52.join)(baseDir, ".claude/agents", relativeFilePath));
5401
- const { frontmatter, body: content } = parseFrontmatter(fileContent);
5402
- const result = ClaudecodeSubagentFrontmatterSchema.safeParse(frontmatter);
5403
- if (!result.success) {
5404
- throw new Error(`Invalid frontmatter in ${relativeFilePath}: ${result.error.message}`);
5405
- }
5406
- return new _ClaudecodeSubagent({
5407
- baseDir,
5408
- relativeDirPath: ".claude/agents",
5409
- relativeFilePath,
5410
- frontmatter: result.data,
5411
- body: content.trim(),
5412
- fileContent,
5413
- validate
5471
+ /**
5472
+ * Load Cline rule configurations from .clinerules/ directory
5473
+ */
5474
+ async loadClineRules() {
5475
+ const settablePaths = ClineRule.getSettablePaths();
5476
+ return await this.loadToolRulesDefault({
5477
+ nonRoot: {
5478
+ relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5479
+ fromFile: (params) => ClineRule.fromFile(params),
5480
+ extension: "md"
5481
+ }
5414
5482
  });
5415
5483
  }
5416
- };
5417
-
5418
- // src/subagents/subagents-processor.ts
5419
- var subagentsProcessorToolTargets = [
5420
- "claudecode",
5421
- "copilot",
5422
- "cursor",
5423
- "codexcli"
5424
- ];
5425
- var subagentsProcessorToolTargetsSimulated = [
5426
- "copilot",
5427
- "cursor",
5428
- "codexcli"
5429
- ];
5430
- var SubagentsProcessorToolTargetSchema = import_mini20.z.enum(subagentsProcessorToolTargets);
5431
- var SubagentsProcessor = class extends FeatureProcessor {
5432
- toolTarget;
5433
- constructor({
5434
- baseDir = ".",
5435
- toolTarget
5436
- }) {
5437
- super({ baseDir });
5438
- this.toolTarget = SubagentsProcessorToolTargetSchema.parse(toolTarget);
5484
+ /**
5485
+ * Load OpenAI Codex CLI rule configuration from AGENTS.md and .codex/memories/*.md files
5486
+ */
5487
+ async loadCodexcliRules() {
5488
+ const settablePaths = CodexcliRule.getSettablePaths();
5489
+ return await this.loadToolRulesDefault({
5490
+ root: {
5491
+ relativeDirPath: settablePaths.root.relativeDirPath,
5492
+ relativeFilePath: settablePaths.root.relativeFilePath,
5493
+ fromFile: (params) => CodexcliRule.fromFile(params)
5494
+ },
5495
+ nonRoot: {
5496
+ relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5497
+ fromFile: (params) => CodexcliRule.fromFile(params),
5498
+ extension: "md"
5499
+ }
5500
+ });
5439
5501
  }
5440
- async convertRulesyncFilesToToolFiles(rulesyncFiles) {
5441
- const rulesyncSubagents = rulesyncFiles.filter(
5442
- (file) => file instanceof RulesyncSubagent
5443
- );
5444
- const toolSubagents = rulesyncSubagents.map((rulesyncSubagent) => {
5445
- switch (this.toolTarget) {
5446
- case "claudecode":
5447
- if (!ClaudecodeSubagent.isTargetedByRulesyncSubagent(rulesyncSubagent)) {
5448
- return null;
5449
- }
5450
- return ClaudecodeSubagent.fromRulesyncSubagent({
5451
- baseDir: this.baseDir,
5452
- relativeDirPath: RulesyncSubagent.getSettablePaths().relativeDirPath,
5453
- rulesyncSubagent
5454
- });
5455
- case "copilot":
5456
- if (!CopilotSubagent.isTargetedByRulesyncSubagent(rulesyncSubagent)) {
5457
- return null;
5458
- }
5459
- return CopilotSubagent.fromRulesyncSubagent({
5460
- baseDir: this.baseDir,
5461
- relativeDirPath: RulesyncSubagent.getSettablePaths().relativeDirPath,
5462
- rulesyncSubagent
5463
- });
5464
- case "cursor":
5465
- if (!CursorSubagent.isTargetedByRulesyncSubagent(rulesyncSubagent)) {
5466
- return null;
5467
- }
5468
- return CursorSubagent.fromRulesyncSubagent({
5469
- baseDir: this.baseDir,
5470
- relativeDirPath: RulesyncSubagent.getSettablePaths().relativeDirPath,
5471
- rulesyncSubagent
5472
- });
5473
- case "codexcli":
5474
- if (!CodexCliSubagent.isTargetedByRulesyncSubagent(rulesyncSubagent)) {
5475
- return null;
5476
- }
5477
- return CodexCliSubagent.fromRulesyncSubagent({
5478
- baseDir: this.baseDir,
5479
- relativeDirPath: RulesyncSubagent.getSettablePaths().relativeDirPath,
5480
- rulesyncSubagent
5481
- });
5482
- default:
5483
- throw new Error(`Unsupported tool target: ${this.toolTarget}`);
5502
+ /**
5503
+ * Load GitHub Copilot rule configuration from .github/copilot-instructions.md file
5504
+ */
5505
+ async loadCopilotRules() {
5506
+ const settablePaths = CopilotRule.getSettablePaths();
5507
+ return await this.loadToolRulesDefault({
5508
+ root: {
5509
+ relativeDirPath: settablePaths.root.relativeDirPath,
5510
+ relativeFilePath: settablePaths.root.relativeFilePath,
5511
+ fromFile: (params) => CopilotRule.fromFile(params)
5512
+ },
5513
+ nonRoot: {
5514
+ relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5515
+ fromFile: (params) => CopilotRule.fromFile(params),
5516
+ extension: "md"
5484
5517
  }
5485
- }).filter((subagent) => subagent !== null);
5486
- return toolSubagents;
5518
+ });
5487
5519
  }
5488
- async convertToolFilesToRulesyncFiles(toolFiles) {
5489
- const toolSubagents = toolFiles.filter(
5490
- (file) => file instanceof ToolSubagent
5491
- );
5492
- const rulesyncSubagents = [];
5493
- for (const toolSubagent of toolSubagents) {
5494
- if (toolSubagent instanceof SimulatedSubagent) {
5495
- logger.debug(
5496
- `Skipping simulated subagent conversion: ${toolSubagent.getRelativeFilePath()}`
5497
- );
5498
- continue;
5520
+ /**
5521
+ * Load Cursor rule configurations from .cursor/rules/ directory
5522
+ */
5523
+ async loadCursorRules() {
5524
+ const settablePaths = CursorRule.getSettablePaths();
5525
+ return await this.loadToolRulesDefault({
5526
+ nonRoot: {
5527
+ relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5528
+ fromFile: (params) => CursorRule.fromFile(params),
5529
+ extension: "mdc"
5499
5530
  }
5500
- rulesyncSubagents.push(toolSubagent.toRulesyncSubagent());
5501
- }
5502
- return rulesyncSubagents;
5531
+ });
5503
5532
  }
5504
5533
  /**
5505
- * Implementation of abstract method from Processor
5506
- * Load and parse rulesync subagent files from .rulesync/subagents/ directory
5534
+ * Load Gemini CLI rule configuration from GEMINI.md file
5507
5535
  */
5508
- async loadRulesyncFiles() {
5509
- const subagentsDir = (0, import_node_path53.join)(this.baseDir, RulesyncSubagent.getSettablePaths().relativeDirPath);
5510
- const dirExists = await directoryExists(subagentsDir);
5511
- if (!dirExists) {
5512
- logger.debug(`Rulesync subagents directory not found: ${subagentsDir}`);
5513
- return [];
5514
- }
5515
- const entries = await listDirectoryFiles(subagentsDir);
5516
- const mdFiles = entries.filter((file) => file.endsWith(".md"));
5517
- if (mdFiles.length === 0) {
5518
- logger.debug(`No markdown files found in rulesync subagents directory: ${subagentsDir}`);
5519
- return [];
5520
- }
5521
- logger.info(`Found ${mdFiles.length} subagent files in ${subagentsDir}`);
5522
- const rulesyncSubagents = [];
5523
- for (const mdFile of mdFiles) {
5524
- const filepath = (0, import_node_path53.join)(subagentsDir, mdFile);
5525
- try {
5526
- const rulesyncSubagent = await RulesyncSubagent.fromFile({
5527
- relativeFilePath: mdFile,
5528
- validate: true
5529
- });
5530
- rulesyncSubagents.push(rulesyncSubagent);
5531
- logger.debug(`Successfully loaded subagent: ${mdFile}`);
5532
- } catch (error) {
5533
- logger.warn(`Failed to load subagent file ${filepath}:`, error);
5534
- continue;
5536
+ async loadGeminicliRules() {
5537
+ const settablePaths = GeminiCliRule.getSettablePaths();
5538
+ return await this.loadToolRulesDefault({
5539
+ root: {
5540
+ relativeDirPath: settablePaths.root.relativeDirPath,
5541
+ relativeFilePath: settablePaths.root.relativeFilePath,
5542
+ fromFile: (params) => GeminiCliRule.fromFile(params)
5543
+ },
5544
+ nonRoot: {
5545
+ relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5546
+ fromFile: (params) => GeminiCliRule.fromFile(params),
5547
+ extension: "md"
5535
5548
  }
5536
- }
5537
- if (rulesyncSubagents.length === 0) {
5538
- logger.debug(`No valid subagents found in ${subagentsDir}`);
5539
- return [];
5540
- }
5541
- logger.info(`Successfully loaded ${rulesyncSubagents.length} rulesync subagents`);
5542
- return rulesyncSubagents;
5549
+ });
5543
5550
  }
5544
5551
  /**
5545
- * Implementation of abstract method from Processor
5546
- * Load tool-specific subagent configurations and parse them into ToolSubagent instances
5552
+ * Load JetBrains Junie rule configuration from .junie/guidelines.md file
5547
5553
  */
5548
- async loadToolFiles() {
5549
- switch (this.toolTarget) {
5550
- case "claudecode":
5551
- return await this.loadClaudecodeSubagents();
5552
- case "copilot":
5553
- return await this.loadCopilotSubagents();
5554
- case "cursor":
5555
- return await this.loadCursorSubagents();
5556
- case "codexcli":
5557
- return await this.loadCodexCliSubagents();
5558
- default:
5559
- throw new Error(`Unsupported tool target: ${this.toolTarget}`);
5560
- }
5554
+ async loadJunieRules() {
5555
+ const settablePaths = JunieRule.getSettablePaths();
5556
+ return await this.loadToolRulesDefault({
5557
+ root: {
5558
+ relativeDirPath: settablePaths.root.relativeDirPath,
5559
+ relativeFilePath: settablePaths.root.relativeFilePath,
5560
+ fromFile: (params) => JunieRule.fromFile(params)
5561
+ },
5562
+ nonRoot: {
5563
+ relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5564
+ fromFile: (params) => JunieRule.fromFile(params),
5565
+ extension: "md"
5566
+ }
5567
+ });
5561
5568
  }
5562
5569
  /**
5563
- * Load Claude Code subagent configurations from .claude/agents/ directory
5570
+ * Load Kiro rule configurations from .kiro/steering/ directory
5564
5571
  */
5565
- async loadClaudecodeSubagents() {
5566
- return await this.loadToolSubagentsDefault({
5567
- relativeDirPath: ClaudecodeSubagent.getSettablePaths().relativeDirPath,
5568
- fromFile: (relativeFilePath) => ClaudecodeSubagent.fromFile({ relativeFilePath })
5572
+ async loadKiroRules() {
5573
+ const settablePaths = KiroRule.getSettablePaths();
5574
+ return await this.loadToolRulesDefault({
5575
+ nonRoot: {
5576
+ relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5577
+ fromFile: (params) => KiroRule.fromFile(params),
5578
+ extension: "md"
5579
+ }
5569
5580
  });
5570
5581
  }
5571
5582
  /**
5572
- * Load Copilot subagent configurations from .copilot/subagents/ directory
5583
+ * Load OpenCode rule configuration from AGENTS.md file and .opencode/memories/*.md files
5573
5584
  */
5574
- async loadCopilotSubagents() {
5575
- return await this.loadToolSubagentsDefault({
5576
- relativeDirPath: CopilotSubagent.getSettablePaths().relativeDirPath,
5577
- fromFile: (relativeFilePath) => CopilotSubagent.fromFile({ relativeFilePath })
5585
+ async loadOpencodeRules() {
5586
+ const settablePaths = OpenCodeRule.getSettablePaths();
5587
+ return await this.loadToolRulesDefault({
5588
+ root: {
5589
+ relativeDirPath: settablePaths.root.relativeDirPath,
5590
+ relativeFilePath: settablePaths.root.relativeFilePath,
5591
+ fromFile: (params) => OpenCodeRule.fromFile(params)
5592
+ },
5593
+ nonRoot: {
5594
+ relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5595
+ fromFile: (params) => OpenCodeRule.fromFile(params),
5596
+ extension: "md"
5597
+ }
5578
5598
  });
5579
5599
  }
5580
5600
  /**
5581
- * Load Cursor subagent configurations from .cursor/subagents/ directory
5601
+ * Load Qwen Code rule configuration from QWEN.md file and .qwen/memories/*.md files
5582
5602
  */
5583
- async loadCursorSubagents() {
5584
- return await this.loadToolSubagentsDefault({
5585
- relativeDirPath: CursorSubagent.getSettablePaths().relativeDirPath,
5586
- fromFile: (relativeFilePath) => CursorSubagent.fromFile({ relativeFilePath })
5603
+ async loadQwencodeRules() {
5604
+ const settablePaths = QwencodeRule.getSettablePaths();
5605
+ return await this.loadToolRulesDefault({
5606
+ root: {
5607
+ relativeDirPath: settablePaths.root.relativeDirPath,
5608
+ relativeFilePath: settablePaths.root.relativeFilePath,
5609
+ fromFile: (params) => QwencodeRule.fromFile(params)
5610
+ },
5611
+ nonRoot: {
5612
+ relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5613
+ fromFile: (params) => QwencodeRule.fromFile(params),
5614
+ extension: "md"
5615
+ }
5587
5616
  });
5588
5617
  }
5589
5618
  /**
5590
- * Load CodexCli subagent configurations from .codex/subagents/ directory
5619
+ * Load Roo Code rule configurations from .roo/rules/ directory
5591
5620
  */
5592
- async loadCodexCliSubagents() {
5593
- return await this.loadToolSubagentsDefault({
5594
- relativeDirPath: CodexCliSubagent.getSettablePaths().relativeDirPath,
5595
- fromFile: (relativeFilePath) => CodexCliSubagent.fromFile({ relativeFilePath })
5621
+ async loadRooRules() {
5622
+ const settablePaths = RooRule.getSettablePaths();
5623
+ return await this.loadToolRulesDefault({
5624
+ nonRoot: {
5625
+ relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5626
+ fromFile: (params) => RooRule.fromFile(params),
5627
+ extension: "md"
5628
+ }
5596
5629
  });
5597
5630
  }
5598
- async loadToolSubagentsDefault({
5599
- relativeDirPath,
5600
- fromFile
5601
- }) {
5602
- const paths = await findFilesByGlobs((0, import_node_path53.join)(this.baseDir, relativeDirPath, "*.md"));
5603
- const subagents = (await Promise.allSettled(paths.map((path2) => fromFile((0, import_node_path53.basename)(path2))))).filter((r) => r.status === "fulfilled").map((r) => r.value);
5604
- logger.info(`Successfully loaded ${subagents.length} ${relativeDirPath} subagents`);
5605
- return subagents;
5631
+ /**
5632
+ * Load Windsurf rule configurations from .windsurf/rules/ directory
5633
+ */
5634
+ async loadWindsurfRules() {
5635
+ const settablePaths = WindsurfRule.getSettablePaths();
5636
+ return await this.loadToolRulesDefault({
5637
+ nonRoot: {
5638
+ relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5639
+ fromFile: (params) => WindsurfRule.fromFile(params),
5640
+ extension: "md"
5641
+ }
5642
+ });
5606
5643
  }
5607
5644
  /**
5608
5645
  * Implementation of abstract method from FeatureProcessor
5609
5646
  * Return the tool targets that this processor supports
5610
5647
  */
5611
- static getToolTargets({
5612
- includeSimulated = false
5613
- } = {}) {
5614
- if (!includeSimulated) {
5615
- return subagentsProcessorToolTargets.filter(
5616
- (target) => !subagentsProcessorToolTargetsSimulated.includes(target)
5648
+ static getToolTargets() {
5649
+ return rulesProcessorToolTargets;
5650
+ }
5651
+ generateXmlReferencesSection(toolRules) {
5652
+ const toolRulesWithoutRoot = toolRules.filter((rule) => !rule.isRoot());
5653
+ if (toolRulesWithoutRoot.length === 0) {
5654
+ return "";
5655
+ }
5656
+ const lines = [];
5657
+ lines.push(
5658
+ "Please also reference the following documents as needed. In this case, `@` stands for the project root directory."
5659
+ );
5660
+ lines.push("");
5661
+ const documentsData = {
5662
+ Documents: {
5663
+ Document: toolRulesWithoutRoot.map((rule) => {
5664
+ const rulesyncRule = rule.toRulesyncRule();
5665
+ const frontmatter = rulesyncRule.getFrontmatter();
5666
+ const relativePath = `@${rule.getRelativePathFromCwd()}`;
5667
+ const document = {
5668
+ Path: relativePath
5669
+ };
5670
+ if (frontmatter.description) {
5671
+ document.Description = frontmatter.description;
5672
+ }
5673
+ if (frontmatter.globs && frontmatter.globs.length > 0) {
5674
+ document.FilePatterns = frontmatter.globs.join(", ");
5675
+ }
5676
+ return document;
5677
+ })
5678
+ }
5679
+ };
5680
+ const builder = new import_fast_xml_parser.XMLBuilder({
5681
+ format: true,
5682
+ ignoreAttributes: false,
5683
+ suppressEmptyNode: false
5684
+ });
5685
+ const xmlContent = builder.build(documentsData);
5686
+ lines.push(xmlContent);
5687
+ return lines.join("\n") + "\n";
5688
+ }
5689
+ generateReferencesSection(toolRules) {
5690
+ const toolRulesWithoutRoot = toolRules.filter((rule) => !rule.isRoot());
5691
+ if (toolRulesWithoutRoot.length === 0) {
5692
+ return "";
5693
+ }
5694
+ const lines = [];
5695
+ lines.push("Please also reference the following documents as needed:");
5696
+ lines.push("");
5697
+ for (const rule of toolRulesWithoutRoot) {
5698
+ const rulesyncRule = rule.toRulesyncRule();
5699
+ const frontmatter = rulesyncRule.getFrontmatter();
5700
+ const escapedDescription = frontmatter.description?.replace(/"/g, '\\"');
5701
+ const globsText = frontmatter.globs?.join(",");
5702
+ lines.push(
5703
+ `@${rule.getRelativePathFromCwd()} description: "${escapedDescription}" globs: "${globsText}"`
5617
5704
  );
5618
5705
  }
5619
- return subagentsProcessorToolTargets;
5706
+ return lines.join("\n") + "\n";
5707
+ }
5708
+ generateAdditionalConventionsSection({
5709
+ commands,
5710
+ subagents
5711
+ }) {
5712
+ const overview = `# Additional Conventions Beyond the Built-in Functions
5713
+
5714
+ As this project's AI coding tool, you must follow the additional conventions below, in addition to the built-in functions.`;
5715
+ const commandsSection = `## Simulated Custom Slash Commands
5716
+
5717
+ Custom slash commands allow you to define frequently-used prompts as Markdown files that you can execute.
5718
+
5719
+ ### Syntax
5720
+
5721
+ Users can use following syntax to invoke a custom command.
5722
+
5723
+ \`\`\`txt
5724
+ s/<command> [arguments]
5725
+ \`\`\`
5726
+
5727
+ This syntax employs a double slash (\`s/\`) to prevent conflicts with built-in slash commands.
5728
+ The \`s\` in \`s/\` stands for *simulate*. Because custom slash commands are not built-in, this syntax provides a pseudo way to invoke them.
5729
+
5730
+ When users call a custom slash command, you have to look for the markdown file, \`${(0, import_node_path53.join)(commands.relativeDirPath, "{command}.md")}\`, then execute the contents of that file as the block of operations.`;
5731
+ const subagentsSection = `## Simulated Subagents
5732
+
5733
+ 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.
5734
+
5735
+ When users call a simulated subagent, it will look for the corresponding markdown file, \`${(0, import_node_path53.join)(subagents.relativeDirPath, "{subagent}.md")}\`, and execute its contents as the block of operations.
5736
+
5737
+ For example, if the user instructs \`Call planner subagent to plan the refactoring\`, you have to look for the markdown file, \`${(0, import_node_path53.join)(subagents.relativeDirPath, "planner.md")}\`, and execute its contents as the block of operations.`;
5738
+ const result = [
5739
+ overview,
5740
+ ...this.simulateCommands && CommandsProcessor.getToolTargetsSimulated().includes(this.toolTarget) ? [commandsSection] : [],
5741
+ ...this.simulateSubagents && SubagentsProcessor.getToolTargetsSimulated().includes(this.toolTarget) ? [subagentsSection] : []
5742
+ ].join("\n\n");
5743
+ return result;
5620
5744
  }
5621
5745
  };
5622
5746
 
@@ -5821,6 +5945,7 @@ var gitignoreCommand = async () => {
5821
5945
  "**/GEMINI.md",
5822
5946
  "**/.gemini/memories/",
5823
5947
  "**/.gemini/commands/",
5948
+ "**/.gemini/subagents/",
5824
5949
  "**/QWEN.md",
5825
5950
  "**/.qwen/memories/",
5826
5951
  "**/.aiexclude",
@@ -5838,6 +5963,7 @@ var gitignoreCommand = async () => {
5838
5963
  "**/.cursor/mcp.json",
5839
5964
  "**/.cline/mcp.json",
5840
5965
  "**/.roo/mcp.json",
5966
+ "**/.roo/subagents/",
5841
5967
  "**/.vscode/mcp.json",
5842
5968
  "**/.github/commands/",
5843
5969
  "**/.github/subagents/",
@@ -5862,8 +5988,8 @@ var gitignoreCommand = async () => {
5862
5988
  }
5863
5989
  const newContent = gitignoreContent ? `${gitignoreContent.trimEnd()}
5864
5990
 
5865
- ${linesToAdd.join("")}
5866
- ` : `${linesToAdd.join("")}
5991
+ ${linesToAdd.join("\n")}
5992
+ ` : `${linesToAdd.join("\n")}
5867
5993
  `;
5868
5994
  await writeFileContent(gitignorePath, newContent);
5869
5995
  logger.success(`Added ${linesToAdd.length} rules to .gitignore:`);
@@ -6060,7 +6186,7 @@ var getVersion = async () => {
6060
6186
  const packageJson = await readJsonFile(packageJsonPath);
6061
6187
  return packageJson.version;
6062
6188
  } catch {
6063
- return "0.75.0";
6189
+ return "0.76.0";
6064
6190
  }
6065
6191
  };
6066
6192
  var main = async () => {