Skip to content

feat(tui): add a single-press session abort and /abort - #53656

Open
Nowaker wants to merge 2 commits into
anomalyco:devfrom
Nowaker:abort-keybind-feedback
Open

Nowaker wants to merge 2 commits into
anomalyco:devfrom
Nowaker:abort-keybind-feedback

Conversation

@Nowaker

@Nowaker Nowaker commented Oct 7, 2026 •

Copy link
Copy Markdown

Issue for this PR

Closes #53653

Stacked on #53655. The first commit belongs to that PR; this PR adds the second commit.

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

  • Adds a session.abort command that aborts on one press, with a new session_abort keybind (default alt+escape). Like any other keybind it accepts several keys, e.g. "alt+escape,ctrl+k". The bindings are registered only while the session is running, so a key shared with the input (ctrl+k deletes to end of line) still edits while the session is idle.
  • Makes the command available as /abort and in the command palette, without starting a turn. On an idle session it shows a toast instead.
  • Fixes a dropped double Escape. A terminal sends Escape as a bare ESC byte, so two presses that land in one read parse as alt+escape, and three or more as a key with no name. That happens when the main thread is busy while the user presses, and with a single tmux send-keys Escape Escape. session.interrupt never saw either key, so the turn kept running. With alt+escape as the default, two coalesced presses now abort, and a small event-match resolver in keymap.tsx maps a run of three or more ESC bytes to alt+escape as well.

session.interrupt and its two-press behavior are unchanged.

How did you verify your code works?

  • bun typecheck, and bun test in packages/tui (195 pass). The new keymap test feeds one, two and four ESC bytes and ctrl+k in single reads and checks which ones reach session.abort.

  • Ran the TUI from source with isolated XDG dirs in a throwaway tmux server, against a local fake provider that streams a long reply and logs when the client disconnects. To simulate a busy main thread, I sent SIGSTOP to the TUI process for the whole time both presses arrived, then resumed it.

    case before after
    Esc Esc while the TUI is blocked 0/3 aborted 3/3, aborting… 96-192ms after resume
    Esc Esc Esc while the TUI is blocked 0/3 aborted 3/3, 165-285ms
    same, plus 4 CPU hogs on the TUI's cores - 3/3 aborted
    tmux send-keys Escape Escape (one write) 0/2 aborted 3/3, 72-529ms
    ctrl+k (session_abort: "alt+escape,ctrl+k"), under load - aborting… 40-98ms, idle 140-179ms
    /abort + Enter - aborting… 102-125ms, idle 159-188ms

Screenshots / recordings

Footer after resuming a TUI that was blocked across Esc Esc:

before   ⬝⬝⬝⬝⬝⬝■■  esc interrupt        (turn keeps streaming)
after    ■■⬝⬝⬝⬝⬝⬝  aborting…

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

The second Escape reset the footer straight back to "esc interrupt",
and nothing else changed until the server finished cancelling the turn
and the session status went idle. Under load that gap is long enough
that the press looks ignored, so users keep pressing.

The double press now sets an "aborting…" state for the session before
the abort request is sent, shown in place of the interrupt hint. It
clears when the session goes idle. If the request fails it clears with
an error toast, and if the session is still running 15s later it clears
with a warning so the user knows to press again.

AI-Tool: opencode 1.18.34-vt-126-907b3bc518
AI-Model: anthropic/claude-opus-5-5
AI-Variant: high
AI-Platform: linux
AI-Harness: Vibeterm 52e9db3
AI-Session-ID: ses_eec446a24ffebz6buEl7LB2m3O
Interrupting a running session took two Escape presses, counted by the
`session.interrupt` command itself. Binding another key to
`session_interrupt` therefore still needed two presses, and there was no
slash command for it.

Add a `session.abort` command that aborts on one press. Its keybind is
`session_abort`, which accepts several keys like every other keybind.
It is also available as `/abort` and in the command palette. Its
bindings are active only while the session is running, so a key shared
with the input, such as ctrl+k (delete to end of line), keeps its
editing meaning while the session is idle. `/abort` on an idle session
shows a toast instead of being sent as a prompt.

The default is alt+escape, which also fixes a double Escape that is
silently dropped. A terminal sends Escape as a bare ESC byte, so two
presses that reach the TUI in one read parse as a single alt+escape,
and three or more as an unnamed key. That happens when the main thread
is busy rendering while the user presses, and with one
`tmux send-keys Escape Escape` call. None of those keys matched
`escape`, so the interrupt never counted. A run of three or more ESC
bytes now also resolves to alt+escape, so any burst of Escape presses
aborts.

AI-Tool: opencode 1.18.34-vt-126-907b3bc518
AI-Model: anthropic/claude-opus-5-5
AI-Variant: high
AI-Platform: linux
AI-Harness: Vibeterm 52e9db3
AI-Session-ID: ses_eec446a24ffebz6buEl7LB2m3O
@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE]: single-press session abort keybind and /abort; a double Escape read as one key is dropped

1 participant