From 6bd599d47b8ebadfa786e10d42f9d925e7a415d0 Mon Sep 17 00:00:00 2001 From: Jared Miller Date: Sat, 31 Jan 2026 09:58:18 -0500 Subject: [PATCH] Fix dashboard to handle terminal serialization output The server's serializeAsHTML() returns the full terminal screen state, not incremental chunks. Updated the dashboard to: 1. Handle initial_state event to receive current terminal state on connection 2. Replace output instead of appending (output event now replaces session.output) 3. Simplify renderSessionOutput() to always do full innerHTML replacement This fixes the issue where output was being duplicated/appended incorrectly. --- public/index.html | 39 ++++++++++++++++----------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/public/index.html b/public/index.html index 4b80cd8..a91712b 100644 --- a/public/index.html +++ b/public/index.html @@ -1133,11 +1133,23 @@ renderSessions(); }); + es.addEventListener('initial_state', (e) => { + const data = JSON.parse(e.data); + const session = state.sessions.get(data.session_id); + if (session) { + // Replace output with current terminal state + session.output = data.html; + session.outputRenderedLength = 0; // Force re-render + renderSessionOutput(data.session_id); + } + }); + es.addEventListener('output', (e) => { const data = JSON.parse(e.data); const session = state.sessions.get(data.session_id); if (session) { - session.output += data.data; + session.output = data.data; // Replace, not append + session.outputRenderedLength = 0; // Force full re-render renderSessionOutput(data.session_id); } }); @@ -1422,28 +1434,9 @@ const $output = document.getElementById(`output-${sessionId}`); if ($output) { - // Append only new content since last render - const newChunk = session.output.slice(session.outputRenderedLength); - if (newChunk) { - // More efficient than innerHTML += as it avoids reparsing existing content - $output.insertAdjacentHTML('beforeend', newChunk); - session.outputRenderedLength = session.output.length; - } - - // Soft cap to prevent unbounded growth in DOM and memory - const MAX_OUTPUT_CHARS = 200000; // ~200KB of HTML per session - if (session.output.length > MAX_OUTPUT_CHARS) { - let start = session.output.length - MAX_OUTPUT_CHARS; - // Find safe cut point - don't cut inside an HTML tag - const firstTagEnd = session.output.indexOf('>', start); - if (firstTagEnd !== -1 && firstTagEnd < start + 100) { - start = firstTagEnd + 1; - } - session.output = session.output.slice(start); - // Reset DOM to trimmed content and sync rendered length - $output.innerHTML = session.output; - session.outputRenderedLength = session.output.length; - } + // Always full replace since serializeAsHTML() returns full screen state + $output.innerHTML = session.output; + session.outputRenderedLength = session.output.length; const $outputContainer = document.getElementById(`session-output-${sessionId}`); if ($outputContainer && session.expanded) {