chore: address copilot comments

This commit is contained in:
Austin Pickett 2026-04-24 12:51:04 -04:00
parent 5500b51800
commit 850fac14e3
8 changed files with 87 additions and 31 deletions

View file

@ -87,6 +87,7 @@ export function ChatSidebar({ channel, className }: ChatSidebarProps) {
const [error, setError] = useState<string | null>(null);
useEffect(() => {
let cancelled = false;
const offState = gw.onState(setState);
const offSessionInfo = gw.on<SessionInfo>("session.info", (ev) => {
@ -111,15 +112,26 @@ export function ChatSidebar({ channel, className }: ChatSidebarProps) {
// sidecar is independent of the PTY pane's session by design — we
// only need a sid to drive the model picker's slash.exec calls.
gw.connect()
.then(() => gw.request<{ session_id: string }>("session.create", {}))
.then((created) => {
if (created?.session_id) {
setSessionId(created.session_id);
.then(() => {
if (cancelled) {
return;
}
return gw.request<{ session_id: string }>("session.create", {});
})
.catch((e: Error) => setError(e.message));
.then((created) => {
if (cancelled || !created?.session_id) {
return;
}
setSessionId(created.session_id);
})
.catch((e: Error) => {
if (!cancelled) {
setError(e.message);
}
});
return () => {
cancelled = true;
offState();
offSessionInfo();
offError();

View file

@ -138,7 +138,7 @@ export function ModelPickerDialog({ gw, sessionId, onClose, onSubmit }: Props) {
return (
<div
className="fixed inset-0 z-100 flex items-center justify-center bg-background/85 backdrop-blur-sm p-4"
className="fixed inset-0 z-[100] flex items-center justify-center bg-background/85 backdrop-blur-sm p-4"
onClick={(e) => e.target === e.currentTarget && onClose()}
role="dialog"
aria-modal="true"

View file

@ -443,6 +443,10 @@ export default function ChatPage() {
const ws = new WebSocket(url);
ws.binaryType = "arraybuffer";
wsRef.current = ws;
// Suppress banner/terminal side-effects when cleanup() calls `ws.close()`
// (React StrictMode remount, route change) so we never write to a
// disposed xterm or setState on an unmounted tree.
let unmounting = false;
ws.onopen = () => {
setBanner(null);
@ -463,6 +467,9 @@ export default function ChatPage() {
ws.onclose = (ev) => {
wsRef.current = null;
if (unmounting) {
return;
}
if (ev.code === 4401) {
setBanner("Auth failed. Reload the page to refresh the session token.");
return;
@ -539,6 +546,7 @@ export default function ChatPage() {
term.focus();
return () => {
unmounting = true;
onDataDisposable.dispose();
onResizeDisposable.dispose();
if (metricsDebounce) clearTimeout(metricsDebounce);