qwen-code/.qwen/skills/terminal-capture/SKILL.md
易良 202be6ec7d
Some checks are pending
Qwen Code CI / Lint (push) Waiting to run
Qwen Code CI / Test (push) Blocked by required conditions
Qwen Code CI / Test-1 (push) Blocked by required conditions
Qwen Code CI / Test-2 (push) Blocked by required conditions
Qwen Code CI / Test-3 (push) Blocked by required conditions
Qwen Code CI / Test-4 (push) Blocked by required conditions
Qwen Code CI / Test-5 (push) Blocked by required conditions
Qwen Code CI / Test-6 (push) Blocked by required conditions
Qwen Code CI / Test-7 (push) Blocked by required conditions
Qwen Code CI / Test-8 (push) Blocked by required conditions
Qwen Code CI / Post Coverage Comment (push) Blocked by required conditions
Qwen Code CI / CodeQL (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run
feat(vscode): expose /skills as slash command with secondary picker (#2548)
* feat(vscode): expose /skills as slash command with secondary picker

Add a secondary completion picker for the /skills slash command in the
VSCode IDE companion, allowing users to browse and select skills from
a dropdown before sending.

Changes:
- CLI: add 'skills' to ALLOWED_BUILTIN_COMMANDS_NON_INTERACTIVE whitelist
- CLI: send available_skills_update via ACP with skill names/descriptions
- Extension: handle available_skills_update in session update handler
- Webview: implement secondary picker that triggers after selecting /skills
- Webview: allow spaces in completion trigger for /skills sub-queries

Closes #1562

Made-with: Cursor

* feat(vscode-ide-companion): embed skills in commands update metadata

- Move available skills from separate session update to _meta field of
  available_commands_update for more efficient delivery
- Simplify skill data to just skill names (string array)
- Add skillsCompletion utility for secondary picker logic
- Cache available skills in WebViewProvider for replay on webview ready
- Update all related types and handlers to support the new structure

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* refactor(vscode-ide-companion): simplify skills picker flow

* refactor(vscode-ide-companion): extract skills completion utils to shared module

Move `isSkillsSecondaryQuery`, `shouldOpenSkillsSecondaryPicker`, and
`SKILL_ITEM_ID_PREFIX` from App.tsx and useCompletionTrigger.ts into a
shared `completionUtils.ts` file to eliminate duplication.

* fix(vscode-ide-companion): restore skills picker state on reload

Cache and replay available skills when the webview becomes ready again.

Clear stale skills when commands metadata does not include availableSkills.

* fix(vscode-ide-companion): replay slash commands after webview reload

Cache available commands in the webview provider.

Replay them on webviewReady so slash command state survives reloads.

* fix(vscode-ide-companion): import AvailableCommand from ACP SDK

* fix(vscode-ide-companion): fallback /skills to direct command

* test(vscode-ide-companion): cover skills secondary picker flow

* test(vscode-ide-companion): guard App mock initialization

* fix(vscode-ide-companion): remove duplicate AvailableCommand import

The auto-merge introduced a duplicate AvailableCommand in the
@agentclientprotocol/sdk import block, causing TS2300.

* fix(vscode-ide-companion): remove duplicate availableCommands replay in handleWebviewReady

The handleWebviewReady method was sending cachedAvailableCommands twice
on every webview-ready handshake, causing an unnecessary extra state
update in the webview.

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-24 23:28:53 +08:00

7.5 KiB

name description
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.

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.ts Low-level PTY, xterm.js, and Playwright engine.
  • integration-tests/terminal-capture/scenario-runner.ts Scenario executor for config, interactions, and screenshots.
  • integration-tests/terminal-capture/run.ts CLI entry point for batch scenario runs.
  • 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'],
  // 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 found Cause: 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)
}