From 628b6e5832f06bc3e76129635eaa16235af034d8 Mon Sep 17 00:00:00 2001 From: Codeman maintainer Date: Tue, 13 Oct 2026 18:04:36 +0200 Subject: [PATCH] docs(remote): a frame that starts on a wrapped line's second half is not placed (#609 merge-time fix) Co-Authored-By: Claude Opus 5.5 (1M context) --- docs/remote-sessions.md | 8 +++++--- src/tmux-manager.ts | 4 +++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/remote-sessions.md b/docs/remote-sessions.md index 8b9587a3..9a38bc31 100644 --- a/docs/remote-sessions.md +++ b/docs/remote-sessions.md @@ -293,9 +293,11 @@ nothing matches), the join is history over frame, as without the screen read. That includes an agent TUI mid-turn (Claude Code, codex, opencode): it keeps a live region (spinner, composer, footer) pinned to the bottom and inserts new rows above it, so the frame is not a shifted copy of the screen and is not -placed. A plain shell places. What is left: when the screen repeats a whole -block of rows, the frame can be -placed at the higher copy, which leaves out the rows between the two copies. +placed. A plain shell places, unless the frame's top row is the second half +of a wrapped line (the screen holds that line as one joined row, so nothing +matches and the join is history over frame). What is left: when the screen +repeats a whole block of rows, the frame can be placed at the higher copy, +which leaves out the rows between the two copies. The history, the history size and the screen are ONE tmux command list (`capture-pane … \; display-message … \; capture-pane …`), not separate `tmux` diff --git a/src/tmux-manager.ts b/src/tmux-manager.ts index 870db37f..5073f7d1 100644 --- a/src/tmux-manager.ts +++ b/src/tmux-manager.ts @@ -737,7 +737,9 @@ function capturedRowText(row: string): string { * a live region (spinner, composer, footer) pinned to the bottom and inserts new * rows above it, so the frame is not a shifted copy of the screen and the * comparison down to the screen's last content row fails. The caller then falls - * back to the plain join. A plain shell places. + * back to the plain join. A plain shell places, unless the frame starts on the + * second half of a wrapped line: -J holds that line as one screen row, so it + * matches nothing and the plain join applies too. */ export function findFrameInScreen(screenRows: string[], frameRows: string[]): number { const screen = screenRows.map(capturedRowText);