@webpieces/pr-gate 0.4.476 → 0.4.477
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webpieces/pr-gate",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.477",
|
|
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",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"directory": "packages/tooling/pr-gate"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@webpieces/rules-config": "0.4.
|
|
27
|
+
"@webpieces/rules-config": "0.4.477",
|
|
28
28
|
"@inversifyjs/binding-decorators": "1.1.5",
|
|
29
29
|
"inversify": "7.10.4",
|
|
30
30
|
"reflect-metadata": "0.2.2"
|
|
@@ -19,6 +19,7 @@ export declare class StartUpsertPrCommand {
|
|
|
19
19
|
constructor(repoRootFinder: RepoRootFinder, aiBranchName: AiBranchName, branchNaming: BranchNaming, buildAffected: BuildAffected, gitExec: GitExec, runUpdate: RunUpdate, checklistDetector: ChecklistDetector, manifestService: ChecklistManifestService, reviewJsonService: ReviewJsonService, diffScope: DiffScope);
|
|
20
20
|
run(): Promise<void>;
|
|
21
21
|
private writePrContext;
|
|
22
|
+
private alreadyReviewed;
|
|
22
23
|
private printChecklistPlan;
|
|
23
24
|
private scaffoldCiWorkflow;
|
|
24
25
|
private updateBranchFromMain;
|
|
@@ -64,15 +64,20 @@ let StartUpsertPrCommand = class StartUpsertPrCommand {
|
|
|
64
64
|
const triggered = this.checklistDetector.detectForRepo(repoRoot, defs);
|
|
65
65
|
const required = this.checklistDetector.toRequired(triggered);
|
|
66
66
|
const reviewPath = (0, rules_config_1.reviewJsonPath)(repoRoot, this.aiBranchName.getFeatureName());
|
|
67
|
+
// REVIEW ONCE PER BRANCH: a checklist that already has a passing/overridden review-<id>.json from an
|
|
68
|
+
// earlier cycle is NOT re-reviewed — only the ones still needing a verdict are handed to the AI. The
|
|
69
|
+
// review files persist in .webpieces, so a second wp-start/wp-finish cycle re-instructs nothing.
|
|
70
|
+
const results = this.reviewJsonService.loadChecklistResults(reviewPath, required);
|
|
71
|
+
const toReview = required.filter((req) => !this.alreadyReviewed(req, results));
|
|
67
72
|
// Persist the review-format + process instructions where any failure message can cite them.
|
|
68
73
|
(0, rules_config_1.writeTemplate)(repoRoot, 'webpieces.review-checklists.md');
|
|
69
74
|
// Persist the PR diff context (base sha + changed files) so reviewer subagents can `git diff` for
|
|
70
75
|
// content instead of the tooling matching on regexes. Written whenever a base resolves.
|
|
71
76
|
this.writePrContext(repoRoot);
|
|
72
|
-
this.printChecklistPlan(
|
|
77
|
+
this.printChecklistPlan(triggered, toReview);
|
|
73
78
|
process.stdout.write('\n' + SEP + '③ Review the PR, then finish\n' + SEP + '\n');
|
|
74
79
|
process.stdout.write(`Branch is updated, pushed, and the build gate passed. Now review your own changes and\n` +
|
|
75
|
-
`${(0, rules_config_1.reviewJsonSchemaHint)(reviewPath,
|
|
80
|
+
`${(0, rules_config_1.reviewJsonSchemaHint)(reviewPath, toReview)}\n\n` +
|
|
76
81
|
`Then run: pnpm wp-finish-upsert-pr\n` +
|
|
77
82
|
`(It re-validates the build, renders the dashboard with your risk/violations, and creates/updates the PR.)\n\n`);
|
|
78
83
|
}
|
|
@@ -89,18 +94,29 @@ let StartUpsertPrCommand = class StartUpsertPrCommand {
|
|
|
89
94
|
const p = this.reviewJsonService.writePrContext(repoRoot, this.aiBranchName.getFeatureName(), new rules_config_1.PrContext(range.base, head, changed));
|
|
90
95
|
process.stdout.write(`\n📂 Wrote PR diff context (${changed.length} changed file(s)) → ${p}\n`);
|
|
91
96
|
}
|
|
92
|
-
//
|
|
93
|
-
//
|
|
94
|
-
|
|
95
|
-
|
|
97
|
+
// A checklist already reviewed on this branch — its review-<id>.json resolves to PASS or OVERRIDDEN —
|
|
98
|
+
// so it is NOT handed back to the AI to re-review (review once per branch).
|
|
99
|
+
alreadyReviewed(req, results) {
|
|
100
|
+
const status = this.reviewJsonService.resolveVerdict(req, results).status;
|
|
101
|
+
return status === rules_config_1.CK_PASS || status === rules_config_1.CK_OVERRIDDEN;
|
|
102
|
+
}
|
|
103
|
+
// Show which matched checklists still need a reviewer subagent (spawn each as a distinct one) and which
|
|
104
|
+
// are already reviewed (reused, not re-run) — so a second cycle re-instructs nothing.
|
|
105
|
+
printChecklistPlan(triggered, toReview) {
|
|
106
|
+
if (triggered.length === 0)
|
|
96
107
|
return;
|
|
97
108
|
process.stdout.write('\n' + SEP + '📋 Review checklists\n' + SEP + '\n');
|
|
98
|
-
|
|
99
|
-
|
|
109
|
+
const toReviewIds = new Set(toReview.map((r) => r.id));
|
|
110
|
+
const reused = triggered.filter((t) => !toReviewIds.has(t.def.id));
|
|
111
|
+
for (const t of reused) {
|
|
112
|
+
process.stdout.write(` ✓ ${t.def.subagent} — already reviewed on this branch (reusing its review-${t.def.id}.json)\n`);
|
|
113
|
+
}
|
|
114
|
+
if (toReview.length === 0) {
|
|
115
|
+
process.stdout.write('All matched checklists are already reviewed — nothing to re-run. Just write review.json and finish.\n');
|
|
100
116
|
return;
|
|
101
117
|
}
|
|
102
118
|
process.stdout.write('Spawn EACH of these as a SEPARATE subagent (a different one per checklist — do not self-certify):\n');
|
|
103
|
-
for (const t of triggered) {
|
|
119
|
+
for (const t of triggered.filter((x) => toReviewIds.has(x.def.id))) {
|
|
104
120
|
process.stdout.write(` • subagent "${t.def.subagent}"`);
|
|
105
121
|
if (t.def.doc.trim() !== '')
|
|
106
122
|
process.stdout.write(` — reads ${t.def.doc}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"start-upsert-pr-command.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/pr-gate/src/scripts/commands/start-upsert-pr-command.ts"],"names":[],"mappings":"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","sourcesContent":["import { execSync } from 'child_process';\nimport { loadAndValidate, reviewJsonPath, reviewJsonSchemaHint, writeTemplate, writeTemplateIfMissing, CliExitError, RepoRootFinder, ChecklistManifestService, ReviewJsonService, DiffScope, ChangedFilesOptions, PrContext } from '@webpieces/rules-config';\nimport { TriggeredChecklist } from '../workflow/checklist-detector';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { AiBranchName } from '../workflow/git-readAiBranchName';\nimport { BranchNaming } from '../workflow/branch-naming';\nimport { BuildAffected, BuildGateOptions } from '../workflow/build-affected';\nimport { ChecklistDetector } from '../workflow/checklist-detector';\nimport { GitExec } from '../workflow/git-exec';\nimport { RunUpdate } from '../workflow/run-update';\n\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\n// START of the AI-first PR flow: the deterministic setup — update from main, push, run the advisory\n// build gate — then hand the AI instructions to WRITE review.json and run `wp-finish-upsert-pr` (which\n// reads it and posts the PR). This command NEVER creates/updates a PR; all `gh` posting lives in finish.\n@injectable(bindingScopeValues.Singleton)\nexport class StartUpsertPrCommand {\n constructor(\n private readonly repoRootFinder: RepoRootFinder,\n private readonly aiBranchName: AiBranchName,\n private readonly branchNaming: BranchNaming,\n private readonly buildAffected: BuildAffected,\n private readonly gitExec: GitExec,\n private readonly runUpdate: RunUpdate,\n private readonly checklistDetector: ChecklistDetector,\n private readonly manifestService: ChecklistManifestService,\n private readonly reviewJsonService: ReviewJsonService,\n private readonly diffScope: DiffScope,\n ) {}\n\n async run(): Promise<void> {\n const repoRoot = this.repoRootFinder.resolveRepoRoot(process.cwd());\n // Refresh the AI-facing workflow doc so it's present + current for any failure message to cite.\n writeTemplate(repoRoot, 'webpieces.git-workflow.md');\n // When this repo has opted into server-side enforcement (a committed gateSalt), scaffold the CI\n // workflow into the gitignored instruct-ai dir (never .github directly — that would dirty the tree\n // before the clean-tree check) and tell the human to copy + require it. IfMissing so it is written\n // once and never clobbers a customized copy.\n this.scaffoldCiWorkflow(repoRoot);\n\n // Precondition: a fully-committed tree. This flow updates, pushes HEAD, and builds — the tooling\n // must not commit your work for you, and pushing HEAD while building the working tree would let\n // an uncommitted change build green yet push a stale commit. Fail early if dirty.\n this.gitExec.assertCleanTree(repoRoot);\n\n await this.updateBranchFromMain(repoRoot);\n // Local branch, remote branch, and PR share the one stable feature name.\n this.gitExec.ensurePushed(this.branchNaming.baseBranchName(execSync('git branch --show-current', { encoding: 'utf8' }).trim()));\n\n // Advisory build gate — early feedback before the AI writes review.json. wp-finish-upsert-pr\n // runs the authoritative one. Both go through the same runBuildGate (only the framing differs).\n this.buildAffected.runBuildGate(repoRoot, new BuildGateOptions(\n '② Build gate (nx affected)', 'pnpm wp-start-upsert-pr', 'Build failed — fix it before reviewing.',\n ));\n\n // Hand the AI its next step: write review.json, then run finish (which posts the PR). Compute the\n // checklists this diff MATCHED (from the manifest doc) so the hint names each reviewer subagent to\n // spawn BEFORE review.json is written (empty for repos with no checklist doc ⇒ the hint is unchanged).\n const defs = this.manifestService.load(repoRoot, loadAndValidate(repoRoot).prGate.checklistDoc);\n const triggered = this.checklistDetector.detectForRepo(repoRoot, defs);\n const required = this.checklistDetector.toRequired(triggered);\n const reviewPath = reviewJsonPath(repoRoot, this.aiBranchName.getFeatureName());\n // Persist the review-format + process instructions where any failure message can cite them.\n writeTemplate(repoRoot, 'webpieces.review-checklists.md');\n // Persist the PR diff context (base sha + changed files) so reviewer subagents can `git diff` for\n // content instead of the tooling matching on regexes. Written whenever a base resolves.\n this.writePrContext(repoRoot);\n this.printChecklistPlan(defs.length, triggered);\n process.stdout.write('\\n' + SEP + '③ Review the PR, then finish\\n' + SEP + '\\n');\n process.stdout.write(\n `Branch is updated, pushed, and the build gate passed. Now review your own changes and\\n` +\n `${reviewJsonSchemaHint(reviewPath, required)}\\n\\n` +\n `Then run: pnpm wp-finish-upsert-pr\\n` +\n `(It re-validates the build, renders the dashboard with your risk/violations, and creates/updates the PR.)\\n\\n`,\n );\n }\n\n // Write pr-context.json (base/head sha + the full changed-file set, tsOnly:false) so a reviewer\n // subagent knows the exact base the gate uses and can `git diff <base> HEAD -- <file>` for content.\n private writePrContext(repoRoot: string): void {\n const range = this.diffScope.resolveBase(repoRoot);\n if (!range.base) return;\n const opts = new ChangedFilesOptions();\n opts.tsOnly = false;\n const changed = this.diffScope.getChangedFiles(repoRoot, range.base, range.head, opts);\n const head = range.head && range.head.trim() !== '' ? range.head : 'HEAD';\n const p = this.reviewJsonService.writePrContext(\n repoRoot, this.aiBranchName.getFeatureName(), new PrContext(range.base, head, changed),\n );\n process.stdout.write(`\\n📂 Wrote PR diff context (${changed.length} changed file(s)) → ${p}\\n`);\n }\n\n // Show which review checklists the diff matched (spawn a SEPARATE subagent for each) and which were\n // skipped because their patterns did not match — so it is visible WHY fewer than all of them ran.\n private printChecklistPlan(total: number, triggered: readonly TriggeredChecklist[]): void {\n if (total === 0) return;\n process.stdout.write('\\n' + SEP + '📋 Review checklists\\n' + SEP + '\\n');\n if (triggered.length === 0) {\n process.stdout.write('No checklist patterns matched this diff — no reviewer subagents needed.\\n');\n return;\n }\n process.stdout.write('Spawn EACH of these as a SEPARATE subagent (a different one per checklist — do not self-certify):\\n');\n for (const t of triggered) {\n process.stdout.write(` • subagent \"${t.def.subagent}\"`);\n if (t.def.doc.trim() !== '') process.stdout.write(` — reads ${t.def.doc}`);\n process.stdout.write(` (matched: ${t.matchedFiles.slice(0, 4).join(', ')})\\n`);\n }\n process.stdout.write('See .webpieces/instruct-ai/webpieces.review-checklists.md for the review-<id>.json format each must write.\\n');\n }\n\n // Scaffold the server-side CI check when (and only when) this repo set a gateSalt. Written to the\n // gitignored instruct-ai dir so it never dirties the tree; the human copies it to .github/workflows\n // and marks it required (webpieces can't set branch protection). No-op for repos with no gateSalt.\n private scaffoldCiWorkflow(repoRoot: string): void {\n if (loadAndValidate(repoRoot).prGate.gateSalt.trim() === '') return;\n writeTemplateIfMissing(repoRoot, 'webpieces-pr-gate.yml');\n process.stdout.write(\n `\\nℹ️ Server-side gate enforcement is ON (gateSalt set). If you have not already:\\n` +\n ` • copy .webpieces/instruct-ai/webpieces-pr-gate.yml → .github/workflows/ and commit it\\n` +\n ` • mark the \"webpieces-pr-gate\" check REQUIRED in branch protection (repo admin only)\\n`,\n );\n }\n\n // Bring the branch up to date with main via the shared 3-point engine (in-process). On conflict the\n // merge process doc it writes names `wp-finish-upsert-pr` as the finish command.\n private async updateBranchFromMain(repoRoot: string): Promise<void> {\n process.stdout.write('\\n' + SEP + '① Updating branch from main\\n' + SEP + '\\n');\n const outcome = await this.runUpdate.runUpdateFromMain(repoRoot, 'wp-start-upsert-pr', 'wp-finish-upsert-pr');\n if (outcome === 'conflict' || outcome === 'unvalidatedResume') {\n throw new CliExitError(2,\n '\\n⏸️ Conflicts — resolve them, then run pnpm wp-finish-upsert-pr (it validates the merge AND finishes the PR).',\n );\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"start-upsert-pr-command.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/pr-gate/src/scripts/commands/start-upsert-pr-command.ts"],"names":[],"mappings":"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","sourcesContent":["import { execSync } from 'child_process';\nimport { loadAndValidate, reviewJsonPath, reviewJsonSchemaHint, writeTemplate, writeTemplateIfMissing, CliExitError, RepoRootFinder, ChecklistManifestService, ReviewJsonService, DiffScope, ChangedFilesOptions, PrContext, RequiredChecklist, ChecklistResult, CK_PASS, CK_OVERRIDDEN } from '@webpieces/rules-config';\nimport { TriggeredChecklist } from '../workflow/checklist-detector';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { AiBranchName } from '../workflow/git-readAiBranchName';\nimport { BranchNaming } from '../workflow/branch-naming';\nimport { BuildAffected, BuildGateOptions } from '../workflow/build-affected';\nimport { ChecklistDetector } from '../workflow/checklist-detector';\nimport { GitExec } from '../workflow/git-exec';\nimport { RunUpdate } from '../workflow/run-update';\n\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\n// START of the AI-first PR flow: the deterministic setup — update from main, push, run the advisory\n// build gate — then hand the AI instructions to WRITE review.json and run `wp-finish-upsert-pr` (which\n// reads it and posts the PR). This command NEVER creates/updates a PR; all `gh` posting lives in finish.\n@injectable(bindingScopeValues.Singleton)\nexport class StartUpsertPrCommand {\n constructor(\n private readonly repoRootFinder: RepoRootFinder,\n private readonly aiBranchName: AiBranchName,\n private readonly branchNaming: BranchNaming,\n private readonly buildAffected: BuildAffected,\n private readonly gitExec: GitExec,\n private readonly runUpdate: RunUpdate,\n private readonly checklistDetector: ChecklistDetector,\n private readonly manifestService: ChecklistManifestService,\n private readonly reviewJsonService: ReviewJsonService,\n private readonly diffScope: DiffScope,\n ) {}\n\n async run(): Promise<void> {\n const repoRoot = this.repoRootFinder.resolveRepoRoot(process.cwd());\n // Refresh the AI-facing workflow doc so it's present + current for any failure message to cite.\n writeTemplate(repoRoot, 'webpieces.git-workflow.md');\n // When this repo has opted into server-side enforcement (a committed gateSalt), scaffold the CI\n // workflow into the gitignored instruct-ai dir (never .github directly — that would dirty the tree\n // before the clean-tree check) and tell the human to copy + require it. IfMissing so it is written\n // once and never clobbers a customized copy.\n this.scaffoldCiWorkflow(repoRoot);\n\n // Precondition: a fully-committed tree. This flow updates, pushes HEAD, and builds — the tooling\n // must not commit your work for you, and pushing HEAD while building the working tree would let\n // an uncommitted change build green yet push a stale commit. Fail early if dirty.\n this.gitExec.assertCleanTree(repoRoot);\n\n await this.updateBranchFromMain(repoRoot);\n // Local branch, remote branch, and PR share the one stable feature name.\n this.gitExec.ensurePushed(this.branchNaming.baseBranchName(execSync('git branch --show-current', { encoding: 'utf8' }).trim()));\n\n // Advisory build gate — early feedback before the AI writes review.json. wp-finish-upsert-pr\n // runs the authoritative one. Both go through the same runBuildGate (only the framing differs).\n this.buildAffected.runBuildGate(repoRoot, new BuildGateOptions(\n '② Build gate (nx affected)', 'pnpm wp-start-upsert-pr', 'Build failed — fix it before reviewing.',\n ));\n\n // Hand the AI its next step: write review.json, then run finish (which posts the PR). Compute the\n // checklists this diff MATCHED (from the manifest doc) so the hint names each reviewer subagent to\n // spawn BEFORE review.json is written (empty for repos with no checklist doc ⇒ the hint is unchanged).\n const defs = this.manifestService.load(repoRoot, loadAndValidate(repoRoot).prGate.checklistDoc);\n const triggered = this.checklistDetector.detectForRepo(repoRoot, defs);\n const required = this.checklistDetector.toRequired(triggered);\n const reviewPath = reviewJsonPath(repoRoot, this.aiBranchName.getFeatureName());\n // REVIEW ONCE PER BRANCH: a checklist that already has a passing/overridden review-<id>.json from an\n // earlier cycle is NOT re-reviewed — only the ones still needing a verdict are handed to the AI. The\n // review files persist in .webpieces, so a second wp-start/wp-finish cycle re-instructs nothing.\n const results = this.reviewJsonService.loadChecklistResults(reviewPath, required);\n const toReview = required.filter((req: RequiredChecklist): boolean => !this.alreadyReviewed(req, results));\n // Persist the review-format + process instructions where any failure message can cite them.\n writeTemplate(repoRoot, 'webpieces.review-checklists.md');\n // Persist the PR diff context (base sha + changed files) so reviewer subagents can `git diff` for\n // content instead of the tooling matching on regexes. Written whenever a base resolves.\n this.writePrContext(repoRoot);\n this.printChecklistPlan(triggered, toReview);\n process.stdout.write('\\n' + SEP + '③ Review the PR, then finish\\n' + SEP + '\\n');\n process.stdout.write(\n `Branch is updated, pushed, and the build gate passed. Now review your own changes and\\n` +\n `${reviewJsonSchemaHint(reviewPath, toReview)}\\n\\n` +\n `Then run: pnpm wp-finish-upsert-pr\\n` +\n `(It re-validates the build, renders the dashboard with your risk/violations, and creates/updates the PR.)\\n\\n`,\n );\n }\n\n // Write pr-context.json (base/head sha + the full changed-file set, tsOnly:false) so a reviewer\n // subagent knows the exact base the gate uses and can `git diff <base> HEAD -- <file>` for content.\n private writePrContext(repoRoot: string): void {\n const range = this.diffScope.resolveBase(repoRoot);\n if (!range.base) return;\n const opts = new ChangedFilesOptions();\n opts.tsOnly = false;\n const changed = this.diffScope.getChangedFiles(repoRoot, range.base, range.head, opts);\n const head = range.head && range.head.trim() !== '' ? range.head : 'HEAD';\n const p = this.reviewJsonService.writePrContext(\n repoRoot, this.aiBranchName.getFeatureName(), new PrContext(range.base, head, changed),\n );\n process.stdout.write(`\\n📂 Wrote PR diff context (${changed.length} changed file(s)) → ${p}\\n`);\n }\n\n // A checklist already reviewed on this branch — its review-<id>.json resolves to PASS or OVERRIDDEN —\n // so it is NOT handed back to the AI to re-review (review once per branch).\n private alreadyReviewed(req: RequiredChecklist, results: readonly ChecklistResult[]): boolean {\n const status = this.reviewJsonService.resolveVerdict(req, results).status;\n return status === CK_PASS || status === CK_OVERRIDDEN;\n }\n\n // Show which matched checklists still need a reviewer subagent (spawn each as a distinct one) and which\n // are already reviewed (reused, not re-run) — so a second cycle re-instructs nothing.\n private printChecklistPlan(triggered: readonly TriggeredChecklist[], toReview: readonly RequiredChecklist[]): void {\n if (triggered.length === 0) return;\n process.stdout.write('\\n' + SEP + '📋 Review checklists\\n' + SEP + '\\n');\n const toReviewIds = new Set(toReview.map((r: RequiredChecklist): string => r.id));\n const reused = triggered.filter((t: TriggeredChecklist): boolean => !toReviewIds.has(t.def.id));\n for (const t of reused) {\n process.stdout.write(` ✓ ${t.def.subagent} — already reviewed on this branch (reusing its review-${t.def.id}.json)\\n`);\n }\n if (toReview.length === 0) {\n process.stdout.write('All matched checklists are already reviewed — nothing to re-run. Just write review.json and finish.\\n');\n return;\n }\n process.stdout.write('Spawn EACH of these as a SEPARATE subagent (a different one per checklist — do not self-certify):\\n');\n for (const t of triggered.filter((x: TriggeredChecklist): boolean => toReviewIds.has(x.def.id))) {\n process.stdout.write(` • subagent \"${t.def.subagent}\"`);\n if (t.def.doc.trim() !== '') process.stdout.write(` — reads ${t.def.doc}`);\n process.stdout.write(` (matched: ${t.matchedFiles.slice(0, 4).join(', ')})\\n`);\n }\n process.stdout.write('See .webpieces/instruct-ai/webpieces.review-checklists.md for the review-<id>.json format each must write.\\n');\n }\n\n // Scaffold the server-side CI check when (and only when) this repo set a gateSalt. Written to the\n // gitignored instruct-ai dir so it never dirties the tree; the human copies it to .github/workflows\n // and marks it required (webpieces can't set branch protection). No-op for repos with no gateSalt.\n private scaffoldCiWorkflow(repoRoot: string): void {\n if (loadAndValidate(repoRoot).prGate.gateSalt.trim() === '') return;\n writeTemplateIfMissing(repoRoot, 'webpieces-pr-gate.yml');\n process.stdout.write(\n `\\nℹ️ Server-side gate enforcement is ON (gateSalt set). If you have not already:\\n` +\n ` • copy .webpieces/instruct-ai/webpieces-pr-gate.yml → .github/workflows/ and commit it\\n` +\n ` • mark the \"webpieces-pr-gate\" check REQUIRED in branch protection (repo admin only)\\n`,\n );\n }\n\n // Bring the branch up to date with main via the shared 3-point engine (in-process). On conflict the\n // merge process doc it writes names `wp-finish-upsert-pr` as the finish command.\n private async updateBranchFromMain(repoRoot: string): Promise<void> {\n process.stdout.write('\\n' + SEP + '① Updating branch from main\\n' + SEP + '\\n');\n const outcome = await this.runUpdate.runUpdateFromMain(repoRoot, 'wp-start-upsert-pr', 'wp-finish-upsert-pr');\n if (outcome === 'conflict' || outcome === 'unvalidatedResume') {\n throw new CliExitError(2,\n '\\n⏸️ Conflicts — resolve them, then run pnpm wp-finish-upsert-pr (it validates the merge AND finishes the PR).',\n );\n }\n }\n}\n"]}
|