@webpieces/pr-gate 0.3.263 → 0.3.272

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 (30) hide show
  1. package/package.json +4 -5
  2. package/src/index.js +1 -1
  3. package/src/index.js.map +1 -1
  4. package/src/scripts/workflow/git-findForkPoint.js +1 -1
  5. package/src/scripts/workflow/git-findForkPoint.js.map +1 -1
  6. package/src/scripts/workflow/git-validateUpToDate.js +1 -1
  7. package/src/scripts/workflow/git-validateUpToDate.js.map +1 -1
  8. package/src/scripts/workflow/merge-end.js +3 -3
  9. package/src/scripts/workflow/merge-end.js.map +1 -1
  10. package/src/scripts/workflow/merge-start.d.ts +1 -1
  11. package/src/scripts/workflow/merge-start.js +24 -19
  12. package/src/scripts/workflow/merge-start.js.map +1 -1
  13. package/src/scripts/workflow/run-update.d.ts +2 -0
  14. package/src/scripts/workflow/run-update.js +30 -0
  15. package/src/scripts/workflow/run-update.js.map +1 -0
  16. package/src/scripts/wp-start-upsert-pr.d.ts +1 -1
  17. package/src/scripts/wp-start-upsert-pr.js +14 -12
  18. package/src/scripts/wp-start-upsert-pr.js.map +1 -1
  19. package/src/scripts/{wp-merge-end.js → wp-update-end.js} +8 -8
  20. package/src/scripts/wp-update-end.js.map +1 -0
  21. package/src/scripts/wp-update-start.js +38 -0
  22. package/src/scripts/wp-update-start.js.map +1 -0
  23. package/src/scripts/git-updateFromMain.js +0 -56
  24. package/src/scripts/git-updateFromMain.js.map +0 -1
  25. package/src/scripts/wp-merge-end.js.map +0 -1
  26. package/src/scripts/wp-merge-start.d.ts +0 -2
  27. package/src/scripts/wp-merge-start.js +0 -45
  28. package/src/scripts/wp-merge-start.js.map +0 -1
  29. /package/src/scripts/{git-updateFromMain.d.ts → wp-update-end.d.ts} +0 -0
  30. /package/src/scripts/{wp-merge-end.d.ts → wp-update-start.d.ts} +0 -0
package/package.json CHANGED
@@ -1,17 +1,16 @@
1
1
  {
2
2
  "name": "@webpieces/pr-gate",
3
- "version": "0.3.263",
3
+ "version": "0.3.272",
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",
7
7
  "bin": {
8
- "wp-git-update": "./src/scripts/git-updateFromMain.js",
9
8
  "wp-git-gather": "./src/scripts/git-gatherInfo.js",
10
9
  "wp-finish-upsert-pr": "./src/scripts/git-finishUpsertPr.js",
11
10
  "wp-build-affected": "./src/scripts/wp-build-affected.js",
12
11
  "wp-start-upsert-pr": "./src/scripts/wp-start-upsert-pr.js",
13
- "wp-merge-start": "./src/scripts/wp-merge-start.js",
14
- "wp-merge-end": "./src/scripts/wp-merge-end.js"
12
+ "wp-update-start": "./src/scripts/wp-update-start.js",
13
+ "wp-update-end": "./src/scripts/wp-update-end.js"
15
14
  },
16
15
  "files": [
17
16
  "src/**/*"
@@ -24,7 +23,7 @@
24
23
  "directory": "packages/tooling/pr-gate"
25
24
  },
26
25
  "dependencies": {
27
- "@webpieces/rules-config": "0.3.263"
26
+ "@webpieces/rules-config": "0.3.272"
28
27
  },
29
28
  "publishConfig": {
30
29
  "access": "public"
package/src/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  //
4
4
  // Now published to npm via the release workflow (OIDC trusted publishing).
5
5
  // Public surface is intentionally small for now. The package mainly ships bin
6
- // commands (wp-git-update, wp-git-gather, wp-finish-upsert-pr, wp-start-upsert-pr,
6
+ // commands (wp-update-start, wp-update-end, wp-git-gather, wp-finish-upsert-pr, wp-start-upsert-pr,
7
7
  // wp-build-affected). Shared library exports (dashboard gate computation, etc.) back
8
8
  // the dashboard those commands render.
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
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,mFAAmF;AACnF,qFAAqF;AACrF,uCAAuC;;;AAEvC,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-git-update, wp-git-gather, wp-finish-upsert-pr, wp-start-upsert-pr,\n// wp-build-affected). Shared library exports (dashboard gate computation, etc.) back\n// 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,oGAAoG;AACpG,qFAAqF;AACrF,uCAAuC;;;AAEvC,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-update-start, wp-update-end, wp-git-gather, wp-finish-upsert-pr, wp-start-upsert-pr,\n// wp-build-affected). Shared library exports (dashboard gate computation, etc.) back\n// the dashboard those commands render.\n\nexport {\n GateResult,\n DisableCounts,\n DashboardInput,\n computeGateResults,\n countAddedDisables,\n renderDashboard,\n} from './dashboard/dashboard';\n"]}
@@ -14,7 +14,7 @@ const SEP = '━━━━━━━━━━━━━━━━━━━━━━
14
14
  function printMergeFromMainError(commit, parent, featureName, currentBranch) {
15
15
  process.stderr.write('\n');
16
16
  process.stderr.write(SEP);
17
- process.stderr.write('❌ This branch merged main without pnpm wp-git-update\n');
17
+ process.stderr.write('❌ This branch merged main without pnpm wp-update-start\n');
18
18
  process.stderr.write(SEP);
19
19
  process.stderr.write('\n');
20
20
  process.stderr.write(`Merge commit detected: ${commit}\n`);
@@ -1 +1 @@
1
- {"version":3,"file":"git-findForkPoint.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/pr-gate/src/scripts/workflow/git-findForkPoint.ts"],"names":[],"mappings":"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","sourcesContent":["import { execSync, spawnSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { prDirFor } from '@webpieces/rules-config';\nimport { getFeatureName } from './git-readAiBranchName';\nimport { mergeDirFor } from './merge-state';\n\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\nfunction printMergeFromMainError(commit: string, parent: string, featureName: string, currentBranch: string): void {\n process.stderr.write('\\n');\n process.stderr.write(SEP);\n process.stderr.write('❌ This branch merged main without pnpm wp-git-update\\n');\n process.stderr.write(SEP);\n process.stderr.write('\\n');\n process.stderr.write(`Merge commit detected: ${commit}\\n`);\n process.stderr.write(`Parent from main: ${parent}\\n`);\n process.stderr.write('\\n');\n process.stderr.write('This prevents clean squash-merge. To recover, follow these steps:\\n');\n process.stderr.write('\\n');\n process.stderr.write('1. Switch to main branch:\\n');\n process.stderr.write(' git checkout main\\n');\n process.stderr.write('\\n');\n process.stderr.write('2. Pull latest changes:\\n');\n process.stderr.write(' git pull\\n');\n process.stderr.write('\\n');\n process.stderr.write('3. Create new branch with a new name:\\n');\n process.stderr.write(` git checkout -b ${featureName}-v2\\n`);\n process.stderr.write('\\n');\n process.stderr.write('4. Squash merge your old branch:\\n');\n process.stderr.write(` git merge --squash ${currentBranch}\\n`);\n process.stderr.write('\\n');\n process.stderr.write('5. Commit the squashed changes:\\n');\n process.stderr.write(` git add -A && git commit -m \"Squashed from ${currentBranch}\"\\n`);\n process.stderr.write('\\n');\n process.stderr.write('6. If you have an existing PR:\\n');\n process.stderr.write(` - Create a NEW PR for ${featureName}-v2\\n`);\n process.stderr.write(` - Close the old PR for ${currentBranch}\\n`);\n process.stderr.write('\\n');\n process.stderr.write(SEP);\n process.stderr.write('\\n');\n}\n\nfunction checkMergeCommits(mergeCommits: string[], outputDir: string, prefix: string, featureName: string, currentBranch: string): void {\n process.stderr.write(`Found ${mergeCommits.length} merge commit(s) to check...\\n`);\n\n for (const commit of mergeCommits) {\n const parentsResult = spawnSync('git', ['rev-list', '--parents', '-n', '1', commit], { encoding: 'utf8' });\n const parents = (parentsResult.stdout ?? '').trim().split(' ').slice(1);\n\n for (const parent of parents) {\n const ancestorCheck = spawnSync('git', ['merge-base', '--is-ancestor', parent, 'origin/main']);\n const reverseCheck = spawnSync('git', ['merge-base', '--is-ancestor', 'origin/main', parent]);\n\n if (ancestorCheck.status === 0 && reverseCheck.status === 0) {\n const errorJson = JSON.stringify({\n error: 'Merge from main detected',\n mergeCommit: commit,\n parentFromMain: parent,\n timestamp: new Date().toISOString(),\n }, null, 2);\n\n fs.writeFileSync(path.join(outputDir, `${prefix}forkpoint-error.json`), errorJson + '\\n');\n printMergeFromMainError(commit, parent, featureName, currentBranch);\n process.exit(1);\n }\n }\n }\n process.stderr.write('✅ No improper merges from main detected\\n');\n}\n\n// Single source of truth for the per-feature dir fork-point output is written to — the SAME nested\n// home the readers use (git-gatherInfo / merge-start read updatemain-hashes.json from mergeDirFor;\n// the review flow reads from prDirFor). Previously findForkPoint wrote to the legacy flat\n// `.webpieces/<workflow>-<feature>/` while readers looked under `.webpieces/merge-info/<feature>/`,\n// so the hash file was written to one path and read from another. Routing the writer through these\n// same helpers is what keeps them from diverging again — guarded by git-findForkPoint.spec.ts.\nexport function forkPointOutputDir(repoRoot: string, featureName: string, workflow: string): string {\n return workflow === 'review' ? prDirFor(repoRoot, featureName) : mergeDirFor(repoRoot, featureName);\n}\n\nexport async function findForkPoint(workflow: string): Promise<void> {\n if (workflow !== 'review' && workflow !== 'merge') {\n process.stderr.write('ERROR: Workflow argument required\\n');\n process.stderr.write('Usage: git-findForkPoint <workflow>\\n');\n process.stderr.write(\" workflow: 'review' or 'merge'\\n\");\n process.exit(1);\n }\n\n const featureName = getFeatureName();\n const currentBranch = execSync('git branch --show-current', { encoding: 'utf8' }).trim();\n const repoRoot = execSync('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();\n\n const outputDir = forkPointOutputDir(repoRoot, featureName, workflow);\n const prefix = workflow === 'review' ? 'review-' : 'updatemain-';\n fs.mkdirSync(outputDir, { recursive: true });\n\n spawnSync('git', ['fetch', 'origin', 'main'], { stdio: 'ignore' });\n\n const featureHead = execSync('git rev-parse HEAD', { encoding: 'utf8' }).trim();\n const originMain = execSync('git rev-parse origin/main', { encoding: 'utf8' }).trim();\n\n process.stderr.write('Finding fork point using git merge-base...\\n');\n\n const forkPointResult = spawnSync('git', ['merge-base', 'origin/main', 'HEAD'], { encoding: 'utf8' });\n const forkPoint = (forkPointResult.stdout ?? '').trim();\n\n if (!forkPoint || forkPointResult.status !== 0) {\n process.stderr.write('ERROR: Could not find common ancestor with origin/main\\n');\n process.exit(1);\n }\n\n process.stderr.write(`✅ Fork point found: ${forkPoint.slice(0, 7)}\\n`);\n process.stderr.write('Checking for improper merges from main...\\n');\n\n const mergeCommitsResult = spawnSync('git', ['log', `${forkPoint}..HEAD`, '--merges', '--format=%H'], { encoding: 'utf8' });\n const mergeCommitsRaw = (mergeCommitsResult.stdout ?? '').trim();\n const mergeCommits = mergeCommitsRaw ? mergeCommitsRaw.split('\\n') : [];\n\n if (mergeCommits.length > 0) {\n checkMergeCommits(mergeCommits, outputDir, prefix, featureName, currentBranch);\n } else {\n process.stderr.write('✅ No merge commits found (clean history)\\n');\n }\n\n const hashesJson = JSON.stringify({\n hashForkPoint: forkPoint,\n hashFeatureHead: featureHead,\n hashMainHead: originMain,\n timestamp: new Date().toISOString(),\n }, null, 2);\n\n fs.writeFileSync(path.join(outputDir, `${prefix}hashes.json`), hashesJson + '\\n');\n process.stderr.write(`✅ Hash points written to: ${outputDir}/${prefix}hashes.json\\n`);\n}\n\nexport async function main(): Promise<void> {\n await findForkPoint(process.argv[2] ?? '');\n}\n\nif (require.main === module) {\n main().catch((err) => {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(message + '\\n');\n process.exit(1);\n });\n}\n"]}
1
+ {"version":3,"file":"git-findForkPoint.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/pr-gate/src/scripts/workflow/git-findForkPoint.ts"],"names":[],"mappings":"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","sourcesContent":["import { execSync, spawnSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { prDirFor } from '@webpieces/rules-config';\nimport { getFeatureName } from './git-readAiBranchName';\nimport { mergeDirFor } from './merge-state';\n\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\nfunction printMergeFromMainError(commit: string, parent: string, featureName: string, currentBranch: string): void {\n process.stderr.write('\\n');\n process.stderr.write(SEP);\n process.stderr.write('❌ This branch merged main without pnpm wp-update-start\\n');\n process.stderr.write(SEP);\n process.stderr.write('\\n');\n process.stderr.write(`Merge commit detected: ${commit}\\n`);\n process.stderr.write(`Parent from main: ${parent}\\n`);\n process.stderr.write('\\n');\n process.stderr.write('This prevents clean squash-merge. To recover, follow these steps:\\n');\n process.stderr.write('\\n');\n process.stderr.write('1. Switch to main branch:\\n');\n process.stderr.write(' git checkout main\\n');\n process.stderr.write('\\n');\n process.stderr.write('2. Pull latest changes:\\n');\n process.stderr.write(' git pull\\n');\n process.stderr.write('\\n');\n process.stderr.write('3. Create new branch with a new name:\\n');\n process.stderr.write(` git checkout -b ${featureName}-v2\\n`);\n process.stderr.write('\\n');\n process.stderr.write('4. Squash merge your old branch:\\n');\n process.stderr.write(` git merge --squash ${currentBranch}\\n`);\n process.stderr.write('\\n');\n process.stderr.write('5. Commit the squashed changes:\\n');\n process.stderr.write(` git add -A && git commit -m \"Squashed from ${currentBranch}\"\\n`);\n process.stderr.write('\\n');\n process.stderr.write('6. If you have an existing PR:\\n');\n process.stderr.write(` - Create a NEW PR for ${featureName}-v2\\n`);\n process.stderr.write(` - Close the old PR for ${currentBranch}\\n`);\n process.stderr.write('\\n');\n process.stderr.write(SEP);\n process.stderr.write('\\n');\n}\n\nfunction checkMergeCommits(mergeCommits: string[], outputDir: string, prefix: string, featureName: string, currentBranch: string): void {\n process.stderr.write(`Found ${mergeCommits.length} merge commit(s) to check...\\n`);\n\n for (const commit of mergeCommits) {\n const parentsResult = spawnSync('git', ['rev-list', '--parents', '-n', '1', commit], { encoding: 'utf8' });\n const parents = (parentsResult.stdout ?? '').trim().split(' ').slice(1);\n\n for (const parent of parents) {\n const ancestorCheck = spawnSync('git', ['merge-base', '--is-ancestor', parent, 'origin/main']);\n const reverseCheck = spawnSync('git', ['merge-base', '--is-ancestor', 'origin/main', parent]);\n\n if (ancestorCheck.status === 0 && reverseCheck.status === 0) {\n const errorJson = JSON.stringify({\n error: 'Merge from main detected',\n mergeCommit: commit,\n parentFromMain: parent,\n timestamp: new Date().toISOString(),\n }, null, 2);\n\n fs.writeFileSync(path.join(outputDir, `${prefix}forkpoint-error.json`), errorJson + '\\n');\n printMergeFromMainError(commit, parent, featureName, currentBranch);\n process.exit(1);\n }\n }\n }\n process.stderr.write('✅ No improper merges from main detected\\n');\n}\n\n// Single source of truth for the per-feature dir fork-point output is written to — the SAME nested\n// home the readers use (git-gatherInfo / merge-start read updatemain-hashes.json from mergeDirFor;\n// the review flow reads from prDirFor). Previously findForkPoint wrote to the legacy flat\n// `.webpieces/<workflow>-<feature>/` while readers looked under `.webpieces/merge-info/<feature>/`,\n// so the hash file was written to one path and read from another. Routing the writer through these\n// same helpers is what keeps them from diverging again — guarded by git-findForkPoint.spec.ts.\nexport function forkPointOutputDir(repoRoot: string, featureName: string, workflow: string): string {\n return workflow === 'review' ? prDirFor(repoRoot, featureName) : mergeDirFor(repoRoot, featureName);\n}\n\nexport async function findForkPoint(workflow: string): Promise<void> {\n if (workflow !== 'review' && workflow !== 'merge') {\n process.stderr.write('ERROR: Workflow argument required\\n');\n process.stderr.write('Usage: git-findForkPoint <workflow>\\n');\n process.stderr.write(\" workflow: 'review' or 'merge'\\n\");\n process.exit(1);\n }\n\n const featureName = getFeatureName();\n const currentBranch = execSync('git branch --show-current', { encoding: 'utf8' }).trim();\n const repoRoot = execSync('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();\n\n const outputDir = forkPointOutputDir(repoRoot, featureName, workflow);\n const prefix = workflow === 'review' ? 'review-' : 'updatemain-';\n fs.mkdirSync(outputDir, { recursive: true });\n\n spawnSync('git', ['fetch', 'origin', 'main'], { stdio: 'ignore' });\n\n const featureHead = execSync('git rev-parse HEAD', { encoding: 'utf8' }).trim();\n const originMain = execSync('git rev-parse origin/main', { encoding: 'utf8' }).trim();\n\n process.stderr.write('Finding fork point using git merge-base...\\n');\n\n const forkPointResult = spawnSync('git', ['merge-base', 'origin/main', 'HEAD'], { encoding: 'utf8' });\n const forkPoint = (forkPointResult.stdout ?? '').trim();\n\n if (!forkPoint || forkPointResult.status !== 0) {\n process.stderr.write('ERROR: Could not find common ancestor with origin/main\\n');\n process.exit(1);\n }\n\n process.stderr.write(`✅ Fork point found: ${forkPoint.slice(0, 7)}\\n`);\n process.stderr.write('Checking for improper merges from main...\\n');\n\n const mergeCommitsResult = spawnSync('git', ['log', `${forkPoint}..HEAD`, '--merges', '--format=%H'], { encoding: 'utf8' });\n const mergeCommitsRaw = (mergeCommitsResult.stdout ?? '').trim();\n const mergeCommits = mergeCommitsRaw ? mergeCommitsRaw.split('\\n') : [];\n\n if (mergeCommits.length > 0) {\n checkMergeCommits(mergeCommits, outputDir, prefix, featureName, currentBranch);\n } else {\n process.stderr.write('✅ No merge commits found (clean history)\\n');\n }\n\n const hashesJson = JSON.stringify({\n hashForkPoint: forkPoint,\n hashFeatureHead: featureHead,\n hashMainHead: originMain,\n timestamp: new Date().toISOString(),\n }, null, 2);\n\n fs.writeFileSync(path.join(outputDir, `${prefix}hashes.json`), hashesJson + '\\n');\n process.stderr.write(`✅ Hash points written to: ${outputDir}/${prefix}hashes.json\\n`);\n}\n\nexport async function main(): Promise<void> {\n await findForkPoint(process.argv[2] ?? '');\n}\n\nif (require.main === module) {\n main().catch((err) => {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(message + '\\n');\n process.exit(1);\n });\n}\n"]}
@@ -38,7 +38,7 @@ async function main() {
38
38
  process.stdout.write(SEP);
39
39
  process.stdout.write('\n');
40
40
  process.stdout.write('1. Update your branch with latest main:\n');
41
- process.stdout.write(' pnpm wp-git-update\n');
41
+ process.stdout.write(' pnpm wp-update-start\n');
42
42
  process.stdout.write('\n');
43
43
  process.stdout.write('2. ⚠️ IMPORTANT: REVIEW THE CODE AFTER MERGE!\n');
44
44
  process.stdout.write(' - Check for merge conflicts\n');
@@ -1 +1 @@
1
- {"version":3,"file":"git-validateUpToDate.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/pr-gate/src/scripts/workflow/git-validateUpToDate.ts"],"names":[],"mappings":"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","sourcesContent":["import { execSync, spawnSync } from 'child_process';\n\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\nexport async function main(): Promise<void> {\n const branch = execSync('git branch --show-current', { encoding: 'utf8' }).trim();\n\n if (branch === 'main') {\n process.stdout.write('✅ On main branch - no validation needed\\n');\n return;\n }\n\n process.stdout.write('Validating branch is up to date with origin/main...\\n');\n process.stdout.write(`Current branch: ${branch}\\n`);\n process.stdout.write('\\n');\n\n process.stdout.write('Fetching latest from origin/main...\\n');\n spawnSync('git', ['fetch', 'origin', 'main', '--quiet'], { stdio: 'inherit' });\n\n const isUpToDate = spawnSync('git', ['merge-base', '--is-ancestor', 'origin/main', 'HEAD']).status === 0;\n\n if (isUpToDate) {\n process.stdout.write('✅ Branch is up to date with origin/main\\n');\n return;\n }\n\n const behindResult = spawnSync('git', ['rev-list', '--count', 'HEAD..origin/main'], { encoding: 'utf8' });\n const commitsBehind = (behindResult.stdout ?? '').trim();\n\n const recentResult = spawnSync('git', ['log', '--oneline', 'HEAD..origin/main'], { encoding: 'utf8' });\n const recentLines = (recentResult.stdout ?? '').split('\\n').filter((l: string) => l).slice(0, 5).join('\\n');\n\n process.stdout.write('\\n');\n process.stdout.write(SEP);\n process.stdout.write('❌ ERROR: Branch is NOT up to date with origin/main\\n');\n process.stdout.write(SEP);\n process.stdout.write('\\n');\n process.stdout.write(`Your branch is ${commitsBehind} commit(s) behind origin/main\\n`);\n process.stdout.write('\\n');\n process.stdout.write('Recent commits in origin/main not in your branch:\\n');\n process.stdout.write(recentLines + '\\n');\n process.stdout.write('\\n');\n process.stdout.write(SEP);\n process.stdout.write('⚠️ CRITICAL: You must update your branch first!\\n');\n process.stdout.write(SEP);\n process.stdout.write('\\n');\n process.stdout.write('1. Update your branch with latest main:\\n');\n process.stdout.write(' pnpm wp-git-update\\n');\n process.stdout.write('\\n');\n process.stdout.write('2. ⚠️ IMPORTANT: REVIEW THE CODE AFTER MERGE!\\n');\n process.stdout.write(' - Check for merge conflicts\\n');\n process.stdout.write(' - Review how your changes interact with new main code\\n');\n process.stdout.write(' - Test that everything still works\\n');\n process.stdout.write(' - This is where things often go wrong!\\n');\n process.stdout.write('\\n');\n process.stdout.write('3. After reviewing, run your command again\\n');\n process.stdout.write('\\n');\n process.stdout.write(SEP);\n process.stdout.write('Why this matters:\\n');\n process.stdout.write(SEP);\n process.stdout.write('\\n');\n process.stdout.write('- Your test plan should cover how your changes work with\\n');\n process.stdout.write(' the LATEST code from main, not outdated code\\n');\n process.stdout.write('- Merging main might introduce conflicts or integration\\n');\n process.stdout.write(' issues that need testing\\n');\n process.stdout.write('- Your changes might interact unexpectedly with new code\\n');\n process.stdout.write(' from main\\n');\n process.stdout.write('\\n');\n process.stdout.write(SEP);\n\n process.exit(1);\n}\n\nif (require.main === module) {\n main().catch((err) => {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(message + '\\n');\n process.exit(1);\n });\n}\n"]}
1
+ {"version":3,"file":"git-validateUpToDate.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/pr-gate/src/scripts/workflow/git-validateUpToDate.ts"],"names":[],"mappings":"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","sourcesContent":["import { execSync, spawnSync } from 'child_process';\n\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\nexport async function main(): Promise<void> {\n const branch = execSync('git branch --show-current', { encoding: 'utf8' }).trim();\n\n if (branch === 'main') {\n process.stdout.write('✅ On main branch - no validation needed\\n');\n return;\n }\n\n process.stdout.write('Validating branch is up to date with origin/main...\\n');\n process.stdout.write(`Current branch: ${branch}\\n`);\n process.stdout.write('\\n');\n\n process.stdout.write('Fetching latest from origin/main...\\n');\n spawnSync('git', ['fetch', 'origin', 'main', '--quiet'], { stdio: 'inherit' });\n\n const isUpToDate = spawnSync('git', ['merge-base', '--is-ancestor', 'origin/main', 'HEAD']).status === 0;\n\n if (isUpToDate) {\n process.stdout.write('✅ Branch is up to date with origin/main\\n');\n return;\n }\n\n const behindResult = spawnSync('git', ['rev-list', '--count', 'HEAD..origin/main'], { encoding: 'utf8' });\n const commitsBehind = (behindResult.stdout ?? '').trim();\n\n const recentResult = spawnSync('git', ['log', '--oneline', 'HEAD..origin/main'], { encoding: 'utf8' });\n const recentLines = (recentResult.stdout ?? '').split('\\n').filter((l: string) => l).slice(0, 5).join('\\n');\n\n process.stdout.write('\\n');\n process.stdout.write(SEP);\n process.stdout.write('❌ ERROR: Branch is NOT up to date with origin/main\\n');\n process.stdout.write(SEP);\n process.stdout.write('\\n');\n process.stdout.write(`Your branch is ${commitsBehind} commit(s) behind origin/main\\n`);\n process.stdout.write('\\n');\n process.stdout.write('Recent commits in origin/main not in your branch:\\n');\n process.stdout.write(recentLines + '\\n');\n process.stdout.write('\\n');\n process.stdout.write(SEP);\n process.stdout.write('⚠️ CRITICAL: You must update your branch first!\\n');\n process.stdout.write(SEP);\n process.stdout.write('\\n');\n process.stdout.write('1. Update your branch with latest main:\\n');\n process.stdout.write(' pnpm wp-update-start\\n');\n process.stdout.write('\\n');\n process.stdout.write('2. ⚠️ IMPORTANT: REVIEW THE CODE AFTER MERGE!\\n');\n process.stdout.write(' - Check for merge conflicts\\n');\n process.stdout.write(' - Review how your changes interact with new main code\\n');\n process.stdout.write(' - Test that everything still works\\n');\n process.stdout.write(' - This is where things often go wrong!\\n');\n process.stdout.write('\\n');\n process.stdout.write('3. After reviewing, run your command again\\n');\n process.stdout.write('\\n');\n process.stdout.write(SEP);\n process.stdout.write('Why this matters:\\n');\n process.stdout.write(SEP);\n process.stdout.write('\\n');\n process.stdout.write('- Your test plan should cover how your changes work with\\n');\n process.stdout.write(' the LATEST code from main, not outdated code\\n');\n process.stdout.write('- Merging main might introduce conflicts or integration\\n');\n process.stdout.write(' issues that need testing\\n');\n process.stdout.write('- Your changes might interact unexpectedly with new code\\n');\n process.stdout.write(' from main\\n');\n process.stdout.write('\\n');\n process.stdout.write(SEP);\n\n process.exit(1);\n}\n\nif (require.main === module) {\n main().catch((err) => {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(message + '\\n');\n process.exit(1);\n });\n}\n"]}
@@ -14,9 +14,9 @@ const merge_state_1 = require("./merge-state");
14
14
  // the branch context, it (optionally) validates + commits the AI's conflict resolution, then ALWAYS
15
15
  // finalizes the merge — promotes `<branch>Squash` to the next numbered generation (base → base2),
16
16
  // force-pushes to the stable base branch, stamps a clean main-sync status, clears the marker and
17
- // sweeps stale tmp. Both wp-git-update (clean path /
18
- // validated resume) and wp-finish-upsert-pr (conflict resolution) call THIS, so finalization happens
19
- // in exactly one place and the conflict path can no longer post a PR from the un-swapped squash branch.
17
+ // sweeps stale tmp. The shared runUpdateFromMain (clean path / validated resume), wp-update-end, and
18
+ // wp-finish-upsert-pr (conflict resolution) all call THIS, so finalization happens in exactly one
19
+ // place and the conflict path can no longer post a PR from the un-swapped squash branch.
20
20
  const SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n';
21
21
  // Validate the AI's resolution of the conflicted files — the part of the process the AI owns
22
22
  // (branch creation/finalization is the script's job, so it is not re-checked here). Exits the
@@ -1 +1 @@
1
- {"version":3,"file":"merge-end.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/pr-gate/src/scripts/workflow/merge-end.ts"],"names":[],"mappings":"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","sourcesContent":["import { execSync, spawnSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { MERGE_EXPLANATION_FILE, stampCleanMainSyncStatus } from '@webpieces/rules-config';\nimport { baseBranchName, nextBranchName } from './branch-naming';\nimport { main as cleanTmp } from './cleanTmp';\nimport { assertNoUntracked, runGitChecked } from './git-exec';\nimport { MergeContext } from './merge-start';\nimport { clearMergeMarker, perFileContextDir, scanConflictMarkers, scanMergeExplanations } from './merge-state';\n\n// merge-END: the second half of the 3-point squash-merge lifecycle, symmetric with merge-START. Given\n// the branch context, it (optionally) validates + commits the AI's conflict resolution, then ALWAYS\n// finalizes the merge — promotes `<branch>Squash` to the next numbered generation (base → base2),\n// force-pushes to the stable base branch, stamps a clean main-sync status, clears the marker and\n// sweeps stale tmp. Both wp-git-update (clean path /\n// validated resume) and wp-finish-upsert-pr (conflict resolution) call THIS, so finalization happens\n// in exactly one place and the conflict path can no longer post a PR from the un-swapped squash branch.\n\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\n// Validate the AI's resolution of the conflicted files — the part of the process the AI owns\n// (branch creation/finalization is the script's job, so it is not re-checked here). Exits the\n// process with a fix instruction on any failure; returns only when all three checks pass.\nfunction validateResolution(repoRoot: string, mergeDir: string, conflictedFiles: string[]): void {\n // 1. Scoped conflict-marker scan (only the conflicted files — O(conflicts), not O(repo)).\n const scan = scanConflictMarkers(repoRoot, conflictedFiles);\n if (!scan.clean) {\n process.stderr.write('❌ Unresolved conflict markers (<<<<<<< / ======= / >>>>>>>) remain in:\\n');\n for (const file of scan.filesWithMarkers) process.stderr.write(` - ${file}\\n`);\n process.stderr.write('\\nResolve them, then re-run: pnpm wp-finish-upsert-pr\\n');\n process.exit(1);\n }\n\n // 2. Ensure git itself has no remaining unmerged entries.\n const unmerged = execSync('git diff --name-only --diff-filter=U', { encoding: 'utf8' }).trim();\n if (unmerged !== '') {\n process.stderr.write('❌ Git still reports unmerged files:\\n' + unmerged + '\\n');\n process.stderr.write('\\nResolve and `git add` them, then re-run: pnpm wp-finish-upsert-pr\\n');\n process.exit(1);\n }\n process.stdout.write('✅ No conflict markers in resolved files.\\n');\n\n // 3. Explanation check — every conflicted file must have a non-empty merge-explanation.md in\n // its per-file context dir, proving the AI deliberately 3-point merged it (and recording how)\n // rather than blindly taking one side. A sidecar file works for any type, incl. JSON/deletes.\n const explanations = scanMergeExplanations(mergeDir, conflictedFiles);\n if (!explanations.clean) {\n process.stderr.write(`❌ Missing/empty merge explanation (${MERGE_EXPLANATION_FILE}) for:\\n`);\n for (const file of explanations.filesWithMarkers) {\n process.stderr.write(` - ${file}\\n → ${path.join(perFileContextDir(mergeDir, file), MERGE_EXPLANATION_FILE)}\\n`);\n }\n process.stderr.write(\n '\\nWrite a few sentences on how you resolved each (which side, what you combined, why),\\n' +\n 'then re-run: pnpm wp-finish-upsert-pr\\n',\n );\n process.exit(1);\n }\n process.stdout.write('✅ Merge explanations present for all resolved files.\\n');\n}\n\n// Promote the squash branch to the NEXT numbered generation, force-push to the stable base\n// branch (where the single PR lives), and stamp clean main-sync. The local branch numbers up\n// (base → base2 → base3) so the generation is visible; the remote/PR name stays `base`.\nfunction finalizeBranch(ctx: MergeContext): void {\n process.stdout.write('\\n' + SEP + '🗑️ Finalizing\\n' + SEP + '\\n');\n const base = baseBranchName(ctx.currentBranch);\n const next = nextBranchName(ctx.currentBranch);\n runGitChecked(['branch', '-D', ctx.currentBranch], 'Failed to delete old feature branch');\n\n const remoteExists = spawnSync('git', ['ls-remote', '--exit-code', '--heads', 'origin', base]).status === 0;\n if (remoteExists) {\n process.stdout.write(ctx.prNumber ? `Updating PR #${ctx.prNumber} (force-with-lease)...\\n` : 'Updating remote branch (force-with-lease)...\\n');\n runGitChecked(['push', '-u', '--force-with-lease', 'origin', `${ctx.squashBranch}:${base}`], 'Failed to push to origin');\n } else {\n process.stdout.write('No remote branch — local only.\\n');\n }\n runGitChecked(['checkout', ctx.squashBranch], 'Failed to checkout squash branch');\n runGitChecked(['branch', '-m', next], 'Failed to rename squash branch');\n\n // Branch now contains origin/main — stamp a clean main-sync status so the feature-branch-guard\n // unblocks edits immediately (no wait for the async refresher).\n stampCleanMainSyncStatus(execSync('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim());\n\n process.stdout.write(`\\n✅ Now on ${next} (remote/PR: ${base}), updated from main. Backup: ${ctx.backupBranch}\\n`);\n process.stdout.write(` Delete backup when safe: git branch -D ${ctx.backupBranch}\\n\\n`);\n}\n\n/**\n * Complete a 3-point squash merge. `conflictedFiles` non-null means a conflict was resolved by the AI\n * and must be validated + committed before finalizing; null means a clean merge that merge-START\n * already committed (finalize only). Either way the merge ends fully finalized on the feature branch.\n */\nexport async function mergeEnd(\n repoRoot: string, mergeDir: string, ctx: MergeContext, conflictedFiles: string[] | null,\n): Promise<void> {\n if (conflictedFiles !== null) {\n process.stdout.write('\\n' + SEP + '🔎 Validating Merge Resolution\\n' + SEP + '\\n');\n validateResolution(repoRoot, mergeDir, conflictedFiles);\n // Stage the AI's resolved conflicts, but NEVER sweep untracked files into the squash commit\n // (a blanket `git add -A` once swept a stale untracked dir in). Fail on untracked so the AI\n // commits or deletes them explicitly; then `git add -u` stages tracked resolutions only.\n assertNoUntracked(repoRoot);\n runGitChecked(['add', '-u'], 'Failed to stage resolved files');\n\n const nothingStaged = spawnSync('git', ['diff-index', '--quiet', '--cached', 'HEAD', '--']).status === 0;\n if (!nothingStaged) {\n runGitChecked(\n ['commit', '-m', `Squash merge of ${ctx.currentBranch} (conflicts resolved)`],\n 'Failed to commit resolved merge',\n );\n }\n fs.writeFileSync(path.join(mergeDir, 'conflicts-resolved'), '');\n process.stdout.write('\\n✅ Merge validated and committed.\\n');\n }\n\n finalizeBranch(ctx);\n clearMergeMarker(mergeDir);\n await cleanTmp();\n}\n"]}
1
+ {"version":3,"file":"merge-end.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/pr-gate/src/scripts/workflow/merge-end.ts"],"names":[],"mappings":"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","sourcesContent":["import { execSync, spawnSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { MERGE_EXPLANATION_FILE, stampCleanMainSyncStatus } from '@webpieces/rules-config';\nimport { baseBranchName, nextBranchName } from './branch-naming';\nimport { main as cleanTmp } from './cleanTmp';\nimport { assertNoUntracked, runGitChecked } from './git-exec';\nimport { MergeContext } from './merge-start';\nimport { clearMergeMarker, perFileContextDir, scanConflictMarkers, scanMergeExplanations } from './merge-state';\n\n// merge-END: the second half of the 3-point squash-merge lifecycle, symmetric with merge-START. Given\n// the branch context, it (optionally) validates + commits the AI's conflict resolution, then ALWAYS\n// finalizes the merge — promotes `<branch>Squash` to the next numbered generation (base → base2),\n// force-pushes to the stable base branch, stamps a clean main-sync status, clears the marker and\n// sweeps stale tmp. The shared runUpdateFromMain (clean path / validated resume), wp-update-end, and\n// wp-finish-upsert-pr (conflict resolution) all call THIS, so finalization happens in exactly one\n// place and the conflict path can no longer post a PR from the un-swapped squash branch.\n\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\n// Validate the AI's resolution of the conflicted files — the part of the process the AI owns\n// (branch creation/finalization is the script's job, so it is not re-checked here). Exits the\n// process with a fix instruction on any failure; returns only when all three checks pass.\nfunction validateResolution(repoRoot: string, mergeDir: string, conflictedFiles: string[]): void {\n // 1. Scoped conflict-marker scan (only the conflicted files — O(conflicts), not O(repo)).\n const scan = scanConflictMarkers(repoRoot, conflictedFiles);\n if (!scan.clean) {\n process.stderr.write('❌ Unresolved conflict markers (<<<<<<< / ======= / >>>>>>>) remain in:\\n');\n for (const file of scan.filesWithMarkers) process.stderr.write(` - ${file}\\n`);\n process.stderr.write('\\nResolve them, then re-run: pnpm wp-finish-upsert-pr\\n');\n process.exit(1);\n }\n\n // 2. Ensure git itself has no remaining unmerged entries.\n const unmerged = execSync('git diff --name-only --diff-filter=U', { encoding: 'utf8' }).trim();\n if (unmerged !== '') {\n process.stderr.write('❌ Git still reports unmerged files:\\n' + unmerged + '\\n');\n process.stderr.write('\\nResolve and `git add` them, then re-run: pnpm wp-finish-upsert-pr\\n');\n process.exit(1);\n }\n process.stdout.write('✅ No conflict markers in resolved files.\\n');\n\n // 3. Explanation check — every conflicted file must have a non-empty merge-explanation.md in\n // its per-file context dir, proving the AI deliberately 3-point merged it (and recording how)\n // rather than blindly taking one side. A sidecar file works for any type, incl. JSON/deletes.\n const explanations = scanMergeExplanations(mergeDir, conflictedFiles);\n if (!explanations.clean) {\n process.stderr.write(`❌ Missing/empty merge explanation (${MERGE_EXPLANATION_FILE}) for:\\n`);\n for (const file of explanations.filesWithMarkers) {\n process.stderr.write(` - ${file}\\n → ${path.join(perFileContextDir(mergeDir, file), MERGE_EXPLANATION_FILE)}\\n`);\n }\n process.stderr.write(\n '\\nWrite a few sentences on how you resolved each (which side, what you combined, why),\\n' +\n 'then re-run: pnpm wp-finish-upsert-pr\\n',\n );\n process.exit(1);\n }\n process.stdout.write('✅ Merge explanations present for all resolved files.\\n');\n}\n\n// Promote the squash branch to the NEXT numbered generation, force-push to the stable base\n// branch (where the single PR lives), and stamp clean main-sync. The local branch numbers up\n// (base → base2 → base3) so the generation is visible; the remote/PR name stays `base`.\nfunction finalizeBranch(ctx: MergeContext): void {\n process.stdout.write('\\n' + SEP + '🗑️ Finalizing\\n' + SEP + '\\n');\n const base = baseBranchName(ctx.currentBranch);\n const next = nextBranchName(ctx.currentBranch);\n runGitChecked(['branch', '-D', ctx.currentBranch], 'Failed to delete old feature branch');\n\n const remoteExists = spawnSync('git', ['ls-remote', '--exit-code', '--heads', 'origin', base]).status === 0;\n if (remoteExists) {\n process.stdout.write(ctx.prNumber ? `Updating PR #${ctx.prNumber} (force-with-lease)...\\n` : 'Updating remote branch (force-with-lease)...\\n');\n runGitChecked(['push', '-u', '--force-with-lease', 'origin', `${ctx.squashBranch}:${base}`], 'Failed to push to origin');\n } else {\n process.stdout.write('No remote branch — local only.\\n');\n }\n runGitChecked(['checkout', ctx.squashBranch], 'Failed to checkout squash branch');\n runGitChecked(['branch', '-m', next], 'Failed to rename squash branch');\n\n // Branch now contains origin/main — stamp a clean main-sync status so the feature-branch-guard\n // unblocks edits immediately (no wait for the async refresher).\n stampCleanMainSyncStatus(execSync('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim());\n\n process.stdout.write(`\\n✅ Now on ${next} (remote/PR: ${base}), updated from main. Backup: ${ctx.backupBranch}\\n`);\n process.stdout.write(` Delete backup when safe: git branch -D ${ctx.backupBranch}\\n\\n`);\n}\n\n/**\n * Complete a 3-point squash merge. `conflictedFiles` non-null means a conflict was resolved by the AI\n * and must be validated + committed before finalizing; null means a clean merge that merge-START\n * already committed (finalize only). Either way the merge ends fully finalized on the feature branch.\n */\nexport async function mergeEnd(\n repoRoot: string, mergeDir: string, ctx: MergeContext, conflictedFiles: string[] | null,\n): Promise<void> {\n if (conflictedFiles !== null) {\n process.stdout.write('\\n' + SEP + '🔎 Validating Merge Resolution\\n' + SEP + '\\n');\n validateResolution(repoRoot, mergeDir, conflictedFiles);\n // Stage the AI's resolved conflicts, but NEVER sweep untracked files into the squash commit\n // (a blanket `git add -A` once swept a stale untracked dir in). Fail on untracked so the AI\n // commits or deletes them explicitly; then `git add -u` stages tracked resolutions only.\n assertNoUntracked(repoRoot);\n runGitChecked(['add', '-u'], 'Failed to stage resolved files');\n\n const nothingStaged = spawnSync('git', ['diff-index', '--quiet', '--cached', 'HEAD', '--']).status === 0;\n if (!nothingStaged) {\n runGitChecked(\n ['commit', '-m', `Squash merge of ${ctx.currentBranch} (conflicts resolved)`],\n 'Failed to commit resolved merge',\n );\n }\n fs.writeFileSync(path.join(mergeDir, 'conflicts-resolved'), '');\n process.stdout.write('\\n✅ Merge validated and committed.\\n');\n }\n\n finalizeBranch(ctx);\n clearMergeMarker(mergeDir);\n await cleanTmp();\n}\n"]}
@@ -10,4 +10,4 @@ export declare class MergeStartResult {
10
10
  context: MergeContext | null;
11
11
  constructor(status: 'clean' | 'conflict', context: MergeContext | null);
12
12
  }
13
- export declare function mergeStart(repoRoot: string, mergeDir: string): Promise<MergeStartResult>;
13
+ export declare function mergeStart(repoRoot: string, mergeDir: string, finishCommand: string): Promise<MergeStartResult>;
@@ -14,9 +14,11 @@ const merge_state_1 = require("./merge-state");
14
14
  // merge-START: the first half of the 3-point squash-merge lifecycle. Brings origin/main into a fresh
15
15
  // `<branch>Squash`, and on conflict writes the 3-point context files + the unvalidated marker + the
16
16
  // process doc, then hands control back to the AI. On a clean merge it commits the squash and returns
17
- // the branch context so the caller (wp-git-update) can run merge-END to finalize. It NEVER finalizes
18
- // or posts a PR — that is merge-END's / wp-finish-upsert-pr's job. Shared so wp-git-update (and, via
19
- // it, wp-start-upsert-pr) all set up a merge through one code path.
17
+ // the branch context so the caller (runUpdateFromMain) can run merge-END to finalize. It NEVER
18
+ // finalizes or posts a PR — that is merge-END's / wp-finish-upsert-pr's job. Shared so
19
+ // runUpdateFromMain (and, via it, wp-update-start + wp-start-upsert-pr) all set up a merge through
20
+ // one code path. `finishCommand` names the command the AI runs to finish after resolving conflicts
21
+ // (standalone update → `wp-update-end`; PR flow → `wp-finish-upsert-pr`).
20
22
  const SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n';
21
23
  // The four branch names merge-END needs to finalize a merge (swap squash→feature, push, clean up).
22
24
  class MergeContext {
@@ -85,7 +87,7 @@ function saveConflictContext(conflictedFiles, mergeDir, forkPoint, featureHead,
85
87
  // is a template constant with {{...}} placeholders so this stays a small filler function.
86
88
  const MERGE_PROCESS_TEMPLATE = `# AI-Assisted Squash-Merge Conflict Resolution (generated)
87
89
 
88
- This file was generated by \`pnpm wp-git-update\` when the 3-point squash-merge hit conflicts.
90
+ This file was generated by \`pnpm wp-update-start\` when the 3-point squash-merge hit conflicts.
89
91
  It is the single source of truth for the merge process — follow it exactly.
90
92
 
91
93
  You are on branch \`{{SQUASH_BRANCH}}\` with conflict markers in the working tree.
@@ -94,9 +96,10 @@ You are on branch \`{{SQUASH_BRANCH}}\` with conflict markers in the working tre
94
96
  ## How the gate works
95
97
 
96
98
  - Resolve every conflicted file in the working tree.
97
- - Run **\`pnpm wp-finish-upsert-pr\`** — the validation + finish gate. It scans for leftover conflict
98
- markers, checks each conflicted file has a written merge explanation, runs the \`nx affected\`
99
- build, and only if all pass stages, commits, then renders the dashboard and creates/updates the PR.
99
+ - Run **\`pnpm {{FINISH_COMMAND}}\`** — the validation + finish gate. It scans for leftover conflict
100
+ markers, checks each conflicted file has a written merge explanation, validates, and commits the
101
+ merge. (In the PR flow this command is \`wp-finish-upsert-pr\`, which additionally runs the
102
+ \`nx affected\` build, renders the dashboard, and creates/updates the PR.)
100
103
  - **Do NOT run \`git add\` / \`git commit\` / \`git push\` / \`gh pr\` yourself.** They are blocked by
101
104
  the \`merge-in-progress-guard\` hook until the gate validates. The gate does the commit.
102
105
 
@@ -138,17 +141,18 @@ this file: which side you took where, what you combined from B-A.diff vs C-A.dif
138
141
  gate fails if any conflicted file's explanation is missing or empty. Do not paste A/B/C context
139
142
  blocks into the source code.
140
143
 
141
- ## STEP 3 — Run the gate (validates the merge AND finishes the PR)
144
+ ## STEP 3 — Run the gate (validates the merge AND finalizes it)
142
145
 
143
146
  \`\`\`
144
- pnpm wp-finish-upsert-pr
147
+ pnpm {{FINISH_COMMAND}}
145
148
  \`\`\`
146
149
 
147
150
  - Leftover conflict markers → fix those files and re-run.
148
151
  - Missing merge explanation → write it (see STEP 2) and re-run.
149
152
  - Build failure → fix the TypeScript/lint errors and re-run (the gate re-stages for you).
150
- - Missing review.json → write it in the printed format (your PR review), then re-run.
151
- - On success it commits, renders the dashboard, and creates/updates the PR.
153
+ - Missing review.json (PR flow only) → write it in the printed format (your PR review), then re-run.
154
+ - On success it commits and finalizes the merge (in the PR flow it also renders the dashboard and
155
+ creates/updates the PR).
152
156
 
153
157
  ## Conflicted files
154
158
 
@@ -164,20 +168,21 @@ git merge --abort 2>/dev/null; git checkout <feature> ; git branch -D {{SQUASH_B
164
168
 
165
169
  Then delete \`{{MERGE_DIR}}/\` for a clean slate.
166
170
  `;
167
- function mergeProcessDoc(mergeDir, squashBranch, conflictedFiles) {
171
+ function mergeProcessDoc(mergeDir, squashBranch, conflictedFiles, finishCommand) {
168
172
  const fileList = conflictedFiles.map((f) => `- \`${f}\``).join('\n');
169
173
  return MERGE_PROCESS_TEMPLATE
170
174
  .replace(/\{\{SQUASH_BRANCH\}\}/g, squashBranch)
171
175
  .replace(/\{\{MERGE_DIR\}\}/g, mergeDir)
172
176
  .replace(/\{\{EXPLANATION_FILE\}\}/g, rules_config_1.MERGE_EXPLANATION_FILE)
177
+ .replace(/\{\{FINISH_COMMAND\}\}/g, finishCommand)
173
178
  .replace(/\{\{FILE_LIST\}\}/g, fileList);
174
179
  }
175
180
  // Returns the absolute path of the written doc.
176
- function writeMergeProcessDoc(repoRoot, mergeDir, squashBranch, conflictedFiles) {
181
+ function writeMergeProcessDoc(repoRoot, mergeDir, squashBranch, conflictedFiles, finishCommand) {
177
182
  const docDir = path.join(repoRoot, rules_config_1.WEBPIECES_TMP_DIR, 'instruct-ai');
178
183
  fs.mkdirSync(docDir, { recursive: true });
179
184
  const docPath = path.join(docDir, 'webpieces.mergeprocess.md');
180
- fs.writeFileSync(docPath, mergeProcessDoc(mergeDir, squashBranch, conflictedFiles));
185
+ fs.writeFileSync(docPath, mergeProcessDoc(mergeDir, squashBranch, conflictedFiles, finishCommand));
181
186
  return docPath;
182
187
  }
183
188
  function printConflictHandback(docPath, mergeDir, squashBranch, conflictedFiles) {
@@ -191,18 +196,18 @@ function printConflictHandback(docPath, mergeDir, squashBranch, conflictedFiles)
191
196
  process.stdout.write('\n' + SEP);
192
197
  }
193
198
  // Write the conflict context files + the unvalidated marker + the process doc. Does NOT exit — the
194
- // caller decides (wp-git-update exits 2 to hand back to the AI).
195
- function handleConflictsHandback(repoRoot, mergeDir, currentBranch, squashBranch, backupBranch, prNumber, hashes) {
199
+ // caller decides (runUpdateFromMain exits 2 to hand back to the AI).
200
+ function handleConflictsHandback(repoRoot, mergeDir, currentBranch, squashBranch, backupBranch, prNumber, hashes, finishCommand) {
196
201
  const raw = (0, child_process_1.execSync)('git diff --name-only --diff-filter=U', { encoding: 'utf8' }).trim();
197
202
  const conflictedFiles = raw.split('\n').filter((f) => f.trim() !== '');
198
203
  fs.writeFileSync(path.join(mergeDir, 'updatemain-conflicted-files.txt'), raw + '\n');
199
204
  saveConflictContext(conflictedFiles, mergeDir, hashes.hashForkPoint, hashes.hashFeatureHead, hashes.hashMainHead);
200
205
  const marker = new merge_state_1.MergeMarker(currentBranch, squashBranch, backupBranch, prNumber, conflictedFiles, hashes.hashForkPoint, hashes.hashFeatureHead, hashes.hashMainHead, false);
201
206
  (0, merge_state_1.writeMergeMarker)(mergeDir, marker);
202
- const docPath = writeMergeProcessDoc(repoRoot, mergeDir, squashBranch, conflictedFiles);
207
+ const docPath = writeMergeProcessDoc(repoRoot, mergeDir, squashBranch, conflictedFiles, finishCommand);
203
208
  printConflictHandback(docPath, mergeDir, squashBranch, conflictedFiles);
204
209
  }
205
- async function mergeStart(repoRoot, mergeDir) {
210
+ async function mergeStart(repoRoot, mergeDir, finishCommand) {
206
211
  const currentBranch = (0, child_process_1.execSync)('git branch --show-current', { encoding: 'utf8' }).trim();
207
212
  if (currentBranch.endsWith('Squash')) {
208
213
  process.stderr.write(`❌ On a leftover ${currentBranch} branch with no merge marker. Clean up: git branch -D ${currentBranch}\n`);
@@ -225,7 +230,7 @@ async function mergeStart(repoRoot, mergeDir) {
225
230
  process.stdout.write('\n' + SEP + `🔀 Squash merging ${currentBranch}\n` + SEP + '\n');
226
231
  const merge = (0, child_process_1.spawnSync)('git', ['merge', '--squash', currentBranch], { stdio: 'inherit' });
227
232
  if (merge.status !== 0) {
228
- handleConflictsHandback(repoRoot, mergeDir, currentBranch, squashBranch, backupBranch, prNumber, hashes);
233
+ handleConflictsHandback(repoRoot, mergeDir, currentBranch, squashBranch, backupBranch, prNumber, hashes, finishCommand);
229
234
  return new MergeStartResult('conflict', null);
230
235
  }
231
236
  const nothingStaged = (0, child_process_1.spawnSync)('git', ['diff-index', '--quiet', '--cached', 'HEAD', '--']).status === 0;
@@ -1 +1 @@
1
- {"version":3,"file":"merge-start.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/pr-gate/src/scripts/workflow/merge-start.ts"],"names":[],"mappings":"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","sourcesContent":["import { execSync, spawnSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { WEBPIECES_TMP_DIR, MERGE_EXPLANATION_FILE } from '@webpieces/rules-config';\nimport { main as gatherInfo } from '../git-gatherInfo';\nimport { baseBranchName, preMergeBackupName } from './branch-naming';\nimport { runGitChecked } from './git-exec';\nimport { MergeMarker, perFileContextDir, writeMergeMarker } from './merge-state';\n\n// merge-START: the first half of the 3-point squash-merge lifecycle. Brings origin/main into a fresh\n// `<branch>Squash`, and on conflict writes the 3-point context files + the unvalidated marker + the\n// process doc, then hands control back to the AI. On a clean merge it commits the squash and returns\n// the branch context so the caller (wp-git-update) can run merge-END to finalize. It NEVER finalizes\n// or posts a PR — that is merge-END's / wp-finish-upsert-pr's job. Shared so wp-git-update (and, via\n// it, wp-start-upsert-pr) all set up a merge through one code path.\n\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\ninterface HashPoints {\n hashForkPoint: string;\n hashFeatureHead: string;\n hashMainHead: string;\n}\n\n// The four branch names merge-END needs to finalize a merge (swap squash→feature, push, clean up).\nexport class MergeContext {\n currentBranch: string;\n squashBranch: string;\n backupBranch: string;\n prNumber: string;\n\n constructor(currentBranch: string, squashBranch: string, backupBranch: string, prNumber: string) {\n this.currentBranch = currentBranch;\n this.squashBranch = squashBranch;\n this.backupBranch = backupBranch;\n this.prNumber = prNumber;\n }\n}\n\n// Outcome of merge-start: 'clean' carries the context for merge-END to finalize; 'conflict' means the\n// marker + context files were written and the caller should hand back to the AI (exit 2).\nexport class MergeStartResult {\n status: 'clean' | 'conflict';\n context: MergeContext | null;\n\n constructor(status: 'clean' | 'conflict', context: MergeContext | null) {\n this.status = status;\n this.context = context;\n }\n}\n\n// Detect the PR by its STABLE base branch — the PR always lives on `base`, never on the numbered\n// generation (base2/base3/…) you may currently be on, so pass baseBranchName(currentBranch).\nfunction detectPr(baseBranch: string): string {\n const result = spawnSync(\n 'gh', ['pr', 'list', '--head', baseBranch, '--json', 'number', '--jq', '.[0].number'],\n { encoding: 'utf8' },\n );\n return result.status === 0 ? (result.stdout ?? '').trim() : '';\n}\n\n// Snapshot the pre-merge state as `<currentBranch>PreMerge`. One overwritable slot per generation:\n// if a stale PreMerge from a crashed rerun of THIS branch exists, delete it first so we never\n// accumulate backups (the old scheme minted a fresh Backup1/Backup2/… on every run).\nfunction createBackup(currentBranch: string): string {\n process.stdout.write('\\n' + SEP + '💾 Creating Pre-Merge Backup\\n' + SEP + '\\n');\n const backupBranch = preMergeBackupName(currentBranch);\n if (spawnSync('git', ['show-ref', '--verify', '--quiet', `refs/heads/${backupBranch}`]).status === 0) {\n runGitChecked(['branch', '-D', backupBranch], 'Failed to delete stale pre-merge backup');\n }\n runGitChecked(['checkout', '-b', backupBranch], 'Failed to create backup branch');\n runGitChecked(['checkout', currentBranch], 'Failed to return to feature branch');\n process.stdout.write(`✅ Backup created: ${backupBranch}\\n\\n`);\n return backupBranch;\n}\n\nfunction saveConflictContext(\n conflictedFiles: string[], mergeDir: string, forkPoint: string, featureHead: string, mainHead: string,\n): void {\n for (const file of conflictedFiles) {\n const fileDir = perFileContextDir(mergeDir, file);\n fs.mkdirSync(fileDir, { recursive: true });\n\n const fork = spawnSync('git', ['show', `${forkPoint}:${file}`], { encoding: 'utf8' });\n fs.writeFileSync(path.join(fileDir, 'A-forkpoint.txt'), fork.status === 0 ? (fork.stdout ?? '') : '(file did not exist)\\n');\n const feature = spawnSync('git', ['show', `${featureHead}:${file}`], { encoding: 'utf8' });\n fs.writeFileSync(path.join(fileDir, 'B-feature.txt'), feature.status === 0 ? (feature.stdout ?? '') : '(file did not exist)\\n');\n const main = spawnSync('git', ['show', `${mainHead}:${file}`], { encoding: 'utf8' });\n fs.writeFileSync(path.join(fileDir, 'C-main.txt'), main.status === 0 ? (main.stdout ?? '') : '(file did not exist)\\n');\n\n const ba = spawnSync('git', ['diff', forkPoint, featureHead, '--', file], { encoding: 'utf8' });\n fs.writeFileSync(path.join(fileDir, 'B-A.diff'), ba.stdout ?? '');\n const ca = spawnSync('git', ['diff', forkPoint, mainHead, '--', file], { encoding: 'utf8' });\n fs.writeFileSync(path.join(fileDir, 'C-A.diff'), ca.stdout ?? '');\n }\n}\n\n// Single source of truth for the merge process. The script WRITES it at conflict time (rather\n// than the AI relying on a separate hand-maintained doc), parameterized with the live MERGE_DIR\n// and conflicted-file list, so the instructions can never drift from the actual layout. The body\n// is a template constant with {{...}} placeholders so this stays a small filler function.\nconst MERGE_PROCESS_TEMPLATE = `# AI-Assisted Squash-Merge Conflict Resolution (generated)\n\nThis file was generated by \\`pnpm wp-git-update\\` when the 3-point squash-merge hit conflicts.\nIt is the single source of truth for the merge process — follow it exactly.\n\nYou are on branch \\`{{SQUASH_BRANCH}}\\` with conflict markers in the working tree.\n\\`MERGE_DIR = {{MERGE_DIR}}\\`\n\n## How the gate works\n\n- Resolve every conflicted file in the working tree.\n- Run **\\`pnpm wp-finish-upsert-pr\\`** — the validation + finish gate. It scans for leftover conflict\n markers, checks each conflicted file has a written merge explanation, runs the \\`nx affected\\`\n build, and — only if all pass — stages, commits, then renders the dashboard and creates/updates the PR.\n- **Do NOT run \\`git add\\` / \\`git commit\\` / \\`git push\\` / \\`gh pr\\` yourself.** They are blocked by\n the \\`merge-in-progress-guard\\` hook until the gate validates. The gate does the commit.\n\n## STEP 1 — Load the merge context\n\nPer conflicted file, \\`MERGE_DIR/updatemain-<safe_path>/\\` holds (\\`<safe_path>\\` = path with \\`/\\`→\\`__\\`):\n\n\\`\\`\\`\nA-forkpoint.txt # file at fork point (base)\nB-feature.txt # file on your feature branch\nC-main.txt # file on main\nB-A.diff # what your feature changed (B−A)\nC-A.diff # what main changed (C−A)\n\\`\\`\\`\n\n\\`updatemain-hashes.json\\` holds A/B/C commit hashes. To see why main changed:\n\\`git log <A>..<C> --oneline\\`.\n\n## STEP 2 — Resolve each conflicted file\n\nFor each file: read the working-tree file (the markers) and its \\`B-A.diff\\` / \\`C-A.diff\\` (intent),\nthen Edit to the resolved version, removing ALL conflict markers.\n\nStrategies: goals align & non-overlapping → merge both · one side removes what the other modifies\n→ prefer the removal · same lines, simple (imports/format) → merge both · same lines, complex or\nconflicting goals → ask the user · feature re-implements what main already squashed → prefer\nmain's, then re-apply only the genuinely new feature work.\n\n**Then write a merge explanation** for each conflicted file — NOT a comment in the source (that\nbreaks for JSON and deleted files). Write it next to that file's diffs, at:\n\n\\`\\`\\`\nMERGE_DIR/updatemain-<safe_path>/{{EXPLANATION_FILE}}\n\\`\\`\\`\n\n(\\`<safe_path>\\` = the conflict file path with \\`/\\` → \\`__\\`, the same dir that holds its\n\\`A-forkpoint.txt\\` / \\`B-A.diff\\` / \\`C-A.diff\\`.) In it, explain in a few sentences how you resolved\nthis file: which side you took where, what you combined from B-A.diff vs C-A.diff, and why. The\ngate fails if any conflicted file's explanation is missing or empty. Do not paste A/B/C context\nblocks into the source code.\n\n## STEP 3 — Run the gate (validates the merge AND finishes the PR)\n\n\\`\\`\\`\npnpm wp-finish-upsert-pr\n\\`\\`\\`\n\n- Leftover conflict markers → fix those files and re-run.\n- Missing merge explanation → write it (see STEP 2) and re-run.\n- Build failure → fix the TypeScript/lint errors and re-run (the gate re-stages for you).\n- Missing review.json → write it in the printed format (your PR review), then re-run.\n- On success it commits, renders the dashboard, and creates/updates the PR.\n\n## Conflicted files\n\n{{FILE_LIST}}\n\n## If you need to bail out\n\nA backup branch was created (e.g. \\`<feature>PreMerge\\`). To abandon:\n\n\\`\\`\\`\ngit merge --abort 2>/dev/null; git checkout <feature> ; git branch -D {{SQUASH_BRANCH}}\n\\`\\`\\`\n\nThen delete \\`{{MERGE_DIR}}/\\` for a clean slate.\n`;\n\nfunction mergeProcessDoc(mergeDir: string, squashBranch: string, conflictedFiles: string[]): string {\n const fileList = conflictedFiles.map((f: string): string => `- \\`${f}\\``).join('\\n');\n return MERGE_PROCESS_TEMPLATE\n .replace(/\\{\\{SQUASH_BRANCH\\}\\}/g, squashBranch)\n .replace(/\\{\\{MERGE_DIR\\}\\}/g, mergeDir)\n .replace(/\\{\\{EXPLANATION_FILE\\}\\}/g, MERGE_EXPLANATION_FILE)\n .replace(/\\{\\{FILE_LIST\\}\\}/g, fileList);\n}\n\n// Returns the absolute path of the written doc.\nfunction writeMergeProcessDoc(repoRoot: string, mergeDir: string, squashBranch: string, conflictedFiles: string[]): string {\n const docDir = path.join(repoRoot, WEBPIECES_TMP_DIR, 'instruct-ai');\n fs.mkdirSync(docDir, { recursive: true });\n const docPath = path.join(docDir, 'webpieces.mergeprocess.md');\n fs.writeFileSync(docPath, mergeProcessDoc(mergeDir, squashBranch, conflictedFiles));\n return docPath;\n}\n\nfunction printConflictHandback(docPath: string, mergeDir: string, squashBranch: string, conflictedFiles: string[]): void {\n process.stdout.write('\\n' + SEP + `⚠️ Conflicts in ${conflictedFiles.length} file(s) — handing control back to you\\n` + SEP + '\\n');\n process.stdout.write(`You are on branch ${squashBranch} with conflicts in the working tree.\\n\\n`);\n process.stdout.write(`FOLLOW THE MERGE PROCESS: ${docPath}\\n`);\n process.stdout.write(`3-point context per file in: ${mergeDir}/updatemain-<file>/\\n\\n`);\n process.stdout.write('Conflicted files:\\n');\n for (const file of conflictedFiles) process.stdout.write(` - ${file}\\n`);\n process.stdout.write('\\n' + SEP);\n}\n\n// Write the conflict context files + the unvalidated marker + the process doc. Does NOT exit — the\n// caller decides (wp-git-update exits 2 to hand back to the AI).\nfunction handleConflictsHandback(\n repoRoot: string, mergeDir: string, currentBranch: string, squashBranch: string,\n backupBranch: string, prNumber: string, hashes: HashPoints,\n): void {\n const raw = execSync('git diff --name-only --diff-filter=U', { encoding: 'utf8' }).trim();\n const conflictedFiles = raw.split('\\n').filter((f: string): boolean => f.trim() !== '');\n fs.writeFileSync(path.join(mergeDir, 'updatemain-conflicted-files.txt'), raw + '\\n');\n saveConflictContext(conflictedFiles, mergeDir, hashes.hashForkPoint, hashes.hashFeatureHead, hashes.hashMainHead);\n\n const marker = new MergeMarker(\n currentBranch, squashBranch, backupBranch, prNumber, conflictedFiles,\n hashes.hashForkPoint, hashes.hashFeatureHead, hashes.hashMainHead, false,\n );\n writeMergeMarker(mergeDir, marker);\n const docPath = writeMergeProcessDoc(repoRoot, mergeDir, squashBranch, conflictedFiles);\n printConflictHandback(docPath, mergeDir, squashBranch, conflictedFiles);\n}\n\nexport async function mergeStart(repoRoot: string, mergeDir: string): Promise<MergeStartResult> {\n const currentBranch = execSync('git branch --show-current', { encoding: 'utf8' }).trim();\n if (currentBranch.endsWith('Squash')) {\n process.stderr.write(`❌ On a leftover ${currentBranch} branch with no merge marker. Clean up: git branch -D ${currentBranch}\\n`);\n process.exit(1);\n }\n\n process.stdout.write('\\n' + SEP + '🔄 Squash-Merge Update from Main\\n' + SEP + '\\n');\n await gatherInfo();\n const hashes = JSON.parse(fs.readFileSync(path.join(mergeDir, 'updatemain-hashes.json'), 'utf8')) as HashPoints;\n\n const prNumber = detectPr(baseBranchName(currentBranch));\n process.stdout.write(prNumber ? `Existing PR #${prNumber} will be updated.\\n` : 'No existing PR (one can be created later).\\n');\n\n const backupBranch = createBackup(currentBranch);\n const squashBranch = `${currentBranch}Squash`;\n if (spawnSync('git', ['show-ref', '--verify', '--quiet', `refs/heads/${squashBranch}`]).status === 0) {\n process.stderr.write(`❌ Stale ${squashBranch} from a previous run. Delete it: git branch -D ${squashBranch}\\n`);\n process.exit(1);\n }\n\n runGitChecked(['checkout', 'main'], 'Failed to checkout main');\n runGitChecked(['pull', 'origin', 'main'], 'Failed to pull origin/main');\n runGitChecked(['checkout', '-b', squashBranch], 'Failed to create squash branch');\n\n process.stdout.write('\\n' + SEP + `🔀 Squash merging ${currentBranch}\\n` + SEP + '\\n');\n const merge = spawnSync('git', ['merge', '--squash', currentBranch], { stdio: 'inherit' });\n if (merge.status !== 0) {\n handleConflictsHandback(repoRoot, mergeDir, currentBranch, squashBranch, backupBranch, prNumber, hashes);\n return new MergeStartResult('conflict', null);\n }\n\n const nothingStaged = spawnSync('git', ['diff-index', '--quiet', '--cached', 'HEAD', '--']).status === 0;\n if (nothingStaged) {\n process.stdout.write('ℹ️ Already up-to-date with main (nothing to merge).\\n');\n } else {\n runGitChecked(['commit', '-m', `Squash merge of ${currentBranch}`], 'Failed to commit squash merge');\n }\n return new MergeStartResult('clean', new MergeContext(currentBranch, squashBranch, backupBranch, prNumber));\n}\n"]}
1
+ {"version":3,"file":"merge-start.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/pr-gate/src/scripts/workflow/merge-start.ts"],"names":[],"mappings":"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","sourcesContent":["import { execSync, spawnSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { WEBPIECES_TMP_DIR, MERGE_EXPLANATION_FILE } from '@webpieces/rules-config';\nimport { main as gatherInfo } from '../git-gatherInfo';\nimport { baseBranchName, preMergeBackupName } from './branch-naming';\nimport { runGitChecked } from './git-exec';\nimport { MergeMarker, perFileContextDir, writeMergeMarker } from './merge-state';\n\n// merge-START: the first half of the 3-point squash-merge lifecycle. Brings origin/main into a fresh\n// `<branch>Squash`, and on conflict writes the 3-point context files + the unvalidated marker + the\n// process doc, then hands control back to the AI. On a clean merge it commits the squash and returns\n// the branch context so the caller (runUpdateFromMain) can run merge-END to finalize. It NEVER\n// finalizes or posts a PR — that is merge-END's / wp-finish-upsert-pr's job. Shared so\n// runUpdateFromMain (and, via it, wp-update-start + wp-start-upsert-pr) all set up a merge through\n// one code path. `finishCommand` names the command the AI runs to finish after resolving conflicts\n// (standalone update → `wp-update-end`; PR flow → `wp-finish-upsert-pr`).\n\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\ninterface HashPoints {\n hashForkPoint: string;\n hashFeatureHead: string;\n hashMainHead: string;\n}\n\n// The four branch names merge-END needs to finalize a merge (swap squash→feature, push, clean up).\nexport class MergeContext {\n currentBranch: string;\n squashBranch: string;\n backupBranch: string;\n prNumber: string;\n\n constructor(currentBranch: string, squashBranch: string, backupBranch: string, prNumber: string) {\n this.currentBranch = currentBranch;\n this.squashBranch = squashBranch;\n this.backupBranch = backupBranch;\n this.prNumber = prNumber;\n }\n}\n\n// Outcome of merge-start: 'clean' carries the context for merge-END to finalize; 'conflict' means the\n// marker + context files were written and the caller should hand back to the AI (exit 2).\nexport class MergeStartResult {\n status: 'clean' | 'conflict';\n context: MergeContext | null;\n\n constructor(status: 'clean' | 'conflict', context: MergeContext | null) {\n this.status = status;\n this.context = context;\n }\n}\n\n// Detect the PR by its STABLE base branch — the PR always lives on `base`, never on the numbered\n// generation (base2/base3/…) you may currently be on, so pass baseBranchName(currentBranch).\nfunction detectPr(baseBranch: string): string {\n const result = spawnSync(\n 'gh', ['pr', 'list', '--head', baseBranch, '--json', 'number', '--jq', '.[0].number'],\n { encoding: 'utf8' },\n );\n return result.status === 0 ? (result.stdout ?? '').trim() : '';\n}\n\n// Snapshot the pre-merge state as `<currentBranch>PreMerge`. One overwritable slot per generation:\n// if a stale PreMerge from a crashed rerun of THIS branch exists, delete it first so we never\n// accumulate backups (the old scheme minted a fresh Backup1/Backup2/… on every run).\nfunction createBackup(currentBranch: string): string {\n process.stdout.write('\\n' + SEP + '💾 Creating Pre-Merge Backup\\n' + SEP + '\\n');\n const backupBranch = preMergeBackupName(currentBranch);\n if (spawnSync('git', ['show-ref', '--verify', '--quiet', `refs/heads/${backupBranch}`]).status === 0) {\n runGitChecked(['branch', '-D', backupBranch], 'Failed to delete stale pre-merge backup');\n }\n runGitChecked(['checkout', '-b', backupBranch], 'Failed to create backup branch');\n runGitChecked(['checkout', currentBranch], 'Failed to return to feature branch');\n process.stdout.write(`✅ Backup created: ${backupBranch}\\n\\n`);\n return backupBranch;\n}\n\nfunction saveConflictContext(\n conflictedFiles: string[], mergeDir: string, forkPoint: string, featureHead: string, mainHead: string,\n): void {\n for (const file of conflictedFiles) {\n const fileDir = perFileContextDir(mergeDir, file);\n fs.mkdirSync(fileDir, { recursive: true });\n\n const fork = spawnSync('git', ['show', `${forkPoint}:${file}`], { encoding: 'utf8' });\n fs.writeFileSync(path.join(fileDir, 'A-forkpoint.txt'), fork.status === 0 ? (fork.stdout ?? '') : '(file did not exist)\\n');\n const feature = spawnSync('git', ['show', `${featureHead}:${file}`], { encoding: 'utf8' });\n fs.writeFileSync(path.join(fileDir, 'B-feature.txt'), feature.status === 0 ? (feature.stdout ?? '') : '(file did not exist)\\n');\n const main = spawnSync('git', ['show', `${mainHead}:${file}`], { encoding: 'utf8' });\n fs.writeFileSync(path.join(fileDir, 'C-main.txt'), main.status === 0 ? (main.stdout ?? '') : '(file did not exist)\\n');\n\n const ba = spawnSync('git', ['diff', forkPoint, featureHead, '--', file], { encoding: 'utf8' });\n fs.writeFileSync(path.join(fileDir, 'B-A.diff'), ba.stdout ?? '');\n const ca = spawnSync('git', ['diff', forkPoint, mainHead, '--', file], { encoding: 'utf8' });\n fs.writeFileSync(path.join(fileDir, 'C-A.diff'), ca.stdout ?? '');\n }\n}\n\n// Single source of truth for the merge process. The script WRITES it at conflict time (rather\n// than the AI relying on a separate hand-maintained doc), parameterized with the live MERGE_DIR\n// and conflicted-file list, so the instructions can never drift from the actual layout. The body\n// is a template constant with {{...}} placeholders so this stays a small filler function.\nconst MERGE_PROCESS_TEMPLATE = `# AI-Assisted Squash-Merge Conflict Resolution (generated)\n\nThis file was generated by \\`pnpm wp-update-start\\` when the 3-point squash-merge hit conflicts.\nIt is the single source of truth for the merge process — follow it exactly.\n\nYou are on branch \\`{{SQUASH_BRANCH}}\\` with conflict markers in the working tree.\n\\`MERGE_DIR = {{MERGE_DIR}}\\`\n\n## How the gate works\n\n- Resolve every conflicted file in the working tree.\n- Run **\\`pnpm {{FINISH_COMMAND}}\\`** — the validation + finish gate. It scans for leftover conflict\n markers, checks each conflicted file has a written merge explanation, validates, and commits the\n merge. (In the PR flow this command is \\`wp-finish-upsert-pr\\`, which additionally runs the\n \\`nx affected\\` build, renders the dashboard, and creates/updates the PR.)\n- **Do NOT run \\`git add\\` / \\`git commit\\` / \\`git push\\` / \\`gh pr\\` yourself.** They are blocked by\n the \\`merge-in-progress-guard\\` hook until the gate validates. The gate does the commit.\n\n## STEP 1 — Load the merge context\n\nPer conflicted file, \\`MERGE_DIR/updatemain-<safe_path>/\\` holds (\\`<safe_path>\\` = path with \\`/\\`→\\`__\\`):\n\n\\`\\`\\`\nA-forkpoint.txt # file at fork point (base)\nB-feature.txt # file on your feature branch\nC-main.txt # file on main\nB-A.diff # what your feature changed (B−A)\nC-A.diff # what main changed (C−A)\n\\`\\`\\`\n\n\\`updatemain-hashes.json\\` holds A/B/C commit hashes. To see why main changed:\n\\`git log <A>..<C> --oneline\\`.\n\n## STEP 2 — Resolve each conflicted file\n\nFor each file: read the working-tree file (the markers) and its \\`B-A.diff\\` / \\`C-A.diff\\` (intent),\nthen Edit to the resolved version, removing ALL conflict markers.\n\nStrategies: goals align & non-overlapping → merge both · one side removes what the other modifies\n→ prefer the removal · same lines, simple (imports/format) → merge both · same lines, complex or\nconflicting goals → ask the user · feature re-implements what main already squashed → prefer\nmain's, then re-apply only the genuinely new feature work.\n\n**Then write a merge explanation** for each conflicted file — NOT a comment in the source (that\nbreaks for JSON and deleted files). Write it next to that file's diffs, at:\n\n\\`\\`\\`\nMERGE_DIR/updatemain-<safe_path>/{{EXPLANATION_FILE}}\n\\`\\`\\`\n\n(\\`<safe_path>\\` = the conflict file path with \\`/\\` → \\`__\\`, the same dir that holds its\n\\`A-forkpoint.txt\\` / \\`B-A.diff\\` / \\`C-A.diff\\`.) In it, explain in a few sentences how you resolved\nthis file: which side you took where, what you combined from B-A.diff vs C-A.diff, and why. The\ngate fails if any conflicted file's explanation is missing or empty. Do not paste A/B/C context\nblocks into the source code.\n\n## STEP 3 — Run the gate (validates the merge AND finalizes it)\n\n\\`\\`\\`\npnpm {{FINISH_COMMAND}}\n\\`\\`\\`\n\n- Leftover conflict markers → fix those files and re-run.\n- Missing merge explanation → write it (see STEP 2) and re-run.\n- Build failure → fix the TypeScript/lint errors and re-run (the gate re-stages for you).\n- Missing review.json (PR flow only) → write it in the printed format (your PR review), then re-run.\n- On success it commits and finalizes the merge (in the PR flow it also renders the dashboard and\n creates/updates the PR).\n\n## Conflicted files\n\n{{FILE_LIST}}\n\n## If you need to bail out\n\nA backup branch was created (e.g. \\`<feature>PreMerge\\`). To abandon:\n\n\\`\\`\\`\ngit merge --abort 2>/dev/null; git checkout <feature> ; git branch -D {{SQUASH_BRANCH}}\n\\`\\`\\`\n\nThen delete \\`{{MERGE_DIR}}/\\` for a clean slate.\n`;\n\nfunction mergeProcessDoc(mergeDir: string, squashBranch: string, conflictedFiles: string[], finishCommand: string): string {\n const fileList = conflictedFiles.map((f: string): string => `- \\`${f}\\``).join('\\n');\n return MERGE_PROCESS_TEMPLATE\n .replace(/\\{\\{SQUASH_BRANCH\\}\\}/g, squashBranch)\n .replace(/\\{\\{MERGE_DIR\\}\\}/g, mergeDir)\n .replace(/\\{\\{EXPLANATION_FILE\\}\\}/g, MERGE_EXPLANATION_FILE)\n .replace(/\\{\\{FINISH_COMMAND\\}\\}/g, finishCommand)\n .replace(/\\{\\{FILE_LIST\\}\\}/g, fileList);\n}\n\n// Returns the absolute path of the written doc.\nfunction writeMergeProcessDoc(repoRoot: string, mergeDir: string, squashBranch: string, conflictedFiles: string[], finishCommand: string): string {\n const docDir = path.join(repoRoot, WEBPIECES_TMP_DIR, 'instruct-ai');\n fs.mkdirSync(docDir, { recursive: true });\n const docPath = path.join(docDir, 'webpieces.mergeprocess.md');\n fs.writeFileSync(docPath, mergeProcessDoc(mergeDir, squashBranch, conflictedFiles, finishCommand));\n return docPath;\n}\n\nfunction printConflictHandback(docPath: string, mergeDir: string, squashBranch: string, conflictedFiles: string[]): void {\n process.stdout.write('\\n' + SEP + `⚠️ Conflicts in ${conflictedFiles.length} file(s) — handing control back to you\\n` + SEP + '\\n');\n process.stdout.write(`You are on branch ${squashBranch} with conflicts in the working tree.\\n\\n`);\n process.stdout.write(`FOLLOW THE MERGE PROCESS: ${docPath}\\n`);\n process.stdout.write(`3-point context per file in: ${mergeDir}/updatemain-<file>/\\n\\n`);\n process.stdout.write('Conflicted files:\\n');\n for (const file of conflictedFiles) process.stdout.write(` - ${file}\\n`);\n process.stdout.write('\\n' + SEP);\n}\n\n// Write the conflict context files + the unvalidated marker + the process doc. Does NOT exit — the\n// caller decides (runUpdateFromMain exits 2 to hand back to the AI).\nfunction handleConflictsHandback(\n repoRoot: string, mergeDir: string, currentBranch: string, squashBranch: string,\n backupBranch: string, prNumber: string, hashes: HashPoints, finishCommand: string,\n): void {\n const raw = execSync('git diff --name-only --diff-filter=U', { encoding: 'utf8' }).trim();\n const conflictedFiles = raw.split('\\n').filter((f: string): boolean => f.trim() !== '');\n fs.writeFileSync(path.join(mergeDir, 'updatemain-conflicted-files.txt'), raw + '\\n');\n saveConflictContext(conflictedFiles, mergeDir, hashes.hashForkPoint, hashes.hashFeatureHead, hashes.hashMainHead);\n\n const marker = new MergeMarker(\n currentBranch, squashBranch, backupBranch, prNumber, conflictedFiles,\n hashes.hashForkPoint, hashes.hashFeatureHead, hashes.hashMainHead, false,\n );\n writeMergeMarker(mergeDir, marker);\n const docPath = writeMergeProcessDoc(repoRoot, mergeDir, squashBranch, conflictedFiles, finishCommand);\n printConflictHandback(docPath, mergeDir, squashBranch, conflictedFiles);\n}\n\nexport async function mergeStart(repoRoot: string, mergeDir: string, finishCommand: string): Promise<MergeStartResult> {\n const currentBranch = execSync('git branch --show-current', { encoding: 'utf8' }).trim();\n if (currentBranch.endsWith('Squash')) {\n process.stderr.write(`❌ On a leftover ${currentBranch} branch with no merge marker. Clean up: git branch -D ${currentBranch}\\n`);\n process.exit(1);\n }\n\n process.stdout.write('\\n' + SEP + '🔄 Squash-Merge Update from Main\\n' + SEP + '\\n');\n await gatherInfo();\n const hashes = JSON.parse(fs.readFileSync(path.join(mergeDir, 'updatemain-hashes.json'), 'utf8')) as HashPoints;\n\n const prNumber = detectPr(baseBranchName(currentBranch));\n process.stdout.write(prNumber ? `Existing PR #${prNumber} will be updated.\\n` : 'No existing PR (one can be created later).\\n');\n\n const backupBranch = createBackup(currentBranch);\n const squashBranch = `${currentBranch}Squash`;\n if (spawnSync('git', ['show-ref', '--verify', '--quiet', `refs/heads/${squashBranch}`]).status === 0) {\n process.stderr.write(`❌ Stale ${squashBranch} from a previous run. Delete it: git branch -D ${squashBranch}\\n`);\n process.exit(1);\n }\n\n runGitChecked(['checkout', 'main'], 'Failed to checkout main');\n runGitChecked(['pull', 'origin', 'main'], 'Failed to pull origin/main');\n runGitChecked(['checkout', '-b', squashBranch], 'Failed to create squash branch');\n\n process.stdout.write('\\n' + SEP + `🔀 Squash merging ${currentBranch}\\n` + SEP + '\\n');\n const merge = spawnSync('git', ['merge', '--squash', currentBranch], { stdio: 'inherit' });\n if (merge.status !== 0) {\n handleConflictsHandback(repoRoot, mergeDir, currentBranch, squashBranch, backupBranch, prNumber, hashes, finishCommand);\n return new MergeStartResult('conflict', null);\n }\n\n const nothingStaged = spawnSync('git', ['diff-index', '--quiet', '--cached', 'HEAD', '--']).status === 0;\n if (nothingStaged) {\n process.stdout.write('ℹ️ Already up-to-date with main (nothing to merge).\\n');\n } else {\n runGitChecked(['commit', '-m', `Squash merge of ${currentBranch}`], 'Failed to commit squash merge');\n }\n return new MergeStartResult('clean', new MergeContext(currentBranch, squashBranch, backupBranch, prNumber));\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export type UpdateOutcome = 'finalized' | 'conflict' | 'unvalidatedResume';
2
+ export declare function runUpdateFromMain(repoRoot: string, finishCommand: string): Promise<UpdateOutcome>;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runUpdateFromMain = runUpdateFromMain;
4
+ const tslib_1 = require("tslib");
5
+ const fs = tslib_1.__importStar(require("fs"));
6
+ const git_readAiBranchName_1 = require("./git-readAiBranchName");
7
+ const merge_state_1 = require("./merge-state");
8
+ const merge_start_1 = require("./merge-start");
9
+ const merge_end_1 = require("./merge-end");
10
+ async function runUpdateFromMain(repoRoot, finishCommand) {
11
+ const mergeDir = (0, merge_state_1.mergeDirFor)(repoRoot, (0, git_readAiBranchName_1.getFeatureName)());
12
+ fs.mkdirSync(mergeDir, { recursive: true });
13
+ // Resume path: a marker means a merge is already in progress.
14
+ const existing = (0, merge_state_1.readMergeMarker)(mergeDir);
15
+ if (existing) {
16
+ if (!existing.validated)
17
+ return 'unvalidatedResume';
18
+ // Already validated → just finalize the branch swap.
19
+ await (0, merge_end_1.mergeEnd)(repoRoot, mergeDir, new merge_start_1.MergeContext(existing.currentBranch, existing.squashBranch, existing.backupBranch, existing.prNumber), null);
20
+ return 'finalized';
21
+ }
22
+ // Fresh update: start, then finalize on clean / hand back on conflict.
23
+ const result = await (0, merge_start_1.mergeStart)(repoRoot, mergeDir, finishCommand);
24
+ if (result.status === 'conflict' || result.context === null) {
25
+ return 'conflict';
26
+ }
27
+ await (0, merge_end_1.mergeEnd)(repoRoot, mergeDir, result.context, null);
28
+ return 'finalized';
29
+ }
30
+ //# sourceMappingURL=run-update.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-update.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/pr-gate/src/scripts/workflow/run-update.ts"],"names":[],"mappings":";;AAiBA,8CAwBC;;AAzCD,+CAAyB;AACzB,iEAAwD;AACxD,+CAA6D;AAC7D,+CAAyD;AACzD,2CAAuC;AAahC,KAAK,UAAU,iBAAiB,CAAC,QAAgB,EAAE,aAAqB;IAC3E,MAAM,QAAQ,GAAG,IAAA,yBAAW,EAAC,QAAQ,EAAE,IAAA,qCAAc,GAAE,CAAC,CAAC;IACzD,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE5C,8DAA8D;IAC9D,MAAM,QAAQ,GAAG,IAAA,6BAAe,EAAC,QAAQ,CAAC,CAAC;IAC3C,IAAI,QAAQ,EAAE,CAAC;QACX,IAAI,CAAC,QAAQ,CAAC,SAAS;YAAE,OAAO,mBAAmB,CAAC;QACpD,qDAAqD;QACrD,MAAM,IAAA,oBAAQ,EACV,QAAQ,EAAE,QAAQ,EAClB,IAAI,0BAAY,CAAC,QAAQ,CAAC,aAAa,EAAE,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC,QAAQ,CAAC,EACzG,IAAI,CACP,CAAC;QACF,OAAO,WAAW,CAAC;IACvB,CAAC;IAED,uEAAuE;IACvE,MAAM,MAAM,GAAG,MAAM,IAAA,wBAAU,EAAC,QAAQ,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC;IACnE,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU,IAAI,MAAM,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;QAC1D,OAAO,UAAU,CAAC;IACtB,CAAC;IACD,MAAM,IAAA,oBAAQ,EAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACzD,OAAO,WAAW,CAAC;AACvB,CAAC","sourcesContent":["import * as fs from 'fs';\nimport { getFeatureName } from './git-readAiBranchName';\nimport { mergeDirFor, readMergeMarker } from './merge-state';\nimport { mergeStart, MergeContext } from './merge-start';\nimport { mergeEnd } from './merge-end';\n\n// The shared \"sync this feature branch from main\" engine — a thin composition of the two lifecycle\n// primitives (merge-START brings main in, merge-END finalizes). It is an INTERNAL function, not a\n// bin: `wp-update-start` (standalone) and `wp-start-upsert-pr` (PR flow) both call it. It NEVER\n// creates a PR and — unlike the old wp-git-update bin — it does NOT process.exit; it RETURNS an\n// outcome so each caller can print the handoff that fits its context.\n//\n// `finishCommand` is the command the AI is told to run after resolving conflicts — the standalone\n// caller passes `wp-update-end`, the PR flow passes `wp-finish-upsert-pr`.\n\nexport type UpdateOutcome = 'finalized' | 'conflict' | 'unvalidatedResume';\n\nexport async function runUpdateFromMain(repoRoot: string, finishCommand: string): Promise<UpdateOutcome> {\n const mergeDir = mergeDirFor(repoRoot, getFeatureName());\n fs.mkdirSync(mergeDir, { recursive: true });\n\n // Resume path: a marker means a merge is already in progress.\n const existing = readMergeMarker(mergeDir);\n if (existing) {\n if (!existing.validated) return 'unvalidatedResume';\n // Already validated → just finalize the branch swap.\n await mergeEnd(\n repoRoot, mergeDir,\n new MergeContext(existing.currentBranch, existing.squashBranch, existing.backupBranch, existing.prNumber),\n null,\n );\n return 'finalized';\n }\n\n // Fresh update: start, then finalize on clean / hand back on conflict.\n const result = await mergeStart(repoRoot, mergeDir, finishCommand);\n if (result.status === 'conflict' || result.context === null) {\n return 'conflict';\n }\n await mergeEnd(repoRoot, mergeDir, result.context, null);\n return 'finalized';\n}\n"]}
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- export declare function main(): void;
2
+ export declare function main(): Promise<void>;
@@ -8,26 +8,24 @@ const git_readAiBranchName_1 = require("./workflow/git-readAiBranchName");
8
8
  const branch_naming_1 = require("./workflow/branch-naming");
9
9
  const build_affected_1 = require("./workflow/build-affected");
10
10
  const git_exec_1 = require("./workflow/git-exec");
11
+ const run_update_1 = require("./workflow/run-update");
11
12
  // START of the AI-first PR flow (webpieces is AI-driven, so we invert trytami's human-first flow):
12
13
  // this command does the deterministic setup — update from main, push, run the build gate — then
13
14
  // hands the AI instructions to WRITE review.json and run `wp-finish-upsert-pr` (which reads it and
14
15
  // posts the PR). This command NEVER creates/updates a PR; all `gh` posting lives in finish.
15
16
  const SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n';
16
- // Step A — bring the branch up to date with main via the 3-point engine (child process, so its
17
- // conflict handback / guard interplay is unaffected by this command's hook context).
18
- function runUpdateFromMain() {
17
+ // Step A — bring the branch up to date with main via the shared 3-point engine (in-process). On
18
+ // conflict the merge process doc it writes names `wp-finish-upsert-pr` as the finish command (this
19
+ // PR flow's finish, which validates + finalizes + builds + posts the PR).
20
+ async function updateBranchFromMain(repoRoot) {
19
21
  process.stdout.write('\n' + SEP + '① Updating branch from main\n' + SEP + '\n');
20
- const result = (0, child_process_1.spawnSync)('pnpm', ['wp-git-update'], { stdio: 'inherit' });
21
- if (result.status === 2) {
22
+ const outcome = await (0, run_update_1.runUpdateFromMain)(repoRoot, 'wp-finish-upsert-pr');
23
+ if (outcome === 'conflict' || outcome === 'unvalidatedResume') {
22
24
  process.stdout.write('\n⏸️ Conflicts — resolve them, then run pnpm wp-finish-upsert-pr (it validates the merge AND finishes the PR).\n');
23
25
  process.exit(2);
24
26
  }
25
- if (result.status !== 0) {
26
- process.stderr.write('\n❌ Branch update failed — see output above.\n');
27
- process.exit(result.status ?? 1);
28
- }
29
27
  }
30
- function main() {
28
+ async function main() {
31
29
  const repoRoot = (0, child_process_1.execSync)('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();
32
30
  // Refresh the AI-facing workflow doc so it's present + current for any failure message to cite.
33
31
  (0, rules_config_1.writeTemplate)(repoRoot, 'webpieces.git-workflow.md');
@@ -35,7 +33,7 @@ function main() {
35
33
  // must not commit your work for you, and pushing HEAD while building the working tree would let an
36
34
  // uncommitted change build green yet push a stale commit. Fail early with instructions if dirty.
37
35
  (0, git_exec_1.assertCleanTree)(repoRoot);
38
- runUpdateFromMain();
36
+ await updateBranchFromMain(repoRoot);
39
37
  // Local branch may be a numbered generation (base2/…); the remote/PR branch is the stable base.
40
38
  (0, git_exec_1.ensurePushed)((0, branch_naming_1.baseBranchName)((0, child_process_1.execSync)('git branch --show-current', { encoding: 'utf8' }).trim()));
41
39
  // Advisory build gate — early feedback before the AI writes review.json. wp-finish-upsert-pr runs
@@ -50,6 +48,10 @@ function main() {
50
48
  `(It re-validates the build, renders the dashboard with your risk/violations, and creates/updates the PR.)\n\n`);
51
49
  }
52
50
  if (require.main === module) {
53
- main();
51
+ main().catch((err) => {
52
+ const message = err instanceof Error ? err.message : String(err);
53
+ process.stderr.write(message + '\n');
54
+ process.exit(1);
55
+ });
54
56
  }
55
57
  //# sourceMappingURL=wp-start-upsert-pr.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"wp-start-upsert-pr.js","sourceRoot":"","sources":["../../../../../../packages/tooling/pr-gate/src/scripts/wp-start-upsert-pr.ts"],"names":[],"mappings":";;;AA8BA,oBA6BC;AA1DD,iDAAoD;AACpD,0DAA8F;AAC9F,0EAAiE;AACjE,4DAA0D;AAC1D,8DAA2E;AAC3E,kDAAoE;AAEpE,mGAAmG;AACnG,gGAAgG;AAChG,mGAAmG;AACnG,4FAA4F;AAE5F,MAAM,GAAG,GAAG,0DAA0D,CAAC;AAEvE,+FAA+F;AAC/F,qFAAqF;AACrF,SAAS,iBAAiB;IACtB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,GAAG,GAAG,+BAA+B,GAAG,GAAG,GAAG,IAAI,CAAC,CAAC;IAChF,MAAM,MAAM,GAAG,IAAA,yBAAS,EAAC,MAAM,EAAE,CAAC,eAAe,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;IAC1E,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mHAAmH,CAAC,CAAC;QAC1I,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gDAAgD,CAAC,CAAC;QACvE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;IACrC,CAAC;AACL,CAAC;AAED,SAAgB,IAAI;IAChB,MAAM,QAAQ,GAAG,IAAA,wBAAQ,EAAC,+BAA+B,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACxF,gGAAgG;IAChG,IAAA,4BAAa,EAAC,QAAQ,EAAE,2BAA2B,CAAC,CAAC;IAErD,iGAAiG;IACjG,mGAAmG;IACnG,iGAAiG;IACjG,IAAA,0BAAe,EAAC,QAAQ,CAAC,CAAC;IAE1B,iBAAiB,EAAE,CAAC;IACpB,gGAAgG;IAChG,IAAA,uBAAY,EAAC,IAAA,8BAAc,EAAC,IAAA,wBAAQ,EAAC,2BAA2B,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAEjG,kGAAkG;IAClG,kGAAkG;IAClG,IAAA,6BAAY,EAAC,QAAQ,EAAE,IAAI,iCAAgB,CACvC,4BAA4B,EAAE,yBAAyB,EAAE,yCAAyC,CACrG,CAAC,CAAC;IAEH,sFAAsF;IACtF,MAAM,UAAU,GAAG,IAAA,6BAAc,EAAC,QAAQ,EAAE,IAAA,qCAAc,GAAE,CAAC,CAAC;IAC9D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,GAAG,GAAG,gCAAgC,GAAG,GAAG,GAAG,IAAI,CAAC,CAAC;IACjF,OAAO,CAAC,MAAM,CAAC,KAAK,CAChB,yFAAyF;QACzF,GAAG,IAAA,mCAAoB,EAAC,UAAU,CAAC,MAAM;QACzC,uCAAuC;QACvC,+GAA+G,CAClH,CAAC;AACN,CAAC;AAED,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;IAC1B,IAAI,EAAE,CAAC;AACX,CAAC","sourcesContent":["#!/usr/bin/env node\nimport { execSync, spawnSync } from 'child_process';\nimport { reviewJsonPath, reviewJsonSchemaHint, writeTemplate } from '@webpieces/rules-config';\nimport { getFeatureName } from './workflow/git-readAiBranchName';\nimport { baseBranchName } from './workflow/branch-naming';\nimport { runBuildGate, BuildGateOptions } from './workflow/build-affected';\nimport { assertCleanTree, ensurePushed } from './workflow/git-exec';\n\n// START of the AI-first PR flow (webpieces is AI-driven, so we invert trytami's human-first flow):\n// this command does the deterministic setup — update from main, push, run the build gate — then\n// hands the AI instructions to WRITE review.json and run `wp-finish-upsert-pr` (which reads it and\n// posts the PR). This command NEVER creates/updates a PR; all `gh` posting lives in finish.\n\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\n// Step A — bring the branch up to date with main via the 3-point engine (child process, so its\n// conflict handback / guard interplay is unaffected by this command's hook context).\nfunction runUpdateFromMain(): void {\n process.stdout.write('\\n' + SEP + '① Updating branch from main\\n' + SEP + '\\n');\n const result = spawnSync('pnpm', ['wp-git-update'], { stdio: 'inherit' });\n if (result.status === 2) {\n process.stdout.write('\\n⏸️ Conflicts — resolve them, then run pnpm wp-finish-upsert-pr (it validates the merge AND finishes the PR).\\n');\n process.exit(2);\n }\n if (result.status !== 0) {\n process.stderr.write('\\n❌ Branch update failed — see output above.\\n');\n process.exit(result.status ?? 1);\n }\n}\n\nexport function main(): void {\n const repoRoot = execSync('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();\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\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 an\n // uncommitted change build green yet push a stale commit. Fail early with instructions if dirty.\n assertCleanTree(repoRoot);\n\n runUpdateFromMain();\n // Local branch may be a numbered generation (base2/…); the remote/PR branch is the stable base.\n ensurePushed(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 runs\n // the authoritative one. Both go through the same shared runBuildGate (only the framing differs).\n 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).\n const reviewPath = reviewJsonPath(repoRoot, getFeatureName());\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)}\\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\nif (require.main === module) {\n main();\n}\n"]}
1
+ {"version":3,"file":"wp-start-upsert-pr.js","sourceRoot":"","sources":["../../../../../../packages/tooling/pr-gate/src/scripts/wp-start-upsert-pr.ts"],"names":[],"mappings":";;;AA4BA,oBA6BC;AAxDD,iDAAyC;AACzC,0DAA8F;AAC9F,0EAAiE;AACjE,4DAA0D;AAC1D,8DAA2E;AAC3E,kDAAoE;AACpE,sDAA0D;AAE1D,mGAAmG;AACnG,gGAAgG;AAChG,mGAAmG;AACnG,4FAA4F;AAE5F,MAAM,GAAG,GAAG,0DAA0D,CAAC;AAEvE,gGAAgG;AAChG,mGAAmG;AACnG,0EAA0E;AAC1E,KAAK,UAAU,oBAAoB,CAAC,QAAgB;IAChD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,GAAG,GAAG,+BAA+B,GAAG,GAAG,GAAG,IAAI,CAAC,CAAC;IAChF,MAAM,OAAO,GAAG,MAAM,IAAA,8BAAiB,EAAC,QAAQ,EAAE,qBAAqB,CAAC,CAAC;IACzE,IAAI,OAAO,KAAK,UAAU,IAAI,OAAO,KAAK,mBAAmB,EAAE,CAAC;QAC5D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mHAAmH,CAAC,CAAC;QAC1I,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,IAAI;IACtB,MAAM,QAAQ,GAAG,IAAA,wBAAQ,EAAC,+BAA+B,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACxF,gGAAgG;IAChG,IAAA,4BAAa,EAAC,QAAQ,EAAE,2BAA2B,CAAC,CAAC;IAErD,iGAAiG;IACjG,mGAAmG;IACnG,iGAAiG;IACjG,IAAA,0BAAe,EAAC,QAAQ,CAAC,CAAC;IAE1B,MAAM,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IACrC,gGAAgG;IAChG,IAAA,uBAAY,EAAC,IAAA,8BAAc,EAAC,IAAA,wBAAQ,EAAC,2BAA2B,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAEjG,kGAAkG;IAClG,kGAAkG;IAClG,IAAA,6BAAY,EAAC,QAAQ,EAAE,IAAI,iCAAgB,CACvC,4BAA4B,EAAE,yBAAyB,EAAE,yCAAyC,CACrG,CAAC,CAAC;IAEH,sFAAsF;IACtF,MAAM,UAAU,GAAG,IAAA,6BAAc,EAAC,QAAQ,EAAE,IAAA,qCAAc,GAAE,CAAC,CAAC;IAC9D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,GAAG,GAAG,gCAAgC,GAAG,GAAG,GAAG,IAAI,CAAC,CAAC;IACjF,OAAO,CAAC,MAAM,CAAC,KAAK,CAChB,yFAAyF;QACzF,GAAG,IAAA,mCAAoB,EAAC,UAAU,CAAC,MAAM;QACzC,uCAAuC;QACvC,+GAA+G,CAClH,CAAC;AACN,CAAC;AAED,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;IAC1B,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAU,EAAE,EAAE;QACxB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;QACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;AACP,CAAC","sourcesContent":["#!/usr/bin/env node\nimport { execSync } from 'child_process';\nimport { reviewJsonPath, reviewJsonSchemaHint, writeTemplate } from '@webpieces/rules-config';\nimport { getFeatureName } from './workflow/git-readAiBranchName';\nimport { baseBranchName } from './workflow/branch-naming';\nimport { runBuildGate, BuildGateOptions } from './workflow/build-affected';\nimport { assertCleanTree, ensurePushed } from './workflow/git-exec';\nimport { runUpdateFromMain } from './workflow/run-update';\n\n// START of the AI-first PR flow (webpieces is AI-driven, so we invert trytami's human-first flow):\n// this command does the deterministic setup — update from main, push, run the build gate — then\n// hands the AI instructions to WRITE review.json and run `wp-finish-upsert-pr` (which reads it and\n// posts the PR). This command NEVER creates/updates a PR; all `gh` posting lives in finish.\n\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\n// Step A — bring the branch up to date with main via the shared 3-point engine (in-process). On\n// conflict the merge process doc it writes names `wp-finish-upsert-pr` as the finish command (this\n// PR flow's finish, which validates + finalizes + builds + posts the PR).\nasync function updateBranchFromMain(repoRoot: string): Promise<void> {\n process.stdout.write('\\n' + SEP + '① Updating branch from main\\n' + SEP + '\\n');\n const outcome = await runUpdateFromMain(repoRoot, 'wp-finish-upsert-pr');\n if (outcome === 'conflict' || outcome === 'unvalidatedResume') {\n process.stdout.write('\\n⏸️ Conflicts — resolve them, then run pnpm wp-finish-upsert-pr (it validates the merge AND finishes the PR).\\n');\n process.exit(2);\n }\n}\n\nexport async function main(): Promise<void> {\n const repoRoot = execSync('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();\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\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 an\n // uncommitted change build green yet push a stale commit. Fail early with instructions if dirty.\n assertCleanTree(repoRoot);\n\n await updateBranchFromMain(repoRoot);\n // Local branch may be a numbered generation (base2/…); the remote/PR branch is the stable base.\n ensurePushed(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 runs\n // the authoritative one. Both go through the same shared runBuildGate (only the framing differs).\n 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).\n const reviewPath = reviewJsonPath(repoRoot, getFeatureName());\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)}\\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\nif (require.main === module) {\n main().catch((err: Error) => {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(message + '\\n');\n process.exit(1);\n });\n}\n"]}
@@ -7,19 +7,19 @@ const git_readAiBranchName_1 = require("./workflow/git-readAiBranchName");
7
7
  const merge_state_1 = require("./workflow/merge-state");
8
8
  const merge_end_1 = require("./workflow/merge-end");
9
9
  const merge_start_1 = require("./workflow/merge-start");
10
- // wp-merge-end — manual entry to the SECOND half of the 3-point squash-merge lifecycle (debug /
11
- // recovery). Given an in-progress merge marker it validates + commits the AI's resolution (only when
12
- // the marker is not yet validated) and ALWAYS finalizes the branch swap (squash→feature, push, stamp
13
- // clean, clear marker). It does NOT run the build gate / dashboard / PR — that is wp-finish-upsert-pr.
14
- // Use it to recover a stuck-but-resolved merge, or to finalize a clean `wp-merge-start`. Refuses to
15
- // run when there is no merge in progress.
10
+ // wp-update-end — finalize half of the 3-point squash-merge lifecycle. Run it AFTER `wp-update-start`
11
+ // handed back conflicts and you resolved them. Given an in-progress merge marker it validates +
12
+ // commits the AI's resolution (when the marker is not yet validated) and ALWAYS finalizes the branch
13
+ // swap (squash→feature, push, stamp clean, clear marker). It does NOT run the build gate / dashboard
14
+ // / PR that is wp-finish-upsert-pr (the PR flow's finish). Refuses to run when there is no merge in
15
+ // progress (a clean `wp-update-start` finalizes on its own — there is nothing left for this to do).
16
16
  async function main() {
17
17
  const repoRoot = (0, child_process_1.execSync)('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();
18
18
  const mergeDir = (0, merge_state_1.mergeDirFor)(repoRoot, (0, git_readAiBranchName_1.getFeatureName)());
19
19
  const marker = (0, merge_state_1.readMergeMarker)(mergeDir);
20
20
  if (!marker) {
21
21
  process.stderr.write('❌ No merge in progress (no marker) — nothing to finalize.\n');
22
- process.stderr.write('Start one with: pnpm wp-git-update (or pnpm wp-merge-start).\n');
22
+ process.stderr.write('Start one with: pnpm wp-update-start (a clean update finalizes itself).\n');
23
23
  process.exit(1);
24
24
  }
25
25
  // Not yet validated => a conflict resolution the AI owns, so validate + commit it first; already
@@ -35,4 +35,4 @@ if (require.main === module) {
35
35
  process.exit(1);
36
36
  });
37
37
  }
38
- //# sourceMappingURL=wp-merge-end.js.map
38
+ //# sourceMappingURL=wp-update-end.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wp-update-end.js","sourceRoot":"","sources":["../../../../../../packages/tooling/pr-gate/src/scripts/wp-update-end.ts"],"names":[],"mappings":";;;AAcA,oBAoBC;AAjCD,iDAAyC;AACzC,0EAAiE;AACjE,wDAAsE;AACtE,oDAAgD;AAChD,wDAAsD;AAEtD,sGAAsG;AACtG,gGAAgG;AAChG,qGAAqG;AACrG,qGAAqG;AACrG,sGAAsG;AACtG,oGAAoG;AAE7F,KAAK,UAAU,IAAI;IACtB,MAAM,QAAQ,GAAG,IAAA,wBAAQ,EAAC,+BAA+B,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACxF,MAAM,QAAQ,GAAG,IAAA,yBAAW,EAAC,QAAQ,EAAE,IAAA,qCAAc,GAAE,CAAC,CAAC;IAEzD,MAAM,MAAM,GAAG,IAAA,6BAAe,EAAC,QAAQ,CAAC,CAAC;IACzC,IAAI,CAAC,MAAM,EAAE,CAAC;QACV,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,6DAA6D,CAAC,CAAC;QACpF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,6EAA6E,CAAC,CAAC;QACpG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IAED,iGAAiG;IACjG,uEAAuE;IACvE,MAAM,eAAe,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC;IACzE,MAAM,IAAA,oBAAQ,EACV,QAAQ,EAAE,QAAQ,EAClB,IAAI,0BAAY,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,QAAQ,CAAC,EACjG,eAAe,CAClB,CAAC;IACF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,yBAAyB,GAAG,MAAM,CAAC,aAAa,GAAG,KAAK,CAAC,CAAC;AACnF,CAAC;AAED,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;IAC1B,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAU,EAAE,EAAE;QACxB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;QACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;AACP,CAAC","sourcesContent":["#!/usr/bin/env node\nimport { execSync } from 'child_process';\nimport { getFeatureName } from './workflow/git-readAiBranchName';\nimport { mergeDirFor, readMergeMarker } from './workflow/merge-state';\nimport { mergeEnd } from './workflow/merge-end';\nimport { MergeContext } from './workflow/merge-start';\n\n// wp-update-end — finalize half of the 3-point squash-merge lifecycle. Run it AFTER `wp-update-start`\n// handed back conflicts and you resolved them. Given an in-progress merge marker it validates +\n// commits the AI's resolution (when the marker is not yet validated) and ALWAYS finalizes the branch\n// swap (squash→feature, push, stamp clean, clear marker). It does NOT run the build gate / dashboard\n// / PR — that is wp-finish-upsert-pr (the PR flow's finish). Refuses to run when there is no merge in\n// progress (a clean `wp-update-start` finalizes on its own — there is nothing left for this to do).\n\nexport async function main(): Promise<void> {\n const repoRoot = execSync('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();\n const mergeDir = mergeDirFor(repoRoot, getFeatureName());\n\n const marker = readMergeMarker(mergeDir);\n if (!marker) {\n process.stderr.write('❌ No merge in progress (no marker) — nothing to finalize.\\n');\n process.stderr.write('Start one with: pnpm wp-update-start (a clean update finalizes itself).\\n');\n process.exit(1);\n }\n\n // Not yet validated => a conflict resolution the AI owns, so validate + commit it first; already\n // validated => clean merge (or previously validated) => finalize only.\n const conflictedFiles = marker.validated ? null : marker.conflictedFiles;\n await mergeEnd(\n repoRoot, mergeDir,\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\nif (require.main === module) {\n main().catch((err: Error) => {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(message + '\\n');\n process.exit(1);\n });\n}\n"]}
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.main = main;
5
+ const child_process_1 = require("child_process");
6
+ const rules_config_1 = require("@webpieces/rules-config");
7
+ const run_update_1 = require("./workflow/run-update");
8
+ // wp-update-start: the "sync this feature branch from main" entry point (the redirect target of the
9
+ // redirect-how-to-merge-main guard). It runs the FULL 3-point squash-update via the shared
10
+ // runUpdateFromMain engine: on a CLEAN merge it finalizes everything (no need to call wp-update-end);
11
+ // on CONFLICT it writes the 3-point context + merge process doc and hands back — you resolve, then
12
+ // run `wp-update-end` to finalize. It NEVER creates a PR (that is the wp-*-upsert-pr flow).
13
+ const SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n';
14
+ async function main() {
15
+ const repoRoot = (0, child_process_1.execSync)('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();
16
+ // Refresh the AI-facing workflow doc so it's present + current for any failure message to cite.
17
+ (0, rules_config_1.writeTemplate)(repoRoot, 'webpieces.git-workflow.md');
18
+ const outcome = await (0, run_update_1.runUpdateFromMain)(repoRoot, 'wp-update-end');
19
+ if (outcome === 'conflict') {
20
+ // Context + marker + merge process doc already written by merge-start; hand back to the AI.
21
+ process.exit(2);
22
+ }
23
+ if (outcome === 'unvalidatedResume') {
24
+ process.stdout.write('\n' + SEP + '⏸️ Merge in progress — not yet validated\n' + SEP + '\n');
25
+ process.stdout.write('Resolve the remaining conflicts in the working tree, then run:\n');
26
+ process.stdout.write(' pnpm wp-update-end\n\n');
27
+ process.exit(1);
28
+ }
29
+ process.stdout.write('\n✅ Updated from main — clean. No need to call wp-update-end.\n');
30
+ }
31
+ if (require.main === module) {
32
+ main().catch((err) => {
33
+ const message = err instanceof Error ? err.message : String(err);
34
+ process.stderr.write(message + '\n');
35
+ process.exit(1);
36
+ });
37
+ }
38
+ //# sourceMappingURL=wp-update-start.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wp-update-start.js","sourceRoot":"","sources":["../../../../../../packages/tooling/pr-gate/src/scripts/wp-update-start.ts"],"names":[],"mappings":";;;AAaA,oBAiBC;AA7BD,iDAAyC;AACzC,0DAAwD;AACxD,sDAA0D;AAE1D,oGAAoG;AACpG,2FAA2F;AAC3F,sGAAsG;AACtG,mGAAmG;AACnG,4FAA4F;AAE5F,MAAM,GAAG,GAAG,0DAA0D,CAAC;AAEhE,KAAK,UAAU,IAAI;IACtB,MAAM,QAAQ,GAAG,IAAA,wBAAQ,EAAC,+BAA+B,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACxF,gGAAgG;IAChG,IAAA,4BAAa,EAAC,QAAQ,EAAE,2BAA2B,CAAC,CAAC;IAErD,MAAM,OAAO,GAAG,MAAM,IAAA,8BAAiB,EAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;IACnE,IAAI,OAAO,KAAK,UAAU,EAAE,CAAC;QACzB,4FAA4F;QAC5F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IACD,IAAI,OAAO,KAAK,mBAAmB,EAAE,CAAC;QAClC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,GAAG,GAAG,6CAA6C,GAAG,GAAG,GAAG,IAAI,CAAC,CAAC;QAC9F,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,kEAAkE,CAAC,CAAC;QACzF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;QACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iEAAiE,CAAC,CAAC;AAC5F,CAAC;AAED,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;IAC1B,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAU,EAAE,EAAE;QACxB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;QACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;AACP,CAAC","sourcesContent":["#!/usr/bin/env node\nimport { execSync } from 'child_process';\nimport { writeTemplate } from '@webpieces/rules-config';\nimport { runUpdateFromMain } from './workflow/run-update';\n\n// wp-update-start: the \"sync this feature branch from main\" entry point (the redirect target of the\n// redirect-how-to-merge-main guard). It runs the FULL 3-point squash-update via the shared\n// runUpdateFromMain engine: on a CLEAN merge it finalizes everything (no need to call wp-update-end);\n// on CONFLICT it writes the 3-point context + merge process doc and hands back — you resolve, then\n// run `wp-update-end` to finalize. It NEVER creates a PR (that is the wp-*-upsert-pr flow).\n\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\nexport async function main(): Promise<void> {\n const repoRoot = execSync('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();\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\n const outcome = await runUpdateFromMain(repoRoot, 'wp-update-end');\n if (outcome === 'conflict') {\n // Context + marker + merge process doc already written by merge-start; hand back to the AI.\n process.exit(2);\n }\n if (outcome === 'unvalidatedResume') {\n process.stdout.write('\\n' + SEP + '⏸️ Merge in progress — not yet validated\\n' + SEP + '\\n');\n process.stdout.write('Resolve the remaining conflicts in the working tree, then run:\\n');\n process.stdout.write(' pnpm wp-update-end\\n\\n');\n process.exit(1);\n }\n process.stdout.write('\\n✅ Updated from main — clean. No need to call wp-update-end.\\n');\n}\n\nif (require.main === module) {\n main().catch((err: Error) => {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(message + '\\n');\n process.exit(1);\n });\n}\n"]}
@@ -1,56 +0,0 @@
1
- #!/usr/bin/env node
2
- "use strict";
3
- Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.main = main;
5
- const tslib_1 = require("tslib");
6
- const child_process_1 = require("child_process");
7
- const fs = tslib_1.__importStar(require("fs"));
8
- const rules_config_1 = require("@webpieces/rules-config");
9
- const git_readAiBranchName_1 = require("./workflow/git-readAiBranchName");
10
- const merge_state_1 = require("./workflow/merge-state");
11
- const merge_start_1 = require("./workflow/merge-start");
12
- const merge_end_1 = require("./workflow/merge-end");
13
- // wp-git-update: the "sync this feature branch from main" entry point (also the redirect target of the
14
- // redirect-how-to-merge-main guard, and the first step wp-start-upsert-pr shells out to). It is a thin
15
- // composition of the two lifecycle primitives: merge-START brings main in, merge-END finalizes. It
16
- // NEVER creates a PR. Three cases: a fresh update (start → finalize on clean, hand back on conflict),
17
- // resuming an already-validated merge (finalize), or resuming an unvalidated one (tell the AI to run
18
- // wp-finish-upsert-pr, which validates + finalizes via merge-END).
19
- const SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n';
20
- async function handleResume(repoRoot, mergeDir, marker) {
21
- if (!marker.validated) {
22
- process.stdout.write('\n' + SEP + '⏸️ Merge in progress — not yet validated\n' + SEP + '\n');
23
- process.stdout.write('Resolve the remaining conflicts in the working tree, then run:\n');
24
- process.stdout.write(' pnpm wp-finish-upsert-pr\n\n');
25
- process.exit(1);
26
- }
27
- process.stdout.write('Resuming: merge validated — finalizing.\n');
28
- await (0, merge_end_1.mergeEnd)(repoRoot, mergeDir, new merge_start_1.MergeContext(marker.currentBranch, marker.squashBranch, marker.backupBranch, marker.prNumber), null);
29
- }
30
- async function main() {
31
- const repoRoot = (0, child_process_1.execSync)('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();
32
- const featureName = (0, git_readAiBranchName_1.getFeatureName)();
33
- const mergeDir = (0, merge_state_1.mergeDirFor)(repoRoot, featureName);
34
- fs.mkdirSync(mergeDir, { recursive: true });
35
- // Refresh the AI-facing workflow doc so it's present + current for any failure message to cite.
36
- (0, rules_config_1.writeTemplate)(repoRoot, 'webpieces.git-workflow.md');
37
- const existing = (0, merge_state_1.readMergeMarker)(mergeDir);
38
- if (existing) {
39
- await handleResume(repoRoot, mergeDir, existing);
40
- return;
41
- }
42
- const result = await (0, merge_start_1.mergeStart)(repoRoot, mergeDir);
43
- if (result.status === 'conflict' || result.context === null) {
44
- // Conflicts: marker + context files written, AI hands resolution off to wp-finish-upsert-pr.
45
- process.exit(2);
46
- }
47
- await (0, merge_end_1.mergeEnd)(repoRoot, mergeDir, result.context, null);
48
- }
49
- if (require.main === module) {
50
- main().catch((err) => {
51
- const message = err instanceof Error ? err.message : String(err);
52
- process.stderr.write(message + '\n');
53
- process.exit(1);
54
- });
55
- }
56
- //# sourceMappingURL=git-updateFromMain.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"git-updateFromMain.js","sourceRoot":"","sources":["../../../../../../packages/tooling/pr-gate/src/scripts/git-updateFromMain.ts"],"names":[],"mappings":";;;AAiCA,oBAoBC;;AApDD,iDAAyC;AACzC,+CAAyB;AACzB,0DAAwD;AACxD,0EAAiE;AACjE,wDAAmF;AACnF,wDAAkE;AAClE,oDAAgD;AAEhD,uGAAuG;AACvG,uGAAuG;AACvG,mGAAmG;AACnG,sGAAsG;AACtG,qGAAqG;AACrG,mEAAmE;AAEnE,MAAM,GAAG,GAAG,0DAA0D,CAAC;AAEvE,KAAK,UAAU,YAAY,CAAC,QAAgB,EAAE,QAAgB,EAAE,MAAmB;IAC/E,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QACpB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,GAAG,GAAG,6CAA6C,GAAG,GAAG,GAAG,IAAI,CAAC,CAAC;QAC9F,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,kEAAkE,CAAC,CAAC;QACzF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;QACvD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAClE,MAAM,IAAA,oBAAQ,EACV,QAAQ,EAAE,QAAQ,EAClB,IAAI,0BAAY,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,QAAQ,CAAC,EACjG,IAAI,CACP,CAAC;AACN,CAAC;AAEM,KAAK,UAAU,IAAI;IACtB,MAAM,QAAQ,GAAG,IAAA,wBAAQ,EAAC,+BAA+B,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACxF,MAAM,WAAW,GAAG,IAAA,qCAAc,GAAE,CAAC;IACrC,MAAM,QAAQ,GAAG,IAAA,yBAAW,EAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IACpD,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,gGAAgG;IAChG,IAAA,4BAAa,EAAC,QAAQ,EAAE,2BAA2B,CAAC,CAAC;IAErD,MAAM,QAAQ,GAAG,IAAA,6BAAe,EAAC,QAAQ,CAAC,CAAC;IAC3C,IAAI,QAAQ,EAAE,CAAC;QACX,MAAM,YAAY,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACjD,OAAO;IACX,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,IAAA,wBAAU,EAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACpD,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU,IAAI,MAAM,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;QAC1D,6FAA6F;QAC7F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IACD,MAAM,IAAA,oBAAQ,EAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AAC7D,CAAC;AAED,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;IAC1B,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAU,EAAE,EAAE;QACxB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;QACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;AACP,CAAC","sourcesContent":["#!/usr/bin/env node\nimport { execSync } from 'child_process';\nimport * as fs from 'fs';\nimport { writeTemplate } from '@webpieces/rules-config';\nimport { getFeatureName } from './workflow/git-readAiBranchName';\nimport { mergeDirFor, readMergeMarker, MergeMarker } from './workflow/merge-state';\nimport { mergeStart, MergeContext } from './workflow/merge-start';\nimport { mergeEnd } from './workflow/merge-end';\n\n// wp-git-update: the \"sync this feature branch from main\" entry point (also the redirect target of the\n// redirect-how-to-merge-main guard, and the first step wp-start-upsert-pr shells out to). It is a thin\n// composition of the two lifecycle primitives: merge-START brings main in, merge-END finalizes. It\n// NEVER creates a PR. Three cases: a fresh update (start → finalize on clean, hand back on conflict),\n// resuming an already-validated merge (finalize), or resuming an unvalidated one (tell the AI to run\n// wp-finish-upsert-pr, which validates + finalizes via merge-END).\n\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\nasync function handleResume(repoRoot: string, mergeDir: string, marker: MergeMarker): Promise<void> {\n if (!marker.validated) {\n process.stdout.write('\\n' + SEP + '⏸️ Merge in progress — not yet validated\\n' + SEP + '\\n');\n process.stdout.write('Resolve the remaining conflicts in the working tree, then run:\\n');\n process.stdout.write(' pnpm wp-finish-upsert-pr\\n\\n');\n process.exit(1);\n }\n process.stdout.write('Resuming: merge validated — finalizing.\\n');\n await mergeEnd(\n repoRoot, mergeDir,\n new MergeContext(marker.currentBranch, marker.squashBranch, marker.backupBranch, marker.prNumber),\n null,\n );\n}\n\nexport async function main(): Promise<void> {\n const repoRoot = execSync('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();\n const featureName = getFeatureName();\n const mergeDir = mergeDirFor(repoRoot, featureName);\n fs.mkdirSync(mergeDir, { recursive: true });\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\n const existing = readMergeMarker(mergeDir);\n if (existing) {\n await handleResume(repoRoot, mergeDir, existing);\n return;\n }\n\n const result = await mergeStart(repoRoot, mergeDir);\n if (result.status === 'conflict' || result.context === null) {\n // Conflicts: marker + context files written, AI hands resolution off to wp-finish-upsert-pr.\n process.exit(2);\n }\n await mergeEnd(repoRoot, mergeDir, result.context, null);\n}\n\nif (require.main === module) {\n main().catch((err: Error) => {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(message + '\\n');\n process.exit(1);\n });\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"wp-merge-end.js","sourceRoot":"","sources":["../../../../../../packages/tooling/pr-gate/src/scripts/wp-merge-end.ts"],"names":[],"mappings":";;;AAcA,oBAoBC;AAjCD,iDAAyC;AACzC,0EAAiE;AACjE,wDAAsE;AACtE,oDAAgD;AAChD,wDAAsD;AAEtD,gGAAgG;AAChG,qGAAqG;AACrG,qGAAqG;AACrG,uGAAuG;AACvG,oGAAoG;AACpG,0CAA0C;AAEnC,KAAK,UAAU,IAAI;IACtB,MAAM,QAAQ,GAAG,IAAA,wBAAQ,EAAC,+BAA+B,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACxF,MAAM,QAAQ,GAAG,IAAA,yBAAW,EAAC,QAAQ,EAAE,IAAA,qCAAc,GAAE,CAAC,CAAC;IAEzD,MAAM,MAAM,GAAG,IAAA,6BAAe,EAAC,QAAQ,CAAC,CAAC;IACzC,IAAI,CAAC,MAAM,EAAE,CAAC;QACV,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,6DAA6D,CAAC,CAAC;QACpF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,kEAAkE,CAAC,CAAC;QACzF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IAED,iGAAiG;IACjG,uEAAuE;IACvE,MAAM,eAAe,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC;IACzE,MAAM,IAAA,oBAAQ,EACV,QAAQ,EAAE,QAAQ,EAClB,IAAI,0BAAY,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,QAAQ,CAAC,EACjG,eAAe,CAClB,CAAC;IACF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,yBAAyB,GAAG,MAAM,CAAC,aAAa,GAAG,KAAK,CAAC,CAAC;AACnF,CAAC;AAED,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;IAC1B,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAU,EAAE,EAAE;QACxB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;QACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;AACP,CAAC","sourcesContent":["#!/usr/bin/env node\nimport { execSync } from 'child_process';\nimport { getFeatureName } from './workflow/git-readAiBranchName';\nimport { mergeDirFor, readMergeMarker } from './workflow/merge-state';\nimport { mergeEnd } from './workflow/merge-end';\nimport { MergeContext } from './workflow/merge-start';\n\n// wp-merge-end — manual entry to the SECOND half of the 3-point squash-merge lifecycle (debug /\n// recovery). Given an in-progress merge marker it validates + commits the AI's resolution (only when\n// the marker is not yet validated) and ALWAYS finalizes the branch swap (squash→feature, push, stamp\n// clean, clear marker). It does NOT run the build gate / dashboard / PR — that is wp-finish-upsert-pr.\n// Use it to recover a stuck-but-resolved merge, or to finalize a clean `wp-merge-start`. Refuses to\n// run when there is no merge in progress.\n\nexport async function main(): Promise<void> {\n const repoRoot = execSync('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();\n const mergeDir = mergeDirFor(repoRoot, getFeatureName());\n\n const marker = readMergeMarker(mergeDir);\n if (!marker) {\n process.stderr.write('❌ No merge in progress (no marker) — nothing to finalize.\\n');\n process.stderr.write('Start one with: pnpm wp-git-update (or pnpm wp-merge-start).\\n');\n process.exit(1);\n }\n\n // Not yet validated => a conflict resolution the AI owns, so validate + commit it first; already\n // validated => clean merge (or previously validated) => finalize only.\n const conflictedFiles = marker.validated ? null : marker.conflictedFiles;\n await mergeEnd(\n repoRoot, mergeDir,\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\nif (require.main === module) {\n main().catch((err: Error) => {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(message + '\\n');\n process.exit(1);\n });\n}\n"]}
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- export declare function main(): Promise<void>;
@@ -1,45 +0,0 @@
1
- #!/usr/bin/env node
2
- "use strict";
3
- Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.main = main;
5
- const tslib_1 = require("tslib");
6
- const child_process_1 = require("child_process");
7
- const fs = tslib_1.__importStar(require("fs"));
8
- const git_readAiBranchName_1 = require("./workflow/git-readAiBranchName");
9
- const merge_state_1 = require("./workflow/merge-state");
10
- const merge_start_1 = require("./workflow/merge-start");
11
- // wp-merge-start — manual entry to the FIRST half of the 3-point squash-merge lifecycle (debug /
12
- // recovery). Most callers want `pnpm wp-git-update`, which runs start AND finalize in one go. This
13
- // runs ONLY merge-START: it brings origin/main in and, on conflict, writes the 3-point context +
14
- // marker and hands back for resolution (exit 2). On a CLEAN merge it leaves the squash staged and
15
- // records a validated marker so a SEPARATE `pnpm wp-merge-end` can finalize the branch swap. It
16
- // refuses to run if a merge is already in progress (a marker is present).
17
- async function main() {
18
- const repoRoot = (0, child_process_1.execSync)('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();
19
- const mergeDir = (0, merge_state_1.mergeDirFor)(repoRoot, (0, git_readAiBranchName_1.getFeatureName)());
20
- fs.mkdirSync(mergeDir, { recursive: true });
21
- if ((0, merge_state_1.readMergeMarker)(mergeDir)) {
22
- process.stderr.write('❌ A merge is already in progress (marker present) — refusing to start another.\n');
23
- process.stderr.write('Resolve any conflicts, then run: pnpm wp-finish-upsert-pr (or pnpm wp-merge-end to only finalize).\n');
24
- process.exit(1);
25
- }
26
- const result = await (0, merge_start_1.mergeStart)(repoRoot, mergeDir);
27
- if (result.status === 'conflict' || result.context === null) {
28
- // Conflicts: merge-START wrote the marker + context files and printed the handback.
29
- process.exit(2);
30
- }
31
- // Clean merge: persist a validated marker so a separate `wp-merge-end` process can finalize
32
- // (the in-memory context is otherwise lost between commands). hashes/conflictedFiles are unused
33
- // by finalize, so they are empty here.
34
- const ctx = result.context;
35
- (0, merge_state_1.writeMergeMarker)(mergeDir, new merge_state_1.MergeMarker(ctx.currentBranch, ctx.squashBranch, ctx.backupBranch, ctx.prNumber, [], '', '', '', true));
36
- process.stdout.write('\n✅ Clean squash staged on ' + ctx.squashBranch + '. Finalize with: pnpm wp-merge-end\n');
37
- }
38
- if (require.main === module) {
39
- main().catch((err) => {
40
- const message = err instanceof Error ? err.message : String(err);
41
- process.stderr.write(message + '\n');
42
- process.exit(1);
43
- });
44
- }
45
- //# sourceMappingURL=wp-merge-start.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"wp-merge-start.js","sourceRoot":"","sources":["../../../../../../packages/tooling/pr-gate/src/scripts/wp-merge-start.ts"],"names":[],"mappings":";;;AAcA,oBAyBC;;AAtCD,iDAAyC;AACzC,+CAAyB;AACzB,0EAAiE;AACjE,wDAAqG;AACrG,wDAAoD;AAEpD,iGAAiG;AACjG,mGAAmG;AACnG,iGAAiG;AACjG,kGAAkG;AAClG,gGAAgG;AAChG,0EAA0E;AAEnE,KAAK,UAAU,IAAI;IACtB,MAAM,QAAQ,GAAG,IAAA,wBAAQ,EAAC,+BAA+B,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACxF,MAAM,QAAQ,GAAG,IAAA,yBAAW,EAAC,QAAQ,EAAE,IAAA,qCAAc,GAAE,CAAC,CAAC;IACzD,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE5C,IAAI,IAAA,6BAAe,EAAC,QAAQ,CAAC,EAAE,CAAC;QAC5B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,kFAAkF,CAAC,CAAC;QACzG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,wGAAwG,CAAC,CAAC;QAC/H,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,IAAA,wBAAU,EAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACpD,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU,IAAI,MAAM,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;QAC1D,oFAAoF;QACpF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IAED,4FAA4F;IAC5F,gGAAgG;IAChG,uCAAuC;IACvC,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC;IAC3B,IAAA,8BAAgB,EAAC,QAAQ,EAAE,IAAI,yBAAW,CACtC,GAAG,CAAC,aAAa,EAAE,GAAG,CAAC,YAAY,EAAE,GAAG,CAAC,YAAY,EAAE,GAAG,CAAC,QAAQ,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,CAC5F,CAAC,CAAC;IACH,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,6BAA6B,GAAG,GAAG,CAAC,YAAY,GAAG,uCAAuC,CAAC,CAAC;AACrH,CAAC;AAED,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;IAC1B,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAU,EAAE,EAAE;QACxB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;QACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;AACP,CAAC","sourcesContent":["#!/usr/bin/env node\nimport { execSync } from 'child_process';\nimport * as fs from 'fs';\nimport { getFeatureName } from './workflow/git-readAiBranchName';\nimport { mergeDirFor, readMergeMarker, writeMergeMarker, MergeMarker } from './workflow/merge-state';\nimport { mergeStart } from './workflow/merge-start';\n\n// wp-merge-start — manual entry to the FIRST half of the 3-point squash-merge lifecycle (debug /\n// recovery). Most callers want `pnpm wp-git-update`, which runs start AND finalize in one go. This\n// runs ONLY merge-START: it brings origin/main in and, on conflict, writes the 3-point context +\n// marker and hands back for resolution (exit 2). On a CLEAN merge it leaves the squash staged and\n// records a validated marker so a SEPARATE `pnpm wp-merge-end` can finalize the branch swap. It\n// refuses to run if a merge is already in progress (a marker is present).\n\nexport async function main(): Promise<void> {\n const repoRoot = execSync('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();\n const mergeDir = mergeDirFor(repoRoot, getFeatureName());\n fs.mkdirSync(mergeDir, { recursive: true });\n\n if (readMergeMarker(mergeDir)) {\n process.stderr.write('❌ A merge is already in progress (marker present) — refusing to start another.\\n');\n process.stderr.write('Resolve any conflicts, then run: pnpm wp-finish-upsert-pr (or pnpm wp-merge-end to only finalize).\\n');\n process.exit(1);\n }\n\n const result = await mergeStart(repoRoot, mergeDir);\n if (result.status === 'conflict' || result.context === null) {\n // Conflicts: merge-START wrote the marker + context files and printed the handback.\n process.exit(2);\n }\n\n // Clean merge: persist a validated marker so a separate `wp-merge-end` process can finalize\n // (the in-memory context is otherwise lost between commands). hashes/conflictedFiles are unused\n // by finalize, so they are empty here.\n const ctx = result.context;\n writeMergeMarker(mergeDir, new MergeMarker(\n ctx.currentBranch, ctx.squashBranch, ctx.backupBranch, ctx.prNumber, [], '', '', '', true,\n ));\n process.stdout.write('\\n✅ Clean squash staged on ' + ctx.squashBranch + '. Finalize with: pnpm wp-merge-end\\n');\n}\n\nif (require.main === module) {\n main().catch((err: Error) => {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(message + '\\n');\n process.exit(1);\n });\n}\n"]}