Skip to content

Commit b73e831

Browse files
committed
feat: add tmux-viewer TUI for viewing CLI test sessions
- Add scripts/tmux/tmux-viewer/ with OpenTUI session viewer - Session replay with timeline navigation - GIF export functionality - Themed terminal output display
1 parent 6034c19 commit b73e831

File tree

17 files changed

+1756
-6
lines changed

17 files changed

+1756
-6
lines changed

.agents/tsconfig.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
"baseUrl": ".",
55
"skipLibCheck": true,
66
"types": ["bun", "node"],
7+
"jsx": "react-jsx",
8+
"jsxImportSource": "@opentui/react",
79
"paths": {
810
"@codebuff/sdk": ["../sdk/src/index.ts"],
911
"@codebuff/common/*": ["../common/src/*"]
1012
}
1113
},
12-
"include": ["**/*.ts"]
14+
"include": ["**/*.ts", "**/*.tsx"]
1315
}

bun.lock

Lines changed: 54 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cli/knowledge.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ SESSION=$(./scripts/tmux/tmux-cli.sh start)
5353
./scripts/tmux/tmux-cli.sh capture "$SESSION" --wait 2 --label "after-help"
5454

5555
# View session data
56-
bun .agents/tmux-viewer/index.tsx "$SESSION" --json
56+
bun scripts/tmux/tmux-viewer/index.tsx "$SESSION" --json
5757

5858
# Clean up
5959
./scripts/tmux/tmux-cli.sh stop "$SESSION"

cli/tmux.knowledge.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,13 @@ Use the **tmux-viewer** to inspect sessions:
5151

5252
```bash
5353
# Interactive TUI (for humans)
54-
bun .agents/tmux-viewer/index.tsx <session-name>
54+
bun scripts/tmux/tmux-viewer/index.tsx <session-name>
5555

5656
# JSON output (for AI consumption)
57-
bun .agents/tmux-viewer/index.tsx <session-name> --json
57+
bun scripts/tmux/tmux-viewer/index.tsx <session-name> --json
5858

5959
# List available sessions
60-
bun .agents/tmux-viewer/index.tsx --list
60+
bun scripts/tmux/tmux-viewer/index.tsx --list
6161
```
6262

6363
### CLI Tmux Tester Agent

knowledge.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ Prefer `ErrorOr<T>` return values (`success(...)`/`failure(...)` in `common/src/
9999

100100
CLI hook testing note: React 19 + Bun + RTL `renderHook()` is unreliable; prefer integration tests via components for hook behavior.
101101

102+
### CLI tmux Testing
103+
104+
For testing CLI behavior via tmux, use the helper scripts in `scripts/tmux/`. These handle bracketed paste mode and session logging automatically. Session data is saved to `debug/tmux-sessions/` in YAML format and can be viewed with `bun scripts/tmux/tmux-viewer/index.tsx`. See `scripts/tmux/README.md` for details.
105+
102106
## Environment Variables
103107

104108
Quick rules:

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"license": "Apache-2.0",
66
"type": "module",
77
"workspaces": [
8+
".agents",
89
"common",
910
"web",
1011
"packages/*",
@@ -35,6 +36,8 @@
3536
},
3637
"dependencies": {
3738
"@t3-oss/env-nextjs": "^0.7.3",
39+
"canvas": "^3.2.0",
40+
"gif-encoder-2": "^1.0.5",
3841
"zod": "^4.2.1"
3942
},
4043
"overrides": {
@@ -44,6 +47,7 @@
4447
"devDependencies": {
4548
"@tanstack/react-query": "^5.90.12",
4649
"@types/bun": "^1.3.5",
50+
"@types/js-yaml": "^4.0.9",
4751
"@types/lodash": "^4.17.21",
4852
"@types/node": "^22.9.0",
4953
"@types/node-fetch": "^2.6.12",

scripts/tmux/package.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"name": "@codebuff/tmux-scripts",
3+
"version": "0.0.1",
4+
"private": true,
5+
"type": "module",
6+
"scripts": {
7+
"view-session": "bun run tmux-viewer/index.tsx"
8+
}
9+
}

scripts/tmux/tmux-viewer/README.md

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
# tmux-viewer
2+
3+
Interactive TUI for viewing tmux session logs. Designed to work for **both humans and AIs**.
4+
5+
## Usage
6+
7+
```bash
8+
# Interactive TUI (for humans)
9+
bun scripts/tmux/tmux-viewer/index.tsx <session-name>
10+
11+
# Start in replay mode (auto-plays through captures like a video)
12+
bun scripts/tmux/tmux-viewer/index.tsx <session-name> --replay
13+
14+
# JSON output (for AIs)
15+
bun scripts/tmux/tmux-viewer/index.tsx <session-name> --json
16+
17+
# Export as animated GIF
18+
bun scripts/tmux/tmux-viewer/index.tsx <session-name> --export-gif output.gif
19+
20+
# Export with custom frame delay (default: 1500ms)
21+
bun scripts/tmux/tmux-viewer/index.tsx <session-name> --export-gif output.gif --frame-delay 2000
22+
23+
# Export with custom font size (default: 14px)
24+
bun scripts/tmux/tmux-viewer/index.tsx <session-name> --export-gif output.gif --font-size 16
25+
26+
# List available sessions
27+
bun scripts/tmux/tmux-viewer/index.tsx --list
28+
29+
# View most recent session (if no session specified)
30+
bun scripts/tmux/tmux-viewer/index.tsx
31+
```
32+
33+
Or using the npm script:
34+
35+
```bash
36+
cd scripts/tmux && bun run view-session <session-name>
37+
```
38+
39+
## Layout
40+
41+
The TUI uses a vertical layout designed for clarity:
42+
43+
```
44+
┌─────────────────────────────────────────────────────────────────┐
45+
│ Session: my-session 120x30 5 cmds 10 captures │ ← Header
46+
├─────────────────────────────────────────────────────────────────┤
47+
│ │
48+
│ ┌──────────────────┐ │
49+
│ │ [terminal output │ │ ← Capture
50+
│ │ centered in │ │ View
51+
│ │ muted border] │ │
52+
│ └──────────────────┘ │
53+
│ │
54+
├─ ⏸ Paused ──────────────────────────────────────────────────────┤
55+
│ ┌─○ [1] 12:00:00─┐ ┌─▶ [2] 12:00:05─┐ ┌─○ [3] 12:00:10─┐ │ ← Timeline
56+
│ │ initial-state │ │ after-command │ │ final-state │ │ Cards
57+
│ │ $ codebuff... │ │ $ /help │ │ $ /quit │ │
58+
│ └────────────────┘ └────────────────┘ └────────────────┘ │
59+
├─────────────────────────────────────────────────────────────────┤
60+
│ ▶ 2/10 @1.5s space: play/pause +/-: speed ←→: navigate │ ← Footer
61+
└─────────────────────────────────────────────────────────────────┘
62+
```
63+
64+
- **Header**: Session name, dimensions, command/capture counts
65+
- **Capture View**: Terminal output centered with a muted border showing exact capture dimensions
66+
- **Timeline**: Horizontal card-style navigation at the bottom, selected card stays centered
67+
- **Footer**: Playback status, position, speed, and keyboard shortcuts
68+
69+
## Features
70+
71+
### For Humans (Interactive TUI)
72+
- **Capture view**: Terminal output centered with visible boundary
73+
- **Timeline panel**: Card-style navigation at the bottom with label and triggering command
74+
- **Auto-centering**: Selected timeline card stays centered in view
75+
- **Metadata display**: Session info, dimensions, command count
76+
- **Replay mode**: Auto-play through captures like a video player
77+
- **Keyboard shortcuts**:
78+
- `` / `` or `h` / `l`: Navigate between captures
79+
- `Space`: Play/pause replay
80+
- `+` / `-`: Adjust playback speed (faster/slower)
81+
- `r`: Restart from beginning
82+
- `q` or Ctrl+C: Quit
83+
- Use the `--json` flag on the CLI entrypoint for JSON output
84+
85+
### Replay Mode
86+
87+
Replay mode auto-advances through captures chronologically, like a video player:
88+
89+
```bash
90+
# Start replay immediately
91+
bun scripts/tmux/tmux-viewer/index.tsx my-session --replay
92+
93+
# Or press Space in the TUI to start/stop replay
94+
```
95+
96+
**Playback controls:**
97+
- `Space` - Toggle play/pause
98+
- `+` or `=` - Speed up (shorter interval between captures)
99+
- `-` or `_` - Slow down (longer interval between captures)
100+
- `r` - Restart from the first capture
101+
- `` / `` - Navigate captures (automatically pauses replay)
102+
103+
**Available speeds:** 0.5s, 1.0s, 1.5s (default), 2.0s, 3.0s, 5.0s per capture
104+
105+
The timeline panel title shows `▶ Playing` or `⏸ Paused`, and the footer shows current position (e.g., `2/10`), playback speed (e.g., `@1.5s`), and controls.
106+
107+
### For AIs (JSON Output)
108+
Use the `--json` flag to get structured output:
109+
110+
```json
111+
{
112+
"session": {
113+
"session": "cli-test-1234567890",
114+
"started": "2025-01-01T12:00:00Z",
115+
"dimensions": { "width": 120, "height": 30 },
116+
"status": "active"
117+
},
118+
"commands": [
119+
{ "timestamp": "...", "type": "text", "input": "/help", "auto_enter": true }
120+
],
121+
"captures": [
122+
{
123+
"sequence": 1,
124+
"label": "initial-state",
125+
"timestamp": "...",
126+
"after_command": null,
127+
"dimensions": { "width": 120, "height": 30 },
128+
"path": "debug/tmux-sessions/.../capture-001-initial-state.txt",
129+
"content": "[terminal output]"
130+
}
131+
],
132+
"timeline": [
133+
{ "timestamp": "...", "type": "command", "data": {...} },
134+
{ "timestamp": "...", "type": "capture", "data": {...} }
135+
]
136+
}
137+
```
138+
139+
## Data Format
140+
141+
The viewer reads YAML-formatted session data from `debug/tmux-sessions/{session}/`:
142+
143+
- `session-info.yaml` - Session metadata
144+
- `commands.yaml` - Array of commands sent
145+
- `capture-*.txt` - Capture files with YAML front-matter
146+
147+
### Session Info (session-info.yaml)
148+
```yaml
149+
session: cli-test-1234567890
150+
started: 2025-01-01T12:00:00Z
151+
started_local: Wed Jan 1 12:00:00 PST 2025
152+
dimensions:
153+
width: 120
154+
height: 30
155+
status: active
156+
```
157+
158+
### Commands (commands.yaml)
159+
```yaml
160+
- timestamp: 2025-01-01T12:00:05Z
161+
type: text
162+
input: "/help"
163+
auto_enter: true
164+
```
165+
166+
### Capture Files (capture-001-label.txt)
167+
```yaml
168+
---
169+
sequence: 1
170+
label: initial-state
171+
timestamp: 2025-01-01T12:00:30Z
172+
after_command: null
173+
dimensions:
174+
width: 120
175+
height: 30
176+
---
177+
[terminal content here]
178+
```
179+
180+
## Integration with cli-ui-tester
181+
182+
The `@cli-ui-tester` agent can use this viewer to inspect session data:
183+
184+
```typescript
185+
// In cli-ui-tester output
186+
{
187+
captures: [
188+
{ path: "debug/tmux-sessions/cli-test-123/capture-001-initial.txt", label: "initial" }
189+
]
190+
}
191+
192+
// Parent agent can view the session
193+
// bun scripts/tmux/tmux-viewer/index.tsx cli-test-123 --json
194+
```
195+
196+
## GIF Export
197+
198+
The `--export-gif` flag renders the session replay as an animated GIF, perfect for:
199+
- Sharing CLI demonstrations
200+
- Embedding in documentation
201+
- Bug reports and issue tracking
202+
- Creating tutorials
203+
204+
### GIF Export Options
205+
206+
| Option | Description | Default |
207+
|--------|-------------|--------|
208+
| `--export-gif [path]` | Output file path | `<session>-<timestamp>.gif` |
209+
| `--frame-delay <ms>` | Delay between frames in milliseconds | `1500` |
210+
| `--font-size <px>` | Font size for terminal text | `14` |
211+
212+
### Examples
213+
214+
```bash
215+
# Basic export (auto-names the file)
216+
bun scripts/tmux/tmux-viewer/index.tsx my-session --export-gif
217+
218+
# Specify output path
219+
bun scripts/tmux/tmux-viewer/index.tsx my-session --export-gif demo.gif
220+
221+
# Fast playback (500ms per frame)
222+
bun scripts/tmux/tmux-viewer/index.tsx my-session --export-gif fast.gif --frame-delay 500
223+
224+
# Larger text for readability
225+
bun scripts/tmux/tmux-viewer/index.tsx my-session --export-gif large.gif --font-size 18
226+
```
227+
228+
### GIF Output
229+
230+
The exported GIF includes:
231+
- Terminal content rendered as monospace text
232+
- Frame labels showing capture sequence number and label
233+
- Timestamps for each frame
234+
- Dark terminal-style background
235+
- Automatic sizing based on terminal dimensions
236+
237+
## Development
238+
239+
```bash
240+
# Typecheck
241+
cd scripts/tmux/tmux-viewer && bun x tsc --noEmit
242+
243+
# Run directly
244+
bun scripts/tmux/tmux-viewer/index.tsx --list
245+
```

0 commit comments

Comments
 (0)