mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-16 13:03:31 +08:00
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
This commit is contained in:
parent
5f3da46354
commit
89ec7d66c9
@ -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(
|
||||
<ProjectContextChip
|
||||
workDir="/workspace/OpenCutSkill/.claude/worktrees/desktop-main-54a09f85"
|
||||
@ -17,9 +17,9 @@ describe('ProjectContextChip', () => {
|
||||
)
|
||||
|
||||
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', () => {
|
||||
|
||||
@ -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 ? (
|
||||
<svg width={compact ? 15 : 18} height={compact ? 15 : 18} viewBox="0 0 16 16" fill="currentColor" className="shrink-0 text-[var(--color-text-secondary)]">
|
||||
<path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z" />
|
||||
</svg>
|
||||
@ -51,7 +52,7 @@ export function ProjectContextChip({
|
||||
<span className={`material-symbols-outlined text-[var(--color-text-secondary)] ${compact ? 'text-[15px]' : 'text-[18px]'}`}>folder</span>
|
||||
)}
|
||||
<span className="truncate font-medium text-[var(--color-text-primary)]">{label}</span>
|
||||
{branch ? (
|
||||
{showBranch ? (
|
||||
<>
|
||||
<span className="text-[var(--color-text-tertiary)]">|</span>
|
||||
<span className="truncate">{branch}</span>
|
||||
@ -63,7 +64,6 @@ export function ProjectContextChip({
|
||||
<span className="shrink-0 rounded-full border border-[var(--color-border)] px-1.5 py-0.5 text-[10px] font-medium uppercase leading-none text-[var(--color-text-tertiary)]">
|
||||
worktree
|
||||
</span>
|
||||
<span className="max-w-[12rem] truncate">{worktreeName}</span>
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
@ -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<string, { workDir: string }>
|
||||
|
||||
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,
|
||||
|
||||
@ -670,9 +670,11 @@ async function getGitInfo(sessionId: string): Promise<Response> {
|
||||
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 = ''
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user