diff --git a/frontend/src/lib/components/sessions/SessionWrapper.svelte b/frontend/src/lib/components/sessions/SessionWrapper.svelte index c2e8d1d92d..4f94dc2888 100644 --- a/frontend/src/lib/components/sessions/SessionWrapper.svelte +++ b/frontend/src/lib/components/sessions/SessionWrapper.svelte @@ -28,6 +28,7 @@ import SessionWorkspaceBar from './SessionWorkspaceBar.svelte' import SessionChangesBar from './SessionChangesBar.svelte' import { + composerFocusRequest, createSession, deleteSessionsForWorkspace, getEffectiveWorkspaceId, @@ -232,6 +233,11 @@ // loading. let aiChat: AIChat | undefined = $state(undefined) $effect(() => { + // Focus the composer when this session becomes active, or on an explicit + // focus request — the latter covers `+` reusing the untouched draft you're + // already viewing, where currentSessionId doesn't change so activation alone + // wouldn't re-run this. + void composerFocusRequest.nonce if (sessionState.currentSessionId !== sessionId) return if (!aiChat) return if (!$copilotInfo.enabled) return diff --git a/frontend/src/lib/components/sessions/sessionState.svelte.ts b/frontend/src/lib/components/sessions/sessionState.svelte.ts index 1edd938de0..d7e169886d 100644 --- a/frontend/src/lib/components/sessions/sessionState.svelte.ts +++ b/frontend/src/lib/components/sessions/sessionState.svelte.ts @@ -611,6 +611,16 @@ export function findSessionByName(name: string): Session | undefined { return sessionState.sessions.find((s) => s.name === name) } +// Bumped to ask the active session's composer to re-focus even when +// `currentSessionId` doesn't change — the `+` reuse path lands you back on the +// untouched draft you're already viewing, so nothing navigates, but the click +// should still drop the cursor in the composer. SessionWrapper's focus effect +// depends on `nonce`. +export const composerFocusRequest = $state<{ nonce: number }>({ nonce: 0 }) +export function requestComposerFocus(): void { + composerFocusRequest.nonce++ +} + export function createSession(): Session { // Reuse an existing untouched draft from the active family rather than pile a // blank entry on every `+`. "Untouched" is exactly `transient`: a pending @@ -622,6 +632,9 @@ export function createSession(): Session { const reusable = sessionState.sessions.find((s) => s.transient && sessionInCurrentFamily(s)) if (reusable) { sessionState.currentSessionId = reusable.id + // Reusing an already-active draft doesn't change currentSessionId, so ask + // the composer to focus explicitly — the caller still navigates/redirects. + requestComposerFocus() return reusable } sessionState.sessions = sessionState.sessions.filter((s) => !s.transient)