Skip to content

feat(tui): static-history path behind REASONIX_STATIC_HISTORY (stage 1 of #1529)#1530

Merged
esengine merged 5 commits into
mainfrom
feat/static-history
May 22, 2026
Merged

feat(tui): static-history path behind REASONIX_STATIC_HISTORY (stage 1 of #1529)#1530
esengine merged 5 commits into
mainfrom
feat/static-history

Conversation

@esengine

Copy link
Copy Markdown
Owner

Summary

Stage 1 of #1529. Add a parallel history renderer that uses Ink <Static> so the terminal owns scrollback, behind a flag so we can validate against the existing virtual-viewport CardStream before later stages delete the old path.

  • New StaticCardStream partitions cards at the first unsettled entry: the settled prefix goes into <Static>, the live tail renders dynamically.
  • isFullySettled is exported from CardStream and reused, so the finalize boundary is identical between the two renderers.
  • Off by default. Opt in with REASONIX_STATIC_HISTORY=1.

No behavior change for users who don't set the env var. Old CardStream and all of viewport-budget / chat-scroll-store / useScrollback / copy-mode stay untouched in this stage — they get removed in stages 2–4.

Test plan

  • npm run lint (warnings only, exits 0)
  • npm run typecheck
  • npm run build
  • npm run test — all 3594 tests pass
  • Manual smoke under REASONIX_STATIC_HISTORY=1: each card kind (user, reasoning, streaming, tool, plan, diff, error) finalizes into scrollback; terminal-native scroll/copy works above the live region
  • Manual smoke without the flag: existing behavior unchanged

Part of #1529.

reasonix added 5 commits May 22, 2026 00:24
…ISTORY

Stage 1 of #1529. New `StaticCardStream` partitions cards into a settled
prefix (rendered via Ink `<Static>` so the terminal owns scrollback) and
an in-flight tail (rendered dynamically). Off by default; opt in with
`REASONIX_STATIC_HISTORY=1` to validate parallel against the current
virtual-viewport `CardStream` before later stages delete the old path.

Reuses `isFullySettled` from `CardStream` to keep the finalize boundary
identical across both renderers.
Without this, the dynamic frame fills the terminal and any card flushed
through <Static> scrolls past the viewport into terminal scrollback the
moment it prints. Letting the outer Box size to content keeps the live
region small so Static-committed history stays visible above it.
The whole point of STATIC_HISTORY is to let the terminal own scrollback,
which can't happen while we still capture wheel events via SGR. Capturing
the wheel also re-renders the persistent frame on every scroll tick,
which shows as composer ghosting when the user mouse-wheels through
history.
PromptInput emits a raw \x1b[row;colH on every render to anchor the
terminal cursor next to the visible \u258c so IMEs place candidate
popups correctly. The math assumes the persistent UI sits at the
terminal bottom (totalRows - rowsBelow). Under STATIC_HISTORY the frame
floats just below the Static-committed history, so the absolute write
moves the cursor far below where Ink thinks the frame ended; Ink's next
cursor-up + clear runs against the wrong starting point and the
previous frame stays visible above the new one. Drop the write in this
mode \u2014 IME popup placement degrades a little, ghost frames go away.
Previously "off" mode emitted nothing on enable, so any SGR /
alternate-scroll capture left over by a prior Reasonix process (or
another TUI that crashed without disabling it) stayed active in the
terminal. Wheel events kept flowing into our keystroke handler instead
of scrolling the native scrollback, which under STATIC_HISTORY made
streaming output jump to the top of the chat-scroll viewport every
wheel tick. Emit disables for ?1000/?1002/?1003/?1006/?1007/?1015 so
the terminal starts in a known wheel-passthrough state.
@esengine esengine merged commit bb76851 into main May 22, 2026
4 checks passed
@esengine esengine deleted the feat/static-history branch May 22, 2026 08:12
esengine pushed a commit that referenced this pull request May 22, 2026
…, theme) (#1524)

Localizes the remaining hardcoded CLI output strings — `reasonix mcp list / search / install` flow, `sessions` listing, `prune-sessions`, and the `/theme` slash handler — so zh-CN users see translated text instead of mixed EN/CN output.

31 new keys across `sessions` / `mcpCli` / `app` namespaces with full EN ↔ zh-CN parity. Mechanical migration — `t()` calls replace each string with the same parameters; no behavior change.

Verified clean rebase on top of the stage-1-through-4 refactor (#1530 / #1534 / #1536 / #1537) plus the path-approval bridge (#1540): typecheck + lint + 3528 tests all pass.
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