From 6c9468e0832dbfc553242243c6fbaa291a287aaf Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Wed, 4 Nov 2026 08:07:18 +0100 Subject: [PATCH] fix(server): a branch the caller named is not renamed from the first agent context The daemon marked every new branch-off worktree for automatic naming, recording the chosen branch as the placeholder, so the first agent's prompt could rename a branch a plugin or client had named through branchName. Only a branch the daemon derived from the worktree slug is a placeholder now. --- .../src/server/paseo-worktree-service.test.ts | 34 +++++++++++++++++++ .../src/server/paseo-worktree-service.ts | 9 +++-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/packages/server/src/server/paseo-worktree-service.test.ts b/packages/server/src/server/paseo-worktree-service.test.ts index 1579f92d5f..47778b63db 100644 --- a/packages/server/src/server/paseo-worktree-service.test.ts +++ b/packages/server/src/server/paseo-worktree-service.test.ts @@ -675,6 +675,40 @@ test("renames the branch even when the app supplies a random placeholder slug", expect(branchAfter).toBe("renamed-from-prompt"); }); +test("keeps a branch the caller named instead of renaming it from the first agent context", async () => { + const { repoDir, tempDir } = createGitRepo(); + cleanupPaths.push(tempDir); + + const created = await createPaseoWorktree( + { + cwd: repoDir, + worktreeSlug: "dazzling-yak", + branchName: "pas-101-slow-sidebar", + firstAgentContext: { prompt: "Investigate the failing login flow" }, + + paseoHome: path.join(tempDir, ".paseo"), + }, + createDeps(), + ); + + expect(created.worktree.branchName).toBe("pas-101-slow-sidebar"); + await expect( + attemptFirstAgentBranchAutoName({ + cwd: created.worktree.worktreePath, + firstAgentContext: { prompt: "Investigate the failing login flow" }, + generateBranchNameFromContext: async () => "must-not-rename", + }), + ).resolves.toEqual({ attempted: false, renamed: false, branchName: null }); + expect( + execFileSync("git", ["branch", "--show-current"], { + cwd: created.worktree.worktreePath, + stdio: "pipe", + }) + .toString() + .trim(), + ).toBe("pas-101-slow-sidebar"); +}); + test("renames the branch from a github_pr attachment when no prompt is supplied", async () => { const { repoDir, tempDir } = createGitRepo(); cleanupPaths.push(tempDir); diff --git a/packages/server/src/server/paseo-worktree-service.ts b/packages/server/src/server/paseo-worktree-service.ts index 322e8704ab..ff02d3fa8c 100644 --- a/packages/server/src/server/paseo-worktree-service.ts +++ b/packages/server/src/server/paseo-worktree-service.ts @@ -90,7 +90,7 @@ async function createPaseoWorktreeWithPriority( }, }); } - await maybeMarkFirstAgentBranchAutoNameEligible({ createdWorktree }); + await maybeMarkFirstAgentBranchAutoNameEligible({ createdWorktree, input }); const workspaceCwd = mapWorkspaceRelativeCwdToWorktree({ relativeWorkspaceCwd: workspaceCwdPlan.relativeWorkspaceCwd, targetWorktreePath: createdWorktree.worktree.worktreePath, @@ -280,11 +280,16 @@ async function findAvailableBranchName(options: { async function maybeMarkFirstAgentBranchAutoNameEligible(options: { createdWorktree: Awaited>; + input: Pick; }): Promise { - const { createdWorktree } = options; + const { createdWorktree, input } = options; if (!createdWorktree.created || createdWorktree.intent.kind !== "branch-off") { return; } + // A branch the caller named is their choice; only a placeholder slug is replaced. + if (input.branchName !== undefined) { + return; + } await writePaseoWorktreeFirstAgentBranchAutoNameMetadata(createdWorktree.worktree.worktreePath, { placeholderBranchName: createdWorktree.worktree.branchName,