From c9e9dbeee1ceb5af3d1b1ce292317390286fe7a0 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Fri, 13 Mar 2026 08:56:48 -0500 Subject: fix(app): terminal cloning without retry (#17354) --- packages/app/src/testing/terminal.ts | 63 +++++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 15 deletions(-) (limited to 'packages/app/src/testing/terminal.ts') diff --git a/packages/app/src/testing/terminal.ts b/packages/app/src/testing/terminal.ts index aa1974404..4c179dee3 100644 --- a/packages/app/src/testing/terminal.ts +++ b/packages/app/src/testing/terminal.ts @@ -2,21 +2,28 @@ export const terminalAttr = "data-pty-id" export type TerminalProbeState = { connected: boolean + connects: number rendered: string settled: number } +type TerminalProbeControl = { + disconnect?: VoidFunction +} + export type E2EWindow = Window & { __opencode_e2e?: { terminal?: { enabled?: boolean terminals?: Record + controls?: Record } } } const seed = (): TerminalProbeState => ({ connected: false, + connects: 0, rendered: "", settled: 0, }) @@ -25,15 +32,28 @@ const root = () => { if (typeof window === "undefined") return const state = (window as E2EWindow).__opencode_e2e?.terminal if (!state?.enabled) return + return state +} + +const terms = () => { + const state = root() + if (!state) return state.terminals ??= {} return state.terminals } +const controls = () => { + const state = root() + if (!state) return + state.controls ??= {} + return state.controls +} + export const terminalProbe = (id: string) => { const set = (next: Partial) => { - const terms = root() - if (!terms) return - terms[id] = { ...(terms[id] ?? seed()), ...next } + const state = terms() + if (!state) return + state[id] = { ...(state[id] ?? seed()), ...next } } return { @@ -41,24 +61,37 @@ export const terminalProbe = (id: string) => { set(seed()) }, connect() { - set({ connected: true }) + const state = terms() + if (!state) return + const prev = state[id] ?? seed() + state[id] = { + ...prev, + connected: true, + connects: prev.connects + 1, + } }, render(data: string) { - const terms = root() - if (!terms) return - const prev = terms[id] ?? seed() - terms[id] = { ...prev, rendered: prev.rendered + data } + const state = terms() + if (!state) return + const prev = state[id] ?? seed() + state[id] = { ...prev, rendered: prev.rendered + data } }, settle() { - const terms = root() - if (!terms) return - const prev = terms[id] ?? seed() - terms[id] = { ...prev, settled: prev.settled + 1 } + const state = terms() + if (!state) return + const prev = state[id] ?? seed() + state[id] = { ...prev, settled: prev.settled + 1 } + }, + control(next: Partial) { + const state = controls() + if (!state) return + state[id] = { ...(state[id] ?? {}), ...next } }, drop() { - const terms = root() - if (!terms) return - delete terms[id] + const state = terms() + if (state) delete state[id] + const control = controls() + if (control) delete control[id] }, } } -- cgit v1.2.3