summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMatt Silverlock <[email protected]>2026-01-04 03:05:08 -0500
committerGitHub <[email protected]>2026-01-04 02:05:08 -0600
commit4486174e4319b9523d134fda863677f35e740105 (patch)
treea83ee60b875b48590c7b81c0714ddb33e017bc9d
parent41cf45a16e0545f9882c8b2b2f258e8935ea19b4 (diff)
downloadopencode-4486174e4319b9523d134fda863677f35e740105.tar.gz
opencode-4486174e4319b9523d134fda863677f35e740105.zip
github: handle duplicate PR creation when agent creates PR (#6777)
-rw-r--r--packages/opencode/src/cli/cmd/github.ts54
1 files changed, 46 insertions, 8 deletions
diff --git a/packages/opencode/src/cli/cmd/github.ts b/packages/opencode/src/cli/cmd/github.ts
index fbd2506e0..4c1e5b0e0 100644
--- a/packages/opencode/src/cli/cmd/github.ts
+++ b/packages/opencode/src/cli/cmd/github.ts
@@ -1237,17 +1237,55 @@ Co-authored-by: ${actor} <${actor}@users.noreply.github.com>"`
async function createPR(base: string, branch: string, title: string, body: string) {
console.log("Creating pull request...")
- const pr = await octoRest.rest.pulls.create({
- owner,
- repo,
- head: branch,
- base,
- title,
- body,
- })
+
+ // Check if an open PR already exists for this head→base combination
+ // This handles the case where the agent created a PR via gh pr create during its run
+ try {
+ const existing = await withRetry(() =>
+ octoRest.rest.pulls.list({
+ owner,
+ repo,
+ head: `${owner}:${branch}`,
+ base,
+ state: "open",
+ }),
+ )
+
+ if (existing.data.length > 0) {
+ console.log(`PR #${existing.data[0].number} already exists for branch ${branch}`)
+ return existing.data[0].number
+ }
+ } catch (e) {
+ // If the check fails, proceed to create - we'll get a clear error if a PR already exists
+ console.log(`Failed to check for existing PR: ${e}`)
+ }
+
+ const pr = await withRetry(() =>
+ octoRest.rest.pulls.create({
+ owner,
+ repo,
+ head: branch,
+ base,
+ title,
+ body,
+ }),
+ )
return pr.data.number
}
+ async function withRetry<T>(fn: () => Promise<T>, retries = 1, delayMs = 5000): Promise<T> {
+ try {
+ return await fn()
+ } catch (e) {
+ if (retries > 0) {
+ console.log(`Retrying after ${delayMs}ms...`)
+ await Bun.sleep(delayMs)
+ return withRetry(fn, retries - 1, delayMs)
+ }
+ throw e
+ }
+ }
+
function footer(opts?: { image?: boolean }) {
const image = (() => {
if (!shareId) return ""