rulesync 22.0.0 → 23.0.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.
@@ -2703,6 +2703,7 @@ var Config = class Config {
2703
2703
  */
2704
2704
  objectFormTargetKeys;
2705
2705
  configFileTargets;
2706
+ configFileSelection;
2706
2707
  verbose;
2707
2708
  delete;
2708
2709
  global;
@@ -2737,7 +2738,7 @@ var Config = class Config {
2737
2738
  inputRoots;
2738
2739
  configFilePath;
2739
2740
  sources;
2740
- constructor({ outputRoots, targets, features, verbose, delete: isDelete, global, silent, simulateCommands, simulateSubagents, simulateSkills, preserveUnownedHooks, deriveSubprojectPathFromGlobs, flattenedCommandNaming, language, gitignoreTargetsOnly, gitignoreDestination, dryRun, check, inputRoot, inputRoots, configFilePath, sources, configFileTargets }) {
2741
+ constructor({ outputRoots, targets, features, verbose, delete: isDelete, global, silent, simulateCommands, simulateSubagents, simulateSkills, preserveUnownedHooks, deriveSubprojectPathFromGlobs, flattenedCommandNaming, language, gitignoreTargetsOnly, gitignoreDestination, dryRun, check, inputRoot, inputRoots, configFilePath, sources, configFileTargets, configFileSelection }) {
2741
2742
  assertTargetsFeaturesExclusive({
2742
2743
  targets,
2743
2744
  features
@@ -2762,6 +2763,7 @@ var Config = class Config {
2762
2763
  this.features = resolvedFeatures;
2763
2764
  this.objectFormTargetKeys = isRulesyncConfigTargetsObject(resolvedTargets) ? Config.filterValidToolTargets(Object.keys(resolvedTargets)) : void 0;
2764
2765
  this.configFileTargets = configFileTargets;
2766
+ this.configFileSelection = configFileSelection;
2765
2767
  this.verbose = verbose;
2766
2768
  this.delete = isDelete;
2767
2769
  this.global = global ?? false;
@@ -2852,17 +2854,54 @@ var Config = class Config {
2852
2854
  getConfigFileTargets() {
2853
2855
  return this.configFileTargets ?? this.getTargets();
2854
2856
  }
2857
+ /**
2858
+ * The features `target` has for a run over the configuration file's
2859
+ * targets, i.e. what `rulesync generate` without `--targets` would produce
2860
+ * for it (a CLI `--features` still applies to array-form targets). Falls
2861
+ * back to {@link getFeatures} when no configuration file declared `targets`.
2862
+ */
2863
+ getConfigFileFeatures(target) {
2864
+ const selection = this.configFileSelection;
2865
+ if (selection === void 0) return this.getFeatures(target);
2866
+ return Config.resolveTargetFeatures({
2867
+ targets: selection.targets,
2868
+ features: selection.features ?? [],
2869
+ target
2870
+ });
2871
+ }
2872
+ /**
2873
+ * The options `target` sets for `feature` in the configuration file, for
2874
+ * the same run as {@link getConfigFileFeatures}. Falls back to
2875
+ * {@link getFeatureOptions} when no configuration file declared `targets`.
2876
+ */
2877
+ getConfigFileFeatureOptions(target, feature) {
2878
+ const selection = this.configFileSelection;
2879
+ if (selection === void 0) return this.getFeatureOptions(target, feature);
2880
+ return Config.resolveFeatureOptions({
2881
+ targets: selection.targets,
2882
+ target,
2883
+ feature
2884
+ });
2885
+ }
2855
2886
  getFeatures(target) {
2856
- if (isRulesyncConfigTargetsObject(this.targets)) {
2857
- if (target) {
2858
- const value = this.targets[target];
2859
- if (!value) return [];
2860
- return Config.normalizeTargetFeatures(value);
2861
- }
2862
- return Config.collectAllFeatures(Object.values(this.targets));
2887
+ if (target) return Config.resolveTargetFeatures({
2888
+ targets: this.targets,
2889
+ features: this.features,
2890
+ target
2891
+ });
2892
+ if (isRulesyncConfigTargetsObject(this.targets)) return Config.collectAllFeatures(Object.values(this.targets));
2893
+ return Config.normalizeFeatureList(this.features);
2894
+ }
2895
+ static resolveTargetFeatures({ targets, features, target }) {
2896
+ if (isRulesyncConfigTargetsObject(targets)) {
2897
+ const value = targets[target];
2898
+ return value ? Config.normalizeTargetFeatures(value) : [];
2863
2899
  }
2864
- if (this.features.includes("*")) return [...ALL_FEATURES];
2865
- return this.features.filter((feature) => feature !== "*");
2900
+ return Config.normalizeFeatureList(features);
2901
+ }
2902
+ static normalizeFeatureList(features) {
2903
+ if (features.includes("*")) return [...ALL_FEATURES];
2904
+ return features.filter((feature) => feature !== "*");
2866
2905
  }
2867
2906
  /**
2868
2907
  * Normalize a per-target features value (array or per-feature object) into
@@ -2903,7 +2942,14 @@ var Config = class Config {
2903
2942
  * feature is not enabled for the given target.
2904
2943
  */
2905
2944
  getFeatureOptions(target, feature) {
2906
- const value = isRulesyncConfigTargetsObject(this.targets) ? this.targets[target] : void 0;
2945
+ return Config.resolveFeatureOptions({
2946
+ targets: this.targets,
2947
+ target,
2948
+ feature
2949
+ });
2950
+ }
2951
+ static resolveFeatureOptions({ targets, target, feature }) {
2952
+ const value = isRulesyncConfigTargetsObject(targets) ? targets[target] : void 0;
2907
2953
  if (!value || Array.isArray(value)) return;
2908
2954
  const featureValue = value[feature];
2909
2955
  if (featureValue && typeof featureValue === "object" && isFeatureValueEnabled(featureValue)) return featureValue;
@@ -3338,7 +3384,15 @@ var ConfigResolver = class {
3338
3384
  sources: configByFile.sources ?? getDefaults().sources,
3339
3385
  flattenedCommandNaming: configByFile.flattenedCommandNaming ?? getDefaults().flattenedCommandNaming,
3340
3386
  language: configByFile.language,
3341
- configFileTargets: extractConfigFileTargets(configByFile.targets)
3387
+ configFileTargets: extractConfigFileTargets(configByFile.targets),
3388
+ configFileSelection: configByFile.targets === void 0 ? void 0 : {
3389
+ targets: configByFile.targets,
3390
+ features: resolveFeaturesAndTargets({
3391
+ features,
3392
+ targets: void 0,
3393
+ configByFile
3394
+ }).resolvedFeatures
3395
+ }
3342
3396
  });
3343
3397
  }
3344
3398
  };
@@ -14940,6 +14994,7 @@ const ANTIGRAVITY_GLOBAL_AGENTS_DIR_PATH = join(ANTIGRAVITY_GLOBAL_CONFIG_DIR_PA
14940
14994
  const ANTIGRAVITY_AGENTS_DIR = ANTIGRAVITY_DIR;
14941
14995
  const ANTIGRAVITY_RULE_FILE_NAME = "AGENTS.md";
14942
14996
  const ANTIGRAVITY_GLOBAL_RULE_FILE_NAME = "GEMINI.md";
14997
+ const ANTIGRAVITY_GLOBAL_RULES_SUBDIR = join(ANTIGRAVITY_GLOBAL_CONFIG_SUBDIR, "rules");
14943
14998
  //#endregion
14944
14999
  //#region src/features/commands/antigravity-command.ts
14945
15000
  const AntigravityWorkflowFrontmatterSchema = z.looseObject({
@@ -73137,97 +73192,6 @@ var AmpRule = class AmpRule extends ToolRule {
73137
73192
  }
73138
73193
  };
73139
73194
  //#endregion
73140
- //#region src/features/rules/antigravity-cli-rule.ts
73141
- /**
73142
- * Rule generator for the Google Antigravity CLI (`agy`, the Gemini-CLI
73143
- * successor in Antigravity 2.0).
73144
- *
73145
- * The CLI reads the same plain-markdown context files as Gemini CLI — a root
73146
- * context file plus non-root memory files in `.agents/rules/` — so this class
73147
- * follows that same plain-markdown approach but points at the new `.agents/` tree.
73148
- *
73149
- * - Project scope: root `AGENTS.md` (the cross-tool standard, matching
73150
- * `antigravity-ide`); non-root `.agents/rules/*.md`.
73151
- * - Global scope: a single plain `~/.gemini/GEMINI.md` (shared with the IDE).
73152
- */
73153
- var AntigravityCliRule = class AntigravityCliRule extends ToolRule {
73154
- static getSettablePaths({ global, excludeToolDir } = {}) {
73155
- if (global) return { root: {
73156
- relativeDirPath: buildToolPath(ANTIGRAVITY_GEMINI_DIR, ".", excludeToolDir),
73157
- relativeFilePath: ANTIGRAVITY_GLOBAL_RULE_FILE_NAME
73158
- } };
73159
- return {
73160
- root: {
73161
- relativeDirPath: ".",
73162
- relativeFilePath: ANTIGRAVITY_RULE_FILE_NAME
73163
- },
73164
- nonRoot: { relativeDirPath: buildToolPath(ANTIGRAVITY_AGENTS_DIR, "rules", excludeToolDir) }
73165
- };
73166
- }
73167
- static async fromFile({ outputRoot = process.cwd(), relativeFilePath, validate = true, global = false }) {
73168
- const paths = this.getSettablePaths({ global });
73169
- if (relativeFilePath === paths.root.relativeFilePath) {
73170
- const relativePath = paths.root.relativeFilePath;
73171
- const fileContent = await readFileContent(join(outputRoot, paths.root.relativeDirPath, relativePath));
73172
- return new AntigravityCliRule({
73173
- outputRoot,
73174
- relativeDirPath: paths.root.relativeDirPath,
73175
- relativeFilePath: paths.root.relativeFilePath,
73176
- fileContent,
73177
- validate,
73178
- root: true
73179
- });
73180
- }
73181
- if (!paths.nonRoot) throw new Error(`nonRoot path is not set for ${relativeFilePath}`);
73182
- const relativePath = join(paths.nonRoot.relativeDirPath, relativeFilePath);
73183
- const fileContent = await readFileContent(join(outputRoot, relativePath));
73184
- return new AntigravityCliRule({
73185
- outputRoot,
73186
- relativeDirPath: paths.nonRoot.relativeDirPath,
73187
- relativeFilePath,
73188
- fileContent,
73189
- validate,
73190
- root: false
73191
- });
73192
- }
73193
- static fromRulesyncRule({ outputRoot = process.cwd(), rulesyncRule, validate = true, global = false }) {
73194
- const paths = this.getSettablePaths({ global });
73195
- return new AntigravityCliRule(this.buildToolRuleParamsDefault({
73196
- outputRoot,
73197
- rulesyncRule,
73198
- validate,
73199
- rootPath: paths.root,
73200
- nonRootPath: paths.nonRoot
73201
- }));
73202
- }
73203
- toRulesyncRule() {
73204
- return this.toRulesyncRuleDefault();
73205
- }
73206
- validate() {
73207
- return {
73208
- success: true,
73209
- error: null
73210
- };
73211
- }
73212
- static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
73213
- const isRoot = relativeFilePath === this.getSettablePaths({ global }).root.relativeFilePath;
73214
- return new AntigravityCliRule({
73215
- outputRoot,
73216
- relativeDirPath,
73217
- relativeFilePath,
73218
- fileContent: "",
73219
- validate: false,
73220
- root: isRoot
73221
- });
73222
- }
73223
- static isTargetedByRulesyncRule(rulesyncRule) {
73224
- return this.isTargetedByRulesyncRuleDefault({
73225
- rulesyncRule,
73226
- toolTarget: "antigravity-cli"
73227
- });
73228
- }
73229
- };
73230
- //#endregion
73231
73195
  //#region src/features/rules/antigravity-rule.ts
73232
73196
  const AntigravityRuleFrontmatterSchema = z.looseObject({
73233
73197
  trigger: z.optional(z.union([
@@ -73374,6 +73338,185 @@ const STRATEGIES$1 = [
73374
73338
  }
73375
73339
  ];
73376
73340
  //#endregion
73341
+ //#region src/features/rules/antigravity-cli-rule.ts
73342
+ /**
73343
+ * Rule generator for the Google Antigravity CLI (`agy`, the Gemini-CLI
73344
+ * successor in Antigravity 2.0).
73345
+ *
73346
+ * The CLI reads the same plain-markdown context files as Gemini CLI — a root
73347
+ * context file plus non-root memory files in `.agents/rules/` — so this class
73348
+ * follows that same plain-markdown approach but points at the new `.agents/` tree.
73349
+ *
73350
+ * - Project scope: root `AGENTS.md` (the cross-tool standard, matching
73351
+ * `antigravity-ide`); non-root `.agents/rules/*.md`.
73352
+ * - Global scope: root plain `~/.gemini/GEMINI.md` (shared with the IDE);
73353
+ * non-root `~/.gemini/config/rules/*.md`. The CLI truncates each rule file at
73354
+ * 24,000 bytes, so keeping non-root rules as separate files stops a large rule
73355
+ * set from being cut off. Every file in that directory must carry a valid
73356
+ * `trigger` frontmatter or the CLI discards it, so these files get the same
73357
+ * trigger-strategy frontmatter as the IDE's non-root rules.
73358
+ *
73359
+ * @see https://antigravity.google/docs/rules
73360
+ */
73361
+ var AntigravityCliRule = class AntigravityCliRule extends ToolRule {
73362
+ static getSettablePaths({ global, excludeToolDir } = {}) {
73363
+ if (global) return {
73364
+ root: {
73365
+ relativeDirPath: buildToolPath(ANTIGRAVITY_GEMINI_DIR, ".", excludeToolDir),
73366
+ relativeFilePath: ANTIGRAVITY_GLOBAL_RULE_FILE_NAME
73367
+ },
73368
+ nonRoot: { relativeDirPath: buildToolPath(ANTIGRAVITY_GEMINI_DIR, ANTIGRAVITY_GLOBAL_RULES_SUBDIR, excludeToolDir) }
73369
+ };
73370
+ return {
73371
+ root: {
73372
+ relativeDirPath: ".",
73373
+ relativeFilePath: ANTIGRAVITY_RULE_FILE_NAME
73374
+ },
73375
+ nonRoot: { relativeDirPath: buildToolPath(ANTIGRAVITY_AGENTS_DIR, "rules", excludeToolDir) }
73376
+ };
73377
+ }
73378
+ static async fromFile({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, validate = true, global = false }) {
73379
+ const paths = this.getSettablePaths({ global });
73380
+ if (relativeFilePath === paths.root.relativeFilePath && (relativeDirPath === void 0 || relativeDirPath === paths.root.relativeDirPath)) {
73381
+ const relativePath = paths.root.relativeFilePath;
73382
+ const fileContent = await readFileContent(join(outputRoot, paths.root.relativeDirPath, relativePath));
73383
+ return new AntigravityCliRule({
73384
+ outputRoot,
73385
+ relativeDirPath: paths.root.relativeDirPath,
73386
+ relativeFilePath: paths.root.relativeFilePath,
73387
+ fileContent,
73388
+ validate,
73389
+ root: true,
73390
+ global
73391
+ });
73392
+ }
73393
+ if (!paths.nonRoot) throw new Error(`nonRoot path is not set for ${relativeFilePath}`);
73394
+ const relativePath = join(paths.nonRoot.relativeDirPath, relativeFilePath);
73395
+ const fileContent = await readFileContent(join(outputRoot, relativePath));
73396
+ const rule = new AntigravityCliRule({
73397
+ outputRoot,
73398
+ relativeDirPath: paths.nonRoot.relativeDirPath,
73399
+ relativeFilePath,
73400
+ fileContent,
73401
+ validate,
73402
+ root: false,
73403
+ global
73404
+ });
73405
+ if (validate) {
73406
+ const result = rule.validate();
73407
+ if (!result.success) throw new Error(`Invalid frontmatter in ${relativePath}: ${result.error.message}`);
73408
+ }
73409
+ return rule;
73410
+ }
73411
+ static fromRulesyncRule({ outputRoot = process.cwd(), rulesyncRule, validate = true, global = false }) {
73412
+ const paths = this.getSettablePaths({ global });
73413
+ const params = this.buildToolRuleParamsDefault({
73414
+ outputRoot,
73415
+ rulesyncRule,
73416
+ validate,
73417
+ rootPath: paths.root,
73418
+ nonRootPath: paths.nonRoot
73419
+ });
73420
+ if (!global || params.root) return new AntigravityCliRule({
73421
+ ...params,
73422
+ global
73423
+ });
73424
+ const rulesyncFrontmatter = rulesyncRule.getFrontmatter();
73425
+ const storedAntigravity = rulesyncFrontmatter.antigravity;
73426
+ const storedTrigger = storedAntigravity?.trigger;
73427
+ const strategy = STRATEGIES$1.find((s) => s.canHandle(storedTrigger));
73428
+ if (!strategy) throw new Error(`No strategy found for trigger: ${storedTrigger}`);
73429
+ const frontmatter = strategy.generateFrontmatter(normalizeStoredAntigravity(storedAntigravity), rulesyncFrontmatter);
73430
+ return new AntigravityCliRule({
73431
+ ...params,
73432
+ relativeFilePath: params.relativeFilePath.split(/[\\/]/).join("-"),
73433
+ fileContent: stringifyFrontmatter(rulesyncRule.getBody(), frontmatter),
73434
+ global
73435
+ });
73436
+ }
73437
+ toRulesyncRule() {
73438
+ if (!this.global || this.root) return this.toRulesyncRuleDefault();
73439
+ const { frontmatter, body } = this.parseGlobalNonRootContent();
73440
+ const strategy = STRATEGIES$1.find((s) => s.canHandle(frontmatter.trigger));
73441
+ const rulesyncData = strategy ? strategy.exportRulesyncData(frontmatter) : {
73442
+ globs: [],
73443
+ antigravity: frontmatter
73444
+ };
73445
+ return new RulesyncRule({
73446
+ outputRoot: process.cwd(),
73447
+ relativeDirPath: RulesyncRule.getSettablePaths().recommended.relativeDirPath,
73448
+ relativeFilePath: this.getRelativeFilePath(),
73449
+ frontmatter: {
73450
+ root: false,
73451
+ targets: ["*"],
73452
+ ...rulesyncData,
73453
+ antigravity: {
73454
+ ...rulesyncData.antigravity,
73455
+ globs: frontmatter.globs ? parseGlobsString$1(frontmatter.globs) : void 0
73456
+ }
73457
+ },
73458
+ body
73459
+ });
73460
+ }
73461
+ validate() {
73462
+ if (!this.global || this.root) return {
73463
+ success: true,
73464
+ error: null
73465
+ };
73466
+ try {
73467
+ const { frontmatter } = this.parseGlobalNonRootContent();
73468
+ const result = AntigravityRuleFrontmatterSchema.safeParse(frontmatter);
73469
+ if (!result.success) return {
73470
+ success: false,
73471
+ error: new Error(formatError(result.error))
73472
+ };
73473
+ } catch (error) {
73474
+ return {
73475
+ success: false,
73476
+ error: error instanceof Error ? error : new Error(String(error))
73477
+ };
73478
+ }
73479
+ return {
73480
+ success: true,
73481
+ error: null
73482
+ };
73483
+ }
73484
+ /**
73485
+ * `~/.gemini/config/rules/` is shared with the Antigravity IDE and holds
73486
+ * global rules the user created outside rulesync, which cannot be told apart
73487
+ * from generated ones, so the orphan sweep never removes files there.
73488
+ */
73489
+ isDeletable() {
73490
+ return !this.global || this.root;
73491
+ }
73492
+ parseGlobalNonRootContent() {
73493
+ const { frontmatter, body } = parseFrontmatter(this.getFileContent(), this.getFilePath());
73494
+ return {
73495
+ frontmatter,
73496
+ body
73497
+ };
73498
+ }
73499
+ static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
73500
+ const paths = this.getSettablePaths({ global });
73501
+ const isRoot = relativeFilePath === paths.root.relativeFilePath && relativeDirPath === paths.root.relativeDirPath;
73502
+ return new AntigravityCliRule({
73503
+ outputRoot,
73504
+ relativeDirPath,
73505
+ relativeFilePath,
73506
+ fileContent: "",
73507
+ validate: false,
73508
+ root: isRoot,
73509
+ global
73510
+ });
73511
+ }
73512
+ static isTargetedByRulesyncRule(rulesyncRule) {
73513
+ return this.isTargetedByRulesyncRuleDefault({
73514
+ rulesyncRule,
73515
+ toolTarget: "antigravity-cli"
73516
+ });
73517
+ }
73518
+ };
73519
+ //#endregion
73377
73520
  //#region src/features/rules/antigravity-ide-rule.ts
73378
73521
  /**
73379
73522
  * Rule generator for the Google Antigravity IDE (Antigravity 2.0).
@@ -79000,7 +79143,9 @@ const toolRuleFactories = /* @__PURE__ */ new Map([
79000
79143
  meta: {
79001
79144
  extension: "md",
79002
79145
  supportsGlobal: true,
79003
- ruleDiscoveryMode: "toon"
79146
+ ruleDiscoveryMode: "toon",
79147
+ ruleDiscoveryModeGlobal: "auto",
79148
+ sharedGlobalNonRootDir: true
79004
79149
  }
79005
79150
  }],
79006
79151
  ["antigravity-ide", {
@@ -80079,7 +80224,7 @@ var RulesProcessor = class extends FeatureProcessor {
80079
80224
  */
80080
80225
  generateReferenceSectionFromMeta(meta, toolRules) {
80081
80226
  switch (resolveRuleDiscoveryMode({
80082
- defaultMode: meta.ruleDiscoveryMode,
80227
+ defaultMode: this.global && meta.ruleDiscoveryModeGlobal ? meta.ruleDiscoveryModeGlobal : meta.ruleDiscoveryMode,
80083
80228
  options: this.featureOptions
80084
80229
  })) {
80085
80230
  case "toon": return this.generateToonReferencesSection(toolRules);
@@ -80598,7 +80743,8 @@ As this project's AI coding tool, you must follow the additional conventions bel
80598
80743
  const nonRootToolRules = await (async () => {
80599
80744
  if (!settablePaths.nonRoot) return [];
80600
80745
  const nonRootOutputRoot = join(this.outputRoot, settablePaths.nonRoot.relativeDirPath);
80601
- const nonRootFilePaths = await findFilesByGlobs(`**/*.${factory.meta.extension}`, { cwd: nonRootOutputRoot });
80746
+ const isSharedGlobalNonRootDir = this.global && factory.meta.sharedGlobalNonRootDir === true;
80747
+ const nonRootFilePaths = await findFilesByGlobs(`${isSharedGlobalNonRootDir ? "" : "**/"}*.${factory.meta.extension}`, { cwd: nonRootOutputRoot });
80602
80748
  if (forDeletion) return buildDeletionRulesFromPaths(nonRootFilePaths, {
80603
80749
  outputRootOverride: nonRootOutputRoot,
80604
80750
  relativeDirPathOverride: settablePaths.nonRoot.relativeDirPath
@@ -80611,19 +80757,25 @@ As this project's AI coding tool, you must follow the additional conventions bel
80611
80757
  if (!ok) this.logger.warn(`Skipping reserved Rovodev path under modular-rules (import): ${join(modularRootRelative, relativeFilePath)}`);
80612
80758
  return ok;
80613
80759
  }) : nonRootFilePaths).filter((filePath) => rootFileNameInSameDir === void 0 || relative(nonRootOutputRoot, filePath) !== rootFileNameInSameDir);
80614
- return await Promise.all(nonRootPathsForImport.map((filePath) => {
80760
+ return (await Promise.all(nonRootPathsForImport.map(async (filePath) => {
80615
80761
  const relativeFilePath = relative(nonRootOutputRoot, filePath);
80616
80762
  checkPathTraversal({
80617
80763
  relativePath: relativeFilePath,
80618
80764
  intendedRootDir: nonRootOutputRoot
80619
80765
  });
80620
- return factory.class.fromFile({
80621
- outputRoot: this.outputRoot,
80622
- relativeDirPath: modularRootRelative,
80623
- relativeFilePath,
80624
- global: this.global
80625
- });
80626
- }));
80766
+ try {
80767
+ return await factory.class.fromFile({
80768
+ outputRoot: this.outputRoot,
80769
+ relativeDirPath: modularRootRelative,
80770
+ relativeFilePath,
80771
+ global: this.global
80772
+ });
80773
+ } catch (error) {
80774
+ if (!isSharedGlobalNonRootDir) throw error;
80775
+ this.logger.warn(`Skipping ${stripControlCharacters(join(modularRootRelative, relativeFilePath))} for ${this.toolTarget}: ${formatError(error)}`);
80776
+ return;
80777
+ }
80778
+ }))).filter((rule) => rule !== void 0);
80627
80779
  })();
80628
80780
  this.logger.debug(`Found ${nonRootToolRules.length} non-root tool rule files`);
80629
80781
  return [
@@ -82017,6 +82169,115 @@ function computeRootFileOwnership(params) {
82017
82169
  }
82018
82170
  return ownerByPath;
82019
82171
  }
82172
+ function createSkippedRootFileCheck({ rootFileOwner }) {
82173
+ const skippedByRoot = /* @__PURE__ */ new Map();
82174
+ const emittedByRoot = /* @__PURE__ */ new Map();
82175
+ const emittedKey = (toolTarget, relativePath) => `${toolTarget}\0${relativePath}`;
82176
+ const loadOwnerToolFiles = async (processor) => {
82177
+ const rulesyncFiles = await processor.loadRulesyncFiles();
82178
+ return {
82179
+ toolFiles: rulesyncFiles.length > 0 ? await processor.convertRulesyncFilesToToolFiles(rulesyncFiles) : [],
82180
+ sourceLoadFailed: processor.hasRulesyncSourceLoadFailure()
82181
+ };
82182
+ };
82183
+ return {
82184
+ observe: ({ toolTarget, outputRoot, processor, toolFiles, skipFilePaths }) => {
82185
+ if (rootFileOwner.size === 0) return;
82186
+ for (const toolFile of toolFiles) {
82187
+ const relativePath = toolFile.getRelativePathFromCwd();
82188
+ if (!rootFileOwner.has(relativePath)) continue;
82189
+ const emitted = emittedByRoot.get(outputRoot) ?? /* @__PURE__ */ new Set();
82190
+ emittedByRoot.set(outputRoot, emitted);
82191
+ emitted.add(emittedKey(toolTarget, relativePath));
82192
+ if (!skipFilePaths.has(relativePath)) continue;
82193
+ const skipped = skippedByRoot.get(outputRoot) ?? /* @__PURE__ */ new Map();
82194
+ skippedByRoot.set(outputRoot, skipped);
82195
+ skipped.set(relativePath, {
82196
+ processor,
82197
+ toolFile
82198
+ });
82199
+ }
82200
+ },
82201
+ verify: async ({ isOwnerProcessed, createOwnerProcessor }) => {
82202
+ let count = 0;
82203
+ const paths = [];
82204
+ let sourceLoadFailed = false;
82205
+ for (const [outputRoot, skipped] of skippedByRoot) {
82206
+ const ownerOutputs = /* @__PURE__ */ new Map();
82207
+ for (const [relativePath, fallback] of skipped) {
82208
+ const owner = rootFileOwner.get(relativePath);
82209
+ if (owner === void 0) continue;
82210
+ if (emittedByRoot.get(outputRoot)?.has(emittedKey(owner, relativePath))) continue;
82211
+ let expected = fallback;
82212
+ if (!isOwnerProcessed(owner)) {
82213
+ if (!ownerOutputs.has(owner)) {
82214
+ const processor = await createOwnerProcessor({
82215
+ toolTarget: owner,
82216
+ outputRoot
82217
+ });
82218
+ if (processor === void 0) ownerOutputs.set(owner, void 0);
82219
+ else {
82220
+ const loaded = await loadOwnerToolFiles(processor);
82221
+ if (loaded.sourceLoadFailed) sourceLoadFailed = true;
82222
+ ownerOutputs.set(owner, {
82223
+ processor,
82224
+ toolFiles: loaded.toolFiles
82225
+ });
82226
+ }
82227
+ }
82228
+ const ownerOutput = ownerOutputs.get(owner);
82229
+ const ownerFile = ownerOutput?.toolFiles.find((file) => file.getRelativePathFromCwd() === relativePath && file.getFilePath() === fallback.toolFile.getFilePath());
82230
+ if (ownerOutput !== void 0 && ownerFile !== void 0) expected = {
82231
+ processor: ownerOutput.processor,
82232
+ toolFile: ownerFile
82233
+ };
82234
+ }
82235
+ const result = await expected.processor.writeAiFiles([expected.toolFile]);
82236
+ count += result.count;
82237
+ paths.push(...result.paths);
82238
+ }
82239
+ }
82240
+ return {
82241
+ count,
82242
+ paths,
82243
+ hasDiff: count > 0,
82244
+ sourceLoadFailed
82245
+ };
82246
+ }
82247
+ };
82248
+ }
82249
+ /**
82250
+ * The skills a full `rulesync generate` hands to the rules step: what the
82251
+ * skills step collects for every config-file target that generates skills, in
82252
+ * the same order. Simulated skill sections in a root file list these, so a
82253
+ * narrowed check needs them to rebuild another target's root file.
82254
+ */
82255
+ async function loadConfigFileSkills({ config, logger }) {
82256
+ const supportedSkillsTargets = SkillsProcessor.getToolTargets({
82257
+ global: config.getGlobal(),
82258
+ includeSimulated: config.getSimulateSkills()
82259
+ });
82260
+ const skills = [];
82261
+ for (const toolTarget of intersection(config.getConfigFileTargets(), supportedSkillsTargets)) {
82262
+ if (!config.getConfigFileFeatures(toolTarget).includes("skills")) continue;
82263
+ for (const outputRoot of config.getOutputRoots(toolTarget)) {
82264
+ const processor = new SkillsProcessor({
82265
+ outputRoot: resolveToolOutputRoot({
82266
+ outputRoot,
82267
+ toolTarget,
82268
+ global: config.getGlobal()
82269
+ }),
82270
+ inputRoots: config.getInputRoots(),
82271
+ toolTarget,
82272
+ global: config.getGlobal(),
82273
+ dryRun: true,
82274
+ logger
82275
+ });
82276
+ for (const rulesyncDir of await processor.loadRulesyncDirs()) if (rulesyncDir instanceof RulesyncSkill) skills.push(rulesyncDir);
82277
+ }
82278
+ }
82279
+ return skills;
82280
+ }
82020
82281
  async function generateRulesCore(params) {
82021
82282
  const { config, logger, sweepPlan, skills } = params;
82022
82283
  let totalCount = 0;
@@ -82032,32 +82293,47 @@ async function generateRulesCore(params) {
82032
82293
  logger
82033
82294
  });
82034
82295
  const foldRootOverwriteWatch = createFoldRootOverwriteWatch({ logger });
82296
+ let fullRunSkills;
82297
+ const loadFullRunSkills = () => {
82298
+ fullRunSkills ??= loadConfigFileSkills({
82299
+ config,
82300
+ logger
82301
+ });
82302
+ return fullRunSkills;
82303
+ };
82304
+ const createProcessor = ({ toolTarget, outputRoot, featureOptions, skills: processorSkills }) => new RulesProcessor({
82305
+ outputRoot: resolveToolOutputRoot({
82306
+ outputRoot,
82307
+ toolTarget,
82308
+ global: config.getGlobal()
82309
+ }),
82310
+ inputRoots: config.getInputRoots(),
82311
+ toolTarget,
82312
+ global: config.getGlobal(),
82313
+ simulateCommands: config.getSimulateCommands(),
82314
+ simulateSubagents: config.getSimulateSubagents(),
82315
+ simulateSkills: config.getSimulateSkills(),
82316
+ language: config.getLanguage(),
82317
+ deriveSubprojectPathFromGlobs: config.getDeriveSubprojectPathFromGlobs(),
82318
+ skills: processorSkills,
82319
+ featureOptions,
82320
+ delete: config.getDelete(),
82321
+ dryRun: config.isPreviewMode(),
82322
+ logger
82323
+ });
82035
82324
  const isCheck = config.getCheck();
82036
82325
  const rootFileOwner = isCheck ? computeRootFileOwnership({
82037
- targets: config.getConfigFileTargets(),
82326
+ targets: config.getConfigFileTargets().filter((target) => (toolTargets.includes(target) ? config.getFeatures(target) : config.getConfigFileFeatures(target)).includes("rules")),
82038
82327
  global: config.getGlobal()
82039
82328
  }) : /* @__PURE__ */ new Map();
82329
+ const skippedRootFileCheck = createSkippedRootFileCheck({ rootFileOwner });
82040
82330
  for (const toolTarget of toolTargets) for (const outputRoot of config.getOutputRoots(toolTarget)) {
82041
82331
  if (!config.getFeatures(toolTarget).includes("rules")) continue;
82042
- const processor = new RulesProcessor({
82043
- outputRoot: resolveToolOutputRoot({
82044
- outputRoot,
82045
- toolTarget,
82046
- global: config.getGlobal()
82047
- }),
82048
- inputRoots: config.getInputRoots(),
82332
+ const processor = createProcessor({
82049
82333
  toolTarget,
82050
- global: config.getGlobal(),
82051
- simulateCommands: config.getSimulateCommands(),
82052
- simulateSubagents: config.getSimulateSubagents(),
82053
- simulateSkills: config.getSimulateSkills(),
82054
- language: config.getLanguage(),
82055
- deriveSubprojectPathFromGlobs: config.getDeriveSubprojectPathFromGlobs(),
82056
- skills,
82334
+ outputRoot,
82057
82335
  featureOptions: config.getFeatureOptions(toolTarget, "rules"),
82058
- delete: config.getDelete(),
82059
- dryRun: config.isPreviewMode(),
82060
- logger
82336
+ skills
82061
82337
  });
82062
82338
  const rulesyncFiles = await processor.loadRulesyncFiles();
82063
82339
  const skipFilePaths = /* @__PURE__ */ new Set();
@@ -82070,16 +82346,39 @@ async function generateRulesCore(params) {
82070
82346
  rulesyncFiles,
82071
82347
  sweepPlan,
82072
82348
  skipFilePaths: skipFilePaths.size > 0 ? skipFilePaths : void 0,
82073
- onToolFiles: (toolFiles) => foldRootOverwriteWatch.observe({
82074
- toolTarget,
82075
- toolFiles
82076
- })
82349
+ onToolFiles: (toolFiles) => {
82350
+ foldRootOverwriteWatch.observe({
82351
+ toolTarget,
82352
+ toolFiles
82353
+ });
82354
+ skippedRootFileCheck.observe({
82355
+ toolTarget,
82356
+ outputRoot,
82357
+ processor,
82358
+ toolFiles,
82359
+ skipFilePaths
82360
+ });
82361
+ }
82077
82362
  });
82078
82363
  totalCount += result.count;
82079
82364
  allPaths.push(...result.paths);
82080
82365
  if (result.hasDiff) hasDiff = true;
82081
82366
  if (result.sourceLoadFailed) sourceLoadFailed = true;
82082
82367
  }
82368
+ if (isCheck) {
82369
+ const skippedResult = await skippedRootFileCheck.verify({
82370
+ isOwnerProcessed: (owner) => toolTargets.includes(owner) && config.getFeatures(owner).includes("rules"),
82371
+ createOwnerProcessor: async (ownerParams) => supportedTargets.includes(ownerParams.toolTarget) && config.getOutputRoots(ownerParams.toolTarget).includes(ownerParams.outputRoot) ? createProcessor({
82372
+ ...ownerParams,
82373
+ featureOptions: config.getConfigFileFeatureOptions(ownerParams.toolTarget, "rules"),
82374
+ skills: config.getSimulateSkills() && SkillsProcessor.getToolTargetsSimulated().includes(ownerParams.toolTarget) ? await loadFullRunSkills() : void 0
82375
+ }) : void 0
82376
+ });
82377
+ totalCount += skippedResult.count;
82378
+ allPaths.push(...skippedResult.paths);
82379
+ if (skippedResult.hasDiff) hasDiff = true;
82380
+ if (skippedResult.sourceLoadFailed) sourceLoadFailed = true;
82381
+ }
82083
82382
  foldRootOverwriteWatch.report();
82084
82383
  return {
82085
82384
  count: totalCount,
@@ -82846,4 +83145,4 @@ async function importChecksCore(params) {
82846
83145
  //#endregion
82847
83146
  export { RulesyncCommand as $, toPosixPath as $t, CLAUDECODE_MEMORIES_DIR_NAME as A, RULESYNC_XDG_CONFIG_HOME_DEFAULT_DIR_NAME as An, checkPathTraversal as At, RulesyncSubagent as B, stripControlCharacters as Bn, listDirectoryEntryNames as Bt, COMMANDCODE_DIR as C, RULESYNC_PERMISSIONS_SCHEMA_URL as Cn, withWarnOnceScope as Ct, CODEXCLI_DIR as D, RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH as Dn, assertDirectoryIfExists as Dt, CODEXCLI_BASH_RULES_FILE_NAME as E, RULESYNC_SKILLS_RELATIVE_DIR_PATH as En, applyFileMode as Et, caseFoldIdentity as F, formatError as Fn, getFileSize as Ft, RulesyncRuleFrontmatterSchema as G, readFileContentOrNull as Gt, RulesyncSkill as H, stripHiddenCharacters as Hn, listSubdirectoryNames as Ht, groupSpellingsByCaseFoldedIdentity as I, truncateText as In, getHomeDirectory as It, RulesyncIgnore as J, removeFile as Jt, RulesyncPermissions as K, removeDirectory as Kt, AUGMENTCODE_DIR as L, hasDeceptiveHiddenCharacters as Ln, isFileNotFoundError as Lt, CLAUDECODE_SKILLS_DIR_PATH as M, ALL_FEATURES as Mn, directoryExists as Mt, FACTORYDROID_DIR as N, ALL_FEATURES_WITH_WILDCARD as Nn, ensureDir as Nt, CLAUDECODE_DIR as O, RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH as On, assertTreeContainsNoSymlinks as Ot, FACTORYDROID_SETTINGS_LOCAL_FILE_NAME as P, DEPRECATED_FEATURE_REPLACEMENTS as Pn, fileExists as Pt, parseJsonc as Q, runWithDirectoryRollback as Qt, AUGMENTCODE_SETTINGS_LOCAL_FILE_NAME as R, hasEnclosingMarkOutsideKeycap as Rn, isFileSystemError as Rt, QWENCODE_LOCAL_RULE_FILE_NAME as S, RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH as Sn, resetRunWarningState as St, ChecksProcessor as T, RULESYNC_RULES_RELATIVE_DIR_PATH as Tn, ErrorCodes as Tt, RulesyncSkillFrontmatterSchema as U, pathEscapesRoot as Ut, RulesyncSubagentFrontmatterSchema as V, stripControlCharactersKeepingLineFeeds as Vn, listFilePathsRecursively as Vt, RulesyncRule as W, readFileContent as Wt, getRulesyncSourceCandidates as X, removeTempDirectory as Xt, RulesyncHooks as Y, removeFileStrict as Yt, resolveRulesyncSourceWritePath as Z, resolvePath as Zt, IgnoreProcessor as _, RULESYNC_IGNORE_RELATIVE_FILE_PATH as _n, JsonLogger as _t, getProcessorRegistryEntry as a, ToolTargetSchema as an, SHARED_USER_MANAGED_CONFIG_PATHS as at, CommandsProcessor as b, RULESYNC_MCP_SCHEMA_URL as bn, warnOnConflictingFlags as bt, RulesProcessor as c, MAX_FILE_SIZE as cn, mergeInputRootConfigs as ct, CODEBUDDY_DIR as d, RULESYNC_COMMANDS_RELATIVE_DIR_PATH as dn, ConfigFileSchema as dt, writeFileBuffer as en, RulesyncCommandFrontmatterSchema as et, CODEBUDDY_LOCAL_RULE_FILE_NAME as f, RULESYNC_CONFIG_RELATIVE_FILE_PATH as fn, GITIGNORE_DESTINATION_KEY as ft, McpProcessor as g, RULESYNC_HOOKS_RELATIVE_FILE_PATH as gn, ConsoleLogger as gt, shortenToWidth as h, RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH as hn, findControlCharacter as ht, inspectInputRoots as i, PACKAGING_TOOL_TARGETS as in, loadYaml as it, CLAUDECODE_SETTINGS_LOCAL_FILE_NAME as j, parseCommaSeparatedList as jn, createTempDirectory as jt, CLAUDECODE_LOCAL_RULE_FILE_NAME as k, RULESYNC_USER_CONFIG_DIR_NAME as kn, assertWritablePathInsideRoot as kt, SubagentsProcessor as l, RULESYNC_AIIGNORE_RELATIVE_FILE_PATH as ln, resolveEffectiveInputRoots as lt, displayWidthOf as m, RULESYNC_CURATED_RULES_RELATIVE_DIR_PATH as mn, assertTargetsFeaturesExclusive as mt, formatSourceLoadFailure as n, ALL_TOOL_TARGETS as nn, RulesyncCheckFrontmatterSchema as nt, convertFromTool as o, CURATED_RULES_FEATURE_SUBDIR as on, SKILL_FILE_NAME as ot, ELLIPSIS_WIDTH as p, RULESYNC_CONFIG_SCHEMA_URL as pn, SourceEntrySchema as pt, RulesyncMcp as q, removeDirectoryStrict as qt, generate as r, ALL_TOOL_TARGETS_WITH_WILDCARD as rn, stringifyFrontmatter as rt, isPackagingToolTarget as s, FEATURE_SOURCE_TREE_ENTRIES as sn, ConfigResolver as st, importFromTool as t, writeFileContent as tn, RulesyncCheck as tt, SkillsProcessor as u, RULESYNC_CHECKS_RELATIVE_DIR_PATH as un, CONFLICTING_TARGET_PAIRS as ut, HooksProcessor as v, RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH as vn, WarningCollectingLogger as vt, COMMANDCODE_SETTINGS_LOCAL_FILE_NAME as w, RULESYNC_RELATIVE_DIR_PATH as wn, CLIError as wt, QWENCODE_DIR as x, RULESYNC_NPM_SOURCES_LOCK_RELATIVE_FILE_PATH as xn, withFallbackLoggerTarget as xt, CRUSH_LOCAL_RULE_FILE_NAME as y, RULESYNC_MCP_RELATIVE_FILE_PATH as yn, fallbackLogger as yt, getLocalSkillDirNames as z, quoteForLog as zn, isSymlink as zt };
82848
83147
 
82849
- //# sourceMappingURL=import-DNDrEvS2.js.map
83148
+ //# sourceMappingURL=import-CGIOcUpR.js.map