diff --git a/src/server/__tests__/sessions.test.ts b/src/server/__tests__/sessions.test.ts index 83ec1bb1..0ed43cb5 100644 --- a/src/server/__tests__/sessions.test.ts +++ b/src/server/__tests__/sessions.test.ts @@ -1677,6 +1677,58 @@ describe('Sessions API', () => { }) }) + it('GET /api/sessions/:id/git-info should prefer CLI worktree-state identity over desktop metadata', async () => { + const workDir = await createCleanGitRepo(tmpDir) + const sessionId = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee' + const activeWorktree = path.join(workDir, '.claude', 'worktrees', 'desktop-main-12345678') + git(workDir, 'worktree', 'add', '-b', 'worktree-desktop-main-12345678', activeWorktree, 'main') + await writeSessionFile(sanitizePath(activeWorktree), sessionId, [ + makeSnapshotEntry(), + { + type: 'session-meta', + isMeta: true, + workDir: activeWorktree, + repository: { + requestedWorkDir: '/stale/source', + repoRoot: '/stale/source', + branch: 'main', + worktree: true, + baseRef: 'main', + worktreePath: '/stale/source/.claude/worktrees/stale', + worktreeBranch: 'worktree-stale', + worktreeSlug: 'stale', + }, + timestamp: '2026-01-01T00:00:00.000Z', + }, + makeWorktreeStateEntry(sessionId, activeWorktree, { + originalCwd: await fs.realpath(workDir), + }), + makeUserEntry('Hello from persisted worktree state'), + ]) + + const res = await fetch(`${baseUrl}/api/sessions/${sessionId}/git-info`) + expect(res.status).toBe(200) + + const body = (await res.json()) as { + branch: string | null + worktree: { + path: string | null + plannedPath: string | null + sourceWorkDir: string | null + slug: string | null + branch: string | null + } | null + } + expect(body.branch).toBe('main') + expect(body.worktree).toMatchObject({ + path: activeWorktree, + plannedPath: activeWorktree, + sourceWorkDir: await fs.realpath(workDir), + slug: 'desktop-main-12345678', + branch: 'worktree-desktop-main-12345678', + }) + }) + it('DELETE /api/sessions/:id should delete the session', async () => { const sessionId = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee' await writeSessionFile('-tmp-api-test', sessionId, [makeSnapshotEntry()]) diff --git a/src/server/api/sessions.ts b/src/server/api/sessions.ts index 8eb82fd7..fdb1f169 100644 --- a/src/server/api/sessions.ts +++ b/src/server/api/sessions.ts @@ -541,15 +541,18 @@ async function getGitInfo(sessionId: string): Promise { const launchInfo = await sessionService.getSessionLaunchInfo(sessionId).catch(() => null) const repository = launchInfo?.repository const worktreeSession = launchInfo?.worktreeSession + // The visible business branch comes from Desktop's launch choice when present. + // CLI originalBranch is the source checkout before creating the worktree, which + // can differ from the selected base ref. const sessionBranch = repository?.branch || worktreeSession?.originalBranch || null const worktree = repository?.worktree || worktreeSession ? { enabled: true, path: worktreeSession?.worktreePath || workDir, - plannedPath: repository?.worktreePath || worktreeSession?.worktreePath || null, - sourceWorkDir: repository?.requestedWorkDir || repository?.repoRoot || worktreeSession?.originalCwd || null, - slug: repository?.worktreeSlug || worktreeSession?.worktreeName || null, - branch: repository?.worktreeBranch || worktreeSession?.worktreeBranch || null, + plannedPath: worktreeSession?.worktreePath || repository?.worktreePath || null, + sourceWorkDir: worktreeSession?.originalCwd || repository?.requestedWorkDir || repository?.repoRoot || null, + slug: worktreeSession?.worktreeName || repository?.worktreeSlug || null, + branch: worktreeSession?.worktreeBranch || repository?.worktreeBranch || null, } : null