Implement double-escape session abort matching TUI behavior

- Add double-escape debounce pattern with 1-second timeout
- First escape shows warning, second escape aborts session
- Fix session busy check to handle undefined timeCompleted field
- Add abortSession API call to sessions store
- Show visual feedback in prompt input during debounce
- Remove Escape from filtered keys in prompt-input auto-focus
This commit is contained in:
Shantur Rathore
2025-10-24 16:09:32 +01:00
parent 6f31ffc467
commit e3bc947195
4 changed files with 109 additions and 19 deletions

View File

@@ -1,8 +1,31 @@
import { keyboardRegistry } from "../keyboard-registry"
type EscapeKeyState = "idle" | "firstPress"
const ESCAPE_DEBOUNCE_TIMEOUT = 1000
let escapeKeyState: EscapeKeyState = "idle"
let escapeTimeoutId: number | null = null
let onEscapeStateChange: ((inDebounce: boolean) => void) | null = null
export function setEscapeStateChangeHandler(handler: (inDebounce: boolean) => void) {
onEscapeStateChange = handler
}
function resetEscapeState() {
escapeKeyState = "idle"
if (escapeTimeoutId !== null) {
clearTimeout(escapeTimeoutId)
escapeTimeoutId = null
}
if (onEscapeStateChange) {
onEscapeStateChange(false)
}
}
export function registerEscapeShortcut(
isSessionBusy: () => boolean,
interruptSession: () => void,
abortSession: () => Promise<void>,
blurInput: () => void,
closeModal: () => void,
) {
@@ -15,14 +38,27 @@ export function registerEscapeShortcut(
if (hasOpenModal) {
closeModal()
resetEscapeState()
return
}
if (isSessionBusy()) {
interruptSession()
if (escapeKeyState === "idle") {
escapeKeyState = "firstPress"
if (onEscapeStateChange) {
onEscapeStateChange(true)
}
escapeTimeoutId = window.setTimeout(() => {
resetEscapeState()
}, ESCAPE_DEBOUNCE_TIMEOUT)
} else if (escapeKeyState === "firstPress") {
resetEscapeState()
abortSession()
}
return
}
resetEscapeState()
blurInput()
},
description: "cancel/close",