summaryrefslogtreecommitdiffhomepage
path: root/packages/app/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/app/src')
-rw-r--r--packages/app/src/components/terminal.tsx6
-rw-r--r--packages/app/src/context/terminal.tsx1
-rw-r--r--packages/app/src/pages/session.tsx71
3 files changed, 17 insertions, 61 deletions
diff --git a/packages/app/src/components/terminal.tsx b/packages/app/src/components/terminal.tsx
index 6bedcfae2..02d561fba 100644
--- a/packages/app/src/components/terminal.tsx
+++ b/packages/app/src/components/terminal.tsx
@@ -111,6 +111,8 @@ export const Terminal = (props: TerminalProps) => {
const mod = await import("ghostty-web")
ghostty = await mod.Ghostty.load()
+ const once = { value: false }
+
const url = new URL(sdk.url + `/pty/${local.pty.id}/connect?directory=${encodeURIComponent(sdk.directory)}`)
if (window.__OPENCODE__?.serverPassword) {
url.username = "opencode"
@@ -258,6 +260,8 @@ export const Terminal = (props: TerminalProps) => {
})
socket.addEventListener("error", (error) => {
if (disposed) return
+ if (once.value) return
+ once.value = true
console.error("WebSocket error:", error)
local.onConnectError?.(error)
})
@@ -266,6 +270,8 @@ export const Terminal = (props: TerminalProps) => {
// 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) {
+ if (once.value) return
+ once.value = true
local.onConnectError?.(new Error(`WebSocket closed abnormally: ${event.code}`))
}
})
diff --git a/packages/app/src/context/terminal.tsx b/packages/app/src/context/terminal.tsx
index 147c4f8f7..72f93edc2 100644
--- a/packages/app/src/context/terminal.tsx
+++ b/packages/app/src/context/terminal.tsx
@@ -13,7 +13,6 @@ export type LocalPTY = {
cols?: number
buffer?: string
scrollY?: number
- error?: boolean
}
const WORKSPACE_KEY = "__workspace__"
diff --git a/packages/app/src/pages/session.tsx b/packages/app/src/pages/session.tsx
index d898e93dc..01368896e 100644
--- a/packages/app/src/pages/session.tsx
+++ b/packages/app/src/pages/session.tsx
@@ -2466,66 +2466,17 @@ export default function Page() {
</Tabs>
<div class="flex-1 min-h-0 relative">
<For each={terminal.all()}>
- {(pty) => {
- const [dismissed, setDismissed] = createSignal(false)
- return (
- <div
- id={`terminal-wrapper-${pty.id}`}
- class="absolute inset-0"
- style={{
- display: terminal.active() === pty.id ? "block" : "none",
- }}
- >
- <Terminal
- pty={pty}
- onCleanup={(data) => terminal.update({ ...data, id: pty.id })}
- onConnect={() => {
- terminal.update({ id: pty.id, error: false })
- setDismissed(false)
- }}
- onConnectError={() => {
- setDismissed(false)
- terminal.update({ id: pty.id, error: true })
- }}
- />
- <Show when={pty.error && !dismissed()}>
- <div
- class="absolute inset-0 flex flex-col items-center justify-center gap-3"
- style={{ "background-color": "rgba(0, 0, 0, 0.6)" }}
- >
- <Icon
- name="circle-ban-sign"
- class="w-8 h-8"
- style={{ color: "rgba(239, 68, 68, 0.8)" }}
- />
- <div class="text-center" style={{ color: "rgba(255, 255, 255, 0.7)" }}>
- <div class="text-14-semibold mb-1">{language.t("terminal.connectionLost.title")}</div>
- <div class="text-12-regular" style={{ color: "rgba(255, 255, 255, 0.5)" }}>
- {language.t("terminal.connectionLost.description")}
- </div>
- </div>
- <button
- class="mt-2 px-3 py-1.5 text-12-medium rounded-lg transition-colors"
- style={{
- "background-color": "rgba(255, 255, 255, 0.1)",
- color: "rgba(255, 255, 255, 0.7)",
- border: "1px solid rgba(255, 255, 255, 0.2)",
- }}
- onMouseEnter={(e) =>
- (e.currentTarget.style.backgroundColor = "rgba(255, 255, 255, 0.15)")
- }
- onMouseLeave={(e) =>
- (e.currentTarget.style.backgroundColor = "rgba(255, 255, 255, 0.1)")
- }
- onClick={() => setDismissed(true)}
- >
- {language.t("common.dismiss")}
- </button>
- </div>
- </Show>
- </div>
- )
- }}
+ {(pty) => (
+ <div
+ id={`terminal-wrapper-${pty.id}`}
+ class="absolute inset-0"
+ style={{
+ display: terminal.active() === pty.id ? "block" : "none",
+ }}
+ >
+ <Terminal pty={pty} onCleanup={terminal.update} onConnectError={() => terminal.clone(pty.id)} />
+ </div>
+ )}
</For>
</div>
</div>