@webpieces/rules-config 0.4.664 → 0.4.665
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 +6 -4
- package/src/default-rules.js.map +1 -1
- package/src/home-config.d.ts +44 -12
- package/src/home-config.js +66 -23
- package/src/home-config.js.map +1 -1
- package/src/index.d.ts +1 -1
- package/src/index.js +11 -9
- package/src/index.js.map +1 -1
- package/src/retired-config-keys.js +9 -9
- package/src/retired-config-keys.js.map +1 -1
- package/src/rule-configs.js +3 -3
- package/src/rule-configs.js.map +1 -1
- package/src/sections.d.ts +2 -2
- package/src/sections.js +2 -2
- package/src/sections.js.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webpieces/rules-config",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.665",
|
|
4
4
|
"description": "Shared webpieces.config.json loader. Single source of truth for validation rule configuration consumed by @webpieces/ai-hook-rules, @webpieces/code-rules, and @webpieces/nx-webpieces-rules.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "./src/index.js",
|
package/src/default-rules.js
CHANGED
|
@@ -76,10 +76,12 @@ exports.defaultRules = {
|
|
|
76
76
|
},
|
|
77
77
|
'pr-lifecycle-guard': { mode: 'ON' },
|
|
78
78
|
// NOTE: `whole-repo-build-guard` is deliberately ABSENT from this table, and from RULE_SCHEMAS and
|
|
79
|
-
// HOOK_GUARD_NAMES with it. It is
|
|
80
|
-
// ~/.webpieces/config.json (`experimental.whole-repo-build-guard`). Adding it back here would
|
|
81
|
-
// a rule every consumer must
|
|
82
|
-
// which is exactly what it did the first time.
|
|
79
|
+
// HOOK_GUARD_NAMES with it. It is ON by default and turned off only from the optional machine-local
|
|
80
|
+
// ~/.webpieces/config.json (`experimental.whole-repo-build-guard: false`). Adding it back here would
|
|
81
|
+
// make it a rule every consumer must CONFIGURE — which is fault Y, i.e. every Bash call blocked on
|
|
82
|
+
// upgrade, which is exactly what it did the first time. That fault was the required KEY, not the
|
|
83
|
+
// default; being on by default from a file nobody has to create cannot reproduce it. See
|
|
84
|
+
// RETIRED_CONFIG_KEYS.
|
|
83
85
|
//
|
|
84
86
|
// branch-state-guard ships ON, INCLUDING its Read-blocking half.
|
|
85
87
|
//
|
package/src/default-rules.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"default-rules.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/default-rules.ts"],"names":[],"mappings":";;;AAAA,2DAA2D;AAC3D,4EAA4E;AAC5E,kEAAkE;AAClE,0EAA0E;AAC1E,MAAM,qBAAqB,GAAsB;IAC7C,cAAc,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;IACrC,WAAW,EAAE,mBAAmB;CACnC,CAAC;AAEF,2EAA2E;AAC3E,6EAA6E;AAC7E,sFAAsF;AACtF,iFAAiF;AACpE,QAAA,YAAY,GAA4C;IACjE,gBAAgB,EAAE,EAAE;IACpB,iBAAiB,EAAE,EAAE;IACrB,gBAAgB,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE;IAChC,kBAAkB,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;IACjC,qBAAqB,EAAE,EAAE;IACzB,yBAAyB,EAAE,EAAE;IAC7B,gBAAgB,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE;IACzC,qBAAqB,EAAE,EAAE;IACzB,yBAAyB,EAAE,EAAE;IAC7B,uBAAuB,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE;IACnD,sBAAsB,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,aAAa,EAAE,EAAE,EAAE;IACrE,sBAAsB,EAAE,EAAE;IAC1B,kBAAkB,EAAE,EAAE;IACtB,mCAAmC,EAAE,EAAE;IACvC,qBAAqB,EAAE,EAAE;IACzB,sFAAsF;IACtF,6FAA6F;IAC7F,6CAA6C;IAC7C,6CAA6C,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;IAC9D,eAAe,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE;IACnC,8BAA8B,EAAE,EAAE;IAClC,iDAAiD,EAAE,EAAE;IACrD,eAAe,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,UAAU,EAAE,CAAC,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE;IAC9G,UAAU,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,UAAU,EAAE,CAAC,QAAQ,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,CAAC,EAAE;IACpH,WAAW,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE;IACvC,UAAU,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE;IACtC,2BAA2B,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE;IACvD,oBAAoB,EAAE;QAClB,IAAI,EAAE,wBAAwB;QAC9B,gBAAgB,EAAE,CAAC,eAAe,CAAC;QACnC,YAAY,EAAE,CAAC,GAAG,qBAAqB,CAAC;KAC3C;IACD,aAAa,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;IAC9B,iGAAiG;IACjG,kGAAkG;IAClG,0EAA0E;IAC1E,yFAAyF;IACzF,oFAAoF;IACpF,iCAAiC,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE;IAC7D,iCAAiC,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE;IAC7D,sBAAsB,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE;IAClD,0BAA0B,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE;IACtD,sBAAsB,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE;IAClD,wFAAwF;IACxF,EAAE;IACF,mGAAmG;IACnG,iGAAiG;IACjG,mGAAmG;IACnG,kGAAkG;IAClG,8FAA8F;IAC9F,gGAAgG;IAChG,iGAAiG;IACjG,6FAA6F;IAC7F,EAAE;IACF,2EAA2E;IAC3E,uBAAuB,EAAE;QACrB,IAAI,EAAE,IAAI;QACV,eAAe,EAAE,sCAAsC;QACvD,sBAAsB,EAAE,IAAI;KAC/B;IACD,oBAAoB,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;IACpC,mGAAmG;IACnG,iGAAiG;IACjG,
|
|
1
|
+
{"version":3,"file":"default-rules.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/default-rules.ts"],"names":[],"mappings":"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","sourcesContent":["// Default holistic exclude list for the validate-ts-in-src\n// rules. Bare names match a directory segment at any depth; globs match the\n// workspace-relative path. `**/*.d.ts` (ambient declarations) and\n// `**/jest.config.ts` legitimately live outside src/ and are exempt here.\nconst DEFAULT_EXCLUDE_PATHS: readonly string[] = [\n 'node_modules', 'dist', '.nx', '.git',\n '**/*.d.ts', '**/jest.config.ts',\n];\n\n// On/off is driven by `mode` (\"OFF\" disables; an absent mode leaves a rule\n// on). Code-rules entries omit `mode` so each executor keeps its own default\n// scope; structural rules declare `mode: 'RUN_EVERY_TIME'`, bash guards `mode: 'ON'`.\n// webpieces-disable no-any-unknown -- rule options are opaque at framework level\nexport const defaultRules: Record<string, Record<string, unknown>> = {\n 'no-any-unknown': {},\n 'no-implicit-any': {},\n 'max-file-lines': { limit: 900 },\n 'max-method-lines': { limit: 80 },\n 'require-return-type': {},\n 'no-inline-type-literals': {},\n 'no-destructure': { allowTopLevel: true },\n 'catch-error-pattern': {},\n 'no-unmanaged-exceptions': {},\n 'no-file-import-cycles': { mode: 'RUN_EVERY_TIME' },\n 'runtime-architecture': { mode: 'RUN_EVERY_TIME', allowedCycles: [] },\n 'prisma-validate-dtos': {},\n 'prisma-converter': {},\n 'angular-no-direct-api-in-resolver': {},\n 'no-symbol-di-tokens': {},\n // Ships OFF: a repo opts in per webpieces.config.json once it is ready to migrate any\n // client-in-a-lib sites (severity defaults to \"warn\" so even when enabled it reports without\n // failing until a repo flips it to \"error\").\n 'no-client-creation-outside-server-or-client': { mode: 'OFF' },\n 'no-custom-css': { allowGlobs: [] },\n 'no-process-exit-outside-main': {},\n 'inject-annotation-not-needed-for-concrete-class': {},\n 'framework-tag': { mode: 'MODIFIED_PROJECTS', knownTypes: ['browser', 'react', 'angular', 'node', 'express'] },\n 'role-tag': { mode: 'MODIFIED_PROJECTS', knownTypes: ['server', 'app', 'designed-lib', 'lib', 'client', 'api-lib'] },\n 'nx-wiring': { mode: 'RUN_EVERY_TIME' },\n 'di-graph': { mode: 'RUN_EVERY_TIME' },\n 'missing-design-annotation': { mode: 'RUN_EVERY_TIME' },\n 'validate-ts-in-src': {\n mode: 'NEW_AND_MODIFIED_FILES',\n allowedRootFiles: ['jest.setup.ts'],\n excludePaths: [...DEFAULT_EXCLUDE_PATHS],\n },\n 'no-js-files': { mode: 'OFF' },\n // The five Nx infrastructure validators. They enforced unconditionally before they were wired to\n // config, so RUN_EVERY_TIME is the only default that keeps existing repos behaving identically on\n // upgrade. Set \"mode\": \"OFF\" to disable one; the two graph-baseline rules\n // (validate-architecture-unchanged / validate-no-architecture-cycles) additionally honor\n // turnOffRuleUntilEpoch — the other three are all-or-nothing (see rule-configs.ts).\n 'validate-architecture-unchanged': { mode: 'RUN_EVERY_TIME' },\n 'validate-no-architecture-cycles': { mode: 'RUN_EVERY_TIME' },\n 'validate-packagejson': { mode: 'RUN_EVERY_TIME' },\n 'validate-versions-locked': { mode: 'RUN_EVERY_TIME' },\n 'validate-eslint-sync': { mode: 'RUN_EVERY_TIME' },\n // autoReapMergedBranches ships TRUE, and it is also what a fresh config is seeded with.\n //\n // It shipped FALSE on the reasoning that an upgrade must never delete branches unattended before a\n // human opts in. In practice that produced the opposite of safety: nobody opts in, dead branches\n // pile up, and the pile is what makes a real branch hard to find. The reap is also NOT destructive\n // in the way the old comment implied — BranchReaper deletes only provably-dead branches (a merged\n // PR, a squash-merge backup of one, or no commits of their own), spares everything else for a\n // human, and logs each deletion to .webpieces/logs/branch-mutations.log with the pre-delete SHA\n // and a ready-made `recover=` command. So the worst case is one paste to undo, which a human can\n // resolve; the previous default's worst case was unbounded accumulation nobody ever cleaned.\n //\n // Set it false to keep reaping manual; `pnpm wp-cleanup` works either way.\n 'branch-creation-guard': {\n mode: 'ON',\n subBranchNaming: 'feature/<ticket>/<short-description>',\n autoReapMergedBranches: true,\n },\n 'pr-lifecycle-guard': { mode: 'ON' },\n // NOTE: `whole-repo-build-guard` is deliberately ABSENT from this table, and from RULE_SCHEMAS and\n // HOOK_GUARD_NAMES with it. It is ON by default and turned off only from the optional machine-local\n // ~/.webpieces/config.json (`experimental.whole-repo-build-guard: false`). Adding it back here would\n // make it a rule every consumer must CONFIGURE — which is fault Y, i.e. every Bash call blocked on\n // upgrade, which is exactly what it did the first time. That fault was the required KEY, not the\n // default; being on by default from a file nobody has to create cannot reproduce it. See\n // RETIRED_CONFIG_KEYS.\n //\n // branch-state-guard ships ON, INCLUDING its Read-blocking half.\n //\n // Its predecessor `read-stale-guard` shipped OFF as a \"phase 1\" staged rollout, on the reasoning\n // that Read is the highest-blast-radius tool there is and nobody should be armed before verifying\n // the fail-open paths against their own git layout. Phase 1 is over: this repo has run it ON in\n // production for releases, and the fail-open paths (branch undeterminable, cache absent, cache for\n // another branch, offline, dirty tree on main) are each covered by tests. Keeping it OFF now buys\n // nothing and costs the exact incident the guard exists for — a session spent reading a tree 18\n // commits behind while the log read \"handled\".\n //\n // Nothing is armed behind anyone's back either way: every built-in requires an explicit entry (the\n // config-sync check blocks until one exists), so a consumer states this mode themselves on upgrade.\n 'branch-state-guard': { mode: 'ON' },\n};\n\nexport const defaultRulesDir: readonly string[] = [];\n"]}
|
package/src/home-config.d.ts
CHANGED
|
@@ -23,14 +23,19 @@
|
|
|
23
23
|
* ai-hook-rules' runner beside the webpieces.config.json pass), so an agent can always repair the file
|
|
24
24
|
* the loader just rejected.
|
|
25
25
|
*
|
|
26
|
-
* ─── WHY
|
|
26
|
+
* ─── WHY A MACHINE-LOCAL SWITCH LIVES HERE AND NOT IN webpieces.config.json ───────────────────────────
|
|
27
27
|
* `whole-repo-build-guard` first shipped as an ordinary validated guard: `mode: 'ON'` by default AND an
|
|
28
28
|
* entry required under `hookGuards`. The consequence on upgrade was an outage — a consumer repo that had
|
|
29
29
|
* not yet added the entry hit fault Y, which blocks EVERY Bash call, for a feature nobody had opted into.
|
|
30
30
|
*
|
|
31
|
-
* The rule that buys back:
|
|
32
|
-
*
|
|
33
|
-
*
|
|
31
|
+
* The rule that buys back: a switch that lives HERE needs no file, no key and no edit to be in its
|
|
32
|
+
* default state. A repo-tracked config key cannot express that — an entry there is something every
|
|
33
|
+
* consumer must add, on a schedule set by whoever bumps the release.
|
|
34
|
+
*
|
|
35
|
+
* Note which half of that was the outage. It was the REQUIRED KEY, not the on-by-default behaviour: the
|
|
36
|
+
* failure was at config LOAD, before any command was judged. `whole-repo-build-guard` defaults ON again
|
|
37
|
+
* today (see WHOLE_REPO_BUILD_GUARD_DEFAULT) and cannot reproduce it, because there is nothing to add
|
|
38
|
+
* anywhere — the only file that could carry it is optional, and absent is a fully supported state.
|
|
34
39
|
*/
|
|
35
40
|
export declare const HOME_CONFIG_DIR = ".webpieces";
|
|
36
41
|
export declare const HOME_CONFIG_FILE = "config.json";
|
|
@@ -38,6 +43,28 @@ export declare const HOME_EXPERIMENTAL_SECTION = "experimental";
|
|
|
38
43
|
export declare const HOME_KEY_BUILD_GATE_LOG_CAPTURE = "buildGateLogCapture";
|
|
39
44
|
export declare const HOME_KEY_WHOLE_REPO_BUILD_GUARD = "whole-repo-build-guard";
|
|
40
45
|
export declare const HOME_KEY_ORPHAN_DIR_SWEEP = "orphan-dir-sweep";
|
|
46
|
+
/**
|
|
47
|
+
* `whole-repo-build-guard`'s value on a machine that does not name the key — including the machine with
|
|
48
|
+
* no such file at all, which is essentially every machine. It is TRUE: the guard is ON by default.
|
|
49
|
+
*
|
|
50
|
+
* ─── Why this one key defaults ON, and why that is not the outage this file warns about ─────────────
|
|
51
|
+
* The outage recorded below was a CONFIG-LOAD failure: the guard once required an entry under
|
|
52
|
+
* `hookGuards` in the repo-tracked `webpieces.config.json`, so every consumer who upgraded without
|
|
53
|
+
* adding it hit fault Y and had EVERY Bash call blocked, for a feature they had never asked for. The
|
|
54
|
+
* shape of that failure is "you must edit a file to get your shell back". Nothing here reproduces it:
|
|
55
|
+
* no file needs to exist, no key needs to be added, and the load path for an absent or silent file is
|
|
56
|
+
* unchanged. What changes is only what the guard DOES once loaded — it refuses a command that would
|
|
57
|
+
* build the whole monorepo, and hands back the scoped command in its place.
|
|
58
|
+
*
|
|
59
|
+
* That is the behaviour the guard was written for, and OFF-by-default is why it never delivered it: a
|
|
60
|
+
* guard nobody opts into never fires. The measured consequence is a sibling repo whose `ci:local`
|
|
61
|
+
* verify chain ran three whole-world passes on every inner loop for months, while the correct command
|
|
62
|
+
* sat unused in `commands.pr-gate.buildCommand`.
|
|
63
|
+
*
|
|
64
|
+
* The escape hatch stays, and it is one line: `{"experimental": {"whole-repo-build-guard": false}}`
|
|
65
|
+
* turns it off for a machine, with no repo config involved.
|
|
66
|
+
*/
|
|
67
|
+
export declare const WHOLE_REPO_BUILD_GUARD_DEFAULT = true;
|
|
41
68
|
/** The parsed `~/.webpieces/config.json`. Data-only (per CLAUDE.md — classes, not interfaces, for data). */
|
|
42
69
|
export declare class HomeConfig {
|
|
43
70
|
/**
|
|
@@ -47,13 +74,16 @@ export declare class HomeConfig {
|
|
|
47
74
|
*/
|
|
48
75
|
buildGateLogCapture: boolean;
|
|
49
76
|
/**
|
|
50
|
-
*
|
|
51
|
-
*
|
|
77
|
+
* NOT experimental, and ON unless this machine says otherwise: `WHOLE_REPO_BUILD_GUARD_DEFAULT`.
|
|
78
|
+
* When true, `whole-repo-build-guard` BLOCKS a Bash command that would build the WHOLE monorepo and
|
|
79
|
+
* hands back the repo's own scoped build command (`pnpm wp-build`). Setting it false makes the guard
|
|
52
80
|
* completely inert: no block, no log, no message.
|
|
53
81
|
*
|
|
54
|
-
* This is the guard's ONLY switch
|
|
55
|
-
* RETIRED_CONFIG_KEYS):
|
|
56
|
-
* blocked is a guard that ships an outage on upgrade, which is exactly
|
|
82
|
+
* This is the guard's ONLY switch, and it is an OPT-OUT. There is deliberately no
|
|
83
|
+
* webpieces.config.json entry for it (see RETIRED_CONFIG_KEYS): a guard that every consumer must
|
|
84
|
+
* ADD A KEY to avoid being blocked by is a guard that ships an outage on upgrade, which is exactly
|
|
85
|
+
* what happened. Defaulting ON here is the opposite shape — nothing has to be added anywhere, and
|
|
86
|
+
* see WHOLE_REPO_BUILD_GUARD_DEFAULT for why that distinction is the whole argument.
|
|
57
87
|
*/
|
|
58
88
|
wholeRepoBuildGuard: boolean;
|
|
59
89
|
/**
|
|
@@ -131,9 +161,11 @@ export declare class HomeConfigService {
|
|
|
131
161
|
private parse;
|
|
132
162
|
private validate;
|
|
133
163
|
/**
|
|
134
|
-
* An absent key
|
|
135
|
-
*
|
|
136
|
-
*
|
|
164
|
+
* An absent key falls back to `whenAbsent`, which every caller states OUT LOUD — there is no implicit
|
|
165
|
+
* "absent means false" any more, because `whole-repo-build-guard` defaults ON and a hidden default
|
|
166
|
+
* would put the two halves of that fact in different files. A PRESENT key of the wrong type is still
|
|
167
|
+
* an error: that is a file somebody wrote wrongly, not a file written for a different release. This
|
|
168
|
+
* is the ONLY reader; see the every-key-is-optional note above for why there is no required variant.
|
|
137
169
|
*/
|
|
138
170
|
private readOptionalBoolean;
|
|
139
171
|
private asBoolean;
|
package/src/home-config.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.HomeConfigService = exports.RETIRED_HOME_CONFIG_KEYS = exports.RetiredHomeConfigKey = exports.HomeConfig = exports.HOME_KEY_ORPHAN_DIR_SWEEP = exports.HOME_KEY_WHOLE_REPO_BUILD_GUARD = exports.HOME_KEY_BUILD_GATE_LOG_CAPTURE = exports.HOME_EXPERIMENTAL_SECTION = exports.HOME_CONFIG_FILE = exports.HOME_CONFIG_DIR = void 0;
|
|
3
|
+
exports.HomeConfigService = exports.RETIRED_HOME_CONFIG_KEYS = exports.RetiredHomeConfigKey = exports.HomeConfig = exports.WHOLE_REPO_BUILD_GUARD_DEFAULT = exports.HOME_KEY_ORPHAN_DIR_SWEEP = exports.HOME_KEY_WHOLE_REPO_BUILD_GUARD = exports.HOME_KEY_BUILD_GATE_LOG_CAPTURE = exports.HOME_EXPERIMENTAL_SECTION = exports.HOME_CONFIG_FILE = exports.HOME_CONFIG_DIR = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const fs = tslib_1.__importStar(require("fs"));
|
|
6
6
|
const os = tslib_1.__importStar(require("os"));
|
|
@@ -33,14 +33,19 @@ const to_error_1 = require("./to-error");
|
|
|
33
33
|
* ai-hook-rules' runner beside the webpieces.config.json pass), so an agent can always repair the file
|
|
34
34
|
* the loader just rejected.
|
|
35
35
|
*
|
|
36
|
-
* ─── WHY
|
|
36
|
+
* ─── WHY A MACHINE-LOCAL SWITCH LIVES HERE AND NOT IN webpieces.config.json ───────────────────────────
|
|
37
37
|
* `whole-repo-build-guard` first shipped as an ordinary validated guard: `mode: 'ON'` by default AND an
|
|
38
38
|
* entry required under `hookGuards`. The consequence on upgrade was an outage — a consumer repo that had
|
|
39
39
|
* not yet added the entry hit fault Y, which blocks EVERY Bash call, for a feature nobody had opted into.
|
|
40
40
|
*
|
|
41
|
-
* The rule that buys back:
|
|
42
|
-
*
|
|
43
|
-
*
|
|
41
|
+
* The rule that buys back: a switch that lives HERE needs no file, no key and no edit to be in its
|
|
42
|
+
* default state. A repo-tracked config key cannot express that — an entry there is something every
|
|
43
|
+
* consumer must add, on a schedule set by whoever bumps the release.
|
|
44
|
+
*
|
|
45
|
+
* Note which half of that was the outage. It was the REQUIRED KEY, not the on-by-default behaviour: the
|
|
46
|
+
* failure was at config LOAD, before any command was judged. `whole-repo-build-guard` defaults ON again
|
|
47
|
+
* today (see WHOLE_REPO_BUILD_GUARD_DEFAULT) and cannot reproduce it, because there is nothing to add
|
|
48
|
+
* anywhere — the only file that could carry it is optional, and absent is a fully supported state.
|
|
44
49
|
*/
|
|
45
50
|
exports.HOME_CONFIG_DIR = '.webpieces';
|
|
46
51
|
exports.HOME_CONFIG_FILE = 'config.json';
|
|
@@ -57,6 +62,32 @@ exports.HOME_KEY_WHOLE_REPO_BUILD_GUARD = 'whole-repo-build-guard';
|
|
|
57
62
|
// The on/off switch for the orphan-directory sweep `wp-checkout-clean-main` runs. Named for the thing
|
|
58
63
|
// it switches, exactly as the guard key above is — one name, greppable from either end.
|
|
59
64
|
exports.HOME_KEY_ORPHAN_DIR_SWEEP = 'orphan-dir-sweep';
|
|
65
|
+
/**
|
|
66
|
+
* `whole-repo-build-guard`'s value on a machine that does not name the key — including the machine with
|
|
67
|
+
* no such file at all, which is essentially every machine. It is TRUE: the guard is ON by default.
|
|
68
|
+
*
|
|
69
|
+
* ─── Why this one key defaults ON, and why that is not the outage this file warns about ─────────────
|
|
70
|
+
* The outage recorded below was a CONFIG-LOAD failure: the guard once required an entry under
|
|
71
|
+
* `hookGuards` in the repo-tracked `webpieces.config.json`, so every consumer who upgraded without
|
|
72
|
+
* adding it hit fault Y and had EVERY Bash call blocked, for a feature they had never asked for. The
|
|
73
|
+
* shape of that failure is "you must edit a file to get your shell back". Nothing here reproduces it:
|
|
74
|
+
* no file needs to exist, no key needs to be added, and the load path for an absent or silent file is
|
|
75
|
+
* unchanged. What changes is only what the guard DOES once loaded — it refuses a command that would
|
|
76
|
+
* build the whole monorepo, and hands back the scoped command in its place.
|
|
77
|
+
*
|
|
78
|
+
* That is the behaviour the guard was written for, and OFF-by-default is why it never delivered it: a
|
|
79
|
+
* guard nobody opts into never fires. The measured consequence is a sibling repo whose `ci:local`
|
|
80
|
+
* verify chain ran three whole-world passes on every inner loop for months, while the correct command
|
|
81
|
+
* sat unused in `commands.pr-gate.buildCommand`.
|
|
82
|
+
*
|
|
83
|
+
* The escape hatch stays, and it is one line: `{"experimental": {"whole-repo-build-guard": false}}`
|
|
84
|
+
* turns it off for a machine, with no repo config involved.
|
|
85
|
+
*/
|
|
86
|
+
exports.WHOLE_REPO_BUILD_GUARD_DEFAULT = true;
|
|
87
|
+
// Every OTHER key's value when it is not named. False — "this machine never opted in" — which for those
|
|
88
|
+
// keys is byte-for-byte the behaviour of having no file at all. Named rather than written as a bare
|
|
89
|
+
// `false` at each call site so the asymmetry with the constant above is visible where it is passed.
|
|
90
|
+
const GUARD_OFF_WHEN_ABSENT = false;
|
|
60
91
|
// The complete accepted shape. Anything not on these lists is an error, so adding a key means adding it
|
|
61
92
|
// here — there is no place for an unvalidated key to hide.
|
|
62
93
|
const ALLOWED_TOP_LEVEL = [exports.HOME_EXPERIMENTAL_SECTION];
|
|
@@ -75,9 +106,12 @@ const ALLOWED_EXPERIMENTAL = [
|
|
|
75
106
|
* There is no third option, and both rejections block. `whole-repo-build-guard` was required for the
|
|
76
107
|
* reason recorded in #627 — a flag that decides whether a command RUNS should not be inferred — and that
|
|
77
108
|
* reasoning was sound for a single version and wrong for a shared file. It is optional now, along with
|
|
78
|
-
* every other key.
|
|
79
|
-
*
|
|
80
|
-
*
|
|
109
|
+
* every other key.
|
|
110
|
+
*
|
|
111
|
+
* Absent then reads as each key's declared default. For every EXPERIMENTAL key that is false, which is
|
|
112
|
+
* byte-for-byte the behaviour of having no file at all. `whole-repo-build-guard` is the one exception
|
|
113
|
+
* and it defaults TRUE — it is no longer experimental — for the reason spelled out at
|
|
114
|
+
* WHOLE_REPO_BUILD_GUARD_DEFAULT.
|
|
81
115
|
*
|
|
82
116
|
* The other half of cross-version safety — an OLD release ignoring a key a NEW one added, rather than
|
|
83
117
|
* rejecting it — is NOT solved here. Adding a key still requires every repo on the machine to be moved
|
|
@@ -97,13 +131,16 @@ class HomeConfig {
|
|
|
97
131
|
*/
|
|
98
132
|
buildGateLogCapture;
|
|
99
133
|
/**
|
|
100
|
-
*
|
|
101
|
-
*
|
|
134
|
+
* NOT experimental, and ON unless this machine says otherwise: `WHOLE_REPO_BUILD_GUARD_DEFAULT`.
|
|
135
|
+
* When true, `whole-repo-build-guard` BLOCKS a Bash command that would build the WHOLE monorepo and
|
|
136
|
+
* hands back the repo's own scoped build command (`pnpm wp-build`). Setting it false makes the guard
|
|
102
137
|
* completely inert: no block, no log, no message.
|
|
103
138
|
*
|
|
104
|
-
* This is the guard's ONLY switch
|
|
105
|
-
* RETIRED_CONFIG_KEYS):
|
|
106
|
-
* blocked is a guard that ships an outage on upgrade, which is exactly
|
|
139
|
+
* This is the guard's ONLY switch, and it is an OPT-OUT. There is deliberately no
|
|
140
|
+
* webpieces.config.json entry for it (see RETIRED_CONFIG_KEYS): a guard that every consumer must
|
|
141
|
+
* ADD A KEY to avoid being blocked by is a guard that ships an outage on upgrade, which is exactly
|
|
142
|
+
* what happened. Defaulting ON here is the opposite shape — nothing has to be added anywhere, and
|
|
143
|
+
* see WHOLE_REPO_BUILD_GUARD_DEFAULT for why that distinction is the whole argument.
|
|
107
144
|
*/
|
|
108
145
|
wholeRepoBuildGuard;
|
|
109
146
|
/**
|
|
@@ -185,11 +222,14 @@ let HomeConfigService = class HomeConfigService {
|
|
|
185
222
|
*/
|
|
186
223
|
load(homeDir = os.homedir()) {
|
|
187
224
|
const raw = this.readIfPresent(this.configPath(homeDir));
|
|
188
|
-
// THE ABSENT-FILE STATE, and the ONE place it is constructed
|
|
189
|
-
//
|
|
225
|
+
// THE ABSENT-FILE STATE, and the ONE place it is constructed. Every EXPERIMENTAL flag is off;
|
|
226
|
+
// `whole-repo-build-guard` is NOT experimental any more and takes WHOLE_REPO_BUILD_GUARD_DEFAULT
|
|
227
|
+
// (true) — the same value a present file that does not name the key gets, so "no file" and "file
|
|
228
|
+
// that ignores this key" can never disagree. Spelled out rather than defaulted in the
|
|
190
229
|
// constructor — see the note there on why a defaulted parameter is a shim.
|
|
191
|
-
if (raw === null)
|
|
192
|
-
return new HomeConfig(
|
|
230
|
+
if (raw === null) {
|
|
231
|
+
return new HomeConfig(GUARD_OFF_WHEN_ABSENT, exports.WHOLE_REPO_BUILD_GUARD_DEFAULT, GUARD_OFF_WHEN_ABSENT);
|
|
232
|
+
}
|
|
193
233
|
return this.validate(this.parse(raw, this.configPath(homeDir)), this.configPath(homeDir));
|
|
194
234
|
}
|
|
195
235
|
/**
|
|
@@ -275,18 +315,21 @@ let HomeConfigService = class HomeConfigService {
|
|
|
275
315
|
// webpieces-disable no-any-unknown -- narrowed to a non-null, non-array object one line above
|
|
276
316
|
const experimental = (section ?? {});
|
|
277
317
|
this.assertKnownKeys(Object.keys(experimental), ALLOWED_EXPERIMENTAL, `${exports.HOME_EXPERIMENTAL_SECTION}.`, file);
|
|
278
|
-
return new HomeConfig(this.readOptionalBoolean(experimental, exports.HOME_KEY_BUILD_GATE_LOG_CAPTURE, file), this.readOptionalBoolean(experimental, exports.HOME_KEY_WHOLE_REPO_BUILD_GUARD, file), this.readOptionalBoolean(experimental, exports.HOME_KEY_ORPHAN_DIR_SWEEP, file));
|
|
318
|
+
return new HomeConfig(this.readOptionalBoolean(experimental, exports.HOME_KEY_BUILD_GATE_LOG_CAPTURE, file, GUARD_OFF_WHEN_ABSENT), this.readOptionalBoolean(experimental, exports.HOME_KEY_WHOLE_REPO_BUILD_GUARD, file, exports.WHOLE_REPO_BUILD_GUARD_DEFAULT), this.readOptionalBoolean(experimental, exports.HOME_KEY_ORPHAN_DIR_SWEEP, file, GUARD_OFF_WHEN_ABSENT));
|
|
279
319
|
}
|
|
280
320
|
/**
|
|
281
|
-
* An absent key
|
|
282
|
-
*
|
|
283
|
-
*
|
|
321
|
+
* An absent key falls back to `whenAbsent`, which every caller states OUT LOUD — there is no implicit
|
|
322
|
+
* "absent means false" any more, because `whole-repo-build-guard` defaults ON and a hidden default
|
|
323
|
+
* would put the two halves of that fact in different files. A PRESENT key of the wrong type is still
|
|
324
|
+
* an error: that is a file somebody wrote wrongly, not a file written for a different release. This
|
|
325
|
+
* is the ONLY reader; see the every-key-is-optional note above for why there is no required variant.
|
|
284
326
|
*/
|
|
285
327
|
// webpieces-disable no-any-unknown -- see parse()
|
|
286
|
-
|
|
328
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
329
|
+
readOptionalBoolean(experimental, key, file, whenAbsent) {
|
|
287
330
|
const value = experimental[key];
|
|
288
331
|
if (value === undefined)
|
|
289
|
-
return
|
|
332
|
+
return whenAbsent;
|
|
290
333
|
return this.asBoolean(value, key, file, ' Remove the quotes, or delete the key.');
|
|
291
334
|
}
|
|
292
335
|
// webpieces-disable no-any-unknown -- see parse()
|
package/src/home-config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"home-config.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/home-config.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\nimport * as os from 'os';\nimport * as path from 'path';\nimport { injectable, bindingScopeValues } from 'inversify';\n\nimport { InformAiError } from './inform-ai-error';\nimport { toError } from './to-error';\n\n/**\n * `~/.webpieces/config.json` — the MACHINE-GLOBAL preference file, and a different thing from the repo's\n * tracked `webpieces.config.json`. It is EXPERIMENTAL and entirely OPTIONAL.\n *\n * ─── ABSENT IS THE NORMAL STATE, AND IT IS NEVER AN ERROR ─────────────────────────────────────────────\n * Essentially every consumer of these packages has no such file, and for them every `wp-*` command must\n * behave byte-for-byte as it did before this file was ever read: no error, no warning, no log line, no\n * extra file, nothing. `load()` therefore treats EVERY failure to READ the bytes — the file missing, the\n * `~/.webpieces` directory missing, a permission error, a path component that is not a directory — as\n * \"not opted in\", and returns all-defaults silently. That is not a fallback for a wrong shape; it is the\n * definition of \"the user did not create this file\".\n *\n * ─── PRESENT IS STRICT, EXACTLY LIKE webpieces.config.json ────────────────────────────────────────────\n * Once the bytes are readable, someone DELIBERATELY created this file, and from that point the same\n * policy applies as to webpieces.config.json (see `retired-config-keys.ts`): an unparseable document, an\n * unknown key, a misspelled key, a retired key or a wrong value TYPE is REJECTED with an error naming the\n * exact fix. No `??` fallback, no alias table, no \"accepted for now\". Every reader of this file is a\n * coding agent, and an accepted shape is never migrated — so a loud failure carrying the mechanical edit\n * is strictly cheaper than duality, and it is the delivery mechanism for the migration.\n *\n * Rejecting is self-recoverable here for the same reason it is for webpieces.config.json: a Write/Edit\n * targeting THIS path is an unconditional PASS in the hook guards (see `isHomeConfigPath`, wired into\n * ai-hook-rules' runner beside the webpieces.config.json pass), so an agent can always repair the file\n * the loader just rejected.\n *\n * ─── WHY AN EXPERIMENTAL FEATURE LIVES HERE AND NOT IN webpieces.config.json ──────────────────────────\n * `whole-repo-build-guard` first shipped as an ordinary validated guard: `mode: 'ON'` by default AND an\n * entry required under `hookGuards`. The consequence on upgrade was an outage — a consumer repo that had\n * not yet added the entry hit fault Y, which blocks EVERY Bash call, for a feature nobody had opted into.\n *\n * The rule that buys back: an EXPERIMENTAL feature is switched from THIS file only, and its absent state\n * is byte-for-byte the old behaviour. A repo-tracked config key cannot express that — an entry there is\n * something every consumer must add, on a schedule set by whoever bumps the release.\n */\nexport const HOME_CONFIG_DIR = '.webpieces';\nexport const HOME_CONFIG_FILE = 'config.json';\n\n// The `experimental` section and its keys. Named as constants because both the validator and its error\n// text must spell them identically — a validator whose message names a different key than the one it\n// checks is worse than no message.\nexport const HOME_EXPERIMENTAL_SECTION = 'experimental';\nexport const HOME_KEY_BUILD_GATE_LOG_CAPTURE = 'buildGateLogCapture';\n// The on/off switch for `whole-repo-build-guard`. Spelled with the GUARD's own name, hyphens and all,\n// so `grep -rn whole-repo-build-guard` finds the switch beside the guard — and so nobody has to learn a\n// second name for one thing. It is a DIFFERENT key from buildGateLogCapture, which is #620's build-log\n// feature and merely selects WHICH refusal this guard prints.\nexport const HOME_KEY_WHOLE_REPO_BUILD_GUARD = 'whole-repo-build-guard';\n// The on/off switch for the orphan-directory sweep `wp-checkout-clean-main` runs. Named for the thing\n// it switches, exactly as the guard key above is — one name, greppable from either end.\nexport const HOME_KEY_ORPHAN_DIR_SWEEP = 'orphan-dir-sweep';\n\n// The complete accepted shape. Anything not on these lists is an error, so adding a key means adding it\n// here — there is no place for an unvalidated key to hide.\nconst ALLOWED_TOP_LEVEL: readonly string[] = [HOME_EXPERIMENTAL_SECTION];\nconst ALLOWED_EXPERIMENTAL: readonly string[] = [\n HOME_KEY_WHOLE_REPO_BUILD_GUARD, HOME_KEY_BUILD_GATE_LOG_CAPTURE, HOME_KEY_ORPHAN_DIR_SWEEP,\n];\n\n/**\n * ─── EVERY KEY IS OPTIONAL, AND THAT IS A HARD REQUIREMENT OF WHERE THIS FILE LIVES ───────────────────\n * This file is MACHINE-GLOBAL: one document, read by every repo on the machine, and those repos pin\n * DIFFERENT webpieces releases. A REQUIRED key cannot survive that, because it makes the set of valid\n * files EMPTY:\n *\n * • omit the new key → the NEW release rejects the file (\"REQUIRED and not set\")\n * • add the new key → every OLDER release rejects the file (\"not a known key\")\n *\n * There is no third option, and both rejections block. `whole-repo-build-guard` was required for the\n * reason recorded in #627 — a flag that decides whether a command RUNS should not be inferred — and that\n * reasoning was sound for a single version and wrong for a shared file. It is optional now, along with\n * every other key. The safety it was protecting is intact anyway: absent reads as FALSE, and false is\n * byte-for-byte the behaviour of having no file at all, so a guessed default can only ever fail towards\n * \"this machine never opted in\".\n *\n * The other half of cross-version safety — an OLD release ignoring a key a NEW one added, rather than\n * rejecting it — is NOT solved here. Adding a key still requires every repo on the machine to be moved\n * to a release that knows it.\n */\n\n// Read errors that mean \"the file is not there / not reachable\" rather than \"the file is wrong\". Every\n// one of these resolves to the all-defaults config, silently. Widened deliberately past ENOENT: the\n// parent `~/.webpieces` may not exist (ENOENT), may be a file (ENOTDIR), may be unreadable (EACCES /\n// EPERM), and the path itself may be a directory (EISDIR). None of those is a user who opted in.\nconst ABSENT_ERROR_CODES: readonly string[] = ['ENOENT', 'ENOTDIR', 'EACCES', 'EPERM', 'EISDIR', 'ELOOP', 'ENAMETOOLONG'];\n\n/** The parsed `~/.webpieces/config.json`. Data-only (per CLAUDE.md — classes, not interfaces, for data). */\nexport class HomeConfig {\n /**\n * EXPERIMENTAL, under test, not a supported knob. When true, the pr-gate build gate captures its full\n * output to `.webpieces/logs/` and hands a failing build's pointer to that file to the AI instead of\n * an instruction to rebuild. Default false — i.e. the behaviour every consumer has today.\n */\n buildGateLogCapture: boolean;\n\n /**\n * EXPERIMENTAL. When true, `whole-repo-build-guard` BLOCKS a Bash command that would build the whole\n * monorepo. False — and the all-defaults value for a machine with no such file — means the guard is\n * completely inert: no block, no log, no message.\n *\n * This is the guard's ONLY switch. There is deliberately no webpieces.config.json entry for it (see\n * RETIRED_CONFIG_KEYS): an experimental guard that every consumer must configure to avoid being\n * blocked is a guard that ships an outage on upgrade, which is exactly what happened.\n */\n wholeRepoBuildGuard: boolean;\n\n /**\n * EXPERIMENTAL. When true, `wp-checkout-clean-main` ARCHIVES the orphan directories it finds — the\n * package directories left behind on every clone by an `nx g move`, which git cannot remove because\n * an ignored `dist/` or `node_modules/` survives the deletion of every tracked file under them.\n *\n * False — and the all-defaults value for a machine with no such file — means the sweep only REPORTS\n * what it found and moves nothing. That asymmetry is the point of shipping this behind the home\n * config at all: the author can run it live across their own clones for a release while every\n * colleague's repo is untouched, and neither state depends on a tracked key anybody must add.\n *\n * The sweep itself never deletes (see OrphanDirArchiver): directories move under `.webpieces/trash/`\n * with a printed `recover=`, so the worst case for a false positive is a `mv` somebody undoes. The\n * ARCHIVE is reaped after 30 days, which is a real deletion — of the second copy, on a timer long\n * enough that anything still wanted has been noticed.\n */\n orphanDirSweep: boolean;\n\n // ALL THREE required, no defaults. A defaulted parameter would leave `new HomeConfig(true)` compiling\n // after this class grew a second flag, silently meaning \"guard off\" — an old spelling that still\n // typechecks with a changed meaning is exactly the shim this repo does not ship. The absent-file\n // state is constructed in exactly one place — load()'s absent-file branch.\n constructor(buildGateLogCapture: boolean, wholeRepoBuildGuard: boolean, orphanDirSweep: boolean) {\n this.buildGateLogCapture = buildGateLogCapture;\n this.wholeRepoBuildGuard = wholeRepoBuildGuard;\n this.orphanDirSweep = orphanDirSweep;\n }\n}\n\n/**\n * One retired `~/.webpieces/config.json` key and the mechanical edit that replaces it. Data-only.\n *\n * This mirrors `RetiredConfigKey` rather than reusing it: that table's entries carry a `scope`\n * (rule-name vs key-in-section) that describes webpieces.config.json's two-level layout and means\n * nothing here, and its `label` convention names that file's sections. One shared class covering both\n * would be a type with fields that are dead for half its instances.\n */\nexport class RetiredHomeConfigKey {\n // Dotted path exactly as it appears in the file, e.g. `experimental.captureBuildGateLog`.\n key: string;\n // Where the value goes now. Empty when the key is deleted outright.\n movedTo: string;\n // The imperative fix, written for the agent that will apply it verbatim.\n instruction: string;\n\n constructor(key: string, movedTo: string, instruction: string) {\n this.key = key;\n this.movedTo = movedTo;\n this.instruction = instruction;\n }\n}\n\n/**\n * Every retired home-config key — the ONE place in the codebase where a dead home-config key may be\n * named, exactly as `RETIRED_CONFIG_KEYS` is for webpieces.config.json. Newest at the bottom.\n *\n * When you retire a key here, DELETE its read path in the same change. `home-config.spec.ts` asserts\n * every entry below actually FAILS the load, so a fallback that quietly accepts one turns it red.\n */\nexport const RETIRED_HOME_CONFIG_KEYS: readonly RetiredHomeConfigKey[] = [\n // `captureBuildGateLog` was the working name while this feature was being built, and it appears in\n // the branch history and in in-flight drafts, so it is exactly the spelling an agent reconstructing\n // the file from memory will type. It never shipped in a release; it is listed so that typing it\n // produces the rename instruction rather than a bare \"unknown key\".\n new RetiredHomeConfigKey(\n 'experimental.captureBuildGateLog', 'experimental.buildGateLogCapture',\n 'Rename the key to \"buildGateLogCapture\" inside the same \"experimental\" object. Its boolean value ' +\n 'carries over unchanged.',\n ),\n];\n\n/**\n * Loads and STRICTLY validates `~/.webpieces/config.json`, and resolves whether a path IS that file (for\n * the guard carve-out that keeps a rejection repairable).\n */\n@injectable(bindingScopeValues.Singleton)\nexport class HomeConfigService {\n /** Absolute path to the preference file. `homeDir` is a parameter so specs never touch a real HOME. */\n configPath(homeDir: string = os.homedir()): string {\n return path.join(homeDir, HOME_CONFIG_DIR, HOME_CONFIG_FILE);\n }\n\n /**\n * The preferences. Returns all-defaults, silently and without touching anything, when the file is not\n * there. THROWS InformAiError, naming the fix, when a file that IS there is wrong.\n */\n load(homeDir: string = os.homedir()): HomeConfig {\n const raw = this.readIfPresent(this.configPath(homeDir));\n // THE ABSENT-FILE STATE, and the ONE place it is constructed: every flag off, i.e. every\n // behaviour this machine had before the file existed. Spelled out rather than defaulted in the\n // constructor — see the note there on why a defaulted parameter is a shim.\n if (raw === null) return new HomeConfig(false, false, false);\n return this.validate(this.parse(raw, this.configPath(homeDir)), this.configPath(homeDir));\n }\n\n /**\n * True when `candidate` names `~/.webpieces/config.json`, in any of the forms an agent writes it:\n * an absolute path, a `~/`-prefixed path, or one still spelled `$HOME/…` / `${HOME}/…`.\n *\n * This is what the hook guards call to grant the file an unconditional Write/Edit PASS. Without it a\n * strict loader could reject the file while the guards blocked the edit that would fix it — the one\n * wedge webpieces.config.json is already immune to, and the reason its own carve-out exists.\n */\n isHomeConfigPath(candidate: string, homeDir: string = os.homedir()): boolean {\n if (candidate.trim() === '') return false;\n return path.resolve(this.expandHome(candidate.trim(), homeDir)) === path.resolve(this.configPath(homeDir));\n }\n\n // `~`, `$HOME` and `${HOME}` at the FRONT only — a home reference anywhere else is not a home path.\n private expandHome(candidate: string, homeDir: string): string {\n if (candidate === '~') return homeDir;\n for (const prefix of ['~/', '$HOME/', '${HOME}/']) {\n if (candidate.startsWith(prefix)) return path.join(homeDir, candidate.slice(prefix.length));\n }\n return candidate;\n }\n\n /**\n * The file's bytes, or null meaning \"no such file — the user did not opt in\".\n *\n * EVERY read failure is null. This is the single most important behaviour in the file: the absent\n * path is the path every consumer of these packages is on, and it may never reach an error branch.\n * An error code outside ABSENT_ERROR_CODES is genuinely exceptional (EIO, EBUSY) and is rethrown,\n * because silently disabling on a failing disk would be its own kind of lie.\n */\n private readIfPresent(file: string): string | null {\n // webpieces-disable no-unmanaged-exceptions -- chokepoint: this catch IS the \"you have no such file\"\n // decision, and that decision may never surface as a failure to a user who never created the file\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n return fs.readFileSync(file, 'utf8');\n } catch (err: unknown) {\n const error = toError(err);\n if (this.isAbsent(error)) return null;\n throw error;\n }\n }\n\n private isAbsent(error: Error): boolean {\n // webpieces-disable no-any-unknown -- node attaches `code` to fs errors without typing it on Error\n const code = (error as unknown as Record<string, unknown>)['code'];\n return typeof code === 'string' && ABSENT_ERROR_CODES.includes(code);\n }\n\n // A readable file that is not a JSON object is a WRONG file, not an absent one — hence the throw.\n // webpieces-disable no-any-unknown -- an unvalidated user-authored document; every field is narrowed below\n private parse(raw: string, file: string): Record<string, unknown> {\n // webpieces-disable no-unmanaged-exceptions -- chokepoint: JSON.parse's own message is useless to an\n // agent on its own, so it is re-thrown as the InformAiError that names the file and the fix\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n // webpieces-disable no-any-unknown -- opaque parsed JSON, narrowed immediately below\n const parsed: unknown = JSON.parse(raw);\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n throw new InformAiError(this.error(file, 'the file must contain a single JSON OBJECT, e.g. {}.'));\n }\n // webpieces-disable no-any-unknown -- narrowed to a non-null, non-array object one line above\n return parsed as Record<string, unknown>;\n } catch (err: unknown) {\n const error = toError(err);\n if (error instanceof InformAiError) throw error;\n throw new InformAiError(this.error(file, `the file is not valid JSON (${error.message}).`), { cause: error });\n }\n }\n\n // webpieces-disable no-any-unknown -- see parse(); the document is user-authored and unvalidated\n private validate(raw: Record<string, unknown>, file: string): HomeConfig {\n this.assertNotRetired(raw, file);\n this.assertKnownKeys(Object.keys(raw), ALLOWED_TOP_LEVEL, '', file);\n const section = raw[HOME_EXPERIMENTAL_SECTION];\n if (section !== undefined && (typeof section !== 'object' || section === null || Array.isArray(section))) {\n throw new InformAiError(this.error(file, `\"${HOME_EXPERIMENTAL_SECTION}\" must be a JSON object.`));\n }\n // webpieces-disable no-any-unknown -- narrowed to a non-null, non-array object one line above\n const experimental = (section ?? {}) as Record<string, unknown>;\n this.assertKnownKeys(Object.keys(experimental), ALLOWED_EXPERIMENTAL, `${HOME_EXPERIMENTAL_SECTION}.`, file);\n return new HomeConfig(\n this.readOptionalBoolean(experimental, HOME_KEY_BUILD_GATE_LOG_CAPTURE, file),\n this.readOptionalBoolean(experimental, HOME_KEY_WHOLE_REPO_BUILD_GUARD, file),\n this.readOptionalBoolean(experimental, HOME_KEY_ORPHAN_DIR_SWEEP, file),\n );\n }\n\n /**\n * An absent key is OFF. A PRESENT key of the wrong type is still an error — that is a file somebody\n * wrote wrongly, not a file written for a different release. This is the ONLY reader; see the\n * every-key-is-optional note above for why there is no required variant.\n */\n // webpieces-disable no-any-unknown -- see parse()\n private readOptionalBoolean(experimental: Record<string, unknown>, key: string, file: string): boolean {\n const value = experimental[key];\n if (value === undefined) return false;\n return this.asBoolean(value, key, file, ' Remove the quotes, or delete the key.');\n }\n\n // webpieces-disable no-any-unknown -- see parse()\n // eslint-disable-next-line @typescript-eslint/max-params\n private asBoolean(value: unknown, key: string, file: string, fix: string): boolean {\n if (typeof value !== 'boolean') {\n throw new InformAiError(this.error(file,\n `\"${HOME_EXPERIMENTAL_SECTION}.${key}\" must be the boolean ` +\n `true or false, not ${JSON.stringify(value)}.${fix}`));\n }\n return value;\n }\n\n // Retired keys are checked BEFORE unknown-key reporting: \"unknown key\" would send an agent deleting a\n // key whose value it should be MOVING, which is the whole reason the retirement table exists.\n // webpieces-disable no-any-unknown -- see parse()\n private assertNotRetired(raw: Record<string, unknown>, file: string): void {\n for (const entry of RETIRED_HOME_CONFIG_KEYS) {\n if (!this.isPresentAt(raw, entry.key)) continue;\n const destination = entry.movedTo === ''\n ? 'It was removed with no replacement.'\n : `It moved to \"${entry.movedTo}\".`;\n throw new InformAiError(this.error(file,\n `\"${entry.key}\" is RETIRED. ${destination} ${entry.instruction}`));\n }\n }\n\n // Is `dotted` (one or two segments — the file is two levels deep by construction) actually present?\n // webpieces-disable no-any-unknown -- see parse()\n private isPresentAt(raw: Record<string, unknown>, dotted: string): boolean {\n const parts = dotted.split('.');\n if (parts.length === 1) return raw[parts[0]] !== undefined;\n const section = raw[parts[0]];\n if (typeof section !== 'object' || section === null || Array.isArray(section)) return false;\n // webpieces-disable no-any-unknown -- narrowed to a non-null, non-array object one line above\n return (section as Record<string, unknown>)[parts[1]] !== undefined;\n }\n\n /**\n * Every accepted key, rendered from ALLOWED_EXPERIMENTAL rather than hand-listed. The hand-listed\n * version named two keys and went stale the moment a third arrived, telling an agent its brand-new\n * key was not accepted while the validator right above accepted it.\n */\n private quotedExperimentalKeys(): string {\n return ALLOWED_EXPERIMENTAL.map((key: string): string =>\n `\"${HOME_EXPERIMENTAL_SECTION}.${key}\"`).join(', ');\n }\n\n private assertKnownKeys(found: string[], allowed: readonly string[], prefix: string, file: string): void {\n for (const key of found) {\n if (allowed.includes(key)) continue;\n throw new InformAiError(this.error(file,\n `\"${prefix}${key}\" is not a known key.${this.didYouMean(key, allowed, prefix)} ` +\n `The only keys this file accepts are ` +\n `${this.quotedExperimentalKeys()}. ` +\n `Fix the spelling or delete the key.`));\n }\n }\n\n // A case-insensitive match is the overwhelmingly common typo and is worth naming outright.\n private didYouMean(key: string, allowed: readonly string[], prefix: string): string {\n for (const candidate of allowed) {\n if (candidate.toLowerCase() === key.toLowerCase()) return ` Did you mean \"${prefix}${candidate}\"?`;\n }\n return '';\n }\n\n // One shape for every rejection: what is wrong, in which file, and the fact that deleting the file is\n // always a legal fix — because the file is optional, and \"no file\" is a fully supported state.\n private error(file: string, detail: string): string {\n return `[~/.webpieces/config.json] ${detail}\\n\\n` +\n `File: ${file}\\n` +\n `This machine-local preference file is OPTIONAL and EXPERIMENTAL. Editing it is always ` +\n `permitted, even while it is invalid, and deleting it outright is a valid fix — with no such ` +\n `file every webpieces command behaves exactly as it does by default.`;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"home-config.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/home-config.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\nimport * as os from 'os';\nimport * as path from 'path';\nimport { injectable, bindingScopeValues } from 'inversify';\n\nimport { InformAiError } from './inform-ai-error';\nimport { toError } from './to-error';\n\n/**\n * `~/.webpieces/config.json` — the MACHINE-GLOBAL preference file, and a different thing from the repo's\n * tracked `webpieces.config.json`. It is EXPERIMENTAL and entirely OPTIONAL.\n *\n * ─── ABSENT IS THE NORMAL STATE, AND IT IS NEVER AN ERROR ─────────────────────────────────────────────\n * Essentially every consumer of these packages has no such file, and for them every `wp-*` command must\n * behave byte-for-byte as it did before this file was ever read: no error, no warning, no log line, no\n * extra file, nothing. `load()` therefore treats EVERY failure to READ the bytes — the file missing, the\n * `~/.webpieces` directory missing, a permission error, a path component that is not a directory — as\n * \"not opted in\", and returns all-defaults silently. That is not a fallback for a wrong shape; it is the\n * definition of \"the user did not create this file\".\n *\n * ─── PRESENT IS STRICT, EXACTLY LIKE webpieces.config.json ────────────────────────────────────────────\n * Once the bytes are readable, someone DELIBERATELY created this file, and from that point the same\n * policy applies as to webpieces.config.json (see `retired-config-keys.ts`): an unparseable document, an\n * unknown key, a misspelled key, a retired key or a wrong value TYPE is REJECTED with an error naming the\n * exact fix. No `??` fallback, no alias table, no \"accepted for now\". Every reader of this file is a\n * coding agent, and an accepted shape is never migrated — so a loud failure carrying the mechanical edit\n * is strictly cheaper than duality, and it is the delivery mechanism for the migration.\n *\n * Rejecting is self-recoverable here for the same reason it is for webpieces.config.json: a Write/Edit\n * targeting THIS path is an unconditional PASS in the hook guards (see `isHomeConfigPath`, wired into\n * ai-hook-rules' runner beside the webpieces.config.json pass), so an agent can always repair the file\n * the loader just rejected.\n *\n * ─── WHY A MACHINE-LOCAL SWITCH LIVES HERE AND NOT IN webpieces.config.json ───────────────────────────\n * `whole-repo-build-guard` first shipped as an ordinary validated guard: `mode: 'ON'` by default AND an\n * entry required under `hookGuards`. The consequence on upgrade was an outage — a consumer repo that had\n * not yet added the entry hit fault Y, which blocks EVERY Bash call, for a feature nobody had opted into.\n *\n * The rule that buys back: a switch that lives HERE needs no file, no key and no edit to be in its\n * default state. A repo-tracked config key cannot express that — an entry there is something every\n * consumer must add, on a schedule set by whoever bumps the release.\n *\n * Note which half of that was the outage. It was the REQUIRED KEY, not the on-by-default behaviour: the\n * failure was at config LOAD, before any command was judged. `whole-repo-build-guard` defaults ON again\n * today (see WHOLE_REPO_BUILD_GUARD_DEFAULT) and cannot reproduce it, because there is nothing to add\n * anywhere — the only file that could carry it is optional, and absent is a fully supported state.\n */\nexport const HOME_CONFIG_DIR = '.webpieces';\nexport const HOME_CONFIG_FILE = 'config.json';\n\n// The `experimental` section and its keys. Named as constants because both the validator and its error\n// text must spell them identically — a validator whose message names a different key than the one it\n// checks is worse than no message.\nexport const HOME_EXPERIMENTAL_SECTION = 'experimental';\nexport const HOME_KEY_BUILD_GATE_LOG_CAPTURE = 'buildGateLogCapture';\n// The on/off switch for `whole-repo-build-guard`. Spelled with the GUARD's own name, hyphens and all,\n// so `grep -rn whole-repo-build-guard` finds the switch beside the guard — and so nobody has to learn a\n// second name for one thing. It is a DIFFERENT key from buildGateLogCapture, which is #620's build-log\n// feature and merely selects WHICH refusal this guard prints.\nexport const HOME_KEY_WHOLE_REPO_BUILD_GUARD = 'whole-repo-build-guard';\n// The on/off switch for the orphan-directory sweep `wp-checkout-clean-main` runs. Named for the thing\n// it switches, exactly as the guard key above is — one name, greppable from either end.\nexport const HOME_KEY_ORPHAN_DIR_SWEEP = 'orphan-dir-sweep';\n\n/**\n * `whole-repo-build-guard`'s value on a machine that does not name the key — including the machine with\n * no such file at all, which is essentially every machine. It is TRUE: the guard is ON by default.\n *\n * ─── Why this one key defaults ON, and why that is not the outage this file warns about ─────────────\n * The outage recorded below was a CONFIG-LOAD failure: the guard once required an entry under\n * `hookGuards` in the repo-tracked `webpieces.config.json`, so every consumer who upgraded without\n * adding it hit fault Y and had EVERY Bash call blocked, for a feature they had never asked for. The\n * shape of that failure is \"you must edit a file to get your shell back\". Nothing here reproduces it:\n * no file needs to exist, no key needs to be added, and the load path for an absent or silent file is\n * unchanged. What changes is only what the guard DOES once loaded — it refuses a command that would\n * build the whole monorepo, and hands back the scoped command in its place.\n *\n * That is the behaviour the guard was written for, and OFF-by-default is why it never delivered it: a\n * guard nobody opts into never fires. The measured consequence is a sibling repo whose `ci:local`\n * verify chain ran three whole-world passes on every inner loop for months, while the correct command\n * sat unused in `commands.pr-gate.buildCommand`.\n *\n * The escape hatch stays, and it is one line: `{\"experimental\": {\"whole-repo-build-guard\": false}}`\n * turns it off for a machine, with no repo config involved.\n */\nexport const WHOLE_REPO_BUILD_GUARD_DEFAULT = true;\n\n// Every OTHER key's value when it is not named. False — \"this machine never opted in\" — which for those\n// keys is byte-for-byte the behaviour of having no file at all. Named rather than written as a bare\n// `false` at each call site so the asymmetry with the constant above is visible where it is passed.\nconst GUARD_OFF_WHEN_ABSENT = false;\n\n// The complete accepted shape. Anything not on these lists is an error, so adding a key means adding it\n// here — there is no place for an unvalidated key to hide.\nconst ALLOWED_TOP_LEVEL: readonly string[] = [HOME_EXPERIMENTAL_SECTION];\nconst ALLOWED_EXPERIMENTAL: readonly string[] = [\n HOME_KEY_WHOLE_REPO_BUILD_GUARD, HOME_KEY_BUILD_GATE_LOG_CAPTURE, HOME_KEY_ORPHAN_DIR_SWEEP,\n];\n\n/**\n * ─── EVERY KEY IS OPTIONAL, AND THAT IS A HARD REQUIREMENT OF WHERE THIS FILE LIVES ───────────────────\n * This file is MACHINE-GLOBAL: one document, read by every repo on the machine, and those repos pin\n * DIFFERENT webpieces releases. A REQUIRED key cannot survive that, because it makes the set of valid\n * files EMPTY:\n *\n * • omit the new key → the NEW release rejects the file (\"REQUIRED and not set\")\n * • add the new key → every OLDER release rejects the file (\"not a known key\")\n *\n * There is no third option, and both rejections block. `whole-repo-build-guard` was required for the\n * reason recorded in #627 — a flag that decides whether a command RUNS should not be inferred — and that\n * reasoning was sound for a single version and wrong for a shared file. It is optional now, along with\n * every other key.\n *\n * Absent then reads as each key's declared default. For every EXPERIMENTAL key that is false, which is\n * byte-for-byte the behaviour of having no file at all. `whole-repo-build-guard` is the one exception\n * and it defaults TRUE — it is no longer experimental — for the reason spelled out at\n * WHOLE_REPO_BUILD_GUARD_DEFAULT.\n *\n * The other half of cross-version safety — an OLD release ignoring a key a NEW one added, rather than\n * rejecting it — is NOT solved here. Adding a key still requires every repo on the machine to be moved\n * to a release that knows it.\n */\n\n// Read errors that mean \"the file is not there / not reachable\" rather than \"the file is wrong\". Every\n// one of these resolves to the all-defaults config, silently. Widened deliberately past ENOENT: the\n// parent `~/.webpieces` may not exist (ENOENT), may be a file (ENOTDIR), may be unreadable (EACCES /\n// EPERM), and the path itself may be a directory (EISDIR). None of those is a user who opted in.\nconst ABSENT_ERROR_CODES: readonly string[] = ['ENOENT', 'ENOTDIR', 'EACCES', 'EPERM', 'EISDIR', 'ELOOP', 'ENAMETOOLONG'];\n\n/** The parsed `~/.webpieces/config.json`. Data-only (per CLAUDE.md — classes, not interfaces, for data). */\nexport class HomeConfig {\n /**\n * EXPERIMENTAL, under test, not a supported knob. When true, the pr-gate build gate captures its full\n * output to `.webpieces/logs/` and hands a failing build's pointer to that file to the AI instead of\n * an instruction to rebuild. Default false — i.e. the behaviour every consumer has today.\n */\n buildGateLogCapture: boolean;\n\n /**\n * NOT experimental, and ON unless this machine says otherwise: `WHOLE_REPO_BUILD_GUARD_DEFAULT`.\n * When true, `whole-repo-build-guard` BLOCKS a Bash command that would build the WHOLE monorepo and\n * hands back the repo's own scoped build command (`pnpm wp-build`). Setting it false makes the guard\n * completely inert: no block, no log, no message.\n *\n * This is the guard's ONLY switch, and it is an OPT-OUT. There is deliberately no\n * webpieces.config.json entry for it (see RETIRED_CONFIG_KEYS): a guard that every consumer must\n * ADD A KEY to avoid being blocked by is a guard that ships an outage on upgrade, which is exactly\n * what happened. Defaulting ON here is the opposite shape — nothing has to be added anywhere, and\n * see WHOLE_REPO_BUILD_GUARD_DEFAULT for why that distinction is the whole argument.\n */\n wholeRepoBuildGuard: boolean;\n\n /**\n * EXPERIMENTAL. When true, `wp-checkout-clean-main` ARCHIVES the orphan directories it finds — the\n * package directories left behind on every clone by an `nx g move`, which git cannot remove because\n * an ignored `dist/` or `node_modules/` survives the deletion of every tracked file under them.\n *\n * False — and the all-defaults value for a machine with no such file — means the sweep only REPORTS\n * what it found and moves nothing. That asymmetry is the point of shipping this behind the home\n * config at all: the author can run it live across their own clones for a release while every\n * colleague's repo is untouched, and neither state depends on a tracked key anybody must add.\n *\n * The sweep itself never deletes (see OrphanDirArchiver): directories move under `.webpieces/trash/`\n * with a printed `recover=`, so the worst case for a false positive is a `mv` somebody undoes. The\n * ARCHIVE is reaped after 30 days, which is a real deletion — of the second copy, on a timer long\n * enough that anything still wanted has been noticed.\n */\n orphanDirSweep: boolean;\n\n // ALL THREE required, no defaults. A defaulted parameter would leave `new HomeConfig(true)` compiling\n // after this class grew a second flag, silently meaning \"guard off\" — an old spelling that still\n // typechecks with a changed meaning is exactly the shim this repo does not ship. The absent-file\n // state is constructed in exactly one place — load()'s absent-file branch.\n constructor(buildGateLogCapture: boolean, wholeRepoBuildGuard: boolean, orphanDirSweep: boolean) {\n this.buildGateLogCapture = buildGateLogCapture;\n this.wholeRepoBuildGuard = wholeRepoBuildGuard;\n this.orphanDirSweep = orphanDirSweep;\n }\n}\n\n/**\n * One retired `~/.webpieces/config.json` key and the mechanical edit that replaces it. Data-only.\n *\n * This mirrors `RetiredConfigKey` rather than reusing it: that table's entries carry a `scope`\n * (rule-name vs key-in-section) that describes webpieces.config.json's two-level layout and means\n * nothing here, and its `label` convention names that file's sections. One shared class covering both\n * would be a type with fields that are dead for half its instances.\n */\nexport class RetiredHomeConfigKey {\n // Dotted path exactly as it appears in the file, e.g. `experimental.captureBuildGateLog`.\n key: string;\n // Where the value goes now. Empty when the key is deleted outright.\n movedTo: string;\n // The imperative fix, written for the agent that will apply it verbatim.\n instruction: string;\n\n constructor(key: string, movedTo: string, instruction: string) {\n this.key = key;\n this.movedTo = movedTo;\n this.instruction = instruction;\n }\n}\n\n/**\n * Every retired home-config key — the ONE place in the codebase where a dead home-config key may be\n * named, exactly as `RETIRED_CONFIG_KEYS` is for webpieces.config.json. Newest at the bottom.\n *\n * When you retire a key here, DELETE its read path in the same change. `home-config.spec.ts` asserts\n * every entry below actually FAILS the load, so a fallback that quietly accepts one turns it red.\n */\nexport const RETIRED_HOME_CONFIG_KEYS: readonly RetiredHomeConfigKey[] = [\n // `captureBuildGateLog` was the working name while this feature was being built, and it appears in\n // the branch history and in in-flight drafts, so it is exactly the spelling an agent reconstructing\n // the file from memory will type. It never shipped in a release; it is listed so that typing it\n // produces the rename instruction rather than a bare \"unknown key\".\n new RetiredHomeConfigKey(\n 'experimental.captureBuildGateLog', 'experimental.buildGateLogCapture',\n 'Rename the key to \"buildGateLogCapture\" inside the same \"experimental\" object. Its boolean value ' +\n 'carries over unchanged.',\n ),\n];\n\n/**\n * Loads and STRICTLY validates `~/.webpieces/config.json`, and resolves whether a path IS that file (for\n * the guard carve-out that keeps a rejection repairable).\n */\n@injectable(bindingScopeValues.Singleton)\nexport class HomeConfigService {\n /** Absolute path to the preference file. `homeDir` is a parameter so specs never touch a real HOME. */\n configPath(homeDir: string = os.homedir()): string {\n return path.join(homeDir, HOME_CONFIG_DIR, HOME_CONFIG_FILE);\n }\n\n /**\n * The preferences. Returns all-defaults, silently and without touching anything, when the file is not\n * there. THROWS InformAiError, naming the fix, when a file that IS there is wrong.\n */\n load(homeDir: string = os.homedir()): HomeConfig {\n const raw = this.readIfPresent(this.configPath(homeDir));\n // THE ABSENT-FILE STATE, and the ONE place it is constructed. Every EXPERIMENTAL flag is off;\n // `whole-repo-build-guard` is NOT experimental any more and takes WHOLE_REPO_BUILD_GUARD_DEFAULT\n // (true) — the same value a present file that does not name the key gets, so \"no file\" and \"file\n // that ignores this key\" can never disagree. Spelled out rather than defaulted in the\n // constructor — see the note there on why a defaulted parameter is a shim.\n if (raw === null) {\n return new HomeConfig(\n GUARD_OFF_WHEN_ABSENT, WHOLE_REPO_BUILD_GUARD_DEFAULT, GUARD_OFF_WHEN_ABSENT);\n }\n return this.validate(this.parse(raw, this.configPath(homeDir)), this.configPath(homeDir));\n }\n\n /**\n * True when `candidate` names `~/.webpieces/config.json`, in any of the forms an agent writes it:\n * an absolute path, a `~/`-prefixed path, or one still spelled `$HOME/…` / `${HOME}/…`.\n *\n * This is what the hook guards call to grant the file an unconditional Write/Edit PASS. Without it a\n * strict loader could reject the file while the guards blocked the edit that would fix it — the one\n * wedge webpieces.config.json is already immune to, and the reason its own carve-out exists.\n */\n isHomeConfigPath(candidate: string, homeDir: string = os.homedir()): boolean {\n if (candidate.trim() === '') return false;\n return path.resolve(this.expandHome(candidate.trim(), homeDir)) === path.resolve(this.configPath(homeDir));\n }\n\n // `~`, `$HOME` and `${HOME}` at the FRONT only — a home reference anywhere else is not a home path.\n private expandHome(candidate: string, homeDir: string): string {\n if (candidate === '~') return homeDir;\n for (const prefix of ['~/', '$HOME/', '${HOME}/']) {\n if (candidate.startsWith(prefix)) return path.join(homeDir, candidate.slice(prefix.length));\n }\n return candidate;\n }\n\n /**\n * The file's bytes, or null meaning \"no such file — the user did not opt in\".\n *\n * EVERY read failure is null. This is the single most important behaviour in the file: the absent\n * path is the path every consumer of these packages is on, and it may never reach an error branch.\n * An error code outside ABSENT_ERROR_CODES is genuinely exceptional (EIO, EBUSY) and is rethrown,\n * because silently disabling on a failing disk would be its own kind of lie.\n */\n private readIfPresent(file: string): string | null {\n // webpieces-disable no-unmanaged-exceptions -- chokepoint: this catch IS the \"you have no such file\"\n // decision, and that decision may never surface as a failure to a user who never created the file\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n return fs.readFileSync(file, 'utf8');\n } catch (err: unknown) {\n const error = toError(err);\n if (this.isAbsent(error)) return null;\n throw error;\n }\n }\n\n private isAbsent(error: Error): boolean {\n // webpieces-disable no-any-unknown -- node attaches `code` to fs errors without typing it on Error\n const code = (error as unknown as Record<string, unknown>)['code'];\n return typeof code === 'string' && ABSENT_ERROR_CODES.includes(code);\n }\n\n // A readable file that is not a JSON object is a WRONG file, not an absent one — hence the throw.\n // webpieces-disable no-any-unknown -- an unvalidated user-authored document; every field is narrowed below\n private parse(raw: string, file: string): Record<string, unknown> {\n // webpieces-disable no-unmanaged-exceptions -- chokepoint: JSON.parse's own message is useless to an\n // agent on its own, so it is re-thrown as the InformAiError that names the file and the fix\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n // webpieces-disable no-any-unknown -- opaque parsed JSON, narrowed immediately below\n const parsed: unknown = JSON.parse(raw);\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n throw new InformAiError(this.error(file, 'the file must contain a single JSON OBJECT, e.g. {}.'));\n }\n // webpieces-disable no-any-unknown -- narrowed to a non-null, non-array object one line above\n return parsed as Record<string, unknown>;\n } catch (err: unknown) {\n const error = toError(err);\n if (error instanceof InformAiError) throw error;\n throw new InformAiError(this.error(file, `the file is not valid JSON (${error.message}).`), { cause: error });\n }\n }\n\n // webpieces-disable no-any-unknown -- see parse(); the document is user-authored and unvalidated\n private validate(raw: Record<string, unknown>, file: string): HomeConfig {\n this.assertNotRetired(raw, file);\n this.assertKnownKeys(Object.keys(raw), ALLOWED_TOP_LEVEL, '', file);\n const section = raw[HOME_EXPERIMENTAL_SECTION];\n if (section !== undefined && (typeof section !== 'object' || section === null || Array.isArray(section))) {\n throw new InformAiError(this.error(file, `\"${HOME_EXPERIMENTAL_SECTION}\" must be a JSON object.`));\n }\n // webpieces-disable no-any-unknown -- narrowed to a non-null, non-array object one line above\n const experimental = (section ?? {}) as Record<string, unknown>;\n this.assertKnownKeys(Object.keys(experimental), ALLOWED_EXPERIMENTAL, `${HOME_EXPERIMENTAL_SECTION}.`, file);\n return new HomeConfig(\n this.readOptionalBoolean(experimental, HOME_KEY_BUILD_GATE_LOG_CAPTURE, file, GUARD_OFF_WHEN_ABSENT),\n this.readOptionalBoolean(experimental, HOME_KEY_WHOLE_REPO_BUILD_GUARD, file, WHOLE_REPO_BUILD_GUARD_DEFAULT),\n this.readOptionalBoolean(experimental, HOME_KEY_ORPHAN_DIR_SWEEP, file, GUARD_OFF_WHEN_ABSENT),\n );\n }\n\n /**\n * An absent key falls back to `whenAbsent`, which every caller states OUT LOUD — there is no implicit\n * \"absent means false\" any more, because `whole-repo-build-guard` defaults ON and a hidden default\n * would put the two halves of that fact in different files. A PRESENT key of the wrong type is still\n * an error: that is a file somebody wrote wrongly, not a file written for a different release. This\n * is the ONLY reader; see the every-key-is-optional note above for why there is no required variant.\n */\n // webpieces-disable no-any-unknown -- see parse()\n // eslint-disable-next-line @typescript-eslint/max-params\n private readOptionalBoolean(\n experimental: Record<string, unknown>, key: string, file: string, whenAbsent: boolean,\n ): boolean {\n const value = experimental[key];\n if (value === undefined) return whenAbsent;\n return this.asBoolean(value, key, file, ' Remove the quotes, or delete the key.');\n }\n\n // webpieces-disable no-any-unknown -- see parse()\n // eslint-disable-next-line @typescript-eslint/max-params\n private asBoolean(value: unknown, key: string, file: string, fix: string): boolean {\n if (typeof value !== 'boolean') {\n throw new InformAiError(this.error(file,\n `\"${HOME_EXPERIMENTAL_SECTION}.${key}\" must be the boolean ` +\n `true or false, not ${JSON.stringify(value)}.${fix}`));\n }\n return value;\n }\n\n // Retired keys are checked BEFORE unknown-key reporting: \"unknown key\" would send an agent deleting a\n // key whose value it should be MOVING, which is the whole reason the retirement table exists.\n // webpieces-disable no-any-unknown -- see parse()\n private assertNotRetired(raw: Record<string, unknown>, file: string): void {\n for (const entry of RETIRED_HOME_CONFIG_KEYS) {\n if (!this.isPresentAt(raw, entry.key)) continue;\n const destination = entry.movedTo === ''\n ? 'It was removed with no replacement.'\n : `It moved to \"${entry.movedTo}\".`;\n throw new InformAiError(this.error(file,\n `\"${entry.key}\" is RETIRED. ${destination} ${entry.instruction}`));\n }\n }\n\n // Is `dotted` (one or two segments — the file is two levels deep by construction) actually present?\n // webpieces-disable no-any-unknown -- see parse()\n private isPresentAt(raw: Record<string, unknown>, dotted: string): boolean {\n const parts = dotted.split('.');\n if (parts.length === 1) return raw[parts[0]] !== undefined;\n const section = raw[parts[0]];\n if (typeof section !== 'object' || section === null || Array.isArray(section)) return false;\n // webpieces-disable no-any-unknown -- narrowed to a non-null, non-array object one line above\n return (section as Record<string, unknown>)[parts[1]] !== undefined;\n }\n\n /**\n * Every accepted key, rendered from ALLOWED_EXPERIMENTAL rather than hand-listed. The hand-listed\n * version named two keys and went stale the moment a third arrived, telling an agent its brand-new\n * key was not accepted while the validator right above accepted it.\n */\n private quotedExperimentalKeys(): string {\n return ALLOWED_EXPERIMENTAL.map((key: string): string =>\n `\"${HOME_EXPERIMENTAL_SECTION}.${key}\"`).join(', ');\n }\n\n private assertKnownKeys(found: string[], allowed: readonly string[], prefix: string, file: string): void {\n for (const key of found) {\n if (allowed.includes(key)) continue;\n throw new InformAiError(this.error(file,\n `\"${prefix}${key}\" is not a known key.${this.didYouMean(key, allowed, prefix)} ` +\n `The only keys this file accepts are ` +\n `${this.quotedExperimentalKeys()}. ` +\n `Fix the spelling or delete the key.`));\n }\n }\n\n // A case-insensitive match is the overwhelmingly common typo and is worth naming outright.\n private didYouMean(key: string, allowed: readonly string[], prefix: string): string {\n for (const candidate of allowed) {\n if (candidate.toLowerCase() === key.toLowerCase()) return ` Did you mean \"${prefix}${candidate}\"?`;\n }\n return '';\n }\n\n // One shape for every rejection: what is wrong, in which file, and the fact that deleting the file is\n // always a legal fix — because the file is optional, and \"no file\" is a fully supported state.\n private error(file: string, detail: string): string {\n return `[~/.webpieces/config.json] ${detail}\\n\\n` +\n `File: ${file}\\n` +\n `This machine-local preference file is OPTIONAL and EXPERIMENTAL. Editing it is always ` +\n `permitted, even while it is invalid, and deleting it outright is a valid fix — with no such ` +\n `file every webpieces command behaves exactly as it does by default.`;\n }\n}\n"]}
|
package/src/index.d.ts
CHANGED
|
@@ -29,7 +29,7 @@ export { unknownKeyErrors, isCommentKey, validateTopLevelKeys, COMMENT_KEY_SUFFI
|
|
|
29
29
|
export { RETIRED_CONFIG_KEYS, RETIRED_SCOPE_KEY, RETIRED_SCOPE_RULE, RetiredConfigKey, isRetiredKey, retiredEntry, retiredKeyError, retiredKeyErrorsIn, retiredRuleFor } from './retired-config-keys';
|
|
30
30
|
export { ConfigPruner, PruneResult, PrunedKey } from './config-pruner';
|
|
31
31
|
export { validateChecklistDocs } from './checklist-docs-validator';
|
|
32
|
-
export { HomeConfig, HomeConfigService, RetiredHomeConfigKey, RETIRED_HOME_CONFIG_KEYS, HOME_CONFIG_DIR, HOME_CONFIG_FILE, HOME_EXPERIMENTAL_SECTION, HOME_KEY_BUILD_GATE_LOG_CAPTURE, HOME_KEY_ORPHAN_DIR_SWEEP, HOME_KEY_WHOLE_REPO_BUILD_GUARD, } from './home-config';
|
|
32
|
+
export { HomeConfig, HomeConfigService, RetiredHomeConfigKey, RETIRED_HOME_CONFIG_KEYS, HOME_CONFIG_DIR, HOME_CONFIG_FILE, HOME_EXPERIMENTAL_SECTION, HOME_KEY_BUILD_GATE_LOG_CAPTURE, HOME_KEY_ORPHAN_DIR_SWEEP, HOME_KEY_WHOLE_REPO_BUILD_GUARD, WHOLE_REPO_BUILD_GUARD_DEFAULT, } from './home-config';
|
|
33
33
|
export { OrphanDirScanner, OrphanCandidate } from './orphan-dir-scan';
|
|
34
34
|
export { OrphanDirArchiver, ArchivedOrphan, FailedOrphan, OrphanSweepResult, OrphanSweepManifest, TRASH_STATE_DIR, TRASH_MANIFEST_FILE, TRASH_RETENTION_DAYS, } from './orphan-dir-archive';
|
|
35
35
|
export { OrphanDirSweeper, OrphanSweepReport } from './orphan-dir-sweep';
|
package/src/index.js
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.RulesConfigDesign = exports.atRoot = exports.AtomicFile = exports.CLAUDE_PROJECT_DIR_UNSET = exports.CLAUDE_PROJECT_DIR_ENV = exports.claudeEnv = exports.ClaudeEnv = exports.RETENTION_DAYS = exports.SweepCount = exports.AgedTreeSweeper = exports.StateMigrationReport = exports.StateDirMigrator = exports.LOGS_STATE_DIR = exports.WORKTREE_STATE_DIR = exports.GitDirs = exports.dotWebpieces = exports.DotWebpieces = exports.INSTRUCT_AI_LEAF = exports.INSTRUCT_AI_DIR = exports.RepoRootFinder = exports.CONFIG_PARSE_RETRY_MILLIS = exports.CONFIG_PARSE_ATTEMPTS = exports.ConfigParseAttempt = exports.ConfigFile = exports.CONFIG_FILENAME = exports.findConfigFile = exports.SECTION_PLACEMENT_MARKER = exports.RETIRED_TOP_LEVEL_MARKER = exports.RETIRED_KEY_MARKER = exports.CONFIG_POLICY_DOC = exports.formatConfigErrorsBanner = exports.ConfigLoader = exports.LoadedConfig = exports.loadAndValidate = exports.toError = exports.runMain = exports.CliArgs = exports.CliArgsCheck = exports.CliArgSet = exports.CliFlag = exports.CliUsage = exports.CliExitError = exports.formatFixOptions = exports.Option = exports.renderRuleFailForHuman = exports.renderRuleFailForAi = exports.RuleFailError = exports.InformAiError = exports.ResolvedRuleConfig = exports.ResolvedConfig = void 0;
|
|
4
4
|
exports.HOME_KEY_WHOLE_REPO_BUILD_GUARD = exports.HOME_KEY_ORPHAN_DIR_SWEEP = exports.HOME_KEY_BUILD_GATE_LOG_CAPTURE = exports.HOME_EXPERIMENTAL_SECTION = exports.HOME_CONFIG_FILE = exports.HOME_CONFIG_DIR = exports.RETIRED_HOME_CONFIG_KEYS = exports.RetiredHomeConfigKey = exports.HomeConfigService = exports.HomeConfig = exports.validateChecklistDocs = exports.PrunedKey = exports.PruneResult = exports.ConfigPruner = exports.retiredRuleFor = exports.retiredKeyErrorsIn = exports.retiredKeyError = exports.retiredEntry = exports.isRetiredKey = exports.RetiredConfigKey = exports.RETIRED_SCOPE_RULE = exports.RETIRED_SCOPE_KEY = exports.RETIRED_CONFIG_KEYS = exports.COMMENT_KEY_SUFFIX = exports.validateTopLevelKeys = exports.isCommentKey = exports.unknownKeyErrors = exports.validateCommandsSection = exports.seedEntryForRule = exports.recommendedSeedModeFor = exports.recommendedSeedMode = exports.allRuleNames = exports.validateMatchRulesSection = exports.validateExcludePaths = exports.validateSectionPlacement = exports.validateChecklistsSection = exports.validatePrGateSection = exports.validateWebpiecesConfig = exports.TemplateWriter = exports.writeTemplate = exports.writeTemplateIfMissing = exports.loadTemplate = exports.defaultRulesDir = exports.defaultRules = exports.matchesAnyGlob = exports.isPathExcluded = exports.ExcludePaths = exports.DESIGN_METADATA_KEYS = exports.isDocumentDesign = exports.DocumentDesign = void 0;
|
|
5
|
-
exports.
|
|
6
|
-
exports.
|
|
7
|
-
exports.
|
|
8
|
-
exports.
|
|
9
|
-
exports.DEFAULT_MERGE_COMPLETE_COMMAND = exports.DEFAULT_UPSERT_PR_COMMAND = exports.buildCommandsConfig = exports.CommandsConfig = exports.logBranchMutation = exports.branchMutationLogPath = exports.BranchMutationLog = exports.BranchMutationEvent = exports.WorktreeReaper = exports.WorktreeReapResult = exports.ReapedWorktree = exports.BranchReaper = exports.ReapResult = exports.ReapedBranch = exports.WorktreeService = exports.Worktree = exports.BRANCH_RETENTION_KEEP = exports.BRANCH_RETENTION_ARCHIVE_TAG = exports.BRANCH_RETENTION_DELETE = exports.BRANCH_RETENTIONS = exports.ARCHIVE_TAG_PREFIX = exports.ArchiveResult = exports.BranchArchiver = exports.PROMPTABLE_CLASSIFICATIONS = exports.CLASSIFICATION_DETACHED = exports.CLASSIFICATION_CURRENT = exports.CLASSIFICATION_LOCKED = exports.CLASSIFICATION_PRUNABLE = exports.CLASSIFICATION_IN_USE = exports.CLASSIFICATION_NEVER_PROPOSED = exports.CLASSIFICATION_CONTENT_IN_MAIN = exports.CLASSIFICATION_SUPERSEDED = exports.CLASSIFICATION_NO_COMMITS = exports.CLASSIFICATION_BACKUP_OF_LIVE = exports.CLASSIFICATION_BACKUP_OF_MERGED = exports.CLASSIFICATION_MERGED_PR = exports.CACHE_STALE_AFTER_MS = exports.CacheFreshness = exports.MergedBranchesService = exports.MergedBranchesCache = exports.DeletableWorktree = exports.DeletableBranch = exports.MergedBranch = exports.squashRecoverySteps = exports.stampCleanMainSyncStatus = exports.computeMainSyncStatus = exports.finishedLock = exports.inProcessLock = void 0;
|
|
5
|
+
exports.MERGE_EXPLANATION_FILE = exports.MERGE_IN_PROGRESS_FILE = exports.PR_REVIEW_DIR = exports.MERGE_INFO_DIR = exports.WEBPIECES_TMP_DIR = exports.hasDisable = exports.RULE_NAMES = exports.WEBPIECES_DISABLE = exports.AbstractRule = exports.ChangedFilesOptions = exports.DiffRange = exports.DiffScope = exports.isNewOrModified = exports.hasChangesInRange = exports.findNewMethodSignaturesInDiff = exports.getChangedLineNumbers = exports.getFileDiff = exports.getChangedFiles = exports.resolveBase = exports.detectBase = exports.SkipRuleResult = exports.getCurrentBranch = exports.shouldSkipRule = exports.FieldDef = exports.sectionForRule = exports.isHookGuard = exports.PR_LIFECYCLE_GUARD_KEY = exports.BRANCH_STATE_GUARD_KEY = exports.HOOK_GUARD_NAMES = exports.schemaFieldNames = exports.DEFAULT_MATCH_RULES = exports.renderMatchRuleMessage = exports.compileMatchRulePatterns = exports.isMatchRuleAllowedPath = exports.findMatchRuleViolations = exports.MatchRuleViolation = exports.MatchRuleConfig = exports.OrphanSweepReport = exports.OrphanDirSweeper = exports.TRASH_RETENTION_DAYS = exports.TRASH_MANIFEST_FILE = exports.TRASH_STATE_DIR = exports.OrphanSweepManifest = exports.OrphanSweepResult = exports.FailedOrphan = exports.ArchivedOrphan = exports.OrphanDirArchiver = exports.OrphanCandidate = exports.OrphanDirScanner = exports.WHOLE_REPO_BUILD_GUARD_DEFAULT = void 0;
|
|
6
|
+
exports.PROJECT_MODES = exports.MODIFIED_CODE_MODES = exports.INLINE_TYPE_MODES = exports.RETURN_TYPE_MODES = exports.FILE_LIMIT_MODES = exports.METHOD_LIMIT_MODES = exports.BaseRuleConfig = exports.ValidateEslintSyncConfig = exports.ValidateVersionsLockedConfig = exports.ValidatePackageJsonConfig = exports.ValidateNoArchitectureCyclesConfig = exports.ValidateArchitectureUnchangedConfig = exports.ValidateTsInSrcConfig = exports.NoJsFilesConfig = exports.DiGraphConfig = exports.NxWiringConfig = exports.RuntimeArchitectureConfig = exports.NoFileImportCyclesConfig = exports.PrLifecycleGuardConfig = exports.BranchCreationGuardConfig = exports.RoleTagConfig = exports.FrameworkTagConfig = exports.InjectAnnotationNotNeededForConcreteClassConfig = exports.NoFunctionOutsideClassConfig = exports.NoProcessExitOutsideMainConfig = exports.NoCustomCssConfig = exports.NoSymbolDiTokensConfig = exports.AngularNoDirectApiInResolverConfig = exports.ThrowCauseRequiredConfig = exports.CatchErrorPatternConfig = exports.NoUnmanagedExceptionsConfig = exports.NoDestructureConfig = exports.PrismaConverterConfig = exports.PrismaValidateDtosConfig = exports.NoImplicitAnyConfig = exports.NoAnyUnknownConfig = exports.NoInlineTypeLiteralsConfig = exports.RequireReturnTypeConfig = exports.MaxFileLinesConfig = exports.MaxMethodLinesConfig = exports.WP_FINISH_PUSH_DEV = exports.WP_PUSH_DEV = exports.WP_FINISH_UPSERT_PR = exports.WP_START_UPSERT_PR = exports.WP_FINISH_UPDATE = exports.WP_START_UPDATE = exports.SyncFlowGuidance = exports.WebpiecesRulesConfig = exports.PRUNE_UNKNOWN_COMMAND = exports.PUSH_DEV_STATE_FILE = void 0;
|
|
7
|
+
exports.ProvenanceResult = exports.TranscriptScan = exports.ReviewerContext = exports.ReviewerEvidence = exports.SubagentProvenanceService = exports.verifyGateToken = exports.extractGateToken = exports.gateTokenMarker = exports.computeGateToken = exports.GateTokenService = exports.ALL_DIFF_ONE_READ_LINES = exports.READ_TRUNCATION_LINES = exports.ContextEntry = exports.BriefedFile = exports.ReviewerBriefing = exports.ReviewerInstructionsService = exports.ChecklistInstructionsService = exports.ChecklistValidator = exports.formatFileList = exports.normalizeChecklistDoc = exports.toChecklist = exports.ChecklistDefinition = exports.MERGE_MODES = exports.MERGE_MODE_NONE = exports.MERGE_MODE_AUTO = exports.buildDevDeployConfig = exports.buildLandPrConfig = exports.buildPrGateConfig = exports.defaultDevDeployConfig = exports.defaultLandPrConfig = exports.defaultPrGateConfig = exports.defaultGates = exports.ReviewContextEntry = exports.DEFAULT_DEV_BRANCH = exports.DEFAULT_DEV_BRANCH_NAMESPACE = exports.DevDeployConfig = exports.LandPrConfig = exports.DEFAULT_BUILD_COMMAND = exports.PrGateConfig = exports.GateDefinition = exports.BranchStateGuardConfig = exports.CLIENT_CREATION_SEVERITIES = exports.NoClientCreationOutsideServerOrClientConfig = exports.VALIDATE_TS_MODES = exports.STRUCTURAL_MODES = exports.ON_OFF_MODES = exports.THROW_CAUSE_MODES = exports.DIRECT_API_RESOLVER_MODES = exports.PRISMA_CONVERTER_MODES = exports.PRISMA_DTOS_MODES = void 0;
|
|
8
|
+
exports.isRefreshInProgress = exports.isLockStale = exports.writeMainSyncLock = exports.readMainSyncLock = exports.computeAllMainSyncStatuses = exports.writeMainSyncStatusFile = exports.writeMainSyncStatus = exports.readMainSyncStatusFile = exports.readMainSyncStatus = exports.mainSyncLockPath = exports.mainSyncStatusPath = exports.DEFAULT_HANG_TIMEOUT_MINUTES = exports.MainSyncStatusService = exports.MainSyncLock = exports.MAIN_SYNC_STATUS_VERSION = exports.PullRequestIndex = exports.MainSyncFileStore = exports.MainSyncStatusFile = exports.MainSyncStatus = exports.reviewJsonSchemaHint = exports.reviewJsonPath = exports.prDirFor = exports.loadReviewJson = exports.ReviewJsonService = exports.ChecklistReviewContext = exports.RequiredChecklist = exports.VERDICT_STATUSES = exports.VERDICT_RED = exports.VERDICT_YELLOW = exports.VERDICT_GREEN = exports.CK_BAD_FORMAT = exports.CK_MISSING = exports.CK_FAIL = exports.CK_OVERRIDDEN = exports.CK_WARN = exports.CK_PASS = exports.ChecklistVerdict = exports.ChecklistResult = exports.PrContext = exports.ReviewJson = exports.DEFAULT_RETENTION_DAYS = exports.ProvenanceWriteRequest = exports.OfferedContext = exports.ReviewerPaths = exports.ReviewerTranscript = exports.ReviewProvenance = exports.ReviewProvenanceService = exports.PROVENANCE_SKIPPED = exports.PROVENANCE_MISSING = exports.PROVENANCE_OK = void 0;
|
|
9
|
+
exports.DEFAULT_MERGE_COMPLETE_COMMAND = exports.DEFAULT_UPSERT_PR_COMMAND = exports.buildCommandsConfig = exports.CommandsConfig = exports.logBranchMutation = exports.branchMutationLogPath = exports.BranchMutationLog = exports.BranchMutationEvent = exports.WorktreeReaper = exports.WorktreeReapResult = exports.ReapedWorktree = exports.BranchReaper = exports.ReapResult = exports.ReapedBranch = exports.WorktreeService = exports.Worktree = exports.BRANCH_RETENTION_KEEP = exports.BRANCH_RETENTION_ARCHIVE_TAG = exports.BRANCH_RETENTION_DELETE = exports.BRANCH_RETENTIONS = exports.ARCHIVE_TAG_PREFIX = exports.ArchiveResult = exports.BranchArchiver = exports.PROMPTABLE_CLASSIFICATIONS = exports.CLASSIFICATION_DETACHED = exports.CLASSIFICATION_CURRENT = exports.CLASSIFICATION_LOCKED = exports.CLASSIFICATION_PRUNABLE = exports.CLASSIFICATION_IN_USE = exports.CLASSIFICATION_NEVER_PROPOSED = exports.CLASSIFICATION_CONTENT_IN_MAIN = exports.CLASSIFICATION_SUPERSEDED = exports.CLASSIFICATION_NO_COMMITS = exports.CLASSIFICATION_BACKUP_OF_LIVE = exports.CLASSIFICATION_BACKUP_OF_MERGED = exports.CLASSIFICATION_MERGED_PR = exports.CACHE_STALE_AFTER_MS = exports.CacheFreshness = exports.MergedBranchesService = exports.MergedBranchesCache = exports.DeletableWorktree = exports.DeletableBranch = exports.MergedBranch = exports.squashRecoverySteps = exports.stampCleanMainSyncStatus = exports.computeMainSyncStatus = exports.finishedLock = exports.inProcessLock = exports.tryAcquireMainSyncLock = void 0;
|
|
10
10
|
var types_1 = require("./types");
|
|
11
11
|
Object.defineProperty(exports, "ResolvedConfig", { enumerable: true, get: function () { return types_1.ResolvedConfig; } });
|
|
12
12
|
Object.defineProperty(exports, "ResolvedRuleConfig", { enumerable: true, get: function () { return types_1.ResolvedRuleConfig; } });
|
|
@@ -145,10 +145,11 @@ Object.defineProperty(exports, "PruneResult", { enumerable: true, get: function
|
|
|
145
145
|
Object.defineProperty(exports, "PrunedKey", { enumerable: true, get: function () { return config_pruner_1.PrunedKey; } });
|
|
146
146
|
var checklist_docs_validator_1 = require("./checklist-docs-validator");
|
|
147
147
|
Object.defineProperty(exports, "validateChecklistDocs", { enumerable: true, get: function () { return checklist_docs_validator_1.validateChecklistDocs; } });
|
|
148
|
-
//
|
|
149
|
-
//
|
|
150
|
-
//
|
|
151
|
-
//
|
|
148
|
+
// The OPTIONAL machine-local `~/.webpieces/config.json`: absent (the normal state for every consumer) means
|
|
149
|
+
// each key's declared default, silently; present means strictly validated, with its own retirement table.
|
|
150
|
+
// `isHomeConfigPath` is what grants the file its unconditional Write/Edit PASS in the hook guards, which is
|
|
151
|
+
// what keeps a rejection repairable. Its `experimental.*` keys are deliberately NOT advertised knobs — the one
|
|
152
|
+
// exception is `whole-repo-build-guard`, which is a supported OPT-OUT and defaults ON.
|
|
152
153
|
var home_config_1 = require("./home-config");
|
|
153
154
|
Object.defineProperty(exports, "HomeConfig", { enumerable: true, get: function () { return home_config_1.HomeConfig; } });
|
|
154
155
|
Object.defineProperty(exports, "HomeConfigService", { enumerable: true, get: function () { return home_config_1.HomeConfigService; } });
|
|
@@ -160,6 +161,7 @@ Object.defineProperty(exports, "HOME_EXPERIMENTAL_SECTION", { enumerable: true,
|
|
|
160
161
|
Object.defineProperty(exports, "HOME_KEY_BUILD_GATE_LOG_CAPTURE", { enumerable: true, get: function () { return home_config_1.HOME_KEY_BUILD_GATE_LOG_CAPTURE; } });
|
|
161
162
|
Object.defineProperty(exports, "HOME_KEY_ORPHAN_DIR_SWEEP", { enumerable: true, get: function () { return home_config_1.HOME_KEY_ORPHAN_DIR_SWEEP; } });
|
|
162
163
|
Object.defineProperty(exports, "HOME_KEY_WHOLE_REPO_BUILD_GUARD", { enumerable: true, get: function () { return home_config_1.HOME_KEY_WHOLE_REPO_BUILD_GUARD; } });
|
|
164
|
+
Object.defineProperty(exports, "WHOLE_REPO_BUILD_GUARD_DEFAULT", { enumerable: true, get: function () { return home_config_1.WHOLE_REPO_BUILD_GUARD_DEFAULT; } });
|
|
163
165
|
// The orphan-directory sweep: the corpse an `nx g move` leaves on every clone, which git cannot remove
|
|
164
166
|
// because an ignored dist/ or node_modules/ outlives every tracked file under it. See orphan-dir-scan.ts
|
|
165
167
|
// for why the predicate is git's own `clean -Xdn` answer rather than a hand-rolled ignore walk.
|
package/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/index.ts"],"names":[],"mappings":"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","sourcesContent":["export { ResolvedConfig, ResolvedRuleConfig, RuleOptions } from './types';\nexport { InformAiError } from './inform-ai-error';\nexport { RuleFailError, renderRuleFailForAi, renderRuleFailForHuman } from './rule-fail-error';\n// THE one representation of a cure, shared by RuleFailError (build-time) and FixHint (edit-time), plus\n// the one renderer that owns the \"Fix Option N:\" numbering and the \"(preferred)\" tag.\nexport { Option, formatFixOptions } from './fix-option';\nexport { CliExitError } from './cli-exit-error';\nexport { CliUsage, CliFlag, CliArgSet, CliArgsCheck, CliArgs } from './cli-args';\nexport { runMain } from './run-main';\nexport { toError } from './to-error';\nexport { loadAndValidate, LoadedConfig, ConfigLoader } from './load-config';\n// The validation-failure banner: ONE cure (edit the file), plus the marker phrases the validator\n// messages embed rather than re-type.\nexport {\n formatConfigErrorsBanner,\n CONFIG_POLICY_DOC,\n RETIRED_KEY_MARKER,\n RETIRED_TOP_LEVEL_MARKER,\n SECTION_PLACEMENT_MARKER,\n} from './config-error-banner';\nexport { findConfigFile, CONFIG_FILENAME, ConfigFile, ConfigParseAttempt, CONFIG_PARSE_ATTEMPTS, CONFIG_PARSE_RETRY_MILLIS } from './config-file';\n// The PARSED-BUT-UNVALIDATED config shape. Exported for readers that walk the file generically rather\n// than through the typed config (the pr-gate active-hatch dashboard section reads every rule's hatches).\nexport type { RawConfigFile } from './config-file';\nexport { RepoRootFinder, INSTRUCT_AI_DIR, INSTRUCT_AI_LEAF } from './repo-root';\n// The scoped `.webpieces` resolver. EVERY reader/writer of `.webpieces/...` goes through one of its two\n// named methods so the call site declares whether the state is repo-wide or worktree-private.\nexport { DotWebpieces, dotWebpieces, GitDirs, WORKTREE_STATE_DIR, LOGS_STATE_DIR } from './state-dir';\nexport { StateDirMigrator, StateMigrationReport } from './state-dir-migration';\n// There is NO machine-global state root. `MachineStateHome`/`StateHome`/`WEBPIECES_STATE_HOME` and the\n// `PrBodyStore` that used them are DELETED: the one artifact that needed a scope above the clone was the\n// gated squash body, and GitHub holds it now (it IS the PR description). Every `.webpieces` path a\n// webpieces tool writes is `{repo}/.webpieces`, resolved through `DotWebpieces` above. See\n// `decisions/0005-the-pr-description-is-the-merge-body.md`.\nexport { AgedTreeSweeper, SweepCount, RETENTION_DAYS } from './aged-tree-sweep';\nexport { ClaudeEnv, claudeEnv, CLAUDE_PROJECT_DIR_ENV, CLAUDE_PROJECT_DIR_UNSET } from './claude-env';\nexport { AtomicFile } from './atomic-file';\n// The ONE formatter for a remedy that must run in a named directory: `cd '<root>' && <command>`.\n// Single-quoted so a repo path containing a space is still runnable (and still un-smuggleable).\nexport { atRoot } from './at-root';\nexport { RulesConfigDesign } from './rules-config-design';\nexport { DocumentDesign, isDocumentDesign, DESIGN_METADATA_KEYS } from './di';\nexport { ExcludePaths } from './exclude-hook-paths';\nexport { isPathExcluded, matchesAnyGlob } from './exclude-paths';\nexport { defaultRules, defaultRulesDir } from './default-rules';\nexport { loadTemplate, writeTemplateIfMissing, writeTemplate, TemplateWriter } from './load-template';\nexport { validateWebpiecesConfig, validatePrGateSection, validateChecklistsSection, validateSectionPlacement, validateExcludePaths, validateMatchRulesSection, allRuleNames, recommendedSeedMode, recommendedSeedModeFor, seedEntryForRule } from './validate-config';\nexport { validateCommandsSection } from './commands-section-validators';\nexport { unknownKeyErrors, isCommentKey, validateTopLevelKeys, COMMENT_KEY_SUFFIX } from './config-key-rules';\n// The retired-key table + the no-back-compat policy it enforces. Exported so the installer can migrate\n// what the errors instruct, and so consumers can enumerate retirements.\nexport { RETIRED_CONFIG_KEYS, RETIRED_SCOPE_KEY, RETIRED_SCOPE_RULE, RetiredConfigKey, isRetiredKey, retiredEntry, retiredKeyError, retiredKeyErrorsIn, retiredRuleFor } from './retired-config-keys';\n// The MECHANICAL cure the unknown-rule error and the banner both name: strip every key no validator has a\n// schema for, so cleanliness is one command rather than a judgement call made while every Bash call is\n// blocked. `PRUNE_UNKNOWN_COMMAND` (constants.ts) is the single spelling of that command.\nexport { ConfigPruner, PruneResult, PrunedKey } from './config-pruner';\nexport { validateChecklistDocs } from './checklist-docs-validator';\n// EXPERIMENTAL, and deliberately NOT an advertised knob. The OPTIONAL machine-local `~/.webpieces/config.json`:\n// absent (the normal state for every consumer) means all-defaults, silently; present means strictly validated,\n// with its own retirement table. `isHomeConfigPath` is what grants the file its unconditional Write/Edit PASS\n// in the hook guards, which is what keeps a rejection repairable.\nexport {\n HomeConfig, HomeConfigService, RetiredHomeConfigKey, RETIRED_HOME_CONFIG_KEYS,\n HOME_CONFIG_DIR, HOME_CONFIG_FILE, HOME_EXPERIMENTAL_SECTION, HOME_KEY_BUILD_GATE_LOG_CAPTURE,\n HOME_KEY_ORPHAN_DIR_SWEEP, HOME_KEY_WHOLE_REPO_BUILD_GUARD,\n} from './home-config';\n// The orphan-directory sweep: the corpse an `nx g move` leaves on every clone, which git cannot remove\n// because an ignored dist/ or node_modules/ outlives every tracked file under it. See orphan-dir-scan.ts\n// for why the predicate is git's own `clean -Xdn` answer rather than a hand-rolled ignore walk.\nexport { OrphanDirScanner, OrphanCandidate } from './orphan-dir-scan';\nexport {\n OrphanDirArchiver, ArchivedOrphan, FailedOrphan, OrphanSweepResult, OrphanSweepManifest,\n TRASH_STATE_DIR, TRASH_MANIFEST_FILE, TRASH_RETENTION_DAYS,\n} from './orphan-dir-archive';\nexport { OrphanDirSweeper, OrphanSweepReport } from './orphan-dir-sweep';\nexport {\n MatchRuleConfig,\n MatchRuleViolation,\n findMatchRuleViolations,\n isMatchRuleAllowedPath,\n compileMatchRulePatterns,\n renderMatchRuleMessage,\n DEFAULT_MATCH_RULES,\n} from './match-rules-config';\nexport type { ConfigSection } from './sections';\nexport { schemaFieldNames } from './rule-schemas';\nexport { HOOK_GUARD_NAMES, BRANCH_STATE_GUARD_KEY, PR_LIFECYCLE_GUARD_KEY, isHookGuard, sectionForRule } from './sections';\nexport { FieldDef } from './field-def';\nexport type { SchemaShape } from './field-def';\nexport { shouldSkipRule, getCurrentBranch } from './skip-rule';\nexport { SkipRuleResult } from './skip-rule';\nexport {\n detectBase,\n resolveBase,\n getChangedFiles,\n getFileDiff,\n getChangedLineNumbers,\n findNewMethodSignaturesInDiff,\n hasChangesInRange,\n isNewOrModified,\n DiffScope,\n DiffRange,\n ChangedFilesOptions,\n} from './diff-scope';\nexport { AbstractRule } from './abstract-rule';\nexport {\n WEBPIECES_DISABLE,\n RULE_NAMES,\n hasDisable,\n WEBPIECES_TMP_DIR,\n MERGE_INFO_DIR,\n PR_REVIEW_DIR,\n MERGE_IN_PROGRESS_FILE,\n MERGE_EXPLANATION_FILE,\n PUSH_DEV_STATE_FILE,\n PRUNE_UNKNOWN_COMMAND,\n} from './constants';\nexport { WebpiecesRulesConfig } from './WebpiecesRulesConfig';\nexport {\n SyncFlowGuidance,\n WP_START_UPDATE,\n WP_FINISH_UPDATE,\n WP_START_UPSERT_PR,\n WP_FINISH_UPSERT_PR,\n WP_PUSH_DEV,\n WP_FINISH_PUSH_DEV,\n} from './sync-flow-guidance';\nexport {\n MaxMethodLinesConfig,\n MaxFileLinesConfig,\n RequireReturnTypeConfig,\n NoInlineTypeLiteralsConfig,\n NoAnyUnknownConfig,\n NoImplicitAnyConfig,\n PrismaValidateDtosConfig,\n PrismaConverterConfig,\n NoDestructureConfig,\n NoUnmanagedExceptionsConfig,\n CatchErrorPatternConfig,\n ThrowCauseRequiredConfig,\n AngularNoDirectApiInResolverConfig,\n NoSymbolDiTokensConfig,\n NoCustomCssConfig,\n NoProcessExitOutsideMainConfig,\n NoFunctionOutsideClassConfig,\n InjectAnnotationNotNeededForConcreteClassConfig,\n FrameworkTagConfig,\n RoleTagConfig,\n BranchCreationGuardConfig,\n PrLifecycleGuardConfig,\n NoFileImportCyclesConfig,\n RuntimeArchitectureConfig,\n NxWiringConfig,\n DiGraphConfig,\n NoJsFilesConfig,\n ValidateTsInSrcConfig,\n ValidateArchitectureUnchangedConfig,\n ValidateNoArchitectureCyclesConfig,\n ValidatePackageJsonConfig,\n ValidateVersionsLockedConfig,\n ValidateEslintSyncConfig,\n BaseRuleConfig,\n} from './rule-configs';\n// Mode unions + their value arrays — the single source of truth shared with code-rules.\nexport {\n METHOD_LIMIT_MODES,\n FILE_LIMIT_MODES,\n RETURN_TYPE_MODES,\n INLINE_TYPE_MODES,\n MODIFIED_CODE_MODES,\n PROJECT_MODES,\n PRISMA_DTOS_MODES,\n PRISMA_CONVERTER_MODES,\n DIRECT_API_RESOLVER_MODES,\n THROW_CAUSE_MODES,\n ON_OFF_MODES,\n STRUCTURAL_MODES,\n VALIDATE_TS_MODES,\n} from './rule-configs';\nexport {\n NoClientCreationOutsideServerOrClientConfig,\n CLIENT_CREATION_SEVERITIES,\n} from './no-client-creation-config';\nexport type { ClientCreationSeverity } from './no-client-creation-config';\nexport type {\n MethodLimitMode,\n FileLimitMode,\n ReturnTypeMode,\n InlineTypeMode,\n ModifiedCodeMode,\n ProjectMode,\n PrismaValidateDtosMode,\n PrismaConverterMode,\n DirectApiResolverMode,\n ThrowCauseMode,\n OnOffMode,\n StructuralMode,\n ValidateTsMode,\n} from './rule-configs';\nexport {\n BranchStateGuardConfig,\n} from './main-sync-guard-configs';\nexport {\n GateDefinition,\n PrGateConfig,\n DEFAULT_BUILD_COMMAND,\n LandPrConfig,\n DevDeployConfig,\n DEFAULT_DEV_BRANCH_NAMESPACE,\n DEFAULT_DEV_BRANCH,\n ReviewContextEntry,\n defaultGates,\n defaultPrGateConfig,\n defaultLandPrConfig,\n defaultDevDeployConfig,\n buildPrGateConfig,\n buildLandPrConfig,\n buildDevDeployConfig,\n MERGE_MODE_AUTO,\n MERGE_MODE_NONE,\n MERGE_MODES,\n} from './pr-gate-config';\nexport {\n ChecklistDefinition,\n toChecklist,\n normalizeChecklistDoc,\n formatFileList,\n} from './checklist-config';\nexport type { RawChecklistItem } from './checklist-config';\nexport { ChecklistValidator } from './checklist-validator';\nexport { ChecklistInstructionsService } from './checklist-instructions';\nexport {\n ReviewerInstructionsService,\n ReviewerBriefing,\n BriefedFile,\n ContextEntry,\n READ_TRUNCATION_LINES,\n ALL_DIFF_ONE_READ_LINES,\n} from './reviewer-instructions';\nexport {\n GateTokenService,\n computeGateToken,\n gateTokenMarker,\n extractGateToken,\n verifyGateToken,\n} from './gate-token';\nexport {\n SubagentProvenanceService,\n ReviewerEvidence,\n ReviewerContext,\n TranscriptScan,\n ProvenanceResult,\n PROVENANCE_OK,\n PROVENANCE_MISSING,\n PROVENANCE_SKIPPED,\n} from './subagent-provenance';\nexport {\n ReviewProvenanceService,\n ReviewProvenance,\n ReviewerTranscript,\n ReviewerPaths,\n OfferedContext,\n ProvenanceWriteRequest,\n DEFAULT_RETENTION_DAYS,\n} from './review-provenance';\nexport {\n ReviewJson,\n PrContext,\n ChecklistResult,\n ChecklistVerdict,\n CK_PASS,\n CK_WARN,\n CK_OVERRIDDEN,\n CK_FAIL,\n CK_MISSING,\n CK_BAD_FORMAT,\n VERDICT_GREEN,\n VERDICT_YELLOW,\n VERDICT_RED,\n VERDICT_STATUSES,\n RequiredChecklist,\n ChecklistReviewContext,\n ReviewJsonService,\n loadReviewJson,\n prDirFor,\n reviewJsonPath,\n reviewJsonSchemaHint,\n} from './review-json';\nexport {\n MainSyncStatus,\n MainSyncStatusFile,\n MainSyncFileStore,\n PullRequestIndex,\n MAIN_SYNC_STATUS_VERSION,\n} from './main-sync-file';\nexport {\n MainSyncLock,\n MainSyncStatusService,\n DEFAULT_HANG_TIMEOUT_MINUTES,\n mainSyncStatusPath,\n mainSyncLockPath,\n readMainSyncStatus,\n readMainSyncStatusFile,\n writeMainSyncStatus,\n writeMainSyncStatusFile,\n computeAllMainSyncStatuses,\n readMainSyncLock,\n writeMainSyncLock,\n isLockStale,\n isRefreshInProgress,\n tryAcquireMainSyncLock,\n inProcessLock,\n finishedLock,\n computeMainSyncStatus,\n stampCleanMainSyncStatus,\n squashRecoverySteps,\n} from './main-sync-status';\nexport {\n MergedBranch,\n DeletableBranch,\n DeletableWorktree,\n MergedBranchesCache,\n MergedBranchesService,\n CacheFreshness,\n CACHE_STALE_AFTER_MS,\n CLASSIFICATION_MERGED_PR,\n CLASSIFICATION_BACKUP_OF_MERGED,\n CLASSIFICATION_BACKUP_OF_LIVE,\n CLASSIFICATION_NO_COMMITS,\n CLASSIFICATION_SUPERSEDED,\n CLASSIFICATION_CONTENT_IN_MAIN,\n CLASSIFICATION_NEVER_PROPOSED,\n CLASSIFICATION_IN_USE,\n CLASSIFICATION_PRUNABLE,\n CLASSIFICATION_LOCKED,\n CLASSIFICATION_CURRENT,\n CLASSIFICATION_DETACHED,\n PROMPTABLE_CLASSIFICATIONS,\n} from './merged-branches';\nexport {\n BranchArchiver,\n ArchiveResult,\n ARCHIVE_TAG_PREFIX,\n BRANCH_RETENTIONS,\n BRANCH_RETENTION_DELETE,\n BRANCH_RETENTION_ARCHIVE_TAG,\n BRANCH_RETENTION_KEEP,\n} from './branch-archiver';\nexport {\n Worktree,\n WorktreeService,\n} from './worktrees';\nexport {\n ReapedBranch,\n ReapResult,\n BranchReaper,\n} from './branch-reaper';\nexport {\n ReapedWorktree,\n WorktreeReapResult,\n WorktreeReaper,\n} from './worktree-reaper';\nexport type { MutationVerb, MutationPhase } from './branch-mutation-log';\nexport {\n BranchMutationEvent,\n BranchMutationLog,\n branchMutationLogPath,\n logBranchMutation,\n} from './branch-mutation-log';\nexport {\n CommandsConfig,\n buildCommandsConfig,\n DEFAULT_UPSERT_PR_COMMAND,\n DEFAULT_MERGE_COMPLETE_COMMAND,\n} from './commands-config';\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/index.ts"],"names":[],"mappings":"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","sourcesContent":["export { ResolvedConfig, ResolvedRuleConfig, RuleOptions } from './types';\nexport { InformAiError } from './inform-ai-error';\nexport { RuleFailError, renderRuleFailForAi, renderRuleFailForHuman } from './rule-fail-error';\n// THE one representation of a cure, shared by RuleFailError (build-time) and FixHint (edit-time), plus\n// the one renderer that owns the \"Fix Option N:\" numbering and the \"(preferred)\" tag.\nexport { Option, formatFixOptions } from './fix-option';\nexport { CliExitError } from './cli-exit-error';\nexport { CliUsage, CliFlag, CliArgSet, CliArgsCheck, CliArgs } from './cli-args';\nexport { runMain } from './run-main';\nexport { toError } from './to-error';\nexport { loadAndValidate, LoadedConfig, ConfigLoader } from './load-config';\n// The validation-failure banner: ONE cure (edit the file), plus the marker phrases the validator\n// messages embed rather than re-type.\nexport {\n formatConfigErrorsBanner,\n CONFIG_POLICY_DOC,\n RETIRED_KEY_MARKER,\n RETIRED_TOP_LEVEL_MARKER,\n SECTION_PLACEMENT_MARKER,\n} from './config-error-banner';\nexport { findConfigFile, CONFIG_FILENAME, ConfigFile, ConfigParseAttempt, CONFIG_PARSE_ATTEMPTS, CONFIG_PARSE_RETRY_MILLIS } from './config-file';\n// The PARSED-BUT-UNVALIDATED config shape. Exported for readers that walk the file generically rather\n// than through the typed config (the pr-gate active-hatch dashboard section reads every rule's hatches).\nexport type { RawConfigFile } from './config-file';\nexport { RepoRootFinder, INSTRUCT_AI_DIR, INSTRUCT_AI_LEAF } from './repo-root';\n// The scoped `.webpieces` resolver. EVERY reader/writer of `.webpieces/...` goes through one of its two\n// named methods so the call site declares whether the state is repo-wide or worktree-private.\nexport { DotWebpieces, dotWebpieces, GitDirs, WORKTREE_STATE_DIR, LOGS_STATE_DIR } from './state-dir';\nexport { StateDirMigrator, StateMigrationReport } from './state-dir-migration';\n// There is NO machine-global state root. `MachineStateHome`/`StateHome`/`WEBPIECES_STATE_HOME` and the\n// `PrBodyStore` that used them are DELETED: the one artifact that needed a scope above the clone was the\n// gated squash body, and GitHub holds it now (it IS the PR description). Every `.webpieces` path a\n// webpieces tool writes is `{repo}/.webpieces`, resolved through `DotWebpieces` above. See\n// `decisions/0005-the-pr-description-is-the-merge-body.md`.\nexport { AgedTreeSweeper, SweepCount, RETENTION_DAYS } from './aged-tree-sweep';\nexport { ClaudeEnv, claudeEnv, CLAUDE_PROJECT_DIR_ENV, CLAUDE_PROJECT_DIR_UNSET } from './claude-env';\nexport { AtomicFile } from './atomic-file';\n// The ONE formatter for a remedy that must run in a named directory: `cd '<root>' && <command>`.\n// Single-quoted so a repo path containing a space is still runnable (and still un-smuggleable).\nexport { atRoot } from './at-root';\nexport { RulesConfigDesign } from './rules-config-design';\nexport { DocumentDesign, isDocumentDesign, DESIGN_METADATA_KEYS } from './di';\nexport { ExcludePaths } from './exclude-hook-paths';\nexport { isPathExcluded, matchesAnyGlob } from './exclude-paths';\nexport { defaultRules, defaultRulesDir } from './default-rules';\nexport { loadTemplate, writeTemplateIfMissing, writeTemplate, TemplateWriter } from './load-template';\nexport { validateWebpiecesConfig, validatePrGateSection, validateChecklistsSection, validateSectionPlacement, validateExcludePaths, validateMatchRulesSection, allRuleNames, recommendedSeedMode, recommendedSeedModeFor, seedEntryForRule } from './validate-config';\nexport { validateCommandsSection } from './commands-section-validators';\nexport { unknownKeyErrors, isCommentKey, validateTopLevelKeys, COMMENT_KEY_SUFFIX } from './config-key-rules';\n// The retired-key table + the no-back-compat policy it enforces. Exported so the installer can migrate\n// what the errors instruct, and so consumers can enumerate retirements.\nexport { RETIRED_CONFIG_KEYS, RETIRED_SCOPE_KEY, RETIRED_SCOPE_RULE, RetiredConfigKey, isRetiredKey, retiredEntry, retiredKeyError, retiredKeyErrorsIn, retiredRuleFor } from './retired-config-keys';\n// The MECHANICAL cure the unknown-rule error and the banner both name: strip every key no validator has a\n// schema for, so cleanliness is one command rather than a judgement call made while every Bash call is\n// blocked. `PRUNE_UNKNOWN_COMMAND` (constants.ts) is the single spelling of that command.\nexport { ConfigPruner, PruneResult, PrunedKey } from './config-pruner';\nexport { validateChecklistDocs } from './checklist-docs-validator';\n// The OPTIONAL machine-local `~/.webpieces/config.json`: absent (the normal state for every consumer) means\n// each key's declared default, silently; present means strictly validated, with its own retirement table.\n// `isHomeConfigPath` is what grants the file its unconditional Write/Edit PASS in the hook guards, which is\n// what keeps a rejection repairable. Its `experimental.*` keys are deliberately NOT advertised knobs — the one\n// exception is `whole-repo-build-guard`, which is a supported OPT-OUT and defaults ON.\nexport {\n HomeConfig, HomeConfigService, RetiredHomeConfigKey, RETIRED_HOME_CONFIG_KEYS,\n HOME_CONFIG_DIR, HOME_CONFIG_FILE, HOME_EXPERIMENTAL_SECTION, HOME_KEY_BUILD_GATE_LOG_CAPTURE,\n HOME_KEY_ORPHAN_DIR_SWEEP, HOME_KEY_WHOLE_REPO_BUILD_GUARD, WHOLE_REPO_BUILD_GUARD_DEFAULT,\n} from './home-config';\n// The orphan-directory sweep: the corpse an `nx g move` leaves on every clone, which git cannot remove\n// because an ignored dist/ or node_modules/ outlives every tracked file under it. See orphan-dir-scan.ts\n// for why the predicate is git's own `clean -Xdn` answer rather than a hand-rolled ignore walk.\nexport { OrphanDirScanner, OrphanCandidate } from './orphan-dir-scan';\nexport {\n OrphanDirArchiver, ArchivedOrphan, FailedOrphan, OrphanSweepResult, OrphanSweepManifest,\n TRASH_STATE_DIR, TRASH_MANIFEST_FILE, TRASH_RETENTION_DAYS,\n} from './orphan-dir-archive';\nexport { OrphanDirSweeper, OrphanSweepReport } from './orphan-dir-sweep';\nexport {\n MatchRuleConfig,\n MatchRuleViolation,\n findMatchRuleViolations,\n isMatchRuleAllowedPath,\n compileMatchRulePatterns,\n renderMatchRuleMessage,\n DEFAULT_MATCH_RULES,\n} from './match-rules-config';\nexport type { ConfigSection } from './sections';\nexport { schemaFieldNames } from './rule-schemas';\nexport { HOOK_GUARD_NAMES, BRANCH_STATE_GUARD_KEY, PR_LIFECYCLE_GUARD_KEY, isHookGuard, sectionForRule } from './sections';\nexport { FieldDef } from './field-def';\nexport type { SchemaShape } from './field-def';\nexport { shouldSkipRule, getCurrentBranch } from './skip-rule';\nexport { SkipRuleResult } from './skip-rule';\nexport {\n detectBase,\n resolveBase,\n getChangedFiles,\n getFileDiff,\n getChangedLineNumbers,\n findNewMethodSignaturesInDiff,\n hasChangesInRange,\n isNewOrModified,\n DiffScope,\n DiffRange,\n ChangedFilesOptions,\n} from './diff-scope';\nexport { AbstractRule } from './abstract-rule';\nexport {\n WEBPIECES_DISABLE,\n RULE_NAMES,\n hasDisable,\n WEBPIECES_TMP_DIR,\n MERGE_INFO_DIR,\n PR_REVIEW_DIR,\n MERGE_IN_PROGRESS_FILE,\n MERGE_EXPLANATION_FILE,\n PUSH_DEV_STATE_FILE,\n PRUNE_UNKNOWN_COMMAND,\n} from './constants';\nexport { WebpiecesRulesConfig } from './WebpiecesRulesConfig';\nexport {\n SyncFlowGuidance,\n WP_START_UPDATE,\n WP_FINISH_UPDATE,\n WP_START_UPSERT_PR,\n WP_FINISH_UPSERT_PR,\n WP_PUSH_DEV,\n WP_FINISH_PUSH_DEV,\n} from './sync-flow-guidance';\nexport {\n MaxMethodLinesConfig,\n MaxFileLinesConfig,\n RequireReturnTypeConfig,\n NoInlineTypeLiteralsConfig,\n NoAnyUnknownConfig,\n NoImplicitAnyConfig,\n PrismaValidateDtosConfig,\n PrismaConverterConfig,\n NoDestructureConfig,\n NoUnmanagedExceptionsConfig,\n CatchErrorPatternConfig,\n ThrowCauseRequiredConfig,\n AngularNoDirectApiInResolverConfig,\n NoSymbolDiTokensConfig,\n NoCustomCssConfig,\n NoProcessExitOutsideMainConfig,\n NoFunctionOutsideClassConfig,\n InjectAnnotationNotNeededForConcreteClassConfig,\n FrameworkTagConfig,\n RoleTagConfig,\n BranchCreationGuardConfig,\n PrLifecycleGuardConfig,\n NoFileImportCyclesConfig,\n RuntimeArchitectureConfig,\n NxWiringConfig,\n DiGraphConfig,\n NoJsFilesConfig,\n ValidateTsInSrcConfig,\n ValidateArchitectureUnchangedConfig,\n ValidateNoArchitectureCyclesConfig,\n ValidatePackageJsonConfig,\n ValidateVersionsLockedConfig,\n ValidateEslintSyncConfig,\n BaseRuleConfig,\n} from './rule-configs';\n// Mode unions + their value arrays — the single source of truth shared with code-rules.\nexport {\n METHOD_LIMIT_MODES,\n FILE_LIMIT_MODES,\n RETURN_TYPE_MODES,\n INLINE_TYPE_MODES,\n MODIFIED_CODE_MODES,\n PROJECT_MODES,\n PRISMA_DTOS_MODES,\n PRISMA_CONVERTER_MODES,\n DIRECT_API_RESOLVER_MODES,\n THROW_CAUSE_MODES,\n ON_OFF_MODES,\n STRUCTURAL_MODES,\n VALIDATE_TS_MODES,\n} from './rule-configs';\nexport {\n NoClientCreationOutsideServerOrClientConfig,\n CLIENT_CREATION_SEVERITIES,\n} from './no-client-creation-config';\nexport type { ClientCreationSeverity } from './no-client-creation-config';\nexport type {\n MethodLimitMode,\n FileLimitMode,\n ReturnTypeMode,\n InlineTypeMode,\n ModifiedCodeMode,\n ProjectMode,\n PrismaValidateDtosMode,\n PrismaConverterMode,\n DirectApiResolverMode,\n ThrowCauseMode,\n OnOffMode,\n StructuralMode,\n ValidateTsMode,\n} from './rule-configs';\nexport {\n BranchStateGuardConfig,\n} from './main-sync-guard-configs';\nexport {\n GateDefinition,\n PrGateConfig,\n DEFAULT_BUILD_COMMAND,\n LandPrConfig,\n DevDeployConfig,\n DEFAULT_DEV_BRANCH_NAMESPACE,\n DEFAULT_DEV_BRANCH,\n ReviewContextEntry,\n defaultGates,\n defaultPrGateConfig,\n defaultLandPrConfig,\n defaultDevDeployConfig,\n buildPrGateConfig,\n buildLandPrConfig,\n buildDevDeployConfig,\n MERGE_MODE_AUTO,\n MERGE_MODE_NONE,\n MERGE_MODES,\n} from './pr-gate-config';\nexport {\n ChecklistDefinition,\n toChecklist,\n normalizeChecklistDoc,\n formatFileList,\n} from './checklist-config';\nexport type { RawChecklistItem } from './checklist-config';\nexport { ChecklistValidator } from './checklist-validator';\nexport { ChecklistInstructionsService } from './checklist-instructions';\nexport {\n ReviewerInstructionsService,\n ReviewerBriefing,\n BriefedFile,\n ContextEntry,\n READ_TRUNCATION_LINES,\n ALL_DIFF_ONE_READ_LINES,\n} from './reviewer-instructions';\nexport {\n GateTokenService,\n computeGateToken,\n gateTokenMarker,\n extractGateToken,\n verifyGateToken,\n} from './gate-token';\nexport {\n SubagentProvenanceService,\n ReviewerEvidence,\n ReviewerContext,\n TranscriptScan,\n ProvenanceResult,\n PROVENANCE_OK,\n PROVENANCE_MISSING,\n PROVENANCE_SKIPPED,\n} from './subagent-provenance';\nexport {\n ReviewProvenanceService,\n ReviewProvenance,\n ReviewerTranscript,\n ReviewerPaths,\n OfferedContext,\n ProvenanceWriteRequest,\n DEFAULT_RETENTION_DAYS,\n} from './review-provenance';\nexport {\n ReviewJson,\n PrContext,\n ChecklistResult,\n ChecklistVerdict,\n CK_PASS,\n CK_WARN,\n CK_OVERRIDDEN,\n CK_FAIL,\n CK_MISSING,\n CK_BAD_FORMAT,\n VERDICT_GREEN,\n VERDICT_YELLOW,\n VERDICT_RED,\n VERDICT_STATUSES,\n RequiredChecklist,\n ChecklistReviewContext,\n ReviewJsonService,\n loadReviewJson,\n prDirFor,\n reviewJsonPath,\n reviewJsonSchemaHint,\n} from './review-json';\nexport {\n MainSyncStatus,\n MainSyncStatusFile,\n MainSyncFileStore,\n PullRequestIndex,\n MAIN_SYNC_STATUS_VERSION,\n} from './main-sync-file';\nexport {\n MainSyncLock,\n MainSyncStatusService,\n DEFAULT_HANG_TIMEOUT_MINUTES,\n mainSyncStatusPath,\n mainSyncLockPath,\n readMainSyncStatus,\n readMainSyncStatusFile,\n writeMainSyncStatus,\n writeMainSyncStatusFile,\n computeAllMainSyncStatuses,\n readMainSyncLock,\n writeMainSyncLock,\n isLockStale,\n isRefreshInProgress,\n tryAcquireMainSyncLock,\n inProcessLock,\n finishedLock,\n computeMainSyncStatus,\n stampCleanMainSyncStatus,\n squashRecoverySteps,\n} from './main-sync-status';\nexport {\n MergedBranch,\n DeletableBranch,\n DeletableWorktree,\n MergedBranchesCache,\n MergedBranchesService,\n CacheFreshness,\n CACHE_STALE_AFTER_MS,\n CLASSIFICATION_MERGED_PR,\n CLASSIFICATION_BACKUP_OF_MERGED,\n CLASSIFICATION_BACKUP_OF_LIVE,\n CLASSIFICATION_NO_COMMITS,\n CLASSIFICATION_SUPERSEDED,\n CLASSIFICATION_CONTENT_IN_MAIN,\n CLASSIFICATION_NEVER_PROPOSED,\n CLASSIFICATION_IN_USE,\n CLASSIFICATION_PRUNABLE,\n CLASSIFICATION_LOCKED,\n CLASSIFICATION_CURRENT,\n CLASSIFICATION_DETACHED,\n PROMPTABLE_CLASSIFICATIONS,\n} from './merged-branches';\nexport {\n BranchArchiver,\n ArchiveResult,\n ARCHIVE_TAG_PREFIX,\n BRANCH_RETENTIONS,\n BRANCH_RETENTION_DELETE,\n BRANCH_RETENTION_ARCHIVE_TAG,\n BRANCH_RETENTION_KEEP,\n} from './branch-archiver';\nexport {\n Worktree,\n WorktreeService,\n} from './worktrees';\nexport {\n ReapedBranch,\n ReapResult,\n BranchReaper,\n} from './branch-reaper';\nexport {\n ReapedWorktree,\n WorktreeReapResult,\n WorktreeReaper,\n} from './worktree-reaper';\nexport type { MutationVerb, MutationPhase } from './branch-mutation-log';\nexport {\n BranchMutationEvent,\n BranchMutationLog,\n branchMutationLogPath,\n logBranchMutation,\n} from './branch-mutation-log';\nexport {\n CommandsConfig,\n buildCommandsConfig,\n DEFAULT_UPSERT_PR_COMMAND,\n DEFAULT_MERGE_COMPLETE_COMMAND,\n} from './commands-config';\n"]}
|
|
@@ -128,15 +128,15 @@ exports.RETIRED_CONFIG_KEYS = [
|
|
|
128
128
|
'only, use that rule\'s own "excludePaths" inside its config block instead.', '[excludePaths]', false),
|
|
129
129
|
// --- whole-repo-build-guard, retired as a REPO-CONFIG key one release after it was added. It shipped
|
|
130
130
|
// as a conventional validated guard (mode ON by default, entry REQUIRED under hookGuards), so every
|
|
131
|
-
// consumer that upgraded hit fault Y — every Bash call blocked — for
|
|
132
|
-
//
|
|
133
|
-
//
|
|
134
|
-
// to
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
'
|
|
138
|
-
'
|
|
139
|
-
'
|
|
131
|
+
// consumer that upgraded hit fault Y — every Bash call blocked — for a feature nobody had opted into.
|
|
132
|
+
// The REQUIRED KEY was the fault, not the default: the failure was at config LOAD, before any command
|
|
133
|
+
// was judged. The switch now lives ONLY in the optional machine-local ~/.webpieces/config.json, where
|
|
134
|
+
// nothing has to be added to be in the default state — and the default is ON again, so deleting this
|
|
135
|
+
// entry loses nothing.
|
|
136
|
+
new RetiredConfigKey(exports.RETIRED_SCOPE_RULE, 'whole-repo-build-guard', '~/.webpieces/config.json → experimental.whole-repo-build-guard', 'DELETE this entry from webpieces.config.json — no repo config key controls this guard any more. ' +
|
|
137
|
+
'The guard is ON by default for everyone, with no file and no key required. To turn it OFF for ' +
|
|
138
|
+
'YOUR machine only, put {"experimental": {"whole-repo-build-guard": false}} in ' +
|
|
139
|
+
'~/.webpieces/config.json — that file is optional and is tracked by no repo.', '[whole-repo-build-guard]', true),
|
|
140
140
|
// --- THE 9 → 3 COLLAPSE of `hookGuards`: one key per POLICY, not one per implementation CLASS.
|
|
141
141
|
//
|
|
142
142
|
// Eight class-named keys become two policy keys. The CLASSES are untouched — `feature-branch-guard`
|
|
@@ -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 an experimental feature nobody\n // had opted into. The switch now lives ONLY in the optional machine-local ~/.webpieces/config.json,\n // whose absent state is byte-for-byte the old behaviour. A repo that never added the entry has nothing\n // to do; a repo that added it to escape fault Y is told right here to take it back out.\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 'and with the entry gone the guard is silently off for everyone in this repo. To switch it on for ' +\n 'YOUR machine only, put {\"experimental\": {\"whole-repo-build-guard\": true}} in ' +\n '~/.webpieces/config.json — that file is optional, is tracked by no repo, and every webpieces ' +\n 'command behaves exactly as it does by default when it does not exist.',\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 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"]}
|
package/src/rule-configs.js
CHANGED
|
@@ -399,9 +399,9 @@ class PrLifecycleGuardConfig extends BaseRuleConfig {
|
|
|
399
399
|
};
|
|
400
400
|
}
|
|
401
401
|
exports.PrLifecycleGuardConfig = PrLifecycleGuardConfig;
|
|
402
|
-
// NOTE: there is deliberately no `WholeRepoBuildGuardConfig`. That guard
|
|
403
|
-
//
|
|
404
|
-
// machine-local ~/.webpieces/config.json (see home-config.ts)
|
|
402
|
+
// NOTE: there is deliberately no `WholeRepoBuildGuardConfig`. That guard has NO webpieces.config.json
|
|
403
|
+
// entry — it is ON by default, and its only switch is the OPT-OUT `experimental.whole-repo-build-guard`
|
|
404
|
+
// in the optional machine-local ~/.webpieces/config.json (see home-config.ts). The build command it prints
|
|
405
405
|
// is handed to it directly from `commands.pr-gate.buildCommand` by ai-hook-rules' runner. Re-adding a
|
|
406
406
|
// config class here puts the guard back in RULE_SCHEMAS and makes it a fault-Y rule again.
|
|
407
407
|
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 is EXPERIMENTAL and has NO\n// webpieces.config.json entry — its only switch is `experimental.whole-repo-build-guard` in the optional\n// machine-local ~/.webpieces/config.json (see home-config.ts), and the affected-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":"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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"]}
|
package/src/sections.d.ts
CHANGED
|
@@ -22,8 +22,8 @@ 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
|
-
* ai-hook-rules runs it outside the config-driven rule set entirely.
|
|
25
|
+
* RETIRED_CONFIG_KEYS). It is ON by default for every tree, with a machine-local OPT-OUT in
|
|
26
|
+
* ~/.webpieces/config.json, and ai-hook-rules runs it outside the config-driven rule set entirely.
|
|
27
27
|
*/
|
|
28
28
|
/**
|
|
29
29
|
* The two POLICY keys shared by more than one class, as named constants.
|
package/src/sections.js
CHANGED
|
@@ -26,8 +26,8 @@ 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
|
-
* ai-hook-rules runs it outside the config-driven rule set entirely.
|
|
29
|
+
* RETIRED_CONFIG_KEYS). It is ON by default for every tree, with a machine-local OPT-OUT in
|
|
30
|
+
* ~/.webpieces/config.json, and ai-hook-rules runs it outside the config-driven rule set entirely.
|
|
31
31
|
*/
|
|
32
32
|
/**
|
|
33
33
|
* 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":";;;AA4DA,kCAEC;AAID,wCAEC;AA1DD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;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
|
|
1
|
+
{"version":3,"file":"sections.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/sections.ts"],"names":[],"mappings":";;;AA4DA,kCAEC;AAID,wCAEC;AA1DD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;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 ON by default for every tree, with a machine-local OPT-OUT in\n * ~/.webpieces/config.json, and ai-hook-rules runs it 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"]}
|