diff --git a/web/src/attach.ts b/web/src/attach.ts index 948d633..ea7e468 100644 --- a/web/src/attach.ts +++ b/web/src/attach.ts @@ -359,6 +359,9 @@ export function createAttachConnection( let ws: WebSocket; let reconnectMs = INITIAL_RECONNECT_MS; let reconnectTimer: number | null = null; + // Snapshot replay starts at row zero, which can leave Codex at its oldest line. + // Follow it once per socket; later scrolling remains under the operator's control. + let awaitingReplay = true; const sendControl = (msg: ClientControl) => { if (ws.readyState !== WebSocket.OPEN) return; @@ -378,6 +381,7 @@ export function createAttachConnection( }; function connect(): void { + awaitingReplay = true; ws = new WebSocket(attachWsUrl(sessionId)); ws.binaryType = "arraybuffer"; @@ -398,10 +402,20 @@ export function createAttachConnection( return; } if (ev.data instanceof ArrayBuffer) { - term.write(new Uint8Array(ev.data)); + const replay = awaitingReplay; + awaitingReplay = false; + term.write(new Uint8Array(ev.data), () => { + if (replay) term.scrollToBottom(); + }); } else if (ev.data instanceof Blob) { // Some browsers may default to Blob despite binaryType="arraybuffer". - ev.data.arrayBuffer().then((b) => term.write(new Uint8Array(b))); + void ev.data.arrayBuffer().then((b) => { + const replay = awaitingReplay; + awaitingReplay = false; + term.write(new Uint8Array(b), () => { + if (replay) term.scrollToBottom(); + }); + }); } };