Skip to content

feat(watch): quick actions — kill pane, abort turn, copy prompt, help overlay#34

Merged
jiunbae merged 2 commits into
mainfrom
feat/watch-quick-actions
May 5, 2026
Merged

feat(watch): quick actions — kill pane, abort turn, copy prompt, help overlay#34
jiunbae merged 2 commits into
mainfrom
feat/watch-quick-actions

Conversation

@jiunbae
Copy link
Copy Markdown
Member

@jiunbae jiunbae commented May 5, 2026

Summary

Promote muxa watch from a read-only picker into a command center.
Power users can now act on a selected agent row without leaving the
TUI:

  • c — copy the agent's last_prompt to the system clipboard
    (pbcopywl-copyxclip in order, falling back to
    /tmp/muxa-clip-<ts>.txt when none are present).
  • K — kill the pane via tmux kill-pane -t <pane_id>.
  • R — abort the current turn by sending Ctrl-C to the pane.
  • ? — toggle a help overlay listing every keybinding.

Keybindings

Key Action Confirm?
c Copy last prompt to clipboard no
K Kill the selected pane yes
R Abort current turn (Ctrl-C) yes
? Toggle help overlay no

K / R are capital — Shift required so accidental k (cursor up)
or r (refresh) presses don't blow up a pane or interrupt an agent.

Safety

  • Destructive actions gate on a y/N confirm popup that defaults to
    No. Only y / Y / Enter accept; n, Esc, Tab, arrow keys,
    q, even the same key that opened it — anything else cancels.
  • Disabled actions (e.g. K on a paneless agent, c on a row with no
    last_prompt) surface a one-line "not applicable" hint in the
    footer rather than silently doing nothing.
  • Action results land in a transient ~2 s footer hint
    (✔ killed pane main:2.0, ✗ kill-pane failed: …,
    ✔ copied prompt via pbcopy).

Design choices

  • Action dispatch is decoupled from the input handler. A new
    QuickAction enum is what handle_event returns; a separate
    dispatch_quick_action helper executes it via a &mut dyn Effects
    trait. Unit tests inject a RecorderEffects stub instead of
    shelling out to tmux / xclip — fast, hermetic, and lets us cover
    the success / failure / fallback paths.
  • No new dependencies. The popup uses the same ratatui
    centered_rect + Clear + Paragraph pattern as the existing
    preview overlay.
  • R is "abort current turn", not "restart". The spec called
    for re-launching the original command after Ctrl-C, but we don't
    reliably know that command across the Claude / Codex / Gemini
    wrappers. Pragmatic version is just to send Ctrl-C; users can
    retype the launch.

Test plan

  • cargo build --workspace
  • cargo test --workspace (15 new tests, all passing)
  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo fmt --all -- --check
  • Manual: open muxa watch, navigate to a Claude row, press
    ? and verify the overlay lists every binding
  • Manual: press K on a pane-bearing row → confirm popup appears
    → press n → popup closes, pane survives
  • Manual: press K again → press y → pane dies, footer shows
    ✔ killed pane … for ~2 s
  • Manual: press c on a row with a prompt → footer shows
    ✔ copied prompt via …; verify clipboard contains the prompt
  • Manual: press K on a paneless row → footer shows
    kill: no tmux pane on this row

🤖 Generated with Claude Code

jiunbae and others added 2 commits May 5, 2026 21:36
… overlay

Promote `muxa watch` from a read-only picker into a command center
without leaving the table. Four new keybindings act on the currently-
selected row:

  c — copy the agent's `last_prompt` to the system clipboard
      (pbcopy / wl-copy / xclip in order, with a `/tmp/muxa-clip-*.txt`
      fallback when none are present).
  K — kill the pane via `tmux kill-pane -t <pane_id>`. Capital so a
      fat-fingered `k` (move cursor up) can't blow up a pane.
  R — abort the current turn by sending Ctrl-C to the pane. Also
      capital. Spec originally framed this as "restart"; reduced
      to "abort" because we don't reliably know the original launch
      command across Claude / Codex / Gemini wrappers.
  ? — toggle a help overlay listing every keybinding.

Destructive actions (`K`, `R`) gate on a y/N confirm popup that
defaults to "No" — only `y` / `Y` / Enter accept; Esc / Tab / arrow
keys / any other character cancels. The popup is a centred ratatui
rect over the table, mirroring the existing `p` preview-popup pattern.

Action dispatch is split: a `QuickAction` enum + `dispatch_quick_action`
helper that takes a `&mut dyn Effects` so unit tests can record calls
without ever shelling out to tmux or the clipboard binaries. Outcome
lands in a ~2 s transient footer hint (`✔ killed pane main:2.0`,
`✗ kill-pane failed: …`, `✔ copied prompt via pbcopy`).

Disabled actions (e.g. `K` on a paneless agent row, `c` on a row with
no `last_prompt`) surface a one-line "not applicable" hint instead of
silently doing nothing — avoids the "I pressed the key, nothing
happened" failure mode.

Tests cover the action selection logic (`kill_action_disabled_for_paneless_row`,
`copy_action_uses_last_prompt`), the confirm popup state machine
(`confirm_popup_y_proceeds`, `_n_cancels`, `_esc_tab_arrow_all_cancel`,
`_enter_proceeds`), and the help overlay (`help_overlay_lists_every_binding`
snapshot).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jiunbae jiunbae merged commit e47452f into main May 5, 2026
6 checks passed
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.

1 participant