Summary
In the interactive TUI, when a question (the askuserquestion tool / question.asked flow) offers a "Type your own answer" option, the typed custom answer cannot be submitted. Pressing Enter after typing does nothing — it only inserts newlines into the input box. Selecting one of the predefined options works fine; only the custom free-text path is broken.
Environment
- opencode
v1.15.13 (latest release at time of filing)
- Linux x86-64, terminal: kitty
- Reproducible regardless of model/agent — it's a TUI input-handling issue.
Steps to reproduce
- In an interactive
opencode TUI session, trigger any question that allows a custom answer (custom defaults to true), so the dialog shows numbered options plus a final "Type your own answer" row.
- Select "Type your own answer" (it enters edit mode and focuses the text input).
- Type some text.
- Press Enter to confirm/submit.
Expected
The typed text is submitted as the answer (question.reply), the same way pressing Enter on a predefined option submits it.
Actual
Enter does nothing except add blank lines in the input box. There is no way to confirm/send the custom answer (and no mouse "submit" affordance either). The only escape is Esc to dismiss the question entirely.
Root cause
In the interactive TUI question component, packages/opencode/src/cli/cmd/tui/routes/session/question.tsx (QuestionPrompt):
- Choosing "Type your own answer" sets
store.editing = true and focuses an @opentui/core <textarea> (via val.focus() in the ref).
- Submission of the typed answer is wired only through the declarative keymap:
useBindings(() => ({
mode: QUESTION_MODE,
enabled: store.editing && !confirm(),
bindings: [
// ...
{ key: "return", desc: "Submit answer edit", cmd: () => { /* pick(text, true) -> question.reply */ } },
],
}))
A focused textarea consumes the Enter keypress itself (newline insertion, up to maxHeight={6}), so the key never reaches the useBindings keymap and the return -> submit binding never fires.
Proof that it's key delivery, not the submit logic: if the binding fired, pick(text, true) would immediately call sdk.client.question.reply(...). It doesn't submit, so the binding is never reached. The only difference between the working option-selection path and the broken custom path is the focused textarea capturing the key.
Why predefined options work but custom doesn't
- Selecting an option: no textarea is focused, so Enter / number keys flow into the other
useBindings block (enabled: !store.editing) and submit normally.
- Typing a custom answer: the focused textarea swallows Enter before the keymap sees it.
In-repo reference implementation that handles this correctly
The direct-mode footer question UI, packages/opencode/src/cli/cmd/run/footer.question.tsx (RunQuestionBody), handles the identical flow correctly by using a global imperative keyboard handler and explicitly preventing default while editing:
useKeyboard((event) => {
// ...
if (cur.editing) {
if (event.name === "escape") { /* cancel */ return }
if (event.name === "return" && !event.shift && !event.ctrl && !event.meta) {
saveCustom()
event.preventDefault() // stops the focused textarea from eating Enter
}
return
}
// ...
})
That event.preventDefault() is exactly what the interactive TUI QuestionPrompt is missing.
Suggested fix
Mirror the footer's approach in QuestionPrompt (tui/routes/session/question.tsx): while store.editing is true, intercept Enter at a level that runs before the focused textarea (e.g. a useKeyboard handler), invoke the existing submit logic, and call event.preventDefault(). Reserve Shift+Enter for inserting a newline. The submit logic itself is already present and correct — only key delivery to it is broken.
Notes
- No existing issue found for this when searching the tracker (custom answer / type your own answer / question submit).
- Affects the latest release (
v1.15.13); the same textarea pattern appears to still be present on main, so this is not fixed by updating.
Permalinks (v1.15.13)
Summary
In the interactive TUI, when a question (the
askuserquestiontool /question.askedflow) offers a "Type your own answer" option, the typed custom answer cannot be submitted. Pressing Enter after typing does nothing — it only inserts newlines into the input box. Selecting one of the predefined options works fine; only the custom free-text path is broken.Environment
v1.15.13(latest release at time of filing)Steps to reproduce
opencodeTUI session, trigger any question that allows a custom answer (customdefaults totrue), so the dialog shows numbered options plus a final "Type your own answer" row.Expected
The typed text is submitted as the answer (
question.reply), the same way pressing Enter on a predefined option submits it.Actual
Enter does nothing except add blank lines in the input box. There is no way to confirm/send the custom answer (and no mouse "submit" affordance either). The only escape is Esc to dismiss the question entirely.
Root cause
In the interactive TUI question component,
packages/opencode/src/cli/cmd/tui/routes/session/question.tsx(QuestionPrompt):store.editing = trueand focuses an@opentui/core<textarea>(viaval.focus()in theref).A focused textarea consumes the Enter keypress itself (newline insertion, up to
maxHeight={6}), so the key never reaches theuseBindingskeymap and thereturn -> submitbinding never fires.Proof that it's key delivery, not the submit logic: if the binding fired,
pick(text, true)would immediately callsdk.client.question.reply(...). It doesn't submit, so the binding is never reached. The only difference between the working option-selection path and the broken custom path is the focused textarea capturing the key.Why predefined options work but custom doesn't
useBindingsblock (enabled: !store.editing) and submit normally.In-repo reference implementation that handles this correctly
The direct-mode footer question UI,
packages/opencode/src/cli/cmd/run/footer.question.tsx(RunQuestionBody), handles the identical flow correctly by using a global imperative keyboard handler and explicitly preventing default while editing:That
event.preventDefault()is exactly what the interactive TUIQuestionPromptis missing.Suggested fix
Mirror the footer's approach in
QuestionPrompt(tui/routes/session/question.tsx): whilestore.editingis true, intercept Enter at a level that runs before the focused textarea (e.g. auseKeyboardhandler), invoke the existing submit logic, and callevent.preventDefault(). Reserve Shift+Enter for inserting a newline. The submit logic itself is already present and correct — only key delivery to it is broken.Notes
v1.15.13); the same textarea pattern appears to still be present onmain, so this is not fixed by updating.Permalinks (v1.15.13)