From 3c1405c08e1a18f4cf6cd868f8191820f6599bac Mon Sep 17 00:00:00 2001 From: Aamer Akhter Date: Mon, 11 May 2026 08:58:40 -0400 Subject: [PATCH] fix: prevent tmux flicker on restart by matching existing window size When a PTY client re-attaches to an existing tmux session, it currently hardcodes the PTY size to 120x40 and tmux resizes the window to match. The xterm.js client then resizes back to its actual viewport on the next render tick, so every restart causes a visible flicker and loses one repaint of buffer content. Also remove the hardcoded `-x 120 -y 40` from `tmux new-session` so initial size adapts to the first client. Changes: - session.ts: query existing window size via `tmux display -p #{window_width} #{window_height}` before pty.spawn, fall back to 120x40 only if tmux is unreachable. - tmux-manager.ts: drop -x/-y from new-session args. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/session.ts | 23 ++++++++++++++++++++--- src/tmux-manager.ts | 2 +- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/session.ts b/src/session.ts index 1bb557e0..05ee5e08 100644 --- a/src/session.ts +++ b/src/session.ts @@ -29,7 +29,7 @@ */ import { EventEmitter } from 'node:events'; -import { execSync } from 'node:child_process'; +import { execSync, execFileSync } from 'node:child_process'; import { v4 as uuidv4 } from 'uuid'; import * as pty from 'node-pty'; import { @@ -946,11 +946,28 @@ export class Session extends EventEmitter { } // Attach to the mux session via PTY + // Query existing tmux window size so re-attach matches (avoids flicker from 120x40 default) + let ptyCols = 120; + let ptyRows = 40; + try { + const sizeStr = execFileSync( + 'tmux', + ['display', '-t', this._muxSession!.muxName, '-p', '#{window_width} #{window_height}'], + { timeout: 2000, encoding: 'utf8' } + ).trim(); + const [w, h] = sizeStr.split(' ').map(Number); + if (w > 0 && h > 0) { + ptyCols = w; + ptyRows = h; + } + } catch { + /* fall back to 120x40 */ + } try { this.ptyProcess = pty.spawn(mux.getAttachCommand(), mux.getAttachArgs(this._muxSession!.muxName), { name: 'xterm-256color', - cols: 120, - rows: 40, + cols: ptyCols, + rows: ptyRows, cwd: this.workingDir, env: buildMuxAttachEnv(), }); diff --git a/src/tmux-manager.ts b/src/tmux-manager.ts index 5d5b2fd7..bb3abe7f 100644 --- a/src/tmux-manager.ts +++ b/src/tmux-manager.ts @@ -556,7 +556,7 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { // (Production uses systemd which has a clean env, but dev/test may be nested.) const cleanEnv = { ...process.env }; delete cleanEnv.TMUX; - execSync(`tmux new-session -ds "${muxName}" -c "${workingDir}" -x 120 -y 40`, { + execSync(`tmux new-session -ds "${muxName}" -c "${workingDir}"`, { cwd: workingDir, timeout: EXEC_TIMEOUT_MS, stdio: 'ignore',