- name
- live-inspect
- description
- Use for one-off / single-question inspection of the running GitLens extension — examining UI state, reading logs, checking feature flags, dispatching a command, or asking "what does the live DOM look like right now". Reference for `vscode-inspector` MCP primitives. For iterative debug-and-fix loops on UI bugs (sweep → fix → re-verify), use `/live-exercise` instead.
# /live-inspect — Live Extension Inspection
Launch a real VS Code instance with GitLens loaded, then inspect UI elements, read logs, interact with views, and evaluate runtime values — all programmatically via Playwright.
## MCP Server (Preferred for Iterative Inspection)
The `vscode-inspector` MCP server provides a **persistent, interactive** session. It launches VS Code once and exposes tools for screenshot/click/inspect/rebuild cycles — much faster than the batch CLI for agentic feedback loops.
The server is auto-discovered via `.mcp.json` when Claude Code starts in this repo. When connected, these MCP tools are available:
| Tool | Purpose |
| --------------------- | ------------------------------------------------------------------------------------- |
| `launch` | Start VS Code with GitLens loaded (persistent session) |
| `teardown` | Close VS Code and clean up |
| `get_status` | Check if session is running |
| `screenshot` | Capture window or webview as inline image (capped at 1920px) |
| `execute_command` | Run any VS Code command by ID |
| `set_account` | Simulate a subscription so Pro-gated features unlock (`plan: "pro"`, … `"none"`) |
| `sign_in` | Sign in to a real GitKraken account (needs a persisted `session`; human-in-the-loop) |
| `click` | Click element by CSS selector (main UI or webview) |
| `type_text` | Type text into inputs |
| `press_key` | Press keyboard shortcuts |
| `inspect_dom` | Query DOM elements for text/HTML/attributes/shadowDOM |
| `aria_snapshot` | Get accessibility tree as YAML (supports webview iframes) |
| `evaluate` | Run JS in extension host with vscode API |
| `evaluate_in_webview` | Run JS in webview renderer (DOM, shadow DOM, computed styles) |
| `list_webviews` | Discover all open webviews with titles, dimensions, content status |
| `wait_for_webview` | Wait for a webview to finish loading and Lit hydration |
| `read_logs` | Search extension output logs |
| `read_console` | Read browser console messages/errors from the main process |
| `resize_window` | Resize VS Code window content area — only for explicit responsive-breakpoint testing |
| `rebuild_and_reload` | Build extension + restart extension host (**kills the evaluator bridge** — see below) |
### Reading host logs (gotchas)
- **`read_logs` uses `pattern`, NOT `filter`.** A wrong/unknown arg is silently ignored and it falls back to `pattern: "GitLens"` — so you only ever see the activation banner and wrongly conclude "no logs". Always: `read_logs({ pattern: "<tag>", last_n })`.
- `read_logs` DOES capture extension-**host** `console.log/warn/error` and GitLens `Logger.warn`/`info`/`error` (info+). It reads the GitLens **LogOutputChannel**, also on disk at `.vscode-test/user-data/logs/<TS>/window1/exthost/eamodio.gitlens/GitLens.log`. `read_console` is webview-only (does not see host logs).
- **`@debug`/`@trace` decorator logs are filtered out.** The channel defaults to `info`; GitLens' rich tracing is `debug`/`trace`. Console-mirroring (`Logger.isDebugging`) is gated on `ExtensionMode.Development`, but the inspector runs in **Test** mode → off. `gitlens.enableDebugLogging` (which runs `workbench.action.output.activeOutputLogLevel.debug`) does NOT take headless. So for ad-hoc host tracing, **instrument with `Logger.warn('[tag] …')`** (info+, always written) and read via `read_logs({ pattern: "[tag]" })`. `gitlens.outputLevel` is deprecated — don't rely on it.
### Typical Workflow
1. Call `launch` (once per session — takes ~10s)
2. Call `execute_command` to open the view you want to inspect
3. Call `list_webviews` to discover open webviews and their exact titles
4. Call `wait_for_webview { webview_title: "<title>" }` to wait for Lit hydration
5. Call `screenshot { target: "webview", webview_title: "<title>" }` or `aria_snapshot { webview_title: "<title>" }` to see the current state
6. Make code changes, then rebuild and reload (see below)
7. Call `screenshot` again to verify changes
8. Repeat steps 6-7 as needed
9. Call `teardown` when done
### Rebuilding After Code Changes
**Extension host code** (commands, providers, services, models, parsers — anything under `src/` outside `src/webviews/apps/`):
```
rebuild_and_reload { build_command: "pnpm run build:extension" }
```
This restarts the extension host with the new code on the same VS Code instance. **The evaluator bridge does not survive it** — it's the `--extensionTestsPath` entry point, which VS Code invokes only at workbench startup, so the restarted host never re-runs it or re-announces its (ephemeral) port. Screenshot/click/DOM tools keep working, but `evaluate`, `set_account` and `execute_command`'s fast path go with it. When you need those after an extension-host change, `teardown` + `launch` instead.
**Webview code** (Lit components, CSS, templates under `src/webviews/apps/`): No extension host restart needed. Build the webviews, then use the view's refresh command:
```
rebuild_and_reload { build_command: "pnpm run build:webviews" }
execute_command { command: "gitlens.views.graph.refresh" }
```
Every GitLens webview has a `gitlens.views.<name>.refresh` command (e.g. `gitlens.views.welcome.refresh`, `gitlens.views.graph.refresh`, `gitlens.views.commitDetails.refresh`). These fully reload the webview with fresh JS/CSS.
**Both changed**: Use `pnpm run build:quick` (builds extension + webviews, no linting), then refresh the relevant view.
### Quick Examples
Extension host code change:
```
launch {}
execute_command { command: "gitlens.showGraphView" }
screenshot {}
# ... edit extension host code ...
rebuild_and_reload { build_command: "pnpm run build:extension" }
screenshot {}
teardown
```
Webview code change:
```
launch {}
execute_command { command: "gitlens.showWelcomeView" }
inspect_dom { selector: "h1", in_webview: true }
# ... edit webview code ...
rebuild_and_reload { build_command: "pnpm run build:webviews" }
execute_command { command: "gitlens.views.welcome.refresh" }
inspect_dom { selector: "h1", in_webview: true }
teardown
```
## Batch CLI (Fallback for One-Shot Inspection)
`scripts/e2e-dev-inspect.mjs` — a general-purpose CLI that supports ordered, repeatable actions. Use this when the MCP server is not available or for quick one-off inspections.
### Two Modes
| Mode | Flag | ExtensionMode | `container.debugging` | `gitkraken.env` | `evaluate()` |
| --------------------- | ------------------ | ------------- | --------------------- | --------------- | ------------ |
| Development (default) | _(none)_ | Development | `true` | ✅ respected | ❌ |
| Test | `--with-evaluator` | Test | `false` | ❌ ignored | ✅ |
Use **Development mode** when you need `gitkraken.env` (e.g. testing feature flags against dev API).
Use **Test mode** when you need `evaluate()` to inspect runtime values (e.g. `vscode.env.machineId`).
## Common Recipes
### Inspect any view's DOM content
```bash
node scripts/e2e-dev-inspect.mjs --command gitlens.showWelcomeView --query-frame h1
```
The `--query-frame` action searches all frames (including nested webview iframes) for matching elements and prints their text content.
### Get the full accessibility tree of a view
```bash
node scripts/e2e-dev-inspect.mjs --command gitlens.showGraphView --aria
```
### Inspect a specific DOM element
```bash
node scripts/e2e-dev-inspect.mjs --command gitlens.showWelcomeView --aria-selector "[class*='header']"
```
### Click something, then inspect the result
```bash
node scripts/e2e-dev-inspect.mjs \
--command gitlens.showGraphView \
--click-frame "button.start-work" \
--pause 2000 \
--query-frame ".dialog-content h2"
```
### Read runtime values (requires --with-evaluator)
```bash
node scripts/e2e-dev-inspect.mjs --with-evaluator \
--eval "vscode.env.machineId" \
--eval "vscode.version" \
--eval "vscode.env.appName"
```
### Check feature flag behavior with dev environment
```bash
node scripts/e2e-dev-inspect.mjs --env dev \
--command gitlens.showWelcomeView \
--query-frame h1 \
--logs FeatureFlagService
```
### Search extension logs for any pattern
```bash
node scripts/e2e-dev-inspect.mjs --logs "error"
node scripts/e2e-dev-inspect.mjs --env dev --logs ConfigCat
```
### Take a screenshot
```bash
node scripts/e2e-dev-inspect.mjs --command gitlens.showGraphView --screenshot /tmp/graph.png
```
### Keep VS Code open for manual interaction
```bash
node scripts/e2e-dev-inspect.mjs --env dev --keep-open
```
### Add custom settings
```bash
node scripts/e2e-dev-inspect.mjs \
--setting "gitlens.currentLine.enabled=true" \
--setting "gitlens.hovers.currentLine.over=line" \
--command gitlens.showWelcomeView --aria
```
## WSL / SSH / Headless Linux
If VS Code is not installed natively in your Linux environment, use `--download-vscode`
to download a portable binary. Xvfb is started automatically if no `$DISPLAY` is set.
```bash
node scripts/e2e-dev-inspect.mjs --download-vscode --command gitlens.showGraphView --aria
```
Requires `xvfb` package for headless environments: `sudo apt-get install xvfb`
## How AI Agents Should Use This
**Prefer the MCP server** for iterative work. Call `launch` once (use `download_vscode: true` on WSL/SSH/headless Linux), then use tools in a loop. No output parsing needed — tools return structured results directly.
### Token & round-trip discipline
How you drive inspection decides whether it's cheap or ruinous. Internalize these defaults:
- **Prefer text/measured evidence over screenshots.** A full-window screenshot costs ~1.7K image tokens (image cost scales with resolution) and is re-shipped on every later turn, so it compounds. Answer "what is the state / is it correct" with `evaluate_in_webview` (geometry via `getBoundingClientRect()`, computed styles, text, counts) or `aria_snapshot({ selector })`. Reserve `screenshot` for when the _pixels themselves_ are the question (visual polish, overlap, alignment), and scope it to a webview.
- **Batch probes into one call.** Don't fire N `evaluate_in_webview` calls reading one field each — return a structured object in a single call: `evaluate_in_webview({ expression: "(() => { const el = document.querySelector('gl-graph-app').shadowRoot.querySelector('…'); return { top: el.getBoundingClientRect().top, color: getComputedStyle(el).color, count: … }; })()" })`. Project only the fields you need (returns are soft-capped at 20K chars); never return whole `innerHTML`.
- **Filter every read.** `read_console({ level: "error", last_n })` and `read_logs({ pattern: "<tag>", last_n })` — the arg is `pattern`, NOT `filter` (a wrong key silently dumps everything). Both default-cap at 200 lines; use `read_console({ clear: true })` as a cursor so the next read only sees new messages.
- **Fold setup into launch.** `launch({ commands: ["gitlens.showGraphView", …], account: "pro", log_level: "info" })` opens views and unlocks Pro features inside the launch call (saves a round-trip each) and keeps on-disk logs small.
- **Reuse the session.** `launch` once, then drive in a loop — it persists. For webview-only edits, `build:webviews` + the view's `.refresh` is ~3–5× cheaper than anything that restarts the host.
- **Extension-host code changes cost a relaunch.** `rebuild_and_reload` restarts the host, but the evaluator bridge does **not** come back: it's the `--extensionTestsPath` entry point, which VS Code runs only at workbench startup, so the restarted host never re-announces its port. Everything bridge-backed (`evaluate`, `set_account`, `execute_command`'s fast path) degrades or dies afterwards, and the tool now says so explicitly instead of failing silently. Use `teardown` + `launch` when you need a live bridge after an extension-host change. (`workbench.action.reloadWindow` is not a workaround — under `--extensionTestsPath` the host exit reads as "tests finished" and the whole instance quits.)
### Delegate the driving to a Sonnet driver (default)
When the session model is Opus or Fable, **default to dispatching the mechanical driving to the `inspector-driver` subagent (pinned to Sonnet 5)** — it costs ~1/5 per token and a smoke test showed quality parity on mechanical inspection (DOM reads, extension-host API reads, measurements). You stay the orchestrator: you decide the probe list, you interpret the returned evidence, you decide fixes.
- **Dispatch:** `Agent({ subagent_type: "inspector-driver", model: "sonnet", prompt: <setup + the exact probes/steps> })`. The agent's system prompt already encodes the driving discipline above, so give it a concrete step list, not a vague goal.
- **You own the instance lifecycle.** Launch once yourself (or in the first dispatch), keep it alive, and tell drivers **not** to `launch`/`teardown` — they reuse your running instance. Teardown yourself when done.
- **Batch the ask.** One dispatch should collect evidence across _many_ states/probes — that's what amortizes the subagent's fixed overhead (~35K tokens). Don't dispatch a driver for a single trivial probe; run that inline.
Auf GitHub ansehen