diff --git a/apps/desktop/src/renderer/lib/terminal/terminal-ws-transport.ts b/apps/desktop/src/renderer/lib/terminal/terminal-ws-transport.ts index 45cc89079a9..a5d4fa5f5a0 100644 --- a/apps/desktop/src/renderer/lib/terminal/terminal-ws-transport.ts +++ b/apps/desktop/src/renderer/lib/terminal/terminal-ws-transport.ts @@ -119,6 +119,22 @@ function cancelReconnect(transport: TerminalTransport) { } } +function formatWsEndpoint(wsUrl: string | null): string { + if (!wsUrl) return "unknown endpoint"; + try { + const url = new URL(wsUrl); + return `${url.protocol}//${url.host}${url.pathname}`; + } catch { + return "invalid terminal WebSocket URL"; + } +} + +function formatCloseDetails(event: CloseEvent): string { + const code = event.code || "unknown"; + const reason = event.reason ? `, reason: ${event.reason}` : ""; + return `code: ${code}${reason}`; +} + export function connect( transport: TerminalTransport, terminal: XTerm, @@ -245,7 +261,7 @@ export function connect( } }); - socket.addEventListener("close", () => { + socket.addEventListener("close", (event) => { if (transport.socket !== socket) return; terminalRendererDebug.warn( "ws-close", @@ -261,12 +277,23 @@ export function connect( ); setConnectionState(transport, "closed"); transport.socket = null; + if (!transport._exited && event.code !== 1000) { + const willReconnect = + !transport._reconnectTimer && + Boolean(transport.currentUrl && transport._terminal) && + transport._reconnectAttempt < MAX_RECONNECT_ATTEMPTS; + terminal.writeln( + `\r\n[terminal] WebSocket closed while connected to ${formatWsEndpoint(transport.currentUrl)} (${formatCloseDetails(event)}). ${willReconnect ? "Reconnecting..." : "Max reconnect attempts reached."}`, + ); + } // Auto-reconnect on unexpected close (host-service restart, network blip) scheduleReconnect(transport); }); socket.addEventListener("error", () => { if (transport.socket !== socket) return; + // FORK NOTE: keep Sentry debug capture (terminalRendererDebug.error) + // alongside upstream's user-facing detailed diagnostic message. terminalRendererDebug.error( "ws-error", { terminalId: transport.debugId }, @@ -275,7 +302,9 @@ export function connect( fingerprint: ["terminal.renderer", "ws-error"], }, ); - terminal.writeln("\r\n[terminal] websocket error"); + terminal.writeln( + `\r\n[terminal] WebSocket error while connecting to ${formatWsEndpoint(transport.currentUrl)}. Check host-service or relay connectivity.`, + ); }); transport.onDataDisposable?.dispose(); diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/TerminalPane/TerminalPane.tsx b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/TerminalPane/TerminalPane.tsx index 2b9038b39cb..602b8f5b920 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/TerminalPane/TerminalPane.tsx +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/TerminalPane/TerminalPane.tsx @@ -177,10 +177,27 @@ export function TerminalPane({ void invalidateTerminalSessionsRef.current({ workspaceId: sessionWorkspaceId, }); + return; } + if (cancelled) return; + const details = result.error + ? `: ${result.error}` + : " for an unknown reason"; + terminalRuntimeRegistry + .getTerminal(terminalId, terminalInstanceId) + ?.writeln( + `\r\n[terminal] Failed to create terminal session${details}`, + ); }) .catch((err) => { console.error("[TerminalPane] ensureSession failed:", err); + if (cancelled) return; + const message = err instanceof Error ? err.message : String(err); + terminalRuntimeRegistry + .getTerminal(terminalId, terminalInstanceId) + ?.writeln( + `\r\n[terminal] terminal.ensureSession request failed: ${message}`, + ); }) .finally(() => { if (cancelled) return; diff --git a/packages/host-service/src/terminal/terminal.ts b/packages/host-service/src/terminal/terminal.ts index 00dd3565b72..cf44c550440 100644 --- a/packages/host-service/src/terminal/terminal.ts +++ b/packages/host-service/src/terminal/terminal.ts @@ -610,10 +610,9 @@ export function registerWorkspaceTerminalRoute({ if (!workspaceId) { sendMessage(ws, { type: "error", - message: - "Session not found. Call terminal.ensureSession first.", + message: `Terminal session "${terminalId}" not found; use terminal.ensureSession or workspaceId.`, }); - ws.close(1011, "Session not found"); + ws.close(1011, "Terminal session not found"); return; }