Qwen-code terminal-capture

Automates terminal UI screenshot testing for CLI commands. Applies when reviewing PRs that affect CLI output, testing slash commands (/about, /context, /auth, /export), generating visual documentation, or when 'terminal screenshot', 'CLI test', 'visual test', or 'terminal-capture' is mentioned.

install
source · Clone the upstream repo
git clone https://github.com/QwenLM/qwen-code
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/QwenLM/qwen-code "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.qwen/skills/terminal-capture" ~/.claude/skills/qwenlm-qwen-code-terminal-capture && rm -rf "$T"
manifest: .qwen/skills/terminal-capture/SKILL.md
source content

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 (including node-pty, xterm, playwright, etc.)
npx playwright install chromium   # Install Playwright browser

Architecture

node-pty (pseudo-terminal) → ANSI byte stream → xterm.js (Playwright headless) → Screenshot

Core files:

FilePurpose
integration-tests/terminal-capture/terminal-capture.ts
Low-level engine (PTY + xterm.js + Playwright)
integration-tests/terminal-capture/scenario-runner.ts
Scenario executor (parses config, drives interactions, auto-screenshots)
integration-tests/terminal-capture/run.ts
CLI entry point (batch run scenarios)
integration-tests/terminal-capture/scenarios/*.ts
Scenario 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'],
  terminal: { title: 'qwen-code', cwd: '../../..' }, // Relative to this config file's location
  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}/
:

FileDescription
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) → Press Enter → Wait for output to stabilize → 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

IssueCauseSolution
Playwright error
browser not found
Browser not installed
npx playwright install chromium
Blank screenshotProcess starts slowly or build failedEnsure
npm run build
succeeds, check spawn command
PTY-related errorsnode-pty native module not compiled
npm rebuild node-pty
Unstable screenshot outputTerminal output not fully renderedCheck if the scenario needs additional 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)
}