@webpieces/rules-config 0.4.539 → 0.4.540

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webpieces/rules-config",
3
- "version": "0.4.539",
3
+ "version": "0.4.540",
4
4
  "description": "Shared webpieces.config.json loader. Single source of truth for validation rule configuration consumed by @webpieces/ai-hook-rules, @webpieces/code-rules, and @webpieces/nx-webpieces-rules.",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -1,5 +1,4 @@
1
1
  export declare class ExcludePaths {
2
- readonly rules: string[];
3
- readonly guards: string[];
4
- constructor(rules: string[], guards: string[]);
2
+ readonly paths: string[];
3
+ constructor(paths: string[]);
5
4
  }
@@ -1,18 +1,24 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ExcludePaths = void 0;
4
- // Top-level `excludePaths` block from webpieces.config.json. Two independently-varying glob lists
5
- // that suppress hook enforcement for matching files (matched against the workspace-relative path):
6
- // - `rules` — paths where code-style rules are skipped (e.g. vendored repos under repositories/**).
7
- // - `guards` — paths where FILE-scoped guards (e.g. feature-branch-guard) are skipped. Bash git/PR
8
- // guards are unaffected they reason about git state, not a file location.
4
+ // Top-level `excludePaths` block from webpieces.config.json: ONE glob list that suppresses hook
5
+ // enforcement for matching files (matched against the workspace-relative path). A path listed here is
6
+ // hands-off for everything code-style rules AND file-scoped guards alike.
7
+ //
8
+ // It used to be TWO independently-varying lists, `rules` and `guards`. The split never earned its
9
+ // keep: every consumer set both to the same value, and the one case that would need them to differ
10
+ // (exclude a generated tree from style rules but keep the git guards on it) is already served better
11
+ // one level down, by a rule's OWN `excludePaths` inside its config block. A path is governed by
12
+ // webpieces or it is not, so the top-level block is a single list.
13
+ //
14
+ // BACK-COMPAT: the object form `{ "rules": [...], "guards": [...] }` is still accepted and UNIONED
15
+ // into one list, so a config written for the old schema keeps working unchanged. See
16
+ // LoadedConfigReader.parseExcludePaths.
9
17
  // Data-only (per CLAUDE.md, classes for data). Built once by loadAndValidate after validation.
10
18
  class ExcludePaths {
11
- rules;
12
- guards;
13
- constructor(rules, guards) {
14
- this.rules = rules;
15
- this.guards = guards;
19
+ paths;
20
+ constructor(paths) {
21
+ this.paths = paths;
16
22
  }
17
23
  }
18
24
  exports.ExcludePaths = ExcludePaths;
@@ -1 +1 @@
1
- {"version":3,"file":"exclude-hook-paths.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/exclude-hook-paths.ts"],"names":[],"mappings":";;;AAAA,kGAAkG;AAClG,mGAAmG;AACnG,sGAAsG;AACtG,oGAAoG;AACpG,0FAA0F;AAC1F,+FAA+F;AAC/F,MAAa,YAAY;IAER;IACA;IAFb,YACa,KAAe,EACf,MAAgB;QADhB,UAAK,GAAL,KAAK,CAAU;QACf,WAAM,GAAN,MAAM,CAAU;IAC1B,CAAC;CACP;AALD,oCAKC","sourcesContent":["// Top-level `excludePaths` block from webpieces.config.json. Two independently-varying glob lists\n// that suppress hook enforcement for matching files (matched against the workspace-relative path):\n// - `rules` — paths where code-style rules are skipped (e.g. vendored repos under repositories/**).\n// - `guards` paths where FILE-scoped guards (e.g. feature-branch-guard) are skipped. Bash git/PR\n// guards are unaffected they reason about git state, not a file location.\n// Data-only (per CLAUDE.md, classes for data). Built once by loadAndValidate after validation.\nexport class ExcludePaths {\n constructor(\n readonly rules: string[],\n readonly guards: string[],\n ) {}\n}\n"]}
1
+ {"version":3,"file":"exclude-hook-paths.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/exclude-hook-paths.ts"],"names":[],"mappings":";;;AAAA,gGAAgG;AAChG,sGAAsG;AACtG,4EAA4E;AAC5E,EAAE;AACF,kGAAkG;AAClG,mGAAmG;AACnG,qGAAqG;AACrG,gGAAgG;AAChG,mEAAmE;AACnE,EAAE;AACF,mGAAmG;AACnG,qFAAqF;AACrF,wCAAwC;AACxC,+FAA+F;AAC/F,MAAa,YAAY;IACA;IAArB,YAAqB,KAAe;QAAf,UAAK,GAAL,KAAK,CAAU;IAAG,CAAC;CAC3C;AAFD,oCAEC","sourcesContent":["// Top-level `excludePaths` block from webpieces.config.json: ONE glob list that suppresses hook\n// enforcement for matching files (matched against the workspace-relative path). A path listed here is\n// hands-off for everything code-style rules AND file-scoped guards alike.\n//\n// It used to be TWO independently-varying lists, `rules` and `guards`. The split never earned its\n// keep: every consumer set both to the same value, and the one case that would need them to differ\n// (exclude a generated tree from style rules but keep the git guards on it) is already served better\n// one level down, by a rule's OWN `excludePaths` inside its config block. A path is governed by\n// webpieces or it is not, so the top-level block is a single list.\n//\n// BACK-COMPAT: the object form `{ \"rules\": [...], \"guards\": [...] }` is still accepted and UNIONED\n// into one list, so a config written for the old schema keeps working unchanged. See\n// LoadedConfigReader.parseExcludePaths.\n// Data-only (per CLAUDE.md, classes for data). Built once by loadAndValidate after validation.\nexport class ExcludePaths {\n constructor(readonly paths: string[]) {}\n}\n"]}
@@ -67,7 +67,7 @@ let ConfigLoader = class ConfigLoader {
67
67
  const configPath = this.configFile.findConfigFile(cwd);
68
68
  if (!configPath) {
69
69
  const emptyCommands = (0, commands_config_1.buildCommandsConfig)(undefined);
70
- return new LoadedConfig(new types_1.ResolvedConfig(new Map(), new Set(), [], null), new WebpiecesRulesConfig_1.WebpiecesRulesConfig(), emptyCommands, emptyCommands.prGate, new exclude_hook_paths_1.ExcludePaths([], []), [], null);
70
+ return new LoadedConfig(new types_1.ResolvedConfig(new Map(), new Set(), [], null), new WebpiecesRulesConfig_1.WebpiecesRulesConfig(), emptyCommands, emptyCommands.prGate, new exclude_hook_paths_1.ExcludePaths([]), [], null);
71
71
  }
72
72
  const consumerConfig = this.configFile.readRawConfig(configPath);
73
73
  const rulesSection = this.normalizeDeprecatedKeys(consumerConfig.rules || {});
@@ -141,15 +141,21 @@ let ConfigLoader = class ConfigLoader {
141
141
  return new types_1.ResolvedRuleConfig(merged);
142
142
  }
143
143
  // Parse the (already-validated) raw excludePaths block into the typed ExcludePaths.
144
+ //
145
+ // CANONICAL shape is a bare string[]. The legacy object form `{ rules: [...], guards: [...] }` is
146
+ // still accepted and UNIONED into one list — a config written for the old two-list schema keeps
147
+ // working, and a path excluded from either list is excluded from everything, which is what every
148
+ // consumer already meant by setting both to the same value.
144
149
  // webpieces-disable no-any-unknown -- `raw` is opaque consumer JSON until narrowed here
145
150
  parseExcludePaths(raw) {
146
- if (typeof raw !== 'object' || raw === null || Array.isArray(raw))
147
- return new exclude_hook_paths_1.ExcludePaths([], []);
151
+ if (Array.isArray(raw))
152
+ return new exclude_hook_paths_1.ExcludePaths(raw.filter(p => typeof p === 'string'));
153
+ if (typeof raw !== 'object' || raw === null)
154
+ return new exclude_hook_paths_1.ExcludePaths([]);
148
155
  // webpieces-disable no-any-unknown -- validateExcludePaths already proved both are string[]
149
156
  const s = raw;
150
- const rules = Array.isArray(s['rules']) ? s['rules'].filter(p => typeof p === 'string') : [];
151
- const guards = Array.isArray(s['guards']) ? s['guards'].filter(p => typeof p === 'string') : [];
152
- return new exclude_hook_paths_1.ExcludePaths(rules, guards);
157
+ const legacy = [...(Array.isArray(s['rules']) ? s['rules'] : []), ...(Array.isArray(s['guards']) ? s['guards'] : [])];
158
+ return new exclude_hook_paths_1.ExcludePaths([...new Set(legacy.filter(p => typeof p === 'string'))]);
153
159
  }
154
160
  // Parse the (already-validated) raw match-rules array into typed MatchRuleConfig[]. The entries use
155
161
  // the canonical field names (turnOffRuleUntilEpoch / turnOffRuleWhileOnBranch) that the match-rules
@@ -1 +1 @@
1
- {"version":3,"file":"load-config.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/load-config.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from 'path';\nimport { injectable, bindingScopeValues } from 'inversify';\n\nimport { buildCommandsConfig, CommandsConfig } from './commands-config';\nimport { ConfigFile } from './config-file';\nimport { defaultRules } from './default-rules';\nimport { ExcludePaths } from './exclude-hook-paths';\nimport { InformAiError } from './inform-ai-error';\nimport { PrGateConfig } from './pr-gate-config';\nimport { ResolvedConfig, ResolvedRuleConfig, RuleOptions } from './types';\nimport { validateCommandsSection, validateExcludePaths, validateMatchRulesSection, validateSectionPlacement, validateWebpiecesConfig } from './validate-config';\nimport { MatchRuleConfig } from './match-rules-config';\nimport { WebpiecesRulesConfig } from './WebpiecesRulesConfig';\n\n/**\n * Everything a consumer might need from webpieces.config.json, produced from ONE parse + ONE\n * validation pass. Data-only (per CLAUDE.md, classes for data).\n */\nexport class LoadedConfig {\n // eslint-disable-next-line @typescript-eslint/max-params\n constructor(\n readonly resolved: ResolvedConfig,\n readonly rulesConfig: WebpiecesRulesConfig,\n readonly commands: CommandsConfig,\n readonly prGate: PrGateConfig,\n readonly excludePaths: ExcludePaths,\n readonly matchRules: readonly MatchRuleConfig[],\n readonly configPath: string | null,\n ) {}\n}\n\n// Config keys that were renamed. A project's webpieces.config.json may still use the OLD key (it can\n// legitimately lag the published rules-config by a release), so normalize any deprecated key to its\n// canonical name BEFORE validation/placement/loading — every downstream consumer then sees one name.\nconst DEPRECATED_RULE_ALIASES: Readonly<Record<string, string>> = {\n 'pr-merge-cleanup': 'pr-merge-guard',\n 'pr-creation-guard': 'pr-creation-or-push-guard',\n // Renamed once the guard grew a second blocked state (already-merged feature branch): it is no\n // longer about `main` at all, it is THE guard that can block a Read.\n 'main-stale-guard': 'read-stale-guard',\n};\n\n// webpieces-disable no-any-unknown -- opaque per-rule option bags from consumer JSON, validated later\ntype RuleSectionMap = Record<string, Record<string, unknown>>;\n\n/**\n * The single load+validate entry point for ALL consumers (ai-hook-rules, code-rules,\n * nx-webpieces-rules, pr-gate scripts). `@injectable(bindingScopeValues.Singleton)` + injects {@link ConfigFile} so it appears\n * in the rules-config DI design.\n */\n@injectable(bindingScopeValues.Singleton)\nexport class ConfigLoader {\n constructor(private readonly configFile: ConfigFile) {}\n\n /**\n * Reads webpieces.config.json once, validates BOTH the `rules` map and the top-level `pr-gate`\n * block, and throws one InformAiError listing every error. When no config file is found it returns\n * lenient empties/defaults (matching prior no-file behavior).\n */\n // webpieces-disable max-lines-new-methods -- the single load+validate pass is one cohesive method\n loadAndValidate(cwd: string): LoadedConfig {\n const configPath = this.configFile.findConfigFile(cwd);\n if (!configPath) {\n const emptyCommands = buildCommandsConfig(undefined);\n return new LoadedConfig(\n new ResolvedConfig(new Map(), new Set(), [], null),\n new WebpiecesRulesConfig(),\n emptyCommands,\n emptyCommands.prGate,\n new ExcludePaths([], []),\n [],\n null,\n );\n }\n\n const consumerConfig = this.configFile.readRawConfig(configPath);\n const rulesSection = this.normalizeDeprecatedKeys(consumerConfig.rules || {});\n const hookGuardsSection = this.normalizeDeprecatedKeys(consumerConfig.hookGuards || {});\n const legacyPrGate = consumerConfig['pr-gate'];\n\n // rules + hookGuards are validated/loaded as one flat name→config map (the runtime dispatches\n // by each rule's own `scope`). Placement is enforced separately.\n const overrideRules = { ...rulesSection, ...hookGuardsSection };\n\n const rulesDir = consumerConfig.rulesDir ?? [];\n\n // The repo root (dir holding webpieces.config.json) lets checklists[].docs existence be checked.\n const repoRoot = path.dirname(configPath);\n const errors = [\n ...validateWebpiecesConfig(overrideRules, rulesDir.length > 0),\n ...validateSectionPlacement(rulesSection, hookGuardsSection),\n ...validateCommandsSection(consumerConfig.commands, legacyPrGate, repoRoot),\n ...validateExcludePaths(consumerConfig.excludePaths),\n ...validateMatchRulesSection(consumerConfig['match-rules']),\n ];\n if (errors.length > 0) {\n throw new InformAiError(this.formatConfigErrorsBanner(errors));\n }\n\n const commands = buildCommandsConfig(consumerConfig.commands, legacyPrGate);\n this.applyCommandDefaults(overrideRules, commands);\n\n const userConfiguredRuleNames = new Set(Object.keys(overrideRules));\n const mergedRules = new Map<string, ResolvedRuleConfig>();\n const allRuleNames = new Set([\n ...Object.keys(defaultRules),\n ...Object.keys(overrideRules),\n ]);\n for (const name of allRuleNames) {\n mergedRules.set(name, this.mergeRule(defaultRules[name], overrideRules[name]));\n }\n const resolved = new ResolvedConfig(mergedRules, userConfiguredRuleNames, rulesDir, configPath);\n\n const rulesConfig = this.buildWebpiecesRulesConfig(overrideRules, rulesDir);\n const excludePaths = this.parseExcludePaths(consumerConfig.excludePaths);\n const matchRules = this.parseMatchRules(consumerConfig['match-rules']);\n\n return new LoadedConfig(resolved, rulesConfig, commands, commands.prGate, excludePaths, matchRules, configPath);\n }\n\n // Inject the canonical command strings (from the `commands` section) as the DEFAULT for the guards\n // that surface them in their fix hints. Only fills a gap — an explicit per-guard override wins.\n private applyCommandDefaults(\n // webpieces-disable no-any-unknown -- opaque merged rule/guard map\n rules: Record<string, Record<string, unknown>>,\n commands: CommandsConfig,\n ): void {\n const prCreation = rules['pr-creation-or-push-guard'];\n if (prCreation && prCreation['upsertPrCommand'] === undefined) {\n prCreation['upsertPrCommand'] = commands.upsertPr;\n }\n const mergeInProgress = rules['merge-in-progress-guard'];\n if (mergeInProgress && mergeInProgress['mergeCompleteCommand'] === undefined) {\n mergeInProgress['mergeCompleteCommand'] = commands.mergeComplete;\n }\n }\n\n // webpieces-disable no-any-unknown -- merging opaque option bags from config JSON\n private mergeRule(\n // webpieces-disable no-any-unknown -- opaque option bag\n baseRule: Record<string, unknown> | undefined,\n // webpieces-disable no-any-unknown -- opaque option bag\n overrideRule: Record<string, unknown> | undefined,\n ): ResolvedRuleConfig {\n if (!baseRule && !overrideRule) return new ResolvedRuleConfig({ mode: 'OFF' });\n if (!baseRule) return new ResolvedRuleConfig(overrideRule! as RuleOptions);\n if (!overrideRule) return new ResolvedRuleConfig(baseRule as RuleOptions);\n\n // webpieces-disable no-any-unknown -- building merged option bag\n const merged: Record<string, unknown> = {};\n for (const key of Object.keys(baseRule)) merged[key] = baseRule[key];\n for (const key of Object.keys(overrideRule)) merged[key] = overrideRule[key];\n return new ResolvedRuleConfig(merged as RuleOptions);\n }\n\n // Parse the (already-validated) raw excludePaths block into the typed ExcludePaths.\n // webpieces-disable no-any-unknown -- `raw` is opaque consumer JSON until narrowed here\n private parseExcludePaths(raw: unknown): ExcludePaths {\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) return new ExcludePaths([], []);\n // webpieces-disable no-any-unknown -- validateExcludePaths already proved both are string[]\n const s = raw as Record<string, string[]>;\n const rules = Array.isArray(s['rules']) ? s['rules'].filter(p => typeof p === 'string') : [];\n const guards = Array.isArray(s['guards']) ? s['guards'].filter(p => typeof p === 'string') : [];\n return new ExcludePaths(rules, guards);\n }\n\n // Parse the (already-validated) raw match-rules array into typed MatchRuleConfig[]. The entries use\n // the canonical field names (turnOffRuleUntilEpoch / turnOffRuleWhileOnBranch) that the match-rules\n // engine reads directly, so no normalization is needed.\n // webpieces-disable no-any-unknown -- validated array; each entry cast to the typed MatchRuleConfig\n private parseMatchRules(raw: unknown): MatchRuleConfig[] {\n if (!Array.isArray(raw)) return [];\n return raw as MatchRuleConfig[];\n }\n\n private buildWebpiecesRulesConfig(\n // webpieces-disable no-any-unknown -- JSON values are opaque until assigned to typed fields\n rawRules: Record<string, Record<string, unknown>>,\n rulesDir: string[],\n ): WebpiecesRulesConfig {\n const typed = new WebpiecesRulesConfig();\n for (const key of Object.keys(rawRules)) {\n // webpieces-disable no-any-unknown -- dynamic key assignment to typed class\n (typed as Record<string, unknown>)[key] = rawRules[key];\n }\n typed.rulesDir = rulesDir;\n return typed;\n }\n\n private normalizeDeprecatedKeys(section: RuleSectionMap): RuleSectionMap {\n const out: RuleSectionMap = {};\n for (const key of Object.keys(section)) {\n out[DEPRECATED_RULE_ALIASES[key] ?? key] = section[key];\n }\n return out;\n }\n\n // Assemble the validation-failure banner. Most of these errors are version skew, not bad config.\n private formatConfigErrorsBanner(errors: string[]): string {\n return (\n `webpieces.config.json has ${errors.length} validation error(s) — fix ALL, then retry:\\n\\n` +\n errors.map(e => ` • ${e}`).join('\\n') +\n `\\n\\n👉 FIX ORDER (do NOT start by deleting keys — that usually deletes VALID config):\\n` +\n ` 1. Run \\`pnpm install\\`. It is ALWAYS allowed through the guard (installer bypass), even ` +\n `while this config is invalid. This is the #1 cause: your installed @webpieces guard is a ` +\n `release BEHIND webpieces.config.json (a dep bump updated the config + lockfile, but ` +\n `node_modules here was never re-installed), so the running validator doesn't know the newer ` +\n `rule names/values yet. \\`pnpm install\\` syncs node_modules to the pinned version.\\n` +\n ` 2. Retry your command. If the errors are gone, you're DONE — do not touch webpieces.config.json.\\n` +\n ` 3. ONLY if an error survives a fresh install is it a genuine typo / removed / renamed rule. ` +\n `Then edit webpieces.config.json (edits to it are ALWAYS allowed) to fix each • above.`\n );\n }\n}\n\n// Temporary migration delegator — consumers migrate to injecting ConfigLoader over follow-up PRs,\n// then this free function is removed. The logic now lives in the injected ConfigLoader class.\nconst configLoaderSvc = new ConfigLoader(new ConfigFile());\n\n// webpieces-disable no-function-outside-class -- temporary back-compat delegator to ConfigLoader; removed once all 118 consumers inject it\nexport function loadAndValidate(cwd: string): LoadedConfig {\n return configLoaderSvc.loadAndValidate(cwd);\n}\n"]}
1
+ {"version":3,"file":"load-config.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/load-config.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from 'path';\nimport { injectable, bindingScopeValues } from 'inversify';\n\nimport { buildCommandsConfig, CommandsConfig } from './commands-config';\nimport { ConfigFile } from './config-file';\nimport { defaultRules } from './default-rules';\nimport { ExcludePaths } from './exclude-hook-paths';\nimport { InformAiError } from './inform-ai-error';\nimport { PrGateConfig } from './pr-gate-config';\nimport { ResolvedConfig, ResolvedRuleConfig, RuleOptions } from './types';\nimport { validateCommandsSection, validateExcludePaths, validateMatchRulesSection, validateSectionPlacement, validateWebpiecesConfig } from './validate-config';\nimport { MatchRuleConfig } from './match-rules-config';\nimport { WebpiecesRulesConfig } from './WebpiecesRulesConfig';\n\n/**\n * Everything a consumer might need from webpieces.config.json, produced from ONE parse + ONE\n * validation pass. Data-only (per CLAUDE.md, classes for data).\n */\nexport class LoadedConfig {\n // eslint-disable-next-line @typescript-eslint/max-params\n constructor(\n readonly resolved: ResolvedConfig,\n readonly rulesConfig: WebpiecesRulesConfig,\n readonly commands: CommandsConfig,\n readonly prGate: PrGateConfig,\n readonly excludePaths: ExcludePaths,\n readonly matchRules: readonly MatchRuleConfig[],\n readonly configPath: string | null,\n ) {}\n}\n\n// Config keys that were renamed. A project's webpieces.config.json may still use the OLD key (it can\n// legitimately lag the published rules-config by a release), so normalize any deprecated key to its\n// canonical name BEFORE validation/placement/loading — every downstream consumer then sees one name.\nconst DEPRECATED_RULE_ALIASES: Readonly<Record<string, string>> = {\n 'pr-merge-cleanup': 'pr-merge-guard',\n 'pr-creation-guard': 'pr-creation-or-push-guard',\n // Renamed once the guard grew a second blocked state (already-merged feature branch): it is no\n // longer about `main` at all, it is THE guard that can block a Read.\n 'main-stale-guard': 'read-stale-guard',\n};\n\n// webpieces-disable no-any-unknown -- opaque per-rule option bags from consumer JSON, validated later\ntype RuleSectionMap = Record<string, Record<string, unknown>>;\n\n/**\n * The single load+validate entry point for ALL consumers (ai-hook-rules, code-rules,\n * nx-webpieces-rules, pr-gate scripts). `@injectable(bindingScopeValues.Singleton)` + injects {@link ConfigFile} so it appears\n * in the rules-config DI design.\n */\n@injectable(bindingScopeValues.Singleton)\nexport class ConfigLoader {\n constructor(private readonly configFile: ConfigFile) {}\n\n /**\n * Reads webpieces.config.json once, validates BOTH the `rules` map and the top-level `pr-gate`\n * block, and throws one InformAiError listing every error. When no config file is found it returns\n * lenient empties/defaults (matching prior no-file behavior).\n */\n // webpieces-disable max-lines-new-methods -- the single load+validate pass is one cohesive method\n loadAndValidate(cwd: string): LoadedConfig {\n const configPath = this.configFile.findConfigFile(cwd);\n if (!configPath) {\n const emptyCommands = buildCommandsConfig(undefined);\n return new LoadedConfig(\n new ResolvedConfig(new Map(), new Set(), [], null),\n new WebpiecesRulesConfig(),\n emptyCommands,\n emptyCommands.prGate,\n new ExcludePaths([]),\n [],\n null,\n );\n }\n\n const consumerConfig = this.configFile.readRawConfig(configPath);\n const rulesSection = this.normalizeDeprecatedKeys(consumerConfig.rules || {});\n const hookGuardsSection = this.normalizeDeprecatedKeys(consumerConfig.hookGuards || {});\n const legacyPrGate = consumerConfig['pr-gate'];\n\n // rules + hookGuards are validated/loaded as one flat name→config map (the runtime dispatches\n // by each rule's own `scope`). Placement is enforced separately.\n const overrideRules = { ...rulesSection, ...hookGuardsSection };\n\n const rulesDir = consumerConfig.rulesDir ?? [];\n\n // The repo root (dir holding webpieces.config.json) lets checklists[].docs existence be checked.\n const repoRoot = path.dirname(configPath);\n const errors = [\n ...validateWebpiecesConfig(overrideRules, rulesDir.length > 0),\n ...validateSectionPlacement(rulesSection, hookGuardsSection),\n ...validateCommandsSection(consumerConfig.commands, legacyPrGate, repoRoot),\n ...validateExcludePaths(consumerConfig.excludePaths),\n ...validateMatchRulesSection(consumerConfig['match-rules']),\n ];\n if (errors.length > 0) {\n throw new InformAiError(this.formatConfigErrorsBanner(errors));\n }\n\n const commands = buildCommandsConfig(consumerConfig.commands, legacyPrGate);\n this.applyCommandDefaults(overrideRules, commands);\n\n const userConfiguredRuleNames = new Set(Object.keys(overrideRules));\n const mergedRules = new Map<string, ResolvedRuleConfig>();\n const allRuleNames = new Set([\n ...Object.keys(defaultRules),\n ...Object.keys(overrideRules),\n ]);\n for (const name of allRuleNames) {\n mergedRules.set(name, this.mergeRule(defaultRules[name], overrideRules[name]));\n }\n const resolved = new ResolvedConfig(mergedRules, userConfiguredRuleNames, rulesDir, configPath);\n\n const rulesConfig = this.buildWebpiecesRulesConfig(overrideRules, rulesDir);\n const excludePaths = this.parseExcludePaths(consumerConfig.excludePaths);\n const matchRules = this.parseMatchRules(consumerConfig['match-rules']);\n\n return new LoadedConfig(resolved, rulesConfig, commands, commands.prGate, excludePaths, matchRules, configPath);\n }\n\n // Inject the canonical command strings (from the `commands` section) as the DEFAULT for the guards\n // that surface them in their fix hints. Only fills a gap — an explicit per-guard override wins.\n private applyCommandDefaults(\n // webpieces-disable no-any-unknown -- opaque merged rule/guard map\n rules: Record<string, Record<string, unknown>>,\n commands: CommandsConfig,\n ): void {\n const prCreation = rules['pr-creation-or-push-guard'];\n if (prCreation && prCreation['upsertPrCommand'] === undefined) {\n prCreation['upsertPrCommand'] = commands.upsertPr;\n }\n const mergeInProgress = rules['merge-in-progress-guard'];\n if (mergeInProgress && mergeInProgress['mergeCompleteCommand'] === undefined) {\n mergeInProgress['mergeCompleteCommand'] = commands.mergeComplete;\n }\n }\n\n // webpieces-disable no-any-unknown -- merging opaque option bags from config JSON\n private mergeRule(\n // webpieces-disable no-any-unknown -- opaque option bag\n baseRule: Record<string, unknown> | undefined,\n // webpieces-disable no-any-unknown -- opaque option bag\n overrideRule: Record<string, unknown> | undefined,\n ): ResolvedRuleConfig {\n if (!baseRule && !overrideRule) return new ResolvedRuleConfig({ mode: 'OFF' });\n if (!baseRule) return new ResolvedRuleConfig(overrideRule! as RuleOptions);\n if (!overrideRule) return new ResolvedRuleConfig(baseRule as RuleOptions);\n\n // webpieces-disable no-any-unknown -- building merged option bag\n const merged: Record<string, unknown> = {};\n for (const key of Object.keys(baseRule)) merged[key] = baseRule[key];\n for (const key of Object.keys(overrideRule)) merged[key] = overrideRule[key];\n return new ResolvedRuleConfig(merged as RuleOptions);\n }\n\n // Parse the (already-validated) raw excludePaths block into the typed ExcludePaths.\n //\n // CANONICAL shape is a bare string[]. The legacy object form `{ rules: [...], guards: [...] }` is\n // still accepted and UNIONED into one list — a config written for the old two-list schema keeps\n // working, and a path excluded from either list is excluded from everything, which is what every\n // consumer already meant by setting both to the same value.\n // webpieces-disable no-any-unknown -- `raw` is opaque consumer JSON until narrowed here\n private parseExcludePaths(raw: unknown): ExcludePaths {\n if (Array.isArray(raw)) return new ExcludePaths(raw.filter(p => typeof p === 'string'));\n if (typeof raw !== 'object' || raw === null) return new ExcludePaths([]);\n // webpieces-disable no-any-unknown -- validateExcludePaths already proved both are string[]\n const s = raw as Record<string, string[]>;\n const legacy = [...(Array.isArray(s['rules']) ? s['rules'] : []), ...(Array.isArray(s['guards']) ? s['guards'] : [])];\n return new ExcludePaths([...new Set(legacy.filter(p => typeof p === 'string'))]);\n }\n\n // Parse the (already-validated) raw match-rules array into typed MatchRuleConfig[]. The entries use\n // the canonical field names (turnOffRuleUntilEpoch / turnOffRuleWhileOnBranch) that the match-rules\n // engine reads directly, so no normalization is needed.\n // webpieces-disable no-any-unknown -- validated array; each entry cast to the typed MatchRuleConfig\n private parseMatchRules(raw: unknown): MatchRuleConfig[] {\n if (!Array.isArray(raw)) return [];\n return raw as MatchRuleConfig[];\n }\n\n private buildWebpiecesRulesConfig(\n // webpieces-disable no-any-unknown -- JSON values are opaque until assigned to typed fields\n rawRules: Record<string, Record<string, unknown>>,\n rulesDir: string[],\n ): WebpiecesRulesConfig {\n const typed = new WebpiecesRulesConfig();\n for (const key of Object.keys(rawRules)) {\n // webpieces-disable no-any-unknown -- dynamic key assignment to typed class\n (typed as Record<string, unknown>)[key] = rawRules[key];\n }\n typed.rulesDir = rulesDir;\n return typed;\n }\n\n private normalizeDeprecatedKeys(section: RuleSectionMap): RuleSectionMap {\n const out: RuleSectionMap = {};\n for (const key of Object.keys(section)) {\n out[DEPRECATED_RULE_ALIASES[key] ?? key] = section[key];\n }\n return out;\n }\n\n // Assemble the validation-failure banner. Most of these errors are version skew, not bad config.\n private formatConfigErrorsBanner(errors: string[]): string {\n return (\n `webpieces.config.json has ${errors.length} validation error(s) — fix ALL, then retry:\\n\\n` +\n errors.map(e => ` • ${e}`).join('\\n') +\n `\\n\\n👉 FIX ORDER (do NOT start by deleting keys — that usually deletes VALID config):\\n` +\n ` 1. Run \\`pnpm install\\`. It is ALWAYS allowed through the guard (installer bypass), even ` +\n `while this config is invalid. This is the #1 cause: your installed @webpieces guard is a ` +\n `release BEHIND webpieces.config.json (a dep bump updated the config + lockfile, but ` +\n `node_modules here was never re-installed), so the running validator doesn't know the newer ` +\n `rule names/values yet. \\`pnpm install\\` syncs node_modules to the pinned version.\\n` +\n ` 2. Retry your command. If the errors are gone, you're DONE — do not touch webpieces.config.json.\\n` +\n ` 3. ONLY if an error survives a fresh install is it a genuine typo / removed / renamed rule. ` +\n `Then edit webpieces.config.json (edits to it are ALWAYS allowed) to fix each • above.`\n );\n }\n}\n\n// Temporary migration delegator — consumers migrate to injecting ConfigLoader over follow-up PRs,\n// then this free function is removed. The logic now lives in the injected ConfigLoader class.\nconst configLoaderSvc = new ConfigLoader(new ConfigFile());\n\n// webpieces-disable no-function-outside-class -- temporary back-compat delegator to ConfigLoader; removed once all 118 consumers inject it\nexport function loadAndValidate(cwd: string): LoadedConfig {\n return configLoaderSvc.loadAndValidate(cwd);\n}\n"]}
@@ -11,10 +11,15 @@ export declare function validateWebpiecesConfig(rawRules: Record<string, Record<
11
11
  */
12
12
  export declare function validatePrGateSection(section: unknown, repoRoot?: string): string[];
13
13
  /**
14
- * Validate the REQUIRED top-level `excludePaths` block: two independent glob lists (`rules`,
15
- * `guards`) that suppress hook enforcement per file path. Required so every client upgrading is
14
+ * Validate the REQUIRED top-level `excludePaths` block: ONE glob list suppressing hook enforcement per
15
+ * file path, for code-style rules and file-scoped guards alike. Required so every client upgrading is
16
16
  * forced to declare it (as [] to keep today's behavior, or with real paths). Returns copy-paste
17
17
  * friendly errors and never throws — same contract as validatePrGateSection.
18
+ *
19
+ * The legacy object form `{ "rules": [...], "guards": [...] }` is STILL ACCEPTED and unioned into one
20
+ * list by parseExcludePaths, so an unmigrated config validates and behaves identically. Rejecting it
21
+ * would deadlock every consumer on upgrade: the block is required, so a hard error here blocks every
22
+ * Bash/Edit including the edit that would fix it.
18
23
  */
19
24
  export declare function validateExcludePaths(section: unknown): string[];
20
25
  /**
@@ -356,12 +356,10 @@ function validatePrGateSection(section, repoRoot) {
356
356
  return errors;
357
357
  }
358
358
  function excludePathsExample() {
359
- return '"excludePaths": {\n' +
360
- ' "rules": ["repositories/**"],\n' +
361
- ' "guards": []\n' +
362
- ' }';
359
+ return '"excludePaths": ["repositories/**"]';
363
360
  }
364
- // One of the two excludePaths lists: required, must be a string[] (may be empty).
361
+ // A glob list: must be a string[] (may be empty). `key` names it for the error, so the legacy
362
+ // two-list form can report which of its lists is malformed.
365
363
  // webpieces-disable no-any-unknown -- `value` is opaque consumer JSON until narrowed here
366
364
  function validateExcludeList(value, key) {
367
365
  if (!(Array.isArray(value) && value.every(p => typeof p === 'string'))) {
@@ -370,27 +368,39 @@ function validateExcludeList(value, key) {
370
368
  return [];
371
369
  }
372
370
  /**
373
- * Validate the REQUIRED top-level `excludePaths` block: two independent glob lists (`rules`,
374
- * `guards`) that suppress hook enforcement per file path. Required so every client upgrading is
371
+ * Validate the REQUIRED top-level `excludePaths` block: ONE glob list suppressing hook enforcement per
372
+ * file path, for code-style rules and file-scoped guards alike. Required so every client upgrading is
375
373
  * forced to declare it (as [] to keep today's behavior, or with real paths). Returns copy-paste
376
374
  * friendly errors and never throws — same contract as validatePrGateSection.
375
+ *
376
+ * The legacy object form `{ "rules": [...], "guards": [...] }` is STILL ACCEPTED and unioned into one
377
+ * list by parseExcludePaths, so an unmigrated config validates and behaves identically. Rejecting it
378
+ * would deadlock every consumer on upgrade: the block is required, so a hard error here blocks every
379
+ * Bash/Edit including the edit that would fix it.
377
380
  */
378
381
  // webpieces-disable no-any-unknown -- `section` is opaque consumer JSON until narrowed below
379
382
  function validateExcludePaths(section) {
380
383
  if (section === undefined || section === null) {
381
384
  return [
382
385
  `[excludePaths] Not configured in webpieces.config.json. Add this REQUIRED block ` +
383
- `(use empty arrays to keep enforcing everywhere):\n\n ${excludePathsExample()}`,
386
+ `(use an empty array to keep enforcing everywhere):\n\n ${excludePathsExample()}`,
384
387
  ];
385
388
  }
386
- if (typeof section !== 'object' || Array.isArray(section)) {
387
- return [`[excludePaths] Must be an object with "rules" and "guards" string arrays. Example:\n\n ${excludePathsExample()}`];
389
+ if (Array.isArray(section))
390
+ return validateExcludeList(section, 'excludePaths');
391
+ if (typeof section !== 'object') {
392
+ return [`[excludePaths] Must be a string[] of glob paths. Example:\n\n ${excludePathsExample()}`];
388
393
  }
394
+ // Legacy two-list form — validate each list it actually declares, then let parseExcludePaths union
395
+ // them. An object carrying neither key is a typo, not a legacy config, so say so.
389
396
  // webpieces-disable no-any-unknown -- narrowing the opaque excludePaths section from consumer JSON
390
397
  const s = section;
398
+ if (s['rules'] === undefined && s['guards'] === undefined) {
399
+ return [`[excludePaths] Must be a string[] of glob paths. Example:\n\n ${excludePathsExample()}`];
400
+ }
391
401
  return [
392
- ...validateExcludeList(s['rules'], 'rules'),
393
- ...validateExcludeList(s['guards'], 'guards'),
402
+ ...(s['rules'] === undefined ? [] : validateExcludeList(s['rules'], 'rules')),
403
+ ...(s['guards'] === undefined ? [] : validateExcludeList(s['guards'], 'guards')),
394
404
  ];
395
405
  }
396
406
  // ---------------------------------------------------------------------------
@@ -1 +1 @@
1
- {"version":3,"file":"validate-config.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/validate-config.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\nimport { FieldDef } from './field-def';\nimport { sectionForRule, isHookGuard } from './sections';\nimport { MODIFIED_CODE_MODES } from './rule-configs';\nimport {\n FeatureBranchGuardConfig,\n ReadStaleGuardConfig,\n MergedBranchBashGuardConfig,\n StaleMainBashGuardConfig,\n} from './main-sync-guard-configs';\nimport { validateChecklistsSection, validateLandPrSection, validateNoGateSaltRationale } from './pr-gate-section-validators';\n\n// Re-exported so the isolated validate-checklist-docs target keeps importing it from here.\nexport { validateChecklistsSection };\nimport { DEFAULT_MATCH_RULES } from './match-rules-config';\nimport { toError } from './to-error';\nimport {\n MaxMethodLinesConfig,\n MaxFileLinesConfig,\n RequireReturnTypeConfig,\n NoInlineTypeLiteralsConfig,\n NoAnyUnknownConfig,\n NoImplicitAnyConfig,\n PrismaValidateDtosConfig,\n PrismaConverterConfig,\n NoDestructureConfig,\n NoUnmanagedExceptionsConfig,\n CatchErrorPatternConfig,\n ThrowCauseRequiredConfig,\n AngularNoDirectApiInResolverConfig,\n NoSymbolDiTokensConfig,\n NoCustomCssConfig,\n NoProcessExitOutsideMainConfig,\n NoFunctionOutsideClassConfig,\n InjectAnnotationNotNeededForConcreteClassConfig,\n FrameworkTagConfig,\n RoleTagConfig,\n BranchCreationGuardConfig,\n PrCreationOrPushGuardConfig,\n MergeInProgressGuardConfig,\n PrMergeGuardConfig,\n RedirectHowToMergeMainConfig,\n NoFileImportCyclesConfig,\n RuntimeArchitectureConfig,\n NxWiringConfig,\n DiGraphConfig,\n MissingDesignAnnotationConfig,\n NoJsFilesConfig,\n ValidateTsInSrcConfig,\n ValidateArchitectureUnchangedConfig,\n ValidateNoArchitectureCyclesConfig,\n ValidatePackageJsonConfig,\n ValidateVersionsLockedConfig,\n ValidateEslintSyncConfig,\n} from './rule-configs';\nimport { NoClientCreationOutsideServerOrClientConfig } from './no-client-creation-config';\n\n// Thin lookup table — each entry delegates to the class's own SCHEMA.\n// No field lists here; all schemas live with their config class.\nconst RULE_SCHEMAS: Record<string, Record<string, FieldDef>> = {\n 'max-method-lines': MaxMethodLinesConfig.SCHEMA,\n 'max-file-lines': MaxFileLinesConfig.SCHEMA,\n 'require-return-type': RequireReturnTypeConfig.SCHEMA,\n 'no-inline-type-literals': NoInlineTypeLiteralsConfig.SCHEMA,\n 'no-any-unknown': NoAnyUnknownConfig.SCHEMA,\n 'no-implicit-any': NoImplicitAnyConfig.SCHEMA,\n 'prisma-validate-dtos': PrismaValidateDtosConfig.SCHEMA,\n 'prisma-converter': PrismaConverterConfig.SCHEMA,\n 'no-destructure': NoDestructureConfig.SCHEMA,\n 'no-unmanaged-exceptions': NoUnmanagedExceptionsConfig.SCHEMA,\n 'catch-error-pattern': CatchErrorPatternConfig.SCHEMA,\n 'throw-cause-required': ThrowCauseRequiredConfig.SCHEMA,\n 'angular-no-direct-api-in-resolver': AngularNoDirectApiInResolverConfig.SCHEMA,\n 'no-symbol-di-tokens': NoSymbolDiTokensConfig.SCHEMA,\n 'no-client-creation-outside-server-or-client': NoClientCreationOutsideServerOrClientConfig.SCHEMA,\n 'no-custom-css': NoCustomCssConfig.SCHEMA,\n 'no-process-exit-outside-main': NoProcessExitOutsideMainConfig.SCHEMA,\n 'no-function-outside-class': NoFunctionOutsideClassConfig.SCHEMA,\n 'inject-annotation-not-needed-for-concrete-class': InjectAnnotationNotNeededForConcreteClassConfig.SCHEMA,\n 'framework-tag': FrameworkTagConfig.SCHEMA,\n 'role-tag': RoleTagConfig.SCHEMA,\n 'branch-creation-guard': BranchCreationGuardConfig.SCHEMA,\n 'pr-creation-or-push-guard': PrCreationOrPushGuardConfig.SCHEMA,\n 'merge-in-progress-guard': MergeInProgressGuardConfig.SCHEMA,\n 'pr-merge-guard': PrMergeGuardConfig.SCHEMA,\n 'redirect-how-to-merge-main': RedirectHowToMergeMainConfig.SCHEMA,\n 'feature-branch-guard': FeatureBranchGuardConfig.SCHEMA,\n 'read-stale-guard': ReadStaleGuardConfig.SCHEMA,\n 'merged-branch-bash-guard': MergedBranchBashGuardConfig.SCHEMA,\n 'stale-main-bash-guard': StaleMainBashGuardConfig.SCHEMA,\n 'no-file-import-cycles': NoFileImportCyclesConfig.SCHEMA,\n 'runtime-architecture': RuntimeArchitectureConfig.SCHEMA,\n 'nx-wiring': NxWiringConfig.SCHEMA,\n 'di-graph': DiGraphConfig.SCHEMA,\n 'missing-design-annotation': MissingDesignAnnotationConfig.SCHEMA,\n 'no-js-files': NoJsFilesConfig.SCHEMA,\n 'validate-ts-in-src': ValidateTsInSrcConfig.SCHEMA,\n 'validate-architecture-unchanged': ValidateArchitectureUnchangedConfig.SCHEMA,\n 'validate-no-architecture-cycles': ValidateNoArchitectureCyclesConfig.SCHEMA,\n 'validate-packagejson': ValidatePackageJsonConfig.SCHEMA,\n 'validate-versions-locked': ValidateVersionsLockedConfig.SCHEMA,\n 'validate-eslint-sync': ValidateEslintSyncConfig.SCHEMA,\n};\n\n// Every built-in rule name that has a typed schema (code rules + bash guards). The installer uses\n// this (with sectionForRule) to seed a fresh webpieces.config.json with every rule in its section.\nexport function allRuleNames(): readonly string[] {\n return Object.keys(RULE_SCHEMAS);\n}\n\nfunction valueHint(def: FieldDef, key?: string): string {\n // The two universal escape hatches, REQUIRED on every rule so they're always visible. Spell out the\n // \"off\" value so a fresh config seeds them in the active/no-op state (0 / null), not a placeholder.\n if (key === 'turnOffRuleUntilEpoch') return '0 (0 = active; future unix-epoch seconds = temporarily off)';\n if (key === 'turnOffRuleWhileOnBranch') return 'null (null = always on; a branch name disables the rule while that branch is checked out)';\n return def.enumValues\n ? `\"${def.enumValues.join(' | ')}\"`\n : def.type === 'string[]' ? '[\"<string>\", ...]'\n : def.type === 'number' ? '<number>'\n : def.type === 'boolean' ? '<boolean>'\n : '\"<string>\"';\n}\n\n// Scoped modes (narrowest → broadest) that enforce ONLY on what changed, so a rule can be\n// adopted gradually instead of all-at-once. When a rule offers one, recommend the first it\n// supports so a fresh config opts into a low-friction rollout rather than reflexively OFF.\nconst GRADUAL_MODE_PREFERENCE = [\n 'MODIFIED_PROJECTS',\n 'NEW_AND_MODIFIED_CODE',\n 'NEW_AND_MODIFIED_METHODS',\n 'MODIFIED_CLASS',\n 'NEW_METHODS',\n 'NEW_AND_MODIFIED_FILES',\n];\n\n/** A rollout hint for the copy-paste snippet: recommend the narrowest gradual mode the rule supports. */\nfunction rolloutTip(schema: Record<string, FieldDef>): string {\n const modes = schema['mode']?.enumValues ?? [];\n const recommended = GRADUAL_MODE_PREFERENCE.find((m: string) => modes.includes(m));\n if (!recommended) return '';\n const optOut = modes.includes('OFF') ? ' Set \"mode\": \"OFF\" to opt out entirely.' : '';\n return (\n `\\n\\n💡 Recommended: start with \"mode\": \"${recommended}\" — it enforces only on what you ` +\n `actually change, so the rule rolls out gradually (existing code stays grandfathered until ` +\n `you next touch that project/file/method).${optOut}`\n );\n}\n\nfunction missingRuleSnippet(ruleName: string, schema: Record<string, FieldDef>): string {\n // Required fields go in the copy-paste entry. The two universal escape hatches\n // (turnOffRuleUntilEpoch / turnOffRuleWhileOnBranch) are now REQUIRED, so they land in that block —\n // which is the whole point: every seeded rule shows both hatches. Optional fields are listed separately.\n const fields = Object.keys(schema);\n const required = fields.filter(f => !schema[f].optional);\n const optional = fields.filter(f => schema[f].optional);\n\n const requiredLines = required.map(f => ` \"${f}\": ${valueHint(schema[f], f)}`);\n const section = sectionForRule(ruleName);\n let out =\n `[${ruleName}] Not configured in webpieces.config.json. Add this entry to the \"${section}\" section\\n` +\n `(choose values appropriate for your project):\\n\\n` +\n ` \"${ruleName}\": {\\n${requiredLines.join(',\\n')}\\n }`;\n\n if (optional.length > 0) {\n const optionalLines = optional.map(f => ` \"${f}\": ${valueHint(schema[f], f)}`);\n out +=\n `\\n\\nOptional fields you may add to this rule (omit if not needed):\\n` +\n `${optionalLines.join(',\\n')}`;\n }\n out += rolloutTip(schema);\n return out;\n}\n\n// A config key under rules/hookGuards that the RUNNING validator has no schema for (and no rulesDir is\n// set to supply custom rules). Two very different causes, so the message leads with the common one:\n// 1. Version skew (most common — happens right after a dep bump): webpieces.config.json references a\n// rule a NEWER @webpieces release added, but the installed guard is OLDER and doesn't know it yet.\n// Fix = `pnpm install` (NOT deleting the key — the key is valid, the validator is just stale).\n// 2. A genuinely removed/renamed rule left behind, or a typo. Fix = remove the key.\n// Do NOT tell the AI to delete first — that destroys valid config in case 1 (the trap that made the AI\n// gut a working config instead of running `pnpm install`). The banner in load-config.ts spells out the\n// ordered \"run pnpm install, THEN edit only if it persists\" fix.\nfunction unknownRuleError(ruleName: string): string {\n return (\n `[${ruleName}] Unknown rule — the running @webpieces validator has no schema for it, and no ` +\n `\"rulesDir\" is configured to supply custom rules. Most often this means your installed guard is a ` +\n `release BEHIND this webpieces.config.json: run \\`pnpm install\\` first (see the fix steps below) so ` +\n `the validator learns \"${ruleName}\". Only if it is STILL unknown after a fresh install is it a ` +\n `removed/renamed rule or a typo — then remove the \"${ruleName}\" key from webpieces.config.json.`\n );\n}\n\n// Fields we DELETED from a rule's schema, keyed by \"<rule>.<field>\". The generic unknown-field error\n// (\"Unknown field ... Valid fields: [...]\") is correct but doesn't say WHY the field vanished, so an AI\n// might re-add it. These hints explain the removal so the only action left is to delete the key.\nconst RETIRED_FIELD_HINTS: Record<string, string> = {\n 'runtime-architecture.servicePaths':\n 'This field was removed — it was never read. The runtime graph is derived automatically from ' +\n 'architecture/dependencies.json (apiRelations + project roles). Delete it.',\n 'runtime-architecture.apiProjectPaths':\n 'This field was removed — it was never read. The runtime graph is derived automatically from ' +\n 'architecture/dependencies.json, so there is NO list of api libs to maintain. Delete it (do not ' +\n 'enumerate api libs and do not replace it with a glob).',\n};\n\n// Universal field renames (apply to EVERY rule/guard AND every match-rule, unlike the per-rule\n// RETIRED_FIELD_HINTS). When an entry still uses the old escape-hatch name, the generic unknown-field\n// error is replaced with a precise \"renamed to X — rename it\" instruction so the fix is mechanical.\nconst RENAMED_FIELD_ALIASES: Record<string, string> = {\n ignoreModifiedUntilEpoch: 'turnOffRuleUntilEpoch',\n ignoreRuleWhileOnBranch: 'turnOffRuleWhileOnBranch',\n};\n\n// The renamed-field message shared by keyed rules and match-rules.\n// webpieces-disable no-function-outside-class -- module-level config validator, matches the rest of this file\nfunction renamedFieldError(scope: string, oldKey: string, newKey: string): string {\n return `${scope} Unknown field \"${oldKey}\" — it was renamed to \"${newKey}\". Rename it (the value carries over unchanged; for the branch hatch, use null when there is no branch).`;\n}\n\n// webpieces-disable no-any-unknown -- rawRules values are opaque JSON; each field is validated individually\nexport function validateWebpiecesConfig(\n rawRules: Record<string, Record<string, unknown>>,\n hasCustomRulesDir: boolean = false,\n): string[] {\n const errors: string[] = [];\n\n // Check field-level correctness for rules that are present\n for (const [ruleName, entry] of Object.entries(rawRules)) {\n const schema = RULE_SCHEMAS[ruleName];\n if (!schema) {\n // No built-in schema. With no rulesDir there are no custom rules, so this key is a\n // dead/typo'd entry — tell the AI to remove it (a removed rule like no-shell-substitution\n // lingers here otherwise). With a rulesDir it may be a legitimate custom rule → skip.\n if (!hasCustomRulesDir) errors.push(unknownRuleError(ruleName));\n continue;\n }\n for (const [key, value] of Object.entries(entry)) {\n const fieldDef = schema[key];\n if (!fieldDef) {\n const renamedTo = RENAMED_FIELD_ALIASES[key];\n if (renamedTo) {\n errors.push(renamedFieldError(`[${ruleName}]`, key, renamedTo));\n continue;\n }\n const retiredHint = RETIRED_FIELD_HINTS[`${ruleName}.${key}`];\n const suffix = retiredHint ? ` ${retiredHint}` : '';\n errors.push(`[${ruleName}] Unknown field \"${key}\". Valid fields: [${Object.keys(schema).join(', ')}].${suffix}`);\n continue;\n }\n // A nullable field (e.g. turnOffRuleWhileOnBranch) accepts JSON null in addition to its type.\n if (value === null && fieldDef.nullable) continue;\n if (fieldDef.type === 'string[]') {\n if (!Array.isArray(value) || !value.every(v => typeof v === 'string'))\n errors.push(`[${ruleName}] \"${key}\" must be string[], got ${typeof value}.`);\n } else if (typeof value !== fieldDef.type) {\n errors.push(`[${ruleName}] \"${key}\" must be ${fieldDef.type}, got ${typeof value}.`);\n } else if (fieldDef.enumValues && !fieldDef.enumValues.includes(value as string)) {\n errors.push(`[${ruleName}] \"${key}\" = \"${value}\" is not valid. Must be one of: ${fieldDef.enumValues.join(', ')}.`);\n }\n }\n // Required fields must actually be present. Until now the loop above only checked\n // fields that WERE present, so an entry like `{}` (or one missing `mode` /\n // `turnOffRuleUntilEpoch`) slipped through. Every non-optional schema field is mandatory.\n for (const [key, fieldDef] of Object.entries(schema)) {\n if (!fieldDef.optional && !(key in entry)) {\n errors.push(`[${ruleName}] Missing required field \"${key}\". Add ${key}: ${valueHint(fieldDef, key)}.`);\n }\n }\n }\n\n // Every built-in rule must be explicitly configured — no silent defaults.\n // When a new rule is added to the framework, this check surfaces it immediately\n // with a ready-to-copy snippet so AI can configure it in one pass.\n for (const [ruleName, schema] of Object.entries(RULE_SCHEMAS)) {\n if (!(ruleName in rawRules)) {\n errors.push(missingRuleSnippet(ruleName, schema));\n }\n }\n\n return errors;\n}\n\nconst PR_GATE_MODES = ['ON', 'OFF'] as const;\n// Optional — omitted means DETECT. Kept inline (like prGateExample) to avoid a load-config ↔\n// pr-gate-config import cycle; the canonical list + semantics live in pr-gate-config.ts.\nconst PR_GATE_MERGE_MODES = ['AUTO', 'NONE'] as const;\n\n// Spelled out because the choice is a POLICY decision with a consequence the chooser cannot see:\n// only the AUTO path can put the compact risk/flags body in main's history, because a UI merge is\n// limited to the repo's squash_merge_commit_title/message settings and no setting produces it.\nconst MERGE_MODE_HELP = (\n `Must be one of: ${PR_GATE_MERGE_MODES.join(', ')}.\\n` +\n ` \"AUTO\" — wp-finish-upsert-pr lands the PR: it squash-merges when mergeable, else enables\\n` +\n ` GitHub auto-merge, both with an explicit --subject/--body-file so main's history\\n` +\n ` gets the PR title + the compact risk/flags body. Needs allow_auto_merge on the repo\\n` +\n ` (gh api repos/{owner}/{repo} --jq .allow_auto_merge).\\n` +\n ` \"NONE\" — wp-finish-upsert-pr only opens/updates the PR; a human merges it. The compact body\\n` +\n ` is then impossible, so set the repo's squash_merge_commit_title to PR_TITLE or\\n` +\n ` commits land as the internal \"Squash merge of <branch>\" subject.`\n);\n\n// Copy-paste example for the top-level `pr-gate` block (sibling of `rules`). Kept inline rather\n// than imported from pr-gate-config.ts to avoid a load-config ↔ pr-gate-config import cycle.\nfunction prGateExample(): string {\n return (\n ` \"pr-gate\": {\\n` +\n ` \"mode\": \"ON\",\\n` +\n ` \"buildCommand\": \"<command CI runs to validate a PR, e.g. pnpm nx affected --target=ci --base=$(git merge-base origin/main HEAD)>\",\\n` +\n ` \"gates\": [\\n` +\n ` { \"name\": \"API Changed\", \"patterns\": [\"libraries/apis/**\", \"**/*Api.ts\"], \"warningColor\": \"yellow\" }\\n` +\n ` ],\\n` +\n ` \"checklists\": [ // OPTIONAL — per-area review, one distinct reviewer subagent each\\n` +\n ` { \"subagent\": \"db-migration-reviewer\", \"doc\": \".claude/review/db-migrations.md\", \"patterns\": [\"**/*.sql\"] }\\n` +\n ` ]\\n` +\n ` }`\n );\n}\n\n// The `gates` array: dashboard-only warning flags. Extracted from validatePrGateSection to keep that\n// method inside the length limit.\n// webpieces-disable no-any-unknown -- `value` is the opaque consumer `gates` value until narrowed here\n// webpieces-disable no-function-outside-class -- module-level config validator, matches the rest of this file\nfunction validateGatesSection(value: unknown): string[] {\n if (!Array.isArray(value)) {\n return [`[pr-gate] \"gates\" must be an array of { name, patterns, warningColor, disabled? }.`];\n }\n const errors: string[] = [];\n for (let i = 0; i < value.length; i += 1) {\n errors.push(...validateGate(value[i], i));\n }\n return errors;\n}\n\n// webpieces-disable no-any-unknown -- one gate entry from opaque consumer JSON, validated field-by-field\nfunction validateGate(gate: unknown, index: number): string[] {\n if (typeof gate !== 'object' || gate === null) {\n return [`[pr-gate] gates[${index}] must be an object { name, patterns, warningColor, disabled? }.`];\n }\n // webpieces-disable no-any-unknown -- narrowing one opaque gate object from consumer JSON\n const g = gate as Record<string, unknown>;\n const errors: string[] = [];\n if (typeof g['name'] !== 'string') errors.push(`[pr-gate] gates[${index}].name must be a string.`);\n if (!Array.isArray(g['patterns']) || !g['patterns'].every(p => typeof p === 'string'))\n errors.push(`[pr-gate] gates[${index}].patterns must be string[].`);\n if (g['warningColor'] === undefined)\n errors.push(`[pr-gate] gates[${index}].warningColor is required — set it to \"yellow\" or \"red\" (green is implicit when nothing matches).`);\n else if (g['warningColor'] !== 'yellow' && g['warningColor'] !== 'red')\n errors.push(`[pr-gate] gates[${index}].warningColor must be \"yellow\" or \"red\" (green is implicit when nothing matches).`);\n if (g['disabled'] !== undefined && typeof g['disabled'] !== 'boolean')\n errors.push(`[pr-gate] gates[${index}].disabled must be a boolean (example/inactive gate kept in the file).`);\n return errors;\n}\n\n/**\n * Validate the top-level `pr-gate` section. It is REQUIRED (a client that opts out sets mode \"OFF\").\n * `buildCommand` is required unless mode is \"OFF\". Returns human-readable, copy-paste-friendly errors\n * — never throws. The pr-gate block lives outside the FieldDef-driven `rules` schema because its\n * nested `gates`/`checklists` arrays can't be expressed there, so they get structural validation here.\n * `repoRoot` (when known) lets the `checklists[].docs` existence check run.\n */\n// webpieces-disable no-any-unknown -- `section` is opaque consumer JSON until narrowed below\n// webpieces-disable no-function-outside-class -- module-level config validator, matches the rest of this file\nexport function validatePrGateSection(section: unknown, repoRoot?: string): string[] {\n if (section === undefined || section === null) {\n return [\n `[pr-gate] Not configured in webpieces.config.json. Add this block under the \"commands\" ` +\n `section (set \"mode\": \"OFF\" to opt out):\\n\\n${prGateExample()}`,\n ];\n }\n if (typeof section !== 'object' || Array.isArray(section)) {\n return [`[pr-gate] Must be an object. Example:\\n\\n${prGateExample()}`];\n }\n // webpieces-disable no-any-unknown -- narrowing the opaque pr-gate section from consumer JSON\n const s = section as Record<string, unknown>;\n const errors: string[] = [];\n\n if (!('mode' in s)) {\n errors.push(`[pr-gate] Missing required field \"mode\". Must be one of: ${PR_GATE_MODES.join(', ')}.`);\n } else if (typeof s['mode'] !== 'string' || !PR_GATE_MODES.includes(s['mode'] as typeof PR_GATE_MODES[number])) {\n errors.push(`[pr-gate] \"mode\" = \"${String(s['mode'])}\" is not valid. Must be one of: ${PR_GATE_MODES.join(', ')}.`);\n }\n\n // buildCommand and mergeMode are both required whenever the gate is active (mode !== OFF). There\n // is deliberately NO default for mergeMode: whether the tooling may land your PRs is a policy\n // decision, and either guess is wrong for somebody.\n if (s['mode'] !== 'OFF') {\n const cmd = s['buildCommand'];\n if (typeof cmd !== 'string' || cmd.trim() === '') {\n errors.push(\n `[pr-gate] Missing required field \"buildCommand\" — the command CI runs to validate a PR. ` +\n `Add e.g. \"buildCommand\": \"pnpm nx affected --target=ci --base=$(git merge-base origin/main HEAD)\".`,\n );\n }\n const mm = s['mergeMode'];\n if (!('mergeMode' in s)) {\n errors.push(`[pr-gate] Missing required field \"mergeMode\". ${MERGE_MODE_HELP}`);\n } else if (typeof mm !== 'string' || !PR_GATE_MERGE_MODES.includes(mm as typeof PR_GATE_MERGE_MODES[number])) {\n errors.push(`[pr-gate] \"mergeMode\" = \"${String(mm)}\" is not valid. ${MERGE_MODE_HELP}`);\n }\n }\n\n if ('gates' in s) errors.push(...validateGatesSection(s['gates']));\n\n // Optional extension point: company review checklists, as an ARRAY right here in the config. Absent ⇒\n // none. The removed { doc } manifest shape is rejected with the exact migration edit.\n if ('checklists' in s) errors.push(...validateChecklistsSection(s['checklists'], repoRoot));\n\n // Optional server-token salt. Absent ⇒ no token minted, CI enforcement is a no-op. Present ⇒ must be\n // a non-empty string (an empty salt would mint a token anyone can forge from a known-empty secret).\n if ('gateSalt' in s) {\n const salt = s['gateSalt'];\n if (typeof salt !== 'string' || salt.trim() === '') {\n errors.push(`[pr-gate] \"gateSalt\" must be a non-empty string — it is the shared secret the gate token is HMAC'd with. Omit the key entirely to disable server-side token enforcement.`);\n }\n }\n\n // Optional: what happens to the LOCAL branch once its PR lands. Absent ⇒ \"archive-tag\".\n if ('landPr' in s) errors.push(...validateLandPrSection(s['landPr']));\n\n errors.push(...validateNoGateSaltRationale(s));\n\n // Optional: publish reviewer output as a PR comment (defaults true). Must be a boolean when present.\n if ('checklistComments' in s && typeof s['checklistComments'] !== 'boolean') {\n errors.push(`[pr-gate] \"checklistComments\" must be a boolean (defaults to true; set false to keep the PR body-only).`);\n }\n\n return errors;\n}\n\nfunction excludePathsExample(): string {\n return '\"excludePaths\": {\\n' +\n ' \"rules\": [\"repositories/**\"],\\n' +\n ' \"guards\": []\\n' +\n ' }';\n}\n\n// One of the two excludePaths lists: required, must be a string[] (may be empty).\n// webpieces-disable no-any-unknown -- `value` is opaque consumer JSON until narrowed here\nfunction validateExcludeList(value: unknown, key: string): string[] {\n if (!(Array.isArray(value) && value.every(p => typeof p === 'string'))) {\n return [`[excludePaths] \"${key}\" must be a string[] of glob paths (use [] for none).`];\n }\n return [];\n}\n\n/**\n * Validate the REQUIRED top-level `excludePaths` block: two independent glob lists (`rules`,\n * `guards`) that suppress hook enforcement per file path. Required so every client upgrading is\n * forced to declare it (as [] to keep today's behavior, or with real paths). Returns copy-paste\n * friendly errors and never throws — same contract as validatePrGateSection.\n */\n// webpieces-disable no-any-unknown -- `section` is opaque consumer JSON until narrowed below\nexport function validateExcludePaths(section: unknown): string[] {\n if (section === undefined || section === null) {\n return [\n `[excludePaths] Not configured in webpieces.config.json. Add this REQUIRED block ` +\n `(use empty arrays to keep enforcing everywhere):\\n\\n ${excludePathsExample()}`,\n ];\n }\n if (typeof section !== 'object' || Array.isArray(section)) {\n return [`[excludePaths] Must be an object with \"rules\" and \"guards\" string arrays. Example:\\n\\n ${excludePathsExample()}`];\n }\n // webpieces-disable no-any-unknown -- narrowing the opaque excludePaths section from consumer JSON\n const s = section as Record<string, unknown>;\n return [\n ...validateExcludeList(s['rules'], 'rules'),\n ...validateExcludeList(s['guards'], 'guards'),\n ];\n}\n\n// ---------------------------------------------------------------------------\n// match-rules — a new top-level ARRAY section (parallel to pr-gate/excludePaths). Each entry is a\n// client-authored content guard (raw-regex patterns + message + scoping). Validated structurally here\n// the same way pr-gate's `gates` are, because an array of objects can't be expressed in FieldDef schema.\n// ---------------------------------------------------------------------------\n\nfunction matchRulesExample(): string {\n return `\"match-rules\": ${JSON.stringify(DEFAULT_MATCH_RULES, null, 4)}`;\n}\n\n// webpieces-disable no-any-unknown -- generic type guard over an opaque JSON value\nfunction isStringArray(value: unknown): value is string[] {\n return Array.isArray(value) && value.every(v => typeof v === 'string');\n}\n\n// Compile a pattern to validate it; returns the error message, or undefined when it compiles.\nfunction regexError(pattern: string): string | undefined {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n // Constructed only to validate the syntax; the object is intentionally discarded.\n void new RegExp(pattern);\n return undefined;\n } catch (err: unknown) {\n const error = toError(err);\n return error.message;\n }\n}\n\n// One entry of the match-rules array, validated field-by-field (see validateGate for the pattern).\n// webpieces-disable no-any-unknown -- one match-rule entry from opaque consumer JSON, validated field-by-field\nfunction validateMatchRule(entry: unknown, index: number): string[] {\n if (typeof entry !== 'object' || entry === null || Array.isArray(entry)) {\n return [`[match-rules] entry[${index}] must be an object { name, patterns, mainMessage, mode, turnOffRuleUntilEpoch, turnOffRuleWhileOnBranch, ... }.`];\n }\n // webpieces-disable no-any-unknown -- narrowing one opaque match-rule entry from consumer JSON\n const e = entry as Record<string, unknown>;\n const label = typeof e['name'] === 'string' ? `\"${e['name']}\"` : `entry[${index}]`;\n const errors: string[] = [];\n\n if (typeof e['name'] !== 'string' || e['name'].trim() === '')\n errors.push(`[match-rules] entry[${index}].name must be a non-empty string (it is the disable token and report label).`);\n\n if (!isStringArray(e['patterns']) || e['patterns'].length === 0) {\n errors.push(`[match-rules] ${label}.patterns must be a non-empty string[] of regexes.`);\n } else {\n e['patterns'].forEach((p: string, pi: number) => {\n const rxErr = regexError(p);\n if (rxErr) errors.push(`[match-rules] ${label}.patterns[${pi}] is not a valid regex: ${rxErr}`);\n });\n }\n\n if (typeof e['mainMessage'] !== 'string' || e['mainMessage'].trim() === '')\n errors.push(`[match-rules] ${label}.mainMessage must be a non-empty string.`);\n\n if (typeof e['mode'] !== 'string' || !MODIFIED_CODE_MODES.includes(e['mode'] as typeof MODIFIED_CODE_MODES[number]))\n errors.push(`[match-rules] ${label}.mode must be one of: ${MODIFIED_CODE_MODES.join(', ')}.`);\n\n // Both escape hatches are REQUIRED on every match-rule too (same as keyed rules), so they are always\n // visible. turnOffRuleUntilEpoch: number (0 = active; a future unix-epoch in seconds = temporarily\n // off). turnOffRuleWhileOnBranch: string | null (null = always on; a branch name disables the rule\n // while that branch is checked out).\n if (typeof e['turnOffRuleUntilEpoch'] !== 'number')\n errors.push(`[match-rules] ${label}.turnOffRuleUntilEpoch must be a number (0 = active; future unix-epoch seconds = temporarily off).`);\n if (!(e['turnOffRuleWhileOnBranch'] === null || typeof e['turnOffRuleWhileOnBranch'] === 'string'))\n errors.push(`[match-rules] ${label}.turnOffRuleWhileOnBranch must be a string or null (null = no branch / always on).`);\n\n // The old escape-hatch names were renamed — flag them precisely.\n for (const oldKey of Object.keys(RENAMED_FIELD_ALIASES)) {\n if (oldKey in e) errors.push(renamedFieldError(`[match-rules] ${label}`, oldKey, RENAMED_FIELD_ALIASES[oldKey]));\n }\n\n if (e['options'] !== undefined && !isStringArray(e['options']))\n errors.push(`[match-rules] ${label}.options must be a string[] (omit if not needed).`);\n if (e['allowedPaths'] !== undefined && !isStringArray(e['allowedPaths']))\n errors.push(`[match-rules] ${label}.allowedPaths must be a string[] of globs (omit if not needed).`);\n if (e['disableAllowed'] !== undefined && typeof e['disableAllowed'] !== 'boolean')\n errors.push(`[match-rules] ${label}.disableAllowed must be a boolean.`);\n\n return errors;\n}\n\n/**\n * Validate the REQUIRED top-level `match-rules` array (client-authored content guards). MISSING →\n * one error printing the ready-to-paste `no-fetch` example (add at least this; more can follow).\n * Present-but-`[]` → allowed (a conscious opt-out, matching pr-gate mode:OFF / excludePaths []).\n * Otherwise every entry is validated field-by-field (each regex compile-checked) plus name\n * uniqueness. Copy-paste-friendly errors; never throws — same contract as validatePrGateSection.\n */\n// webpieces-disable no-any-unknown -- `section` is opaque consumer JSON until narrowed below\nexport function validateMatchRulesSection(section: unknown): string[] {\n if (section === undefined || section === null) {\n return [\n `[match-rules] Not configured in webpieces.config.json. Add this REQUIRED top-level array — ` +\n `seed it with the no-fetch guard below (you can add more entries: no-moment, no-lodash-chain, …):\\n\\n${matchRulesExample()}`,\n ];\n }\n if (!Array.isArray(section)) {\n return [`[match-rules] Must be an array of content-guard objects. Example:\\n\\n${matchRulesExample()}`];\n }\n\n const errors: string[] = [];\n const seen = new Set<string>();\n for (let i = 0; i < section.length; i += 1) {\n errors.push(...validateMatchRule(section[i], i));\n // webpieces-disable no-any-unknown -- reading the name off an opaque entry only to dedupe\n const name = (section[i] as Record<string, unknown> | null)?.['name'];\n if (typeof name === 'string') {\n if (seen.has(name)) errors.push(`[match-rules] duplicate entry name \"${name}\" — each match-rule name must be unique.`);\n seen.add(name);\n }\n }\n return errors;\n}\n\n/**\n * Enforce that each built-in lives in its correct section: code rules under `rules`, bash guards\n * under `hookGuards`. A guard left in `rules` (or a rule placed in `hookGuards`) is reported with a\n * \"move it\" message so the split stays clean. Unknown/custom names are ignored (they may be custom\n * rules from rulesDir). Presence (\"every built-in must be configured\") is checked separately by\n * validateWebpiecesConfig against the merged map.\n */\n// webpieces-disable no-any-unknown -- section maps are opaque consumer JSON\nexport function validateSectionPlacement(\n rulesSection: Record<string, Record<string, unknown>>,\n hookGuardsSection: Record<string, Record<string, unknown>>,\n): string[] {\n const errors: string[] = [];\n for (const name of Object.keys(rulesSection)) {\n if (isHookGuard(name)) {\n errors.push(\n `[${name}] is a hook guard and belongs in the \"hookGuards\" section, not \"rules\". ` +\n `Move it (or run \\`pnpm wp-install-ai-hooks --sync\\` to migrate automatically).`,\n );\n }\n }\n for (const name of Object.keys(hookGuardsSection)) {\n // Only flag KNOWN code rules misplaced into hookGuards; unknown names may be custom rules.\n if (!isHookGuard(name) && RULE_SCHEMAS[name]) {\n errors.push(\n `[${name}] is a code rule and belongs in the \"rules\" section, not \"hookGuards\". ` +\n `Move it (or run \\`pnpm wp-install-ai-hooks --sync\\` to migrate automatically).`,\n );\n }\n }\n return errors;\n}\n\n/**\n * Validate the `commands` section: its `pr-gate` block (delegated to validatePrGateSection) plus the\n * optional command-string fields. Also surfaces a migration error if a DEPRECATED top-level `pr-gate`\n * block is still present, telling the consumer to move it under `commands`.\n */\n// webpieces-disable no-any-unknown -- `commands`/`legacyPrGate` are opaque consumer JSON\n// webpieces-disable no-function-outside-class -- module-level config validator, matches the rest of this file\nexport function validateCommandsSection(commands: unknown, legacyPrGate: unknown, repoRoot?: string): string[] {\n const errors: string[] = [];\n\n if (legacyPrGate !== undefined) {\n errors.push(\n `[pr-gate] The top-level \"pr-gate\" block is deprecated. Move it under the \"commands\" ` +\n `section as commands[\"pr-gate\"] (run \\`pnpm wp-install-ai-hooks --sync\\` to migrate automatically).`,\n );\n }\n\n if (commands !== undefined && (typeof commands !== 'object' || commands === null || Array.isArray(commands))) {\n errors.push(`[commands] Must be an object { \"pr-gate\": {...}, \"upsertPr\": \"...\", \"mergeComplete\": \"...\" }.`);\n return errors;\n }\n\n // webpieces-disable no-any-unknown -- narrowing the opaque commands section from consumer JSON\n const c = (commands ?? {}) as Record<string, unknown>;\n\n // pr-gate is required (set mode OFF to opt out). Prefer commands[\"pr-gate\"]; fall back to the\n // legacy top-level block so an un-migrated file still validates its gate config.\n errors.push(...validatePrGateSection(c['pr-gate'] ?? legacyPrGate, repoRoot));\n\n // Canonical guard-hint strings live under commands.guardHints; each value, when present, must be a\n // non-empty command string. The two names bind to the two guards that surface them in fix hints.\n const hints = c['guardHints'];\n if (hints !== undefined) {\n if (typeof hints !== 'object' || hints === null || Array.isArray(hints)) {\n errors.push(`[commands] \"guardHints\" must be an object { \"prCreationOrPush\": \"...\", \"mergeInProgress\": \"...\" }.`);\n } else {\n // webpieces-disable no-any-unknown -- narrowing the opaque guardHints object from consumer JSON\n const h = hints as Record<string, unknown>;\n for (const field of ['prCreationOrPush', 'mergeInProgress']) {\n if (field in h && (typeof h[field] !== 'string' || (h[field] as string).trim() === '')) {\n errors.push(`[commands] \"guardHints.${field}\" must be a non-empty string (the gated command to run).`);\n }\n }\n }\n }\n\n // Legacy FLAT command strings (pre-guardHints). Still accepted for back-compat; a migrated file\n // uses commands.guardHints instead.\n for (const field of ['upsertPr', 'mergeComplete']) {\n if (field in c && typeof c[field] !== 'string') {\n errors.push(`[commands] \"${field}\" must be a string (the gated command to run).`);\n }\n }\n\n return errors;\n}\n"]}
1
+ {"version":3,"file":"validate-config.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/validate-config.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\nimport { FieldDef } from './field-def';\nimport { sectionForRule, isHookGuard } from './sections';\nimport { MODIFIED_CODE_MODES } from './rule-configs';\nimport {\n FeatureBranchGuardConfig,\n ReadStaleGuardConfig,\n MergedBranchBashGuardConfig,\n StaleMainBashGuardConfig,\n} from './main-sync-guard-configs';\nimport { validateChecklistsSection, validateLandPrSection, validateNoGateSaltRationale } from './pr-gate-section-validators';\n\n// Re-exported so the isolated validate-checklist-docs target keeps importing it from here.\nexport { validateChecklistsSection };\nimport { DEFAULT_MATCH_RULES } from './match-rules-config';\nimport { toError } from './to-error';\nimport {\n MaxMethodLinesConfig,\n MaxFileLinesConfig,\n RequireReturnTypeConfig,\n NoInlineTypeLiteralsConfig,\n NoAnyUnknownConfig,\n NoImplicitAnyConfig,\n PrismaValidateDtosConfig,\n PrismaConverterConfig,\n NoDestructureConfig,\n NoUnmanagedExceptionsConfig,\n CatchErrorPatternConfig,\n ThrowCauseRequiredConfig,\n AngularNoDirectApiInResolverConfig,\n NoSymbolDiTokensConfig,\n NoCustomCssConfig,\n NoProcessExitOutsideMainConfig,\n NoFunctionOutsideClassConfig,\n InjectAnnotationNotNeededForConcreteClassConfig,\n FrameworkTagConfig,\n RoleTagConfig,\n BranchCreationGuardConfig,\n PrCreationOrPushGuardConfig,\n MergeInProgressGuardConfig,\n PrMergeGuardConfig,\n RedirectHowToMergeMainConfig,\n NoFileImportCyclesConfig,\n RuntimeArchitectureConfig,\n NxWiringConfig,\n DiGraphConfig,\n MissingDesignAnnotationConfig,\n NoJsFilesConfig,\n ValidateTsInSrcConfig,\n ValidateArchitectureUnchangedConfig,\n ValidateNoArchitectureCyclesConfig,\n ValidatePackageJsonConfig,\n ValidateVersionsLockedConfig,\n ValidateEslintSyncConfig,\n} from './rule-configs';\nimport { NoClientCreationOutsideServerOrClientConfig } from './no-client-creation-config';\n\n// Thin lookup table — each entry delegates to the class's own SCHEMA.\n// No field lists here; all schemas live with their config class.\nconst RULE_SCHEMAS: Record<string, Record<string, FieldDef>> = {\n 'max-method-lines': MaxMethodLinesConfig.SCHEMA,\n 'max-file-lines': MaxFileLinesConfig.SCHEMA,\n 'require-return-type': RequireReturnTypeConfig.SCHEMA,\n 'no-inline-type-literals': NoInlineTypeLiteralsConfig.SCHEMA,\n 'no-any-unknown': NoAnyUnknownConfig.SCHEMA,\n 'no-implicit-any': NoImplicitAnyConfig.SCHEMA,\n 'prisma-validate-dtos': PrismaValidateDtosConfig.SCHEMA,\n 'prisma-converter': PrismaConverterConfig.SCHEMA,\n 'no-destructure': NoDestructureConfig.SCHEMA,\n 'no-unmanaged-exceptions': NoUnmanagedExceptionsConfig.SCHEMA,\n 'catch-error-pattern': CatchErrorPatternConfig.SCHEMA,\n 'throw-cause-required': ThrowCauseRequiredConfig.SCHEMA,\n 'angular-no-direct-api-in-resolver': AngularNoDirectApiInResolverConfig.SCHEMA,\n 'no-symbol-di-tokens': NoSymbolDiTokensConfig.SCHEMA,\n 'no-client-creation-outside-server-or-client': NoClientCreationOutsideServerOrClientConfig.SCHEMA,\n 'no-custom-css': NoCustomCssConfig.SCHEMA,\n 'no-process-exit-outside-main': NoProcessExitOutsideMainConfig.SCHEMA,\n 'no-function-outside-class': NoFunctionOutsideClassConfig.SCHEMA,\n 'inject-annotation-not-needed-for-concrete-class': InjectAnnotationNotNeededForConcreteClassConfig.SCHEMA,\n 'framework-tag': FrameworkTagConfig.SCHEMA,\n 'role-tag': RoleTagConfig.SCHEMA,\n 'branch-creation-guard': BranchCreationGuardConfig.SCHEMA,\n 'pr-creation-or-push-guard': PrCreationOrPushGuardConfig.SCHEMA,\n 'merge-in-progress-guard': MergeInProgressGuardConfig.SCHEMA,\n 'pr-merge-guard': PrMergeGuardConfig.SCHEMA,\n 'redirect-how-to-merge-main': RedirectHowToMergeMainConfig.SCHEMA,\n 'feature-branch-guard': FeatureBranchGuardConfig.SCHEMA,\n 'read-stale-guard': ReadStaleGuardConfig.SCHEMA,\n 'merged-branch-bash-guard': MergedBranchBashGuardConfig.SCHEMA,\n 'stale-main-bash-guard': StaleMainBashGuardConfig.SCHEMA,\n 'no-file-import-cycles': NoFileImportCyclesConfig.SCHEMA,\n 'runtime-architecture': RuntimeArchitectureConfig.SCHEMA,\n 'nx-wiring': NxWiringConfig.SCHEMA,\n 'di-graph': DiGraphConfig.SCHEMA,\n 'missing-design-annotation': MissingDesignAnnotationConfig.SCHEMA,\n 'no-js-files': NoJsFilesConfig.SCHEMA,\n 'validate-ts-in-src': ValidateTsInSrcConfig.SCHEMA,\n 'validate-architecture-unchanged': ValidateArchitectureUnchangedConfig.SCHEMA,\n 'validate-no-architecture-cycles': ValidateNoArchitectureCyclesConfig.SCHEMA,\n 'validate-packagejson': ValidatePackageJsonConfig.SCHEMA,\n 'validate-versions-locked': ValidateVersionsLockedConfig.SCHEMA,\n 'validate-eslint-sync': ValidateEslintSyncConfig.SCHEMA,\n};\n\n// Every built-in rule name that has a typed schema (code rules + bash guards). The installer uses\n// this (with sectionForRule) to seed a fresh webpieces.config.json with every rule in its section.\nexport function allRuleNames(): readonly string[] {\n return Object.keys(RULE_SCHEMAS);\n}\n\nfunction valueHint(def: FieldDef, key?: string): string {\n // The two universal escape hatches, REQUIRED on every rule so they're always visible. Spell out the\n // \"off\" value so a fresh config seeds them in the active/no-op state (0 / null), not a placeholder.\n if (key === 'turnOffRuleUntilEpoch') return '0 (0 = active; future unix-epoch seconds = temporarily off)';\n if (key === 'turnOffRuleWhileOnBranch') return 'null (null = always on; a branch name disables the rule while that branch is checked out)';\n return def.enumValues\n ? `\"${def.enumValues.join(' | ')}\"`\n : def.type === 'string[]' ? '[\"<string>\", ...]'\n : def.type === 'number' ? '<number>'\n : def.type === 'boolean' ? '<boolean>'\n : '\"<string>\"';\n}\n\n// Scoped modes (narrowest → broadest) that enforce ONLY on what changed, so a rule can be\n// adopted gradually instead of all-at-once. When a rule offers one, recommend the first it\n// supports so a fresh config opts into a low-friction rollout rather than reflexively OFF.\nconst GRADUAL_MODE_PREFERENCE = [\n 'MODIFIED_PROJECTS',\n 'NEW_AND_MODIFIED_CODE',\n 'NEW_AND_MODIFIED_METHODS',\n 'MODIFIED_CLASS',\n 'NEW_METHODS',\n 'NEW_AND_MODIFIED_FILES',\n];\n\n/** A rollout hint for the copy-paste snippet: recommend the narrowest gradual mode the rule supports. */\nfunction rolloutTip(schema: Record<string, FieldDef>): string {\n const modes = schema['mode']?.enumValues ?? [];\n const recommended = GRADUAL_MODE_PREFERENCE.find((m: string) => modes.includes(m));\n if (!recommended) return '';\n const optOut = modes.includes('OFF') ? ' Set \"mode\": \"OFF\" to opt out entirely.' : '';\n return (\n `\\n\\n💡 Recommended: start with \"mode\": \"${recommended}\" — it enforces only on what you ` +\n `actually change, so the rule rolls out gradually (existing code stays grandfathered until ` +\n `you next touch that project/file/method).${optOut}`\n );\n}\n\nfunction missingRuleSnippet(ruleName: string, schema: Record<string, FieldDef>): string {\n // Required fields go in the copy-paste entry. The two universal escape hatches\n // (turnOffRuleUntilEpoch / turnOffRuleWhileOnBranch) are now REQUIRED, so they land in that block —\n // which is the whole point: every seeded rule shows both hatches. Optional fields are listed separately.\n const fields = Object.keys(schema);\n const required = fields.filter(f => !schema[f].optional);\n const optional = fields.filter(f => schema[f].optional);\n\n const requiredLines = required.map(f => ` \"${f}\": ${valueHint(schema[f], f)}`);\n const section = sectionForRule(ruleName);\n let out =\n `[${ruleName}] Not configured in webpieces.config.json. Add this entry to the \"${section}\" section\\n` +\n `(choose values appropriate for your project):\\n\\n` +\n ` \"${ruleName}\": {\\n${requiredLines.join(',\\n')}\\n }`;\n\n if (optional.length > 0) {\n const optionalLines = optional.map(f => ` \"${f}\": ${valueHint(schema[f], f)}`);\n out +=\n `\\n\\nOptional fields you may add to this rule (omit if not needed):\\n` +\n `${optionalLines.join(',\\n')}`;\n }\n out += rolloutTip(schema);\n return out;\n}\n\n// A config key under rules/hookGuards that the RUNNING validator has no schema for (and no rulesDir is\n// set to supply custom rules). Two very different causes, so the message leads with the common one:\n// 1. Version skew (most common — happens right after a dep bump): webpieces.config.json references a\n// rule a NEWER @webpieces release added, but the installed guard is OLDER and doesn't know it yet.\n// Fix = `pnpm install` (NOT deleting the key — the key is valid, the validator is just stale).\n// 2. A genuinely removed/renamed rule left behind, or a typo. Fix = remove the key.\n// Do NOT tell the AI to delete first — that destroys valid config in case 1 (the trap that made the AI\n// gut a working config instead of running `pnpm install`). The banner in load-config.ts spells out the\n// ordered \"run pnpm install, THEN edit only if it persists\" fix.\nfunction unknownRuleError(ruleName: string): string {\n return (\n `[${ruleName}] Unknown rule — the running @webpieces validator has no schema for it, and no ` +\n `\"rulesDir\" is configured to supply custom rules. Most often this means your installed guard is a ` +\n `release BEHIND this webpieces.config.json: run \\`pnpm install\\` first (see the fix steps below) so ` +\n `the validator learns \"${ruleName}\". Only if it is STILL unknown after a fresh install is it a ` +\n `removed/renamed rule or a typo — then remove the \"${ruleName}\" key from webpieces.config.json.`\n );\n}\n\n// Fields we DELETED from a rule's schema, keyed by \"<rule>.<field>\". The generic unknown-field error\n// (\"Unknown field ... Valid fields: [...]\") is correct but doesn't say WHY the field vanished, so an AI\n// might re-add it. These hints explain the removal so the only action left is to delete the key.\nconst RETIRED_FIELD_HINTS: Record<string, string> = {\n 'runtime-architecture.servicePaths':\n 'This field was removed — it was never read. The runtime graph is derived automatically from ' +\n 'architecture/dependencies.json (apiRelations + project roles). Delete it.',\n 'runtime-architecture.apiProjectPaths':\n 'This field was removed — it was never read. The runtime graph is derived automatically from ' +\n 'architecture/dependencies.json, so there is NO list of api libs to maintain. Delete it (do not ' +\n 'enumerate api libs and do not replace it with a glob).',\n};\n\n// Universal field renames (apply to EVERY rule/guard AND every match-rule, unlike the per-rule\n// RETIRED_FIELD_HINTS). When an entry still uses the old escape-hatch name, the generic unknown-field\n// error is replaced with a precise \"renamed to X — rename it\" instruction so the fix is mechanical.\nconst RENAMED_FIELD_ALIASES: Record<string, string> = {\n ignoreModifiedUntilEpoch: 'turnOffRuleUntilEpoch',\n ignoreRuleWhileOnBranch: 'turnOffRuleWhileOnBranch',\n};\n\n// The renamed-field message shared by keyed rules and match-rules.\n// webpieces-disable no-function-outside-class -- module-level config validator, matches the rest of this file\nfunction renamedFieldError(scope: string, oldKey: string, newKey: string): string {\n return `${scope} Unknown field \"${oldKey}\" — it was renamed to \"${newKey}\". Rename it (the value carries over unchanged; for the branch hatch, use null when there is no branch).`;\n}\n\n// webpieces-disable no-any-unknown -- rawRules values are opaque JSON; each field is validated individually\nexport function validateWebpiecesConfig(\n rawRules: Record<string, Record<string, unknown>>,\n hasCustomRulesDir: boolean = false,\n): string[] {\n const errors: string[] = [];\n\n // Check field-level correctness for rules that are present\n for (const [ruleName, entry] of Object.entries(rawRules)) {\n const schema = RULE_SCHEMAS[ruleName];\n if (!schema) {\n // No built-in schema. With no rulesDir there are no custom rules, so this key is a\n // dead/typo'd entry — tell the AI to remove it (a removed rule like no-shell-substitution\n // lingers here otherwise). With a rulesDir it may be a legitimate custom rule → skip.\n if (!hasCustomRulesDir) errors.push(unknownRuleError(ruleName));\n continue;\n }\n for (const [key, value] of Object.entries(entry)) {\n const fieldDef = schema[key];\n if (!fieldDef) {\n const renamedTo = RENAMED_FIELD_ALIASES[key];\n if (renamedTo) {\n errors.push(renamedFieldError(`[${ruleName}]`, key, renamedTo));\n continue;\n }\n const retiredHint = RETIRED_FIELD_HINTS[`${ruleName}.${key}`];\n const suffix = retiredHint ? ` ${retiredHint}` : '';\n errors.push(`[${ruleName}] Unknown field \"${key}\". Valid fields: [${Object.keys(schema).join(', ')}].${suffix}`);\n continue;\n }\n // A nullable field (e.g. turnOffRuleWhileOnBranch) accepts JSON null in addition to its type.\n if (value === null && fieldDef.nullable) continue;\n if (fieldDef.type === 'string[]') {\n if (!Array.isArray(value) || !value.every(v => typeof v === 'string'))\n errors.push(`[${ruleName}] \"${key}\" must be string[], got ${typeof value}.`);\n } else if (typeof value !== fieldDef.type) {\n errors.push(`[${ruleName}] \"${key}\" must be ${fieldDef.type}, got ${typeof value}.`);\n } else if (fieldDef.enumValues && !fieldDef.enumValues.includes(value as string)) {\n errors.push(`[${ruleName}] \"${key}\" = \"${value}\" is not valid. Must be one of: ${fieldDef.enumValues.join(', ')}.`);\n }\n }\n // Required fields must actually be present. Until now the loop above only checked\n // fields that WERE present, so an entry like `{}` (or one missing `mode` /\n // `turnOffRuleUntilEpoch`) slipped through. Every non-optional schema field is mandatory.\n for (const [key, fieldDef] of Object.entries(schema)) {\n if (!fieldDef.optional && !(key in entry)) {\n errors.push(`[${ruleName}] Missing required field \"${key}\". Add ${key}: ${valueHint(fieldDef, key)}.`);\n }\n }\n }\n\n // Every built-in rule must be explicitly configured — no silent defaults.\n // When a new rule is added to the framework, this check surfaces it immediately\n // with a ready-to-copy snippet so AI can configure it in one pass.\n for (const [ruleName, schema] of Object.entries(RULE_SCHEMAS)) {\n if (!(ruleName in rawRules)) {\n errors.push(missingRuleSnippet(ruleName, schema));\n }\n }\n\n return errors;\n}\n\nconst PR_GATE_MODES = ['ON', 'OFF'] as const;\n// Optional — omitted means DETECT. Kept inline (like prGateExample) to avoid a load-config ↔\n// pr-gate-config import cycle; the canonical list + semantics live in pr-gate-config.ts.\nconst PR_GATE_MERGE_MODES = ['AUTO', 'NONE'] as const;\n\n// Spelled out because the choice is a POLICY decision with a consequence the chooser cannot see:\n// only the AUTO path can put the compact risk/flags body in main's history, because a UI merge is\n// limited to the repo's squash_merge_commit_title/message settings and no setting produces it.\nconst MERGE_MODE_HELP = (\n `Must be one of: ${PR_GATE_MERGE_MODES.join(', ')}.\\n` +\n ` \"AUTO\" — wp-finish-upsert-pr lands the PR: it squash-merges when mergeable, else enables\\n` +\n ` GitHub auto-merge, both with an explicit --subject/--body-file so main's history\\n` +\n ` gets the PR title + the compact risk/flags body. Needs allow_auto_merge on the repo\\n` +\n ` (gh api repos/{owner}/{repo} --jq .allow_auto_merge).\\n` +\n ` \"NONE\" — wp-finish-upsert-pr only opens/updates the PR; a human merges it. The compact body\\n` +\n ` is then impossible, so set the repo's squash_merge_commit_title to PR_TITLE or\\n` +\n ` commits land as the internal \"Squash merge of <branch>\" subject.`\n);\n\n// Copy-paste example for the top-level `pr-gate` block (sibling of `rules`). Kept inline rather\n// than imported from pr-gate-config.ts to avoid a load-config ↔ pr-gate-config import cycle.\nfunction prGateExample(): string {\n return (\n ` \"pr-gate\": {\\n` +\n ` \"mode\": \"ON\",\\n` +\n ` \"buildCommand\": \"<command CI runs to validate a PR, e.g. pnpm nx affected --target=ci --base=$(git merge-base origin/main HEAD)>\",\\n` +\n ` \"gates\": [\\n` +\n ` { \"name\": \"API Changed\", \"patterns\": [\"libraries/apis/**\", \"**/*Api.ts\"], \"warningColor\": \"yellow\" }\\n` +\n ` ],\\n` +\n ` \"checklists\": [ // OPTIONAL — per-area review, one distinct reviewer subagent each\\n` +\n ` { \"subagent\": \"db-migration-reviewer\", \"doc\": \".claude/review/db-migrations.md\", \"patterns\": [\"**/*.sql\"] }\\n` +\n ` ]\\n` +\n ` }`\n );\n}\n\n// The `gates` array: dashboard-only warning flags. Extracted from validatePrGateSection to keep that\n// method inside the length limit.\n// webpieces-disable no-any-unknown -- `value` is the opaque consumer `gates` value until narrowed here\n// webpieces-disable no-function-outside-class -- module-level config validator, matches the rest of this file\nfunction validateGatesSection(value: unknown): string[] {\n if (!Array.isArray(value)) {\n return [`[pr-gate] \"gates\" must be an array of { name, patterns, warningColor, disabled? }.`];\n }\n const errors: string[] = [];\n for (let i = 0; i < value.length; i += 1) {\n errors.push(...validateGate(value[i], i));\n }\n return errors;\n}\n\n// webpieces-disable no-any-unknown -- one gate entry from opaque consumer JSON, validated field-by-field\nfunction validateGate(gate: unknown, index: number): string[] {\n if (typeof gate !== 'object' || gate === null) {\n return [`[pr-gate] gates[${index}] must be an object { name, patterns, warningColor, disabled? }.`];\n }\n // webpieces-disable no-any-unknown -- narrowing one opaque gate object from consumer JSON\n const g = gate as Record<string, unknown>;\n const errors: string[] = [];\n if (typeof g['name'] !== 'string') errors.push(`[pr-gate] gates[${index}].name must be a string.`);\n if (!Array.isArray(g['patterns']) || !g['patterns'].every(p => typeof p === 'string'))\n errors.push(`[pr-gate] gates[${index}].patterns must be string[].`);\n if (g['warningColor'] === undefined)\n errors.push(`[pr-gate] gates[${index}].warningColor is required — set it to \"yellow\" or \"red\" (green is implicit when nothing matches).`);\n else if (g['warningColor'] !== 'yellow' && g['warningColor'] !== 'red')\n errors.push(`[pr-gate] gates[${index}].warningColor must be \"yellow\" or \"red\" (green is implicit when nothing matches).`);\n if (g['disabled'] !== undefined && typeof g['disabled'] !== 'boolean')\n errors.push(`[pr-gate] gates[${index}].disabled must be a boolean (example/inactive gate kept in the file).`);\n return errors;\n}\n\n/**\n * Validate the top-level `pr-gate` section. It is REQUIRED (a client that opts out sets mode \"OFF\").\n * `buildCommand` is required unless mode is \"OFF\". Returns human-readable, copy-paste-friendly errors\n * — never throws. The pr-gate block lives outside the FieldDef-driven `rules` schema because its\n * nested `gates`/`checklists` arrays can't be expressed there, so they get structural validation here.\n * `repoRoot` (when known) lets the `checklists[].docs` existence check run.\n */\n// webpieces-disable no-any-unknown -- `section` is opaque consumer JSON until narrowed below\n// webpieces-disable no-function-outside-class -- module-level config validator, matches the rest of this file\nexport function validatePrGateSection(section: unknown, repoRoot?: string): string[] {\n if (section === undefined || section === null) {\n return [\n `[pr-gate] Not configured in webpieces.config.json. Add this block under the \"commands\" ` +\n `section (set \"mode\": \"OFF\" to opt out):\\n\\n${prGateExample()}`,\n ];\n }\n if (typeof section !== 'object' || Array.isArray(section)) {\n return [`[pr-gate] Must be an object. Example:\\n\\n${prGateExample()}`];\n }\n // webpieces-disable no-any-unknown -- narrowing the opaque pr-gate section from consumer JSON\n const s = section as Record<string, unknown>;\n const errors: string[] = [];\n\n if (!('mode' in s)) {\n errors.push(`[pr-gate] Missing required field \"mode\". Must be one of: ${PR_GATE_MODES.join(', ')}.`);\n } else if (typeof s['mode'] !== 'string' || !PR_GATE_MODES.includes(s['mode'] as typeof PR_GATE_MODES[number])) {\n errors.push(`[pr-gate] \"mode\" = \"${String(s['mode'])}\" is not valid. Must be one of: ${PR_GATE_MODES.join(', ')}.`);\n }\n\n // buildCommand and mergeMode are both required whenever the gate is active (mode !== OFF). There\n // is deliberately NO default for mergeMode: whether the tooling may land your PRs is a policy\n // decision, and either guess is wrong for somebody.\n if (s['mode'] !== 'OFF') {\n const cmd = s['buildCommand'];\n if (typeof cmd !== 'string' || cmd.trim() === '') {\n errors.push(\n `[pr-gate] Missing required field \"buildCommand\" — the command CI runs to validate a PR. ` +\n `Add e.g. \"buildCommand\": \"pnpm nx affected --target=ci --base=$(git merge-base origin/main HEAD)\".`,\n );\n }\n const mm = s['mergeMode'];\n if (!('mergeMode' in s)) {\n errors.push(`[pr-gate] Missing required field \"mergeMode\". ${MERGE_MODE_HELP}`);\n } else if (typeof mm !== 'string' || !PR_GATE_MERGE_MODES.includes(mm as typeof PR_GATE_MERGE_MODES[number])) {\n errors.push(`[pr-gate] \"mergeMode\" = \"${String(mm)}\" is not valid. ${MERGE_MODE_HELP}`);\n }\n }\n\n if ('gates' in s) errors.push(...validateGatesSection(s['gates']));\n\n // Optional extension point: company review checklists, as an ARRAY right here in the config. Absent ⇒\n // none. The removed { doc } manifest shape is rejected with the exact migration edit.\n if ('checklists' in s) errors.push(...validateChecklistsSection(s['checklists'], repoRoot));\n\n // Optional server-token salt. Absent ⇒ no token minted, CI enforcement is a no-op. Present ⇒ must be\n // a non-empty string (an empty salt would mint a token anyone can forge from a known-empty secret).\n if ('gateSalt' in s) {\n const salt = s['gateSalt'];\n if (typeof salt !== 'string' || salt.trim() === '') {\n errors.push(`[pr-gate] \"gateSalt\" must be a non-empty string — it is the shared secret the gate token is HMAC'd with. Omit the key entirely to disable server-side token enforcement.`);\n }\n }\n\n // Optional: what happens to the LOCAL branch once its PR lands. Absent ⇒ \"archive-tag\".\n if ('landPr' in s) errors.push(...validateLandPrSection(s['landPr']));\n\n errors.push(...validateNoGateSaltRationale(s));\n\n // Optional: publish reviewer output as a PR comment (defaults true). Must be a boolean when present.\n if ('checklistComments' in s && typeof s['checklistComments'] !== 'boolean') {\n errors.push(`[pr-gate] \"checklistComments\" must be a boolean (defaults to true; set false to keep the PR body-only).`);\n }\n\n return errors;\n}\n\nfunction excludePathsExample(): string {\n return '\"excludePaths\": [\"repositories/**\"]';\n}\n\n// A glob list: must be a string[] (may be empty). `key` names it for the error, so the legacy\n// two-list form can report which of its lists is malformed.\n// webpieces-disable no-any-unknown -- `value` is opaque consumer JSON until narrowed here\nfunction validateExcludeList(value: unknown, key: string): string[] {\n if (!(Array.isArray(value) && value.every(p => typeof p === 'string'))) {\n return [`[excludePaths] \"${key}\" must be a string[] of glob paths (use [] for none).`];\n }\n return [];\n}\n\n/**\n * Validate the REQUIRED top-level `excludePaths` block: ONE glob list suppressing hook enforcement per\n * file path, for code-style rules and file-scoped guards alike. Required so every client upgrading is\n * forced to declare it (as [] to keep today's behavior, or with real paths). Returns copy-paste\n * friendly errors and never throws — same contract as validatePrGateSection.\n *\n * The legacy object form `{ \"rules\": [...], \"guards\": [...] }` is STILL ACCEPTED and unioned into one\n * list by parseExcludePaths, so an unmigrated config validates and behaves identically. Rejecting it\n * would deadlock every consumer on upgrade: the block is required, so a hard error here blocks every\n * Bash/Edit including the edit that would fix it.\n */\n// webpieces-disable no-any-unknown -- `section` is opaque consumer JSON until narrowed below\nexport function validateExcludePaths(section: unknown): string[] {\n if (section === undefined || section === null) {\n return [\n `[excludePaths] Not configured in webpieces.config.json. Add this REQUIRED block ` +\n `(use an empty array to keep enforcing everywhere):\\n\\n ${excludePathsExample()}`,\n ];\n }\n if (Array.isArray(section)) return validateExcludeList(section, 'excludePaths');\n if (typeof section !== 'object') {\n return [`[excludePaths] Must be a string[] of glob paths. Example:\\n\\n ${excludePathsExample()}`];\n }\n // Legacy two-list form — validate each list it actually declares, then let parseExcludePaths union\n // them. An object carrying neither key is a typo, not a legacy config, so say so.\n // webpieces-disable no-any-unknown -- narrowing the opaque excludePaths section from consumer JSON\n const s = section as Record<string, unknown>;\n if (s['rules'] === undefined && s['guards'] === undefined) {\n return [`[excludePaths] Must be a string[] of glob paths. Example:\\n\\n ${excludePathsExample()}`];\n }\n return [\n ...(s['rules'] === undefined ? [] : validateExcludeList(s['rules'], 'rules')),\n ...(s['guards'] === undefined ? [] : validateExcludeList(s['guards'], 'guards')),\n ];\n}\n\n// ---------------------------------------------------------------------------\n// match-rules — a new top-level ARRAY section (parallel to pr-gate/excludePaths). Each entry is a\n// client-authored content guard (raw-regex patterns + message + scoping). Validated structurally here\n// the same way pr-gate's `gates` are, because an array of objects can't be expressed in FieldDef schema.\n// ---------------------------------------------------------------------------\n\nfunction matchRulesExample(): string {\n return `\"match-rules\": ${JSON.stringify(DEFAULT_MATCH_RULES, null, 4)}`;\n}\n\n// webpieces-disable no-any-unknown -- generic type guard over an opaque JSON value\nfunction isStringArray(value: unknown): value is string[] {\n return Array.isArray(value) && value.every(v => typeof v === 'string');\n}\n\n// Compile a pattern to validate it; returns the error message, or undefined when it compiles.\nfunction regexError(pattern: string): string | undefined {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n // Constructed only to validate the syntax; the object is intentionally discarded.\n void new RegExp(pattern);\n return undefined;\n } catch (err: unknown) {\n const error = toError(err);\n return error.message;\n }\n}\n\n// One entry of the match-rules array, validated field-by-field (see validateGate for the pattern).\n// webpieces-disable no-any-unknown -- one match-rule entry from opaque consumer JSON, validated field-by-field\nfunction validateMatchRule(entry: unknown, index: number): string[] {\n if (typeof entry !== 'object' || entry === null || Array.isArray(entry)) {\n return [`[match-rules] entry[${index}] must be an object { name, patterns, mainMessage, mode, turnOffRuleUntilEpoch, turnOffRuleWhileOnBranch, ... }.`];\n }\n // webpieces-disable no-any-unknown -- narrowing one opaque match-rule entry from consumer JSON\n const e = entry as Record<string, unknown>;\n const label = typeof e['name'] === 'string' ? `\"${e['name']}\"` : `entry[${index}]`;\n const errors: string[] = [];\n\n if (typeof e['name'] !== 'string' || e['name'].trim() === '')\n errors.push(`[match-rules] entry[${index}].name must be a non-empty string (it is the disable token and report label).`);\n\n if (!isStringArray(e['patterns']) || e['patterns'].length === 0) {\n errors.push(`[match-rules] ${label}.patterns must be a non-empty string[] of regexes.`);\n } else {\n e['patterns'].forEach((p: string, pi: number) => {\n const rxErr = regexError(p);\n if (rxErr) errors.push(`[match-rules] ${label}.patterns[${pi}] is not a valid regex: ${rxErr}`);\n });\n }\n\n if (typeof e['mainMessage'] !== 'string' || e['mainMessage'].trim() === '')\n errors.push(`[match-rules] ${label}.mainMessage must be a non-empty string.`);\n\n if (typeof e['mode'] !== 'string' || !MODIFIED_CODE_MODES.includes(e['mode'] as typeof MODIFIED_CODE_MODES[number]))\n errors.push(`[match-rules] ${label}.mode must be one of: ${MODIFIED_CODE_MODES.join(', ')}.`);\n\n // Both escape hatches are REQUIRED on every match-rule too (same as keyed rules), so they are always\n // visible. turnOffRuleUntilEpoch: number (0 = active; a future unix-epoch in seconds = temporarily\n // off). turnOffRuleWhileOnBranch: string | null (null = always on; a branch name disables the rule\n // while that branch is checked out).\n if (typeof e['turnOffRuleUntilEpoch'] !== 'number')\n errors.push(`[match-rules] ${label}.turnOffRuleUntilEpoch must be a number (0 = active; future unix-epoch seconds = temporarily off).`);\n if (!(e['turnOffRuleWhileOnBranch'] === null || typeof e['turnOffRuleWhileOnBranch'] === 'string'))\n errors.push(`[match-rules] ${label}.turnOffRuleWhileOnBranch must be a string or null (null = no branch / always on).`);\n\n // The old escape-hatch names were renamed — flag them precisely.\n for (const oldKey of Object.keys(RENAMED_FIELD_ALIASES)) {\n if (oldKey in e) errors.push(renamedFieldError(`[match-rules] ${label}`, oldKey, RENAMED_FIELD_ALIASES[oldKey]));\n }\n\n if (e['options'] !== undefined && !isStringArray(e['options']))\n errors.push(`[match-rules] ${label}.options must be a string[] (omit if not needed).`);\n if (e['allowedPaths'] !== undefined && !isStringArray(e['allowedPaths']))\n errors.push(`[match-rules] ${label}.allowedPaths must be a string[] of globs (omit if not needed).`);\n if (e['disableAllowed'] !== undefined && typeof e['disableAllowed'] !== 'boolean')\n errors.push(`[match-rules] ${label}.disableAllowed must be a boolean.`);\n\n return errors;\n}\n\n/**\n * Validate the REQUIRED top-level `match-rules` array (client-authored content guards). MISSING →\n * one error printing the ready-to-paste `no-fetch` example (add at least this; more can follow).\n * Present-but-`[]` → allowed (a conscious opt-out, matching pr-gate mode:OFF / excludePaths []).\n * Otherwise every entry is validated field-by-field (each regex compile-checked) plus name\n * uniqueness. Copy-paste-friendly errors; never throws — same contract as validatePrGateSection.\n */\n// webpieces-disable no-any-unknown -- `section` is opaque consumer JSON until narrowed below\nexport function validateMatchRulesSection(section: unknown): string[] {\n if (section === undefined || section === null) {\n return [\n `[match-rules] Not configured in webpieces.config.json. Add this REQUIRED top-level array — ` +\n `seed it with the no-fetch guard below (you can add more entries: no-moment, no-lodash-chain, …):\\n\\n${matchRulesExample()}`,\n ];\n }\n if (!Array.isArray(section)) {\n return [`[match-rules] Must be an array of content-guard objects. Example:\\n\\n${matchRulesExample()}`];\n }\n\n const errors: string[] = [];\n const seen = new Set<string>();\n for (let i = 0; i < section.length; i += 1) {\n errors.push(...validateMatchRule(section[i], i));\n // webpieces-disable no-any-unknown -- reading the name off an opaque entry only to dedupe\n const name = (section[i] as Record<string, unknown> | null)?.['name'];\n if (typeof name === 'string') {\n if (seen.has(name)) errors.push(`[match-rules] duplicate entry name \"${name}\" — each match-rule name must be unique.`);\n seen.add(name);\n }\n }\n return errors;\n}\n\n/**\n * Enforce that each built-in lives in its correct section: code rules under `rules`, bash guards\n * under `hookGuards`. A guard left in `rules` (or a rule placed in `hookGuards`) is reported with a\n * \"move it\" message so the split stays clean. Unknown/custom names are ignored (they may be custom\n * rules from rulesDir). Presence (\"every built-in must be configured\") is checked separately by\n * validateWebpiecesConfig against the merged map.\n */\n// webpieces-disable no-any-unknown -- section maps are opaque consumer JSON\nexport function validateSectionPlacement(\n rulesSection: Record<string, Record<string, unknown>>,\n hookGuardsSection: Record<string, Record<string, unknown>>,\n): string[] {\n const errors: string[] = [];\n for (const name of Object.keys(rulesSection)) {\n if (isHookGuard(name)) {\n errors.push(\n `[${name}] is a hook guard and belongs in the \"hookGuards\" section, not \"rules\". ` +\n `Move it (or run \\`pnpm wp-install-ai-hooks --sync\\` to migrate automatically).`,\n );\n }\n }\n for (const name of Object.keys(hookGuardsSection)) {\n // Only flag KNOWN code rules misplaced into hookGuards; unknown names may be custom rules.\n if (!isHookGuard(name) && RULE_SCHEMAS[name]) {\n errors.push(\n `[${name}] is a code rule and belongs in the \"rules\" section, not \"hookGuards\". ` +\n `Move it (or run \\`pnpm wp-install-ai-hooks --sync\\` to migrate automatically).`,\n );\n }\n }\n return errors;\n}\n\n/**\n * Validate the `commands` section: its `pr-gate` block (delegated to validatePrGateSection) plus the\n * optional command-string fields. Also surfaces a migration error if a DEPRECATED top-level `pr-gate`\n * block is still present, telling the consumer to move it under `commands`.\n */\n// webpieces-disable no-any-unknown -- `commands`/`legacyPrGate` are opaque consumer JSON\n// webpieces-disable no-function-outside-class -- module-level config validator, matches the rest of this file\nexport function validateCommandsSection(commands: unknown, legacyPrGate: unknown, repoRoot?: string): string[] {\n const errors: string[] = [];\n\n if (legacyPrGate !== undefined) {\n errors.push(\n `[pr-gate] The top-level \"pr-gate\" block is deprecated. Move it under the \"commands\" ` +\n `section as commands[\"pr-gate\"] (run \\`pnpm wp-install-ai-hooks --sync\\` to migrate automatically).`,\n );\n }\n\n if (commands !== undefined && (typeof commands !== 'object' || commands === null || Array.isArray(commands))) {\n errors.push(`[commands] Must be an object { \"pr-gate\": {...}, \"upsertPr\": \"...\", \"mergeComplete\": \"...\" }.`);\n return errors;\n }\n\n // webpieces-disable no-any-unknown -- narrowing the opaque commands section from consumer JSON\n const c = (commands ?? {}) as Record<string, unknown>;\n\n // pr-gate is required (set mode OFF to opt out). Prefer commands[\"pr-gate\"]; fall back to the\n // legacy top-level block so an un-migrated file still validates its gate config.\n errors.push(...validatePrGateSection(c['pr-gate'] ?? legacyPrGate, repoRoot));\n\n // Canonical guard-hint strings live under commands.guardHints; each value, when present, must be a\n // non-empty command string. The two names bind to the two guards that surface them in fix hints.\n const hints = c['guardHints'];\n if (hints !== undefined) {\n if (typeof hints !== 'object' || hints === null || Array.isArray(hints)) {\n errors.push(`[commands] \"guardHints\" must be an object { \"prCreationOrPush\": \"...\", \"mergeInProgress\": \"...\" }.`);\n } else {\n // webpieces-disable no-any-unknown -- narrowing the opaque guardHints object from consumer JSON\n const h = hints as Record<string, unknown>;\n for (const field of ['prCreationOrPush', 'mergeInProgress']) {\n if (field in h && (typeof h[field] !== 'string' || (h[field] as string).trim() === '')) {\n errors.push(`[commands] \"guardHints.${field}\" must be a non-empty string (the gated command to run).`);\n }\n }\n }\n }\n\n // Legacy FLAT command strings (pre-guardHints). Still accepted for back-compat; a migrated file\n // uses commands.guardHints instead.\n for (const field of ['upsertPr', 'mergeComplete']) {\n if (field in c && typeof c[field] !== 'string') {\n errors.push(`[commands] \"${field}\" must be a string (the gated command to run).`);\n }\n }\n\n return errors;\n}\n"]}