control-cli
Control CLI
Use a repeatable local harness to exercise an interactive CLI instead of poking at it manually. First reuse the repo's own test/demo harness if it exists; otherwise assemble a temporary harness from standard local tools.
What It Is Used For
- Reproducing CLI/TUI bugs with deterministic input.
- Verifying keyboard flows, prompts, interrupts, resize behavior, and terminal layout.
- Capturing before/after transcripts for bug fixes.
- Profiling startup time, slow operations, hangs, or memory growth.
- Recording a short terminal demo when output is easier to show than explain.
Harness Loop
- Identify the command under test and the smallest reproducible workspace.
- Discover existing local harnesses: package scripts, e2e tests, demo recorders, expect scripts, or PTY helpers.
- If no harness exists, launch the CLI in an isolated terminal session with deterministic env vars.
- Capture the current screen before interacting.
- Send one action at a time: text, Enter, arrows, Escape, Ctrl-C, resize.
- Wait for a concrete screen pattern or prompt before the next action.
- Save the transcript and any profile artifacts.
- Kill the session cleanly.
Harness Options
- Repo-native harness: prefer checked-in scripts because they know the app's startup, env, and prompts.
tmux: managed sessions,capture-pane,send-keys, attach/detach.- PTY probe: use a short Python, Node, or Expect script when tmux is unavailable.
- Runtime inspector: use Node or Bun inspector for CPU profiles, heap snapshots, and live evaluation.
- Terminal recorder: use repo-local demo tools or asciinema-compatible tools when the user asks for a demo.
Minimal tmux Harness
SESSION="cli-harness-$(date +%s)"
tmux new-session -d -s "$SESSION" -- <command-under-test>
tmux capture-pane -pt "$SESSION"
tmux send-keys -t "$SESSION" "help" Enter
tmux capture-pane -pt "$SESSION"
tmux kill-session -t "$SESSION"
For Node CLIs:
NODE_OPTIONS="--inspect=127.0.0.1:0" tmux new-session -d -s "$SESSION" -- <node-cli-command>
Read the terminal output to find the inspector URL, then use Chrome DevTools-compatible tooling if profiling is needed.
Minimal PTY Harness
Use a PTY script when you need deterministic waits in a repo that does not have tmux or a demo harness. Keep it temporary unless the user asks to add a reusable test.
import os
import pty
import select
import subprocess
import time
master_fd, slave_fd = pty.openpty()
proc = subprocess.Popen(
["<command>", "<arg>"],
stdin=slave_fd,
stdout=slave_fd,
stderr=slave_fd,
close_fds=True,
)
os.close(slave_fd)
deadline = time.time() + 30
buffer = b""
while time.time() < deadline:
ready, _, _ = select.select([master_fd], [], [], 0.25)
if not ready:
continue
chunk = os.read(master_fd, 4096)
buffer += chunk
if b"<ready text>" in buffer:
os.write(master_fd, b"help\n")
break
print(buffer.decode(errors="replace"))
proc.terminate()
os.close(master_fd)
If the CLI needs richer terminal control, use pty.fork() or an existing PTY library.
Profiling Recipes
- Startup regression: capture baseline and treatment startup timings under the same machine, env, and command.
- Slow operation: start a CPU profile, perform the operation, stop the profile, and compare top self-time functions.
- Memory leak: force GC if available, take a heap snapshot, perform the operation repeatedly, force GC again, and take another snapshot.
- Hang: capture the screen, active handles/resources, and a stack/CPU sample before interrupting.
Guardrails
- Prefer deterministic waits over sleeps. If you must sleep, explain why.
- Do not send credentials or destructive commands into a controlled session.
- Keep the harness in
/tmpunless the repo already has a testing/demo harness. - Do not hard-code paths from another repository. Adapt commands to the current repo's scripts and runtime.
- Clean up tmux sessions, temp dirs, inspector processes, and demo artifacts unless the user asks to keep them.
More from cursor/plugins
deslop
Remove AI-generated code slop and clean up code style
254fix-merge-conflicts
Resolve merge conflicts non-interactively, validate build and tests, and finalize conflict resolution
109continual-learning
Orchestrate continual learning by delegating transcript mining and AGENTS.md updates to `agents-memory-updater`.
83ralph-loop
Start a Ralph Loop for iterative self-referential development. Use when the user asks to run a ralph loop, start an iterative loop, or wants repeated autonomous iteration on a task until completion.
48check-compiler-errors
Run compile and type-check commands and report failures
46get-pr-comments
Fetch and summarize review comments from the active pull request
44