terminal-capture
Terminal Capture — CLI Terminal Screenshot Automation
Drive terminal interactions and screenshots via TypeScript configuration, used for visual verification during PR reviews.
Prerequisites
Ensure the following dependencies are installed before running:
npm install # Install project dependencies.
npx playwright install chromium # Install Playwright browser
Architecture
node-pty (pseudo-terminal)
→ ANSI byte stream
→ xterm.js (Playwright headless)
→ Screenshot
Core files:
integration-tests/terminal-capture/terminal-capture.tsLow-level PTY, xterm.js, and Playwright engine.integration-tests/terminal-capture/scenario-runner.tsScenario executor for config, interactions, and screenshots.integration-tests/terminal-capture/run.tsCLI entry point for batch scenario runs.integration-tests/terminal-capture/scenarios/*.tsScenario configuration files.
Quick Start
1. Write Scenario Configuration
Create a .ts file under integration-tests/terminal-capture/scenarios/:
import type { ScenarioConfig } from '../scenario-runner.js';
export default {
name: '/about',
spawn: ['node', 'dist/cli.js', '--yolo'],
// cwd is relative to this config file's location.
terminal: { title: 'qwen-code', cwd: '../../..' },
flow: [
{ type: 'Hi, can you help me understand this codebase?' },
{ type: '/about' },
],
} satisfies ScenarioConfig;
2. Run
# Single scenario
npx tsx integration-tests/terminal-capture/run.ts \
integration-tests/terminal-capture/scenarios/about.ts
# Batch (entire directory)
npx tsx integration-tests/terminal-capture/run.ts \
integration-tests/terminal-capture/scenarios/
3. Output
Screenshots are saved to
integration-tests/terminal-capture/scenarios/screenshots/{name}/:
| File | Description |
|---|---|
01-01.png |
Step 1 input state |
01-02.png |
Step 1 execution result |
02-01.png |
Step 2 input state |
02-02.png |
Step 2 execution result |
full-flow.png |
Final state full-length screenshot |
FlowStep API
Each flow step can contain the following fields:
type: string — Input Text
Automatic behavior: Input text → Screenshot (01) → Enter → stable output → Screenshot (02).
{
type: 'Hello';
} // Plain text
{
type: '/about';
} // Slash command (auto-completion handled automatically)
Special rule: If the next step is key, do not auto-press Enter (hand over
control to the key sequence).
key: string | string[] — Send Key Press
Used for menu selection, Tab completion, and other interactions. Does not auto-press Enter or auto-screenshot.
Supported key names: ArrowUp, ArrowDown, ArrowLeft, ArrowRight, Enter,
Tab, Escape, Backspace, Space, Home, End, PageUp, PageDown,
Delete
{
key: 'ArrowDown';
} // Single key
{
key: ['ArrowDown', 'ArrowDown', 'Enter'];
} // Multiple keys
Auto-screenshot is triggered after the key sequence ends (when the next step is
not a key).
streaming — Capture During Execution
Capture multiple screenshots at intervals during long-running output (e.g., progress bars). Optionally generates an animated GIF.
{
type: 'Run this command: bash progress.sh',
streaming: {
delayMs: 7000, // Wait before first capture (skip initial waiting phase)
intervalMs: 500, // Interval between captures
count: 20, // Maximum number of captures
gif: true, // Generate animated GIF (default: true, requires ffmpeg)
},
}
delayMs(optional): Milliseconds to wait after pressing Enter before starting captures. Useful for skipping model thinking/approval time.- Captures stop early if terminal output is unchanged for 3 consecutive intervals.
- Duplicate frames (no output change) are automatically skipped.
GIF prerequisite: If the scenario uses streaming with GIF enabled
(default), check if ffmpeg is installed before running. If not, ask the user
whether they'd like to install it:
# Check
which ffmpeg
# Install (macOS)
brew install ffmpeg
If the user declines, the scenario still runs. GIF generation is skipped with a warning.
capture / captureFull — Explicit Screenshot
Use as a standalone step, or override automatic naming:
{
capture: 'initial.png';
} // Screenshot current viewport only
{
captureFull: 'all-output.png';
} // Screenshot full scrollback buffer
Scenario Examples
Basic: Input + Command
flow: [{ type: 'explain this project' }, { type: '/about' }];
Secondary Menu Selection (/auth)
flow: [
{ type: '/auth' },
{ key: 'ArrowDown' }, // Select API Key option
{ key: 'Enter' }, // Confirm
{ type: 'sk-xxx' }, // Input API key
];
Tab Completion Selection (/export)
flow: [
{ type: 'Tell me about yourself' },
{ type: '/export' }, // No auto-Enter (next step is key)
{ key: 'Tab' }, // Pop format selection
{ key: 'ArrowDown' }, // Select format
{ key: 'Enter' }, // Confirm → auto-screenshot
];
Array Batch (Multiple Scenarios in One File)
export default [
{ name: '/about', spawn: [...], flow: [...] },
{ name: '/context', spawn: [...], flow: [...] },
] satisfies ScenarioConfig[];
Integration with PR Review
This tool is commonly used for visual verification during PR reviews.
Troubleshooting
- Playwright error
browser not foundCause: browser not installed. Solution:npx playwright install chromium. - Blank screenshot Cause: process starts slowly or build failed. Solution: check build success and the spawn command.
- PTY-related errors
Cause: node-pty native module not compiled.
Solution:
npm rebuild node-pty. - Unstable screenshot output Cause: terminal output not fully rendered. Solution: add scenario wait time.
Full ScenarioConfig Type
interface FlowStep {
type?: string; // Input text
key?: string | string[]; // Key press(es)
capture?: string; // Viewport screenshot filename
captureFull?: string; // Full scrollback screenshot filename
streaming?: {
delayMs?: number; // Delay before first capture (default: 0)
intervalMs: number; // Interval between captures in ms
count: number; // Maximum number of captures
gif?: boolean; // Generate animated GIF (default: true)
};
}
interface ScenarioConfig {
name: string; // Scenario name (also used as screenshot subdirectory name)
spawn: string[]; // Launch command ["node", "dist/cli.js", "--yolo"]
flow: FlowStep[]; // Interaction steps
terminal?: {
cols?: number; // Number of columns, default 100
rows?: number; // Number of rows, default 28
theme?: string; // Theme: dracula|one-dark|github-dark|monokai|night-owl
chrome?: boolean; // macOS window decorations, default true
title?: string; // Window title, default "Terminal"
fontSize?: number; // Font size
cwd?: string; // Working directory (relative to config file)
};
outputDir?: string; // Screenshot output directory (relative to config file)
}
More from qwenlm/qwen-code
docs-audit-and-refresh
Audit the repository's docs/ content against the current codebase,
5docs-update-from-diff
Review local code changes with git diff and update the official
4e2e-testing
Guide for running end-to-end tests of the Qwen Code CLI, including
3qwen-code-claw
Use Qwen Code as a Code Agent for code understanding, project
3pr-review
Reviews pull requests with code analysis and terminal smoke testing. Applies when examining code changes, running CLI tests, or when 'PR review', 'code review', 'terminal screenshot', 'visual test' is mentioned.
2structured-debugging
Hypothesis-driven debugging methodology for hard bugs. Use this
2