fix: terminal size sync — resize message handler + xterm-256color default-terminal

This commit is contained in:
jay 2026-05-16 03:30:27 +02:00
parent b64aaab40a
commit fcfe729d23
2 changed files with 38 additions and 0 deletions

View File

@ -22,6 +22,7 @@ import { readChunks } from "../../buffer/reader.js";
import type { StateEvent } from "../../pi/events.js"; import type { StateEvent } from "../../pi/events.js";
import { SequenceCounter } from "../../sequence.js"; import { SequenceCounter } from "../../sequence.js";
import { ControlClient } from "../../tmux/control.js"; import { ControlClient } from "../../tmux/control.js";
import { resizeSession } from "../../tmux/manager.js";
import { capturePane } from "../../tmux/snapshot.js"; import { capturePane } from "../../tmux/snapshot.js";
import type { WsClient, WsServer } from "../types.js"; import type { WsClient, WsServer } from "../types.js";
@ -155,6 +156,12 @@ function handleStreamConnection(
if (ws.readyState !== 1) break; if (ws.readyState !== 1) break;
sendBinary(ws, buildBinaryFrame(chunk.seq, chunk.data)); sendBinary(ws, buildBinaryFrame(chunk.seq, chunk.data));
} }
} else if (m.type === "resize") {
// IC-1 extension: client reports its actual terminal dimensions.
// Resize the tmux window so line-wrapping matches what the client sees.
const cols = typeof m.cols === "number" ? m.cols : 80;
const rows = typeof m.rows === "number" ? m.rows : 24;
resizeSession(sessionId, cols, rows).catch(() => {});
} else if (m.type === "snapshot-request") { } else if (m.type === "snapshot-request") {
capturePane({ session: sessionId }) capturePane({ session: sessionId })
.then((text) => { .then((text) => {

View File

@ -60,6 +60,15 @@ export async function spawnSession(opts: {
await checkTmuxVersion(); await checkTmuxVersion();
const { name, width = 120, height = 40, command = "" } = opts; const { name, width = 120, height = 40, command = "" } = opts;
// Set default-terminal globally so programs inside tmux get xterm-256color
// and emit the escape sequences that SwiftTerm / xterm-compatible clients expect.
await execFileAsync("tmux", [
"set-option",
"-g",
"default-terminal",
"xterm-256color",
]).catch(() => {}); // best-effort; older tmux may not support all options
const args = [ const args = [
"new-session", "new-session",
"-d", "-d",
@ -76,6 +85,28 @@ export async function spawnSession(opts: {
return name; return name;
} }
/**
* Resize an existing session's window.
* Safe to call at any time; silently ignores unknown sessions.
*/
export async function resizeSession(
name: string,
cols: number,
rows: number,
): Promise<void> {
const c = Math.max(1, Math.min(Math.round(cols), 500));
const r = Math.max(1, Math.min(Math.round(rows), 200));
await execFileAsync("tmux", [
"resize-window",
"-t",
name,
"-x",
String(c),
"-y",
String(r),
]).catch(() => {}); // session may not exist yet; ignore
}
/** /**
* List all tmux sessions with metadata. * List all tmux sessions with metadata.
*/ */