Repository navigation
Description
Description
Global keybinds (like Tab for agent cycling) continue to execute when a dialog or picker is open in the TUI. This causes unintended side effects in the background while the user is interacting with a modal.
Example: When the Model Selector (<leader>m) or Command Palette (Ctrl+P) is open, pressing Tab will cycle through agents in the background instead of being ignored or handled by the dialog.
Note: This bug likely also exists in the Desktop/Web app (
packages/app/), wherepackages/app/src/context/command.tsxhas a similar pattern - the keybind handler does not check if a dialog is active before executing commands.
Root Cause
In packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx, there are two useKeyboard handlers:
-
Handler in
init()(lines 46-55): Processes all registered commands with keybinds (includingagent.cycle). This handler checkssuspended()but does not check if a dialog is open (dialog.stack.length > 0). -
Handler in
CommandProvider(lines 100-108): Only handles opening the command palette. This handler correctly checks bothsuspended()anddialog.stack.length > 0.
The inconsistency between these two handlers causes the bug.
Technical Analysis
Options Considered:
-
Add
dialog.stack.length > 0check (chosen solution)- Add the same guard used in
CommandProviderto theinit()handler - Minimal change (1 line), follows existing pattern in the same file
- No architectural changes needed
- Add the same guard used in
-
Use
command.keybinds(false/true)in dialogs (similar to autocomplete)- Make dialogs suspend keybinds when opening and resume when closing
- Would require
DialogProviderto accessCommandProvider, butDialogProvideris initialized beforeCommandProviderin the component tree, making this impractical without restructuring
-
Reactive effect on
dialog.stack.length- Use
createEffectto observe dialog state and updatesuspendCount - More complex than option 1, achieves the same result indirectly
- Use
Decision: Option 1 was chosen because:
- It follows the existing pattern already used in the same file (line 102)
- It's consistent with how
session/index.tsxhandles the same scenario (line 254) - Minimal change with no risk of introducing regressions
- No architectural changes required
Steps to reproduce
- Open the TUI (
opencode) - Open any dialog/picker (e.g.,
Ctrl+Pfor Command Palette or<leader>mfor Model Selector) - While the dialog is open, press
Tab(agent cycle keybind) - Close the dialog
- Observe that the agent has changed in the background
Expected: Keybinds should not execute while a dialog is open
Actual: Keybinds execute in the background, causing unintended state changes
OpenCode version
v1.0.191
Operating System
macOS (applies to all platforms)
Terminal
Any terminal
Activity
anntnzrb commentedon Dec 23, 2025
Fix submitted in #6017
github-actions commentedon Dec 23, 2025
For keybind-related issues, please also check our pinned keybinds documentation: #4997