From a9bd96f8b0233e1367be781c5b47360c6a9eb831 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: Thu, 14 May 2026 23:02:15 +0800 Subject: [PATCH] fix: keep empty-session launch controls visually attached The active empty-session composer used the same launch controls as the new-session surface but rendered them outside the glass panel, creating an inconsistent gap between the prompt box and project/branch/worktree selectors. Embed the desktop hero launch row in the composer panel and keep the existing mobile and post-message context-chip paths unchanged. Constraint: Preserve the existing new-session composer layout and shared RepositoryLaunchControls behavior. Rejected: Adjust outer margins only | would keep the active empty-session DOM structurally different from the already-correct new-session composer. Confidence: high Scope-risk: narrow Tested: cd desktop && bun run test -- src/components/chat/ChatInput.test.tsx src/pages/EmptySession.test.tsx Tested: cd desktop && bun run lint Tested: git diff --check Tested: agent-browser DOM check confirmed the launch row is inside chat-input-panel with 1px bottom gap Not-tested: Full bun run verify gate --- .../src/components/chat/ChatInput.test.tsx | 7 +++++++ desktop/src/components/chat/ChatInput.tsx | 21 +++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/desktop/src/components/chat/ChatInput.test.tsx b/desktop/src/components/chat/ChatInput.test.tsx index cd9953e2..869c2990 100644 --- a/desktop/src/components/chat/ChatInput.test.tsx +++ b/desktop/src/components/chat/ChatInput.test.tsx @@ -320,9 +320,16 @@ describe('ChatInput file mentions', () => { render() + const panel = screen.getByTestId('chat-input-panel') + expect(panel).toHaveClass('rounded-xl') + expect(panel).not.toHaveClass('rounded-b-none') + expect(await screen.findByRole('button', { name: /Select branch: main/ })).toBeInTheDocument() expect(screen.getByText('Current worktree')).toBeInTheDocument() expect(screen.queryByText('Select a project...')).not.toBeInTheDocument() + const branchButton = screen.getByRole('button', { name: /Select branch: main/ }) + expect(panel).toContainElement(branchButton.parentElement) + expect(branchButton.parentElement).toHaveClass('bg-transparent') }) it('uses the persisted message count to keep reopened sessions in context mode while history loads', async () => { diff --git a/desktop/src/components/chat/ChatInput.tsx b/desktop/src/components/chat/ChatInput.tsx index 1e74add3..eecfccf9 100644 --- a/desktop/src/components/chat/ChatInput.tsx +++ b/desktop/src/components/chat/ChatInput.tsx @@ -151,6 +151,7 @@ export function ChatInput({ variant = 'default', compact = false }: ChatInputPro const useCompactControls = compact || isMobileComposer const iconOnlyAction = compact || isMobileComposer const activeLaunchWorkDir = showLaunchControls ? (launchWorkDir || resolvedWorkDir || '') : (resolvedWorkDir || '') + const embedLaunchControlsInHero = isHeroComposer && !useCompactControls && showLaunchControls const pendingSlashUiAction = !isMemberSession && input.trim().startsWith('/') ? resolveSlashUiAction(input.trim().slice(1)) : null @@ -802,7 +803,7 @@ export function ChatInput({ variant = 'default', compact = false }: ChatInputPro
+ + {embedLaunchControlsInHero && ( +
+ +
+ )} - {!isMemberSession && ( + {!isMemberSession && !embedLaunchControlsInHero && (
{messageCount > 0 ? (