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.cjs CHANGED
@@ -116,9 +116,6 @@ var Logger = class {
116
116
  };
117
117
  var logger = new Logger();
118
118
 
119
- // src/cli/commands/generate.ts
120
- var import_es_toolkit4 = require("es-toolkit");
121
-
122
119
  // src/config/config-resolver.ts
123
120
  var import_jsonc_parser = require("jsonc-parser");
124
121
  var import_node_path2 = require("path");
@@ -490,6 +487,10 @@ function getBaseDirsInLightOfGlobal({
490
487
  return resolvedBaseDirs;
491
488
  }
492
489
 
490
+ // src/lib/generate.ts
491
+ var import_es_toolkit4 = require("es-toolkit");
492
+ var import_node_path98 = require("path");
493
+
493
494
  // src/constants/rulesync-paths.ts
494
495
  var import_node_path3 = require("path");
495
496
  var RULESYNC_CONFIG_RELATIVE_FILE_PATH = "rulesync.jsonc";
@@ -8939,7 +8940,8 @@ var import_node_path76 = require("path");
8939
8940
  var import_node_path75 = require("path");
8940
8941
  var import_mini38 = require("zod/mini");
8941
8942
  var RulesyncRuleFrontmatterSchema = import_mini38.z.object({
8942
- root: import_mini38.z.optional(import_mini38.z.optional(import_mini38.z.boolean())),
8943
+ root: import_mini38.z.optional(import_mini38.z.boolean()),
8944
+ localRoot: import_mini38.z.optional(import_mini38.z.boolean()),
8943
8945
  targets: import_mini38.z.optional(RulesyncTargetsSchema),
8944
8946
  description: import_mini38.z.optional(import_mini38.z.string()),
8945
8947
  globs: import_mini38.z.optional(import_mini38.z.array(import_mini38.z.string())),
@@ -9047,6 +9049,7 @@ var RulesyncRule = class _RulesyncRule extends RulesyncFile {
9047
9049
  }
9048
9050
  const validatedFrontmatter = {
9049
9051
  root: result.data.root ?? false,
9052
+ localRoot: result.data.localRoot ?? false,
9050
9053
  targets: result.data.targets ?? ["*"],
9051
9054
  description: result.data.description ?? "",
9052
9055
  globs: result.data.globs ?? [],
@@ -9080,6 +9083,7 @@ var RulesyncRule = class _RulesyncRule extends RulesyncFile {
9080
9083
  }
9081
9084
  const validatedFrontmatter = {
9082
9085
  root: result.data.root ?? false,
9086
+ localRoot: result.data.localRoot ?? false,
9083
9087
  targets: result.data.targets ?? ["*"],
9084
9088
  description: result.data.description ?? "",
9085
9089
  globs: result.data.globs ?? [],
@@ -11722,9 +11726,11 @@ var RulesProcessor = class extends FeatureProcessor {
11722
11726
  const rulesyncRules = rulesyncFiles.filter(
11723
11727
  (file) => file instanceof RulesyncRule
11724
11728
  );
11729
+ const localRootRules = rulesyncRules.filter((rule) => rule.getFrontmatter().localRoot);
11730
+ const nonLocalRootRules = rulesyncRules.filter((rule) => !rule.getFrontmatter().localRoot);
11725
11731
  const factory = this.getFactory(this.toolTarget);
11726
11732
  const { meta } = factory;
11727
- const toolRules = rulesyncRules.map((rulesyncRule) => {
11733
+ const toolRules = nonLocalRootRules.map((rulesyncRule) => {
11728
11734
  if (!factory.class.isTargetedByRulesyncRule(rulesyncRule)) {
11729
11735
  return null;
11730
11736
  }
@@ -11735,6 +11741,12 @@ var RulesProcessor = class extends FeatureProcessor {
11735
11741
  global: this.global
11736
11742
  });
11737
11743
  }).filter((rule) => rule !== null);
11744
+ if (localRootRules.length > 0 && !this.global) {
11745
+ const localRootRule = localRootRules[0];
11746
+ if (localRootRule && factory.class.isTargetedByRulesyncRule(localRootRule)) {
11747
+ this.handleLocalRootRule(toolRules, localRootRule, factory);
11748
+ }
11749
+ }
11738
11750
  const isSimulated = this.simulateCommands || this.simulateSubagents || this.simulateSkills;
11739
11751
  if (isSimulated && meta.createsSeparateConventionsRule && meta.additionalConventions) {
11740
11752
  const conventionsContent = this.generateAdditionalConventionsSectionFromMeta(meta);
@@ -11789,6 +11801,50 @@ var RulesProcessor = class extends FeatureProcessor {
11789
11801
  };
11790
11802
  });
11791
11803
  }
11804
+ /**
11805
+ * Handle localRoot rule generation based on tool target.
11806
+ * - Claude Code: generates `.claude/CLAUDE.local.md`
11807
+ * - Claude Code Legacy: generates `./CLAUDE.local.md`
11808
+ * - Other tools: appends content to the root file with one blank line separator
11809
+ */
11810
+ handleLocalRootRule(toolRules, localRootRule, _factory) {
11811
+ const localRootBody = localRootRule.getBody();
11812
+ if (this.toolTarget === "claudecode") {
11813
+ const paths = ClaudecodeRule.getSettablePaths({ global: this.global });
11814
+ toolRules.push(
11815
+ new ClaudecodeRule({
11816
+ baseDir: this.baseDir,
11817
+ relativeDirPath: paths.root.relativeDirPath,
11818
+ relativeFilePath: "CLAUDE.local.md",
11819
+ frontmatter: {},
11820
+ body: localRootBody,
11821
+ validate: true,
11822
+ root: true
11823
+ // Treat as root so it doesn't have frontmatter
11824
+ })
11825
+ );
11826
+ } else if (this.toolTarget === "claudecode-legacy") {
11827
+ const paths = ClaudecodeLegacyRule.getSettablePaths({ global: this.global });
11828
+ toolRules.push(
11829
+ new ClaudecodeLegacyRule({
11830
+ baseDir: this.baseDir,
11831
+ relativeDirPath: paths.root.relativeDirPath,
11832
+ relativeFilePath: "CLAUDE.local.md",
11833
+ fileContent: localRootBody,
11834
+ validate: true,
11835
+ root: true
11836
+ // Treat as root so it doesn't have frontmatter
11837
+ })
11838
+ );
11839
+ } else {
11840
+ const rootRule = toolRules.find((rule) => rule.isRoot());
11841
+ if (rootRule) {
11842
+ const currentContent = rootRule.getFileContent();
11843
+ const newContent = currentContent + "\n\n" + localRootBody;
11844
+ rootRule.setFileContent(newContent);
11845
+ }
11846
+ }
11847
+ }
11792
11848
  /**
11793
11849
  * Generate reference section based on meta configuration.
11794
11850
  */
@@ -11857,6 +11913,18 @@ var RulesProcessor = class extends FeatureProcessor {
11857
11913
  if (rootRules.length > 1) {
11858
11914
  throw new Error("Multiple root rulesync rules found");
11859
11915
  }
11916
+ if (rootRules.length === 0 && rulesyncRules.length > 0) {
11917
+ logger.warn(
11918
+ `No root rulesync rule file found. Consider adding 'root: true' to one of your rule files in ${RULESYNC_RULES_RELATIVE_DIR_PATH}.`
11919
+ );
11920
+ }
11921
+ const localRootRules = rulesyncRules.filter((rule) => rule.getFrontmatter().localRoot);
11922
+ if (localRootRules.length > 1) {
11923
+ throw new Error("Multiple localRoot rules found. Only one rule can have localRoot: true");
11924
+ }
11925
+ if (localRootRules.length > 0 && rootRules.length === 0) {
11926
+ throw new Error("localRoot: true requires a root: true rule to exist");
11927
+ }
11860
11928
  if (this.global) {
11861
11929
  const nonRootRules = rulesyncRules.filter((rule) => !rule.getFrontmatter().root);
11862
11930
  if (nonRootRules.length > 0) {
@@ -11864,6 +11932,11 @@ var RulesProcessor = class extends FeatureProcessor {
11864
11932
  `${nonRootRules.length} non-root rulesync rules found, but it's in global mode, so ignoring them`
11865
11933
  );
11866
11934
  }
11935
+ if (localRootRules.length > 0) {
11936
+ logger.warn(
11937
+ `${localRootRules.length} localRoot rules found, but localRoot is not supported in global mode, ignoring them`
11938
+ );
11939
+ }
11867
11940
  return rootRules;
11868
11941
  }
11869
11942
  return rulesyncRules;
@@ -11917,6 +11990,29 @@ var RulesProcessor = class extends FeatureProcessor {
11917
11990
  );
11918
11991
  })();
11919
11992
  logger.debug(`Found ${rootToolRules.length} root tool rule files`);
11993
+ const localRootToolRules = await (async () => {
11994
+ if (!forDeletion) {
11995
+ return [];
11996
+ }
11997
+ if (this.toolTarget !== "claudecode" && this.toolTarget !== "claudecode-legacy") {
11998
+ return [];
11999
+ }
12000
+ if (!settablePaths.root) {
12001
+ return [];
12002
+ }
12003
+ const localRootFilePaths = await findFilesByGlobs(
12004
+ (0, import_node_path97.join)(this.baseDir, settablePaths.root.relativeDirPath ?? ".", "CLAUDE.local.md")
12005
+ );
12006
+ return localRootFilePaths.map(
12007
+ (filePath) => factory.class.forDeletion({
12008
+ baseDir: this.baseDir,
12009
+ relativeDirPath: settablePaths.root?.relativeDirPath ?? ".",
12010
+ relativeFilePath: (0, import_node_path97.basename)(filePath),
12011
+ global: this.global
12012
+ })
12013
+ ).filter((rule) => rule.isDeletable());
12014
+ })();
12015
+ logger.debug(`Found ${localRootToolRules.length} local root tool rule files for deletion`);
11920
12016
  const nonRootToolRules = await (async () => {
11921
12017
  if (!settablePaths.nonRoot) {
11922
12018
  return [];
@@ -11945,7 +12041,7 @@ var RulesProcessor = class extends FeatureProcessor {
11945
12041
  );
11946
12042
  })();
11947
12043
  logger.debug(`Found ${nonRootToolRules.length} non-root tool rule files`);
11948
- return [...rootToolRules, ...nonRootToolRules];
12044
+ return [...rootToolRules, ...localRootToolRules, ...nonRootToolRules];
11949
12045
  } catch (error) {
11950
12046
  logger.error(`Failed to load tool files: ${formatError(error)}`);
11951
12047
  return [];
@@ -12065,51 +12161,34 @@ ${toonContent}`;
12065
12161
  }
12066
12162
  };
12067
12163
 
12068
- // src/cli/commands/generate.ts
12069
- async function generateCommand(options) {
12070
- const config = await ConfigResolver.resolve(options);
12071
- logger.configure({
12072
- verbose: config.getVerbose(),
12073
- silent: config.getSilent()
12074
- });
12075
- logger.info("Generating files...");
12076
- if (!await fileExists(RULESYNC_RELATIVE_DIR_PATH)) {
12077
- logger.error("\u274C .rulesync directory not found. Run 'rulesync init' first.");
12078
- process.exit(1);
12079
- }
12080
- logger.info(`Base directories: ${config.getBaseDirs().join(", ")}`);
12081
- const totalIgnoreOutputs = await generateIgnore(config);
12082
- const totalMcpOutputs = await generateMcp(config);
12083
- const totalCommandOutputs = await generateCommands(config);
12084
- const totalSubagentOutputs = await generateSubagents(config);
12085
- const skillsResult = await generateSkills(config);
12086
- const totalRulesOutputs = await generateRules(config, {
12164
+ // src/lib/generate.ts
12165
+ async function checkRulesyncDirExists(params) {
12166
+ return fileExists((0, import_node_path98.join)(params.baseDir, RULESYNC_RELATIVE_DIR_PATH));
12167
+ }
12168
+ async function generate(params) {
12169
+ const { config } = params;
12170
+ const ignoreCount = await generateIgnoreCore({ config });
12171
+ const mcpCount = await generateMcpCore({ config });
12172
+ const commandsCount = await generateCommandsCore({ config });
12173
+ const subagentsCount = await generateSubagentsCore({ config });
12174
+ const skillsResult = await generateSkillsCore({ config });
12175
+ const rulesCount = await generateRulesCore({ config, skills: skillsResult.skills });
12176
+ return {
12177
+ rulesCount,
12178
+ ignoreCount,
12179
+ mcpCount,
12180
+ commandsCount,
12181
+ subagentsCount,
12182
+ skillsCount: skillsResult.count,
12087
12183
  skills: skillsResult.skills
12088
- });
12089
- const totalGenerated = totalRulesOutputs + totalMcpOutputs + totalCommandOutputs + totalIgnoreOutputs + totalSubagentOutputs + skillsResult.totalOutputs;
12090
- if (totalGenerated === 0) {
12091
- const enabledFeatures = config.getFeatures().join(", ");
12092
- logger.warn(`\u26A0\uFE0F No files generated for enabled features: ${enabledFeatures}`);
12093
- return;
12094
- }
12095
- if (totalGenerated > 0) {
12096
- const parts = [];
12097
- if (totalRulesOutputs > 0) parts.push(`${totalRulesOutputs} rules`);
12098
- if (totalIgnoreOutputs > 0) parts.push(`${totalIgnoreOutputs} ignore files`);
12099
- if (totalMcpOutputs > 0) parts.push(`${totalMcpOutputs} MCP files`);
12100
- if (totalCommandOutputs > 0) parts.push(`${totalCommandOutputs} commands`);
12101
- if (totalSubagentOutputs > 0) parts.push(`${totalSubagentOutputs} subagents`);
12102
- if (skillsResult.totalOutputs > 0) parts.push(`${skillsResult.totalOutputs} skills`);
12103
- logger.success(`\u{1F389} All done! Generated ${totalGenerated} file(s) total (${parts.join(" + ")})`);
12104
- }
12184
+ };
12105
12185
  }
12106
- async function generateRules(config, options) {
12186
+ async function generateRulesCore(params) {
12187
+ const { config, skills } = params;
12107
12188
  if (!config.getFeatures().includes("rules")) {
12108
- logger.debug("Skipping rule generation (not in --features)");
12109
12189
  return 0;
12110
12190
  }
12111
- let totalRulesOutputs = 0;
12112
- logger.info("Generating rule files...");
12191
+ let totalCount = 0;
12113
12192
  const toolTargets = (0, import_es_toolkit4.intersection)(
12114
12193
  config.getTargets(),
12115
12194
  RulesProcessor.getToolTargets({ global: config.getGlobal() })
@@ -12123,7 +12202,7 @@ async function generateRules(config, options) {
12123
12202
  simulateCommands: config.getSimulateCommands(),
12124
12203
  simulateSubagents: config.getSimulateSubagents(),
12125
12204
  simulateSkills: config.getSimulateSkills(),
12126
- skills: options?.skills
12205
+ skills
12127
12206
  });
12128
12207
  if (config.getDelete()) {
12129
12208
  const oldToolFiles = await processor.loadToolFiles({ forDeletion: true });
@@ -12132,23 +12211,20 @@ async function generateRules(config, options) {
12132
12211
  const rulesyncFiles = await processor.loadRulesyncFiles();
12133
12212
  const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
12134
12213
  const writtenCount = await processor.writeAiFiles(toolFiles);
12135
- totalRulesOutputs += writtenCount;
12136
- logger.success(`Generated ${writtenCount} ${toolTarget} rule(s) in ${baseDir}`);
12214
+ totalCount += writtenCount;
12137
12215
  }
12138
12216
  }
12139
- return totalRulesOutputs;
12217
+ return totalCount;
12140
12218
  }
12141
- async function generateIgnore(config) {
12219
+ async function generateIgnoreCore(params) {
12220
+ const { config } = params;
12142
12221
  if (!config.getFeatures().includes("ignore")) {
12143
- logger.debug("Skipping ignore file generation (not in --features)");
12144
12222
  return 0;
12145
12223
  }
12146
12224
  if (config.getGlobal()) {
12147
- logger.debug("Skipping ignore file generation (not supported in global mode)");
12148
12225
  return 0;
12149
12226
  }
12150
- let totalIgnoreOutputs = 0;
12151
- logger.info("Generating ignore files...");
12227
+ let totalCount = 0;
12152
12228
  for (const toolTarget of (0, import_es_toolkit4.intersection)(config.getTargets(), IgnoreProcessor.getToolTargets())) {
12153
12229
  for (const baseDir of config.getBaseDirs()) {
12154
12230
  try {
@@ -12164,30 +12240,24 @@ async function generateIgnore(config) {
12164
12240
  if (rulesyncFiles.length > 0) {
12165
12241
  const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
12166
12242
  const writtenCount = await processor.writeAiFiles(toolFiles);
12167
- totalIgnoreOutputs += writtenCount;
12168
- logger.success(`Generated ${writtenCount} ${toolTarget} ignore file(s) in ${baseDir}`);
12243
+ totalCount += writtenCount;
12169
12244
  }
12170
12245
  } catch (error) {
12171
12246
  logger.warn(
12172
- `Failed to generate ${toolTarget} ignore files for ${baseDir}:`,
12173
- error instanceof Error ? error.message : String(error)
12247
+ `Failed to generate ${toolTarget} ignore files for ${baseDir}: ${formatError(error)}`
12174
12248
  );
12175
12249
  continue;
12176
12250
  }
12177
12251
  }
12178
12252
  }
12179
- return totalIgnoreOutputs;
12253
+ return totalCount;
12180
12254
  }
12181
- async function generateMcp(config) {
12255
+ async function generateMcpCore(params) {
12256
+ const { config } = params;
12182
12257
  if (!config.getFeatures().includes("mcp")) {
12183
- logger.debug("Skipping MCP configuration generation (not in --features)");
12184
12258
  return 0;
12185
12259
  }
12186
- let totalMcpOutputs = 0;
12187
- logger.info("Generating MCP files...");
12188
- if (config.getModularMcp()) {
12189
- logger.info("\u2139\uFE0F Modular MCP support is experimental.");
12190
- }
12260
+ let totalCount = 0;
12191
12261
  const toolTargets = (0, import_es_toolkit4.intersection)(
12192
12262
  config.getTargets(),
12193
12263
  McpProcessor.getToolTargets({ global: config.getGlobal() })
@@ -12207,19 +12277,17 @@ async function generateMcp(config) {
12207
12277
  const rulesyncFiles = await processor.loadRulesyncFiles();
12208
12278
  const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
12209
12279
  const writtenCount = await processor.writeAiFiles(toolFiles);
12210
- totalMcpOutputs += writtenCount;
12211
- logger.success(`Generated ${writtenCount} ${toolTarget} MCP configuration(s) in ${baseDir}`);
12280
+ totalCount += writtenCount;
12212
12281
  }
12213
12282
  }
12214
- return totalMcpOutputs;
12283
+ return totalCount;
12215
12284
  }
12216
- async function generateCommands(config) {
12285
+ async function generateCommandsCore(params) {
12286
+ const { config } = params;
12217
12287
  if (!config.getFeatures().includes("commands")) {
12218
- logger.debug("Skipping command file generation (not in --features)");
12219
12288
  return 0;
12220
12289
  }
12221
- let totalCommandOutputs = 0;
12222
- logger.info("Generating command files...");
12290
+ let totalCount = 0;
12223
12291
  const toolTargets = (0, import_es_toolkit4.intersection)(
12224
12292
  config.getTargets(),
12225
12293
  CommandsProcessor.getToolTargets({
@@ -12241,19 +12309,17 @@ async function generateCommands(config) {
12241
12309
  const rulesyncFiles = await processor.loadRulesyncFiles();
12242
12310
  const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
12243
12311
  const writtenCount = await processor.writeAiFiles(toolFiles);
12244
- totalCommandOutputs += writtenCount;
12245
- logger.success(`Generated ${writtenCount} ${toolTarget} command(s) in ${baseDir}`);
12312
+ totalCount += writtenCount;
12246
12313
  }
12247
12314
  }
12248
- return totalCommandOutputs;
12315
+ return totalCount;
12249
12316
  }
12250
- async function generateSubagents(config) {
12317
+ async function generateSubagentsCore(params) {
12318
+ const { config } = params;
12251
12319
  if (!config.getFeatures().includes("subagents")) {
12252
- logger.debug("Skipping subagent file generation (not in --features)");
12253
12320
  return 0;
12254
12321
  }
12255
- let totalSubagentOutputs = 0;
12256
- logger.info("Generating subagent files...");
12322
+ let totalCount = 0;
12257
12323
  const toolTargets = (0, import_es_toolkit4.intersection)(
12258
12324
  config.getTargets(),
12259
12325
  SubagentsProcessor.getToolTargets({
@@ -12275,20 +12341,18 @@ async function generateSubagents(config) {
12275
12341
  const rulesyncFiles = await processor.loadRulesyncFiles();
12276
12342
  const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
12277
12343
  const writtenCount = await processor.writeAiFiles(toolFiles);
12278
- totalSubagentOutputs += writtenCount;
12279
- logger.success(`Generated ${writtenCount} ${toolTarget} subagent(s) in ${baseDir}`);
12344
+ totalCount += writtenCount;
12280
12345
  }
12281
12346
  }
12282
- return totalSubagentOutputs;
12347
+ return totalCount;
12283
12348
  }
12284
- async function generateSkills(config) {
12349
+ async function generateSkillsCore(params) {
12350
+ const { config } = params;
12285
12351
  if (!config.getFeatures().includes("skills")) {
12286
- logger.debug("Skipping skill generation (not in --features)");
12287
- return { totalOutputs: 0, skills: [] };
12352
+ return { count: 0, skills: [] };
12288
12353
  }
12289
- let totalSkillOutputs = 0;
12354
+ let totalCount = 0;
12290
12355
  const allSkills = [];
12291
- logger.info("Generating skill files...");
12292
12356
  const toolTargets = (0, import_es_toolkit4.intersection)(
12293
12357
  config.getTargets(),
12294
12358
  SkillsProcessor.getToolTargets({
@@ -12315,15 +12379,84 @@ async function generateSkills(config) {
12315
12379
  }
12316
12380
  const toolDirs = await processor.convertRulesyncDirsToToolDirs(rulesyncDirs);
12317
12381
  const writtenCount = await processor.writeAiDirs(toolDirs);
12318
- totalSkillOutputs += writtenCount;
12319
- logger.success(`Generated ${writtenCount} ${toolTarget} skill(s) in ${baseDir}`);
12382
+ totalCount += writtenCount;
12320
12383
  }
12321
12384
  }
12322
- return { totalOutputs: totalSkillOutputs, skills: allSkills };
12385
+ return { count: totalCount, skills: allSkills };
12386
+ }
12387
+
12388
+ // src/cli/commands/generate.ts
12389
+ async function generateCommand(options) {
12390
+ const config = await ConfigResolver.resolve(options);
12391
+ logger.configure({
12392
+ verbose: config.getVerbose(),
12393
+ silent: config.getSilent()
12394
+ });
12395
+ logger.info("Generating files...");
12396
+ if (!await checkRulesyncDirExists({ baseDir: config.getBaseDirs()[0] ?? process.cwd() })) {
12397
+ logger.error("\u274C .rulesync directory not found. Run 'rulesync init' first.");
12398
+ process.exit(1);
12399
+ }
12400
+ logger.info(`Base directories: ${config.getBaseDirs().join(", ")}`);
12401
+ const features = config.getFeatures();
12402
+ if (features.includes("ignore")) {
12403
+ logger.info("Generating ignore files...");
12404
+ }
12405
+ if (features.includes("mcp")) {
12406
+ logger.info("Generating MCP files...");
12407
+ if (config.getModularMcp()) {
12408
+ logger.info("\u2139\uFE0F Modular MCP support is experimental.");
12409
+ }
12410
+ }
12411
+ if (features.includes("commands")) {
12412
+ logger.info("Generating command files...");
12413
+ }
12414
+ if (features.includes("subagents")) {
12415
+ logger.info("Generating subagent files...");
12416
+ }
12417
+ if (features.includes("skills")) {
12418
+ logger.info("Generating skill files...");
12419
+ }
12420
+ if (features.includes("rules")) {
12421
+ logger.info("Generating rule files...");
12422
+ }
12423
+ const result = await generate({ config });
12424
+ if (result.ignoreCount > 0) {
12425
+ logger.success(`Generated ${result.ignoreCount} ignore file(s)`);
12426
+ }
12427
+ if (result.mcpCount > 0) {
12428
+ logger.success(`Generated ${result.mcpCount} MCP configuration(s)`);
12429
+ }
12430
+ if (result.commandsCount > 0) {
12431
+ logger.success(`Generated ${result.commandsCount} command(s)`);
12432
+ }
12433
+ if (result.subagentsCount > 0) {
12434
+ logger.success(`Generated ${result.subagentsCount} subagent(s)`);
12435
+ }
12436
+ if (result.skillsCount > 0) {
12437
+ logger.success(`Generated ${result.skillsCount} skill(s)`);
12438
+ }
12439
+ if (result.rulesCount > 0) {
12440
+ logger.success(`Generated ${result.rulesCount} rule(s)`);
12441
+ }
12442
+ const totalGenerated = result.rulesCount + result.ignoreCount + result.mcpCount + result.commandsCount + result.subagentsCount + result.skillsCount;
12443
+ if (totalGenerated === 0) {
12444
+ const enabledFeatures = features.join(", ");
12445
+ logger.warn(`\u26A0\uFE0F No files generated for enabled features: ${enabledFeatures}`);
12446
+ return;
12447
+ }
12448
+ const parts = [];
12449
+ if (result.rulesCount > 0) parts.push(`${result.rulesCount} rules`);
12450
+ if (result.ignoreCount > 0) parts.push(`${result.ignoreCount} ignore files`);
12451
+ if (result.mcpCount > 0) parts.push(`${result.mcpCount} MCP files`);
12452
+ if (result.commandsCount > 0) parts.push(`${result.commandsCount} commands`);
12453
+ if (result.subagentsCount > 0) parts.push(`${result.subagentsCount} subagents`);
12454
+ if (result.skillsCount > 0) parts.push(`${result.skillsCount} skills`);
12455
+ logger.success(`\u{1F389} All done! Generated ${totalGenerated} file(s) total (${parts.join(" + ")})`);
12323
12456
  }
12324
12457
 
12325
12458
  // src/cli/commands/gitignore.ts
12326
- var import_node_path98 = require("path");
12459
+ var import_node_path99 = require("path");
12327
12460
  var RULESYNC_HEADER = "# Generated by Rulesync";
12328
12461
  var LEGACY_RULESYNC_HEADER = "# Generated by rulesync - AI tool configuration files";
12329
12462
  var RULESYNC_IGNORE_ENTRIES = [
@@ -12340,7 +12473,9 @@ var RULESYNC_IGNORE_ENTRIES = [
12340
12473
  "**/.augment-guidelines",
12341
12474
  // Claude Code
12342
12475
  "**/CLAUDE.md",
12476
+ "**/CLAUDE.local.md",
12343
12477
  "**/.claude/CLAUDE.md",
12478
+ "**/.claude/CLAUDE.local.md",
12344
12479
  "**/.claude/memories/",
12345
12480
  "**/.claude/rules/",
12346
12481
  "**/.claude/commands/",
@@ -12412,6 +12547,7 @@ var RULESYNC_IGNORE_ENTRIES = [
12412
12547
  "**/WARP.md",
12413
12548
  // Others
12414
12549
  "**/modular-mcp.json",
12550
+ ".rulesync/rules/*.local.md",
12415
12551
  "!.rulesync/.aiignore"
12416
12552
  ];
12417
12553
  var isRulesyncHeader = (line) => {
@@ -12464,7 +12600,7 @@ var removeExistingRulesyncEntries = (content) => {
12464
12600
  return result;
12465
12601
  };
12466
12602
  var gitignoreCommand = async () => {
12467
- const gitignorePath = (0, import_node_path98.join)(process.cwd(), ".gitignore");
12603
+ const gitignorePath = (0, import_node_path99.join)(process.cwd(), ".gitignore");
12468
12604
  let gitignoreContent = "";
12469
12605
  if (await fileExists(gitignorePath)) {
12470
12606
  gitignoreContent = await readFileContent(gitignorePath);
@@ -12666,7 +12802,7 @@ async function importSkills(config, tool) {
12666
12802
  }
12667
12803
 
12668
12804
  // src/cli/commands/init.ts
12669
- var import_node_path99 = require("path");
12805
+ var import_node_path100 = require("path");
12670
12806
  async function initCommand() {
12671
12807
  logger.info("Initializing rulesync...");
12672
12808
  await ensureDir(RULESYNC_RELATIVE_DIR_PATH);
@@ -12844,14 +12980,14 @@ Keep the summary concise and ready to reuse in future tasks.`
12844
12980
  await ensureDir(subagentPaths.relativeDirPath);
12845
12981
  await ensureDir(skillPaths.relativeDirPath);
12846
12982
  await ensureDir(ignorePaths.recommended.relativeDirPath);
12847
- const ruleFilepath = (0, import_node_path99.join)(rulePaths.recommended.relativeDirPath, sampleRuleFile.filename);
12983
+ const ruleFilepath = (0, import_node_path100.join)(rulePaths.recommended.relativeDirPath, sampleRuleFile.filename);
12848
12984
  if (!await fileExists(ruleFilepath)) {
12849
12985
  await writeFileContent(ruleFilepath, sampleRuleFile.content);
12850
12986
  logger.success(`Created ${ruleFilepath}`);
12851
12987
  } else {
12852
12988
  logger.info(`Skipped ${ruleFilepath} (already exists)`);
12853
12989
  }
12854
- const mcpFilepath = (0, import_node_path99.join)(
12990
+ const mcpFilepath = (0, import_node_path100.join)(
12855
12991
  mcpPaths.recommended.relativeDirPath,
12856
12992
  mcpPaths.recommended.relativeFilePath
12857
12993
  );
@@ -12861,30 +12997,30 @@ Keep the summary concise and ready to reuse in future tasks.`
12861
12997
  } else {
12862
12998
  logger.info(`Skipped ${mcpFilepath} (already exists)`);
12863
12999
  }
12864
- const commandFilepath = (0, import_node_path99.join)(commandPaths.relativeDirPath, sampleCommandFile.filename);
13000
+ const commandFilepath = (0, import_node_path100.join)(commandPaths.relativeDirPath, sampleCommandFile.filename);
12865
13001
  if (!await fileExists(commandFilepath)) {
12866
13002
  await writeFileContent(commandFilepath, sampleCommandFile.content);
12867
13003
  logger.success(`Created ${commandFilepath}`);
12868
13004
  } else {
12869
13005
  logger.info(`Skipped ${commandFilepath} (already exists)`);
12870
13006
  }
12871
- const subagentFilepath = (0, import_node_path99.join)(subagentPaths.relativeDirPath, sampleSubagentFile.filename);
13007
+ const subagentFilepath = (0, import_node_path100.join)(subagentPaths.relativeDirPath, sampleSubagentFile.filename);
12872
13008
  if (!await fileExists(subagentFilepath)) {
12873
13009
  await writeFileContent(subagentFilepath, sampleSubagentFile.content);
12874
13010
  logger.success(`Created ${subagentFilepath}`);
12875
13011
  } else {
12876
13012
  logger.info(`Skipped ${subagentFilepath} (already exists)`);
12877
13013
  }
12878
- const skillDirPath = (0, import_node_path99.join)(skillPaths.relativeDirPath, sampleSkillFile.dirName);
13014
+ const skillDirPath = (0, import_node_path100.join)(skillPaths.relativeDirPath, sampleSkillFile.dirName);
12879
13015
  await ensureDir(skillDirPath);
12880
- const skillFilepath = (0, import_node_path99.join)(skillDirPath, SKILL_FILE_NAME);
13016
+ const skillFilepath = (0, import_node_path100.join)(skillDirPath, SKILL_FILE_NAME);
12881
13017
  if (!await fileExists(skillFilepath)) {
12882
13018
  await writeFileContent(skillFilepath, sampleSkillFile.content);
12883
13019
  logger.success(`Created ${skillFilepath}`);
12884
13020
  } else {
12885
13021
  logger.info(`Skipped ${skillFilepath} (already exists)`);
12886
13022
  }
12887
- const ignoreFilepath = (0, import_node_path99.join)(
13023
+ const ignoreFilepath = (0, import_node_path100.join)(
12888
13024
  ignorePaths.recommended.relativeDirPath,
12889
13025
  ignorePaths.recommended.relativeFilePath
12890
13026
  );
@@ -12903,12 +13039,12 @@ var import_fastmcp = require("fastmcp");
12903
13039
  var import_mini51 = require("zod/mini");
12904
13040
 
12905
13041
  // src/mcp/commands.ts
12906
- var import_node_path100 = require("path");
13042
+ var import_node_path101 = require("path");
12907
13043
  var import_mini45 = require("zod/mini");
12908
13044
  var maxCommandSizeBytes = 1024 * 1024;
12909
13045
  var maxCommandsCount = 1e3;
12910
13046
  async function listCommands() {
12911
- const commandsDir = (0, import_node_path100.join)(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH);
13047
+ const commandsDir = (0, import_node_path101.join)(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH);
12912
13048
  try {
12913
13049
  const files = await listDirectoryFiles(commandsDir);
12914
13050
  const mdFiles = files.filter((file) => file.endsWith(".md"));
@@ -12920,7 +13056,7 @@ async function listCommands() {
12920
13056
  });
12921
13057
  const frontmatter = command.getFrontmatter();
12922
13058
  return {
12923
- relativePathFromCwd: (0, import_node_path100.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, file),
13059
+ relativePathFromCwd: (0, import_node_path101.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, file),
12924
13060
  frontmatter
12925
13061
  };
12926
13062
  } catch (error) {
@@ -12940,13 +13076,13 @@ async function getCommand({ relativePathFromCwd }) {
12940
13076
  relativePath: relativePathFromCwd,
12941
13077
  intendedRootDir: process.cwd()
12942
13078
  });
12943
- const filename = (0, import_node_path100.basename)(relativePathFromCwd);
13079
+ const filename = (0, import_node_path101.basename)(relativePathFromCwd);
12944
13080
  try {
12945
13081
  const command = await RulesyncCommand.fromFile({
12946
13082
  relativeFilePath: filename
12947
13083
  });
12948
13084
  return {
12949
- relativePathFromCwd: (0, import_node_path100.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),
13085
+ relativePathFromCwd: (0, import_node_path101.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),
12950
13086
  frontmatter: command.getFrontmatter(),
12951
13087
  body: command.getBody()
12952
13088
  };
@@ -12965,7 +13101,7 @@ async function putCommand({
12965
13101
  relativePath: relativePathFromCwd,
12966
13102
  intendedRootDir: process.cwd()
12967
13103
  });
12968
- const filename = (0, import_node_path100.basename)(relativePathFromCwd);
13104
+ const filename = (0, import_node_path101.basename)(relativePathFromCwd);
12969
13105
  const estimatedSize = JSON.stringify(frontmatter).length + body.length;
12970
13106
  if (estimatedSize > maxCommandSizeBytes) {
12971
13107
  throw new Error(
@@ -12975,7 +13111,7 @@ async function putCommand({
12975
13111
  try {
12976
13112
  const existingCommands = await listCommands();
12977
13113
  const isUpdate = existingCommands.some(
12978
- (command2) => command2.relativePathFromCwd === (0, import_node_path100.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename)
13114
+ (command2) => command2.relativePathFromCwd === (0, import_node_path101.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename)
12979
13115
  );
12980
13116
  if (!isUpdate && existingCommands.length >= maxCommandsCount) {
12981
13117
  throw new Error(`Maximum number of commands (${maxCommandsCount}) reached`);
@@ -12990,11 +13126,11 @@ async function putCommand({
12990
13126
  fileContent,
12991
13127
  validate: true
12992
13128
  });
12993
- const commandsDir = (0, import_node_path100.join)(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH);
13129
+ const commandsDir = (0, import_node_path101.join)(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH);
12994
13130
  await ensureDir(commandsDir);
12995
13131
  await writeFileContent(command.getFilePath(), command.getFileContent());
12996
13132
  return {
12997
- relativePathFromCwd: (0, import_node_path100.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),
13133
+ relativePathFromCwd: (0, import_node_path101.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),
12998
13134
  frontmatter: command.getFrontmatter(),
12999
13135
  body: command.getBody()
13000
13136
  };
@@ -13009,12 +13145,12 @@ async function deleteCommand({ relativePathFromCwd }) {
13009
13145
  relativePath: relativePathFromCwd,
13010
13146
  intendedRootDir: process.cwd()
13011
13147
  });
13012
- const filename = (0, import_node_path100.basename)(relativePathFromCwd);
13013
- const fullPath = (0, import_node_path100.join)(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename);
13148
+ const filename = (0, import_node_path101.basename)(relativePathFromCwd);
13149
+ const fullPath = (0, import_node_path101.join)(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename);
13014
13150
  try {
13015
13151
  await removeFile(fullPath);
13016
13152
  return {
13017
- relativePathFromCwd: (0, import_node_path100.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename)
13153
+ relativePathFromCwd: (0, import_node_path101.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename)
13018
13154
  };
13019
13155
  } catch (error) {
13020
13156
  throw new Error(`Failed to delete command file ${relativePathFromCwd}: ${formatError(error)}`, {
@@ -13039,7 +13175,7 @@ var commandToolSchemas = {
13039
13175
  var commandTools = {
13040
13176
  listCommands: {
13041
13177
  name: "listCommands",
13042
- description: `List all commands from ${(0, import_node_path100.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
13178
+ description: `List all commands from ${(0, import_node_path101.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
13043
13179
  parameters: commandToolSchemas.listCommands,
13044
13180
  execute: async () => {
13045
13181
  const commands = await listCommands();
@@ -13081,11 +13217,11 @@ var commandTools = {
13081
13217
  };
13082
13218
 
13083
13219
  // src/mcp/ignore.ts
13084
- var import_node_path101 = require("path");
13220
+ var import_node_path102 = require("path");
13085
13221
  var import_mini46 = require("zod/mini");
13086
13222
  var maxIgnoreFileSizeBytes = 100 * 1024;
13087
13223
  async function getIgnoreFile() {
13088
- const ignoreFilePath = (0, import_node_path101.join)(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);
13224
+ const ignoreFilePath = (0, import_node_path102.join)(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);
13089
13225
  try {
13090
13226
  const content = await readFileContent(ignoreFilePath);
13091
13227
  return {
@@ -13099,7 +13235,7 @@ async function getIgnoreFile() {
13099
13235
  }
13100
13236
  }
13101
13237
  async function putIgnoreFile({ content }) {
13102
- const ignoreFilePath = (0, import_node_path101.join)(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);
13238
+ const ignoreFilePath = (0, import_node_path102.join)(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);
13103
13239
  const contentSizeBytes = Buffer.byteLength(content, "utf8");
13104
13240
  if (contentSizeBytes > maxIgnoreFileSizeBytes) {
13105
13241
  throw new Error(
@@ -13120,8 +13256,8 @@ async function putIgnoreFile({ content }) {
13120
13256
  }
13121
13257
  }
13122
13258
  async function deleteIgnoreFile() {
13123
- const aiignorePath = (0, import_node_path101.join)(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);
13124
- const legacyIgnorePath = (0, import_node_path101.join)(process.cwd(), RULESYNC_IGNORE_RELATIVE_FILE_PATH);
13259
+ const aiignorePath = (0, import_node_path102.join)(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);
13260
+ const legacyIgnorePath = (0, import_node_path102.join)(process.cwd(), RULESYNC_IGNORE_RELATIVE_FILE_PATH);
13125
13261
  try {
13126
13262
  await Promise.all([removeFile(aiignorePath), removeFile(legacyIgnorePath)]);
13127
13263
  return {
@@ -13176,7 +13312,7 @@ var ignoreTools = {
13176
13312
  };
13177
13313
 
13178
13314
  // src/mcp/mcp.ts
13179
- var import_node_path102 = require("path");
13315
+ var import_node_path103 = require("path");
13180
13316
  var import_mini47 = require("zod/mini");
13181
13317
  var maxMcpSizeBytes = 1024 * 1024;
13182
13318
  async function getMcpFile() {
@@ -13186,7 +13322,7 @@ async function getMcpFile() {
13186
13322
  validate: true,
13187
13323
  modularMcp: config.getModularMcp()
13188
13324
  });
13189
- const relativePathFromCwd = (0, import_node_path102.join)(
13325
+ const relativePathFromCwd = (0, import_node_path103.join)(
13190
13326
  rulesyncMcp.getRelativeDirPath(),
13191
13327
  rulesyncMcp.getRelativeFilePath()
13192
13328
  );
@@ -13219,7 +13355,7 @@ async function putMcpFile({ content }) {
13219
13355
  const paths = RulesyncMcp.getSettablePaths();
13220
13356
  const relativeDirPath = paths.recommended.relativeDirPath;
13221
13357
  const relativeFilePath = paths.recommended.relativeFilePath;
13222
- const fullPath = (0, import_node_path102.join)(baseDir, relativeDirPath, relativeFilePath);
13358
+ const fullPath = (0, import_node_path103.join)(baseDir, relativeDirPath, relativeFilePath);
13223
13359
  const rulesyncMcp = new RulesyncMcp({
13224
13360
  baseDir,
13225
13361
  relativeDirPath,
@@ -13228,9 +13364,9 @@ async function putMcpFile({ content }) {
13228
13364
  validate: true,
13229
13365
  modularMcp: config.getModularMcp()
13230
13366
  });
13231
- await ensureDir((0, import_node_path102.join)(baseDir, relativeDirPath));
13367
+ await ensureDir((0, import_node_path103.join)(baseDir, relativeDirPath));
13232
13368
  await writeFileContent(fullPath, content);
13233
- const relativePathFromCwd = (0, import_node_path102.join)(relativeDirPath, relativeFilePath);
13369
+ const relativePathFromCwd = (0, import_node_path103.join)(relativeDirPath, relativeFilePath);
13234
13370
  return {
13235
13371
  relativePathFromCwd,
13236
13372
  content: rulesyncMcp.getFileContent()
@@ -13245,15 +13381,15 @@ async function deleteMcpFile() {
13245
13381
  try {
13246
13382
  const baseDir = process.cwd();
13247
13383
  const paths = RulesyncMcp.getSettablePaths();
13248
- const recommendedPath = (0, import_node_path102.join)(
13384
+ const recommendedPath = (0, import_node_path103.join)(
13249
13385
  baseDir,
13250
13386
  paths.recommended.relativeDirPath,
13251
13387
  paths.recommended.relativeFilePath
13252
13388
  );
13253
- const legacyPath = (0, import_node_path102.join)(baseDir, paths.legacy.relativeDirPath, paths.legacy.relativeFilePath);
13389
+ const legacyPath = (0, import_node_path103.join)(baseDir, paths.legacy.relativeDirPath, paths.legacy.relativeFilePath);
13254
13390
  await removeFile(recommendedPath);
13255
13391
  await removeFile(legacyPath);
13256
- const relativePathFromCwd = (0, import_node_path102.join)(
13392
+ const relativePathFromCwd = (0, import_node_path103.join)(
13257
13393
  paths.recommended.relativeDirPath,
13258
13394
  paths.recommended.relativeFilePath
13259
13395
  );
@@ -13304,12 +13440,12 @@ var mcpTools = {
13304
13440
  };
13305
13441
 
13306
13442
  // src/mcp/rules.ts
13307
- var import_node_path103 = require("path");
13443
+ var import_node_path104 = require("path");
13308
13444
  var import_mini48 = require("zod/mini");
13309
13445
  var maxRuleSizeBytes = 1024 * 1024;
13310
13446
  var maxRulesCount = 1e3;
13311
13447
  async function listRules() {
13312
- const rulesDir = (0, import_node_path103.join)(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH);
13448
+ const rulesDir = (0, import_node_path104.join)(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH);
13313
13449
  try {
13314
13450
  const files = await listDirectoryFiles(rulesDir);
13315
13451
  const mdFiles = files.filter((file) => file.endsWith(".md"));
@@ -13322,7 +13458,7 @@ async function listRules() {
13322
13458
  });
13323
13459
  const frontmatter = rule.getFrontmatter();
13324
13460
  return {
13325
- relativePathFromCwd: (0, import_node_path103.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, file),
13461
+ relativePathFromCwd: (0, import_node_path104.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, file),
13326
13462
  frontmatter
13327
13463
  };
13328
13464
  } catch (error) {
@@ -13342,14 +13478,14 @@ async function getRule({ relativePathFromCwd }) {
13342
13478
  relativePath: relativePathFromCwd,
13343
13479
  intendedRootDir: process.cwd()
13344
13480
  });
13345
- const filename = (0, import_node_path103.basename)(relativePathFromCwd);
13481
+ const filename = (0, import_node_path104.basename)(relativePathFromCwd);
13346
13482
  try {
13347
13483
  const rule = await RulesyncRule.fromFile({
13348
13484
  relativeFilePath: filename,
13349
13485
  validate: true
13350
13486
  });
13351
13487
  return {
13352
- relativePathFromCwd: (0, import_node_path103.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),
13488
+ relativePathFromCwd: (0, import_node_path104.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),
13353
13489
  frontmatter: rule.getFrontmatter(),
13354
13490
  body: rule.getBody()
13355
13491
  };
@@ -13368,7 +13504,7 @@ async function putRule({
13368
13504
  relativePath: relativePathFromCwd,
13369
13505
  intendedRootDir: process.cwd()
13370
13506
  });
13371
- const filename = (0, import_node_path103.basename)(relativePathFromCwd);
13507
+ const filename = (0, import_node_path104.basename)(relativePathFromCwd);
13372
13508
  const estimatedSize = JSON.stringify(frontmatter).length + body.length;
13373
13509
  if (estimatedSize > maxRuleSizeBytes) {
13374
13510
  throw new Error(
@@ -13378,7 +13514,7 @@ async function putRule({
13378
13514
  try {
13379
13515
  const existingRules = await listRules();
13380
13516
  const isUpdate = existingRules.some(
13381
- (rule2) => rule2.relativePathFromCwd === (0, import_node_path103.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, filename)
13517
+ (rule2) => rule2.relativePathFromCwd === (0, import_node_path104.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, filename)
13382
13518
  );
13383
13519
  if (!isUpdate && existingRules.length >= maxRulesCount) {
13384
13520
  throw new Error(`Maximum number of rules (${maxRulesCount}) reached`);
@@ -13391,11 +13527,11 @@ async function putRule({
13391
13527
  body,
13392
13528
  validate: true
13393
13529
  });
13394
- const rulesDir = (0, import_node_path103.join)(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH);
13530
+ const rulesDir = (0, import_node_path104.join)(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH);
13395
13531
  await ensureDir(rulesDir);
13396
13532
  await writeFileContent(rule.getFilePath(), rule.getFileContent());
13397
13533
  return {
13398
- relativePathFromCwd: (0, import_node_path103.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),
13534
+ relativePathFromCwd: (0, import_node_path104.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),
13399
13535
  frontmatter: rule.getFrontmatter(),
13400
13536
  body: rule.getBody()
13401
13537
  };
@@ -13410,12 +13546,12 @@ async function deleteRule({ relativePathFromCwd }) {
13410
13546
  relativePath: relativePathFromCwd,
13411
13547
  intendedRootDir: process.cwd()
13412
13548
  });
13413
- const filename = (0, import_node_path103.basename)(relativePathFromCwd);
13414
- const fullPath = (0, import_node_path103.join)(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH, filename);
13549
+ const filename = (0, import_node_path104.basename)(relativePathFromCwd);
13550
+ const fullPath = (0, import_node_path104.join)(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH, filename);
13415
13551
  try {
13416
13552
  await removeFile(fullPath);
13417
13553
  return {
13418
- relativePathFromCwd: (0, import_node_path103.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, filename)
13554
+ relativePathFromCwd: (0, import_node_path104.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, filename)
13419
13555
  };
13420
13556
  } catch (error) {
13421
13557
  throw new Error(`Failed to delete rule file ${relativePathFromCwd}: ${formatError(error)}`, {
@@ -13440,7 +13576,7 @@ var ruleToolSchemas = {
13440
13576
  var ruleTools = {
13441
13577
  listRules: {
13442
13578
  name: "listRules",
13443
- description: `List all rules from ${(0, import_node_path103.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
13579
+ description: `List all rules from ${(0, import_node_path104.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
13444
13580
  parameters: ruleToolSchemas.listRules,
13445
13581
  execute: async () => {
13446
13582
  const rules = await listRules();
@@ -13482,7 +13618,7 @@ var ruleTools = {
13482
13618
  };
13483
13619
 
13484
13620
  // src/mcp/skills.ts
13485
- var import_node_path104 = require("path");
13621
+ var import_node_path105 = require("path");
13486
13622
  var import_mini49 = require("zod/mini");
13487
13623
  var maxSkillSizeBytes = 1024 * 1024;
13488
13624
  var maxSkillsCount = 1e3;
@@ -13499,19 +13635,19 @@ function mcpSkillFileToAiDirFile(file) {
13499
13635
  };
13500
13636
  }
13501
13637
  function extractDirName(relativeDirPathFromCwd) {
13502
- const dirName = (0, import_node_path104.basename)(relativeDirPathFromCwd);
13638
+ const dirName = (0, import_node_path105.basename)(relativeDirPathFromCwd);
13503
13639
  if (!dirName) {
13504
13640
  throw new Error(`Invalid path: ${relativeDirPathFromCwd}`);
13505
13641
  }
13506
13642
  return dirName;
13507
13643
  }
13508
13644
  async function listSkills() {
13509
- const skillsDir = (0, import_node_path104.join)(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH);
13645
+ const skillsDir = (0, import_node_path105.join)(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH);
13510
13646
  try {
13511
- const skillDirPaths = await findFilesByGlobs((0, import_node_path104.join)(skillsDir, "*"), { type: "dir" });
13647
+ const skillDirPaths = await findFilesByGlobs((0, import_node_path105.join)(skillsDir, "*"), { type: "dir" });
13512
13648
  const skills = await Promise.all(
13513
13649
  skillDirPaths.map(async (dirPath) => {
13514
- const dirName = (0, import_node_path104.basename)(dirPath);
13650
+ const dirName = (0, import_node_path105.basename)(dirPath);
13515
13651
  if (!dirName) return null;
13516
13652
  try {
13517
13653
  const skill = await RulesyncSkill.fromDir({
@@ -13519,7 +13655,7 @@ async function listSkills() {
13519
13655
  });
13520
13656
  const frontmatter = skill.getFrontmatter();
13521
13657
  return {
13522
- relativeDirPathFromCwd: (0, import_node_path104.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
13658
+ relativeDirPathFromCwd: (0, import_node_path105.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
13523
13659
  frontmatter
13524
13660
  };
13525
13661
  } catch (error) {
@@ -13545,7 +13681,7 @@ async function getSkill({ relativeDirPathFromCwd }) {
13545
13681
  dirName
13546
13682
  });
13547
13683
  return {
13548
- relativeDirPathFromCwd: (0, import_node_path104.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
13684
+ relativeDirPathFromCwd: (0, import_node_path105.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
13549
13685
  frontmatter: skill.getFrontmatter(),
13550
13686
  body: skill.getBody(),
13551
13687
  otherFiles: skill.getOtherFiles().map(aiDirFileToMcpSkillFile)
@@ -13579,7 +13715,7 @@ async function putSkill({
13579
13715
  try {
13580
13716
  const existingSkills = await listSkills();
13581
13717
  const isUpdate = existingSkills.some(
13582
- (skill2) => skill2.relativeDirPathFromCwd === (0, import_node_path104.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName)
13718
+ (skill2) => skill2.relativeDirPathFromCwd === (0, import_node_path105.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName)
13583
13719
  );
13584
13720
  if (!isUpdate && existingSkills.length >= maxSkillsCount) {
13585
13721
  throw new Error(`Maximum number of skills (${maxSkillsCount}) reached`);
@@ -13594,9 +13730,9 @@ async function putSkill({
13594
13730
  otherFiles: aiDirFiles,
13595
13731
  validate: true
13596
13732
  });
13597
- const skillDirPath = (0, import_node_path104.join)(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName);
13733
+ const skillDirPath = (0, import_node_path105.join)(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName);
13598
13734
  await ensureDir(skillDirPath);
13599
- const skillFilePath = (0, import_node_path104.join)(skillDirPath, SKILL_FILE_NAME);
13735
+ const skillFilePath = (0, import_node_path105.join)(skillDirPath, SKILL_FILE_NAME);
13600
13736
  const skillFileContent = stringifyFrontmatter(body, frontmatter);
13601
13737
  await writeFileContent(skillFilePath, skillFileContent);
13602
13738
  for (const file of otherFiles) {
@@ -13604,15 +13740,15 @@ async function putSkill({
13604
13740
  relativePath: file.name,
13605
13741
  intendedRootDir: skillDirPath
13606
13742
  });
13607
- const filePath = (0, import_node_path104.join)(skillDirPath, file.name);
13608
- const fileDir = (0, import_node_path104.join)(skillDirPath, (0, import_node_path104.dirname)(file.name));
13743
+ const filePath = (0, import_node_path105.join)(skillDirPath, file.name);
13744
+ const fileDir = (0, import_node_path105.join)(skillDirPath, (0, import_node_path105.dirname)(file.name));
13609
13745
  if (fileDir !== skillDirPath) {
13610
13746
  await ensureDir(fileDir);
13611
13747
  }
13612
13748
  await writeFileContent(filePath, file.body);
13613
13749
  }
13614
13750
  return {
13615
- relativeDirPathFromCwd: (0, import_node_path104.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
13751
+ relativeDirPathFromCwd: (0, import_node_path105.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
13616
13752
  frontmatter: skill.getFrontmatter(),
13617
13753
  body: skill.getBody(),
13618
13754
  otherFiles: skill.getOtherFiles().map(aiDirFileToMcpSkillFile)
@@ -13634,13 +13770,13 @@ async function deleteSkill({
13634
13770
  intendedRootDir: process.cwd()
13635
13771
  });
13636
13772
  const dirName = extractDirName(relativeDirPathFromCwd);
13637
- const skillDirPath = (0, import_node_path104.join)(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName);
13773
+ const skillDirPath = (0, import_node_path105.join)(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName);
13638
13774
  try {
13639
13775
  if (await directoryExists(skillDirPath)) {
13640
13776
  await removeDirectory(skillDirPath);
13641
13777
  }
13642
13778
  return {
13643
- relativeDirPathFromCwd: (0, import_node_path104.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName)
13779
+ relativeDirPathFromCwd: (0, import_node_path105.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName)
13644
13780
  };
13645
13781
  } catch (error) {
13646
13782
  throw new Error(
@@ -13673,7 +13809,7 @@ var skillToolSchemas = {
13673
13809
  var skillTools = {
13674
13810
  listSkills: {
13675
13811
  name: "listSkills",
13676
- description: `List all skills from ${(0, import_node_path104.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, "*", SKILL_FILE_NAME)} with their frontmatter.`,
13812
+ description: `List all skills from ${(0, import_node_path105.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, "*", SKILL_FILE_NAME)} with their frontmatter.`,
13677
13813
  parameters: skillToolSchemas.listSkills,
13678
13814
  execute: async () => {
13679
13815
  const skills = await listSkills();
@@ -13716,12 +13852,12 @@ var skillTools = {
13716
13852
  };
13717
13853
 
13718
13854
  // src/mcp/subagents.ts
13719
- var import_node_path105 = require("path");
13855
+ var import_node_path106 = require("path");
13720
13856
  var import_mini50 = require("zod/mini");
13721
13857
  var maxSubagentSizeBytes = 1024 * 1024;
13722
13858
  var maxSubagentsCount = 1e3;
13723
13859
  async function listSubagents() {
13724
- const subagentsDir = (0, import_node_path105.join)(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH);
13860
+ const subagentsDir = (0, import_node_path106.join)(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH);
13725
13861
  try {
13726
13862
  const files = await listDirectoryFiles(subagentsDir);
13727
13863
  const mdFiles = files.filter((file) => file.endsWith(".md"));
@@ -13734,7 +13870,7 @@ async function listSubagents() {
13734
13870
  });
13735
13871
  const frontmatter = subagent.getFrontmatter();
13736
13872
  return {
13737
- relativePathFromCwd: (0, import_node_path105.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, file),
13873
+ relativePathFromCwd: (0, import_node_path106.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, file),
13738
13874
  frontmatter
13739
13875
  };
13740
13876
  } catch (error) {
@@ -13756,14 +13892,14 @@ async function getSubagent({ relativePathFromCwd }) {
13756
13892
  relativePath: relativePathFromCwd,
13757
13893
  intendedRootDir: process.cwd()
13758
13894
  });
13759
- const filename = (0, import_node_path105.basename)(relativePathFromCwd);
13895
+ const filename = (0, import_node_path106.basename)(relativePathFromCwd);
13760
13896
  try {
13761
13897
  const subagent = await RulesyncSubagent.fromFile({
13762
13898
  relativeFilePath: filename,
13763
13899
  validate: true
13764
13900
  });
13765
13901
  return {
13766
- relativePathFromCwd: (0, import_node_path105.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),
13902
+ relativePathFromCwd: (0, import_node_path106.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),
13767
13903
  frontmatter: subagent.getFrontmatter(),
13768
13904
  body: subagent.getBody()
13769
13905
  };
@@ -13782,7 +13918,7 @@ async function putSubagent({
13782
13918
  relativePath: relativePathFromCwd,
13783
13919
  intendedRootDir: process.cwd()
13784
13920
  });
13785
- const filename = (0, import_node_path105.basename)(relativePathFromCwd);
13921
+ const filename = (0, import_node_path106.basename)(relativePathFromCwd);
13786
13922
  const estimatedSize = JSON.stringify(frontmatter).length + body.length;
13787
13923
  if (estimatedSize > maxSubagentSizeBytes) {
13788
13924
  throw new Error(
@@ -13792,7 +13928,7 @@ async function putSubagent({
13792
13928
  try {
13793
13929
  const existingSubagents = await listSubagents();
13794
13930
  const isUpdate = existingSubagents.some(
13795
- (subagent2) => subagent2.relativePathFromCwd === (0, import_node_path105.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename)
13931
+ (subagent2) => subagent2.relativePathFromCwd === (0, import_node_path106.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename)
13796
13932
  );
13797
13933
  if (!isUpdate && existingSubagents.length >= maxSubagentsCount) {
13798
13934
  throw new Error(`Maximum number of subagents (${maxSubagentsCount}) reached`);
@@ -13805,11 +13941,11 @@ async function putSubagent({
13805
13941
  body,
13806
13942
  validate: true
13807
13943
  });
13808
- const subagentsDir = (0, import_node_path105.join)(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH);
13944
+ const subagentsDir = (0, import_node_path106.join)(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH);
13809
13945
  await ensureDir(subagentsDir);
13810
13946
  await writeFileContent(subagent.getFilePath(), subagent.getFileContent());
13811
13947
  return {
13812
- relativePathFromCwd: (0, import_node_path105.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),
13948
+ relativePathFromCwd: (0, import_node_path106.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),
13813
13949
  frontmatter: subagent.getFrontmatter(),
13814
13950
  body: subagent.getBody()
13815
13951
  };
@@ -13824,12 +13960,12 @@ async function deleteSubagent({ relativePathFromCwd }) {
13824
13960
  relativePath: relativePathFromCwd,
13825
13961
  intendedRootDir: process.cwd()
13826
13962
  });
13827
- const filename = (0, import_node_path105.basename)(relativePathFromCwd);
13828
- const fullPath = (0, import_node_path105.join)(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename);
13963
+ const filename = (0, import_node_path106.basename)(relativePathFromCwd);
13964
+ const fullPath = (0, import_node_path106.join)(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename);
13829
13965
  try {
13830
13966
  await removeFile(fullPath);
13831
13967
  return {
13832
- relativePathFromCwd: (0, import_node_path105.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename)
13968
+ relativePathFromCwd: (0, import_node_path106.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename)
13833
13969
  };
13834
13970
  } catch (error) {
13835
13971
  throw new Error(
@@ -13857,7 +13993,7 @@ var subagentToolSchemas = {
13857
13993
  var subagentTools = {
13858
13994
  listSubagents: {
13859
13995
  name: "listSubagents",
13860
- description: `List all subagents from ${(0, import_node_path105.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
13996
+ description: `List all subagents from ${(0, import_node_path106.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
13861
13997
  parameters: subagentToolSchemas.listSubagents,
13862
13998
  execute: async () => {
13863
13999
  const subagents = await listSubagents();
@@ -14108,7 +14244,7 @@ async function mcpCommand({ version }) {
14108
14244
  }
14109
14245
 
14110
14246
  // src/cli/index.ts
14111
- var getVersion = () => "5.8.0";
14247
+ var getVersion = () => "5.9.1";
14112
14248
  var main = async () => {
14113
14249
  const program = new import_commander.Command();
14114
14250
  const version = getVersion();