From 2e3a08fad2d2027cd922e7e80e586a4878b31967 Mon Sep 17 00:00:00 2001 From: arkon Date: Thu, 26 Feb 2026 13:03:28 +0100 Subject: [PATCH] fix: emit needsRefresh after OpenCode TUI stabilizes After the 3s TUI stabilization timeout, emit needsRefresh so the client fetches the full terminal buffer. Without this, the terminal appears empty until the user manually refreshes or switches tabs. Wire needsRefresh as a proper session listener in server.ts with cleanup in both removal paths to prevent memory leaks. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/session.ts | 2 ++ src/web/server.ts | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/src/session.ts b/src/session.ts index 06ca2c6f..9561b337 100644 --- a/src/session.ts +++ b/src/session.ts @@ -986,9 +986,11 @@ export class Session extends EventEmitter { // OpenCode uses Bubble Tea TUI — no ❯ prompt to detect. // Wait for TUI to stabilize (output stops changing), then mark ready. // Don't clear the buffer — the TUI's initial render IS the useful content. + // Emit needsRefresh so the client fetches the full buffer once the TUI has rendered. this._promptCheckTimeout = setTimeout(() => { this._promptCheckTimeout = null; this._status = 'idle'; + this.emit('needsRefresh'); }, 3000); } else { // Claude mode: wait for ❯ prompt diff --git a/src/web/server.ts b/src/web/server.ts index 34108feb..301d23fb 100644 --- a/src/web/server.ts +++ b/src/web/server.ts @@ -307,6 +307,7 @@ function getOrCreateSelfSignedCert(): { key: string; cert: string } { interface SessionListenerRefs { terminal: (data: string) => void; clearTerminal: () => void; + needsRefresh: () => void; message: (msg: ClaudeMessage) => void; error: (error: string) => void; completion: (result: string, cost: number) => void; @@ -4169,6 +4170,7 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; if (listeners) { session.off('terminal', listeners.terminal); session.off('clearTerminal', listeners.clearTerminal); + session.off('needsRefresh', listeners.needsRefresh); session.off('message', listeners.message); session.off('error', listeners.error); session.off('completion', listeners.completion); @@ -4238,6 +4240,11 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; this.broadcast('session:clearTerminal', { id: session.id }); }, + needsRefresh: () => { + // Tell clients to reload the terminal buffer (e.g., after OpenCode TUI stabilizes) + this.broadcast('session:needsRefresh', { id: session.id }); + }, + message: (msg: ClaudeMessage) => { this.broadcast('session:message', { id: session.id, message: msg }); }, @@ -4436,6 +4443,7 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; // Attach all listeners to the session session.on('terminal', listeners.terminal); session.on('clearTerminal', listeners.clearTerminal); + session.on('needsRefresh', listeners.needsRefresh); session.on('message', listeners.message); session.on('error', listeners.error); session.on('completion', listeners.completion); @@ -5611,6 +5619,7 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; if (listeners) { session.off('terminal', listeners.terminal); session.off('clearTerminal', listeners.clearTerminal); + session.off('needsRefresh', listeners.needsRefresh); session.off('message', listeners.message); session.off('error', listeners.error); session.off('completion', listeners.completion);