@webpieces/rules-config 0.4.670 → 0.4.672
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 +1 -1
- package/src/default-rules.js +5 -6
- package/src/default-rules.js.map +1 -1
- package/src/home-config.d.ts +27 -44
- package/src/home-config.js +46 -57
- package/src/home-config.js.map +1 -1
- package/src/index.d.ts +2 -1
- package/src/index.js +8 -5
- package/src/index.js.map +1 -1
- package/src/no-custom-css-scope.d.ts +32 -0
- package/src/no-custom-css-scope.js +50 -0
- package/src/no-custom-css-scope.js.map +1 -0
- package/src/retired-config-keys.js +4 -4
- package/src/retired-config-keys.js.map +1 -1
- package/src/rule-configs.js +3 -2
- package/src/rule-configs.js.map +1 -1
- package/src/sections.d.ts +3 -2
- package/src/sections.js +3 -2
- package/src/sections.js.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retired-config-keys.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/retired-config-keys.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Retired webpieces.config.json keys — the ONE place in the codebase where a dead config key may be named.\n *\n * ## THE POLICY: webpieces.config.json is never released backwards-compatible\n *\n * When a config key moves, is renamed, or is deleted, the loader REJECTS the old shape with an error that\n * names the destination. It does NOT quietly accept both. There is no fallback, no alias table applied\n * before validation, no \"still accepted for back-compat until every consumer migrates\".\n *\n * This is safe *here* in a way it is not for a normal library, and the reason is the consumer: every reader\n * of this file is a coding agent. The config is validated on startup, the agent is handed the exact edit,\n * and it applies it in one pass — so the upgrade is seamless without shipping a compatibility layer. That\n * makes a hard failure strictly cheaper than duality: two accepted shapes means two code paths, two sets of\n * defaults and two sets of error messages to keep honest forever, and the stale shape then lives in\n * consumer configs indefinitely because nothing ever forces the edit.\n *\n * A hard rejection here is always self-recoverable, which is what makes it safe to do:\n * - editing webpieces.config.json is ALWAYS permitted, even while the config is invalid (see the banner\n * in config-file.ts and the guard matrix — a Write/Edit targeting this file is an unconditional PASS),\n * - and `PRUNE_UNKNOWN_COMMAND` is an L0 CURE, so the mechanical cleanup of keys no validator knows runs\n * from inside the block too.\n * So rejecting an old shape can never wedge a repo. \"It would deadlock the consumer\" is not a reason to add\n * a fallback; it is not true.\n *\n * NOT `pnpm install`. This paragraph used to offer it as the escape hatch that \"fixes the far more common\n * cause of a validation failure: an installed validator lagging the config by a release\". It is permitted\n * (installer bypass), but it is not the cure for anything you can read here: the shim's version-drift guard\n * compares the pin against the installed version and denies every tool call BEFORE the validator runs, so a\n * validation error on screen is proof that package.json and node_modules already agree. The banner from this\n * same package now says \"Do NOT run `pnpm install` — it cannot help\", and a docstring teaching the opposite\n * is how that advice leaked back out.\n *\n * ## Adding an entry\n *\n * When you retire a key, add it here and DELETE its read path — do not leave a `??` fallback behind. The\n * `instruction` is the whole product: it is read by an agent that will act on it verbatim, so give the\n * mechanical edit (\"rename X to Y\", \"move A into B\"), not a description of the change. Saying where a thing\n * moved to is exactly the point of this table; it is what makes the fallback unnecessary.\n *\n * retired-config-keys.spec.ts asserts every entry below actually FAILS the load. That spec is the guard: a\n * future fallback that silently swallows a retired key turns it red.\n */\n\nimport { RETIRED_KEY_MARKER } from './config-error-banner';\nimport { PRUNE_UNKNOWN_COMMAND } from './constants';\n\n// A retired key is matched one of two ways, because config keys live at two very different levels.\n// RULE — a rule/guard NAME, which may sit under either `rules` or `hookGuards`, so it is matched by bare\n// name rather than by a fixed path.\n// KEY — a plain key inside a known section, matched by name within that section.\nexport const RETIRED_SCOPE_RULE = 'rule';\nexport const RETIRED_SCOPE_KEY = 'key';\n\n/** One retired config key and the mechanical edit that replaces it. Data-only (per CLAUDE.md). */\nexport class RetiredConfigKey {\n scope: string;\n // The key exactly as it appears in webpieces.config.json.\n key: string;\n // Where the value goes now. Empty string when the key is deleted outright with no replacement.\n movedTo: string;\n // The imperative fix, written for the agent that will apply it.\n instruction: string;\n // Bracketed label leading the error, matching the `[rule-name]` / `[section]` convention in this package.\n label: string;\n /**\n * True when DELETING the key from webpieces.config.json is the entire edit — nothing in THIS file\n * replaces it, so `PRUNE_UNKNOWN_COMMAND` may strip it mechanically. `whole-repo-build-guard` is the\n * worked example: its switch moved OUT of the repo config into `~/.webpieces/config.json`, so the\n * value has nowhere to go here.\n *\n * False for a rename or an in-file move: deleting those would DISCARD a value the reader still needs,\n * so they keep their migration instruction and the pruner leaves them alone. Required, not defaulted —\n * a defaulted `false` would let a future deletion-only retirement silently opt out of the mechanical\n * cure and land back in \"the reader decides while every Bash call is blocked\".\n */\n prunable: boolean;\n\n // eslint-disable-next-line @typescript-eslint/max-params\n constructor(scope: string, key: string, movedTo: string, instruction: string, label: string, prunable: boolean) {\n this.scope = scope;\n this.key = key;\n this.movedTo = movedTo;\n this.instruction = instruction;\n this.label = label;\n this.prunable = prunable;\n }\n}\n\n/**\n * Every retired key. Keep the newest at the bottom with the release that retired it, so the list reads as a\n * changelog an agent can walk when a config is several versions behind.\n */\nexport const RETIRED_CONFIG_KEYS: readonly RetiredConfigKey[] = [\n // --- Guard renames. Previously applied SILENTLY before validation (a DEPRECATED_RULE_ALIASES table in\n // load-config.ts rewrote the key so no validator ever saw it). That hid the rename from the config file\n // forever: the old name kept working, so no consumer ever updated, and the alias table could never be\n // deleted. Now each is a hard error with the new name.\n //\n // These three RE-POINTED when hookGuards collapsed to one key per policy. Their old destinations\n // (`pr-merge-guard`, `pr-creation-or-push-guard`, `read-stale-guard`) are themselves retired now,\n // and a retirement whose `movedTo` names a dead key teaches the removed API — the same defect one\n // level out. Each therefore names the POLICY key it lands on today, in one hop.\n new RetiredConfigKey(\n RETIRED_SCOPE_RULE, 'pr-merge-cleanup', 'pr-lifecycle-guard',\n 'Rename the key to \"pr-lifecycle-guard\" (merging its value into that entry if you already have ' +\n 'one — the four PR/merge guards share one key now). Its mode and escape hatches carry over.',\n '[pr-merge-cleanup]', false,\n ),\n new RetiredConfigKey(\n RETIRED_SCOPE_RULE, 'pr-creation-guard', 'pr-lifecycle-guard',\n 'Rename the key to \"pr-lifecycle-guard\" (merging its value into that entry if you already have ' +\n 'one — the four PR/merge guards share one key now). Its mode and escape hatches carry over; the ' +\n 'old \"upsertPrCommand\" field does NOT — that string lives only in commands.guardHints.prCreationOrPush.',\n '[pr-creation-guard]', false,\n ),\n new RetiredConfigKey(\n RETIRED_SCOPE_RULE, 'main-stale-guard', 'branch-state-guard',\n 'Rename the key to \"branch-state-guard\" (merging its value into that entry if you already have ' +\n 'one — the four branch-state guards share one key now). Its mode and escape hatches carry over. ' +\n 'Note the widened scope: that key arms the Write, Read AND Bash halves of the branch-state ' +\n 'policy, not just the Read block this key used to name.',\n '[main-stale-guard]', false,\n ),\n\n // --- The two flat guard-hint strings, superseded by commands.guardHints so that every guard-facing\n // command string sits in one named sub-object instead of loose beside the gate config.\n new RetiredConfigKey(\n RETIRED_SCOPE_KEY, 'upsertPr', 'commands.guardHints.prCreationOrPush',\n 'Move the value to \"guardHints\": { \"prCreationOrPush\": <value> } inside the same \"commands\" ' +\n 'section, then delete \"upsertPr\".',\n '[commands]', false,\n ),\n new RetiredConfigKey(\n RETIRED_SCOPE_KEY, 'mergeComplete', 'commands.guardHints.mergeInProgress',\n 'Move the value to \"guardHints\": { \"mergeInProgress\": <value> } inside the same \"commands\" ' +\n 'section, then delete \"mergeComplete\".',\n '[commands]', false,\n ),\n\n // --- The two-list excludePaths object. The split never earned its keep (every consumer set both lists\n // to the same value), and the one case that would need them to differ is served better by a rule's own\n // `excludePaths`. Retired as a SHAPE: `rules` is the entry validateExcludePaths reports for either key.\n new RetiredConfigKey(\n RETIRED_SCOPE_KEY, 'rules', 'excludePaths (one flat array)',\n 'Replace the whole { \"rules\": [...], \"guards\": [...] } object with ONE array holding the union of ' +\n 'both lists, de-duplicated — e.g. \"excludePaths\": [\"repositories/**\"]. A path is governed by ' +\n 'webpieces or it is not, so there is no longer a per-engine split. To exclude a path from one rule ' +\n 'only, use that rule\\'s own \"excludePaths\" inside its config block instead.',\n '[excludePaths]', false,\n ),\n\n // --- whole-repo-build-guard, retired as a REPO-CONFIG key one release after it was added. It shipped\n // as a conventional validated guard (mode ON by default, entry REQUIRED under hookGuards), so every\n // consumer that upgraded hit fault Y — every Bash call blocked — for a feature nobody had opted into.\n // The REQUIRED KEY was the fault, not the default: the failure was at config LOAD, before any command\n // was judged. The switch now lives ONLY in the optional machine-local ~/.webpieces/config.json, where\n // nothing has to be added to be in the default state — and the default is ON again, so deleting this\n // entry loses nothing.\n new RetiredConfigKey(\n RETIRED_SCOPE_RULE, 'whole-repo-build-guard', '~/.webpieces/config.json → experimental.whole-repo-build-guard',\n 'DELETE this entry from webpieces.config.json — no repo config key controls this guard any more. ' +\n 'The guard is ON by default for everyone, with no file and no key required. To turn it OFF for ' +\n 'YOUR machine only, put {\"experimental\": {\"whole-repo-build-guard\": false}} in ' +\n '~/.webpieces/config.json — that file is optional and is tracked by no repo.',\n '[whole-repo-build-guard]', true,\n ),\n\n // --- THE 9 → 3 COLLAPSE of `hookGuards`: one key per POLICY, not one per implementation CLASS.\n //\n // Eight class-named keys become two policy keys. The CLASSES are untouched — `feature-branch-guard`\n // is still the rule name in every decision-log line and every deny report — so nothing an operator\n // greps for moved. What moved is the SWITCH, because nine keys let a consumer configure HALF a\n // policy: `read-stale-guard: OFF` beside `merged-branch-bash-guard: ON` is \"read the file, yes;\n // `cat` the same file, no\", which nobody chose and the config made reachable.\n //\n // EVERY ONE OF THESE IS `prunable: false`, and that is not bookkeeping. `PRUNABLE_SECTIONS` in\n // ConfigPruner includes `hookGuards`, and the validation banner actively RECOMMENDS running the\n // pruner. A `prunable: true` here would mean the recommended cure silently DELETES four configured\n // guards with no destination named — a config loss, which is worse than a block. False keeps the\n // migration instruction and makes the pruner return null for these keys.\n //\n // 4 → 1 is legal for this table (nothing requires `movedTo` to be unique), but it is NOT legal for\n // a naive 1:1 migrator: see migrateRetiredRuleNames in ai-hook-rules' setup.ts, which unions the\n // four old entries into the destination and then fills any missing required field, rather than\n // renaming the first and deleting the rest.\n ...branchStateRetirements(),\n ...prLifecycleRetirements(),\n];\n\n// The four branch-state classes. Split into a helper purely to keep the table above readable; the\n// instruction is per-key because the fields that carry over differ (only feature-branch-guard had\n// `branchNamingConvention`).\n// webpieces-disable no-function-outside-class -- table data for RETIRED_CONFIG_KEYS, beside the array it feeds\nfunction branchStateRetirements(): RetiredConfigKey[] {\n const merged = 'MERGE it into ONE \"branch-state-guard\" entry under \"hookGuards\"';\n const shared =\n `${merged}. All four of feature-branch-guard, read-stale-guard, stale-main-bash-guard and ` +\n 'merged-branch-bash-guard now read that single entry — they are one policy (\"may I work here, ' +\n 'and is what I read current?\") implemented by four classes, and configuring them separately let ' +\n 'you switch on half of it. Keep \"mode\", \"turnOffRuleUntilEpoch\" and \"turnOffRuleWhileOnBranch\"; ' +\n 'the ONE \"hangTimeoutMinutes\" survives (there was only ever one refresher and one cache, so at ' +\n 'most one of the four values could ever take effect); \"branchNamingConvention\" survives from ' +\n 'feature-branch-guard. If the four disagreed on \"mode\", pick the one you meant — \"ON\" arms the ' +\n 'whole policy including the Read block. Then DELETE this key.';\n return [\n new RetiredConfigKey(RETIRED_SCOPE_RULE, 'feature-branch-guard', 'branch-state-guard', shared, '[feature-branch-guard]', false),\n new RetiredConfigKey(RETIRED_SCOPE_RULE, 'read-stale-guard', 'branch-state-guard', shared, '[read-stale-guard]', false),\n new RetiredConfigKey(RETIRED_SCOPE_RULE, 'stale-main-bash-guard', 'branch-state-guard', shared, '[stale-main-bash-guard]', false),\n new RetiredConfigKey(RETIRED_SCOPE_RULE, 'merged-branch-bash-guard', 'branch-state-guard', shared, '[merged-branch-bash-guard]', false),\n ];\n}\n\n// The four PR-lifecycle classes.\n// webpieces-disable no-function-outside-class -- table data for RETIRED_CONFIG_KEYS, beside the array it feeds\nfunction prLifecycleRetirements(): RetiredConfigKey[] {\n const shared =\n 'MERGE it into ONE \"pr-lifecycle-guard\" entry under \"hookGuards\". All four of ' +\n 'pr-creation-or-push-guard, merge-in-progress-guard, pr-merge-guard and ' +\n 'redirect-how-to-merge-main now read that single entry — they are one policy (\"do PRs and ' +\n 'merges go through the gated flow?\"). Keep \"mode\", \"turnOffRuleUntilEpoch\" and ' +\n '\"turnOffRuleWhileOnBranch\". Know what \"mode\": \"OFF\" now means: it releases the ' +\n 'unvalidated-merge gate as well as the PR/push blocks, because merge-in-progress-guard is under ' +\n 'this key too. The per-guard \"upsertPrCommand\" / \"mergeCompleteCommand\" fields are gone — those ' +\n 'strings live ONLY in commands.guardHints.prCreationOrPush / .mergeInProgress. Then DELETE this key.';\n return [\n new RetiredConfigKey(RETIRED_SCOPE_RULE, 'pr-creation-or-push-guard', 'pr-lifecycle-guard', shared, '[pr-creation-or-push-guard]', false),\n new RetiredConfigKey(RETIRED_SCOPE_RULE, 'merge-in-progress-guard', 'pr-lifecycle-guard', shared, '[merge-in-progress-guard]', false),\n new RetiredConfigKey(RETIRED_SCOPE_RULE, 'pr-merge-guard', 'pr-lifecycle-guard', shared, '[pr-merge-guard]', false),\n new RetiredConfigKey(RETIRED_SCOPE_RULE, 'redirect-how-to-merge-main', 'pr-lifecycle-guard', shared, '[redirect-how-to-merge-main]', false),\n ];\n}\n\n/**\n * The shared message. Leads with the retirement, then the destination, then the edit — an agent reading this\n * should not have to infer anything.\n *\n * RETIRED_KEY_MARKER is the phrase the banner classifier keys off to call this error DEFINITIVE (no\n * install can revive a key this table names), so the marker is IMPORTED rather than re-typed here.\n */\n// webpieces-disable no-function-outside-class -- module-level config validator, matches the rest of this package\nexport function retiredKeyError(entry: RetiredConfigKey): string {\n const destination = entry.movedTo === ''\n ? 'It was removed with no replacement.'\n : `It moved to \"${entry.movedTo}\".`;\n // Deletion-only retirements get the mechanical cure named right here, so the reader never has to\n // decide whether removing a key is safe while the guard is denying every Bash call.\n const mechanical = entry.prunable\n ? ` Deleting it is the WHOLE fix — \\`${PRUNE_UNKNOWN_COMMAND}\\` does it for you.`\n : '';\n return `${entry.label} \"${entry.key}\" ${RETIRED_KEY_MARKER}. ${destination} ${entry.instruction}${mechanical}`;\n}\n\n/**\n * The retired entry for a rule/guard NAME, or null. Callers must consult this BEFORE reporting a name as an\n * unknown rule: the generic unknown-rule message can only say \"delete it\", while this table knows WHERE the\n * setting went — a rename that must carry its value over, or a move to `~/.webpieces/config.json`. The\n * destination is the whole product, and a bare \"delete it\" would throw it away.\n */\n// webpieces-disable no-function-outside-class -- module-level config validator, matches the rest of this package\nexport function retiredRuleFor(ruleName: string): RetiredConfigKey | null {\n return RETIRED_CONFIG_KEYS.find(e => e.scope === RETIRED_SCOPE_RULE && e.key === ruleName) ?? null;\n}\n\n/**\n * Whether `key` is retired within `label`'s section. Unknown-key rejection consults this so a retired key\n * gets its migration message instead of a generic \"unknown key, delete it\" — the migration instruction is\n * the entire reason this table exists.\n */\n// webpieces-disable no-function-outside-class -- module-level config validator, matches the rest of this package\nexport function isRetiredKey(key: string, label: string): boolean {\n return RETIRED_CONFIG_KEYS.some(e => e.scope === RETIRED_SCOPE_KEY && e.label === label && e.key === key);\n}\n\n/**\n * The retired entry for `key` within `label`'s section. For a retirement that is a SHAPE rather than a\n * single key (the excludePaths object), the validator looks the entry up directly so one table row remains\n * the single source of the message.\n */\n// webpieces-disable no-function-outside-class -- module-level config validator, matches the rest of this package\nexport function retiredEntry(key: string, label: string): RetiredConfigKey | null {\n return RETIRED_CONFIG_KEYS.find(e => e.scope === RETIRED_SCOPE_KEY && e.label === label && e.key === key) ?? null;\n}\n\n/** Errors for every retired plain key present in `section`. `label` scopes the lookup to that section. */\n// webpieces-disable no-any-unknown -- `section` is opaque consumer JSON; only key PRESENCE is read\n// webpieces-disable no-function-outside-class -- module-level config validator, matches the rest of this package\nexport function retiredKeyErrorsIn(section: Record<string, unknown>, label: string): string[] {\n return RETIRED_CONFIG_KEYS\n .filter(e => e.scope === RETIRED_SCOPE_KEY && e.label === label && e.key in section)\n .map(e => retiredKeyError(e));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"retired-config-keys.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/retired-config-keys.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Retired webpieces.config.json keys — the ONE place in the codebase where a dead config key may be named.\n *\n * ## THE POLICY: webpieces.config.json is never released backwards-compatible\n *\n * When a config key moves, is renamed, or is deleted, the loader REJECTS the old shape with an error that\n * names the destination. It does NOT quietly accept both. There is no fallback, no alias table applied\n * before validation, no \"still accepted for back-compat until every consumer migrates\".\n *\n * This is safe *here* in a way it is not for a normal library, and the reason is the consumer: every reader\n * of this file is a coding agent. The config is validated on startup, the agent is handed the exact edit,\n * and it applies it in one pass — so the upgrade is seamless without shipping a compatibility layer. That\n * makes a hard failure strictly cheaper than duality: two accepted shapes means two code paths, two sets of\n * defaults and two sets of error messages to keep honest forever, and the stale shape then lives in\n * consumer configs indefinitely because nothing ever forces the edit.\n *\n * A hard rejection here is always self-recoverable, which is what makes it safe to do:\n * - editing webpieces.config.json is ALWAYS permitted, even while the config is invalid (see the banner\n * in config-file.ts and the guard matrix — a Write/Edit targeting this file is an unconditional PASS),\n * - and `PRUNE_UNKNOWN_COMMAND` is an L0 CURE, so the mechanical cleanup of keys no validator knows runs\n * from inside the block too.\n * So rejecting an old shape can never wedge a repo. \"It would deadlock the consumer\" is not a reason to add\n * a fallback; it is not true.\n *\n * NOT `pnpm install`. This paragraph used to offer it as the escape hatch that \"fixes the far more common\n * cause of a validation failure: an installed validator lagging the config by a release\". It is permitted\n * (installer bypass), but it is not the cure for anything you can read here: the shim's version-drift guard\n * compares the pin against the installed version and denies every tool call BEFORE the validator runs, so a\n * validation error on screen is proof that package.json and node_modules already agree. The banner from this\n * same package now says \"Do NOT run `pnpm install` — it cannot help\", and a docstring teaching the opposite\n * is how that advice leaked back out.\n *\n * ## Adding an entry\n *\n * When you retire a key, add it here and DELETE its read path — do not leave a `??` fallback behind. The\n * `instruction` is the whole product: it is read by an agent that will act on it verbatim, so give the\n * mechanical edit (\"rename X to Y\", \"move A into B\"), not a description of the change. Saying where a thing\n * moved to is exactly the point of this table; it is what makes the fallback unnecessary.\n *\n * retired-config-keys.spec.ts asserts every entry below actually FAILS the load. That spec is the guard: a\n * future fallback that silently swallows a retired key turns it red.\n */\n\nimport { RETIRED_KEY_MARKER } from './config-error-banner';\nimport { PRUNE_UNKNOWN_COMMAND } from './constants';\n\n// A retired key is matched one of two ways, because config keys live at two very different levels.\n// RULE — a rule/guard NAME, which may sit under either `rules` or `hookGuards`, so it is matched by bare\n// name rather than by a fixed path.\n// KEY — a plain key inside a known section, matched by name within that section.\nexport const RETIRED_SCOPE_RULE = 'rule';\nexport const RETIRED_SCOPE_KEY = 'key';\n\n/** One retired config key and the mechanical edit that replaces it. Data-only (per CLAUDE.md). */\nexport class RetiredConfigKey {\n scope: string;\n // The key exactly as it appears in webpieces.config.json.\n key: string;\n // Where the value goes now. Empty string when the key is deleted outright with no replacement.\n movedTo: string;\n // The imperative fix, written for the agent that will apply it.\n instruction: string;\n // Bracketed label leading the error, matching the `[rule-name]` / `[section]` convention in this package.\n label: string;\n /**\n * True when DELETING the key from webpieces.config.json is the entire edit — nothing in THIS file\n * replaces it, so `PRUNE_UNKNOWN_COMMAND` may strip it mechanically. `whole-repo-build-guard` is the\n * worked example: its switch moved OUT of the repo config into `~/.webpieces/config.json`, so the\n * value has nowhere to go here.\n *\n * False for a rename or an in-file move: deleting those would DISCARD a value the reader still needs,\n * so they keep their migration instruction and the pruner leaves them alone. Required, not defaulted —\n * a defaulted `false` would let a future deletion-only retirement silently opt out of the mechanical\n * cure and land back in \"the reader decides while every Bash call is blocked\".\n */\n prunable: boolean;\n\n // eslint-disable-next-line @typescript-eslint/max-params\n constructor(scope: string, key: string, movedTo: string, instruction: string, label: string, prunable: boolean) {\n this.scope = scope;\n this.key = key;\n this.movedTo = movedTo;\n this.instruction = instruction;\n this.label = label;\n this.prunable = prunable;\n }\n}\n\n/**\n * Every retired key. Keep the newest at the bottom with the release that retired it, so the list reads as a\n * changelog an agent can walk when a config is several versions behind.\n */\nexport const RETIRED_CONFIG_KEYS: readonly RetiredConfigKey[] = [\n // --- Guard renames. Previously applied SILENTLY before validation (a DEPRECATED_RULE_ALIASES table in\n // load-config.ts rewrote the key so no validator ever saw it). That hid the rename from the config file\n // forever: the old name kept working, so no consumer ever updated, and the alias table could never be\n // deleted. Now each is a hard error with the new name.\n //\n // These three RE-POINTED when hookGuards collapsed to one key per policy. Their old destinations\n // (`pr-merge-guard`, `pr-creation-or-push-guard`, `read-stale-guard`) are themselves retired now,\n // and a retirement whose `movedTo` names a dead key teaches the removed API — the same defect one\n // level out. Each therefore names the POLICY key it lands on today, in one hop.\n new RetiredConfigKey(\n RETIRED_SCOPE_RULE, 'pr-merge-cleanup', 'pr-lifecycle-guard',\n 'Rename the key to \"pr-lifecycle-guard\" (merging its value into that entry if you already have ' +\n 'one — the four PR/merge guards share one key now). Its mode and escape hatches carry over.',\n '[pr-merge-cleanup]', false,\n ),\n new RetiredConfigKey(\n RETIRED_SCOPE_RULE, 'pr-creation-guard', 'pr-lifecycle-guard',\n 'Rename the key to \"pr-lifecycle-guard\" (merging its value into that entry if you already have ' +\n 'one — the four PR/merge guards share one key now). Its mode and escape hatches carry over; the ' +\n 'old \"upsertPrCommand\" field does NOT — that string lives only in commands.guardHints.prCreationOrPush.',\n '[pr-creation-guard]', false,\n ),\n new RetiredConfigKey(\n RETIRED_SCOPE_RULE, 'main-stale-guard', 'branch-state-guard',\n 'Rename the key to \"branch-state-guard\" (merging its value into that entry if you already have ' +\n 'one — the four branch-state guards share one key now). Its mode and escape hatches carry over. ' +\n 'Note the widened scope: that key arms the Write, Read AND Bash halves of the branch-state ' +\n 'policy, not just the Read block this key used to name.',\n '[main-stale-guard]', false,\n ),\n\n // --- The two flat guard-hint strings, superseded by commands.guardHints so that every guard-facing\n // command string sits in one named sub-object instead of loose beside the gate config.\n new RetiredConfigKey(\n RETIRED_SCOPE_KEY, 'upsertPr', 'commands.guardHints.prCreationOrPush',\n 'Move the value to \"guardHints\": { \"prCreationOrPush\": <value> } inside the same \"commands\" ' +\n 'section, then delete \"upsertPr\".',\n '[commands]', false,\n ),\n new RetiredConfigKey(\n RETIRED_SCOPE_KEY, 'mergeComplete', 'commands.guardHints.mergeInProgress',\n 'Move the value to \"guardHints\": { \"mergeInProgress\": <value> } inside the same \"commands\" ' +\n 'section, then delete \"mergeComplete\".',\n '[commands]', false,\n ),\n\n // --- The two-list excludePaths object. The split never earned its keep (every consumer set both lists\n // to the same value), and the one case that would need them to differ is served better by a rule's own\n // `excludePaths`. Retired as a SHAPE: `rules` is the entry validateExcludePaths reports for either key.\n new RetiredConfigKey(\n RETIRED_SCOPE_KEY, 'rules', 'excludePaths (one flat array)',\n 'Replace the whole { \"rules\": [...], \"guards\": [...] } object with ONE array holding the union of ' +\n 'both lists, de-duplicated — e.g. \"excludePaths\": [\"repositories/**\"]. A path is governed by ' +\n 'webpieces or it is not, so there is no longer a per-engine split. To exclude a path from one rule ' +\n 'only, use that rule\\'s own \"excludePaths\" inside its config block instead.',\n '[excludePaths]', false,\n ),\n\n // --- whole-repo-build-guard, retired as a REPO-CONFIG key one release after it was added. It shipped\n // as a conventional validated guard (mode ON by default, entry REQUIRED under hookGuards), so every\n // consumer that upgraded hit fault Y — every Bash call blocked — for a feature nobody had opted into.\n // The REQUIRED KEY was the fault, not the default: the failure was at config LOAD, before any command\n // was judged. The switch now lives ONLY in the optional machine-local ~/.webpieces/config.json, where\n // nothing has to be added to be in the default state — and the default is OFF, as every experimental\n // flag's is, so deleting this entry loses nothing.\n new RetiredConfigKey(\n RETIRED_SCOPE_RULE, 'whole-repo-build-guard', '~/.webpieces/config.json → experimental.whole-repo-build-guard',\n 'DELETE this entry from webpieces.config.json — no repo config key controls this guard any more. ' +\n 'The guard is OFF by default for everyone, with no file and no key required. To turn it ON for ' +\n 'YOUR machine only, put {\"experimental\": {\"whole-repo-build-guard\": true}} in ' +\n '~/.webpieces/config.json — that file is optional and is tracked by no repo.',\n '[whole-repo-build-guard]', true,\n ),\n\n // --- THE 9 → 3 COLLAPSE of `hookGuards`: one key per POLICY, not one per implementation CLASS.\n //\n // Eight class-named keys become two policy keys. The CLASSES are untouched — `feature-branch-guard`\n // is still the rule name in every decision-log line and every deny report — so nothing an operator\n // greps for moved. What moved is the SWITCH, because nine keys let a consumer configure HALF a\n // policy: `read-stale-guard: OFF` beside `merged-branch-bash-guard: ON` is \"read the file, yes;\n // `cat` the same file, no\", which nobody chose and the config made reachable.\n //\n // EVERY ONE OF THESE IS `prunable: false`, and that is not bookkeeping. `PRUNABLE_SECTIONS` in\n // ConfigPruner includes `hookGuards`, and the validation banner actively RECOMMENDS running the\n // pruner. A `prunable: true` here would mean the recommended cure silently DELETES four configured\n // guards with no destination named — a config loss, which is worse than a block. False keeps the\n // migration instruction and makes the pruner return null for these keys.\n //\n // 4 → 1 is legal for this table (nothing requires `movedTo` to be unique), but it is NOT legal for\n // a naive 1:1 migrator: see migrateRetiredRuleNames in ai-hook-rules' setup.ts, which unions the\n // four old entries into the destination and then fills any missing required field, rather than\n // renaming the first and deleting the rest.\n ...branchStateRetirements(),\n ...prLifecycleRetirements(),\n];\n\n// The four branch-state classes. Split into a helper purely to keep the table above readable; the\n// instruction is per-key because the fields that carry over differ (only feature-branch-guard had\n// `branchNamingConvention`).\n// webpieces-disable no-function-outside-class -- table data for RETIRED_CONFIG_KEYS, beside the array it feeds\nfunction branchStateRetirements(): RetiredConfigKey[] {\n const merged = 'MERGE it into ONE \"branch-state-guard\" entry under \"hookGuards\"';\n const shared =\n `${merged}. All four of feature-branch-guard, read-stale-guard, stale-main-bash-guard and ` +\n 'merged-branch-bash-guard now read that single entry — they are one policy (\"may I work here, ' +\n 'and is what I read current?\") implemented by four classes, and configuring them separately let ' +\n 'you switch on half of it. Keep \"mode\", \"turnOffRuleUntilEpoch\" and \"turnOffRuleWhileOnBranch\"; ' +\n 'the ONE \"hangTimeoutMinutes\" survives (there was only ever one refresher and one cache, so at ' +\n 'most one of the four values could ever take effect); \"branchNamingConvention\" survives from ' +\n 'feature-branch-guard. If the four disagreed on \"mode\", pick the one you meant — \"ON\" arms the ' +\n 'whole policy including the Read block. Then DELETE this key.';\n return [\n new RetiredConfigKey(RETIRED_SCOPE_RULE, 'feature-branch-guard', 'branch-state-guard', shared, '[feature-branch-guard]', false),\n new RetiredConfigKey(RETIRED_SCOPE_RULE, 'read-stale-guard', 'branch-state-guard', shared, '[read-stale-guard]', false),\n new RetiredConfigKey(RETIRED_SCOPE_RULE, 'stale-main-bash-guard', 'branch-state-guard', shared, '[stale-main-bash-guard]', false),\n new RetiredConfigKey(RETIRED_SCOPE_RULE, 'merged-branch-bash-guard', 'branch-state-guard', shared, '[merged-branch-bash-guard]', false),\n ];\n}\n\n// The four PR-lifecycle classes.\n// webpieces-disable no-function-outside-class -- table data for RETIRED_CONFIG_KEYS, beside the array it feeds\nfunction prLifecycleRetirements(): RetiredConfigKey[] {\n const shared =\n 'MERGE it into ONE \"pr-lifecycle-guard\" entry under \"hookGuards\". All four of ' +\n 'pr-creation-or-push-guard, merge-in-progress-guard, pr-merge-guard and ' +\n 'redirect-how-to-merge-main now read that single entry — they are one policy (\"do PRs and ' +\n 'merges go through the gated flow?\"). Keep \"mode\", \"turnOffRuleUntilEpoch\" and ' +\n '\"turnOffRuleWhileOnBranch\". Know what \"mode\": \"OFF\" now means: it releases the ' +\n 'unvalidated-merge gate as well as the PR/push blocks, because merge-in-progress-guard is under ' +\n 'this key too. The per-guard \"upsertPrCommand\" / \"mergeCompleteCommand\" fields are gone — those ' +\n 'strings live ONLY in commands.guardHints.prCreationOrPush / .mergeInProgress. Then DELETE this key.';\n return [\n new RetiredConfigKey(RETIRED_SCOPE_RULE, 'pr-creation-or-push-guard', 'pr-lifecycle-guard', shared, '[pr-creation-or-push-guard]', false),\n new RetiredConfigKey(RETIRED_SCOPE_RULE, 'merge-in-progress-guard', 'pr-lifecycle-guard', shared, '[merge-in-progress-guard]', false),\n new RetiredConfigKey(RETIRED_SCOPE_RULE, 'pr-merge-guard', 'pr-lifecycle-guard', shared, '[pr-merge-guard]', false),\n new RetiredConfigKey(RETIRED_SCOPE_RULE, 'redirect-how-to-merge-main', 'pr-lifecycle-guard', shared, '[redirect-how-to-merge-main]', false),\n ];\n}\n\n/**\n * The shared message. Leads with the retirement, then the destination, then the edit — an agent reading this\n * should not have to infer anything.\n *\n * RETIRED_KEY_MARKER is the phrase the banner classifier keys off to call this error DEFINITIVE (no\n * install can revive a key this table names), so the marker is IMPORTED rather than re-typed here.\n */\n// webpieces-disable no-function-outside-class -- module-level config validator, matches the rest of this package\nexport function retiredKeyError(entry: RetiredConfigKey): string {\n const destination = entry.movedTo === ''\n ? 'It was removed with no replacement.'\n : `It moved to \"${entry.movedTo}\".`;\n // Deletion-only retirements get the mechanical cure named right here, so the reader never has to\n // decide whether removing a key is safe while the guard is denying every Bash call.\n const mechanical = entry.prunable\n ? ` Deleting it is the WHOLE fix — \\`${PRUNE_UNKNOWN_COMMAND}\\` does it for you.`\n : '';\n return `${entry.label} \"${entry.key}\" ${RETIRED_KEY_MARKER}. ${destination} ${entry.instruction}${mechanical}`;\n}\n\n/**\n * The retired entry for a rule/guard NAME, or null. Callers must consult this BEFORE reporting a name as an\n * unknown rule: the generic unknown-rule message can only say \"delete it\", while this table knows WHERE the\n * setting went — a rename that must carry its value over, or a move to `~/.webpieces/config.json`. The\n * destination is the whole product, and a bare \"delete it\" would throw it away.\n */\n// webpieces-disable no-function-outside-class -- module-level config validator, matches the rest of this package\nexport function retiredRuleFor(ruleName: string): RetiredConfigKey | null {\n return RETIRED_CONFIG_KEYS.find(e => e.scope === RETIRED_SCOPE_RULE && e.key === ruleName) ?? null;\n}\n\n/**\n * Whether `key` is retired within `label`'s section. Unknown-key rejection consults this so a retired key\n * gets its migration message instead of a generic \"unknown key, delete it\" — the migration instruction is\n * the entire reason this table exists.\n */\n// webpieces-disable no-function-outside-class -- module-level config validator, matches the rest of this package\nexport function isRetiredKey(key: string, label: string): boolean {\n return RETIRED_CONFIG_KEYS.some(e => e.scope === RETIRED_SCOPE_KEY && e.label === label && e.key === key);\n}\n\n/**\n * The retired entry for `key` within `label`'s section. For a retirement that is a SHAPE rather than a\n * single key (the excludePaths object), the validator looks the entry up directly so one table row remains\n * the single source of the message.\n */\n// webpieces-disable no-function-outside-class -- module-level config validator, matches the rest of this package\nexport function retiredEntry(key: string, label: string): RetiredConfigKey | null {\n return RETIRED_CONFIG_KEYS.find(e => e.scope === RETIRED_SCOPE_KEY && e.label === label && e.key === key) ?? null;\n}\n\n/** Errors for every retired plain key present in `section`. `label` scopes the lookup to that section. */\n// webpieces-disable no-any-unknown -- `section` is opaque consumer JSON; only key PRESENCE is read\n// webpieces-disable no-function-outside-class -- module-level config validator, matches the rest of this package\nexport function retiredKeyErrorsIn(section: Record<string, unknown>, label: string): string[] {\n return RETIRED_CONFIG_KEYS\n .filter(e => e.scope === RETIRED_SCOPE_KEY && e.label === label && e.key in section)\n .map(e => retiredKeyError(e));\n}\n"]}
|
package/src/rule-configs.js
CHANGED
|
@@ -400,8 +400,9 @@ class PrLifecycleGuardConfig extends BaseRuleConfig {
|
|
|
400
400
|
}
|
|
401
401
|
exports.PrLifecycleGuardConfig = PrLifecycleGuardConfig;
|
|
402
402
|
// NOTE: there is deliberately no `WholeRepoBuildGuardConfig`. That guard has NO webpieces.config.json
|
|
403
|
-
// entry — it is
|
|
404
|
-
// in the optional machine-local ~/.webpieces/config.json
|
|
403
|
+
// entry — it is EXPERIMENTAL and OFF by default, and its only switch is the OPT-IN
|
|
404
|
+
// `experimental.whole-repo-build-guard: true` in the optional machine-local ~/.webpieces/config.json
|
|
405
|
+
// (see home-config.ts). The build command it prints
|
|
405
406
|
// is handed to it directly from `commands.pr-gate.buildCommand` by ai-hook-rules' runner. Re-adding a
|
|
406
407
|
// config class here puts the guard back in RULE_SCHEMAS and makes it a fault-Y rule again.
|
|
407
408
|
class NoFileImportCyclesConfig extends BaseRuleConfig {
|
package/src/rule-configs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rule-configs.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/rule-configs.ts"],"names":[],"mappings":"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","sourcesContent":["import { FieldDef, SchemaShape } from './field-def';\n\n// Mode const arrays — TypeScript union types derived from them, and FieldDef enum\n// values reference the same array. Impossible for the type and runtime check to diverge.\n\n// Single source of truth for rule \"mode\" values. Exported so code-rules (and any other\n// consumer) imports these instead of re-declaring the same unions — a rename here ripples\n// everywhere at compile time. The FieldDef SCHEMA below references the same arrays, so the\n// type and the runtime validation can never diverge.\nexport const METHOD_LIMIT_MODES = ['OFF', 'NEW_METHODS', 'NEW_AND_MODIFIED_METHODS', 'NEW_AND_MODIFIED_FILES'] as const;\nexport type MethodLimitMode = typeof METHOD_LIMIT_MODES[number];\n\nexport const FILE_LIMIT_MODES = ['OFF', 'NEW_AND_MODIFIED_FILES'] as const;\nexport type FileLimitMode = typeof FILE_LIMIT_MODES[number];\n\nexport const RETURN_TYPE_MODES = ['OFF', 'NEW_METHODS', 'NEW_AND_MODIFIED_METHODS', 'NEW_AND_MODIFIED_FILES'] as const;\nexport type ReturnTypeMode = typeof RETURN_TYPE_MODES[number];\n\nexport const INLINE_TYPE_MODES = ['OFF', 'NEW_METHODS', 'NEW_AND_MODIFIED_METHODS', 'NEW_AND_MODIFIED_FILES'] as const;\nexport type InlineTypeMode = typeof INLINE_TYPE_MODES[number];\n\nexport const MODIFIED_CODE_MODES = ['OFF', 'NEW_AND_MODIFIED_CODE', 'NEW_AND_MODIFIED_FILES'] as const;\nexport type ModifiedCodeMode = typeof MODIFIED_CODE_MODES[number];\n\n// PROJECT-level rules (e.g. framework-tag): the check is neither line- nor file-scoped — it runs\n// for a whole project when ANY file the project owns is touched. `MODIFIED_PROJECTS` names that\n// honestly (nx `affected` already narrows execution to the changed projects).\nexport const PROJECT_MODES = ['OFF', 'MODIFIED_PROJECTS'] as const;\nexport type ProjectMode = typeof PROJECT_MODES[number];\n\nexport const PRISMA_DTOS_MODES = ['OFF', 'MODIFIED_CLASS', 'NEW_AND_MODIFIED_FILES'] as const;\nexport type PrismaValidateDtosMode = typeof PRISMA_DTOS_MODES[number];\n\nexport const PRISMA_CONVERTER_MODES = ['OFF', 'NEW_AND_MODIFIED_METHODS', 'NEW_AND_MODIFIED_FILES'] as const;\nexport type PrismaConverterMode = typeof PRISMA_CONVERTER_MODES[number];\n\nexport const DIRECT_API_RESOLVER_MODES = ['OFF', 'NEW_AND_MODIFIED_CODE', 'NEW_AND_MODIFIED_METHODS', 'NEW_AND_MODIFIED_FILES'] as const;\nexport type DirectApiResolverMode = typeof DIRECT_API_RESOLVER_MODES[number];\n\nexport const THROW_CAUSE_MODES = ['OFF', 'NEW_AND_MODIFIED_CODE'] as const;\nexport type ThrowCauseMode = typeof THROW_CAUSE_MODES[number];\n\nexport const ON_OFF_MODES = ['ON', 'OFF'] as const;\nexport type OnOffMode = typeof ON_OFF_MODES[number];\n\n// branch-creation-guard modes. ON_NO_SUBBRANCHES is the strict variant: it hard-blocks\n// creating a branch off any non-main branch (no sub-branch affordance), pointing the agent\n// back to `git checkout main && git pull && git checkout -b <branch>`. Temporarily overridable\n// via the universal turnOffRuleUntilEpoch escape hatch.\nexport const BRANCH_GUARD_MODES = ['ON', 'OFF', 'ON_NO_SUBBRANCHES'] as const;\nexport type BranchGuardMode = typeof BRANCH_GUARD_MODES[number];\n\nexport const VALIDATE_TS_MODES = ['OFF', 'NEW_AND_MODIFIED_FILES'] as const;\nexport type ValidateTsMode = typeof VALIDATE_TS_MODES[number];\n\n// Structural / whole-graph rules (import-cycle, runtime-architecture, nx-wiring). They can't be\n// scoped to changed lines/files — a cycle or wiring break can route through a project that wasn't\n// itself edited — so when active they run the FULL check every time (nx-affected already limits\n// them to affected projects externally). RUN_EVERY_TIME replaces the old, vaguer \"ON\".\nexport const STRUCTURAL_MODES = ['OFF', 'RUN_EVERY_TIME'] as const;\nexport type StructuralMode = typeof STRUCTURAL_MODES[number];\n\n// ---------------------------------------------------------------------------\n// Universal escape hatches — EVERY rule supports temporarily disabling itself\n// either while on a named git branch (turnOffRuleWhileOnBranch) or until an\n// epoch passes (turnOffRuleUntilEpoch). They live on a shared base class so the\n// fields (and their schema entries) are declared once instead of repeated per\n// rule. `mode` stays per-rule because its allowed values vary (ON/OFF vs\n// NEW_AND_MODIFIED_CODE vs NEW_AND_MODIFIED_METHODS, etc).\n//\n// BOTH fields are REQUIRED on every rule so both hatches are ALWAYS VISIBLE in the config — an AI\n// editing webpieces.config.json sees them on every rule and cannot miss that a rule can be time-boxed\n// or branch-scoped off. Convention:\n// turnOffRuleUntilEpoch: 0 = rule active (epoch in the past); a future unix epoch IN SECONDS =\n// temporarily disabled until that moment.\n// turnOffRuleWhileOnBranch: null = always on; a branch name = disabled while that branch is checked out.\n// The name is matched EXACTLY (===). Globs/wildcards are NOT supported and\n// must not be added: a pattern would switch a rule off on branches nobody\n// enumerated. It is also ignored (loudly — shouldSkipRule throws) on a pull\n// request from a FORK, where the branch name is the contributor's to choose.\n// Required-but-nullable so its \"unset\" state is present-and-visible (null)\n// rather than omitted.\n// The earlier spellings of these two fields were RENAMED to the names above and are no longer accepted —\n// the validator rejects them with a \"renamed to X\" hint. RENAMED_FIELD_ALIASES in validate-config.ts is\n// the ONE place in src/ a dead spelling may still be written (see escape-hatch-key-spelling.spec.ts).\n// ---------------------------------------------------------------------------\nexport abstract class BaseRuleConfig {\n // `mode` is declared here (loosely typed) so the shared AbstractRule base can read it for\n // on/off. Each concrete *Config narrows it to its own union (e.g. `mode?: ModifiedCodeMode`),\n // which is an assignable (covariant) override.\n mode?: string;\n // TS-optional, but schema-REQUIRED (see BASE_RULE_SCHEMA) — same split as `mode`. Read directly by\n // AbstractRule.shouldRun, RuleGate, and the code-rules validators.\n turnOffRuleUntilEpoch?: number;\n turnOffRuleWhileOnBranch?: string | null;\n}\n\nexport const BASE_RULE_SCHEMA = {\n turnOffRuleUntilEpoch: new FieldDef('number'),\n turnOffRuleWhileOnBranch: FieldDef.nullableString(),\n};\n\nexport class MaxMethodLinesConfig extends BaseRuleConfig {\n declare mode?: MethodLimitMode;\n limit?: number;\n disableAllowed?: boolean;\n\n static readonly SCHEMA: SchemaShape<MaxMethodLinesConfig> = {\n mode: new FieldDef('string', METHOD_LIMIT_MODES),\n limit: FieldDef.optional('number'),\n disableAllowed: FieldDef.optional('boolean'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class MaxFileLinesConfig extends BaseRuleConfig {\n declare mode?: FileLimitMode;\n limit?: number;\n disableAllowed?: boolean;\n\n static readonly SCHEMA: SchemaShape<MaxFileLinesConfig> = {\n mode: new FieldDef('string', FILE_LIMIT_MODES),\n limit: FieldDef.optional('number'),\n disableAllowed: FieldDef.optional('boolean'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class RequireReturnTypeConfig extends BaseRuleConfig {\n declare mode?: ReturnTypeMode;\n disableAllowed?: boolean;\n\n static readonly SCHEMA: SchemaShape<RequireReturnTypeConfig> = {\n mode: new FieldDef('string', RETURN_TYPE_MODES),\n disableAllowed: FieldDef.optional('boolean'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class NoInlineTypeLiteralsConfig extends BaseRuleConfig {\n declare mode?: InlineTypeMode;\n disableAllowed?: boolean;\n\n static readonly SCHEMA: SchemaShape<NoInlineTypeLiteralsConfig> = {\n mode: new FieldDef('string', INLINE_TYPE_MODES),\n disableAllowed: FieldDef.optional('boolean'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class NoAnyUnknownConfig extends BaseRuleConfig {\n declare mode?: ModifiedCodeMode;\n disableAllowed?: boolean;\n\n static readonly SCHEMA: SchemaShape<NoAnyUnknownConfig> = {\n mode: new FieldDef('string', MODIFIED_CODE_MODES),\n disableAllowed: FieldDef.optional('boolean'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class NoImplicitAnyConfig extends BaseRuleConfig {\n declare mode?: ModifiedCodeMode;\n disableAllowed?: boolean;\n\n static readonly SCHEMA: SchemaShape<NoImplicitAnyConfig> = {\n mode: new FieldDef('string', MODIFIED_CODE_MODES),\n disableAllowed: FieldDef.optional('boolean'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class PrismaValidateDtosConfig extends BaseRuleConfig {\n declare mode?: PrismaValidateDtosMode;\n disableAllowed?: boolean;\n prismaSchemaPath?: string;\n dtoSourcePaths?: string[];\n\n static readonly SCHEMA: SchemaShape<PrismaValidateDtosConfig> = {\n mode: new FieldDef('string', PRISMA_DTOS_MODES),\n disableAllowed: FieldDef.optional('boolean'),\n prismaSchemaPath: FieldDef.optional('string'),\n dtoSourcePaths: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class PrismaConverterConfig extends BaseRuleConfig {\n declare mode?: PrismaConverterMode;\n disableAllowed?: boolean;\n schemaPath?: string;\n convertersPaths?: string[];\n enforcePaths?: string[];\n\n static readonly SCHEMA: SchemaShape<PrismaConverterConfig> = {\n mode: new FieldDef('string', PRISMA_CONVERTER_MODES),\n disableAllowed: FieldDef.optional('boolean'),\n schemaPath: FieldDef.optional('string'),\n convertersPaths: FieldDef.optional('string[]'),\n enforcePaths: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\n// `allowedPaths` exempts whole file trees whose idioms are destructuring by construction (React /\n// React Native components and hooks — `const [x, setX] = useState()`, destructured props — framework\n// glue), matched with the shared glob/prefix/segment semantics of `isPathExcluded`. It is the ONLY\n// escape when `disableAllowed: false`, since that setting deliberately ignores inline disables.\nexport class NoDestructureConfig extends BaseRuleConfig {\n declare mode?: ModifiedCodeMode;\n allowTopLevel?: boolean;\n disableAllowed?: boolean;\n allowedPaths?: string[];\n\n static readonly SCHEMA: SchemaShape<NoDestructureConfig> = {\n mode: new FieldDef('string', MODIFIED_CODE_MODES),\n allowTopLevel: FieldDef.optional('boolean'),\n disableAllowed: FieldDef.optional('boolean'),\n allowedPaths: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class NoUnmanagedExceptionsConfig extends BaseRuleConfig {\n declare mode?: ModifiedCodeMode;\n disableAllowed?: boolean;\n\n static readonly SCHEMA: SchemaShape<NoUnmanagedExceptionsConfig> = {\n mode: new FieldDef('string', MODIFIED_CODE_MODES),\n disableAllowed: FieldDef.optional('boolean'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class CatchErrorPatternConfig extends BaseRuleConfig {\n declare mode?: ModifiedCodeMode;\n disableAllowed?: boolean;\n\n static readonly SCHEMA: SchemaShape<CatchErrorPatternConfig> = {\n mode: new FieldDef('string', MODIFIED_CODE_MODES),\n disableAllowed: FieldDef.optional('boolean'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class ThrowCauseRequiredConfig extends BaseRuleConfig {\n declare mode?: ThrowCauseMode;\n disableAllowed?: boolean;\n\n static readonly SCHEMA: SchemaShape<ThrowCauseRequiredConfig> = {\n mode: new FieldDef('string', THROW_CAUSE_MODES),\n disableAllowed: FieldDef.optional('boolean'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class AngularNoDirectApiInResolverConfig extends BaseRuleConfig {\n declare mode?: DirectApiResolverMode;\n disableAllowed?: boolean;\n enforcePaths?: string[];\n\n static readonly SCHEMA: SchemaShape<AngularNoDirectApiInResolverConfig> = {\n mode: new FieldDef('string', DIRECT_API_RESOLVER_MODES),\n disableAllowed: FieldDef.optional('boolean'),\n enforcePaths: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\n// Bans hand-written CSS in Angular sources (styles:/styleUrls:/styleUrl: in @Component, and inline\n// style=/[style.x]/[ngStyle] in templates) so teams style with Tailwind utility classes. `allowGlobs`\n// exempts paths WITHIN the Angular scope (e.g. a vendored Fuse kit copied verbatim with its own CSS).\nexport class NoCustomCssConfig extends BaseRuleConfig {\n declare mode?: ModifiedCodeMode;\n disableAllowed?: boolean;\n allowGlobs?: string[];\n\n static readonly SCHEMA: SchemaShape<NoCustomCssConfig> = {\n mode: new FieldDef('string', MODIFIED_CODE_MODES),\n disableAllowed: FieldDef.optional('boolean'),\n allowGlobs: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class NoSymbolDiTokensConfig extends BaseRuleConfig {\n declare mode?: ModifiedCodeMode;\n disableAllowed?: boolean;\n allowedPaths?: string[];\n\n static readonly SCHEMA: SchemaShape<NoSymbolDiTokensConfig> = {\n mode: new FieldDef('string', MODIFIED_CODE_MODES),\n disableAllowed: FieldDef.optional('boolean'),\n allowedPaths: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\n// Flags `process.exit(...)` outside a main()/runMain wrapper (and `import { main }`) so a deep exit\n// can't silently kill a reused server/command. Gradual-rollout knobs via the standard base: mode\n// (OFF | NEW_AND_MODIFIED_CODE | NEW_AND_MODIFIED_FILES), turnOffRuleUntilEpoch, branch, and\n// disableAllowed for the inline `// webpieces-disable` escape at genuine terminal boundaries.\nexport class NoProcessExitOutsideMainConfig extends BaseRuleConfig {\n declare mode?: ModifiedCodeMode;\n disableAllowed?: boolean;\n\n static readonly SCHEMA: SchemaShape<NoProcessExitOutsideMainConfig> = {\n mode: new FieldDef('string', MODIFIED_CODE_MODES),\n disableAllowed: FieldDef.optional('boolean'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\n// Flags a function CREATED OUTSIDE A CLASS at module scope: a top-level `function foo()` declaration\n// or a top-level `const foo = () => {}` / `= function(){}`. The point is that webpieces DI +\n// @DocumentDesign only work when behavior lives in injectable classes — a module-scope function is a\n// dead-end the DI graph can't reach. Inline callbacks, nested functions inside methods, and non-function\n// top-level consts (objects, zod schemas, primitives) are NOT flagged. Standard rollout knobs via the\n// base: mode (OFF | NEW_AND_MODIFIED_CODE | NEW_AND_MODIFIED_FILES), turnOffRuleUntilEpoch, branch,\n// and disableAllowed for the inline `// webpieces-disable` escape. `allowedPaths` exempts whole file\n// trees that legitimately live outside the class-per-behavior model (e.g. React component/hook files,\n// framework glue), matched with the shared glob/prefix/segment semantics of `isPathExcluded`.\nexport class NoFunctionOutsideClassConfig extends BaseRuleConfig {\n declare mode?: ModifiedCodeMode;\n disableAllowed?: boolean;\n allowedPaths?: string[];\n\n static readonly SCHEMA: SchemaShape<NoFunctionOutsideClassConfig> = {\n mode: new FieldDef('string', MODIFIED_CODE_MODES),\n disableAllowed: FieldDef.optional('boolean'),\n allowedPaths: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\n// inject-annotation-not-needed-for-concrete-class — flags a REDUNDANT `@inject(X)` whose token is\n// textually identical to the parameter's own declared type (`@inject(Foo) private readonly foo: Foo`).\n// In this inversify setup the decorator is pure noise there: reflect-metadata (emitDecoratorMetadata)\n// already resolves a constructor parameter by its class type, so `private readonly foo: Foo` binds on\n// its own (see CLAUDE.md, and the no-symbol-di-tokens rule that pushes the same way). Symbol/interface\n// tokens are NOT flagged because they never equal the type (`@inject(FOO_TOKEN) x: Provider<Foo>`).\n// AI keeps carpet-bombing `@inject`; this fails the build on the redundant form. Standard rollout knobs\n// via the base: mode (OFF | NEW_AND_MODIFIED_CODE | NEW_AND_MODIFIED_FILES), turnOffRuleUntilEpoch,\n// branch, and disableAllowed for the inline `// webpieces-disable` escape. `allowedPaths` exempts whole\n// file trees, matched with the shared glob/prefix/segment semantics.\nexport class InjectAnnotationNotNeededForConcreteClassConfig extends BaseRuleConfig {\n declare mode?: ModifiedCodeMode;\n disableAllowed?: boolean;\n allowedPaths?: string[];\n\n static readonly SCHEMA: SchemaShape<InjectAnnotationNotNeededForConcreteClassConfig> = {\n mode: new FieldDef('string', MODIFIED_CODE_MODES),\n disableAllowed: FieldDef.optional('boolean'),\n allowedPaths: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\n// framework-tag — every project that a changed source file belongs to must carry >=1\n// `framework:<browser|react|angular|node|express>` nx tag in its project.json. Those tags are the\n// project's \"libType\" — the SET of runtime environments it runs in — and the source of truth for\n// the dependencies.json `framework` field and the `library-types-match-client` rule. Multiple tags\n// are allowed (the env set) and values are validated against the known set (`framework:all` is a\n// hard error). `knownTypes` customizes that set (defaults to browser, react, angular, node, express).\nexport class FrameworkTagConfig extends BaseRuleConfig {\n declare mode?: ProjectMode;\n knownTypes?: string[];\n\n static readonly SCHEMA: SchemaShape<FrameworkTagConfig> = {\n mode: new FieldDef('string', PROJECT_MODES),\n knownTypes: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\n// role-tag — every project that a changed source file belongs to must carry a\n// `role:<server|designed-lib|lib|client>` nx tag in its project.json. That tag is the project's\n// ROLE (orthogonal to `framework` libType) — the source of truth for the dependencies.json `role`\n// field, the `role-dependency` edge rule (apps are never depended upon), and DI-design generation\n// (server→@Controller, designed-lib→@ApiImplementation, lib→none, client→angular design).\n// `knownTypes` customizes the list suggested to the author when a tag is missing.\nexport class RoleTagConfig extends BaseRuleConfig {\n declare mode?: ProjectMode;\n knownTypes?: string[];\n\n static readonly SCHEMA: SchemaShape<RoleTagConfig> = {\n mode: new FieldDef('string', PROJECT_MODES),\n knownTypes: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class BranchCreationGuardConfig extends BaseRuleConfig {\n declare mode?: BranchGuardMode;\n // Naming pattern for stacked SUB-branches only (branches created off another feature branch,\n // which require human approval). Never applied to branches created off main.\n subBranchNaming?: string;\n // Human-sentence instruction telling the AI how to name a NEW branch off main. Surfaced back\n // to the agent in the guard's fix hints. May mirror no-edit-on-main.branchNamingConvention.\n branchFormat?: string;\n // Hard cap on local feature branches (excluding main). Creating one past the cap is BLOCKED until\n // already-merged branches are reaped, which is what keeps the branch list from growing without\n // bound. Branch creation is the gate because it is the only moment cleanup is both cheap and\n // obviously worth it. See merged-branches.ts for how \"already merged\" is determined.\n maxLocalBranches?: number;\n // Hard cap on LINKED worktrees (the primary clone is never counted). A separate budget from\n // maxLocalBranches: every worktree holds a branch, so if worktree-held branches also spent the\n // branch budget, five worktrees would leave room for zero branches. Held branches count here;\n // parked branches count against maxLocalBranches. Enforced at `git worktree add`.\n maxWorktrees?: number;\n // Let the detached background refresher DELETE dead branches on its own, instead of only\n // reporting them. Every candidate is provably dead (a MERGED PR — its own, or the PR of the branch\n // it snapshots; nothing else qualifies) and\n // recoverable by the SHA logged to branch-mutations.log — but it is still UNATTENDED deletion,\n // so this is schema-REQUIRED like `mode` and `turnOffRuleUntilEpoch`. \"Every built-in rule\n // must be explicitly configured — no silent defaults\" (validate-config.ts) applies with extra\n // force here: branches disappearing on a preference nobody ever stated is precisely the kind of\n // default that must not exist. Validation makes each consumer answer the question once.\n //\n // TS-optional but schema-required — the same split `mode` uses. Absent at RUNTIME therefore means\n // the config never passed validation, and the only safe reading of \"nobody has answered\" is: do\n // not delete anything.\n autoReapMergedBranches?: boolean;\n\n static readonly SCHEMA: SchemaShape<BranchCreationGuardConfig> = {\n mode: new FieldDef('string', BRANCH_GUARD_MODES),\n subBranchNaming: FieldDef.optional('string'),\n branchFormat: FieldDef.optional('string'),\n maxLocalBranches: FieldDef.optional('number'),\n maxWorktrees: FieldDef.optional('number'),\n autoReapMergedBranches: new FieldDef('boolean'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\n/**\n * `pr-lifecycle-guard` — ONE key, ONE policy: *PRs and merges go through the gated flow.*\n *\n * Four CLASSES implement it, and their names are unchanged (they are the operator identity every\n * decision-log line and every deny report carries):\n *\n * pr-creation-or-push-guard a manual `git push` / `gh pr create|edit` / a raw pulls API call\n * merge-in-progress-guard a PR command while a 3-point merge is half-finished\n * pr-merge-guard a bare `gh pr merge`\n * redirect-how-to-merge-main \"how do I get main into my branch?\" → the documented flow\n *\n * ## Say this out loud: `\"mode\": \"OFF\"` releases the unvalidated-merge gate too\n *\n * Three of the four are pure COMMAND-SHAPE blocks and can never fire spuriously. The fourth,\n * merge-in-progress-guard, is STATE-conditional — it fires only while a 3-point merge is actually in\n * progress, and it is the one state L2 explicitly stands down for. So turning this key OFF to unblock\n * `gh pr merge` ALSO drops the \"you have an unfinished merge\" gate. That is the honest cost of one key\n * per policy, and it is stated here, in guards/L4-pr-lifecycle.md, and in the error path, rather than\n * being papered over with a granular sub-mode (which would be four knobs wearing one key's name).\n *\n * ## The command strings are NOT here\n *\n * `upsertPrCommand` and `mergeCompleteCommand` used to sit on the two guards, and — being read at the\n * point of use — they BEAT `commands.guardHints`, so `guardHintsWhy`'s claim that renaming a gated\n * command there makes \"every guard message follow\" was simply false. They are DELETED, not deprecated.\n * `commands.guardHints.prCreationOrPush` / `.mergeInProgress` is the one place those strings live, and\n * the loader hands the resolved values to the two rules directly. A consumer that still sets the old\n * per-guard field gets a RETIRED_FIELD_HINTS error naming the destination.\n */\nexport class PrLifecycleGuardConfig extends BaseRuleConfig {\n declare mode?: OnOffMode;\n\n static readonly SCHEMA: SchemaShape<PrLifecycleGuardConfig> = {\n mode: new FieldDef('string', ON_OFF_MODES),\n ...BASE_RULE_SCHEMA,\n };\n}\n\n// NOTE: there is deliberately no `WholeRepoBuildGuardConfig`. That guard has NO webpieces.config.json\n// entry — it is ON by default, and its only switch is the OPT-OUT `experimental.whole-repo-build-guard`\n// in the optional machine-local ~/.webpieces/config.json (see home-config.ts). The build command it prints\n// is handed to it directly from `commands.pr-gate.buildCommand` by ai-hook-rules' runner. Re-adding a\n// config class here puts the guard back in RULE_SCHEMAS and makes it a fault-Y rule again.\n\nexport class NoFileImportCyclesConfig extends BaseRuleConfig {\n declare mode?: StructuralMode;\n ignoreTypeOnly?: boolean;\n excludePackages?: string[];\n // Raw regex escape hatch for a cycle inside the project being checked — generated code, a\n // vendored tree, or a deliberate bidirectional domain model — that `excludePackages` cannot reach\n // (it resolves npm package NAMES, so it only excludes a *sibling* package, never a directory\n // inside this one). Patterns are handed to madge verbatim and matched against ids RELATIVE TO THE\n // PROJECT (e.g. \"^src/generated/\", \"^src/modules/(item|category)/\") — NOT workspace-rooted or\n // absolute, which silently match nothing. The executor warns when a pattern matches zero\n // traversed files, so a mis-anchored pattern is visible rather than a silent no-op.\n excludeRegExp?: string[];\n\n static readonly SCHEMA: SchemaShape<NoFileImportCyclesConfig> = {\n mode: new FieldDef('string', STRUCTURAL_MODES),\n ignoreTypeOnly: FieldDef.optional('boolean'),\n excludePackages: FieldDef.optional('string[]'),\n excludeRegExp: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class RuntimeArchitectureConfig extends BaseRuleConfig {\n declare mode?: StructuralMode;\n // NOTE: `servicePaths` / `apiProjectPaths` were removed — they were never read. The runtime graph\n // is derived SOLELY from architecture/dependencies.json apiRelations + project roles (see\n // nx-webpieces-rules/src/lib/runtime-graph.ts), so any config still listing them (a hand-maintained\n // enumeration of api libs) now fails the unknown-field check in validateWebpiecesConfig. There is\n // nothing to enumerate — delete the keys.\n allowedCycles?: string[];\n /**\n * Draw a dashed terminal node for every contract a service calls that NOTHING in-repo\n * implements (firestore, gmail, ...) — the vendor systems the runtime graph otherwise stops one\n * hop short of. Defaults to true; set false in a repo whose external surface is noisy. Purely a\n * RENDER switch: levels, cycle detection and runtime-dependencies.json are identical either way.\n */\n showExternalNodes?: boolean;\n /**\n * Project roots whose exported `*Api` types are contracts for systems OUTSIDE this repo\n * (firestore, gmail, gcp-storage, ...), e.g. `[\"libraries/apis/external/**\"]`. Globs, matched\n * against the nx project root.\n *\n * Needed because an external contract does NOT look like an in-repo one: it is a plain\n * `interface` bound to a Symbol token and injected, never an `abstract class` carrying @ApiPath\n * reached through `createRpcClient`. Without this list the scanner has no way to tell a vendor\n * seam from any other library, so every call leaving the repo is invisible to the runtime graph.\n *\n * Defaults to none, which is correct for a repo with no vendor wrapper libraries.\n */\n externalApiPaths?: string[];\n\n static readonly SCHEMA: SchemaShape<RuntimeArchitectureConfig> = {\n mode: new FieldDef('string', STRUCTURAL_MODES),\n allowedCycles: FieldDef.optional('string[]'),\n showExternalNodes: FieldDef.optional('boolean'),\n externalApiPaths: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class NxWiringConfig extends BaseRuleConfig {\n declare mode?: StructuralMode;\n\n static readonly SCHEMA: SchemaShape<NxWiringConfig> = {\n mode: new FieldDef('string', STRUCTURAL_MODES),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class DiGraphConfig extends BaseRuleConfig {\n // Structural: the DI graph is regenerated whole-project on every build (generate +\n // unchanged gate), so it cannot be scoped to changed lines.\n declare mode?: StructuralMode;\n\n static readonly SCHEMA: SchemaShape<DiGraphConfig> = {\n mode: new FieldDef('string', STRUCTURAL_MODES),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class MissingDesignAnnotationConfig extends BaseRuleConfig {\n // Structural: enforced per-project by the di-graph-generate executor, which\n // roots the whole DI design on @DocumentDesign classes — cannot be line-scoped.\n declare mode?: StructuralMode;\n\n static readonly SCHEMA: SchemaShape<MissingDesignAnnotationConfig> = {\n mode: new FieldDef('string', STRUCTURAL_MODES),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class NoJsFilesConfig extends BaseRuleConfig {\n // File-tier: NEW_AND_MODIFIED_FILES (active) intercepts a .js/.jsx Write — the file being\n // written is inherently a new/modified file, so it's already diff-scoped in practice.\n declare mode?: FileLimitMode;\n allowedPaths?: string[];\n\n static readonly SCHEMA: SchemaShape<NoJsFilesConfig> = {\n mode: new FieldDef('string', FILE_LIMIT_MODES),\n allowedPaths: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\n// ---------------------------------------------------------------------------\n// The five Nx infrastructure validators (architecture-unchanged, no-architecture-cycles,\n// packagejson, versions-locked, eslint-sync). Each is whole-graph / whole-repo by nature (a cycle, a\n// drifted dependencies.json, an unlocked version can be introduced by a file nobody in this diff\n// touched), so the only honest mode set is STRUCTURAL_MODES: RUN_EVERY_TIME (the default) or OFF.\n//\n// All five now honor the universal escape hatches (turnOffRuleUntilEpoch / turnOffRuleWhileOnBranch)\n// via shouldSkipRule — the RuleGate is called with honorEpoch:true from\n// every executor. This lets a repo time-box or branch-scope a failing infrastructure check (e.g. hold\n// validate-packagejson off until an upgrade PR lands) with a one-value edit, instead of only the\n// blunt \"mode\": \"OFF\". Originally packagejson/versions-locked/eslint-sync were all-or-nothing on the\n// theory that \"no blessed baseline\" made grandfathering meaningless, but a time-box is a schedule, not\n// a baseline: \"do not enforce this until <epoch>/off <branch>\" is coherent for any rule.\n// ---------------------------------------------------------------------------\n\nexport class ValidateArchitectureUnchangedConfig extends BaseRuleConfig {\n declare mode?: StructuralMode;\n\n static readonly SCHEMA: SchemaShape<ValidateArchitectureUnchangedConfig> = {\n mode: new FieldDef('string', STRUCTURAL_MODES),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class ValidateNoArchitectureCyclesConfig extends BaseRuleConfig {\n declare mode?: StructuralMode;\n\n static readonly SCHEMA: SchemaShape<ValidateNoArchitectureCyclesConfig> = {\n mode: new FieldDef('string', STRUCTURAL_MODES),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class ValidatePackageJsonConfig extends BaseRuleConfig {\n declare mode?: StructuralMode;\n\n static readonly SCHEMA: SchemaShape<ValidatePackageJsonConfig> = {\n mode: new FieldDef('string', STRUCTURAL_MODES),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class ValidateVersionsLockedConfig extends BaseRuleConfig {\n declare mode?: StructuralMode;\n\n static readonly SCHEMA: SchemaShape<ValidateVersionsLockedConfig> = {\n mode: new FieldDef('string', STRUCTURAL_MODES),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class ValidateEslintSyncConfig extends BaseRuleConfig {\n declare mode?: StructuralMode;\n\n static readonly SCHEMA: SchemaShape<ValidateEslintSyncConfig> = {\n mode: new FieldDef('string', STRUCTURAL_MODES),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class ValidateTsInSrcConfig extends BaseRuleConfig {\n declare mode?: ValidateTsMode;\n allowedRootFiles?: string[];\n excludePaths?: string[];\n\n static readonly SCHEMA: SchemaShape<ValidateTsInSrcConfig> = {\n mode: new FieldDef('string', VALIDATE_TS_MODES),\n allowedRootFiles: FieldDef.optional('string[]'),\n excludePaths: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"rule-configs.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/rule-configs.ts"],"names":[],"mappings":";;;AAAA,2CAAoD;AAEpD,kFAAkF;AAClF,yFAAyF;AAEzF,uFAAuF;AACvF,0FAA0F;AAC1F,2FAA2F;AAC3F,qDAAqD;AACxC,QAAA,kBAAkB,GAAG,CAAC,KAAK,EAAE,aAAa,EAAE,0BAA0B,EAAE,wBAAwB,CAAU,CAAC;AAG3G,QAAA,gBAAgB,GAAG,CAAC,KAAK,EAAE,wBAAwB,CAAU,CAAC;AAG9D,QAAA,iBAAiB,GAAG,CAAC,KAAK,EAAE,aAAa,EAAE,0BAA0B,EAAE,wBAAwB,CAAU,CAAC;AAG1G,QAAA,iBAAiB,GAAG,CAAC,KAAK,EAAE,aAAa,EAAE,0BAA0B,EAAE,wBAAwB,CAAU,CAAC;AAG1G,QAAA,mBAAmB,GAAG,CAAC,KAAK,EAAE,uBAAuB,EAAE,wBAAwB,CAAU,CAAC;AAGvG,iGAAiG;AACjG,gGAAgG;AAChG,8EAA8E;AACjE,QAAA,aAAa,GAAG,CAAC,KAAK,EAAE,mBAAmB,CAAU,CAAC;AAGtD,QAAA,iBAAiB,GAAG,CAAC,KAAK,EAAE,gBAAgB,EAAE,wBAAwB,CAAU,CAAC;AAGjF,QAAA,sBAAsB,GAAG,CAAC,KAAK,EAAE,0BAA0B,EAAE,wBAAwB,CAAU,CAAC;AAGhG,QAAA,yBAAyB,GAAG,CAAC,KAAK,EAAE,uBAAuB,EAAE,0BAA0B,EAAE,wBAAwB,CAAU,CAAC;AAG5H,QAAA,iBAAiB,GAAG,CAAC,KAAK,EAAE,uBAAuB,CAAU,CAAC;AAG9D,QAAA,YAAY,GAAG,CAAC,IAAI,EAAE,KAAK,CAAU,CAAC;AAGnD,uFAAuF;AACvF,2FAA2F;AAC3F,+FAA+F;AAC/F,wDAAwD;AAC3C,QAAA,kBAAkB,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,mBAAmB,CAAU,CAAC;AAGjE,QAAA,iBAAiB,GAAG,CAAC,KAAK,EAAE,wBAAwB,CAAU,CAAC;AAG5E,gGAAgG;AAChG,kGAAkG;AAClG,gGAAgG;AAChG,uFAAuF;AAC1E,QAAA,gBAAgB,GAAG,CAAC,KAAK,EAAE,gBAAgB,CAAU,CAAC;AAGnE,8EAA8E;AAC9E,8EAA8E;AAC9E,4EAA4E;AAC5E,gFAAgF;AAChF,8EAA8E;AAC9E,yEAAyE;AACzE,2DAA2D;AAC3D,EAAE;AACF,kGAAkG;AAClG,sGAAsG;AACtG,oCAAoC;AACpC,oGAAoG;AACpG,sEAAsE;AACtE,2GAA2G;AAC3G,uGAAuG;AACvG,sGAAsG;AACtG,wGAAwG;AACxG,yGAAyG;AACzG,uGAAuG;AACvG,mDAAmD;AACnD,yGAAyG;AACzG,wGAAwG;AACxG,sGAAsG;AACtG,8EAA8E;AAC9E,MAAsB,cAAc;IAChC,0FAA0F;IAC1F,8FAA8F;IAC9F,+CAA+C;IAC/C,IAAI,CAAU;IACd,mGAAmG;IACnG,mEAAmE;IACnE,qBAAqB,CAAU;IAC/B,wBAAwB,CAAiB;CAC5C;AATD,wCASC;AAEY,QAAA,gBAAgB,GAAG;IAC5B,qBAAqB,EAAE,IAAI,oBAAQ,CAAC,QAAQ,CAAC;IAC7C,wBAAwB,EAAE,oBAAQ,CAAC,cAAc,EAAE;CACtD,CAAC;AAEF,MAAa,oBAAqB,SAAQ,cAAc;IAEpD,KAAK,CAAU;IACf,cAAc,CAAW;IAEzB,MAAM,CAAU,MAAM,GAAsC;QACxD,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,0BAAkB,CAAC;QAChD,KAAK,EAAE,oBAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAClC,cAAc,EAAE,oBAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC5C,GAAG,wBAAgB;KACtB,CAAC;;AAVN,oDAWC;AAED,MAAa,kBAAmB,SAAQ,cAAc;IAElD,KAAK,CAAU;IACf,cAAc,CAAW;IAEzB,MAAM,CAAU,MAAM,GAAoC;QACtD,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,wBAAgB,CAAC;QAC9C,KAAK,EAAE,oBAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAClC,cAAc,EAAE,oBAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC5C,GAAG,wBAAgB;KACtB,CAAC;;AAVN,gDAWC;AAED,MAAa,uBAAwB,SAAQ,cAAc;IAEvD,cAAc,CAAW;IAEzB,MAAM,CAAU,MAAM,GAAyC;QAC3D,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,yBAAiB,CAAC;QAC/C,cAAc,EAAE,oBAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC5C,GAAG,wBAAgB;KACtB,CAAC;;AARN,0DASC;AAED,MAAa,0BAA2B,SAAQ,cAAc;IAE1D,cAAc,CAAW;IAEzB,MAAM,CAAU,MAAM,GAA4C;QAC9D,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,yBAAiB,CAAC;QAC/C,cAAc,EAAE,oBAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC5C,GAAG,wBAAgB;KACtB,CAAC;;AARN,gEASC;AAED,MAAa,kBAAmB,SAAQ,cAAc;IAElD,cAAc,CAAW;IAEzB,MAAM,CAAU,MAAM,GAAoC;QACtD,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,2BAAmB,CAAC;QACjD,cAAc,EAAE,oBAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC5C,GAAG,wBAAgB;KACtB,CAAC;;AARN,gDASC;AAED,MAAa,mBAAoB,SAAQ,cAAc;IAEnD,cAAc,CAAW;IAEzB,MAAM,CAAU,MAAM,GAAqC;QACvD,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,2BAAmB,CAAC;QACjD,cAAc,EAAE,oBAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC5C,GAAG,wBAAgB;KACtB,CAAC;;AARN,kDASC;AAED,MAAa,wBAAyB,SAAQ,cAAc;IAExD,cAAc,CAAW;IACzB,gBAAgB,CAAU;IAC1B,cAAc,CAAY;IAE1B,MAAM,CAAU,MAAM,GAA0C;QAC5D,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,yBAAiB,CAAC;QAC/C,cAAc,EAAE,oBAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC5C,gBAAgB,EAAE,oBAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAC7C,cAAc,EAAE,oBAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC7C,GAAG,wBAAgB;KACtB,CAAC;;AAZN,4DAaC;AAED,MAAa,qBAAsB,SAAQ,cAAc;IAErD,cAAc,CAAW;IACzB,UAAU,CAAU;IACpB,eAAe,CAAY;IAC3B,YAAY,CAAY;IAExB,MAAM,CAAU,MAAM,GAAuC;QACzD,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,8BAAsB,CAAC;QACpD,cAAc,EAAE,oBAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC5C,UAAU,EAAE,oBAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC;QACvC,eAAe,EAAE,oBAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC9C,YAAY,EAAE,oBAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC3C,GAAG,wBAAgB;KACtB,CAAC;;AAdN,sDAeC;AAED,kGAAkG;AAClG,qGAAqG;AACrG,mGAAmG;AACnG,gGAAgG;AAChG,MAAa,mBAAoB,SAAQ,cAAc;IAEnD,aAAa,CAAW;IACxB,cAAc,CAAW;IACzB,YAAY,CAAY;IAExB,MAAM,CAAU,MAAM,GAAqC;QACvD,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,2BAAmB,CAAC;QACjD,aAAa,EAAE,oBAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC3C,cAAc,EAAE,oBAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC5C,YAAY,EAAE,oBAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC3C,GAAG,wBAAgB;KACtB,CAAC;;AAZN,kDAaC;AAED,MAAa,2BAA4B,SAAQ,cAAc;IAE3D,cAAc,CAAW;IAEzB,MAAM,CAAU,MAAM,GAA6C;QAC/D,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,2BAAmB,CAAC;QACjD,cAAc,EAAE,oBAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC5C,GAAG,wBAAgB;KACtB,CAAC;;AARN,kEASC;AAED,MAAa,uBAAwB,SAAQ,cAAc;IAEvD,cAAc,CAAW;IAEzB,MAAM,CAAU,MAAM,GAAyC;QAC3D,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,2BAAmB,CAAC;QACjD,cAAc,EAAE,oBAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC5C,GAAG,wBAAgB;KACtB,CAAC;;AARN,0DASC;AAED,MAAa,wBAAyB,SAAQ,cAAc;IAExD,cAAc,CAAW;IAEzB,MAAM,CAAU,MAAM,GAA0C;QAC5D,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,yBAAiB,CAAC;QAC/C,cAAc,EAAE,oBAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC5C,GAAG,wBAAgB;KACtB,CAAC;;AARN,4DASC;AAED,MAAa,kCAAmC,SAAQ,cAAc;IAElE,cAAc,CAAW;IACzB,YAAY,CAAY;IAExB,MAAM,CAAU,MAAM,GAAoD;QACtE,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,iCAAyB,CAAC;QACvD,cAAc,EAAE,oBAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC5C,YAAY,EAAE,oBAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC3C,GAAG,wBAAgB;KACtB,CAAC;;AAVN,gFAWC;AAED,mGAAmG;AACnG,sGAAsG;AACtG,sGAAsG;AACtG,MAAa,iBAAkB,SAAQ,cAAc;IAEjD,cAAc,CAAW;IACzB,UAAU,CAAY;IAEtB,MAAM,CAAU,MAAM,GAAmC;QACrD,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,2BAAmB,CAAC;QACjD,cAAc,EAAE,oBAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC5C,UAAU,EAAE,oBAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC;QACzC,GAAG,wBAAgB;KACtB,CAAC;;AAVN,8CAWC;AAED,MAAa,sBAAuB,SAAQ,cAAc;IAEtD,cAAc,CAAW;IACzB,YAAY,CAAY;IAExB,MAAM,CAAU,MAAM,GAAwC;QAC1D,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,2BAAmB,CAAC;QACjD,cAAc,EAAE,oBAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC5C,YAAY,EAAE,oBAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC3C,GAAG,wBAAgB;KACtB,CAAC;;AAVN,wDAWC;AAED,oGAAoG;AACpG,iGAAiG;AACjG,6FAA6F;AAC7F,8FAA8F;AAC9F,MAAa,8BAA+B,SAAQ,cAAc;IAE9D,cAAc,CAAW;IAEzB,MAAM,CAAU,MAAM,GAAgD;QAClE,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,2BAAmB,CAAC;QACjD,cAAc,EAAE,oBAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC5C,GAAG,wBAAgB;KACtB,CAAC;;AARN,wEASC;AAED,qGAAqG;AACrG,6FAA6F;AAC7F,qGAAqG;AACrG,yGAAyG;AACzG,sGAAsG;AACtG,oGAAoG;AACpG,qGAAqG;AACrG,sGAAsG;AACtG,8FAA8F;AAC9F,MAAa,4BAA6B,SAAQ,cAAc;IAE5D,cAAc,CAAW;IACzB,YAAY,CAAY;IAExB,MAAM,CAAU,MAAM,GAA8C;QAChE,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,2BAAmB,CAAC;QACjD,cAAc,EAAE,oBAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC5C,YAAY,EAAE,oBAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC3C,GAAG,wBAAgB;KACtB,CAAC;;AAVN,oEAWC;AAED,kGAAkG;AAClG,uGAAuG;AACvG,sGAAsG;AACtG,sGAAsG;AACtG,uGAAuG;AACvG,oGAAoG;AACpG,wGAAwG;AACxG,oGAAoG;AACpG,wGAAwG;AACxG,qEAAqE;AACrE,MAAa,+CAAgD,SAAQ,cAAc;IAE/E,cAAc,CAAW;IACzB,YAAY,CAAY;IAExB,MAAM,CAAU,MAAM,GAAiE;QACnF,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,2BAAmB,CAAC;QACjD,cAAc,EAAE,oBAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC5C,YAAY,EAAE,oBAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC3C,GAAG,wBAAgB;KACtB,CAAC;;AAVN,0GAWC;AAED,qFAAqF;AACrF,kGAAkG;AAClG,iGAAiG;AACjG,mGAAmG;AACnG,iGAAiG;AACjG,sGAAsG;AACtG,MAAa,kBAAmB,SAAQ,cAAc;IAElD,UAAU,CAAY;IAEtB,MAAM,CAAU,MAAM,GAAoC;QACtD,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,qBAAa,CAAC;QAC3C,UAAU,EAAE,oBAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC;QACzC,GAAG,wBAAgB;KACtB,CAAC;;AARN,gDASC;AAED,8EAA8E;AAC9E,gGAAgG;AAChG,kGAAkG;AAClG,kGAAkG;AAClG,0FAA0F;AAC1F,kFAAkF;AAClF,MAAa,aAAc,SAAQ,cAAc;IAE7C,UAAU,CAAY;IAEtB,MAAM,CAAU,MAAM,GAA+B;QACjD,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,qBAAa,CAAC;QAC3C,UAAU,EAAE,oBAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC;QACzC,GAAG,wBAAgB;KACtB,CAAC;;AARN,sCASC;AAED,MAAa,yBAA0B,SAAQ,cAAc;IAEzD,6FAA6F;IAC7F,6EAA6E;IAC7E,eAAe,CAAU;IACzB,6FAA6F;IAC7F,4FAA4F;IAC5F,YAAY,CAAU;IACtB,kGAAkG;IAClG,+FAA+F;IAC/F,6FAA6F;IAC7F,qFAAqF;IACrF,gBAAgB,CAAU;IAC1B,4FAA4F;IAC5F,+FAA+F;IAC/F,8FAA8F;IAC9F,kFAAkF;IAClF,YAAY,CAAU;IACtB,yFAAyF;IACzF,mGAAmG;IACnG,4CAA4C;IAC5C,+FAA+F;IAC/F,2FAA2F;IAC3F,8FAA8F;IAC9F,gGAAgG;IAChG,wFAAwF;IACxF,EAAE;IACF,kGAAkG;IAClG,gGAAgG;IAChG,uBAAuB;IACvB,sBAAsB,CAAW;IAEjC,MAAM,CAAU,MAAM,GAA2C;QAC7D,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,0BAAkB,CAAC;QAChD,eAAe,EAAE,oBAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAC5C,YAAY,EAAE,oBAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC;QACzC,gBAAgB,EAAE,oBAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAC7C,YAAY,EAAE,oBAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC;QACzC,sBAAsB,EAAE,IAAI,oBAAQ,CAAC,SAAS,CAAC;QAC/C,GAAG,wBAAgB;KACtB,CAAC;;AAxCN,8DAyCC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAa,sBAAuB,SAAQ,cAAc;IAGtD,MAAM,CAAU,MAAM,GAAwC;QAC1D,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,oBAAY,CAAC;QAC1C,GAAG,wBAAgB;KACtB,CAAC;;AANN,wDAOC;AAED,sGAAsG;AACtG,mFAAmF;AACnF,qGAAqG;AACrG,oDAAoD;AACpD,sGAAsG;AACtG,2FAA2F;AAE3F,MAAa,wBAAyB,SAAQ,cAAc;IAExD,cAAc,CAAW;IACzB,eAAe,CAAY;IAC3B,0FAA0F;IAC1F,kGAAkG;IAClG,6FAA6F;IAC7F,kGAAkG;IAClG,8FAA8F;IAC9F,yFAAyF;IACzF,oFAAoF;IACpF,aAAa,CAAY;IAEzB,MAAM,CAAU,MAAM,GAA0C;QAC5D,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,wBAAgB,CAAC;QAC9C,cAAc,EAAE,oBAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC5C,eAAe,EAAE,oBAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC9C,aAAa,EAAE,oBAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC5C,GAAG,wBAAgB;KACtB,CAAC;;AAnBN,4DAoBC;AAED,MAAa,yBAA0B,SAAQ,cAAc;IAEzD,kGAAkG;IAClG,0FAA0F;IAC1F,oGAAoG;IACpG,kGAAkG;IAClG,0CAA0C;IAC1C,aAAa,CAAY;IACzB;;;;;OAKG;IACH,iBAAiB,CAAW;IAC5B;;;;;;;;;;;OAWG;IACH,gBAAgB,CAAY;IAE5B,MAAM,CAAU,MAAM,GAA2C;QAC7D,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,wBAAgB,CAAC;QAC9C,aAAa,EAAE,oBAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC5C,iBAAiB,EAAE,oBAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC/C,gBAAgB,EAAE,oBAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC/C,GAAG,wBAAgB;KACtB,CAAC;;AAnCN,8DAoCC;AAED,MAAa,cAAe,SAAQ,cAAc;IAG9C,MAAM,CAAU,MAAM,GAAgC;QAClD,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,wBAAgB,CAAC;QAC9C,GAAG,wBAAgB;KACtB,CAAC;;AANN,wCAOC;AAED,MAAa,aAAc,SAAQ,cAAc;IAK7C,MAAM,CAAU,MAAM,GAA+B;QACjD,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,wBAAgB,CAAC;QAC9C,GAAG,wBAAgB;KACtB,CAAC;;AARN,sCASC;AAED,MAAa,6BAA8B,SAAQ,cAAc;IAK7D,MAAM,CAAU,MAAM,GAA+C;QACjE,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,wBAAgB,CAAC;QAC9C,GAAG,wBAAgB;KACtB,CAAC;;AARN,sEASC;AAED,MAAa,eAAgB,SAAQ,cAAc;IAI/C,YAAY,CAAY;IAExB,MAAM,CAAU,MAAM,GAAiC;QACnD,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,wBAAgB,CAAC;QAC9C,YAAY,EAAE,oBAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC3C,GAAG,wBAAgB;KACtB,CAAC;;AAVN,0CAWC;AAED,8EAA8E;AAC9E,yFAAyF;AACzF,qGAAqG;AACrG,iGAAiG;AACjG,kGAAkG;AAClG,EAAE;AACF,qGAAqG;AACrG,wEAAwE;AACxE,sGAAsG;AACtG,iGAAiG;AACjG,qGAAqG;AACrG,uGAAuG;AACvG,yFAAyF;AACzF,8EAA8E;AAE9E,MAAa,mCAAoC,SAAQ,cAAc;IAGnE,MAAM,CAAU,MAAM,GAAqD;QACvE,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,wBAAgB,CAAC;QAC9C,GAAG,wBAAgB;KACtB,CAAC;;AANN,kFAOC;AAED,MAAa,kCAAmC,SAAQ,cAAc;IAGlE,MAAM,CAAU,MAAM,GAAoD;QACtE,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,wBAAgB,CAAC;QAC9C,GAAG,wBAAgB;KACtB,CAAC;;AANN,gFAOC;AAED,MAAa,yBAA0B,SAAQ,cAAc;IAGzD,MAAM,CAAU,MAAM,GAA2C;QAC7D,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,wBAAgB,CAAC;QAC9C,GAAG,wBAAgB;KACtB,CAAC;;AANN,8DAOC;AAED,MAAa,4BAA6B,SAAQ,cAAc;IAG5D,MAAM,CAAU,MAAM,GAA8C;QAChE,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,wBAAgB,CAAC;QAC9C,GAAG,wBAAgB;KACtB,CAAC;;AANN,oEAOC;AAED,MAAa,wBAAyB,SAAQ,cAAc;IAGxD,MAAM,CAAU,MAAM,GAA0C;QAC5D,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,wBAAgB,CAAC;QAC9C,GAAG,wBAAgB;KACtB,CAAC;;AANN,4DAOC;AAED,MAAa,qBAAsB,SAAQ,cAAc;IAErD,gBAAgB,CAAY;IAC5B,YAAY,CAAY;IAExB,MAAM,CAAU,MAAM,GAAuC;QACzD,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,yBAAiB,CAAC;QAC/C,gBAAgB,EAAE,oBAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC/C,YAAY,EAAE,oBAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC3C,GAAG,wBAAgB;KACtB,CAAC;;AAVN,sDAWC","sourcesContent":["import { FieldDef, SchemaShape } from './field-def';\n\n// Mode const arrays — TypeScript union types derived from them, and FieldDef enum\n// values reference the same array. Impossible for the type and runtime check to diverge.\n\n// Single source of truth for rule \"mode\" values. Exported so code-rules (and any other\n// consumer) imports these instead of re-declaring the same unions — a rename here ripples\n// everywhere at compile time. The FieldDef SCHEMA below references the same arrays, so the\n// type and the runtime validation can never diverge.\nexport const METHOD_LIMIT_MODES = ['OFF', 'NEW_METHODS', 'NEW_AND_MODIFIED_METHODS', 'NEW_AND_MODIFIED_FILES'] as const;\nexport type MethodLimitMode = typeof METHOD_LIMIT_MODES[number];\n\nexport const FILE_LIMIT_MODES = ['OFF', 'NEW_AND_MODIFIED_FILES'] as const;\nexport type FileLimitMode = typeof FILE_LIMIT_MODES[number];\n\nexport const RETURN_TYPE_MODES = ['OFF', 'NEW_METHODS', 'NEW_AND_MODIFIED_METHODS', 'NEW_AND_MODIFIED_FILES'] as const;\nexport type ReturnTypeMode = typeof RETURN_TYPE_MODES[number];\n\nexport const INLINE_TYPE_MODES = ['OFF', 'NEW_METHODS', 'NEW_AND_MODIFIED_METHODS', 'NEW_AND_MODIFIED_FILES'] as const;\nexport type InlineTypeMode = typeof INLINE_TYPE_MODES[number];\n\nexport const MODIFIED_CODE_MODES = ['OFF', 'NEW_AND_MODIFIED_CODE', 'NEW_AND_MODIFIED_FILES'] as const;\nexport type ModifiedCodeMode = typeof MODIFIED_CODE_MODES[number];\n\n// PROJECT-level rules (e.g. framework-tag): the check is neither line- nor file-scoped — it runs\n// for a whole project when ANY file the project owns is touched. `MODIFIED_PROJECTS` names that\n// honestly (nx `affected` already narrows execution to the changed projects).\nexport const PROJECT_MODES = ['OFF', 'MODIFIED_PROJECTS'] as const;\nexport type ProjectMode = typeof PROJECT_MODES[number];\n\nexport const PRISMA_DTOS_MODES = ['OFF', 'MODIFIED_CLASS', 'NEW_AND_MODIFIED_FILES'] as const;\nexport type PrismaValidateDtosMode = typeof PRISMA_DTOS_MODES[number];\n\nexport const PRISMA_CONVERTER_MODES = ['OFF', 'NEW_AND_MODIFIED_METHODS', 'NEW_AND_MODIFIED_FILES'] as const;\nexport type PrismaConverterMode = typeof PRISMA_CONVERTER_MODES[number];\n\nexport const DIRECT_API_RESOLVER_MODES = ['OFF', 'NEW_AND_MODIFIED_CODE', 'NEW_AND_MODIFIED_METHODS', 'NEW_AND_MODIFIED_FILES'] as const;\nexport type DirectApiResolverMode = typeof DIRECT_API_RESOLVER_MODES[number];\n\nexport const THROW_CAUSE_MODES = ['OFF', 'NEW_AND_MODIFIED_CODE'] as const;\nexport type ThrowCauseMode = typeof THROW_CAUSE_MODES[number];\n\nexport const ON_OFF_MODES = ['ON', 'OFF'] as const;\nexport type OnOffMode = typeof ON_OFF_MODES[number];\n\n// branch-creation-guard modes. ON_NO_SUBBRANCHES is the strict variant: it hard-blocks\n// creating a branch off any non-main branch (no sub-branch affordance), pointing the agent\n// back to `git checkout main && git pull && git checkout -b <branch>`. Temporarily overridable\n// via the universal turnOffRuleUntilEpoch escape hatch.\nexport const BRANCH_GUARD_MODES = ['ON', 'OFF', 'ON_NO_SUBBRANCHES'] as const;\nexport type BranchGuardMode = typeof BRANCH_GUARD_MODES[number];\n\nexport const VALIDATE_TS_MODES = ['OFF', 'NEW_AND_MODIFIED_FILES'] as const;\nexport type ValidateTsMode = typeof VALIDATE_TS_MODES[number];\n\n// Structural / whole-graph rules (import-cycle, runtime-architecture, nx-wiring). They can't be\n// scoped to changed lines/files — a cycle or wiring break can route through a project that wasn't\n// itself edited — so when active they run the FULL check every time (nx-affected already limits\n// them to affected projects externally). RUN_EVERY_TIME replaces the old, vaguer \"ON\".\nexport const STRUCTURAL_MODES = ['OFF', 'RUN_EVERY_TIME'] as const;\nexport type StructuralMode = typeof STRUCTURAL_MODES[number];\n\n// ---------------------------------------------------------------------------\n// Universal escape hatches — EVERY rule supports temporarily disabling itself\n// either while on a named git branch (turnOffRuleWhileOnBranch) or until an\n// epoch passes (turnOffRuleUntilEpoch). They live on a shared base class so the\n// fields (and their schema entries) are declared once instead of repeated per\n// rule. `mode` stays per-rule because its allowed values vary (ON/OFF vs\n// NEW_AND_MODIFIED_CODE vs NEW_AND_MODIFIED_METHODS, etc).\n//\n// BOTH fields are REQUIRED on every rule so both hatches are ALWAYS VISIBLE in the config — an AI\n// editing webpieces.config.json sees them on every rule and cannot miss that a rule can be time-boxed\n// or branch-scoped off. Convention:\n// turnOffRuleUntilEpoch: 0 = rule active (epoch in the past); a future unix epoch IN SECONDS =\n// temporarily disabled until that moment.\n// turnOffRuleWhileOnBranch: null = always on; a branch name = disabled while that branch is checked out.\n// The name is matched EXACTLY (===). Globs/wildcards are NOT supported and\n// must not be added: a pattern would switch a rule off on branches nobody\n// enumerated. It is also ignored (loudly — shouldSkipRule throws) on a pull\n// request from a FORK, where the branch name is the contributor's to choose.\n// Required-but-nullable so its \"unset\" state is present-and-visible (null)\n// rather than omitted.\n// The earlier spellings of these two fields were RENAMED to the names above and are no longer accepted —\n// the validator rejects them with a \"renamed to X\" hint. RENAMED_FIELD_ALIASES in validate-config.ts is\n// the ONE place in src/ a dead spelling may still be written (see escape-hatch-key-spelling.spec.ts).\n// ---------------------------------------------------------------------------\nexport abstract class BaseRuleConfig {\n // `mode` is declared here (loosely typed) so the shared AbstractRule base can read it for\n // on/off. Each concrete *Config narrows it to its own union (e.g. `mode?: ModifiedCodeMode`),\n // which is an assignable (covariant) override.\n mode?: string;\n // TS-optional, but schema-REQUIRED (see BASE_RULE_SCHEMA) — same split as `mode`. Read directly by\n // AbstractRule.shouldRun, RuleGate, and the code-rules validators.\n turnOffRuleUntilEpoch?: number;\n turnOffRuleWhileOnBranch?: string | null;\n}\n\nexport const BASE_RULE_SCHEMA = {\n turnOffRuleUntilEpoch: new FieldDef('number'),\n turnOffRuleWhileOnBranch: FieldDef.nullableString(),\n};\n\nexport class MaxMethodLinesConfig extends BaseRuleConfig {\n declare mode?: MethodLimitMode;\n limit?: number;\n disableAllowed?: boolean;\n\n static readonly SCHEMA: SchemaShape<MaxMethodLinesConfig> = {\n mode: new FieldDef('string', METHOD_LIMIT_MODES),\n limit: FieldDef.optional('number'),\n disableAllowed: FieldDef.optional('boolean'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class MaxFileLinesConfig extends BaseRuleConfig {\n declare mode?: FileLimitMode;\n limit?: number;\n disableAllowed?: boolean;\n\n static readonly SCHEMA: SchemaShape<MaxFileLinesConfig> = {\n mode: new FieldDef('string', FILE_LIMIT_MODES),\n limit: FieldDef.optional('number'),\n disableAllowed: FieldDef.optional('boolean'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class RequireReturnTypeConfig extends BaseRuleConfig {\n declare mode?: ReturnTypeMode;\n disableAllowed?: boolean;\n\n static readonly SCHEMA: SchemaShape<RequireReturnTypeConfig> = {\n mode: new FieldDef('string', RETURN_TYPE_MODES),\n disableAllowed: FieldDef.optional('boolean'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class NoInlineTypeLiteralsConfig extends BaseRuleConfig {\n declare mode?: InlineTypeMode;\n disableAllowed?: boolean;\n\n static readonly SCHEMA: SchemaShape<NoInlineTypeLiteralsConfig> = {\n mode: new FieldDef('string', INLINE_TYPE_MODES),\n disableAllowed: FieldDef.optional('boolean'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class NoAnyUnknownConfig extends BaseRuleConfig {\n declare mode?: ModifiedCodeMode;\n disableAllowed?: boolean;\n\n static readonly SCHEMA: SchemaShape<NoAnyUnknownConfig> = {\n mode: new FieldDef('string', MODIFIED_CODE_MODES),\n disableAllowed: FieldDef.optional('boolean'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class NoImplicitAnyConfig extends BaseRuleConfig {\n declare mode?: ModifiedCodeMode;\n disableAllowed?: boolean;\n\n static readonly SCHEMA: SchemaShape<NoImplicitAnyConfig> = {\n mode: new FieldDef('string', MODIFIED_CODE_MODES),\n disableAllowed: FieldDef.optional('boolean'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class PrismaValidateDtosConfig extends BaseRuleConfig {\n declare mode?: PrismaValidateDtosMode;\n disableAllowed?: boolean;\n prismaSchemaPath?: string;\n dtoSourcePaths?: string[];\n\n static readonly SCHEMA: SchemaShape<PrismaValidateDtosConfig> = {\n mode: new FieldDef('string', PRISMA_DTOS_MODES),\n disableAllowed: FieldDef.optional('boolean'),\n prismaSchemaPath: FieldDef.optional('string'),\n dtoSourcePaths: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class PrismaConverterConfig extends BaseRuleConfig {\n declare mode?: PrismaConverterMode;\n disableAllowed?: boolean;\n schemaPath?: string;\n convertersPaths?: string[];\n enforcePaths?: string[];\n\n static readonly SCHEMA: SchemaShape<PrismaConverterConfig> = {\n mode: new FieldDef('string', PRISMA_CONVERTER_MODES),\n disableAllowed: FieldDef.optional('boolean'),\n schemaPath: FieldDef.optional('string'),\n convertersPaths: FieldDef.optional('string[]'),\n enforcePaths: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\n// `allowedPaths` exempts whole file trees whose idioms are destructuring by construction (React /\n// React Native components and hooks — `const [x, setX] = useState()`, destructured props — framework\n// glue), matched with the shared glob/prefix/segment semantics of `isPathExcluded`. It is the ONLY\n// escape when `disableAllowed: false`, since that setting deliberately ignores inline disables.\nexport class NoDestructureConfig extends BaseRuleConfig {\n declare mode?: ModifiedCodeMode;\n allowTopLevel?: boolean;\n disableAllowed?: boolean;\n allowedPaths?: string[];\n\n static readonly SCHEMA: SchemaShape<NoDestructureConfig> = {\n mode: new FieldDef('string', MODIFIED_CODE_MODES),\n allowTopLevel: FieldDef.optional('boolean'),\n disableAllowed: FieldDef.optional('boolean'),\n allowedPaths: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class NoUnmanagedExceptionsConfig extends BaseRuleConfig {\n declare mode?: ModifiedCodeMode;\n disableAllowed?: boolean;\n\n static readonly SCHEMA: SchemaShape<NoUnmanagedExceptionsConfig> = {\n mode: new FieldDef('string', MODIFIED_CODE_MODES),\n disableAllowed: FieldDef.optional('boolean'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class CatchErrorPatternConfig extends BaseRuleConfig {\n declare mode?: ModifiedCodeMode;\n disableAllowed?: boolean;\n\n static readonly SCHEMA: SchemaShape<CatchErrorPatternConfig> = {\n mode: new FieldDef('string', MODIFIED_CODE_MODES),\n disableAllowed: FieldDef.optional('boolean'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class ThrowCauseRequiredConfig extends BaseRuleConfig {\n declare mode?: ThrowCauseMode;\n disableAllowed?: boolean;\n\n static readonly SCHEMA: SchemaShape<ThrowCauseRequiredConfig> = {\n mode: new FieldDef('string', THROW_CAUSE_MODES),\n disableAllowed: FieldDef.optional('boolean'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class AngularNoDirectApiInResolverConfig extends BaseRuleConfig {\n declare mode?: DirectApiResolverMode;\n disableAllowed?: boolean;\n enforcePaths?: string[];\n\n static readonly SCHEMA: SchemaShape<AngularNoDirectApiInResolverConfig> = {\n mode: new FieldDef('string', DIRECT_API_RESOLVER_MODES),\n disableAllowed: FieldDef.optional('boolean'),\n enforcePaths: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\n// Bans hand-written CSS in Angular sources (styles:/styleUrls:/styleUrl: in @Component, and inline\n// style=/[style.x]/[ngStyle] in templates) so teams style with Tailwind utility classes. `allowGlobs`\n// exempts paths WITHIN the Angular scope (e.g. a vendored Fuse kit copied verbatim with its own CSS).\nexport class NoCustomCssConfig extends BaseRuleConfig {\n declare mode?: ModifiedCodeMode;\n disableAllowed?: boolean;\n allowGlobs?: string[];\n\n static readonly SCHEMA: SchemaShape<NoCustomCssConfig> = {\n mode: new FieldDef('string', MODIFIED_CODE_MODES),\n disableAllowed: FieldDef.optional('boolean'),\n allowGlobs: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class NoSymbolDiTokensConfig extends BaseRuleConfig {\n declare mode?: ModifiedCodeMode;\n disableAllowed?: boolean;\n allowedPaths?: string[];\n\n static readonly SCHEMA: SchemaShape<NoSymbolDiTokensConfig> = {\n mode: new FieldDef('string', MODIFIED_CODE_MODES),\n disableAllowed: FieldDef.optional('boolean'),\n allowedPaths: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\n// Flags `process.exit(...)` outside a main()/runMain wrapper (and `import { main }`) so a deep exit\n// can't silently kill a reused server/command. Gradual-rollout knobs via the standard base: mode\n// (OFF | NEW_AND_MODIFIED_CODE | NEW_AND_MODIFIED_FILES), turnOffRuleUntilEpoch, branch, and\n// disableAllowed for the inline `// webpieces-disable` escape at genuine terminal boundaries.\nexport class NoProcessExitOutsideMainConfig extends BaseRuleConfig {\n declare mode?: ModifiedCodeMode;\n disableAllowed?: boolean;\n\n static readonly SCHEMA: SchemaShape<NoProcessExitOutsideMainConfig> = {\n mode: new FieldDef('string', MODIFIED_CODE_MODES),\n disableAllowed: FieldDef.optional('boolean'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\n// Flags a function CREATED OUTSIDE A CLASS at module scope: a top-level `function foo()` declaration\n// or a top-level `const foo = () => {}` / `= function(){}`. The point is that webpieces DI +\n// @DocumentDesign only work when behavior lives in injectable classes — a module-scope function is a\n// dead-end the DI graph can't reach. Inline callbacks, nested functions inside methods, and non-function\n// top-level consts (objects, zod schemas, primitives) are NOT flagged. Standard rollout knobs via the\n// base: mode (OFF | NEW_AND_MODIFIED_CODE | NEW_AND_MODIFIED_FILES), turnOffRuleUntilEpoch, branch,\n// and disableAllowed for the inline `// webpieces-disable` escape. `allowedPaths` exempts whole file\n// trees that legitimately live outside the class-per-behavior model (e.g. React component/hook files,\n// framework glue), matched with the shared glob/prefix/segment semantics of `isPathExcluded`.\nexport class NoFunctionOutsideClassConfig extends BaseRuleConfig {\n declare mode?: ModifiedCodeMode;\n disableAllowed?: boolean;\n allowedPaths?: string[];\n\n static readonly SCHEMA: SchemaShape<NoFunctionOutsideClassConfig> = {\n mode: new FieldDef('string', MODIFIED_CODE_MODES),\n disableAllowed: FieldDef.optional('boolean'),\n allowedPaths: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\n// inject-annotation-not-needed-for-concrete-class — flags a REDUNDANT `@inject(X)` whose token is\n// textually identical to the parameter's own declared type (`@inject(Foo) private readonly foo: Foo`).\n// In this inversify setup the decorator is pure noise there: reflect-metadata (emitDecoratorMetadata)\n// already resolves a constructor parameter by its class type, so `private readonly foo: Foo` binds on\n// its own (see CLAUDE.md, and the no-symbol-di-tokens rule that pushes the same way). Symbol/interface\n// tokens are NOT flagged because they never equal the type (`@inject(FOO_TOKEN) x: Provider<Foo>`).\n// AI keeps carpet-bombing `@inject`; this fails the build on the redundant form. Standard rollout knobs\n// via the base: mode (OFF | NEW_AND_MODIFIED_CODE | NEW_AND_MODIFIED_FILES), turnOffRuleUntilEpoch,\n// branch, and disableAllowed for the inline `// webpieces-disable` escape. `allowedPaths` exempts whole\n// file trees, matched with the shared glob/prefix/segment semantics.\nexport class InjectAnnotationNotNeededForConcreteClassConfig extends BaseRuleConfig {\n declare mode?: ModifiedCodeMode;\n disableAllowed?: boolean;\n allowedPaths?: string[];\n\n static readonly SCHEMA: SchemaShape<InjectAnnotationNotNeededForConcreteClassConfig> = {\n mode: new FieldDef('string', MODIFIED_CODE_MODES),\n disableAllowed: FieldDef.optional('boolean'),\n allowedPaths: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\n// framework-tag — every project that a changed source file belongs to must carry >=1\n// `framework:<browser|react|angular|node|express>` nx tag in its project.json. Those tags are the\n// project's \"libType\" — the SET of runtime environments it runs in — and the source of truth for\n// the dependencies.json `framework` field and the `library-types-match-client` rule. Multiple tags\n// are allowed (the env set) and values are validated against the known set (`framework:all` is a\n// hard error). `knownTypes` customizes that set (defaults to browser, react, angular, node, express).\nexport class FrameworkTagConfig extends BaseRuleConfig {\n declare mode?: ProjectMode;\n knownTypes?: string[];\n\n static readonly SCHEMA: SchemaShape<FrameworkTagConfig> = {\n mode: new FieldDef('string', PROJECT_MODES),\n knownTypes: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\n// role-tag — every project that a changed source file belongs to must carry a\n// `role:<server|designed-lib|lib|client>` nx tag in its project.json. That tag is the project's\n// ROLE (orthogonal to `framework` libType) — the source of truth for the dependencies.json `role`\n// field, the `role-dependency` edge rule (apps are never depended upon), and DI-design generation\n// (server→@Controller, designed-lib→@ApiImplementation, lib→none, client→angular design).\n// `knownTypes` customizes the list suggested to the author when a tag is missing.\nexport class RoleTagConfig extends BaseRuleConfig {\n declare mode?: ProjectMode;\n knownTypes?: string[];\n\n static readonly SCHEMA: SchemaShape<RoleTagConfig> = {\n mode: new FieldDef('string', PROJECT_MODES),\n knownTypes: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class BranchCreationGuardConfig extends BaseRuleConfig {\n declare mode?: BranchGuardMode;\n // Naming pattern for stacked SUB-branches only (branches created off another feature branch,\n // which require human approval). Never applied to branches created off main.\n subBranchNaming?: string;\n // Human-sentence instruction telling the AI how to name a NEW branch off main. Surfaced back\n // to the agent in the guard's fix hints. May mirror no-edit-on-main.branchNamingConvention.\n branchFormat?: string;\n // Hard cap on local feature branches (excluding main). Creating one past the cap is BLOCKED until\n // already-merged branches are reaped, which is what keeps the branch list from growing without\n // bound. Branch creation is the gate because it is the only moment cleanup is both cheap and\n // obviously worth it. See merged-branches.ts for how \"already merged\" is determined.\n maxLocalBranches?: number;\n // Hard cap on LINKED worktrees (the primary clone is never counted). A separate budget from\n // maxLocalBranches: every worktree holds a branch, so if worktree-held branches also spent the\n // branch budget, five worktrees would leave room for zero branches. Held branches count here;\n // parked branches count against maxLocalBranches. Enforced at `git worktree add`.\n maxWorktrees?: number;\n // Let the detached background refresher DELETE dead branches on its own, instead of only\n // reporting them. Every candidate is provably dead (a MERGED PR — its own, or the PR of the branch\n // it snapshots; nothing else qualifies) and\n // recoverable by the SHA logged to branch-mutations.log — but it is still UNATTENDED deletion,\n // so this is schema-REQUIRED like `mode` and `turnOffRuleUntilEpoch`. \"Every built-in rule\n // must be explicitly configured — no silent defaults\" (validate-config.ts) applies with extra\n // force here: branches disappearing on a preference nobody ever stated is precisely the kind of\n // default that must not exist. Validation makes each consumer answer the question once.\n //\n // TS-optional but schema-required — the same split `mode` uses. Absent at RUNTIME therefore means\n // the config never passed validation, and the only safe reading of \"nobody has answered\" is: do\n // not delete anything.\n autoReapMergedBranches?: boolean;\n\n static readonly SCHEMA: SchemaShape<BranchCreationGuardConfig> = {\n mode: new FieldDef('string', BRANCH_GUARD_MODES),\n subBranchNaming: FieldDef.optional('string'),\n branchFormat: FieldDef.optional('string'),\n maxLocalBranches: FieldDef.optional('number'),\n maxWorktrees: FieldDef.optional('number'),\n autoReapMergedBranches: new FieldDef('boolean'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\n/**\n * `pr-lifecycle-guard` — ONE key, ONE policy: *PRs and merges go through the gated flow.*\n *\n * Four CLASSES implement it, and their names are unchanged (they are the operator identity every\n * decision-log line and every deny report carries):\n *\n * pr-creation-or-push-guard a manual `git push` / `gh pr create|edit` / a raw pulls API call\n * merge-in-progress-guard a PR command while a 3-point merge is half-finished\n * pr-merge-guard a bare `gh pr merge`\n * redirect-how-to-merge-main \"how do I get main into my branch?\" → the documented flow\n *\n * ## Say this out loud: `\"mode\": \"OFF\"` releases the unvalidated-merge gate too\n *\n * Three of the four are pure COMMAND-SHAPE blocks and can never fire spuriously. The fourth,\n * merge-in-progress-guard, is STATE-conditional — it fires only while a 3-point merge is actually in\n * progress, and it is the one state L2 explicitly stands down for. So turning this key OFF to unblock\n * `gh pr merge` ALSO drops the \"you have an unfinished merge\" gate. That is the honest cost of one key\n * per policy, and it is stated here, in guards/L4-pr-lifecycle.md, and in the error path, rather than\n * being papered over with a granular sub-mode (which would be four knobs wearing one key's name).\n *\n * ## The command strings are NOT here\n *\n * `upsertPrCommand` and `mergeCompleteCommand` used to sit on the two guards, and — being read at the\n * point of use — they BEAT `commands.guardHints`, so `guardHintsWhy`'s claim that renaming a gated\n * command there makes \"every guard message follow\" was simply false. They are DELETED, not deprecated.\n * `commands.guardHints.prCreationOrPush` / `.mergeInProgress` is the one place those strings live, and\n * the loader hands the resolved values to the two rules directly. A consumer that still sets the old\n * per-guard field gets a RETIRED_FIELD_HINTS error naming the destination.\n */\nexport class PrLifecycleGuardConfig extends BaseRuleConfig {\n declare mode?: OnOffMode;\n\n static readonly SCHEMA: SchemaShape<PrLifecycleGuardConfig> = {\n mode: new FieldDef('string', ON_OFF_MODES),\n ...BASE_RULE_SCHEMA,\n };\n}\n\n// NOTE: there is deliberately no `WholeRepoBuildGuardConfig`. That guard has NO webpieces.config.json\n// entry — it is EXPERIMENTAL and OFF by default, and its only switch is the OPT-IN\n// `experimental.whole-repo-build-guard: true` in the optional machine-local ~/.webpieces/config.json\n// (see home-config.ts). The build command it prints\n// is handed to it directly from `commands.pr-gate.buildCommand` by ai-hook-rules' runner. Re-adding a\n// config class here puts the guard back in RULE_SCHEMAS and makes it a fault-Y rule again.\n\nexport class NoFileImportCyclesConfig extends BaseRuleConfig {\n declare mode?: StructuralMode;\n ignoreTypeOnly?: boolean;\n excludePackages?: string[];\n // Raw regex escape hatch for a cycle inside the project being checked — generated code, a\n // vendored tree, or a deliberate bidirectional domain model — that `excludePackages` cannot reach\n // (it resolves npm package NAMES, so it only excludes a *sibling* package, never a directory\n // inside this one). Patterns are handed to madge verbatim and matched against ids RELATIVE TO THE\n // PROJECT (e.g. \"^src/generated/\", \"^src/modules/(item|category)/\") — NOT workspace-rooted or\n // absolute, which silently match nothing. The executor warns when a pattern matches zero\n // traversed files, so a mis-anchored pattern is visible rather than a silent no-op.\n excludeRegExp?: string[];\n\n static readonly SCHEMA: SchemaShape<NoFileImportCyclesConfig> = {\n mode: new FieldDef('string', STRUCTURAL_MODES),\n ignoreTypeOnly: FieldDef.optional('boolean'),\n excludePackages: FieldDef.optional('string[]'),\n excludeRegExp: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class RuntimeArchitectureConfig extends BaseRuleConfig {\n declare mode?: StructuralMode;\n // NOTE: `servicePaths` / `apiProjectPaths` were removed — they were never read. The runtime graph\n // is derived SOLELY from architecture/dependencies.json apiRelations + project roles (see\n // nx-webpieces-rules/src/lib/runtime-graph.ts), so any config still listing them (a hand-maintained\n // enumeration of api libs) now fails the unknown-field check in validateWebpiecesConfig. There is\n // nothing to enumerate — delete the keys.\n allowedCycles?: string[];\n /**\n * Draw a dashed terminal node for every contract a service calls that NOTHING in-repo\n * implements (firestore, gmail, ...) — the vendor systems the runtime graph otherwise stops one\n * hop short of. Defaults to true; set false in a repo whose external surface is noisy. Purely a\n * RENDER switch: levels, cycle detection and runtime-dependencies.json are identical either way.\n */\n showExternalNodes?: boolean;\n /**\n * Project roots whose exported `*Api` types are contracts for systems OUTSIDE this repo\n * (firestore, gmail, gcp-storage, ...), e.g. `[\"libraries/apis/external/**\"]`. Globs, matched\n * against the nx project root.\n *\n * Needed because an external contract does NOT look like an in-repo one: it is a plain\n * `interface` bound to a Symbol token and injected, never an `abstract class` carrying @ApiPath\n * reached through `createRpcClient`. Without this list the scanner has no way to tell a vendor\n * seam from any other library, so every call leaving the repo is invisible to the runtime graph.\n *\n * Defaults to none, which is correct for a repo with no vendor wrapper libraries.\n */\n externalApiPaths?: string[];\n\n static readonly SCHEMA: SchemaShape<RuntimeArchitectureConfig> = {\n mode: new FieldDef('string', STRUCTURAL_MODES),\n allowedCycles: FieldDef.optional('string[]'),\n showExternalNodes: FieldDef.optional('boolean'),\n externalApiPaths: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class NxWiringConfig extends BaseRuleConfig {\n declare mode?: StructuralMode;\n\n static readonly SCHEMA: SchemaShape<NxWiringConfig> = {\n mode: new FieldDef('string', STRUCTURAL_MODES),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class DiGraphConfig extends BaseRuleConfig {\n // Structural: the DI graph is regenerated whole-project on every build (generate +\n // unchanged gate), so it cannot be scoped to changed lines.\n declare mode?: StructuralMode;\n\n static readonly SCHEMA: SchemaShape<DiGraphConfig> = {\n mode: new FieldDef('string', STRUCTURAL_MODES),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class MissingDesignAnnotationConfig extends BaseRuleConfig {\n // Structural: enforced per-project by the di-graph-generate executor, which\n // roots the whole DI design on @DocumentDesign classes — cannot be line-scoped.\n declare mode?: StructuralMode;\n\n static readonly SCHEMA: SchemaShape<MissingDesignAnnotationConfig> = {\n mode: new FieldDef('string', STRUCTURAL_MODES),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class NoJsFilesConfig extends BaseRuleConfig {\n // File-tier: NEW_AND_MODIFIED_FILES (active) intercepts a .js/.jsx Write — the file being\n // written is inherently a new/modified file, so it's already diff-scoped in practice.\n declare mode?: FileLimitMode;\n allowedPaths?: string[];\n\n static readonly SCHEMA: SchemaShape<NoJsFilesConfig> = {\n mode: new FieldDef('string', FILE_LIMIT_MODES),\n allowedPaths: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\n// ---------------------------------------------------------------------------\n// The five Nx infrastructure validators (architecture-unchanged, no-architecture-cycles,\n// packagejson, versions-locked, eslint-sync). Each is whole-graph / whole-repo by nature (a cycle, a\n// drifted dependencies.json, an unlocked version can be introduced by a file nobody in this diff\n// touched), so the only honest mode set is STRUCTURAL_MODES: RUN_EVERY_TIME (the default) or OFF.\n//\n// All five now honor the universal escape hatches (turnOffRuleUntilEpoch / turnOffRuleWhileOnBranch)\n// via shouldSkipRule — the RuleGate is called with honorEpoch:true from\n// every executor. This lets a repo time-box or branch-scope a failing infrastructure check (e.g. hold\n// validate-packagejson off until an upgrade PR lands) with a one-value edit, instead of only the\n// blunt \"mode\": \"OFF\". Originally packagejson/versions-locked/eslint-sync were all-or-nothing on the\n// theory that \"no blessed baseline\" made grandfathering meaningless, but a time-box is a schedule, not\n// a baseline: \"do not enforce this until <epoch>/off <branch>\" is coherent for any rule.\n// ---------------------------------------------------------------------------\n\nexport class ValidateArchitectureUnchangedConfig extends BaseRuleConfig {\n declare mode?: StructuralMode;\n\n static readonly SCHEMA: SchemaShape<ValidateArchitectureUnchangedConfig> = {\n mode: new FieldDef('string', STRUCTURAL_MODES),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class ValidateNoArchitectureCyclesConfig extends BaseRuleConfig {\n declare mode?: StructuralMode;\n\n static readonly SCHEMA: SchemaShape<ValidateNoArchitectureCyclesConfig> = {\n mode: new FieldDef('string', STRUCTURAL_MODES),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class ValidatePackageJsonConfig extends BaseRuleConfig {\n declare mode?: StructuralMode;\n\n static readonly SCHEMA: SchemaShape<ValidatePackageJsonConfig> = {\n mode: new FieldDef('string', STRUCTURAL_MODES),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class ValidateVersionsLockedConfig extends BaseRuleConfig {\n declare mode?: StructuralMode;\n\n static readonly SCHEMA: SchemaShape<ValidateVersionsLockedConfig> = {\n mode: new FieldDef('string', STRUCTURAL_MODES),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class ValidateEslintSyncConfig extends BaseRuleConfig {\n declare mode?: StructuralMode;\n\n static readonly SCHEMA: SchemaShape<ValidateEslintSyncConfig> = {\n mode: new FieldDef('string', STRUCTURAL_MODES),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class ValidateTsInSrcConfig extends BaseRuleConfig {\n declare mode?: ValidateTsMode;\n allowedRootFiles?: string[];\n excludePaths?: string[];\n\n static readonly SCHEMA: SchemaShape<ValidateTsInSrcConfig> = {\n mode: new FieldDef('string', VALIDATE_TS_MODES),\n allowedRootFiles: FieldDef.optional('string[]'),\n excludePaths: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n"]}
|
package/src/sections.d.ts
CHANGED
|
@@ -22,8 +22,9 @@ export type ConfigSection = 'rules' | 'hookGuards';
|
|
|
22
22
|
* retirement, a migration and prose churn for zero policy change.
|
|
23
23
|
*
|
|
24
24
|
* `whole-repo-build-guard` is NOT here: it has no webpieces.config.json entry at all (see
|
|
25
|
-
* RETIRED_CONFIG_KEYS). It is
|
|
26
|
-
* ~/.webpieces/config.json, and ai-hook-rules runs it
|
|
25
|
+
* RETIRED_CONFIG_KEYS). It is EXPERIMENTAL and OFF for every tree until a machine opts in with
|
|
26
|
+
* `experimental.whole-repo-build-guard: true` in ~/.webpieces/config.json, and ai-hook-rules runs it
|
|
27
|
+
* outside the config-driven rule set entirely.
|
|
27
28
|
*/
|
|
28
29
|
/**
|
|
29
30
|
* The two POLICY keys shared by more than one class, as named constants.
|
package/src/sections.js
CHANGED
|
@@ -26,8 +26,9 @@ exports.sectionForRule = sectionForRule;
|
|
|
26
26
|
* retirement, a migration and prose churn for zero policy change.
|
|
27
27
|
*
|
|
28
28
|
* `whole-repo-build-guard` is NOT here: it has no webpieces.config.json entry at all (see
|
|
29
|
-
* RETIRED_CONFIG_KEYS). It is
|
|
30
|
-
* ~/.webpieces/config.json, and ai-hook-rules runs it
|
|
29
|
+
* RETIRED_CONFIG_KEYS). It is EXPERIMENTAL and OFF for every tree until a machine opts in with
|
|
30
|
+
* `experimental.whole-repo-build-guard: true` in ~/.webpieces/config.json, and ai-hook-rules runs it
|
|
31
|
+
* outside the config-driven rule set entirely.
|
|
31
32
|
*/
|
|
32
33
|
/**
|
|
33
34
|
* The two POLICY keys shared by more than one class, as named constants.
|
package/src/sections.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sections.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/sections.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"sections.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/sections.ts"],"names":[],"mappings":";;;AA6DA,kCAEC;AAID,wCAEC;AA3DD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH;;;;;;GAMG;AACU,QAAA,sBAAsB,GAAG,oBAAoB,CAAC;AAC9C,QAAA,sBAAsB,GAAG,oBAAoB,CAAC;AAE9C,QAAA,gBAAgB,GAAsB;IAC/C,8BAAsB;IACtB,uBAAuB;IACvB,8BAAsB;CACzB,CAAC;AAEF,MAAM,cAAc,GAAwB,IAAI,GAAG,CAAC,wBAAgB,CAAC,CAAC;AAEtE;;;;GAIG;AACH,kOAAkO;AAClO,SAAgB,WAAW,CAAC,SAAiB;IACzC,OAAO,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AACzC,CAAC;AAED,yGAAyG;AACzG,2GAA2G;AAC3G,SAAgB,cAAc,CAAC,SAAiB;IAC5C,OAAO,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC;AAClE,CAAC","sourcesContent":["// Which top-level section of webpieces.config.json a built-in belongs to.\n//\n// - \"rules\" — code-style validators (scope edit/file). They inspect file contents/diffs.\n// - \"hookGuards\" — git/PR/branch protection (scope bash). They intercept the shell command an\n// agent is about to run (git/gh) rather than validate file contents.\n//\n// These are conceptually different and are installed differently (guards typically for the whole\n// team, code rules often per-developer while iterating), so they live in separate config sections.\nexport type ConfigSection = 'rules' | 'hookGuards';\n\n/**\n * The `hookGuards` CONFIG KEYS — ONE PER POLICY, not one per implementation class.\n *\n * Single source of truth for the rule/guard split, imported by the config validator (placement\n * checks), the loader (section merge), and the installer (config seeding).\n *\n * | key | the question it answers | classes behind it |\n * |---|---|---|\n * | `branch-state-guard` | may I work here, and is what I read current? | feature-branch-guard, read-stale-guard, stale-main-bash-guard, merged-branch-bash-guard |\n * | `branch-creation-guard` | should this branch/worktree exist at all? | branch-creation-guard |\n * | `pr-lifecycle-guard` | do PRs and merges go through the gated flow? | pr-creation-or-push-guard, merge-in-progress-guard, pr-merge-guard, redirect-how-to-merge-main |\n *\n * A consumer turns a POLICY on or off; the class split is an implementation detail of tool wiring\n * (Read names one file, Bash is opaque, Write is neither). Nine keys let you configure half a policy —\n * `read-stale-guard: OFF` beside `merged-branch-bash-guard: ON` is \"read the file, yes; `cat` the same\n * file, no\" — and one key per policy makes that unrepresentable. The eight retired names are in\n * RETIRED_CONFIG_KEYS with the destination, all `prunable: false` so nothing deletes a configured guard.\n *\n * `branch-creation-guard` KEEPS its name. It is already one class and one policy carrying real\n * settings; renaming it to `branch-cleanup-guard` (which three docs once proposed) would cost a\n * retirement, a migration and prose churn for zero policy change.\n *\n * `whole-repo-build-guard` is NOT here: it has no webpieces.config.json entry at all (see\n * RETIRED_CONFIG_KEYS). It is EXPERIMENTAL and OFF for every tree until a machine opts in with\n * `experimental.whole-repo-build-guard: true` in ~/.webpieces/config.json, and ai-hook-rules runs it\n * outside the config-driven rule set entirely.\n */\n/**\n * The two POLICY keys shared by more than one class, as named constants.\n *\n * Every class behind them passes the constant as its `configKey`, so the wiring is a compile-time\n * reference rather than a repeated string literal that a rename could miss in one file out of four —\n * which is exactly how `applyCommandDefaults` used to break silently.\n */\nexport const BRANCH_STATE_GUARD_KEY = 'branch-state-guard';\nexport const PR_LIFECYCLE_GUARD_KEY = 'pr-lifecycle-guard';\n\nexport const HOOK_GUARD_NAMES: readonly string[] = [\n BRANCH_STATE_GUARD_KEY,\n 'branch-creation-guard',\n PR_LIFECYCLE_GUARD_KEY,\n];\n\nconst HOOK_GUARD_SET: ReadonlySet<string> = new Set(HOOK_GUARD_NAMES);\n\n/**\n * Is this CONFIG KEY a hookGuard? Callers must pass `AbstractRule.configKey`, never `rule.name` — the\n * two diverge for every class behind a collapsed policy key, and passing a class name would classify\n * `feature-branch-guard` as a code-style rule and run it in the wrong hook.\n */\n// webpieces-disable no-function-outside-class -- pure predicate over the module-scope key set beside it; it is imported by the validator, the loader and the installer alike, and a class here would be a namespace with no state\nexport function isHookGuard(configKey: string): boolean {\n return HOOK_GUARD_SET.has(configKey);\n}\n\n/** Which section `configKey`'s entry belongs in. Same contract as isHookGuard: keys, not class names. */\n// webpieces-disable no-function-outside-class -- sibling of isHookGuard over the same module-scope key set\nexport function sectionForRule(configKey: string): ConfigSection {\n return HOOK_GUARD_SET.has(configKey) ? 'hookGuards' : 'rules';\n}\n"]}
|