Skip to content

Hand back a replay a terminal can read, or the output it missed - #41

Merged
Lakr233 merged 1 commit into
mainfrom
replay-integrity
Oct 29, 2026
Merged

Lakr233 merged 1 commit into
mainfrom
replay-integrity

Conversation

@Lakr233

@Lakr233 Lakr233 commented Oct 29, 2026

Copy link
Copy Markdown
Contributor

What was wrong

Every attach handed back the daemon's raw output buffer, trimmed from the front. A terminal fed it:

  • began mid-sequence (a cut CSI printed its parameters, a cut character printed U+FFFD);
  • lost every mode set before the cut — alternate screen, mouse reporting, bracketed paste, kitty keyboard flags — while the program still expected them;
  • answered the old questions in it (DA1, CPR, XTVERSION, OSC 11, DECRQM…) into the program's input, and replayed clipboard writes and notifications;
  • drew a ZMODEM transfer whose start had been trimmed as a screen of binary — the garbage after sz.

All four reproduced on a guest running 1.6.20.

What changed

  • Rebuilt replay (ighostvtd-io): SessionOutputLog keeps the buffer with its stream offsets and the terminal state at its start, read once by TerminalStreamTracker (Ghostty's parser at the pinned commit). A replay writes that state back, starts at a sequence boundary, and leaves out questions, OSC 52, notifications, ENQ, answered kitty graphics and ZMODEM conversations.
  • Continuation: an attach may name how much of the output the client holds (outputOffset); the reply is then the rest, unchanged (outputResumed). The tab keeps its position across transports, so a dropped link resumes with no gap and nothing printed twice. No reconnecting line is written into the terminal any more (the pill says it).
  • Backpressure: the app pauses its transport while the terminal has more than 512 KiB unparsed, instead of letting the library drop the oldest bytes of a detached surface.

Both new fields are optional both ways, so every patch of the 1.6 line keeps talking to every other.

Tested

  • make test: all suites, including the new Tests/ReplayStream (a fresh terminal and one that already showed the session both end in the whole stream's state, over random streams), and PTY harness checks on a real session and over the proxy wire.
  • make deb, make ipa.
  • jp-01 iOS 26.4 / 27.0.1 and jp-02 iPadOS 26.4 / 27.0.1: no old question answered, every mode back (DECRQM against the real surface), a trimmed transfer leaves a clean screen, a cut flooding tab reattaches through a rebuild.

🤖 Generated with Claude Code

The replay an attach handed back was the raw buffer, trimmed from the
front: a terminal fed it began mid-sequence, lost every mode set before
the cut, answered the old questions in it into the program's input, and
drew a trimmed ZMODEM transfer as a screen of binary.

ighostvtd-io now keeps the buffer as a SessionOutputLog, read once by a
TerminalStreamTracker that follows Ghostty's parser. A client that names
how much of the stream it holds gets the rest unchanged; any other gets
the screen rebuilt: the state the trimmed output left, then the newest
output from a sequence boundary, without questions, clipboard writes,
notifications or transfers. Both fields are optional both ways.

The app holds received output back while its terminal catches up rather
than letting the library drop the oldest of it, and no longer writes a
reconnecting line between two links.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Lakr233
Lakr233 merged commit 486d55f into main Oct 29, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant