rulesync 5.8.0 → 5.9.1

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 +1 -0
  2. package/dist/index.cjs +307 -171
  3. package/dist/index.js +296 -160
  4. package/package.json +11 -11
package/dist/index.js CHANGED
@@ -93,9 +93,6 @@ var Logger = class {
93
93
  };
94
94
  var logger = new Logger();
95
95
 
96
- // src/cli/commands/generate.ts
97
- import { intersection } from "es-toolkit";
98
-
99
96
  // src/config/config-resolver.ts
100
97
  import { parse as parseJsonc } from "jsonc-parser";
101
98
  import { resolve as resolve2 } from "path";
@@ -467,6 +464,10 @@ function getBaseDirsInLightOfGlobal({
467
464
  return resolvedBaseDirs;
468
465
  }
469
466
 
467
+ // src/lib/generate.ts
468
+ import { intersection } from "es-toolkit";
469
+ import { join as join96 } from "path";
470
+
470
471
  // src/constants/rulesync-paths.ts
471
472
  import { join as join2 } from "path";
472
473
  var RULESYNC_CONFIG_RELATIVE_FILE_PATH = "rulesync.jsonc";
@@ -8916,7 +8917,8 @@ import { join as join74 } from "path";
8916
8917
  import { basename as basename22, join as join73 } from "path";
8917
8918
  import { z as z38 } from "zod/mini";
8918
8919
  var RulesyncRuleFrontmatterSchema = z38.object({
8919
- root: z38.optional(z38.optional(z38.boolean())),
8920
+ root: z38.optional(z38.boolean()),
8921
+ localRoot: z38.optional(z38.boolean()),
8920
8922
  targets: z38.optional(RulesyncTargetsSchema),
8921
8923
  description: z38.optional(z38.string()),
8922
8924
  globs: z38.optional(z38.array(z38.string())),
@@ -9024,6 +9026,7 @@ var RulesyncRule = class _RulesyncRule extends RulesyncFile {
9024
9026
  }
9025
9027
  const validatedFrontmatter = {
9026
9028
  root: result.data.root ?? false,
9029
+ localRoot: result.data.localRoot ?? false,
9027
9030
  targets: result.data.targets ?? ["*"],
9028
9031
  description: result.data.description ?? "",
9029
9032
  globs: result.data.globs ?? [],
@@ -9057,6 +9060,7 @@ var RulesyncRule = class _RulesyncRule extends RulesyncFile {
9057
9060
  }
9058
9061
  const validatedFrontmatter = {
9059
9062
  root: result.data.root ?? false,
9063
+ localRoot: result.data.localRoot ?? false,
9060
9064
  targets: result.data.targets ?? ["*"],
9061
9065
  description: result.data.description ?? "",
9062
9066
  globs: result.data.globs ?? [],
@@ -11699,9 +11703,11 @@ var RulesProcessor = class extends FeatureProcessor {
11699
11703
  const rulesyncRules = rulesyncFiles.filter(
11700
11704
  (file) => file instanceof RulesyncRule
11701
11705
  );
11706
+ const localRootRules = rulesyncRules.filter((rule) => rule.getFrontmatter().localRoot);
11707
+ const nonLocalRootRules = rulesyncRules.filter((rule) => !rule.getFrontmatter().localRoot);
11702
11708
  const factory = this.getFactory(this.toolTarget);
11703
11709
  const { meta } = factory;
11704
- const toolRules = rulesyncRules.map((rulesyncRule) => {
11710
+ const toolRules = nonLocalRootRules.map((rulesyncRule) => {
11705
11711
  if (!factory.class.isTargetedByRulesyncRule(rulesyncRule)) {
11706
11712
  return null;
11707
11713
  }
@@ -11712,6 +11718,12 @@ var RulesProcessor = class extends FeatureProcessor {
11712
11718
  global: this.global
11713
11719
  });
11714
11720
  }).filter((rule) => rule !== null);
11721
+ if (localRootRules.length > 0 && !this.global) {
11722
+ const localRootRule = localRootRules[0];
11723
+ if (localRootRule && factory.class.isTargetedByRulesyncRule(localRootRule)) {
11724
+ this.handleLocalRootRule(toolRules, localRootRule, factory);
11725
+ }
11726
+ }
11715
11727
  const isSimulated = this.simulateCommands || this.simulateSubagents || this.simulateSkills;
11716
11728
  if (isSimulated && meta.createsSeparateConventionsRule && meta.additionalConventions) {
11717
11729
  const conventionsContent = this.generateAdditionalConventionsSectionFromMeta(meta);
@@ -11766,6 +11778,50 @@ var RulesProcessor = class extends FeatureProcessor {
11766
11778
  };
11767
11779
  });
11768
11780
  }
11781
+ /**
11782
+ * Handle localRoot rule generation based on tool target.
11783
+ * - Claude Code: generates `.claude/CLAUDE.local.md`
11784
+ * - Claude Code Legacy: generates `./CLAUDE.local.md`
11785
+ * - Other tools: appends content to the root file with one blank line separator
11786
+ */
11787
+ handleLocalRootRule(toolRules, localRootRule, _factory) {
11788
+ const localRootBody = localRootRule.getBody();
11789
+ if (this.toolTarget === "claudecode") {
11790
+ const paths = ClaudecodeRule.getSettablePaths({ global: this.global });
11791
+ toolRules.push(
11792
+ new ClaudecodeRule({
11793
+ baseDir: this.baseDir,
11794
+ relativeDirPath: paths.root.relativeDirPath,
11795
+ relativeFilePath: "CLAUDE.local.md",
11796
+ frontmatter: {},
11797
+ body: localRootBody,
11798
+ validate: true,
11799
+ root: true
11800
+ // Treat as root so it doesn't have frontmatter
11801
+ })
11802
+ );
11803
+ } else if (this.toolTarget === "claudecode-legacy") {
11804
+ const paths = ClaudecodeLegacyRule.getSettablePaths({ global: this.global });
11805
+ toolRules.push(
11806
+ new ClaudecodeLegacyRule({
11807
+ baseDir: this.baseDir,
11808
+ relativeDirPath: paths.root.relativeDirPath,
11809
+ relativeFilePath: "CLAUDE.local.md",
11810
+ fileContent: localRootBody,
11811
+ validate: true,
11812
+ root: true
11813
+ // Treat as root so it doesn't have frontmatter
11814
+ })
11815
+ );
11816
+ } else {
11817
+ const rootRule = toolRules.find((rule) => rule.isRoot());
11818
+ if (rootRule) {
11819
+ const currentContent = rootRule.getFileContent();
11820
+ const newContent = currentContent + "\n\n" + localRootBody;
11821
+ rootRule.setFileContent(newContent);
11822
+ }
11823
+ }
11824
+ }
11769
11825
  /**
11770
11826
  * Generate reference section based on meta configuration.
11771
11827
  */
@@ -11834,6 +11890,18 @@ var RulesProcessor = class extends FeatureProcessor {
11834
11890
  if (rootRules.length > 1) {
11835
11891
  throw new Error("Multiple root rulesync rules found");
11836
11892
  }
11893
+ if (rootRules.length === 0 && rulesyncRules.length > 0) {
11894
+ logger.warn(
11895
+ `No root rulesync rule file found. Consider adding 'root: true' to one of your rule files in ${RULESYNC_RULES_RELATIVE_DIR_PATH}.`
11896
+ );
11897
+ }
11898
+ const localRootRules = rulesyncRules.filter((rule) => rule.getFrontmatter().localRoot);
11899
+ if (localRootRules.length > 1) {
11900
+ throw new Error("Multiple localRoot rules found. Only one rule can have localRoot: true");
11901
+ }
11902
+ if (localRootRules.length > 0 && rootRules.length === 0) {
11903
+ throw new Error("localRoot: true requires a root: true rule to exist");
11904
+ }
11837
11905
  if (this.global) {
11838
11906
  const nonRootRules = rulesyncRules.filter((rule) => !rule.getFrontmatter().root);
11839
11907
  if (nonRootRules.length > 0) {
@@ -11841,6 +11909,11 @@ var RulesProcessor = class extends FeatureProcessor {
11841
11909
  `${nonRootRules.length} non-root rulesync rules found, but it's in global mode, so ignoring them`
11842
11910
  );
11843
11911
  }
11912
+ if (localRootRules.length > 0) {
11913
+ logger.warn(
11914
+ `${localRootRules.length} localRoot rules found, but localRoot is not supported in global mode, ignoring them`
11915
+ );
11916
+ }
11844
11917
  return rootRules;
11845
11918
  }
11846
11919
  return rulesyncRules;
@@ -11894,6 +11967,29 @@ var RulesProcessor = class extends FeatureProcessor {
11894
11967
  );
11895
11968
  })();
11896
11969
  logger.debug(`Found ${rootToolRules.length} root tool rule files`);
11970
+ const localRootToolRules = await (async () => {
11971
+ if (!forDeletion) {
11972
+ return [];
11973
+ }
11974
+ if (this.toolTarget !== "claudecode" && this.toolTarget !== "claudecode-legacy") {
11975
+ return [];
11976
+ }
11977
+ if (!settablePaths.root) {
11978
+ return [];
11979
+ }
11980
+ const localRootFilePaths = await findFilesByGlobs(
11981
+ join95(this.baseDir, settablePaths.root.relativeDirPath ?? ".", "CLAUDE.local.md")
11982
+ );
11983
+ return localRootFilePaths.map(
11984
+ (filePath) => factory.class.forDeletion({
11985
+ baseDir: this.baseDir,
11986
+ relativeDirPath: settablePaths.root?.relativeDirPath ?? ".",
11987
+ relativeFilePath: basename24(filePath),
11988
+ global: this.global
11989
+ })
11990
+ ).filter((rule) => rule.isDeletable());
11991
+ })();
11992
+ logger.debug(`Found ${localRootToolRules.length} local root tool rule files for deletion`);
11897
11993
  const nonRootToolRules = await (async () => {
11898
11994
  if (!settablePaths.nonRoot) {
11899
11995
  return [];
@@ -11922,7 +12018,7 @@ var RulesProcessor = class extends FeatureProcessor {
11922
12018
  );
11923
12019
  })();
11924
12020
  logger.debug(`Found ${nonRootToolRules.length} non-root tool rule files`);
11925
- return [...rootToolRules, ...nonRootToolRules];
12021
+ return [...rootToolRules, ...localRootToolRules, ...nonRootToolRules];
11926
12022
  } catch (error) {
11927
12023
  logger.error(`Failed to load tool files: ${formatError(error)}`);
11928
12024
  return [];
@@ -12042,51 +12138,34 @@ ${toonContent}`;
12042
12138
  }
12043
12139
  };
12044
12140
 
12045
- // src/cli/commands/generate.ts
12046
- async function generateCommand(options) {
12047
- const config = await ConfigResolver.resolve(options);
12048
- logger.configure({
12049
- verbose: config.getVerbose(),
12050
- silent: config.getSilent()
12051
- });
12052
- logger.info("Generating files...");
12053
- if (!await fileExists(RULESYNC_RELATIVE_DIR_PATH)) {
12054
- logger.error("\u274C .rulesync directory not found. Run 'rulesync init' first.");
12055
- process.exit(1);
12056
- }
12057
- logger.info(`Base directories: ${config.getBaseDirs().join(", ")}`);
12058
- const totalIgnoreOutputs = await generateIgnore(config);
12059
- const totalMcpOutputs = await generateMcp(config);
12060
- const totalCommandOutputs = await generateCommands(config);
12061
- const totalSubagentOutputs = await generateSubagents(config);
12062
- const skillsResult = await generateSkills(config);
12063
- const totalRulesOutputs = await generateRules(config, {
12141
+ // src/lib/generate.ts
12142
+ async function checkRulesyncDirExists(params) {
12143
+ return fileExists(join96(params.baseDir, RULESYNC_RELATIVE_DIR_PATH));
12144
+ }
12145
+ async function generate(params) {
12146
+ const { config } = params;
12147
+ const ignoreCount = await generateIgnoreCore({ config });
12148
+ const mcpCount = await generateMcpCore({ config });
12149
+ const commandsCount = await generateCommandsCore({ config });
12150
+ const subagentsCount = await generateSubagentsCore({ config });
12151
+ const skillsResult = await generateSkillsCore({ config });
12152
+ const rulesCount = await generateRulesCore({ config, skills: skillsResult.skills });
12153
+ return {
12154
+ rulesCount,
12155
+ ignoreCount,
12156
+ mcpCount,
12157
+ commandsCount,
12158
+ subagentsCount,
12159
+ skillsCount: skillsResult.count,
12064
12160
  skills: skillsResult.skills
12065
- });
12066
- const totalGenerated = totalRulesOutputs + totalMcpOutputs + totalCommandOutputs + totalIgnoreOutputs + totalSubagentOutputs + skillsResult.totalOutputs;
12067
- if (totalGenerated === 0) {
12068
- const enabledFeatures = config.getFeatures().join(", ");
12069
- logger.warn(`\u26A0\uFE0F No files generated for enabled features: ${enabledFeatures}`);
12070
- return;
12071
- }
12072
- if (totalGenerated > 0) {
12073
- const parts = [];
12074
- if (totalRulesOutputs > 0) parts.push(`${totalRulesOutputs} rules`);
12075
- if (totalIgnoreOutputs > 0) parts.push(`${totalIgnoreOutputs} ignore files`);
12076
- if (totalMcpOutputs > 0) parts.push(`${totalMcpOutputs} MCP files`);
12077
- if (totalCommandOutputs > 0) parts.push(`${totalCommandOutputs} commands`);
12078
- if (totalSubagentOutputs > 0) parts.push(`${totalSubagentOutputs} subagents`);
12079
- if (skillsResult.totalOutputs > 0) parts.push(`${skillsResult.totalOutputs} skills`);
12080
- logger.success(`\u{1F389} All done! Generated ${totalGenerated} file(s) total (${parts.join(" + ")})`);
12081
- }
12161
+ };
12082
12162
  }
12083
- async function generateRules(config, options) {
12163
+ async function generateRulesCore(params) {
12164
+ const { config, skills } = params;
12084
12165
  if (!config.getFeatures().includes("rules")) {
12085
- logger.debug("Skipping rule generation (not in --features)");
12086
12166
  return 0;
12087
12167
  }
12088
- let totalRulesOutputs = 0;
12089
- logger.info("Generating rule files...");
12168
+ let totalCount = 0;
12090
12169
  const toolTargets = intersection(
12091
12170
  config.getTargets(),
12092
12171
  RulesProcessor.getToolTargets({ global: config.getGlobal() })
@@ -12100,7 +12179,7 @@ async function generateRules(config, options) {
12100
12179
  simulateCommands: config.getSimulateCommands(),
12101
12180
  simulateSubagents: config.getSimulateSubagents(),
12102
12181
  simulateSkills: config.getSimulateSkills(),
12103
- skills: options?.skills
12182
+ skills
12104
12183
  });
12105
12184
  if (config.getDelete()) {
12106
12185
  const oldToolFiles = await processor.loadToolFiles({ forDeletion: true });
@@ -12109,23 +12188,20 @@ async function generateRules(config, options) {
12109
12188
  const rulesyncFiles = await processor.loadRulesyncFiles();
12110
12189
  const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
12111
12190
  const writtenCount = await processor.writeAiFiles(toolFiles);
12112
- totalRulesOutputs += writtenCount;
12113
- logger.success(`Generated ${writtenCount} ${toolTarget} rule(s) in ${baseDir}`);
12191
+ totalCount += writtenCount;
12114
12192
  }
12115
12193
  }
12116
- return totalRulesOutputs;
12194
+ return totalCount;
12117
12195
  }
12118
- async function generateIgnore(config) {
12196
+ async function generateIgnoreCore(params) {
12197
+ const { config } = params;
12119
12198
  if (!config.getFeatures().includes("ignore")) {
12120
- logger.debug("Skipping ignore file generation (not in --features)");
12121
12199
  return 0;
12122
12200
  }
12123
12201
  if (config.getGlobal()) {
12124
- logger.debug("Skipping ignore file generation (not supported in global mode)");
12125
12202
  return 0;
12126
12203
  }
12127
- let totalIgnoreOutputs = 0;
12128
- logger.info("Generating ignore files...");
12204
+ let totalCount = 0;
12129
12205
  for (const toolTarget of intersection(config.getTargets(), IgnoreProcessor.getToolTargets())) {
12130
12206
  for (const baseDir of config.getBaseDirs()) {
12131
12207
  try {
@@ -12141,30 +12217,24 @@ async function generateIgnore(config) {
12141
12217
  if (rulesyncFiles.length > 0) {
12142
12218
  const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
12143
12219
  const writtenCount = await processor.writeAiFiles(toolFiles);
12144
- totalIgnoreOutputs += writtenCount;
12145
- logger.success(`Generated ${writtenCount} ${toolTarget} ignore file(s) in ${baseDir}`);
12220
+ totalCount += writtenCount;
12146
12221
  }
12147
12222
  } catch (error) {
12148
12223
  logger.warn(
12149
- `Failed to generate ${toolTarget} ignore files for ${baseDir}:`,
12150
- error instanceof Error ? error.message : String(error)
12224
+ `Failed to generate ${toolTarget} ignore files for ${baseDir}: ${formatError(error)}`
12151
12225
  );
12152
12226
  continue;
12153
12227
  }
12154
12228
  }
12155
12229
  }
12156
- return totalIgnoreOutputs;
12230
+ return totalCount;
12157
12231
  }
12158
- async function generateMcp(config) {
12232
+ async function generateMcpCore(params) {
12233
+ const { config } = params;
12159
12234
  if (!config.getFeatures().includes("mcp")) {
12160
- logger.debug("Skipping MCP configuration generation (not in --features)");
12161
12235
  return 0;
12162
12236
  }
12163
- let totalMcpOutputs = 0;
12164
- logger.info("Generating MCP files...");
12165
- if (config.getModularMcp()) {
12166
- logger.info("\u2139\uFE0F Modular MCP support is experimental.");
12167
- }
12237
+ let totalCount = 0;
12168
12238
  const toolTargets = intersection(
12169
12239
  config.getTargets(),
12170
12240
  McpProcessor.getToolTargets({ global: config.getGlobal() })
@@ -12184,19 +12254,17 @@ async function generateMcp(config) {
12184
12254
  const rulesyncFiles = await processor.loadRulesyncFiles();
12185
12255
  const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
12186
12256
  const writtenCount = await processor.writeAiFiles(toolFiles);
12187
- totalMcpOutputs += writtenCount;
12188
- logger.success(`Generated ${writtenCount} ${toolTarget} MCP configuration(s) in ${baseDir}`);
12257
+ totalCount += writtenCount;
12189
12258
  }
12190
12259
  }
12191
- return totalMcpOutputs;
12260
+ return totalCount;
12192
12261
  }
12193
- async function generateCommands(config) {
12262
+ async function generateCommandsCore(params) {
12263
+ const { config } = params;
12194
12264
  if (!config.getFeatures().includes("commands")) {
12195
- logger.debug("Skipping command file generation (not in --features)");
12196
12265
  return 0;
12197
12266
  }
12198
- let totalCommandOutputs = 0;
12199
- logger.info("Generating command files...");
12267
+ let totalCount = 0;
12200
12268
  const toolTargets = intersection(
12201
12269
  config.getTargets(),
12202
12270
  CommandsProcessor.getToolTargets({
@@ -12218,19 +12286,17 @@ async function generateCommands(config) {
12218
12286
  const rulesyncFiles = await processor.loadRulesyncFiles();
12219
12287
  const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
12220
12288
  const writtenCount = await processor.writeAiFiles(toolFiles);
12221
- totalCommandOutputs += writtenCount;
12222
- logger.success(`Generated ${writtenCount} ${toolTarget} command(s) in ${baseDir}`);
12289
+ totalCount += writtenCount;
12223
12290
  }
12224
12291
  }
12225
- return totalCommandOutputs;
12292
+ return totalCount;
12226
12293
  }
12227
- async function generateSubagents(config) {
12294
+ async function generateSubagentsCore(params) {
12295
+ const { config } = params;
12228
12296
  if (!config.getFeatures().includes("subagents")) {
12229
- logger.debug("Skipping subagent file generation (not in --features)");
12230
12297
  return 0;
12231
12298
  }
12232
- let totalSubagentOutputs = 0;
12233
- logger.info("Generating subagent files...");
12299
+ let totalCount = 0;
12234
12300
  const toolTargets = intersection(
12235
12301
  config.getTargets(),
12236
12302
  SubagentsProcessor.getToolTargets({
@@ -12252,20 +12318,18 @@ async function generateSubagents(config) {
12252
12318
  const rulesyncFiles = await processor.loadRulesyncFiles();
12253
12319
  const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
12254
12320
  const writtenCount = await processor.writeAiFiles(toolFiles);
12255
- totalSubagentOutputs += writtenCount;
12256
- logger.success(`Generated ${writtenCount} ${toolTarget} subagent(s) in ${baseDir}`);
12321
+ totalCount += writtenCount;
12257
12322
  }
12258
12323
  }
12259
- return totalSubagentOutputs;
12324
+ return totalCount;
12260
12325
  }
12261
- async function generateSkills(config) {
12326
+ async function generateSkillsCore(params) {
12327
+ const { config } = params;
12262
12328
  if (!config.getFeatures().includes("skills")) {
12263
- logger.debug("Skipping skill generation (not in --features)");
12264
- return { totalOutputs: 0, skills: [] };
12329
+ return { count: 0, skills: [] };
12265
12330
  }
12266
- let totalSkillOutputs = 0;
12331
+ let totalCount = 0;
12267
12332
  const allSkills = [];
12268
- logger.info("Generating skill files...");
12269
12333
  const toolTargets = intersection(
12270
12334
  config.getTargets(),
12271
12335
  SkillsProcessor.getToolTargets({
@@ -12292,15 +12356,84 @@ async function generateSkills(config) {
12292
12356
  }
12293
12357
  const toolDirs = await processor.convertRulesyncDirsToToolDirs(rulesyncDirs);
12294
12358
  const writtenCount = await processor.writeAiDirs(toolDirs);
12295
- totalSkillOutputs += writtenCount;
12296
- logger.success(`Generated ${writtenCount} ${toolTarget} skill(s) in ${baseDir}`);
12359
+ totalCount += writtenCount;
12360
+ }
12361
+ }
12362
+ return { count: totalCount, skills: allSkills };
12363
+ }
12364
+
12365
+ // src/cli/commands/generate.ts
12366
+ async function generateCommand(options) {
12367
+ const config = await ConfigResolver.resolve(options);
12368
+ logger.configure({
12369
+ verbose: config.getVerbose(),
12370
+ silent: config.getSilent()
12371
+ });
12372
+ logger.info("Generating files...");
12373
+ if (!await checkRulesyncDirExists({ baseDir: config.getBaseDirs()[0] ?? process.cwd() })) {
12374
+ logger.error("\u274C .rulesync directory not found. Run 'rulesync init' first.");
12375
+ process.exit(1);
12376
+ }
12377
+ logger.info(`Base directories: ${config.getBaseDirs().join(", ")}`);
12378
+ const features = config.getFeatures();
12379
+ if (features.includes("ignore")) {
12380
+ logger.info("Generating ignore files...");
12381
+ }
12382
+ if (features.includes("mcp")) {
12383
+ logger.info("Generating MCP files...");
12384
+ if (config.getModularMcp()) {
12385
+ logger.info("\u2139\uFE0F Modular MCP support is experimental.");
12297
12386
  }
12298
12387
  }
12299
- return { totalOutputs: totalSkillOutputs, skills: allSkills };
12388
+ if (features.includes("commands")) {
12389
+ logger.info("Generating command files...");
12390
+ }
12391
+ if (features.includes("subagents")) {
12392
+ logger.info("Generating subagent files...");
12393
+ }
12394
+ if (features.includes("skills")) {
12395
+ logger.info("Generating skill files...");
12396
+ }
12397
+ if (features.includes("rules")) {
12398
+ logger.info("Generating rule files...");
12399
+ }
12400
+ const result = await generate({ config });
12401
+ if (result.ignoreCount > 0) {
12402
+ logger.success(`Generated ${result.ignoreCount} ignore file(s)`);
12403
+ }
12404
+ if (result.mcpCount > 0) {
12405
+ logger.success(`Generated ${result.mcpCount} MCP configuration(s)`);
12406
+ }
12407
+ if (result.commandsCount > 0) {
12408
+ logger.success(`Generated ${result.commandsCount} command(s)`);
12409
+ }
12410
+ if (result.subagentsCount > 0) {
12411
+ logger.success(`Generated ${result.subagentsCount} subagent(s)`);
12412
+ }
12413
+ if (result.skillsCount > 0) {
12414
+ logger.success(`Generated ${result.skillsCount} skill(s)`);
12415
+ }
12416
+ if (result.rulesCount > 0) {
12417
+ logger.success(`Generated ${result.rulesCount} rule(s)`);
12418
+ }
12419
+ const totalGenerated = result.rulesCount + result.ignoreCount + result.mcpCount + result.commandsCount + result.subagentsCount + result.skillsCount;
12420
+ if (totalGenerated === 0) {
12421
+ const enabledFeatures = features.join(", ");
12422
+ logger.warn(`\u26A0\uFE0F No files generated for enabled features: ${enabledFeatures}`);
12423
+ return;
12424
+ }
12425
+ const parts = [];
12426
+ if (result.rulesCount > 0) parts.push(`${result.rulesCount} rules`);
12427
+ if (result.ignoreCount > 0) parts.push(`${result.ignoreCount} ignore files`);
12428
+ if (result.mcpCount > 0) parts.push(`${result.mcpCount} MCP files`);
12429
+ if (result.commandsCount > 0) parts.push(`${result.commandsCount} commands`);
12430
+ if (result.subagentsCount > 0) parts.push(`${result.subagentsCount} subagents`);
12431
+ if (result.skillsCount > 0) parts.push(`${result.skillsCount} skills`);
12432
+ logger.success(`\u{1F389} All done! Generated ${totalGenerated} file(s) total (${parts.join(" + ")})`);
12300
12433
  }
12301
12434
 
12302
12435
  // src/cli/commands/gitignore.ts
12303
- import { join as join96 } from "path";
12436
+ import { join as join97 } from "path";
12304
12437
  var RULESYNC_HEADER = "# Generated by Rulesync";
12305
12438
  var LEGACY_RULESYNC_HEADER = "# Generated by rulesync - AI tool configuration files";
12306
12439
  var RULESYNC_IGNORE_ENTRIES = [
@@ -12317,7 +12450,9 @@ var RULESYNC_IGNORE_ENTRIES = [
12317
12450
  "**/.augment-guidelines",
12318
12451
  // Claude Code
12319
12452
  "**/CLAUDE.md",
12453
+ "**/CLAUDE.local.md",
12320
12454
  "**/.claude/CLAUDE.md",
12455
+ "**/.claude/CLAUDE.local.md",
12321
12456
  "**/.claude/memories/",
12322
12457
  "**/.claude/rules/",
12323
12458
  "**/.claude/commands/",
@@ -12389,6 +12524,7 @@ var RULESYNC_IGNORE_ENTRIES = [
12389
12524
  "**/WARP.md",
12390
12525
  // Others
12391
12526
  "**/modular-mcp.json",
12527
+ ".rulesync/rules/*.local.md",
12392
12528
  "!.rulesync/.aiignore"
12393
12529
  ];
12394
12530
  var isRulesyncHeader = (line) => {
@@ -12441,7 +12577,7 @@ var removeExistingRulesyncEntries = (content) => {
12441
12577
  return result;
12442
12578
  };
12443
12579
  var gitignoreCommand = async () => {
12444
- const gitignorePath = join96(process.cwd(), ".gitignore");
12580
+ const gitignorePath = join97(process.cwd(), ".gitignore");
12445
12581
  let gitignoreContent = "";
12446
12582
  if (await fileExists(gitignorePath)) {
12447
12583
  gitignoreContent = await readFileContent(gitignorePath);
@@ -12643,7 +12779,7 @@ async function importSkills(config, tool) {
12643
12779
  }
12644
12780
 
12645
12781
  // src/cli/commands/init.ts
12646
- import { join as join97 } from "path";
12782
+ import { join as join98 } from "path";
12647
12783
  async function initCommand() {
12648
12784
  logger.info("Initializing rulesync...");
12649
12785
  await ensureDir(RULESYNC_RELATIVE_DIR_PATH);
@@ -12821,14 +12957,14 @@ Keep the summary concise and ready to reuse in future tasks.`
12821
12957
  await ensureDir(subagentPaths.relativeDirPath);
12822
12958
  await ensureDir(skillPaths.relativeDirPath);
12823
12959
  await ensureDir(ignorePaths.recommended.relativeDirPath);
12824
- const ruleFilepath = join97(rulePaths.recommended.relativeDirPath, sampleRuleFile.filename);
12960
+ const ruleFilepath = join98(rulePaths.recommended.relativeDirPath, sampleRuleFile.filename);
12825
12961
  if (!await fileExists(ruleFilepath)) {
12826
12962
  await writeFileContent(ruleFilepath, sampleRuleFile.content);
12827
12963
  logger.success(`Created ${ruleFilepath}`);
12828
12964
  } else {
12829
12965
  logger.info(`Skipped ${ruleFilepath} (already exists)`);
12830
12966
  }
12831
- const mcpFilepath = join97(
12967
+ const mcpFilepath = join98(
12832
12968
  mcpPaths.recommended.relativeDirPath,
12833
12969
  mcpPaths.recommended.relativeFilePath
12834
12970
  );
@@ -12838,30 +12974,30 @@ Keep the summary concise and ready to reuse in future tasks.`
12838
12974
  } else {
12839
12975
  logger.info(`Skipped ${mcpFilepath} (already exists)`);
12840
12976
  }
12841
- const commandFilepath = join97(commandPaths.relativeDirPath, sampleCommandFile.filename);
12977
+ const commandFilepath = join98(commandPaths.relativeDirPath, sampleCommandFile.filename);
12842
12978
  if (!await fileExists(commandFilepath)) {
12843
12979
  await writeFileContent(commandFilepath, sampleCommandFile.content);
12844
12980
  logger.success(`Created ${commandFilepath}`);
12845
12981
  } else {
12846
12982
  logger.info(`Skipped ${commandFilepath} (already exists)`);
12847
12983
  }
12848
- const subagentFilepath = join97(subagentPaths.relativeDirPath, sampleSubagentFile.filename);
12984
+ const subagentFilepath = join98(subagentPaths.relativeDirPath, sampleSubagentFile.filename);
12849
12985
  if (!await fileExists(subagentFilepath)) {
12850
12986
  await writeFileContent(subagentFilepath, sampleSubagentFile.content);
12851
12987
  logger.success(`Created ${subagentFilepath}`);
12852
12988
  } else {
12853
12989
  logger.info(`Skipped ${subagentFilepath} (already exists)`);
12854
12990
  }
12855
- const skillDirPath = join97(skillPaths.relativeDirPath, sampleSkillFile.dirName);
12991
+ const skillDirPath = join98(skillPaths.relativeDirPath, sampleSkillFile.dirName);
12856
12992
  await ensureDir(skillDirPath);
12857
- const skillFilepath = join97(skillDirPath, SKILL_FILE_NAME);
12993
+ const skillFilepath = join98(skillDirPath, SKILL_FILE_NAME);
12858
12994
  if (!await fileExists(skillFilepath)) {
12859
12995
  await writeFileContent(skillFilepath, sampleSkillFile.content);
12860
12996
  logger.success(`Created ${skillFilepath}`);
12861
12997
  } else {
12862
12998
  logger.info(`Skipped ${skillFilepath} (already exists)`);
12863
12999
  }
12864
- const ignoreFilepath = join97(
13000
+ const ignoreFilepath = join98(
12865
13001
  ignorePaths.recommended.relativeDirPath,
12866
13002
  ignorePaths.recommended.relativeFilePath
12867
13003
  );
@@ -12880,12 +13016,12 @@ import { FastMCP } from "fastmcp";
12880
13016
  import { z as z51 } from "zod/mini";
12881
13017
 
12882
13018
  // src/mcp/commands.ts
12883
- import { basename as basename25, join as join98 } from "path";
13019
+ import { basename as basename25, join as join99 } from "path";
12884
13020
  import { z as z45 } from "zod/mini";
12885
13021
  var maxCommandSizeBytes = 1024 * 1024;
12886
13022
  var maxCommandsCount = 1e3;
12887
13023
  async function listCommands() {
12888
- const commandsDir = join98(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH);
13024
+ const commandsDir = join99(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH);
12889
13025
  try {
12890
13026
  const files = await listDirectoryFiles(commandsDir);
12891
13027
  const mdFiles = files.filter((file) => file.endsWith(".md"));
@@ -12897,7 +13033,7 @@ async function listCommands() {
12897
13033
  });
12898
13034
  const frontmatter = command.getFrontmatter();
12899
13035
  return {
12900
- relativePathFromCwd: join98(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, file),
13036
+ relativePathFromCwd: join99(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, file),
12901
13037
  frontmatter
12902
13038
  };
12903
13039
  } catch (error) {
@@ -12923,7 +13059,7 @@ async function getCommand({ relativePathFromCwd }) {
12923
13059
  relativeFilePath: filename
12924
13060
  });
12925
13061
  return {
12926
- relativePathFromCwd: join98(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),
13062
+ relativePathFromCwd: join99(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),
12927
13063
  frontmatter: command.getFrontmatter(),
12928
13064
  body: command.getBody()
12929
13065
  };
@@ -12952,7 +13088,7 @@ async function putCommand({
12952
13088
  try {
12953
13089
  const existingCommands = await listCommands();
12954
13090
  const isUpdate = existingCommands.some(
12955
- (command2) => command2.relativePathFromCwd === join98(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename)
13091
+ (command2) => command2.relativePathFromCwd === join99(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename)
12956
13092
  );
12957
13093
  if (!isUpdate && existingCommands.length >= maxCommandsCount) {
12958
13094
  throw new Error(`Maximum number of commands (${maxCommandsCount}) reached`);
@@ -12967,11 +13103,11 @@ async function putCommand({
12967
13103
  fileContent,
12968
13104
  validate: true
12969
13105
  });
12970
- const commandsDir = join98(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH);
13106
+ const commandsDir = join99(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH);
12971
13107
  await ensureDir(commandsDir);
12972
13108
  await writeFileContent(command.getFilePath(), command.getFileContent());
12973
13109
  return {
12974
- relativePathFromCwd: join98(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),
13110
+ relativePathFromCwd: join99(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),
12975
13111
  frontmatter: command.getFrontmatter(),
12976
13112
  body: command.getBody()
12977
13113
  };
@@ -12987,11 +13123,11 @@ async function deleteCommand({ relativePathFromCwd }) {
12987
13123
  intendedRootDir: process.cwd()
12988
13124
  });
12989
13125
  const filename = basename25(relativePathFromCwd);
12990
- const fullPath = join98(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename);
13126
+ const fullPath = join99(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename);
12991
13127
  try {
12992
13128
  await removeFile(fullPath);
12993
13129
  return {
12994
- relativePathFromCwd: join98(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename)
13130
+ relativePathFromCwd: join99(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename)
12995
13131
  };
12996
13132
  } catch (error) {
12997
13133
  throw new Error(`Failed to delete command file ${relativePathFromCwd}: ${formatError(error)}`, {
@@ -13016,7 +13152,7 @@ var commandToolSchemas = {
13016
13152
  var commandTools = {
13017
13153
  listCommands: {
13018
13154
  name: "listCommands",
13019
- description: `List all commands from ${join98(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
13155
+ description: `List all commands from ${join99(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
13020
13156
  parameters: commandToolSchemas.listCommands,
13021
13157
  execute: async () => {
13022
13158
  const commands = await listCommands();
@@ -13058,11 +13194,11 @@ var commandTools = {
13058
13194
  };
13059
13195
 
13060
13196
  // src/mcp/ignore.ts
13061
- import { join as join99 } from "path";
13197
+ import { join as join100 } from "path";
13062
13198
  import { z as z46 } from "zod/mini";
13063
13199
  var maxIgnoreFileSizeBytes = 100 * 1024;
13064
13200
  async function getIgnoreFile() {
13065
- const ignoreFilePath = join99(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);
13201
+ const ignoreFilePath = join100(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);
13066
13202
  try {
13067
13203
  const content = await readFileContent(ignoreFilePath);
13068
13204
  return {
@@ -13076,7 +13212,7 @@ async function getIgnoreFile() {
13076
13212
  }
13077
13213
  }
13078
13214
  async function putIgnoreFile({ content }) {
13079
- const ignoreFilePath = join99(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);
13215
+ const ignoreFilePath = join100(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);
13080
13216
  const contentSizeBytes = Buffer.byteLength(content, "utf8");
13081
13217
  if (contentSizeBytes > maxIgnoreFileSizeBytes) {
13082
13218
  throw new Error(
@@ -13097,8 +13233,8 @@ async function putIgnoreFile({ content }) {
13097
13233
  }
13098
13234
  }
13099
13235
  async function deleteIgnoreFile() {
13100
- const aiignorePath = join99(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);
13101
- const legacyIgnorePath = join99(process.cwd(), RULESYNC_IGNORE_RELATIVE_FILE_PATH);
13236
+ const aiignorePath = join100(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);
13237
+ const legacyIgnorePath = join100(process.cwd(), RULESYNC_IGNORE_RELATIVE_FILE_PATH);
13102
13238
  try {
13103
13239
  await Promise.all([removeFile(aiignorePath), removeFile(legacyIgnorePath)]);
13104
13240
  return {
@@ -13153,7 +13289,7 @@ var ignoreTools = {
13153
13289
  };
13154
13290
 
13155
13291
  // src/mcp/mcp.ts
13156
- import { join as join100 } from "path";
13292
+ import { join as join101 } from "path";
13157
13293
  import { z as z47 } from "zod/mini";
13158
13294
  var maxMcpSizeBytes = 1024 * 1024;
13159
13295
  async function getMcpFile() {
@@ -13163,7 +13299,7 @@ async function getMcpFile() {
13163
13299
  validate: true,
13164
13300
  modularMcp: config.getModularMcp()
13165
13301
  });
13166
- const relativePathFromCwd = join100(
13302
+ const relativePathFromCwd = join101(
13167
13303
  rulesyncMcp.getRelativeDirPath(),
13168
13304
  rulesyncMcp.getRelativeFilePath()
13169
13305
  );
@@ -13196,7 +13332,7 @@ async function putMcpFile({ content }) {
13196
13332
  const paths = RulesyncMcp.getSettablePaths();
13197
13333
  const relativeDirPath = paths.recommended.relativeDirPath;
13198
13334
  const relativeFilePath = paths.recommended.relativeFilePath;
13199
- const fullPath = join100(baseDir, relativeDirPath, relativeFilePath);
13335
+ const fullPath = join101(baseDir, relativeDirPath, relativeFilePath);
13200
13336
  const rulesyncMcp = new RulesyncMcp({
13201
13337
  baseDir,
13202
13338
  relativeDirPath,
@@ -13205,9 +13341,9 @@ async function putMcpFile({ content }) {
13205
13341
  validate: true,
13206
13342
  modularMcp: config.getModularMcp()
13207
13343
  });
13208
- await ensureDir(join100(baseDir, relativeDirPath));
13344
+ await ensureDir(join101(baseDir, relativeDirPath));
13209
13345
  await writeFileContent(fullPath, content);
13210
- const relativePathFromCwd = join100(relativeDirPath, relativeFilePath);
13346
+ const relativePathFromCwd = join101(relativeDirPath, relativeFilePath);
13211
13347
  return {
13212
13348
  relativePathFromCwd,
13213
13349
  content: rulesyncMcp.getFileContent()
@@ -13222,15 +13358,15 @@ async function deleteMcpFile() {
13222
13358
  try {
13223
13359
  const baseDir = process.cwd();
13224
13360
  const paths = RulesyncMcp.getSettablePaths();
13225
- const recommendedPath = join100(
13361
+ const recommendedPath = join101(
13226
13362
  baseDir,
13227
13363
  paths.recommended.relativeDirPath,
13228
13364
  paths.recommended.relativeFilePath
13229
13365
  );
13230
- const legacyPath = join100(baseDir, paths.legacy.relativeDirPath, paths.legacy.relativeFilePath);
13366
+ const legacyPath = join101(baseDir, paths.legacy.relativeDirPath, paths.legacy.relativeFilePath);
13231
13367
  await removeFile(recommendedPath);
13232
13368
  await removeFile(legacyPath);
13233
- const relativePathFromCwd = join100(
13369
+ const relativePathFromCwd = join101(
13234
13370
  paths.recommended.relativeDirPath,
13235
13371
  paths.recommended.relativeFilePath
13236
13372
  );
@@ -13281,12 +13417,12 @@ var mcpTools = {
13281
13417
  };
13282
13418
 
13283
13419
  // src/mcp/rules.ts
13284
- import { basename as basename26, join as join101 } from "path";
13420
+ import { basename as basename26, join as join102 } from "path";
13285
13421
  import { z as z48 } from "zod/mini";
13286
13422
  var maxRuleSizeBytes = 1024 * 1024;
13287
13423
  var maxRulesCount = 1e3;
13288
13424
  async function listRules() {
13289
- const rulesDir = join101(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH);
13425
+ const rulesDir = join102(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH);
13290
13426
  try {
13291
13427
  const files = await listDirectoryFiles(rulesDir);
13292
13428
  const mdFiles = files.filter((file) => file.endsWith(".md"));
@@ -13299,7 +13435,7 @@ async function listRules() {
13299
13435
  });
13300
13436
  const frontmatter = rule.getFrontmatter();
13301
13437
  return {
13302
- relativePathFromCwd: join101(RULESYNC_RULES_RELATIVE_DIR_PATH, file),
13438
+ relativePathFromCwd: join102(RULESYNC_RULES_RELATIVE_DIR_PATH, file),
13303
13439
  frontmatter
13304
13440
  };
13305
13441
  } catch (error) {
@@ -13326,7 +13462,7 @@ async function getRule({ relativePathFromCwd }) {
13326
13462
  validate: true
13327
13463
  });
13328
13464
  return {
13329
- relativePathFromCwd: join101(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),
13465
+ relativePathFromCwd: join102(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),
13330
13466
  frontmatter: rule.getFrontmatter(),
13331
13467
  body: rule.getBody()
13332
13468
  };
@@ -13355,7 +13491,7 @@ async function putRule({
13355
13491
  try {
13356
13492
  const existingRules = await listRules();
13357
13493
  const isUpdate = existingRules.some(
13358
- (rule2) => rule2.relativePathFromCwd === join101(RULESYNC_RULES_RELATIVE_DIR_PATH, filename)
13494
+ (rule2) => rule2.relativePathFromCwd === join102(RULESYNC_RULES_RELATIVE_DIR_PATH, filename)
13359
13495
  );
13360
13496
  if (!isUpdate && existingRules.length >= maxRulesCount) {
13361
13497
  throw new Error(`Maximum number of rules (${maxRulesCount}) reached`);
@@ -13368,11 +13504,11 @@ async function putRule({
13368
13504
  body,
13369
13505
  validate: true
13370
13506
  });
13371
- const rulesDir = join101(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH);
13507
+ const rulesDir = join102(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH);
13372
13508
  await ensureDir(rulesDir);
13373
13509
  await writeFileContent(rule.getFilePath(), rule.getFileContent());
13374
13510
  return {
13375
- relativePathFromCwd: join101(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),
13511
+ relativePathFromCwd: join102(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),
13376
13512
  frontmatter: rule.getFrontmatter(),
13377
13513
  body: rule.getBody()
13378
13514
  };
@@ -13388,11 +13524,11 @@ async function deleteRule({ relativePathFromCwd }) {
13388
13524
  intendedRootDir: process.cwd()
13389
13525
  });
13390
13526
  const filename = basename26(relativePathFromCwd);
13391
- const fullPath = join101(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH, filename);
13527
+ const fullPath = join102(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH, filename);
13392
13528
  try {
13393
13529
  await removeFile(fullPath);
13394
13530
  return {
13395
- relativePathFromCwd: join101(RULESYNC_RULES_RELATIVE_DIR_PATH, filename)
13531
+ relativePathFromCwd: join102(RULESYNC_RULES_RELATIVE_DIR_PATH, filename)
13396
13532
  };
13397
13533
  } catch (error) {
13398
13534
  throw new Error(`Failed to delete rule file ${relativePathFromCwd}: ${formatError(error)}`, {
@@ -13417,7 +13553,7 @@ var ruleToolSchemas = {
13417
13553
  var ruleTools = {
13418
13554
  listRules: {
13419
13555
  name: "listRules",
13420
- description: `List all rules from ${join101(RULESYNC_RULES_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
13556
+ description: `List all rules from ${join102(RULESYNC_RULES_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
13421
13557
  parameters: ruleToolSchemas.listRules,
13422
13558
  execute: async () => {
13423
13559
  const rules = await listRules();
@@ -13459,7 +13595,7 @@ var ruleTools = {
13459
13595
  };
13460
13596
 
13461
13597
  // src/mcp/skills.ts
13462
- import { basename as basename27, dirname as dirname2, join as join102 } from "path";
13598
+ import { basename as basename27, dirname as dirname2, join as join103 } from "path";
13463
13599
  import { z as z49 } from "zod/mini";
13464
13600
  var maxSkillSizeBytes = 1024 * 1024;
13465
13601
  var maxSkillsCount = 1e3;
@@ -13483,9 +13619,9 @@ function extractDirName(relativeDirPathFromCwd) {
13483
13619
  return dirName;
13484
13620
  }
13485
13621
  async function listSkills() {
13486
- const skillsDir = join102(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH);
13622
+ const skillsDir = join103(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH);
13487
13623
  try {
13488
- const skillDirPaths = await findFilesByGlobs(join102(skillsDir, "*"), { type: "dir" });
13624
+ const skillDirPaths = await findFilesByGlobs(join103(skillsDir, "*"), { type: "dir" });
13489
13625
  const skills = await Promise.all(
13490
13626
  skillDirPaths.map(async (dirPath) => {
13491
13627
  const dirName = basename27(dirPath);
@@ -13496,7 +13632,7 @@ async function listSkills() {
13496
13632
  });
13497
13633
  const frontmatter = skill.getFrontmatter();
13498
13634
  return {
13499
- relativeDirPathFromCwd: join102(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
13635
+ relativeDirPathFromCwd: join103(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
13500
13636
  frontmatter
13501
13637
  };
13502
13638
  } catch (error) {
@@ -13522,7 +13658,7 @@ async function getSkill({ relativeDirPathFromCwd }) {
13522
13658
  dirName
13523
13659
  });
13524
13660
  return {
13525
- relativeDirPathFromCwd: join102(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
13661
+ relativeDirPathFromCwd: join103(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
13526
13662
  frontmatter: skill.getFrontmatter(),
13527
13663
  body: skill.getBody(),
13528
13664
  otherFiles: skill.getOtherFiles().map(aiDirFileToMcpSkillFile)
@@ -13556,7 +13692,7 @@ async function putSkill({
13556
13692
  try {
13557
13693
  const existingSkills = await listSkills();
13558
13694
  const isUpdate = existingSkills.some(
13559
- (skill2) => skill2.relativeDirPathFromCwd === join102(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName)
13695
+ (skill2) => skill2.relativeDirPathFromCwd === join103(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName)
13560
13696
  );
13561
13697
  if (!isUpdate && existingSkills.length >= maxSkillsCount) {
13562
13698
  throw new Error(`Maximum number of skills (${maxSkillsCount}) reached`);
@@ -13571,9 +13707,9 @@ async function putSkill({
13571
13707
  otherFiles: aiDirFiles,
13572
13708
  validate: true
13573
13709
  });
13574
- const skillDirPath = join102(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName);
13710
+ const skillDirPath = join103(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName);
13575
13711
  await ensureDir(skillDirPath);
13576
- const skillFilePath = join102(skillDirPath, SKILL_FILE_NAME);
13712
+ const skillFilePath = join103(skillDirPath, SKILL_FILE_NAME);
13577
13713
  const skillFileContent = stringifyFrontmatter(body, frontmatter);
13578
13714
  await writeFileContent(skillFilePath, skillFileContent);
13579
13715
  for (const file of otherFiles) {
@@ -13581,15 +13717,15 @@ async function putSkill({
13581
13717
  relativePath: file.name,
13582
13718
  intendedRootDir: skillDirPath
13583
13719
  });
13584
- const filePath = join102(skillDirPath, file.name);
13585
- const fileDir = join102(skillDirPath, dirname2(file.name));
13720
+ const filePath = join103(skillDirPath, file.name);
13721
+ const fileDir = join103(skillDirPath, dirname2(file.name));
13586
13722
  if (fileDir !== skillDirPath) {
13587
13723
  await ensureDir(fileDir);
13588
13724
  }
13589
13725
  await writeFileContent(filePath, file.body);
13590
13726
  }
13591
13727
  return {
13592
- relativeDirPathFromCwd: join102(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
13728
+ relativeDirPathFromCwd: join103(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
13593
13729
  frontmatter: skill.getFrontmatter(),
13594
13730
  body: skill.getBody(),
13595
13731
  otherFiles: skill.getOtherFiles().map(aiDirFileToMcpSkillFile)
@@ -13611,13 +13747,13 @@ async function deleteSkill({
13611
13747
  intendedRootDir: process.cwd()
13612
13748
  });
13613
13749
  const dirName = extractDirName(relativeDirPathFromCwd);
13614
- const skillDirPath = join102(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName);
13750
+ const skillDirPath = join103(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName);
13615
13751
  try {
13616
13752
  if (await directoryExists(skillDirPath)) {
13617
13753
  await removeDirectory(skillDirPath);
13618
13754
  }
13619
13755
  return {
13620
- relativeDirPathFromCwd: join102(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName)
13756
+ relativeDirPathFromCwd: join103(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName)
13621
13757
  };
13622
13758
  } catch (error) {
13623
13759
  throw new Error(
@@ -13650,7 +13786,7 @@ var skillToolSchemas = {
13650
13786
  var skillTools = {
13651
13787
  listSkills: {
13652
13788
  name: "listSkills",
13653
- description: `List all skills from ${join102(RULESYNC_SKILLS_RELATIVE_DIR_PATH, "*", SKILL_FILE_NAME)} with their frontmatter.`,
13789
+ description: `List all skills from ${join103(RULESYNC_SKILLS_RELATIVE_DIR_PATH, "*", SKILL_FILE_NAME)} with their frontmatter.`,
13654
13790
  parameters: skillToolSchemas.listSkills,
13655
13791
  execute: async () => {
13656
13792
  const skills = await listSkills();
@@ -13693,12 +13829,12 @@ var skillTools = {
13693
13829
  };
13694
13830
 
13695
13831
  // src/mcp/subagents.ts
13696
- import { basename as basename28, join as join103 } from "path";
13832
+ import { basename as basename28, join as join104 } from "path";
13697
13833
  import { z as z50 } from "zod/mini";
13698
13834
  var maxSubagentSizeBytes = 1024 * 1024;
13699
13835
  var maxSubagentsCount = 1e3;
13700
13836
  async function listSubagents() {
13701
- const subagentsDir = join103(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH);
13837
+ const subagentsDir = join104(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH);
13702
13838
  try {
13703
13839
  const files = await listDirectoryFiles(subagentsDir);
13704
13840
  const mdFiles = files.filter((file) => file.endsWith(".md"));
@@ -13711,7 +13847,7 @@ async function listSubagents() {
13711
13847
  });
13712
13848
  const frontmatter = subagent.getFrontmatter();
13713
13849
  return {
13714
- relativePathFromCwd: join103(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, file),
13850
+ relativePathFromCwd: join104(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, file),
13715
13851
  frontmatter
13716
13852
  };
13717
13853
  } catch (error) {
@@ -13740,7 +13876,7 @@ async function getSubagent({ relativePathFromCwd }) {
13740
13876
  validate: true
13741
13877
  });
13742
13878
  return {
13743
- relativePathFromCwd: join103(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),
13879
+ relativePathFromCwd: join104(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),
13744
13880
  frontmatter: subagent.getFrontmatter(),
13745
13881
  body: subagent.getBody()
13746
13882
  };
@@ -13769,7 +13905,7 @@ async function putSubagent({
13769
13905
  try {
13770
13906
  const existingSubagents = await listSubagents();
13771
13907
  const isUpdate = existingSubagents.some(
13772
- (subagent2) => subagent2.relativePathFromCwd === join103(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename)
13908
+ (subagent2) => subagent2.relativePathFromCwd === join104(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename)
13773
13909
  );
13774
13910
  if (!isUpdate && existingSubagents.length >= maxSubagentsCount) {
13775
13911
  throw new Error(`Maximum number of subagents (${maxSubagentsCount}) reached`);
@@ -13782,11 +13918,11 @@ async function putSubagent({
13782
13918
  body,
13783
13919
  validate: true
13784
13920
  });
13785
- const subagentsDir = join103(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH);
13921
+ const subagentsDir = join104(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH);
13786
13922
  await ensureDir(subagentsDir);
13787
13923
  await writeFileContent(subagent.getFilePath(), subagent.getFileContent());
13788
13924
  return {
13789
- relativePathFromCwd: join103(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),
13925
+ relativePathFromCwd: join104(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),
13790
13926
  frontmatter: subagent.getFrontmatter(),
13791
13927
  body: subagent.getBody()
13792
13928
  };
@@ -13802,11 +13938,11 @@ async function deleteSubagent({ relativePathFromCwd }) {
13802
13938
  intendedRootDir: process.cwd()
13803
13939
  });
13804
13940
  const filename = basename28(relativePathFromCwd);
13805
- const fullPath = join103(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename);
13941
+ const fullPath = join104(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename);
13806
13942
  try {
13807
13943
  await removeFile(fullPath);
13808
13944
  return {
13809
- relativePathFromCwd: join103(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename)
13945
+ relativePathFromCwd: join104(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename)
13810
13946
  };
13811
13947
  } catch (error) {
13812
13948
  throw new Error(
@@ -13834,7 +13970,7 @@ var subagentToolSchemas = {
13834
13970
  var subagentTools = {
13835
13971
  listSubagents: {
13836
13972
  name: "listSubagents",
13837
- description: `List all subagents from ${join103(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
13973
+ description: `List all subagents from ${join104(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
13838
13974
  parameters: subagentToolSchemas.listSubagents,
13839
13975
  execute: async () => {
13840
13976
  const subagents = await listSubagents();
@@ -14085,7 +14221,7 @@ async function mcpCommand({ version }) {
14085
14221
  }
14086
14222
 
14087
14223
  // src/cli/index.ts
14088
- var getVersion = () => "5.8.0";
14224
+ var getVersion = () => "5.9.1";
14089
14225
  var main = async () => {
14090
14226
  const program = new Command();
14091
14227
  const version = getVersion();