diff --git a/extensions/remote-control/server/routes/stream.ts b/extensions/remote-control/server/routes/stream.ts index 454ef65..e793594 100644 --- a/extensions/remote-control/server/routes/stream.ts +++ b/extensions/remote-control/server/routes/stream.ts @@ -22,6 +22,7 @@ import { readChunks } from "../../buffer/reader.js"; import type { StateEvent } from "../../pi/events.js"; import { SequenceCounter } from "../../sequence.js"; import { ControlClient } from "../../tmux/control.js"; +import { resizeSession } from "../../tmux/manager.js"; import { capturePane } from "../../tmux/snapshot.js"; import type { WsClient, WsServer } from "../types.js"; @@ -155,6 +156,12 @@ function handleStreamConnection( if (ws.readyState !== 1) break; 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") { capturePane({ session: sessionId }) .then((text) => { diff --git a/extensions/remote-control/tmux/manager.ts b/extensions/remote-control/tmux/manager.ts index 214131c..705983c 100644 --- a/extensions/remote-control/tmux/manager.ts +++ b/extensions/remote-control/tmux/manager.ts @@ -60,6 +60,15 @@ export async function spawnSession(opts: { await checkTmuxVersion(); 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 = [ "new-session", "-d", @@ -76,6 +85,28 @@ export async function spawnSession(opts: { 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 { + 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. */