fix(terminal): create PTYs at the client viewport size, not 80x24 (#2023)

New terminals were always spawned by the daemon at the hardcoded 80x24
default and only resized once the client's first resize arrived. On a
slow first mount that leaves a window -- or a stuck state -- where a new
terminal renders far smaller than its pane (e.g. vim in a corner).

Seed the PTY with the client's measured viewport size at creation time
so it is born at the right size and the race window is gone.

- protocol: optional `size` on create_terminal_request. Old daemons
  ignore it and keep 80x24; old clients send nothing. Fully backward
  compatible, no capability gate.
- client: a small last-measured-size cache keyed by serverId+cwd (every
  terminal in a workspace shares the pane) with a most-recent fallback;
  written on fit, read at create.
- server: thread rows/cols through the controller, terminal manager, and
  the worker-thread boundary into the existing size-aware createTerminal.

Tests: cache logic, protocol back-compat parse, controller forwarding.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Christoph Leiter
2026-07-13 03:26:52 +08:00
committed by GitHub
co-authored by Claude Opus 4.8
parent ec93ca866e
commit 2658132384
11 changed files with 232 additions and 1 deletions
+10
View File
@@ -1984,6 +1984,16 @@ export const CreateTerminalRequestSchema = z.object({
agentId: z.string().optional(),
command: z.string().optional(),
args: z.array(z.string()).optional(),
// COMPAT(createTerminalSize): added in v0.1.107, drop the optional gate when floor >= v0.1.107.
// The client seeds the PTY with its measured viewport size so a new terminal isn't born at the
// 80x24 default and then visibly reflowed. Old daemons ignore this field and start at 80x24;
// the client's first resize corrects it as before.
size: z
.object({
rows: z.number().int().positive(),
cols: z.number().int().positive(),
})
.optional(),
requestId: z.string(),
});