mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-05 02:31:47 +00:00
feat(tui): replace /clear double-press gate with a proper confirm overlay
The time-window gate felt wrong — users would hit /clear, read the prompt, retype, and consistently blow past the window. Swapping to a real yes/no overlay that blocks input like the existing Approval and Clarify prompts. - add ConfirmReq type + OverlayState.confirm + $isBlocked coverage - ConfirmPrompt component (prompts.tsx): cancel row on top as the default, danger-coloured confirm row on the bottom, Y/N hotkeys, Enter on default = cancel, Esc/Ctrl+C cancel - wire into PromptZone (appOverlays.tsx) - /clear + /new now push onto the overlay instead of arming a timer - HERMES_TUI_NO_CONFIRM=1 still skips the prompt for scripting - drop the destructiveGate + createSlashHandler reset wiring (destructive.ts and its tests removed) Refs #4069.
This commit is contained in:
parent
75377feb07
commit
df5ca5065f
9 changed files with 132 additions and 115 deletions
|
|
@ -1,65 +0,0 @@
|
|||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import { CONFIRM_WINDOW_MS, createDestructiveGate } from '../domain/destructive.js'
|
||||
|
||||
describe('createDestructiveGate', () => {
|
||||
it('uses a generous default window so real humans can retype (#4069)', () => {
|
||||
expect(CONFIRM_WINDOW_MS).toBeGreaterThanOrEqual(15_000)
|
||||
})
|
||||
|
||||
it('first request is not confirmed — it arms the gate', () => {
|
||||
const g = createDestructiveGate()
|
||||
expect(g.request('clear', 0)).toBe(false)
|
||||
})
|
||||
|
||||
it('second request within window with same key is confirmed', () => {
|
||||
const g = createDestructiveGate()
|
||||
g.request('clear', 0)
|
||||
expect(g.request('clear', CONFIRM_WINDOW_MS - 1)).toBe(true)
|
||||
})
|
||||
|
||||
it('second request outside the window re-arms and is not confirmed', () => {
|
||||
const g = createDestructiveGate()
|
||||
g.request('clear', 0)
|
||||
expect(g.request('clear', CONFIRM_WINDOW_MS + 1)).toBe(false)
|
||||
})
|
||||
|
||||
it('armed() reports the pending key while fresh, null otherwise', () => {
|
||||
const g = createDestructiveGate(100)
|
||||
expect(g.armed()).toBe(null)
|
||||
g.request('clear')
|
||||
expect(g.armed()).toBe('clear')
|
||||
g.reset()
|
||||
expect(g.armed()).toBe(null)
|
||||
})
|
||||
|
||||
it('different key re-arms the gate, does not confirm', () => {
|
||||
const g = createDestructiveGate()
|
||||
g.request('clear', 0)
|
||||
expect(g.request('undo', 500)).toBe(false)
|
||||
expect(g.request('undo', 900)).toBe(true)
|
||||
})
|
||||
|
||||
it('confirmation consumes the pending state so a third press re-arms', () => {
|
||||
const g = createDestructiveGate()
|
||||
g.request('clear', 0)
|
||||
g.request('clear', 500)
|
||||
expect(g.request('clear', 600)).toBe(false)
|
||||
})
|
||||
|
||||
it('reset clears pending state', () => {
|
||||
const g = createDestructiveGate()
|
||||
g.request('clear', 0)
|
||||
g.reset()
|
||||
expect(g.request('clear', 500)).toBe(false)
|
||||
})
|
||||
|
||||
it('respects a custom window', () => {
|
||||
const g = createDestructiveGate(100)
|
||||
g.request('clear', 0)
|
||||
expect(g.request('clear', 50)).toBe(true)
|
||||
|
||||
g.request('clear', 0)
|
||||
expect(g.request('clear', 150)).toBe(false)
|
||||
})
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue