claudedo/src/claudedo/keys.py
disqualifier d96dc3898f feat: backspace/space/erase editing commands + colored prefixed console
voice editing: 'space [<n>]' inserts spaces, 'backspace [<n>]' (alias delete)
deletes chars, 'erase' (alias clear/wipe) wipes the current input. the daemon
tracks a per-session uncommitted-input char count so backspace is capped at the
last submit boundary and erase clears exactly back to it; submit/set reset it.
keys.py gains BSpace/space; grammar gains a count parser (digits + number words).

new console.py renders every daemon line as 'HH:MM:SS [prefix] message' with
color: [<session>] for injected lines (green), [SYSTEM] for state, [VOICE] for
recognition/drops (red/dim). bump to 0.1.2.

Signed-off-by: disqualifier <dev@disqualifier.me>
2026-06-26 01:17:22 -04:00

57 lines
2.0 KiB
Python

"""the claude code prompt keymap — single source of truth.
these keystrokes were confirmed empirically against a live ``claude`` v2.1.191
session in a throwaway tmux session (capture-pane observation of benign prompts:
the folder-trust prompt and a bash-command permission prompt). do not guess or
assume — if claude code changes its prompt ui, re-confirm against a live session
and update here.
confirmed behaviour (claude code v2.1.191):
- numbered select menus (trust prompt, permission prompt): pressing the bare
digit selects AND confirms IMMEDIATELY. NO trailing enter. (sending an extra
enter would leak into the next prompt or the input box.)
- arrow keys (Up/Down) move the highlight WITHOUT acting; Enter then confirms —
available as a robust alternative, modelled as a sequence.
- the permission prompt is "1. Yes / 2. Yes, and don't ask again / 3. No".
- Escape backs out of / cancels a prompt ("Esc to cancel" footer).
- the main input box: literal text is inserted via ``send-keys -l`` without
submitting; a bare Enter submits.
each value is a list of tmux key tokens to send in order. a single-element list
is a single keypress. ``type`` literal text is handled separately by inject.py
via ``send-keys -l`` and is not part of this keymap.
"""
YES = ["1"]
NO = ["3"]
SELECT_1 = ["1"]
SELECT_2 = ["2"]
SELECT_3 = ["3"]
SELECT_4 = ["4"]
APPROVE = ["1"]
APPROVE_ALWAYS = ["2"]
DENY = ["3"]
SUBMIT = ["Enter"]
CANCEL = ["Escape"]
# BACKSPACE deletes one char left; SPACE inserts one literal space. both are emitted
# repeatedly for `backspace <n>` / `space <n>` and for `erase` (n = the daemon's
# tracked uncommitted-input count). BSpace is tmux's name for the backspace key.
BACKSPACE = ["BSpace"]
SPACE = [" "]
SELECT_BY_INDEX = {
1: SELECT_1,
2: SELECT_2,
3: SELECT_3,
4: SELECT_4,
}
SELECT_1_ARROW = ["Up", "Up", "Up", "Enter"]
SELECT_2_ARROW = ["Up", "Up", "Enter"]
SELECT_3_ARROW = ["Up", "Enter"]
SELECT_4_ARROW = ["Enter"]