rulesync 5.8.0 → 5.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +1 -0
  2. package/dist/index.cjs +306 -171
  3. package/dist/index.js +295 -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/",
@@ -12464,7 +12599,7 @@ var removeExistingRulesyncEntries = (content) => {
12464
12599
  return result;
12465
12600
  };
12466
12601
  var gitignoreCommand = async () => {
12467
- const gitignorePath = (0, import_node_path98.join)(process.cwd(), ".gitignore");
12602
+ const gitignorePath = (0, import_node_path99.join)(process.cwd(), ".gitignore");
12468
12603
  let gitignoreContent = "";
12469
12604
  if (await fileExists(gitignorePath)) {
12470
12605
  gitignoreContent = await readFileContent(gitignorePath);
@@ -12666,7 +12801,7 @@ async function importSkills(config, tool) {
12666
12801
  }
12667
12802
 
12668
12803
  // src/cli/commands/init.ts
12669
- var import_node_path99 = require("path");
12804
+ var import_node_path100 = require("path");
12670
12805
  async function initCommand() {
12671
12806
  logger.info("Initializing rulesync...");
12672
12807
  await ensureDir(RULESYNC_RELATIVE_DIR_PATH);
@@ -12844,14 +12979,14 @@ Keep the summary concise and ready to reuse in future tasks.`
12844
12979
  await ensureDir(subagentPaths.relativeDirPath);
12845
12980
  await ensureDir(skillPaths.relativeDirPath);
12846
12981
  await ensureDir(ignorePaths.recommended.relativeDirPath);
12847
- const ruleFilepath = (0, import_node_path99.join)(rulePaths.recommended.relativeDirPath, sampleRuleFile.filename);
12982
+ const ruleFilepath = (0, import_node_path100.join)(rulePaths.recommended.relativeDirPath, sampleRuleFile.filename);
12848
12983
  if (!await fileExists(ruleFilepath)) {
12849
12984
  await writeFileContent(ruleFilepath, sampleRuleFile.content);
12850
12985
  logger.success(`Created ${ruleFilepath}`);
12851
12986
  } else {
12852
12987
  logger.info(`Skipped ${ruleFilepath} (already exists)`);
12853
12988
  }
12854
- const mcpFilepath = (0, import_node_path99.join)(
12989
+ const mcpFilepath = (0, import_node_path100.join)(
12855
12990
  mcpPaths.recommended.relativeDirPath,
12856
12991
  mcpPaths.recommended.relativeFilePath
12857
12992
  );
@@ -12861,30 +12996,30 @@ Keep the summary concise and ready to reuse in future tasks.`
12861
12996
  } else {
12862
12997
  logger.info(`Skipped ${mcpFilepath} (already exists)`);
12863
12998
  }
12864
- const commandFilepath = (0, import_node_path99.join)(commandPaths.relativeDirPath, sampleCommandFile.filename);
12999
+ const commandFilepath = (0, import_node_path100.join)(commandPaths.relativeDirPath, sampleCommandFile.filename);
12865
13000
  if (!await fileExists(commandFilepath)) {
12866
13001
  await writeFileContent(commandFilepath, sampleCommandFile.content);
12867
13002
  logger.success(`Created ${commandFilepath}`);
12868
13003
  } else {
12869
13004
  logger.info(`Skipped ${commandFilepath} (already exists)`);
12870
13005
  }
12871
- const subagentFilepath = (0, import_node_path99.join)(subagentPaths.relativeDirPath, sampleSubagentFile.filename);
13006
+ const subagentFilepath = (0, import_node_path100.join)(subagentPaths.relativeDirPath, sampleSubagentFile.filename);
12872
13007
  if (!await fileExists(subagentFilepath)) {
12873
13008
  await writeFileContent(subagentFilepath, sampleSubagentFile.content);
12874
13009
  logger.success(`Created ${subagentFilepath}`);
12875
13010
  } else {
12876
13011
  logger.info(`Skipped ${subagentFilepath} (already exists)`);
12877
13012
  }
12878
- const skillDirPath = (0, import_node_path99.join)(skillPaths.relativeDirPath, sampleSkillFile.dirName);
13013
+ const skillDirPath = (0, import_node_path100.join)(skillPaths.relativeDirPath, sampleSkillFile.dirName);
12879
13014
  await ensureDir(skillDirPath);
12880
- const skillFilepath = (0, import_node_path99.join)(skillDirPath, SKILL_FILE_NAME);
13015
+ const skillFilepath = (0, import_node_path100.join)(skillDirPath, SKILL_FILE_NAME);
12881
13016
  if (!await fileExists(skillFilepath)) {
12882
13017
  await writeFileContent(skillFilepath, sampleSkillFile.content);
12883
13018
  logger.success(`Created ${skillFilepath}`);
12884
13019
  } else {
12885
13020
  logger.info(`Skipped ${skillFilepath} (already exists)`);
12886
13021
  }
12887
- const ignoreFilepath = (0, import_node_path99.join)(
13022
+ const ignoreFilepath = (0, import_node_path100.join)(
12888
13023
  ignorePaths.recommended.relativeDirPath,
12889
13024
  ignorePaths.recommended.relativeFilePath
12890
13025
  );
@@ -12903,12 +13038,12 @@ var import_fastmcp = require("fastmcp");
12903
13038
  var import_mini51 = require("zod/mini");
12904
13039
 
12905
13040
  // src/mcp/commands.ts
12906
- var import_node_path100 = require("path");
13041
+ var import_node_path101 = require("path");
12907
13042
  var import_mini45 = require("zod/mini");
12908
13043
  var maxCommandSizeBytes = 1024 * 1024;
12909
13044
  var maxCommandsCount = 1e3;
12910
13045
  async function listCommands() {
12911
- const commandsDir = (0, import_node_path100.join)(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH);
13046
+ const commandsDir = (0, import_node_path101.join)(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH);
12912
13047
  try {
12913
13048
  const files = await listDirectoryFiles(commandsDir);
12914
13049
  const mdFiles = files.filter((file) => file.endsWith(".md"));
@@ -12920,7 +13055,7 @@ async function listCommands() {
12920
13055
  });
12921
13056
  const frontmatter = command.getFrontmatter();
12922
13057
  return {
12923
- relativePathFromCwd: (0, import_node_path100.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, file),
13058
+ relativePathFromCwd: (0, import_node_path101.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, file),
12924
13059
  frontmatter
12925
13060
  };
12926
13061
  } catch (error) {
@@ -12940,13 +13075,13 @@ async function getCommand({ relativePathFromCwd }) {
12940
13075
  relativePath: relativePathFromCwd,
12941
13076
  intendedRootDir: process.cwd()
12942
13077
  });
12943
- const filename = (0, import_node_path100.basename)(relativePathFromCwd);
13078
+ const filename = (0, import_node_path101.basename)(relativePathFromCwd);
12944
13079
  try {
12945
13080
  const command = await RulesyncCommand.fromFile({
12946
13081
  relativeFilePath: filename
12947
13082
  });
12948
13083
  return {
12949
- relativePathFromCwd: (0, import_node_path100.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),
13084
+ relativePathFromCwd: (0, import_node_path101.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),
12950
13085
  frontmatter: command.getFrontmatter(),
12951
13086
  body: command.getBody()
12952
13087
  };
@@ -12965,7 +13100,7 @@ async function putCommand({
12965
13100
  relativePath: relativePathFromCwd,
12966
13101
  intendedRootDir: process.cwd()
12967
13102
  });
12968
- const filename = (0, import_node_path100.basename)(relativePathFromCwd);
13103
+ const filename = (0, import_node_path101.basename)(relativePathFromCwd);
12969
13104
  const estimatedSize = JSON.stringify(frontmatter).length + body.length;
12970
13105
  if (estimatedSize > maxCommandSizeBytes) {
12971
13106
  throw new Error(
@@ -12975,7 +13110,7 @@ async function putCommand({
12975
13110
  try {
12976
13111
  const existingCommands = await listCommands();
12977
13112
  const isUpdate = existingCommands.some(
12978
- (command2) => command2.relativePathFromCwd === (0, import_node_path100.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename)
13113
+ (command2) => command2.relativePathFromCwd === (0, import_node_path101.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename)
12979
13114
  );
12980
13115
  if (!isUpdate && existingCommands.length >= maxCommandsCount) {
12981
13116
  throw new Error(`Maximum number of commands (${maxCommandsCount}) reached`);
@@ -12990,11 +13125,11 @@ async function putCommand({
12990
13125
  fileContent,
12991
13126
  validate: true
12992
13127
  });
12993
- const commandsDir = (0, import_node_path100.join)(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH);
13128
+ const commandsDir = (0, import_node_path101.join)(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH);
12994
13129
  await ensureDir(commandsDir);
12995
13130
  await writeFileContent(command.getFilePath(), command.getFileContent());
12996
13131
  return {
12997
- relativePathFromCwd: (0, import_node_path100.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),
13132
+ relativePathFromCwd: (0, import_node_path101.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),
12998
13133
  frontmatter: command.getFrontmatter(),
12999
13134
  body: command.getBody()
13000
13135
  };
@@ -13009,12 +13144,12 @@ async function deleteCommand({ relativePathFromCwd }) {
13009
13144
  relativePath: relativePathFromCwd,
13010
13145
  intendedRootDir: process.cwd()
13011
13146
  });
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);
13147
+ const filename = (0, import_node_path101.basename)(relativePathFromCwd);
13148
+ const fullPath = (0, import_node_path101.join)(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename);
13014
13149
  try {
13015
13150
  await removeFile(fullPath);
13016
13151
  return {
13017
- relativePathFromCwd: (0, import_node_path100.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename)
13152
+ relativePathFromCwd: (0, import_node_path101.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename)
13018
13153
  };
13019
13154
  } catch (error) {
13020
13155
  throw new Error(`Failed to delete command file ${relativePathFromCwd}: ${formatError(error)}`, {
@@ -13039,7 +13174,7 @@ var commandToolSchemas = {
13039
13174
  var commandTools = {
13040
13175
  listCommands: {
13041
13176
  name: "listCommands",
13042
- description: `List all commands from ${(0, import_node_path100.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
13177
+ description: `List all commands from ${(0, import_node_path101.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
13043
13178
  parameters: commandToolSchemas.listCommands,
13044
13179
  execute: async () => {
13045
13180
  const commands = await listCommands();
@@ -13081,11 +13216,11 @@ var commandTools = {
13081
13216
  };
13082
13217
 
13083
13218
  // src/mcp/ignore.ts
13084
- var import_node_path101 = require("path");
13219
+ var import_node_path102 = require("path");
13085
13220
  var import_mini46 = require("zod/mini");
13086
13221
  var maxIgnoreFileSizeBytes = 100 * 1024;
13087
13222
  async function getIgnoreFile() {
13088
- const ignoreFilePath = (0, import_node_path101.join)(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);
13223
+ const ignoreFilePath = (0, import_node_path102.join)(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);
13089
13224
  try {
13090
13225
  const content = await readFileContent(ignoreFilePath);
13091
13226
  return {
@@ -13099,7 +13234,7 @@ async function getIgnoreFile() {
13099
13234
  }
13100
13235
  }
13101
13236
  async function putIgnoreFile({ content }) {
13102
- const ignoreFilePath = (0, import_node_path101.join)(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);
13237
+ const ignoreFilePath = (0, import_node_path102.join)(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);
13103
13238
  const contentSizeBytes = Buffer.byteLength(content, "utf8");
13104
13239
  if (contentSizeBytes > maxIgnoreFileSizeBytes) {
13105
13240
  throw new Error(
@@ -13120,8 +13255,8 @@ async function putIgnoreFile({ content }) {
13120
13255
  }
13121
13256
  }
13122
13257
  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);
13258
+ const aiignorePath = (0, import_node_path102.join)(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);
13259
+ const legacyIgnorePath = (0, import_node_path102.join)(process.cwd(), RULESYNC_IGNORE_RELATIVE_FILE_PATH);
13125
13260
  try {
13126
13261
  await Promise.all([removeFile(aiignorePath), removeFile(legacyIgnorePath)]);
13127
13262
  return {
@@ -13176,7 +13311,7 @@ var ignoreTools = {
13176
13311
  };
13177
13312
 
13178
13313
  // src/mcp/mcp.ts
13179
- var import_node_path102 = require("path");
13314
+ var import_node_path103 = require("path");
13180
13315
  var import_mini47 = require("zod/mini");
13181
13316
  var maxMcpSizeBytes = 1024 * 1024;
13182
13317
  async function getMcpFile() {
@@ -13186,7 +13321,7 @@ async function getMcpFile() {
13186
13321
  validate: true,
13187
13322
  modularMcp: config.getModularMcp()
13188
13323
  });
13189
- const relativePathFromCwd = (0, import_node_path102.join)(
13324
+ const relativePathFromCwd = (0, import_node_path103.join)(
13190
13325
  rulesyncMcp.getRelativeDirPath(),
13191
13326
  rulesyncMcp.getRelativeFilePath()
13192
13327
  );
@@ -13219,7 +13354,7 @@ async function putMcpFile({ content }) {
13219
13354
  const paths = RulesyncMcp.getSettablePaths();
13220
13355
  const relativeDirPath = paths.recommended.relativeDirPath;
13221
13356
  const relativeFilePath = paths.recommended.relativeFilePath;
13222
- const fullPath = (0, import_node_path102.join)(baseDir, relativeDirPath, relativeFilePath);
13357
+ const fullPath = (0, import_node_path103.join)(baseDir, relativeDirPath, relativeFilePath);
13223
13358
  const rulesyncMcp = new RulesyncMcp({
13224
13359
  baseDir,
13225
13360
  relativeDirPath,
@@ -13228,9 +13363,9 @@ async function putMcpFile({ content }) {
13228
13363
  validate: true,
13229
13364
  modularMcp: config.getModularMcp()
13230
13365
  });
13231
- await ensureDir((0, import_node_path102.join)(baseDir, relativeDirPath));
13366
+ await ensureDir((0, import_node_path103.join)(baseDir, relativeDirPath));
13232
13367
  await writeFileContent(fullPath, content);
13233
- const relativePathFromCwd = (0, import_node_path102.join)(relativeDirPath, relativeFilePath);
13368
+ const relativePathFromCwd = (0, import_node_path103.join)(relativeDirPath, relativeFilePath);
13234
13369
  return {
13235
13370
  relativePathFromCwd,
13236
13371
  content: rulesyncMcp.getFileContent()
@@ -13245,15 +13380,15 @@ async function deleteMcpFile() {
13245
13380
  try {
13246
13381
  const baseDir = process.cwd();
13247
13382
  const paths = RulesyncMcp.getSettablePaths();
13248
- const recommendedPath = (0, import_node_path102.join)(
13383
+ const recommendedPath = (0, import_node_path103.join)(
13249
13384
  baseDir,
13250
13385
  paths.recommended.relativeDirPath,
13251
13386
  paths.recommended.relativeFilePath
13252
13387
  );
13253
- const legacyPath = (0, import_node_path102.join)(baseDir, paths.legacy.relativeDirPath, paths.legacy.relativeFilePath);
13388
+ const legacyPath = (0, import_node_path103.join)(baseDir, paths.legacy.relativeDirPath, paths.legacy.relativeFilePath);
13254
13389
  await removeFile(recommendedPath);
13255
13390
  await removeFile(legacyPath);
13256
- const relativePathFromCwd = (0, import_node_path102.join)(
13391
+ const relativePathFromCwd = (0, import_node_path103.join)(
13257
13392
  paths.recommended.relativeDirPath,
13258
13393
  paths.recommended.relativeFilePath
13259
13394
  );
@@ -13304,12 +13439,12 @@ var mcpTools = {
13304
13439
  };
13305
13440
 
13306
13441
  // src/mcp/rules.ts
13307
- var import_node_path103 = require("path");
13442
+ var import_node_path104 = require("path");
13308
13443
  var import_mini48 = require("zod/mini");
13309
13444
  var maxRuleSizeBytes = 1024 * 1024;
13310
13445
  var maxRulesCount = 1e3;
13311
13446
  async function listRules() {
13312
- const rulesDir = (0, import_node_path103.join)(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH);
13447
+ const rulesDir = (0, import_node_path104.join)(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH);
13313
13448
  try {
13314
13449
  const files = await listDirectoryFiles(rulesDir);
13315
13450
  const mdFiles = files.filter((file) => file.endsWith(".md"));
@@ -13322,7 +13457,7 @@ async function listRules() {
13322
13457
  });
13323
13458
  const frontmatter = rule.getFrontmatter();
13324
13459
  return {
13325
- relativePathFromCwd: (0, import_node_path103.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, file),
13460
+ relativePathFromCwd: (0, import_node_path104.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, file),
13326
13461
  frontmatter
13327
13462
  };
13328
13463
  } catch (error) {
@@ -13342,14 +13477,14 @@ async function getRule({ relativePathFromCwd }) {
13342
13477
  relativePath: relativePathFromCwd,
13343
13478
  intendedRootDir: process.cwd()
13344
13479
  });
13345
- const filename = (0, import_node_path103.basename)(relativePathFromCwd);
13480
+ const filename = (0, import_node_path104.basename)(relativePathFromCwd);
13346
13481
  try {
13347
13482
  const rule = await RulesyncRule.fromFile({
13348
13483
  relativeFilePath: filename,
13349
13484
  validate: true
13350
13485
  });
13351
13486
  return {
13352
- relativePathFromCwd: (0, import_node_path103.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),
13487
+ relativePathFromCwd: (0, import_node_path104.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),
13353
13488
  frontmatter: rule.getFrontmatter(),
13354
13489
  body: rule.getBody()
13355
13490
  };
@@ -13368,7 +13503,7 @@ async function putRule({
13368
13503
  relativePath: relativePathFromCwd,
13369
13504
  intendedRootDir: process.cwd()
13370
13505
  });
13371
- const filename = (0, import_node_path103.basename)(relativePathFromCwd);
13506
+ const filename = (0, import_node_path104.basename)(relativePathFromCwd);
13372
13507
  const estimatedSize = JSON.stringify(frontmatter).length + body.length;
13373
13508
  if (estimatedSize > maxRuleSizeBytes) {
13374
13509
  throw new Error(
@@ -13378,7 +13513,7 @@ async function putRule({
13378
13513
  try {
13379
13514
  const existingRules = await listRules();
13380
13515
  const isUpdate = existingRules.some(
13381
- (rule2) => rule2.relativePathFromCwd === (0, import_node_path103.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, filename)
13516
+ (rule2) => rule2.relativePathFromCwd === (0, import_node_path104.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, filename)
13382
13517
  );
13383
13518
  if (!isUpdate && existingRules.length >= maxRulesCount) {
13384
13519
  throw new Error(`Maximum number of rules (${maxRulesCount}) reached`);
@@ -13391,11 +13526,11 @@ async function putRule({
13391
13526
  body,
13392
13527
  validate: true
13393
13528
  });
13394
- const rulesDir = (0, import_node_path103.join)(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH);
13529
+ const rulesDir = (0, import_node_path104.join)(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH);
13395
13530
  await ensureDir(rulesDir);
13396
13531
  await writeFileContent(rule.getFilePath(), rule.getFileContent());
13397
13532
  return {
13398
- relativePathFromCwd: (0, import_node_path103.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),
13533
+ relativePathFromCwd: (0, import_node_path104.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),
13399
13534
  frontmatter: rule.getFrontmatter(),
13400
13535
  body: rule.getBody()
13401
13536
  };
@@ -13410,12 +13545,12 @@ async function deleteRule({ relativePathFromCwd }) {
13410
13545
  relativePath: relativePathFromCwd,
13411
13546
  intendedRootDir: process.cwd()
13412
13547
  });
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);
13548
+ const filename = (0, import_node_path104.basename)(relativePathFromCwd);
13549
+ const fullPath = (0, import_node_path104.join)(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH, filename);
13415
13550
  try {
13416
13551
  await removeFile(fullPath);
13417
13552
  return {
13418
- relativePathFromCwd: (0, import_node_path103.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, filename)
13553
+ relativePathFromCwd: (0, import_node_path104.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, filename)
13419
13554
  };
13420
13555
  } catch (error) {
13421
13556
  throw new Error(`Failed to delete rule file ${relativePathFromCwd}: ${formatError(error)}`, {
@@ -13440,7 +13575,7 @@ var ruleToolSchemas = {
13440
13575
  var ruleTools = {
13441
13576
  listRules: {
13442
13577
  name: "listRules",
13443
- description: `List all rules from ${(0, import_node_path103.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
13578
+ description: `List all rules from ${(0, import_node_path104.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
13444
13579
  parameters: ruleToolSchemas.listRules,
13445
13580
  execute: async () => {
13446
13581
  const rules = await listRules();
@@ -13482,7 +13617,7 @@ var ruleTools = {
13482
13617
  };
13483
13618
 
13484
13619
  // src/mcp/skills.ts
13485
- var import_node_path104 = require("path");
13620
+ var import_node_path105 = require("path");
13486
13621
  var import_mini49 = require("zod/mini");
13487
13622
  var maxSkillSizeBytes = 1024 * 1024;
13488
13623
  var maxSkillsCount = 1e3;
@@ -13499,19 +13634,19 @@ function mcpSkillFileToAiDirFile(file) {
13499
13634
  };
13500
13635
  }
13501
13636
  function extractDirName(relativeDirPathFromCwd) {
13502
- const dirName = (0, import_node_path104.basename)(relativeDirPathFromCwd);
13637
+ const dirName = (0, import_node_path105.basename)(relativeDirPathFromCwd);
13503
13638
  if (!dirName) {
13504
13639
  throw new Error(`Invalid path: ${relativeDirPathFromCwd}`);
13505
13640
  }
13506
13641
  return dirName;
13507
13642
  }
13508
13643
  async function listSkills() {
13509
- const skillsDir = (0, import_node_path104.join)(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH);
13644
+ const skillsDir = (0, import_node_path105.join)(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH);
13510
13645
  try {
13511
- const skillDirPaths = await findFilesByGlobs((0, import_node_path104.join)(skillsDir, "*"), { type: "dir" });
13646
+ const skillDirPaths = await findFilesByGlobs((0, import_node_path105.join)(skillsDir, "*"), { type: "dir" });
13512
13647
  const skills = await Promise.all(
13513
13648
  skillDirPaths.map(async (dirPath) => {
13514
- const dirName = (0, import_node_path104.basename)(dirPath);
13649
+ const dirName = (0, import_node_path105.basename)(dirPath);
13515
13650
  if (!dirName) return null;
13516
13651
  try {
13517
13652
  const skill = await RulesyncSkill.fromDir({
@@ -13519,7 +13654,7 @@ async function listSkills() {
13519
13654
  });
13520
13655
  const frontmatter = skill.getFrontmatter();
13521
13656
  return {
13522
- relativeDirPathFromCwd: (0, import_node_path104.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
13657
+ relativeDirPathFromCwd: (0, import_node_path105.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
13523
13658
  frontmatter
13524
13659
  };
13525
13660
  } catch (error) {
@@ -13545,7 +13680,7 @@ async function getSkill({ relativeDirPathFromCwd }) {
13545
13680
  dirName
13546
13681
  });
13547
13682
  return {
13548
- relativeDirPathFromCwd: (0, import_node_path104.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
13683
+ relativeDirPathFromCwd: (0, import_node_path105.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
13549
13684
  frontmatter: skill.getFrontmatter(),
13550
13685
  body: skill.getBody(),
13551
13686
  otherFiles: skill.getOtherFiles().map(aiDirFileToMcpSkillFile)
@@ -13579,7 +13714,7 @@ async function putSkill({
13579
13714
  try {
13580
13715
  const existingSkills = await listSkills();
13581
13716
  const isUpdate = existingSkills.some(
13582
- (skill2) => skill2.relativeDirPathFromCwd === (0, import_node_path104.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName)
13717
+ (skill2) => skill2.relativeDirPathFromCwd === (0, import_node_path105.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName)
13583
13718
  );
13584
13719
  if (!isUpdate && existingSkills.length >= maxSkillsCount) {
13585
13720
  throw new Error(`Maximum number of skills (${maxSkillsCount}) reached`);
@@ -13594,9 +13729,9 @@ async function putSkill({
13594
13729
  otherFiles: aiDirFiles,
13595
13730
  validate: true
13596
13731
  });
13597
- const skillDirPath = (0, import_node_path104.join)(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName);
13732
+ const skillDirPath = (0, import_node_path105.join)(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName);
13598
13733
  await ensureDir(skillDirPath);
13599
- const skillFilePath = (0, import_node_path104.join)(skillDirPath, SKILL_FILE_NAME);
13734
+ const skillFilePath = (0, import_node_path105.join)(skillDirPath, SKILL_FILE_NAME);
13600
13735
  const skillFileContent = stringifyFrontmatter(body, frontmatter);
13601
13736
  await writeFileContent(skillFilePath, skillFileContent);
13602
13737
  for (const file of otherFiles) {
@@ -13604,15 +13739,15 @@ async function putSkill({
13604
13739
  relativePath: file.name,
13605
13740
  intendedRootDir: skillDirPath
13606
13741
  });
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));
13742
+ const filePath = (0, import_node_path105.join)(skillDirPath, file.name);
13743
+ const fileDir = (0, import_node_path105.join)(skillDirPath, (0, import_node_path105.dirname)(file.name));
13609
13744
  if (fileDir !== skillDirPath) {
13610
13745
  await ensureDir(fileDir);
13611
13746
  }
13612
13747
  await writeFileContent(filePath, file.body);
13613
13748
  }
13614
13749
  return {
13615
- relativeDirPathFromCwd: (0, import_node_path104.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
13750
+ relativeDirPathFromCwd: (0, import_node_path105.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
13616
13751
  frontmatter: skill.getFrontmatter(),
13617
13752
  body: skill.getBody(),
13618
13753
  otherFiles: skill.getOtherFiles().map(aiDirFileToMcpSkillFile)
@@ -13634,13 +13769,13 @@ async function deleteSkill({
13634
13769
  intendedRootDir: process.cwd()
13635
13770
  });
13636
13771
  const dirName = extractDirName(relativeDirPathFromCwd);
13637
- const skillDirPath = (0, import_node_path104.join)(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName);
13772
+ const skillDirPath = (0, import_node_path105.join)(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName);
13638
13773
  try {
13639
13774
  if (await directoryExists(skillDirPath)) {
13640
13775
  await removeDirectory(skillDirPath);
13641
13776
  }
13642
13777
  return {
13643
- relativeDirPathFromCwd: (0, import_node_path104.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName)
13778
+ relativeDirPathFromCwd: (0, import_node_path105.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName)
13644
13779
  };
13645
13780
  } catch (error) {
13646
13781
  throw new Error(
@@ -13673,7 +13808,7 @@ var skillToolSchemas = {
13673
13808
  var skillTools = {
13674
13809
  listSkills: {
13675
13810
  name: "listSkills",
13676
- description: `List all skills from ${(0, import_node_path104.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, "*", SKILL_FILE_NAME)} with their frontmatter.`,
13811
+ description: `List all skills from ${(0, import_node_path105.join)(RULESYNC_SKILLS_RELATIVE_DIR_PATH, "*", SKILL_FILE_NAME)} with their frontmatter.`,
13677
13812
  parameters: skillToolSchemas.listSkills,
13678
13813
  execute: async () => {
13679
13814
  const skills = await listSkills();
@@ -13716,12 +13851,12 @@ var skillTools = {
13716
13851
  };
13717
13852
 
13718
13853
  // src/mcp/subagents.ts
13719
- var import_node_path105 = require("path");
13854
+ var import_node_path106 = require("path");
13720
13855
  var import_mini50 = require("zod/mini");
13721
13856
  var maxSubagentSizeBytes = 1024 * 1024;
13722
13857
  var maxSubagentsCount = 1e3;
13723
13858
  async function listSubagents() {
13724
- const subagentsDir = (0, import_node_path105.join)(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH);
13859
+ const subagentsDir = (0, import_node_path106.join)(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH);
13725
13860
  try {
13726
13861
  const files = await listDirectoryFiles(subagentsDir);
13727
13862
  const mdFiles = files.filter((file) => file.endsWith(".md"));
@@ -13734,7 +13869,7 @@ async function listSubagents() {
13734
13869
  });
13735
13870
  const frontmatter = subagent.getFrontmatter();
13736
13871
  return {
13737
- relativePathFromCwd: (0, import_node_path105.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, file),
13872
+ relativePathFromCwd: (0, import_node_path106.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, file),
13738
13873
  frontmatter
13739
13874
  };
13740
13875
  } catch (error) {
@@ -13756,14 +13891,14 @@ async function getSubagent({ relativePathFromCwd }) {
13756
13891
  relativePath: relativePathFromCwd,
13757
13892
  intendedRootDir: process.cwd()
13758
13893
  });
13759
- const filename = (0, import_node_path105.basename)(relativePathFromCwd);
13894
+ const filename = (0, import_node_path106.basename)(relativePathFromCwd);
13760
13895
  try {
13761
13896
  const subagent = await RulesyncSubagent.fromFile({
13762
13897
  relativeFilePath: filename,
13763
13898
  validate: true
13764
13899
  });
13765
13900
  return {
13766
- relativePathFromCwd: (0, import_node_path105.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),
13901
+ relativePathFromCwd: (0, import_node_path106.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),
13767
13902
  frontmatter: subagent.getFrontmatter(),
13768
13903
  body: subagent.getBody()
13769
13904
  };
@@ -13782,7 +13917,7 @@ async function putSubagent({
13782
13917
  relativePath: relativePathFromCwd,
13783
13918
  intendedRootDir: process.cwd()
13784
13919
  });
13785
- const filename = (0, import_node_path105.basename)(relativePathFromCwd);
13920
+ const filename = (0, import_node_path106.basename)(relativePathFromCwd);
13786
13921
  const estimatedSize = JSON.stringify(frontmatter).length + body.length;
13787
13922
  if (estimatedSize > maxSubagentSizeBytes) {
13788
13923
  throw new Error(
@@ -13792,7 +13927,7 @@ async function putSubagent({
13792
13927
  try {
13793
13928
  const existingSubagents = await listSubagents();
13794
13929
  const isUpdate = existingSubagents.some(
13795
- (subagent2) => subagent2.relativePathFromCwd === (0, import_node_path105.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename)
13930
+ (subagent2) => subagent2.relativePathFromCwd === (0, import_node_path106.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename)
13796
13931
  );
13797
13932
  if (!isUpdate && existingSubagents.length >= maxSubagentsCount) {
13798
13933
  throw new Error(`Maximum number of subagents (${maxSubagentsCount}) reached`);
@@ -13805,11 +13940,11 @@ async function putSubagent({
13805
13940
  body,
13806
13941
  validate: true
13807
13942
  });
13808
- const subagentsDir = (0, import_node_path105.join)(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH);
13943
+ const subagentsDir = (0, import_node_path106.join)(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH);
13809
13944
  await ensureDir(subagentsDir);
13810
13945
  await writeFileContent(subagent.getFilePath(), subagent.getFileContent());
13811
13946
  return {
13812
- relativePathFromCwd: (0, import_node_path105.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),
13947
+ relativePathFromCwd: (0, import_node_path106.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),
13813
13948
  frontmatter: subagent.getFrontmatter(),
13814
13949
  body: subagent.getBody()
13815
13950
  };
@@ -13824,12 +13959,12 @@ async function deleteSubagent({ relativePathFromCwd }) {
13824
13959
  relativePath: relativePathFromCwd,
13825
13960
  intendedRootDir: process.cwd()
13826
13961
  });
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);
13962
+ const filename = (0, import_node_path106.basename)(relativePathFromCwd);
13963
+ const fullPath = (0, import_node_path106.join)(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename);
13829
13964
  try {
13830
13965
  await removeFile(fullPath);
13831
13966
  return {
13832
- relativePathFromCwd: (0, import_node_path105.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename)
13967
+ relativePathFromCwd: (0, import_node_path106.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename)
13833
13968
  };
13834
13969
  } catch (error) {
13835
13970
  throw new Error(
@@ -13857,7 +13992,7 @@ var subagentToolSchemas = {
13857
13992
  var subagentTools = {
13858
13993
  listSubagents: {
13859
13994
  name: "listSubagents",
13860
- description: `List all subagents from ${(0, import_node_path105.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
13995
+ description: `List all subagents from ${(0, import_node_path106.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
13861
13996
  parameters: subagentToolSchemas.listSubagents,
13862
13997
  execute: async () => {
13863
13998
  const subagents = await listSubagents();
@@ -14108,7 +14243,7 @@ async function mcpCommand({ version }) {
14108
14243
  }
14109
14244
 
14110
14245
  // src/cli/index.ts
14111
- var getVersion = () => "5.8.0";
14246
+ var getVersion = () => "5.9.0";
14112
14247
  var main = async () => {
14113
14248
  const program = new import_commander.Command();
14114
14249
  const version = getVersion();