SIGN IN SIGN UP

Keep tool calls visible while resizing terminals (#21)

* fix: keep tool-bearing agent turns in the conversation view

The conversation view discarded every assistant entry that carried no
prose, keeping only the last answer of each exchange. On Claude Code
transcripts that is most of the record: the parser emits one text-less
assistant entry per tool call, so a 200-entry page collapsed to about
21 rows and the screen looked far thinner than an Oh My Pi pane.

Keep an entry when it carries either text or tool activity, and render
the tools that survive: arguments are JSON-decoded one field per line
instead of printed as a raw blob, and a payload past the preview budget
is clamped behind a "Show all N lines" expander so a long file write
cannot bury the turn.

Validated by unit tests over the filter, the formatter and the clamp,
plus a browser journey that drives the real rendered card and asserts
the decoded argument text.

* fix: retain tool activity beside later prose

Ordering the prose branch before the tools branch meant an assistant turn
carrying both text and tool calls was captured as the pending prose answer and
then discarded by the next prose turn, dropping exactly the tool activity the
conversation view exists to show.

* fix: stop wrapping terminal rows at a width the pane never used

The wrapping layout was applied whenever the relay advertised the
pane-size lease capability, which it does unconditionally. Advertising
is not holding: a pane shown before its lease lands, or while the client
declines to lease, had no leased width, so the row cap fell back to
`max-width: 100%` and `overflow-wrap: anywhere` broke every row mid-word
at the phone's container width. The same predicate left the screen's
content width unset, so there was no horizontal scroll to fall back on,
and the virtual row-height model still estimated wrapped line counts,
corrupting the scroll geometry.

Engage the wrapping layout only once a cell advance and a pane width are
both known, and size the screen to the widest row when it is not: an
unleased pane now keeps the fixed layout and scrolls horizontally, which
is the same path a relay without the capability already used. Route the
CSS class, the render cap, the height model, the layout signature and
the content width through one predicate so they cannot disagree.

`preserveLineEnds` deliberately stays keyed to the session rather than
the layout, documented at the call site.

Validated by unit tests over both predicates and by a browser journey
that measures real geometry: the wide row renders one line tall with the
screen wider than the viewport, and reverting either half of the fix
puts it back to three wrapped lines with no scroll.

* fix: bound the wait for a resized pane frame

Frames read while a pane repaints at a new size are suppressed so a
half-drawn screen never replaces the stable one. The wait had no upper
bound: a shared session whose desktop client keeps fighting the leased
size makes the relay flag every frame as settling, and the phone then
froze on its last painted frame indefinitely.

The wait now expires one relay poll after the relay's own three-second
settling window, so a stale screen gives way to the newest frame.

* test: cover the unleased branch of the resize wait

The bounded wait guards two states: a pane the relay keeps flagging as
settling, and a pane with no lease yet. Only the first was covered.

* fix: wrap pane rows at the container while a size lease is pending

A pane read before its width lease lands is neither of the two regimes the
terminal had. The relay could not lease at all: the pane is served at its own
width, so keeping every row on one line and scrolling sideways preserves the
column alignment that width really has. The relay had leased: rows wrap at the
leased width. In between - capability advertised, no width granted - rows were
rendered for a width nobody had, so the reader was left panning right to read
line ends, and the pan came back after every 1s refresh.

Name that third regime and wrap in it: the screen claims no width of its own,
box-drawing rows fall back to wrappable text past the container width instead
of a fixed cell grid, and the row-height estimate counts the wrapped lines -
without which the virtualizer understates the log by 26-32% and lands scrolls
in the wrong place.

Verified on Chromium and WebKit at phone size against a captured omp pane:
zero horizontal overflow across first paint and three updates, height estimate
error 1-3%. Every piece falsified by mutation.

* fix: keep compact conversation focused

---------

Co-authored-by: Christophe Vidal <christophe.vidal.1983@gmail.com>
K
Kiryl Berasneu committed
95846734075dff1e5c489b0b383813b85f9ad6cc
Parent: a290f57
Committed by GitHub <noreply@github.com> on 8/29/2026, 6:14:47 AM