fix terminal autoscroll

3clyp50 committed Jan 21, 2026 at 15:00 UTC 9698e9150488887db0ede74afb131551841cef15
1 file changed +18 -5
webui/js/messages.js
+18 -5
@@ -1590,9 +1590,15 @@ function updateProcessStep(stepElement, id, type, heading, content, kvps, durati
1590 let skipFullRender = false;
1591
1592 if (detailContent) {
1593 - // Capture scroll state before re-render (uses existing Scroller pattern)
1593 + // Capture scroll state before re-render
1594 const terminal = detailContent.querySelector(".terminal-output");
1595 - const scroller = terminal ? new Scroller(terminal) : null;
1595 + let wasAtBottom = true; // Default to true for new terminals
1596 + let previousScrollTop = 0;
1597 + if (terminal) {
1598 + const distanceFromBottom = terminal.scrollHeight - terminal.clientHeight - terminal.scrollTop;
1599 + wasAtBottom = distanceFromBottom <= 10;
1600 + previousScrollTop = terminal.scrollTop;
1601 + }
1602
1603 // For browser, update image src incrementally to avoid flashing
1604 if (type === "browser" && kvps?.screenshot) {
@@ -1611,10 +1617,17 @@ function updateProcessStep(stepElement, id, type, heading, content, kvps, durati
1617 if (!skipFullRender) {
1618 renderStepDetailContent(detailContent, content, kvps, type);
1619
1614 - // Re-apply scroll (stays at bottom if was at bottom)
1620 + // Restore scroll position after re-render
1621 const newTerminal = detailContent.querySelector(".terminal-output");
1616 - if (newTerminal && scroller?.wasAtBottom) {
1617 - newTerminal.scrollTop = newTerminal.scrollHeight;
1622 + if (newTerminal) {
1623 + if (wasAtBottom) {
1624 + // Pin to bottom if was at bottom
1625 + newTerminal.scrollTop = newTerminal.scrollHeight;
1626 + } else {
1627 + // Restore previous position (clamped to max)
1628 + const maxScroll = Math.max(newTerminal.scrollHeight - newTerminal.clientHeight, 0);
1629 + newTerminal.scrollTop = Math.min(previousScrollTop, maxScroll);
1630 + }
1631 }
1632 }
1633 }