Skip to content

docs(plans): add viewport-relative cursor and server-side sub-status plans - #537

Open
RonenMars wants to merge 3 commits into
mainfrom
docs/agent-status-and-cursor-plans
Open

docs(plans): add viewport-relative cursor and server-side sub-status plans#537
RonenMars wants to merge 3 commits into
mainfrom
docs/agent-status-and-cursor-plans

Conversation

@RonenMars

Copy link
Copy Markdown
Owner

Two implementation plans, each validated across multiple review rounds with every load-bearing claim independently reproduced before it was written down.

PlanCup — viewport-relative cursor positioning (tb-mobile)

services/virtual-terminal.ts resolves absolute cursor moves against its whole append-only scrollback grid instead of the 40-row viewport the TUI paints against, so every footer repaint lands in the middle of the transcript.

Measured on origin/main: one repaint after 41+ seeded rows loses two transcript lines and mangles a third into "tr✻ Brewing… (12s · ↑ 3.4k tokens)", and a spinner repeats it for the whole turn.
It fires on every session resume, not only long sessions, because terminal_replay seeds ~200 rendered rows before the first live frame arrives.

Scope is the four cursor-moving handlers — H, f, A, B — chosen by two independent principles that select the same set: handlers that move the cursor become viewport-relative, handlers that mutate grid structure do not; and only defects with measured impact are in.
The prototype is 152/152 across eleven terminal suites with tsc clean and zero test rewrites.

PlanIndicator — server-side agent sub-status (tb-streamer + tb-mobile)

Replaces the closed #647, which derived the indicator on the client by scraping mobile's own emulator and never worked because of the bug above.
The streamer already runs a correct headless screen at the geometry the TUI paints against, already scrapes it on every chunk, and already ships model/effort/permissionMode off the same footer.

The plan carries the clearing rule that keeps the phase from latching, a bespoke scoped frame rather than a session copy, and an always-emit-null contract.

Review notes

Two questions each caught a defect that had already cleared two sign-offs, and both are recorded in the plans:

  • Any input used to reject an alternative must be run against the accepted design. This caught an unclamped cursor move that made the fix strictly worse than the status quo — 62 stray escapes evicted 121 of 200 transcript rows where main lost none — and then caught a phase field that latched exactly as #647's pill did.
  • What does the thing I am reusing already do on every call? This caught unguarded per-tick SQLite writes, a response mapper whose != null guard silently drops an explicit null, and an elapsedMs that recomputes every call and would have re-rendered the app ~3x/second for a whole turn.

Line-anchor drift occurred twice during review, so every path:line reference in both documents was extracted and machine-checked against the cited file.

Docs only — no code changes.

…plans

PlanCup fixes absolute cursor positioning in tb-mobile's terminal emulator, which resolves CSI H/f/A/B against the whole scrollback grid rather than the 40-row viewport the TUI paints against.
One footer repaint past 41 rows loses two transcript lines and mangles a third, and terminal_replay seeds ~200 rows on every subscribe, so it fires on every session resume.

PlanIndicator replaces the closed PR #647 by deriving agent phase in the streamer, where a correct headless screen and a throttled scrape pass already exist, rather than on the client against the broken emulator.

Both plans carry their full review logs, including two review questions that each caught defects after two sign-offs: run any input used to reject an alternative against the accepted design, and ask what reused machinery already does on every call.
…am findings

A capture of Claude Code v2.1.228 at the streamer's real 120x40 geometry validates PlanCup against a reference emulator: the fix reproduces `@xterm/headless` output where `origin/main` does not, and absolute cursor moves address a maximum row of exactly 40, so `VIEWPORT_ROWS = 40` is measured rather than assumed.

Three findings taken from that capture were wrong and are corrected here.
`CSI 2J`, `CSI r` and `ESC 7`/`ESC 8` were each read as firing ~30 times mid-turn and each proposed for promotion out of the deferred queue; all three are one startup sequence replayed once per snapshot, because every snapshot is a full ring-buffer dump.
Nothing in the deferred family is reachable mid-turn, so the queue is downgraded uniformly rather than reordered.

The capture README is committed alongside because the raw bytes live outside any repo and two PRs cite them.
Registers what is done, what is blocked, and what remains across both plans and both repos, so the state does not live only in a conversation.
Records the deliberately-not-filed decisions too — conditional wire geometry, capture housekeeping, the stale worktree — so they are not re-derived.
Carries the method notes this work earned: run the test that killed the thing you are replacing before proposing the replacement, and ask per statistic whether it is sensitive to how the evidence file was assembled.
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