rulesync 8.0.0 → 8.2.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
@@ -28,7 +28,7 @@ npm install -g rulesync
28
28
  brew install rulesync
29
29
  ```
30
30
 
31
- ### Single Binary (Experimental)
31
+ ### Single Binary
32
32
 
33
33
  ```bash
34
34
  curl -fsSL https://github.com/dyoshikawa/rulesync/releases/latest/download/install.sh | bash
@@ -33,12 +33,13 @@ var FeaturesSchema = z.array(FeatureSchema);
33
33
  var FeatureOptionsSchema = z.record(z.string(), z.unknown());
34
34
  var FeatureValueSchema = z.union([z.boolean(), FeatureOptionsSchema]);
35
35
  var PerFeatureConfigSchema = z.record(z.string(), FeatureValueSchema);
36
+ var PerTargetFeaturesValueSchema = z.union([
37
+ z.array(z.enum(ALL_FEATURES_WITH_WILDCARD)),
38
+ PerFeatureConfigSchema
39
+ ]);
36
40
  var RulesyncFeaturesSchema = z.union([
37
41
  z.array(z.enum(ALL_FEATURES_WITH_WILDCARD)),
38
- z.record(
39
- z.string(),
40
- z.union([z.array(z.enum(ALL_FEATURES_WITH_WILDCARD)), PerFeatureConfigSchema])
41
- )
42
+ z.record(z.string(), PerTargetFeaturesValueSchema)
42
43
  ]);
43
44
  var isFeatureValueEnabled = (value) => {
44
45
  if (value === true) return true;
@@ -81,6 +82,14 @@ var ALL_TOOL_TARGETS_WITH_WILDCARD = [...ALL_TOOL_TARGETS, "*"];
81
82
  var ToolTargetSchema = z2.enum(ALL_TOOL_TARGETS);
82
83
  var ToolTargetsSchema = z2.array(ToolTargetSchema);
83
84
  var RulesyncTargetsSchema = z2.array(z2.enum(ALL_TOOL_TARGETS_WITH_WILDCARD));
85
+ var RulesyncConfigTargetsObjectSchema = z2.record(z2.string(), PerTargetFeaturesValueSchema);
86
+ var RulesyncConfigTargetsSchema = z2.union([
87
+ RulesyncTargetsSchema,
88
+ RulesyncConfigTargetsObjectSchema
89
+ ]);
90
+ var isRulesyncConfigTargetsObject = (value) => {
91
+ return !Array.isArray(value);
92
+ };
84
93
 
85
94
  // src/config/config-resolver.ts
86
95
  import { dirname as dirname2, join as join3, resolve as resolve2 } from "path";
@@ -338,7 +347,7 @@ var SourceEntrySchema = z3.object({
338
347
  });
339
348
  var ConfigParamsSchema = z3.object({
340
349
  baseDirs: z3.array(z3.string()),
341
- targets: RulesyncTargetsSchema,
350
+ targets: RulesyncConfigTargetsSchema,
342
351
  features: RulesyncFeaturesSchema,
343
352
  verbose: z3.boolean(),
344
353
  delete: z3.boolean(),
@@ -348,6 +357,7 @@ var ConfigParamsSchema = z3.object({
348
357
  simulateCommands: optional(z3.boolean()),
349
358
  simulateSubagents: optional(z3.boolean()),
350
359
  simulateSkills: optional(z3.boolean()),
360
+ gitignoreTargetsOnly: optional(z3.boolean()),
351
361
  dryRun: optional(z3.boolean()),
352
362
  check: optional(z3.boolean()),
353
363
  // Declarative skill sources
@@ -364,10 +374,42 @@ var CONFLICTING_TARGET_PAIRS = [
364
374
  ["claudecode", "claudecode-legacy"]
365
375
  ];
366
376
  var LEGACY_TARGETS = ["augmentcode-legacy", "claudecode-legacy"];
377
+ var assertTargetsFeaturesExclusive = ({
378
+ targets,
379
+ features
380
+ }) => {
381
+ const targetsIsObject = targets !== void 0 && !Array.isArray(targets);
382
+ const featuresIsObject = features !== void 0 && !Array.isArray(features);
383
+ if (targetsIsObject && features !== void 0) {
384
+ throw new Error(
385
+ "Invalid config: when 'targets' is in object form, 'features' must be omitted. Declare per-target features inside the 'targets' object instead."
386
+ );
387
+ }
388
+ if (featuresIsObject && targets !== void 0) {
389
+ throw new Error(
390
+ "Invalid config: when 'features' is in object form, 'targets' must be omitted. Migrate to the 'targets' object form, e.g. `targets: { claudecode: [...] }`."
391
+ );
392
+ }
393
+ };
394
+ var assertTargetsOrFeaturesProvided = ({
395
+ targets,
396
+ features
397
+ }) => {
398
+ if (targets === void 0 && features === void 0) {
399
+ throw new Error("Invalid config: at least one of 'targets' or 'features' must be provided.");
400
+ }
401
+ };
367
402
  var Config = class _Config {
368
403
  baseDirs;
369
404
  targets;
370
405
  features;
406
+ /**
407
+ * Cached list of validated `ToolTarget` keys for the object form of
408
+ * `targets`. Populated in the constructor after `validateObjectFormTargetKeys`
409
+ * so `getTargets()` does not rebuild the `ALL_TOOL_TARGETS` set on every call.
410
+ * Undefined when `this.targets` is in array form.
411
+ */
412
+ objectFormTargetKeys;
371
413
  verbose;
372
414
  delete;
373
415
  global;
@@ -375,6 +417,7 @@ var Config = class _Config {
375
417
  simulateCommands;
376
418
  simulateSubagents;
377
419
  simulateSkills;
420
+ gitignoreTargetsOnly;
378
421
  dryRun;
379
422
  check;
380
423
  sources;
@@ -389,17 +432,24 @@ var Config = class _Config {
389
432
  simulateCommands,
390
433
  simulateSubagents,
391
434
  simulateSkills,
435
+ gitignoreTargetsOnly,
392
436
  dryRun,
393
437
  check,
394
438
  sources
395
439
  }) {
396
- this.validateConflictingTargets(targets);
440
+ assertTargetsFeaturesExclusive({ targets, features });
441
+ assertTargetsOrFeaturesProvided({ targets, features });
442
+ const resolvedTargets = targets ?? [];
443
+ const resolvedFeatures = features ?? [];
444
+ this.validateObjectFormTargetKeys(resolvedTargets);
445
+ this.validateConflictingTargets(resolvedTargets);
397
446
  if (dryRun && check) {
398
447
  throw new Error("--dry-run and --check cannot be used together");
399
448
  }
400
449
  this.baseDirs = baseDirs;
401
- this.targets = targets;
402
- this.features = features;
450
+ this.targets = resolvedTargets;
451
+ this.features = resolvedFeatures;
452
+ this.objectFormTargetKeys = isRulesyncConfigTargetsObject(resolvedTargets) ? _Config.filterValidToolTargets(Object.keys(resolvedTargets)) : void 0;
403
453
  this.verbose = verbose;
404
454
  this.delete = isDelete;
405
455
  this.global = global ?? false;
@@ -407,15 +457,42 @@ var Config = class _Config {
407
457
  this.simulateCommands = simulateCommands ?? false;
408
458
  this.simulateSubagents = simulateSubagents ?? false;
409
459
  this.simulateSkills = simulateSkills ?? false;
460
+ this.gitignoreTargetsOnly = gitignoreTargetsOnly ?? true;
410
461
  this.dryRun = dryRun ?? false;
411
462
  this.check = check ?? false;
412
463
  this.sources = sources ?? [];
413
464
  }
465
+ /**
466
+ * Rejects unknown keys (and the special `*` key) in the object form of
467
+ * `targets`. For the array form this is already enforced at the Zod schema
468
+ * level via `z.enum(ALL_TOOL_TARGETS_WITH_WILDCARD)`; for the object form
469
+ * `z.record(z.string(), ...)` intentionally accepts any string key (to work
470
+ * around zod's `z.record(z.enum(...))` requiring ALL enum members), so
471
+ * runtime validation lives here instead.
472
+ */
473
+ validateObjectFormTargetKeys(targets) {
474
+ if (Array.isArray(targets)) return;
475
+ const validTargets = new Set(ALL_TOOL_TARGETS);
476
+ for (const key of Object.keys(targets)) {
477
+ if (key === "*") {
478
+ throw new Error(
479
+ "Invalid target '*' in object form: wildcard is only supported in the array form `targets: ['*']`. Per-target options cannot be attached to a wildcard."
480
+ );
481
+ }
482
+ if (!validTargets.has(key)) {
483
+ throw new Error(`Unknown target '${key}'. Valid targets: ${ALL_TOOL_TARGETS.join(", ")}.`);
484
+ }
485
+ }
486
+ }
414
487
  validateConflictingTargets(targets) {
488
+ const has = (target) => {
489
+ if (Array.isArray(targets)) {
490
+ return targets.includes(target);
491
+ }
492
+ return Object.prototype.hasOwnProperty.call(targets, target);
493
+ };
415
494
  for (const [target1, target2] of CONFLICTING_TARGET_PAIRS) {
416
- const hasTarget1 = targets.includes(target1);
417
- const hasTarget2 = targets.includes(target2);
418
- if (hasTarget1 && hasTarget2) {
495
+ if (has(target1) && has(target2)) {
419
496
  throw new Error(
420
497
  `Conflicting targets: '${target1}' and '${target2}' cannot be used together. Please choose one.`
421
498
  );
@@ -425,16 +502,45 @@ var Config = class _Config {
425
502
  getBaseDirs() {
426
503
  return this.baseDirs;
427
504
  }
505
+ /**
506
+ * Filter an arbitrary string-key list down to the known `ToolTarget` set,
507
+ * skipping `*` (which is only meaningful as an array element, not a key).
508
+ */
509
+ static filterValidToolTargets(keys) {
510
+ const validTargets = new Set(ALL_TOOL_TARGETS);
511
+ const result = [];
512
+ for (const key of keys) {
513
+ if (key === "*") continue;
514
+ if (!validTargets.has(key)) continue;
515
+ result.push(key);
516
+ }
517
+ return result;
518
+ }
428
519
  getTargets() {
429
- if (this.targets.includes("*")) {
520
+ if (this.objectFormTargetKeys !== void 0) {
521
+ return this.objectFormTargetKeys;
522
+ }
523
+ const arrayTargets = Array.isArray(this.targets) ? this.targets : [];
524
+ if (!Array.isArray(this.features)) {
525
+ return _Config.filterValidToolTargets(Object.keys(this.features));
526
+ }
527
+ if (arrayTargets.includes("*")) {
430
528
  return ALL_TOOL_TARGETS.filter(
431
529
  // eslint-disable-next-line no-type-assertion/no-type-assertion
432
530
  (target) => !LEGACY_TARGETS.includes(target)
433
531
  );
434
532
  }
435
- return this.targets.filter((target) => target !== "*");
533
+ return arrayTargets.filter((target) => target !== "*");
436
534
  }
437
535
  getFeatures(target) {
536
+ if (isRulesyncConfigTargetsObject(this.targets)) {
537
+ if (target) {
538
+ const value = this.targets[target];
539
+ if (!value) return [];
540
+ return _Config.normalizeTargetFeatures(value);
541
+ }
542
+ return _Config.collectAllFeatures(Object.values(this.targets));
543
+ }
438
544
  if (!Array.isArray(this.features)) {
439
545
  const perTargetFeatures = this.features;
440
546
  if (target) {
@@ -444,20 +550,7 @@ var Config = class _Config {
444
550
  }
445
551
  return _Config.normalizeTargetFeatures(targetFeatures);
446
552
  }
447
- const allFeatures = [];
448
- for (const features of Object.values(perTargetFeatures)) {
449
- if (!features) continue;
450
- const normalized = _Config.normalizeTargetFeatures(features);
451
- for (const feature of normalized) {
452
- if (!allFeatures.includes(feature)) {
453
- allFeatures.push(feature);
454
- }
455
- }
456
- if (allFeatures.length === ALL_FEATURES.length) {
457
- return allFeatures;
458
- }
459
- }
460
- return allFeatures;
553
+ return _Config.collectAllFeatures(Object.values(perTargetFeatures));
461
554
  }
462
555
  if (this.features.includes("*")) {
463
556
  return [...ALL_FEATURES];
@@ -485,23 +578,40 @@ var Config = class _Config {
485
578
  }
486
579
  return enabled;
487
580
  }
581
+ /**
582
+ * Collect the union of features across all per-target values.
583
+ * Used when `getFeatures()` is called without a target in object mode.
584
+ */
585
+ static collectAllFeatures(values) {
586
+ const allFeatures = [];
587
+ for (const value of values) {
588
+ if (!value) continue;
589
+ const normalized = _Config.normalizeTargetFeatures(value);
590
+ for (const feature of normalized) {
591
+ if (!allFeatures.includes(feature)) {
592
+ allFeatures.push(feature);
593
+ }
594
+ }
595
+ if (allFeatures.length === ALL_FEATURES.length) {
596
+ return allFeatures;
597
+ }
598
+ }
599
+ return allFeatures;
600
+ }
488
601
  /**
489
602
  * Returns the per-feature options object for a given target/feature, if any.
490
603
  * Returns `undefined` when no per-feature options were provided or when the
491
604
  * feature is not enabled for the given target.
492
605
  */
493
606
  getFeatureOptions(target, feature) {
494
- if (Array.isArray(this.features)) {
607
+ const value = isRulesyncConfigTargetsObject(this.targets) ? this.targets[target] : !Array.isArray(this.features) ? this.features[target] : void 0;
608
+ if (!value || Array.isArray(value)) {
495
609
  return void 0;
496
610
  }
497
- const targetFeatures = this.features[target];
498
- if (!targetFeatures || Array.isArray(targetFeatures)) {
499
- return void 0;
500
- }
501
- const perFeature = targetFeatures;
502
- const value = perFeature[feature];
503
- if (value && typeof value === "object" && isFeatureValueEnabled(value)) {
504
- return value;
611
+ const perFeature = value;
612
+ const featureValue = perFeature[feature];
613
+ if (featureValue && typeof featureValue === "object" && isFeatureValueEnabled(featureValue)) {
614
+ return featureValue;
505
615
  }
506
616
  return void 0;
507
617
  }
@@ -509,6 +619,13 @@ var Config = class _Config {
509
619
  * Check if per-target features configuration is being used.
510
620
  */
511
621
  hasPerTargetFeatures() {
622
+ return isRulesyncConfigTargetsObject(this.targets) || !Array.isArray(this.features);
623
+ }
624
+ /**
625
+ * Returns true if the deprecated object form under `features` is in use.
626
+ * Callers can use this to emit a migration warning.
627
+ */
628
+ hasDeprecatedFeaturesObjectForm() {
512
629
  return !Array.isArray(this.features);
513
630
  }
514
631
  getVerbose() {
@@ -532,6 +649,9 @@ var Config = class _Config {
532
649
  getSimulateSkills() {
533
650
  return this.simulateSkills;
534
651
  }
652
+ getGitignoreTargetsOnly() {
653
+ return this.gitignoreTargetsOnly;
654
+ }
535
655
  getDryRun() {
536
656
  return this.dryRun;
537
657
  }
@@ -550,6 +670,17 @@ var Config = class _Config {
550
670
  }
551
671
  };
552
672
 
673
+ // src/config/deprecation-warnings.ts
674
+ var deprecationWarningEmitted = false;
675
+ var emitFeaturesObjectFormDeprecationWarning = () => {
676
+ if (deprecationWarningEmitted) return;
677
+ if (process.env.RULESYNC_SILENT_DEPRECATION) return;
678
+ deprecationWarningEmitted = true;
679
+ console.warn(
680
+ "[rulesync] DEPRECATED: 'features' object form is deprecated. Use the new 'targets' object form instead: `targets: { claudecode: { rules: true, ignore: { fileMode: 'local' } } }`. See https://github.com/dyoshikawa/rulesync/blob/main/docs/guide/configuration.md for the migration guide."
681
+ );
682
+ };
683
+
553
684
  // src/config/config-resolver.ts
554
685
  var getDefaults = () => ({
555
686
  targets: ["agentsmd"],
@@ -563,6 +694,7 @@ var getDefaults = () => ({
563
694
  simulateCommands: false,
564
695
  simulateSubagents: false,
565
696
  simulateSkills: false,
697
+ gitignoreTargetsOnly: true,
566
698
  dryRun: false,
567
699
  check: false,
568
700
  sources: []
@@ -575,6 +707,10 @@ var loadConfigFromFile = async (filePath) => {
575
707
  const jsonData = parseJsonc(fileContent);
576
708
  const parsed = ConfigFileSchema.parse(jsonData);
577
709
  const { $schema: _schema, ...configParams } = parsed;
710
+ assertTargetsFeaturesExclusive({
711
+ targets: configParams.targets,
712
+ features: configParams.features
713
+ });
578
714
  return configParams;
579
715
  };
580
716
  var mergeConfigs = (baseConfig, localConfig) => {
@@ -589,6 +725,7 @@ var mergeConfigs = (baseConfig, localConfig) => {
589
725
  simulateCommands: localConfig.simulateCommands ?? baseConfig.simulateCommands,
590
726
  simulateSubagents: localConfig.simulateSubagents ?? baseConfig.simulateSubagents,
591
727
  simulateSkills: localConfig.simulateSkills ?? baseConfig.simulateSkills,
728
+ gitignoreTargetsOnly: localConfig.gitignoreTargetsOnly ?? baseConfig.gitignoreTargetsOnly,
592
729
  dryRun: localConfig.dryRun ?? baseConfig.dryRun,
593
730
  check: localConfig.check ?? baseConfig.check,
594
731
  sources: localConfig.sources ?? baseConfig.sources
@@ -607,6 +744,7 @@ var ConfigResolver = class {
607
744
  simulateCommands,
608
745
  simulateSubagents,
609
746
  simulateSkills,
747
+ gitignoreTargetsOnly,
610
748
  dryRun,
611
749
  check
612
750
  }) {
@@ -616,13 +754,35 @@ var ConfigResolver = class {
616
754
  const localConfigPath = join3(configDir, RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH);
617
755
  const localConfig = await loadConfigFromFile(localConfigPath);
618
756
  const configByFile = mergeConfigs(baseConfig, localConfig);
757
+ try {
758
+ assertTargetsFeaturesExclusive({
759
+ targets: configByFile.targets,
760
+ features: configByFile.features
761
+ });
762
+ } catch (error) {
763
+ const detail = error instanceof Error ? error.message : String(error);
764
+ throw new Error(
765
+ `${detail} (detected after merging '${validatedConfigPath}' with '${localConfigPath}' \u2014 the two files combined produce the invalid combination; remove the conflicting field from one of them).`,
766
+ { cause: error }
767
+ );
768
+ }
619
769
  const resolvedGlobal = global ?? configByFile.global ?? getDefaults().global;
620
770
  const resolvedSimulateCommands = simulateCommands ?? configByFile.simulateCommands ?? getDefaults().simulateCommands;
621
771
  const resolvedSimulateSubagents = simulateSubagents ?? configByFile.simulateSubagents ?? getDefaults().simulateSubagents;
622
772
  const resolvedSimulateSkills = simulateSkills ?? configByFile.simulateSkills ?? getDefaults().simulateSkills;
773
+ const resolvedGitignoreTargetsOnly = gitignoreTargetsOnly ?? configByFile.gitignoreTargetsOnly ?? getDefaults().gitignoreTargetsOnly;
774
+ const userProvidedFeatures = features ?? configByFile.features;
775
+ const userProvidedTargets = targets ?? configByFile.targets;
776
+ const targetsIsObject = userProvidedTargets !== void 0 && !Array.isArray(userProvidedTargets);
777
+ const featuresIsObject = userProvidedFeatures !== void 0 && !Array.isArray(userProvidedFeatures);
778
+ if (featuresIsObject) {
779
+ emitFeaturesObjectFormDeprecationWarning();
780
+ }
781
+ const resolvedFeatures = userProvidedFeatures ?? (targetsIsObject ? void 0 : getDefaults().features);
782
+ const resolvedTargets = userProvidedTargets ?? (featuresIsObject ? void 0 : getDefaults().targets);
623
783
  const configParams = {
624
- targets: targets ?? configByFile.targets ?? getDefaults().targets,
625
- features: features ?? configByFile.features ?? getDefaults().features,
784
+ targets: resolvedTargets,
785
+ features: resolvedFeatures,
626
786
  verbose: verbose ?? configByFile.verbose ?? getDefaults().verbose,
627
787
  delete: isDelete ?? configByFile.delete ?? getDefaults().delete,
628
788
  baseDirs: getBaseDirsInLightOfGlobal({
@@ -634,6 +794,7 @@ var ConfigResolver = class {
634
794
  simulateCommands: resolvedSimulateCommands,
635
795
  simulateSubagents: resolvedSimulateSubagents,
636
796
  simulateSkills: resolvedSimulateSkills,
797
+ gitignoreTargetsOnly: resolvedGitignoreTargetsOnly,
637
798
  dryRun: dryRun ?? configByFile.dryRun ?? getDefaults().dryRun,
638
799
  check: check ?? configByFile.check ?? getDefaults().check,
639
800
  sources: configByFile.sources ?? getDefaults().sources
@@ -14799,12 +14960,16 @@ var CopilotSubagent = class _CopilotSubagent extends ToolSubagent {
14799
14960
  const body = rulesyncSubagent.getBody();
14800
14961
  const fileContent = stringifyFrontmatter(body, copilotFrontmatter);
14801
14962
  const paths = this.getSettablePaths({ global });
14963
+ let relativeFilePath = rulesyncSubagent.getRelativeFilePath();
14964
+ if (!relativeFilePath.endsWith(".agent.md")) {
14965
+ relativeFilePath = relativeFilePath.replace(/\.md$/, ".agent.md");
14966
+ }
14802
14967
  return new _CopilotSubagent({
14803
14968
  baseDir,
14804
14969
  frontmatter: copilotFrontmatter,
14805
14970
  body,
14806
14971
  relativeDirPath: paths.relativeDirPath,
14807
- relativeFilePath: rulesyncSubagent.getRelativeFilePath(),
14972
+ relativeFilePath,
14808
14973
  fileContent,
14809
14974
  validate,
14810
14975
  global
@@ -19323,7 +19488,8 @@ var rulesProcessorToolTargets = [
19323
19488
  var RulesProcessorToolTargetSchema = z70.enum(rulesProcessorToolTargets);
19324
19489
  var formatRulePaths = (rules) => rules.map((r) => join135(r.getRelativeDirPath(), r.getRelativeFilePath())).join(", ");
19325
19490
  var RulesFeatureOptionsSchema = z70.looseObject({
19326
- ruleDiscoveryMode: z70.optional(z70.enum(["none", "explicit"]))
19491
+ ruleDiscoveryMode: z70.optional(z70.enum(["none", "explicit"])),
19492
+ includeLocalRoot: z70.optional(z70.boolean())
19327
19493
  });
19328
19494
  var resolveRuleDiscoveryMode = ({
19329
19495
  defaultMode,
@@ -19344,6 +19510,19 @@ var resolveRuleDiscoveryMode = ({
19344
19510
  }
19345
19511
  return parsed.data.ruleDiscoveryMode === "none" ? "auto" : "toon";
19346
19512
  };
19513
+ var IncludeLocalRootSchema = z70.looseObject({
19514
+ includeLocalRoot: z70.optional(z70.boolean())
19515
+ });
19516
+ var resolveIncludeLocalRoot = (options) => {
19517
+ if (!options) return true;
19518
+ const parsed = IncludeLocalRootSchema.safeParse(options);
19519
+ if (!parsed.success) {
19520
+ throw new Error(
19521
+ `Invalid options for rules feature: ${parsed.error.message}. \`includeLocalRoot\` must be a boolean.`
19522
+ );
19523
+ }
19524
+ return parsed.data.includeLocalRoot ?? true;
19525
+ };
19347
19526
  var toolRuleFactories = /* @__PURE__ */ new Map([
19348
19527
  [
19349
19528
  "agentsmd",
@@ -19707,7 +19886,8 @@ var RulesProcessor = class extends FeatureProcessor {
19707
19886
  global: this.global
19708
19887
  });
19709
19888
  }).filter((rule) => rule !== null);
19710
- if (localRootRules.length > 0 && !this.global) {
19889
+ const includeLocalRoot = resolveIncludeLocalRoot(this.featureOptions);
19890
+ if (localRootRules.length > 0 && !this.global && includeLocalRoot) {
19711
19891
  const localRootRule = localRootRules[0];
19712
19892
  if (localRootRule && factory.class.isTargetedByRulesyncRule(localRootRule)) {
19713
19893
  this.handleLocalRootRule(toolRules, localRootRule, factory);
@@ -21123,6 +21303,7 @@ var JsonLogger = class extends BaseLogger {
21123
21303
 
21124
21304
  export {
21125
21305
  RULESYNC_CONFIG_RELATIVE_FILE_PATH,
21306
+ RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH,
21126
21307
  RULESYNC_RELATIVE_DIR_PATH,
21127
21308
  RULESYNC_RULES_RELATIVE_DIR_PATH,
21128
21309
  RULESYNC_COMMANDS_RELATIVE_DIR_PATH,