You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fixes#87069 — the dashboard Chat tab inserted a stray l into the composer on every session switch.
Root cause: PtySession.attach() injects a raw Ctrl-L byte (0x0c) to force a TUI repaint on keep-alive PTY reattach (#86332 / #68071). The Ink keypress parser maps that byte to a ctrl+l key event which reaches both listeners — the global hotkey handler (which redraws but doesn't stop propagation) and the composer's TextInput, which falls through to the generic insert branch and types a literal l.
Change
One line: add isAction(key, input, 'l') to shouldPassThroughToGlobalHandler so the composer ignores the redraw keypress, mirroring the global handler's own isAction(key, ch, 'l') check in useInputHandlers.ts. Unmodified l still types normally; the existing ctrl+c/x/o pass-through entries are untouched.
Test plan
cd ui-tui && npx tsc --noEmit
cd ui-tui && npx vitest run src/__tests__/textInputPassThrough.test.ts (7 passed)
cd ui-tui && npx vitest run src/__tests__/textInput (107 passed)
Manual: with the composer focused, Ctrl+L no longer inserts l; typing l normally is unaffected.
AI code review — automated review for reference, author can ignore or act on any point.
fix(tui): pass through Ctrl/Cmd+L so the dashboard redraw byte never inserts a stray 'l'
No blocking issues found. A few minor observations:
Test only pins the Ctrl half (ui-tui/src/__tests__/textInputPassThrough.test.ts): isAction(key, input, 'l') is isActionMod(key) && input.toLowerCase() === 'l', which on macOS covers Cmd+L — the "Cmd" half the PR title advertises. An explicit meta/super case (like key({ meta: true })) would pin that path so a future change to isActionMod can't silently drop it.
Two rule shapes coexist in the same boolean (ui-tui/src/components/textInput.tsx): the sibling entries (key.ctrl && input === 'c'/'x'/'o') are explicit ctrl-only checks, while the new entry uses isAction (modifier-inclusive). A later contributor adding e.g. Ctrl+K may copy the wrong shape, making some keys meta-inclusive and others not. Not blocking — worth a comment noting the intent.
Redraw path: the fix routes Ctrl+L to the global handler, which is right for the embedded dashboard (xterm.js) case. Worth a quick manual check in the plain hermes --tui on a terminal where Ctrl+L previously reached the composer as a literal 'l' — the pass-through should now reach the terminal's redraw instead of the input.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
comp/tuiTerminal UI (ui-tui/ + tui_gateway/)P3Low — cosmetic, nice to havetype/bugSomething isn't working
3 participants
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #87069 — the dashboard Chat tab inserted a stray
linto the composer on every session switch.Root cause:
PtySession.attach()injects a raw Ctrl-L byte (0x0c) to force a TUI repaint on keep-alive PTY reattach (#86332 / #68071). The Ink keypress parser maps that byte to actrl+lkey event which reaches both listeners — the global hotkey handler (which redraws but doesn't stop propagation) and the composer'sTextInput, which falls through to the generic insert branch and types a literall.Change
One line: add
isAction(key, input, 'l')toshouldPassThroughToGlobalHandlerso the composer ignores the redraw keypress, mirroring the global handler's ownisAction(key, ch, 'l')check inuseInputHandlers.ts. Unmodifiedlstill types normally; the existing ctrl+c/x/o pass-through entries are untouched.Test plan
cd ui-tui && npx tsc --noEmitcd ui-tui && npx vitest run src/__tests__/textInputPassThrough.test.ts(7 passed)cd ui-tui && npx vitest run src/__tests__/textInput(107 passed)l; typinglnormally is unaffected.Related