From 5c5b0ea1417f97b2e36c9a3e4709e59f03dd8ca5 Mon Sep 17 00:00:00 2001 From: zerone0x Date: Sun, 29 Mar 2026 15:40:43 +0800 Subject: [PATCH] Regenerate PR title and body when updating an existing PR When an open PR already exists for the current branch, runPrStep previously short-circuited and returned the stale PR metadata without regenerating the title or body. This caused the original PR title to persist across subsequent pushes. Now the code always computes fresh range context and generates new PR content regardless of whether a PR exists. For existing PRs it calls editPullRequest to update the title and body on GitHub, ensuring each push produces an accurate PR description. Fixes #1487 Co-Authored-By: Claude Opus 4.6 --- apps/server/src/git/Layers/GitManager.test.ts | 21 ++++++++++++ apps/server/src/git/Layers/GitManager.ts | 33 ++++++++++++------- 2 files changed, 43 insertions(+), 11 deletions(-) diff --git a/apps/server/src/git/Layers/GitManager.test.ts b/apps/server/src/git/Layers/GitManager.test.ts index db82ea4c72..a3d72bfa29 100644 --- a/apps/server/src/git/Layers/GitManager.test.ts +++ b/apps/server/src/git/Layers/GitManager.test.ts @@ -352,6 +352,16 @@ function createGitHubCliWithFakeGh(scenario: FakeGhScenario = {}): { }); } + if (args[0] === "pr" && args[1] === "edit") { + return Effect.succeed({ + stdout: "", + stderr: "", + code: 0, + signal: null, + timedOut: false, + }); + } + if (args[0] === "repo" && args[1] === "view") { const repository = args[2]; if (typeof repository === "string" && args.includes("nameWithOwner,url,sshUrl")) { @@ -464,6 +474,17 @@ function createGitHubCliWithFakeGh(scenario: FakeGhScenario = {}): { cwd: input.cwd, args: ["pr", "checkout", input.reference, ...(input.force ? ["--force"] : [])], }).pipe(Effect.asVoid), + editPullRequest: (input) => + execute({ + cwd: input.cwd, + args: [ + "pr", + "edit", + String(input.number), + ...(input.title ? ["--title", input.title] : []), + ...(input.bodyFile ? ["--body-file", input.bodyFile] : []), + ], + }).pipe(Effect.asVoid), }, ghCalls, }; diff --git a/apps/server/src/git/Layers/GitManager.ts b/apps/server/src/git/Layers/GitManager.ts index dc082674b7..64d0ee8952 100644 --- a/apps/server/src/git/Layers/GitManager.ts +++ b/apps/server/src/git/Layers/GitManager.ts @@ -889,19 +889,9 @@ export const makeGitManager = Effect.fn("makeGitManager")(function* () { upstreamRef: details.upstreamRef, }); + const baseBranch = yield* resolveBaseBranch(cwd, branch, details.upstreamRef, headContext); const existing = yield* findOpenPr(cwd, headContext.headSelectors); - if (existing) { - return { - status: "opened_existing" as const, - url: existing.url, - number: existing.number, - baseBranch: existing.baseRefName, - headBranch: existing.headRefName, - title: existing.title, - }; - } - const baseBranch = yield* resolveBaseBranch(cwd, branch, details.upstreamRef, headContext); const rangeContext = yield* gitCore.readRangeContext(cwd, baseBranch); const generated = yield* textGeneration.generatePrContent({ @@ -922,6 +912,27 @@ export const makeGitManager = Effect.fn("makeGitManager")(function* () { gitManagerError("runPrStep", "Failed to write pull request body temp file.", cause), ), ); + + if (existing) { + yield* gitHubCli + .editPullRequest({ + cwd, + number: existing.number, + title: generated.title, + bodyFile, + }) + .pipe(Effect.ensuring(fileSystem.remove(bodyFile).pipe(Effect.catch(() => Effect.void)))); + + return { + status: "opened_existing" as const, + url: existing.url, + number: existing.number, + baseBranch: existing.baseRefName, + headBranch: existing.headRefName, + title: generated.title, + }; + } + yield* gitHubCli .createPullRequest({ cwd,