@webpieces/rules-config 0.4.599 → 0.4.600

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webpieces/rules-config",
3
- "version": "0.4.599",
3
+ "version": "0.4.600",
4
4
  "description": "Shared webpieces.config.json loader. Single source of truth for validation rule configuration consumed by @webpieces/ai-hook-rules, @webpieces/code-rules, and @webpieces/nx-webpieces-rules.",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * How long a file survives an AGED-TREE SWEEP without being rewritten — the policy `cleanTmp` applies
3
- * to `<clone>/.webpieces` and to `~/.webpieces/prs`, from this one number so the two roots cannot drift.
3
+ * to `{repo}/.webpieces`, which is the only root webpieces writes state under.
4
4
  *
5
5
  * NOT the same knob as `DEFAULT_RETENTION_DAYS` in review-provenance.ts, which happens to be 30 as well.
6
6
  * That one is a CONFIGURABLE ceiling on reviewer transcripts, overridable per repo in settings; this one
@@ -19,11 +19,11 @@ export declare class SweepCount {
19
19
  /**
20
20
  * The 30-day depth-first reap, as ONE implementation.
21
21
  *
22
- * It was written inside `CleanTmp` for `<primary>/.webpieces`, and the machine-global PR-body store
23
- * (`PrBodyStore`) needs exactly the same policy for exactly the same reasonthose directories
24
- * accumulate forever, and after `rm -rf <clone>` there is no clone left to delete them with
25
- * (`decisions/0001` § O3). A second copy of a deletion loop is the last thing this repo needs, so the
26
- * loop lives here and both callers pass their own root and their own reporter.
22
+ * It was written inside `CleanTmp` for `<primary>/.webpieces`, and extracted here when a second root
23
+ * (the machine-global PR-body store) needed the identical policy. That second root is gonethe gated
24
+ * merge body is the PR's own description now, see `decisions/0005` so today there is one caller. The
25
+ * loop stays extracted anyway: it is the sweep policy, testable on its own root, and `CleanTmp` reads
26
+ * as the command it is rather than as a deletion algorithm.
27
27
  *
28
28
  * `onDelete` is a reporter, not a policy hook: it is told what was removed AFTER the decision, so a
29
29
  * caller can print a line and cannot change the outcome.
@@ -7,7 +7,7 @@ const path = tslib_1.__importStar(require("path"));
7
7
  const inversify_1 = require("inversify");
8
8
  /**
9
9
  * How long a file survives an AGED-TREE SWEEP without being rewritten — the policy `cleanTmp` applies
10
- * to `<clone>/.webpieces` and to `~/.webpieces/prs`, from this one number so the two roots cannot drift.
10
+ * to `{repo}/.webpieces`, which is the only root webpieces writes state under.
11
11
  *
12
12
  * NOT the same knob as `DEFAULT_RETENTION_DAYS` in review-provenance.ts, which happens to be 30 as well.
13
13
  * That one is a CONFIGURABLE ceiling on reviewer transcripts, overridable per repo in settings; this one
@@ -35,11 +35,11 @@ exports.SweepCount = SweepCount;
35
35
  /**
36
36
  * The 30-day depth-first reap, as ONE implementation.
37
37
  *
38
- * It was written inside `CleanTmp` for `<primary>/.webpieces`, and the machine-global PR-body store
39
- * (`PrBodyStore`) needs exactly the same policy for exactly the same reasonthose directories
40
- * accumulate forever, and after `rm -rf <clone>` there is no clone left to delete them with
41
- * (`decisions/0001` § O3). A second copy of a deletion loop is the last thing this repo needs, so the
42
- * loop lives here and both callers pass their own root and their own reporter.
38
+ * It was written inside `CleanTmp` for `<primary>/.webpieces`, and extracted here when a second root
39
+ * (the machine-global PR-body store) needed the identical policy. That second root is gonethe gated
40
+ * merge body is the PR's own description now, see `decisions/0005` so today there is one caller. The
41
+ * loop stays extracted anyway: it is the sweep policy, testable on its own root, and `CleanTmp` reads
42
+ * as the command it is rather than as a deletion algorithm.
43
43
  *
44
44
  * `onDelete` is a reporter, not a policy hook: it is told what was removed AFTER the decision, so a
45
45
  * caller can print a line and cannot change the outcome.
@@ -1 +1 @@
1
- {"version":3,"file":"aged-tree-sweep.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/aged-tree-sweep.ts"],"names":[],"mappings":";;;;AAAA,+CAAyB;AACzB,mDAA6B;AAC7B,yCAA2D;AAE3D;;;;;;;;GAQG;AACU,QAAA,cAAc,GAAG,EAAE,CAAC;AAEjC,wGAAwG;AACxG,MAAa,UAAU;IACnB,KAAK,CAAS;IACd,IAAI,CAAS;IAEb,YAAY,KAAK,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC;QAC3B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACrB,CAAC;IAED,GAAG,CAAC,KAAiB;QACjB,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC;QAC1B,IAAI,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC;IAC5B,CAAC;IAED,IAAI,KAAK;QACL,OAAO,IAAI,CAAC,KAAK,KAAK,CAAC,IAAI,IAAI,CAAC,IAAI,KAAK,CAAC,CAAC;IAC/C,CAAC;CACJ;AAjBD,gCAiBC;AAED;;;;;;;;;;;GAWG;AAEI,IAAM,eAAe,GAArB,MAAM,eAAe;IACxB;;;;;;OAMG;IACH,KAAK,CAAC,IAAY,EAAE,QAAgB,EAAE,WAAsD,GAAS,EAAE,GAAE,CAAC;QACtG,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,UAAU,EAAE,CAAC;QAClD,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IACjE,CAAC;IAED,mGAAmG;IACnG,wDAAwD;IACxD,yDAAyD;IACjD,IAAI,CAAC,GAAW,EAAE,GAAW,EAAE,QAAgB,EAAE,MAAe,EAAE,QAAmD;QACzH,MAAM,KAAK,GAAG,IAAI,UAAU,EAAE,CAAC;QAC/B,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;YACtC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YACnC,6FAA6F;YAC7F,wFAAwF;YACxF,MAAM,IAAI,GAAG,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAChC,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;gBACrB,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC;YAC/D,CAAC;iBAAM,IAAI,GAAG,GAAG,IAAI,CAAC,OAAO,IAAI,QAAQ,EAAE,CAAC;gBACxC,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;gBACjC,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;gBACtB,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC;YACrB,CAAC;QACL,CAAC;QACD,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9C,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YAClB,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YACpB,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC;QACpB,CAAC;QACD,OAAO,KAAK,CAAC;IACjB,CAAC;CACJ,CAAA;AAtCY,0CAAe;0BAAf,eAAe;IAD3B,IAAA,sBAAU,EAAC,8BAAkB,CAAC,SAAS,CAAC;GAC5B,eAAe,CAsC3B","sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\nimport { injectable, bindingScopeValues } from 'inversify';\n\n/**\n * How long a file survives an AGED-TREE SWEEP without being rewritten — the policy `cleanTmp` applies\n * to `<clone>/.webpieces` and to `~/.webpieces/prs`, from this one number so the two roots cannot drift.\n *\n * NOT the same knob as `DEFAULT_RETENTION_DAYS` in review-provenance.ts, which happens to be 30 as well.\n * That one is a CONFIGURABLE ceiling on reviewer transcripts, overridable per repo in settings; this one\n * is the fixed sweep cutoff and nothing reads it from config. Same number today, different decisions,\n * so folding them would couple a repo's transcript-retention preference to when scratch dirs are reaped.\n */\nexport const RETENTION_DAYS = 30;\n\n/** What one sweep reaped: files deleted for age, and directories pruned because they ended up empty. */\nexport class SweepCount {\n files: number;\n dirs: number;\n\n constructor(files = 0, dirs = 0) {\n this.files = files;\n this.dirs = dirs;\n }\n\n add(other: SweepCount): void {\n this.files += other.files;\n this.dirs += other.dirs;\n }\n\n get empty(): boolean {\n return this.files === 0 && this.dirs === 0;\n }\n}\n\n/**\n * The 30-day depth-first reap, as ONE implementation.\n *\n * It was written inside `CleanTmp` for `<primary>/.webpieces`, and the machine-global PR-body store\n * (`PrBodyStore`) needs exactly the same policy for exactly the same reasonthose directories\n * accumulate forever, and after `rm -rf <clone>` there is no clone left to delete them with\n * (`decisions/0001` § O3). A second copy of a deletion loop is the last thing this repo needs, so the\n * loop lives here and both callers pass their own root and their own reporter.\n *\n * `onDelete` is a reporter, not a policy hook: it is told what was removed AFTER the decision, so a\n * caller can print a line and cannot change the outcome.\n */\n@injectable(bindingScopeValues.Singleton)\nexport class AgedTreeSweeper {\n /**\n * Delete every file under `root` older than `cutoffMs`, then prune every directory left empty.\n * `root` itself is swept INTO but never removed — every writer `mkdirSync`s its target, so an empty\n * root is harmless, whereas removing it can race a concurrent writer.\n *\n * A missing `root` is a no-op, not an error.\n */\n sweep(root: string, cutoffMs: number, onDelete: (removed: string, isDir: boolean) => void = (): void => {}): SweepCount {\n if (!fs.existsSync(root)) return new SweepCount();\n return this.walk(root, Date.now(), cutoffMs, true, onDelete);\n }\n\n // Depth-first, POST-order: children first, so a directory whose last file just aged out is seen as\n // empty on the way back up and pruned in the same pass.\n // eslint-disable-next-line @typescript-eslint/max-params\n private walk(dir: string, now: number, cutoffMs: number, isRoot: boolean, onDelete: (removed: string, isDir: boolean) => void): SweepCount {\n const count = new SweepCount();\n for (const entry of fs.readdirSync(dir)) {\n const full = path.join(dir, entry);\n // lstat, never stat: a symlink is a leaf that ages out like a file and is NEVER followed, so\n // a sweep can never wander outside `dir` or delete somebody else's file through a link.\n const stat = fs.lstatSync(full);\n if (stat.isDirectory()) {\n count.add(this.walk(full, now, cutoffMs, false, onDelete));\n } else if (now - stat.mtimeMs >= cutoffMs) {\n fs.rmSync(full, { force: true });\n onDelete(full, false);\n count.files += 1;\n }\n }\n if (!isRoot && fs.readdirSync(dir).length === 0) {\n fs.rmdirSync(dir);\n onDelete(dir, true);\n count.dirs += 1;\n }\n return count;\n }\n}\n"]}
1
+ {"version":3,"file":"aged-tree-sweep.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/aged-tree-sweep.ts"],"names":[],"mappings":";;;;AAAA,+CAAyB;AACzB,mDAA6B;AAC7B,yCAA2D;AAE3D;;;;;;;;GAQG;AACU,QAAA,cAAc,GAAG,EAAE,CAAC;AAEjC,wGAAwG;AACxG,MAAa,UAAU;IACnB,KAAK,CAAS;IACd,IAAI,CAAS;IAEb,YAAY,KAAK,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC;QAC3B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACrB,CAAC;IAED,GAAG,CAAC,KAAiB;QACjB,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC;QAC1B,IAAI,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC;IAC5B,CAAC;IAED,IAAI,KAAK;QACL,OAAO,IAAI,CAAC,KAAK,KAAK,CAAC,IAAI,IAAI,CAAC,IAAI,KAAK,CAAC,CAAC;IAC/C,CAAC;CACJ;AAjBD,gCAiBC;AAED;;;;;;;;;;;GAWG;AAEI,IAAM,eAAe,GAArB,MAAM,eAAe;IACxB;;;;;;OAMG;IACH,KAAK,CAAC,IAAY,EAAE,QAAgB,EAAE,WAAsD,GAAS,EAAE,GAAE,CAAC;QACtG,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,UAAU,EAAE,CAAC;QAClD,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IACjE,CAAC;IAED,mGAAmG;IACnG,wDAAwD;IACxD,yDAAyD;IACjD,IAAI,CAAC,GAAW,EAAE,GAAW,EAAE,QAAgB,EAAE,MAAe,EAAE,QAAmD;QACzH,MAAM,KAAK,GAAG,IAAI,UAAU,EAAE,CAAC;QAC/B,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;YACtC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YACnC,6FAA6F;YAC7F,wFAAwF;YACxF,MAAM,IAAI,GAAG,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAChC,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;gBACrB,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC;YAC/D,CAAC;iBAAM,IAAI,GAAG,GAAG,IAAI,CAAC,OAAO,IAAI,QAAQ,EAAE,CAAC;gBACxC,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;gBACjC,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;gBACtB,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC;YACrB,CAAC;QACL,CAAC;QACD,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9C,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YAClB,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YACpB,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC;QACpB,CAAC;QACD,OAAO,KAAK,CAAC;IACjB,CAAC;CACJ,CAAA;AAtCY,0CAAe;0BAAf,eAAe;IAD3B,IAAA,sBAAU,EAAC,8BAAkB,CAAC,SAAS,CAAC;GAC5B,eAAe,CAsC3B","sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\nimport { injectable, bindingScopeValues } from 'inversify';\n\n/**\n * How long a file survives an AGED-TREE SWEEP without being rewritten — the policy `cleanTmp` applies\n * to `{repo}/.webpieces`, which is the only root webpieces writes state under.\n *\n * NOT the same knob as `DEFAULT_RETENTION_DAYS` in review-provenance.ts, which happens to be 30 as well.\n * That one is a CONFIGURABLE ceiling on reviewer transcripts, overridable per repo in settings; this one\n * is the fixed sweep cutoff and nothing reads it from config. Same number today, different decisions,\n * so folding them would couple a repo's transcript-retention preference to when scratch dirs are reaped.\n */\nexport const RETENTION_DAYS = 30;\n\n/** What one sweep reaped: files deleted for age, and directories pruned because they ended up empty. */\nexport class SweepCount {\n files: number;\n dirs: number;\n\n constructor(files = 0, dirs = 0) {\n this.files = files;\n this.dirs = dirs;\n }\n\n add(other: SweepCount): void {\n this.files += other.files;\n this.dirs += other.dirs;\n }\n\n get empty(): boolean {\n return this.files === 0 && this.dirs === 0;\n }\n}\n\n/**\n * The 30-day depth-first reap, as ONE implementation.\n *\n * It was written inside `CleanTmp` for `<primary>/.webpieces`, and extracted here when a second root\n * (the machine-global PR-body store) needed the identical policy. That second root is gonethe gated\n * merge body is the PR's own description now, see `decisions/0005` so today there is one caller. The\n * loop stays extracted anyway: it is the sweep policy, testable on its own root, and `CleanTmp` reads\n * as the command it is rather than as a deletion algorithm.\n *\n * `onDelete` is a reporter, not a policy hook: it is told what was removed AFTER the decision, so a\n * caller can print a line and cannot change the outcome.\n */\n@injectable(bindingScopeValues.Singleton)\nexport class AgedTreeSweeper {\n /**\n * Delete every file under `root` older than `cutoffMs`, then prune every directory left empty.\n * `root` itself is swept INTO but never removed — every writer `mkdirSync`s its target, so an empty\n * root is harmless, whereas removing it can race a concurrent writer.\n *\n * A missing `root` is a no-op, not an error.\n */\n sweep(root: string, cutoffMs: number, onDelete: (removed: string, isDir: boolean) => void = (): void => {}): SweepCount {\n if (!fs.existsSync(root)) return new SweepCount();\n return this.walk(root, Date.now(), cutoffMs, true, onDelete);\n }\n\n // Depth-first, POST-order: children first, so a directory whose last file just aged out is seen as\n // empty on the way back up and pruned in the same pass.\n // eslint-disable-next-line @typescript-eslint/max-params\n private walk(dir: string, now: number, cutoffMs: number, isRoot: boolean, onDelete: (removed: string, isDir: boolean) => void): SweepCount {\n const count = new SweepCount();\n for (const entry of fs.readdirSync(dir)) {\n const full = path.join(dir, entry);\n // lstat, never stat: a symlink is a leaf that ages out like a file and is NEVER followed, so\n // a sweep can never wander outside `dir` or delete somebody else's file through a link.\n const stat = fs.lstatSync(full);\n if (stat.isDirectory()) {\n count.add(this.walk(full, now, cutoffMs, false, onDelete));\n } else if (now - stat.mtimeMs >= cutoffMs) {\n fs.rmSync(full, { force: true });\n onDelete(full, false);\n count.files += 1;\n }\n }\n if (!isRoot && fs.readdirSync(dir).length === 0) {\n fs.rmdirSync(dir);\n onDelete(dir, true);\n count.dirs += 1;\n }\n return count;\n }\n}\n"]}
package/src/index.d.ts CHANGED
@@ -11,9 +11,7 @@ export { findConfigFile, CONFIG_FILENAME, ConfigFile, ConfigParseAttempt, CONFIG
11
11
  export { RepoRootFinder, INSTRUCT_AI_DIR, INSTRUCT_AI_LEAF } from './repo-root';
12
12
  export { DotWebpieces, dotWebpieces, GitDirs, WORKTREE_STATE_DIR, LOGS_STATE_DIR, HOOKS_STATE_DIR } from './state-dir';
13
13
  export { StateDirMigrator, StateMigrationReport } from './state-dir-migration';
14
- export { MachineStateHome, machineStateHome, StateHome, WEBPIECES_STATE_HOME_ENV } from './machine-state-home';
15
14
  export { AgedTreeSweeper, SweepCount, RETENTION_DAYS } from './aged-tree-sweep';
16
- export { PrBodyStore, PrBodyLocation, PrBodyOrigin, RepoSlug, PRS_STATE_DIR, MERGE_BODY_FILE, PR_ORIGIN_FILE, } from './pr-body-store';
17
15
  export { ClaudeEnv, claudeEnv, CLAUDE_PROJECT_DIR_ENV, CLAUDE_PROJECT_DIR_UNSET } from './claude-env';
18
16
  export { AtomicFile } from './atomic-file';
19
17
  export { atRoot } from './at-root';
package/src/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PR_ORIGIN_FILE = exports.MERGE_BODY_FILE = exports.PRS_STATE_DIR = exports.RepoSlug = exports.PrBodyOrigin = exports.PrBodyLocation = exports.PrBodyStore = exports.RETENTION_DAYS = exports.SweepCount = exports.AgedTreeSweeper = exports.WEBPIECES_STATE_HOME_ENV = exports.StateHome = exports.machineStateHome = exports.MachineStateHome = exports.StateMigrationReport = exports.StateDirMigrator = exports.HOOKS_STATE_DIR = 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.formatConfigErrorsBanner = exports.ConfigLoader = exports.LoadedConfig = exports.loadAndValidate = exports.toError = exports.runMain = exports.CliArgs = exports.CliArgsCheck = exports.CliArgSet = exports.CliFlag = exports.CliUsage = exports.CliExitError = exports.RuleFailError = exports.InformAiError = exports.ResolvedRuleConfig = exports.ResolvedConfig = void 0;
4
- exports.renderMatchRuleMessage = exports.compileMatchRulePatterns = exports.isMatchRuleAllowedPath = exports.findMatchRuleViolations = exports.MatchRuleViolation = exports.MatchRuleConfig = exports.validateChecklistDocs = 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 = exports.RulesConfigDesign = exports.atRoot = exports.AtomicFile = exports.CLAUDE_PROJECT_DIR_UNSET = exports.CLAUDE_PROJECT_DIR_ENV = exports.claudeEnv = exports.ClaudeEnv = void 0;
5
- 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.PUSH_DEV_STATE_FILE = 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.getCurrentBranch = exports.shouldSkipRule = exports.FieldDef = exports.sectionForRule = exports.isHookGuard = exports.HOOK_GUARD_NAMES = exports.DEFAULT_MATCH_RULES = void 0;
6
- exports.defaultGates = exports.ReviewContextEntry = exports.DEFAULT_DEV_BRANCH = exports.DEFAULT_DEV_BRANCH_NAMESPACE = exports.DevDeployConfig = exports.LandPrConfig = exports.PrGateConfig = exports.GateDefinition = exports.StaleMainBashGuardConfig = exports.MergedBranchBashGuardConfig = exports.ReadStaleGuardConfig = exports.FeatureBranchGuardConfig = 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 = 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.RedirectHowToMergeMainConfig = exports.PrMergeGuardConfig = exports.MergeInProgressGuardConfig = exports.PrCreationOrPushGuardConfig = exports.BranchCreationGuardConfig = exports.RoleTagConfig = exports.FrameworkTagConfig = exports.InjectAnnotationNotNeededForConcreteClassConfig = exports.NoFunctionOutsideClassConfig = exports.NoProcessExitOutsideMainConfig = exports.NoCustomCssConfig = void 0;
7
- 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 = exports.ProvenanceResult = exports.TranscriptScan = exports.EvidenceRequest = 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 = void 0;
8
- 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 = 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 = 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 = void 0;
3
+ exports.ExcludePaths = exports.DESIGN_METADATA_KEYS = exports.isDocumentDesign = exports.DocumentDesign = 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.HOOKS_STATE_DIR = 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.formatConfigErrorsBanner = exports.ConfigLoader = exports.LoadedConfig = exports.loadAndValidate = exports.toError = exports.runMain = exports.CliArgs = exports.CliArgsCheck = exports.CliArgSet = exports.CliFlag = exports.CliUsage = exports.CliExitError = exports.RuleFailError = exports.InformAiError = exports.ResolvedRuleConfig = exports.ResolvedConfig = void 0;
4
+ exports.getFileDiff = exports.getChangedFiles = exports.resolveBase = exports.detectBase = exports.getCurrentBranch = exports.shouldSkipRule = exports.FieldDef = exports.sectionForRule = exports.isHookGuard = exports.HOOK_GUARD_NAMES = exports.DEFAULT_MATCH_RULES = exports.renderMatchRuleMessage = exports.compileMatchRulePatterns = exports.isMatchRuleAllowedPath = exports.findMatchRuleViolations = exports.MatchRuleViolation = exports.MatchRuleConfig = exports.validateChecklistDocs = 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 = void 0;
5
+ exports.RedirectHowToMergeMainConfig = exports.PrMergeGuardConfig = exports.MergeInProgressGuardConfig = exports.PrCreationOrPushGuardConfig = 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.PUSH_DEV_STATE_FILE = 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 = void 0;
6
+ 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.PrGateConfig = exports.GateDefinition = exports.StaleMainBashGuardConfig = exports.MergedBranchBashGuardConfig = exports.ReadStaleGuardConfig = exports.FeatureBranchGuardConfig = 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 = 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 = void 0;
7
+ 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 = exports.ProvenanceResult = exports.TranscriptScan = exports.EvidenceRequest = 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 = void 0;
8
+ 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 = 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 = 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 = 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; } });
@@ -60,25 +60,15 @@ Object.defineProperty(exports, "HOOKS_STATE_DIR", { enumerable: true, get: funct
60
60
  var state_dir_migration_1 = require("./state-dir-migration");
61
61
  Object.defineProperty(exports, "StateDirMigrator", { enumerable: true, get: function () { return state_dir_migration_1.StateDirMigrator; } });
62
62
  Object.defineProperty(exports, "StateMigrationReport", { enumerable: true, get: function () { return state_dir_migration_1.StateMigrationReport; } });
63
- // MACHINE-GLOBAL state the scope ABOVE the clone. Used only for artifacts whose identity is bigger
64
- // than a clone (today: the gated squash body, keyed by the PR's global identity). See pr-body-store.ts.
65
- var machine_state_home_1 = require("./machine-state-home");
66
- Object.defineProperty(exports, "MachineStateHome", { enumerable: true, get: function () { return machine_state_home_1.MachineStateHome; } });
67
- Object.defineProperty(exports, "machineStateHome", { enumerable: true, get: function () { return machine_state_home_1.machineStateHome; } });
68
- Object.defineProperty(exports, "StateHome", { enumerable: true, get: function () { return machine_state_home_1.StateHome; } });
69
- Object.defineProperty(exports, "WEBPIECES_STATE_HOME_ENV", { enumerable: true, get: function () { return machine_state_home_1.WEBPIECES_STATE_HOME_ENV; } });
63
+ // There is NO machine-global state root. `MachineStateHome`/`StateHome`/`WEBPIECES_STATE_HOME` and the
64
+ // `PrBodyStore` that used them are DELETED: the one artifact that needed a scope above the clone was the
65
+ // gated squash body, and GitHub holds it now (it IS the PR description). Every `.webpieces` path a
66
+ // webpieces tool writes is `{repo}/.webpieces`, resolved through `DotWebpieces` above. See
67
+ // `decisions/0005-the-pr-description-is-the-merge-body.md`.
70
68
  var aged_tree_sweep_1 = require("./aged-tree-sweep");
71
69
  Object.defineProperty(exports, "AgedTreeSweeper", { enumerable: true, get: function () { return aged_tree_sweep_1.AgedTreeSweeper; } });
72
70
  Object.defineProperty(exports, "SweepCount", { enumerable: true, get: function () { return aged_tree_sweep_1.SweepCount; } });
73
71
  Object.defineProperty(exports, "RETENTION_DAYS", { enumerable: true, get: function () { return aged_tree_sweep_1.RETENTION_DAYS; } });
74
- var pr_body_store_1 = require("./pr-body-store");
75
- Object.defineProperty(exports, "PrBodyStore", { enumerable: true, get: function () { return pr_body_store_1.PrBodyStore; } });
76
- Object.defineProperty(exports, "PrBodyLocation", { enumerable: true, get: function () { return pr_body_store_1.PrBodyLocation; } });
77
- Object.defineProperty(exports, "PrBodyOrigin", { enumerable: true, get: function () { return pr_body_store_1.PrBodyOrigin; } });
78
- Object.defineProperty(exports, "RepoSlug", { enumerable: true, get: function () { return pr_body_store_1.RepoSlug; } });
79
- Object.defineProperty(exports, "PRS_STATE_DIR", { enumerable: true, get: function () { return pr_body_store_1.PRS_STATE_DIR; } });
80
- Object.defineProperty(exports, "MERGE_BODY_FILE", { enumerable: true, get: function () { return pr_body_store_1.MERGE_BODY_FILE; } });
81
- Object.defineProperty(exports, "PR_ORIGIN_FILE", { enumerable: true, get: function () { return pr_body_store_1.PR_ORIGIN_FILE; } });
82
72
  var claude_env_1 = require("./claude-env");
83
73
  Object.defineProperty(exports, "ClaudeEnv", { enumerable: true, get: function () { return claude_env_1.ClaudeEnv; } });
84
74
  Object.defineProperty(exports, "claudeEnv", { enumerable: true, get: function () { return claude_env_1.claudeEnv; } });
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 } from './rule-fail-error';\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 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';\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, HOOKS_STATE_DIR } from './state-dir';\nexport { StateDirMigrator, StateMigrationReport } from './state-dir-migration';\n// MACHINE-GLOBAL state — the scope ABOVE the clone. Used only for artifacts whose identity is bigger\n// than a clone (today: the gated squash body, keyed by the PR's global identity). See pr-body-store.ts.\nexport { MachineStateHome, machineStateHome, StateHome, WEBPIECES_STATE_HOME_ENV } from './machine-state-home';\nexport { AgedTreeSweeper, SweepCount, RETENTION_DAYS } from './aged-tree-sweep';\nexport {\n PrBodyStore, PrBodyLocation, PrBodyOrigin, RepoSlug,\n PRS_STATE_DIR, MERGE_BODY_FILE, PR_ORIGIN_FILE,\n} from './pr-body-store';\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';\nexport { validateChecklistDocs } from './checklist-docs-validator';\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 { HOOK_GUARD_NAMES, isHookGuard, sectionForRule } from './sections';\nexport { FieldDef } from './field-def';\nexport type { SchemaShape } from './field-def';\nexport { shouldSkipRule, getCurrentBranch } from './skip-rule';\nexport type { 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} 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 PrCreationOrPushGuardConfig,\n MergeInProgressGuardConfig,\n PrMergeGuardConfig,\n RedirectHowToMergeMainConfig,\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 FeatureBranchGuardConfig,\n ReadStaleGuardConfig,\n MergedBranchBashGuardConfig,\n StaleMainBashGuardConfig,\n} from './main-sync-guard-configs';\nexport {\n GateDefinition,\n PrGateConfig,\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 EvidenceRequest,\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 } from './rule-fail-error';\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 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';\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, HOOKS_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';\nexport { validateChecklistDocs } from './checklist-docs-validator';\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 { HOOK_GUARD_NAMES, isHookGuard, sectionForRule } from './sections';\nexport { FieldDef } from './field-def';\nexport type { SchemaShape } from './field-def';\nexport { shouldSkipRule, getCurrentBranch } from './skip-rule';\nexport type { 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} 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 PrCreationOrPushGuardConfig,\n MergeInProgressGuardConfig,\n PrMergeGuardConfig,\n RedirectHowToMergeMainConfig,\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 FeatureBranchGuardConfig,\n ReadStaleGuardConfig,\n MergedBranchBashGuardConfig,\n StaleMainBashGuardConfig,\n} from './main-sync-guard-configs';\nexport {\n GateDefinition,\n PrGateConfig,\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 EvidenceRequest,\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,75 +0,0 @@
1
- /**
2
- * The environment variable that takes over completely. See {@link MachineStateHome} and
3
- * `decisions/0001-tree-identity-and-governance.md` § D3.
4
- */
5
- export declare const WEBPIECES_STATE_HOME_ENV = "WEBPIECES_STATE_HOME";
6
- /**
7
- * Where the MACHINE-GLOBAL state root resolved to, and whether it is really machine-global.
8
- *
9
- * Data-only (classes for data, per CLAUDE.md). `degraded` is the whole reason this is a class rather
10
- * than a bare string: a caller that fell back to the clone has NOT written a machine-global artifact,
11
- * and any message it prints about "this machine" would be a lie. `reason` is the sentence to print.
12
- */
13
- export declare class StateHome {
14
- /** The directory that IS the root. Callers append their own namespace beneath it. */
15
- readonly root: string;
16
- /** TRUE when this is the per-clone fallback, i.e. NOT visible from another clone. */
17
- readonly degraded: boolean;
18
- /** '' when not degraded; otherwise one human-readable clause naming what went wrong. */
19
- readonly reason: string;
20
- constructor(root: string, degraded?: boolean, reason?: string);
21
- }
22
- /**
23
- * The ONE resolver for state that belongs to the MACHINE rather than to a clone or a worktree.
24
- *
25
- * ─── Why this exists at all ────────────────────────────────────────────────────────────────────────
26
- * `DotWebpieces` answers "where does state for THIS TREE live" and has two scopes, shared (repo-wide)
27
- * and local (this worktree). Both are anchored inside the primary clone, which is correct for every
28
- * fact whose scope is a clone: branches, worktrees, in-flight merges.
29
- *
30
- * It is WRONG for a fact whose scope is larger than a clone. `wp-finish-upsert-pr` renders the compact
31
- * squash-commit body for PR #N; `wp-land-pr` must pass those exact bytes to `gh pr merge --body-file`.
32
- * PR #N is a fact of the REMOTE repository — the same object seen from every clone and every worktree
33
- * on this machine — so storing its receipt under a per-worktree namespace made landing work only while
34
- * the branch never changed trees. It did (the flow ran in the primary clone, landing happened from a
35
- * linked worktree), landing found nothing, and the artifact got copied across by hand.
36
- *
37
- * ─── D3: `WEBPIECES_STATE_HOME` is a FULL override, not a prefix ────────────────────────────────────
38
- * Point it at a directory and that directory IS the root — no `.webpieces` appended, no per-repo
39
- * nesting. That is the escape for a container/sandbox with no writable `$HOME`, and it is also "put it
40
- * back inside the tree" for anyone who wants that.
41
- *
42
- * ─── Never throws ──────────────────────────────────────────────────────────────────────────────────
43
- * D3 again: this sits under code that runs on a hook's blocking path, so an unwritable or absent `$HOME`
44
- * DEGRADES to `<primary clone>/.webpieces` and says so, rather than raising. A degraded home is not a
45
- * silent one: {@link StateHome.degraded} travels with the path, and every consumer prints the reason —
46
- * because a receipt written into a clone is exactly the thing that was broken to begin with, and a
47
- * reader who is not told will spend the next incident looking for it on the wrong machine.
48
- */
49
- export declare class MachineStateHome {
50
- private readonly cache;
51
- /**
52
- * The machine-global state root.
53
- *
54
- * @param cloneFallback the primary clone's root, used ONLY when neither the override nor `$HOME`
55
- * is usable. Pass the repo root you already resolved; it is never consulted
56
- * on the happy path.
57
- */
58
- resolve(cloneFallback: string): StateHome;
59
- private resolveUncached;
60
- /**
61
- * `$HOME` FIRST, `os.homedir()` second — deliberately not the other way round.
62
- *
63
- * On macOS `os.homedir()` falls back to the PASSWORD DATABASE when `$HOME` is unset, so it happily
64
- * returns the real home of a process that was launched with a scrubbed environment on purpose. It
65
- * also makes `HOME=<tmp>` untestable, and a state root nothing can point at a temp directory is a
66
- * state root nothing has real tests for.
67
- */
68
- private homeDir;
69
- private usable;
70
- }
71
- /**
72
- * Process-wide instance for the many non-DI call sites, mirroring `dotWebpieces`. Inversify still
73
- * injects the singleton wherever a container is in play.
74
- */
75
- export declare const machineStateHome: MachineStateHome;
@@ -1,152 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.machineStateHome = exports.MachineStateHome = exports.StateHome = exports.WEBPIECES_STATE_HOME_ENV = void 0;
4
- const tslib_1 = require("tslib");
5
- const fs = tslib_1.__importStar(require("fs"));
6
- const os = tslib_1.__importStar(require("os"));
7
- const path = tslib_1.__importStar(require("path"));
8
- const inversify_1 = require("inversify");
9
- const constants_1 = require("./constants");
10
- const to_error_1 = require("./to-error");
11
- /**
12
- * The environment variable that takes over completely. See {@link MachineStateHome} and
13
- * `decisions/0001-tree-identity-and-governance.md` § D3.
14
- */
15
- exports.WEBPIECES_STATE_HOME_ENV = 'WEBPIECES_STATE_HOME';
16
- /**
17
- * Where the MACHINE-GLOBAL state root resolved to, and whether it is really machine-global.
18
- *
19
- * Data-only (classes for data, per CLAUDE.md). `degraded` is the whole reason this is a class rather
20
- * than a bare string: a caller that fell back to the clone has NOT written a machine-global artifact,
21
- * and any message it prints about "this machine" would be a lie. `reason` is the sentence to print.
22
- */
23
- class StateHome {
24
- /** The directory that IS the root. Callers append their own namespace beneath it. */
25
- root;
26
- /** TRUE when this is the per-clone fallback, i.e. NOT visible from another clone. */
27
- degraded;
28
- /** '' when not degraded; otherwise one human-readable clause naming what went wrong. */
29
- reason;
30
- constructor(root, degraded = false, reason = '') {
31
- this.root = root;
32
- this.degraded = degraded;
33
- this.reason = reason;
34
- }
35
- }
36
- exports.StateHome = StateHome;
37
- /**
38
- * The ONE resolver for state that belongs to the MACHINE rather than to a clone or a worktree.
39
- *
40
- * ─── Why this exists at all ────────────────────────────────────────────────────────────────────────
41
- * `DotWebpieces` answers "where does state for THIS TREE live" and has two scopes, shared (repo-wide)
42
- * and local (this worktree). Both are anchored inside the primary clone, which is correct for every
43
- * fact whose scope is a clone: branches, worktrees, in-flight merges.
44
- *
45
- * It is WRONG for a fact whose scope is larger than a clone. `wp-finish-upsert-pr` renders the compact
46
- * squash-commit body for PR #N; `wp-land-pr` must pass those exact bytes to `gh pr merge --body-file`.
47
- * PR #N is a fact of the REMOTE repository — the same object seen from every clone and every worktree
48
- * on this machine — so storing its receipt under a per-worktree namespace made landing work only while
49
- * the branch never changed trees. It did (the flow ran in the primary clone, landing happened from a
50
- * linked worktree), landing found nothing, and the artifact got copied across by hand.
51
- *
52
- * ─── D3: `WEBPIECES_STATE_HOME` is a FULL override, not a prefix ────────────────────────────────────
53
- * Point it at a directory and that directory IS the root — no `.webpieces` appended, no per-repo
54
- * nesting. That is the escape for a container/sandbox with no writable `$HOME`, and it is also "put it
55
- * back inside the tree" for anyone who wants that.
56
- *
57
- * ─── Never throws ──────────────────────────────────────────────────────────────────────────────────
58
- * D3 again: this sits under code that runs on a hook's blocking path, so an unwritable or absent `$HOME`
59
- * DEGRADES to `<primary clone>/.webpieces` and says so, rather than raising. A degraded home is not a
60
- * silent one: {@link StateHome.degraded} travels with the path, and every consumer prints the reason —
61
- * because a receipt written into a clone is exactly the thing that was broken to begin with, and a
62
- * reader who is not told will spend the next incident looking for it on the wrong machine.
63
- */
64
- let MachineStateHome = class MachineStateHome {
65
- // Resolved roots, keyed by the fallback that was offered. Probing writability costs a mkdir + a
66
- // stat, and every path lookup in a command goes through here.
67
- cache = new Map();
68
- /**
69
- * The machine-global state root.
70
- *
71
- * @param cloneFallback the primary clone's root, used ONLY when neither the override nor `$HOME`
72
- * is usable. Pass the repo root you already resolved; it is never consulted
73
- * on the happy path.
74
- */
75
- resolve(cloneFallback) {
76
- const cached = this.cache.get(cloneFallback);
77
- if (cached !== undefined)
78
- return cached;
79
- const home = this.resolveUncached(cloneFallback);
80
- this.cache.set(cloneFallback, home);
81
- return home;
82
- }
83
- resolveUncached(cloneFallback) {
84
- const override = (process.env[exports.WEBPIECES_STATE_HOME_ENV] ?? '').trim();
85
- if (override !== '') {
86
- // FULL override: this directory IS the root. No `<key>` nesting, no `.webpieces` suffix.
87
- if (this.usable(override))
88
- return new StateHome(path.resolve(override));
89
- return new StateHome(path.join(cloneFallback, constants_1.WEBPIECES_TMP_DIR), true, `${exports.WEBPIECES_STATE_HOME_ENV}=${override} is not a writable directory`);
90
- }
91
- const home = this.homeDir();
92
- if (home !== '') {
93
- const root = path.join(home, constants_1.WEBPIECES_TMP_DIR);
94
- if (this.usable(root))
95
- return new StateHome(root);
96
- return new StateHome(path.join(cloneFallback, constants_1.WEBPIECES_TMP_DIR), true, `${root} could not be created or written to`);
97
- }
98
- return new StateHome(path.join(cloneFallback, constants_1.WEBPIECES_TMP_DIR), true, 'this process has no home directory ($HOME is unset and os.homedir() gave nothing)');
99
- }
100
- /**
101
- * `$HOME` FIRST, `os.homedir()` second — deliberately not the other way round.
102
- *
103
- * On macOS `os.homedir()` falls back to the PASSWORD DATABASE when `$HOME` is unset, so it happily
104
- * returns the real home of a process that was launched with a scrubbed environment on purpose. It
105
- * also makes `HOME=<tmp>` untestable, and a state root nothing can point at a temp directory is a
106
- * state root nothing has real tests for.
107
- */
108
- homeDir() {
109
- const fromEnv = (process.env['HOME'] ?? '').trim();
110
- if (fromEnv !== '')
111
- return fromEnv;
112
- // webpieces-disable no-unmanaged-exceptions -- chokepoint: os.homedir() throws on some sandboxes; '' is the honest answer
113
- // eslint-disable-next-line @webpieces/no-unmanaged-exceptions
114
- try {
115
- return (os.homedir() ?? '').trim();
116
- }
117
- catch (err) {
118
- const error = (0, to_error_1.toError)(err);
119
- void error;
120
- return '';
121
- }
122
- }
123
- // Can we actually create and write inside `dir`? Probed by creating it and writing a marker rather
124
- // than by reading mode bits: a read-only mount, an SELinux/sandbox denial and a plain permission
125
- // error all present differently in `stat`, and all of them fail the write identically.
126
- usable(dir) {
127
- // webpieces-disable no-unmanaged-exceptions -- chokepoint: any filesystem refusal means "not usable", never a crash
128
- // eslint-disable-next-line @webpieces/no-unmanaged-exceptions
129
- try {
130
- fs.mkdirSync(dir, { recursive: true });
131
- const probe = path.join(dir, '.writable-probe');
132
- fs.writeFileSync(probe, '');
133
- fs.rmSync(probe, { force: true });
134
- return true;
135
- }
136
- catch (err) {
137
- const error = (0, to_error_1.toError)(err);
138
- void error;
139
- return false;
140
- }
141
- }
142
- };
143
- exports.MachineStateHome = MachineStateHome;
144
- exports.MachineStateHome = MachineStateHome = tslib_1.__decorate([
145
- (0, inversify_1.injectable)(inversify_1.bindingScopeValues.Singleton)
146
- ], MachineStateHome);
147
- /**
148
- * Process-wide instance for the many non-DI call sites, mirroring `dotWebpieces`. Inversify still
149
- * injects the singleton wherever a container is in play.
150
- */
151
- exports.machineStateHome = new MachineStateHome();
152
- //# sourceMappingURL=machine-state-home.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"machine-state-home.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/machine-state-home.ts"],"names":[],"mappings":";;;;AAAA,+CAAyB;AACzB,+CAAyB;AACzB,mDAA6B;AAC7B,yCAA2D;AAE3D,2CAAgD;AAChD,yCAAqC;AAErC;;;GAGG;AACU,QAAA,wBAAwB,GAAG,sBAAsB,CAAC;AAE/D;;;;;;GAMG;AACH,MAAa,SAAS;IAClB,qFAAqF;IAC5E,IAAI,CAAS;IACtB,qFAAqF;IAC5E,QAAQ,CAAU;IAC3B,wFAAwF;IAC/E,MAAM,CAAS;IAExB,YAAY,IAAY,EAAE,QAAQ,GAAG,KAAK,EAAE,MAAM,GAAG,EAAE;QACnD,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACzB,CAAC;CACJ;AAbD,8BAaC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEI,IAAM,gBAAgB,GAAtB,MAAM,gBAAgB;IACzB,gGAAgG;IAChG,8DAA8D;IAC7C,KAAK,GAAG,IAAI,GAAG,EAAqB,CAAC;IAEtD;;;;;;OAMG;IACH,OAAO,CAAC,aAAqB;QACzB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QAC7C,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,MAAM,CAAC;QACxC,MAAM,IAAI,GAAG,IAAI,CAAC,eAAe,CAAC,aAAa,CAAC,CAAC;QACjD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;QACpC,OAAO,IAAI,CAAC;IAChB,CAAC;IAEO,eAAe,CAAC,aAAqB;QACzC,MAAM,QAAQ,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,gCAAwB,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACtE,IAAI,QAAQ,KAAK,EAAE,EAAE,CAAC;YAClB,yFAAyF;YACzF,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC;gBAAE,OAAO,IAAI,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;YACxE,OAAO,IAAI,SAAS,CAChB,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,6BAAiB,CAAC,EAAE,IAAI,EACjD,GAAG,gCAAwB,IAAI,QAAQ,8BAA8B,CAAC,CAAC;QAC/E,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC5B,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;YACd,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,6BAAiB,CAAC,CAAC;YAChD,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;gBAAE,OAAO,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC;YAClD,OAAO,IAAI,SAAS,CAChB,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,6BAAiB,CAAC,EAAE,IAAI,EACjD,GAAG,IAAI,qCAAqC,CAAC,CAAC;QACtD,CAAC;QAED,OAAO,IAAI,SAAS,CAChB,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,6BAAiB,CAAC,EAAE,IAAI,EACjD,mFAAmF,CAAC,CAAC;IAC7F,CAAC;IAED;;;;;;;OAOG;IACK,OAAO;QACX,MAAM,OAAO,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACnD,IAAI,OAAO,KAAK,EAAE;YAAE,OAAO,OAAO,CAAC;QACnC,0HAA0H;QAC1H,8DAA8D;QAC9D,IAAI,CAAC;YACD,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACvC,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACpB,MAAM,KAAK,GAAG,IAAA,kBAAO,EAAC,GAAG,CAAC,CAAC;YAC3B,KAAK,KAAK,CAAC;YACX,OAAO,EAAE,CAAC;QACd,CAAC;IACL,CAAC;IAED,mGAAmG;IACnG,iGAAiG;IACjG,uFAAuF;IAC/E,MAAM,CAAC,GAAW;QACtB,oHAAoH;QACpH,8DAA8D;QAC9D,IAAI,CAAC;YACD,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACvC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC;YAChD,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAC5B,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YAClC,OAAO,IAAI,CAAC;QAChB,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACpB,MAAM,KAAK,GAAG,IAAA,kBAAO,EAAC,GAAG,CAAC,CAAC;YAC3B,KAAK,KAAK,CAAC;YACX,OAAO,KAAK,CAAC;QACjB,CAAC;IACL,CAAC;CACJ,CAAA;AApFY,4CAAgB;2BAAhB,gBAAgB;IAD5B,IAAA,sBAAU,EAAC,8BAAkB,CAAC,SAAS,CAAC;GAC5B,gBAAgB,CAoF5B;AAED;;;GAGG;AACU,QAAA,gBAAgB,GAAG,IAAI,gBAAgB,EAAE,CAAC","sourcesContent":["import * as fs from 'fs';\nimport * as os from 'os';\nimport * as path from 'path';\nimport { injectable, bindingScopeValues } from 'inversify';\n\nimport { WEBPIECES_TMP_DIR } from './constants';\nimport { toError } from './to-error';\n\n/**\n * The environment variable that takes over completely. See {@link MachineStateHome} and\n * `decisions/0001-tree-identity-and-governance.md` § D3.\n */\nexport const WEBPIECES_STATE_HOME_ENV = 'WEBPIECES_STATE_HOME';\n\n/**\n * Where the MACHINE-GLOBAL state root resolved to, and whether it is really machine-global.\n *\n * Data-only (classes for data, per CLAUDE.md). `degraded` is the whole reason this is a class rather\n * than a bare string: a caller that fell back to the clone has NOT written a machine-global artifact,\n * and any message it prints about \"this machine\" would be a lie. `reason` is the sentence to print.\n */\nexport class StateHome {\n /** The directory that IS the root. Callers append their own namespace beneath it. */\n readonly root: string;\n /** TRUE when this is the per-clone fallback, i.e. NOT visible from another clone. */\n readonly degraded: boolean;\n /** '' when not degraded; otherwise one human-readable clause naming what went wrong. */\n readonly reason: string;\n\n constructor(root: string, degraded = false, reason = '') {\n this.root = root;\n this.degraded = degraded;\n this.reason = reason;\n }\n}\n\n/**\n * The ONE resolver for state that belongs to the MACHINE rather than to a clone or a worktree.\n *\n * ─── Why this exists at all ────────────────────────────────────────────────────────────────────────\n * `DotWebpieces` answers \"where does state for THIS TREE live\" and has two scopes, shared (repo-wide)\n * and local (this worktree). Both are anchored inside the primary clone, which is correct for every\n * fact whose scope is a clone: branches, worktrees, in-flight merges.\n *\n * It is WRONG for a fact whose scope is larger than a clone. `wp-finish-upsert-pr` renders the compact\n * squash-commit body for PR #N; `wp-land-pr` must pass those exact bytes to `gh pr merge --body-file`.\n * PR #N is a fact of the REMOTE repository — the same object seen from every clone and every worktree\n * on this machine — so storing its receipt under a per-worktree namespace made landing work only while\n * the branch never changed trees. It did (the flow ran in the primary clone, landing happened from a\n * linked worktree), landing found nothing, and the artifact got copied across by hand.\n *\n * ─── D3: `WEBPIECES_STATE_HOME` is a FULL override, not a prefix ────────────────────────────────────\n * Point it at a directory and that directory IS the root — no `.webpieces` appended, no per-repo\n * nesting. That is the escape for a container/sandbox with no writable `$HOME`, and it is also \"put it\n * back inside the tree\" for anyone who wants that.\n *\n * ─── Never throws ──────────────────────────────────────────────────────────────────────────────────\n * D3 again: this sits under code that runs on a hook's blocking path, so an unwritable or absent `$HOME`\n * DEGRADES to `<primary clone>/.webpieces` and says so, rather than raising. A degraded home is not a\n * silent one: {@link StateHome.degraded} travels with the path, and every consumer prints the reason —\n * because a receipt written into a clone is exactly the thing that was broken to begin with, and a\n * reader who is not told will spend the next incident looking for it on the wrong machine.\n */\n@injectable(bindingScopeValues.Singleton)\nexport class MachineStateHome {\n // Resolved roots, keyed by the fallback that was offered. Probing writability costs a mkdir + a\n // stat, and every path lookup in a command goes through here.\n private readonly cache = new Map<string, StateHome>();\n\n /**\n * The machine-global state root.\n *\n * @param cloneFallback the primary clone's root, used ONLY when neither the override nor `$HOME`\n * is usable. Pass the repo root you already resolved; it is never consulted\n * on the happy path.\n */\n resolve(cloneFallback: string): StateHome {\n const cached = this.cache.get(cloneFallback);\n if (cached !== undefined) return cached;\n const home = this.resolveUncached(cloneFallback);\n this.cache.set(cloneFallback, home);\n return home;\n }\n\n private resolveUncached(cloneFallback: string): StateHome {\n const override = (process.env[WEBPIECES_STATE_HOME_ENV] ?? '').trim();\n if (override !== '') {\n // FULL override: this directory IS the root. No `<key>` nesting, no `.webpieces` suffix.\n if (this.usable(override)) return new StateHome(path.resolve(override));\n return new StateHome(\n path.join(cloneFallback, WEBPIECES_TMP_DIR), true,\n `${WEBPIECES_STATE_HOME_ENV}=${override} is not a writable directory`);\n }\n\n const home = this.homeDir();\n if (home !== '') {\n const root = path.join(home, WEBPIECES_TMP_DIR);\n if (this.usable(root)) return new StateHome(root);\n return new StateHome(\n path.join(cloneFallback, WEBPIECES_TMP_DIR), true,\n `${root} could not be created or written to`);\n }\n\n return new StateHome(\n path.join(cloneFallback, WEBPIECES_TMP_DIR), true,\n 'this process has no home directory ($HOME is unset and os.homedir() gave nothing)');\n }\n\n /**\n * `$HOME` FIRST, `os.homedir()` second — deliberately not the other way round.\n *\n * On macOS `os.homedir()` falls back to the PASSWORD DATABASE when `$HOME` is unset, so it happily\n * returns the real home of a process that was launched with a scrubbed environment on purpose. It\n * also makes `HOME=<tmp>` untestable, and a state root nothing can point at a temp directory is a\n * state root nothing has real tests for.\n */\n private homeDir(): string {\n const fromEnv = (process.env['HOME'] ?? '').trim();\n if (fromEnv !== '') return fromEnv;\n // webpieces-disable no-unmanaged-exceptions -- chokepoint: os.homedir() throws on some sandboxes; '' is the honest answer\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n return (os.homedir() ?? '').trim();\n } catch (err: unknown) {\n const error = toError(err);\n void error;\n return '';\n }\n }\n\n // Can we actually create and write inside `dir`? Probed by creating it and writing a marker rather\n // than by reading mode bits: a read-only mount, an SELinux/sandbox denial and a plain permission\n // error all present differently in `stat`, and all of them fail the write identically.\n private usable(dir: string): boolean {\n // webpieces-disable no-unmanaged-exceptions -- chokepoint: any filesystem refusal means \"not usable\", never a crash\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n fs.mkdirSync(dir, { recursive: true });\n const probe = path.join(dir, '.writable-probe');\n fs.writeFileSync(probe, '');\n fs.rmSync(probe, { force: true });\n return true;\n } catch (err: unknown) {\n const error = toError(err);\n void error;\n return false;\n }\n }\n}\n\n/**\n * Process-wide instance for the many non-DI call sites, mirroring `dotWebpieces`. Inversify still\n * injects the singleton wherever a container is in play.\n */\nexport const machineStateHome = new MachineStateHome();\n"]}
@@ -1,143 +0,0 @@
1
- import { AgedTreeSweeper, SweepCount } from './aged-tree-sweep';
2
- import { MachineStateHome, StateHome } from './machine-state-home';
3
- import { DotWebpieces } from './state-dir';
4
- /** The namespace under the machine-global state root. Everything PR-shaped lives beneath it. */
5
- export declare const PRS_STATE_DIR = "prs";
6
- /** The gated squash-commit body `wp-finish-upsert-pr` renders and `wp-land-pr` passes to `gh`. */
7
- export declare const MERGE_BODY_FILE = "merge-commit-body.md";
8
- /** The provenance sidecar — also the `origin.json` marker `decisions/0001` § O3 asks for. */
9
- export declare const PR_ORIGIN_FILE = "origin.json";
10
- /**
11
- * The REMOTE repository a PR belongs to: `github.com` / `deanhiller` / `webpieces-ts30`. Data-only.
12
- *
13
- * `owner` is a PATH, not one token — GitLab subgroups and Azure DevOps project paths are legitimately
14
- * several segments deep, and collapsing them would merge two repos into one directory.
15
- */
16
- export declare class RepoSlug {
17
- readonly host: string;
18
- readonly owner: string;
19
- readonly repo: string;
20
- constructor(host: string, owner: string, repo: string);
21
- /** FALSE when the remote could not be read or parsed — the caller must then not pretend to store. */
22
- get known(): boolean;
23
- /** The directory segments, in order. `owner` may contribute more than one. */
24
- segments(): string[];
25
- toString(): string;
26
- }
27
- /**
28
- * WHO wrote a PR body, and from WHERE. Data-only, serialized beside the body as `origin.json`.
29
- *
30
- * `treeRoot` is the load-bearing field: `wp-land-pr` compares it against the tree it is standing in to
31
- * decide whether the tree-bound bookkeeping (archive the pre-squash tip, promote merge-info, reap the
32
- * worktree) belongs to it. See `land-pr-command.ts`.
33
- */
34
- export declare class PrBodyOrigin {
35
- treeRoot: string;
36
- primaryRoot: string;
37
- branch: string;
38
- feature: string;
39
- prNumber: string;
40
- prUrl: string;
41
- writtenAt: string;
42
- }
43
- /** A stored body: where it is, and the provenance beside it (`null` origin ⇒ no readable sidecar). */
44
- export declare class PrBodyLocation {
45
- readonly dir: string;
46
- readonly bodyFile: string;
47
- readonly origin: PrBodyOrigin | null;
48
- constructor(dir: string, bodyFile: string, origin: PrBodyOrigin | null);
49
- }
50
- /**
51
- * The gated squash-commit body for a PR, stored by the PR's GLOBAL identity rather than by the tree
52
- * that happened to render it:
53
- *
54
- * ~/.webpieces/prs/<host>/<owner>/<repo>/<prNumber>/merge-commit-body.md
55
- *
56
- * ─── The bug this fixes ─────────────────────────────────────────────────────────────────────────────
57
- * The body used to live at `<primary>/.webpieces/worktrees/<name>/pr-review/<branch>/`, i.e. in
58
- * PER-WORKTREE state. But `pr-review/<branch>/` is keyed by BRANCH, and a branch is a REPO-WIDE fact —
59
- * git forbids two worktrees checking out one branch — so a per-tree home only worked while the branch
60
- * never moved trees. The gated flow ran in the primary clone, landing happened from a linked worktree,
61
- * `wp-land-pr` looked under the worktree's namespace and printed "Nothing to land". That is a SCOPE
62
- * MISMATCH, not a missing fallback, and the fix is to give the artifact the scope of its identity.
63
- *
64
- * ─── Why keyed by the remote, when `decisions/0001` § D2 forbids exactly that ───────────────────────
65
- * D2 rejects the remote URL as the key for CLONE state, because two clones of one repo have different
66
- * branches, worktrees and in-flight merges and must NOT share. That reasoning is intact and this is its
67
- * mirror image: a PR NUMBER is a fact of the remote, the same object seen from every clone, and here
68
- * sharing is the REQUIREMENT — landing must work from any tree, and from a second clone of the same
69
- * repo, as long as the PR was posted from this machine. The rule underneath both is one rule: key an
70
- * artifact by the scope of the fact it describes.
71
- *
72
- * ─── Why nested segments and not D2's flattening ────────────────────────────────────────────────────
73
- * D2 flattens because it keys on an absolute PATH, whose separators must survive as data. Here each
74
- * segment is already a single opaque token (`github.com`, `deanhiller`, `webpieces-ts30`, `604`), the
75
- * hierarchy is real, and it buys two things a flattened key cannot: it is browsable by a human
76
- * debugging a landing, and the retention sweep prunes the empty parents of a reaped PR for free.
77
- *
78
- * ─── What is NOT stored here ────────────────────────────────────────────────────────────────────────
79
- * Everything else under `pr-review/<branch>/` — review.json, the per-checklist verdicts, pr-context.json
80
- * and the stage snapshots. Those describe work in progress in ONE tree and correctly stay local. Only
81
- * the finished receipt for a posted PR is machine-global.
82
- *
83
- * ─── Never regenerated ──────────────────────────────────────────────────────────────────────────────
84
- * `wp-land-pr` READS this and never re-renders it. The bytes that land are the bytes finish produced;
85
- * re-deriving them at land time would be a second authoritative gate whose result nobody reads. See
86
- * `land-pr-command.ts`.
87
- */
88
- export declare class PrBodyStore {
89
- private readonly stateHome;
90
- private readonly dotDir;
91
- private readonly sweeper;
92
- private readonly slugByDir;
93
- constructor(stateHome?: MachineStateHome, dotDir?: DotWebpieces, sweeper?: AgedTreeSweeper);
94
- /** The machine-global root this store writes under, plus whether it degraded to the clone. */
95
- home(startDir: string): StateHome;
96
- /** `<state home>/prs` — the sweep root, and the directory a human is pointed at when landing fails. */
97
- prsRoot(startDir: string): string;
98
- /**
99
- * The remote this working tree pushes to. Read from `origin`, because that is the remote `gh` itself
100
- * resolves a PR against — asking a different remote would key the body under a repo the PR is not on.
101
- * An unknown slug (no remote, detached tooling, a URL shape we decline to guess at) is returned as
102
- * `known === false`; it is never fabricated.
103
- */
104
- slugFor(startDir: string): RepoSlug;
105
- /** The directory for one PR, or '' when the remote is unknown or `prNumber` is not a number. */
106
- dirFor(startDir: string, prNumber: string): string;
107
- /**
108
- * Store the gated body for `prNumber` and return where it went — `null` when it cannot be stored at
109
- * all (unknown remote, or a PR whose number could not be read back from GitHub). A `null` here is
110
- * NOT fatal for the caller that is about to merge in the same process: it still holds the bytes. It
111
- * IS the reason a later `wp-land-pr` will report the PR as not found on this machine, which is the
112
- * honest answer — no durable receipt was ever filed.
113
- */
114
- write(startDir: string, prNumber: string, body: string, origin: PrBodyOrigin): PrBodyLocation | null;
115
- /** The stored body for `prNumber`, or `null` when this machine has none. */
116
- read(startDir: string, prNumber: string): PrBodyLocation | null;
117
- /**
118
- * The 30-day reap of `prs/`, run from the same place every other `.webpieces` sweep runs.
119
- *
120
- * `decisions/0001` § O3: these directories outlive every clone, so nothing else will ever delete
121
- * them. A landed PR's body is never rewritten, so it ages out on schedule; a PR still being pushed
122
- * to gets a fresh mtime on every `wp-finish-upsert-pr`, so an open PR is never reaped out from under
123
- * a landing.
124
- */
125
- sweep(startDir: string, onDelete?: (removed: string, isDir: boolean) => void): SweepCount;
126
- private readOrigin;
127
- private str;
128
- private remoteUrl;
129
- /**
130
- * Remote URL → host/owner/repo, for the three shapes git actually hands out:
131
- *
132
- * git@github.com:owner/repo.git scp-like
133
- * ssh://git@github.com:22/owner/repo.git url with a port
134
- * https://user@host/owner/sub/repo.git url, possibly with credentials and subgroups
135
- *
136
- * Anything else returns an UNKNOWN slug rather than a guess. A wrong key here silently files the
137
- * receipt under a repo the PR is not on, which reads to the next reader as "the body was never
138
- * written" — the exact failure being fixed. Not guessing is the only safe default.
139
- */
140
- private parseRemote;
141
- private urlParts;
142
- private safe;
143
- }
@@ -1,301 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PrBodyStore = exports.PrBodyLocation = exports.PrBodyOrigin = exports.RepoSlug = exports.PR_ORIGIN_FILE = exports.MERGE_BODY_FILE = exports.PRS_STATE_DIR = void 0;
4
- const tslib_1 = require("tslib");
5
- const child_process_1 = require("child_process");
6
- const fs = tslib_1.__importStar(require("fs"));
7
- const path = tslib_1.__importStar(require("path"));
8
- const inversify_1 = require("inversify");
9
- const aged_tree_sweep_1 = require("./aged-tree-sweep");
10
- const machine_state_home_1 = require("./machine-state-home");
11
- const state_dir_1 = require("./state-dir");
12
- const to_error_1 = require("./to-error");
13
- /** The namespace under the machine-global state root. Everything PR-shaped lives beneath it. */
14
- exports.PRS_STATE_DIR = 'prs';
15
- /** The gated squash-commit body `wp-finish-upsert-pr` renders and `wp-land-pr` passes to `gh`. */
16
- exports.MERGE_BODY_FILE = 'merge-commit-body.md';
17
- /** The provenance sidecar — also the `origin.json` marker `decisions/0001` § O3 asks for. */
18
- exports.PR_ORIGIN_FILE = 'origin.json';
19
- // Every path segment is a single opaque token taken from a remote URL, so anything that is not an
20
- // ordinary name character is folded away. `.` and `..` are rejected outright rather than folded,
21
- // because folding them to `-`/`--` would silently key two different repos to one directory.
22
- const UNSAFE_SEGMENT_CHARS = /[^A-Za-z0-9._-]+/g;
23
- /**
24
- * The REMOTE repository a PR belongs to: `github.com` / `deanhiller` / `webpieces-ts30`. Data-only.
25
- *
26
- * `owner` is a PATH, not one token — GitLab subgroups and Azure DevOps project paths are legitimately
27
- * several segments deep, and collapsing them would merge two repos into one directory.
28
- */
29
- class RepoSlug {
30
- host;
31
- owner;
32
- repo;
33
- constructor(host, owner, repo) {
34
- this.host = host;
35
- this.owner = owner;
36
- this.repo = repo;
37
- }
38
- /** FALSE when the remote could not be read or parsed — the caller must then not pretend to store. */
39
- get known() {
40
- return this.host !== '' && this.owner !== '' && this.repo !== '';
41
- }
42
- /** The directory segments, in order. `owner` may contribute more than one. */
43
- segments() {
44
- return [this.host, ...this.owner.split('/'), this.repo];
45
- }
46
- toString() {
47
- return `${this.host}/${this.owner}/${this.repo}`;
48
- }
49
- }
50
- exports.RepoSlug = RepoSlug;
51
- /**
52
- * WHO wrote a PR body, and from WHERE. Data-only, serialized beside the body as `origin.json`.
53
- *
54
- * `treeRoot` is the load-bearing field: `wp-land-pr` compares it against the tree it is standing in to
55
- * decide whether the tree-bound bookkeeping (archive the pre-squash tip, promote merge-info, reap the
56
- * worktree) belongs to it. See `land-pr-command.ts`.
57
- */
58
- class PrBodyOrigin {
59
- treeRoot = '';
60
- primaryRoot = '';
61
- branch = '';
62
- feature = '';
63
- prNumber = '';
64
- prUrl = '';
65
- writtenAt = '';
66
- }
67
- exports.PrBodyOrigin = PrBodyOrigin;
68
- /** A stored body: where it is, and the provenance beside it (`null` origin ⇒ no readable sidecar). */
69
- class PrBodyLocation {
70
- dir;
71
- bodyFile;
72
- origin;
73
- constructor(dir, bodyFile, origin) {
74
- this.dir = dir;
75
- this.bodyFile = bodyFile;
76
- this.origin = origin;
77
- }
78
- }
79
- exports.PrBodyLocation = PrBodyLocation;
80
- /**
81
- * The gated squash-commit body for a PR, stored by the PR's GLOBAL identity rather than by the tree
82
- * that happened to render it:
83
- *
84
- * ~/.webpieces/prs/<host>/<owner>/<repo>/<prNumber>/merge-commit-body.md
85
- *
86
- * ─── The bug this fixes ─────────────────────────────────────────────────────────────────────────────
87
- * The body used to live at `<primary>/.webpieces/worktrees/<name>/pr-review/<branch>/`, i.e. in
88
- * PER-WORKTREE state. But `pr-review/<branch>/` is keyed by BRANCH, and a branch is a REPO-WIDE fact —
89
- * git forbids two worktrees checking out one branch — so a per-tree home only worked while the branch
90
- * never moved trees. The gated flow ran in the primary clone, landing happened from a linked worktree,
91
- * `wp-land-pr` looked under the worktree's namespace and printed "Nothing to land". That is a SCOPE
92
- * MISMATCH, not a missing fallback, and the fix is to give the artifact the scope of its identity.
93
- *
94
- * ─── Why keyed by the remote, when `decisions/0001` § D2 forbids exactly that ───────────────────────
95
- * D2 rejects the remote URL as the key for CLONE state, because two clones of one repo have different
96
- * branches, worktrees and in-flight merges and must NOT share. That reasoning is intact and this is its
97
- * mirror image: a PR NUMBER is a fact of the remote, the same object seen from every clone, and here
98
- * sharing is the REQUIREMENT — landing must work from any tree, and from a second clone of the same
99
- * repo, as long as the PR was posted from this machine. The rule underneath both is one rule: key an
100
- * artifact by the scope of the fact it describes.
101
- *
102
- * ─── Why nested segments and not D2's flattening ────────────────────────────────────────────────────
103
- * D2 flattens because it keys on an absolute PATH, whose separators must survive as data. Here each
104
- * segment is already a single opaque token (`github.com`, `deanhiller`, `webpieces-ts30`, `604`), the
105
- * hierarchy is real, and it buys two things a flattened key cannot: it is browsable by a human
106
- * debugging a landing, and the retention sweep prunes the empty parents of a reaped PR for free.
107
- *
108
- * ─── What is NOT stored here ────────────────────────────────────────────────────────────────────────
109
- * Everything else under `pr-review/<branch>/` — review.json, the per-checklist verdicts, pr-context.json
110
- * and the stage snapshots. Those describe work in progress in ONE tree and correctly stay local. Only
111
- * the finished receipt for a posted PR is machine-global.
112
- *
113
- * ─── Never regenerated ──────────────────────────────────────────────────────────────────────────────
114
- * `wp-land-pr` READS this and never re-renders it. The bytes that land are the bytes finish produced;
115
- * re-deriving them at land time would be a second authoritative gate whose result nobody reads. See
116
- * `land-pr-command.ts`.
117
- */
118
- let PrBodyStore = class PrBodyStore {
119
- stateHome;
120
- dotDir;
121
- sweeper;
122
- // startDir → the remote slug. `git remote get-url` is a process spawn; commands ask more than once.
123
- slugByDir = new Map();
124
- constructor(stateHome = machine_state_home_1.machineStateHome, dotDir = state_dir_1.dotWebpieces, sweeper = new aged_tree_sweep_1.AgedTreeSweeper()) {
125
- this.stateHome = stateHome;
126
- this.dotDir = dotDir;
127
- this.sweeper = sweeper;
128
- }
129
- /** The machine-global root this store writes under, plus whether it degraded to the clone. */
130
- home(startDir) {
131
- return this.stateHome.resolve(this.dotDir.primaryRoot(startDir));
132
- }
133
- /** `<state home>/prs` — the sweep root, and the directory a human is pointed at when landing fails. */
134
- prsRoot(startDir) {
135
- return path.join(this.home(startDir).root, exports.PRS_STATE_DIR);
136
- }
137
- /**
138
- * The remote this working tree pushes to. Read from `origin`, because that is the remote `gh` itself
139
- * resolves a PR against — asking a different remote would key the body under a repo the PR is not on.
140
- * An unknown slug (no remote, detached tooling, a URL shape we decline to guess at) is returned as
141
- * `known === false`; it is never fabricated.
142
- */
143
- slugFor(startDir) {
144
- const cached = this.slugByDir.get(startDir);
145
- if (cached !== undefined)
146
- return cached;
147
- const slug = this.parseRemote(this.remoteUrl(startDir));
148
- this.slugByDir.set(startDir, slug);
149
- return slug;
150
- }
151
- /** The directory for one PR, or '' when the remote is unknown or `prNumber` is not a number. */
152
- dirFor(startDir, prNumber) {
153
- const slug = this.slugFor(startDir);
154
- if (!slug.known || !/^\d+$/.test(prNumber.trim()))
155
- return '';
156
- return path.join(this.prsRoot(startDir), ...slug.segments(), prNumber.trim());
157
- }
158
- /**
159
- * Store the gated body for `prNumber` and return where it went — `null` when it cannot be stored at
160
- * all (unknown remote, or a PR whose number could not be read back from GitHub). A `null` here is
161
- * NOT fatal for the caller that is about to merge in the same process: it still holds the bytes. It
162
- * IS the reason a later `wp-land-pr` will report the PR as not found on this machine, which is the
163
- * honest answer — no durable receipt was ever filed.
164
- */
165
- write(startDir, prNumber, body, origin) {
166
- const dir = this.dirFor(startDir, prNumber);
167
- if (dir === '')
168
- return null;
169
- // webpieces-disable no-unmanaged-exceptions -- chokepoint: a store that cannot be written degrades to null, never a crash mid-PR-post
170
- // eslint-disable-next-line @webpieces/no-unmanaged-exceptions
171
- try {
172
- fs.mkdirSync(dir, { recursive: true });
173
- const bodyFile = path.join(dir, exports.MERGE_BODY_FILE);
174
- fs.writeFileSync(bodyFile, body);
175
- fs.writeFileSync(path.join(dir, exports.PR_ORIGIN_FILE), JSON.stringify(origin, null, 2) + '\n');
176
- return new PrBodyLocation(dir, bodyFile, origin);
177
- }
178
- catch (err) {
179
- const error = (0, to_error_1.toError)(err);
180
- void error;
181
- return null;
182
- }
183
- }
184
- /** The stored body for `prNumber`, or `null` when this machine has none. */
185
- read(startDir, prNumber) {
186
- const dir = this.dirFor(startDir, prNumber);
187
- if (dir === '')
188
- return null;
189
- const bodyFile = path.join(dir, exports.MERGE_BODY_FILE);
190
- if (!fs.existsSync(bodyFile))
191
- return null;
192
- return new PrBodyLocation(dir, bodyFile, this.readOrigin(dir));
193
- }
194
- /**
195
- * The 30-day reap of `prs/`, run from the same place every other `.webpieces` sweep runs.
196
- *
197
- * `decisions/0001` § O3: these directories outlive every clone, so nothing else will ever delete
198
- * them. A landed PR's body is never rewritten, so it ages out on schedule; a PR still being pushed
199
- * to gets a fresh mtime on every `wp-finish-upsert-pr`, so an open PR is never reaped out from under
200
- * a landing.
201
- */
202
- sweep(startDir, onDelete = () => { }) {
203
- return this.sweeper.sweep(this.prsRoot(startDir), aged_tree_sweep_1.RETENTION_DAYS * 24 * 60 * 60 * 1000, onDelete);
204
- }
205
- readOrigin(dir) {
206
- const file = path.join(dir, exports.PR_ORIGIN_FILE);
207
- if (!fs.existsSync(file))
208
- return null;
209
- // webpieces-disable no-unmanaged-exceptions -- chokepoint: an unreadable sidecar means "no provenance", never a crash
210
- // eslint-disable-next-line @webpieces/no-unmanaged-exceptions
211
- try {
212
- // webpieces-disable no-any-unknown -- parsed JSON is opaque until narrowed field-by-field below
213
- const raw = JSON.parse(fs.readFileSync(file, 'utf8'));
214
- const origin = new PrBodyOrigin();
215
- origin.treeRoot = this.str(raw['treeRoot']);
216
- origin.primaryRoot = this.str(raw['primaryRoot']);
217
- origin.branch = this.str(raw['branch']);
218
- origin.feature = this.str(raw['feature']);
219
- origin.prNumber = this.str(raw['prNumber']);
220
- origin.prUrl = this.str(raw['prUrl']);
221
- origin.writtenAt = this.str(raw['writtenAt']);
222
- return origin;
223
- }
224
- catch (err) {
225
- const error = (0, to_error_1.toError)(err);
226
- void error;
227
- return null;
228
- }
229
- }
230
- // webpieces-disable no-any-unknown -- one opaque JSON field, narrowed to string
231
- str(value) {
232
- return typeof value === 'string' ? value : '';
233
- }
234
- remoteUrl(startDir) {
235
- const result = (0, child_process_1.spawnSync)('git', ['-C', startDir, 'remote', 'get-url', 'origin'], { encoding: 'utf8' });
236
- if (result.status !== 0)
237
- return '';
238
- return (result.stdout ?? '').trim();
239
- }
240
- /**
241
- * Remote URL → host/owner/repo, for the three shapes git actually hands out:
242
- *
243
- * git@github.com:owner/repo.git scp-like
244
- * ssh://git@github.com:22/owner/repo.git url with a port
245
- * https://user@host/owner/sub/repo.git url, possibly with credentials and subgroups
246
- *
247
- * Anything else returns an UNKNOWN slug rather than a guess. A wrong key here silently files the
248
- * receipt under a repo the PR is not on, which reads to the next reader as "the body was never
249
- * written" — the exact failure being fixed. Not guessing is the only safe default.
250
- */
251
- parseRemote(url) {
252
- const unknown = new RepoSlug('', '', '');
253
- if (url === '')
254
- return unknown;
255
- const scp = /^(?:[^@/]+@)?([^:/@]+):(?!\/)(.+)$/.exec(url);
256
- const parts = scp !== null
257
- ? new RemoteParts(scp[1] ?? '', scp[2] ?? '')
258
- : this.urlParts(url);
259
- if (parts === null)
260
- return unknown;
261
- const segments = parts.pathPart.replace(/\.git$/, '').split('/').filter((s) => s !== '');
262
- if (segments.length < 2)
263
- return unknown;
264
- const repo = this.safe(segments[segments.length - 1] ?? '');
265
- const owner = segments.slice(0, -1).map((s) => this.safe(s)).join('/');
266
- const host = this.safe(parts.host);
267
- if (repo === '' || owner.includes('//') || owner === '' || host === '')
268
- return unknown;
269
- return new RepoSlug(host, owner, repo);
270
- }
271
- urlParts(url) {
272
- const match = /^[a-zA-Z][a-zA-Z0-9+.-]*:\/\/(?:[^@/]+@)?([^/:]+)(?::\d+)?\/(.+)$/.exec(url);
273
- if (match === null)
274
- return null;
275
- return new RemoteParts(match[1] ?? '', match[2] ?? '');
276
- }
277
- // One path segment, reduced to characters that cannot escape the directory they name. `.` and `..`
278
- // are refused rather than folded: folding them would key two distinct repos to one directory.
279
- safe(segment) {
280
- if (segment === '.' || segment === '..')
281
- return '';
282
- return segment.replace(UNSAFE_SEGMENT_CHARS, '-');
283
- }
284
- };
285
- exports.PrBodyStore = PrBodyStore;
286
- exports.PrBodyStore = PrBodyStore = tslib_1.__decorate([
287
- (0, inversify_1.injectable)(inversify_1.bindingScopeValues.Singleton),
288
- tslib_1.__metadata("design:paramtypes", [machine_state_home_1.MachineStateHome,
289
- state_dir_1.DotWebpieces,
290
- aged_tree_sweep_1.AgedTreeSweeper])
291
- ], PrBodyStore);
292
- /** Data-only split of a remote URL into the two pieces the slug needs. */
293
- class RemoteParts {
294
- host;
295
- pathPart;
296
- constructor(host, pathPart) {
297
- this.host = host;
298
- this.pathPart = pathPart;
299
- }
300
- }
301
- //# sourceMappingURL=pr-body-store.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"pr-body-store.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/pr-body-store.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawnSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { injectable, bindingScopeValues } from 'inversify';\n\nimport { AgedTreeSweeper, RETENTION_DAYS, SweepCount } from './aged-tree-sweep';\nimport { MachineStateHome, StateHome, machineStateHome } from './machine-state-home';\nimport { DotWebpieces, dotWebpieces } from './state-dir';\nimport { toError } from './to-error';\n\n/** The namespace under the machine-global state root. Everything PR-shaped lives beneath it. */\nexport const PRS_STATE_DIR = 'prs';\n/** The gated squash-commit body `wp-finish-upsert-pr` renders and `wp-land-pr` passes to `gh`. */\nexport const MERGE_BODY_FILE = 'merge-commit-body.md';\n/** The provenance sidecar — also the `origin.json` marker `decisions/0001` § O3 asks for. */\nexport const PR_ORIGIN_FILE = 'origin.json';\n\n// Every path segment is a single opaque token taken from a remote URL, so anything that is not an\n// ordinary name character is folded away. `.` and `..` are rejected outright rather than folded,\n// because folding them to `-`/`--` would silently key two different repos to one directory.\nconst UNSAFE_SEGMENT_CHARS = /[^A-Za-z0-9._-]+/g;\n\n/**\n * The REMOTE repository a PR belongs to: `github.com` / `deanhiller` / `webpieces-ts30`. Data-only.\n *\n * `owner` is a PATH, not one token — GitLab subgroups and Azure DevOps project paths are legitimately\n * several segments deep, and collapsing them would merge two repos into one directory.\n */\nexport class RepoSlug {\n readonly host: string;\n readonly owner: string;\n readonly repo: string;\n\n constructor(host: string, owner: string, repo: string) {\n this.host = host;\n this.owner = owner;\n this.repo = repo;\n }\n\n /** FALSE when the remote could not be read or parsed — the caller must then not pretend to store. */\n get known(): boolean {\n return this.host !== '' && this.owner !== '' && this.repo !== '';\n }\n\n /** The directory segments, in order. `owner` may contribute more than one. */\n segments(): string[] {\n return [this.host, ...this.owner.split('/'), this.repo];\n }\n\n toString(): string {\n return `${this.host}/${this.owner}/${this.repo}`;\n }\n}\n\n/**\n * WHO wrote a PR body, and from WHERE. Data-only, serialized beside the body as `origin.json`.\n *\n * `treeRoot` is the load-bearing field: `wp-land-pr` compares it against the tree it is standing in to\n * decide whether the tree-bound bookkeeping (archive the pre-squash tip, promote merge-info, reap the\n * worktree) belongs to it. See `land-pr-command.ts`.\n */\nexport class PrBodyOrigin {\n treeRoot = '';\n primaryRoot = '';\n branch = '';\n feature = '';\n prNumber = '';\n prUrl = '';\n writtenAt = '';\n}\n\n/** A stored body: where it is, and the provenance beside it (`null` origin ⇒ no readable sidecar). */\nexport class PrBodyLocation {\n readonly dir: string;\n readonly bodyFile: string;\n readonly origin: PrBodyOrigin | null;\n\n constructor(dir: string, bodyFile: string, origin: PrBodyOrigin | null) {\n this.dir = dir;\n this.bodyFile = bodyFile;\n this.origin = origin;\n }\n}\n\n/**\n * The gated squash-commit body for a PR, stored by the PR's GLOBAL identity rather than by the tree\n * that happened to render it:\n *\n * ~/.webpieces/prs/<host>/<owner>/<repo>/<prNumber>/merge-commit-body.md\n *\n * ─── The bug this fixes ─────────────────────────────────────────────────────────────────────────────\n * The body used to live at `<primary>/.webpieces/worktrees/<name>/pr-review/<branch>/`, i.e. in\n * PER-WORKTREE state. But `pr-review/<branch>/` is keyed by BRANCH, and a branch is a REPO-WIDE fact —\n * git forbids two worktrees checking out one branch — so a per-tree home only worked while the branch\n * never moved trees. The gated flow ran in the primary clone, landing happened from a linked worktree,\n * `wp-land-pr` looked under the worktree's namespace and printed \"Nothing to land\". That is a SCOPE\n * MISMATCH, not a missing fallback, and the fix is to give the artifact the scope of its identity.\n *\n * ─── Why keyed by the remote, when `decisions/0001` § D2 forbids exactly that ───────────────────────\n * D2 rejects the remote URL as the key for CLONE state, because two clones of one repo have different\n * branches, worktrees and in-flight merges and must NOT share. That reasoning is intact and this is its\n * mirror image: a PR NUMBER is a fact of the remote, the same object seen from every clone, and here\n * sharing is the REQUIREMENT — landing must work from any tree, and from a second clone of the same\n * repo, as long as the PR was posted from this machine. The rule underneath both is one rule: key an\n * artifact by the scope of the fact it describes.\n *\n * ─── Why nested segments and not D2's flattening ────────────────────────────────────────────────────\n * D2 flattens because it keys on an absolute PATH, whose separators must survive as data. Here each\n * segment is already a single opaque token (`github.com`, `deanhiller`, `webpieces-ts30`, `604`), the\n * hierarchy is real, and it buys two things a flattened key cannot: it is browsable by a human\n * debugging a landing, and the retention sweep prunes the empty parents of a reaped PR for free.\n *\n * ─── What is NOT stored here ────────────────────────────────────────────────────────────────────────\n * Everything else under `pr-review/<branch>/` — review.json, the per-checklist verdicts, pr-context.json\n * and the stage snapshots. Those describe work in progress in ONE tree and correctly stay local. Only\n * the finished receipt for a posted PR is machine-global.\n *\n * ─── Never regenerated ──────────────────────────────────────────────────────────────────────────────\n * `wp-land-pr` READS this and never re-renders it. The bytes that land are the bytes finish produced;\n * re-deriving them at land time would be a second authoritative gate whose result nobody reads. See\n * `land-pr-command.ts`.\n */\n@injectable(bindingScopeValues.Singleton)\nexport class PrBodyStore {\n // startDir → the remote slug. `git remote get-url` is a process spawn; commands ask more than once.\n private readonly slugByDir = new Map<string, RepoSlug>();\n\n constructor(\n private readonly stateHome: MachineStateHome = machineStateHome,\n private readonly dotDir: DotWebpieces = dotWebpieces,\n private readonly sweeper: AgedTreeSweeper = new AgedTreeSweeper(),\n ) {}\n\n /** The machine-global root this store writes under, plus whether it degraded to the clone. */\n home(startDir: string): StateHome {\n return this.stateHome.resolve(this.dotDir.primaryRoot(startDir));\n }\n\n /** `<state home>/prs` — the sweep root, and the directory a human is pointed at when landing fails. */\n prsRoot(startDir: string): string {\n return path.join(this.home(startDir).root, PRS_STATE_DIR);\n }\n\n /**\n * The remote this working tree pushes to. Read from `origin`, because that is the remote `gh` itself\n * resolves a PR against — asking a different remote would key the body under a repo the PR is not on.\n * An unknown slug (no remote, detached tooling, a URL shape we decline to guess at) is returned as\n * `known === false`; it is never fabricated.\n */\n slugFor(startDir: string): RepoSlug {\n const cached = this.slugByDir.get(startDir);\n if (cached !== undefined) return cached;\n const slug = this.parseRemote(this.remoteUrl(startDir));\n this.slugByDir.set(startDir, slug);\n return slug;\n }\n\n /** The directory for one PR, or '' when the remote is unknown or `prNumber` is not a number. */\n dirFor(startDir: string, prNumber: string): string {\n const slug = this.slugFor(startDir);\n if (!slug.known || !/^\\d+$/.test(prNumber.trim())) return '';\n return path.join(this.prsRoot(startDir), ...slug.segments(), prNumber.trim());\n }\n\n /**\n * Store the gated body for `prNumber` and return where it went — `null` when it cannot be stored at\n * all (unknown remote, or a PR whose number could not be read back from GitHub). A `null` here is\n * NOT fatal for the caller that is about to merge in the same process: it still holds the bytes. It\n * IS the reason a later `wp-land-pr` will report the PR as not found on this machine, which is the\n * honest answer — no durable receipt was ever filed.\n */\n write(startDir: string, prNumber: string, body: string, origin: PrBodyOrigin): PrBodyLocation | null {\n const dir = this.dirFor(startDir, prNumber);\n if (dir === '') return null;\n // webpieces-disable no-unmanaged-exceptions -- chokepoint: a store that cannot be written degrades to null, never a crash mid-PR-post\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n fs.mkdirSync(dir, { recursive: true });\n const bodyFile = path.join(dir, MERGE_BODY_FILE);\n fs.writeFileSync(bodyFile, body);\n fs.writeFileSync(path.join(dir, PR_ORIGIN_FILE), JSON.stringify(origin, null, 2) + '\\n');\n return new PrBodyLocation(dir, bodyFile, origin);\n } catch (err: unknown) {\n const error = toError(err);\n void error;\n return null;\n }\n }\n\n /** The stored body for `prNumber`, or `null` when this machine has none. */\n read(startDir: string, prNumber: string): PrBodyLocation | null {\n const dir = this.dirFor(startDir, prNumber);\n if (dir === '') return null;\n const bodyFile = path.join(dir, MERGE_BODY_FILE);\n if (!fs.existsSync(bodyFile)) return null;\n return new PrBodyLocation(dir, bodyFile, this.readOrigin(dir));\n }\n\n /**\n * The 30-day reap of `prs/`, run from the same place every other `.webpieces` sweep runs.\n *\n * `decisions/0001` § O3: these directories outlive every clone, so nothing else will ever delete\n * them. A landed PR's body is never rewritten, so it ages out on schedule; a PR still being pushed\n * to gets a fresh mtime on every `wp-finish-upsert-pr`, so an open PR is never reaped out from under\n * a landing.\n */\n sweep(startDir: string, onDelete: (removed: string, isDir: boolean) => void = (): void => {}): SweepCount {\n return this.sweeper.sweep(this.prsRoot(startDir), RETENTION_DAYS * 24 * 60 * 60 * 1000, onDelete);\n }\n\n private readOrigin(dir: string): PrBodyOrigin | null {\n const file = path.join(dir, PR_ORIGIN_FILE);\n if (!fs.existsSync(file)) return null;\n // webpieces-disable no-unmanaged-exceptions -- chokepoint: an unreadable sidecar means \"no provenance\", never a crash\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n // webpieces-disable no-any-unknown -- parsed JSON is opaque until narrowed field-by-field below\n const raw = JSON.parse(fs.readFileSync(file, 'utf8')) as Record<string, unknown>;\n const origin = new PrBodyOrigin();\n origin.treeRoot = this.str(raw['treeRoot']);\n origin.primaryRoot = this.str(raw['primaryRoot']);\n origin.branch = this.str(raw['branch']);\n origin.feature = this.str(raw['feature']);\n origin.prNumber = this.str(raw['prNumber']);\n origin.prUrl = this.str(raw['prUrl']);\n origin.writtenAt = this.str(raw['writtenAt']);\n return origin;\n } catch (err: unknown) {\n const error = toError(err);\n void error;\n return null;\n }\n }\n\n // webpieces-disable no-any-unknown -- one opaque JSON field, narrowed to string\n private str(value: unknown): string {\n return typeof value === 'string' ? value : '';\n }\n\n private remoteUrl(startDir: string): string {\n const result = spawnSync('git', ['-C', startDir, 'remote', 'get-url', 'origin'], { encoding: 'utf8' });\n if (result.status !== 0) return '';\n return (result.stdout ?? '').trim();\n }\n\n /**\n * Remote URL → host/owner/repo, for the three shapes git actually hands out:\n *\n * git@github.com:owner/repo.git scp-like\n * ssh://git@github.com:22/owner/repo.git url with a port\n * https://user@host/owner/sub/repo.git url, possibly with credentials and subgroups\n *\n * Anything else returns an UNKNOWN slug rather than a guess. A wrong key here silently files the\n * receipt under a repo the PR is not on, which reads to the next reader as \"the body was never\n * written\" — the exact failure being fixed. Not guessing is the only safe default.\n */\n private parseRemote(url: string): RepoSlug {\n const unknown = new RepoSlug('', '', '');\n if (url === '') return unknown;\n const scp = /^(?:[^@/]+@)?([^:/@]+):(?!\\/)(.+)$/.exec(url);\n const parts = scp !== null\n ? new RemoteParts(scp[1] ?? '', scp[2] ?? '')\n : this.urlParts(url);\n if (parts === null) return unknown;\n\n const segments = parts.pathPart.replace(/\\.git$/, '').split('/').filter((s: string): boolean => s !== '');\n if (segments.length < 2) return unknown;\n const repo = this.safe(segments[segments.length - 1] ?? '');\n const owner = segments.slice(0, -1).map((s: string): string => this.safe(s)).join('/');\n const host = this.safe(parts.host);\n if (repo === '' || owner.includes('//') || owner === '' || host === '') return unknown;\n return new RepoSlug(host, owner, repo);\n }\n\n private urlParts(url: string): RemoteParts | null {\n const match = /^[a-zA-Z][a-zA-Z0-9+.-]*:\\/\\/(?:[^@/]+@)?([^/:]+)(?::\\d+)?\\/(.+)$/.exec(url);\n if (match === null) return null;\n return new RemoteParts(match[1] ?? '', match[2] ?? '');\n }\n\n // One path segment, reduced to characters that cannot escape the directory they name. `.` and `..`\n // are refused rather than folded: folding them would key two distinct repos to one directory.\n private safe(segment: string): string {\n if (segment === '.' || segment === '..') return '';\n return segment.replace(UNSAFE_SEGMENT_CHARS, '-');\n }\n}\n\n/** Data-only split of a remote URL into the two pieces the slug needs. */\nclass RemoteParts {\n readonly host: string;\n readonly pathPart: string;\n\n constructor(host: string, pathPart: string) {\n this.host = host;\n this.pathPart = pathPart;\n }\n}\n"]}