From 3ba1111ed047ca4cc42bc964ae23c32959c0e8fd Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Wed, 21 Jan 2026 13:23:45 -0600 Subject: fix(app): terminal issues/regression --- .../session/session-sortable-terminal-tab.tsx | 29 ++++++++++++++++++---- packages/app/src/components/terminal.tsx | 7 +++++- 2 files changed, 30 insertions(+), 6 deletions(-) (limited to 'packages/app/src/components') diff --git a/packages/app/src/components/session/session-sortable-terminal-tab.tsx b/packages/app/src/components/session/session-sortable-terminal-tab.tsx index 539195553..2c661edf8 100644 --- a/packages/app/src/components/session/session-sortable-terminal-tab.tsx +++ b/packages/app/src/components/session/session-sortable-terminal-tab.tsx @@ -18,12 +18,22 @@ export function SortableTerminalTab(props: { terminal: LocalPTY; onClose?: () => const [menuPosition, setMenuPosition] = createSignal({ x: 0, y: 0 }) const [blurEnabled, setBlurEnabled] = createSignal(false) + const isDefaultTitle = () => { + const number = props.terminal.titleNumber + if (!Number.isFinite(number) || number <= 0) return false + const match = props.terminal.title.match(/^Terminal (\d+)$/) + if (!match) return false + const parsed = Number(match[1]) + if (!Number.isFinite(parsed) || parsed <= 0) return false + return parsed === number + } + const label = () => { language.locale() + if (props.terminal.title && !isDefaultTitle()) return props.terminal.title + const number = props.terminal.titleNumber - if (Number.isFinite(number) && number > 0) { - return language.t("terminal.title.numbered", { number }) - } + if (Number.isFinite(number) && number > 0) return language.t("terminal.title.numbered", { number }) if (props.terminal.title) return props.terminal.title return language.t("terminal.title") } @@ -102,8 +112,15 @@ export function SortableTerminalTab(props: { terminal: LocalPTY; onClose?: () => } return ( - // @ts-ignore -
+
onClick={focus} onMouseDown={(e) => e.preventDefault()} onContextMenu={menu} + class="!shadow-none" + classes={{ button: "outline-none focus:outline-none focus-visible:outline-none !shadow-none !ring-0" }} closeButton={ { pty: LocalPTY onSubmit?: () => void onCleanup?: (pty: LocalPTY) => void + onConnect?: () => void onConnectError?: (error: unknown) => void } @@ -40,7 +41,7 @@ export const Terminal = (props: TerminalProps) => { const settings = useSettings() const theme = useTheme() let container!: HTMLDivElement - const [local, others] = splitProps(props, ["pty", "class", "classList", "onConnectError"]) + const [local, others] = splitProps(props, ["pty", "class", "classList", "onConnect", "onConnectError"]) let ws: WebSocket | undefined let term: Term | undefined let ghostty: Ghostty @@ -241,6 +242,7 @@ export const Terminal = (props: TerminalProps) => { // console.log("Scroll position:", ydisp) // }) socket.addEventListener("open", () => { + local.onConnect?.() sdk.client.pty .update({ ptyID: local.pty.id, @@ -255,10 +257,12 @@ export const Terminal = (props: TerminalProps) => { t.write(event.data) }) socket.addEventListener("error", (error) => { + if (disposed) return console.error("WebSocket error:", error) local.onConnectError?.(error) }) socket.addEventListener("close", (event) => { + if (disposed) return // Normal closure (code 1000) means PTY process exited - server event handles cleanup // For other codes (network issues, server restart), trigger error handler if (event.code !== 1000) { @@ -268,6 +272,7 @@ export const Terminal = (props: TerminalProps) => { }) onCleanup(() => { + disposed = true if (handleResize) { window.removeEventListener("resize", handleResize) } -- cgit v1.2.3