@webpieces/pr-gate 0.3.354 → 0.3.355

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 (70) hide show
  1. package/package.json +7 -2
  2. package/src/dashboard/dashboard.d.ts +12 -3
  3. package/src/dashboard/dashboard.js +136 -129
  4. package/src/dashboard/dashboard.js.map +1 -1
  5. package/src/index.d.ts +2 -1
  6. package/src/index.js +4 -4
  7. package/src/index.js.map +1 -1
  8. package/src/scripts/commands/finish-update-command.d.ts +10 -0
  9. package/src/scripts/commands/finish-update-command.js +51 -0
  10. package/src/scripts/commands/finish-update-command.js.map +1 -0
  11. package/src/scripts/commands/finish-upsert-pr-command.d.ts +22 -0
  12. package/src/scripts/commands/finish-upsert-pr-command.js +131 -0
  13. package/src/scripts/commands/finish-upsert-pr-command.js.map +1 -0
  14. package/src/scripts/commands/start-update-command.d.ts +9 -0
  15. package/src/scripts/commands/start-update-command.js +67 -0
  16. package/src/scripts/commands/start-update-command.js.map +1 -0
  17. package/src/scripts/commands/start-upsert-pr-command.d.ts +15 -0
  18. package/src/scripts/commands/start-upsert-pr-command.js +73 -0
  19. package/src/scripts/commands/start-upsert-pr-command.js.map +1 -0
  20. package/src/scripts/git-finishUpsertPr.d.ts +1 -1
  21. package/src/scripts/git-finishUpsertPr.js +11 -109
  22. package/src/scripts/git-finishUpsertPr.js.map +1 -1
  23. package/src/scripts/git-gatherInfo.d.ts +15 -1
  24. package/src/scripts/git-gatherInfo.js +79 -61
  25. package/src/scripts/git-gatherInfo.js.map +1 -1
  26. package/src/scripts/pr-gate-app.d.ts +25 -0
  27. package/src/scripts/pr-gate-app.js +56 -0
  28. package/src/scripts/pr-gate-app.js.map +1 -0
  29. package/src/scripts/workflow/branch-naming.d.ts +11 -8
  30. package/src/scripts/workflow/branch-naming.js +30 -21
  31. package/src/scripts/workflow/branch-naming.js.map +1 -1
  32. package/src/scripts/workflow/build-affected.d.ts +21 -30
  33. package/src/scripts/workflow/build-affected.js +57 -63
  34. package/src/scripts/workflow/build-affected.js.map +1 -1
  35. package/src/scripts/workflow/cleanTmp.d.ts +6 -1
  36. package/src/scripts/workflow/cleanTmp.js +83 -78
  37. package/src/scripts/workflow/cleanTmp.js.map +1 -1
  38. package/src/scripts/workflow/git-exec.d.ts +32 -28
  39. package/src/scripts/workflow/git-exec.js +92 -85
  40. package/src/scripts/workflow/git-exec.js.map +1 -1
  41. package/src/scripts/workflow/git-findForkPoint.d.ts +12 -3
  42. package/src/scripts/workflow/git-findForkPoint.js +116 -107
  43. package/src/scripts/workflow/git-findForkPoint.js.map +1 -1
  44. package/src/scripts/workflow/git-readAiBranchName.d.ts +7 -2
  45. package/src/scripts/workflow/git-readAiBranchName.js +24 -15
  46. package/src/scripts/workflow/git-readAiBranchName.js.map +1 -1
  47. package/src/scripts/workflow/merge-end.d.ts +21 -6
  48. package/src/scripts/workflow/merge-end.js +147 -133
  49. package/src/scripts/workflow/merge-end.js.map +1 -1
  50. package/src/scripts/workflow/merge-start.d.ts +22 -1
  51. package/src/scripts/workflow/merge-start.js +180 -186
  52. package/src/scripts/workflow/merge-start.js.map +1 -1
  53. package/src/scripts/workflow/merge-state.d.ts +26 -23
  54. package/src/scripts/workflow/merge-state.js +131 -137
  55. package/src/scripts/workflow/merge-state.js.map +1 -1
  56. package/src/scripts/workflow/open-pr-check.d.ts +7 -1
  57. package/src/scripts/workflow/open-pr-check.js +34 -23
  58. package/src/scripts/workflow/open-pr-check.js.map +1 -1
  59. package/src/scripts/workflow/run-update.d.ts +13 -1
  60. package/src/scripts/workflow/run-update.js +59 -28
  61. package/src/scripts/workflow/run-update.js.map +1 -1
  62. package/src/scripts/wp-finish-update.d.ts +1 -1
  63. package/src/scripts/wp-finish-update.js +11 -30
  64. package/src/scripts/wp-finish-update.js.map +1 -1
  65. package/src/scripts/wp-start-update.d.ts +1 -2
  66. package/src/scripts/wp-start-update.js +11 -51
  67. package/src/scripts/wp-start-update.js.map +1 -1
  68. package/src/scripts/wp-start-upsert-pr.d.ts +1 -1
  69. package/src/scripts/wp-start-upsert-pr.js +11 -47
  70. package/src/scripts/wp-start-upsert-pr.js.map +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webpieces/pr-gate",
3
- "version": "0.3.354",
3
+ "version": "0.3.355",
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",
@@ -21,7 +21,12 @@
21
21
  "directory": "packages/tooling/pr-gate"
22
22
  },
23
23
  "dependencies": {
24
- "@webpieces/rules-config": "0.3.354"
24
+ "@webpieces/rules-config": "0.3.355",
25
+ "@webpieces/core-context": "0.3.355",
26
+ "@webpieces/core-util": "0.3.355",
27
+ "@inversifyjs/binding-decorators": "1.1.5",
28
+ "inversify": "7.10.4",
29
+ "reflect-metadata": "0.2.2"
25
30
  },
26
31
  "publishConfig": {
27
32
  "access": "public"
@@ -5,14 +5,12 @@ export declare class GateResult {
5
5
  matchedFiles: string[];
6
6
  constructor(name: string, warningColor: string, matchedFiles: string[]);
7
7
  }
8
- export declare function computeGateResults(gates: GateDefinition[], changedFiles: string[]): GateResult[];
9
8
  export declare class DisableCounts {
10
9
  webpiecesCount: number;
11
10
  eslintCount: number;
12
11
  webpiecesRules: string[];
13
12
  constructor(webpiecesCount: number, eslintCount: number, webpiecesRules: string[]);
14
13
  }
15
- export declare function countAddedDisables(patch: string): DisableCounts;
16
14
  export declare class DashboardInput {
17
15
  title: string;
18
16
  gateResults: GateResult[];
@@ -24,4 +22,15 @@ export declare class DashboardInput {
24
22
  review: ReviewJson;
25
23
  constructor(title: string, gateResults: GateResult[], disables: DisableCounts, buildPassed: boolean, forkPoint: string, featureHead: string, mainHead: string, review: ReviewJson);
26
24
  }
27
- export declare function renderDashboard(input: DashboardInput): string;
25
+ /** Renders the PR-gate dashboard markdown (gates Ɨ changed files, disables, risk, 3-point hashes). */
26
+ export declare class Dashboard {
27
+ computeGateResults(gates: GateDefinition[], changedFiles: string[]): GateResult[];
28
+ countAddedDisables(patch: string): DisableCounts;
29
+ renderDashboard(input: DashboardInput): string;
30
+ private globToRegex;
31
+ private matchesAny;
32
+ private gateLine;
33
+ private riskBar;
34
+ private riskLines;
35
+ private disableLine;
36
+ }
@@ -1,50 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DashboardInput = exports.DisableCounts = exports.GateResult = void 0;
4
- exports.computeGateResults = computeGateResults;
5
- exports.countAddedDisables = countAddedDisables;
6
- exports.renderDashboard = renderDashboard;
3
+ exports.Dashboard = exports.DashboardInput = exports.DisableCounts = exports.GateResult = void 0;
4
+ const tslib_1 = require("tslib");
7
5
  const rules_config_1 = require("@webpieces/rules-config");
8
- // Self-contained glob matcher (** , * , ?) so pr-gate needs no extra runtime dependency.
9
- function globToRegex(pattern) {
10
- let re = '';
11
- let i = 0;
12
- while (i < pattern.length) {
13
- const ch = pattern[i];
14
- if (ch === '*' && pattern[i + 1] === '*') {
15
- re += '.*';
16
- i += 2;
17
- if (pattern[i] === '/')
18
- i += 1;
19
- continue;
20
- }
21
- if (ch === '*') {
22
- re += '[^/]*';
23
- i += 1;
24
- continue;
25
- }
26
- if (ch === '?') {
27
- re += '[^/]';
28
- i += 1;
29
- continue;
30
- }
31
- if ('.+^$(){}|[]\\'.includes(ch)) {
32
- re += '\\' + ch;
33
- i += 1;
34
- continue;
35
- }
36
- re += ch;
37
- i += 1;
38
- }
39
- return new RegExp('^' + re + '$');
40
- }
41
- function matchesAny(patterns, file) {
42
- for (const pattern of patterns) {
43
- if (globToRegex(pattern).test(file))
44
- return true;
45
- }
46
- return false;
47
- }
6
+ const core_context_1 = require("@webpieces/core-context");
7
+ const inversify_1 = require("inversify");
48
8
  class GateResult {
49
9
  name;
50
10
  warningColor; // 'yellow' | 'red' — the color shown WHEN files matched (green is implicit)
@@ -56,15 +16,6 @@ class GateResult {
56
16
  }
57
17
  }
58
18
  exports.GateResult = GateResult;
59
- // Disabled gates are in-file examples (JSON has no comments) — skip them entirely.
60
- function computeGateResults(gates, changedFiles) {
61
- return gates
62
- .filter((gate) => !gate.disabled)
63
- .map((gate) => {
64
- const matched = changedFiles.filter((file) => matchesAny(gate.patterns, file));
65
- return new GateResult(gate.name, gate.warningColor, matched);
66
- });
67
- }
68
19
  class DisableCounts {
69
20
  webpiecesCount;
70
21
  eslintCount;
@@ -76,28 +27,6 @@ class DisableCounts {
76
27
  }
77
28
  }
78
29
  exports.DisableCounts = DisableCounts;
79
- // Count disables ADDED in this PR by scanning added (`+`) lines of the diff patch. Rule-aware:
80
- // reports which webpieces rules were disabled, using the canonical RULE_NAMES vocabulary.
81
- function countAddedDisables(patch) {
82
- let webpiecesCount = 0;
83
- let eslintCount = 0;
84
- const rules = new Set();
85
- const allRuleTokens = Object.keys(rules_config_1.RULE_NAMES).map((key) => rules_config_1.RULE_NAMES[key]);
86
- for (const line of patch.split('\n')) {
87
- if (!line.startsWith('+') || line.startsWith('+++'))
88
- continue;
89
- if (line.includes(rules_config_1.WEBPIECES_DISABLE)) {
90
- webpiecesCount += 1;
91
- for (const token of allRuleTokens) {
92
- if (line.includes(token))
93
- rules.add(token);
94
- }
95
- }
96
- if (line.includes('eslint-disable'))
97
- eslintCount += 1;
98
- }
99
- return new DisableCounts(webpiecesCount, eslintCount, Array.from(rules).sort());
100
- }
101
30
  class DashboardInput {
102
31
  title;
103
32
  gateResults;
@@ -119,60 +48,138 @@ class DashboardInput {
119
48
  }
120
49
  }
121
50
  exports.DashboardInput = DashboardInput;
122
- function gateLine(result) {
123
- if (result.matchedFiles.length === 0)
124
- return `**${result.name}:** 🟢 No`;
125
- const emoji = result.warningColor === 'red' ? 'šŸ”“' : '🟔';
126
- return `**${result.name}:** ${emoji} Yes (${result.matchedFiles.length} file(s))`;
127
- }
128
- // 10-cell risk bar colored by band (🟩 ≤25, 🟨 ≤50, 🟧 ≤75, 🟄 >75), at least one filled cell —
129
- // ported from trytami's github_risk_bar (git-display-utils.sh).
130
- function riskBar(score) {
131
- const clamped = Math.max(0, Math.min(100, score));
132
- const cell = clamped <= 25 ? '🟩' : clamped <= 50 ? '🟨' : clamped <= 75 ? '🟧' : '🟄';
133
- const filled = Math.max(1, Math.min(10, Math.round(clamped / 10)));
134
- return cell.repeat(filled) + '⬜'.repeat(10 - filled);
135
- }
136
- // RISK section (trytami's AI half): Risk Score bar, Risk Level, Pattern Violations.
137
- function riskLines(review) {
138
- const violations = review.violations.length;
139
- const violationLine = violations === 0 ? '🟢 No' : `🟔 Yes (${violations} violation(s))`;
140
- return [
141
- `**Risk Score:** ${riskBar(review.riskScore)} **${review.riskScore}/100** ${review.riskEmoji}`,
142
- `**Risk Level:** ${review.riskEmoji} **${review.riskLevel}**`,
143
- `**Pattern Violations:** ${violationLine}`,
144
- ];
145
- }
146
- function disableLine(disables) {
147
- if (disables.webpiecesCount === 0)
148
- return '**Webpieces Disables Added:** 🟢 No';
149
- const which = disables.webpiecesRules.length > 0 ? ` — ${disables.webpiecesRules.join(', ')}` : '';
150
- return `**Webpieces Disables Added:** 🟔 ${disables.webpiecesCount} line(s)${which}`;
151
- }
152
- function renderDashboard(input) {
153
- const lines = [];
154
- lines.push('## 🚦 PR Gate Dashboard');
155
- lines.push('');
156
- for (const line of riskLines(input.review))
157
- lines.push(line);
158
- lines.push(`**Build (nx affected):** ${input.buildPassed ? '🟢 Passed' : 'šŸ”“ Failed'}`);
159
- for (const result of input.gateResults)
160
- lines.push(gateLine(result));
161
- lines.push(disableLine(input.disables));
162
- const eslintEmoji = input.disables.eslintCount === 0 ? '🟢 No' : `🟔 ${input.disables.eslintCount} line(s)`;
163
- lines.push(`**ESLint Disables Added:** ${eslintEmoji}`);
164
- lines.push('');
165
- if (input.review.summary.trim() !== '') {
166
- lines.push('### Summary');
167
- lines.push(input.review.summary.trim());
51
+ /** Renders the PR-gate dashboard markdown (gates Ɨ changed files, disables, risk, 3-point hashes). */
52
+ let Dashboard = class Dashboard {
53
+ // Disabled gates are in-file examples (JSON has no comments) — skip them entirely.
54
+ computeGateResults(gates, changedFiles) {
55
+ return gates
56
+ .filter((gate) => !gate.disabled)
57
+ .map((gate) => {
58
+ const matched = changedFiles.filter((file) => this.matchesAny(gate.patterns, file));
59
+ return new GateResult(gate.name, gate.warningColor, matched);
60
+ });
61
+ }
62
+ // Count disables ADDED in this PR by scanning added (`+`) lines of the diff patch. Rule-aware:
63
+ // reports which webpieces rules were disabled, using the canonical RULE_NAMES vocabulary.
64
+ countAddedDisables(patch) {
65
+ let webpiecesCount = 0;
66
+ let eslintCount = 0;
67
+ const rules = new Set();
68
+ const allRuleTokens = Object.keys(rules_config_1.RULE_NAMES).map((key) => rules_config_1.RULE_NAMES[key]);
69
+ for (const line of patch.split('\n')) {
70
+ if (!line.startsWith('+') || line.startsWith('+++'))
71
+ continue;
72
+ if (line.includes(rules_config_1.WEBPIECES_DISABLE)) {
73
+ webpiecesCount += 1;
74
+ for (const token of allRuleTokens) {
75
+ if (line.includes(token))
76
+ rules.add(token);
77
+ }
78
+ }
79
+ if (line.includes('eslint-disable'))
80
+ eslintCount += 1;
81
+ }
82
+ return new DisableCounts(webpiecesCount, eslintCount, Array.from(rules).sort());
83
+ }
84
+ renderDashboard(input) {
85
+ const lines = [];
86
+ lines.push('## 🚦 PR Gate Dashboard');
87
+ lines.push('');
88
+ for (const line of this.riskLines(input.review))
89
+ lines.push(line);
90
+ lines.push(`**Build (nx affected):** ${input.buildPassed ? '🟢 Passed' : 'šŸ”“ Failed'}`);
91
+ for (const result of input.gateResults)
92
+ lines.push(this.gateLine(result));
93
+ lines.push(this.disableLine(input.disables));
94
+ const eslintEmoji = input.disables.eslintCount === 0 ? '🟢 No' : `🟔 ${input.disables.eslintCount} line(s)`;
95
+ lines.push(`**ESLint Disables Added:** ${eslintEmoji}`);
168
96
  lines.push('');
97
+ if (input.review.summary.trim() !== '') {
98
+ lines.push('### Summary');
99
+ lines.push(input.review.summary.trim());
100
+ lines.push('');
101
+ }
102
+ lines.push('### šŸ” 3-Point Hash Points');
103
+ lines.push(`- Fork point (A): \`${input.forkPoint.slice(0, 12)}\``);
104
+ lines.push(`- Feature HEAD (B): \`${input.featureHead.slice(0, 12)}\``);
105
+ lines.push(`- Main HEAD (C): \`${input.mainHead.slice(0, 12)}\``);
106
+ lines.push('');
107
+ lines.push('<sub>šŸ¤– Generated by `pnpm wp-finish-upsert-pr` (build ran via nx affected — not self-attested).</sub>');
108
+ return lines.join('\n');
169
109
  }
170
- lines.push('### šŸ” 3-Point Hash Points');
171
- lines.push(`- Fork point (A): \`${input.forkPoint.slice(0, 12)}\``);
172
- lines.push(`- Feature HEAD (B): \`${input.featureHead.slice(0, 12)}\``);
173
- lines.push(`- Main HEAD (C): \`${input.mainHead.slice(0, 12)}\``);
174
- lines.push('');
175
- lines.push('<sub>šŸ¤– Generated by `pnpm wp-finish-upsert-pr` (build ran via nx affected — not self-attested).</sub>');
176
- return lines.join('\n');
177
- }
110
+ // Self-contained glob matcher (** , * , ?) so pr-gate needs no extra runtime dependency.
111
+ globToRegex(pattern) {
112
+ let re = '';
113
+ let i = 0;
114
+ while (i < pattern.length) {
115
+ const ch = pattern[i];
116
+ if (ch === '*' && pattern[i + 1] === '*') {
117
+ re += '.*';
118
+ i += 2;
119
+ if (pattern[i] === '/')
120
+ i += 1;
121
+ continue;
122
+ }
123
+ if (ch === '*') {
124
+ re += '[^/]*';
125
+ i += 1;
126
+ continue;
127
+ }
128
+ if (ch === '?') {
129
+ re += '[^/]';
130
+ i += 1;
131
+ continue;
132
+ }
133
+ if ('.+^$(){}|[]\\'.includes(ch)) {
134
+ re += '\\' + ch;
135
+ i += 1;
136
+ continue;
137
+ }
138
+ re += ch;
139
+ i += 1;
140
+ }
141
+ return new RegExp('^' + re + '$');
142
+ }
143
+ matchesAny(patterns, file) {
144
+ for (const pattern of patterns) {
145
+ if (this.globToRegex(pattern).test(file))
146
+ return true;
147
+ }
148
+ return false;
149
+ }
150
+ gateLine(result) {
151
+ if (result.matchedFiles.length === 0)
152
+ return `**${result.name}:** 🟢 No`;
153
+ const emoji = result.warningColor === 'red' ? 'šŸ”“' : '🟔';
154
+ return `**${result.name}:** ${emoji} Yes (${result.matchedFiles.length} file(s))`;
155
+ }
156
+ // 10-cell risk bar colored by band (🟩 ≤25, 🟨 ≤50, 🟧 ≤75, 🟄 >75), at least one filled cell.
157
+ riskBar(score) {
158
+ const clamped = Math.max(0, Math.min(100, score));
159
+ const cell = clamped <= 25 ? '🟩' : clamped <= 50 ? '🟨' : clamped <= 75 ? '🟧' : '🟄';
160
+ const filled = Math.max(1, Math.min(10, Math.round(clamped / 10)));
161
+ return cell.repeat(filled) + '⬜'.repeat(10 - filled);
162
+ }
163
+ // RISK section (the AI half): Risk Score bar, Risk Level, Pattern Violations.
164
+ riskLines(review) {
165
+ const violations = review.violations.length;
166
+ const violationLine = violations === 0 ? '🟢 No' : `🟔 Yes (${violations} violation(s))`;
167
+ return [
168
+ `**Risk Score:** ${this.riskBar(review.riskScore)} **${review.riskScore}/100** ${review.riskEmoji}`,
169
+ `**Risk Level:** ${review.riskEmoji} **${review.riskLevel}**`,
170
+ `**Pattern Violations:** ${violationLine}`,
171
+ ];
172
+ }
173
+ disableLine(disables) {
174
+ if (disables.webpiecesCount === 0)
175
+ return '**Webpieces Disables Added:** 🟢 No';
176
+ const which = disables.webpiecesRules.length > 0 ? ` — ${disables.webpiecesRules.join(', ')}` : '';
177
+ return `**Webpieces Disables Added:** 🟔 ${disables.webpiecesCount} line(s)${which}`;
178
+ }
179
+ };
180
+ exports.Dashboard = Dashboard;
181
+ exports.Dashboard = Dashboard = tslib_1.__decorate([
182
+ (0, core_context_1.provideSingleton)(),
183
+ (0, inversify_1.injectable)()
184
+ ], Dashboard);
178
185
  //# sourceMappingURL=dashboard.js.map
@@ -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 { GateDefinition, WEBPIECES_DISABLE, RULE_NAMES, ReviewJson } from '@webpieces/rules-config';\n\n// Self-contained glob matcher (** , * , ?) so pr-gate needs no extra runtime dependency.\nfunction 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\nfunction matchesAny(patterns: string[], file: string): boolean {\n for (const pattern of patterns) {\n if (globToRegex(pattern).test(file)) return true;\n }\n return false;\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// Disabled gates are in-file examples (JSON has no comments) — skip them entirely.\nexport function 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 => matchesAny(gate.patterns, file));\n return new GateResult(gate.name, gate.warningColor, matched);\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\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.\nexport function 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\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\n constructor(\n title: string, gateResults: GateResult[], disables: DisableCounts,\n buildPassed: boolean, forkPoint: string, featureHead: string, mainHead: string, review: ReviewJson,\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 }\n}\n\nfunction 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// 10-cell risk bar colored by band (🟩 ≤25, 🟨 ≤50, 🟧 ≤75, 🟄 >75), at least one filled cell —\n// ported from trytami's github_risk_bar (git-display-utils.sh).\nfunction 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 (trytami's AI half): Risk Score bar, Risk Level, Pattern Violations.\nfunction 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:** ${riskBar(review.riskScore)} **${review.riskScore}/100** ${review.riskEmoji}`,\n `**Risk Level:** ${review.riskEmoji} **${review.riskLevel}**`,\n `**Pattern Violations:** ${violationLine}`,\n ];\n}\n\nfunction 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\nexport function renderDashboard(input: DashboardInput): string {\n const lines: string[] = [];\n lines.push('## 🚦 PR Gate Dashboard');\n lines.push('');\n for (const line of 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(gateLine(result));\n lines.push(disableLine(input.disables));\n const eslintEmoji = input.disables.eslintCount === 0 ? '🟢 No' : `🟔 ${input.disables.eslintCount} line(s)`;\n lines.push(`**ESLint Disables Added:** ${eslintEmoji}`);\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"]}
1
+ {"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../../../../../packages/tooling/pr-gate/src/dashboard/dashboard.ts"],"names":[],"mappings":"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","sourcesContent":["import { GateDefinition, WEBPIECES_DISABLE, RULE_NAMES, ReviewJson } from '@webpieces/rules-config';\nimport { provideSingleton } from '@webpieces/core-context';\nimport { injectable } from 'inversify';\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\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\n constructor(\n title: string, gateResults: GateResult[], disables: DisableCounts,\n buildPassed: boolean, forkPoint: string, featureHead: string, mainHead: string, review: ReviewJson,\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 }\n}\n\n/** Renders the PR-gate dashboard markdown (gates Ɨ changed files, disables, risk, 3-point hashes). */\n@provideSingleton()\n@injectable()\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 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 // 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 // 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"]}
package/src/index.d.ts CHANGED
@@ -1 +1,2 @@
1
- export { GateResult, DisableCounts, DashboardInput, computeGateResults, countAddedDisables, renderDashboard, } from './dashboard/dashboard';
1
+ export { GateResult, DisableCounts, DashboardInput, Dashboard, } from './dashboard/dashboard';
2
+ export { PrGateApp } from './scripts/pr-gate-app';
package/src/index.js CHANGED
@@ -8,12 +8,12 @@
8
8
  // (runBuildAffected, gatherInfo), not bins. Shared library exports (dashboard gate computation,
9
9
  // etc.) back the dashboard those commands render.
10
10
  Object.defineProperty(exports, "__esModule", { value: true });
11
- exports.renderDashboard = exports.countAddedDisables = exports.computeGateResults = exports.DashboardInput = exports.DisableCounts = exports.GateResult = void 0;
11
+ exports.PrGateApp = exports.Dashboard = exports.DashboardInput = exports.DisableCounts = exports.GateResult = void 0;
12
12
  var dashboard_1 = require("./dashboard/dashboard");
13
13
  Object.defineProperty(exports, "GateResult", { enumerable: true, get: function () { return dashboard_1.GateResult; } });
14
14
  Object.defineProperty(exports, "DisableCounts", { enumerable: true, get: function () { return dashboard_1.DisableCounts; } });
15
15
  Object.defineProperty(exports, "DashboardInput", { enumerable: true, get: function () { return dashboard_1.DashboardInput; } });
16
- Object.defineProperty(exports, "computeGateResults", { enumerable: true, get: function () { return dashboard_1.computeGateResults; } });
17
- Object.defineProperty(exports, "countAddedDisables", { enumerable: true, get: function () { return dashboard_1.countAddedDisables; } });
18
- Object.defineProperty(exports, "renderDashboard", { enumerable: true, get: function () { return dashboard_1.renderDashboard; } });
16
+ Object.defineProperty(exports, "Dashboard", { enumerable: true, get: function () { return dashboard_1.Dashboard; } });
17
+ var pr_gate_app_1 = require("./scripts/pr-gate-app");
18
+ Object.defineProperty(exports, "PrGateApp", { enumerable: true, get: function () { return pr_gate_app_1.PrGateApp; } });
19
19
  //# sourceMappingURL=index.js.map
package/src/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/tooling/pr-gate/src/index.ts"],"names":[],"mappings":";AAAA,wCAAwC;AACxC,EAAE;AACF,2EAA2E;AAC3E,8EAA8E;AAC9E,yFAAyF;AACzF,6FAA6F;AAC7F,gGAAgG;AAChG,kDAAkD;;;AAElD,mDAO+B;AAN3B,uGAAA,UAAU,OAAA;AACV,0GAAA,aAAa,OAAA;AACb,2GAAA,cAAc,OAAA;AACd,+GAAA,kBAAkB,OAAA;AAClB,+GAAA,kBAAkB,OAAA;AAClB,4GAAA,eAAe,OAAA","sourcesContent":["// @webpieces/pr-gate — gated PR system.\n//\n// Now published to npm via the release workflow (OIDC trusted publishing).\n// Public surface is intentionally small for now. The package mainly ships bin\n// commands (wp-start-update, wp-finish-update, wp-finish-upsert-pr, wp-start-upsert-pr).\n// The build gate and 3-point merge-info gathering are internal `workflow/` library functions\n// (runBuildAffected, gatherInfo), not bins. Shared library exports (dashboard gate computation,\n// etc.) back the dashboard those commands render.\n\nexport {\n GateResult,\n DisableCounts,\n DashboardInput,\n computeGateResults,\n countAddedDisables,\n renderDashboard,\n} from './dashboard/dashboard';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/tooling/pr-gate/src/index.ts"],"names":[],"mappings":";AAAA,wCAAwC;AACxC,EAAE;AACF,2EAA2E;AAC3E,8EAA8E;AAC9E,yFAAyF;AACzF,6FAA6F;AAC7F,gGAAgG;AAChG,kDAAkD;;;AAElD,mDAK+B;AAJ3B,uGAAA,UAAU,OAAA;AACV,0GAAA,aAAa,OAAA;AACb,2GAAA,cAAc,OAAA;AACd,sGAAA,SAAS,OAAA;AAEb,qDAAkD;AAAzC,wGAAA,SAAS,OAAA","sourcesContent":["// @webpieces/pr-gate — gated PR system.\n//\n// Now published to npm via the release workflow (OIDC trusted publishing).\n// Public surface is intentionally small for now. The package mainly ships bin\n// commands (wp-start-update, wp-finish-update, wp-finish-upsert-pr, wp-start-upsert-pr).\n// The build gate and 3-point merge-info gathering are internal `workflow/` library functions\n// (runBuildAffected, gatherInfo), not bins. Shared library exports (dashboard gate computation,\n// etc.) back the dashboard those commands render.\n\nexport {\n GateResult,\n DisableCounts,\n DashboardInput,\n Dashboard,\n} from './dashboard/dashboard';\nexport { PrGateApp } from './scripts/pr-gate-app';\n"]}
@@ -0,0 +1,10 @@
1
+ import { AiBranchName } from '../workflow/git-readAiBranchName';
2
+ import { MergeState } from '../workflow/merge-state';
3
+ import { MergeEnd } from '../workflow/merge-end';
4
+ export declare class FinishUpdateCommand {
5
+ private readonly aiBranchName;
6
+ private readonly mergeState;
7
+ private readonly mergeEnd;
8
+ constructor(aiBranchName: AiBranchName, mergeState: MergeState, mergeEnd: MergeEnd);
9
+ run(): Promise<void>;
10
+ }
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FinishUpdateCommand = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const child_process_1 = require("child_process");
6
+ const rules_config_1 = require("@webpieces/rules-config");
7
+ const core_context_1 = require("@webpieces/core-context");
8
+ const inversify_1 = require("inversify");
9
+ const git_readAiBranchName_1 = require("../workflow/git-readAiBranchName");
10
+ const merge_state_1 = require("../workflow/merge-state");
11
+ const merge_end_1 = require("../workflow/merge-end");
12
+ const merge_start_1 = require("../workflow/merge-start");
13
+ // wp-finish-update — the finalize half of the 3-point squash-merge lifecycle. Run AFTER wp-start-update
14
+ // handed back conflicts and you resolved them. Given an in-progress marker it validates + commits the
15
+ // AI's resolution (when not yet validated) and ALWAYS finalizes the branch swap. It does NOT run the
16
+ // build gate / dashboard / PR — that is wp-finish-upsert-pr. Refuses when no merge is in progress.
17
+ let FinishUpdateCommand = class FinishUpdateCommand {
18
+ aiBranchName;
19
+ mergeState;
20
+ mergeEnd;
21
+ constructor(aiBranchName, mergeState, mergeEnd) {
22
+ this.aiBranchName = aiBranchName;
23
+ this.mergeState = mergeState;
24
+ this.mergeEnd = mergeEnd;
25
+ }
26
+ async run() {
27
+ const repoRoot = (0, child_process_1.execSync)('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();
28
+ const home = this.mergeState.mergeDirFor(repoRoot, this.aiBranchName.getFeatureName());
29
+ // The in-progress merge is the `merge-<n>/` run dir holding a marker.
30
+ const activeDir = this.mergeState.findActiveMergeRunDir(home);
31
+ const marker = activeDir ? this.mergeState.readMergeMarker(activeDir) : null;
32
+ if (!activeDir || !marker) {
33
+ throw new rules_config_1.CliExitError(1, 'āŒ No merge in progress (no marker) — nothing to finalize.\n' +
34
+ 'Start one with: pnpm wp-start-update (a clean update finalizes itself).');
35
+ }
36
+ // Not yet validated => a conflict resolution the AI owns, so validate + commit it first;
37
+ // already validated => clean merge (or previously validated) => finalize only.
38
+ const conflictedFiles = marker.validated ? null : marker.conflictedFiles;
39
+ await this.mergeEnd.mergeEnd(repoRoot, 'wp-finish-update', activeDir, new merge_start_1.MergeContext(marker.currentBranch, marker.squashBranch, marker.backupBranch, marker.prNumber), conflictedFiles);
40
+ process.stdout.write('\nāœ… Merge finalized on ' + marker.currentBranch + '.\n');
41
+ }
42
+ };
43
+ exports.FinishUpdateCommand = FinishUpdateCommand;
44
+ exports.FinishUpdateCommand = FinishUpdateCommand = tslib_1.__decorate([
45
+ (0, core_context_1.provideSingleton)(),
46
+ (0, inversify_1.injectable)(),
47
+ tslib_1.__metadata("design:paramtypes", [git_readAiBranchName_1.AiBranchName,
48
+ merge_state_1.MergeState,
49
+ merge_end_1.MergeEnd])
50
+ ], FinishUpdateCommand);
51
+ //# sourceMappingURL=finish-update-command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finish-update-command.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/pr-gate/src/scripts/commands/finish-update-command.ts"],"names":[],"mappings":";;;;AAAA,iDAAyC;AACzC,0DAAuD;AACvD,0DAA2D;AAC3D,yCAAuC;AACvC,2EAAgE;AAChE,yDAAqD;AACrD,qDAAiD;AACjD,yDAAuD;AAEvD,wGAAwG;AACxG,sGAAsG;AACtG,qGAAqG;AACrG,mGAAmG;AAG5F,IAAM,mBAAmB,GAAzB,MAAM,mBAAmB;IAEP;IACA;IACA;IAHrB,YACqB,YAA0B,EAC1B,UAAsB,EACtB,QAAkB;QAFlB,iBAAY,GAAZ,YAAY,CAAc;QAC1B,eAAU,GAAV,UAAU,CAAY;QACtB,aAAQ,GAAR,QAAQ,CAAU;IACpC,CAAC;IAEJ,KAAK,CAAC,GAAG;QACL,MAAM,QAAQ,GAAG,IAAA,wBAAQ,EAAC,+BAA+B,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACxF,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,QAAQ,EAAE,IAAI,CAAC,YAAY,CAAC,cAAc,EAAE,CAAC,CAAC;QAEvF,sEAAsE;QACtE,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC;QAC9D,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC7E,IAAI,CAAC,SAAS,IAAI,CAAC,MAAM,EAAE,CAAC;YACxB,MAAM,IAAI,2BAAY,CAAC,CAAC,EACpB,6DAA6D;gBAC7D,2EAA2E,CAC9E,CAAC;QACN,CAAC;QAED,yFAAyF;QACzF,+EAA+E;QAC/E,MAAM,eAAe,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC;QACzE,MAAM,IAAI,CAAC,QAAQ,CAAC,QAAQ,CACxB,QAAQ,EAAE,kBAAkB,EAAE,SAAS,EACvC,IAAI,0BAAY,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,QAAQ,CAAC,EACjG,eAAe,CAClB,CAAC;QACF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,yBAAyB,GAAG,MAAM,CAAC,aAAa,GAAG,KAAK,CAAC,CAAC;IACnF,CAAC;CACJ,CAAA;AA/BY,kDAAmB;8BAAnB,mBAAmB;IAF/B,IAAA,+BAAgB,GAAE;IAClB,IAAA,sBAAU,GAAE;6CAG0B,mCAAY;QACd,wBAAU;QACZ,oBAAQ;GAJ9B,mBAAmB,CA+B/B","sourcesContent":["import { execSync } from 'child_process';\nimport { CliExitError } from '@webpieces/rules-config';\nimport { provideSingleton } from '@webpieces/core-context';\nimport { injectable } from 'inversify';\nimport { AiBranchName } from '../workflow/git-readAiBranchName';\nimport { MergeState } from '../workflow/merge-state';\nimport { MergeEnd } from '../workflow/merge-end';\nimport { MergeContext } from '../workflow/merge-start';\n\n// wp-finish-update — the finalize half of the 3-point squash-merge lifecycle. Run AFTER wp-start-update\n// handed back conflicts and you resolved them. Given an in-progress marker it validates + commits the\n// AI's resolution (when not yet validated) and ALWAYS finalizes the branch swap. It does NOT run the\n// build gate / dashboard / PR — that is wp-finish-upsert-pr. Refuses when no merge is in progress.\n@provideSingleton()\n@injectable()\nexport class FinishUpdateCommand {\n constructor(\n private readonly aiBranchName: AiBranchName,\n private readonly mergeState: MergeState,\n private readonly mergeEnd: MergeEnd,\n ) {}\n\n async run(): Promise<void> {\n const repoRoot = execSync('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();\n const home = this.mergeState.mergeDirFor(repoRoot, this.aiBranchName.getFeatureName());\n\n // The in-progress merge is the `merge-<n>/` run dir holding a marker.\n const activeDir = this.mergeState.findActiveMergeRunDir(home);\n const marker = activeDir ? this.mergeState.readMergeMarker(activeDir) : null;\n if (!activeDir || !marker) {\n throw new CliExitError(1,\n 'āŒ No merge in progress (no marker) — nothing to finalize.\\n' +\n 'Start one with: pnpm wp-start-update (a clean update finalizes itself).',\n );\n }\n\n // Not yet validated => a conflict resolution the AI owns, so validate + commit it first;\n // already validated => clean merge (or previously validated) => finalize only.\n const conflictedFiles = marker.validated ? null : marker.conflictedFiles;\n await this.mergeEnd.mergeEnd(\n repoRoot, 'wp-finish-update', activeDir,\n new MergeContext(marker.currentBranch, marker.squashBranch, marker.backupBranch, marker.prNumber),\n conflictedFiles,\n );\n process.stdout.write('\\nāœ… Merge finalized on ' + marker.currentBranch + '.\\n');\n }\n}\n"]}
@@ -0,0 +1,22 @@
1
+ import { AiBranchName } from '../workflow/git-readAiBranchName';
2
+ import { BranchNaming } from '../workflow/branch-naming';
3
+ import { GitExec } from '../workflow/git-exec';
4
+ import { BuildAffected } from '../workflow/build-affected';
5
+ import { MergeState } from '../workflow/merge-state';
6
+ import { MergeEnd } from '../workflow/merge-end';
7
+ import { Dashboard } from '../../dashboard/dashboard';
8
+ export declare class FinishUpsertPrCommand {
9
+ private readonly aiBranchName;
10
+ private readonly branchNaming;
11
+ private readonly gitExec;
12
+ private readonly buildAffected;
13
+ private readonly mergeState;
14
+ private readonly mergeEnd;
15
+ private readonly dashboard;
16
+ constructor(aiBranchName: AiBranchName, branchNaming: BranchNaming, gitExec: GitExec, buildAffected: BuildAffected, mergeState: MergeState, mergeEnd: MergeEnd, dashboard: Dashboard);
17
+ run(): Promise<void>;
18
+ private gitOut;
19
+ private prTitleFrom;
20
+ private buildDashboard;
21
+ private upsertPr;
22
+ }