From 89ec7d66c9e875ccb1a012e6904486e6efa6a92f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E5=91=98=E9=98=BF=E6=B1=9F=28Relakkes?= =?UTF-8?q?=29?= Date: Sat, 23 May 2026 16:16:30 +0800 Subject: [PATCH] fix: hide internal worktree branch labels Desktop worktree sessions should show the source project and worktree marker without surfacing implementation refs like worktree-desktop-* as user-facing branch state. The git-info response now keeps launch branch metadata separate from worktree identity, and the desktop chip hides branch and slug labels in isolated worktree mode. Constraint: Git worktrees need an internal branch for isolated execution, but that ref is product plumbing rather than useful UI context Rejected: Show both launch branch and worktree slug | duplicated noisy identifiers and confused the session location Confidence: high Scope-risk: narrow Tested: bun test src/server/__tests__/sessions.test.ts -t "git-info"; cd desktop && bun run test src/components/shared/ProjectContextChip.test.tsx; bun run check:server; bun run check:desktop; git diff --check Not-tested: Live desktop screenshot smoke --- .../components/shared/ProjectContextChip.test.tsx | 6 +++--- desktop/src/components/shared/ProjectContextChip.tsx | 6 +++--- src/server/__tests__/sessions.test.ts | 12 ++++++------ src/server/api/sessions.ts | 8 +++++--- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/desktop/src/components/shared/ProjectContextChip.test.tsx b/desktop/src/components/shared/ProjectContextChip.test.tsx index d5ff758c..68be5c39 100644 --- a/desktop/src/components/shared/ProjectContextChip.test.tsx +++ b/desktop/src/components/shared/ProjectContextChip.test.tsx @@ -4,7 +4,7 @@ import '@testing-library/jest-dom' import { ProjectContextChip } from './ProjectContextChip' describe('ProjectContextChip', () => { - it('keeps the source project label and adds worktree identity', () => { + it('shows only the source project label and worktree marker for isolated worktrees', () => { render( { ) expect(screen.getByText('OpenCutSkill')).toBeInTheDocument() - expect(screen.getByText('main')).toBeInTheDocument() expect(screen.getByText('worktree')).toBeInTheDocument() - expect(screen.getByText('desktop-main-54a09f85')).toBeInTheDocument() + expect(screen.queryByText('main')).not.toBeInTheDocument() + expect(screen.queryByText('desktop-main-54a09f85')).not.toBeInTheDocument() }) it('does not show worktree details for a normal checkout', () => { diff --git a/desktop/src/components/shared/ProjectContextChip.tsx b/desktop/src/components/shared/ProjectContextChip.tsx index 1cc58a5a..8eb4a708 100644 --- a/desktop/src/components/shared/ProjectContextChip.tsx +++ b/desktop/src/components/shared/ProjectContextChip.tsx @@ -26,6 +26,7 @@ export function ProjectContextChip({ const labelRoot = isWorktree ? (sourceWorkDir || workDir) : workDir const label = branch ? (repoName || basename(labelRoot)) : (basename(labelRoot) || repoName || '') const worktreeName = worktreeSlug || basename(worktreePath) || 'isolated' + const showBranch = !!branch && !isWorktree const title = [ label, branch ? `branch: ${branch}` : null, @@ -43,7 +44,7 @@ export function ProjectContextChip({ compact ? 'gap-1.5 px-3 py-1.5 text-xs' : 'gap-2 px-4 py-2 text-sm' }`} > - {branch ? ( + {showBranch ? ( @@ -51,7 +52,7 @@ export function ProjectContextChip({ folder )} {label} - {branch ? ( + {showBranch ? ( <> | {branch} @@ -63,7 +64,6 @@ export function ProjectContextChip({ worktree - {worktreeName} ) : null} diff --git a/src/server/__tests__/sessions.test.ts b/src/server/__tests__/sessions.test.ts index cfb77ba1..0b8e419d 100644 --- a/src/server/__tests__/sessions.test.ts +++ b/src/server/__tests__/sessions.test.ts @@ -1990,11 +1990,11 @@ describe('Sessions API', () => { } }) - it('GET /api/sessions/:id/git-info should include isolated worktree identity', async () => { + it('GET /api/sessions/:id/git-info should keep the visible launch branch while including isolated worktree identity', async () => { const workDir = await createCleanGitRepo(tmpDir) const { sessionId } = await sessionService.createSession( workDir, - { branch: 'main', worktree: true }, + { branch: 'feature/rail', worktree: true }, ) const launchInfo = await sessionService.getSessionLaunchInfo(sessionId) const repository = launchInfo?.repository @@ -2002,7 +2002,7 @@ describe('Sessions API', () => { expect(repository?.worktreeBranch).toBeTruthy() const activeWorktree = repository!.worktreePath! - git(workDir, 'worktree', 'add', '-b', repository!.worktreeBranch!, activeWorktree, 'main') + git(workDir, 'worktree', 'add', '-b', repository!.worktreeBranch!, activeWorktree, 'feature/rail') const sessionsMap = (conversationService as any).sessions as Map sessionsMap.set(sessionId, { workDir: activeWorktree }) @@ -2022,7 +2022,7 @@ describe('Sessions API', () => { branch: string | null } | null } - expect(body.branch).toBe(repository!.worktreeBranch) + expect(body.branch).toBe('feature/rail') expect(body.workDir).toBe(activeWorktree) expect(body.worktree).toEqual({ enabled: true, @@ -2067,7 +2067,7 @@ describe('Sessions API', () => { branch: string | null } | null } - expect(body.branch).toBe('worktree-desktop-main-12345678') + expect(body.branch).toBe('main') expect(body.workDir).toBe(activeWorktree) expect(body.worktree).toEqual({ enabled: true, @@ -2121,7 +2121,7 @@ describe('Sessions API', () => { branch: string | null } | null } - expect(body.branch).toBe('worktree-desktop-main-12345678') + expect(body.branch).toBe('main') expect(body.worktree).toMatchObject({ path: activeWorktree, plannedPath: activeWorktree, diff --git a/src/server/api/sessions.ts b/src/server/api/sessions.ts index e404d1fe..b71acc4e 100644 --- a/src/server/api/sessions.ts +++ b/src/server/api/sessions.ts @@ -670,9 +670,11 @@ async function getGitInfo(sessionId: string): Promise { sameResolvedPath(workDir, worktree.path) || sameResolvedPath(workDir, worktree.plannedPath) ) - const branch = materializedWorktree - ? (gitBranch || worktree.branch || sessionBranch) - : (sessionBranch || gitBranch) + const branch = sessionBranch || ( + materializedWorktree + ? (worktree.branch || gitBranch) + : gitBranch + ) // Get repo name from remote or directory let repoName = ''