diff --git a/packages/app-bundle/overlay/packages/app/src/pages/session/composer/session-bug-dock.tsx b/packages/app-bundle/overlay/packages/app/src/pages/session/composer/session-bug-dock.tsx index b255dfd8..2da0e315 100644 --- a/packages/app-bundle/overlay/packages/app/src/pages/session/composer/session-bug-dock.tsx +++ b/packages/app-bundle/overlay/packages/app/src/pages/session/composer/session-bug-dock.tsx @@ -292,6 +292,22 @@ export function BugDockView(props: { }) { const [store, setStore] = createStore({ height: HEADER_HEIGHT + 120 }) let contentRef: HTMLDivElement | undefined + let textareaRef: HTMLTextAreaElement | undefined + let wasFocused = false + let blurTimer: number | undefined + + // Preserve focus across background diagnostics completion (amicode#478): + // the bug session flips busy and agentText appears while the user may be + // mid-typing. A reactive border/text update must not steal focus. The blur + // timer keeps wasFocused true through the synchronous blur that fires during + // the DOM patch so the deferred effect still sees it. + const restoreFocusIfNeeded = () => { + if (wasFocused && textareaRef && document.activeElement !== textareaRef) { + requestAnimationFrame(() => textareaRef?.focus()) + } + } + createEffect(on(() => props.busy, restoreFocusIfNeeded, { defer: true })) + createEffect(on(() => props.agentText, restoreFocusIfNeeded, { defer: true })) // The dock family's animated max-height idiom (the todo dock's shape): // measure the collapse-independent content, spring between full and header. @@ -457,15 +473,22 @@ export function BugDockView(props: {