-
Notifications
You must be signed in to change notification settings - Fork 2
Description
Problem
The double Ctrl+C to exit functionality from sst/opencode#4900 was broken during a recent upstream merge. This feature prevents accidental exits by requiring users to press Ctrl+C twice within 2 seconds.
Currently, pressing Ctrl+C when the prompt is empty immediately exits the application, which is frustrating when users accidentally clear their prompt or hit Ctrl+C by mistake.
Expected Behavior
- First Ctrl+C press (with empty prompt): Show a warning toast "Press again to exit"
- Second Ctrl+C press within 2 seconds: Exit the application
- After 2 seconds: Reset the exit attempt counter
Current Behavior
Ctrl+C immediately exits when the prompt is empty, with no warning or confirmation.
Root Cause
During upstream merge, the tryExit function and lastExitAttempt tracking variable were lost from packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx. The code at line ~848-855 now directly calls exit() instead of the protective tryExit() wrapper.
Interestingly, the search.tsx component still has the tryExit implementation (lines 42-59), showing this pattern was preserved in some places but lost in the main prompt.
Acceptance Criteria
-
tryExit()function restored inpackages/opencode/src/cli/cmd/tui/component/prompt/index.tsx -
lastExitAttemptvariable tracks last exit attempt timestamp - Warning toast shows "Press again to exit" on first Ctrl+C
- Second Ctrl+C within 2 seconds actually exits
- Timer resets after 2 seconds of no activity
- Feature documented in
script/sync/fork-features.json(already present)
Implementation Details
Reference Implementation (from PR anomalyco#4900)
The original implementation adds these changes to prompt/index.tsx:
// After: const exit = useExit()
let lastExitAttempt = 0
async function tryExit() {
const now = Date.now()
if (now - lastExitAttempt < 2000) {
await exit()
return
}
lastExitAttempt = now
toast.show({
variant: "warning",
message: "Press again to exit",
duration: 2000,
})
}Then change the exit handler from:
if (keybind.match("app_exit", e)) {
if (store.prompt.input === "") {
await exit() // <-- Currently thisTo:
if (keybind.match("app_exit", e)) {
if (store.prompt.input === "") {
await tryExit() // <-- Should be thisFiles to Modify
| File | Change |
|---|---|
packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx:669 |
Add lastExitAttempt variable and tryExit() function after const exit = useExit() |
packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx:848-855 |
Replace exit() with tryExit() in app_exit keybind handler |
Reference: search.tsx Working Implementation
See packages/opencode/src/cli/cmd/tui/component/prompt/search.tsx:42-59 for the working pattern already in the codebase:
let lastExitAttempt = 0
async function tryExit() {
const now = Date.now()
if (now - lastExitAttempt < 2000) {
await exit()
return
}
lastExitAttempt = now
toast.show({
variant: "warning",
message: "Press again to exit",
duration: 2000,
})
}External References
- Original PR: sst/opencode#4900
- Author: @AmineGuitouni
- Fork integration commit:
9a8b8b019af0d18de5a6edeb1ae43a16689b5e77
Tasks
- Add
lastExitAttemptvariable after line 669 - Add
tryExit()function afterlastExitAttempt - Update exit handler at line ~850 to call
tryExit()instead ofexit() - Verify
useToasthook is imported (already present at line 31) - Test double Ctrl+C functionality
- Run
bun testin packages/opencode