diff --git a/packages/web/src/components/DirectTerminal.tsx b/packages/web/src/components/DirectTerminal.tsx index afa6cba6e..c18f4a370 100644 --- a/packages/web/src/components/DirectTerminal.tsx +++ b/packages/web/src/components/DirectTerminal.tsx @@ -482,17 +482,23 @@ export function DirectTerminal({ const statusDotClass = displayStatus === "connected" ? "bg-[var(--color-status-ready)]" - : displayStatus === "error" + : displayStatus === "error" || displayStatus === "disconnected" ? "bg-[var(--color-status-error)]" : "bg-[var(--color-status-attention)] animate-[pulse_1.5s_ease-in-out_infinite]"; const statusText = - displayStatus === "connected" ? "Connected" : displayStatus === "error" ? (error ?? "Error") : "Connecting…"; + displayStatus === "connected" + ? "Connected" + : displayStatus === "error" + ? (error ?? "Error") + : displayStatus === "disconnected" + ? "Disconnected" + : "Connecting…"; const statusTextColor = displayStatus === "connected" ? "text-[var(--color-status-ready)]" - : displayStatus === "error" + : displayStatus === "error" || displayStatus === "disconnected" ? "text-[var(--color-status-error)]" : "text-[var(--color-text-tertiary)]"; diff --git a/packages/web/src/hooks/useSessionEvents.ts b/packages/web/src/hooks/useSessionEvents.ts index a90011aba..b1c8f8719 100644 --- a/packages/web/src/hooks/useSessionEvents.ts +++ b/packages/web/src/hooks/useSessionEvents.ts @@ -233,11 +233,14 @@ export function useSessionEvents( if (muxActive) { dispatch({ type: "setConnection", status: "connected" }); return () => { - // Clear any pending refresh timer so it doesn't fire after unmount + // Clear timer and reset all refresh state so the aborted fetch's + // .finally() handler doesn't reschedule after unmount. if (refreshTimerRef.current) { clearTimeout(refreshTimerRef.current); refreshTimerRef.current = null; } + pendingMembershipKeyRef.current = null; + refreshingRef.current = false; activeRefreshControllerRef.current?.abort(); activeRefreshControllerRef.current = null; };