rulesync 7.0.0 → 7.1.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 +155 -2
  2. package/dist/index.cjs +1280 -671
  3. package/dist/index.js +1276 -667
  4. package/package.json +3 -1
package/dist/index.cjs CHANGED
@@ -129,7 +129,7 @@ var logger = new Logger();
129
129
 
130
130
  // src/lib/fetch.ts
131
131
  var import_promise = require("es-toolkit/promise");
132
- var import_node_path108 = require("path");
132
+ var import_node_path109 = require("path");
133
133
 
134
134
  // src/constants/rulesync-paths.ts
135
135
  var import_node_path = require("path");
@@ -146,9 +146,15 @@ var RULESYNC_AIIGNORE_RELATIVE_FILE_PATH = (0, import_node_path.join)(RULESYNC_R
146
146
  var RULESYNC_IGNORE_RELATIVE_FILE_PATH = ".rulesyncignore";
147
147
  var RULESYNC_OVERVIEW_FILE_NAME = "overview.md";
148
148
  var RULESYNC_SKILLS_RELATIVE_DIR_PATH = (0, import_node_path.join)(RULESYNC_RELATIVE_DIR_PATH, "skills");
149
+ var RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH = (0, import_node_path.join)(
150
+ RULESYNC_SKILLS_RELATIVE_DIR_PATH,
151
+ ".curated"
152
+ );
153
+ var RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH = "rulesync.lock";
149
154
  var RULESYNC_MCP_FILE_NAME = "mcp.json";
150
155
  var RULESYNC_HOOKS_FILE_NAME = "hooks.json";
151
156
  var MAX_FILE_SIZE = 10 * 1024 * 1024;
157
+ var FETCH_CONCURRENCY_LIMIT = 10;
152
158
 
153
159
  // src/features/commands/commands-processor.ts
154
160
  var import_node_path19 = require("path");
@@ -321,10 +327,11 @@ var FeatureProcessor = class {
321
327
  }
322
328
  /**
323
329
  * Once converted to rulesync/tool files, write them to the filesystem.
324
- * Returns the number of files written.
330
+ * Returns the count and paths of files written.
325
331
  */
326
332
  async writeAiFiles(aiFiles) {
327
333
  let changedCount = 0;
334
+ const changedPaths = [];
328
335
  for (const aiFile of aiFiles) {
329
336
  const filePath = aiFile.getFilePath();
330
337
  const contentWithNewline = addTrailingNewline(aiFile.getFileContent());
@@ -338,8 +345,9 @@ var FeatureProcessor = class {
338
345
  await writeFileContent(filePath, contentWithNewline);
339
346
  }
340
347
  changedCount++;
348
+ changedPaths.push(aiFile.getRelativePathFromCwd());
341
349
  }
342
- return changedCount;
350
+ return { count: changedCount, paths: changedPaths };
343
351
  }
344
352
  async removeAiFiles(aiFiles) {
345
353
  for (const aiFile of aiFiles) {
@@ -1679,7 +1687,7 @@ var GeminiCliCommand = class _GeminiCliCommand extends ToolCommand {
1679
1687
  const result = GeminiCliCommandFrontmatterSchema.safeParse(parsed);
1680
1688
  if (!result.success) {
1681
1689
  throw new Error(
1682
- `Invalid frontmatter in Gemini CLI command file: ${formatError(result.error)}`
1690
+ `Invalid frontmatter in ${(0, import_node_path14.join)(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
1683
1691
  );
1684
1692
  }
1685
1693
  return {
@@ -1687,7 +1695,10 @@ var GeminiCliCommand = class _GeminiCliCommand extends ToolCommand {
1687
1695
  description: result.data.description || ""
1688
1696
  };
1689
1697
  } catch (error) {
1690
- throw new Error(`Failed to parse TOML command file: ${error}`, { cause: error });
1698
+ throw new Error(
1699
+ `Failed to parse TOML command file (${(0, import_node_path14.join)(this.relativeDirPath, this.relativeFilePath)}): ${error}`,
1700
+ { cause: error }
1701
+ );
1691
1702
  }
1692
1703
  }
1693
1704
  getBody() {
@@ -2442,7 +2453,7 @@ var CommandsProcessor = class extends FeatureProcessor {
2442
2453
  (path4) => RulesyncCommand.fromFile({ relativeFilePath: (0, import_node_path19.basename)(path4) })
2443
2454
  )
2444
2455
  );
2445
- logger.info(`Successfully loaded ${rulesyncCommands.length} rulesync commands`);
2456
+ logger.debug(`Successfully loaded ${rulesyncCommands.length} rulesync commands`);
2446
2457
  return rulesyncCommands;
2447
2458
  }
2448
2459
  /**
@@ -2466,7 +2477,7 @@ var CommandsProcessor = class extends FeatureProcessor {
2466
2477
  global: this.global
2467
2478
  })
2468
2479
  ).filter((cmd) => cmd.isDeletable());
2469
- logger.info(`Successfully loaded ${toolCommands2.length} ${paths.relativeDirPath} commands`);
2480
+ logger.debug(`Successfully loaded ${toolCommands2.length} ${paths.relativeDirPath} commands`);
2470
2481
  return toolCommands2;
2471
2482
  }
2472
2483
  const toolCommands = await Promise.all(
@@ -2478,7 +2489,7 @@ var CommandsProcessor = class extends FeatureProcessor {
2478
2489
  })
2479
2490
  )
2480
2491
  );
2481
- logger.info(`Successfully loaded ${toolCommands.length} ${paths.relativeDirPath} commands`);
2492
+ logger.debug(`Successfully loaded ${toolCommands.length} ${paths.relativeDirPath} commands`);
2482
2493
  return toolCommands;
2483
2494
  }
2484
2495
  /**
@@ -2815,10 +2826,7 @@ var ClaudecodeHooks = class _ClaudecodeHooks extends ToolHooks {
2815
2826
  }) {
2816
2827
  const paths = _ClaudecodeHooks.getSettablePaths({ global });
2817
2828
  const filePath = (0, import_node_path21.join)(baseDir, paths.relativeDirPath, paths.relativeFilePath);
2818
- const fileContent = await readOrInitializeFileContent(
2819
- filePath,
2820
- JSON.stringify({ hooks: {} }, null, 2)
2821
- );
2829
+ const fileContent = await readFileContentOrNull(filePath) ?? '{"hooks":{}}';
2822
2830
  return new _ClaudecodeHooks({
2823
2831
  baseDir,
2824
2832
  relativeDirPath: paths.relativeDirPath,
@@ -2865,9 +2873,12 @@ var ClaudecodeHooks = class _ClaudecodeHooks extends ToolHooks {
2865
2873
  try {
2866
2874
  settings = JSON.parse(this.getFileContent());
2867
2875
  } catch (error) {
2868
- throw new Error(`Failed to parse Claude hooks content: ${formatError(error)}`, {
2869
- cause: error
2870
- });
2876
+ throw new Error(
2877
+ `Failed to parse Claude hooks content in ${(0, import_node_path21.join)(this.getRelativeDirPath(), this.getRelativeFilePath())}: ${formatError(error)}`,
2878
+ {
2879
+ cause: error
2880
+ }
2881
+ );
2871
2882
  }
2872
2883
  const hooks = claudeHooksToCanonical(settings.hooks);
2873
2884
  return this.toRulesyncHooksDefault({
@@ -3090,10 +3101,7 @@ var FactorydroidHooks = class _FactorydroidHooks extends ToolHooks {
3090
3101
  }) {
3091
3102
  const paths = _FactorydroidHooks.getSettablePaths({ global });
3092
3103
  const filePath = (0, import_node_path23.join)(baseDir, paths.relativeDirPath, paths.relativeFilePath);
3093
- const fileContent = await readOrInitializeFileContent(
3094
- filePath,
3095
- JSON.stringify({ hooks: {} }, null, 2)
3096
- );
3104
+ const fileContent = await readFileContentOrNull(filePath) ?? '{"hooks":{}}';
3097
3105
  return new _FactorydroidHooks({
3098
3106
  baseDir,
3099
3107
  relativeDirPath: paths.relativeDirPath,
@@ -3140,9 +3148,12 @@ var FactorydroidHooks = class _FactorydroidHooks extends ToolHooks {
3140
3148
  try {
3141
3149
  settings = JSON.parse(this.getFileContent());
3142
3150
  } catch (error) {
3143
- throw new Error(`Failed to parse Factory Droid hooks content: ${formatError(error)}`, {
3144
- cause: error
3145
- });
3151
+ throw new Error(
3152
+ `Failed to parse Factory Droid hooks content in ${(0, import_node_path23.join)(this.getRelativeDirPath(), this.getRelativeFilePath())}: ${formatError(error)}`,
3153
+ {
3154
+ cause: error
3155
+ }
3156
+ );
3146
3157
  }
3147
3158
  const hooks = factorydroidHooksToCanonical(settings.hooks);
3148
3159
  return this.toRulesyncHooksDefault({
@@ -3395,7 +3406,9 @@ var HooksProcessor = class extends FeatureProcessor {
3395
3406
  })
3396
3407
  ];
3397
3408
  } catch (error) {
3398
- logger.error(`Failed to load Rulesync hooks file: ${formatError(error)}`);
3409
+ logger.error(
3410
+ `Failed to load Rulesync hooks file (${RULESYNC_HOOKS_RELATIVE_FILE_PATH}): ${formatError(error)}`
3411
+ );
3399
3412
  return [];
3400
3413
  }
3401
3414
  }
@@ -3412,7 +3425,7 @@ var HooksProcessor = class extends FeatureProcessor {
3412
3425
  global: this.global
3413
3426
  });
3414
3427
  const list = toolHooks2.isDeletable?.() !== false ? [toolHooks2] : [];
3415
- logger.info(
3428
+ logger.debug(
3416
3429
  `Successfully loaded ${list.length} ${this.toolTarget} hooks files for deletion`
3417
3430
  );
3418
3431
  return list;
@@ -3422,7 +3435,7 @@ var HooksProcessor = class extends FeatureProcessor {
3422
3435
  validate: true,
3423
3436
  global: this.global
3424
3437
  });
3425
- logger.info(`Successfully loaded 1 ${this.toolTarget} hooks file`);
3438
+ logger.debug(`Successfully loaded 1 ${this.toolTarget} hooks file`);
3426
3439
  return [toolHooks];
3427
3440
  } catch (error) {
3428
3441
  const msg = `Failed to load hooks files for tool target: ${this.toolTarget}: ${formatError(error)}`;
@@ -4486,7 +4499,9 @@ var IgnoreProcessor = class extends FeatureProcessor {
4486
4499
  try {
4487
4500
  return [await RulesyncIgnore.fromFile()];
4488
4501
  } catch (error) {
4489
- logger.error(`Failed to load rulesync files: ${formatError(error)}`);
4502
+ logger.error(
4503
+ `Failed to load rulesync ignore file (${RULESYNC_AIIGNORE_RELATIVE_FILE_PATH}): ${formatError(error)}`
4504
+ );
4490
4505
  return [];
4491
4506
  }
4492
4507
  }
@@ -4512,7 +4527,7 @@ var IgnoreProcessor = class extends FeatureProcessor {
4512
4527
  const toolIgnores = await this.loadToolIgnores();
4513
4528
  return toolIgnores;
4514
4529
  } catch (error) {
4515
- const errorMessage = `Failed to load tool files: ${formatError(error)}`;
4530
+ const errorMessage = `Failed to load tool files for ${this.toolTarget}: ${formatError(error)}`;
4516
4531
  if (error instanceof Error && error.message.includes("no such file or directory")) {
4517
4532
  logger.debug(errorMessage);
4518
4533
  } else {
@@ -4777,10 +4792,7 @@ var ClaudecodeMcp = class _ClaudecodeMcp extends ToolMcp {
4777
4792
  global = false
4778
4793
  }) {
4779
4794
  const paths = this.getSettablePaths({ global });
4780
- const fileContent = await readOrInitializeFileContent(
4781
- (0, import_node_path39.join)(baseDir, paths.relativeDirPath, paths.relativeFilePath),
4782
- JSON.stringify({ mcpServers: {} }, null, 2)
4783
- );
4795
+ const fileContent = await readFileContentOrNull((0, import_node_path39.join)(baseDir, paths.relativeDirPath, paths.relativeFilePath)) ?? '{"mcpServers":{}}';
4784
4796
  const json = JSON.parse(fileContent);
4785
4797
  const newJson = { ...json, mcpServers: json.mcpServers ?? {} };
4786
4798
  return new _ClaudecodeMcp({
@@ -5333,10 +5345,7 @@ var GeminiCliMcp = class _GeminiCliMcp extends ToolMcp {
5333
5345
  global = false
5334
5346
  }) {
5335
5347
  const paths = this.getSettablePaths({ global });
5336
- const fileContent = await readOrInitializeFileContent(
5337
- (0, import_node_path45.join)(baseDir, paths.relativeDirPath, paths.relativeFilePath),
5338
- JSON.stringify({ mcpServers: {} }, null, 2)
5339
- );
5348
+ const fileContent = await readFileContentOrNull((0, import_node_path45.join)(baseDir, paths.relativeDirPath, paths.relativeFilePath)) ?? '{"mcpServers":{}}';
5340
5349
  const json = JSON.parse(fileContent);
5341
5350
  const newJson = { ...json, mcpServers: json.mcpServers ?? {} };
5342
5351
  return new _GeminiCliMcp({
@@ -5491,10 +5500,7 @@ var KiloMcp = class _KiloMcp extends ToolMcp {
5491
5500
  validate = true
5492
5501
  }) {
5493
5502
  const paths = this.getSettablePaths();
5494
- const fileContent = await readOrInitializeFileContent(
5495
- (0, import_node_path47.join)(baseDir, paths.relativeDirPath, paths.relativeFilePath),
5496
- JSON.stringify({ mcpServers: {} }, null, 2)
5497
- );
5503
+ const fileContent = await readFileContentOrNull((0, import_node_path47.join)(baseDir, paths.relativeDirPath, paths.relativeFilePath)) ?? '{"mcpServers":{}}';
5498
5504
  return new _KiloMcp({
5499
5505
  baseDir,
5500
5506
  relativeDirPath: paths.relativeDirPath,
@@ -5563,10 +5569,7 @@ var KiroMcp = class _KiroMcp extends ToolMcp {
5563
5569
  validate = true
5564
5570
  }) {
5565
5571
  const paths = this.getSettablePaths();
5566
- const fileContent = await readOrInitializeFileContent(
5567
- (0, import_node_path48.join)(baseDir, paths.relativeDirPath, paths.relativeFilePath),
5568
- JSON.stringify({ mcpServers: {} }, null, 2)
5569
- );
5572
+ const fileContent = await readFileContentOrNull((0, import_node_path48.join)(baseDir, paths.relativeDirPath, paths.relativeFilePath)) ?? '{"mcpServers":{}}';
5570
5573
  return new _KiroMcp({
5571
5574
  baseDir,
5572
5575
  relativeDirPath: paths.relativeDirPath,
@@ -5737,10 +5740,7 @@ var OpencodeMcp = class _OpencodeMcp extends ToolMcp {
5737
5740
  global = false
5738
5741
  }) {
5739
5742
  const paths = this.getSettablePaths({ global });
5740
- const fileContent = await readOrInitializeFileContent(
5741
- (0, import_node_path49.join)(baseDir, paths.relativeDirPath, paths.relativeFilePath),
5742
- JSON.stringify({ mcp: {} }, null, 2)
5743
- );
5743
+ const fileContent = await readFileContentOrNull((0, import_node_path49.join)(baseDir, paths.relativeDirPath, paths.relativeFilePath)) ?? '{"mcp":{}}';
5744
5744
  const json = JSON.parse(fileContent);
5745
5745
  const newJson = { ...json, mcp: json.mcp ?? {} };
5746
5746
  return new _OpencodeMcp({
@@ -6068,7 +6068,9 @@ var McpProcessor = class extends FeatureProcessor {
6068
6068
  try {
6069
6069
  return [await RulesyncMcp.fromFile({})];
6070
6070
  } catch (error) {
6071
- logger.error(`Failed to load a Rulesync MCP file: ${formatError(error)}`);
6071
+ logger.error(
6072
+ `Failed to load a Rulesync MCP file (${RULESYNC_MCP_RELATIVE_FILE_PATH}): ${formatError(error)}`
6073
+ );
6072
6074
  return [];
6073
6075
  }
6074
6076
  }
@@ -6090,7 +6092,7 @@ var McpProcessor = class extends FeatureProcessor {
6090
6092
  global: this.global
6091
6093
  });
6092
6094
  const toolMcps2 = toolMcp.isDeletable() ? [toolMcp] : [];
6093
- logger.info(`Successfully loaded ${toolMcps2.length} ${this.toolTarget} MCP files`);
6095
+ logger.debug(`Successfully loaded ${toolMcps2.length} ${this.toolTarget} MCP files`);
6094
6096
  return toolMcps2;
6095
6097
  }
6096
6098
  const toolMcps = [
@@ -6100,7 +6102,7 @@ var McpProcessor = class extends FeatureProcessor {
6100
6102
  global: this.global
6101
6103
  })
6102
6104
  ];
6103
- logger.info(`Successfully loaded ${toolMcps.length} ${this.toolTarget} MCP files`);
6105
+ logger.debug(`Successfully loaded ${toolMcps.length} ${this.toolTarget} MCP files`);
6104
6106
  return toolMcps;
6105
6107
  } catch (error) {
6106
6108
  const errorMessage = `Failed to load MCP files for tool target: ${this.toolTarget}: ${formatError(error)}`;
@@ -6160,7 +6162,7 @@ var McpProcessor = class extends FeatureProcessor {
6160
6162
 
6161
6163
  // src/features/rules/rules-processor.ts
6162
6164
  var import_toon = require("@toon-format/toon");
6163
- var import_node_path107 = require("path");
6165
+ var import_node_path108 = require("path");
6164
6166
  var import_mini48 = require("zod/mini");
6165
6167
 
6166
6168
  // src/constants/general.ts
@@ -6623,7 +6625,7 @@ var FactorydroidSkill = class _FactorydroidSkill extends SimulatedSkill {
6623
6625
  };
6624
6626
 
6625
6627
  // src/features/skills/skills-processor.ts
6626
- var import_node_path70 = require("path");
6628
+ var import_node_path71 = require("path");
6627
6629
  var import_mini33 = require("zod/mini");
6628
6630
 
6629
6631
  // src/types/dir-feature-processor.ts
@@ -6651,6 +6653,7 @@ var DirFeatureProcessor = class {
6651
6653
  */
6652
6654
  async writeAiDirs(aiDirs) {
6653
6655
  let changedCount = 0;
6656
+ const changedPaths = [];
6654
6657
  for (const aiDir of aiDirs) {
6655
6658
  const dirPath = aiDir.getDirPath();
6656
6659
  let dirHasChanges = false;
@@ -6681,19 +6684,23 @@ var DirFeatureProcessor = class {
6681
6684
  if (!dirHasChanges) {
6682
6685
  continue;
6683
6686
  }
6687
+ const relativeDir = aiDir.getRelativePathFromCwd();
6684
6688
  if (this.dryRun) {
6685
6689
  logger.info(`[DRY RUN] Would create directory: ${dirPath}`);
6686
6690
  if (mainFile) {
6687
6691
  logger.info(`[DRY RUN] Would write: ${(0, import_node_path56.join)(dirPath, mainFile.name)}`);
6692
+ changedPaths.push((0, import_node_path56.join)(relativeDir, mainFile.name));
6688
6693
  }
6689
6694
  for (const file of otherFiles) {
6690
6695
  logger.info(`[DRY RUN] Would write: ${(0, import_node_path56.join)(dirPath, file.relativeFilePathToDirPath)}`);
6696
+ changedPaths.push((0, import_node_path56.join)(relativeDir, file.relativeFilePathToDirPath));
6691
6697
  }
6692
6698
  } else {
6693
6699
  await ensureDir(dirPath);
6694
6700
  if (mainFile && mainFileContent) {
6695
6701
  const mainFilePath = (0, import_node_path56.join)(dirPath, mainFile.name);
6696
6702
  await writeFileContent(mainFilePath, mainFileContent);
6703
+ changedPaths.push((0, import_node_path56.join)(relativeDir, mainFile.name));
6697
6704
  }
6698
6705
  for (const [i, file] of otherFiles.entries()) {
6699
6706
  const filePath = (0, import_node_path56.join)(dirPath, file.relativeFilePathToDirPath);
@@ -6704,11 +6711,12 @@ var DirFeatureProcessor = class {
6704
6711
  );
6705
6712
  }
6706
6713
  await writeFileContent(filePath, content);
6714
+ changedPaths.push((0, import_node_path56.join)(relativeDir, file.relativeFilePathToDirPath));
6707
6715
  }
6708
6716
  }
6709
6717
  changedCount++;
6710
6718
  }
6711
- return changedCount;
6719
+ return { count: changedCount, paths: changedPaths };
6712
6720
  }
6713
6721
  async removeAiDirs(aiDirs) {
6714
6722
  for (const aiDir of aiDirs) {
@@ -6805,7 +6813,7 @@ var RulesyncSkill = class _RulesyncSkill extends AiDir {
6805
6813
  }
6806
6814
  getFrontmatter() {
6807
6815
  if (!this.mainFile?.frontmatter) {
6808
- throw new Error("Frontmatter is not defined");
6816
+ throw new Error(`Frontmatter is not defined in ${(0, import_node_path57.join)(this.relativeDirPath, this.dirName)}`);
6809
6817
  }
6810
6818
  const result = RulesyncSkillFrontmatterSchema.parse(this.mainFile.frontmatter);
6811
6819
  return result;
@@ -6906,7 +6914,7 @@ var AgentsSkillsSkill = class _AgentsSkillsSkill extends ToolSkill {
6906
6914
  }
6907
6915
  getFrontmatter() {
6908
6916
  if (!this.mainFile?.frontmatter) {
6909
- throw new Error("Frontmatter is not defined");
6917
+ throw new Error(`Frontmatter is not defined in ${(0, import_node_path58.join)(this.relativeDirPath, this.dirName)}`);
6910
6918
  }
6911
6919
  const result = AgentsSkillsSkillFrontmatterSchema.parse(this.mainFile.frontmatter);
6912
6920
  return result;
@@ -7070,7 +7078,7 @@ var AntigravitySkill = class _AntigravitySkill extends ToolSkill {
7070
7078
  }
7071
7079
  getFrontmatter() {
7072
7080
  if (!this.mainFile?.frontmatter) {
7073
- throw new Error("Frontmatter is not defined");
7081
+ throw new Error(`Frontmatter is not defined in ${(0, import_node_path59.join)(this.relativeDirPath, this.dirName)}`);
7074
7082
  }
7075
7083
  const result = AntigravitySkillFrontmatterSchema.parse(this.mainFile.frontmatter);
7076
7084
  return result;
@@ -7229,7 +7237,7 @@ var ClaudecodeSkill = class _ClaudecodeSkill extends ToolSkill {
7229
7237
  }
7230
7238
  getFrontmatter() {
7231
7239
  if (!this.mainFile?.frontmatter) {
7232
- throw new Error("Frontmatter is not defined");
7240
+ throw new Error(`Frontmatter is not defined in ${(0, import_node_path60.join)(this.relativeDirPath, this.dirName)}`);
7233
7241
  }
7234
7242
  const result = ClaudecodeSkillFrontmatterSchema.parse(this.mainFile.frontmatter);
7235
7243
  return result;
@@ -7398,7 +7406,7 @@ var CodexCliSkill = class _CodexCliSkill extends ToolSkill {
7398
7406
  }
7399
7407
  getFrontmatter() {
7400
7408
  if (!this.mainFile?.frontmatter) {
7401
- throw new Error("Frontmatter is not defined");
7409
+ throw new Error(`Frontmatter is not defined in ${(0, import_node_path61.join)(this.relativeDirPath, this.dirName)}`);
7402
7410
  }
7403
7411
  const result = CodexCliSkillFrontmatterSchema.parse(this.mainFile.frontmatter);
7404
7412
  return result;
@@ -7568,7 +7576,7 @@ var CopilotSkill = class _CopilotSkill extends ToolSkill {
7568
7576
  }
7569
7577
  getFrontmatter() {
7570
7578
  if (!this.mainFile?.frontmatter) {
7571
- throw new Error("Frontmatter is not defined");
7579
+ throw new Error(`Frontmatter is not defined in ${(0, import_node_path62.join)(this.relativeDirPath, this.dirName)}`);
7572
7580
  }
7573
7581
  const result = CopilotSkillFrontmatterSchema.parse(this.mainFile.frontmatter);
7574
7582
  return result;
@@ -7731,7 +7739,7 @@ var CursorSkill = class _CursorSkill extends ToolSkill {
7731
7739
  }
7732
7740
  getFrontmatter() {
7733
7741
  if (!this.mainFile?.frontmatter) {
7734
- throw new Error("Frontmatter is not defined");
7742
+ throw new Error(`Frontmatter is not defined in ${(0, import_node_path63.join)(this.relativeDirPath, this.dirName)}`);
7735
7743
  }
7736
7744
  const result = CursorSkillFrontmatterSchema.parse(this.mainFile.frontmatter);
7737
7745
  return result;
@@ -7890,7 +7898,7 @@ var GeminiCliSkill = class _GeminiCliSkill extends ToolSkill {
7890
7898
  }
7891
7899
  getFrontmatter() {
7892
7900
  if (!this.mainFile?.frontmatter) {
7893
- throw new Error("Frontmatter is not defined");
7901
+ throw new Error(`Frontmatter is not defined in ${(0, import_node_path64.join)(this.relativeDirPath, this.dirName)}`);
7894
7902
  }
7895
7903
  const result = GeminiCliSkillFrontmatterSchema.parse(this.mainFile.frontmatter);
7896
7904
  return result;
@@ -8049,7 +8057,7 @@ var KiloSkill = class _KiloSkill extends ToolSkill {
8049
8057
  }
8050
8058
  getFrontmatter() {
8051
8059
  if (!this.mainFile?.frontmatter) {
8052
- throw new Error("Frontmatter is not defined");
8060
+ throw new Error(`Frontmatter is not defined in ${(0, import_node_path65.join)(this.relativeDirPath, this.dirName)}`);
8053
8061
  }
8054
8062
  const result = KiloSkillFrontmatterSchema.parse(this.mainFile.frontmatter);
8055
8063
  return result;
@@ -8227,7 +8235,7 @@ var KiroSkill = class _KiroSkill extends ToolSkill {
8227
8235
  }
8228
8236
  getFrontmatter() {
8229
8237
  if (!this.mainFile?.frontmatter) {
8230
- throw new Error("Frontmatter is not defined");
8238
+ throw new Error(`Frontmatter is not defined in ${(0, import_node_path66.join)(this.relativeDirPath, this.dirName)}`);
8231
8239
  }
8232
8240
  const result = KiroSkillFrontmatterSchema.parse(this.mainFile.frontmatter);
8233
8241
  return result;
@@ -8404,7 +8412,7 @@ var OpenCodeSkill = class _OpenCodeSkill extends ToolSkill {
8404
8412
  }
8405
8413
  getFrontmatter() {
8406
8414
  if (!this.mainFile?.frontmatter) {
8407
- throw new Error("Frontmatter is not defined");
8415
+ throw new Error(`Frontmatter is not defined in ${(0, import_node_path67.join)(this.relativeDirPath, this.dirName)}`);
8408
8416
  }
8409
8417
  const result = OpenCodeSkillFrontmatterSchema.parse(this.mainFile.frontmatter);
8410
8418
  return result;
@@ -8569,7 +8577,7 @@ var ReplitSkill = class _ReplitSkill extends ToolSkill {
8569
8577
  }
8570
8578
  getFrontmatter() {
8571
8579
  if (!this.mainFile?.frontmatter) {
8572
- throw new Error("Frontmatter is not defined");
8580
+ throw new Error(`Frontmatter is not defined in ${(0, import_node_path68.join)(this.relativeDirPath, this.dirName)}`);
8573
8581
  }
8574
8582
  const result = ReplitSkillFrontmatterSchema.parse(this.mainFile.frontmatter);
8575
8583
  return result;
@@ -8728,7 +8736,7 @@ var RooSkill = class _RooSkill extends ToolSkill {
8728
8736
  }
8729
8737
  getFrontmatter() {
8730
8738
  if (!this.mainFile?.frontmatter) {
8731
- throw new Error("Frontmatter is not defined");
8739
+ throw new Error(`Frontmatter is not defined in ${(0, import_node_path69.join)(this.relativeDirPath, this.dirName)}`);
8732
8740
  }
8733
8741
  const result = RooSkillFrontmatterSchema.parse(this.mainFile.frontmatter);
8734
8742
  return result;
@@ -8859,6 +8867,23 @@ var RooSkill = class _RooSkill extends ToolSkill {
8859
8867
  }
8860
8868
  };
8861
8869
 
8870
+ // src/features/skills/skills-utils.ts
8871
+ var import_node_path70 = require("path");
8872
+ async function getLocalSkillDirNames(baseDir) {
8873
+ const skillsDir = (0, import_node_path70.join)(baseDir, RULESYNC_SKILLS_RELATIVE_DIR_PATH);
8874
+ const names = /* @__PURE__ */ new Set();
8875
+ if (!await directoryExists(skillsDir)) {
8876
+ return names;
8877
+ }
8878
+ const dirPaths = await findFilesByGlobs((0, import_node_path70.join)(skillsDir, "*"), { type: "dir" });
8879
+ for (const dirPath of dirPaths) {
8880
+ const name = (0, import_node_path70.basename)(dirPath);
8881
+ if (name === (0, import_node_path70.basename)(RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH)) continue;
8882
+ names.add(name);
8883
+ }
8884
+ return names;
8885
+ }
8886
+
8862
8887
  // src/features/skills/skills-processor.ts
8863
8888
  var skillsProcessorToolTargetTuple = [
8864
8889
  "agentsmd",
@@ -9060,19 +9085,46 @@ var SkillsProcessor = class extends DirFeatureProcessor {
9060
9085
  /**
9061
9086
  * Implementation of abstract method from DirFeatureProcessor
9062
9087
  * Load and parse rulesync skill directories from .rulesync/skills/ directory
9088
+ * and also from .rulesync/skills/.curated/ for remote skills.
9089
+ * Local skills take precedence over curated skills with the same name.
9063
9090
  */
9064
9091
  async loadRulesyncDirs() {
9065
- const paths = RulesyncSkill.getSettablePaths();
9066
- const rulesyncSkillsDirPath = (0, import_node_path70.join)(this.baseDir, paths.relativeDirPath);
9067
- const dirPaths = await findFilesByGlobs((0, import_node_path70.join)(rulesyncSkillsDirPath, "*"), { type: "dir" });
9068
- const dirNames = dirPaths.map((path4) => (0, import_node_path70.basename)(path4));
9069
- const rulesyncSkills = await Promise.all(
9070
- dirNames.map(
9092
+ const localDirNames = [...await getLocalSkillDirNames(this.baseDir)];
9093
+ const localSkills = await Promise.all(
9094
+ localDirNames.map(
9071
9095
  (dirName) => RulesyncSkill.fromDir({ baseDir: this.baseDir, dirName, global: this.global })
9072
9096
  )
9073
9097
  );
9074
- logger.info(`Successfully loaded ${rulesyncSkills.length} rulesync skills`);
9075
- return rulesyncSkills;
9098
+ const localSkillNames = new Set(localDirNames);
9099
+ const curatedDirPath = (0, import_node_path71.join)(this.baseDir, RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH);
9100
+ let curatedSkills = [];
9101
+ if (await directoryExists(curatedDirPath)) {
9102
+ const curatedDirPaths = await findFilesByGlobs((0, import_node_path71.join)(curatedDirPath, "*"), { type: "dir" });
9103
+ const curatedDirNames = curatedDirPaths.map((path4) => (0, import_node_path71.basename)(path4));
9104
+ const nonConflicting = curatedDirNames.filter((name) => {
9105
+ if (localSkillNames.has(name)) {
9106
+ logger.debug(`Skipping curated skill "${name}": local skill takes precedence.`);
9107
+ return false;
9108
+ }
9109
+ return true;
9110
+ });
9111
+ const curatedRelativeDirPath = RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH;
9112
+ curatedSkills = await Promise.all(
9113
+ nonConflicting.map(
9114
+ (dirName) => RulesyncSkill.fromDir({
9115
+ baseDir: this.baseDir,
9116
+ relativeDirPath: curatedRelativeDirPath,
9117
+ dirName,
9118
+ global: this.global
9119
+ })
9120
+ )
9121
+ );
9122
+ }
9123
+ const allSkills = [...localSkills, ...curatedSkills];
9124
+ logger.debug(
9125
+ `Successfully loaded ${allSkills.length} rulesync skills (${localSkills.length} local, ${curatedSkills.length} curated)`
9126
+ );
9127
+ return allSkills;
9076
9128
  }
9077
9129
  /**
9078
9130
  * Implementation of abstract method from DirFeatureProcessor
@@ -9081,9 +9133,9 @@ var SkillsProcessor = class extends DirFeatureProcessor {
9081
9133
  async loadToolDirs() {
9082
9134
  const factory = this.getFactory(this.toolTarget);
9083
9135
  const paths = factory.class.getSettablePaths({ global: this.global });
9084
- const skillsDirPath = (0, import_node_path70.join)(this.baseDir, paths.relativeDirPath);
9085
- const dirPaths = await findFilesByGlobs((0, import_node_path70.join)(skillsDirPath, "*"), { type: "dir" });
9086
- const dirNames = dirPaths.map((path4) => (0, import_node_path70.basename)(path4));
9136
+ const skillsDirPath = (0, import_node_path71.join)(this.baseDir, paths.relativeDirPath);
9137
+ const dirPaths = await findFilesByGlobs((0, import_node_path71.join)(skillsDirPath, "*"), { type: "dir" });
9138
+ const dirNames = dirPaths.map((path4) => (0, import_node_path71.basename)(path4));
9087
9139
  const toolSkills = await Promise.all(
9088
9140
  dirNames.map(
9089
9141
  (dirName) => factory.class.fromDir({
@@ -9093,15 +9145,15 @@ var SkillsProcessor = class extends DirFeatureProcessor {
9093
9145
  })
9094
9146
  )
9095
9147
  );
9096
- logger.info(`Successfully loaded ${toolSkills.length} ${paths.relativeDirPath} skills`);
9148
+ logger.debug(`Successfully loaded ${toolSkills.length} ${paths.relativeDirPath} skills`);
9097
9149
  return toolSkills;
9098
9150
  }
9099
9151
  async loadToolDirsToDelete() {
9100
9152
  const factory = this.getFactory(this.toolTarget);
9101
9153
  const paths = factory.class.getSettablePaths({ global: this.global });
9102
- const skillsDirPath = (0, import_node_path70.join)(this.baseDir, paths.relativeDirPath);
9103
- const dirPaths = await findFilesByGlobs((0, import_node_path70.join)(skillsDirPath, "*"), { type: "dir" });
9104
- const dirNames = dirPaths.map((path4) => (0, import_node_path70.basename)(path4));
9154
+ const skillsDirPath = (0, import_node_path71.join)(this.baseDir, paths.relativeDirPath);
9155
+ const dirPaths = await findFilesByGlobs((0, import_node_path71.join)(skillsDirPath, "*"), { type: "dir" });
9156
+ const dirNames = dirPaths.map((path4) => (0, import_node_path71.basename)(path4));
9105
9157
  const toolSkills = dirNames.map(
9106
9158
  (dirName) => factory.class.forDeletion({
9107
9159
  baseDir: this.baseDir,
@@ -9110,7 +9162,7 @@ var SkillsProcessor = class extends DirFeatureProcessor {
9110
9162
  global: this.global
9111
9163
  })
9112
9164
  );
9113
- logger.info(
9165
+ logger.debug(
9114
9166
  `Successfully loaded ${toolSkills.length} ${paths.relativeDirPath} skills for deletion`
9115
9167
  );
9116
9168
  return toolSkills;
@@ -9162,10 +9214,10 @@ var SkillsProcessor = class extends DirFeatureProcessor {
9162
9214
  };
9163
9215
 
9164
9216
  // src/features/subagents/agentsmd-subagent.ts
9165
- var import_node_path72 = require("path");
9217
+ var import_node_path73 = require("path");
9166
9218
 
9167
9219
  // src/features/subagents/simulated-subagent.ts
9168
- var import_node_path71 = require("path");
9220
+ var import_node_path72 = require("path");
9169
9221
  var import_mini34 = require("zod/mini");
9170
9222
 
9171
9223
  // src/features/subagents/tool-subagent.ts
@@ -9221,7 +9273,7 @@ var SimulatedSubagent = class extends ToolSubagent {
9221
9273
  const result = SimulatedSubagentFrontmatterSchema.safeParse(frontmatter);
9222
9274
  if (!result.success) {
9223
9275
  throw new Error(
9224
- `Invalid frontmatter in ${(0, import_node_path71.join)(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
9276
+ `Invalid frontmatter in ${(0, import_node_path72.join)(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
9225
9277
  );
9226
9278
  }
9227
9279
  }
@@ -9272,7 +9324,7 @@ var SimulatedSubagent = class extends ToolSubagent {
9272
9324
  return {
9273
9325
  success: false,
9274
9326
  error: new Error(
9275
- `Invalid frontmatter in ${(0, import_node_path71.join)(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
9327
+ `Invalid frontmatter in ${(0, import_node_path72.join)(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
9276
9328
  )
9277
9329
  };
9278
9330
  }
@@ -9282,7 +9334,7 @@ var SimulatedSubagent = class extends ToolSubagent {
9282
9334
  relativeFilePath,
9283
9335
  validate = true
9284
9336
  }) {
9285
- const filePath = (0, import_node_path71.join)(baseDir, this.getSettablePaths().relativeDirPath, relativeFilePath);
9337
+ const filePath = (0, import_node_path72.join)(baseDir, this.getSettablePaths().relativeDirPath, relativeFilePath);
9286
9338
  const fileContent = await readFileContent(filePath);
9287
9339
  const { frontmatter, body: content } = parseFrontmatter(fileContent);
9288
9340
  const result = SimulatedSubagentFrontmatterSchema.safeParse(frontmatter);
@@ -9292,7 +9344,7 @@ var SimulatedSubagent = class extends ToolSubagent {
9292
9344
  return {
9293
9345
  baseDir,
9294
9346
  relativeDirPath: this.getSettablePaths().relativeDirPath,
9295
- relativeFilePath: (0, import_node_path71.basename)(relativeFilePath),
9347
+ relativeFilePath: (0, import_node_path72.basename)(relativeFilePath),
9296
9348
  frontmatter: result.data,
9297
9349
  body: content.trim(),
9298
9350
  validate
@@ -9318,7 +9370,7 @@ var SimulatedSubagent = class extends ToolSubagent {
9318
9370
  var AgentsmdSubagent = class _AgentsmdSubagent extends SimulatedSubagent {
9319
9371
  static getSettablePaths() {
9320
9372
  return {
9321
- relativeDirPath: (0, import_node_path72.join)(".agents", "subagents")
9373
+ relativeDirPath: (0, import_node_path73.join)(".agents", "subagents")
9322
9374
  };
9323
9375
  }
9324
9376
  static async fromFile(params) {
@@ -9341,11 +9393,11 @@ var AgentsmdSubagent = class _AgentsmdSubagent extends SimulatedSubagent {
9341
9393
  };
9342
9394
 
9343
9395
  // src/features/subagents/codexcli-subagent.ts
9344
- var import_node_path73 = require("path");
9396
+ var import_node_path74 = require("path");
9345
9397
  var CodexCliSubagent = class _CodexCliSubagent extends SimulatedSubagent {
9346
9398
  static getSettablePaths() {
9347
9399
  return {
9348
- relativeDirPath: (0, import_node_path73.join)(".codex", "subagents")
9400
+ relativeDirPath: (0, import_node_path74.join)(".codex", "subagents")
9349
9401
  };
9350
9402
  }
9351
9403
  static async fromFile(params) {
@@ -9368,11 +9420,11 @@ var CodexCliSubagent = class _CodexCliSubagent extends SimulatedSubagent {
9368
9420
  };
9369
9421
 
9370
9422
  // src/features/subagents/factorydroid-subagent.ts
9371
- var import_node_path74 = require("path");
9423
+ var import_node_path75 = require("path");
9372
9424
  var FactorydroidSubagent = class _FactorydroidSubagent extends SimulatedSubagent {
9373
9425
  static getSettablePaths(_options) {
9374
9426
  return {
9375
- relativeDirPath: (0, import_node_path74.join)(".factory", "droids")
9427
+ relativeDirPath: (0, import_node_path75.join)(".factory", "droids")
9376
9428
  };
9377
9429
  }
9378
9430
  static async fromFile(params) {
@@ -9395,11 +9447,11 @@ var FactorydroidSubagent = class _FactorydroidSubagent extends SimulatedSubagent
9395
9447
  };
9396
9448
 
9397
9449
  // src/features/subagents/geminicli-subagent.ts
9398
- var import_node_path75 = require("path");
9450
+ var import_node_path76 = require("path");
9399
9451
  var GeminiCliSubagent = class _GeminiCliSubagent extends SimulatedSubagent {
9400
9452
  static getSettablePaths() {
9401
9453
  return {
9402
- relativeDirPath: (0, import_node_path75.join)(".gemini", "subagents")
9454
+ relativeDirPath: (0, import_node_path76.join)(".gemini", "subagents")
9403
9455
  };
9404
9456
  }
9405
9457
  static async fromFile(params) {
@@ -9422,11 +9474,11 @@ var GeminiCliSubagent = class _GeminiCliSubagent extends SimulatedSubagent {
9422
9474
  };
9423
9475
 
9424
9476
  // src/features/subagents/roo-subagent.ts
9425
- var import_node_path76 = require("path");
9477
+ var import_node_path77 = require("path");
9426
9478
  var RooSubagent = class _RooSubagent extends SimulatedSubagent {
9427
9479
  static getSettablePaths() {
9428
9480
  return {
9429
- relativeDirPath: (0, import_node_path76.join)(".roo", "subagents")
9481
+ relativeDirPath: (0, import_node_path77.join)(".roo", "subagents")
9430
9482
  };
9431
9483
  }
9432
9484
  static async fromFile(params) {
@@ -9449,15 +9501,15 @@ var RooSubagent = class _RooSubagent extends SimulatedSubagent {
9449
9501
  };
9450
9502
 
9451
9503
  // src/features/subagents/subagents-processor.ts
9452
- var import_node_path83 = require("path");
9504
+ var import_node_path84 = require("path");
9453
9505
  var import_mini41 = require("zod/mini");
9454
9506
 
9455
9507
  // src/features/subagents/claudecode-subagent.ts
9456
- var import_node_path78 = require("path");
9508
+ var import_node_path79 = require("path");
9457
9509
  var import_mini36 = require("zod/mini");
9458
9510
 
9459
9511
  // src/features/subagents/rulesync-subagent.ts
9460
- var import_node_path77 = require("path");
9512
+ var import_node_path78 = require("path");
9461
9513
  var import_mini35 = require("zod/mini");
9462
9514
  var RulesyncSubagentFrontmatterSchema = import_mini35.z.looseObject({
9463
9515
  targets: import_mini35.z._default(RulesyncTargetsSchema, ["*"]),
@@ -9471,7 +9523,7 @@ var RulesyncSubagent = class _RulesyncSubagent extends RulesyncFile {
9471
9523
  const parseResult = RulesyncSubagentFrontmatterSchema.safeParse(frontmatter);
9472
9524
  if (!parseResult.success && rest.validate !== false) {
9473
9525
  throw new Error(
9474
- `Invalid frontmatter in ${(0, import_node_path77.join)(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(parseResult.error)}`
9526
+ `Invalid frontmatter in ${(0, import_node_path78.join)(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(parseResult.error)}`
9475
9527
  );
9476
9528
  }
9477
9529
  const parsedFrontmatter = parseResult.success ? { ...frontmatter, ...parseResult.data } : { ...frontmatter, targets: frontmatter?.targets ?? ["*"] };
@@ -9504,7 +9556,7 @@ var RulesyncSubagent = class _RulesyncSubagent extends RulesyncFile {
9504
9556
  return {
9505
9557
  success: false,
9506
9558
  error: new Error(
9507
- `Invalid frontmatter in ${(0, import_node_path77.join)(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
9559
+ `Invalid frontmatter in ${(0, import_node_path78.join)(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
9508
9560
  )
9509
9561
  };
9510
9562
  }
@@ -9513,14 +9565,14 @@ var RulesyncSubagent = class _RulesyncSubagent extends RulesyncFile {
9513
9565
  relativeFilePath
9514
9566
  }) {
9515
9567
  const fileContent = await readFileContent(
9516
- (0, import_node_path77.join)(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, relativeFilePath)
9568
+ (0, import_node_path78.join)(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, relativeFilePath)
9517
9569
  );
9518
9570
  const { frontmatter, body: content } = parseFrontmatter(fileContent);
9519
9571
  const result = RulesyncSubagentFrontmatterSchema.safeParse(frontmatter);
9520
9572
  if (!result.success) {
9521
9573
  throw new Error(`Invalid frontmatter in ${relativeFilePath}: ${formatError(result.error)}`);
9522
9574
  }
9523
- const filename = (0, import_node_path77.basename)(relativeFilePath);
9575
+ const filename = (0, import_node_path78.basename)(relativeFilePath);
9524
9576
  return new _RulesyncSubagent({
9525
9577
  baseDir: process.cwd(),
9526
9578
  relativeDirPath: this.getSettablePaths().relativeDirPath,
@@ -9548,7 +9600,7 @@ var ClaudecodeSubagent = class _ClaudecodeSubagent extends ToolSubagent {
9548
9600
  const result = ClaudecodeSubagentFrontmatterSchema.safeParse(frontmatter);
9549
9601
  if (!result.success) {
9550
9602
  throw new Error(
9551
- `Invalid frontmatter in ${(0, import_node_path78.join)(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
9603
+ `Invalid frontmatter in ${(0, import_node_path79.join)(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
9552
9604
  );
9553
9605
  }
9554
9606
  }
@@ -9560,7 +9612,7 @@ var ClaudecodeSubagent = class _ClaudecodeSubagent extends ToolSubagent {
9560
9612
  }
9561
9613
  static getSettablePaths(_options = {}) {
9562
9614
  return {
9563
- relativeDirPath: (0, import_node_path78.join)(".claude", "agents")
9615
+ relativeDirPath: (0, import_node_path79.join)(".claude", "agents")
9564
9616
  };
9565
9617
  }
9566
9618
  getFrontmatter() {
@@ -9607,7 +9659,9 @@ var ClaudecodeSubagent = class _ClaudecodeSubagent extends ToolSubagent {
9607
9659
  };
9608
9660
  const result = ClaudecodeSubagentFrontmatterSchema.safeParse(rawClaudecodeFrontmatter);
9609
9661
  if (!result.success) {
9610
- throw new Error(`Invalid claudecode subagent frontmatter: ${formatError(result.error)}`);
9662
+ throw new Error(
9663
+ `Invalid claudecode subagent frontmatter in ${rulesyncSubagent.getRelativeFilePath()}: ${formatError(result.error)}`
9664
+ );
9611
9665
  }
9612
9666
  const claudecodeFrontmatter = result.data;
9613
9667
  const body = rulesyncSubagent.getBody();
@@ -9634,7 +9688,7 @@ var ClaudecodeSubagent = class _ClaudecodeSubagent extends ToolSubagent {
9634
9688
  return {
9635
9689
  success: false,
9636
9690
  error: new Error(
9637
- `Invalid frontmatter in ${(0, import_node_path78.join)(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
9691
+ `Invalid frontmatter in ${(0, import_node_path79.join)(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
9638
9692
  )
9639
9693
  };
9640
9694
  }
@@ -9652,7 +9706,7 @@ var ClaudecodeSubagent = class _ClaudecodeSubagent extends ToolSubagent {
9652
9706
  global = false
9653
9707
  }) {
9654
9708
  const paths = this.getSettablePaths({ global });
9655
- const filePath = (0, import_node_path78.join)(baseDir, paths.relativeDirPath, relativeFilePath);
9709
+ const filePath = (0, import_node_path79.join)(baseDir, paths.relativeDirPath, relativeFilePath);
9656
9710
  const fileContent = await readFileContent(filePath);
9657
9711
  const { frontmatter, body: content } = parseFrontmatter(fileContent);
9658
9712
  const result = ClaudecodeSubagentFrontmatterSchema.safeParse(frontmatter);
@@ -9687,7 +9741,7 @@ var ClaudecodeSubagent = class _ClaudecodeSubagent extends ToolSubagent {
9687
9741
  };
9688
9742
 
9689
9743
  // src/features/subagents/copilot-subagent.ts
9690
- var import_node_path79 = require("path");
9744
+ var import_node_path80 = require("path");
9691
9745
  var import_mini37 = require("zod/mini");
9692
9746
  var REQUIRED_TOOL = "agent/runSubagent";
9693
9747
  var CopilotSubagentFrontmatterSchema = import_mini37.z.looseObject({
@@ -9713,7 +9767,7 @@ var CopilotSubagent = class _CopilotSubagent extends ToolSubagent {
9713
9767
  const result = CopilotSubagentFrontmatterSchema.safeParse(frontmatter);
9714
9768
  if (!result.success) {
9715
9769
  throw new Error(
9716
- `Invalid frontmatter in ${(0, import_node_path79.join)(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
9770
+ `Invalid frontmatter in ${(0, import_node_path80.join)(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
9717
9771
  );
9718
9772
  }
9719
9773
  }
@@ -9725,7 +9779,7 @@ var CopilotSubagent = class _CopilotSubagent extends ToolSubagent {
9725
9779
  }
9726
9780
  static getSettablePaths(_options = {}) {
9727
9781
  return {
9728
- relativeDirPath: (0, import_node_path79.join)(".github", "agents")
9782
+ relativeDirPath: (0, import_node_path80.join)(".github", "agents")
9729
9783
  };
9730
9784
  }
9731
9785
  getFrontmatter() {
@@ -9799,7 +9853,7 @@ var CopilotSubagent = class _CopilotSubagent extends ToolSubagent {
9799
9853
  return {
9800
9854
  success: false,
9801
9855
  error: new Error(
9802
- `Invalid frontmatter in ${(0, import_node_path79.join)(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
9856
+ `Invalid frontmatter in ${(0, import_node_path80.join)(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
9803
9857
  )
9804
9858
  };
9805
9859
  }
@@ -9817,7 +9871,7 @@ var CopilotSubagent = class _CopilotSubagent extends ToolSubagent {
9817
9871
  global = false
9818
9872
  }) {
9819
9873
  const paths = this.getSettablePaths({ global });
9820
- const filePath = (0, import_node_path79.join)(baseDir, paths.relativeDirPath, relativeFilePath);
9874
+ const filePath = (0, import_node_path80.join)(baseDir, paths.relativeDirPath, relativeFilePath);
9821
9875
  const fileContent = await readFileContent(filePath);
9822
9876
  const { frontmatter, body: content } = parseFrontmatter(fileContent);
9823
9877
  const result = CopilotSubagentFrontmatterSchema.safeParse(frontmatter);
@@ -9853,7 +9907,7 @@ var CopilotSubagent = class _CopilotSubagent extends ToolSubagent {
9853
9907
  };
9854
9908
 
9855
9909
  // src/features/subagents/cursor-subagent.ts
9856
- var import_node_path80 = require("path");
9910
+ var import_node_path81 = require("path");
9857
9911
  var import_mini38 = require("zod/mini");
9858
9912
  var CursorSubagentFrontmatterSchema = import_mini38.z.looseObject({
9859
9913
  name: import_mini38.z.string(),
@@ -9867,7 +9921,7 @@ var CursorSubagent = class _CursorSubagent extends ToolSubagent {
9867
9921
  const result = CursorSubagentFrontmatterSchema.safeParse(frontmatter);
9868
9922
  if (!result.success) {
9869
9923
  throw new Error(
9870
- `Invalid frontmatter in ${(0, import_node_path80.join)(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
9924
+ `Invalid frontmatter in ${(0, import_node_path81.join)(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
9871
9925
  );
9872
9926
  }
9873
9927
  }
@@ -9879,7 +9933,7 @@ var CursorSubagent = class _CursorSubagent extends ToolSubagent {
9879
9933
  }
9880
9934
  static getSettablePaths(_options = {}) {
9881
9935
  return {
9882
- relativeDirPath: (0, import_node_path80.join)(".cursor", "agents")
9936
+ relativeDirPath: (0, import_node_path81.join)(".cursor", "agents")
9883
9937
  };
9884
9938
  }
9885
9939
  getFrontmatter() {
@@ -9946,7 +10000,7 @@ var CursorSubagent = class _CursorSubagent extends ToolSubagent {
9946
10000
  return {
9947
10001
  success: false,
9948
10002
  error: new Error(
9949
- `Invalid frontmatter in ${(0, import_node_path80.join)(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
10003
+ `Invalid frontmatter in ${(0, import_node_path81.join)(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
9950
10004
  )
9951
10005
  };
9952
10006
  }
@@ -9964,7 +10018,7 @@ var CursorSubagent = class _CursorSubagent extends ToolSubagent {
9964
10018
  global = false
9965
10019
  }) {
9966
10020
  const paths = this.getSettablePaths({ global });
9967
- const filePath = (0, import_node_path80.join)(baseDir, paths.relativeDirPath, relativeFilePath);
10021
+ const filePath = (0, import_node_path81.join)(baseDir, paths.relativeDirPath, relativeFilePath);
9968
10022
  const fileContent = await readFileContent(filePath);
9969
10023
  const { frontmatter, body: content } = parseFrontmatter(fileContent);
9970
10024
  const result = CursorSubagentFrontmatterSchema.safeParse(frontmatter);
@@ -10000,7 +10054,7 @@ var CursorSubagent = class _CursorSubagent extends ToolSubagent {
10000
10054
  };
10001
10055
 
10002
10056
  // src/features/subagents/kiro-subagent.ts
10003
- var import_node_path81 = require("path");
10057
+ var import_node_path82 = require("path");
10004
10058
  var import_mini39 = require("zod/mini");
10005
10059
  var KiroCliSubagentJsonSchema = import_mini39.z.looseObject({
10006
10060
  name: import_mini39.z.string(),
@@ -10028,7 +10082,7 @@ var KiroSubagent = class _KiroSubagent extends ToolSubagent {
10028
10082
  }
10029
10083
  static getSettablePaths(_options = {}) {
10030
10084
  return {
10031
- relativeDirPath: (0, import_node_path81.join)(".kiro", "agents")
10085
+ relativeDirPath: (0, import_node_path82.join)(".kiro", "agents")
10032
10086
  };
10033
10087
  }
10034
10088
  getBody() {
@@ -10108,7 +10162,7 @@ var KiroSubagent = class _KiroSubagent extends ToolSubagent {
10108
10162
  global = false
10109
10163
  }) {
10110
10164
  const paths = this.getSettablePaths({ global });
10111
- const filePath = (0, import_node_path81.join)(baseDir, paths.relativeDirPath, relativeFilePath);
10165
+ const filePath = (0, import_node_path82.join)(baseDir, paths.relativeDirPath, relativeFilePath);
10112
10166
  const fileContent = await readFileContent(filePath);
10113
10167
  return new _KiroSubagent({
10114
10168
  baseDir,
@@ -10137,11 +10191,11 @@ var KiroSubagent = class _KiroSubagent extends ToolSubagent {
10137
10191
  };
10138
10192
 
10139
10193
  // src/features/subagents/opencode-subagent.ts
10140
- var import_node_path82 = require("path");
10194
+ var import_node_path83 = require("path");
10141
10195
  var import_mini40 = require("zod/mini");
10142
10196
  var OpenCodeSubagentFrontmatterSchema = import_mini40.z.looseObject({
10143
10197
  description: import_mini40.z.string(),
10144
- mode: import_mini40.z.literal("subagent"),
10198
+ mode: import_mini40.z.optional(import_mini40.z._default(import_mini40.z.string(), "subagent")),
10145
10199
  name: import_mini40.z.optional(import_mini40.z.string())
10146
10200
  });
10147
10201
  var OpenCodeSubagent = class _OpenCodeSubagent extends ToolSubagent {
@@ -10152,7 +10206,7 @@ var OpenCodeSubagent = class _OpenCodeSubagent extends ToolSubagent {
10152
10206
  const result = OpenCodeSubagentFrontmatterSchema.safeParse(frontmatter);
10153
10207
  if (!result.success) {
10154
10208
  throw new Error(
10155
- `Invalid frontmatter in ${(0, import_node_path82.join)(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
10209
+ `Invalid frontmatter in ${(0, import_node_path83.join)(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
10156
10210
  );
10157
10211
  }
10158
10212
  }
@@ -10166,7 +10220,7 @@ var OpenCodeSubagent = class _OpenCodeSubagent extends ToolSubagent {
10166
10220
  global = false
10167
10221
  } = {}) {
10168
10222
  return {
10169
- relativeDirPath: global ? (0, import_node_path82.join)(".config", "opencode", "agent") : (0, import_node_path82.join)(".opencode", "agent")
10223
+ relativeDirPath: global ? (0, import_node_path83.join)(".config", "opencode", "agent") : (0, import_node_path83.join)(".opencode", "agent")
10170
10224
  };
10171
10225
  }
10172
10226
  getFrontmatter() {
@@ -10179,7 +10233,7 @@ var OpenCodeSubagent = class _OpenCodeSubagent extends ToolSubagent {
10179
10233
  const { description, mode, name, ...opencodeSection } = this.frontmatter;
10180
10234
  const rulesyncFrontmatter = {
10181
10235
  targets: ["*"],
10182
- name: name ?? (0, import_node_path82.basename)(this.getRelativeFilePath(), ".md"),
10236
+ name: name ?? (0, import_node_path83.basename)(this.getRelativeFilePath(), ".md"),
10183
10237
  description,
10184
10238
  opencode: { mode, ...opencodeSection }
10185
10239
  };
@@ -10232,7 +10286,7 @@ var OpenCodeSubagent = class _OpenCodeSubagent extends ToolSubagent {
10232
10286
  return {
10233
10287
  success: false,
10234
10288
  error: new Error(
10235
- `Invalid frontmatter in ${(0, import_node_path82.join)(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
10289
+ `Invalid frontmatter in ${(0, import_node_path83.join)(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
10236
10290
  )
10237
10291
  };
10238
10292
  }
@@ -10249,7 +10303,7 @@ var OpenCodeSubagent = class _OpenCodeSubagent extends ToolSubagent {
10249
10303
  global = false
10250
10304
  }) {
10251
10305
  const paths = this.getSettablePaths({ global });
10252
- const filePath = (0, import_node_path82.join)(baseDir, paths.relativeDirPath, relativeFilePath);
10306
+ const filePath = (0, import_node_path83.join)(baseDir, paths.relativeDirPath, relativeFilePath);
10253
10307
  const fileContent = await readFileContent(filePath);
10254
10308
  const { frontmatter, body: content } = parseFrontmatter(fileContent);
10255
10309
  const result = OpenCodeSubagentFrontmatterSchema.safeParse(frontmatter);
@@ -10460,7 +10514,7 @@ var SubagentsProcessor = class extends FeatureProcessor {
10460
10514
  * Load and parse rulesync subagent files from .rulesync/subagents/ directory
10461
10515
  */
10462
10516
  async loadRulesyncFiles() {
10463
- const subagentsDir = (0, import_node_path83.join)(this.baseDir, RulesyncSubagent.getSettablePaths().relativeDirPath);
10517
+ const subagentsDir = (0, import_node_path84.join)(this.baseDir, RulesyncSubagent.getSettablePaths().relativeDirPath);
10464
10518
  const dirExists = await directoryExists(subagentsDir);
10465
10519
  if (!dirExists) {
10466
10520
  logger.debug(`Rulesync subagents directory not found: ${subagentsDir}`);
@@ -10472,10 +10526,10 @@ var SubagentsProcessor = class extends FeatureProcessor {
10472
10526
  logger.debug(`No markdown files found in rulesync subagents directory: ${subagentsDir}`);
10473
10527
  return [];
10474
10528
  }
10475
- logger.info(`Found ${mdFiles.length} subagent files in ${subagentsDir}`);
10529
+ logger.debug(`Found ${mdFiles.length} subagent files in ${subagentsDir}`);
10476
10530
  const rulesyncSubagents = [];
10477
10531
  for (const mdFile of mdFiles) {
10478
- const filepath = (0, import_node_path83.join)(subagentsDir, mdFile);
10532
+ const filepath = (0, import_node_path84.join)(subagentsDir, mdFile);
10479
10533
  try {
10480
10534
  const rulesyncSubagent = await RulesyncSubagent.fromFile({
10481
10535
  relativeFilePath: mdFile,
@@ -10484,7 +10538,7 @@ var SubagentsProcessor = class extends FeatureProcessor {
10484
10538
  rulesyncSubagents.push(rulesyncSubagent);
10485
10539
  logger.debug(`Successfully loaded subagent: ${mdFile}`);
10486
10540
  } catch (error) {
10487
- logger.warn(`Failed to load subagent file ${filepath}:`, error);
10541
+ logger.warn(`Failed to load subagent file ${filepath}: ${formatError(error)}`);
10488
10542
  continue;
10489
10543
  }
10490
10544
  }
@@ -10492,7 +10546,7 @@ var SubagentsProcessor = class extends FeatureProcessor {
10492
10546
  logger.debug(`No valid subagents found in ${subagentsDir}`);
10493
10547
  return [];
10494
10548
  }
10495
- logger.info(`Successfully loaded ${rulesyncSubagents.length} rulesync subagents`);
10549
+ logger.debug(`Successfully loaded ${rulesyncSubagents.length} rulesync subagents`);
10496
10550
  return rulesyncSubagents;
10497
10551
  }
10498
10552
  /**
@@ -10505,30 +10559,32 @@ var SubagentsProcessor = class extends FeatureProcessor {
10505
10559
  const factory = this.getFactory(this.toolTarget);
10506
10560
  const paths = factory.class.getSettablePaths({ global: this.global });
10507
10561
  const subagentFilePaths = await findFilesByGlobs(
10508
- (0, import_node_path83.join)(this.baseDir, paths.relativeDirPath, factory.meta.filePattern)
10562
+ (0, import_node_path84.join)(this.baseDir, paths.relativeDirPath, factory.meta.filePattern)
10509
10563
  );
10510
10564
  if (forDeletion) {
10511
10565
  const toolSubagents2 = subagentFilePaths.map(
10512
10566
  (path4) => factory.class.forDeletion({
10513
10567
  baseDir: this.baseDir,
10514
10568
  relativeDirPath: paths.relativeDirPath,
10515
- relativeFilePath: (0, import_node_path83.basename)(path4),
10569
+ relativeFilePath: (0, import_node_path84.basename)(path4),
10516
10570
  global: this.global
10517
10571
  })
10518
10572
  ).filter((subagent) => subagent.isDeletable());
10519
- logger.info(`Successfully loaded ${toolSubagents2.length} ${paths.relativeDirPath} subagents`);
10573
+ logger.debug(
10574
+ `Successfully loaded ${toolSubagents2.length} ${paths.relativeDirPath} subagents`
10575
+ );
10520
10576
  return toolSubagents2;
10521
10577
  }
10522
10578
  const toolSubagents = await Promise.all(
10523
10579
  subagentFilePaths.map(
10524
10580
  (path4) => factory.class.fromFile({
10525
10581
  baseDir: this.baseDir,
10526
- relativeFilePath: (0, import_node_path83.basename)(path4),
10582
+ relativeFilePath: (0, import_node_path84.basename)(path4),
10527
10583
  global: this.global
10528
10584
  })
10529
10585
  )
10530
10586
  );
10531
- logger.info(`Successfully loaded ${toolSubagents.length} ${paths.relativeDirPath} subagents`);
10587
+ logger.debug(`Successfully loaded ${toolSubagents.length} ${paths.relativeDirPath} subagents`);
10532
10588
  return toolSubagents;
10533
10589
  }
10534
10590
  /**
@@ -10568,13 +10624,13 @@ var SubagentsProcessor = class extends FeatureProcessor {
10568
10624
  };
10569
10625
 
10570
10626
  // src/features/rules/agentsmd-rule.ts
10571
- var import_node_path86 = require("path");
10627
+ var import_node_path87 = require("path");
10572
10628
 
10573
10629
  // src/features/rules/tool-rule.ts
10574
- var import_node_path85 = require("path");
10630
+ var import_node_path86 = require("path");
10575
10631
 
10576
10632
  // src/features/rules/rulesync-rule.ts
10577
- var import_node_path84 = require("path");
10633
+ var import_node_path85 = require("path");
10578
10634
  var import_mini42 = require("zod/mini");
10579
10635
  var RulesyncRuleFrontmatterSchema = import_mini42.z.object({
10580
10636
  root: import_mini42.z.optional(import_mini42.z.boolean()),
@@ -10621,7 +10677,7 @@ var RulesyncRule = class _RulesyncRule extends RulesyncFile {
10621
10677
  const parseResult = RulesyncRuleFrontmatterSchema.safeParse(frontmatter);
10622
10678
  if (!parseResult.success && rest.validate !== false) {
10623
10679
  throw new Error(
10624
- `Invalid frontmatter in ${(0, import_node_path84.join)(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(parseResult.error)}`
10680
+ `Invalid frontmatter in ${(0, import_node_path85.join)(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(parseResult.error)}`
10625
10681
  );
10626
10682
  }
10627
10683
  const parsedFrontmatter = parseResult.success ? parseResult.data : { ...frontmatter, targets: frontmatter.targets ?? ["*"] };
@@ -10656,7 +10712,7 @@ var RulesyncRule = class _RulesyncRule extends RulesyncFile {
10656
10712
  return {
10657
10713
  success: false,
10658
10714
  error: new Error(
10659
- `Invalid frontmatter in ${(0, import_node_path84.join)(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
10715
+ `Invalid frontmatter in ${(0, import_node_path85.join)(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
10660
10716
  )
10661
10717
  };
10662
10718
  }
@@ -10665,7 +10721,7 @@ var RulesyncRule = class _RulesyncRule extends RulesyncFile {
10665
10721
  relativeFilePath,
10666
10722
  validate = true
10667
10723
  }) {
10668
- const filePath = (0, import_node_path84.join)(
10724
+ const filePath = (0, import_node_path85.join)(
10669
10725
  process.cwd(),
10670
10726
  this.getSettablePaths().recommended.relativeDirPath,
10671
10727
  relativeFilePath
@@ -10749,7 +10805,7 @@ var ToolRule = class extends ToolFile {
10749
10805
  };
10750
10806
  }
10751
10807
  if (!nonRootPath) {
10752
- throw new Error("nonRootPath is not set");
10808
+ throw new Error(`nonRootPath is not set for ${rulesyncRule.getRelativeFilePath()}`);
10753
10809
  }
10754
10810
  return {
10755
10811
  baseDir,
@@ -10767,7 +10823,7 @@ var ToolRule = class extends ToolFile {
10767
10823
  rulesyncRule,
10768
10824
  validate = true,
10769
10825
  rootPath = { relativeDirPath: ".", relativeFilePath: "AGENTS.md" },
10770
- nonRootPath = { relativeDirPath: (0, import_node_path85.join)(".agents", "memories") }
10826
+ nonRootPath = { relativeDirPath: (0, import_node_path86.join)(".agents", "memories") }
10771
10827
  }) {
10772
10828
  const params = this.buildToolRuleParamsDefault({
10773
10829
  baseDir,
@@ -10778,7 +10834,7 @@ var ToolRule = class extends ToolFile {
10778
10834
  });
10779
10835
  const rulesyncFrontmatter = rulesyncRule.getFrontmatter();
10780
10836
  if (!rulesyncFrontmatter.root && rulesyncFrontmatter.agentsmd?.subprojectPath) {
10781
- params.relativeDirPath = (0, import_node_path85.join)(rulesyncFrontmatter.agentsmd.subprojectPath);
10837
+ params.relativeDirPath = (0, import_node_path86.join)(rulesyncFrontmatter.agentsmd.subprojectPath);
10782
10838
  params.relativeFilePath = "AGENTS.md";
10783
10839
  }
10784
10840
  return params;
@@ -10827,7 +10883,7 @@ var ToolRule = class extends ToolFile {
10827
10883
  }
10828
10884
  };
10829
10885
  function buildToolPath(toolDir, subDir, excludeToolDir) {
10830
- return excludeToolDir ? subDir : (0, import_node_path85.join)(toolDir, subDir);
10886
+ return excludeToolDir ? subDir : (0, import_node_path86.join)(toolDir, subDir);
10831
10887
  }
10832
10888
 
10833
10889
  // src/features/rules/agentsmd-rule.ts
@@ -10856,8 +10912,8 @@ var AgentsMdRule = class _AgentsMdRule extends ToolRule {
10856
10912
  validate = true
10857
10913
  }) {
10858
10914
  const isRoot = relativeFilePath === "AGENTS.md";
10859
- const relativePath = isRoot ? "AGENTS.md" : (0, import_node_path86.join)(".agents", "memories", relativeFilePath);
10860
- const fileContent = await readFileContent((0, import_node_path86.join)(baseDir, relativePath));
10915
+ const relativePath = isRoot ? "AGENTS.md" : (0, import_node_path87.join)(".agents", "memories", relativeFilePath);
10916
+ const fileContent = await readFileContent((0, import_node_path87.join)(baseDir, relativePath));
10861
10917
  return new _AgentsMdRule({
10862
10918
  baseDir,
10863
10919
  relativeDirPath: isRoot ? this.getSettablePaths().root.relativeDirPath : this.getSettablePaths().nonRoot.relativeDirPath,
@@ -10912,7 +10968,7 @@ var AgentsMdRule = class _AgentsMdRule extends ToolRule {
10912
10968
  };
10913
10969
 
10914
10970
  // src/features/rules/antigravity-rule.ts
10915
- var import_node_path87 = require("path");
10971
+ var import_node_path88 = require("path");
10916
10972
  var import_mini43 = require("zod/mini");
10917
10973
  var AntigravityRuleFrontmatterSchema = import_mini43.z.looseObject({
10918
10974
  trigger: import_mini43.z.optional(
@@ -11071,7 +11127,7 @@ var AntigravityRule = class _AntigravityRule extends ToolRule {
11071
11127
  const result = AntigravityRuleFrontmatterSchema.safeParse(frontmatter);
11072
11128
  if (!result.success) {
11073
11129
  throw new Error(
11074
- `Invalid frontmatter in ${(0, import_node_path87.join)(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
11130
+ `Invalid frontmatter in ${(0, import_node_path88.join)(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
11075
11131
  );
11076
11132
  }
11077
11133
  }
@@ -11095,7 +11151,7 @@ var AntigravityRule = class _AntigravityRule extends ToolRule {
11095
11151
  relativeFilePath,
11096
11152
  validate = true
11097
11153
  }) {
11098
- const filePath = (0, import_node_path87.join)(
11154
+ const filePath = (0, import_node_path88.join)(
11099
11155
  baseDir,
11100
11156
  this.getSettablePaths().nonRoot.relativeDirPath,
11101
11157
  relativeFilePath
@@ -11236,7 +11292,7 @@ var AntigravityRule = class _AntigravityRule extends ToolRule {
11236
11292
  };
11237
11293
 
11238
11294
  // src/features/rules/augmentcode-legacy-rule.ts
11239
- var import_node_path88 = require("path");
11295
+ var import_node_path89 = require("path");
11240
11296
  var AugmentcodeLegacyRule = class _AugmentcodeLegacyRule extends ToolRule {
11241
11297
  toRulesyncRule() {
11242
11298
  const rulesyncFrontmatter = {
@@ -11297,8 +11353,8 @@ var AugmentcodeLegacyRule = class _AugmentcodeLegacyRule extends ToolRule {
11297
11353
  }) {
11298
11354
  const settablePaths = this.getSettablePaths();
11299
11355
  const isRoot = relativeFilePath === settablePaths.root.relativeFilePath;
11300
- const relativePath = isRoot ? settablePaths.root.relativeFilePath : (0, import_node_path88.join)(settablePaths.nonRoot.relativeDirPath, relativeFilePath);
11301
- const fileContent = await readFileContent((0, import_node_path88.join)(baseDir, relativePath));
11356
+ const relativePath = isRoot ? settablePaths.root.relativeFilePath : (0, import_node_path89.join)(settablePaths.nonRoot.relativeDirPath, relativeFilePath);
11357
+ const fileContent = await readFileContent((0, import_node_path89.join)(baseDir, relativePath));
11302
11358
  return new _AugmentcodeLegacyRule({
11303
11359
  baseDir,
11304
11360
  relativeDirPath: isRoot ? settablePaths.root.relativeDirPath : settablePaths.nonRoot.relativeDirPath,
@@ -11327,7 +11383,7 @@ var AugmentcodeLegacyRule = class _AugmentcodeLegacyRule extends ToolRule {
11327
11383
  };
11328
11384
 
11329
11385
  // src/features/rules/augmentcode-rule.ts
11330
- var import_node_path89 = require("path");
11386
+ var import_node_path90 = require("path");
11331
11387
  var AugmentcodeRule = class _AugmentcodeRule extends ToolRule {
11332
11388
  toRulesyncRule() {
11333
11389
  return this.toRulesyncRuleDefault();
@@ -11359,7 +11415,7 @@ var AugmentcodeRule = class _AugmentcodeRule extends ToolRule {
11359
11415
  validate = true
11360
11416
  }) {
11361
11417
  const fileContent = await readFileContent(
11362
- (0, import_node_path89.join)(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
11418
+ (0, import_node_path90.join)(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
11363
11419
  );
11364
11420
  const { body: content } = parseFrontmatter(fileContent);
11365
11421
  return new _AugmentcodeRule({
@@ -11395,7 +11451,7 @@ var AugmentcodeRule = class _AugmentcodeRule extends ToolRule {
11395
11451
  };
11396
11452
 
11397
11453
  // src/features/rules/claudecode-legacy-rule.ts
11398
- var import_node_path90 = require("path");
11454
+ var import_node_path91 = require("path");
11399
11455
  var ClaudecodeLegacyRule = class _ClaudecodeLegacyRule extends ToolRule {
11400
11456
  static getSettablePaths({
11401
11457
  global,
@@ -11430,7 +11486,7 @@ var ClaudecodeLegacyRule = class _ClaudecodeLegacyRule extends ToolRule {
11430
11486
  if (isRoot) {
11431
11487
  const relativePath2 = paths.root.relativeFilePath;
11432
11488
  const fileContent2 = await readFileContent(
11433
- (0, import_node_path90.join)(baseDir, paths.root.relativeDirPath, relativePath2)
11489
+ (0, import_node_path91.join)(baseDir, paths.root.relativeDirPath, relativePath2)
11434
11490
  );
11435
11491
  return new _ClaudecodeLegacyRule({
11436
11492
  baseDir,
@@ -11442,10 +11498,10 @@ var ClaudecodeLegacyRule = class _ClaudecodeLegacyRule extends ToolRule {
11442
11498
  });
11443
11499
  }
11444
11500
  if (!paths.nonRoot) {
11445
- throw new Error("nonRoot path is not set");
11501
+ throw new Error(`nonRoot path is not set for ${relativeFilePath}`);
11446
11502
  }
11447
- const relativePath = (0, import_node_path90.join)(paths.nonRoot.relativeDirPath, relativeFilePath);
11448
- const fileContent = await readFileContent((0, import_node_path90.join)(baseDir, relativePath));
11503
+ const relativePath = (0, import_node_path91.join)(paths.nonRoot.relativeDirPath, relativeFilePath);
11504
+ const fileContent = await readFileContent((0, import_node_path91.join)(baseDir, relativePath));
11449
11505
  return new _ClaudecodeLegacyRule({
11450
11506
  baseDir,
11451
11507
  relativeDirPath: paths.nonRoot.relativeDirPath,
@@ -11504,7 +11560,7 @@ var ClaudecodeLegacyRule = class _ClaudecodeLegacyRule extends ToolRule {
11504
11560
  };
11505
11561
 
11506
11562
  // src/features/rules/claudecode-rule.ts
11507
- var import_node_path91 = require("path");
11563
+ var import_node_path92 = require("path");
11508
11564
  var import_mini44 = require("zod/mini");
11509
11565
  var ClaudecodeRuleFrontmatterSchema = import_mini44.z.object({
11510
11566
  paths: import_mini44.z.optional(import_mini44.z.array(import_mini44.z.string()))
@@ -11539,7 +11595,7 @@ var ClaudecodeRule = class _ClaudecodeRule extends ToolRule {
11539
11595
  const result = ClaudecodeRuleFrontmatterSchema.safeParse(frontmatter);
11540
11596
  if (!result.success) {
11541
11597
  throw new Error(
11542
- `Invalid frontmatter in ${(0, import_node_path91.join)(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
11598
+ `Invalid frontmatter in ${(0, import_node_path92.join)(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
11543
11599
  );
11544
11600
  }
11545
11601
  }
@@ -11567,7 +11623,7 @@ var ClaudecodeRule = class _ClaudecodeRule extends ToolRule {
11567
11623
  const isRoot = relativeFilePath === paths.root.relativeFilePath;
11568
11624
  if (isRoot) {
11569
11625
  const fileContent2 = await readFileContent(
11570
- (0, import_node_path91.join)(baseDir, paths.root.relativeDirPath, paths.root.relativeFilePath)
11626
+ (0, import_node_path92.join)(baseDir, paths.root.relativeDirPath, paths.root.relativeFilePath)
11571
11627
  );
11572
11628
  return new _ClaudecodeRule({
11573
11629
  baseDir,
@@ -11580,15 +11636,15 @@ var ClaudecodeRule = class _ClaudecodeRule extends ToolRule {
11580
11636
  });
11581
11637
  }
11582
11638
  if (!paths.nonRoot) {
11583
- throw new Error("nonRoot path is not set");
11639
+ throw new Error(`nonRoot path is not set for ${relativeFilePath}`);
11584
11640
  }
11585
- const relativePath = (0, import_node_path91.join)(paths.nonRoot.relativeDirPath, relativeFilePath);
11586
- const fileContent = await readFileContent((0, import_node_path91.join)(baseDir, relativePath));
11641
+ const relativePath = (0, import_node_path92.join)(paths.nonRoot.relativeDirPath, relativeFilePath);
11642
+ const fileContent = await readFileContent((0, import_node_path92.join)(baseDir, relativePath));
11587
11643
  const { frontmatter, body: content } = parseFrontmatter(fileContent);
11588
11644
  const result = ClaudecodeRuleFrontmatterSchema.safeParse(frontmatter);
11589
11645
  if (!result.success) {
11590
11646
  throw new Error(
11591
- `Invalid frontmatter in ${(0, import_node_path91.join)(baseDir, relativePath)}: ${formatError(result.error)}`
11647
+ `Invalid frontmatter in ${(0, import_node_path92.join)(baseDir, relativePath)}: ${formatError(result.error)}`
11592
11648
  );
11593
11649
  }
11594
11650
  return new _ClaudecodeRule({
@@ -11647,7 +11703,7 @@ var ClaudecodeRule = class _ClaudecodeRule extends ToolRule {
11647
11703
  });
11648
11704
  }
11649
11705
  if (!paths.nonRoot) {
11650
- throw new Error("nonRoot path is not set");
11706
+ throw new Error(`nonRoot path is not set for ${rulesyncRule.getRelativeFilePath()}`);
11651
11707
  }
11652
11708
  return new _ClaudecodeRule({
11653
11709
  baseDir,
@@ -11695,7 +11751,7 @@ var ClaudecodeRule = class _ClaudecodeRule extends ToolRule {
11695
11751
  return {
11696
11752
  success: false,
11697
11753
  error: new Error(
11698
- `Invalid frontmatter in ${(0, import_node_path91.join)(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
11754
+ `Invalid frontmatter in ${(0, import_node_path92.join)(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
11699
11755
  )
11700
11756
  };
11701
11757
  }
@@ -11715,7 +11771,7 @@ var ClaudecodeRule = class _ClaudecodeRule extends ToolRule {
11715
11771
  };
11716
11772
 
11717
11773
  // src/features/rules/cline-rule.ts
11718
- var import_node_path92 = require("path");
11774
+ var import_node_path93 = require("path");
11719
11775
  var import_mini45 = require("zod/mini");
11720
11776
  var ClineRuleFrontmatterSchema = import_mini45.z.object({
11721
11777
  description: import_mini45.z.string()
@@ -11761,7 +11817,7 @@ var ClineRule = class _ClineRule extends ToolRule {
11761
11817
  validate = true
11762
11818
  }) {
11763
11819
  const fileContent = await readFileContent(
11764
- (0, import_node_path92.join)(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
11820
+ (0, import_node_path93.join)(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
11765
11821
  );
11766
11822
  return new _ClineRule({
11767
11823
  baseDir,
@@ -11787,7 +11843,7 @@ var ClineRule = class _ClineRule extends ToolRule {
11787
11843
  };
11788
11844
 
11789
11845
  // src/features/rules/codexcli-rule.ts
11790
- var import_node_path93 = require("path");
11846
+ var import_node_path94 = require("path");
11791
11847
  var CodexcliRule = class _CodexcliRule extends ToolRule {
11792
11848
  static getSettablePaths({
11793
11849
  global,
@@ -11822,7 +11878,7 @@ var CodexcliRule = class _CodexcliRule extends ToolRule {
11822
11878
  if (isRoot) {
11823
11879
  const relativePath2 = paths.root.relativeFilePath;
11824
11880
  const fileContent2 = await readFileContent(
11825
- (0, import_node_path93.join)(baseDir, paths.root.relativeDirPath, relativePath2)
11881
+ (0, import_node_path94.join)(baseDir, paths.root.relativeDirPath, relativePath2)
11826
11882
  );
11827
11883
  return new _CodexcliRule({
11828
11884
  baseDir,
@@ -11834,10 +11890,10 @@ var CodexcliRule = class _CodexcliRule extends ToolRule {
11834
11890
  });
11835
11891
  }
11836
11892
  if (!paths.nonRoot) {
11837
- throw new Error("nonRoot path is not set");
11893
+ throw new Error(`nonRoot path is not set for ${relativeFilePath}`);
11838
11894
  }
11839
- const relativePath = (0, import_node_path93.join)(paths.nonRoot.relativeDirPath, relativeFilePath);
11840
- const fileContent = await readFileContent((0, import_node_path93.join)(baseDir, relativePath));
11895
+ const relativePath = (0, import_node_path94.join)(paths.nonRoot.relativeDirPath, relativeFilePath);
11896
+ const fileContent = await readFileContent((0, import_node_path94.join)(baseDir, relativePath));
11841
11897
  return new _CodexcliRule({
11842
11898
  baseDir,
11843
11899
  relativeDirPath: paths.nonRoot.relativeDirPath,
@@ -11896,7 +11952,7 @@ var CodexcliRule = class _CodexcliRule extends ToolRule {
11896
11952
  };
11897
11953
 
11898
11954
  // src/features/rules/copilot-rule.ts
11899
- var import_node_path94 = require("path");
11955
+ var import_node_path95 = require("path");
11900
11956
  var import_mini46 = require("zod/mini");
11901
11957
  var CopilotRuleFrontmatterSchema = import_mini46.z.object({
11902
11958
  description: import_mini46.z.optional(import_mini46.z.string()),
@@ -11922,7 +11978,7 @@ var CopilotRule = class _CopilotRule extends ToolRule {
11922
11978
  const result = CopilotRuleFrontmatterSchema.safeParse(frontmatter);
11923
11979
  if (!result.success) {
11924
11980
  throw new Error(
11925
- `Invalid frontmatter in ${(0, import_node_path94.join)(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
11981
+ `Invalid frontmatter in ${(0, import_node_path95.join)(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
11926
11982
  );
11927
11983
  }
11928
11984
  }
@@ -12004,11 +12060,11 @@ var CopilotRule = class _CopilotRule extends ToolRule {
12004
12060
  validate = true
12005
12061
  }) {
12006
12062
  const isRoot = relativeFilePath === "copilot-instructions.md";
12007
- const relativePath = isRoot ? (0, import_node_path94.join)(
12063
+ const relativePath = isRoot ? (0, import_node_path95.join)(
12008
12064
  this.getSettablePaths().root.relativeDirPath,
12009
12065
  this.getSettablePaths().root.relativeFilePath
12010
- ) : (0, import_node_path94.join)(this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath);
12011
- const fileContent = await readFileContent((0, import_node_path94.join)(baseDir, relativePath));
12066
+ ) : (0, import_node_path95.join)(this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath);
12067
+ const fileContent = await readFileContent((0, import_node_path95.join)(baseDir, relativePath));
12012
12068
  if (isRoot) {
12013
12069
  return new _CopilotRule({
12014
12070
  baseDir,
@@ -12024,7 +12080,7 @@ var CopilotRule = class _CopilotRule extends ToolRule {
12024
12080
  const result = CopilotRuleFrontmatterSchema.safeParse(frontmatter);
12025
12081
  if (!result.success) {
12026
12082
  throw new Error(
12027
- `Invalid frontmatter in ${(0, import_node_path94.join)(baseDir, relativeFilePath)}: ${formatError(result.error)}`
12083
+ `Invalid frontmatter in ${(0, import_node_path95.join)(baseDir, relativeFilePath)}: ${formatError(result.error)}`
12028
12084
  );
12029
12085
  }
12030
12086
  return new _CopilotRule({
@@ -12064,7 +12120,7 @@ var CopilotRule = class _CopilotRule extends ToolRule {
12064
12120
  return {
12065
12121
  success: false,
12066
12122
  error: new Error(
12067
- `Invalid frontmatter in ${(0, import_node_path94.join)(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
12123
+ `Invalid frontmatter in ${(0, import_node_path95.join)(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
12068
12124
  )
12069
12125
  };
12070
12126
  }
@@ -12084,7 +12140,7 @@ var CopilotRule = class _CopilotRule extends ToolRule {
12084
12140
  };
12085
12141
 
12086
12142
  // src/features/rules/cursor-rule.ts
12087
- var import_node_path95 = require("path");
12143
+ var import_node_path96 = require("path");
12088
12144
  var import_mini47 = require("zod/mini");
12089
12145
  var CursorRuleFrontmatterSchema = import_mini47.z.object({
12090
12146
  description: import_mini47.z.optional(import_mini47.z.string()),
@@ -12106,7 +12162,7 @@ var CursorRule = class _CursorRule extends ToolRule {
12106
12162
  const result = CursorRuleFrontmatterSchema.safeParse(frontmatter);
12107
12163
  if (!result.success) {
12108
12164
  throw new Error(
12109
- `Invalid frontmatter in ${(0, import_node_path95.join)(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
12165
+ `Invalid frontmatter in ${(0, import_node_path96.join)(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`
12110
12166
  );
12111
12167
  }
12112
12168
  }
@@ -12223,13 +12279,13 @@ var CursorRule = class _CursorRule extends ToolRule {
12223
12279
  validate = true
12224
12280
  }) {
12225
12281
  const fileContent = await readFileContent(
12226
- (0, import_node_path95.join)(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
12282
+ (0, import_node_path96.join)(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
12227
12283
  );
12228
12284
  const { frontmatter, body: content } = _CursorRule.parseCursorFrontmatter(fileContent);
12229
12285
  const result = CursorRuleFrontmatterSchema.safeParse(frontmatter);
12230
12286
  if (!result.success) {
12231
12287
  throw new Error(
12232
- `Invalid frontmatter in ${(0, import_node_path95.join)(baseDir, relativeFilePath)}: ${formatError(result.error)}`
12288
+ `Invalid frontmatter in ${(0, import_node_path96.join)(baseDir, relativeFilePath)}: ${formatError(result.error)}`
12233
12289
  );
12234
12290
  }
12235
12291
  return new _CursorRule({
@@ -12266,7 +12322,7 @@ var CursorRule = class _CursorRule extends ToolRule {
12266
12322
  return {
12267
12323
  success: false,
12268
12324
  error: new Error(
12269
- `Invalid frontmatter in ${(0, import_node_path95.join)(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
12325
+ `Invalid frontmatter in ${(0, import_node_path96.join)(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
12270
12326
  )
12271
12327
  };
12272
12328
  }
@@ -12286,7 +12342,7 @@ var CursorRule = class _CursorRule extends ToolRule {
12286
12342
  };
12287
12343
 
12288
12344
  // src/features/rules/factorydroid-rule.ts
12289
- var import_node_path96 = require("path");
12345
+ var import_node_path97 = require("path");
12290
12346
  var FactorydroidRule = class _FactorydroidRule extends ToolRule {
12291
12347
  constructor({ fileContent, root, ...rest }) {
12292
12348
  super({
@@ -12326,8 +12382,8 @@ var FactorydroidRule = class _FactorydroidRule extends ToolRule {
12326
12382
  const paths = this.getSettablePaths({ global });
12327
12383
  const isRoot = relativeFilePath === paths.root.relativeFilePath;
12328
12384
  if (isRoot) {
12329
- const relativePath2 = (0, import_node_path96.join)(paths.root.relativeDirPath, paths.root.relativeFilePath);
12330
- const fileContent2 = await readFileContent((0, import_node_path96.join)(baseDir, relativePath2));
12385
+ const relativePath2 = (0, import_node_path97.join)(paths.root.relativeDirPath, paths.root.relativeFilePath);
12386
+ const fileContent2 = await readFileContent((0, import_node_path97.join)(baseDir, relativePath2));
12331
12387
  return new _FactorydroidRule({
12332
12388
  baseDir,
12333
12389
  relativeDirPath: paths.root.relativeDirPath,
@@ -12338,10 +12394,10 @@ var FactorydroidRule = class _FactorydroidRule extends ToolRule {
12338
12394
  });
12339
12395
  }
12340
12396
  if (!paths.nonRoot) {
12341
- throw new Error("nonRoot path is not set");
12397
+ throw new Error(`nonRoot path is not set for ${relativeFilePath}`);
12342
12398
  }
12343
- const relativePath = (0, import_node_path96.join)(paths.nonRoot.relativeDirPath, relativeFilePath);
12344
- const fileContent = await readFileContent((0, import_node_path96.join)(baseDir, relativePath));
12399
+ const relativePath = (0, import_node_path97.join)(paths.nonRoot.relativeDirPath, relativeFilePath);
12400
+ const fileContent = await readFileContent((0, import_node_path97.join)(baseDir, relativePath));
12345
12401
  return new _FactorydroidRule({
12346
12402
  baseDir,
12347
12403
  relativeDirPath: paths.nonRoot.relativeDirPath,
@@ -12400,7 +12456,7 @@ var FactorydroidRule = class _FactorydroidRule extends ToolRule {
12400
12456
  };
12401
12457
 
12402
12458
  // src/features/rules/geminicli-rule.ts
12403
- var import_node_path97 = require("path");
12459
+ var import_node_path98 = require("path");
12404
12460
  var GeminiCliRule = class _GeminiCliRule extends ToolRule {
12405
12461
  static getSettablePaths({
12406
12462
  global,
@@ -12435,7 +12491,7 @@ var GeminiCliRule = class _GeminiCliRule extends ToolRule {
12435
12491
  if (isRoot) {
12436
12492
  const relativePath2 = paths.root.relativeFilePath;
12437
12493
  const fileContent2 = await readFileContent(
12438
- (0, import_node_path97.join)(baseDir, paths.root.relativeDirPath, relativePath2)
12494
+ (0, import_node_path98.join)(baseDir, paths.root.relativeDirPath, relativePath2)
12439
12495
  );
12440
12496
  return new _GeminiCliRule({
12441
12497
  baseDir,
@@ -12447,10 +12503,10 @@ var GeminiCliRule = class _GeminiCliRule extends ToolRule {
12447
12503
  });
12448
12504
  }
12449
12505
  if (!paths.nonRoot) {
12450
- throw new Error("nonRoot path is not set");
12506
+ throw new Error(`nonRoot path is not set for ${relativeFilePath}`);
12451
12507
  }
12452
- const relativePath = (0, import_node_path97.join)(paths.nonRoot.relativeDirPath, relativeFilePath);
12453
- const fileContent = await readFileContent((0, import_node_path97.join)(baseDir, relativePath));
12508
+ const relativePath = (0, import_node_path98.join)(paths.nonRoot.relativeDirPath, relativeFilePath);
12509
+ const fileContent = await readFileContent((0, import_node_path98.join)(baseDir, relativePath));
12454
12510
  return new _GeminiCliRule({
12455
12511
  baseDir,
12456
12512
  relativeDirPath: paths.nonRoot.relativeDirPath,
@@ -12509,7 +12565,7 @@ var GeminiCliRule = class _GeminiCliRule extends ToolRule {
12509
12565
  };
12510
12566
 
12511
12567
  // src/features/rules/junie-rule.ts
12512
- var import_node_path98 = require("path");
12568
+ var import_node_path99 = require("path");
12513
12569
  var JunieRule = class _JunieRule extends ToolRule {
12514
12570
  static getSettablePaths(_options = {}) {
12515
12571
  return {
@@ -12528,8 +12584,8 @@ var JunieRule = class _JunieRule extends ToolRule {
12528
12584
  validate = true
12529
12585
  }) {
12530
12586
  const isRoot = relativeFilePath === "guidelines.md";
12531
- const relativePath = isRoot ? "guidelines.md" : (0, import_node_path98.join)(".junie", "memories", relativeFilePath);
12532
- const fileContent = await readFileContent((0, import_node_path98.join)(baseDir, relativePath));
12587
+ const relativePath = isRoot ? "guidelines.md" : (0, import_node_path99.join)(".junie", "memories", relativeFilePath);
12588
+ const fileContent = await readFileContent((0, import_node_path99.join)(baseDir, relativePath));
12533
12589
  return new _JunieRule({
12534
12590
  baseDir,
12535
12591
  relativeDirPath: isRoot ? this.getSettablePaths().root.relativeDirPath : this.getSettablePaths().nonRoot.relativeDirPath,
@@ -12584,7 +12640,7 @@ var JunieRule = class _JunieRule extends ToolRule {
12584
12640
  };
12585
12641
 
12586
12642
  // src/features/rules/kilo-rule.ts
12587
- var import_node_path99 = require("path");
12643
+ var import_node_path100 = require("path");
12588
12644
  var KiloRule = class _KiloRule extends ToolRule {
12589
12645
  static getSettablePaths(_options = {}) {
12590
12646
  return {
@@ -12599,7 +12655,7 @@ var KiloRule = class _KiloRule extends ToolRule {
12599
12655
  validate = true
12600
12656
  }) {
12601
12657
  const fileContent = await readFileContent(
12602
- (0, import_node_path99.join)(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
12658
+ (0, import_node_path100.join)(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
12603
12659
  );
12604
12660
  return new _KiloRule({
12605
12661
  baseDir,
@@ -12651,7 +12707,7 @@ var KiloRule = class _KiloRule extends ToolRule {
12651
12707
  };
12652
12708
 
12653
12709
  // src/features/rules/kiro-rule.ts
12654
- var import_node_path100 = require("path");
12710
+ var import_node_path101 = require("path");
12655
12711
  var KiroRule = class _KiroRule extends ToolRule {
12656
12712
  static getSettablePaths(_options = {}) {
12657
12713
  return {
@@ -12666,7 +12722,7 @@ var KiroRule = class _KiroRule extends ToolRule {
12666
12722
  validate = true
12667
12723
  }) {
12668
12724
  const fileContent = await readFileContent(
12669
- (0, import_node_path100.join)(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
12725
+ (0, import_node_path101.join)(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
12670
12726
  );
12671
12727
  return new _KiroRule({
12672
12728
  baseDir,
@@ -12720,7 +12776,7 @@ var KiroRule = class _KiroRule extends ToolRule {
12720
12776
  };
12721
12777
 
12722
12778
  // src/features/rules/opencode-rule.ts
12723
- var import_node_path101 = require("path");
12779
+ var import_node_path102 = require("path");
12724
12780
  var OpenCodeRule = class _OpenCodeRule extends ToolRule {
12725
12781
  static getSettablePaths(_options = {}) {
12726
12782
  return {
@@ -12739,8 +12795,8 @@ var OpenCodeRule = class _OpenCodeRule extends ToolRule {
12739
12795
  validate = true
12740
12796
  }) {
12741
12797
  const isRoot = relativeFilePath === "AGENTS.md";
12742
- const relativePath = isRoot ? "AGENTS.md" : (0, import_node_path101.join)(".opencode", "memories", relativeFilePath);
12743
- const fileContent = await readFileContent((0, import_node_path101.join)(baseDir, relativePath));
12798
+ const relativePath = isRoot ? "AGENTS.md" : (0, import_node_path102.join)(".opencode", "memories", relativeFilePath);
12799
+ const fileContent = await readFileContent((0, import_node_path102.join)(baseDir, relativePath));
12744
12800
  return new _OpenCodeRule({
12745
12801
  baseDir,
12746
12802
  relativeDirPath: isRoot ? this.getSettablePaths().root.relativeDirPath : this.getSettablePaths().nonRoot.relativeDirPath,
@@ -12795,7 +12851,7 @@ var OpenCodeRule = class _OpenCodeRule extends ToolRule {
12795
12851
  };
12796
12852
 
12797
12853
  // src/features/rules/qwencode-rule.ts
12798
- var import_node_path102 = require("path");
12854
+ var import_node_path103 = require("path");
12799
12855
  var QwencodeRule = class _QwencodeRule extends ToolRule {
12800
12856
  static getSettablePaths(_options = {}) {
12801
12857
  return {
@@ -12814,8 +12870,8 @@ var QwencodeRule = class _QwencodeRule extends ToolRule {
12814
12870
  validate = true
12815
12871
  }) {
12816
12872
  const isRoot = relativeFilePath === "QWEN.md";
12817
- const relativePath = isRoot ? "QWEN.md" : (0, import_node_path102.join)(".qwen", "memories", relativeFilePath);
12818
- const fileContent = await readFileContent((0, import_node_path102.join)(baseDir, relativePath));
12873
+ const relativePath = isRoot ? "QWEN.md" : (0, import_node_path103.join)(".qwen", "memories", relativeFilePath);
12874
+ const fileContent = await readFileContent((0, import_node_path103.join)(baseDir, relativePath));
12819
12875
  return new _QwencodeRule({
12820
12876
  baseDir,
12821
12877
  relativeDirPath: isRoot ? this.getSettablePaths().root.relativeDirPath : this.getSettablePaths().nonRoot.relativeDirPath,
@@ -12867,7 +12923,7 @@ var QwencodeRule = class _QwencodeRule extends ToolRule {
12867
12923
  };
12868
12924
 
12869
12925
  // src/features/rules/replit-rule.ts
12870
- var import_node_path103 = require("path");
12926
+ var import_node_path104 = require("path");
12871
12927
  var ReplitRule = class _ReplitRule extends ToolRule {
12872
12928
  static getSettablePaths(_options = {}) {
12873
12929
  return {
@@ -12885,11 +12941,11 @@ var ReplitRule = class _ReplitRule extends ToolRule {
12885
12941
  const paths = this.getSettablePaths();
12886
12942
  const isRoot = relativeFilePath === paths.root.relativeFilePath;
12887
12943
  if (!isRoot) {
12888
- throw new Error("ReplitRule only supports root rules");
12944
+ throw new Error(`ReplitRule only supports root rules: ${relativeFilePath}`);
12889
12945
  }
12890
12946
  const relativePath = paths.root.relativeFilePath;
12891
12947
  const fileContent = await readFileContent(
12892
- (0, import_node_path103.join)(baseDir, paths.root.relativeDirPath, relativePath)
12948
+ (0, import_node_path104.join)(baseDir, paths.root.relativeDirPath, relativePath)
12893
12949
  );
12894
12950
  return new _ReplitRule({
12895
12951
  baseDir,
@@ -12908,7 +12964,7 @@ var ReplitRule = class _ReplitRule extends ToolRule {
12908
12964
  const paths = this.getSettablePaths();
12909
12965
  const isRoot = rulesyncRule.getFrontmatter().root ?? false;
12910
12966
  if (!isRoot) {
12911
- throw new Error("ReplitRule only supports root rules");
12967
+ throw new Error(`ReplitRule only supports root rules: ${rulesyncRule.getRelativeFilePath()}`);
12912
12968
  }
12913
12969
  return new _ReplitRule(
12914
12970
  this.buildToolRuleParamsDefault({
@@ -12955,7 +13011,7 @@ var ReplitRule = class _ReplitRule extends ToolRule {
12955
13011
  };
12956
13012
 
12957
13013
  // src/features/rules/roo-rule.ts
12958
- var import_node_path104 = require("path");
13014
+ var import_node_path105 = require("path");
12959
13015
  var RooRule = class _RooRule extends ToolRule {
12960
13016
  static getSettablePaths(_options = {}) {
12961
13017
  return {
@@ -12970,7 +13026,7 @@ var RooRule = class _RooRule extends ToolRule {
12970
13026
  validate = true
12971
13027
  }) {
12972
13028
  const fileContent = await readFileContent(
12973
- (0, import_node_path104.join)(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
13029
+ (0, import_node_path105.join)(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
12974
13030
  );
12975
13031
  return new _RooRule({
12976
13032
  baseDir,
@@ -13039,7 +13095,7 @@ var RooRule = class _RooRule extends ToolRule {
13039
13095
  };
13040
13096
 
13041
13097
  // src/features/rules/warp-rule.ts
13042
- var import_node_path105 = require("path");
13098
+ var import_node_path106 = require("path");
13043
13099
  var WarpRule = class _WarpRule extends ToolRule {
13044
13100
  constructor({ fileContent, root, ...rest }) {
13045
13101
  super({
@@ -13065,8 +13121,8 @@ var WarpRule = class _WarpRule extends ToolRule {
13065
13121
  validate = true
13066
13122
  }) {
13067
13123
  const isRoot = relativeFilePath === this.getSettablePaths().root.relativeFilePath;
13068
- const relativePath = isRoot ? this.getSettablePaths().root.relativeFilePath : (0, import_node_path105.join)(this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath);
13069
- const fileContent = await readFileContent((0, import_node_path105.join)(baseDir, relativePath));
13124
+ const relativePath = isRoot ? this.getSettablePaths().root.relativeFilePath : (0, import_node_path106.join)(this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath);
13125
+ const fileContent = await readFileContent((0, import_node_path106.join)(baseDir, relativePath));
13070
13126
  return new _WarpRule({
13071
13127
  baseDir,
13072
13128
  relativeDirPath: isRoot ? this.getSettablePaths().root.relativeDirPath : ".warp",
@@ -13121,7 +13177,7 @@ var WarpRule = class _WarpRule extends ToolRule {
13121
13177
  };
13122
13178
 
13123
13179
  // src/features/rules/windsurf-rule.ts
13124
- var import_node_path106 = require("path");
13180
+ var import_node_path107 = require("path");
13125
13181
  var WindsurfRule = class _WindsurfRule extends ToolRule {
13126
13182
  static getSettablePaths(_options = {}) {
13127
13183
  return {
@@ -13136,7 +13192,7 @@ var WindsurfRule = class _WindsurfRule extends ToolRule {
13136
13192
  validate = true
13137
13193
  }) {
13138
13194
  const fileContent = await readFileContent(
13139
- (0, import_node_path106.join)(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
13195
+ (0, import_node_path107.join)(baseDir, this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath)
13140
13196
  );
13141
13197
  return new _WindsurfRule({
13142
13198
  baseDir,
@@ -13522,7 +13578,7 @@ var RulesProcessor = class extends FeatureProcessor {
13522
13578
  }).relativeDirPath;
13523
13579
  return this.skills.filter((skill) => skillClass.isTargetedByRulesyncSkill(skill)).map((skill) => {
13524
13580
  const frontmatter = skill.getFrontmatter();
13525
- const relativePath = (0, import_node_path107.join)(toolRelativeDirPath, skill.getDirName(), SKILL_FILE_NAME);
13581
+ const relativePath = (0, import_node_path108.join)(toolRelativeDirPath, skill.getDirName(), SKILL_FILE_NAME);
13526
13582
  return {
13527
13583
  name: frontmatter.name,
13528
13584
  description: frontmatter.description,
@@ -13633,12 +13689,12 @@ var RulesProcessor = class extends FeatureProcessor {
13633
13689
  * Load and parse rulesync rule files from .rulesync/rules/ directory
13634
13690
  */
13635
13691
  async loadRulesyncFiles() {
13636
- const rulesyncBaseDir = (0, import_node_path107.join)(this.baseDir, RULESYNC_RULES_RELATIVE_DIR_PATH);
13637
- const files = await findFilesByGlobs((0, import_node_path107.join)(rulesyncBaseDir, "**", "*.md"));
13692
+ const rulesyncBaseDir = (0, import_node_path108.join)(this.baseDir, RULESYNC_RULES_RELATIVE_DIR_PATH);
13693
+ const files = await findFilesByGlobs((0, import_node_path108.join)(rulesyncBaseDir, "**", "*.md"));
13638
13694
  logger.debug(`Found ${files.length} rulesync files`);
13639
13695
  const rulesyncRules = await Promise.all(
13640
13696
  files.map((file) => {
13641
- const relativeFilePath = (0, import_node_path107.relative)(rulesyncBaseDir, file);
13697
+ const relativeFilePath = (0, import_node_path108.relative)(rulesyncBaseDir, file);
13642
13698
  checkPathTraversal({ relativePath: relativeFilePath, intendedRootDir: rulesyncBaseDir });
13643
13699
  return RulesyncRule.fromFile({
13644
13700
  relativeFilePath
@@ -13647,7 +13703,9 @@ var RulesProcessor = class extends FeatureProcessor {
13647
13703
  );
13648
13704
  const rootRules = rulesyncRules.filter((rule) => rule.getFrontmatter().root);
13649
13705
  if (rootRules.length > 1) {
13650
- throw new Error("Multiple root rulesync rules found");
13706
+ throw new Error(
13707
+ `Multiple root rulesync rules found: ${rootRules.map((r) => (0, import_node_path108.join)(r.getRelativeDirPath(), r.getRelativeFilePath())).join(", ")}`
13708
+ );
13651
13709
  }
13652
13710
  if (rootRules.length === 0 && rulesyncRules.length > 0) {
13653
13711
  logger.warn(
@@ -13656,21 +13714,25 @@ var RulesProcessor = class extends FeatureProcessor {
13656
13714
  }
13657
13715
  const localRootRules = rulesyncRules.filter((rule) => rule.getFrontmatter().localRoot);
13658
13716
  if (localRootRules.length > 1) {
13659
- throw new Error("Multiple localRoot rules found. Only one rule can have localRoot: true");
13717
+ throw new Error(
13718
+ `Multiple localRoot rules found: ${localRootRules.map((r) => (0, import_node_path108.join)(r.getRelativeDirPath(), r.getRelativeFilePath())).join(", ")}. Only one rule can have localRoot: true`
13719
+ );
13660
13720
  }
13661
13721
  if (localRootRules.length > 0 && rootRules.length === 0) {
13662
- throw new Error("localRoot: true requires a root: true rule to exist");
13722
+ throw new Error(
13723
+ `localRoot: true requires a root: true rule to exist (found in ${localRootRules.map((r) => (0, import_node_path108.join)(r.getRelativeDirPath(), r.getRelativeFilePath())).join(", ")})`
13724
+ );
13663
13725
  }
13664
13726
  if (this.global) {
13665
13727
  const nonRootRules = rulesyncRules.filter((rule) => !rule.getFrontmatter().root);
13666
13728
  if (nonRootRules.length > 0) {
13667
13729
  logger.warn(
13668
- `${nonRootRules.length} non-root rulesync rules found, but it's in global mode, so ignoring them`
13730
+ `${nonRootRules.length} non-root rulesync rules found, but it's in global mode, so ignoring them: ${nonRootRules.map((r) => (0, import_node_path108.join)(r.getRelativeDirPath(), r.getRelativeFilePath())).join(", ")}`
13669
13731
  );
13670
13732
  }
13671
13733
  if (localRootRules.length > 0) {
13672
13734
  logger.warn(
13673
- `${localRootRules.length} localRoot rules found, but localRoot is not supported in global mode, ignoring them`
13735
+ `${localRootRules.length} localRoot rules found, but localRoot is not supported in global mode, ignoring them: ${localRootRules.map((r) => (0, import_node_path108.join)(r.getRelativeDirPath(), r.getRelativeFilePath())).join(", ")}`
13674
13736
  );
13675
13737
  }
13676
13738
  return rootRules;
@@ -13692,7 +13754,7 @@ var RulesProcessor = class extends FeatureProcessor {
13692
13754
  return [];
13693
13755
  }
13694
13756
  const rootFilePaths = await findFilesByGlobs(
13695
- (0, import_node_path107.join)(
13757
+ (0, import_node_path108.join)(
13696
13758
  this.baseDir,
13697
13759
  settablePaths.root.relativeDirPath ?? ".",
13698
13760
  settablePaths.root.relativeFilePath
@@ -13703,7 +13765,7 @@ var RulesProcessor = class extends FeatureProcessor {
13703
13765
  (filePath) => factory.class.forDeletion({
13704
13766
  baseDir: this.baseDir,
13705
13767
  relativeDirPath: settablePaths.root?.relativeDirPath ?? ".",
13706
- relativeFilePath: (0, import_node_path107.basename)(filePath),
13768
+ relativeFilePath: (0, import_node_path108.basename)(filePath),
13707
13769
  global: this.global
13708
13770
  })
13709
13771
  ).filter((rule) => rule.isDeletable());
@@ -13712,7 +13774,7 @@ var RulesProcessor = class extends FeatureProcessor {
13712
13774
  rootFilePaths.map(
13713
13775
  (filePath) => factory.class.fromFile({
13714
13776
  baseDir: this.baseDir,
13715
- relativeFilePath: (0, import_node_path107.basename)(filePath),
13777
+ relativeFilePath: (0, import_node_path108.basename)(filePath),
13716
13778
  global: this.global
13717
13779
  })
13718
13780
  )
@@ -13730,13 +13792,13 @@ var RulesProcessor = class extends FeatureProcessor {
13730
13792
  return [];
13731
13793
  }
13732
13794
  const localRootFilePaths = await findFilesByGlobs(
13733
- (0, import_node_path107.join)(this.baseDir, settablePaths.root.relativeDirPath ?? ".", "CLAUDE.local.md")
13795
+ (0, import_node_path108.join)(this.baseDir, settablePaths.root.relativeDirPath ?? ".", "CLAUDE.local.md")
13734
13796
  );
13735
13797
  return localRootFilePaths.map(
13736
13798
  (filePath) => factory.class.forDeletion({
13737
13799
  baseDir: this.baseDir,
13738
13800
  relativeDirPath: settablePaths.root?.relativeDirPath ?? ".",
13739
- relativeFilePath: (0, import_node_path107.basename)(filePath),
13801
+ relativeFilePath: (0, import_node_path108.basename)(filePath),
13740
13802
  global: this.global
13741
13803
  })
13742
13804
  ).filter((rule) => rule.isDeletable());
@@ -13746,13 +13808,13 @@ var RulesProcessor = class extends FeatureProcessor {
13746
13808
  if (!settablePaths.nonRoot) {
13747
13809
  return [];
13748
13810
  }
13749
- const nonRootBaseDir = (0, import_node_path107.join)(this.baseDir, settablePaths.nonRoot.relativeDirPath);
13811
+ const nonRootBaseDir = (0, import_node_path108.join)(this.baseDir, settablePaths.nonRoot.relativeDirPath);
13750
13812
  const nonRootFilePaths = await findFilesByGlobs(
13751
- (0, import_node_path107.join)(nonRootBaseDir, "**", `*.${factory.meta.extension}`)
13813
+ (0, import_node_path108.join)(nonRootBaseDir, "**", `*.${factory.meta.extension}`)
13752
13814
  );
13753
13815
  if (forDeletion) {
13754
13816
  return nonRootFilePaths.map((filePath) => {
13755
- const relativeFilePath = (0, import_node_path107.relative)(nonRootBaseDir, filePath);
13817
+ const relativeFilePath = (0, import_node_path108.relative)(nonRootBaseDir, filePath);
13756
13818
  checkPathTraversal({
13757
13819
  relativePath: relativeFilePath,
13758
13820
  intendedRootDir: nonRootBaseDir
@@ -13767,7 +13829,7 @@ var RulesProcessor = class extends FeatureProcessor {
13767
13829
  }
13768
13830
  return await Promise.all(
13769
13831
  nonRootFilePaths.map((filePath) => {
13770
- const relativeFilePath = (0, import_node_path107.relative)(nonRootBaseDir, filePath);
13832
+ const relativeFilePath = (0, import_node_path108.relative)(nonRootBaseDir, filePath);
13771
13833
  checkPathTraversal({ relativePath: relativeFilePath, intendedRootDir: nonRootBaseDir });
13772
13834
  return factory.class.fromFile({
13773
13835
  baseDir: this.baseDir,
@@ -13780,7 +13842,7 @@ var RulesProcessor = class extends FeatureProcessor {
13780
13842
  logger.debug(`Found ${nonRootToolRules.length} non-root tool rule files`);
13781
13843
  return [...rootToolRules, ...localRootToolRules, ...nonRootToolRules];
13782
13844
  } catch (error) {
13783
- logger.error(`Failed to load tool files: ${formatError(error)}`);
13845
+ logger.error(`Failed to load tool files for ${this.toolTarget}: ${formatError(error)}`);
13784
13846
  return [];
13785
13847
  }
13786
13848
  }
@@ -13877,14 +13939,14 @@ s/<command> [arguments]
13877
13939
  This syntax employs a double slash (\`s/\`) to prevent conflicts with built-in slash commands.
13878
13940
  The \`s\` in \`s/\` stands for *simulate*. Because custom slash commands are not built-in, this syntax provides a pseudo way to invoke them.
13879
13941
 
13880
- When users call a custom slash command, you have to look for the markdown file, \`${(0, import_node_path107.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, "{command}.md")}\`, then execute the contents of that file as the block of operations.` : "";
13942
+ When users call a custom slash command, you have to look for the markdown file, \`${(0, import_node_path108.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, "{command}.md")}\`, then execute the contents of that file as the block of operations.` : "";
13881
13943
  const subagentsSection = subagents ? `## Simulated Subagents
13882
13944
 
13883
13945
  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.
13884
13946
 
13885
- When users call a simulated subagent, it will look for the corresponding markdown file, \`${(0, import_node_path107.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, "{subagent}.md")}\`, and execute its contents as the block of operations.
13947
+ When users call a simulated subagent, it will look for the corresponding markdown file, \`${(0, import_node_path108.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, "{subagent}.md")}\`, and execute its contents as the block of operations.
13886
13948
 
13887
- For example, if the user instructs \`Call planner subagent to plan the refactoring\`, you have to look for the markdown file, \`${(0, import_node_path107.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, "planner.md")}\`, and execute its contents as the block of operations.` : "";
13949
+ For example, if the user instructs \`Call planner subagent to plan the refactoring\`, you have to look for the markdown file, \`${(0, import_node_path108.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, "planner.md")}\`, and execute its contents as the block of operations.` : "";
13888
13950
  const skillsSection = skills ? this.generateSkillsSection(skills) : "";
13889
13951
  const result = [
13890
13952
  overview,
@@ -13911,61 +13973,56 @@ ${toonContent}`;
13911
13973
  }
13912
13974
  };
13913
13975
 
13914
- // src/types/git-provider.ts
13915
- var import_mini49 = require("zod/mini");
13916
- var ALL_GIT_PROVIDERS = ["github", "gitlab"];
13917
- var GitProviderSchema = import_mini49.z.enum(ALL_GIT_PROVIDERS);
13918
-
13919
13976
  // src/lib/github-client.ts
13920
13977
  var import_request_error = require("@octokit/request-error");
13921
13978
  var import_rest = require("@octokit/rest");
13922
13979
 
13923
13980
  // src/types/fetch.ts
13924
- var import_mini51 = require("zod/mini");
13981
+ var import_mini50 = require("zod/mini");
13925
13982
 
13926
13983
  // src/types/fetch-targets.ts
13927
- var import_mini50 = require("zod/mini");
13984
+ var import_mini49 = require("zod/mini");
13928
13985
  var ALL_FETCH_TARGETS = ["rulesync", ...ALL_TOOL_TARGETS];
13929
- var FetchTargetSchema = import_mini50.z.enum(ALL_FETCH_TARGETS);
13986
+ var FetchTargetSchema = import_mini49.z.enum(ALL_FETCH_TARGETS);
13930
13987
 
13931
13988
  // src/types/fetch.ts
13932
- var ConflictStrategySchema = import_mini51.z.enum(["skip", "overwrite"]);
13933
- var GitHubFileTypeSchema = import_mini51.z.enum(["file", "dir", "symlink", "submodule"]);
13934
- var GitHubFileEntrySchema = import_mini51.z.looseObject({
13935
- name: import_mini51.z.string(),
13936
- path: import_mini51.z.string(),
13937
- sha: import_mini51.z.string(),
13938
- size: import_mini51.z.number(),
13989
+ var ConflictStrategySchema = import_mini50.z.enum(["skip", "overwrite"]);
13990
+ var GitHubFileTypeSchema = import_mini50.z.enum(["file", "dir", "symlink", "submodule"]);
13991
+ var GitHubFileEntrySchema = import_mini50.z.looseObject({
13992
+ name: import_mini50.z.string(),
13993
+ path: import_mini50.z.string(),
13994
+ sha: import_mini50.z.string(),
13995
+ size: import_mini50.z.number(),
13939
13996
  type: GitHubFileTypeSchema,
13940
- download_url: import_mini51.z.nullable(import_mini51.z.string())
13997
+ download_url: import_mini50.z.nullable(import_mini50.z.string())
13941
13998
  });
13942
- var FetchOptionsSchema = import_mini51.z.looseObject({
13943
- target: import_mini51.z.optional(FetchTargetSchema),
13944
- features: import_mini51.z.optional(import_mini51.z.array(import_mini51.z.enum(ALL_FEATURES_WITH_WILDCARD))),
13945
- ref: import_mini51.z.optional(import_mini51.z.string()),
13946
- path: import_mini51.z.optional(import_mini51.z.string()),
13947
- output: import_mini51.z.optional(import_mini51.z.string()),
13948
- conflict: import_mini51.z.optional(ConflictStrategySchema),
13949
- token: import_mini51.z.optional(import_mini51.z.string()),
13950
- verbose: import_mini51.z.optional(import_mini51.z.boolean()),
13951
- silent: import_mini51.z.optional(import_mini51.z.boolean())
13999
+ var FetchOptionsSchema = import_mini50.z.looseObject({
14000
+ target: import_mini50.z.optional(FetchTargetSchema),
14001
+ features: import_mini50.z.optional(import_mini50.z.array(import_mini50.z.enum(ALL_FEATURES_WITH_WILDCARD))),
14002
+ ref: import_mini50.z.optional(import_mini50.z.string()),
14003
+ path: import_mini50.z.optional(import_mini50.z.string()),
14004
+ output: import_mini50.z.optional(import_mini50.z.string()),
14005
+ conflict: import_mini50.z.optional(ConflictStrategySchema),
14006
+ token: import_mini50.z.optional(import_mini50.z.string()),
14007
+ verbose: import_mini50.z.optional(import_mini50.z.boolean()),
14008
+ silent: import_mini50.z.optional(import_mini50.z.boolean())
13952
14009
  });
13953
- var FetchFileStatusSchema = import_mini51.z.enum(["created", "overwritten", "skipped"]);
13954
- var GitHubRepoInfoSchema = import_mini51.z.looseObject({
13955
- default_branch: import_mini51.z.string(),
13956
- private: import_mini51.z.boolean()
14010
+ var FetchFileStatusSchema = import_mini50.z.enum(["created", "overwritten", "skipped"]);
14011
+ var GitHubRepoInfoSchema = import_mini50.z.looseObject({
14012
+ default_branch: import_mini50.z.string(),
14013
+ private: import_mini50.z.boolean()
13957
14014
  });
13958
- var GitHubReleaseAssetSchema = import_mini51.z.looseObject({
13959
- name: import_mini51.z.string(),
13960
- browser_download_url: import_mini51.z.string(),
13961
- size: import_mini51.z.number()
14015
+ var GitHubReleaseAssetSchema = import_mini50.z.looseObject({
14016
+ name: import_mini50.z.string(),
14017
+ browser_download_url: import_mini50.z.string(),
14018
+ size: import_mini50.z.number()
13962
14019
  });
13963
- var GitHubReleaseSchema = import_mini51.z.looseObject({
13964
- tag_name: import_mini51.z.string(),
13965
- name: import_mini51.z.nullable(import_mini51.z.string()),
13966
- prerelease: import_mini51.z.boolean(),
13967
- draft: import_mini51.z.boolean(),
13968
- assets: import_mini51.z.array(GitHubReleaseAssetSchema)
14020
+ var GitHubReleaseSchema = import_mini50.z.looseObject({
14021
+ tag_name: import_mini50.z.string(),
14022
+ name: import_mini50.z.nullable(import_mini50.z.string()),
14023
+ prerelease: import_mini50.z.boolean(),
14024
+ draft: import_mini50.z.boolean(),
14025
+ assets: import_mini50.z.array(GitHubReleaseAssetSchema)
13969
14026
  });
13970
14027
 
13971
14028
  // src/lib/github-client.ts
@@ -14133,6 +14190,21 @@ var GitHubClient = class {
14133
14190
  throw error;
14134
14191
  }
14135
14192
  }
14193
+ /**
14194
+ * Resolve a ref (branch, tag, or SHA) to a full commit SHA.
14195
+ */
14196
+ async resolveRefToSha(owner, repo, ref) {
14197
+ try {
14198
+ const { data } = await this.octokit.repos.getCommit({
14199
+ owner,
14200
+ repo,
14201
+ ref
14202
+ });
14203
+ return data.sha;
14204
+ } catch (error) {
14205
+ throw this.handleError(error);
14206
+ }
14207
+ }
14136
14208
  /**
14137
14209
  * Get the latest release from a repository
14138
14210
  */
@@ -14203,96 +14275,60 @@ var GitHubClient = class {
14203
14275
  }
14204
14276
  };
14205
14277
 
14206
- // src/lib/fetch.ts
14207
- var FEATURE_PATHS = {
14208
- rules: ["rules"],
14209
- commands: ["commands"],
14210
- subagents: ["subagents"],
14211
- skills: ["skills"],
14212
- ignore: [RULESYNC_AIIGNORE_FILE_NAME],
14213
- mcp: [RULESYNC_MCP_FILE_NAME],
14214
- hooks: [RULESYNC_HOOKS_FILE_NAME]
14215
- };
14216
- function isToolTarget(target) {
14217
- return target !== "rulesync";
14278
+ // src/lib/github-utils.ts
14279
+ var MAX_RECURSION_DEPTH = 15;
14280
+ async function withSemaphore(semaphore, fn) {
14281
+ await semaphore.acquire();
14282
+ try {
14283
+ return await fn();
14284
+ } finally {
14285
+ semaphore.release();
14286
+ }
14218
14287
  }
14219
- function validateFileSize(relativePath, size) {
14220
- if (size > MAX_FILE_SIZE) {
14221
- throw new GitHubClientError(
14222
- `File "${relativePath}" exceeds maximum size limit (${(size / 1024 / 1024).toFixed(2)}MB > ${MAX_FILE_SIZE / 1024 / 1024}MB)`
14288
+ async function listDirectoryRecursive(params) {
14289
+ const { client, owner, repo, path: path4, ref, depth = 0, semaphore } = params;
14290
+ if (depth > MAX_RECURSION_DEPTH) {
14291
+ throw new Error(
14292
+ `Maximum recursion depth (${MAX_RECURSION_DEPTH}) exceeded while listing directory: ${path4}`
14223
14293
  );
14224
14294
  }
14225
- }
14226
- async function processFeatureConversion(params) {
14227
- const { processor, outputDir } = params;
14228
- const paths = [];
14229
- const toolFiles = await processor.loadToolFiles();
14230
- if (toolFiles.length === 0) {
14231
- return { paths: [] };
14295
+ const entries = await withSemaphore(
14296
+ semaphore,
14297
+ () => client.listDirectory(owner, repo, path4, ref)
14298
+ );
14299
+ const files = [];
14300
+ const directories = [];
14301
+ for (const entry of entries) {
14302
+ if (entry.type === "file") {
14303
+ files.push(entry);
14304
+ } else if (entry.type === "dir") {
14305
+ directories.push(entry);
14306
+ }
14232
14307
  }
14233
- const rulesyncFiles = await processor.convertToolFilesToRulesyncFiles(toolFiles);
14234
- for (const file of rulesyncFiles) {
14235
- const relativePath = (0, import_node_path108.join)(file.getRelativeDirPath(), file.getRelativeFilePath());
14236
- const outputPath = (0, import_node_path108.join)(outputDir, relativePath);
14237
- await writeFileContent(outputPath, file.getFileContent());
14238
- paths.push(relativePath);
14239
- }
14240
- return { paths };
14241
- }
14242
- async function convertFetchedFilesToRulesync(params) {
14243
- const { tempDir, outputDir, target, features } = params;
14244
- const convertedPaths = [];
14245
- const featureConfigs = [
14246
- {
14247
- feature: "rules",
14248
- getTargets: () => RulesProcessor.getToolTargets({ global: false }),
14249
- createProcessor: () => new RulesProcessor({ baseDir: tempDir, toolTarget: target, global: false })
14250
- },
14251
- {
14252
- feature: "commands",
14253
- getTargets: () => CommandsProcessor.getToolTargets({ global: false, includeSimulated: false }),
14254
- createProcessor: () => new CommandsProcessor({ baseDir: tempDir, toolTarget: target, global: false })
14255
- },
14256
- {
14257
- feature: "subagents",
14258
- getTargets: () => SubagentsProcessor.getToolTargets({ global: false, includeSimulated: false }),
14259
- createProcessor: () => new SubagentsProcessor({ baseDir: tempDir, toolTarget: target, global: false })
14260
- },
14261
- {
14262
- feature: "ignore",
14263
- getTargets: () => IgnoreProcessor.getToolTargets(),
14264
- createProcessor: () => new IgnoreProcessor({ baseDir: tempDir, toolTarget: target })
14265
- },
14266
- {
14267
- feature: "mcp",
14268
- getTargets: () => McpProcessor.getToolTargets({ global: false }),
14269
- createProcessor: () => new McpProcessor({ baseDir: tempDir, toolTarget: target, global: false })
14270
- },
14271
- {
14272
- feature: "hooks",
14273
- getTargets: () => HooksProcessor.getToolTargets({ global: false }),
14274
- createProcessor: () => new HooksProcessor({ baseDir: tempDir, toolTarget: target, global: false })
14275
- }
14276
- ];
14277
- for (const config of featureConfigs) {
14278
- if (!features.includes(config.feature)) {
14279
- continue;
14280
- }
14281
- const supportedTargets = config.getTargets();
14282
- if (!supportedTargets.includes(target)) {
14283
- continue;
14284
- }
14285
- const processor = config.createProcessor();
14286
- const result = await processFeatureConversion({ processor, outputDir });
14287
- convertedPaths.push(...result.paths);
14288
- }
14289
- if (features.includes("skills")) {
14290
- logger.debug(
14291
- "Skills conversion is not yet supported in fetch command. Use import command instead."
14292
- );
14293
- }
14294
- return { converted: convertedPaths.length, convertedPaths };
14308
+ const subResults = await Promise.all(
14309
+ directories.map(
14310
+ (dir) => listDirectoryRecursive({
14311
+ client,
14312
+ owner,
14313
+ repo,
14314
+ path: dir.path,
14315
+ ref,
14316
+ depth: depth + 1,
14317
+ semaphore
14318
+ })
14319
+ )
14320
+ );
14321
+ return [...files, ...subResults.flat()];
14295
14322
  }
14323
+
14324
+ // src/types/git-provider.ts
14325
+ var import_mini51 = require("zod/mini");
14326
+ var ALL_GIT_PROVIDERS = ["github", "gitlab"];
14327
+ var GitProviderSchema = import_mini51.z.enum(ALL_GIT_PROVIDERS);
14328
+
14329
+ // src/lib/source-parser.ts
14330
+ var GITHUB_HOSTS = /* @__PURE__ */ new Set(["github.com", "www.github.com"]);
14331
+ var GITLAB_HOSTS = /* @__PURE__ */ new Set(["gitlab.com", "www.gitlab.com"]);
14296
14332
  function parseSource(source) {
14297
14333
  if (source.startsWith("http://") || source.startsWith("https://")) {
14298
14334
  return parseUrl(source);
@@ -14309,18 +14345,6 @@ function parseSource(source) {
14309
14345
  }
14310
14346
  return { provider: "github", ...parseShorthand(source) };
14311
14347
  }
14312
- var GITHUB_HOSTS = /* @__PURE__ */ new Set(["github.com", "www.github.com"]);
14313
- var GITLAB_HOSTS = /* @__PURE__ */ new Set(["gitlab.com", "www.gitlab.com"]);
14314
- var MAX_RECURSION_DEPTH = 15;
14315
- var FETCH_CONCURRENCY_LIMIT = 10;
14316
- async function withSemaphore(semaphore, fn) {
14317
- await semaphore.acquire();
14318
- try {
14319
- return await fn();
14320
- } finally {
14321
- semaphore.release();
14322
- }
14323
- }
14324
14348
  function parseUrl(url) {
14325
14349
  const urlObj = new URL(url);
14326
14350
  const host = urlObj.hostname.toLowerCase();
@@ -14395,6 +14419,97 @@ function parseShorthand(source) {
14395
14419
  path: path4
14396
14420
  };
14397
14421
  }
14422
+
14423
+ // src/lib/fetch.ts
14424
+ var FEATURE_PATHS = {
14425
+ rules: ["rules"],
14426
+ commands: ["commands"],
14427
+ subagents: ["subagents"],
14428
+ skills: ["skills"],
14429
+ ignore: [RULESYNC_AIIGNORE_FILE_NAME],
14430
+ mcp: [RULESYNC_MCP_FILE_NAME],
14431
+ hooks: [RULESYNC_HOOKS_FILE_NAME]
14432
+ };
14433
+ function isToolTarget(target) {
14434
+ return target !== "rulesync";
14435
+ }
14436
+ function validateFileSize(relativePath, size) {
14437
+ if (size > MAX_FILE_SIZE) {
14438
+ throw new GitHubClientError(
14439
+ `File "${relativePath}" exceeds maximum size limit (${(size / 1024 / 1024).toFixed(2)}MB > ${MAX_FILE_SIZE / 1024 / 1024}MB)`
14440
+ );
14441
+ }
14442
+ }
14443
+ async function processFeatureConversion(params) {
14444
+ const { processor, outputDir } = params;
14445
+ const paths = [];
14446
+ const toolFiles = await processor.loadToolFiles();
14447
+ if (toolFiles.length === 0) {
14448
+ return { paths: [] };
14449
+ }
14450
+ const rulesyncFiles = await processor.convertToolFilesToRulesyncFiles(toolFiles);
14451
+ for (const file of rulesyncFiles) {
14452
+ const relativePath = (0, import_node_path109.join)(file.getRelativeDirPath(), file.getRelativeFilePath());
14453
+ const outputPath = (0, import_node_path109.join)(outputDir, relativePath);
14454
+ await writeFileContent(outputPath, file.getFileContent());
14455
+ paths.push(relativePath);
14456
+ }
14457
+ return { paths };
14458
+ }
14459
+ async function convertFetchedFilesToRulesync(params) {
14460
+ const { tempDir, outputDir, target, features } = params;
14461
+ const convertedPaths = [];
14462
+ const featureConfigs = [
14463
+ {
14464
+ feature: "rules",
14465
+ getTargets: () => RulesProcessor.getToolTargets({ global: false }),
14466
+ createProcessor: () => new RulesProcessor({ baseDir: tempDir, toolTarget: target, global: false })
14467
+ },
14468
+ {
14469
+ feature: "commands",
14470
+ getTargets: () => CommandsProcessor.getToolTargets({ global: false, includeSimulated: false }),
14471
+ createProcessor: () => new CommandsProcessor({ baseDir: tempDir, toolTarget: target, global: false })
14472
+ },
14473
+ {
14474
+ feature: "subagents",
14475
+ getTargets: () => SubagentsProcessor.getToolTargets({ global: false, includeSimulated: false }),
14476
+ createProcessor: () => new SubagentsProcessor({ baseDir: tempDir, toolTarget: target, global: false })
14477
+ },
14478
+ {
14479
+ feature: "ignore",
14480
+ getTargets: () => IgnoreProcessor.getToolTargets(),
14481
+ createProcessor: () => new IgnoreProcessor({ baseDir: tempDir, toolTarget: target })
14482
+ },
14483
+ {
14484
+ feature: "mcp",
14485
+ getTargets: () => McpProcessor.getToolTargets({ global: false }),
14486
+ createProcessor: () => new McpProcessor({ baseDir: tempDir, toolTarget: target, global: false })
14487
+ },
14488
+ {
14489
+ feature: "hooks",
14490
+ getTargets: () => HooksProcessor.getToolTargets({ global: false }),
14491
+ createProcessor: () => new HooksProcessor({ baseDir: tempDir, toolTarget: target, global: false })
14492
+ }
14493
+ ];
14494
+ for (const config of featureConfigs) {
14495
+ if (!features.includes(config.feature)) {
14496
+ continue;
14497
+ }
14498
+ const supportedTargets = config.getTargets();
14499
+ if (!supportedTargets.includes(target)) {
14500
+ continue;
14501
+ }
14502
+ const processor = config.createProcessor();
14503
+ const result = await processFeatureConversion({ processor, outputDir });
14504
+ convertedPaths.push(...result.paths);
14505
+ }
14506
+ if (features.includes("skills")) {
14507
+ logger.debug(
14508
+ "Skills conversion is not yet supported in fetch command. Use import command instead."
14509
+ );
14510
+ }
14511
+ return { converted: convertedPaths.length, convertedPaths };
14512
+ }
14398
14513
  function resolveFeatures(features) {
14399
14514
  if (!features || features.length === 0 || features.includes("*")) {
14400
14515
  return [...ALL_FEATURES];
@@ -14481,7 +14596,7 @@ async function fetchFiles(params) {
14481
14596
  skipped: 0
14482
14597
  };
14483
14598
  }
14484
- const outputBasePath = (0, import_node_path108.join)(baseDir, outputDir);
14599
+ const outputBasePath = (0, import_node_path109.join)(baseDir, outputDir);
14485
14600
  for (const { relativePath, size } of filesToFetch) {
14486
14601
  checkPathTraversal({
14487
14602
  relativePath,
@@ -14491,7 +14606,7 @@ async function fetchFiles(params) {
14491
14606
  }
14492
14607
  const results = await Promise.all(
14493
14608
  filesToFetch.map(async ({ remotePath, relativePath }) => {
14494
- const localPath = (0, import_node_path108.join)(outputBasePath, relativePath);
14609
+ const localPath = (0, import_node_path109.join)(outputBasePath, relativePath);
14495
14610
  const exists = await fileExists(localPath);
14496
14611
  if (exists && conflictStrategy === "skip") {
14497
14612
  logger.debug(`Skipping existing file: ${relativePath}`);
@@ -14533,7 +14648,7 @@ async function collectFeatureFiles(params) {
14533
14648
  );
14534
14649
  const results = await Promise.all(
14535
14650
  tasks.map(async ({ featurePath }) => {
14536
- const fullPath = basePath === "." || basePath === "" ? featurePath : (0, import_node_path108.join)(basePath, featurePath);
14651
+ const fullPath = basePath === "." || basePath === "" ? featurePath : (0, import_node_path109.join)(basePath, featurePath);
14537
14652
  const collected = [];
14538
14653
  try {
14539
14654
  if (featurePath.includes(".")) {
@@ -14586,41 +14701,6 @@ async function collectFeatureFiles(params) {
14586
14701
  );
14587
14702
  return results.flat();
14588
14703
  }
14589
- async function listDirectoryRecursive(params) {
14590
- const { client, owner, repo, path: path4, ref, depth = 0, semaphore } = params;
14591
- if (depth > MAX_RECURSION_DEPTH) {
14592
- throw new Error(
14593
- `Maximum recursion depth (${MAX_RECURSION_DEPTH}) exceeded while listing directory: ${path4}`
14594
- );
14595
- }
14596
- const entries = await withSemaphore(
14597
- semaphore,
14598
- () => client.listDirectory(owner, repo, path4, ref)
14599
- );
14600
- const files = [];
14601
- const directories = [];
14602
- for (const entry of entries) {
14603
- if (entry.type === "file") {
14604
- files.push(entry);
14605
- } else if (entry.type === "dir") {
14606
- directories.push(entry);
14607
- }
14608
- }
14609
- const subResults = await Promise.all(
14610
- directories.map(
14611
- (dir) => listDirectoryRecursive({
14612
- client,
14613
- owner,
14614
- repo,
14615
- path: dir.path,
14616
- ref,
14617
- depth: depth + 1,
14618
- semaphore
14619
- })
14620
- )
14621
- );
14622
- return [...files, ...subResults.flat()];
14623
- }
14624
14704
  async function fetchAndConvertToolFiles(params) {
14625
14705
  const {
14626
14706
  client,
@@ -14668,7 +14748,7 @@ async function fetchAndConvertToolFiles(params) {
14668
14748
  relativePath: toolRelativePath,
14669
14749
  intendedRootDir: tempDir
14670
14750
  });
14671
- const localPath = (0, import_node_path108.join)(tempDir, toolRelativePath);
14751
+ const localPath = (0, import_node_path109.join)(tempDir, toolRelativePath);
14672
14752
  const content = await withSemaphore(
14673
14753
  semaphore,
14674
14754
  () => client.getFileContent(parsed.owner, parsed.repo, remotePath, ref)
@@ -14677,7 +14757,7 @@ async function fetchAndConvertToolFiles(params) {
14677
14757
  logger.debug(`Fetched to temp: ${toolRelativePath}`);
14678
14758
  })
14679
14759
  );
14680
- const outputBasePath = (0, import_node_path108.join)(baseDir, outputDir);
14760
+ const outputBasePath = (0, import_node_path109.join)(baseDir, outputDir);
14681
14761
  const { converted, convertedPaths } = await convertFetchedFilesToRulesync({
14682
14762
  tempDir,
14683
14763
  outputDir: outputBasePath,
@@ -14688,7 +14768,7 @@ async function fetchAndConvertToolFiles(params) {
14688
14768
  relativePath,
14689
14769
  status: "created"
14690
14770
  }));
14691
- logger.info(`Converted ${converted} files from ${target} format to rulesync format`);
14771
+ logger.debug(`Converted ${converted} files from ${target} format to rulesync format`);
14692
14772
  return {
14693
14773
  source: `${parsed.owner}/${parsed.repo}`,
14694
14774
  ref,
@@ -14750,7 +14830,7 @@ function mapToToolPath(relativePath, toolPaths) {
14750
14830
  if (relativePath.startsWith("rules/")) {
14751
14831
  const restPath = relativePath.substring("rules/".length);
14752
14832
  if (toolPaths.rules?.nonRoot) {
14753
- return (0, import_node_path108.join)(toolPaths.rules.nonRoot, restPath);
14833
+ return (0, import_node_path109.join)(toolPaths.rules.nonRoot, restPath);
14754
14834
  }
14755
14835
  }
14756
14836
  if (toolPaths.rules?.root && relativePath === toolPaths.rules.root) {
@@ -14759,19 +14839,19 @@ function mapToToolPath(relativePath, toolPaths) {
14759
14839
  if (relativePath.startsWith("commands/")) {
14760
14840
  const restPath = relativePath.substring("commands/".length);
14761
14841
  if (toolPaths.commands) {
14762
- return (0, import_node_path108.join)(toolPaths.commands, restPath);
14842
+ return (0, import_node_path109.join)(toolPaths.commands, restPath);
14763
14843
  }
14764
14844
  }
14765
14845
  if (relativePath.startsWith("subagents/")) {
14766
14846
  const restPath = relativePath.substring("subagents/".length);
14767
14847
  if (toolPaths.subagents) {
14768
- return (0, import_node_path108.join)(toolPaths.subagents, restPath);
14848
+ return (0, import_node_path109.join)(toolPaths.subagents, restPath);
14769
14849
  }
14770
14850
  }
14771
14851
  if (relativePath.startsWith("skills/")) {
14772
14852
  const restPath = relativePath.substring("skills/".length);
14773
14853
  if (toolPaths.skills) {
14774
- return (0, import_node_path108.join)(toolPaths.skills, restPath);
14854
+ return (0, import_node_path109.join)(toolPaths.skills, restPath);
14775
14855
  }
14776
14856
  }
14777
14857
  return relativePath;
@@ -14801,7 +14881,7 @@ async function fetchCommand(options) {
14801
14881
  verbose: fetchOptions.verbose ?? false,
14802
14882
  silent: fetchOptions.silent ?? false
14803
14883
  });
14804
- logger.info(`Fetching files from ${source}...`);
14884
+ logger.debug(`Fetching files from ${source}...`);
14805
14885
  try {
14806
14886
  const summary = await fetchFiles({
14807
14887
  source,
@@ -14824,10 +14904,14 @@ async function fetchCommand(options) {
14824
14904
 
14825
14905
  // src/config/config-resolver.ts
14826
14906
  var import_jsonc_parser = require("jsonc-parser");
14827
- var import_node_path109 = require("path");
14907
+ var import_node_path110 = require("path");
14828
14908
 
14829
14909
  // src/config/config.ts
14830
14910
  var import_mini52 = require("zod/mini");
14911
+ var SourceEntrySchema = import_mini52.z.object({
14912
+ source: import_mini52.z.string().check((0, import_mini52.minLength)(1, "source must be a non-empty string")),
14913
+ skills: (0, import_mini52.optional)(import_mini52.z.array(import_mini52.z.string()))
14914
+ });
14831
14915
  var ConfigParamsSchema = import_mini52.z.object({
14832
14916
  baseDirs: import_mini52.z.array(import_mini52.z.string()),
14833
14917
  targets: RulesyncTargetsSchema,
@@ -14841,7 +14925,9 @@ var ConfigParamsSchema = import_mini52.z.object({
14841
14925
  simulateSubagents: (0, import_mini52.optional)(import_mini52.z.boolean()),
14842
14926
  simulateSkills: (0, import_mini52.optional)(import_mini52.z.boolean()),
14843
14927
  dryRun: (0, import_mini52.optional)(import_mini52.z.boolean()),
14844
- check: (0, import_mini52.optional)(import_mini52.z.boolean())
14928
+ check: (0, import_mini52.optional)(import_mini52.z.boolean()),
14929
+ // Declarative skill sources
14930
+ sources: (0, import_mini52.optional)(import_mini52.z.array(SourceEntrySchema))
14845
14931
  });
14846
14932
  var PartialConfigParamsSchema = import_mini52.z.partial(ConfigParamsSchema);
14847
14933
  var ConfigFileSchema = import_mini52.z.object({
@@ -14867,6 +14953,7 @@ var Config = class {
14867
14953
  simulateSkills;
14868
14954
  dryRun;
14869
14955
  check;
14956
+ sources;
14870
14957
  constructor({
14871
14958
  baseDirs,
14872
14959
  targets,
@@ -14879,7 +14966,8 @@ var Config = class {
14879
14966
  simulateSubagents,
14880
14967
  simulateSkills,
14881
14968
  dryRun,
14882
- check
14969
+ check,
14970
+ sources
14883
14971
  }) {
14884
14972
  this.validateConflictingTargets(targets);
14885
14973
  if (dryRun && check) {
@@ -14897,6 +14985,7 @@ var Config = class {
14897
14985
  this.simulateSkills = simulateSkills ?? false;
14898
14986
  this.dryRun = dryRun ?? false;
14899
14987
  this.check = check ?? false;
14988
+ this.sources = sources ?? [];
14900
14989
  }
14901
14990
  validateConflictingTargets(targets) {
14902
14991
  for (const [target1, target2] of CONFLICTING_TARGET_PAIRS) {
@@ -14987,6 +15076,9 @@ var Config = class {
14987
15076
  getCheck() {
14988
15077
  return this.check;
14989
15078
  }
15079
+ getSources() {
15080
+ return this.sources;
15081
+ }
14990
15082
  /**
14991
15083
  * Returns true if either dry-run or check mode is enabled.
14992
15084
  * In both modes, no files should be written.
@@ -15010,7 +15102,8 @@ var getDefaults = () => ({
15010
15102
  simulateSubagents: false,
15011
15103
  simulateSkills: false,
15012
15104
  dryRun: false,
15013
- check: false
15105
+ check: false,
15106
+ sources: []
15014
15107
  });
15015
15108
  var loadConfigFromFile = async (filePath) => {
15016
15109
  if (!await fileExists(filePath)) {
@@ -15040,7 +15133,8 @@ var mergeConfigs = (baseConfig, localConfig) => {
15040
15133
  simulateSubagents: localConfig.simulateSubagents ?? baseConfig.simulateSubagents,
15041
15134
  simulateSkills: localConfig.simulateSkills ?? baseConfig.simulateSkills,
15042
15135
  dryRun: localConfig.dryRun ?? baseConfig.dryRun,
15043
- check: localConfig.check ?? baseConfig.check
15136
+ check: localConfig.check ?? baseConfig.check,
15137
+ sources: localConfig.sources ?? baseConfig.sources
15044
15138
  };
15045
15139
  };
15046
15140
  var ConfigResolver = class {
@@ -15061,8 +15155,8 @@ var ConfigResolver = class {
15061
15155
  }) {
15062
15156
  const validatedConfigPath = resolvePath(configPath, process.cwd());
15063
15157
  const baseConfig = await loadConfigFromFile(validatedConfigPath);
15064
- const configDir = (0, import_node_path109.dirname)(validatedConfigPath);
15065
- const localConfigPath = (0, import_node_path109.join)(configDir, RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH);
15158
+ const configDir = (0, import_node_path110.dirname)(validatedConfigPath);
15159
+ const localConfigPath = (0, import_node_path110.join)(configDir, RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH);
15066
15160
  const localConfig = await loadConfigFromFile(localConfigPath);
15067
15161
  const configByFile = mergeConfigs(baseConfig, localConfig);
15068
15162
  const resolvedGlobal = global ?? configByFile.global ?? getDefaults().global;
@@ -15084,7 +15178,8 @@ var ConfigResolver = class {
15084
15178
  simulateSubagents: resolvedSimulateSubagents,
15085
15179
  simulateSkills: resolvedSimulateSkills,
15086
15180
  dryRun: dryRun ?? configByFile.dryRun ?? getDefaults().dryRun,
15087
- check: check ?? configByFile.check ?? getDefaults().check
15181
+ check: check ?? configByFile.check ?? getDefaults().check,
15182
+ sources: configByFile.sources ?? getDefaults().sources
15088
15183
  };
15089
15184
  return new Config(configParams);
15090
15185
  }
@@ -15096,7 +15191,7 @@ function getBaseDirsInLightOfGlobal({
15096
15191
  if (global) {
15097
15192
  return [getHomeDirectory()];
15098
15193
  }
15099
- const resolvedBaseDirs = baseDirs.map((baseDir) => (0, import_node_path109.resolve)(baseDir));
15194
+ const resolvedBaseDirs = baseDirs.map((baseDir) => (0, import_node_path110.resolve)(baseDir));
15100
15195
  resolvedBaseDirs.forEach((baseDir) => {
15101
15196
  validateBaseDir(baseDir);
15102
15197
  });
@@ -15105,34 +15200,38 @@ function getBaseDirsInLightOfGlobal({
15105
15200
 
15106
15201
  // src/lib/generate.ts
15107
15202
  var import_es_toolkit4 = require("es-toolkit");
15108
- var import_node_path110 = require("path");
15203
+ var import_node_path111 = require("path");
15109
15204
  async function processFeatureGeneration(params) {
15110
15205
  const { config, processor, toolFiles } = params;
15111
15206
  let totalCount = 0;
15207
+ const allPaths = [];
15112
15208
  let hasDiff = false;
15113
- const writtenCount = await processor.writeAiFiles(toolFiles);
15114
- totalCount += writtenCount;
15115
- if (writtenCount > 0) hasDiff = true;
15209
+ const writeResult = await processor.writeAiFiles(toolFiles);
15210
+ totalCount += writeResult.count;
15211
+ allPaths.push(...writeResult.paths);
15212
+ if (writeResult.count > 0) hasDiff = true;
15116
15213
  if (config.getDelete()) {
15117
15214
  const existingToolFiles = await processor.loadToolFiles({ forDeletion: true });
15118
15215
  const orphanCount = await processor.removeOrphanAiFiles(existingToolFiles, toolFiles);
15119
15216
  if (orphanCount > 0) hasDiff = true;
15120
15217
  }
15121
- return { count: totalCount, hasDiff };
15218
+ return { count: totalCount, paths: allPaths, hasDiff };
15122
15219
  }
15123
15220
  async function processDirFeatureGeneration(params) {
15124
15221
  const { config, processor, toolDirs } = params;
15125
15222
  let totalCount = 0;
15223
+ const allPaths = [];
15126
15224
  let hasDiff = false;
15127
- const writtenCount = await processor.writeAiDirs(toolDirs);
15128
- totalCount += writtenCount;
15129
- if (writtenCount > 0) hasDiff = true;
15225
+ const writeResult = await processor.writeAiDirs(toolDirs);
15226
+ totalCount += writeResult.count;
15227
+ allPaths.push(...writeResult.paths);
15228
+ if (writeResult.count > 0) hasDiff = true;
15130
15229
  if (config.getDelete()) {
15131
15230
  const existingToolDirs = await processor.loadToolDirsToDelete();
15132
15231
  const orphanCount = await processor.removeOrphanAiDirs(existingToolDirs, toolDirs);
15133
15232
  if (orphanCount > 0) hasDiff = true;
15134
15233
  }
15135
- return { count: totalCount, hasDiff };
15234
+ return { count: totalCount, paths: allPaths, hasDiff };
15136
15235
  }
15137
15236
  async function processEmptyFeatureGeneration(params) {
15138
15237
  const { config, processor } = params;
@@ -15143,10 +15242,10 @@ async function processEmptyFeatureGeneration(params) {
15143
15242
  const orphanCount = await processor.removeOrphanAiFiles(existingToolFiles, []);
15144
15243
  if (orphanCount > 0) hasDiff = true;
15145
15244
  }
15146
- return { count: totalCount, hasDiff };
15245
+ return { count: totalCount, paths: [], hasDiff };
15147
15246
  }
15148
15247
  async function checkRulesyncDirExists(params) {
15149
- return fileExists((0, import_node_path110.join)(params.baseDir, RULESYNC_RELATIVE_DIR_PATH));
15248
+ return fileExists((0, import_node_path111.join)(params.baseDir, RULESYNC_RELATIVE_DIR_PATH));
15150
15249
  }
15151
15250
  async function generate(params) {
15152
15251
  const { config } = params;
@@ -15160,12 +15259,19 @@ async function generate(params) {
15160
15259
  const hasDiff = ignoreResult.hasDiff || mcpResult.hasDiff || commandsResult.hasDiff || subagentsResult.hasDiff || skillsResult.hasDiff || hooksResult.hasDiff || rulesResult.hasDiff;
15161
15260
  return {
15162
15261
  rulesCount: rulesResult.count,
15262
+ rulesPaths: rulesResult.paths,
15163
15263
  ignoreCount: ignoreResult.count,
15264
+ ignorePaths: ignoreResult.paths,
15164
15265
  mcpCount: mcpResult.count,
15266
+ mcpPaths: mcpResult.paths,
15165
15267
  commandsCount: commandsResult.count,
15268
+ commandsPaths: commandsResult.paths,
15166
15269
  subagentsCount: subagentsResult.count,
15270
+ subagentsPaths: subagentsResult.paths,
15167
15271
  skillsCount: skillsResult.count,
15272
+ skillsPaths: skillsResult.paths,
15168
15273
  hooksCount: hooksResult.count,
15274
+ hooksPaths: hooksResult.paths,
15169
15275
  skills: skillsResult.skills,
15170
15276
  hasDiff
15171
15277
  };
@@ -15173,6 +15279,7 @@ async function generate(params) {
15173
15279
  async function generateRulesCore(params) {
15174
15280
  const { config, skills } = params;
15175
15281
  let totalCount = 0;
15282
+ const allPaths = [];
15176
15283
  let hasDiff = false;
15177
15284
  const toolTargets = (0, import_es_toolkit4.intersection)(
15178
15285
  config.getTargets(),
@@ -15201,17 +15308,19 @@ async function generateRulesCore(params) {
15201
15308
  toolFiles
15202
15309
  });
15203
15310
  totalCount += result.count;
15311
+ allPaths.push(...result.paths);
15204
15312
  if (result.hasDiff) hasDiff = true;
15205
15313
  }
15206
15314
  }
15207
- return { count: totalCount, hasDiff };
15315
+ return { count: totalCount, paths: allPaths, hasDiff };
15208
15316
  }
15209
15317
  async function generateIgnoreCore(params) {
15210
15318
  const { config } = params;
15211
15319
  if (config.getGlobal()) {
15212
- return { count: 0, hasDiff: false };
15320
+ return { count: 0, paths: [], hasDiff: false };
15213
15321
  }
15214
15322
  let totalCount = 0;
15323
+ const allPaths = [];
15215
15324
  let hasDiff = false;
15216
15325
  for (const toolTarget of (0, import_es_toolkit4.intersection)(config.getTargets(), IgnoreProcessor.getToolTargets())) {
15217
15326
  if (!config.getFeatures(toolTarget).includes("ignore")) {
@@ -15240,6 +15349,7 @@ async function generateIgnoreCore(params) {
15240
15349
  });
15241
15350
  }
15242
15351
  totalCount += result.count;
15352
+ allPaths.push(...result.paths);
15243
15353
  if (result.hasDiff) hasDiff = true;
15244
15354
  } catch (error) {
15245
15355
  logger.warn(
@@ -15249,11 +15359,12 @@ async function generateIgnoreCore(params) {
15249
15359
  }
15250
15360
  }
15251
15361
  }
15252
- return { count: totalCount, hasDiff };
15362
+ return { count: totalCount, paths: allPaths, hasDiff };
15253
15363
  }
15254
15364
  async function generateMcpCore(params) {
15255
15365
  const { config } = params;
15256
15366
  let totalCount = 0;
15367
+ const allPaths = [];
15257
15368
  let hasDiff = false;
15258
15369
  const toolTargets = (0, import_es_toolkit4.intersection)(
15259
15370
  config.getTargets(),
@@ -15278,14 +15389,16 @@ async function generateMcpCore(params) {
15278
15389
  toolFiles
15279
15390
  });
15280
15391
  totalCount += result.count;
15392
+ allPaths.push(...result.paths);
15281
15393
  if (result.hasDiff) hasDiff = true;
15282
15394
  }
15283
15395
  }
15284
- return { count: totalCount, hasDiff };
15396
+ return { count: totalCount, paths: allPaths, hasDiff };
15285
15397
  }
15286
15398
  async function generateCommandsCore(params) {
15287
15399
  const { config } = params;
15288
15400
  let totalCount = 0;
15401
+ const allPaths = [];
15289
15402
  let hasDiff = false;
15290
15403
  const toolTargets = (0, import_es_toolkit4.intersection)(
15291
15404
  config.getTargets(),
@@ -15313,14 +15426,16 @@ async function generateCommandsCore(params) {
15313
15426
  toolFiles
15314
15427
  });
15315
15428
  totalCount += result.count;
15429
+ allPaths.push(...result.paths);
15316
15430
  if (result.hasDiff) hasDiff = true;
15317
15431
  }
15318
15432
  }
15319
- return { count: totalCount, hasDiff };
15433
+ return { count: totalCount, paths: allPaths, hasDiff };
15320
15434
  }
15321
15435
  async function generateSubagentsCore(params) {
15322
15436
  const { config } = params;
15323
15437
  let totalCount = 0;
15438
+ const allPaths = [];
15324
15439
  let hasDiff = false;
15325
15440
  const toolTargets = (0, import_es_toolkit4.intersection)(
15326
15441
  config.getTargets(),
@@ -15348,14 +15463,16 @@ async function generateSubagentsCore(params) {
15348
15463
  toolFiles
15349
15464
  });
15350
15465
  totalCount += result.count;
15466
+ allPaths.push(...result.paths);
15351
15467
  if (result.hasDiff) hasDiff = true;
15352
15468
  }
15353
15469
  }
15354
- return { count: totalCount, hasDiff };
15470
+ return { count: totalCount, paths: allPaths, hasDiff };
15355
15471
  }
15356
15472
  async function generateSkillsCore(params) {
15357
15473
  const { config } = params;
15358
15474
  let totalCount = 0;
15475
+ const allPaths = [];
15359
15476
  let hasDiff = false;
15360
15477
  const allSkills = [];
15361
15478
  const toolTargets = (0, import_es_toolkit4.intersection)(
@@ -15389,14 +15506,16 @@ async function generateSkillsCore(params) {
15389
15506
  toolDirs
15390
15507
  });
15391
15508
  totalCount += result.count;
15509
+ allPaths.push(...result.paths);
15392
15510
  if (result.hasDiff) hasDiff = true;
15393
15511
  }
15394
15512
  }
15395
- return { count: totalCount, skills: allSkills, hasDiff };
15513
+ return { count: totalCount, paths: allPaths, skills: allSkills, hasDiff };
15396
15514
  }
15397
15515
  async function generateHooksCore(params) {
15398
15516
  const { config } = params;
15399
15517
  let totalCount = 0;
15518
+ const allPaths = [];
15400
15519
  let hasDiff = false;
15401
15520
  const toolTargets = (0, import_es_toolkit4.intersection)(
15402
15521
  config.getTargets(),
@@ -15429,10 +15548,11 @@ async function generateHooksCore(params) {
15429
15548
  });
15430
15549
  }
15431
15550
  totalCount += result.count;
15551
+ allPaths.push(...result.paths);
15432
15552
  if (result.hasDiff) hasDiff = true;
15433
15553
  }
15434
15554
  }
15435
- return { count: totalCount, hasDiff };
15555
+ return { count: totalCount, paths: allPaths, hasDiff };
15436
15556
  }
15437
15557
 
15438
15558
  // src/utils/result.ts
@@ -15442,13 +15562,16 @@ function calculateTotalCount(result) {
15442
15562
 
15443
15563
  // src/cli/commands/generate.ts
15444
15564
  function logFeatureResult(params) {
15445
- const { count, featureName, isPreview, modePrefix } = params;
15565
+ const { count, paths, featureName, isPreview, modePrefix } = params;
15446
15566
  if (count > 0) {
15447
15567
  if (isPreview) {
15448
15568
  logger.info(`${modePrefix} Would write ${count} ${featureName}`);
15449
15569
  } else {
15450
15570
  logger.success(`Written ${count} ${featureName}`);
15451
15571
  }
15572
+ for (const p of paths) {
15573
+ logger.info(` ${p}`);
15574
+ }
15452
15575
  }
15453
15576
  }
15454
15577
  async function generateCommand(options) {
@@ -15460,73 +15583,80 @@ async function generateCommand(options) {
15460
15583
  const check = config.getCheck();
15461
15584
  const isPreview = config.isPreviewMode();
15462
15585
  const modePrefix = isPreview ? "[DRY RUN]" : "";
15463
- logger.info("Generating files...");
15586
+ logger.debug("Generating files...");
15464
15587
  if (!await checkRulesyncDirExists({ baseDir: process.cwd() })) {
15465
15588
  logger.error("\u274C .rulesync directory not found. Run 'rulesync init' first.");
15466
15589
  process.exit(1);
15467
15590
  }
15468
- logger.info(`Base directories: ${config.getBaseDirs().join(", ")}`);
15591
+ logger.debug(`Base directories: ${config.getBaseDirs().join(", ")}`);
15469
15592
  const features = config.getFeatures();
15470
15593
  if (features.includes("ignore")) {
15471
- logger.info("Generating ignore files...");
15594
+ logger.debug("Generating ignore files...");
15472
15595
  }
15473
15596
  if (features.includes("mcp")) {
15474
- logger.info("Generating MCP files...");
15597
+ logger.debug("Generating MCP files...");
15475
15598
  }
15476
15599
  if (features.includes("commands")) {
15477
- logger.info("Generating command files...");
15600
+ logger.debug("Generating command files...");
15478
15601
  }
15479
15602
  if (features.includes("subagents")) {
15480
- logger.info("Generating subagent files...");
15603
+ logger.debug("Generating subagent files...");
15481
15604
  }
15482
15605
  if (features.includes("skills")) {
15483
- logger.info("Generating skill files...");
15606
+ logger.debug("Generating skill files...");
15484
15607
  }
15485
15608
  if (features.includes("hooks")) {
15486
- logger.info("Generating hooks...");
15609
+ logger.debug("Generating hooks...");
15487
15610
  }
15488
15611
  if (features.includes("rules")) {
15489
- logger.info("Generating rule files...");
15612
+ logger.debug("Generating rule files...");
15490
15613
  }
15491
15614
  const result = await generate({ config });
15492
15615
  logFeatureResult({
15493
15616
  count: result.ignoreCount,
15617
+ paths: result.ignorePaths,
15494
15618
  featureName: "ignore file(s)",
15495
15619
  isPreview,
15496
15620
  modePrefix
15497
15621
  });
15498
15622
  logFeatureResult({
15499
15623
  count: result.mcpCount,
15624
+ paths: result.mcpPaths,
15500
15625
  featureName: "MCP configuration(s)",
15501
15626
  isPreview,
15502
15627
  modePrefix
15503
15628
  });
15504
15629
  logFeatureResult({
15505
15630
  count: result.commandsCount,
15631
+ paths: result.commandsPaths,
15506
15632
  featureName: "command(s)",
15507
15633
  isPreview,
15508
15634
  modePrefix
15509
15635
  });
15510
15636
  logFeatureResult({
15511
15637
  count: result.subagentsCount,
15638
+ paths: result.subagentsPaths,
15512
15639
  featureName: "subagent(s)",
15513
15640
  isPreview,
15514
15641
  modePrefix
15515
15642
  });
15516
15643
  logFeatureResult({
15517
15644
  count: result.skillsCount,
15645
+ paths: result.skillsPaths,
15518
15646
  featureName: "skill(s)",
15519
15647
  isPreview,
15520
15648
  modePrefix
15521
15649
  });
15522
15650
  logFeatureResult({
15523
15651
  count: result.hooksCount,
15652
+ paths: result.hooksPaths,
15524
15653
  featureName: "hooks file(s)",
15525
15654
  isPreview,
15526
15655
  modePrefix
15527
15656
  });
15528
15657
  logFeatureResult({
15529
15658
  count: result.rulesCount,
15659
+ paths: result.rulesPaths,
15530
15660
  featureName: "rule(s)",
15531
15661
  isPreview,
15532
15662
  modePrefix
@@ -15561,10 +15691,12 @@ async function generateCommand(options) {
15561
15691
  }
15562
15692
 
15563
15693
  // src/cli/commands/gitignore.ts
15564
- var import_node_path111 = require("path");
15694
+ var import_node_path112 = require("path");
15565
15695
  var RULESYNC_HEADER = "# Generated by Rulesync";
15566
15696
  var LEGACY_RULESYNC_HEADER = "# Generated by rulesync - AI tool configuration files";
15567
15697
  var RULESYNC_IGNORE_ENTRIES = [
15698
+ // Rulesync curated (fetched) skills
15699
+ ".rulesync/skills/.curated/",
15568
15700
  // AGENTS.md
15569
15701
  "**/AGENTS.md",
15570
15702
  "**/.agents/",
@@ -15709,7 +15841,7 @@ var removeExistingRulesyncEntries = (content) => {
15709
15841
  return result;
15710
15842
  };
15711
15843
  var gitignoreCommand = async () => {
15712
- const gitignorePath = (0, import_node_path111.join)(process.cwd(), ".gitignore");
15844
+ const gitignorePath = (0, import_node_path112.join)(process.cwd(), ".gitignore");
15713
15845
  let gitignoreContent = "";
15714
15846
  if (await fileExists(gitignorePath)) {
15715
15847
  gitignoreContent = await readFileContent(gitignorePath);
@@ -15781,7 +15913,7 @@ async function importRulesCore(params) {
15781
15913
  return 0;
15782
15914
  }
15783
15915
  const rulesyncFiles = await rulesProcessor.convertToolFilesToRulesyncFiles(toolFiles);
15784
- const writtenCount = await rulesProcessor.writeAiFiles(rulesyncFiles);
15916
+ const { count: writtenCount } = await rulesProcessor.writeAiFiles(rulesyncFiles);
15785
15917
  if (config.getVerbose() && writtenCount > 0) {
15786
15918
  logger.success(`Created ${writtenCount} rule files`);
15787
15919
  }
@@ -15808,7 +15940,7 @@ async function importIgnoreCore(params) {
15808
15940
  return 0;
15809
15941
  }
15810
15942
  const rulesyncFiles = await ignoreProcessor.convertToolFilesToRulesyncFiles(toolFiles);
15811
- const writtenCount = await ignoreProcessor.writeAiFiles(rulesyncFiles);
15943
+ const { count: writtenCount } = await ignoreProcessor.writeAiFiles(rulesyncFiles);
15812
15944
  if (config.getVerbose()) {
15813
15945
  logger.success(`Created ignore files from ${toolFiles.length} tool ignore configurations`);
15814
15946
  }
@@ -15837,7 +15969,7 @@ async function importMcpCore(params) {
15837
15969
  return 0;
15838
15970
  }
15839
15971
  const rulesyncFiles = await mcpProcessor.convertToolFilesToRulesyncFiles(toolFiles);
15840
- const writtenCount = await mcpProcessor.writeAiFiles(rulesyncFiles);
15972
+ const { count: writtenCount } = await mcpProcessor.writeAiFiles(rulesyncFiles);
15841
15973
  if (config.getVerbose() && writtenCount > 0) {
15842
15974
  logger.success(`Created ${writtenCount} MCP files`);
15843
15975
  }
@@ -15863,7 +15995,7 @@ async function importCommandsCore(params) {
15863
15995
  return 0;
15864
15996
  }
15865
15997
  const rulesyncFiles = await commandsProcessor.convertToolFilesToRulesyncFiles(toolFiles);
15866
- const writtenCount = await commandsProcessor.writeAiFiles(rulesyncFiles);
15998
+ const { count: writtenCount } = await commandsProcessor.writeAiFiles(rulesyncFiles);
15867
15999
  if (config.getVerbose() && writtenCount > 0) {
15868
16000
  logger.success(`Created ${writtenCount} command files`);
15869
16001
  }
@@ -15889,7 +16021,7 @@ async function importSubagentsCore(params) {
15889
16021
  return 0;
15890
16022
  }
15891
16023
  const rulesyncFiles = await subagentsProcessor.convertToolFilesToRulesyncFiles(toolFiles);
15892
- const writtenCount = await subagentsProcessor.writeAiFiles(rulesyncFiles);
16024
+ const { count: writtenCount } = await subagentsProcessor.writeAiFiles(rulesyncFiles);
15893
16025
  if (config.getVerbose() && writtenCount > 0) {
15894
16026
  logger.success(`Created ${writtenCount} subagent files`);
15895
16027
  }
@@ -15915,7 +16047,7 @@ async function importSkillsCore(params) {
15915
16047
  return 0;
15916
16048
  }
15917
16049
  const rulesyncDirs = await skillsProcessor.convertToolDirsToRulesyncDirs(toolDirs);
15918
- const writtenCount = await skillsProcessor.writeAiDirs(rulesyncDirs);
16050
+ const { count: writtenCount } = await skillsProcessor.writeAiDirs(rulesyncDirs);
15919
16051
  if (config.getVerbose() && writtenCount > 0) {
15920
16052
  logger.success(`Created ${writtenCount} skill directories`);
15921
16053
  }
@@ -15946,7 +16078,7 @@ async function importHooksCore(params) {
15946
16078
  return 0;
15947
16079
  }
15948
16080
  const rulesyncFiles = await hooksProcessor.convertToolFilesToRulesyncFiles(toolFiles);
15949
- const writtenCount = await hooksProcessor.writeAiFiles(rulesyncFiles);
16081
+ const { count: writtenCount } = await hooksProcessor.writeAiFiles(rulesyncFiles);
15950
16082
  if (config.getVerbose() && writtenCount > 0) {
15951
16083
  logger.success(`Created ${writtenCount} hooks file(s)`);
15952
16084
  }
@@ -15969,7 +16101,7 @@ async function importCommand(options) {
15969
16101
  silent: config.getSilent()
15970
16102
  });
15971
16103
  const tool = config.getTargets()[0];
15972
- logger.info(`Importing files from ${tool}...`);
16104
+ logger.debug(`Importing files from ${tool}...`);
15973
16105
  const result = await importFromTool({ config, tool });
15974
16106
  const totalImported = calculateTotalCount(result);
15975
16107
  if (totalImported === 0) {
@@ -15989,7 +16121,7 @@ async function importCommand(options) {
15989
16121
  }
15990
16122
 
15991
16123
  // src/lib/init.ts
15992
- var import_node_path112 = require("path");
16124
+ var import_node_path113 = require("path");
15993
16125
  async function init() {
15994
16126
  const sampleFiles = await createSampleFiles();
15995
16127
  const configFile = await createConfigFile();
@@ -16179,27 +16311,27 @@ Keep the summary concise and ready to reuse in future tasks.`
16179
16311
  await ensureDir(subagentPaths.relativeDirPath);
16180
16312
  await ensureDir(skillPaths.relativeDirPath);
16181
16313
  await ensureDir(ignorePaths.recommended.relativeDirPath);
16182
- const ruleFilepath = (0, import_node_path112.join)(rulePaths.recommended.relativeDirPath, sampleRuleFile.filename);
16314
+ const ruleFilepath = (0, import_node_path113.join)(rulePaths.recommended.relativeDirPath, sampleRuleFile.filename);
16183
16315
  results.push(await writeIfNotExists(ruleFilepath, sampleRuleFile.content));
16184
- const mcpFilepath = (0, import_node_path112.join)(
16316
+ const mcpFilepath = (0, import_node_path113.join)(
16185
16317
  mcpPaths.recommended.relativeDirPath,
16186
16318
  mcpPaths.recommended.relativeFilePath
16187
16319
  );
16188
16320
  results.push(await writeIfNotExists(mcpFilepath, sampleMcpFile.content));
16189
- const commandFilepath = (0, import_node_path112.join)(commandPaths.relativeDirPath, sampleCommandFile.filename);
16321
+ const commandFilepath = (0, import_node_path113.join)(commandPaths.relativeDirPath, sampleCommandFile.filename);
16190
16322
  results.push(await writeIfNotExists(commandFilepath, sampleCommandFile.content));
16191
- const subagentFilepath = (0, import_node_path112.join)(subagentPaths.relativeDirPath, sampleSubagentFile.filename);
16323
+ const subagentFilepath = (0, import_node_path113.join)(subagentPaths.relativeDirPath, sampleSubagentFile.filename);
16192
16324
  results.push(await writeIfNotExists(subagentFilepath, sampleSubagentFile.content));
16193
- const skillDirPath = (0, import_node_path112.join)(skillPaths.relativeDirPath, sampleSkillFile.dirName);
16325
+ const skillDirPath = (0, import_node_path113.join)(skillPaths.relativeDirPath, sampleSkillFile.dirName);
16194
16326
  await ensureDir(skillDirPath);
16195
- const skillFilepath = (0, import_node_path112.join)(skillDirPath, SKILL_FILE_NAME);
16327
+ const skillFilepath = (0, import_node_path113.join)(skillDirPath, SKILL_FILE_NAME);
16196
16328
  results.push(await writeIfNotExists(skillFilepath, sampleSkillFile.content));
16197
- const ignoreFilepath = (0, import_node_path112.join)(
16329
+ const ignoreFilepath = (0, import_node_path113.join)(
16198
16330
  ignorePaths.recommended.relativeDirPath,
16199
16331
  ignorePaths.recommended.relativeFilePath
16200
16332
  );
16201
16333
  results.push(await writeIfNotExists(ignoreFilepath, sampleIgnoreFile.content));
16202
- const hooksFilepath = (0, import_node_path112.join)(hooksPaths.relativeDirPath, hooksPaths.relativeFilePath);
16334
+ const hooksFilepath = (0, import_node_path113.join)(hooksPaths.relativeDirPath, hooksPaths.relativeFilePath);
16203
16335
  results.push(await writeIfNotExists(hooksFilepath, sampleHooksFile.content));
16204
16336
  return results;
16205
16337
  }
@@ -16213,7 +16345,7 @@ async function writeIfNotExists(path4, content) {
16213
16345
 
16214
16346
  // src/cli/commands/init.ts
16215
16347
  async function initCommand() {
16216
- logger.info("Initializing rulesync...");
16348
+ logger.debug("Initializing rulesync...");
16217
16349
  await ensureDir(RULESYNC_RELATIVE_DIR_PATH);
16218
16350
  const result = await init();
16219
16351
  for (const file of result.sampleFiles) {
@@ -16236,19 +16368,447 @@ async function initCommand() {
16236
16368
  logger.info("2. Run 'rulesync generate' to create configuration files");
16237
16369
  }
16238
16370
 
16371
+ // src/lib/sources.ts
16372
+ var import_promise2 = require("es-toolkit/promise");
16373
+ var import_node_path115 = require("path");
16374
+
16375
+ // src/lib/sources-lock.ts
16376
+ var import_node_crypto = require("crypto");
16377
+ var import_node_path114 = require("path");
16378
+ var import_mini53 = require("zod/mini");
16379
+ var LOCKFILE_VERSION = 1;
16380
+ var LockedSkillSchema = import_mini53.z.object({
16381
+ integrity: import_mini53.z.string()
16382
+ });
16383
+ var LockedSourceSchema = import_mini53.z.object({
16384
+ requestedRef: (0, import_mini53.optional)(import_mini53.z.string()),
16385
+ resolvedRef: import_mini53.z.string(),
16386
+ resolvedAt: (0, import_mini53.optional)(import_mini53.z.string()),
16387
+ skills: import_mini53.z.record(import_mini53.z.string(), LockedSkillSchema)
16388
+ });
16389
+ var SourcesLockSchema = import_mini53.z.object({
16390
+ lockfileVersion: import_mini53.z.number(),
16391
+ sources: import_mini53.z.record(import_mini53.z.string(), LockedSourceSchema)
16392
+ });
16393
+ var LegacyLockedSourceSchema = import_mini53.z.object({
16394
+ resolvedRef: import_mini53.z.string(),
16395
+ skills: import_mini53.z.array(import_mini53.z.string())
16396
+ });
16397
+ var LegacySourcesLockSchema = import_mini53.z.object({
16398
+ sources: import_mini53.z.record(import_mini53.z.string(), LegacyLockedSourceSchema)
16399
+ });
16400
+ function migrateLegacyLock(legacy) {
16401
+ const sources = {};
16402
+ for (const [key, entry] of Object.entries(legacy.sources)) {
16403
+ const skills = {};
16404
+ for (const name of entry.skills) {
16405
+ skills[name] = { integrity: "" };
16406
+ }
16407
+ sources[key] = {
16408
+ resolvedRef: entry.resolvedRef,
16409
+ skills
16410
+ };
16411
+ }
16412
+ logger.info(
16413
+ "Migrated legacy sources lockfile to version 1. Run 'rulesync install --update' to populate integrity hashes."
16414
+ );
16415
+ return { lockfileVersion: LOCKFILE_VERSION, sources };
16416
+ }
16417
+ function createEmptyLock() {
16418
+ return { lockfileVersion: LOCKFILE_VERSION, sources: {} };
16419
+ }
16420
+ async function readLockFile(params) {
16421
+ const lockPath = (0, import_node_path114.join)(params.baseDir, RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH);
16422
+ if (!await fileExists(lockPath)) {
16423
+ logger.debug("No sources lockfile found, starting fresh.");
16424
+ return createEmptyLock();
16425
+ }
16426
+ try {
16427
+ const content = await readFileContent(lockPath);
16428
+ const data = JSON.parse(content);
16429
+ const result = SourcesLockSchema.safeParse(data);
16430
+ if (result.success) {
16431
+ return result.data;
16432
+ }
16433
+ const legacyResult = LegacySourcesLockSchema.safeParse(data);
16434
+ if (legacyResult.success) {
16435
+ return migrateLegacyLock(legacyResult.data);
16436
+ }
16437
+ logger.warn(
16438
+ `Invalid sources lockfile format (${RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH}). Starting fresh.`
16439
+ );
16440
+ return createEmptyLock();
16441
+ } catch {
16442
+ logger.warn(
16443
+ `Failed to read sources lockfile (${RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH}). Starting fresh.`
16444
+ );
16445
+ return createEmptyLock();
16446
+ }
16447
+ }
16448
+ async function writeLockFile(params) {
16449
+ const lockPath = (0, import_node_path114.join)(params.baseDir, RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH);
16450
+ const content = JSON.stringify(params.lock, null, 2) + "\n";
16451
+ await writeFileContent(lockPath, content);
16452
+ logger.debug(`Wrote sources lockfile to ${lockPath}`);
16453
+ }
16454
+ function computeSkillIntegrity(files) {
16455
+ const hash = (0, import_node_crypto.createHash)("sha256");
16456
+ const sorted = files.toSorted((a, b) => a.path.localeCompare(b.path));
16457
+ for (const file of sorted) {
16458
+ hash.update(file.path);
16459
+ hash.update("\0");
16460
+ hash.update(file.content);
16461
+ hash.update("\0");
16462
+ }
16463
+ return `sha256-${hash.digest("hex")}`;
16464
+ }
16465
+ function normalizeSourceKey(source) {
16466
+ let key = source;
16467
+ for (const prefix of [
16468
+ "https://www.github.com/",
16469
+ "https://github.com/",
16470
+ "http://www.github.com/",
16471
+ "http://github.com/"
16472
+ ]) {
16473
+ if (key.toLowerCase().startsWith(prefix)) {
16474
+ key = key.substring(prefix.length);
16475
+ break;
16476
+ }
16477
+ }
16478
+ if (key.startsWith("github:")) {
16479
+ key = key.substring("github:".length);
16480
+ }
16481
+ key = key.replace(/\/+$/, "");
16482
+ key = key.replace(/\.git$/, "");
16483
+ key = key.toLowerCase();
16484
+ return key;
16485
+ }
16486
+ function getLockedSource(lock, sourceKey) {
16487
+ const normalized = normalizeSourceKey(sourceKey);
16488
+ for (const [key, value] of Object.entries(lock.sources)) {
16489
+ if (normalizeSourceKey(key) === normalized) {
16490
+ return value;
16491
+ }
16492
+ }
16493
+ return void 0;
16494
+ }
16495
+ function setLockedSource(lock, sourceKey, entry) {
16496
+ const normalized = normalizeSourceKey(sourceKey);
16497
+ const filteredSources = {};
16498
+ for (const [key, value] of Object.entries(lock.sources)) {
16499
+ if (normalizeSourceKey(key) !== normalized) {
16500
+ filteredSources[key] = value;
16501
+ }
16502
+ }
16503
+ return {
16504
+ lockfileVersion: lock.lockfileVersion,
16505
+ sources: {
16506
+ ...filteredSources,
16507
+ [normalized]: entry
16508
+ }
16509
+ };
16510
+ }
16511
+ function getLockedSkillNames(entry) {
16512
+ return Object.keys(entry.skills);
16513
+ }
16514
+
16515
+ // src/lib/sources.ts
16516
+ async function resolveAndFetchSources(params) {
16517
+ const { sources, baseDir, options = {} } = params;
16518
+ if (sources.length === 0) {
16519
+ return { fetchedSkillCount: 0, sourcesProcessed: 0 };
16520
+ }
16521
+ if (options.skipSources) {
16522
+ logger.info("Skipping source fetching.");
16523
+ return { fetchedSkillCount: 0, sourcesProcessed: 0 };
16524
+ }
16525
+ let lock = options.updateSources ? createEmptyLock() : await readLockFile({ baseDir });
16526
+ if (options.frozen) {
16527
+ const missingKeys = [];
16528
+ const missingSkills = [];
16529
+ const curatedDir = (0, import_node_path115.join)(baseDir, RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH);
16530
+ for (const source of sources) {
16531
+ const locked = getLockedSource(lock, source.source);
16532
+ if (!locked) {
16533
+ missingKeys.push(source.source);
16534
+ continue;
16535
+ }
16536
+ const skillNames = getLockedSkillNames(locked);
16537
+ for (const skillName of skillNames) {
16538
+ if (!await directoryExists((0, import_node_path115.join)(curatedDir, skillName))) {
16539
+ missingSkills.push(`${source.source}:${skillName}`);
16540
+ }
16541
+ }
16542
+ }
16543
+ if (missingKeys.length > 0) {
16544
+ throw new Error(
16545
+ `Frozen install failed: lockfile is missing entries for: ${missingKeys.join(", ")}. Run 'rulesync install' to update the lockfile.`
16546
+ );
16547
+ }
16548
+ if (missingSkills.length > 0) {
16549
+ throw new Error(
16550
+ `Frozen install failed: locked skills missing from disk: ${missingSkills.join(", ")}. Run 'rulesync install' to fetch missing skills.`
16551
+ );
16552
+ }
16553
+ }
16554
+ const originalLockJson = JSON.stringify(lock);
16555
+ const token = GitHubClient.resolveToken(options.token);
16556
+ const client = new GitHubClient({ token });
16557
+ const localSkillNames = await getLocalSkillDirNames(baseDir);
16558
+ let totalSkillCount = 0;
16559
+ const allFetchedSkillNames = /* @__PURE__ */ new Set();
16560
+ for (const sourceEntry of sources) {
16561
+ try {
16562
+ const { skillCount, fetchedSkillNames, updatedLock } = await fetchSource({
16563
+ sourceEntry,
16564
+ client,
16565
+ baseDir,
16566
+ lock,
16567
+ localSkillNames,
16568
+ alreadyFetchedSkillNames: allFetchedSkillNames,
16569
+ updateSources: options.updateSources ?? false
16570
+ });
16571
+ lock = updatedLock;
16572
+ totalSkillCount += skillCount;
16573
+ for (const name of fetchedSkillNames) {
16574
+ allFetchedSkillNames.add(name);
16575
+ }
16576
+ } catch (error) {
16577
+ if (error instanceof GitHubClientError) {
16578
+ logGitHubAuthHints(error);
16579
+ } else {
16580
+ logger.error(`Failed to fetch source "${sourceEntry.source}": ${formatError(error)}`);
16581
+ }
16582
+ }
16583
+ }
16584
+ const sourceKeys = new Set(sources.map((s) => normalizeSourceKey(s.source)));
16585
+ const prunedSources = {};
16586
+ for (const [key, value] of Object.entries(lock.sources)) {
16587
+ if (sourceKeys.has(normalizeSourceKey(key))) {
16588
+ prunedSources[key] = value;
16589
+ } else {
16590
+ logger.debug(`Pruned stale lockfile entry: ${key}`);
16591
+ }
16592
+ }
16593
+ lock = { lockfileVersion: lock.lockfileVersion, sources: prunedSources };
16594
+ if (!options.frozen && JSON.stringify(lock) !== originalLockJson) {
16595
+ await writeLockFile({ baseDir, lock });
16596
+ } else {
16597
+ logger.debug("Lockfile unchanged, skipping write.");
16598
+ }
16599
+ return { fetchedSkillCount: totalSkillCount, sourcesProcessed: sources.length };
16600
+ }
16601
+ async function checkLockedSkillsExist(curatedDir, skillNames) {
16602
+ if (skillNames.length === 0) return true;
16603
+ for (const name of skillNames) {
16604
+ if (!await directoryExists((0, import_node_path115.join)(curatedDir, name))) {
16605
+ return false;
16606
+ }
16607
+ }
16608
+ return true;
16609
+ }
16610
+ async function fetchSource(params) {
16611
+ const { sourceEntry, client, baseDir, localSkillNames, alreadyFetchedSkillNames, updateSources } = params;
16612
+ let { lock } = params;
16613
+ const parsed = parseSource(sourceEntry.source);
16614
+ if (parsed.provider === "gitlab") {
16615
+ throw new Error("GitLab sources are not yet supported.");
16616
+ }
16617
+ const sourceKey = sourceEntry.source;
16618
+ const locked = getLockedSource(lock, sourceKey);
16619
+ const lockedSkillNames = locked ? getLockedSkillNames(locked) : [];
16620
+ let ref;
16621
+ let resolvedSha;
16622
+ let requestedRef;
16623
+ if (locked && !updateSources) {
16624
+ ref = locked.resolvedRef;
16625
+ resolvedSha = locked.resolvedRef;
16626
+ requestedRef = locked.requestedRef;
16627
+ logger.debug(`Using locked ref for ${sourceKey}: ${resolvedSha}`);
16628
+ } else {
16629
+ requestedRef = parsed.ref ?? await client.getDefaultBranch(parsed.owner, parsed.repo);
16630
+ resolvedSha = await client.resolveRefToSha(parsed.owner, parsed.repo, requestedRef);
16631
+ ref = resolvedSha;
16632
+ logger.debug(`Resolved ${sourceKey} ref "${requestedRef}" to SHA: ${resolvedSha}`);
16633
+ }
16634
+ const curatedDir = (0, import_node_path115.join)(baseDir, RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH);
16635
+ if (locked && resolvedSha === locked.resolvedRef && !updateSources) {
16636
+ const allExist = await checkLockedSkillsExist(curatedDir, lockedSkillNames);
16637
+ if (allExist) {
16638
+ logger.debug(`SHA unchanged for ${sourceKey}, skipping re-fetch.`);
16639
+ return {
16640
+ skillCount: 0,
16641
+ fetchedSkillNames: lockedSkillNames,
16642
+ updatedLock: lock
16643
+ };
16644
+ }
16645
+ }
16646
+ const skillFilter = sourceEntry.skills ?? ["*"];
16647
+ const isWildcard = skillFilter.length === 1 && skillFilter[0] === "*";
16648
+ const skillsBasePath = parsed.path ?? "skills";
16649
+ let remoteSkillDirs;
16650
+ try {
16651
+ const entries = await client.listDirectory(parsed.owner, parsed.repo, skillsBasePath, ref);
16652
+ remoteSkillDirs = entries.filter((e) => e.type === "dir").map((e) => ({ name: e.name, path: e.path }));
16653
+ } catch (error) {
16654
+ if (error instanceof GitHubClientError && error.statusCode === 404) {
16655
+ logger.warn(`No skills/ directory found in ${sourceKey}. Skipping.`);
16656
+ return { skillCount: 0, fetchedSkillNames: [], updatedLock: lock };
16657
+ }
16658
+ throw error;
16659
+ }
16660
+ const filteredDirs = isWildcard ? remoteSkillDirs : remoteSkillDirs.filter((d) => skillFilter.includes(d.name));
16661
+ const semaphore = new import_promise2.Semaphore(FETCH_CONCURRENCY_LIMIT);
16662
+ const fetchedSkills = {};
16663
+ if (locked) {
16664
+ const resolvedCuratedDir = (0, import_node_path115.resolve)(curatedDir);
16665
+ for (const prevSkill of lockedSkillNames) {
16666
+ const prevDir = (0, import_node_path115.join)(curatedDir, prevSkill);
16667
+ if (!(0, import_node_path115.resolve)(prevDir).startsWith(resolvedCuratedDir + import_node_path115.sep)) {
16668
+ logger.warn(
16669
+ `Skipping removal of "${prevSkill}": resolved path is outside the curated directory.`
16670
+ );
16671
+ continue;
16672
+ }
16673
+ if (await directoryExists(prevDir)) {
16674
+ await removeDirectory(prevDir);
16675
+ }
16676
+ }
16677
+ }
16678
+ for (const skillDir of filteredDirs) {
16679
+ if (skillDir.name.includes("..") || skillDir.name.includes("/") || skillDir.name.includes("\\")) {
16680
+ logger.warn(
16681
+ `Skipping skill with invalid name "${skillDir.name}" from ${sourceKey}: contains path traversal characters.`
16682
+ );
16683
+ continue;
16684
+ }
16685
+ if (localSkillNames.has(skillDir.name)) {
16686
+ logger.debug(
16687
+ `Skipping remote skill "${skillDir.name}" from ${sourceKey}: local skill takes precedence.`
16688
+ );
16689
+ continue;
16690
+ }
16691
+ if (alreadyFetchedSkillNames.has(skillDir.name)) {
16692
+ logger.warn(
16693
+ `Skipping duplicate skill "${skillDir.name}" from ${sourceKey}: already fetched from another source.`
16694
+ );
16695
+ continue;
16696
+ }
16697
+ const allFiles = await listDirectoryRecursive({
16698
+ client,
16699
+ owner: parsed.owner,
16700
+ repo: parsed.repo,
16701
+ path: skillDir.path,
16702
+ ref,
16703
+ semaphore
16704
+ });
16705
+ const files = allFiles.filter((file) => {
16706
+ if (file.size > MAX_FILE_SIZE) {
16707
+ logger.warn(
16708
+ `Skipping file "${file.path}" (${(file.size / 1024 / 1024).toFixed(2)}MB exceeds ${MAX_FILE_SIZE / 1024 / 1024}MB limit).`
16709
+ );
16710
+ return false;
16711
+ }
16712
+ return true;
16713
+ });
16714
+ const skillFiles = [];
16715
+ for (const file of files) {
16716
+ const relativeToSkill = file.path.substring(skillDir.path.length + 1);
16717
+ const localFilePath = (0, import_node_path115.join)(curatedDir, skillDir.name, relativeToSkill);
16718
+ checkPathTraversal({
16719
+ relativePath: relativeToSkill,
16720
+ intendedRootDir: (0, import_node_path115.join)(curatedDir, skillDir.name)
16721
+ });
16722
+ const content = await withSemaphore(
16723
+ semaphore,
16724
+ () => client.getFileContent(parsed.owner, parsed.repo, file.path, ref)
16725
+ );
16726
+ await writeFileContent(localFilePath, content);
16727
+ skillFiles.push({ path: relativeToSkill, content });
16728
+ }
16729
+ const integrity = computeSkillIntegrity(skillFiles);
16730
+ const lockedSkillEntry = locked?.skills[skillDir.name];
16731
+ if (lockedSkillEntry && lockedSkillEntry.integrity && lockedSkillEntry.integrity !== integrity && resolvedSha === locked?.resolvedRef) {
16732
+ logger.warn(
16733
+ `Integrity mismatch for skill "${skillDir.name}" from ${sourceKey}: expected "${lockedSkillEntry.integrity}", got "${integrity}". Content may have been tampered with.`
16734
+ );
16735
+ }
16736
+ fetchedSkills[skillDir.name] = { integrity };
16737
+ logger.debug(`Fetched skill "${skillDir.name}" from ${sourceKey}`);
16738
+ }
16739
+ const fetchedNames = Object.keys(fetchedSkills);
16740
+ const mergedSkills = { ...fetchedSkills };
16741
+ if (locked) {
16742
+ for (const [skillName, skillEntry] of Object.entries(locked.skills)) {
16743
+ if (!(skillName in mergedSkills)) {
16744
+ mergedSkills[skillName] = skillEntry;
16745
+ }
16746
+ }
16747
+ }
16748
+ lock = setLockedSource(lock, sourceKey, {
16749
+ requestedRef,
16750
+ resolvedRef: resolvedSha,
16751
+ resolvedAt: (/* @__PURE__ */ new Date()).toISOString(),
16752
+ skills: mergedSkills
16753
+ });
16754
+ logger.info(
16755
+ `Fetched ${fetchedNames.length} skill(s) from ${sourceKey}: ${fetchedNames.join(", ") || "(none)"}`
16756
+ );
16757
+ return {
16758
+ skillCount: fetchedNames.length,
16759
+ fetchedSkillNames: fetchedNames,
16760
+ updatedLock: lock
16761
+ };
16762
+ }
16763
+
16764
+ // src/cli/commands/install.ts
16765
+ async function installCommand(options) {
16766
+ logger.configure({
16767
+ verbose: options.verbose ?? false,
16768
+ silent: options.silent ?? false
16769
+ });
16770
+ const config = await ConfigResolver.resolve({
16771
+ configPath: options.configPath,
16772
+ verbose: options.verbose,
16773
+ silent: options.silent
16774
+ });
16775
+ const sources = config.getSources();
16776
+ if (sources.length === 0) {
16777
+ logger.warn("No sources defined in configuration. Nothing to install.");
16778
+ return;
16779
+ }
16780
+ logger.debug(`Installing skills from ${sources.length} source(s)...`);
16781
+ const result = await resolveAndFetchSources({
16782
+ sources,
16783
+ baseDir: process.cwd(),
16784
+ options: {
16785
+ updateSources: options.update,
16786
+ frozen: options.frozen,
16787
+ token: options.token
16788
+ }
16789
+ });
16790
+ if (result.fetchedSkillCount > 0) {
16791
+ logger.success(
16792
+ `Installed ${result.fetchedSkillCount} skill(s) from ${result.sourcesProcessed} source(s).`
16793
+ );
16794
+ } else {
16795
+ logger.success(`All skills up to date (${result.sourcesProcessed} source(s) checked).`);
16796
+ }
16797
+ }
16798
+
16239
16799
  // src/cli/commands/mcp.ts
16240
16800
  var import_fastmcp = require("fastmcp");
16241
16801
 
16242
16802
  // src/mcp/tools.ts
16243
- var import_mini61 = require("zod/mini");
16803
+ var import_mini62 = require("zod/mini");
16244
16804
 
16245
16805
  // src/mcp/commands.ts
16246
- var import_node_path113 = require("path");
16247
- var import_mini53 = require("zod/mini");
16806
+ var import_node_path116 = require("path");
16807
+ var import_mini54 = require("zod/mini");
16248
16808
  var maxCommandSizeBytes = 1024 * 1024;
16249
16809
  var maxCommandsCount = 1e3;
16250
16810
  async function listCommands() {
16251
- const commandsDir = (0, import_node_path113.join)(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH);
16811
+ const commandsDir = (0, import_node_path116.join)(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH);
16252
16812
  try {
16253
16813
  const files = await listDirectoryFiles(commandsDir);
16254
16814
  const mdFiles = files.filter((file) => file.endsWith(".md"));
@@ -16260,7 +16820,7 @@ async function listCommands() {
16260
16820
  });
16261
16821
  const frontmatter = command.getFrontmatter();
16262
16822
  return {
16263
- relativePathFromCwd: (0, import_node_path113.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, file),
16823
+ relativePathFromCwd: (0, import_node_path116.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, file),
16264
16824
  frontmatter
16265
16825
  };
16266
16826
  } catch (error) {
@@ -16271,7 +16831,9 @@ async function listCommands() {
16271
16831
  );
16272
16832
  return commands.filter((command) => command !== null);
16273
16833
  } catch (error) {
16274
- logger.error(`Failed to read commands directory: ${formatError(error)}`);
16834
+ logger.error(
16835
+ `Failed to read commands directory (${RULESYNC_COMMANDS_RELATIVE_DIR_PATH}): ${formatError(error)}`
16836
+ );
16275
16837
  return [];
16276
16838
  }
16277
16839
  }
@@ -16280,13 +16842,13 @@ async function getCommand({ relativePathFromCwd }) {
16280
16842
  relativePath: relativePathFromCwd,
16281
16843
  intendedRootDir: process.cwd()
16282
16844
  });
16283
- const filename = (0, import_node_path113.basename)(relativePathFromCwd);
16845
+ const filename = (0, import_node_path116.basename)(relativePathFromCwd);
16284
16846
  try {
16285
16847
  const command = await RulesyncCommand.fromFile({
16286
16848
  relativeFilePath: filename
16287
16849
  });
16288
16850
  return {
16289
- relativePathFromCwd: (0, import_node_path113.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),
16851
+ relativePathFromCwd: (0, import_node_path116.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),
16290
16852
  frontmatter: command.getFrontmatter(),
16291
16853
  body: command.getBody()
16292
16854
  };
@@ -16305,20 +16867,22 @@ async function putCommand({
16305
16867
  relativePath: relativePathFromCwd,
16306
16868
  intendedRootDir: process.cwd()
16307
16869
  });
16308
- const filename = (0, import_node_path113.basename)(relativePathFromCwd);
16870
+ const filename = (0, import_node_path116.basename)(relativePathFromCwd);
16309
16871
  const estimatedSize = JSON.stringify(frontmatter).length + body.length;
16310
16872
  if (estimatedSize > maxCommandSizeBytes) {
16311
16873
  throw new Error(
16312
- `Command size ${estimatedSize} bytes exceeds maximum ${maxCommandSizeBytes} bytes (1MB)`
16874
+ `Command size ${estimatedSize} bytes exceeds maximum ${maxCommandSizeBytes} bytes (1MB) for ${relativePathFromCwd}`
16313
16875
  );
16314
16876
  }
16315
16877
  try {
16316
16878
  const existingCommands = await listCommands();
16317
16879
  const isUpdate = existingCommands.some(
16318
- (command2) => command2.relativePathFromCwd === (0, import_node_path113.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename)
16880
+ (command2) => command2.relativePathFromCwd === (0, import_node_path116.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename)
16319
16881
  );
16320
16882
  if (!isUpdate && existingCommands.length >= maxCommandsCount) {
16321
- throw new Error(`Maximum number of commands (${maxCommandsCount}) reached`);
16883
+ throw new Error(
16884
+ `Maximum number of commands (${maxCommandsCount}) reached in ${RULESYNC_COMMANDS_RELATIVE_DIR_PATH}`
16885
+ );
16322
16886
  }
16323
16887
  const fileContent = stringifyFrontmatter(body, frontmatter);
16324
16888
  const command = new RulesyncCommand({
@@ -16330,11 +16894,11 @@ async function putCommand({
16330
16894
  fileContent,
16331
16895
  validate: true
16332
16896
  });
16333
- const commandsDir = (0, import_node_path113.join)(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH);
16897
+ const commandsDir = (0, import_node_path116.join)(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH);
16334
16898
  await ensureDir(commandsDir);
16335
16899
  await writeFileContent(command.getFilePath(), command.getFileContent());
16336
16900
  return {
16337
- relativePathFromCwd: (0, import_node_path113.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),
16901
+ relativePathFromCwd: (0, import_node_path116.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),
16338
16902
  frontmatter: command.getFrontmatter(),
16339
16903
  body: command.getBody()
16340
16904
  };
@@ -16349,12 +16913,12 @@ async function deleteCommand({ relativePathFromCwd }) {
16349
16913
  relativePath: relativePathFromCwd,
16350
16914
  intendedRootDir: process.cwd()
16351
16915
  });
16352
- const filename = (0, import_node_path113.basename)(relativePathFromCwd);
16353
- const fullPath = (0, import_node_path113.join)(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename);
16916
+ const filename = (0, import_node_path116.basename)(relativePathFromCwd);
16917
+ const fullPath = (0, import_node_path116.join)(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename);
16354
16918
  try {
16355
16919
  await removeFile(fullPath);
16356
16920
  return {
16357
- relativePathFromCwd: (0, import_node_path113.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename)
16921
+ relativePathFromCwd: (0, import_node_path116.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename)
16358
16922
  };
16359
16923
  } catch (error) {
16360
16924
  throw new Error(`Failed to delete command file ${relativePathFromCwd}: ${formatError(error)}`, {
@@ -16363,23 +16927,23 @@ async function deleteCommand({ relativePathFromCwd }) {
16363
16927
  }
16364
16928
  }
16365
16929
  var commandToolSchemas = {
16366
- listCommands: import_mini53.z.object({}),
16367
- getCommand: import_mini53.z.object({
16368
- relativePathFromCwd: import_mini53.z.string()
16930
+ listCommands: import_mini54.z.object({}),
16931
+ getCommand: import_mini54.z.object({
16932
+ relativePathFromCwd: import_mini54.z.string()
16369
16933
  }),
16370
- putCommand: import_mini53.z.object({
16371
- relativePathFromCwd: import_mini53.z.string(),
16934
+ putCommand: import_mini54.z.object({
16935
+ relativePathFromCwd: import_mini54.z.string(),
16372
16936
  frontmatter: RulesyncCommandFrontmatterSchema,
16373
- body: import_mini53.z.string()
16937
+ body: import_mini54.z.string()
16374
16938
  }),
16375
- deleteCommand: import_mini53.z.object({
16376
- relativePathFromCwd: import_mini53.z.string()
16939
+ deleteCommand: import_mini54.z.object({
16940
+ relativePathFromCwd: import_mini54.z.string()
16377
16941
  })
16378
16942
  };
16379
16943
  var commandTools = {
16380
16944
  listCommands: {
16381
16945
  name: "listCommands",
16382
- description: `List all commands from ${(0, import_node_path113.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
16946
+ description: `List all commands from ${(0, import_node_path116.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
16383
16947
  parameters: commandToolSchemas.listCommands,
16384
16948
  execute: async () => {
16385
16949
  const commands = await listCommands();
@@ -16421,15 +16985,15 @@ var commandTools = {
16421
16985
  };
16422
16986
 
16423
16987
  // src/mcp/generate.ts
16424
- var import_mini54 = require("zod/mini");
16425
- var generateOptionsSchema = import_mini54.z.object({
16426
- targets: import_mini54.z.optional(import_mini54.z.array(import_mini54.z.string())),
16427
- features: import_mini54.z.optional(import_mini54.z.array(import_mini54.z.string())),
16428
- delete: import_mini54.z.optional(import_mini54.z.boolean()),
16429
- global: import_mini54.z.optional(import_mini54.z.boolean()),
16430
- simulateCommands: import_mini54.z.optional(import_mini54.z.boolean()),
16431
- simulateSubagents: import_mini54.z.optional(import_mini54.z.boolean()),
16432
- simulateSkills: import_mini54.z.optional(import_mini54.z.boolean())
16988
+ var import_mini55 = require("zod/mini");
16989
+ var generateOptionsSchema = import_mini55.z.object({
16990
+ targets: import_mini55.z.optional(import_mini55.z.array(import_mini55.z.string())),
16991
+ features: import_mini55.z.optional(import_mini55.z.array(import_mini55.z.string())),
16992
+ delete: import_mini55.z.optional(import_mini55.z.boolean()),
16993
+ global: import_mini55.z.optional(import_mini55.z.boolean()),
16994
+ simulateCommands: import_mini55.z.optional(import_mini55.z.boolean()),
16995
+ simulateSubagents: import_mini55.z.optional(import_mini55.z.boolean()),
16996
+ simulateSkills: import_mini55.z.optional(import_mini55.z.boolean())
16433
16997
  });
16434
16998
  async function executeGenerate(options = {}) {
16435
16999
  try {
@@ -16506,11 +17070,11 @@ var generateTools = {
16506
17070
  };
16507
17071
 
16508
17072
  // src/mcp/ignore.ts
16509
- var import_node_path114 = require("path");
16510
- var import_mini55 = require("zod/mini");
17073
+ var import_node_path117 = require("path");
17074
+ var import_mini56 = require("zod/mini");
16511
17075
  var maxIgnoreFileSizeBytes = 100 * 1024;
16512
17076
  async function getIgnoreFile() {
16513
- const ignoreFilePath = (0, import_node_path114.join)(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);
17077
+ const ignoreFilePath = (0, import_node_path117.join)(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);
16514
17078
  try {
16515
17079
  const content = await readFileContent(ignoreFilePath);
16516
17080
  return {
@@ -16518,17 +17082,20 @@ async function getIgnoreFile() {
16518
17082
  content
16519
17083
  };
16520
17084
  } catch (error) {
16521
- throw new Error(`Failed to read .rulesync/.aiignore file: ${formatError(error)}`, {
16522
- cause: error
16523
- });
17085
+ throw new Error(
17086
+ `Failed to read ignore file (${RULESYNC_AIIGNORE_RELATIVE_FILE_PATH}): ${formatError(error)}`,
17087
+ {
17088
+ cause: error
17089
+ }
17090
+ );
16524
17091
  }
16525
17092
  }
16526
17093
  async function putIgnoreFile({ content }) {
16527
- const ignoreFilePath = (0, import_node_path114.join)(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);
17094
+ const ignoreFilePath = (0, import_node_path117.join)(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);
16528
17095
  const contentSizeBytes = Buffer.byteLength(content, "utf8");
16529
17096
  if (contentSizeBytes > maxIgnoreFileSizeBytes) {
16530
17097
  throw new Error(
16531
- `Ignore file size ${contentSizeBytes} bytes exceeds maximum ${maxIgnoreFileSizeBytes} bytes (100KB)`
17098
+ `Ignore file size ${contentSizeBytes} bytes exceeds maximum ${maxIgnoreFileSizeBytes} bytes (100KB) for ${RULESYNC_AIIGNORE_RELATIVE_FILE_PATH}`
16532
17099
  );
16533
17100
  }
16534
17101
  try {
@@ -16539,14 +17106,17 @@ async function putIgnoreFile({ content }) {
16539
17106
  content
16540
17107
  };
16541
17108
  } catch (error) {
16542
- throw new Error(`Failed to write .rulesync/.aiignore file: ${formatError(error)}`, {
16543
- cause: error
16544
- });
17109
+ throw new Error(
17110
+ `Failed to write ignore file (${RULESYNC_AIIGNORE_RELATIVE_FILE_PATH}): ${formatError(error)}`,
17111
+ {
17112
+ cause: error
17113
+ }
17114
+ );
16545
17115
  }
16546
17116
  }
16547
17117
  async function deleteIgnoreFile() {
16548
- const aiignorePath = (0, import_node_path114.join)(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);
16549
- const legacyIgnorePath = (0, import_node_path114.join)(process.cwd(), RULESYNC_IGNORE_RELATIVE_FILE_PATH);
17118
+ const aiignorePath = (0, import_node_path117.join)(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);
17119
+ const legacyIgnorePath = (0, import_node_path117.join)(process.cwd(), RULESYNC_IGNORE_RELATIVE_FILE_PATH);
16550
17120
  try {
16551
17121
  await Promise.all([removeFile(aiignorePath), removeFile(legacyIgnorePath)]);
16552
17122
  return {
@@ -16556,7 +17126,7 @@ async function deleteIgnoreFile() {
16556
17126
  };
16557
17127
  } catch (error) {
16558
17128
  throw new Error(
16559
- `Failed to delete .rulesyncignore and .rulesync/.aiignore files: ${formatError(error)}`,
17129
+ `Failed to delete ignore files (${RULESYNC_AIIGNORE_RELATIVE_FILE_PATH}, ${RULESYNC_IGNORE_RELATIVE_FILE_PATH}): ${formatError(error)}`,
16560
17130
  {
16561
17131
  cause: error
16562
17132
  }
@@ -16564,11 +17134,11 @@ async function deleteIgnoreFile() {
16564
17134
  }
16565
17135
  }
16566
17136
  var ignoreToolSchemas = {
16567
- getIgnoreFile: import_mini55.z.object({}),
16568
- putIgnoreFile: import_mini55.z.object({
16569
- content: import_mini55.z.string()
17137
+ getIgnoreFile: import_mini56.z.object({}),
17138
+ putIgnoreFile: import_mini56.z.object({
17139
+ content: import_mini56.z.string()
16570
17140
  }),
16571
- deleteIgnoreFile: import_mini55.z.object({})
17141
+ deleteIgnoreFile: import_mini56.z.object({})
16572
17142
  };
16573
17143
  var ignoreTools = {
16574
17144
  getIgnoreFile: {
@@ -16601,11 +17171,11 @@ var ignoreTools = {
16601
17171
  };
16602
17172
 
16603
17173
  // src/mcp/import.ts
16604
- var import_mini56 = require("zod/mini");
16605
- var importOptionsSchema = import_mini56.z.object({
16606
- target: import_mini56.z.string(),
16607
- features: import_mini56.z.optional(import_mini56.z.array(import_mini56.z.string())),
16608
- global: import_mini56.z.optional(import_mini56.z.boolean())
17174
+ var import_mini57 = require("zod/mini");
17175
+ var importOptionsSchema = import_mini57.z.object({
17176
+ target: import_mini57.z.string(),
17177
+ features: import_mini57.z.optional(import_mini57.z.array(import_mini57.z.string())),
17178
+ global: import_mini57.z.optional(import_mini57.z.boolean())
16609
17179
  });
16610
17180
  async function executeImport(options) {
16611
17181
  try {
@@ -16674,15 +17244,15 @@ var importTools = {
16674
17244
  };
16675
17245
 
16676
17246
  // src/mcp/mcp.ts
16677
- var import_node_path115 = require("path");
16678
- var import_mini57 = require("zod/mini");
17247
+ var import_node_path118 = require("path");
17248
+ var import_mini58 = require("zod/mini");
16679
17249
  var maxMcpSizeBytes = 1024 * 1024;
16680
17250
  async function getMcpFile() {
16681
17251
  try {
16682
17252
  const rulesyncMcp = await RulesyncMcp.fromFile({
16683
17253
  validate: true
16684
17254
  });
16685
- const relativePathFromCwd = (0, import_node_path115.join)(
17255
+ const relativePathFromCwd = (0, import_node_path118.join)(
16686
17256
  rulesyncMcp.getRelativeDirPath(),
16687
17257
  rulesyncMcp.getRelativeFilePath()
16688
17258
  );
@@ -16691,30 +17261,36 @@ async function getMcpFile() {
16691
17261
  content: rulesyncMcp.getFileContent()
16692
17262
  };
16693
17263
  } catch (error) {
16694
- throw new Error(`Failed to read MCP file: ${formatError(error)}`, {
16695
- cause: error
16696
- });
17264
+ throw new Error(
17265
+ `Failed to read MCP file (${RULESYNC_MCP_RELATIVE_FILE_PATH}): ${formatError(error)}`,
17266
+ {
17267
+ cause: error
17268
+ }
17269
+ );
16697
17270
  }
16698
17271
  }
16699
17272
  async function putMcpFile({ content }) {
16700
17273
  if (content.length > maxMcpSizeBytes) {
16701
17274
  throw new Error(
16702
- `MCP file size ${content.length} bytes exceeds maximum ${maxMcpSizeBytes} bytes (1MB)`
17275
+ `MCP file size ${content.length} bytes exceeds maximum ${maxMcpSizeBytes} bytes (1MB) for ${RULESYNC_MCP_RELATIVE_FILE_PATH}`
16703
17276
  );
16704
17277
  }
16705
17278
  try {
16706
17279
  JSON.parse(content);
16707
17280
  } catch (error) {
16708
- throw new Error(`Invalid JSON format in MCP file: ${formatError(error)}`, {
16709
- cause: error
16710
- });
17281
+ throw new Error(
17282
+ `Invalid JSON format in MCP file (${RULESYNC_MCP_RELATIVE_FILE_PATH}): ${formatError(error)}`,
17283
+ {
17284
+ cause: error
17285
+ }
17286
+ );
16711
17287
  }
16712
17288
  try {
16713
17289
  const baseDir = process.cwd();
16714
17290
  const paths = RulesyncMcp.getSettablePaths();
16715
17291
  const relativeDirPath = paths.recommended.relativeDirPath;
16716
17292
  const relativeFilePath = paths.recommended.relativeFilePath;
16717
- const fullPath = (0, import_node_path115.join)(baseDir, relativeDirPath, relativeFilePath);
17293
+ const fullPath = (0, import_node_path118.join)(baseDir, relativeDirPath, relativeFilePath);
16718
17294
  const rulesyncMcp = new RulesyncMcp({
16719
17295
  baseDir,
16720
17296
  relativeDirPath,
@@ -16722,32 +17298,35 @@ async function putMcpFile({ content }) {
16722
17298
  fileContent: content,
16723
17299
  validate: true
16724
17300
  });
16725
- await ensureDir((0, import_node_path115.join)(baseDir, relativeDirPath));
17301
+ await ensureDir((0, import_node_path118.join)(baseDir, relativeDirPath));
16726
17302
  await writeFileContent(fullPath, content);
16727
- const relativePathFromCwd = (0, import_node_path115.join)(relativeDirPath, relativeFilePath);
17303
+ const relativePathFromCwd = (0, import_node_path118.join)(relativeDirPath, relativeFilePath);
16728
17304
  return {
16729
17305
  relativePathFromCwd,
16730
17306
  content: rulesyncMcp.getFileContent()
16731
17307
  };
16732
17308
  } catch (error) {
16733
- throw new Error(`Failed to write MCP file: ${formatError(error)}`, {
16734
- cause: error
16735
- });
17309
+ throw new Error(
17310
+ `Failed to write MCP file (${RULESYNC_MCP_RELATIVE_FILE_PATH}): ${formatError(error)}`,
17311
+ {
17312
+ cause: error
17313
+ }
17314
+ );
16736
17315
  }
16737
17316
  }
16738
17317
  async function deleteMcpFile() {
16739
17318
  try {
16740
17319
  const baseDir = process.cwd();
16741
17320
  const paths = RulesyncMcp.getSettablePaths();
16742
- const recommendedPath = (0, import_node_path115.join)(
17321
+ const recommendedPath = (0, import_node_path118.join)(
16743
17322
  baseDir,
16744
17323
  paths.recommended.relativeDirPath,
16745
17324
  paths.recommended.relativeFilePath
16746
17325
  );
16747
- const legacyPath = (0, import_node_path115.join)(baseDir, paths.legacy.relativeDirPath, paths.legacy.relativeFilePath);
17326
+ const legacyPath = (0, import_node_path118.join)(baseDir, paths.legacy.relativeDirPath, paths.legacy.relativeFilePath);
16748
17327
  await removeFile(recommendedPath);
16749
17328
  await removeFile(legacyPath);
16750
- const relativePathFromCwd = (0, import_node_path115.join)(
17329
+ const relativePathFromCwd = (0, import_node_path118.join)(
16751
17330
  paths.recommended.relativeDirPath,
16752
17331
  paths.recommended.relativeFilePath
16753
17332
  );
@@ -16755,17 +17334,20 @@ async function deleteMcpFile() {
16755
17334
  relativePathFromCwd
16756
17335
  };
16757
17336
  } catch (error) {
16758
- throw new Error(`Failed to delete MCP file: ${formatError(error)}`, {
16759
- cause: error
16760
- });
17337
+ throw new Error(
17338
+ `Failed to delete MCP file (${RULESYNC_MCP_RELATIVE_FILE_PATH}): ${formatError(error)}`,
17339
+ {
17340
+ cause: error
17341
+ }
17342
+ );
16761
17343
  }
16762
17344
  }
16763
17345
  var mcpToolSchemas = {
16764
- getMcpFile: import_mini57.z.object({}),
16765
- putMcpFile: import_mini57.z.object({
16766
- content: import_mini57.z.string()
17346
+ getMcpFile: import_mini58.z.object({}),
17347
+ putMcpFile: import_mini58.z.object({
17348
+ content: import_mini58.z.string()
16767
17349
  }),
16768
- deleteMcpFile: import_mini57.z.object({})
17350
+ deleteMcpFile: import_mini58.z.object({})
16769
17351
  };
16770
17352
  var mcpTools = {
16771
17353
  getMcpFile: {
@@ -16798,12 +17380,12 @@ var mcpTools = {
16798
17380
  };
16799
17381
 
16800
17382
  // src/mcp/rules.ts
16801
- var import_node_path116 = require("path");
16802
- var import_mini58 = require("zod/mini");
17383
+ var import_node_path119 = require("path");
17384
+ var import_mini59 = require("zod/mini");
16803
17385
  var maxRuleSizeBytes = 1024 * 1024;
16804
17386
  var maxRulesCount = 1e3;
16805
17387
  async function listRules() {
16806
- const rulesDir = (0, import_node_path116.join)(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH);
17388
+ const rulesDir = (0, import_node_path119.join)(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH);
16807
17389
  try {
16808
17390
  const files = await listDirectoryFiles(rulesDir);
16809
17391
  const mdFiles = files.filter((file) => file.endsWith(".md"));
@@ -16816,7 +17398,7 @@ async function listRules() {
16816
17398
  });
16817
17399
  const frontmatter = rule.getFrontmatter();
16818
17400
  return {
16819
- relativePathFromCwd: (0, import_node_path116.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, file),
17401
+ relativePathFromCwd: (0, import_node_path119.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, file),
16820
17402
  frontmatter
16821
17403
  };
16822
17404
  } catch (error) {
@@ -16827,7 +17409,9 @@ async function listRules() {
16827
17409
  );
16828
17410
  return rules.filter((rule) => rule !== null);
16829
17411
  } catch (error) {
16830
- logger.error(`Failed to read rules directory: ${formatError(error)}`);
17412
+ logger.error(
17413
+ `Failed to read rules directory (${RULESYNC_RULES_RELATIVE_DIR_PATH}): ${formatError(error)}`
17414
+ );
16831
17415
  return [];
16832
17416
  }
16833
17417
  }
@@ -16836,14 +17420,14 @@ async function getRule({ relativePathFromCwd }) {
16836
17420
  relativePath: relativePathFromCwd,
16837
17421
  intendedRootDir: process.cwd()
16838
17422
  });
16839
- const filename = (0, import_node_path116.basename)(relativePathFromCwd);
17423
+ const filename = (0, import_node_path119.basename)(relativePathFromCwd);
16840
17424
  try {
16841
17425
  const rule = await RulesyncRule.fromFile({
16842
17426
  relativeFilePath: filename,
16843
17427
  validate: true
16844
17428
  });
16845
17429
  return {
16846
- relativePathFromCwd: (0, import_node_path116.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),
17430
+ relativePathFromCwd: (0, import_node_path119.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),
16847
17431
  frontmatter: rule.getFrontmatter(),
16848
17432
  body: rule.getBody()
16849
17433
  };
@@ -16862,20 +17446,22 @@ async function putRule({
16862
17446
  relativePath: relativePathFromCwd,
16863
17447
  intendedRootDir: process.cwd()
16864
17448
  });
16865
- const filename = (0, import_node_path116.basename)(relativePathFromCwd);
17449
+ const filename = (0, import_node_path119.basename)(relativePathFromCwd);
16866
17450
  const estimatedSize = JSON.stringify(frontmatter).length + body.length;
16867
17451
  if (estimatedSize > maxRuleSizeBytes) {
16868
17452
  throw new Error(
16869
- `Rule size ${estimatedSize} bytes exceeds maximum ${maxRuleSizeBytes} bytes (1MB)`
17453
+ `Rule size ${estimatedSize} bytes exceeds maximum ${maxRuleSizeBytes} bytes (1MB) for ${relativePathFromCwd}`
16870
17454
  );
16871
17455
  }
16872
17456
  try {
16873
17457
  const existingRules = await listRules();
16874
17458
  const isUpdate = existingRules.some(
16875
- (rule2) => rule2.relativePathFromCwd === (0, import_node_path116.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, filename)
17459
+ (rule2) => rule2.relativePathFromCwd === (0, import_node_path119.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, filename)
16876
17460
  );
16877
17461
  if (!isUpdate && existingRules.length >= maxRulesCount) {
16878
- throw new Error(`Maximum number of rules (${maxRulesCount}) reached`);
17462
+ throw new Error(
17463
+ `Maximum number of rules (${maxRulesCount}) reached in ${RULESYNC_RULES_RELATIVE_DIR_PATH}`
17464
+ );
16879
17465
  }
16880
17466
  const rule = new RulesyncRule({
16881
17467
  baseDir: process.cwd(),
@@ -16885,11 +17471,11 @@ async function putRule({
16885
17471
  body,
16886
17472
  validate: true
16887
17473
  });
16888
- const rulesDir = (0, import_node_path116.join)(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH);
17474
+ const rulesDir = (0, import_node_path119.join)(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH);
16889
17475
  await ensureDir(rulesDir);
16890
17476
  await writeFileContent(rule.getFilePath(), rule.getFileContent());
16891
17477
  return {
16892
- relativePathFromCwd: (0, import_node_path116.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),
17478
+ relativePathFromCwd: (0, import_node_path119.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),
16893
17479
  frontmatter: rule.getFrontmatter(),
16894
17480
  body: rule.getBody()
16895
17481
  };
@@ -16904,12 +17490,12 @@ async function deleteRule({ relativePathFromCwd }) {
16904
17490
  relativePath: relativePathFromCwd,
16905
17491
  intendedRootDir: process.cwd()
16906
17492
  });
16907
- const filename = (0, import_node_path116.basename)(relativePathFromCwd);
16908
- const fullPath = (0, import_node_path116.join)(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH, filename);
17493
+ const filename = (0, import_node_path119.basename)(relativePathFromCwd);
17494
+ const fullPath = (0, import_node_path119.join)(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH, filename);
16909
17495
  try {
16910
17496
  await removeFile(fullPath);
16911
17497
  return {
16912
- relativePathFromCwd: (0, import_node_path116.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, filename)
17498
+ relativePathFromCwd: (0, import_node_path119.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, filename)
16913
17499
  };
16914
17500
  } catch (error) {
16915
17501
  throw new Error(`Failed to delete rule file ${relativePathFromCwd}: ${formatError(error)}`, {
@@ -16918,23 +17504,23 @@ async function deleteRule({ relativePathFromCwd }) {
16918
17504
  }
16919
17505
  }
16920
17506
  var ruleToolSchemas = {
16921
- listRules: import_mini58.z.object({}),
16922
- getRule: import_mini58.z.object({
16923
- relativePathFromCwd: import_mini58.z.string()
17507
+ listRules: import_mini59.z.object({}),
17508
+ getRule: import_mini59.z.object({
17509
+ relativePathFromCwd: import_mini59.z.string()
16924
17510
  }),
16925
- putRule: import_mini58.z.object({
16926
- relativePathFromCwd: import_mini58.z.string(),
17511
+ putRule: import_mini59.z.object({
17512
+ relativePathFromCwd: import_mini59.z.string(),
16927
17513
  frontmatter: RulesyncRuleFrontmatterSchema,
16928
- body: import_mini58.z.string()
17514
+ body: import_mini59.z.string()
16929
17515
  }),
16930
- deleteRule: import_mini58.z.object({
16931
- relativePathFromCwd: import_mini58.z.string()
17516
+ deleteRule: import_mini59.z.object({
17517
+ relativePathFromCwd: import_mini59.z.string()
16932
17518
  })
16933
17519
  };
16934
17520
  var ruleTools = {
16935
17521
  listRules: {
16936
17522
  name: "listRules",
16937
- description: `List all rules from ${(0, import_node_path116.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
17523
+ description: `List all rules from ${(0, import_node_path119.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
16938
17524
  parameters: ruleToolSchemas.listRules,
16939
17525
  execute: async () => {
16940
17526
  const rules = await listRules();
@@ -16976,8 +17562,8 @@ var ruleTools = {
16976
17562
  };
16977
17563
 
16978
17564
  // src/mcp/skills.ts
16979
- var import_node_path117 = require("path");
16980
- var import_mini59 = require("zod/mini");
17565
+ var import_node_path120 = require("path");
17566
+ var import_mini60 = require("zod/mini");
16981
17567
  var maxSkillSizeBytes = 1024 * 1024;
16982
17568
  var maxSkillsCount = 1e3;
16983
17569
  function aiDirFileToMcpSkillFile(file) {
@@ -16993,19 +17579,19 @@ function mcpSkillFileToAiDirFile(file) {
16993
17579
  };
16994
17580
  }
16995
17581
  function extractDirName(relativeDirPathFromCwd) {
16996
- const dirName = (0, import_node_path117.basename)(relativeDirPathFromCwd);
17582
+ const dirName = (0, import_node_path120.basename)(relativeDirPathFromCwd);
16997
17583
  if (!dirName) {
16998
17584
  throw new Error(`Invalid path: ${relativeDirPathFromCwd}`);
16999
17585
  }
17000
17586
  return dirName;
17001
17587
  }
17002
17588
  async function listSkills() {
17003
- const skillsDir = (0, import_node_path117.join)(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH);
17589
+ const skillsDir = (0, import_node_path120.join)(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH);
17004
17590
  try {
17005
- const skillDirPaths = await findFilesByGlobs((0, import_node_path117.join)(skillsDir, "*"), { type: "dir" });
17591
+ const skillDirPaths = await findFilesByGlobs((0, import_node_path120.join)(skillsDir, "*"), { type: "dir" });
17006
17592
  const skills = await Promise.all(
17007
17593
  skillDirPaths.map(async (dirPath) => {
17008
- const dirName = (0, import_node_path117.basename)(dirPath);
17594
+ const dirName = (0, import_node_path120.basename)(dirPath);
17009
17595
  if (!dirName) return null;
17010
17596
  try {
17011
17597
  const skill = await RulesyncSkill.fromDir({
@@ -17013,7 +17599,7 @@ async function listSkills() {
17013
17599
  });
17014
17600
  const frontmatter = skill.getFrontmatter();
17015
17601
  return {
17016
- relativeDirPathFromCwd: (0, import_node_path117.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
17602
+ relativeDirPathFromCwd: (0, import_node_path120.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
17017
17603
  frontmatter
17018
17604
  };
17019
17605
  } catch (error) {
@@ -17024,7 +17610,9 @@ async function listSkills() {
17024
17610
  );
17025
17611
  return skills.filter((skill) => skill !== null);
17026
17612
  } catch (error) {
17027
- logger.error(`Failed to read skills directory: ${formatError(error)}`);
17613
+ logger.error(
17614
+ `Failed to read skills directory (${RULESYNC_SKILLS_RELATIVE_DIR_PATH}): ${formatError(error)}`
17615
+ );
17028
17616
  return [];
17029
17617
  }
17030
17618
  }
@@ -17039,7 +17627,7 @@ async function getSkill({ relativeDirPathFromCwd }) {
17039
17627
  dirName
17040
17628
  });
17041
17629
  return {
17042
- relativeDirPathFromCwd: (0, import_node_path117.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
17630
+ relativeDirPathFromCwd: (0, import_node_path120.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
17043
17631
  frontmatter: skill.getFrontmatter(),
17044
17632
  body: skill.getBody(),
17045
17633
  otherFiles: skill.getOtherFiles().map(aiDirFileToMcpSkillFile)
@@ -17067,16 +17655,18 @@ async function putSkill({
17067
17655
  const estimatedSize = JSON.stringify(frontmatter).length + body.length + otherFiles.reduce((acc, file) => acc + file.name.length + file.body.length, 0);
17068
17656
  if (estimatedSize > maxSkillSizeBytes) {
17069
17657
  throw new Error(
17070
- `Skill size ${estimatedSize} bytes exceeds maximum ${maxSkillSizeBytes} bytes (1MB)`
17658
+ `Skill size ${estimatedSize} bytes exceeds maximum ${maxSkillSizeBytes} bytes (1MB) for ${relativeDirPathFromCwd}`
17071
17659
  );
17072
17660
  }
17073
17661
  try {
17074
17662
  const existingSkills = await listSkills();
17075
17663
  const isUpdate = existingSkills.some(
17076
- (skill2) => skill2.relativeDirPathFromCwd === (0, import_node_path117.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName)
17664
+ (skill2) => skill2.relativeDirPathFromCwd === (0, import_node_path120.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName)
17077
17665
  );
17078
17666
  if (!isUpdate && existingSkills.length >= maxSkillsCount) {
17079
- throw new Error(`Maximum number of skills (${maxSkillsCount}) reached`);
17667
+ throw new Error(
17668
+ `Maximum number of skills (${maxSkillsCount}) reached in ${RULESYNC_SKILLS_RELATIVE_DIR_PATH}`
17669
+ );
17080
17670
  }
17081
17671
  const aiDirFiles = otherFiles.map(mcpSkillFileToAiDirFile);
17082
17672
  const skill = new RulesyncSkill({
@@ -17088,9 +17678,9 @@ async function putSkill({
17088
17678
  otherFiles: aiDirFiles,
17089
17679
  validate: true
17090
17680
  });
17091
- const skillDirPath = (0, import_node_path117.join)(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName);
17681
+ const skillDirPath = (0, import_node_path120.join)(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName);
17092
17682
  await ensureDir(skillDirPath);
17093
- const skillFilePath = (0, import_node_path117.join)(skillDirPath, SKILL_FILE_NAME);
17683
+ const skillFilePath = (0, import_node_path120.join)(skillDirPath, SKILL_FILE_NAME);
17094
17684
  const skillFileContent = stringifyFrontmatter(body, frontmatter);
17095
17685
  await writeFileContent(skillFilePath, skillFileContent);
17096
17686
  for (const file of otherFiles) {
@@ -17098,15 +17688,15 @@ async function putSkill({
17098
17688
  relativePath: file.name,
17099
17689
  intendedRootDir: skillDirPath
17100
17690
  });
17101
- const filePath = (0, import_node_path117.join)(skillDirPath, file.name);
17102
- const fileDir = (0, import_node_path117.join)(skillDirPath, (0, import_node_path117.dirname)(file.name));
17691
+ const filePath = (0, import_node_path120.join)(skillDirPath, file.name);
17692
+ const fileDir = (0, import_node_path120.join)(skillDirPath, (0, import_node_path120.dirname)(file.name));
17103
17693
  if (fileDir !== skillDirPath) {
17104
17694
  await ensureDir(fileDir);
17105
17695
  }
17106
17696
  await writeFileContent(filePath, file.body);
17107
17697
  }
17108
17698
  return {
17109
- relativeDirPathFromCwd: (0, import_node_path117.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
17699
+ relativeDirPathFromCwd: (0, import_node_path120.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
17110
17700
  frontmatter: skill.getFrontmatter(),
17111
17701
  body: skill.getBody(),
17112
17702
  otherFiles: skill.getOtherFiles().map(aiDirFileToMcpSkillFile)
@@ -17128,13 +17718,13 @@ async function deleteSkill({
17128
17718
  intendedRootDir: process.cwd()
17129
17719
  });
17130
17720
  const dirName = extractDirName(relativeDirPathFromCwd);
17131
- const skillDirPath = (0, import_node_path117.join)(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName);
17721
+ const skillDirPath = (0, import_node_path120.join)(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName);
17132
17722
  try {
17133
17723
  if (await directoryExists(skillDirPath)) {
17134
17724
  await removeDirectory(skillDirPath);
17135
17725
  }
17136
17726
  return {
17137
- relativeDirPathFromCwd: (0, import_node_path117.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName)
17727
+ relativeDirPathFromCwd: (0, import_node_path120.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName)
17138
17728
  };
17139
17729
  } catch (error) {
17140
17730
  throw new Error(
@@ -17145,29 +17735,29 @@ async function deleteSkill({
17145
17735
  );
17146
17736
  }
17147
17737
  }
17148
- var McpSkillFileSchema = import_mini59.z.object({
17149
- name: import_mini59.z.string(),
17150
- body: import_mini59.z.string()
17738
+ var McpSkillFileSchema = import_mini60.z.object({
17739
+ name: import_mini60.z.string(),
17740
+ body: import_mini60.z.string()
17151
17741
  });
17152
17742
  var skillToolSchemas = {
17153
- listSkills: import_mini59.z.object({}),
17154
- getSkill: import_mini59.z.object({
17155
- relativeDirPathFromCwd: import_mini59.z.string()
17743
+ listSkills: import_mini60.z.object({}),
17744
+ getSkill: import_mini60.z.object({
17745
+ relativeDirPathFromCwd: import_mini60.z.string()
17156
17746
  }),
17157
- putSkill: import_mini59.z.object({
17158
- relativeDirPathFromCwd: import_mini59.z.string(),
17747
+ putSkill: import_mini60.z.object({
17748
+ relativeDirPathFromCwd: import_mini60.z.string(),
17159
17749
  frontmatter: RulesyncSkillFrontmatterSchema,
17160
- body: import_mini59.z.string(),
17161
- otherFiles: import_mini59.z.optional(import_mini59.z.array(McpSkillFileSchema))
17750
+ body: import_mini60.z.string(),
17751
+ otherFiles: import_mini60.z.optional(import_mini60.z.array(McpSkillFileSchema))
17162
17752
  }),
17163
- deleteSkill: import_mini59.z.object({
17164
- relativeDirPathFromCwd: import_mini59.z.string()
17753
+ deleteSkill: import_mini60.z.object({
17754
+ relativeDirPathFromCwd: import_mini60.z.string()
17165
17755
  })
17166
17756
  };
17167
17757
  var skillTools = {
17168
17758
  listSkills: {
17169
17759
  name: "listSkills",
17170
- description: `List all skills from ${(0, import_node_path117.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, "*", SKILL_FILE_NAME)} with their frontmatter.`,
17760
+ description: `List all skills from ${(0, import_node_path120.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, "*", SKILL_FILE_NAME)} with their frontmatter.`,
17171
17761
  parameters: skillToolSchemas.listSkills,
17172
17762
  execute: async () => {
17173
17763
  const skills = await listSkills();
@@ -17210,12 +17800,12 @@ var skillTools = {
17210
17800
  };
17211
17801
 
17212
17802
  // src/mcp/subagents.ts
17213
- var import_node_path118 = require("path");
17214
- var import_mini60 = require("zod/mini");
17803
+ var import_node_path121 = require("path");
17804
+ var import_mini61 = require("zod/mini");
17215
17805
  var maxSubagentSizeBytes = 1024 * 1024;
17216
17806
  var maxSubagentsCount = 1e3;
17217
17807
  async function listSubagents() {
17218
- const subagentsDir = (0, import_node_path118.join)(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH);
17808
+ const subagentsDir = (0, import_node_path121.join)(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH);
17219
17809
  try {
17220
17810
  const files = await listDirectoryFiles(subagentsDir);
17221
17811
  const mdFiles = files.filter((file) => file.endsWith(".md"));
@@ -17228,7 +17818,7 @@ async function listSubagents() {
17228
17818
  });
17229
17819
  const frontmatter = subagent.getFrontmatter();
17230
17820
  return {
17231
- relativePathFromCwd: (0, import_node_path118.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, file),
17821
+ relativePathFromCwd: (0, import_node_path121.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, file),
17232
17822
  frontmatter
17233
17823
  };
17234
17824
  } catch (error) {
@@ -17241,7 +17831,9 @@ async function listSubagents() {
17241
17831
  (subagent) => subagent !== null
17242
17832
  );
17243
17833
  } catch (error) {
17244
- logger.error(`Failed to read subagents directory: ${formatError(error)}`);
17834
+ logger.error(
17835
+ `Failed to read subagents directory (${RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH}): ${formatError(error)}`
17836
+ );
17245
17837
  return [];
17246
17838
  }
17247
17839
  }
@@ -17250,14 +17842,14 @@ async function getSubagent({ relativePathFromCwd }) {
17250
17842
  relativePath: relativePathFromCwd,
17251
17843
  intendedRootDir: process.cwd()
17252
17844
  });
17253
- const filename = (0, import_node_path118.basename)(relativePathFromCwd);
17845
+ const filename = (0, import_node_path121.basename)(relativePathFromCwd);
17254
17846
  try {
17255
17847
  const subagent = await RulesyncSubagent.fromFile({
17256
17848
  relativeFilePath: filename,
17257
17849
  validate: true
17258
17850
  });
17259
17851
  return {
17260
- relativePathFromCwd: (0, import_node_path118.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),
17852
+ relativePathFromCwd: (0, import_node_path121.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),
17261
17853
  frontmatter: subagent.getFrontmatter(),
17262
17854
  body: subagent.getBody()
17263
17855
  };
@@ -17276,20 +17868,22 @@ async function putSubagent({
17276
17868
  relativePath: relativePathFromCwd,
17277
17869
  intendedRootDir: process.cwd()
17278
17870
  });
17279
- const filename = (0, import_node_path118.basename)(relativePathFromCwd);
17871
+ const filename = (0, import_node_path121.basename)(relativePathFromCwd);
17280
17872
  const estimatedSize = JSON.stringify(frontmatter).length + body.length;
17281
17873
  if (estimatedSize > maxSubagentSizeBytes) {
17282
17874
  throw new Error(
17283
- `Subagent size ${estimatedSize} bytes exceeds maximum ${maxSubagentSizeBytes} bytes (1MB)`
17875
+ `Subagent size ${estimatedSize} bytes exceeds maximum ${maxSubagentSizeBytes} bytes (1MB) for ${relativePathFromCwd}`
17284
17876
  );
17285
17877
  }
17286
17878
  try {
17287
17879
  const existingSubagents = await listSubagents();
17288
17880
  const isUpdate = existingSubagents.some(
17289
- (subagent2) => subagent2.relativePathFromCwd === (0, import_node_path118.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename)
17881
+ (subagent2) => subagent2.relativePathFromCwd === (0, import_node_path121.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename)
17290
17882
  );
17291
17883
  if (!isUpdate && existingSubagents.length >= maxSubagentsCount) {
17292
- throw new Error(`Maximum number of subagents (${maxSubagentsCount}) reached`);
17884
+ throw new Error(
17885
+ `Maximum number of subagents (${maxSubagentsCount}) reached in ${RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH}`
17886
+ );
17293
17887
  }
17294
17888
  const subagent = new RulesyncSubagent({
17295
17889
  baseDir: process.cwd(),
@@ -17299,11 +17893,11 @@ async function putSubagent({
17299
17893
  body,
17300
17894
  validate: true
17301
17895
  });
17302
- const subagentsDir = (0, import_node_path118.join)(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH);
17896
+ const subagentsDir = (0, import_node_path121.join)(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH);
17303
17897
  await ensureDir(subagentsDir);
17304
17898
  await writeFileContent(subagent.getFilePath(), subagent.getFileContent());
17305
17899
  return {
17306
- relativePathFromCwd: (0, import_node_path118.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),
17900
+ relativePathFromCwd: (0, import_node_path121.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),
17307
17901
  frontmatter: subagent.getFrontmatter(),
17308
17902
  body: subagent.getBody()
17309
17903
  };
@@ -17318,12 +17912,12 @@ async function deleteSubagent({ relativePathFromCwd }) {
17318
17912
  relativePath: relativePathFromCwd,
17319
17913
  intendedRootDir: process.cwd()
17320
17914
  });
17321
- const filename = (0, import_node_path118.basename)(relativePathFromCwd);
17322
- const fullPath = (0, import_node_path118.join)(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename);
17915
+ const filename = (0, import_node_path121.basename)(relativePathFromCwd);
17916
+ const fullPath = (0, import_node_path121.join)(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename);
17323
17917
  try {
17324
17918
  await removeFile(fullPath);
17325
17919
  return {
17326
- relativePathFromCwd: (0, import_node_path118.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename)
17920
+ relativePathFromCwd: (0, import_node_path121.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename)
17327
17921
  };
17328
17922
  } catch (error) {
17329
17923
  throw new Error(
@@ -17335,23 +17929,23 @@ async function deleteSubagent({ relativePathFromCwd }) {
17335
17929
  }
17336
17930
  }
17337
17931
  var subagentToolSchemas = {
17338
- listSubagents: import_mini60.z.object({}),
17339
- getSubagent: import_mini60.z.object({
17340
- relativePathFromCwd: import_mini60.z.string()
17932
+ listSubagents: import_mini61.z.object({}),
17933
+ getSubagent: import_mini61.z.object({
17934
+ relativePathFromCwd: import_mini61.z.string()
17341
17935
  }),
17342
- putSubagent: import_mini60.z.object({
17343
- relativePathFromCwd: import_mini60.z.string(),
17936
+ putSubagent: import_mini61.z.object({
17937
+ relativePathFromCwd: import_mini61.z.string(),
17344
17938
  frontmatter: RulesyncSubagentFrontmatterSchema,
17345
- body: import_mini60.z.string()
17939
+ body: import_mini61.z.string()
17346
17940
  }),
17347
- deleteSubagent: import_mini60.z.object({
17348
- relativePathFromCwd: import_mini60.z.string()
17941
+ deleteSubagent: import_mini61.z.object({
17942
+ relativePathFromCwd: import_mini61.z.string()
17349
17943
  })
17350
17944
  };
17351
17945
  var subagentTools = {
17352
17946
  listSubagents: {
17353
17947
  name: "listSubagents",
17354
- description: `List all subagents from ${(0, import_node_path118.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
17948
+ description: `List all subagents from ${(0, import_node_path121.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
17355
17949
  parameters: subagentToolSchemas.listSubagents,
17356
17950
  execute: async () => {
17357
17951
  const subagents = await listSubagents();
@@ -17393,7 +17987,7 @@ var subagentTools = {
17393
17987
  };
17394
17988
 
17395
17989
  // src/mcp/tools.ts
17396
- var rulesyncFeatureSchema = import_mini61.z.enum([
17990
+ var rulesyncFeatureSchema = import_mini62.z.enum([
17397
17991
  "rule",
17398
17992
  "command",
17399
17993
  "subagent",
@@ -17403,21 +17997,21 @@ var rulesyncFeatureSchema = import_mini61.z.enum([
17403
17997
  "generate",
17404
17998
  "import"
17405
17999
  ]);
17406
- var rulesyncOperationSchema = import_mini61.z.enum(["list", "get", "put", "delete", "run"]);
17407
- var skillFileSchema = import_mini61.z.object({
17408
- name: import_mini61.z.string(),
17409
- body: import_mini61.z.string()
18000
+ var rulesyncOperationSchema = import_mini62.z.enum(["list", "get", "put", "delete", "run"]);
18001
+ var skillFileSchema = import_mini62.z.object({
18002
+ name: import_mini62.z.string(),
18003
+ body: import_mini62.z.string()
17410
18004
  });
17411
- var rulesyncToolSchema = import_mini61.z.object({
18005
+ var rulesyncToolSchema = import_mini62.z.object({
17412
18006
  feature: rulesyncFeatureSchema,
17413
18007
  operation: rulesyncOperationSchema,
17414
- targetPathFromCwd: import_mini61.z.optional(import_mini61.z.string()),
17415
- frontmatter: import_mini61.z.optional(import_mini61.z.unknown()),
17416
- body: import_mini61.z.optional(import_mini61.z.string()),
17417
- otherFiles: import_mini61.z.optional(import_mini61.z.array(skillFileSchema)),
17418
- content: import_mini61.z.optional(import_mini61.z.string()),
17419
- generateOptions: import_mini61.z.optional(generateOptionsSchema),
17420
- importOptions: import_mini61.z.optional(importOptionsSchema)
18008
+ targetPathFromCwd: import_mini62.z.optional(import_mini62.z.string()),
18009
+ frontmatter: import_mini62.z.optional(import_mini62.z.unknown()),
18010
+ body: import_mini62.z.optional(import_mini62.z.string()),
18011
+ otherFiles: import_mini62.z.optional(import_mini62.z.array(skillFileSchema)),
18012
+ content: import_mini62.z.optional(import_mini62.z.string()),
18013
+ generateOptions: import_mini62.z.optional(generateOptionsSchema),
18014
+ importOptions: import_mini62.z.optional(importOptionsSchema)
17421
18015
  });
17422
18016
  var supportedOperationsByFeature = {
17423
18017
  rule: ["list", "get", "put", "delete"],
@@ -17746,7 +18340,7 @@ async function downloadFile(url, destPath) {
17746
18340
  redirect: "follow"
17747
18341
  });
17748
18342
  if (!response.ok) {
17749
- throw new Error(`Failed to download: HTTP ${response.status}`);
18343
+ throw new Error(`Failed to download ${url}: HTTP ${response.status}`);
17750
18344
  }
17751
18345
  if (response.url) {
17752
18346
  validateDownloadUrl(response.url);
@@ -17976,7 +18570,7 @@ async function updateCommand(currentVersion, options) {
17976
18570
  }
17977
18571
 
17978
18572
  // src/cli/index.ts
17979
- var getVersion = () => "7.0.0";
18573
+ var getVersion = () => "7.1.0";
17980
18574
  var main = async () => {
17981
18575
  const program = new import_commander.Command();
17982
18576
  const version = getVersion();
@@ -18049,6 +18643,21 @@ var main = async () => {
18049
18643
  process.exit(1);
18050
18644
  }
18051
18645
  });
18646
+ program.command("install").description("Install skills from declarative sources in rulesync.jsonc").option("--update", "Force re-resolve all source refs, ignoring lockfile").option("--frozen", "Fail if lockfile is missing or out of sync (for CI)").option("--token <token>", "GitHub token for private repos").option("-c, --config <path>", "Path to configuration file").option("-V, --verbose", "Verbose output").option("-s, --silent", "Suppress all output").action(async (options) => {
18647
+ try {
18648
+ await installCommand({
18649
+ update: options.update,
18650
+ frozen: options.frozen,
18651
+ token: options.token,
18652
+ configPath: options.config,
18653
+ verbose: options.verbose,
18654
+ silent: options.silent
18655
+ });
18656
+ } catch (error) {
18657
+ logger.error(formatError(error));
18658
+ process.exit(1);
18659
+ }
18660
+ });
18052
18661
  program.command("generate").description("Generate configuration files for AI tools").option(
18053
18662
  "-t, --targets <tools>",
18054
18663
  "Comma-separated list of tools to generate for (e.g., 'copilot,cursor,cline' or '*' for all)",