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/dist/index.cjs CHANGED
@@ -262,12 +262,13 @@ var FeaturesSchema = import_mini.z.array(FeatureSchema);
262
262
  var FeatureOptionsSchema = import_mini.z.record(import_mini.z.string(), import_mini.z.unknown());
263
263
  var FeatureValueSchema = import_mini.z.union([import_mini.z.boolean(), FeatureOptionsSchema]);
264
264
  var PerFeatureConfigSchema = import_mini.z.record(import_mini.z.string(), FeatureValueSchema);
265
+ var PerTargetFeaturesValueSchema = import_mini.z.union([
266
+ import_mini.z.array(import_mini.z.enum(ALL_FEATURES_WITH_WILDCARD)),
267
+ PerFeatureConfigSchema
268
+ ]);
265
269
  var RulesyncFeaturesSchema = import_mini.z.union([
266
270
  import_mini.z.array(import_mini.z.enum(ALL_FEATURES_WITH_WILDCARD)),
267
- import_mini.z.record(
268
- import_mini.z.string(),
269
- import_mini.z.union([import_mini.z.array(import_mini.z.enum(ALL_FEATURES_WITH_WILDCARD)), PerFeatureConfigSchema])
270
- )
271
+ import_mini.z.record(import_mini.z.string(), PerTargetFeaturesValueSchema)
271
272
  ]);
272
273
  var isFeatureValueEnabled = (value) => {
273
274
  if (value === true) return true;
@@ -310,6 +311,14 @@ var ALL_TOOL_TARGETS_WITH_WILDCARD = [...ALL_TOOL_TARGETS, "*"];
310
311
  var ToolTargetSchema = import_mini2.z.enum(ALL_TOOL_TARGETS);
311
312
  var ToolTargetsSchema = import_mini2.z.array(ToolTargetSchema);
312
313
  var RulesyncTargetsSchema = import_mini2.z.array(import_mini2.z.enum(ALL_TOOL_TARGETS_WITH_WILDCARD));
314
+ var RulesyncConfigTargetsObjectSchema = import_mini2.z.record(import_mini2.z.string(), PerTargetFeaturesValueSchema);
315
+ var RulesyncConfigTargetsSchema = import_mini2.z.union([
316
+ RulesyncTargetsSchema,
317
+ RulesyncConfigTargetsObjectSchema
318
+ ]);
319
+ var isRulesyncConfigTargetsObject = (value) => {
320
+ return !Array.isArray(value);
321
+ };
313
322
 
314
323
  // src/utils/validation.ts
315
324
  function findControlCharacter(value) {
@@ -346,7 +355,7 @@ var SourceEntrySchema = import_mini3.z.object({
346
355
  });
347
356
  var ConfigParamsSchema = import_mini3.z.object({
348
357
  baseDirs: import_mini3.z.array(import_mini3.z.string()),
349
- targets: RulesyncTargetsSchema,
358
+ targets: RulesyncConfigTargetsSchema,
350
359
  features: RulesyncFeaturesSchema,
351
360
  verbose: import_mini3.z.boolean(),
352
361
  delete: import_mini3.z.boolean(),
@@ -356,6 +365,7 @@ var ConfigParamsSchema = import_mini3.z.object({
356
365
  simulateCommands: (0, import_mini3.optional)(import_mini3.z.boolean()),
357
366
  simulateSubagents: (0, import_mini3.optional)(import_mini3.z.boolean()),
358
367
  simulateSkills: (0, import_mini3.optional)(import_mini3.z.boolean()),
368
+ gitignoreTargetsOnly: (0, import_mini3.optional)(import_mini3.z.boolean()),
359
369
  dryRun: (0, import_mini3.optional)(import_mini3.z.boolean()),
360
370
  check: (0, import_mini3.optional)(import_mini3.z.boolean()),
361
371
  // Declarative skill sources
@@ -372,10 +382,42 @@ var CONFLICTING_TARGET_PAIRS = [
372
382
  ["claudecode", "claudecode-legacy"]
373
383
  ];
374
384
  var LEGACY_TARGETS = ["augmentcode-legacy", "claudecode-legacy"];
385
+ var assertTargetsFeaturesExclusive = ({
386
+ targets,
387
+ features
388
+ }) => {
389
+ const targetsIsObject = targets !== void 0 && !Array.isArray(targets);
390
+ const featuresIsObject = features !== void 0 && !Array.isArray(features);
391
+ if (targetsIsObject && features !== void 0) {
392
+ throw new Error(
393
+ "Invalid config: when 'targets' is in object form, 'features' must be omitted. Declare per-target features inside the 'targets' object instead."
394
+ );
395
+ }
396
+ if (featuresIsObject && targets !== void 0) {
397
+ throw new Error(
398
+ "Invalid config: when 'features' is in object form, 'targets' must be omitted. Migrate to the 'targets' object form, e.g. `targets: { claudecode: [...] }`."
399
+ );
400
+ }
401
+ };
402
+ var assertTargetsOrFeaturesProvided = ({
403
+ targets,
404
+ features
405
+ }) => {
406
+ if (targets === void 0 && features === void 0) {
407
+ throw new Error("Invalid config: at least one of 'targets' or 'features' must be provided.");
408
+ }
409
+ };
375
410
  var Config = class _Config {
376
411
  baseDirs;
377
412
  targets;
378
413
  features;
414
+ /**
415
+ * Cached list of validated `ToolTarget` keys for the object form of
416
+ * `targets`. Populated in the constructor after `validateObjectFormTargetKeys`
417
+ * so `getTargets()` does not rebuild the `ALL_TOOL_TARGETS` set on every call.
418
+ * Undefined when `this.targets` is in array form.
419
+ */
420
+ objectFormTargetKeys;
379
421
  verbose;
380
422
  delete;
381
423
  global;
@@ -383,6 +425,7 @@ var Config = class _Config {
383
425
  simulateCommands;
384
426
  simulateSubagents;
385
427
  simulateSkills;
428
+ gitignoreTargetsOnly;
386
429
  dryRun;
387
430
  check;
388
431
  sources;
@@ -397,17 +440,24 @@ var Config = class _Config {
397
440
  simulateCommands,
398
441
  simulateSubagents,
399
442
  simulateSkills,
443
+ gitignoreTargetsOnly,
400
444
  dryRun,
401
445
  check,
402
446
  sources
403
447
  }) {
404
- this.validateConflictingTargets(targets);
448
+ assertTargetsFeaturesExclusive({ targets, features });
449
+ assertTargetsOrFeaturesProvided({ targets, features });
450
+ const resolvedTargets = targets ?? [];
451
+ const resolvedFeatures = features ?? [];
452
+ this.validateObjectFormTargetKeys(resolvedTargets);
453
+ this.validateConflictingTargets(resolvedTargets);
405
454
  if (dryRun && check) {
406
455
  throw new Error("--dry-run and --check cannot be used together");
407
456
  }
408
457
  this.baseDirs = baseDirs;
409
- this.targets = targets;
410
- this.features = features;
458
+ this.targets = resolvedTargets;
459
+ this.features = resolvedFeatures;
460
+ this.objectFormTargetKeys = isRulesyncConfigTargetsObject(resolvedTargets) ? _Config.filterValidToolTargets(Object.keys(resolvedTargets)) : void 0;
411
461
  this.verbose = verbose;
412
462
  this.delete = isDelete;
413
463
  this.global = global ?? false;
@@ -415,15 +465,42 @@ var Config = class _Config {
415
465
  this.simulateCommands = simulateCommands ?? false;
416
466
  this.simulateSubagents = simulateSubagents ?? false;
417
467
  this.simulateSkills = simulateSkills ?? false;
468
+ this.gitignoreTargetsOnly = gitignoreTargetsOnly ?? true;
418
469
  this.dryRun = dryRun ?? false;
419
470
  this.check = check ?? false;
420
471
  this.sources = sources ?? [];
421
472
  }
473
+ /**
474
+ * Rejects unknown keys (and the special `*` key) in the object form of
475
+ * `targets`. For the array form this is already enforced at the Zod schema
476
+ * level via `z.enum(ALL_TOOL_TARGETS_WITH_WILDCARD)`; for the object form
477
+ * `z.record(z.string(), ...)` intentionally accepts any string key (to work
478
+ * around zod's `z.record(z.enum(...))` requiring ALL enum members), so
479
+ * runtime validation lives here instead.
480
+ */
481
+ validateObjectFormTargetKeys(targets) {
482
+ if (Array.isArray(targets)) return;
483
+ const validTargets = new Set(ALL_TOOL_TARGETS);
484
+ for (const key of Object.keys(targets)) {
485
+ if (key === "*") {
486
+ throw new Error(
487
+ "Invalid target '*' in object form: wildcard is only supported in the array form `targets: ['*']`. Per-target options cannot be attached to a wildcard."
488
+ );
489
+ }
490
+ if (!validTargets.has(key)) {
491
+ throw new Error(`Unknown target '${key}'. Valid targets: ${ALL_TOOL_TARGETS.join(", ")}.`);
492
+ }
493
+ }
494
+ }
422
495
  validateConflictingTargets(targets) {
496
+ const has = (target) => {
497
+ if (Array.isArray(targets)) {
498
+ return targets.includes(target);
499
+ }
500
+ return Object.prototype.hasOwnProperty.call(targets, target);
501
+ };
423
502
  for (const [target1, target2] of CONFLICTING_TARGET_PAIRS) {
424
- const hasTarget1 = targets.includes(target1);
425
- const hasTarget2 = targets.includes(target2);
426
- if (hasTarget1 && hasTarget2) {
503
+ if (has(target1) && has(target2)) {
427
504
  throw new Error(
428
505
  `Conflicting targets: '${target1}' and '${target2}' cannot be used together. Please choose one.`
429
506
  );
@@ -433,16 +510,45 @@ var Config = class _Config {
433
510
  getBaseDirs() {
434
511
  return this.baseDirs;
435
512
  }
513
+ /**
514
+ * Filter an arbitrary string-key list down to the known `ToolTarget` set,
515
+ * skipping `*` (which is only meaningful as an array element, not a key).
516
+ */
517
+ static filterValidToolTargets(keys) {
518
+ const validTargets = new Set(ALL_TOOL_TARGETS);
519
+ const result = [];
520
+ for (const key of keys) {
521
+ if (key === "*") continue;
522
+ if (!validTargets.has(key)) continue;
523
+ result.push(key);
524
+ }
525
+ return result;
526
+ }
436
527
  getTargets() {
437
- if (this.targets.includes("*")) {
528
+ if (this.objectFormTargetKeys !== void 0) {
529
+ return this.objectFormTargetKeys;
530
+ }
531
+ const arrayTargets = Array.isArray(this.targets) ? this.targets : [];
532
+ if (!Array.isArray(this.features)) {
533
+ return _Config.filterValidToolTargets(Object.keys(this.features));
534
+ }
535
+ if (arrayTargets.includes("*")) {
438
536
  return ALL_TOOL_TARGETS.filter(
439
537
  // eslint-disable-next-line no-type-assertion/no-type-assertion
440
538
  (target) => !LEGACY_TARGETS.includes(target)
441
539
  );
442
540
  }
443
- return this.targets.filter((target) => target !== "*");
541
+ return arrayTargets.filter((target) => target !== "*");
444
542
  }
445
543
  getFeatures(target) {
544
+ if (isRulesyncConfigTargetsObject(this.targets)) {
545
+ if (target) {
546
+ const value = this.targets[target];
547
+ if (!value) return [];
548
+ return _Config.normalizeTargetFeatures(value);
549
+ }
550
+ return _Config.collectAllFeatures(Object.values(this.targets));
551
+ }
446
552
  if (!Array.isArray(this.features)) {
447
553
  const perTargetFeatures = this.features;
448
554
  if (target) {
@@ -452,20 +558,7 @@ var Config = class _Config {
452
558
  }
453
559
  return _Config.normalizeTargetFeatures(targetFeatures);
454
560
  }
455
- const allFeatures = [];
456
- for (const features of Object.values(perTargetFeatures)) {
457
- if (!features) continue;
458
- const normalized = _Config.normalizeTargetFeatures(features);
459
- for (const feature of normalized) {
460
- if (!allFeatures.includes(feature)) {
461
- allFeatures.push(feature);
462
- }
463
- }
464
- if (allFeatures.length === ALL_FEATURES.length) {
465
- return allFeatures;
466
- }
467
- }
468
- return allFeatures;
561
+ return _Config.collectAllFeatures(Object.values(perTargetFeatures));
469
562
  }
470
563
  if (this.features.includes("*")) {
471
564
  return [...ALL_FEATURES];
@@ -493,23 +586,40 @@ var Config = class _Config {
493
586
  }
494
587
  return enabled;
495
588
  }
589
+ /**
590
+ * Collect the union of features across all per-target values.
591
+ * Used when `getFeatures()` is called without a target in object mode.
592
+ */
593
+ static collectAllFeatures(values) {
594
+ const allFeatures = [];
595
+ for (const value of values) {
596
+ if (!value) continue;
597
+ const normalized = _Config.normalizeTargetFeatures(value);
598
+ for (const feature of normalized) {
599
+ if (!allFeatures.includes(feature)) {
600
+ allFeatures.push(feature);
601
+ }
602
+ }
603
+ if (allFeatures.length === ALL_FEATURES.length) {
604
+ return allFeatures;
605
+ }
606
+ }
607
+ return allFeatures;
608
+ }
496
609
  /**
497
610
  * Returns the per-feature options object for a given target/feature, if any.
498
611
  * Returns `undefined` when no per-feature options were provided or when the
499
612
  * feature is not enabled for the given target.
500
613
  */
501
614
  getFeatureOptions(target, feature) {
502
- if (Array.isArray(this.features)) {
615
+ const value = isRulesyncConfigTargetsObject(this.targets) ? this.targets[target] : !Array.isArray(this.features) ? this.features[target] : void 0;
616
+ if (!value || Array.isArray(value)) {
503
617
  return void 0;
504
618
  }
505
- const targetFeatures = this.features[target];
506
- if (!targetFeatures || Array.isArray(targetFeatures)) {
507
- return void 0;
508
- }
509
- const perFeature = targetFeatures;
510
- const value = perFeature[feature];
511
- if (value && typeof value === "object" && isFeatureValueEnabled(value)) {
512
- return value;
619
+ const perFeature = value;
620
+ const featureValue = perFeature[feature];
621
+ if (featureValue && typeof featureValue === "object" && isFeatureValueEnabled(featureValue)) {
622
+ return featureValue;
513
623
  }
514
624
  return void 0;
515
625
  }
@@ -517,6 +627,13 @@ var Config = class _Config {
517
627
  * Check if per-target features configuration is being used.
518
628
  */
519
629
  hasPerTargetFeatures() {
630
+ return isRulesyncConfigTargetsObject(this.targets) || !Array.isArray(this.features);
631
+ }
632
+ /**
633
+ * Returns true if the deprecated object form under `features` is in use.
634
+ * Callers can use this to emit a migration warning.
635
+ */
636
+ hasDeprecatedFeaturesObjectForm() {
520
637
  return !Array.isArray(this.features);
521
638
  }
522
639
  getVerbose() {
@@ -540,6 +657,9 @@ var Config = class _Config {
540
657
  getSimulateSkills() {
541
658
  return this.simulateSkills;
542
659
  }
660
+ getGitignoreTargetsOnly() {
661
+ return this.gitignoreTargetsOnly;
662
+ }
543
663
  getDryRun() {
544
664
  return this.dryRun;
545
665
  }
@@ -558,6 +678,17 @@ var Config = class _Config {
558
678
  }
559
679
  };
560
680
 
681
+ // src/config/deprecation-warnings.ts
682
+ var deprecationWarningEmitted = false;
683
+ var emitFeaturesObjectFormDeprecationWarning = () => {
684
+ if (deprecationWarningEmitted) return;
685
+ if (process.env.RULESYNC_SILENT_DEPRECATION) return;
686
+ deprecationWarningEmitted = true;
687
+ console.warn(
688
+ "[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."
689
+ );
690
+ };
691
+
561
692
  // src/config/config-resolver.ts
562
693
  var getDefaults = () => ({
563
694
  targets: ["agentsmd"],
@@ -571,6 +702,7 @@ var getDefaults = () => ({
571
702
  simulateCommands: false,
572
703
  simulateSubagents: false,
573
704
  simulateSkills: false,
705
+ gitignoreTargetsOnly: true,
574
706
  dryRun: false,
575
707
  check: false,
576
708
  sources: []
@@ -583,6 +715,10 @@ var loadConfigFromFile = async (filePath) => {
583
715
  const jsonData = (0, import_jsonc_parser.parse)(fileContent);
584
716
  const parsed = ConfigFileSchema.parse(jsonData);
585
717
  const { $schema: _schema, ...configParams } = parsed;
718
+ assertTargetsFeaturesExclusive({
719
+ targets: configParams.targets,
720
+ features: configParams.features
721
+ });
586
722
  return configParams;
587
723
  };
588
724
  var mergeConfigs = (baseConfig, localConfig) => {
@@ -597,6 +733,7 @@ var mergeConfigs = (baseConfig, localConfig) => {
597
733
  simulateCommands: localConfig.simulateCommands ?? baseConfig.simulateCommands,
598
734
  simulateSubagents: localConfig.simulateSubagents ?? baseConfig.simulateSubagents,
599
735
  simulateSkills: localConfig.simulateSkills ?? baseConfig.simulateSkills,
736
+ gitignoreTargetsOnly: localConfig.gitignoreTargetsOnly ?? baseConfig.gitignoreTargetsOnly,
600
737
  dryRun: localConfig.dryRun ?? baseConfig.dryRun,
601
738
  check: localConfig.check ?? baseConfig.check,
602
739
  sources: localConfig.sources ?? baseConfig.sources
@@ -615,6 +752,7 @@ var ConfigResolver = class {
615
752
  simulateCommands,
616
753
  simulateSubagents,
617
754
  simulateSkills,
755
+ gitignoreTargetsOnly,
618
756
  dryRun,
619
757
  check
620
758
  }) {
@@ -624,13 +762,35 @@ var ConfigResolver = class {
624
762
  const localConfigPath = (0, import_node_path4.join)(configDir, RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH);
625
763
  const localConfig = await loadConfigFromFile(localConfigPath);
626
764
  const configByFile = mergeConfigs(baseConfig, localConfig);
765
+ try {
766
+ assertTargetsFeaturesExclusive({
767
+ targets: configByFile.targets,
768
+ features: configByFile.features
769
+ });
770
+ } catch (error) {
771
+ const detail = error instanceof Error ? error.message : String(error);
772
+ throw new Error(
773
+ `${detail} (detected after merging '${validatedConfigPath}' with '${localConfigPath}' \u2014 the two files combined produce the invalid combination; remove the conflicting field from one of them).`,
774
+ { cause: error }
775
+ );
776
+ }
627
777
  const resolvedGlobal = global ?? configByFile.global ?? getDefaults().global;
628
778
  const resolvedSimulateCommands = simulateCommands ?? configByFile.simulateCommands ?? getDefaults().simulateCommands;
629
779
  const resolvedSimulateSubagents = simulateSubagents ?? configByFile.simulateSubagents ?? getDefaults().simulateSubagents;
630
780
  const resolvedSimulateSkills = simulateSkills ?? configByFile.simulateSkills ?? getDefaults().simulateSkills;
781
+ const resolvedGitignoreTargetsOnly = gitignoreTargetsOnly ?? configByFile.gitignoreTargetsOnly ?? getDefaults().gitignoreTargetsOnly;
782
+ const userProvidedFeatures = features ?? configByFile.features;
783
+ const userProvidedTargets = targets ?? configByFile.targets;
784
+ const targetsIsObject = userProvidedTargets !== void 0 && !Array.isArray(userProvidedTargets);
785
+ const featuresIsObject = userProvidedFeatures !== void 0 && !Array.isArray(userProvidedFeatures);
786
+ if (featuresIsObject) {
787
+ emitFeaturesObjectFormDeprecationWarning();
788
+ }
789
+ const resolvedFeatures = userProvidedFeatures ?? (targetsIsObject ? void 0 : getDefaults().features);
790
+ const resolvedTargets = userProvidedTargets ?? (featuresIsObject ? void 0 : getDefaults().targets);
631
791
  const configParams = {
632
- targets: targets ?? configByFile.targets ?? getDefaults().targets,
633
- features: features ?? configByFile.features ?? getDefaults().features,
792
+ targets: resolvedTargets,
793
+ features: resolvedFeatures,
634
794
  verbose: verbose ?? configByFile.verbose ?? getDefaults().verbose,
635
795
  delete: isDelete ?? configByFile.delete ?? getDefaults().delete,
636
796
  baseDirs: getBaseDirsInLightOfGlobal({
@@ -642,6 +802,7 @@ var ConfigResolver = class {
642
802
  simulateCommands: resolvedSimulateCommands,
643
803
  simulateSubagents: resolvedSimulateSubagents,
644
804
  simulateSkills: resolvedSimulateSkills,
805
+ gitignoreTargetsOnly: resolvedGitignoreTargetsOnly,
645
806
  dryRun: dryRun ?? configByFile.dryRun ?? getDefaults().dryRun,
646
807
  check: check ?? configByFile.check ?? getDefaults().check,
647
808
  sources: configByFile.sources ?? getDefaults().sources
@@ -14807,12 +14968,16 @@ var CopilotSubagent = class _CopilotSubagent extends ToolSubagent {
14807
14968
  const body = rulesyncSubagent.getBody();
14808
14969
  const fileContent = stringifyFrontmatter(body, copilotFrontmatter);
14809
14970
  const paths = this.getSettablePaths({ global });
14971
+ let relativeFilePath = rulesyncSubagent.getRelativeFilePath();
14972
+ if (!relativeFilePath.endsWith(".agent.md")) {
14973
+ relativeFilePath = relativeFilePath.replace(/\.md$/, ".agent.md");
14974
+ }
14810
14975
  return new _CopilotSubagent({
14811
14976
  baseDir,
14812
14977
  frontmatter: copilotFrontmatter,
14813
14978
  body,
14814
14979
  relativeDirPath: paths.relativeDirPath,
14815
- relativeFilePath: rulesyncSubagent.getRelativeFilePath(),
14980
+ relativeFilePath,
14816
14981
  fileContent,
14817
14982
  validate,
14818
14983
  global
@@ -19331,7 +19496,8 @@ var rulesProcessorToolTargets = [
19331
19496
  var RulesProcessorToolTargetSchema = import_mini70.z.enum(rulesProcessorToolTargets);
19332
19497
  var formatRulePaths = (rules) => rules.map((r) => (0, import_node_path138.join)(r.getRelativeDirPath(), r.getRelativeFilePath())).join(", ");
19333
19498
  var RulesFeatureOptionsSchema = import_mini70.z.looseObject({
19334
- ruleDiscoveryMode: import_mini70.z.optional(import_mini70.z.enum(["none", "explicit"]))
19499
+ ruleDiscoveryMode: import_mini70.z.optional(import_mini70.z.enum(["none", "explicit"])),
19500
+ includeLocalRoot: import_mini70.z.optional(import_mini70.z.boolean())
19335
19501
  });
19336
19502
  var resolveRuleDiscoveryMode = ({
19337
19503
  defaultMode,
@@ -19352,6 +19518,19 @@ var resolveRuleDiscoveryMode = ({
19352
19518
  }
19353
19519
  return parsed.data.ruleDiscoveryMode === "none" ? "auto" : "toon";
19354
19520
  };
19521
+ var IncludeLocalRootSchema = import_mini70.z.looseObject({
19522
+ includeLocalRoot: import_mini70.z.optional(import_mini70.z.boolean())
19523
+ });
19524
+ var resolveIncludeLocalRoot = (options) => {
19525
+ if (!options) return true;
19526
+ const parsed = IncludeLocalRootSchema.safeParse(options);
19527
+ if (!parsed.success) {
19528
+ throw new Error(
19529
+ `Invalid options for rules feature: ${parsed.error.message}. \`includeLocalRoot\` must be a boolean.`
19530
+ );
19531
+ }
19532
+ return parsed.data.includeLocalRoot ?? true;
19533
+ };
19355
19534
  var toolRuleFactories = /* @__PURE__ */ new Map([
19356
19535
  [
19357
19536
  "agentsmd",
@@ -19715,7 +19894,8 @@ var RulesProcessor = class extends FeatureProcessor {
19715
19894
  global: this.global
19716
19895
  });
19717
19896
  }).filter((rule) => rule !== null);
19718
- if (localRootRules.length > 0 && !this.global) {
19897
+ const includeLocalRoot = resolveIncludeLocalRoot(this.featureOptions);
19898
+ if (localRootRules.length > 0 && !this.global && includeLocalRoot) {
19719
19899
  const localRootRule = localRootRules[0];
19720
19900
  if (localRootRule && factory.class.isTargetedByRulesyncRule(localRootRule)) {
19721
19901
  this.handleLocalRootRule(toolRules, localRootRule, factory);
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  checkRulesyncDirExists,
7
7
  generate,
8
8
  importFromTool
9
- } from "./chunk-GB6XLCGB.js";
9
+ } from "./chunk-K4IN6URH.js";
10
10
 
11
11
  // src/index.ts
12
12
  async function generate2(options = {}) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rulesync",
3
- "version": "8.0.0",
3
+ "version": "8.2.0",
4
4
  "description": "Unified AI rules management CLI tool that generates configuration files for various AI development tools",
5
5
  "keywords": [
6
6
  "ai",
@@ -96,6 +96,7 @@
96
96
  "tsx": "4.21.0",
97
97
  "typescript": "5.9.3",
98
98
  "typescript-eslint": "8.57.1",
99
+ "vite": "7.3.1",
99
100
  "vitepress": "1.6.4",
100
101
  "vitest": "4.1.0"
101
102
  },