You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Web: rapidly toggling the terminal open creates duplicate terminals and leaves them unfocused #55992
Pressing the toggle-terminal shortcut repeatedly (open, close, open again in quick succession, while the first pty create request is still in flight) creates two terminal tabs instead of one. When the two create replies resolve out of order, the pending focus request ends up naming a terminal that is no longer active, so the panel opens with focus nowhere - typing does nothing until you click into the terminal input.
Plugins
None (built-in terminal extension).
OpenCode version
2.0.26 (v2 branch)
Steps to reproduce
Open a session and focus the composer.
Press the toggle terminal shortcut three times in quick succession (open / close / open) before the first terminal finishes creating.
Two "Terminal 1" tabs appear; once things settle, focus is not in the terminal and typing goes nowhere until you click the terminal input.
Thanks for the clear report! I was able to reproduce this on 2.0.26, and it still happens on the latest dev (37e3912d8).
I didn't have a browser available, so I drove the terminal code directly, with a fake server so I could control when each create request replies. Opening, closing and opening the terminal again before the first terminal is created sends two create requests, both titled "Terminal 1". When the second reply arrives before the first, you get two "Terminal 1" tabs. The active tab is the one from the first request, but the pending focus request names the other one, so neither terminal gets focus. This matches what you described.
The script below reproduces it as a bun test inside packages/gui-extensions. It passes while the bug is present.
No related issues cover this exact problem. The closest are #54559 (Ctrl+backtick not toggling the terminal on web) and #55016 (Mod+J terminal toggle).
Reproduction script (repro-55992.test.ts)
// Run: copy into packages/gui-extensions/src/terminal/ of a dev checkout, then from packages/gui-extensions:// bun install && bun test --conditions=browser src/terminal/repro-55992.test.ts// The test passes while the bug is present (asserts 2 tabs and no focus on the active terminal).// Reproduction for anomalyco/opencode#55992: open / close / open the terminal dock while the first// pty.create is in flight. Uses the real terminal model (model.ts) and the panel's auto-create and// focus-gating logic (copied from panel.tsx), with a fake server whose pty.create replies we resolve by hand.import{expect,test}from"bun:test"import{createRoot,createSignal}from"solid-js"import{createStore,produce}from"solid-js/store"import{createKeyed}from"../sdk"import{createTerminalModel}from"./model"test("#55992 rapid toggle creates duplicate terminals and leaves focus on a non-active one",async()=>{constpending: Array<{title: string;resolve: (v: {data: {id: string;title: string}})=>void}>=[]constclient={pty: {create: (input: {title: string})=>newPromise<{data: {id: string;title: string}}>((resolve)=>pending.push({title: input.title, resolve })),update: async()=>({}),remove: async()=>({}),},}constserver={id: "srv", client,data: {on: ()=>()=>{}}}conststorage={memory: (_: string,opts: {initial: unknown})=>[opts.initial],store: (_: string,opts: {initial: {all: unknown[];active?: string}})=>{const[state,setState]=createStore({value: structuredClone(opts.initial)})return{getvalue(){returnstate.value},ready: ()=>true,update: (fn: (draft: any)=>void)=>setState("value",produce(fnasany)),set: (v: any)=>setState("value",v),}},remove: ()=>{},}awaitcreateRoot(async(dispose)=>{constmodel=createTerminalModel({storage: storageasany,sessions: {list: ()=>[]}asany})constsession={server: serverasany,directory: "/proj"}constterminal=()=>model.load(session)const[opened,setOpened]=createSignal(false)// panel.tsx: while the dock shows, a workspace first observed empty gets its first terminal.createKeyed(opened,()=>{constseen={workspace: ""}createKeyed(()=>(terminal().ready() ? terminal() : undefined),(workspace)=>{if(seen.workspace===workspace.key)returnseen.workspace=workspace.keyif(workspace.all().length===0)workspace.new()},)})// Let setup effects run, then toggle: open, close, open, each as its own key press,// all before the first create replies.awaitBun.sleep(0)setOpened(true)awaitBun.sleep(0)setOpened(false)awaitBun.sleep(0)setOpened(true)awaitBun.sleep(0)console.log("pty.create calls in flight:",pending.length,pending.map((p)=>p.title))// Replies arrive out of order: the second create resolves first.pending[1]?.resolve({data: {id: "pty-B",title: pending[1].title}})awaitBun.sleep(0)pending[0]?.resolve({data: {id: "pty-A",title: pending[0].title}})awaitBun.sleep(0)constws=terminal()consttabs=ws.all().map((p)=>`${p.id}:${p.title}`)constactive=ws.active()!// panel.tsx focus gate: focus only when opened && focusRequested(active)constwillFocus=opened()&&ws.focusRequested(active)constfocusNamesOther=ws.all().some((p)=>p.id!==active&&ws.focusRequested(p.id))console.log("tabs:",tabs)console.log("active:",active,"| panel focuses active terminal:",willFocus,"| focus request names a non-active terminal:",focusNamesOther)expect(tabs.length).toBe(2)// bug: should be 1expect(willFocus).toBe(false)// bug: should be truedispose()})})
Activity
opencode-agent commentedon Oct 16, 2026
Thanks for the clear report! I was able to reproduce this on 2.0.26, and it still happens on the latest
dev(37e3912d8).I didn't have a browser available, so I drove the terminal code directly, with a fake server so I could control when each create request replies. Opening, closing and opening the terminal again before the first terminal is created sends two create requests, both titled "Terminal 1". When the second reply arrives before the first, you get two "Terminal 1" tabs. The active tab is the one from the first request, but the pending focus request names the other one, so neither terminal gets focus. This matches what you described.
The script below reproduces it as a
bun testinsidepackages/gui-extensions. It passes while the bug is present.No related issues cover this exact problem. The closest are #54559 (Ctrl+backtick not toggling the terminal on web) and #55016 (Mod+J terminal toggle).
Reproduction script (repro-55992.test.ts)
Run it:
bun repro-55992.test.ts