@webpieces/pr-gate 0.4.497 → 0.4.499

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.
Files changed (53) hide show
  1. package/package.json +3 -3
  2. package/src/dashboard/dashboard.d.ts +15 -0
  3. package/src/dashboard/dashboard.js +25 -2
  4. package/src/dashboard/dashboard.js.map +1 -1
  5. package/src/scripts/commands/cleanup-command.d.ts +42 -3
  6. package/src/scripts/commands/cleanup-command.js +69 -11
  7. package/src/scripts/commands/cleanup-command.js.map +1 -1
  8. package/src/scripts/commands/finish-upsert-pr-command.d.ts +55 -5
  9. package/src/scripts/commands/finish-upsert-pr-command.js +162 -30
  10. package/src/scripts/commands/finish-upsert-pr-command.js.map +1 -1
  11. package/src/scripts/commands/land-pr-command.d.ts +17 -2
  12. package/src/scripts/commands/land-pr-command.js +32 -3
  13. package/src/scripts/commands/land-pr-command.js.map +1 -1
  14. package/src/scripts/commands/review-upsert-pr-command.d.ts +88 -0
  15. package/src/scripts/commands/review-upsert-pr-command.js +244 -0
  16. package/src/scripts/commands/review-upsert-pr-command.js.map +1 -0
  17. package/src/scripts/commands/start-upsert-pr-command.d.ts +10 -15
  18. package/src/scripts/commands/start-upsert-pr-command.js +41 -47
  19. package/src/scripts/commands/start-upsert-pr-command.js.map +1 -1
  20. package/src/scripts/commands/worktree-cleanup.d.ts +45 -0
  21. package/src/scripts/commands/worktree-cleanup.js +130 -0
  22. package/src/scripts/commands/worktree-cleanup.js.map +1 -0
  23. package/src/scripts/pr-gate-app.d.ts +9 -5
  24. package/src/scripts/pr-gate-app.js +12 -8
  25. package/src/scripts/pr-gate-app.js.map +1 -1
  26. package/src/scripts/workflow/checklist-scanner.d.ts +27 -11
  27. package/src/scripts/workflow/checklist-scanner.js +37 -15
  28. package/src/scripts/workflow/checklist-scanner.js.map +1 -1
  29. package/src/scripts/workflow/diff-basis.d.ts +53 -0
  30. package/src/scripts/workflow/diff-basis.js +113 -0
  31. package/src/scripts/workflow/diff-basis.js.map +1 -0
  32. package/src/scripts/workflow/diff-materializer.d.ts +85 -0
  33. package/src/scripts/workflow/diff-materializer.js +253 -0
  34. package/src/scripts/workflow/diff-materializer.js.map +1 -0
  35. package/src/scripts/workflow/git-findForkPoint.d.ts +1 -1
  36. package/src/scripts/workflow/git-findForkPoint.js +1 -1
  37. package/src/scripts/workflow/git-findForkPoint.js.map +1 -1
  38. package/src/scripts/workflow/pr-context-writer.d.ts +16 -10
  39. package/src/scripts/workflow/pr-context-writer.js +20 -14
  40. package/src/scripts/workflow/pr-context-writer.js.map +1 -1
  41. package/src/scripts/workflow/review-stage-receipt.d.ts +36 -0
  42. package/src/scripts/workflow/review-stage-receipt.js +82 -0
  43. package/src/scripts/workflow/review-stage-receipt.js.map +1 -0
  44. package/src/scripts/workflow/reviewer-briefing-builder.d.ts +36 -0
  45. package/src/scripts/workflow/reviewer-briefing-builder.js +104 -0
  46. package/src/scripts/workflow/reviewer-briefing-builder.js.map +1 -0
  47. package/src/scripts/{wp-checklist.js → wp-review-upsert-pr.js} +3 -3
  48. package/src/scripts/wp-review-upsert-pr.js.map +1 -0
  49. package/src/scripts/commands/checklist-command.d.ts +0 -27
  50. package/src/scripts/commands/checklist-command.js +0 -97
  51. package/src/scripts/commands/checklist-command.js.map +0 -1
  52. package/src/scripts/wp-checklist.js.map +0 -1
  53. /package/src/scripts/{wp-checklist.d.ts → wp-review-upsert-pr.d.ts} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webpieces/pr-gate",
3
- "version": "0.4.497",
3
+ "version": "0.4.499",
4
4
  "description": "Gated PR system: 3-point squash-merge, merge validation gate, and red/yellow/green PR dashboard. Standalone scripts, no Nx dependency required.",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -12,7 +12,7 @@
12
12
  "wp-cleanup": "./src/scripts/wp-cleanup.js",
13
13
  "wp-land-pr": "./src/scripts/wp-land-pr.js",
14
14
  "wp-check-pr": "./src/scripts/wp-check-pr.js",
15
- "wp-checklist": "./src/scripts/wp-checklist.js"
15
+ "wp-review-upsert-pr": "./src/scripts/wp-review-upsert-pr.js"
16
16
  },
17
17
  "files": [
18
18
  "src/**/*"
@@ -25,7 +25,7 @@
25
25
  "directory": "packages/tooling/pr-gate"
26
26
  },
27
27
  "dependencies": {
28
- "@webpieces/rules-config": "0.4.497",
28
+ "@webpieces/rules-config": "0.4.499",
29
29
  "@inversifyjs/binding-decorators": "1.1.5",
30
30
  "inversify": "7.10.4",
31
31
  "reflect-metadata": "0.2.2"
@@ -30,6 +30,15 @@ export declare class ChecklistCommentRow {
30
30
  firedPatterns: string[];
31
31
  matchedFiles: string[];
32
32
  changedFileCount: number;
33
+ /**
34
+ * Whether this reviewer's own transcript shows it OPENING the extracted diff.
35
+ *
36
+ * '' = not assessed (no Claude Code session, or nothing was materialized) and prints nothing — "no
37
+ * evidence recorded" and "evidence says it never looked" are different claims, and conflating them
38
+ * would accuse a reviewer that ran perfectly well in CI. 'yes' | 'no' otherwise. Defaulted, so every
39
+ * existing construction site is unchanged.
40
+ */
41
+ diffRead: string;
33
42
  constructor(subagent: string, status: string, detail: string, ran: boolean, configuredPatterns: string[], firedPatterns: string[], matchedFiles: string[], changedFileCount: number);
34
43
  }
35
44
  export declare class DisableCounts {
@@ -72,6 +81,12 @@ export declare class Dashboard {
72
81
  private rollupHeader;
73
82
  private rollupCounts;
74
83
  private rosterBullet;
84
+ /**
85
+ * Whether the reviewer demonstrably opened the diff, read from its own transcript. A QUALITY signal and
86
+ * never a blocker (see SubagentProvenanceService.evidenceFor) — but published, because "wrote a verdict
87
+ * without reading the change" is exactly what a reader of this comment would want to weigh.
88
+ */
89
+ private evidenceSuffix;
75
90
  private verdictEmoji;
76
91
  private verdictWords;
77
92
  /**
@@ -67,6 +67,15 @@ class ChecklistCommentRow {
67
67
  firedPatterns; // which configured globs actually hit a changed file
68
68
  matchedFiles;
69
69
  changedFileCount; // how many files were considered at all — "0 of N" needs the N
70
+ /**
71
+ * Whether this reviewer's own transcript shows it OPENING the extracted diff.
72
+ *
73
+ * '' = not assessed (no Claude Code session, or nothing was materialized) and prints nothing — "no
74
+ * evidence recorded" and "evidence says it never looked" are different claims, and conflating them
75
+ * would accuse a reviewer that ran perfectly well in CI. 'yes' | 'no' otherwise. Defaulted, so every
76
+ * existing construction site is unchanged.
77
+ */
78
+ diffRead = '';
70
79
  // eslint-disable-next-line @typescript-eslint/max-params
71
80
  constructor(subagent, status, detail, ran, configuredPatterns, firedPatterns, matchedFiles, changedFileCount) {
72
81
  this.subagent = subagent;
@@ -246,9 +255,19 @@ let Dashboard = class Dashboard {
246
255
  // checklist was evaluated and did not apply, which the words state as the good news it is.
247
256
  rosterBullet(row) {
248
257
  const box = row.ran ? '- [x]' : '- [ ]';
249
- return `${box} ${this.verdictEmoji(row)} **${row.subagent}** — ${this.verdictWords(row)}\n` +
258
+ return `${box} ${this.verdictEmoji(row)} **${row.subagent}** — ${this.verdictWords(row)}${this.evidenceSuffix(row)}\n` +
250
259
  ` - ${this.whyLine(row)}`;
251
260
  }
261
+ /**
262
+ * Whether the reviewer demonstrably opened the diff, read from its own transcript. A QUALITY signal and
263
+ * never a blocker (see SubagentProvenanceService.evidenceFor) — but published, because "wrote a verdict
264
+ * without reading the change" is exactly what a reader of this comment would want to weigh.
265
+ */
266
+ evidenceSuffix(row) {
267
+ if (!row.ran || row.diffRead === '')
268
+ return '';
269
+ return row.diffRead === 'yes' ? ' _(diff read ✓)_' : ' _(⚠️ no diff read recorded)_';
270
+ }
252
271
  verdictEmoji(row) {
253
272
  if (!row.ran)
254
273
  return '⚪';
@@ -288,7 +307,11 @@ let Dashboard = class Dashboard {
288
307
  whyLine(row) {
289
308
  const total = row.changedFileCount;
290
309
  if (row.configuredPatterns.length === 0) {
291
- return `ALWAYS RUNS (no patterns) whole diff in scope, ${total} changed file(s): ` +
310
+ // Say what "no patterns" COSTS, not just what it means. Six patternless checklists all firing on
311
+ // a one-file docs PR is what a missing `patterns` looks like from the outside, and a reader who
312
+ // is told only "ALWAYS RUNS" has no reason to suspect the config rather than the diff.
313
+ return `ALWAYS RUNS — no \`patterns\` configured, so this fires on EVERY PR including docs-only ` +
314
+ `ones; add \`patterns\` if that is not intended. Whole diff in scope, ${total} changed file(s): ` +
292
315
  `${(0, rules_config_1.formatFileList)(row.matchedFiles)}`;
293
316
  }
294
317
  const configured = this.asCode(row.configuredPatterns);
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../../../../../packages/tooling/pr-gate/src/dashboard/dashboard.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n GateDefinition, WEBPIECES_DISABLE, RULE_NAMES, ReviewJson, formatFileList,\n CK_PASS, CK_WARN, CK_OVERRIDDEN, CK_FAIL, CK_MISSING,\n} from '@webpieces/rules-config';\nimport { injectable, bindingScopeValues } from 'inversify';\n\n// Hidden marker on the checklist review COMMENT, so wp-finish can find + PATCH its own comment on every\n// push instead of appending a new one. Versioned so the format can evolve without matching an old shape.\n// v2 = the full roster (every DEFINED checklist, matched or not) + tri-state verdicts.\nexport const CHECKLIST_COMMENT_MARKER = '<!-- webpieces-checklists v2 -->';\nconst COMMENT_LIMIT = 65000; // under GitHub's 65536-char cap, with headroom for the marker + roll-up.\n\n// One checklist section for the combined comment (heading + verbatim reviewer output), so oversize\n// truncation can shrink the longest BODY without ever dropping a verdict heading.\nclass CommentSection {\n heading: string;\n body: string;\n\n constructor(heading: string, body: string) {\n this.heading = heading;\n this.body = body;\n }\n}\n\nexport class GateResult {\n name: string;\n warningColor: string; // 'yellow' | 'red' — the color shown WHEN files matched (green is implicit)\n matchedFiles: string[];\n\n constructor(name: string, warningColor: string, matchedFiles: string[]) {\n this.name = name;\n this.warningColor = warningColor;\n this.matchedFiles = matchedFiles;\n }\n}\n\n// One row for a consumer review checklist the branch triggered. `status` is the resolved verdict (one of\n// CK_PASS | CK_WARN | CK_OVERRIDDEN | CK_FAIL | CK_MISSING | CK_BAD_FORMAT); `detail` is the reviewer\n// output / override justification. A row is always PASS/WARN/OVERRIDDEN by the time it renders — a failed,\n// missing or unreadable verdict throws before the dashboard is built. Rendered into the PR body so the\n// verdict reaches the server — the PR body is the artifact of the local flow that leaves the checkout\n// (alongside the HMAC gate token that proves the flow ran).\nexport class ChecklistRow {\n title: string; // the checklist id (= reviewer subagent name)\n status: string; // CK_* verdict\n detail: string; // reviewer output / override justification (surfaced for OVERRIDDEN)\n\n constructor(title: string, status: string, detail = '') {\n this.title = title;\n this.status = status;\n this.detail = detail;\n }\n}\n\n/**\n * One roster line of the checklist COMMENT: a defined checklist, whether its reviewer ran, and the evidence\n * for WHY. Deliberately separate from {@link ChecklistRow} rather than five more fields on it — ChecklistRow\n * also feeds the PR body and the squash-commit body, and roster evidence has no business travelling into\n * main's git history or through every DashboardInput construction site.\n *\n * Kept in pr-gate, not rules-config: the shape of a GitHub comment is this package's concern, and\n * rules-config is the dependency, not the dependent.\n */\nexport class ChecklistCommentRow {\n subagent: string; // the reviewer / checklist id\n status: string; // CK_* verdict; '' when it did not run\n detail: string; // verbatim reviewer output\n ran: boolean; // false = skipped, which is a NORMAL, healthy outcome\n // The checklist's CONFIGURED globs. The only safe signal for \"always runs\": a patternless checklist and\n // a skipped one both have an empty `firedPatterns`, and they mean opposite things.\n configuredPatterns: string[];\n firedPatterns: string[]; // which configured globs actually hit a changed file\n matchedFiles: string[];\n changedFileCount: number; // how many files were considered at all — \"0 of N\" needs the N\n\n // eslint-disable-next-line @typescript-eslint/max-params\n constructor(\n subagent: string, status: string, detail: string, ran: boolean,\n configuredPatterns: string[], firedPatterns: string[], matchedFiles: string[], changedFileCount: number,\n ) {\n this.subagent = subagent;\n this.status = status;\n this.detail = detail;\n this.ran = ran;\n this.configuredPatterns = configuredPatterns;\n this.firedPatterns = firedPatterns;\n this.matchedFiles = matchedFiles;\n this.changedFileCount = changedFileCount;\n }\n}\n\nexport class DisableCounts {\n webpiecesCount: number;\n eslintCount: number;\n webpiecesRules: string[];\n\n constructor(webpiecesCount: number, eslintCount: number, webpiecesRules: string[]) {\n this.webpiecesCount = webpiecesCount;\n this.eslintCount = eslintCount;\n this.webpiecesRules = webpiecesRules;\n }\n}\n\nexport class DashboardInput {\n title: string;\n gateResults: GateResult[];\n disables: DisableCounts;\n buildPassed: boolean;\n forkPoint: string;\n featureHead: string;\n mainHead: string;\n review: ReviewJson; // AI-authored risk/violations/summary (from review.json)\n checklists: ChecklistRow[]; // consumer checklists this branch triggered; [] for non-adopting repos\n\n // eslint-disable-next-line @typescript-eslint/max-params\n constructor(\n title: string, gateResults: GateResult[], disables: DisableCounts,\n buildPassed: boolean, forkPoint: string, featureHead: string, mainHead: string, review: ReviewJson,\n checklists: ChecklistRow[] = [],\n ) {\n this.title = title;\n this.gateResults = gateResults;\n this.disables = disables;\n this.buildPassed = buildPassed;\n this.forkPoint = forkPoint;\n this.featureHead = featureHead;\n this.mainHead = mainHead;\n this.review = review;\n this.checklists = checklists;\n }\n}\n\n/** Renders the PR-gate dashboard markdown (gates × changed files, disables, risk, 3-point hashes). */\n@injectable(bindingScopeValues.Singleton)\nexport class Dashboard {\n // Disabled gates are in-file examples (JSON has no comments) — skip them entirely.\n computeGateResults(gates: GateDefinition[], changedFiles: string[]): GateResult[] {\n return gates\n .filter((gate: GateDefinition): boolean => !gate.disabled)\n .map((gate: GateDefinition): GateResult => {\n const matched = changedFiles.filter((file: string): boolean => this.matchesAny(gate.patterns, file));\n return new GateResult(gate.name, gate.warningColor, matched);\n });\n }\n\n // Count disables ADDED in this PR by scanning added (`+`) lines of the diff patch. Rule-aware:\n // reports which webpieces rules were disabled, using the canonical RULE_NAMES vocabulary.\n countAddedDisables(patch: string): DisableCounts {\n let webpiecesCount = 0;\n let eslintCount = 0;\n const rules = new Set<string>();\n const allRuleTokens = Object.keys(RULE_NAMES).map((key: string): string => (RULE_NAMES as Record<string, string>)[key]);\n\n for (const line of patch.split('\\n')) {\n if (!line.startsWith('+') || line.startsWith('+++')) continue;\n if (line.includes(WEBPIECES_DISABLE)) {\n webpiecesCount += 1;\n for (const token of allRuleTokens) {\n if (line.includes(token)) rules.add(token);\n }\n }\n if (line.includes('eslint-disable')) eslintCount += 1;\n }\n return new DisableCounts(webpiecesCount, eslintCount, Array.from(rules).sort());\n }\n\n renderDashboard(input: DashboardInput): string {\n const lines: string[] = [];\n lines.push('## 🚦 PR Gate Dashboard');\n lines.push('');\n for (const line of this.riskLines(input.review)) lines.push(line);\n lines.push(`**Build (nx affected):** ${input.buildPassed ? '🟢 Passed' : '🔴 Failed'}`);\n for (const result of input.gateResults) lines.push(this.gateLine(result));\n lines.push(this.disableLine(input.disables));\n const eslintEmoji = input.disables.eslintCount === 0 ? '🟢 No' : `🟡 ${input.disables.eslintCount} line(s)`;\n lines.push(`**ESLint Disables Added:** ${eslintEmoji}`);\n // One row per triggered consumer checklist — only when some fired, so non-adopting repos see no\n // change to the dashboard at all.\n for (const row of input.checklists) lines.push(this.checklistLine(row));\n lines.push('');\n if (input.review.summary.trim() !== '') {\n lines.push('### Summary');\n lines.push(input.review.summary.trim());\n lines.push('');\n }\n lines.push('### 🔍 3-Point Hash Points');\n lines.push(`- Fork point (A): \\`${input.forkPoint.slice(0, 12)}\\``);\n lines.push(`- Feature HEAD (B): \\`${input.featureHead.slice(0, 12)}\\``);\n lines.push(`- Main HEAD (C): \\`${input.mainHead.slice(0, 12)}\\``);\n lines.push('');\n lines.push('<sub>🤖 Generated by `pnpm wp-finish-upsert-pr` (build ran via nx affected — not self-attested).</sub>');\n return lines.join('\\n');\n }\n\n /**\n * The ONE combined PR comment. Two halves, in this order:\n *\n * 1. A roll-up plus the FULL ROSTER — every DEFINED checklist as a checkbox, each with a sub-bullet\n * stating exactly which globs fired against which files, or which did not and out of how many.\n * Skipped checklists are listed on purpose: skipping is the normal, healthy outcome, and a comment\n * that names only the reviewers that fired cannot distinguish \"evaluated and irrelevant\" from\n * \"never wired up\" — nor answer \"why did the DB reviewer run on my frontend PR?\".\n * 2. One section per reviewer that RAN, carrying its full `output` — the depth a verdict line throws\n * away. Overridden first, then warned, then passed: a reader should meet the exceptions first.\n *\n * Idempotent: keyed by the hidden marker so wp-finish PATCHes this same comment on every push.\n */\n renderChecklistComment(rows: readonly ChecklistCommentRow[], provenanceVerified: boolean, baseResolved: boolean): string {\n const ran = this.ranOrdered(rows);\n const prov = provenanceVerified\n ? '_Each reviewer ran as its own independent subagent, verified from the Claude Code harness._'\n : '_⚠️ Reviewer provenance was NOT verified (no Claude Code session) — treat these as unverified._';\n // The roster lives in the HEADER, never in a section: fitComment only ever shrinks section bodies,\n // so a roster line can never be the thing an oversize comment silently drops.\n const lines: string[] = [CHECKLIST_COMMENT_MARKER, this.rollupHeader(rows, baseResolved)];\n // No reviewer ran ⇒ no provenance claim to make. Printing one either way would attest to nothing.\n if (ran.length > 0) lines.push(prov);\n lines.push('', `### Checklists (all ${rows.length})`);\n for (const row of rows) lines.push(this.rosterBullet(row));\n const header = lines.join('\\n');\n if (ran.length === 0) {\n return `${header}\\n\\n_No reviewer had to run on this diff — every configured checklist was ` +\n `evaluated and none of them applied._`;\n }\n return this.fitComment(`${header}\\n\\n### Reviews that ran`, ran.map((r: ChecklistCommentRow): CommentSection => this.commentSection(r)));\n }\n\n // The roll-up line. `baseResolved:false` replaces it entirely: with no fork point the changed-file set is\n // EMPTY, so nothing matched — including patternless ALWAYS-RUNS checklists — and reporting that as\n // \"all skipped ✅\" would post a green all-clear for a PR where nothing was actually evaluated.\n private rollupHeader(rows: readonly ChecklistCommentRow[], baseResolved: boolean): string {\n if (!baseResolved) {\n return `## 🔍 Company review checklists — ⚠️ NOT EVALUATED (${rows.length} defined)\\n` +\n `_No diff base (fork point of main) could be resolved, so no checklist was matched against ` +\n `anything. This is **not** an all-clear._`;\n }\n const ran = rows.filter((r: ChecklistCommentRow): boolean => r.ran);\n const skipped = rows.length - ran.length;\n const parts: string[] = [];\n for (const pair of this.rollupCounts(ran)) parts.push(pair);\n const breakdown = parts.length > 0 ? ` (${parts.join(' · ')})` : '';\n const skip = skipped > 0 ? ` · ${skipped} skipped ✅` : '';\n return `## 🔍 Company review checklists — ${rows.length} defined · ${ran.length} ran${breakdown}${skip}`;\n }\n\n // `🟢 2 · 🟡 1` — only the non-zero buckets, so a clean run reads as one number rather than four.\n private rollupCounts(ran: readonly ChecklistCommentRow[]): string[] {\n const counts: string[] = [];\n const emojiFor: string[] = ['🟢', '🟡', '🟠'];\n const statusFor: string[] = [CK_PASS, CK_WARN, CK_OVERRIDDEN];\n statusFor.forEach((status: string, i: number): void => {\n const n = ran.filter((r: ChecklistCommentRow): boolean => r.status === status).length;\n if (n > 0) counts.push(`${emojiFor[i]} ${n}`);\n });\n return counts;\n }\n\n // One roster line + its why sub-bullet. A checked box means a reviewer ran; an unchecked one means the\n // checklist was evaluated and did not apply, which the words state as the good news it is.\n private rosterBullet(row: ChecklistCommentRow): string {\n const box = row.ran ? '- [x]' : '- [ ]';\n return `${box} ${this.verdictEmoji(row)} **${row.subagent}** — ${this.verdictWords(row)}\\n` +\n ` - ${this.whyLine(row)}`;\n }\n\n private verdictEmoji(row: ChecklistCommentRow): string {\n if (!row.ran) return '⚪';\n if (row.status === CK_PASS) return '🟢';\n if (row.status === CK_WARN) return '🟡';\n if (row.status === CK_OVERRIDDEN) return '🟠';\n if (row.status === CK_FAIL) return '🔴';\n return '⚪';\n }\n\n // SHORT words for a roster line / section heading. Short on purpose: the reviewer's own output and any\n // override justification get their own section below, and a roster exists to be scanned.\n private verdictWords(row: ChecklistCommentRow): string {\n if (!row.ran) return 'skipped, not applicable to this diff (expected ✅)';\n if (row.status === CK_PASS) return 'passed';\n if (row.status === CK_WARN) return 'passed with concerns';\n if (row.status === CK_OVERRIDDEN) return 'OVERRIDDEN — shipped with a stated justification';\n if (row.status === CK_FAIL) return 'FAILED review';\n if (row.status === CK_MISSING) return 'no verdict written';\n return `unknown verdict (${row.status})`;\n }\n\n /**\n * WHY this checklist ran or did not — the line that answers \"why was this reviewer involved?\". Branches\n * on `configuredPatterns`, NEVER on `firedPatterns.length`: a patternless checklist and a skipped one\n * both fired zero globs and they mean opposite things, so keying off the fired list would tell every\n * skipped checklist's reader that the whole diff had been in its scope.\n */\n private whyLine(row: ChecklistCommentRow): string {\n const total = row.changedFileCount;\n if (row.configuredPatterns.length === 0) {\n return `ALWAYS RUNS (no patterns) — whole diff in scope, ${total} changed file(s): ` +\n `${formatFileList(row.matchedFiles)}`;\n }\n const configured = this.asCode(row.configuredPatterns);\n if (row.firedPatterns.length === 0) {\n return `${configured} matched 0 of ${total} changed file(s)`;\n }\n return `matched ${this.asCode(row.firedPatterns)} → ${row.matchedFiles.length} of ${total} ` +\n `changed file(s): ${formatFileList(row.matchedFiles)}`;\n }\n\n private asCode(patterns: readonly string[]): string {\n return patterns.map((p: string): string => `\\`${p}\\``).join(', ');\n }\n\n // Reviewers that ran, exceptions first (overridden → warned → passed) so a reader meets what needs\n // attention before a wall of green.\n private ranOrdered(rows: readonly ChecklistCommentRow[]): ChecklistCommentRow[] {\n const rank: string[] = [CK_OVERRIDDEN, CK_WARN, CK_PASS];\n return rows\n .filter((r: ChecklistCommentRow): boolean => r.ran)\n .slice()\n .sort((a: ChecklistCommentRow, b: ChecklistCommentRow): number =>\n this.rankOf(rank, a.status) - this.rankOf(rank, b.status));\n }\n\n private rankOf(rank: readonly string[], status: string): number {\n const idx = rank.indexOf(status);\n return idx < 0 ? rank.length : idx;\n }\n\n private commentSection(row: ChecklistCommentRow): CommentSection {\n const heading = `#### ${this.verdictEmoji(row)} ${row.subagent} — ${this.verdictWords(row)}`;\n const body = row.detail.trim() !== '' ? row.detail.trim() : '_(reviewer recorded no output)_';\n return new CommentSection(heading, body);\n }\n\n // Keep the comment under GitHub's size cap by shrinking the LONGEST section body first (so a short\n // overridden note is never cut to make room for a long passing one), never dropping a verdict heading.\n private fitComment(header: string, sections: CommentSection[]): string {\n const assemble = (): string => `${header}\\n\\n${sections.map((s: CommentSection): string => `${s.heading}\\n\\n${s.body}`).join('\\n\\n')}`;\n const trunc = '\\n\\n…_[truncated to fit the GitHub comment size limit]_';\n let out = assemble();\n while (out.length > COMMENT_LIMIT) {\n const idx = this.longestBodyIndex(sections);\n if (idx < 0 || sections[idx].body.length <= trunc.length + 1) break;\n const over = out.length - COMMENT_LIMIT;\n const keep = Math.max(0, sections[idx].body.length - over - trunc.length - 8);\n sections[idx].body = sections[idx].body.slice(0, keep).trimEnd() + trunc;\n out = assemble();\n }\n return out;\n }\n\n private longestBodyIndex(sections: readonly CommentSection[]): number {\n let idx = -1;\n let max = -1;\n sections.forEach((s: CommentSection, i: number): void => {\n if (s.body.length > max) { max = s.body.length; idx = i; }\n });\n return idx;\n }\n\n // The squash-merge COMMIT body that lands in main's history (subject is the PR title, passed to\n // `gh pr merge --subject`). Deliberately compact — unlike the full PR-body dashboard: the risk score\n // (always), every NON-green flag (green rows omitted — a commit log should surface only what stands\n // out), the summary capped at 4 sentences, and a quick link back to the PR for the full dashboard.\n renderCommitBody(input: DashboardInput, prUrl: string): string {\n const lines: string[] = [];\n lines.push(`Risk: ${this.riskBar(input.review.riskScore)} ${input.review.riskScore}/100 ${input.review.riskEmoji} (${input.review.riskLevel})`);\n lines.push('');\n const flags = this.nonGreenFlags(input);\n if (flags.length === 0) {\n lines.push('Flags: 🟢 all green');\n } else {\n lines.push('Flags (non-green):');\n for (const flag of flags) lines.push(`- ${flag}`);\n }\n const summary = this.firstSentences(input.review.summary.trim(), 4);\n if (summary !== '') {\n lines.push('');\n lines.push(summary);\n }\n if (prUrl !== '') {\n lines.push('');\n lines.push(`PR: ${prUrl}`);\n }\n return lines.join('\\n');\n }\n\n // Every dashboard row that is NOT green, as a flat bullet list for the commit body. Green rows\n // (build passed, gate did not match, zero disables/violations) are intentionally omitted.\n private nonGreenFlags(input: DashboardInput): string[] {\n const flags: string[] = [];\n if (!input.buildPassed) flags.push('Build (nx affected): 🔴 Failed');\n if (input.review.violations.length > 0) flags.push(`Pattern Violations: 🟡 ${input.review.violations.length} violation(s)`);\n for (const result of input.gateResults) {\n if (result.matchedFiles.length === 0) continue;\n const emoji = result.warningColor === 'red' ? '🔴' : '🟡';\n flags.push(`${result.name}: ${emoji} ${result.matchedFiles.length} file(s)`);\n }\n if (input.disables.webpiecesCount > 0) {\n const which = input.disables.webpiecesRules.length > 0 ? ` — ${input.disables.webpiecesRules.join(', ')}` : '';\n flags.push(`Webpieces Disables Added: 🟡 ${input.disables.webpiecesCount} line(s)${which}`);\n }\n if (input.disables.eslintCount > 0) flags.push(`ESLint Disables Added: 🟡 ${input.disables.eslintCount} line(s)`);\n // A triggered checklist is noteworthy in main's history — carry each into the commit body.\n for (const row of input.checklists) {\n flags.push(`Checklist — ${row.title}: ${this.checklistStatusText(row)}`);\n }\n return flags;\n }\n\n // Emoji + words for a checklist verdict, shared by the dashboard row and the commit-body flag.\n // Every state is matched EXPLICITLY and the fallthrough names the status it did not recognize. The\n // previous `return '🟢 passed'` fallthrough meant any newly-added verdict rendered as a clean pass on\n // both the PR body and main's commit history until someone noticed — exactly the wrong default.\n private checklistStatusText(row: ChecklistRow): string {\n if (row.status === CK_OVERRIDDEN) {\n const why = row.detail.trim() !== '' ? ` — override: ${row.detail.trim()}` : '';\n return `🟠 OVERRIDDEN${why}`;\n }\n if (row.status === CK_WARN) return '🟡 passed with concerns';\n if (row.status === CK_FAIL) return '🔴 FAILED review';\n if (row.status === CK_MISSING) return '⚪ not reviewed';\n if (row.status === CK_PASS) return '🟢 passed';\n return `⚪ unknown verdict (${row.status})`;\n }\n\n // First `max` sentences of `text`. A sentence ends at `. ! ?` ONLY when followed by whitespace or\n // end-of-string, so interior dots in filenames/paths/versions (dependencies.json, runtime-graph.ts,\n // 0.4.447) do NOT split — and, unlike a greedy `[^.!?]+` regex, no text is ever dropped when such a\n // dot appears (that footgun silently deleted the run of prose up to the next real boundary). Keeps\n // the commit body scannable; the full summary still lives in the PR-body dashboard.\n private firstSentences(text: string, max: number): string {\n if (text === '') return '';\n const sentences: string[] = [];\n let start = 0;\n for (let i = 0; i < text.length && sentences.length < max; i++) {\n const ch = text[i];\n const isTerminator = ch === '.' || ch === '!' || ch === '?';\n const next = text[i + 1];\n if (isTerminator && (next === undefined || /\\s/.test(next))) {\n sentences.push(text.slice(start, i + 1).trim());\n start = i + 1;\n }\n }\n // Trailing text with no terminator still counts as a sentence (up to the cap).\n if (sentences.length < max && start < text.length) {\n const tail = text.slice(start).trim();\n if (tail !== '') sentences.push(tail);\n }\n return sentences.join(' ').trim();\n }\n\n // Self-contained glob matcher (** , * , ?) so pr-gate needs no extra runtime dependency.\n private globToRegex(pattern: string): RegExp {\n let re = '';\n let i = 0;\n while (i < pattern.length) {\n const ch = pattern[i];\n if (ch === '*' && pattern[i + 1] === '*') {\n re += '.*';\n i += 2;\n if (pattern[i] === '/') i += 1;\n continue;\n }\n if (ch === '*') { re += '[^/]*'; i += 1; continue; }\n if (ch === '?') { re += '[^/]'; i += 1; continue; }\n if ('.+^$(){}|[]\\\\'.includes(ch)) { re += '\\\\' + ch; i += 1; continue; }\n re += ch;\n i += 1;\n }\n return new RegExp('^' + re + '$');\n }\n\n private matchesAny(patterns: string[], file: string): boolean {\n for (const pattern of patterns) {\n if (this.globToRegex(pattern).test(file)) return true;\n }\n return false;\n }\n\n private gateLine(result: GateResult): string {\n if (result.matchedFiles.length === 0) return `**${result.name}:** 🟢 No`;\n const emoji = result.warningColor === 'red' ? '🔴' : '🟡';\n return `**${result.name}:** ${emoji} Yes (${result.matchedFiles.length} file(s))`;\n }\n\n // A triggered consumer checklist row: the resolved verdict (passed / overridden / failed / …).\n private checklistLine(row: ChecklistRow): string {\n return `**Checklist — ${row.title}:** ${this.checklistStatusText(row)}`;\n }\n\n // 10-cell risk bar colored by band (🟩 ≤25, 🟨 ≤50, 🟧 ≤75, 🟥 >75), at least one filled cell.\n private riskBar(score: number): string {\n const clamped = Math.max(0, Math.min(100, score));\n const cell = clamped <= 25 ? '🟩' : clamped <= 50 ? '🟨' : clamped <= 75 ? '🟧' : '🟥';\n const filled = Math.max(1, Math.min(10, Math.round(clamped / 10)));\n return cell.repeat(filled) + '⬜'.repeat(10 - filled);\n }\n\n // RISK section (the AI half): Risk Score bar, Risk Level, Pattern Violations.\n private riskLines(review: ReviewJson): string[] {\n const violations = review.violations.length;\n const violationLine = violations === 0 ? '🟢 No' : `🟡 Yes (${violations} violation(s))`;\n return [\n `**Risk Score:** ${this.riskBar(review.riskScore)} **${review.riskScore}/100** ${review.riskEmoji}`,\n `**Risk Level:** ${review.riskEmoji} **${review.riskLevel}**`,\n `**Pattern Violations:** ${violationLine}`,\n ];\n }\n\n private disableLine(disables: DisableCounts): string {\n if (disables.webpiecesCount === 0) return '**Webpieces Disables Added:** 🟢 No';\n const which = disables.webpiecesRules.length > 0 ? ` — ${disables.webpiecesRules.join(', ')}` : '';\n return `**Webpieces Disables Added:** 🟡 ${disables.webpiecesCount} line(s)${which}`;\n }\n}\n"]}
1
+ {"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../../../../../packages/tooling/pr-gate/src/dashboard/dashboard.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n GateDefinition, WEBPIECES_DISABLE, RULE_NAMES, ReviewJson, formatFileList,\n CK_PASS, CK_WARN, CK_OVERRIDDEN, CK_FAIL, CK_MISSING,\n} from '@webpieces/rules-config';\nimport { injectable, bindingScopeValues } from 'inversify';\n\n// Hidden marker on the checklist review COMMENT, so wp-finish can find + PATCH its own comment on every\n// push instead of appending a new one. Versioned so the format can evolve without matching an old shape.\n// v2 = the full roster (every DEFINED checklist, matched or not) + tri-state verdicts.\nexport const CHECKLIST_COMMENT_MARKER = '<!-- webpieces-checklists v2 -->';\nconst COMMENT_LIMIT = 65000; // under GitHub's 65536-char cap, with headroom for the marker + roll-up.\n\n// One checklist section for the combined comment (heading + verbatim reviewer output), so oversize\n// truncation can shrink the longest BODY without ever dropping a verdict heading.\nclass CommentSection {\n heading: string;\n body: string;\n\n constructor(heading: string, body: string) {\n this.heading = heading;\n this.body = body;\n }\n}\n\nexport class GateResult {\n name: string;\n warningColor: string; // 'yellow' | 'red' — the color shown WHEN files matched (green is implicit)\n matchedFiles: string[];\n\n constructor(name: string, warningColor: string, matchedFiles: string[]) {\n this.name = name;\n this.warningColor = warningColor;\n this.matchedFiles = matchedFiles;\n }\n}\n\n// One row for a consumer review checklist the branch triggered. `status` is the resolved verdict (one of\n// CK_PASS | CK_WARN | CK_OVERRIDDEN | CK_FAIL | CK_MISSING | CK_BAD_FORMAT); `detail` is the reviewer\n// output / override justification. A row is always PASS/WARN/OVERRIDDEN by the time it renders — a failed,\n// missing or unreadable verdict throws before the dashboard is built. Rendered into the PR body so the\n// verdict reaches the server — the PR body is the artifact of the local flow that leaves the checkout\n// (alongside the HMAC gate token that proves the flow ran).\nexport class ChecklistRow {\n title: string; // the checklist id (= reviewer subagent name)\n status: string; // CK_* verdict\n detail: string; // reviewer output / override justification (surfaced for OVERRIDDEN)\n\n constructor(title: string, status: string, detail = '') {\n this.title = title;\n this.status = status;\n this.detail = detail;\n }\n}\n\n/**\n * One roster line of the checklist COMMENT: a defined checklist, whether its reviewer ran, and the evidence\n * for WHY. Deliberately separate from {@link ChecklistRow} rather than five more fields on it — ChecklistRow\n * also feeds the PR body and the squash-commit body, and roster evidence has no business travelling into\n * main's git history or through every DashboardInput construction site.\n *\n * Kept in pr-gate, not rules-config: the shape of a GitHub comment is this package's concern, and\n * rules-config is the dependency, not the dependent.\n */\nexport class ChecklistCommentRow {\n subagent: string; // the reviewer / checklist id\n status: string; // CK_* verdict; '' when it did not run\n detail: string; // verbatim reviewer output\n ran: boolean; // false = skipped, which is a NORMAL, healthy outcome\n // The checklist's CONFIGURED globs. The only safe signal for \"always runs\": a patternless checklist and\n // a skipped one both have an empty `firedPatterns`, and they mean opposite things.\n configuredPatterns: string[];\n firedPatterns: string[]; // which configured globs actually hit a changed file\n matchedFiles: string[];\n changedFileCount: number; // how many files were considered at all — \"0 of N\" needs the N\n /**\n * Whether this reviewer's own transcript shows it OPENING the extracted diff.\n *\n * '' = not assessed (no Claude Code session, or nothing was materialized) and prints nothing — \"no\n * evidence recorded\" and \"evidence says it never looked\" are different claims, and conflating them\n * would accuse a reviewer that ran perfectly well in CI. 'yes' | 'no' otherwise. Defaulted, so every\n * existing construction site is unchanged.\n */\n diffRead: string = '';\n\n // eslint-disable-next-line @typescript-eslint/max-params\n constructor(\n subagent: string, status: string, detail: string, ran: boolean,\n configuredPatterns: string[], firedPatterns: string[], matchedFiles: string[], changedFileCount: number,\n ) {\n this.subagent = subagent;\n this.status = status;\n this.detail = detail;\n this.ran = ran;\n this.configuredPatterns = configuredPatterns;\n this.firedPatterns = firedPatterns;\n this.matchedFiles = matchedFiles;\n this.changedFileCount = changedFileCount;\n }\n}\n\nexport class DisableCounts {\n webpiecesCount: number;\n eslintCount: number;\n webpiecesRules: string[];\n\n constructor(webpiecesCount: number, eslintCount: number, webpiecesRules: string[]) {\n this.webpiecesCount = webpiecesCount;\n this.eslintCount = eslintCount;\n this.webpiecesRules = webpiecesRules;\n }\n}\n\nexport class DashboardInput {\n title: string;\n gateResults: GateResult[];\n disables: DisableCounts;\n buildPassed: boolean;\n forkPoint: string;\n featureHead: string;\n mainHead: string;\n review: ReviewJson; // AI-authored risk/violations/summary (from review.json)\n checklists: ChecklistRow[]; // consumer checklists this branch triggered; [] for non-adopting repos\n\n // eslint-disable-next-line @typescript-eslint/max-params\n constructor(\n title: string, gateResults: GateResult[], disables: DisableCounts,\n buildPassed: boolean, forkPoint: string, featureHead: string, mainHead: string, review: ReviewJson,\n checklists: ChecklistRow[] = [],\n ) {\n this.title = title;\n this.gateResults = gateResults;\n this.disables = disables;\n this.buildPassed = buildPassed;\n this.forkPoint = forkPoint;\n this.featureHead = featureHead;\n this.mainHead = mainHead;\n this.review = review;\n this.checklists = checklists;\n }\n}\n\n/** Renders the PR-gate dashboard markdown (gates × changed files, disables, risk, 3-point hashes). */\n@injectable(bindingScopeValues.Singleton)\nexport class Dashboard {\n // Disabled gates are in-file examples (JSON has no comments) — skip them entirely.\n computeGateResults(gates: GateDefinition[], changedFiles: string[]): GateResult[] {\n return gates\n .filter((gate: GateDefinition): boolean => !gate.disabled)\n .map((gate: GateDefinition): GateResult => {\n const matched = changedFiles.filter((file: string): boolean => this.matchesAny(gate.patterns, file));\n return new GateResult(gate.name, gate.warningColor, matched);\n });\n }\n\n // Count disables ADDED in this PR by scanning added (`+`) lines of the diff patch. Rule-aware:\n // reports which webpieces rules were disabled, using the canonical RULE_NAMES vocabulary.\n countAddedDisables(patch: string): DisableCounts {\n let webpiecesCount = 0;\n let eslintCount = 0;\n const rules = new Set<string>();\n const allRuleTokens = Object.keys(RULE_NAMES).map((key: string): string => (RULE_NAMES as Record<string, string>)[key]);\n\n for (const line of patch.split('\\n')) {\n if (!line.startsWith('+') || line.startsWith('+++')) continue;\n if (line.includes(WEBPIECES_DISABLE)) {\n webpiecesCount += 1;\n for (const token of allRuleTokens) {\n if (line.includes(token)) rules.add(token);\n }\n }\n if (line.includes('eslint-disable')) eslintCount += 1;\n }\n return new DisableCounts(webpiecesCount, eslintCount, Array.from(rules).sort());\n }\n\n renderDashboard(input: DashboardInput): string {\n const lines: string[] = [];\n lines.push('## 🚦 PR Gate Dashboard');\n lines.push('');\n for (const line of this.riskLines(input.review)) lines.push(line);\n lines.push(`**Build (nx affected):** ${input.buildPassed ? '🟢 Passed' : '🔴 Failed'}`);\n for (const result of input.gateResults) lines.push(this.gateLine(result));\n lines.push(this.disableLine(input.disables));\n const eslintEmoji = input.disables.eslintCount === 0 ? '🟢 No' : `🟡 ${input.disables.eslintCount} line(s)`;\n lines.push(`**ESLint Disables Added:** ${eslintEmoji}`);\n // One row per triggered consumer checklist — only when some fired, so non-adopting repos see no\n // change to the dashboard at all.\n for (const row of input.checklists) lines.push(this.checklistLine(row));\n lines.push('');\n if (input.review.summary.trim() !== '') {\n lines.push('### Summary');\n lines.push(input.review.summary.trim());\n lines.push('');\n }\n lines.push('### 🔍 3-Point Hash Points');\n lines.push(`- Fork point (A): \\`${input.forkPoint.slice(0, 12)}\\``);\n lines.push(`- Feature HEAD (B): \\`${input.featureHead.slice(0, 12)}\\``);\n lines.push(`- Main HEAD (C): \\`${input.mainHead.slice(0, 12)}\\``);\n lines.push('');\n lines.push('<sub>🤖 Generated by `pnpm wp-finish-upsert-pr` (build ran via nx affected — not self-attested).</sub>');\n return lines.join('\\n');\n }\n\n /**\n * The ONE combined PR comment. Two halves, in this order:\n *\n * 1. A roll-up plus the FULL ROSTER — every DEFINED checklist as a checkbox, each with a sub-bullet\n * stating exactly which globs fired against which files, or which did not and out of how many.\n * Skipped checklists are listed on purpose: skipping is the normal, healthy outcome, and a comment\n * that names only the reviewers that fired cannot distinguish \"evaluated and irrelevant\" from\n * \"never wired up\" — nor answer \"why did the DB reviewer run on my frontend PR?\".\n * 2. One section per reviewer that RAN, carrying its full `output` — the depth a verdict line throws\n * away. Overridden first, then warned, then passed: a reader should meet the exceptions first.\n *\n * Idempotent: keyed by the hidden marker so wp-finish PATCHes this same comment on every push.\n */\n renderChecklistComment(rows: readonly ChecklistCommentRow[], provenanceVerified: boolean, baseResolved: boolean): string {\n const ran = this.ranOrdered(rows);\n const prov = provenanceVerified\n ? '_Each reviewer ran as its own independent subagent, verified from the Claude Code harness._'\n : '_⚠️ Reviewer provenance was NOT verified (no Claude Code session) — treat these as unverified._';\n // The roster lives in the HEADER, never in a section: fitComment only ever shrinks section bodies,\n // so a roster line can never be the thing an oversize comment silently drops.\n const lines: string[] = [CHECKLIST_COMMENT_MARKER, this.rollupHeader(rows, baseResolved)];\n // No reviewer ran ⇒ no provenance claim to make. Printing one either way would attest to nothing.\n if (ran.length > 0) lines.push(prov);\n lines.push('', `### Checklists (all ${rows.length})`);\n for (const row of rows) lines.push(this.rosterBullet(row));\n const header = lines.join('\\n');\n if (ran.length === 0) {\n return `${header}\\n\\n_No reviewer had to run on this diff — every configured checklist was ` +\n `evaluated and none of them applied._`;\n }\n return this.fitComment(`${header}\\n\\n### Reviews that ran`, ran.map((r: ChecklistCommentRow): CommentSection => this.commentSection(r)));\n }\n\n // The roll-up line. `baseResolved:false` replaces it entirely: with no fork point the changed-file set is\n // EMPTY, so nothing matched — including patternless ALWAYS-RUNS checklists — and reporting that as\n // \"all skipped ✅\" would post a green all-clear for a PR where nothing was actually evaluated.\n private rollupHeader(rows: readonly ChecklistCommentRow[], baseResolved: boolean): string {\n if (!baseResolved) {\n return `## 🔍 Company review checklists — ⚠️ NOT EVALUATED (${rows.length} defined)\\n` +\n `_No diff base (fork point of main) could be resolved, so no checklist was matched against ` +\n `anything. This is **not** an all-clear._`;\n }\n const ran = rows.filter((r: ChecklistCommentRow): boolean => r.ran);\n const skipped = rows.length - ran.length;\n const parts: string[] = [];\n for (const pair of this.rollupCounts(ran)) parts.push(pair);\n const breakdown = parts.length > 0 ? ` (${parts.join(' · ')})` : '';\n const skip = skipped > 0 ? ` · ${skipped} skipped ✅` : '';\n return `## 🔍 Company review checklists — ${rows.length} defined · ${ran.length} ran${breakdown}${skip}`;\n }\n\n // `🟢 2 · 🟡 1` — only the non-zero buckets, so a clean run reads as one number rather than four.\n private rollupCounts(ran: readonly ChecklistCommentRow[]): string[] {\n const counts: string[] = [];\n const emojiFor: string[] = ['🟢', '🟡', '🟠'];\n const statusFor: string[] = [CK_PASS, CK_WARN, CK_OVERRIDDEN];\n statusFor.forEach((status: string, i: number): void => {\n const n = ran.filter((r: ChecklistCommentRow): boolean => r.status === status).length;\n if (n > 0) counts.push(`${emojiFor[i]} ${n}`);\n });\n return counts;\n }\n\n // One roster line + its why sub-bullet. A checked box means a reviewer ran; an unchecked one means the\n // checklist was evaluated and did not apply, which the words state as the good news it is.\n private rosterBullet(row: ChecklistCommentRow): string {\n const box = row.ran ? '- [x]' : '- [ ]';\n return `${box} ${this.verdictEmoji(row)} **${row.subagent}** — ${this.verdictWords(row)}${this.evidenceSuffix(row)}\\n` +\n ` - ${this.whyLine(row)}`;\n }\n\n /**\n * Whether the reviewer demonstrably opened the diff, read from its own transcript. A QUALITY signal and\n * never a blocker (see SubagentProvenanceService.evidenceFor) — but published, because \"wrote a verdict\n * without reading the change\" is exactly what a reader of this comment would want to weigh.\n */\n private evidenceSuffix(row: ChecklistCommentRow): string {\n if (!row.ran || row.diffRead === '') return '';\n return row.diffRead === 'yes' ? ' _(diff read ✓)_' : ' _(⚠️ no diff read recorded)_';\n }\n\n private verdictEmoji(row: ChecklistCommentRow): string {\n if (!row.ran) return '⚪';\n if (row.status === CK_PASS) return '🟢';\n if (row.status === CK_WARN) return '🟡';\n if (row.status === CK_OVERRIDDEN) return '🟠';\n if (row.status === CK_FAIL) return '🔴';\n return '⚪';\n }\n\n // SHORT words for a roster line / section heading. Short on purpose: the reviewer's own output and any\n // override justification get their own section below, and a roster exists to be scanned.\n private verdictWords(row: ChecklistCommentRow): string {\n if (!row.ran) return 'skipped, not applicable to this diff (expected ✅)';\n if (row.status === CK_PASS) return 'passed';\n if (row.status === CK_WARN) return 'passed with concerns';\n if (row.status === CK_OVERRIDDEN) return 'OVERRIDDEN — shipped with a stated justification';\n if (row.status === CK_FAIL) return 'FAILED review';\n if (row.status === CK_MISSING) return 'no verdict written';\n return `unknown verdict (${row.status})`;\n }\n\n /**\n * WHY this checklist ran or did not — the line that answers \"why was this reviewer involved?\". Branches\n * on `configuredPatterns`, NEVER on `firedPatterns.length`: a patternless checklist and a skipped one\n * both fired zero globs and they mean opposite things, so keying off the fired list would tell every\n * skipped checklist's reader that the whole diff had been in its scope.\n */\n private whyLine(row: ChecklistCommentRow): string {\n const total = row.changedFileCount;\n if (row.configuredPatterns.length === 0) {\n // Say what \"no patterns\" COSTS, not just what it means. Six patternless checklists all firing on\n // a one-file docs PR is what a missing `patterns` looks like from the outside, and a reader who\n // is told only \"ALWAYS RUNS\" has no reason to suspect the config rather than the diff.\n return `ALWAYS RUNS — no \\`patterns\\` configured, so this fires on EVERY PR including docs-only ` +\n `ones; add \\`patterns\\` if that is not intended. Whole diff in scope, ${total} changed file(s): ` +\n `${formatFileList(row.matchedFiles)}`;\n }\n const configured = this.asCode(row.configuredPatterns);\n if (row.firedPatterns.length === 0) {\n return `${configured} matched 0 of ${total} changed file(s)`;\n }\n return `matched ${this.asCode(row.firedPatterns)} → ${row.matchedFiles.length} of ${total} ` +\n `changed file(s): ${formatFileList(row.matchedFiles)}`;\n }\n\n private asCode(patterns: readonly string[]): string {\n return patterns.map((p: string): string => `\\`${p}\\``).join(', ');\n }\n\n // Reviewers that ran, exceptions first (overridden → warned → passed) so a reader meets what needs\n // attention before a wall of green.\n private ranOrdered(rows: readonly ChecklistCommentRow[]): ChecklistCommentRow[] {\n const rank: string[] = [CK_OVERRIDDEN, CK_WARN, CK_PASS];\n return rows\n .filter((r: ChecklistCommentRow): boolean => r.ran)\n .slice()\n .sort((a: ChecklistCommentRow, b: ChecklistCommentRow): number =>\n this.rankOf(rank, a.status) - this.rankOf(rank, b.status));\n }\n\n private rankOf(rank: readonly string[], status: string): number {\n const idx = rank.indexOf(status);\n return idx < 0 ? rank.length : idx;\n }\n\n private commentSection(row: ChecklistCommentRow): CommentSection {\n const heading = `#### ${this.verdictEmoji(row)} ${row.subagent} — ${this.verdictWords(row)}`;\n const body = row.detail.trim() !== '' ? row.detail.trim() : '_(reviewer recorded no output)_';\n return new CommentSection(heading, body);\n }\n\n // Keep the comment under GitHub's size cap by shrinking the LONGEST section body first (so a short\n // overridden note is never cut to make room for a long passing one), never dropping a verdict heading.\n private fitComment(header: string, sections: CommentSection[]): string {\n const assemble = (): string => `${header}\\n\\n${sections.map((s: CommentSection): string => `${s.heading}\\n\\n${s.body}`).join('\\n\\n')}`;\n const trunc = '\\n\\n…_[truncated to fit the GitHub comment size limit]_';\n let out = assemble();\n while (out.length > COMMENT_LIMIT) {\n const idx = this.longestBodyIndex(sections);\n if (idx < 0 || sections[idx].body.length <= trunc.length + 1) break;\n const over = out.length - COMMENT_LIMIT;\n const keep = Math.max(0, sections[idx].body.length - over - trunc.length - 8);\n sections[idx].body = sections[idx].body.slice(0, keep).trimEnd() + trunc;\n out = assemble();\n }\n return out;\n }\n\n private longestBodyIndex(sections: readonly CommentSection[]): number {\n let idx = -1;\n let max = -1;\n sections.forEach((s: CommentSection, i: number): void => {\n if (s.body.length > max) { max = s.body.length; idx = i; }\n });\n return idx;\n }\n\n // The squash-merge COMMIT body that lands in main's history (subject is the PR title, passed to\n // `gh pr merge --subject`). Deliberately compact — unlike the full PR-body dashboard: the risk score\n // (always), every NON-green flag (green rows omitted — a commit log should surface only what stands\n // out), the summary capped at 4 sentences, and a quick link back to the PR for the full dashboard.\n renderCommitBody(input: DashboardInput, prUrl: string): string {\n const lines: string[] = [];\n lines.push(`Risk: ${this.riskBar(input.review.riskScore)} ${input.review.riskScore}/100 ${input.review.riskEmoji} (${input.review.riskLevel})`);\n lines.push('');\n const flags = this.nonGreenFlags(input);\n if (flags.length === 0) {\n lines.push('Flags: 🟢 all green');\n } else {\n lines.push('Flags (non-green):');\n for (const flag of flags) lines.push(`- ${flag}`);\n }\n const summary = this.firstSentences(input.review.summary.trim(), 4);\n if (summary !== '') {\n lines.push('');\n lines.push(summary);\n }\n if (prUrl !== '') {\n lines.push('');\n lines.push(`PR: ${prUrl}`);\n }\n return lines.join('\\n');\n }\n\n // Every dashboard row that is NOT green, as a flat bullet list for the commit body. Green rows\n // (build passed, gate did not match, zero disables/violations) are intentionally omitted.\n private nonGreenFlags(input: DashboardInput): string[] {\n const flags: string[] = [];\n if (!input.buildPassed) flags.push('Build (nx affected): 🔴 Failed');\n if (input.review.violations.length > 0) flags.push(`Pattern Violations: 🟡 ${input.review.violations.length} violation(s)`);\n for (const result of input.gateResults) {\n if (result.matchedFiles.length === 0) continue;\n const emoji = result.warningColor === 'red' ? '🔴' : '🟡';\n flags.push(`${result.name}: ${emoji} ${result.matchedFiles.length} file(s)`);\n }\n if (input.disables.webpiecesCount > 0) {\n const which = input.disables.webpiecesRules.length > 0 ? ` — ${input.disables.webpiecesRules.join(', ')}` : '';\n flags.push(`Webpieces Disables Added: 🟡 ${input.disables.webpiecesCount} line(s)${which}`);\n }\n if (input.disables.eslintCount > 0) flags.push(`ESLint Disables Added: 🟡 ${input.disables.eslintCount} line(s)`);\n // A triggered checklist is noteworthy in main's history — carry each into the commit body.\n for (const row of input.checklists) {\n flags.push(`Checklist — ${row.title}: ${this.checklistStatusText(row)}`);\n }\n return flags;\n }\n\n // Emoji + words for a checklist verdict, shared by the dashboard row and the commit-body flag.\n // Every state is matched EXPLICITLY and the fallthrough names the status it did not recognize. The\n // previous `return '🟢 passed'` fallthrough meant any newly-added verdict rendered as a clean pass on\n // both the PR body and main's commit history until someone noticed — exactly the wrong default.\n private checklistStatusText(row: ChecklistRow): string {\n if (row.status === CK_OVERRIDDEN) {\n const why = row.detail.trim() !== '' ? ` — override: ${row.detail.trim()}` : '';\n return `🟠 OVERRIDDEN${why}`;\n }\n if (row.status === CK_WARN) return '🟡 passed with concerns';\n if (row.status === CK_FAIL) return '🔴 FAILED review';\n if (row.status === CK_MISSING) return '⚪ not reviewed';\n if (row.status === CK_PASS) return '🟢 passed';\n return `⚪ unknown verdict (${row.status})`;\n }\n\n // First `max` sentences of `text`. A sentence ends at `. ! ?` ONLY when followed by whitespace or\n // end-of-string, so interior dots in filenames/paths/versions (dependencies.json, runtime-graph.ts,\n // 0.4.447) do NOT split — and, unlike a greedy `[^.!?]+` regex, no text is ever dropped when such a\n // dot appears (that footgun silently deleted the run of prose up to the next real boundary). Keeps\n // the commit body scannable; the full summary still lives in the PR-body dashboard.\n private firstSentences(text: string, max: number): string {\n if (text === '') return '';\n const sentences: string[] = [];\n let start = 0;\n for (let i = 0; i < text.length && sentences.length < max; i++) {\n const ch = text[i];\n const isTerminator = ch === '.' || ch === '!' || ch === '?';\n const next = text[i + 1];\n if (isTerminator && (next === undefined || /\\s/.test(next))) {\n sentences.push(text.slice(start, i + 1).trim());\n start = i + 1;\n }\n }\n // Trailing text with no terminator still counts as a sentence (up to the cap).\n if (sentences.length < max && start < text.length) {\n const tail = text.slice(start).trim();\n if (tail !== '') sentences.push(tail);\n }\n return sentences.join(' ').trim();\n }\n\n // Self-contained glob matcher (** , * , ?) so pr-gate needs no extra runtime dependency.\n private globToRegex(pattern: string): RegExp {\n let re = '';\n let i = 0;\n while (i < pattern.length) {\n const ch = pattern[i];\n if (ch === '*' && pattern[i + 1] === '*') {\n re += '.*';\n i += 2;\n if (pattern[i] === '/') i += 1;\n continue;\n }\n if (ch === '*') { re += '[^/]*'; i += 1; continue; }\n if (ch === '?') { re += '[^/]'; i += 1; continue; }\n if ('.+^$(){}|[]\\\\'.includes(ch)) { re += '\\\\' + ch; i += 1; continue; }\n re += ch;\n i += 1;\n }\n return new RegExp('^' + re + '$');\n }\n\n private matchesAny(patterns: string[], file: string): boolean {\n for (const pattern of patterns) {\n if (this.globToRegex(pattern).test(file)) return true;\n }\n return false;\n }\n\n private gateLine(result: GateResult): string {\n if (result.matchedFiles.length === 0) return `**${result.name}:** 🟢 No`;\n const emoji = result.warningColor === 'red' ? '🔴' : '🟡';\n return `**${result.name}:** ${emoji} Yes (${result.matchedFiles.length} file(s))`;\n }\n\n // A triggered consumer checklist row: the resolved verdict (passed / overridden / failed / …).\n private checklistLine(row: ChecklistRow): string {\n return `**Checklist — ${row.title}:** ${this.checklistStatusText(row)}`;\n }\n\n // 10-cell risk bar colored by band (🟩 ≤25, 🟨 ≤50, 🟧 ≤75, 🟥 >75), at least one filled cell.\n private riskBar(score: number): string {\n const clamped = Math.max(0, Math.min(100, score));\n const cell = clamped <= 25 ? '🟩' : clamped <= 50 ? '🟨' : clamped <= 75 ? '🟧' : '🟥';\n const filled = Math.max(1, Math.min(10, Math.round(clamped / 10)));\n return cell.repeat(filled) + '⬜'.repeat(10 - filled);\n }\n\n // RISK section (the AI half): Risk Score bar, Risk Level, Pattern Violations.\n private riskLines(review: ReviewJson): string[] {\n const violations = review.violations.length;\n const violationLine = violations === 0 ? '🟢 No' : `🟡 Yes (${violations} violation(s))`;\n return [\n `**Risk Score:** ${this.riskBar(review.riskScore)} **${review.riskScore}/100** ${review.riskEmoji}`,\n `**Risk Level:** ${review.riskEmoji} **${review.riskLevel}**`,\n `**Pattern Violations:** ${violationLine}`,\n ];\n }\n\n private disableLine(disables: DisableCounts): string {\n if (disables.webpiecesCount === 0) return '**Webpieces Disables Added:** 🟢 No';\n const which = disables.webpiecesRules.length > 0 ? ` — ${disables.webpiecesRules.join(', ')}` : '';\n return `**Webpieces Disables Added:** 🟡 ${disables.webpiecesCount} line(s)${which}`;\n }\n}\n"]}
@@ -1,7 +1,15 @@
1
1
  import { BranchArchiver, BranchReaper, RepoRootFinder } from '@webpieces/rules-config';
2
+ import { WorktreeCleanupSection } from './worktree-cleanup';
2
3
  /**
3
- * wp-cleanup: delete the local branches whose PR is already merged (or that hold no commits), then ASK
4
- * about the ones that are merely probably-dead.
4
+ * wp-cleanup: remove the dead WORKTREES, delete the local branches whose PR is already merged (or that
5
+ * hold no commits), then ASK about the ones that are merely probably-dead.
6
+ *
7
+ * WHY WORKTREES ARE PART OF THIS: they were the half that never got reaped. The verdicts existed —
8
+ * merged-branches.ts has been writing a full `DeletableWorktree[]` into the cache all along — and their
9
+ * only consumer used them to BLOCK the next `git worktree add`, never to remove anything. Meanwhile a
10
+ * live worktree pins its branch, so the branch was spared too. Two things the tooling could PROVE were
11
+ * dead, accumulating forever, until the guard refused to create the next branch and the only remedy it
12
+ * could offer was loosening its own cap. See WorktreeCleanupSection and WorktreeReaper.
5
13
  *
6
14
  * WHY a named command instead of the `git branch -D a b c` the guards used to print: an AI agent
7
15
  * reads a raw `-D` as destructive, so it asks permission and stops — which is exactly why branches
@@ -24,10 +32,41 @@ export declare class CleanupCommand {
24
32
  private readonly repoRootFinder;
25
33
  private readonly branchReaper;
26
34
  private readonly archiver;
27
- constructor(repoRootFinder: RepoRootFinder, branchReaper: BranchReaper, archiver: BranchArchiver);
35
+ private readonly worktreeSection;
36
+ constructor(repoRootFinder: RepoRootFinder, branchReaper: BranchReaper, archiver: BranchArchiver, worktreeSection: WorktreeCleanupSection);
37
+ /**
38
+ * WORKTREES FIRST, then branches. The order is the fix, not a detail: a worktree HOLDS its branch,
39
+ * so that branch is spared `in-use` ("remove that worktree before deleting the branch") and nothing
40
+ * used to remove the worktree — so both piled up until branch-creation-guard refused to make the
41
+ * next one. Reaping the worktree takes its branch with it, and the branch pass then recomputes its
42
+ * verdicts from scratch against the post-removal truth.
43
+ */
28
44
  run(): Promise<void>;
45
+ private cleanUpBranches;
46
+ /**
47
+ * Reap the provably-dead worktrees, then ASK about the probably-dead ones — the same two-tier
48
+ * posture the branch half has, because it is the same verdict on the same branch.
49
+ *
50
+ * WorktreeReaper enforces the safety rails regardless of what is passed or answered: never the
51
+ * primary clone, never the tree this command is running in, and never `--force` (git's refusal to
52
+ * remove a worktree holding untracked or modified files is a feature, and forcing it is how a
53
+ * cleanup command becomes a data-loss command).
54
+ */
55
+ private cleanUpWorktrees;
29
56
  private report;
30
57
  private reapedLine;
58
+ /**
59
+ * The spared branches a human can meaningfully rule on, grouped and ordered most-safe first.
60
+ *
61
+ * Branches spared as IN_USE — checked out in a worktree — are still excluded here, but the reason
62
+ * is no longer "git would simply refuse". That premise died the moment worktrees became reapable.
63
+ * The real reason is the ORDER in run(): the worktree pass has already run, so an IN_USE branch is
64
+ * one of exactly two things. Either its worktree was dead and the reap took the branch with it (so
65
+ * it is not in this list at all), or its worktree is one we are deliberately keeping — locked, held
66
+ * open by uncommitted work, or the one we are standing in — and offering to delete the branch out
67
+ * from under a live checkout is not a question worth asking. The pair is offered TOGETHER by the
68
+ * worktree prompt, which shows both the path and the branch it holds, or it is not offered at all.
69
+ */
31
70
  private promptable;
32
71
  private classifiedBlock;
33
72
  /**
@@ -5,6 +5,7 @@ const tslib_1 = require("tslib");
5
5
  const readline = tslib_1.__importStar(require("readline"));
6
6
  const rules_config_1 = require("@webpieces/rules-config");
7
7
  const inversify_1 = require("inversify");
8
+ const worktree_cleanup_1 = require("./worktree-cleanup");
8
9
  const SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n';
9
10
  // One line of human-facing explanation per promptable classification, ordered most-safe first. These
10
11
  // replace the single string `no merged PR found — a human must decide`, which covered all three of
@@ -18,8 +19,15 @@ const CLASSIFICATION_HEADINGS = {
18
19
  + ' Read the unique-commit counts before answering. This is the group to say no to if unsure.',
19
20
  };
20
21
  /**
21
- * wp-cleanup: delete the local branches whose PR is already merged (or that hold no commits), then ASK
22
- * about the ones that are merely probably-dead.
22
+ * wp-cleanup: remove the dead WORKTREES, delete the local branches whose PR is already merged (or that
23
+ * hold no commits), then ASK about the ones that are merely probably-dead.
24
+ *
25
+ * WHY WORKTREES ARE PART OF THIS: they were the half that never got reaped. The verdicts existed —
26
+ * merged-branches.ts has been writing a full `DeletableWorktree[]` into the cache all along — and their
27
+ * only consumer used them to BLOCK the next `git worktree add`, never to remove anything. Meanwhile a
28
+ * live worktree pins its branch, so the branch was spared too. Two things the tooling could PROVE were
29
+ * dead, accumulating forever, until the guard refused to create the next branch and the only remedy it
30
+ * could offer was loosening its own cap. See WorktreeCleanupSection and WorktreeReaper.
23
31
  *
24
32
  * WHY a named command instead of the `git branch -D a b c` the guards used to print: an AI agent
25
33
  * reads a raw `-D` as destructive, so it asks permission and stops — which is exactly why branches
@@ -42,14 +50,27 @@ let CleanupCommand = class CleanupCommand {
42
50
  repoRootFinder;
43
51
  branchReaper;
44
52
  archiver;
45
- constructor(repoRootFinder, branchReaper, archiver) {
53
+ worktreeSection;
54
+ constructor(repoRootFinder, branchReaper, archiver, worktreeSection) {
46
55
  this.repoRootFinder = repoRootFinder;
47
56
  this.branchReaper = branchReaper;
48
57
  this.archiver = archiver;
58
+ this.worktreeSection = worktreeSection;
49
59
  }
60
+ /**
61
+ * WORKTREES FIRST, then branches. The order is the fix, not a detail: a worktree HOLDS its branch,
62
+ * so that branch is spared `in-use` ("remove that worktree before deleting the branch") and nothing
63
+ * used to remove the worktree — so both piled up until branch-creation-guard refused to make the
64
+ * next one. Reaping the worktree takes its branch with it, and the branch pass then recomputes its
65
+ * verdicts from scratch against the post-removal truth.
66
+ */
50
67
  async run() {
51
68
  const repoRoot = this.repoRootFinder.resolveRepoRoot(process.cwd());
52
69
  const retention = (0, rules_config_1.loadAndValidate)(repoRoot).prGate.landPr.branchRetention;
70
+ await this.cleanUpWorktrees(repoRoot, retention);
71
+ await this.cleanUpBranches(repoRoot, retention);
72
+ }
73
+ async cleanUpBranches(repoRoot, retention) {
53
74
  // No cache argument: wp-cleanup recomputes the verdicts itself. The file on disk is allowed to
54
75
  // go stale, and stale evidence is fine for BLOCKING but never for DELETING.
55
76
  const result = this.branchReaper.reap(repoRoot, 'wp-cleanup', null, retention);
@@ -58,7 +79,7 @@ let CleanupCommand = class CleanupCommand {
58
79
  if (promptable.length === 0)
59
80
  return;
60
81
  process.stdout.write(this.classifiedBlock(promptable));
61
- const approved = await this.askWhichToDelete(promptable);
82
+ const approved = await this.askWhichToDelete(promptable, 'branch');
62
83
  if (approved.length === 0) {
63
84
  process.stdout.write('\nNothing deleted — the branches above were kept.\n');
64
85
  return;
@@ -66,6 +87,33 @@ let CleanupCommand = class CleanupCommand {
66
87
  const second = this.branchReaper.reapApproved(repoRoot, 'wp-cleanup', approved, retention);
67
88
  process.stdout.write(this.report(second));
68
89
  }
90
+ /**
91
+ * Reap the provably-dead worktrees, then ASK about the probably-dead ones — the same two-tier
92
+ * posture the branch half has, because it is the same verdict on the same branch.
93
+ *
94
+ * WorktreeReaper enforces the safety rails regardless of what is passed or answered: never the
95
+ * primary clone, never the tree this command is running in, and never `--force` (git's refusal to
96
+ * remove a worktree holding untracked or modified files is a feature, and forcing it is how a
97
+ * cleanup command becomes a data-loss command).
98
+ */
99
+ async cleanUpWorktrees(repoRoot, retention) {
100
+ const verdicts = this.worktreeSection.verdicts(repoRoot);
101
+ const dead = this.worktreeSection.provablyDead(verdicts);
102
+ if (dead.length > 0) {
103
+ process.stdout.write(this.worktreeSection.report(this.worktreeSection.reap(repoRoot, 'wp-cleanup', dead, retention)));
104
+ }
105
+ process.stdout.write(this.worktreeSection.sparedBlock(verdicts, dead));
106
+ const promptable = this.worktreeSection.promptable(verdicts);
107
+ if (promptable.length === 0)
108
+ return;
109
+ process.stdout.write(this.worktreeSection.promptBlock(promptable));
110
+ const approved = await this.askWhichToDelete(promptable, 'worktree');
111
+ if (approved.length === 0) {
112
+ process.stdout.write('\nNothing removed — the worktrees above were kept.\n');
113
+ return;
114
+ }
115
+ process.stdout.write(this.worktreeSection.report(this.worktreeSection.reap(repoRoot, 'wp-cleanup', approved, retention)));
116
+ }
69
117
  report(result) {
70
118
  if (result.reaped.length === 0 && result.failed.length === 0) {
71
119
  return '\n✅ Nothing to clean up — no local branch is provably dead.\n';
@@ -93,9 +141,18 @@ let CleanupCommand = class CleanupCommand {
93
141
  : '';
94
142
  return ` ✓ ${entry.branch}${sha} — ${entry.reason}${archived}\n`;
95
143
  }
96
- // The spared branches a human can meaningfully rule on, grouped and ordered most-safe first.
97
- // Branches spared for a MECHANICAL reason (checked out in a worktree) are deliberately excluded:
98
- // there is no judgement to make, git would simply refuse.
144
+ /**
145
+ * The spared branches a human can meaningfully rule on, grouped and ordered most-safe first.
146
+ *
147
+ * Branches spared as IN_USE — checked out in a worktree — are still excluded here, but the reason
148
+ * is no longer "git would simply refuse". That premise died the moment worktrees became reapable.
149
+ * The real reason is the ORDER in run(): the worktree pass has already run, so an IN_USE branch is
150
+ * one of exactly two things. Either its worktree was dead and the reap took the branch with it (so
151
+ * it is not in this list at all), or its worktree is one we are deliberately keeping — locked, held
152
+ * open by uncommitted work, or the one we are standing in — and offering to delete the branch out
153
+ * from under a live checkout is not a question worth asking. The pair is offered TOGETHER by the
154
+ * worktree prompt, which shows both the path and the branch it holds, or it is not offered at all.
155
+ */
99
156
  promptable(spared) {
100
157
  const out = [];
101
158
  for (const classification of rules_config_1.PROMPTABLE_CLASSIFICATIONS) {
@@ -130,13 +187,13 @@ let CleanupCommand = class CleanupCommand {
130
187
  * nobody can see must never be read as consent, and this is the one place in the tooling where a
131
188
  * deletion is not backed by a proof.
132
189
  */
133
- async askWhichToDelete(promptable) {
190
+ async askWhichToDelete(promptable, kind) {
134
191
  if (process.stdin.isTTY !== true) {
135
- process.stdout.write('\nNot a terminal — nothing was deleted and nothing was assumed.\n'
192
+ process.stdout.write(`\nNot a terminal — no ${kind} was deleted and nothing was assumed.\n`
136
193
  + 'Run `pnpm wp-cleanup` in an interactive shell to answer, or delete individually.\n');
137
194
  return [];
138
195
  }
139
- const answer = (await this.question(`\nDelete which? [all / none / e.g. "1,3"] (default none): `)).trim().toLowerCase();
196
+ const answer = (await this.question(`\nDelete which ${kind}(s)? [all / none / e.g. "1,3"] (default none): `)).trim().toLowerCase();
140
197
  if (answer === '' || answer === 'none' || answer === 'n')
141
198
  return [];
142
199
  if (answer === 'all' || answer === 'a')
@@ -171,6 +228,7 @@ exports.CleanupCommand = CleanupCommand = tslib_1.__decorate([
171
228
  (0, inversify_1.injectable)(inversify_1.bindingScopeValues.Singleton),
172
229
  tslib_1.__metadata("design:paramtypes", [rules_config_1.RepoRootFinder,
173
230
  rules_config_1.BranchReaper,
174
- rules_config_1.BranchArchiver])
231
+ rules_config_1.BranchArchiver,
232
+ worktree_cleanup_1.WorktreeCleanupSection])
175
233
  ], CleanupCommand);
176
234
  //# sourceMappingURL=cleanup-command.js.map