From eecf74c00110976ca2749f952affd847f087e5b0 Mon Sep 17 00:00:00 2001 From: aakhter Date: Mon, 11 May 2026 16:32:17 -0400 Subject: [PATCH] fix: prevent tmux flicker on restart by matching existing window size (#80) 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',