hermes-agent/ui-tui/src/components
Brooklyn Nicholson 3b4dd68326 fix(tui): align composer cursorLayout with wrap-ansi to kill multiline cursor drift
The composer's `cursorLayout` (in `ui-tui/src/lib/inputMetrics.ts`) used a
hand-rolled word-wrap algorithm to decide where `useDeclaredCursor`
should park the hardware cursor. But Ink's `<Text wrap="wrap">` renders
the same text via `wrap-ansi`. The two algorithms disagreed on common
real-world inputs — `"branch investigate"` at cols=20, `"hello world"`
at cols=8, exact-fill strings like `"abcdefgh"` at cols=8 — so the
hardware cursor parked several cells past where Ink actually rendered
the last character. Users saw a multi-cell blank gap between their
last-typed letter and the cursor block, especially on narrow terminals
(the Cursor IDE built-in terminal was the worst offender).

Three previous PRs (#26717, #25860, #22197) chased fast-echo
displayCursor/cursorDeclaration drift and in-band-vs-native cursor
heuristics. None of them touched the underlying wrap-algorithm
mismatch, which is why the bug kept resurfacing.

Fix: source cursorLayout's line breaks from wrap-ansi directly. Walk
its emitted string char-by-char, tracking original-string offsets, push
a VisualLine at each '\n'. Also drop the buggy `column >= w` overflow
rule in cursorLayout — that's what pushed exact-fill text onto a
phantom next row.

canFastBackspaceShape now detects the wrap boundary in BOTH coordinate
conventions (column === 0 OR column >= columns), since exact-fill now
reports as (0, columns) instead of the previous (1, 0). The physical
state is identical — the terminal auto-wraps at column N either way —
but the layout function reports the position more honestly.

Tests:
- ui-tui/src/__tests__/textInputWrap.test.ts: 3 tests that pinned the
  BUGGY behavior were updated to assert wrap-ansi parity (the real
  invariant). Added a typing-prefix invariant: cursorLayout must agree
  with wrap-ansi at every character of a long input.
- ui-tui/src/__tests__/cursorDriftRegression.test.ts: new file. Walks
  the user-reported bug message char-by-char at 7 widths and asserts
  agreement with wrap-ansi at every prefix.

Verification:
- 791/791 vitest tests pass.
- 84/84 tui-gateway pytest tests pass via scripts/run_tests.sh.
- PTY repro (typing into a real `hermes --tui` PTY at cols=50/55/60):
  cursor lands exactly 1 cell past the last typed char in every case
  the bug previously drifted.
2026-05-17 11:10:06 -05:00
..
agentsOverlay.tsx fix(tui): handle timeout/error subagent statuses in /agents (#26687) 2026-05-15 20:19:02 -05:00
appChrome.tsx feat(tui): segment turns with rule above non-first user msgs; trim ticker dead space (#21846) 2026-05-08 05:12:09 -07:00
appLayout.tsx feat(tui): segment turns with rule above non-first user msgs; trim ticker dead space (#21846) 2026-05-08 05:12:09 -07:00
appOverlays.tsx fix(tui): honor skin highlight colors (#20895) 2026-05-06 14:01:56 -07:00
branding.tsx feat(tui): collapsible sections in startup banner (skills, system prompt, MCP) 2026-05-06 03:34:00 -07:00
fpsOverlay.tsx fix(tui): restore macOS copy behavior and theme polish (#17131) 2026-04-28 18:47:14 -05:00
helpHint.tsx feat(tui): add a mini help menu when u write ? in the input field 2026-04-30 13:37:12 -04:00
markdown.tsx fix(tui): width-aware markdown table rendering with vertical fallback (#26195) 2026-05-15 20:25:56 -05:00
maskedPrompt.tsx fix(tui): restore macOS copy behavior and theme polish (#17131) 2026-04-28 18:47:14 -05:00
messageLine.tsx fix(tui): harden Terminal.app render behavior 2026-05-16 22:51:51 -05:00
modelPicker.tsx fix(tui): address remaining review feedback — ordering and digit shortcuts 2026-04-30 23:41:19 -04:00
overlayControls.tsx fix(tui): restore macOS copy behavior and theme polish (#17131) 2026-04-28 18:47:14 -05:00
prompts.tsx fix(tui): allow transcript scroll + Esc during approval/clarify/confirm prompts (#26414) 2026-05-15 21:59:28 -05:00
queuedMessages.tsx fix(tui): restore macOS copy behavior and theme polish (#17131) 2026-04-28 18:47:14 -05:00
sessionPicker.tsx fix(tui): require double-tap d to confirm session delete 2026-04-29 20:21:16 -07:00
skillsHub.tsx fix(tui): restore macOS copy behavior and theme polish (#17131) 2026-04-28 18:47:14 -05:00
streamingAssistant.tsx fix(tui): inline todo in transcript, group across thinking 2026-04-26 16:09:28 -05:00
streamingMarkdown.tsx fix(tui): width-aware markdown table rendering with vertical fallback (#26195) 2026-05-15 20:25:56 -05:00
textInput.tsx fix(tui): align composer cursorLayout with wrap-ansi to kill multiline cursor drift 2026-05-17 11:10:06 -05:00
themed.tsx refactor(tui): /clean pass across ui-tui — 49 files, −217 LOC 2026-04-16 22:32:53 -05:00
thinking.tsx fix(tui): handle timeout/error subagent statuses in /agents (#26687) 2026-05-15 20:19:02 -05:00
todoPanel.tsx fix(tui): restore macOS copy behavior and theme polish (#17131) 2026-04-28 18:47:14 -05:00