Skip to content

fix(tui): stop the first keystroke after entering a panel from leaking into the chat buffer - #139

Merged
sosidudku1 merged 2 commits into
mainfrom
valeryb/single-keystroke-focus
Aug 18, 2026
Merged

fix(tui): stop the first keystroke after entering a panel from leaking into the chat buffer#139
sosidudku1 merged 2 commits into
mainfrom
valeryb/single-keystroke-focus

Conversation

@plombeer31

Copy link
Copy Markdown
Collaborator

What

The first keystroke after entering a panel tab was delivered to the panel and the chat
editor at once. On Tasks, a single / opened the panel's search row, the global slash
palette, and seeded / into the prompt buffer — three surfaces from one key — and the stray
character survived the trip back to Run, prefixing the next message.

Why it happens

Ink keeps the latest useInput handler current on every render, but applies isActive
through a passive effect. Between the commit that flips editorFocus to false and that
effect's flush there is a window where the editor's subscription is still live — and the
handler body only checked disabled, never focus. A keypress landing in the window is
processed by the freshly-active panel bindings and the stale editor subscription. The
palette then rides along for free: it opens whenever the buffer becomes /…
(onEditorChangeslash_palette_opened), so the leaked / is what summons it.

Fix

multi-line-editor.tsx: a ref written during render mirrors focus && !disabled, and the
useInput callback early-returns when it is false. The focus flip now takes effect the same
frame; no new focus model, no new state.

Testing

The window is invisible to rerender() (ink-testing-library flushes effects before
returning), so the regression test drives it the way the app really hits it: a bus-originated
tab switch, two setImmediate yields — render committed, teardown effect not yet run — then
the keystroke. Verified stable 3/3 in both directions: on unpatched code the frame shows
the seeded ❯ / plus the palette (test fails); patched, only the tasks search opens.

  • npm run lint clean
  • New: multi-line-editor.test.tsx (focused/unfocused basics) + the app-level window test
  • Full src/tui serial: failure set identical to main's pre-existing five (tui-app ×2
    stale copy, splash-banner, chat-log, persist-embedding-hybrid-recall;
    llm-health-poller 12/12 solo, fails only under parallel load)

@sosidudku1
sosidudku1 merged commit a879000 into main Aug 18, 2026
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.

2 participants