@@ -107,6 +107,8 @@ const {
107107 runLegacyUpdateIfRequested,
108108} = require ( './lib/update-checker' ) ;
109109const { checkBinDirOnPath, printPathWarning } = require ( '../lib/path-check' ) ;
110+ const { quoteShellArgument } = require ( '../lib/git-remote-utils' ) ;
111+ const { renderPullRequestBody, resolveIssueContext } = require ( '../src/pr-body-template' ) ;
110112const { StatusFooter, AGENT_STATE , ACTIVE_STATES } = require ( '../src/status-footer' ) ;
111113const { EVENT_COPY , formatMergeStatus } = require ( './event-copy' ) ;
112114
@@ -2012,9 +2014,25 @@ function buildContextSummary({
20122014 return contextSummary ;
20132015}
20142016
2015- function buildCompletionPrompt ( { contextSummary, taskText, issueNumber, issueTitle } ) {
2016- const mergeGoal = 'CREATE PR AND MERGE IT' ;
2017- const mergeStep = `
2017+ function buildDefaultFinishPrBody ( { taskText, issueNumber, issueTitle } ) {
2018+ const issueReference = renderPullRequestBody ( undefined , { issueNumber, issueTitle } ) ;
2019+ return [
2020+ issueReference ,
2021+ issueReference ? '' : null ,
2022+ '## Summary' ,
2023+ `${ String ( taskText || 'Unknown task' ) . slice ( 0 , 200 ) } ...` ,
2024+ '' ,
2025+ '## Changes' ,
2026+ '- Implementation complete' ,
2027+ '- All validations addressed' ,
2028+ '' ,
2029+ '🤖 Generated with zeroshot finish' ,
2030+ ]
2031+ . filter ( ( line ) => line !== null )
2032+ . join ( '\n' ) ;
2033+ }
2034+
2035+ const FINISH_MERGE_STEP = `
201820368. MERGE THE PR - THIS IS MANDATORY:
20192037 \`\`\`bash
20202038 gh pr merge --merge --auto
@@ -2029,7 +2047,29 @@ function buildCompletionPrompt({ contextSummary, taskText, issueNumber, issueTit
20292047
20302048 REPEAT UNTIL MERGED. DO NOT GIVE UP.` ;
20312049
2032- return `# YOUR MISSION: ${ mergeGoal }
2050+ function buildFinishCommandArguments ( { taskText, issueNumber, issueTitle, prBody } ) {
2051+ const issueContext = resolveIssueContext ( { issueNumber, issueTitle } ) ;
2052+ const resolvedTitle = issueContext . issueTitle ;
2053+ const resolvedBody =
2054+ typeof prBody === 'string'
2055+ ? renderPullRequestBody ( prBody , { issueNumber, issueTitle : resolvedTitle } )
2056+ : buildDefaultFinishPrBody ( { taskText, issueNumber, issueTitle : resolvedTitle } ) ;
2057+ return {
2058+ commitMessage : quoteShellArgument ( resolvedTitle || 'feat: implement task' ) ,
2059+ branch : quoteShellArgument (
2060+ issueContext . issueNumber !== 'unknown'
2061+ ? `issue-${ issueContext . issueNumber } `
2062+ : 'feature/implementation'
2063+ ) ,
2064+ prTitle : quoteShellArgument ( resolvedTitle ) ,
2065+ prBody : quoteShellArgument ( resolvedBody ) ,
2066+ } ;
2067+ }
2068+
2069+ function buildCompletionPrompt ( { contextSummary, taskText, issueNumber, issueTitle, prBody } ) {
2070+ const args = buildFinishCommandArguments ( { taskText, issueNumber, issueTitle, prBody } ) ;
2071+
2072+ return `# YOUR MISSION: CREATE PR AND MERGE IT
20332073
20342074${ contextSummary }
20352075
@@ -2050,12 +2090,12 @@ You are the FINISHER. Your ONLY job is to take this cluster's work and push it a
205020902. COMMIT ALL CHANGES - Stage and commit everything:
20512091 \`\`\`bash
20522092 git add .
2053- git commit -m " ${ issueTitle || 'feat: implement task' } "
2093+ git commit -m ${ args . commitMessage }
20542094 \`\`\`
20552095
205620963. CREATE BRANCH - Use issue number if available:
20572097 \`\`\`bash
2058- ${ issueNumber ? ` git checkout -b issue- ${ issueNumber } ` : 'git checkout -b feature/implementation' }
2098+ git checkout -b ${ args . branch }
20592099 \`\`\`
20602100
206121014. PUSH TO REMOTE:
@@ -2065,16 +2105,7 @@ You are the FINISHER. Your ONLY job is to take this cluster's work and push it a
20652105
206621065. CREATE PULL REQUEST:
20672107 \`\`\`bash
2068- gh pr create --title "${ issueTitle || 'Implementation' } " --body "Closes #${ issueNumber || 'N/A' }
2069-
2070- ## Summary
2071- ${ taskText . slice ( 0 , 200 ) } ...
2072-
2073- ## Changes
2074- - Implementation complete
2075- - All validations addressed
2076-
2077- 🤖 Generated with zeroshot finish"
2108+ gh pr create --title ${ args . prTitle } --body ${ args . prBody }
20782109 \`\`\`
20792110
208021116. GET PR URL:
@@ -2083,7 +2114,7 @@ ${taskText.slice(0, 200)}...
20832114 \`\`\`
20842115
208521167. OUTPUT THE PR URL - Print it clearly so user can see it
2086- ${ mergeStep }
2117+ ${ FINISH_MERGE_STEP }
20872118
20882119## RULES
20892120
@@ -2707,6 +2738,10 @@ program
27072738 'Full automation: worktree isolation + PR + auto-merge (use --docker for Docker)'
27082739 )
27092740 . option ( '--pr-base <branch>' , 'Target branch for PRs (default: repo default branch)' )
2741+ . option (
2742+ '--pr-body <template>' ,
2743+ 'PR body template; supports {{issue_number}}, {{issue_title}}, and {{issue_reference}}'
2744+ )
27102745 . option ( '--merge-queue' , 'Use GitHub merge queue instead of direct merge' )
27112746 . option (
27122747 '--close-issue <mode>' ,
@@ -3714,6 +3749,10 @@ program
37143749 . helpGroup ( 'Control:' )
37153750 . description ( 'Take existing cluster and create completion-focused task (creates PR and merges)' )
37163751 . option ( '-y, --yes' , 'Skip confirmation if cluster is running' )
3752+ . option (
3753+ '--pr-body <template>' ,
3754+ 'PR body template; supports {{issue_number}}, {{issue_title}}, and {{issue_reference}}'
3755+ )
37173756 . action ( async ( id , options ) => {
37183757 try {
37193758 const orchestrator = await getOrchestrator ( ) ;
@@ -3732,6 +3771,7 @@ program
37323771 taskText : context . taskText ,
37333772 issueNumber : context . issueNumber ,
37343773 issueTitle : context . issueTitle ,
3774+ prBody : options . prBody ?? cluster . prOptions ?. prBody ,
37353775 } ) ;
37363776 printCompletionPromptPreview ( completionPrompt ) ;
37373777
@@ -6190,6 +6230,9 @@ module.exports = {
61906230 isStartupUpdateEligible,
61916231 handleNoArgumentInvocation,
61926232 shouldRunInitialSetup,
6233+ extractFinishContext,
6234+ buildDefaultFinishPrBody,
6235+ buildCompletionPrompt,
61936236 resolveRunMode,
61946237 killRunningClusters,
61956238} ;
0 commit comments