rulesync 5.9.1 → 6.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -272,6 +272,30 @@ Example:
272
272
  }
273
273
  ```
274
274
 
275
+ ### Local Configuration
276
+
277
+ Rulesync supports a local configuration file (`rulesync.local.jsonc`) for machine-specific or developer-specific settings. This file is automatically added to `.gitignore` by `rulesync gitignore` and should not be committed to the repository.
278
+
279
+ **Configuration Priority** (highest to lowest):
280
+
281
+ 1. CLI options
282
+ 2. `rulesync.local.jsonc`
283
+ 3. `rulesync.jsonc`
284
+ 4. Default values
285
+
286
+ Example usage:
287
+
288
+ ```jsonc
289
+ // rulesync.local.jsonc (not committed to git)
290
+ {
291
+ "$schema": "https://raw.githubusercontent.com/dyoshikawa/rulesync/refs/heads/main/config-schema.json",
292
+ // Override targets for local development
293
+ "targets": ["claudecode"],
294
+ // Enable verbose output for debugging
295
+ "verbose": true,
296
+ }
297
+ ```
298
+
275
299
  ### Target Order and File Conflicts
276
300
 
277
301
  When multiple targets write to the same output file, **the last target in the array wins**. This is the "last-wins" behavior.
package/dist/index.cjs CHANGED
@@ -118,14 +118,29 @@ var logger = new Logger();
118
118
 
119
119
  // src/config/config-resolver.ts
120
120
  var import_jsonc_parser = require("jsonc-parser");
121
- var import_node_path2 = require("path");
121
+ var import_node_path3 = require("path");
122
+
123
+ // src/constants/rulesync-paths.ts
124
+ var import_node_path = require("path");
125
+ var RULESYNC_CONFIG_RELATIVE_FILE_PATH = "rulesync.jsonc";
126
+ var RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH = "rulesync.local.jsonc";
127
+ var RULESYNC_RELATIVE_DIR_PATH = ".rulesync";
128
+ var RULESYNC_RULES_RELATIVE_DIR_PATH = (0, import_node_path.join)(RULESYNC_RELATIVE_DIR_PATH, "rules");
129
+ var RULESYNC_COMMANDS_RELATIVE_DIR_PATH = (0, import_node_path.join)(RULESYNC_RELATIVE_DIR_PATH, "commands");
130
+ var RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH = (0, import_node_path.join)(RULESYNC_RELATIVE_DIR_PATH, "subagents");
131
+ var RULESYNC_MCP_RELATIVE_FILE_PATH = (0, import_node_path.join)(RULESYNC_RELATIVE_DIR_PATH, "mcp.json");
132
+ var RULESYNC_AIIGNORE_FILE_NAME = ".aiignore";
133
+ var RULESYNC_AIIGNORE_RELATIVE_FILE_PATH = (0, import_node_path.join)(RULESYNC_RELATIVE_DIR_PATH, ".aiignore");
134
+ var RULESYNC_IGNORE_RELATIVE_FILE_PATH = ".rulesyncignore";
135
+ var RULESYNC_OVERVIEW_FILE_NAME = "overview.md";
136
+ var RULESYNC_SKILLS_RELATIVE_DIR_PATH = (0, import_node_path.join)(RULESYNC_RELATIVE_DIR_PATH, "skills");
122
137
 
123
138
  // src/utils/file.ts
124
139
  var import_es_toolkit = require("es-toolkit");
125
140
  var import_globby = require("globby");
126
141
  var import_promises = require("fs/promises");
127
142
  var import_node_os = __toESM(require("os"), 1);
128
- var import_node_path = require("path");
143
+ var import_node_path2 = require("path");
129
144
  async function ensureDir(dirPath) {
130
145
  try {
131
146
  await (0, import_promises.stat)(dirPath);
@@ -137,7 +152,7 @@ async function readOrInitializeFileContent(filePath, initialContent = "") {
137
152
  if (await fileExists(filePath)) {
138
153
  return await readFileContent(filePath);
139
154
  } else {
140
- await ensureDir((0, import_node_path.dirname)(filePath));
155
+ await ensureDir((0, import_node_path2.dirname)(filePath));
141
156
  await writeFileContent(filePath, initialContent);
142
157
  return initialContent;
143
158
  }
@@ -150,16 +165,16 @@ function checkPathTraversal({
150
165
  if (segments.includes("..")) {
151
166
  throw new Error(`Path traversal detected: ${relativePath}`);
152
167
  }
153
- const resolved = (0, import_node_path.resolve)(intendedRootDir, relativePath);
154
- const rel = (0, import_node_path.relative)(intendedRootDir, resolved);
155
- if (rel.startsWith("..") || (0, import_node_path.resolve)(resolved) !== resolved) {
168
+ const resolved = (0, import_node_path2.resolve)(intendedRootDir, relativePath);
169
+ const rel = (0, import_node_path2.relative)(intendedRootDir, resolved);
170
+ if (rel.startsWith("..") || (0, import_node_path2.resolve)(resolved) !== resolved) {
156
171
  throw new Error(`Path traversal detected: ${relativePath}`);
157
172
  }
158
173
  }
159
174
  function resolvePath(relativePath, baseDir) {
160
175
  if (!baseDir) return relativePath;
161
176
  checkPathTraversal({ relativePath, intendedRootDir: baseDir });
162
- return (0, import_node_path.resolve)(baseDir, relativePath);
177
+ return (0, import_node_path2.resolve)(baseDir, relativePath);
163
178
  }
164
179
  async function directoryExists(dirPath) {
165
180
  try {
@@ -185,7 +200,7 @@ function addTrailingNewline(content) {
185
200
  }
186
201
  async function writeFileContent(filepath, content) {
187
202
  logger.debug(`Writing file: ${filepath}`);
188
- await ensureDir((0, import_node_path.dirname)(filepath));
203
+ await ensureDir((0, import_node_path2.dirname)(filepath));
189
204
  await (0, import_promises.writeFile)(filepath, content, "utf-8");
190
205
  }
191
206
  async function fileExists(filepath) {
@@ -413,7 +428,7 @@ var getDefaults = () => ({
413
428
  verbose: false,
414
429
  delete: false,
415
430
  baseDirs: [process.cwd()],
416
- configPath: "rulesync.jsonc",
431
+ configPath: RULESYNC_CONFIG_RELATIVE_FILE_PATH,
417
432
  global: false,
418
433
  silent: false,
419
434
  simulateCommands: false,
@@ -421,6 +436,36 @@ var getDefaults = () => ({
421
436
  simulateSkills: false,
422
437
  modularMcp: false
423
438
  });
439
+ var loadConfigFromFile = async (filePath) => {
440
+ if (!await fileExists(filePath)) {
441
+ return {};
442
+ }
443
+ try {
444
+ const fileContent = await readFileContent(filePath);
445
+ const jsonData = (0, import_jsonc_parser.parse)(fileContent);
446
+ const parsed = ConfigFileSchema.parse(jsonData);
447
+ const { $schema: _schema, ...configParams } = parsed;
448
+ return configParams;
449
+ } catch (error) {
450
+ logger.error(`Failed to load config file "${filePath}": ${formatError(error)}`);
451
+ throw error;
452
+ }
453
+ };
454
+ var mergeConfigs = (baseConfig, localConfig) => {
455
+ return {
456
+ targets: localConfig.targets ?? baseConfig.targets,
457
+ features: localConfig.features ?? baseConfig.features,
458
+ verbose: localConfig.verbose ?? baseConfig.verbose,
459
+ delete: localConfig.delete ?? baseConfig.delete,
460
+ baseDirs: localConfig.baseDirs ?? baseConfig.baseDirs,
461
+ global: localConfig.global ?? baseConfig.global,
462
+ silent: localConfig.silent ?? baseConfig.silent,
463
+ simulateCommands: localConfig.simulateCommands ?? baseConfig.simulateCommands,
464
+ simulateSubagents: localConfig.simulateSubagents ?? baseConfig.simulateSubagents,
465
+ simulateSkills: localConfig.simulateSkills ?? baseConfig.simulateSkills,
466
+ modularMcp: localConfig.modularMcp ?? baseConfig.modularMcp
467
+ };
468
+ };
424
469
  var ConfigResolver = class {
425
470
  static async resolve({
426
471
  targets,
@@ -437,19 +482,11 @@ var ConfigResolver = class {
437
482
  modularMcp
438
483
  }) {
439
484
  const validatedConfigPath = resolvePath(configPath, process.cwd());
440
- let configByFile = {};
441
- if (await fileExists(validatedConfigPath)) {
442
- try {
443
- const fileContent = await readFileContent(validatedConfigPath);
444
- const jsonData = (0, import_jsonc_parser.parse)(fileContent);
445
- const parsed = ConfigFileSchema.parse(jsonData);
446
- const { $schema: _schema, ...configParams2 } = parsed;
447
- configByFile = configParams2;
448
- } catch (error) {
449
- logger.error(`Failed to load config file: ${formatError(error)}`);
450
- throw error;
451
- }
452
- }
485
+ const baseConfig = await loadConfigFromFile(validatedConfigPath);
486
+ const configDir = (0, import_node_path3.dirname)(validatedConfigPath);
487
+ const localConfigPath = (0, import_node_path3.join)(configDir, RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH);
488
+ const localConfig = await loadConfigFromFile(localConfigPath);
489
+ const configByFile = mergeConfigs(baseConfig, localConfig);
453
490
  const resolvedGlobal = global ?? configByFile.global ?? getDefaults().global;
454
491
  const resolvedSimulateCommands = simulateCommands ?? configByFile.simulateCommands ?? getDefaults().simulateCommands;
455
492
  const resolvedSimulateSubagents = simulateSubagents ?? configByFile.simulateSubagents ?? getDefaults().simulateSubagents;
@@ -480,7 +517,7 @@ function getBaseDirsInLightOfGlobal({
480
517
  if (global) {
481
518
  return [getHomeDirectory()];
482
519
  }
483
- const resolvedBaseDirs = baseDirs.map((baseDir) => (0, import_node_path2.resolve)(baseDir));
520
+ const resolvedBaseDirs = baseDirs.map((baseDir) => (0, import_node_path3.resolve)(baseDir));
484
521
  resolvedBaseDirs.forEach((baseDir) => {
485
522
  validateBaseDir(baseDir);
486
523
  });
@@ -491,20 +528,6 @@ function getBaseDirsInLightOfGlobal({
491
528
  var import_es_toolkit4 = require("es-toolkit");
492
529
  var import_node_path98 = require("path");
493
530
 
494
- // src/constants/rulesync-paths.ts
495
- var import_node_path3 = require("path");
496
- var RULESYNC_CONFIG_RELATIVE_FILE_PATH = "rulesync.jsonc";
497
- var RULESYNC_RELATIVE_DIR_PATH = ".rulesync";
498
- var RULESYNC_RULES_RELATIVE_DIR_PATH = (0, import_node_path3.join)(RULESYNC_RELATIVE_DIR_PATH, "rules");
499
- var RULESYNC_COMMANDS_RELATIVE_DIR_PATH = (0, import_node_path3.join)(RULESYNC_RELATIVE_DIR_PATH, "commands");
500
- var RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH = (0, import_node_path3.join)(RULESYNC_RELATIVE_DIR_PATH, "subagents");
501
- var RULESYNC_MCP_RELATIVE_FILE_PATH = (0, import_node_path3.join)(RULESYNC_RELATIVE_DIR_PATH, "mcp.json");
502
- var RULESYNC_AIIGNORE_FILE_NAME = ".aiignore";
503
- var RULESYNC_AIIGNORE_RELATIVE_FILE_PATH = (0, import_node_path3.join)(RULESYNC_RELATIVE_DIR_PATH, ".aiignore");
504
- var RULESYNC_IGNORE_RELATIVE_FILE_PATH = ".rulesyncignore";
505
- var RULESYNC_OVERVIEW_FILE_NAME = "overview.md";
506
- var RULESYNC_SKILLS_RELATIVE_DIR_PATH = (0, import_node_path3.join)(RULESYNC_RELATIVE_DIR_PATH, "skills");
507
-
508
531
  // src/features/commands/commands-processor.ts
509
532
  var import_node_path19 = require("path");
510
533
  var import_mini12 = require("zod/mini");
@@ -938,9 +961,6 @@ var RulesyncFile = class extends AiFile {
938
961
  static async fromFile(_params) {
939
962
  throw new Error("Please implement this method in the subclass.");
940
963
  }
941
- static async fromFileLegacy(_params) {
942
- throw new Error("Please implement this method in the subclass.");
943
- }
944
964
  };
945
965
 
946
966
  // src/features/commands/rulesync-command.ts
@@ -4321,6 +4341,46 @@ var CopilotMcp = class _CopilotMcp extends ToolMcp {
4321
4341
 
4322
4342
  // src/features/mcp/cursor-mcp.ts
4323
4343
  var import_node_path39 = require("path");
4344
+ var CURSOR_ENV_VAR_PATTERN = /\$\{env:([^}]+)\}/g;
4345
+ function isMcpServers(value) {
4346
+ return value !== void 0 && value !== null && typeof value === "object";
4347
+ }
4348
+ function convertEnvFromCursorFormat(mcpServers) {
4349
+ return Object.fromEntries(
4350
+ Object.entries(mcpServers).map(([name, config]) => [
4351
+ name,
4352
+ {
4353
+ ...config,
4354
+ ...config.env && {
4355
+ env: Object.fromEntries(
4356
+ Object.entries(config.env).map(([k, v]) => [
4357
+ k,
4358
+ v.replace(CURSOR_ENV_VAR_PATTERN, "${$1}")
4359
+ ])
4360
+ )
4361
+ }
4362
+ }
4363
+ ])
4364
+ );
4365
+ }
4366
+ function convertEnvToCursorFormat(mcpServers) {
4367
+ return Object.fromEntries(
4368
+ Object.entries(mcpServers).map(([name, config]) => [
4369
+ name,
4370
+ {
4371
+ ...config,
4372
+ ...config.env && {
4373
+ env: Object.fromEntries(
4374
+ Object.entries(config.env).map(([k, v]) => [
4375
+ k,
4376
+ v.replace(/\$\{(?!env:)([^}:]+)\}/g, "${env:$1}")
4377
+ ])
4378
+ )
4379
+ }
4380
+ }
4381
+ ])
4382
+ );
4383
+ }
4324
4384
  var CursorMcp = class _CursorMcp extends ToolMcp {
4325
4385
  json;
4326
4386
  constructor(params) {
@@ -4361,8 +4421,10 @@ var CursorMcp = class _CursorMcp extends ToolMcp {
4361
4421
  validate = true
4362
4422
  }) {
4363
4423
  const json = rulesyncMcp.getJson();
4424
+ const mcpServers = isMcpServers(json.mcpServers) ? json.mcpServers : {};
4425
+ const transformedServers = convertEnvToCursorFormat(mcpServers);
4364
4426
  const cursorConfig = {
4365
- mcpServers: json.mcpServers || {}
4427
+ mcpServers: transformedServers
4366
4428
  };
4367
4429
  const fileContent = JSON.stringify(cursorConfig, null, 2);
4368
4430
  return new _CursorMcp({
@@ -4374,11 +4436,17 @@ var CursorMcp = class _CursorMcp extends ToolMcp {
4374
4436
  });
4375
4437
  }
4376
4438
  toRulesyncMcp() {
4439
+ const mcpServers = isMcpServers(this.json.mcpServers) ? this.json.mcpServers : {};
4440
+ const transformedServers = convertEnvFromCursorFormat(mcpServers);
4441
+ const transformedJson = {
4442
+ ...this.json,
4443
+ mcpServers: transformedServers
4444
+ };
4377
4445
  return new RulesyncMcp({
4378
4446
  baseDir: this.baseDir,
4379
4447
  relativeDirPath: this.relativeDirPath,
4380
4448
  relativeFilePath: "rulesync.mcp.json",
4381
- fileContent: this.fileContent,
4449
+ fileContent: JSON.stringify(transformedJson),
4382
4450
  validate: true
4383
4451
  });
4384
4452
  }
@@ -9025,47 +9093,6 @@ var RulesyncRule = class _RulesyncRule extends RulesyncFile {
9025
9093
  };
9026
9094
  }
9027
9095
  }
9028
- static async fromFileLegacy({
9029
- relativeFilePath,
9030
- validate = true
9031
- }) {
9032
- const legacyPath = (0, import_node_path75.join)(
9033
- process.cwd(),
9034
- this.getSettablePaths().legacy.relativeDirPath,
9035
- relativeFilePath
9036
- );
9037
- const recommendedPath = (0, import_node_path75.join)(
9038
- this.getSettablePaths().recommended.relativeDirPath,
9039
- relativeFilePath
9040
- );
9041
- logger.warn(
9042
- `\u26A0\uFE0F Using deprecated path "${legacyPath}". Please migrate to "${recommendedPath}"`
9043
- );
9044
- const fileContent = await readFileContent(legacyPath);
9045
- const { frontmatter, body: content } = parseFrontmatter(fileContent);
9046
- const result = RulesyncRuleFrontmatterSchema.safeParse(frontmatter);
9047
- if (!result.success) {
9048
- throw new Error(`Invalid frontmatter in ${legacyPath}: ${formatError(result.error)}`);
9049
- }
9050
- const validatedFrontmatter = {
9051
- root: result.data.root ?? false,
9052
- localRoot: result.data.localRoot ?? false,
9053
- targets: result.data.targets ?? ["*"],
9054
- description: result.data.description ?? "",
9055
- globs: result.data.globs ?? [],
9056
- agentsmd: result.data.agentsmd,
9057
- cursor: result.data.cursor
9058
- };
9059
- const filename = (0, import_node_path75.basename)(legacyPath);
9060
- return new _RulesyncRule({
9061
- baseDir: process.cwd(),
9062
- relativeDirPath: this.getSettablePaths().recommended.relativeDirPath,
9063
- relativeFilePath: filename,
9064
- frontmatter: validatedFrontmatter,
9065
- body: content.trim(),
9066
- validate
9067
- });
9068
- }
9069
9096
  static async fromFile({
9070
9097
  relativeFilePath,
9071
9098
  validate = true
@@ -9090,11 +9117,10 @@ var RulesyncRule = class _RulesyncRule extends RulesyncFile {
9090
9117
  agentsmd: result.data.agentsmd,
9091
9118
  cursor: result.data.cursor
9092
9119
  };
9093
- const filename = (0, import_node_path75.basename)(filePath);
9094
9120
  return new _RulesyncRule({
9095
9121
  baseDir: process.cwd(),
9096
9122
  relativeDirPath: this.getSettablePaths().recommended.relativeDirPath,
9097
- relativeFilePath: filename,
9123
+ relativeFilePath,
9098
9124
  frontmatter: validatedFrontmatter,
9099
9125
  body: content.trim(),
9100
9126
  validate
@@ -9927,7 +9953,7 @@ var ClaudecodeRule = class _ClaudecodeRule extends ToolRule {
9927
9953
  }
9928
9954
  return {
9929
9955
  root: {
9930
- relativeDirPath: ".claude",
9956
+ relativeDirPath: ".",
9931
9957
  relativeFilePath: "CLAUDE.md"
9932
9958
  },
9933
9959
  nonRoot: {
@@ -10634,7 +10660,7 @@ var CursorRule = class _CursorRule extends ToolRule {
10634
10660
  return new _CursorRule({
10635
10661
  baseDir,
10636
10662
  relativeDirPath: this.getSettablePaths().nonRoot.relativeDirPath,
10637
- relativeFilePath: (0, import_node_path86.basename)(relativeFilePath),
10663
+ relativeFilePath,
10638
10664
  frontmatter: result.data,
10639
10665
  body: content.trim(),
10640
10666
  validate
@@ -11803,7 +11829,7 @@ var RulesProcessor = class extends FeatureProcessor {
11803
11829
  }
11804
11830
  /**
11805
11831
  * Handle localRoot rule generation based on tool target.
11806
- * - Claude Code: generates `.claude/CLAUDE.local.md`
11832
+ * - Claude Code: generates `./CLAUDE.local.md`
11807
11833
  * - Claude Code Legacy: generates `./CLAUDE.local.md`
11808
11834
  * - Other tools: appends content to the root file with one blank line separator
11809
11835
  */
@@ -11904,10 +11930,17 @@ var RulesProcessor = class extends FeatureProcessor {
11904
11930
  * Load and parse rulesync rule files from .rulesync/rules/ directory
11905
11931
  */
11906
11932
  async loadRulesyncFiles() {
11907
- const files = await findFilesByGlobs((0, import_node_path97.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, "*.md"));
11933
+ const rulesyncBaseDir = (0, import_node_path97.join)(this.baseDir, RULESYNC_RULES_RELATIVE_DIR_PATH);
11934
+ const files = await findFilesByGlobs((0, import_node_path97.join)(rulesyncBaseDir, "**", "*.md"));
11908
11935
  logger.debug(`Found ${files.length} rulesync files`);
11909
11936
  const rulesyncRules = await Promise.all(
11910
- files.map((file) => RulesyncRule.fromFile({ relativeFilePath: (0, import_node_path97.basename)(file) }))
11937
+ files.map((file) => {
11938
+ const relativeFilePath = (0, import_node_path97.relative)(rulesyncBaseDir, file);
11939
+ checkPathTraversal({ relativePath: relativeFilePath, intendedRootDir: rulesyncBaseDir });
11940
+ return RulesyncRule.fromFile({
11941
+ relativeFilePath
11942
+ });
11943
+ })
11911
11944
  );
11912
11945
  const rootRules = rulesyncRules.filter((rule) => rule.getFrontmatter().root);
11913
11946
  if (rootRules.length > 1) {
@@ -11941,13 +11974,6 @@ var RulesProcessor = class extends FeatureProcessor {
11941
11974
  }
11942
11975
  return rulesyncRules;
11943
11976
  }
11944
- async loadRulesyncFilesLegacy() {
11945
- const legacyFiles = await findFilesByGlobs((0, import_node_path97.join)(RULESYNC_RELATIVE_DIR_PATH, "*.md"));
11946
- logger.debug(`Found ${legacyFiles.length} legacy rulesync files`);
11947
- return Promise.all(
11948
- legacyFiles.map((file) => RulesyncRule.fromFileLegacy({ relativeFilePath: (0, import_node_path97.basename)(file) }))
11949
- );
11950
- }
11951
11977
  /**
11952
11978
  * Implementation of abstract method from FeatureProcessor
11953
11979
  * Load tool-specific rule configurations and parse them into ToolRule instances
@@ -12017,27 +12043,35 @@ var RulesProcessor = class extends FeatureProcessor {
12017
12043
  if (!settablePaths.nonRoot) {
12018
12044
  return [];
12019
12045
  }
12046
+ const nonRootBaseDir = (0, import_node_path97.join)(this.baseDir, settablePaths.nonRoot.relativeDirPath);
12020
12047
  const nonRootFilePaths = await findFilesByGlobs(
12021
- (0, import_node_path97.join)(this.baseDir, settablePaths.nonRoot.relativeDirPath, `*.${factory.meta.extension}`)
12048
+ (0, import_node_path97.join)(nonRootBaseDir, "**", `*.${factory.meta.extension}`)
12022
12049
  );
12023
12050
  if (forDeletion) {
12024
- return nonRootFilePaths.map(
12025
- (filePath) => factory.class.forDeletion({
12051
+ return nonRootFilePaths.map((filePath) => {
12052
+ const relativeFilePath = (0, import_node_path97.relative)(nonRootBaseDir, filePath);
12053
+ checkPathTraversal({
12054
+ relativePath: relativeFilePath,
12055
+ intendedRootDir: nonRootBaseDir
12056
+ });
12057
+ return factory.class.forDeletion({
12026
12058
  baseDir: this.baseDir,
12027
12059
  relativeDirPath: settablePaths.nonRoot?.relativeDirPath ?? ".",
12028
- relativeFilePath: (0, import_node_path97.basename)(filePath),
12060
+ relativeFilePath,
12029
12061
  global: this.global
12030
- })
12031
- ).filter((rule) => rule.isDeletable());
12062
+ });
12063
+ }).filter((rule) => rule.isDeletable());
12032
12064
  }
12033
12065
  return await Promise.all(
12034
- nonRootFilePaths.map(
12035
- (filePath) => factory.class.fromFile({
12066
+ nonRootFilePaths.map((filePath) => {
12067
+ const relativeFilePath = (0, import_node_path97.relative)(nonRootBaseDir, filePath);
12068
+ checkPathTraversal({ relativePath: relativeFilePath, intendedRootDir: nonRootBaseDir });
12069
+ return factory.class.fromFile({
12036
12070
  baseDir: this.baseDir,
12037
- relativeFilePath: (0, import_node_path97.basename)(filePath),
12071
+ relativeFilePath,
12038
12072
  global: this.global
12039
- })
12040
- )
12073
+ });
12074
+ })
12041
12075
  );
12042
12076
  })();
12043
12077
  logger.debug(`Found ${nonRootToolRules.length} non-root tool rule files`);
@@ -12548,6 +12582,7 @@ var RULESYNC_IGNORE_ENTRIES = [
12548
12582
  // Others
12549
12583
  "**/modular-mcp.json",
12550
12584
  ".rulesync/rules/*.local.md",
12585
+ "rulesync.local.jsonc",
12551
12586
  "!.rulesync/.aiignore"
12552
12587
  ];
12553
12588
  var isRulesyncHeader = (line) => {
@@ -12829,6 +12864,7 @@ async function createConfigFile() {
12829
12864
  baseDirs: ["."],
12830
12865
  delete: true,
12831
12866
  verbose: false,
12867
+ silent: false,
12832
12868
  global: false,
12833
12869
  simulateCommands: false,
12834
12870
  simulateSubagents: false,
@@ -14244,7 +14280,7 @@ async function mcpCommand({ version }) {
14244
14280
  }
14245
14281
 
14246
14282
  // src/cli/index.ts
14247
- var getVersion = () => "5.9.1";
14283
+ var getVersion = () => "6.1.0";
14248
14284
  var main = async () => {
14249
14285
  const program = new import_commander.Command();
14250
14286
  const version = getVersion();