Initial commit
This commit is contained in:
178
skills/interactive-commands/SKILL.md
Normal file
178
skills/interactive-commands/SKILL.md
Normal file
@@ -0,0 +1,178 @@
|
||||
---
|
||||
name: using-tmux-for-interactive-commands
|
||||
description: Use when you need to run interactive CLI tools (vim, git rebase -i, Python REPL, etc.) that require real-time input/output - provides tmux-based approach for controlling interactive sessions through detached sessions and send-keys
|
||||
---
|
||||
|
||||
# Using tmux for Interactive Commands
|
||||
|
||||
## Overview
|
||||
|
||||
Interactive CLI tools (vim, interactive git rebase, REPLs, etc.) cannot be controlled through standard bash because they require a real terminal. tmux provides detached sessions that can be controlled programmatically via `send-keys` and `capture-pane`.
|
||||
|
||||
## When to Use
|
||||
|
||||
**Use tmux when:**
|
||||
- Running vim, nano, or other text editors programmatically
|
||||
- Controlling interactive REPLs (Python, Node, etc.)
|
||||
- Handling interactive git commands (`git rebase -i`, `git add -p`)
|
||||
- Working with full-screen terminal apps (htop, etc.)
|
||||
- Commands that require terminal control codes or readline
|
||||
|
||||
**Don't use for:**
|
||||
- Simple non-interactive commands (use regular Bash tool)
|
||||
- Commands that accept input via stdin redirection
|
||||
- One-shot commands that don't need interaction
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Task | Command |
|
||||
| -------------- | ----------------------------------------- |
|
||||
| Start session | `tmux new-session -d -s <name> <command>` |
|
||||
| Send input | `tmux send-keys -t <name> 'text' Enter` |
|
||||
| Capture output | `tmux capture-pane -t <name> -p` |
|
||||
| Stop session | `tmux kill-session -t <name>` |
|
||||
| List sessions | `tmux list-sessions` |
|
||||
|
||||
## Core Pattern
|
||||
|
||||
### Before (Won't Work)
|
||||
```bash
|
||||
# This hangs because vim expects interactive terminal
|
||||
bash -c "vim file.txt"
|
||||
```
|
||||
|
||||
### After (Works)
|
||||
```bash
|
||||
# Create detached tmux session
|
||||
tmux new-session -d -s edit_session vim file.txt
|
||||
|
||||
# Send commands (Enter, Escape are tmux key names)
|
||||
tmux send-keys -t edit_session 'i' 'Hello World' Escape ':wq' Enter
|
||||
|
||||
# Capture what's on screen
|
||||
tmux capture-pane -t edit_session -p
|
||||
|
||||
# Clean up
|
||||
tmux kill-session -t edit_session
|
||||
```
|
||||
|
||||
## Implementation
|
||||
|
||||
### Basic Workflow
|
||||
|
||||
1. **Create detached session** with the interactive command
|
||||
2. **Wait briefly** for initialization (100-500ms depending on command)
|
||||
3. **Send input** using `send-keys` (can send special keys like Enter, Escape)
|
||||
4. **Capture output** using `capture-pane -p` to see current screen state
|
||||
5. **Repeat** steps 3-4 as needed
|
||||
6. **Terminate** session when done
|
||||
|
||||
### Special Keys
|
||||
|
||||
Common tmux key names:
|
||||
- `Enter` - Return/newline
|
||||
- `Escape` - ESC key
|
||||
- `C-c` - Ctrl+C
|
||||
- `C-x` - Ctrl+X
|
||||
- `Up`, `Down`, `Left`, `Right` - Arrow keys
|
||||
- `Space` - Space bar
|
||||
- `BSpace` - Backspace
|
||||
|
||||
### Working Directory
|
||||
|
||||
Specify working directory when creating session:
|
||||
```bash
|
||||
tmux new-session -d -s git_session -c /path/to/repo git rebase -i HEAD~3
|
||||
```
|
||||
|
||||
### Helper Wrapper
|
||||
|
||||
Run the executable helper script `scripts/tmux-wrapper.sh`:
|
||||
```bash
|
||||
# Start session
|
||||
scripts/tmux-wrapper.sh start <session-name> <command> [args...]
|
||||
|
||||
# Send input
|
||||
scripts/tmux-wrapper.sh send <session-name> 'text' Enter
|
||||
|
||||
# Capture current state
|
||||
scripts/tmux-wrapper.sh capture <session-name>
|
||||
|
||||
# Stop
|
||||
scripts/tmux-wrapper.sh stop <session-name>
|
||||
```
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Python REPL
|
||||
```bash
|
||||
tmux new-session -d -s python python3 -i
|
||||
tmux send-keys -t python 'import math' Enter
|
||||
tmux send-keys -t python 'print(math.pi)' Enter
|
||||
tmux capture-pane -t python -p # See output
|
||||
tmux kill-session -t python
|
||||
```
|
||||
|
||||
### Vim Editing
|
||||
```bash
|
||||
tmux new-session -d -s vim vim /tmp/file.txt
|
||||
sleep 0.3 # Wait for vim to start
|
||||
tmux send-keys -t vim 'i' 'New content' Escape ':wq' Enter
|
||||
# File is now saved
|
||||
```
|
||||
|
||||
### Interactive Git Rebase
|
||||
```bash
|
||||
tmux new-session -d -s rebase -c /repo/path git rebase -i HEAD~3
|
||||
sleep 0.5
|
||||
tmux capture-pane -t rebase -p # See rebase editor
|
||||
# Send commands to modify rebase instructions
|
||||
tmux send-keys -t rebase 'Down' 'Home' 'squash' Escape
|
||||
tmux send-keys -t rebase ':wq' Enter
|
||||
```
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
### Not Waiting After Session Start
|
||||
**Problem:** Capturing immediately after `new-session` shows blank screen
|
||||
|
||||
**Fix:** Add brief sleep (100-500ms) before first capture
|
||||
```bash
|
||||
tmux new-session -d -s sess command
|
||||
sleep 0.3 # Let command initialize
|
||||
tmux capture-pane -t sess -p
|
||||
```
|
||||
|
||||
### Forgetting Enter Key
|
||||
**Problem:** Commands typed but not executed
|
||||
|
||||
**Fix:** Explicitly send Enter
|
||||
```bash
|
||||
tmux send-keys -t sess 'print("hello")' Enter # Note: Enter is separate argument
|
||||
```
|
||||
|
||||
### Using Wrong Key Names
|
||||
**Problem:** `tmux send-keys -t sess '\n'` doesn't work
|
||||
|
||||
**Fix:** Use tmux key names: `Enter`, not `\n`
|
||||
```bash
|
||||
tmux send-keys -t sess 'text' Enter # ✓
|
||||
tmux send-keys -t sess 'text\n' # ✗
|
||||
```
|
||||
|
||||
### Not Cleaning Up Sessions
|
||||
**Problem:** Orphaned tmux sessions accumulate
|
||||
|
||||
**Fix:** Always kill sessions when done
|
||||
```bash
|
||||
tmux kill-session -t session_name
|
||||
# Or check for existing: tmux has-session -t name 2>/dev/null
|
||||
```
|
||||
|
||||
## Real-World Impact
|
||||
|
||||
- Enables programmatic control of vim/nano for file editing
|
||||
- Allows automation of interactive git workflows (rebase, add -p)
|
||||
- Makes REPL-based testing/debugging possible
|
||||
- Unblocks any tool that requires terminal interaction
|
||||
- No need to build custom PTY management - tmux handles it all
|
||||
84
skills/interactive-commands/scripts/tmux-wrapper.sh
Executable file
84
skills/interactive-commands/scripts/tmux-wrapper.sh
Executable file
@@ -0,0 +1,84 @@
|
||||
#!/bin/bash
|
||||
# Simple wrapper around tmux for Claude Code to interact with interactive programs
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
ACTION="${1:-}"
|
||||
SESSION_NAME="${2:-}"
|
||||
|
||||
case "$ACTION" in
|
||||
start)
|
||||
COMMAND="${3:-bash}"
|
||||
shift 3 || true
|
||||
ARGS="$*"
|
||||
|
||||
# Create new detached session
|
||||
if [ -n "$ARGS" ]; then
|
||||
tmux new-session -d -s "$SESSION_NAME" "$COMMAND" "$@"
|
||||
else
|
||||
tmux new-session -d -s "$SESSION_NAME" "$COMMAND"
|
||||
fi
|
||||
|
||||
# Wait for initial output
|
||||
sleep 0.3
|
||||
|
||||
# Capture and display initial state
|
||||
echo "Session: $SESSION_NAME"
|
||||
echo "---"
|
||||
tmux capture-pane -t "$SESSION_NAME" -p
|
||||
;;
|
||||
|
||||
send)
|
||||
shift 2
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "Error: No input provided" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Send all arguments as separate keys (allows "Enter", "Escape", etc.)
|
||||
tmux send-keys -t "$SESSION_NAME" "$@"
|
||||
|
||||
# Wait a moment for output
|
||||
sleep 0.2
|
||||
|
||||
# Capture and display updated state
|
||||
echo "Session: $SESSION_NAME"
|
||||
echo "---"
|
||||
tmux capture-pane -t "$SESSION_NAME" -p
|
||||
;;
|
||||
|
||||
capture)
|
||||
echo "Session: $SESSION_NAME"
|
||||
echo "---"
|
||||
tmux capture-pane -t "$SESSION_NAME" -p
|
||||
;;
|
||||
|
||||
stop)
|
||||
tmux kill-session -t "$SESSION_NAME"
|
||||
echo "Session $SESSION_NAME terminated"
|
||||
;;
|
||||
|
||||
list)
|
||||
tmux list-sessions
|
||||
;;
|
||||
|
||||
*)
|
||||
cat <<EOF
|
||||
Usage: $0 <action> <session-name> [args...]
|
||||
|
||||
Actions:
|
||||
start <session-name> <command> [args...] - Start a new interactive session
|
||||
send <session-name> <input> - Send input to session (use Enter for newline)
|
||||
capture <session-name> - Capture current pane output
|
||||
stop <session-name> - Terminate session
|
||||
list - List all sessions
|
||||
|
||||
Examples:
|
||||
$0 start python_session python3 -i
|
||||
$0 send python_session 'print("hello")' Enter
|
||||
$0 capture python_session
|
||||
$0 stop python_session
|
||||
EOF
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user