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.js CHANGED
@@ -742,7 +742,7 @@ import { basename as basename6, join as join6 } from "path";
742
742
  var CopilotCommand = class _CopilotCommand extends SimulatedCommand {
743
743
  static getSettablePaths() {
744
744
  return {
745
- relativeDirPath: ".copilot/commands"
745
+ relativeDirPath: ".github/commands"
746
746
  };
747
747
  }
748
748
  static fromRulesyncCommand({
@@ -1300,6 +1300,9 @@ var CommandsProcessor = class extends FeatureProcessor {
1300
1300
  }
1301
1301
  return commandsProcessorToolTargets;
1302
1302
  }
1303
+ static getToolTargetsSimulated() {
1304
+ return commandsProcessorToolTargetsSimulated;
1305
+ }
1303
1306
  };
1304
1307
 
1305
1308
  // src/config/config-resolver.ts
@@ -2777,9 +2780,9 @@ var McpProcessor = class extends FeatureProcessor {
2777
2780
  };
2778
2781
 
2779
2782
  // src/rules/rules-processor.ts
2780
- import { basename as basename14, join as join49 } from "path";
2783
+ import { basename as basename16, join as join52 } from "path";
2781
2784
  import { XMLBuilder } from "fast-xml-parser";
2782
- import { z as z17 } from "zod/mini";
2785
+ import { z as z20 } from "zod/mini";
2783
2786
 
2784
2787
  // src/constants/paths.ts
2785
2788
  import { join as join29 } from "path";
@@ -2937,7 +2940,7 @@ var CodexCliSubagent = class _CodexCliSubagent extends SimulatedSubagent {
2937
2940
  var CopilotSubagent = class _CopilotSubagent extends SimulatedSubagent {
2938
2941
  static getSettablePaths() {
2939
2942
  return {
2940
- relativeDirPath: ".copilot/subagents"
2943
+ relativeDirPath: ".github/subagents"
2941
2944
  };
2942
2945
  }
2943
2946
  static async fromFile(params) {
@@ -2979,189 +2982,686 @@ var CursorSubagent = class _CursorSubagent extends SimulatedSubagent {
2979
2982
  }
2980
2983
  };
2981
2984
 
2982
- // src/rules/agentsmd-rule.ts
2985
+ // src/subagents/geminicli-subagent.ts
2986
+ var GeminiCliSubagent = class _GeminiCliSubagent extends SimulatedSubagent {
2987
+ static getSettablePaths() {
2988
+ return {
2989
+ relativeDirPath: ".gemini/subagents"
2990
+ };
2991
+ }
2992
+ static async fromFile(params) {
2993
+ const baseParams = await this.fromFileDefault(params);
2994
+ return new _GeminiCliSubagent(baseParams);
2995
+ }
2996
+ static fromRulesyncSubagent(params) {
2997
+ const baseParams = this.fromRulesyncSubagentDefault(params);
2998
+ return new _GeminiCliSubagent(baseParams);
2999
+ }
3000
+ static isTargetedByRulesyncSubagent(rulesyncSubagent) {
3001
+ return this.isTargetedByRulesyncSubagentDefault({
3002
+ rulesyncSubagent,
3003
+ toolTarget: "geminicli"
3004
+ });
3005
+ }
3006
+ };
3007
+
3008
+ // src/subagents/roo-subagent.ts
3009
+ var RooSubagent = class _RooSubagent extends SimulatedSubagent {
3010
+ static getSettablePaths() {
3011
+ return {
3012
+ relativeDirPath: ".roo/subagents"
3013
+ };
3014
+ }
3015
+ static async fromFile(params) {
3016
+ const baseParams = await this.fromFileDefault(params);
3017
+ return new _RooSubagent(baseParams);
3018
+ }
3019
+ static fromRulesyncSubagent(params) {
3020
+ const baseParams = this.fromRulesyncSubagentDefault(params);
3021
+ return new _RooSubagent(baseParams);
3022
+ }
3023
+ static isTargetedByRulesyncSubagent(rulesyncSubagent) {
3024
+ return this.isTargetedByRulesyncSubagentDefault({
3025
+ rulesyncSubagent,
3026
+ toolTarget: "roo"
3027
+ });
3028
+ }
3029
+ };
3030
+
3031
+ // src/subagents/subagents-processor.ts
3032
+ import { basename as basename13, join as join33 } from "path";
3033
+ import { z as z15 } from "zod/mini";
3034
+
3035
+ // src/subagents/claudecode-subagent.ts
2983
3036
  import { join as join32 } from "path";
3037
+ import { z as z14 } from "zod/mini";
2984
3038
 
2985
- // src/rules/rulesync-rule.ts
3039
+ // src/subagents/rulesync-subagent.ts
2986
3040
  import { basename as basename12, join as join31 } from "path";
2987
3041
  import { z as z13 } from "zod/mini";
2988
- var RulesyncRuleFrontmatterSchema = z13.object({
2989
- root: z13.optional(z13.optional(z13.boolean())),
2990
- targets: z13.optional(RulesyncTargetsSchema),
2991
- description: z13.optional(z13.string()),
2992
- globs: z13.optional(z13.array(z13.string())),
2993
- cursor: z13.optional(
3042
+ var RulesyncSubagentModelSchema = z13.enum(["opus", "sonnet", "haiku", "inherit"]);
3043
+ var RulesyncSubagentFrontmatterSchema = z13.object({
3044
+ targets: RulesyncTargetsSchema,
3045
+ name: z13.string(),
3046
+ description: z13.string(),
3047
+ claudecode: z13.optional(
2994
3048
  z13.object({
2995
- alwaysApply: z13.optional(z13.boolean()),
2996
- description: z13.optional(z13.string()),
2997
- globs: z13.optional(z13.array(z13.string()))
3049
+ model: RulesyncSubagentModelSchema
2998
3050
  })
2999
3051
  )
3000
3052
  });
3001
- var RulesyncRule = class _RulesyncRule extends RulesyncFile {
3053
+ var RulesyncSubagent = class _RulesyncSubagent extends RulesyncFile {
3002
3054
  frontmatter;
3003
3055
  body;
3004
3056
  constructor({ frontmatter, body, ...rest }) {
3005
3057
  if (rest.validate !== false) {
3006
- const result = RulesyncRuleFrontmatterSchema.safeParse(frontmatter);
3058
+ const result = RulesyncSubagentFrontmatterSchema.safeParse(frontmatter);
3007
3059
  if (!result.success) {
3008
3060
  throw result.error;
3009
3061
  }
3010
3062
  }
3011
3063
  super({
3012
- ...rest,
3013
- fileContent: stringifyFrontmatter(body, frontmatter)
3064
+ ...rest
3014
3065
  });
3015
3066
  this.frontmatter = frontmatter;
3016
3067
  this.body = body;
3017
3068
  }
3018
3069
  static getSettablePaths() {
3019
3070
  return {
3020
- recommended: {
3021
- relativeDirPath: ".rulesync/rules"
3022
- },
3023
- legacy: {
3024
- relativeDirPath: ".rulesync"
3025
- }
3071
+ relativeDirPath: ".rulesync/subagents"
3026
3072
  };
3027
3073
  }
3028
3074
  getFrontmatter() {
3029
3075
  return this.frontmatter;
3030
3076
  }
3077
+ getBody() {
3078
+ return this.body;
3079
+ }
3031
3080
  validate() {
3032
3081
  if (!this.frontmatter) {
3033
3082
  return { success: true, error: null };
3034
3083
  }
3035
- const result = RulesyncRuleFrontmatterSchema.safeParse(this.frontmatter);
3084
+ const result = RulesyncSubagentFrontmatterSchema.safeParse(this.frontmatter);
3036
3085
  if (result.success) {
3037
3086
  return { success: true, error: null };
3038
3087
  } else {
3039
3088
  return { success: false, error: result.error };
3040
3089
  }
3041
3090
  }
3042
- static async fromFileLegacy({
3043
- relativeFilePath,
3044
- validate = true
3091
+ static async fromFile({
3092
+ relativeFilePath
3045
3093
  }) {
3046
- const filePath = join31(this.getSettablePaths().legacy.relativeDirPath, relativeFilePath);
3047
- const fileContent = await readFileContent(filePath);
3094
+ const fileContent = await readFileContent(join31(RULESYNC_SUBAGENTS_DIR, relativeFilePath));
3048
3095
  const { frontmatter, body: content } = parseFrontmatter(fileContent);
3049
- const result = RulesyncRuleFrontmatterSchema.safeParse(frontmatter);
3096
+ const result = RulesyncSubagentFrontmatterSchema.safeParse(frontmatter);
3050
3097
  if (!result.success) {
3051
- throw new Error(`Invalid frontmatter in ${filePath}: ${result.error.message}`);
3098
+ throw new Error(`Invalid frontmatter in ${relativeFilePath}: ${result.error.message}`);
3052
3099
  }
3053
- const validatedFrontmatter = {
3054
- root: result.data.root ?? false,
3055
- targets: result.data.targets ?? ["*"],
3056
- description: result.data.description ?? "",
3057
- globs: result.data.globs ?? [],
3058
- cursor: result.data.cursor
3059
- };
3060
- const filename = basename12(filePath);
3061
- return new _RulesyncRule({
3100
+ const filename = basename12(relativeFilePath);
3101
+ return new _RulesyncSubagent({
3062
3102
  baseDir: ".",
3063
- relativeDirPath: this.getSettablePaths().recommended.relativeDirPath,
3103
+ relativeDirPath: this.getSettablePaths().relativeDirPath,
3064
3104
  relativeFilePath: filename,
3065
- frontmatter: validatedFrontmatter,
3105
+ frontmatter: result.data,
3066
3106
  body: content.trim(),
3067
- validate
3107
+ fileContent
3068
3108
  });
3069
3109
  }
3070
- static async fromFile({
3071
- relativeFilePath,
3072
- validate = true
3073
- }) {
3074
- const filePath = join31(this.getSettablePaths().recommended.relativeDirPath, relativeFilePath);
3075
- const fileContent = await readFileContent(filePath);
3076
- const { frontmatter, body: content } = parseFrontmatter(fileContent);
3077
- const result = RulesyncRuleFrontmatterSchema.safeParse(frontmatter);
3078
- if (!result.success) {
3079
- throw new Error(`Invalid frontmatter in ${filePath}: ${result.error.message}`);
3110
+ };
3111
+
3112
+ // src/subagents/claudecode-subagent.ts
3113
+ var ClaudecodeSubagentFrontmatterSchema = z14.object({
3114
+ name: z14.string(),
3115
+ description: z14.string(),
3116
+ model: z14.optional(z14.enum(["opus", "sonnet", "haiku", "inherit"]))
3117
+ });
3118
+ var ClaudecodeSubagent = class _ClaudecodeSubagent extends ToolSubagent {
3119
+ frontmatter;
3120
+ body;
3121
+ constructor({ frontmatter, body, ...rest }) {
3122
+ if (rest.validate !== false) {
3123
+ const result = ClaudecodeSubagentFrontmatterSchema.safeParse(frontmatter);
3124
+ if (!result.success) {
3125
+ throw result.error;
3126
+ }
3080
3127
  }
3081
- const validatedFrontmatter = {
3082
- root: result.data.root ?? false,
3083
- targets: result.data.targets ?? ["*"],
3084
- description: result.data.description ?? "",
3085
- globs: result.data.globs ?? [],
3086
- cursor: result.data.cursor
3087
- };
3088
- const filename = basename12(filePath);
3089
- return new _RulesyncRule({
3090
- baseDir: ".",
3091
- relativeDirPath: this.getSettablePaths().recommended.relativeDirPath,
3092
- relativeFilePath: filename,
3093
- frontmatter: validatedFrontmatter,
3094
- body: content.trim(),
3095
- validate
3128
+ super({
3129
+ ...rest
3096
3130
  });
3131
+ this.frontmatter = frontmatter;
3132
+ this.body = body;
3097
3133
  }
3098
- getBody() {
3099
- return this.body;
3134
+ static getSettablePaths() {
3135
+ return {
3136
+ relativeDirPath: ".claude/agents"
3137
+ };
3100
3138
  }
3101
- };
3102
-
3103
- // src/rules/tool-rule.ts
3104
- var ToolRule = class extends ToolFile {
3105
- root;
3106
- constructor({ root = false, ...rest }) {
3107
- super(rest);
3108
- this.root = root;
3139
+ getFrontmatter() {
3140
+ return this.frontmatter;
3109
3141
  }
3110
- static async fromFile(_params) {
3111
- throw new Error("Please implement this method in the subclass.");
3142
+ getBody() {
3143
+ return this.body;
3112
3144
  }
3113
- static fromRulesyncRule(_params) {
3114
- throw new Error("Please implement this method in the subclass.");
3145
+ toRulesyncSubagent() {
3146
+ const rulesyncFrontmatter = {
3147
+ targets: ["claudecode"],
3148
+ name: this.frontmatter.name,
3149
+ description: this.frontmatter.description,
3150
+ ...this.frontmatter.model && {
3151
+ claudecode: {
3152
+ model: this.frontmatter.model
3153
+ }
3154
+ }
3155
+ };
3156
+ const fileContent = stringifyFrontmatter(this.body, rulesyncFrontmatter);
3157
+ return new RulesyncSubagent({
3158
+ frontmatter: rulesyncFrontmatter,
3159
+ body: this.body,
3160
+ baseDir: this.baseDir,
3161
+ relativeDirPath: ".rulesync/subagents",
3162
+ relativeFilePath: this.getRelativeFilePath(),
3163
+ fileContent,
3164
+ validate: true
3165
+ });
3115
3166
  }
3116
- static buildToolRuleParamsDefault({
3167
+ static fromRulesyncSubagent({
3117
3168
  baseDir = ".",
3118
- rulesyncRule,
3119
- validate = true,
3120
- rootPath = { relativeDirPath: ".", relativeFilePath: "AGENTS.md" },
3121
- nonRootPath = { relativeDirPath: ".agents/memories" }
3169
+ rulesyncSubagent,
3170
+ validate = true
3122
3171
  }) {
3123
- const fileContent = rulesyncRule.getBody();
3124
- return {
3172
+ const rulesyncFrontmatter = rulesyncSubagent.getFrontmatter();
3173
+ const claudecodeFrontmatter = {
3174
+ name: rulesyncFrontmatter.name,
3175
+ description: rulesyncFrontmatter.description,
3176
+ model: rulesyncFrontmatter.claudecode?.model
3177
+ };
3178
+ const body = rulesyncSubagent.getBody();
3179
+ const fileContent = stringifyFrontmatter(body, claudecodeFrontmatter);
3180
+ return new _ClaudecodeSubagent({
3125
3181
  baseDir,
3126
- relativeDirPath: rulesyncRule.getFrontmatter().root ? rootPath.relativeDirPath : nonRootPath.relativeDirPath,
3127
- relativeFilePath: rulesyncRule.getFrontmatter().root ? rootPath.relativeFilePath : rulesyncRule.getRelativeFilePath(),
3182
+ frontmatter: claudecodeFrontmatter,
3183
+ body,
3184
+ relativeDirPath: ".claude/agents",
3185
+ relativeFilePath: rulesyncSubagent.getRelativeFilePath(),
3128
3186
  fileContent,
3129
- validate,
3130
- root: rulesyncRule.getFrontmatter().root ?? false
3131
- };
3132
- }
3133
- toRulesyncRuleDefault() {
3134
- return new RulesyncRule({
3135
- baseDir: this.getBaseDir(),
3136
- relativeDirPath: RULESYNC_RULES_DIR,
3137
- relativeFilePath: this.getRelativeFilePath(),
3138
- frontmatter: {
3139
- root: this.isRoot(),
3140
- targets: ["*"],
3141
- description: "",
3142
- globs: this.isRoot() ? ["**/*"] : []
3143
- },
3144
- body: this.getFileContent()
3187
+ validate
3145
3188
  });
3146
3189
  }
3147
- isRoot() {
3148
- return this.root;
3190
+ validate() {
3191
+ if (!this.frontmatter) {
3192
+ return { success: true, error: null };
3193
+ }
3194
+ const result = ClaudecodeSubagentFrontmatterSchema.safeParse(this.frontmatter);
3195
+ if (result.success) {
3196
+ return { success: true, error: null };
3197
+ } else {
3198
+ return { success: false, error: result.error };
3199
+ }
3149
3200
  }
3150
- static isTargetedByRulesyncRule(_rulesyncRule) {
3151
- throw new Error("Please implement this method in the subclass.");
3201
+ static isTargetedByRulesyncSubagent(rulesyncSubagent) {
3202
+ return this.isTargetedByRulesyncSubagentDefault({
3203
+ rulesyncSubagent,
3204
+ toolTarget: "claudecode"
3205
+ });
3152
3206
  }
3153
- static isTargetedByRulesyncRuleDefault({
3154
- rulesyncRule,
3155
- toolTarget
3207
+ static async fromFile({
3208
+ baseDir = ".",
3209
+ relativeFilePath,
3210
+ validate = true
3156
3211
  }) {
3157
- const targets = rulesyncRule.getFrontmatter().targets;
3158
- if (!targets) {
3159
- return true;
3160
- }
3161
- if (targets.includes("*")) {
3162
- return true;
3212
+ const fileContent = await readFileContent(join32(baseDir, ".claude/agents", relativeFilePath));
3213
+ const { frontmatter, body: content } = parseFrontmatter(fileContent);
3214
+ const result = ClaudecodeSubagentFrontmatterSchema.safeParse(frontmatter);
3215
+ if (!result.success) {
3216
+ throw new Error(`Invalid frontmatter in ${relativeFilePath}: ${result.error.message}`);
3163
3217
  }
3164
- if (targets.includes(toolTarget)) {
3218
+ return new _ClaudecodeSubagent({
3219
+ baseDir,
3220
+ relativeDirPath: ".claude/agents",
3221
+ relativeFilePath,
3222
+ frontmatter: result.data,
3223
+ body: content.trim(),
3224
+ fileContent,
3225
+ validate
3226
+ });
3227
+ }
3228
+ };
3229
+
3230
+ // src/subagents/subagents-processor.ts
3231
+ var subagentsProcessorToolTargets = [
3232
+ "claudecode",
3233
+ "copilot",
3234
+ "cursor",
3235
+ "codexcli",
3236
+ "geminicli",
3237
+ "roo"
3238
+ ];
3239
+ var subagentsProcessorToolTargetsSimulated = [
3240
+ "copilot",
3241
+ "cursor",
3242
+ "codexcli",
3243
+ "geminicli",
3244
+ "roo"
3245
+ ];
3246
+ var SubagentsProcessorToolTargetSchema = z15.enum(subagentsProcessorToolTargets);
3247
+ var SubagentsProcessor = class extends FeatureProcessor {
3248
+ toolTarget;
3249
+ constructor({
3250
+ baseDir = ".",
3251
+ toolTarget
3252
+ }) {
3253
+ super({ baseDir });
3254
+ this.toolTarget = SubagentsProcessorToolTargetSchema.parse(toolTarget);
3255
+ }
3256
+ async convertRulesyncFilesToToolFiles(rulesyncFiles) {
3257
+ const rulesyncSubagents = rulesyncFiles.filter(
3258
+ (file) => file instanceof RulesyncSubagent
3259
+ );
3260
+ const toolSubagents = rulesyncSubagents.map((rulesyncSubagent) => {
3261
+ switch (this.toolTarget) {
3262
+ case "claudecode":
3263
+ if (!ClaudecodeSubagent.isTargetedByRulesyncSubagent(rulesyncSubagent)) {
3264
+ return null;
3265
+ }
3266
+ return ClaudecodeSubagent.fromRulesyncSubagent({
3267
+ baseDir: this.baseDir,
3268
+ relativeDirPath: RulesyncSubagent.getSettablePaths().relativeDirPath,
3269
+ rulesyncSubagent
3270
+ });
3271
+ case "copilot":
3272
+ if (!CopilotSubagent.isTargetedByRulesyncSubagent(rulesyncSubagent)) {
3273
+ return null;
3274
+ }
3275
+ return CopilotSubagent.fromRulesyncSubagent({
3276
+ baseDir: this.baseDir,
3277
+ relativeDirPath: RulesyncSubagent.getSettablePaths().relativeDirPath,
3278
+ rulesyncSubagent
3279
+ });
3280
+ case "cursor":
3281
+ if (!CursorSubagent.isTargetedByRulesyncSubagent(rulesyncSubagent)) {
3282
+ return null;
3283
+ }
3284
+ return CursorSubagent.fromRulesyncSubagent({
3285
+ baseDir: this.baseDir,
3286
+ relativeDirPath: RulesyncSubagent.getSettablePaths().relativeDirPath,
3287
+ rulesyncSubagent
3288
+ });
3289
+ case "codexcli":
3290
+ if (!CodexCliSubagent.isTargetedByRulesyncSubagent(rulesyncSubagent)) {
3291
+ return null;
3292
+ }
3293
+ return CodexCliSubagent.fromRulesyncSubagent({
3294
+ baseDir: this.baseDir,
3295
+ relativeDirPath: RulesyncSubagent.getSettablePaths().relativeDirPath,
3296
+ rulesyncSubagent
3297
+ });
3298
+ case "geminicli":
3299
+ if (!GeminiCliSubagent.isTargetedByRulesyncSubagent(rulesyncSubagent)) {
3300
+ return null;
3301
+ }
3302
+ return GeminiCliSubagent.fromRulesyncSubagent({
3303
+ baseDir: this.baseDir,
3304
+ relativeDirPath: RulesyncSubagent.getSettablePaths().relativeDirPath,
3305
+ rulesyncSubagent
3306
+ });
3307
+ case "roo":
3308
+ if (!RooSubagent.isTargetedByRulesyncSubagent(rulesyncSubagent)) {
3309
+ return null;
3310
+ }
3311
+ return RooSubagent.fromRulesyncSubagent({
3312
+ baseDir: this.baseDir,
3313
+ relativeDirPath: RulesyncSubagent.getSettablePaths().relativeDirPath,
3314
+ rulesyncSubagent
3315
+ });
3316
+ default:
3317
+ throw new Error(`Unsupported tool target: ${this.toolTarget}`);
3318
+ }
3319
+ }).filter((subagent) => subagent !== null);
3320
+ return toolSubagents;
3321
+ }
3322
+ async convertToolFilesToRulesyncFiles(toolFiles) {
3323
+ const toolSubagents = toolFiles.filter(
3324
+ (file) => file instanceof ToolSubagent
3325
+ );
3326
+ const rulesyncSubagents = [];
3327
+ for (const toolSubagent of toolSubagents) {
3328
+ if (toolSubagent instanceof SimulatedSubagent) {
3329
+ logger.debug(
3330
+ `Skipping simulated subagent conversion: ${toolSubagent.getRelativeFilePath()}`
3331
+ );
3332
+ continue;
3333
+ }
3334
+ rulesyncSubagents.push(toolSubagent.toRulesyncSubagent());
3335
+ }
3336
+ return rulesyncSubagents;
3337
+ }
3338
+ /**
3339
+ * Implementation of abstract method from Processor
3340
+ * Load and parse rulesync subagent files from .rulesync/subagents/ directory
3341
+ */
3342
+ async loadRulesyncFiles() {
3343
+ const subagentsDir = join33(this.baseDir, RulesyncSubagent.getSettablePaths().relativeDirPath);
3344
+ const dirExists = await directoryExists(subagentsDir);
3345
+ if (!dirExists) {
3346
+ logger.debug(`Rulesync subagents directory not found: ${subagentsDir}`);
3347
+ return [];
3348
+ }
3349
+ const entries = await listDirectoryFiles(subagentsDir);
3350
+ const mdFiles = entries.filter((file) => file.endsWith(".md"));
3351
+ if (mdFiles.length === 0) {
3352
+ logger.debug(`No markdown files found in rulesync subagents directory: ${subagentsDir}`);
3353
+ return [];
3354
+ }
3355
+ logger.info(`Found ${mdFiles.length} subagent files in ${subagentsDir}`);
3356
+ const rulesyncSubagents = [];
3357
+ for (const mdFile of mdFiles) {
3358
+ const filepath = join33(subagentsDir, mdFile);
3359
+ try {
3360
+ const rulesyncSubagent = await RulesyncSubagent.fromFile({
3361
+ relativeFilePath: mdFile,
3362
+ validate: true
3363
+ });
3364
+ rulesyncSubagents.push(rulesyncSubagent);
3365
+ logger.debug(`Successfully loaded subagent: ${mdFile}`);
3366
+ } catch (error) {
3367
+ logger.warn(`Failed to load subagent file ${filepath}:`, error);
3368
+ continue;
3369
+ }
3370
+ }
3371
+ if (rulesyncSubagents.length === 0) {
3372
+ logger.debug(`No valid subagents found in ${subagentsDir}`);
3373
+ return [];
3374
+ }
3375
+ logger.info(`Successfully loaded ${rulesyncSubagents.length} rulesync subagents`);
3376
+ return rulesyncSubagents;
3377
+ }
3378
+ /**
3379
+ * Implementation of abstract method from Processor
3380
+ * Load tool-specific subagent configurations and parse them into ToolSubagent instances
3381
+ */
3382
+ async loadToolFiles() {
3383
+ switch (this.toolTarget) {
3384
+ case "claudecode":
3385
+ return await this.loadClaudecodeSubagents();
3386
+ case "copilot":
3387
+ return await this.loadCopilotSubagents();
3388
+ case "cursor":
3389
+ return await this.loadCursorSubagents();
3390
+ case "codexcli":
3391
+ return await this.loadCodexCliSubagents();
3392
+ case "geminicli":
3393
+ return await this.loadGeminiCliSubagents();
3394
+ case "roo":
3395
+ return await this.loadRooSubagents();
3396
+ default:
3397
+ throw new Error(`Unsupported tool target: ${this.toolTarget}`);
3398
+ }
3399
+ }
3400
+ /**
3401
+ * Load Claude Code subagent configurations from .claude/agents/ directory
3402
+ */
3403
+ async loadClaudecodeSubagents() {
3404
+ return await this.loadToolSubagentsDefault({
3405
+ relativeDirPath: ClaudecodeSubagent.getSettablePaths().relativeDirPath,
3406
+ fromFile: (relativeFilePath) => ClaudecodeSubagent.fromFile({ relativeFilePath })
3407
+ });
3408
+ }
3409
+ /**
3410
+ * Load Copilot subagent configurations from .github/subagents/ directory
3411
+ */
3412
+ async loadCopilotSubagents() {
3413
+ return await this.loadToolSubagentsDefault({
3414
+ relativeDirPath: CopilotSubagent.getSettablePaths().relativeDirPath,
3415
+ fromFile: (relativeFilePath) => CopilotSubagent.fromFile({ relativeFilePath })
3416
+ });
3417
+ }
3418
+ /**
3419
+ * Load Cursor subagent configurations from .cursor/subagents/ directory
3420
+ */
3421
+ async loadCursorSubagents() {
3422
+ return await this.loadToolSubagentsDefault({
3423
+ relativeDirPath: CursorSubagent.getSettablePaths().relativeDirPath,
3424
+ fromFile: (relativeFilePath) => CursorSubagent.fromFile({ relativeFilePath })
3425
+ });
3426
+ }
3427
+ /**
3428
+ * Load CodexCli subagent configurations from .codex/subagents/ directory
3429
+ */
3430
+ async loadCodexCliSubagents() {
3431
+ return await this.loadToolSubagentsDefault({
3432
+ relativeDirPath: CodexCliSubagent.getSettablePaths().relativeDirPath,
3433
+ fromFile: (relativeFilePath) => CodexCliSubagent.fromFile({ relativeFilePath })
3434
+ });
3435
+ }
3436
+ /**
3437
+ * Load GeminiCli subagent configurations from .gemini/subagents/ directory
3438
+ */
3439
+ async loadGeminiCliSubagents() {
3440
+ return await this.loadToolSubagentsDefault({
3441
+ relativeDirPath: GeminiCliSubagent.getSettablePaths().relativeDirPath,
3442
+ fromFile: (relativeFilePath) => GeminiCliSubagent.fromFile({ relativeFilePath })
3443
+ });
3444
+ }
3445
+ /**
3446
+ * Load Roo subagent configurations from .roo/subagents/ directory
3447
+ */
3448
+ async loadRooSubagents() {
3449
+ return await this.loadToolSubagentsDefault({
3450
+ relativeDirPath: RooSubagent.getSettablePaths().relativeDirPath,
3451
+ fromFile: (relativeFilePath) => RooSubagent.fromFile({ relativeFilePath })
3452
+ });
3453
+ }
3454
+ async loadToolSubagentsDefault({
3455
+ relativeDirPath,
3456
+ fromFile
3457
+ }) {
3458
+ const paths = await findFilesByGlobs(join33(this.baseDir, relativeDirPath, "*.md"));
3459
+ const subagents = (await Promise.allSettled(paths.map((path2) => fromFile(basename13(path2))))).filter((r) => r.status === "fulfilled").map((r) => r.value);
3460
+ logger.info(`Successfully loaded ${subagents.length} ${relativeDirPath} subagents`);
3461
+ return subagents;
3462
+ }
3463
+ /**
3464
+ * Implementation of abstract method from FeatureProcessor
3465
+ * Return the tool targets that this processor supports
3466
+ */
3467
+ static getToolTargets({
3468
+ includeSimulated = false
3469
+ } = {}) {
3470
+ if (!includeSimulated) {
3471
+ return subagentsProcessorToolTargets.filter(
3472
+ (target) => !subagentsProcessorToolTargetsSimulated.includes(target)
3473
+ );
3474
+ }
3475
+ return subagentsProcessorToolTargets;
3476
+ }
3477
+ static getToolTargetsSimulated() {
3478
+ return subagentsProcessorToolTargetsSimulated;
3479
+ }
3480
+ };
3481
+
3482
+ // src/rules/agentsmd-rule.ts
3483
+ import { join as join35 } from "path";
3484
+
3485
+ // src/rules/rulesync-rule.ts
3486
+ import { basename as basename14, join as join34 } from "path";
3487
+ import { z as z16 } from "zod/mini";
3488
+ var RulesyncRuleFrontmatterSchema = z16.object({
3489
+ root: z16.optional(z16.optional(z16.boolean())),
3490
+ targets: z16.optional(RulesyncTargetsSchema),
3491
+ description: z16.optional(z16.string()),
3492
+ globs: z16.optional(z16.array(z16.string())),
3493
+ cursor: z16.optional(
3494
+ z16.object({
3495
+ alwaysApply: z16.optional(z16.boolean()),
3496
+ description: z16.optional(z16.string()),
3497
+ globs: z16.optional(z16.array(z16.string()))
3498
+ })
3499
+ )
3500
+ });
3501
+ var RulesyncRule = class _RulesyncRule extends RulesyncFile {
3502
+ frontmatter;
3503
+ body;
3504
+ constructor({ frontmatter, body, ...rest }) {
3505
+ if (rest.validate !== false) {
3506
+ const result = RulesyncRuleFrontmatterSchema.safeParse(frontmatter);
3507
+ if (!result.success) {
3508
+ throw result.error;
3509
+ }
3510
+ }
3511
+ super({
3512
+ ...rest,
3513
+ fileContent: stringifyFrontmatter(body, frontmatter)
3514
+ });
3515
+ this.frontmatter = frontmatter;
3516
+ this.body = body;
3517
+ }
3518
+ static getSettablePaths() {
3519
+ return {
3520
+ recommended: {
3521
+ relativeDirPath: ".rulesync/rules"
3522
+ },
3523
+ legacy: {
3524
+ relativeDirPath: ".rulesync"
3525
+ }
3526
+ };
3527
+ }
3528
+ getFrontmatter() {
3529
+ return this.frontmatter;
3530
+ }
3531
+ validate() {
3532
+ if (!this.frontmatter) {
3533
+ return { success: true, error: null };
3534
+ }
3535
+ const result = RulesyncRuleFrontmatterSchema.safeParse(this.frontmatter);
3536
+ if (result.success) {
3537
+ return { success: true, error: null };
3538
+ } else {
3539
+ return { success: false, error: result.error };
3540
+ }
3541
+ }
3542
+ static async fromFileLegacy({
3543
+ relativeFilePath,
3544
+ validate = true
3545
+ }) {
3546
+ const filePath = join34(this.getSettablePaths().legacy.relativeDirPath, relativeFilePath);
3547
+ const fileContent = await readFileContent(filePath);
3548
+ const { frontmatter, body: content } = parseFrontmatter(fileContent);
3549
+ const result = RulesyncRuleFrontmatterSchema.safeParse(frontmatter);
3550
+ if (!result.success) {
3551
+ throw new Error(`Invalid frontmatter in ${filePath}: ${result.error.message}`);
3552
+ }
3553
+ const validatedFrontmatter = {
3554
+ root: result.data.root ?? false,
3555
+ targets: result.data.targets ?? ["*"],
3556
+ description: result.data.description ?? "",
3557
+ globs: result.data.globs ?? [],
3558
+ cursor: result.data.cursor
3559
+ };
3560
+ const filename = basename14(filePath);
3561
+ return new _RulesyncRule({
3562
+ baseDir: ".",
3563
+ relativeDirPath: this.getSettablePaths().recommended.relativeDirPath,
3564
+ relativeFilePath: filename,
3565
+ frontmatter: validatedFrontmatter,
3566
+ body: content.trim(),
3567
+ validate
3568
+ });
3569
+ }
3570
+ static async fromFile({
3571
+ relativeFilePath,
3572
+ validate = true
3573
+ }) {
3574
+ const filePath = join34(this.getSettablePaths().recommended.relativeDirPath, relativeFilePath);
3575
+ const fileContent = await readFileContent(filePath);
3576
+ const { frontmatter, body: content } = parseFrontmatter(fileContent);
3577
+ const result = RulesyncRuleFrontmatterSchema.safeParse(frontmatter);
3578
+ if (!result.success) {
3579
+ throw new Error(`Invalid frontmatter in ${filePath}: ${result.error.message}`);
3580
+ }
3581
+ const validatedFrontmatter = {
3582
+ root: result.data.root ?? false,
3583
+ targets: result.data.targets ?? ["*"],
3584
+ description: result.data.description ?? "",
3585
+ globs: result.data.globs ?? [],
3586
+ cursor: result.data.cursor
3587
+ };
3588
+ const filename = basename14(filePath);
3589
+ return new _RulesyncRule({
3590
+ baseDir: ".",
3591
+ relativeDirPath: this.getSettablePaths().recommended.relativeDirPath,
3592
+ relativeFilePath: filename,
3593
+ frontmatter: validatedFrontmatter,
3594
+ body: content.trim(),
3595
+ validate
3596
+ });
3597
+ }
3598
+ getBody() {
3599
+ return this.body;
3600
+ }
3601
+ };
3602
+
3603
+ // src/rules/tool-rule.ts
3604
+ var ToolRule = class extends ToolFile {
3605
+ root;
3606
+ constructor({ root = false, ...rest }) {
3607
+ super(rest);
3608
+ this.root = root;
3609
+ }
3610
+ static async fromFile(_params) {
3611
+ throw new Error("Please implement this method in the subclass.");
3612
+ }
3613
+ static fromRulesyncRule(_params) {
3614
+ throw new Error("Please implement this method in the subclass.");
3615
+ }
3616
+ static buildToolRuleParamsDefault({
3617
+ baseDir = ".",
3618
+ rulesyncRule,
3619
+ validate = true,
3620
+ rootPath = { relativeDirPath: ".", relativeFilePath: "AGENTS.md" },
3621
+ nonRootPath = { relativeDirPath: ".agents/memories" }
3622
+ }) {
3623
+ const fileContent = rulesyncRule.getBody();
3624
+ return {
3625
+ baseDir,
3626
+ relativeDirPath: rulesyncRule.getFrontmatter().root ? rootPath.relativeDirPath : nonRootPath.relativeDirPath,
3627
+ relativeFilePath: rulesyncRule.getFrontmatter().root ? rootPath.relativeFilePath : rulesyncRule.getRelativeFilePath(),
3628
+ fileContent,
3629
+ validate,
3630
+ root: rulesyncRule.getFrontmatter().root ?? false
3631
+ };
3632
+ }
3633
+ toRulesyncRuleDefault() {
3634
+ return new RulesyncRule({
3635
+ baseDir: this.getBaseDir(),
3636
+ relativeDirPath: RULESYNC_RULES_DIR,
3637
+ relativeFilePath: this.getRelativeFilePath(),
3638
+ frontmatter: {
3639
+ root: this.isRoot(),
3640
+ targets: ["*"],
3641
+ description: "",
3642
+ globs: this.isRoot() ? ["**/*"] : []
3643
+ },
3644
+ body: this.getFileContent()
3645
+ });
3646
+ }
3647
+ isRoot() {
3648
+ return this.root;
3649
+ }
3650
+ static isTargetedByRulesyncRule(_rulesyncRule) {
3651
+ throw new Error("Please implement this method in the subclass.");
3652
+ }
3653
+ static isTargetedByRulesyncRuleDefault({
3654
+ rulesyncRule,
3655
+ toolTarget
3656
+ }) {
3657
+ const targets = rulesyncRule.getFrontmatter().targets;
3658
+ if (!targets) {
3659
+ return true;
3660
+ }
3661
+ if (targets.includes("*")) {
3662
+ return true;
3663
+ }
3664
+ if (targets.includes(toolTarget)) {
3165
3665
  return true;
3166
3666
  }
3167
3667
  return false;
@@ -3194,8 +3694,8 @@ var AgentsMdRule = class _AgentsMdRule extends ToolRule {
3194
3694
  validate = true
3195
3695
  }) {
3196
3696
  const isRoot = relativeFilePath === "AGENTS.md";
3197
- const relativePath = isRoot ? "AGENTS.md" : join32(".agents/memories", relativeFilePath);
3198
- const fileContent = await readFileContent(join32(baseDir, relativePath));
3697
+ const relativePath = isRoot ? "AGENTS.md" : join35(".agents/memories", relativeFilePath);
3698
+ const fileContent = await readFileContent(join35(baseDir, relativePath));
3199
3699
  return new _AgentsMdRule({
3200
3700
  baseDir,
3201
3701
  relativeDirPath: isRoot ? this.getSettablePaths().root.relativeDirPath : this.getSettablePaths().nonRoot.relativeDirPath,
@@ -3235,7 +3735,7 @@ var AgentsMdRule = class _AgentsMdRule extends ToolRule {
3235
3735
  };
3236
3736
 
3237
3737
  // src/rules/amazonqcli-rule.ts
3238
- import { join as join33 } from "path";
3738
+ import { join as join36 } from "path";
3239
3739
  var AmazonQCliRule = class _AmazonQCliRule extends ToolRule {
3240
3740
  static getSettablePaths() {
3241
3741
  return {
@@ -3250,7 +3750,7 @@ var AmazonQCliRule = class _AmazonQCliRule extends ToolRule {
3250
3750
  validate = true
3251
3751
  }) {
3252
3752
  const fileContent = await readFileContent(
3253
- join33(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
3753
+ join36(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
3254
3754
  );
3255
3755
  return new _AmazonQCliRule({
3256
3756
  baseDir,
@@ -3290,7 +3790,7 @@ var AmazonQCliRule = class _AmazonQCliRule extends ToolRule {
3290
3790
  };
3291
3791
 
3292
3792
  // src/rules/augmentcode-legacy-rule.ts
3293
- import { join as join34 } from "path";
3793
+ import { join as join37 } from "path";
3294
3794
  var AugmentcodeLegacyRule = class _AugmentcodeLegacyRule extends ToolRule {
3295
3795
  toRulesyncRule() {
3296
3796
  const rulesyncFrontmatter = {
@@ -3350,8 +3850,8 @@ var AugmentcodeLegacyRule = class _AugmentcodeLegacyRule extends ToolRule {
3350
3850
  }) {
3351
3851
  const settablePaths = this.getSettablePaths();
3352
3852
  const isRoot = relativeFilePath === settablePaths.root.relativeFilePath;
3353
- const relativePath = isRoot ? settablePaths.root.relativeFilePath : join34(settablePaths.nonRoot.relativeDirPath, relativeFilePath);
3354
- const fileContent = await readFileContent(join34(baseDir, relativePath));
3853
+ const relativePath = isRoot ? settablePaths.root.relativeFilePath : join37(settablePaths.nonRoot.relativeDirPath, relativeFilePath);
3854
+ const fileContent = await readFileContent(join37(baseDir, relativePath));
3355
3855
  return new _AugmentcodeLegacyRule({
3356
3856
  baseDir,
3357
3857
  relativeDirPath: isRoot ? settablePaths.root.relativeDirPath : settablePaths.nonRoot.relativeDirPath,
@@ -3364,7 +3864,7 @@ var AugmentcodeLegacyRule = class _AugmentcodeLegacyRule extends ToolRule {
3364
3864
  };
3365
3865
 
3366
3866
  // src/rules/augmentcode-rule.ts
3367
- import { join as join35 } from "path";
3867
+ import { join as join38 } from "path";
3368
3868
  var AugmentcodeRule = class _AugmentcodeRule extends ToolRule {
3369
3869
  toRulesyncRule() {
3370
3870
  return this.toRulesyncRuleDefault();
@@ -3396,7 +3896,7 @@ var AugmentcodeRule = class _AugmentcodeRule extends ToolRule {
3396
3896
  validate = true
3397
3897
  }) {
3398
3898
  const fileContent = await readFileContent(
3399
- join35(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
3899
+ join38(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
3400
3900
  );
3401
3901
  const { body: content } = parseFrontmatter(fileContent);
3402
3902
  return new _AugmentcodeRule({
@@ -3419,7 +3919,7 @@ var AugmentcodeRule = class _AugmentcodeRule extends ToolRule {
3419
3919
  };
3420
3920
 
3421
3921
  // src/rules/claudecode-rule.ts
3422
- import { join as join36 } from "path";
3922
+ import { join as join39 } from "path";
3423
3923
  var ClaudecodeRule = class _ClaudecodeRule extends ToolRule {
3424
3924
  static getSettablePaths() {
3425
3925
  return {
@@ -3438,8 +3938,8 @@ var ClaudecodeRule = class _ClaudecodeRule extends ToolRule {
3438
3938
  validate = true
3439
3939
  }) {
3440
3940
  const isRoot = relativeFilePath === this.getSettablePaths().root.relativeFilePath;
3441
- const relativePath = isRoot ? this.getSettablePaths().root.relativeFilePath : join36(this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath);
3442
- const fileContent = await readFileContent(join36(baseDir, relativePath));
3941
+ const relativePath = isRoot ? this.getSettablePaths().root.relativeFilePath : join39(this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath);
3942
+ const fileContent = await readFileContent(join39(baseDir, relativePath));
3443
3943
  return new _ClaudecodeRule({
3444
3944
  baseDir,
3445
3945
  relativeDirPath: isRoot ? this.getSettablePaths().root.relativeDirPath : this.getSettablePaths().nonRoot.relativeDirPath,
@@ -3479,10 +3979,10 @@ var ClaudecodeRule = class _ClaudecodeRule extends ToolRule {
3479
3979
  };
3480
3980
 
3481
3981
  // src/rules/cline-rule.ts
3482
- import { join as join37 } from "path";
3483
- import { z as z14 } from "zod/mini";
3484
- var ClineRuleFrontmatterSchema = z14.object({
3485
- description: z14.string()
3982
+ import { join as join40 } from "path";
3983
+ import { z as z17 } from "zod/mini";
3984
+ var ClineRuleFrontmatterSchema = z17.object({
3985
+ description: z17.string()
3486
3986
  });
3487
3987
  var ClineRule = class _ClineRule extends ToolRule {
3488
3988
  static getSettablePaths() {
@@ -3524,7 +4024,7 @@ var ClineRule = class _ClineRule extends ToolRule {
3524
4024
  validate = true
3525
4025
  }) {
3526
4026
  const fileContent = await readFileContent(
3527
- join37(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
4027
+ join40(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
3528
4028
  );
3529
4029
  return new _ClineRule({
3530
4030
  baseDir,
@@ -3537,7 +4037,7 @@ var ClineRule = class _ClineRule extends ToolRule {
3537
4037
  };
3538
4038
 
3539
4039
  // src/rules/codexcli-rule.ts
3540
- import { join as join38 } from "path";
4040
+ import { join as join41 } from "path";
3541
4041
  var CodexcliRule = class _CodexcliRule extends ToolRule {
3542
4042
  static getSettablePaths() {
3543
4043
  return {
@@ -3556,8 +4056,8 @@ var CodexcliRule = class _CodexcliRule extends ToolRule {
3556
4056
  validate = true
3557
4057
  }) {
3558
4058
  const isRoot = relativeFilePath === "AGENTS.md";
3559
- const relativePath = isRoot ? "AGENTS.md" : join38(this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath);
3560
- const fileContent = await readFileContent(join38(baseDir, relativePath));
4059
+ const relativePath = isRoot ? "AGENTS.md" : join41(this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath);
4060
+ const fileContent = await readFileContent(join41(baseDir, relativePath));
3561
4061
  return new _CodexcliRule({
3562
4062
  baseDir,
3563
4063
  relativeDirPath: isRoot ? this.getSettablePaths().root.relativeDirPath : this.getSettablePaths().nonRoot.relativeDirPath,
@@ -3597,11 +4097,11 @@ var CodexcliRule = class _CodexcliRule extends ToolRule {
3597
4097
  };
3598
4098
 
3599
4099
  // src/rules/copilot-rule.ts
3600
- import { join as join39 } from "path";
3601
- import { z as z15 } from "zod/mini";
3602
- var CopilotRuleFrontmatterSchema = z15.object({
3603
- description: z15.optional(z15.string()),
3604
- applyTo: z15.optional(z15.string())
4100
+ import { join as join42 } from "path";
4101
+ import { z as z18 } from "zod/mini";
4102
+ var CopilotRuleFrontmatterSchema = z18.object({
4103
+ description: z18.optional(z18.string()),
4104
+ applyTo: z18.optional(z18.string())
3605
4105
  });
3606
4106
  var CopilotRule = class _CopilotRule extends ToolRule {
3607
4107
  frontmatter;
@@ -3689,11 +4189,11 @@ var CopilotRule = class _CopilotRule extends ToolRule {
3689
4189
  validate = true
3690
4190
  }) {
3691
4191
  const isRoot = relativeFilePath === "copilot-instructions.md";
3692
- const relativePath = isRoot ? join39(
4192
+ const relativePath = isRoot ? join42(
3693
4193
  this.getSettablePaths().root.relativeDirPath,
3694
4194
  this.getSettablePaths().root.relativeFilePath
3695
- ) : join39(this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath);
3696
- const fileContent = await readFileContent(join39(baseDir, relativePath));
4195
+ ) : join42(this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath);
4196
+ const fileContent = await readFileContent(join42(baseDir, relativePath));
3697
4197
  if (isRoot) {
3698
4198
  return new _CopilotRule({
3699
4199
  baseDir,
@@ -3712,7 +4212,7 @@ var CopilotRule = class _CopilotRule extends ToolRule {
3712
4212
  const result = CopilotRuleFrontmatterSchema.safeParse(frontmatter);
3713
4213
  if (!result.success) {
3714
4214
  throw new Error(
3715
- `Invalid frontmatter in ${join39(baseDir, relativeFilePath)}: ${result.error.message}`
4215
+ `Invalid frontmatter in ${join42(baseDir, relativeFilePath)}: ${result.error.message}`
3716
4216
  );
3717
4217
  }
3718
4218
  return new _CopilotRule({
@@ -3751,12 +4251,12 @@ var CopilotRule = class _CopilotRule extends ToolRule {
3751
4251
  };
3752
4252
 
3753
4253
  // src/rules/cursor-rule.ts
3754
- import { basename as basename13, join as join40 } from "path";
3755
- import { z as z16 } from "zod/mini";
3756
- var CursorRuleFrontmatterSchema = z16.object({
3757
- description: z16.optional(z16.string()),
3758
- globs: z16.optional(z16.string()),
3759
- alwaysApply: z16.optional(z16.boolean())
4254
+ import { basename as basename15, join as join43 } from "path";
4255
+ import { z as z19 } from "zod/mini";
4256
+ var CursorRuleFrontmatterSchema = z19.object({
4257
+ description: z19.optional(z19.string()),
4258
+ globs: z19.optional(z19.string()),
4259
+ alwaysApply: z19.optional(z19.boolean())
3760
4260
  });
3761
4261
  var CursorRule = class _CursorRule extends ToolRule {
3762
4262
  frontmatter;
@@ -3881,19 +4381,19 @@ var CursorRule = class _CursorRule extends ToolRule {
3881
4381
  validate = true
3882
4382
  }) {
3883
4383
  const fileContent = await readFileContent(
3884
- join40(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
4384
+ join43(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
3885
4385
  );
3886
4386
  const { frontmatter, body: content } = _CursorRule.parseCursorFrontmatter(fileContent);
3887
4387
  const result = CursorRuleFrontmatterSchema.safeParse(frontmatter);
3888
4388
  if (!result.success) {
3889
4389
  throw new Error(
3890
- `Invalid frontmatter in ${join40(baseDir, relativeFilePath)}: ${result.error.message}`
4390
+ `Invalid frontmatter in ${join43(baseDir, relativeFilePath)}: ${result.error.message}`
3891
4391
  );
3892
4392
  }
3893
4393
  return new _CursorRule({
3894
4394
  baseDir,
3895
4395
  relativeDirPath: this.getSettablePaths().nonRoot.relativeDirPath,
3896
- relativeFilePath: basename13(relativeFilePath),
4396
+ relativeFilePath: basename15(relativeFilePath),
3897
4397
  frontmatter: result.data,
3898
4398
  body: content.trim(),
3899
4399
  validate
@@ -3925,7 +4425,7 @@ var CursorRule = class _CursorRule extends ToolRule {
3925
4425
  };
3926
4426
 
3927
4427
  // src/rules/geminicli-rule.ts
3928
- import { join as join41 } from "path";
4428
+ import { join as join44 } from "path";
3929
4429
  var GeminiCliRule = class _GeminiCliRule extends ToolRule {
3930
4430
  static getSettablePaths() {
3931
4431
  return {
@@ -3944,8 +4444,8 @@ var GeminiCliRule = class _GeminiCliRule extends ToolRule {
3944
4444
  validate = true
3945
4445
  }) {
3946
4446
  const isRoot = relativeFilePath === "GEMINI.md";
3947
- const relativePath = isRoot ? "GEMINI.md" : join41(".gemini/memories", relativeFilePath);
3948
- const fileContent = await readFileContent(join41(baseDir, relativePath));
4447
+ const relativePath = isRoot ? "GEMINI.md" : join44(".gemini/memories", relativeFilePath);
4448
+ const fileContent = await readFileContent(join44(baseDir, relativePath));
3949
4449
  return new _GeminiCliRule({
3950
4450
  baseDir,
3951
4451
  relativeDirPath: isRoot ? this.getSettablePaths().root.relativeDirPath : this.getSettablePaths().nonRoot.relativeDirPath,
@@ -3985,7 +4485,7 @@ var GeminiCliRule = class _GeminiCliRule extends ToolRule {
3985
4485
  };
3986
4486
 
3987
4487
  // src/rules/junie-rule.ts
3988
- import { join as join42 } from "path";
4488
+ import { join as join45 } from "path";
3989
4489
  var JunieRule = class _JunieRule extends ToolRule {
3990
4490
  static getSettablePaths() {
3991
4491
  return {
@@ -4004,8 +4504,8 @@ var JunieRule = class _JunieRule extends ToolRule {
4004
4504
  validate = true
4005
4505
  }) {
4006
4506
  const isRoot = relativeFilePath === "guidelines.md";
4007
- const relativePath = isRoot ? "guidelines.md" : join42(".junie/memories", relativeFilePath);
4008
- const fileContent = await readFileContent(join42(baseDir, relativePath));
4507
+ const relativePath = isRoot ? "guidelines.md" : join45(".junie/memories", relativeFilePath);
4508
+ const fileContent = await readFileContent(join45(baseDir, relativePath));
4009
4509
  return new _JunieRule({
4010
4510
  baseDir,
4011
4511
  relativeDirPath: isRoot ? this.getSettablePaths().root.relativeDirPath : this.getSettablePaths().nonRoot.relativeDirPath,
@@ -4045,7 +4545,7 @@ var JunieRule = class _JunieRule extends ToolRule {
4045
4545
  };
4046
4546
 
4047
4547
  // src/rules/kiro-rule.ts
4048
- import { join as join43 } from "path";
4548
+ import { join as join46 } from "path";
4049
4549
  var KiroRule = class _KiroRule extends ToolRule {
4050
4550
  static getSettablePaths() {
4051
4551
  return {
@@ -4060,7 +4560,7 @@ var KiroRule = class _KiroRule extends ToolRule {
4060
4560
  validate = true
4061
4561
  }) {
4062
4562
  const fileContent = await readFileContent(
4063
- join43(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
4563
+ join46(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
4064
4564
  );
4065
4565
  return new _KiroRule({
4066
4566
  baseDir,
@@ -4100,7 +4600,7 @@ var KiroRule = class _KiroRule extends ToolRule {
4100
4600
  };
4101
4601
 
4102
4602
  // src/rules/opencode-rule.ts
4103
- import { join as join44 } from "path";
4603
+ import { join as join47 } from "path";
4104
4604
  var OpenCodeRule = class _OpenCodeRule extends ToolRule {
4105
4605
  static getSettablePaths() {
4106
4606
  return {
@@ -4119,8 +4619,8 @@ var OpenCodeRule = class _OpenCodeRule extends ToolRule {
4119
4619
  validate = true
4120
4620
  }) {
4121
4621
  const isRoot = relativeFilePath === "AGENTS.md";
4122
- const relativePath = isRoot ? "AGENTS.md" : join44(".opencode/memories", relativeFilePath);
4123
- const fileContent = await readFileContent(join44(baseDir, relativePath));
4622
+ const relativePath = isRoot ? "AGENTS.md" : join47(".opencode/memories", relativeFilePath);
4623
+ const fileContent = await readFileContent(join47(baseDir, relativePath));
4124
4624
  return new _OpenCodeRule({
4125
4625
  baseDir,
4126
4626
  relativeDirPath: isRoot ? this.getSettablePaths().root.relativeDirPath : this.getSettablePaths().nonRoot.relativeDirPath,
@@ -4160,7 +4660,7 @@ var OpenCodeRule = class _OpenCodeRule extends ToolRule {
4160
4660
  };
4161
4661
 
4162
4662
  // src/rules/qwencode-rule.ts
4163
- import { join as join45 } from "path";
4663
+ import { join as join48 } from "path";
4164
4664
  var QwencodeRule = class _QwencodeRule extends ToolRule {
4165
4665
  static getSettablePaths() {
4166
4666
  return {
@@ -4179,8 +4679,8 @@ var QwencodeRule = class _QwencodeRule extends ToolRule {
4179
4679
  validate = true
4180
4680
  }) {
4181
4681
  const isRoot = relativeFilePath === "QWEN.md";
4182
- const relativePath = isRoot ? "QWEN.md" : join45(".qwen/memories", relativeFilePath);
4183
- const fileContent = await readFileContent(join45(baseDir, relativePath));
4682
+ const relativePath = isRoot ? "QWEN.md" : join48(".qwen/memories", relativeFilePath);
4683
+ const fileContent = await readFileContent(join48(baseDir, relativePath));
4184
4684
  return new _QwencodeRule({
4185
4685
  baseDir,
4186
4686
  relativeDirPath: isRoot ? this.getSettablePaths().root.relativeDirPath : this.getSettablePaths().nonRoot.relativeDirPath,
@@ -4217,7 +4717,7 @@ var QwencodeRule = class _QwencodeRule extends ToolRule {
4217
4717
  };
4218
4718
 
4219
4719
  // src/rules/roo-rule.ts
4220
- import { join as join46 } from "path";
4720
+ import { join as join49 } from "path";
4221
4721
  var RooRule = class _RooRule extends ToolRule {
4222
4722
  static getSettablePaths() {
4223
4723
  return {
@@ -4232,7 +4732,7 @@ var RooRule = class _RooRule extends ToolRule {
4232
4732
  validate = true
4233
4733
  }) {
4234
4734
  const fileContent = await readFileContent(
4235
- join46(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
4735
+ join49(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
4236
4736
  );
4237
4737
  return new _RooRule({
4238
4738
  baseDir,
@@ -4287,7 +4787,7 @@ var RooRule = class _RooRule extends ToolRule {
4287
4787
  };
4288
4788
 
4289
4789
  // src/rules/warp-rule.ts
4290
- import { join as join47 } from "path";
4790
+ import { join as join50 } from "path";
4291
4791
  var WarpRule = class _WarpRule extends ToolRule {
4292
4792
  constructor({ fileContent, root, ...rest }) {
4293
4793
  super({
@@ -4313,8 +4813,8 @@ var WarpRule = class _WarpRule extends ToolRule {
4313
4813
  validate = true
4314
4814
  }) {
4315
4815
  const isRoot = relativeFilePath === this.getSettablePaths().root.relativeFilePath;
4316
- const relativePath = isRoot ? this.getSettablePaths().root.relativeFilePath : join47(this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath);
4317
- const fileContent = await readFileContent(join47(baseDir, relativePath));
4816
+ const relativePath = isRoot ? this.getSettablePaths().root.relativeFilePath : join50(this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath);
4817
+ const fileContent = await readFileContent(join50(baseDir, relativePath));
4318
4818
  return new _WarpRule({
4319
4819
  baseDir,
4320
4820
  relativeDirPath: isRoot ? this.getSettablePaths().root.relativeDirPath : ".warp",
@@ -4354,7 +4854,7 @@ var WarpRule = class _WarpRule extends ToolRule {
4354
4854
  };
4355
4855
 
4356
4856
  // src/rules/windsurf-rule.ts
4357
- import { join as join48 } from "path";
4857
+ import { join as join51 } from "path";
4358
4858
  var WindsurfRule = class _WindsurfRule extends ToolRule {
4359
4859
  static getSettablePaths() {
4360
4860
  return {
@@ -4369,7 +4869,7 @@ var WindsurfRule = class _WindsurfRule extends ToolRule {
4369
4869
  validate = true
4370
4870
  }) {
4371
4871
  const fileContent = await readFileContent(
4372
- join48(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
4872
+ join51(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
4373
4873
  );
4374
4874
  return new _WindsurfRule({
4375
4875
  baseDir,
@@ -4427,7 +4927,7 @@ var rulesProcessorToolTargets = [
4427
4927
  "warp",
4428
4928
  "windsurf"
4429
4929
  ];
4430
- var RulesProcessorToolTargetSchema = z17.enum(rulesProcessorToolTargets);
4930
+ var RulesProcessorToolTargetSchema = z20.enum(rulesProcessorToolTargets);
4431
4931
  var RulesProcessor = class extends FeatureProcessor {
4432
4932
  toolTarget;
4433
4933
  simulateCommands;
@@ -4606,7 +5106,8 @@ var RulesProcessor = class extends FeatureProcessor {
4606
5106
  throw new Error(`Unsupported tool target: ${this.toolTarget}`);
4607
5107
  }
4608
5108
  }).filter((rule) => rule !== null);
4609
- if (this.toolTarget === "cursor" && (this.simulateCommands || this.simulateSubagents)) {
5109
+ const isSimulated = this.simulateCommands || this.simulateSubagents;
5110
+ if (isSimulated && this.toolTarget === "cursor") {
4610
5111
  toolRules.push(
4611
5112
  new CursorRule({
4612
5113
  baseDir: this.baseDir,
@@ -4625,6 +5126,22 @@ var RulesProcessor = class extends FeatureProcessor {
4625
5126
  })
4626
5127
  );
4627
5128
  }
5129
+ if (isSimulated && this.toolTarget === "roo") {
5130
+ toolRules.push(
5131
+ new RooRule({
5132
+ baseDir: this.baseDir,
5133
+ relativeDirPath: RooRule.getSettablePaths().nonRoot.relativeDirPath,
5134
+ relativeFilePath: "additional-conventions.md",
5135
+ fileContent: this.generateAdditionalConventionsSection({
5136
+ commands: { relativeDirPath: RooCommand.getSettablePaths().relativeDirPath },
5137
+ subagents: {
5138
+ relativeDirPath: RooSubagent.getSettablePaths().relativeDirPath
5139
+ }
5140
+ }),
5141
+ validate: true
5142
+ })
5143
+ );
5144
+ }
4628
5145
  const rootRuleIndex = toolRules.findIndex((rule) => rule.isRoot());
4629
5146
  if (rootRuleIndex === -1) {
4630
5147
  return toolRules;
@@ -4678,7 +5195,12 @@ var RulesProcessor = class extends FeatureProcessor {
4678
5195
  case "geminicli": {
4679
5196
  const rootRule = toolRules[rootRuleIndex];
4680
5197
  rootRule?.setFileContent(
4681
- this.generateXmlReferencesSection(toolRules) + rootRule.getFileContent()
5198
+ this.generateXmlReferencesSection(toolRules) + this.generateAdditionalConventionsSection({
5199
+ commands: { relativeDirPath: GeminiCliCommand.getSettablePaths().relativeDirPath },
5200
+ subagents: {
5201
+ relativeDirPath: GeminiCliSubagent.getSettablePaths().relativeDirPath
5202
+ }
5203
+ }) + rootRule.getFileContent()
4682
5204
  );
4683
5205
  return toolRules;
4684
5206
  }
@@ -4726,17 +5248,17 @@ var RulesProcessor = class extends FeatureProcessor {
4726
5248
  * Load and parse rulesync rule files from .rulesync/rules/ directory
4727
5249
  */
4728
5250
  async loadRulesyncFiles() {
4729
- const files = await findFilesByGlobs(join49(RULESYNC_RULES_DIR, "*.md"));
5251
+ const files = await findFilesByGlobs(join52(RULESYNC_RULES_DIR, "*.md"));
4730
5252
  logger.debug(`Found ${files.length} rulesync files`);
4731
5253
  return Promise.all(
4732
- files.map((file) => RulesyncRule.fromFile({ relativeFilePath: basename14(file) }))
5254
+ files.map((file) => RulesyncRule.fromFile({ relativeFilePath: basename16(file) }))
4733
5255
  );
4734
5256
  }
4735
5257
  async loadRulesyncFilesLegacy() {
4736
- const legacyFiles = await findFilesByGlobs(join49(RULESYNC_RULES_DIR_LEGACY, "*.md"));
5258
+ const legacyFiles = await findFilesByGlobs(join52(RULESYNC_RULES_DIR_LEGACY, "*.md"));
4737
5259
  logger.debug(`Found ${legacyFiles.length} legacy rulesync files`);
4738
5260
  return Promise.all(
4739
- legacyFiles.map((file) => RulesyncRule.fromFileLegacy({ relativeFilePath: basename14(file) }))
5261
+ legacyFiles.map((file) => RulesyncRule.fromFileLegacy({ relativeFilePath: basename16(file) }))
4740
5262
  );
4741
5263
  }
4742
5264
  /**
@@ -4797,803 +5319,405 @@ var RulesProcessor = class extends FeatureProcessor {
4797
5319
  return [];
4798
5320
  }
4799
5321
  const rootFilePaths = await findFilesByGlobs(
4800
- join49(this.baseDir, root.relativeDirPath ?? ".", root.relativeFilePath)
5322
+ join52(this.baseDir, root.relativeDirPath ?? ".", root.relativeFilePath)
4801
5323
  );
4802
5324
  return await Promise.all(
4803
5325
  rootFilePaths.map(
4804
5326
  (filePath) => root.fromFile({
4805
5327
  baseDir: this.baseDir,
4806
- relativeFilePath: basename14(filePath)
4807
- })
4808
- )
4809
- );
4810
- })();
4811
- logger.debug(`Found ${rootToolRules.length} root tool rule files`);
4812
- const nonRootToolRules = await (async () => {
4813
- if (!nonRoot) {
4814
- return [];
4815
- }
4816
- const nonRootFilePaths = await findFilesByGlobs(
4817
- join49(this.baseDir, nonRoot.relativeDirPath, `*.${nonRoot.extension}`)
4818
- );
4819
- return await Promise.all(
4820
- nonRootFilePaths.map(
4821
- (filePath) => nonRoot.fromFile({
4822
- baseDir: this.baseDir,
4823
- relativeFilePath: basename14(filePath)
5328
+ relativeFilePath: basename16(filePath)
4824
5329
  })
4825
5330
  )
4826
5331
  );
4827
- })();
4828
- logger.debug(`Found ${nonRootToolRules.length} non-root tool rule files`);
4829
- return [...rootToolRules, ...nonRootToolRules];
4830
- }
4831
- /**
4832
- * Load AGENTS.md rule configuration
4833
- */
4834
- async loadAgentsmdRules() {
4835
- const settablePaths = AgentsMdRule.getSettablePaths();
4836
- return await this.loadToolRulesDefault({
4837
- root: {
4838
- relativeDirPath: settablePaths.root.relativeDirPath,
4839
- relativeFilePath: settablePaths.root.relativeFilePath,
4840
- fromFile: (params) => AgentsMdRule.fromFile(params)
4841
- },
4842
- nonRoot: {
4843
- relativeDirPath: settablePaths.nonRoot.relativeDirPath,
4844
- fromFile: (params) => AgentsMdRule.fromFile(params),
4845
- extension: "md"
4846
- }
4847
- });
4848
- }
4849
- async loadWarpRules() {
4850
- const settablePaths = WarpRule.getSettablePaths();
4851
- return await this.loadToolRulesDefault({
4852
- root: {
4853
- relativeDirPath: settablePaths.root.relativeDirPath,
4854
- relativeFilePath: settablePaths.root.relativeFilePath,
4855
- fromFile: (params) => WarpRule.fromFile(params)
4856
- },
4857
- nonRoot: {
4858
- relativeDirPath: settablePaths.nonRoot.relativeDirPath,
4859
- fromFile: (params) => WarpRule.fromFile(params),
4860
- extension: "md"
4861
- }
4862
- });
4863
- }
4864
- /**
4865
- * Load Amazon Q Developer CLI rule configurations from .amazonq/rules/ directory
4866
- */
4867
- async loadAmazonqcliRules() {
4868
- const settablePaths = AmazonQCliRule.getSettablePaths();
4869
- return await this.loadToolRulesDefault({
4870
- nonRoot: {
4871
- relativeDirPath: settablePaths.nonRoot.relativeDirPath,
4872
- fromFile: (params) => AmazonQCliRule.fromFile(params),
4873
- extension: "md"
4874
- }
4875
- });
4876
- }
4877
- /**
4878
- * Load AugmentCode rule configurations from .augment/rules/ directory
4879
- */
4880
- async loadAugmentcodeRules() {
4881
- const settablePaths = AugmentcodeRule.getSettablePaths();
4882
- return await this.loadToolRulesDefault({
4883
- nonRoot: {
4884
- relativeDirPath: settablePaths.nonRoot.relativeDirPath,
4885
- fromFile: (params) => AugmentcodeRule.fromFile(params),
4886
- extension: "md"
4887
- }
4888
- });
4889
- }
4890
- /**
4891
- * Load AugmentCode legacy rule configuration from .augment-guidelines file and .augment/rules/ directory
4892
- */
4893
- async loadAugmentcodeLegacyRules() {
4894
- const settablePaths = AugmentcodeLegacyRule.getSettablePaths();
4895
- return await this.loadToolRulesDefault({
4896
- root: {
4897
- relativeDirPath: settablePaths.root.relativeDirPath,
4898
- relativeFilePath: settablePaths.root.relativeFilePath,
4899
- fromFile: (params) => AugmentcodeLegacyRule.fromFile(params)
4900
- },
4901
- nonRoot: {
4902
- relativeDirPath: settablePaths.nonRoot.relativeDirPath,
4903
- fromFile: (params) => AugmentcodeLegacyRule.fromFile(params),
4904
- extension: "md"
4905
- }
4906
- });
4907
- }
4908
- /**
4909
- * Load Claude Code rule configuration from CLAUDE.md file
4910
- */
4911
- async loadClaudecodeRules() {
4912
- const settablePaths = ClaudecodeRule.getSettablePaths();
4913
- return await this.loadToolRulesDefault({
4914
- root: {
4915
- relativeDirPath: settablePaths.root.relativeDirPath,
4916
- relativeFilePath: settablePaths.root.relativeFilePath,
4917
- fromFile: (params) => ClaudecodeRule.fromFile(params)
4918
- },
4919
- nonRoot: {
4920
- relativeDirPath: settablePaths.nonRoot.relativeDirPath,
4921
- fromFile: (params) => ClaudecodeRule.fromFile(params),
4922
- extension: "md"
4923
- }
4924
- });
4925
- }
4926
- /**
4927
- * Load Cline rule configurations from .clinerules/ directory
4928
- */
4929
- async loadClineRules() {
4930
- const settablePaths = ClineRule.getSettablePaths();
4931
- return await this.loadToolRulesDefault({
4932
- nonRoot: {
4933
- relativeDirPath: settablePaths.nonRoot.relativeDirPath,
4934
- fromFile: (params) => ClineRule.fromFile(params),
4935
- extension: "md"
4936
- }
4937
- });
4938
- }
4939
- /**
4940
- * Load OpenAI Codex CLI rule configuration from AGENTS.md and .codex/memories/*.md files
4941
- */
4942
- async loadCodexcliRules() {
4943
- const settablePaths = CodexcliRule.getSettablePaths();
4944
- return await this.loadToolRulesDefault({
4945
- root: {
4946
- relativeDirPath: settablePaths.root.relativeDirPath,
4947
- relativeFilePath: settablePaths.root.relativeFilePath,
4948
- fromFile: (params) => CodexcliRule.fromFile(params)
4949
- },
4950
- nonRoot: {
4951
- relativeDirPath: settablePaths.nonRoot.relativeDirPath,
4952
- fromFile: (params) => CodexcliRule.fromFile(params),
4953
- extension: "md"
4954
- }
4955
- });
4956
- }
4957
- /**
4958
- * Load GitHub Copilot rule configuration from .github/copilot-instructions.md file
4959
- */
4960
- async loadCopilotRules() {
4961
- const settablePaths = CopilotRule.getSettablePaths();
4962
- return await this.loadToolRulesDefault({
4963
- root: {
4964
- relativeDirPath: settablePaths.root.relativeDirPath,
4965
- relativeFilePath: settablePaths.root.relativeFilePath,
4966
- fromFile: (params) => CopilotRule.fromFile(params)
4967
- },
4968
- nonRoot: {
4969
- relativeDirPath: settablePaths.nonRoot.relativeDirPath,
4970
- fromFile: (params) => CopilotRule.fromFile(params),
4971
- extension: "md"
4972
- }
4973
- });
4974
- }
4975
- /**
4976
- * Load Cursor rule configurations from .cursor/rules/ directory
4977
- */
4978
- async loadCursorRules() {
4979
- const settablePaths = CursorRule.getSettablePaths();
4980
- return await this.loadToolRulesDefault({
4981
- nonRoot: {
4982
- relativeDirPath: settablePaths.nonRoot.relativeDirPath,
4983
- fromFile: (params) => CursorRule.fromFile(params),
4984
- extension: "mdc"
4985
- }
4986
- });
4987
- }
4988
- /**
4989
- * Load Gemini CLI rule configuration from GEMINI.md file
4990
- */
4991
- async loadGeminicliRules() {
4992
- const settablePaths = GeminiCliRule.getSettablePaths();
4993
- return await this.loadToolRulesDefault({
4994
- root: {
4995
- relativeDirPath: settablePaths.root.relativeDirPath,
4996
- relativeFilePath: settablePaths.root.relativeFilePath,
4997
- fromFile: (params) => GeminiCliRule.fromFile(params)
4998
- },
4999
- nonRoot: {
5000
- relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5001
- fromFile: (params) => GeminiCliRule.fromFile(params),
5002
- extension: "md"
5003
- }
5004
- });
5005
- }
5006
- /**
5007
- * Load JetBrains Junie rule configuration from .junie/guidelines.md file
5008
- */
5009
- async loadJunieRules() {
5010
- const settablePaths = JunieRule.getSettablePaths();
5011
- return await this.loadToolRulesDefault({
5012
- root: {
5013
- relativeDirPath: settablePaths.root.relativeDirPath,
5014
- relativeFilePath: settablePaths.root.relativeFilePath,
5015
- fromFile: (params) => JunieRule.fromFile(params)
5016
- },
5017
- nonRoot: {
5018
- relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5019
- fromFile: (params) => JunieRule.fromFile(params),
5020
- extension: "md"
5021
- }
5022
- });
5023
- }
5024
- /**
5025
- * Load Kiro rule configurations from .kiro/steering/ directory
5026
- */
5027
- async loadKiroRules() {
5028
- const settablePaths = KiroRule.getSettablePaths();
5029
- return await this.loadToolRulesDefault({
5030
- nonRoot: {
5031
- relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5032
- fromFile: (params) => KiroRule.fromFile(params),
5033
- extension: "md"
5332
+ })();
5333
+ logger.debug(`Found ${rootToolRules.length} root tool rule files`);
5334
+ const nonRootToolRules = await (async () => {
5335
+ if (!nonRoot) {
5336
+ return [];
5034
5337
  }
5035
- });
5338
+ const nonRootFilePaths = await findFilesByGlobs(
5339
+ join52(this.baseDir, nonRoot.relativeDirPath, `*.${nonRoot.extension}`)
5340
+ );
5341
+ return await Promise.all(
5342
+ nonRootFilePaths.map(
5343
+ (filePath) => nonRoot.fromFile({
5344
+ baseDir: this.baseDir,
5345
+ relativeFilePath: basename16(filePath)
5346
+ })
5347
+ )
5348
+ );
5349
+ })();
5350
+ logger.debug(`Found ${nonRootToolRules.length} non-root tool rule files`);
5351
+ return [...rootToolRules, ...nonRootToolRules];
5036
5352
  }
5037
5353
  /**
5038
- * Load OpenCode rule configuration from AGENTS.md file and .opencode/memories/*.md files
5354
+ * Load AGENTS.md rule configuration
5039
5355
  */
5040
- async loadOpencodeRules() {
5041
- const settablePaths = OpenCodeRule.getSettablePaths();
5356
+ async loadAgentsmdRules() {
5357
+ const settablePaths = AgentsMdRule.getSettablePaths();
5042
5358
  return await this.loadToolRulesDefault({
5043
5359
  root: {
5044
5360
  relativeDirPath: settablePaths.root.relativeDirPath,
5045
5361
  relativeFilePath: settablePaths.root.relativeFilePath,
5046
- fromFile: (params) => OpenCodeRule.fromFile(params)
5362
+ fromFile: (params) => AgentsMdRule.fromFile(params)
5047
5363
  },
5048
5364
  nonRoot: {
5049
5365
  relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5050
- fromFile: (params) => OpenCodeRule.fromFile(params),
5366
+ fromFile: (params) => AgentsMdRule.fromFile(params),
5051
5367
  extension: "md"
5052
5368
  }
5053
5369
  });
5054
5370
  }
5055
- /**
5056
- * Load Qwen Code rule configuration from QWEN.md file and .qwen/memories/*.md files
5057
- */
5058
- async loadQwencodeRules() {
5059
- const settablePaths = QwencodeRule.getSettablePaths();
5371
+ async loadWarpRules() {
5372
+ const settablePaths = WarpRule.getSettablePaths();
5060
5373
  return await this.loadToolRulesDefault({
5061
5374
  root: {
5062
5375
  relativeDirPath: settablePaths.root.relativeDirPath,
5063
5376
  relativeFilePath: settablePaths.root.relativeFilePath,
5064
- fromFile: (params) => QwencodeRule.fromFile(params)
5377
+ fromFile: (params) => WarpRule.fromFile(params)
5065
5378
  },
5066
5379
  nonRoot: {
5067
5380
  relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5068
- fromFile: (params) => QwencodeRule.fromFile(params),
5069
- extension: "md"
5070
- }
5071
- });
5072
- }
5073
- /**
5074
- * Load Roo Code rule configurations from .roo/rules/ directory
5075
- */
5076
- async loadRooRules() {
5077
- const settablePaths = RooRule.getSettablePaths();
5078
- return await this.loadToolRulesDefault({
5079
- nonRoot: {
5080
- relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5081
- fromFile: (params) => RooRule.fromFile(params),
5082
- extension: "md"
5083
- }
5084
- });
5085
- }
5086
- /**
5087
- * Load Windsurf rule configurations from .windsurf/rules/ directory
5088
- */
5089
- async loadWindsurfRules() {
5090
- const settablePaths = WindsurfRule.getSettablePaths();
5091
- return await this.loadToolRulesDefault({
5092
- nonRoot: {
5093
- relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5094
- fromFile: (params) => WindsurfRule.fromFile(params),
5381
+ fromFile: (params) => WarpRule.fromFile(params),
5095
5382
  extension: "md"
5096
5383
  }
5097
5384
  });
5098
5385
  }
5099
- /**
5100
- * Implementation of abstract method from FeatureProcessor
5101
- * Return the tool targets that this processor supports
5102
- */
5103
- static getToolTargets() {
5104
- return rulesProcessorToolTargets;
5105
- }
5106
- generateXmlReferencesSection(toolRules) {
5107
- const toolRulesWithoutRoot = toolRules.filter((rule) => !rule.isRoot());
5108
- if (toolRulesWithoutRoot.length === 0) {
5109
- return "";
5110
- }
5111
- const lines = [];
5112
- lines.push(
5113
- "Please also reference the following documents as needed. In this case, `@` stands for the project root directory."
5114
- );
5115
- lines.push("");
5116
- const documentsData = {
5117
- Documents: {
5118
- Document: toolRulesWithoutRoot.map((rule) => {
5119
- const rulesyncRule = rule.toRulesyncRule();
5120
- const frontmatter = rulesyncRule.getFrontmatter();
5121
- const relativePath = `@${rule.getRelativePathFromCwd()}`;
5122
- const document = {
5123
- Path: relativePath
5124
- };
5125
- if (frontmatter.description) {
5126
- document.Description = frontmatter.description;
5127
- }
5128
- if (frontmatter.globs && frontmatter.globs.length > 0) {
5129
- document.FilePatterns = frontmatter.globs.join(", ");
5130
- }
5131
- return document;
5132
- })
5133
- }
5134
- };
5135
- const builder = new XMLBuilder({
5136
- format: true,
5137
- ignoreAttributes: false,
5138
- suppressEmptyNode: false
5139
- });
5140
- const xmlContent = builder.build(documentsData);
5141
- lines.push(xmlContent);
5142
- return lines.join("\n") + "\n";
5143
- }
5144
- generateReferencesSection(toolRules) {
5145
- const toolRulesWithoutRoot = toolRules.filter((rule) => !rule.isRoot());
5146
- if (toolRulesWithoutRoot.length === 0) {
5147
- return "";
5148
- }
5149
- const lines = [];
5150
- lines.push("Please also reference the following documents as needed:");
5151
- lines.push("");
5152
- for (const rule of toolRulesWithoutRoot) {
5153
- const rulesyncRule = rule.toRulesyncRule();
5154
- const frontmatter = rulesyncRule.getFrontmatter();
5155
- const escapedDescription = frontmatter.description?.replace(/"/g, '\\"');
5156
- const globsText = frontmatter.globs?.join(",");
5157
- lines.push(
5158
- `@${rule.getRelativePathFromCwd()} description: "${escapedDescription}" globs: "${globsText}"`
5159
- );
5160
- }
5161
- return lines.join("\n") + "\n";
5162
- }
5163
- generateAdditionalConventionsSection({
5164
- commands,
5165
- subagents
5166
- }) {
5167
- return `# Additional Conventions Beyond the Built-in Functions
5168
-
5169
- As this project's AI coding tool, you must follow the additional conventions below, in addition to the built-in functions.
5170
-
5171
- ${this.simulateCommands ? `## Simulated Custom Slash Commands
5172
-
5173
- Custom slash commands allow you to define frequently-used prompts as Markdown files that you can execute.
5174
-
5175
- ### Syntax
5176
-
5177
- Users can use following syntax to invoke a custom command.
5178
-
5179
- \`\`\`txt
5180
- s/<command> [arguments]
5181
- \`\`\`
5182
-
5183
- This syntax employs a double slash (\`s/\`) to prevent conflicts with built-in slash commands.
5184
- The \`s\` in \`s/\` stands for *simulate*. Because custom slash commands are not built-in, this syntax provides a pseudo way to invoke them.
5185
-
5186
- When users call a custom slash command, you have to look for the markdown file, \`${join49(commands.relativeDirPath, "{command}.md")}\`, then execute the contents of that file as the block of operations.` : ""}
5187
-
5188
- ${this.simulateSubagents ? `## Simulated Subagents
5189
-
5190
- 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.
5191
-
5192
- When users call a simulated subagent, it will look for the corresponding markdown file, \`${join49(subagents.relativeDirPath, "{subagent}.md")}\`, and execute its contents as the block of operations.` : ""}`.trim();
5193
- }
5194
- };
5195
-
5196
- // src/subagents/subagents-processor.ts
5197
- import { basename as basename16, join as join52 } from "path";
5198
- import { z as z20 } from "zod/mini";
5199
-
5200
- // src/subagents/claudecode-subagent.ts
5201
- import { join as join51 } from "path";
5202
- import { z as z19 } from "zod/mini";
5203
-
5204
- // src/subagents/rulesync-subagent.ts
5205
- import { basename as basename15, join as join50 } from "path";
5206
- import { z as z18 } from "zod/mini";
5207
- var RulesyncSubagentModelSchema = z18.enum(["opus", "sonnet", "haiku", "inherit"]);
5208
- var RulesyncSubagentFrontmatterSchema = z18.object({
5209
- targets: RulesyncTargetsSchema,
5210
- name: z18.string(),
5211
- description: z18.string(),
5212
- claudecode: z18.optional(
5213
- z18.object({
5214
- model: RulesyncSubagentModelSchema
5215
- })
5216
- )
5217
- });
5218
- var RulesyncSubagent = class _RulesyncSubagent extends RulesyncFile {
5219
- frontmatter;
5220
- body;
5221
- constructor({ frontmatter, body, ...rest }) {
5222
- if (rest.validate !== false) {
5223
- const result = RulesyncSubagentFrontmatterSchema.safeParse(frontmatter);
5224
- if (!result.success) {
5225
- throw result.error;
5226
- }
5227
- }
5228
- super({
5229
- ...rest
5230
- });
5231
- this.frontmatter = frontmatter;
5232
- this.body = body;
5233
- }
5234
- static getSettablePaths() {
5235
- return {
5236
- relativeDirPath: ".rulesync/subagents"
5237
- };
5238
- }
5239
- getFrontmatter() {
5240
- return this.frontmatter;
5241
- }
5242
- getBody() {
5243
- return this.body;
5244
- }
5245
- validate() {
5246
- if (!this.frontmatter) {
5247
- return { success: true, error: null };
5248
- }
5249
- const result = RulesyncSubagentFrontmatterSchema.safeParse(this.frontmatter);
5250
- if (result.success) {
5251
- return { success: true, error: null };
5252
- } else {
5253
- return { success: false, error: result.error };
5254
- }
5255
- }
5256
- static async fromFile({
5257
- relativeFilePath
5258
- }) {
5259
- const fileContent = await readFileContent(join50(RULESYNC_SUBAGENTS_DIR, relativeFilePath));
5260
- const { frontmatter, body: content } = parseFrontmatter(fileContent);
5261
- const result = RulesyncSubagentFrontmatterSchema.safeParse(frontmatter);
5262
- if (!result.success) {
5263
- throw new Error(`Invalid frontmatter in ${relativeFilePath}: ${result.error.message}`);
5264
- }
5265
- const filename = basename15(relativeFilePath);
5266
- return new _RulesyncSubagent({
5267
- baseDir: ".",
5268
- relativeDirPath: this.getSettablePaths().relativeDirPath,
5269
- relativeFilePath: filename,
5270
- frontmatter: result.data,
5271
- body: content.trim(),
5272
- fileContent
5273
- });
5274
- }
5275
- };
5276
-
5277
- // src/subagents/claudecode-subagent.ts
5278
- var ClaudecodeSubagentFrontmatterSchema = z19.object({
5279
- name: z19.string(),
5280
- description: z19.string(),
5281
- model: z19.optional(z19.enum(["opus", "sonnet", "haiku", "inherit"]))
5282
- });
5283
- var ClaudecodeSubagent = class _ClaudecodeSubagent extends ToolSubagent {
5284
- frontmatter;
5285
- body;
5286
- constructor({ frontmatter, body, ...rest }) {
5287
- if (rest.validate !== false) {
5288
- const result = ClaudecodeSubagentFrontmatterSchema.safeParse(frontmatter);
5289
- if (!result.success) {
5290
- throw result.error;
5291
- }
5292
- }
5293
- super({
5294
- ...rest
5295
- });
5296
- this.frontmatter = frontmatter;
5297
- this.body = body;
5298
- }
5299
- static getSettablePaths() {
5300
- return {
5301
- relativeDirPath: ".claude/agents"
5302
- };
5303
- }
5304
- getFrontmatter() {
5305
- return this.frontmatter;
5306
- }
5307
- getBody() {
5308
- return this.body;
5309
- }
5310
- toRulesyncSubagent() {
5311
- const rulesyncFrontmatter = {
5312
- targets: ["claudecode"],
5313
- name: this.frontmatter.name,
5314
- description: this.frontmatter.description,
5315
- ...this.frontmatter.model && {
5316
- claudecode: {
5317
- model: this.frontmatter.model
5318
- }
5386
+ /**
5387
+ * Load Amazon Q Developer CLI rule configurations from .amazonq/rules/ directory
5388
+ */
5389
+ async loadAmazonqcliRules() {
5390
+ const settablePaths = AmazonQCliRule.getSettablePaths();
5391
+ return await this.loadToolRulesDefault({
5392
+ nonRoot: {
5393
+ relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5394
+ fromFile: (params) => AmazonQCliRule.fromFile(params),
5395
+ extension: "md"
5319
5396
  }
5320
- };
5321
- const fileContent = stringifyFrontmatter(this.body, rulesyncFrontmatter);
5322
- return new RulesyncSubagent({
5323
- frontmatter: rulesyncFrontmatter,
5324
- body: this.body,
5325
- baseDir: this.baseDir,
5326
- relativeDirPath: ".rulesync/subagents",
5327
- relativeFilePath: this.getRelativeFilePath(),
5328
- fileContent,
5329
- validate: true
5330
5397
  });
5331
5398
  }
5332
- static fromRulesyncSubagent({
5333
- baseDir = ".",
5334
- rulesyncSubagent,
5335
- validate = true
5336
- }) {
5337
- const rulesyncFrontmatter = rulesyncSubagent.getFrontmatter();
5338
- const claudecodeFrontmatter = {
5339
- name: rulesyncFrontmatter.name,
5340
- description: rulesyncFrontmatter.description,
5341
- model: rulesyncFrontmatter.claudecode?.model
5342
- };
5343
- const body = rulesyncSubagent.getBody();
5344
- const fileContent = stringifyFrontmatter(body, claudecodeFrontmatter);
5345
- return new _ClaudecodeSubagent({
5346
- baseDir,
5347
- frontmatter: claudecodeFrontmatter,
5348
- body,
5349
- relativeDirPath: ".claude/agents",
5350
- relativeFilePath: rulesyncSubagent.getRelativeFilePath(),
5351
- fileContent,
5352
- validate
5399
+ /**
5400
+ * Load AugmentCode rule configurations from .augment/rules/ directory
5401
+ */
5402
+ async loadAugmentcodeRules() {
5403
+ const settablePaths = AugmentcodeRule.getSettablePaths();
5404
+ return await this.loadToolRulesDefault({
5405
+ nonRoot: {
5406
+ relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5407
+ fromFile: (params) => AugmentcodeRule.fromFile(params),
5408
+ extension: "md"
5409
+ }
5353
5410
  });
5354
5411
  }
5355
- validate() {
5356
- if (!this.frontmatter) {
5357
- return { success: true, error: null };
5358
- }
5359
- const result = ClaudecodeSubagentFrontmatterSchema.safeParse(this.frontmatter);
5360
- if (result.success) {
5361
- return { success: true, error: null };
5362
- } else {
5363
- return { success: false, error: result.error };
5364
- }
5412
+ /**
5413
+ * Load AugmentCode legacy rule configuration from .augment-guidelines file and .augment/rules/ directory
5414
+ */
5415
+ async loadAugmentcodeLegacyRules() {
5416
+ const settablePaths = AugmentcodeLegacyRule.getSettablePaths();
5417
+ return await this.loadToolRulesDefault({
5418
+ root: {
5419
+ relativeDirPath: settablePaths.root.relativeDirPath,
5420
+ relativeFilePath: settablePaths.root.relativeFilePath,
5421
+ fromFile: (params) => AugmentcodeLegacyRule.fromFile(params)
5422
+ },
5423
+ nonRoot: {
5424
+ relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5425
+ fromFile: (params) => AugmentcodeLegacyRule.fromFile(params),
5426
+ extension: "md"
5427
+ }
5428
+ });
5365
5429
  }
5366
- static isTargetedByRulesyncSubagent(rulesyncSubagent) {
5367
- return this.isTargetedByRulesyncSubagentDefault({
5368
- rulesyncSubagent,
5369
- toolTarget: "claudecode"
5430
+ /**
5431
+ * Load Claude Code rule configuration from CLAUDE.md file
5432
+ */
5433
+ async loadClaudecodeRules() {
5434
+ const settablePaths = ClaudecodeRule.getSettablePaths();
5435
+ return await this.loadToolRulesDefault({
5436
+ root: {
5437
+ relativeDirPath: settablePaths.root.relativeDirPath,
5438
+ relativeFilePath: settablePaths.root.relativeFilePath,
5439
+ fromFile: (params) => ClaudecodeRule.fromFile(params)
5440
+ },
5441
+ nonRoot: {
5442
+ relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5443
+ fromFile: (params) => ClaudecodeRule.fromFile(params),
5444
+ extension: "md"
5445
+ }
5370
5446
  });
5371
5447
  }
5372
- static async fromFile({
5373
- baseDir = ".",
5374
- relativeFilePath,
5375
- validate = true
5376
- }) {
5377
- const fileContent = await readFileContent(join51(baseDir, ".claude/agents", relativeFilePath));
5378
- const { frontmatter, body: content } = parseFrontmatter(fileContent);
5379
- const result = ClaudecodeSubagentFrontmatterSchema.safeParse(frontmatter);
5380
- if (!result.success) {
5381
- throw new Error(`Invalid frontmatter in ${relativeFilePath}: ${result.error.message}`);
5382
- }
5383
- return new _ClaudecodeSubagent({
5384
- baseDir,
5385
- relativeDirPath: ".claude/agents",
5386
- relativeFilePath,
5387
- frontmatter: result.data,
5388
- body: content.trim(),
5389
- fileContent,
5390
- validate
5448
+ /**
5449
+ * Load Cline rule configurations from .clinerules/ directory
5450
+ */
5451
+ async loadClineRules() {
5452
+ const settablePaths = ClineRule.getSettablePaths();
5453
+ return await this.loadToolRulesDefault({
5454
+ nonRoot: {
5455
+ relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5456
+ fromFile: (params) => ClineRule.fromFile(params),
5457
+ extension: "md"
5458
+ }
5391
5459
  });
5392
5460
  }
5393
- };
5394
-
5395
- // src/subagents/subagents-processor.ts
5396
- var subagentsProcessorToolTargets = [
5397
- "claudecode",
5398
- "copilot",
5399
- "cursor",
5400
- "codexcli"
5401
- ];
5402
- var subagentsProcessorToolTargetsSimulated = [
5403
- "copilot",
5404
- "cursor",
5405
- "codexcli"
5406
- ];
5407
- var SubagentsProcessorToolTargetSchema = z20.enum(subagentsProcessorToolTargets);
5408
- var SubagentsProcessor = class extends FeatureProcessor {
5409
- toolTarget;
5410
- constructor({
5411
- baseDir = ".",
5412
- toolTarget
5413
- }) {
5414
- super({ baseDir });
5415
- this.toolTarget = SubagentsProcessorToolTargetSchema.parse(toolTarget);
5461
+ /**
5462
+ * Load OpenAI Codex CLI rule configuration from AGENTS.md and .codex/memories/*.md files
5463
+ */
5464
+ async loadCodexcliRules() {
5465
+ const settablePaths = CodexcliRule.getSettablePaths();
5466
+ return await this.loadToolRulesDefault({
5467
+ root: {
5468
+ relativeDirPath: settablePaths.root.relativeDirPath,
5469
+ relativeFilePath: settablePaths.root.relativeFilePath,
5470
+ fromFile: (params) => CodexcliRule.fromFile(params)
5471
+ },
5472
+ nonRoot: {
5473
+ relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5474
+ fromFile: (params) => CodexcliRule.fromFile(params),
5475
+ extension: "md"
5476
+ }
5477
+ });
5416
5478
  }
5417
- async convertRulesyncFilesToToolFiles(rulesyncFiles) {
5418
- const rulesyncSubagents = rulesyncFiles.filter(
5419
- (file) => file instanceof RulesyncSubagent
5420
- );
5421
- const toolSubagents = rulesyncSubagents.map((rulesyncSubagent) => {
5422
- switch (this.toolTarget) {
5423
- case "claudecode":
5424
- if (!ClaudecodeSubagent.isTargetedByRulesyncSubagent(rulesyncSubagent)) {
5425
- return null;
5426
- }
5427
- return ClaudecodeSubagent.fromRulesyncSubagent({
5428
- baseDir: this.baseDir,
5429
- relativeDirPath: RulesyncSubagent.getSettablePaths().relativeDirPath,
5430
- rulesyncSubagent
5431
- });
5432
- case "copilot":
5433
- if (!CopilotSubagent.isTargetedByRulesyncSubagent(rulesyncSubagent)) {
5434
- return null;
5435
- }
5436
- return CopilotSubagent.fromRulesyncSubagent({
5437
- baseDir: this.baseDir,
5438
- relativeDirPath: RulesyncSubagent.getSettablePaths().relativeDirPath,
5439
- rulesyncSubagent
5440
- });
5441
- case "cursor":
5442
- if (!CursorSubagent.isTargetedByRulesyncSubagent(rulesyncSubagent)) {
5443
- return null;
5444
- }
5445
- return CursorSubagent.fromRulesyncSubagent({
5446
- baseDir: this.baseDir,
5447
- relativeDirPath: RulesyncSubagent.getSettablePaths().relativeDirPath,
5448
- rulesyncSubagent
5449
- });
5450
- case "codexcli":
5451
- if (!CodexCliSubagent.isTargetedByRulesyncSubagent(rulesyncSubagent)) {
5452
- return null;
5453
- }
5454
- return CodexCliSubagent.fromRulesyncSubagent({
5455
- baseDir: this.baseDir,
5456
- relativeDirPath: RulesyncSubagent.getSettablePaths().relativeDirPath,
5457
- rulesyncSubagent
5458
- });
5459
- default:
5460
- throw new Error(`Unsupported tool target: ${this.toolTarget}`);
5479
+ /**
5480
+ * Load GitHub Copilot rule configuration from .github/copilot-instructions.md file
5481
+ */
5482
+ async loadCopilotRules() {
5483
+ const settablePaths = CopilotRule.getSettablePaths();
5484
+ return await this.loadToolRulesDefault({
5485
+ root: {
5486
+ relativeDirPath: settablePaths.root.relativeDirPath,
5487
+ relativeFilePath: settablePaths.root.relativeFilePath,
5488
+ fromFile: (params) => CopilotRule.fromFile(params)
5489
+ },
5490
+ nonRoot: {
5491
+ relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5492
+ fromFile: (params) => CopilotRule.fromFile(params),
5493
+ extension: "md"
5461
5494
  }
5462
- }).filter((subagent) => subagent !== null);
5463
- return toolSubagents;
5495
+ });
5464
5496
  }
5465
- async convertToolFilesToRulesyncFiles(toolFiles) {
5466
- const toolSubagents = toolFiles.filter(
5467
- (file) => file instanceof ToolSubagent
5468
- );
5469
- const rulesyncSubagents = [];
5470
- for (const toolSubagent of toolSubagents) {
5471
- if (toolSubagent instanceof SimulatedSubagent) {
5472
- logger.debug(
5473
- `Skipping simulated subagent conversion: ${toolSubagent.getRelativeFilePath()}`
5474
- );
5475
- continue;
5497
+ /**
5498
+ * Load Cursor rule configurations from .cursor/rules/ directory
5499
+ */
5500
+ async loadCursorRules() {
5501
+ const settablePaths = CursorRule.getSettablePaths();
5502
+ return await this.loadToolRulesDefault({
5503
+ nonRoot: {
5504
+ relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5505
+ fromFile: (params) => CursorRule.fromFile(params),
5506
+ extension: "mdc"
5476
5507
  }
5477
- rulesyncSubagents.push(toolSubagent.toRulesyncSubagent());
5478
- }
5479
- return rulesyncSubagents;
5508
+ });
5480
5509
  }
5481
5510
  /**
5482
- * Implementation of abstract method from Processor
5483
- * Load and parse rulesync subagent files from .rulesync/subagents/ directory
5511
+ * Load Gemini CLI rule configuration from GEMINI.md file
5484
5512
  */
5485
- async loadRulesyncFiles() {
5486
- const subagentsDir = join52(this.baseDir, RulesyncSubagent.getSettablePaths().relativeDirPath);
5487
- const dirExists = await directoryExists(subagentsDir);
5488
- if (!dirExists) {
5489
- logger.debug(`Rulesync subagents directory not found: ${subagentsDir}`);
5490
- return [];
5491
- }
5492
- const entries = await listDirectoryFiles(subagentsDir);
5493
- const mdFiles = entries.filter((file) => file.endsWith(".md"));
5494
- if (mdFiles.length === 0) {
5495
- logger.debug(`No markdown files found in rulesync subagents directory: ${subagentsDir}`);
5496
- return [];
5497
- }
5498
- logger.info(`Found ${mdFiles.length} subagent files in ${subagentsDir}`);
5499
- const rulesyncSubagents = [];
5500
- for (const mdFile of mdFiles) {
5501
- const filepath = join52(subagentsDir, mdFile);
5502
- try {
5503
- const rulesyncSubagent = await RulesyncSubagent.fromFile({
5504
- relativeFilePath: mdFile,
5505
- validate: true
5506
- });
5507
- rulesyncSubagents.push(rulesyncSubagent);
5508
- logger.debug(`Successfully loaded subagent: ${mdFile}`);
5509
- } catch (error) {
5510
- logger.warn(`Failed to load subagent file ${filepath}:`, error);
5511
- continue;
5513
+ async loadGeminicliRules() {
5514
+ const settablePaths = GeminiCliRule.getSettablePaths();
5515
+ return await this.loadToolRulesDefault({
5516
+ root: {
5517
+ relativeDirPath: settablePaths.root.relativeDirPath,
5518
+ relativeFilePath: settablePaths.root.relativeFilePath,
5519
+ fromFile: (params) => GeminiCliRule.fromFile(params)
5520
+ },
5521
+ nonRoot: {
5522
+ relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5523
+ fromFile: (params) => GeminiCliRule.fromFile(params),
5524
+ extension: "md"
5512
5525
  }
5513
- }
5514
- if (rulesyncSubagents.length === 0) {
5515
- logger.debug(`No valid subagents found in ${subagentsDir}`);
5516
- return [];
5517
- }
5518
- logger.info(`Successfully loaded ${rulesyncSubagents.length} rulesync subagents`);
5519
- return rulesyncSubagents;
5526
+ });
5520
5527
  }
5521
5528
  /**
5522
- * Implementation of abstract method from Processor
5523
- * Load tool-specific subagent configurations and parse them into ToolSubagent instances
5529
+ * Load JetBrains Junie rule configuration from .junie/guidelines.md file
5524
5530
  */
5525
- async loadToolFiles() {
5526
- switch (this.toolTarget) {
5527
- case "claudecode":
5528
- return await this.loadClaudecodeSubagents();
5529
- case "copilot":
5530
- return await this.loadCopilotSubagents();
5531
- case "cursor":
5532
- return await this.loadCursorSubagents();
5533
- case "codexcli":
5534
- return await this.loadCodexCliSubagents();
5535
- default:
5536
- throw new Error(`Unsupported tool target: ${this.toolTarget}`);
5537
- }
5531
+ async loadJunieRules() {
5532
+ const settablePaths = JunieRule.getSettablePaths();
5533
+ return await this.loadToolRulesDefault({
5534
+ root: {
5535
+ relativeDirPath: settablePaths.root.relativeDirPath,
5536
+ relativeFilePath: settablePaths.root.relativeFilePath,
5537
+ fromFile: (params) => JunieRule.fromFile(params)
5538
+ },
5539
+ nonRoot: {
5540
+ relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5541
+ fromFile: (params) => JunieRule.fromFile(params),
5542
+ extension: "md"
5543
+ }
5544
+ });
5538
5545
  }
5539
5546
  /**
5540
- * Load Claude Code subagent configurations from .claude/agents/ directory
5547
+ * Load Kiro rule configurations from .kiro/steering/ directory
5541
5548
  */
5542
- async loadClaudecodeSubagents() {
5543
- return await this.loadToolSubagentsDefault({
5544
- relativeDirPath: ClaudecodeSubagent.getSettablePaths().relativeDirPath,
5545
- fromFile: (relativeFilePath) => ClaudecodeSubagent.fromFile({ relativeFilePath })
5549
+ async loadKiroRules() {
5550
+ const settablePaths = KiroRule.getSettablePaths();
5551
+ return await this.loadToolRulesDefault({
5552
+ nonRoot: {
5553
+ relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5554
+ fromFile: (params) => KiroRule.fromFile(params),
5555
+ extension: "md"
5556
+ }
5546
5557
  });
5547
5558
  }
5548
5559
  /**
5549
- * Load Copilot subagent configurations from .copilot/subagents/ directory
5560
+ * Load OpenCode rule configuration from AGENTS.md file and .opencode/memories/*.md files
5550
5561
  */
5551
- async loadCopilotSubagents() {
5552
- return await this.loadToolSubagentsDefault({
5553
- relativeDirPath: CopilotSubagent.getSettablePaths().relativeDirPath,
5554
- fromFile: (relativeFilePath) => CopilotSubagent.fromFile({ relativeFilePath })
5562
+ async loadOpencodeRules() {
5563
+ const settablePaths = OpenCodeRule.getSettablePaths();
5564
+ return await this.loadToolRulesDefault({
5565
+ root: {
5566
+ relativeDirPath: settablePaths.root.relativeDirPath,
5567
+ relativeFilePath: settablePaths.root.relativeFilePath,
5568
+ fromFile: (params) => OpenCodeRule.fromFile(params)
5569
+ },
5570
+ nonRoot: {
5571
+ relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5572
+ fromFile: (params) => OpenCodeRule.fromFile(params),
5573
+ extension: "md"
5574
+ }
5555
5575
  });
5556
5576
  }
5557
5577
  /**
5558
- * Load Cursor subagent configurations from .cursor/subagents/ directory
5578
+ * Load Qwen Code rule configuration from QWEN.md file and .qwen/memories/*.md files
5559
5579
  */
5560
- async loadCursorSubagents() {
5561
- return await this.loadToolSubagentsDefault({
5562
- relativeDirPath: CursorSubagent.getSettablePaths().relativeDirPath,
5563
- fromFile: (relativeFilePath) => CursorSubagent.fromFile({ relativeFilePath })
5580
+ async loadQwencodeRules() {
5581
+ const settablePaths = QwencodeRule.getSettablePaths();
5582
+ return await this.loadToolRulesDefault({
5583
+ root: {
5584
+ relativeDirPath: settablePaths.root.relativeDirPath,
5585
+ relativeFilePath: settablePaths.root.relativeFilePath,
5586
+ fromFile: (params) => QwencodeRule.fromFile(params)
5587
+ },
5588
+ nonRoot: {
5589
+ relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5590
+ fromFile: (params) => QwencodeRule.fromFile(params),
5591
+ extension: "md"
5592
+ }
5564
5593
  });
5565
5594
  }
5566
5595
  /**
5567
- * Load CodexCli subagent configurations from .codex/subagents/ directory
5596
+ * Load Roo Code rule configurations from .roo/rules/ directory
5568
5597
  */
5569
- async loadCodexCliSubagents() {
5570
- return await this.loadToolSubagentsDefault({
5571
- relativeDirPath: CodexCliSubagent.getSettablePaths().relativeDirPath,
5572
- fromFile: (relativeFilePath) => CodexCliSubagent.fromFile({ relativeFilePath })
5598
+ async loadRooRules() {
5599
+ const settablePaths = RooRule.getSettablePaths();
5600
+ return await this.loadToolRulesDefault({
5601
+ nonRoot: {
5602
+ relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5603
+ fromFile: (params) => RooRule.fromFile(params),
5604
+ extension: "md"
5605
+ }
5573
5606
  });
5574
5607
  }
5575
- async loadToolSubagentsDefault({
5576
- relativeDirPath,
5577
- fromFile
5578
- }) {
5579
- const paths = await findFilesByGlobs(join52(this.baseDir, relativeDirPath, "*.md"));
5580
- const subagents = (await Promise.allSettled(paths.map((path2) => fromFile(basename16(path2))))).filter((r) => r.status === "fulfilled").map((r) => r.value);
5581
- logger.info(`Successfully loaded ${subagents.length} ${relativeDirPath} subagents`);
5582
- return subagents;
5608
+ /**
5609
+ * Load Windsurf rule configurations from .windsurf/rules/ directory
5610
+ */
5611
+ async loadWindsurfRules() {
5612
+ const settablePaths = WindsurfRule.getSettablePaths();
5613
+ return await this.loadToolRulesDefault({
5614
+ nonRoot: {
5615
+ relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5616
+ fromFile: (params) => WindsurfRule.fromFile(params),
5617
+ extension: "md"
5618
+ }
5619
+ });
5583
5620
  }
5584
5621
  /**
5585
5622
  * Implementation of abstract method from FeatureProcessor
5586
5623
  * Return the tool targets that this processor supports
5587
5624
  */
5588
- static getToolTargets({
5589
- includeSimulated = false
5590
- } = {}) {
5591
- if (!includeSimulated) {
5592
- return subagentsProcessorToolTargets.filter(
5593
- (target) => !subagentsProcessorToolTargetsSimulated.includes(target)
5625
+ static getToolTargets() {
5626
+ return rulesProcessorToolTargets;
5627
+ }
5628
+ generateXmlReferencesSection(toolRules) {
5629
+ const toolRulesWithoutRoot = toolRules.filter((rule) => !rule.isRoot());
5630
+ if (toolRulesWithoutRoot.length === 0) {
5631
+ return "";
5632
+ }
5633
+ const lines = [];
5634
+ lines.push(
5635
+ "Please also reference the following documents as needed. In this case, `@` stands for the project root directory."
5636
+ );
5637
+ lines.push("");
5638
+ const documentsData = {
5639
+ Documents: {
5640
+ Document: toolRulesWithoutRoot.map((rule) => {
5641
+ const rulesyncRule = rule.toRulesyncRule();
5642
+ const frontmatter = rulesyncRule.getFrontmatter();
5643
+ const relativePath = `@${rule.getRelativePathFromCwd()}`;
5644
+ const document = {
5645
+ Path: relativePath
5646
+ };
5647
+ if (frontmatter.description) {
5648
+ document.Description = frontmatter.description;
5649
+ }
5650
+ if (frontmatter.globs && frontmatter.globs.length > 0) {
5651
+ document.FilePatterns = frontmatter.globs.join(", ");
5652
+ }
5653
+ return document;
5654
+ })
5655
+ }
5656
+ };
5657
+ const builder = new XMLBuilder({
5658
+ format: true,
5659
+ ignoreAttributes: false,
5660
+ suppressEmptyNode: false
5661
+ });
5662
+ const xmlContent = builder.build(documentsData);
5663
+ lines.push(xmlContent);
5664
+ return lines.join("\n") + "\n";
5665
+ }
5666
+ generateReferencesSection(toolRules) {
5667
+ const toolRulesWithoutRoot = toolRules.filter((rule) => !rule.isRoot());
5668
+ if (toolRulesWithoutRoot.length === 0) {
5669
+ return "";
5670
+ }
5671
+ const lines = [];
5672
+ lines.push("Please also reference the following documents as needed:");
5673
+ lines.push("");
5674
+ for (const rule of toolRulesWithoutRoot) {
5675
+ const rulesyncRule = rule.toRulesyncRule();
5676
+ const frontmatter = rulesyncRule.getFrontmatter();
5677
+ const escapedDescription = frontmatter.description?.replace(/"/g, '\\"');
5678
+ const globsText = frontmatter.globs?.join(",");
5679
+ lines.push(
5680
+ `@${rule.getRelativePathFromCwd()} description: "${escapedDescription}" globs: "${globsText}"`
5594
5681
  );
5595
5682
  }
5596
- return subagentsProcessorToolTargets;
5683
+ return lines.join("\n") + "\n";
5684
+ }
5685
+ generateAdditionalConventionsSection({
5686
+ commands,
5687
+ subagents
5688
+ }) {
5689
+ const overview = `# Additional Conventions Beyond the Built-in Functions
5690
+
5691
+ As this project's AI coding tool, you must follow the additional conventions below, in addition to the built-in functions.`;
5692
+ const commandsSection = `## Simulated Custom Slash Commands
5693
+
5694
+ Custom slash commands allow you to define frequently-used prompts as Markdown files that you can execute.
5695
+
5696
+ ### Syntax
5697
+
5698
+ Users can use following syntax to invoke a custom command.
5699
+
5700
+ \`\`\`txt
5701
+ s/<command> [arguments]
5702
+ \`\`\`
5703
+
5704
+ This syntax employs a double slash (\`s/\`) to prevent conflicts with built-in slash commands.
5705
+ The \`s\` in \`s/\` stands for *simulate*. Because custom slash commands are not built-in, this syntax provides a pseudo way to invoke them.
5706
+
5707
+ When users call a custom slash command, you have to look for the markdown file, \`${join52(commands.relativeDirPath, "{command}.md")}\`, then execute the contents of that file as the block of operations.`;
5708
+ const subagentsSection = `## Simulated Subagents
5709
+
5710
+ 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.
5711
+
5712
+ When users call a simulated subagent, it will look for the corresponding markdown file, \`${join52(subagents.relativeDirPath, "{subagent}.md")}\`, and execute its contents as the block of operations.
5713
+
5714
+ For example, if the user instructs \`Call planner subagent to plan the refactoring\`, you have to look for the markdown file, \`${join52(subagents.relativeDirPath, "planner.md")}\`, and execute its contents as the block of operations.`;
5715
+ const result = [
5716
+ overview,
5717
+ ...this.simulateCommands && CommandsProcessor.getToolTargetsSimulated().includes(this.toolTarget) ? [commandsSection] : [],
5718
+ ...this.simulateSubagents && SubagentsProcessor.getToolTargetsSimulated().includes(this.toolTarget) ? [subagentsSection] : []
5719
+ ].join("\n\n");
5720
+ return result;
5597
5721
  }
5598
5722
  };
5599
5723
 
@@ -5798,6 +5922,7 @@ var gitignoreCommand = async () => {
5798
5922
  "**/GEMINI.md",
5799
5923
  "**/.gemini/memories/",
5800
5924
  "**/.gemini/commands/",
5925
+ "**/.gemini/subagents/",
5801
5926
  "**/QWEN.md",
5802
5927
  "**/.qwen/memories/",
5803
5928
  "**/.aiexclude",
@@ -5815,6 +5940,7 @@ var gitignoreCommand = async () => {
5815
5940
  "**/.cursor/mcp.json",
5816
5941
  "**/.cline/mcp.json",
5817
5942
  "**/.roo/mcp.json",
5943
+ "**/.roo/subagents/",
5818
5944
  "**/.vscode/mcp.json",
5819
5945
  "**/.github/commands/",
5820
5946
  "**/.github/subagents/",
@@ -5839,8 +5965,8 @@ var gitignoreCommand = async () => {
5839
5965
  }
5840
5966
  const newContent = gitignoreContent ? `${gitignoreContent.trimEnd()}
5841
5967
 
5842
- ${linesToAdd.join("")}
5843
- ` : `${linesToAdd.join("")}
5968
+ ${linesToAdd.join("\n")}
5969
+ ` : `${linesToAdd.join("\n")}
5844
5970
  `;
5845
5971
  await writeFileContent(gitignorePath, newContent);
5846
5972
  logger.success(`Added ${linesToAdd.length} rules to .gitignore:`);
@@ -6036,7 +6162,7 @@ var getVersion = async () => {
6036
6162
  const packageJson = await readJsonFile(packageJsonPath);
6037
6163
  return packageJson.version;
6038
6164
  } catch {
6039
- return "0.75.0";
6165
+ return "0.76.0";
6040
6166
  }
6041
6167
  };
6042
6168
  var main = async () => {