Files
claude-cloak/.claude/skills/tui-verify/SKILL.md
2026-07-09 08:49:53 +02:00

99 lines
4.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: tui-verify
description: Drive and visually verify this TUI (claude-cloak, or any terminal app / embedded claude pane) by running it inside a headless tmux session, sending real keystrokes, and capturing the rendered screen as text. Use whenever you need to confirm a UI/pane/rendering change actually works end-to-end — not just that tests pass — e.g. "verify the pane expands", "does @ show the menu", "check the layout at a small size". Claude Code's own TUI cannot run in a non-tty, so tmux is the way to give it a real terminal.
---
# Verifying a TUI with tmux
The app renders to a real terminal and cannot run in a plain pipe. tmux gives it
a genuine tty in the background, lets you type into it, and lets you read back
exactly what's on screen as plain text — so you can *see* a rendering change
instead of guessing from tests.
## The safety rule (read first)
**Never use `pkill`, `killall`, `kill -9 <pattern>`, or any broad
process-matching kill.** The user runs their own real claude-cloak instances
(including the one hosting your session) on the same machine. `pkill -f
claude-cloak` will kill all of them. Only ever tear down tmux sessions **you
created, by their exact name**:
```bash
tmux kill-session -t <your-session-name> # only your own named session
```
Pick a distinctive session name (e.g. `ccverify`) so you never touch anything
else. Before starting, `tmux ls` to see what's already there and avoid name
clashes — never kill a session you didn't create.
## Core loop
1. **Build** the thing you're testing (`cargo build --release`).
2. **Launch** it in a detached tmux session, sized to the scenario you care
about. Small sizes (e.g. `-x 100 -y 20`) are what expose layout/overflow
bugs — a big terminal hides them.
```bash
tmux new-session -d -s ccverify -x 100 -y 20 "./target/release/claude-cloak"
sleep 2 # give it time to draw the first frame
```
3. **Capture** the rendered screen as text:
```bash
tmux capture-pane -t ccverify -p
```
Add `-e` to include ANSI escapes (then `| cat -A`) when you need to inspect
colors/attributes — e.g. which menu row is highlighted:
```bash
tmux capture-pane -t ccverify -p -e | cat -A
```
4. **Send keystrokes**, then `sleep` briefly (the app redraws on its own ~30fps
tick — give it 12s) and capture again:
```bash
tmux send-keys -t ccverify "a" # a literal key
tmux send-keys -t ccverify "Down" "Enter" # named keys
tmux send-keys -t ccverify "C-u" # ctrl-u (clear line)
tmux send-keys -t ccverify "@src" # a literal string
```
5. **Tear down your session by name** when done (see safety rule).
## send-keys gotchas
- Each space-separated token is interpreted as a **key name** (`Down`, `Enter`,
`Space`, `C-f`, `Escape`). So `send-keys "Down Down Down"` sends three Down
keys — but if the app has meanwhile changed state (e.g. a menu collapsed to a
single match and closed), the same tokens can land as literal text. If you see
literal `Down Down Down` in an input box, that's this — resend as needed.
- To send a literal string that contains spaces or key-like words, send it as
one quoted argument and/or use `-l` (literal): `tmux send-keys -l -t s "Down"`.
- Control/modifier chords: `C-u`, `C-f`, `C-q`, `S-Tab` (shift-tab). This app
avoids Alt on purpose — don't test Alt chords.
- After any keystroke, **sleep before capturing.** Captures taken mid-repaint
show a transient frame (a half-drawn box), which can look like a bug that
isn't there. 11.5s is usually enough.
## Reading the claude-cloak screen
- The bottom footer line shows the bound proxy port and the active keybinding
hints — a quick sanity check that the app is alive and in the expected mode.
- The embedded pane is the lower bordered box titled `claude · <id>`. Its
compact framing (`src/term.rs`) shows one context row, the input box (bracketed
by `──── … ──` rules), and either the statusLine (idle) or an `@`/`/` menu.
- To spawn an embedded claude pane for pane tests: press `a` (model picker),
navigate with `Down`, `Enter` to spawn. It resumes-then-clears to a fresh
chat. `ctrl-f` toggles fullscreen (shows the child's raw screen verbatim —
useful to see what Ink actually drew vs. what we crop).
## Why this beats tests alone
Unit tests over `compact_frame` / `compact_view_range` pin the framing math, but
they can't catch a PTY-sizing feedback loop where Ink never draws the rows we'd
measure — that only shows up when a real `claude` child renders into a real PTY.
Run the tmux loop for any change to pane sizing, cropping, cursor, or layout.