@petukhovart/agent-view 0.8.2 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,540 +1,563 @@
1
- # agent-view
2
-
3
- **Give your AI agent eyes and hands for complex desktop apps verification**
4
-
5
- AI coding agents can write code, run tests, and read logs — but they can't *see* what the app actually looks like. Without visual verification, an agent is essentially **coding blind** — builds pass, tests are green, but the login form is broken, the button is off-screen, or the modal never appears.
6
-
7
- agent-view bridges that gap: it connects to any Chromium-based desktop app via Chrome DevTools Protocol and lets the agent inspect, interact, and verify.
8
-
9
- Built for [Claude Code](https://docs.anthropic.com/en/docs/claude-code), but works with any AI agent or automation pipeline that can call CLI commands.
10
-
11
- ## 5-minute quickstart
12
-
13
- 1. **[Install](#install--update)** — `npm i -g @petukhovart/agent-view` plus the Claude Code plugin.
14
- 2. **[Enable CDP](#enabling-cdp) in your app** — one line in your Electron `main.ts`, gated to dev builds.
15
- 3. **`agent-view init`** in your project — then add `"allowEval": true` to the generated `agent-view.config.json`.
16
- 4. **`agent-view launch`** — starts your app and waits for CDP readiness.
17
- 5. **In Claude Code:** describe what you want verified — see [example prompts](#recommended-workflow-with-claude-code).
18
-
19
- Each step links to the full explanation below.
20
-
21
- ## What it does
22
-
23
- - **DOM accessibility tree** with ref IDs — compact, LLM-friendly, with text/role filters; `--compact` merges single-child chains for 40–60% fewer tokens, `--count` returns just the match count, `--max-lines` caps output, `--diff` emits only what changed since the last call
24
- - **Screenshots** full-res PNG, scaled WebP (~3–12× fewer vision tokens), or `--crop <filter>` to a single element bounding box
25
- - **Interaction** — click, fill, and drag by ref or coordinates; works with Vue/React/native frameworks
26
- - **JS state via `eval`** read store contents, computed values, async results without scraping the DOM
27
- - **Reactive state via `watch`** — stream JSON-patch diffs of any expression (store, ref, computed) until a condition is met
28
- - **Console capture** — `console.log/warn/error` per page and per worker, with level/since filters and `--follow --until <pattern>` for early exit on a matching log
29
- - **Worker access** — SharedWorker, ServiceWorker, dedicated Worker visible alongside pages; fuzzy `--target` resolution everywhere (id → title → URL)
30
- - **Canvas / WebGL scene graph** — PixiJS today, engine-pluggable; `--compact` mirrors the DOM mode
31
- - **Design-conformance verification** — pair screenshot commands with local design references (Figma export, hand-off
32
- PNGs, any image on disk) inside a verify-recipe; the `verify` skill compares screenshots against the references inline
33
-
34
- ## Why CLI, not MCP?
35
-
36
- Most alternatives in this space are MCP servers with 30+ tool definitions loaded into context on every session. That burns tokens before the agent even starts working.
37
-
38
- agent-view is a CLI. One Bash call, compact text output, zero schema overhead. The accessibility tree comes back as plain text not wrapped in JSON-RPC with metadata. For an agent that runs dozens of verification steps, the token savings add up fast.
39
-
40
- And CLI works everywhere — Claude Code, Copilot, Codex, custom pipelines, CI. No MCP client required.
41
-
42
- ## Install & Update
43
-
44
- ### Claude Code (recommended)
45
-
46
- Two steps both required:
47
-
48
- ```bash
49
- # 1. Install the plugin — adds two skills: verify (run checks against a live app) and verify-recipe (author a verification plan)
50
- /plugin marketplace add PetukhovArt/agent-view
51
- /plugin install agent-view@agent-view
52
-
53
- # 2. Install the CLI — the skill calls these binaries; the plugin doesn't bundle them
54
- npm install -g @petukhovart/agent-view
55
- ```
56
-
57
- The plugin ships two skills. **`verify`** executes visual and runtime checks against a running app. **`verify-recipe`** generates a `.claude/verify-recipes/<slug>.md` file — a disciplined, cheapest-first command sequence for a feature or bugfix — that you or any AI agent can run later. Trigger it with phrases like "write a verify-recipe for the login fix" or "generate a verification plan for this feature".
58
-
59
- For the canonical author-once / re-run flow, see [Recommended workflow with Claude Code](#recommended-workflow-with-claude-code) below.
60
-
61
- Verify:
62
-
63
- ```bash
64
- agent-view --version # 0.5.0+
65
- ```
66
-
67
- ### Standalone CLI (any other agent, CI, or scripting)
68
-
69
- ```bash
70
- npm install -g @petukhovart/agent-view
71
- ```
72
-
73
- Everything works from this alone — `agent-view dom`, `screenshot`, `eval`, etc. Skip the plugin step.
74
-
75
- ### Update
76
-
77
- ```bash
78
- # Update the CLI to the latest version
79
- npm update -g @petukhovart/agent-view
80
-
81
- # Update the Claude Code plugin (refreshes skills from the marketplace)
82
- /plugin marketplace update agent-view
83
- /plugin install agent-view@agent-view # re-run to pick up new skill versions
84
- ```
85
-
86
- The two are independent — bump the CLI when a new release ships features (see `CHANGELOG.md`), bump the plugin when skill instructions change.
87
-
88
- ## Enabling CDP
89
-
90
- agent-view talks to your app over Chrome DevTools Protocol. Your app must be launched with a debugging port open.
91
-
92
- ### Recommended: in code (reliable, works with any build tool)
93
-
94
- Add to your Electron main process, **before `app.whenReady()`** (top of `main.ts`/`main.js`, right after the `electron` import — switches set after the app is ready are ignored):
95
-
96
- ```js
97
- import { app } from 'electron';
98
-
99
- app.commandLine.appendSwitch('remote-debugging-port', '9876');
100
- ```
101
-
102
- > Any free port works — `9876` is just an example. Avoid `9222` (Chrome's own default remote-debugging port) to prevent
103
- > collisions when Chrome is open.
104
-
105
- **Production safety:** an open CDP port in a signed/notarized build is a remote-code-execution surface. Gate it on `!app.isPackaged` so it only opens in dev:
106
-
107
- ```js
108
- if (!app.isPackaged) {
109
- app.commandLine.appendSwitch('remote-debugging-port', '9876');
110
- }
111
- ```
112
-
113
- ### Alternative: via CLI flag (no code changes)
114
-
115
- ```bash
116
- # Plain Electron
117
- electron . --remote-debugging-port=9876
118
-
119
- # electron-vite (note the -- to forward the flag past the build tool)
120
- npx electron-vite dev -- --remote-debugging-port=9876
121
- ```
122
-
123
- ### Other runtimes
124
-
125
- | Runtime | Setup |
126
- |----------------------|--------------------------------------------|
127
- | **Tauri** | CDP via devtools configuration |
128
- | **Any Chromium app** | `--remote-debugging-port=9876` launch flag |
129
-
130
- ### Verify CDP is working
131
-
132
- ```bash
133
- curl -s http://localhost:9876/json/version
134
- ```
135
-
136
- If you see a JSON response with process info — you're good.
137
-
138
- ## Quick start with Claude Code (Prompting)
139
-
140
- Assumes the plugin and CLI are installed (see [Install & Update](#install--update)) and CDP is enabled in your app (
141
- see [Enabling CDP](#enabling-cdp)).
142
-
143
- **1. Generate config once:**
144
-
145
- ```bash
146
- cd your-electron-project
147
- agent-view init # writes agent-view.config.json auto-detects runtime, port, launch script, webgl engine
148
- ```
149
-
150
- Then open `agent-view.config.json` and add `"allowEval": true` if you want recipes to use `eval` / `watch` (most do —
151
- store/state assertions are 100× cheaper than DOM scraping). Off by default for security; see [Config](#config) for the
152
- full field list.
153
-
154
- **2. Start your app:**
155
-
156
- ```bash
157
- agent-view launch # uses the `launch` command from config, waits for CDP readiness, idempotent
158
- ```
159
-
160
- (Or start it yourself with `npm run dev` etc. — `launch` is just a convenience.)
161
-
162
- **3. From Claude Code, ask for a verification:**
163
-
164
- ```text
165
- The "Save" button on the Settings dialog stayed enabled while a save was in flight.
166
- I added a `saving` ref bound to :disabled. Verify it works:
167
- - after click, button must be disabled until network completes
168
- - no console errors in the flow
169
- ```
170
-
171
- Claude picks the `verify` skill, runs a handful of `eval` / `dom --filter` / `console` calls against your live app,
172
- reports what passed and what failed. No CLI commands typed by you.
173
-
174
- For a repeatable, multi-step verification (PRD/plan-driven, with optional design-mockup conformance),
175
- see [Recommended workflow with Claude Code](#recommended-workflow-with-claude-code) — it's the canonical 3-phase prompt
176
- flow this package is built around.
177
-
178
- ### Without Claude Code (manual CLI / CI / other agents)
179
-
180
- If you're scripting from CI or another agent, the CLI works standalone:
181
-
182
- ```bash
183
- agent-view discover # List all windows (JSON)
184
- agent-view dom --filter "Submit" # Accessibility tree, filtered, with ref IDs
185
- agent-view fill 3 "hello@example.com"
186
- agent-view click 7
187
- agent-view eval "store.state.user.role"
188
- agent-view screenshot --crop "Sidebar" --scale 0.5
189
- ```
190
-
191
- Full surface in [Commands](#commands) below.
192
-
193
- ## Recommended workflow with Claude Code
194
-
195
- A repeatable, token-efficient flow for "I shipped a feature/fix → confirm it actually works visually and at runtime". Two phases, each driven by a focused prompt.
196
-
197
- ```mermaid
198
- flowchart TD
199
- Dev["Developer<br/>in Claude Code"] -->|prompt| Agent["Main Claude agent<br/>(Opus / Sonnet)"]
200
-
201
- Agent -->|"verify ad-hoc"| Verify["verify skill"]
202
- Agent -->|"write recipe"| Recipe["verify-recipe skill"]
203
-
204
- Recipe -->|interview| Dev
205
- Recipe -->|writes| File[".claude/verify-recipes/&lt;slug&gt;.md"]
206
- File -.->|read on next run| Verify
207
-
208
- Verify -->|"agent-view dom / eval / click /<br/>screenshot / watch / console"| CLI["agent-view CLI"]
209
- CLI -->|CDP| App["Live app<br/>(Electron / Tauri / Browser)"]
210
- App -->|stdout / image paths| Verify
211
-
212
- Verify -->|"pass / fail summary<br/>+ design conformance verdict"| Dev
213
-
214
- classDef skill fill:#e8f0ff,stroke:#3060a0,color:#0a1f3d
215
- classDef tool fill:#fff4d6,stroke:#a07020,color:#3d2a05
216
- class Verify,Recipe skill
217
- class CLI tool
218
- ```
219
-
220
- ### Phase 1 — Author the verification plan (once)
221
-
222
- Generate the recipe **once**, from a PRD / plan file / Jira ticket / commit range. The recipe is reusable re-run after every iteration on the same feature.
223
-
224
- ```text
225
- Generate a verify-recipe for the changes in commits <hash1>..<hash2>.
226
- Source plan: .claude/plans/2026-04-27-login-redirect.md
227
- Original symptom: after login, redirect went to /home instead of /dashboard.
228
-
229
- Design references (if any):
230
- - /abs/path/figma-exports/login-success.png → label "post-login dashboard"
231
- - /abs/path/figma-exports/error-state.png → label "invalid creds error"
232
- ```
233
-
234
- What this triggers: the `verify-recipe` skill interviews you (if more context needed), then writes a `.claude/verify-recipes/<slug>.md` with `Repro Steps`, `Evidence Commands` (cheapest-first: `eval` / `dom --filter` before `screenshot`), `Regression Checks`, and — if you provided design refs — a `Design Conformance` table mapping screenshot commands to expected reference images.
235
-
236
- **Tip:** if you implemented from a Figma file via the `figma-implement-design` skill, it likely already saved exports somewhere on disk — pass those paths. agent-view does NOT fetch from Figma URLs; provide local files only.
237
-
238
- ### Phase 2 Run the recipe
239
-
240
- ```text
241
- Run the verify-recipe at .claude/verify-recipes/<slug>.md.
242
- ```
243
-
244
- What this triggers: the `verify` skill reads the recipe, performs the `Repro Steps` setup, runs each `Evidence Command` against the live app, compares output to the recipe's `Expected:` lines, and reports pass/fail per step. If the recipe has a `Design Conformance` section, the same skill captures the screenshots, opens both actual and expected images, and reports `match` / `minor_mismatch` / `major_mismatch` per pair — all inline, in the same conversation.
245
-
246
- When something fails, ask the main agent to fix and re-run only the affected steps:
247
-
248
- ```text
249
- Step 4 failed (zone filter not mutating store). Fix and re-run that step plus step 7.
250
- ```
251
-
252
- ### One-shot prompt (when there's no plan to convert)
253
-
254
- For small fixes where you don't want a persistent recipe file:
255
-
256
- ```text
257
- The "Save" button on the Settings dialog wasn't disabling while a save was in flight.
258
- I added a `saving` ref and bound it to :disabled. Verify it works:
259
- - after click, button must be disabled until network completes
260
- - no console errors
261
- - visual: button greys out (compare to /abs/path/saving-state.png if one is provided)
262
- ```
263
-
264
- Claude will pick the right skill (usually `verify` ad-hoc mode), run a handful of `eval` / `dom --filter` / `console` calls, and only screenshot if the visual claim needs it.
265
-
266
- ### Anti-patterns to avoid
267
-
268
- - "Just verify the feature" with no plan or symptom — the recipe author can't pick the cheapest signal without knowing what "works" means. Give it the symptom that motivated the fix.
269
- - Pasting Figma URLs and expecting agent-view to download them — it won't. Export the frames you care about to PNG first.
270
- - Stuffing 50 assertions into one recipe — split per-feature. A recipe should run in <2 minutes and produce a report you can read in 30 seconds.
271
-
272
- ## How it works
273
-
274
- ```
275
- CLI TCP Lazy Server CDP Your App
276
- ```
277
-
278
- A background server connects to your app's CDP port, caches sessions, and auto-shuts down after 5 minutes of inactivity. No manual `connect` step — the server starts on first CLI call and handles connection lifecycle automatically.
279
-
280
- ## Config
281
-
282
- Running `agent-view init` in your project root generates `agent-view.config.json`. Minimal form:
283
-
284
- ```json
285
- {
286
- "runtime": "electron",
287
- "port": 9876,
288
- "launch": "npm run dev"
289
- }
290
- ```
291
-
292
- Full form with all optional fields:
293
-
294
- ```json
295
- {
296
- "runtime": "electron",
297
- "port": 9876,
298
- "launch": "npm run dev",
299
- "allowEval": true,
300
- "webgl": {
301
- "engine": "pixi"
302
- },
303
- "consoleBufferSize": 500,
304
- "consoleTargets": ["page", "shared_worker", "service_worker"]
305
- }
306
- ```
307
-
308
- | Field | Required | Description |
309
- |---------------------|----------|-----------------------------------------------------------------------------------------------------------|
310
- | `runtime` | yes | `"electron"`, `"tauri"`, or `"browser"` |
311
- | `port` | yes | CDP debugging port |
312
- | `launch` | no | Command to start the app |
313
- | `webgl.engine` | no | `"pixi"` (scene extractor architecture supports adding more engines) |
314
- | `allowEval` | no | `true` to enable `agent-view eval` and `watch`. Off by default — opt-in for arbitrary JS execution |
315
- | `consoleBufferSize` | no | Per-target console ring capacity. Default `500` |
316
- | `consoleTargets` | no | Target types `agent-view console` auto-attaches to. Default `["page", "shared_worker", "service_worker"]` |
317
-
318
- ## Commands
319
-
320
- Every command targeting a window accepts `--window <id|title-substring>` (IDs come from `discover`). Examples below omit
321
- it for brevity.
322
-
323
- ### `init`
324
-
325
- Auto-generates config by reading `package.json`.
326
-
327
- ### `discover`
328
-
329
- Lists running app windows as JSON window IDs, titles, URLs.
330
-
331
- ```bash
332
- agent-view discover
333
- ```
334
-
335
- ### `dom`
336
-
337
- Dumps the accessibility tree in compact text format. Each element gets a session ref ID for interaction.
338
-
339
- ```bash
340
- agent-view dom
341
- agent-view dom --filter "Submit" # Filter by text/role
342
- agent-view dom --depth 3 # Limit tree depth
343
- agent-view dom --max-lines 200 # Hard line budget (refs for hidden nodes still stored)
344
- agent-view dom --text # Fall back to DOM textContent search when AX returns no match
345
- agent-view dom --compact # Merge single-child chains onto one line (saves ~40-60% tokens)
346
- agent-view dom --count # Return only the count of matching nodes (e.g. "5")
347
- agent-view dom --filter "row" --count # Count how many rows match
348
- agent-view dom --diff # Show only lines that changed since last call
349
- ```
350
-
351
- When `--filter` is set, depth defaults to unlimited so deep matches aren't truncated.
352
-
353
- `--count` skips tree formatting and ref-store mutations entirely — useful for assertions like "does this section have N rows?" without the token cost of a full tree dump.
354
-
355
- `--max-lines <n>` caps the number of output lines. When the tree exceeds the budget, output is truncated after `n-1` lines and a summary tail `… M more nodes` is appended. Refs for all nodes — including those past the cutoff — are still registered in the ref store, so a follow-up `dom --filter` or `click <ref>` works without re-running.
356
-
357
- `--diff` computes a line-level diff against the previous `dom` call for the same target. The first call always returns the full tree (no prior snapshot). Subsequent calls emit only added (`+ `) and removed (`- `) lines. Returns `No changes` when the tree is identical.
358
-
359
- ### `click`
360
-
361
- Clicks a DOM element by ref ID or coordinates.
362
-
363
- ```bash
364
- agent-view click 5 # By ref from dom output
365
- agent-view click --pos 100,200 # By coordinates (for canvas)
366
- ```
367
-
368
- ### `fill`
369
-
370
- Types text into an input. Uses native value setter + dispatches input/change events (works with Vue, React, and other frameworks).
371
-
372
- ```bash
373
- agent-view fill 3 "hello@example.com"
374
- ```
375
-
376
- ### `drag`
377
-
378
- HTML5 / pointer-driven drag-and-drop via CDP `Input.dispatchMouseEvent`
379
- (`mousePressed` → N × `mouseMoved` → `mouseReleased`). Real mouse events, not
380
- synthesized JS events — works with `vue-draggable-resizable`, `react-grid-layout`,
381
- gridstack, kanban boards, file drop zones, map pin drags, resize handles.
382
-
383
- ```bash
384
- agent-view drag --from 42 --to 88 # ref → ref
385
- agent-view drag --from-pos 86,792 --to-pos 640,200 # coord → coord (canvas, custom DnD)
386
- agent-view drag --from 42 --to-pos 640,200 # mixed
387
- agent-view drag --from 5 --to 9 --steps 20 --hold-ms 150
388
- ```
389
-
390
- `--steps` (default 10) controls intermediate `mouseMoved` events so libraries
391
- that throttle on movement deltas still see continuous motion. `--hold-ms`
392
- inserts a pause between press and the first move (some libs require >100ms
393
- for touch-style activation). `--button` accepts `left|right|middle`.
394
-
395
- ### `screenshot`
396
-
397
- Captures a screenshot, saves to temp dir, prints the file path. PNG by default; WebP (q=80) when `--scale` is set (JPEG fallback for older Chrome/Electron).
398
-
399
- ```bash
400
- agent-view screenshot
401
- agent-view screenshot --scale 0.5 # Half-res WebP (~3× fewer vision tokens)
402
- agent-view screenshot --scale 0.25 # Quarter-res WebP (~12× fewer, 1 tile)
403
- agent-view screenshot --crop "Sidebar" # Crop to element bounding box (~12× fewer in best case)
404
- agent-view screenshot --crop "Chart" --scale 0.5 # Crop + scale (stacks)
405
- ```
406
-
407
- `--scale` accepts a factor in `(0, 1]`. CDP-side clip + WebP encode — recommended for agent loops where vision tokens dominate cost.
408
-
409
- `--crop <filter>` resolves a DOM element by the same filter syntax as `dom --filter`, then crops the screenshot to its bounding box before encoding. One tile (~1.6k vision tokens) instead of twelve (~19k) in the best case. If the filter matches nothing a warning is emitted to stderr and the full window is captured instead. Combines naturally with `--scale`.
410
-
411
- ### `scene`
412
-
413
- Reads the WebGL scene graph for canvas-based apps. Currently supports PixiJS via `window.__PIXI_DEVTOOLS__`.
414
-
415
- ```bash
416
- agent-view scene # Full scene graph
417
- agent-view scene --diff # Changes since last call
418
- agent-view scene --filter "player" # Filter by name/type
419
- agent-view scene --verbose # Extended props (alpha, scale, bounds)
420
- agent-view scene --compact # Merge single-child chains onto one line
421
- ```
422
-
423
- ### `snap`
424
-
425
- Combined DOM + scene graph in one call. Shows DOM always; scene section appears when a WebGL engine is detected. Pass `--scale` to also capture a screenshot and append it as a third section.
426
-
427
- ```bash
428
- agent-view snap
429
- agent-view snap --scale 0.5 # DOM + Scene + Screenshot (path written to tmp)
430
- ```
431
-
432
- ### `wait`
433
-
434
- Waits for a DOM element matching the filter to appear. Useful after navigation or async operations.
435
-
436
- ```bash
437
- agent-view wait --filter "Dashboard" # Wait for element (default 10s)
438
- agent-view wait --filter "Dashboard" --timeout 30 # Custom timeout in seconds
439
- ```
440
-
441
- ### `launch`
442
-
443
- Starts the app using the `launch` command from config. Polls CDP until ready (60s timeout). Idempotent — skips if already running.
444
-
445
- ### `targets`
446
-
447
- Lists every CDP target — pages, iframes, shared/service/dedicated workers. Use this when you need access to non-page targets (e.g. an Electron app with a `SharedWorker`).
448
-
449
- ```bash
450
- agent-view targets # all supported types
451
- agent-view targets --type shared_worker,service_worker # filter
452
- agent-view targets --json # machine-readable
453
- ```
454
-
455
- ### `eval`
456
-
457
- Runs `Runtime.evaluate` in any connectable target. **Requires `"allowEval": true` in `agent-view.config.json`** — the local socket is shared and this is the project-owner opt-in.
458
-
459
- ```bash
460
- agent-view eval "document.title"
461
- agent-view eval --target IJ56KL "self.constructor.name" # by id (or title/url substring)
462
- agent-view eval --window "Monitor 1" --await "fetch('/api/health').then(r => r.status)"
463
- agent-view eval --json "({ buttons: document.querySelectorAll('button').length })"
464
- ```
465
-
466
- Output is capped at 64 KB. Thrown exceptions and syntax errors propagate as non-zero exit with the CDP error message.
467
-
468
- ### `console`
469
-
470
- Streams or dumps console output (`Runtime.consoleAPICalled` + `Log.entryAdded`) from auto-attached targets. Lazy: first call attaches matching targets, subsequent calls reuse them.
471
-
472
- ```bash
473
- agent-view console # buffered messages since attach
474
- agent-view console --follow --timeout 10 # stream for 10s
475
- agent-view console --follow --until "ready" # exit as soon as a message contains "ready"
476
- agent-view console --follow --until "/error/i" # exit on regex match (case-insensitive)
477
- agent-view console --target IJ56KL # restrict to one target (exact id)
478
- agent-view console --target sync-worker # restrict to one target (title/URL substring)
479
- agent-view console --level error,warn # level filter
480
- agent-view console --since "2026-04-26T10:00:00Z"
481
- agent-view console --clear # drop in-memory ring
482
- ```
483
-
484
- `--until <pattern>` requires `--follow`. Exits as soon as a message matches the pattern (substring or `/regex/flags`). On timeout without match exits non-zero with `Timeout: pattern not seen in <N>s`.
485
-
486
- `--target` resolves the same way as `eval --target`: exact id wins, then title substring, then URL substring. If no match is found, an error is returned.
487
-
488
- Default attached target types: `page`, `shared_worker`, `service_worker`. Override with `consoleTargets` in config.
489
-
490
- ### `watch`
491
-
492
- Polls a JS expression and streams JSON-patch (RFC 6902) diffs as it changes. Closes the "what changed between click and final state?" gap that screenshots and DOM dumps can't cover. **Requires `"allowEval": true`** (same gate as `eval`).
493
-
494
- ```bash
495
- agent-view watch "store.cart.total" # 250ms poll, exits at 10 changes or 30s
496
- agent-view watch "appState" --interval 100 --duration 60 # tighter cadence, longer window
497
- agent-view watch "store.status" --until "store.status === 'ready'" # wait-for assertion
498
- agent-view watch "appState" --max-changes 1 # snapshot first change after a click
499
- agent-view watch "appState" --json # NDJSON, one frame per line
500
- ```
501
-
502
- Output frames: `init` (baseline value), `diff` (RFC 6902 ops since last frame), `error`, `stop`. SIGINT exits cleanly. Snapshot size cap 256 KB — narrow the expression (e.g. `store.cart.items.length`) when watching large objects.
503
-
504
- ### `stop`
505
-
506
- Stops the background lazy server.
507
-
508
- ## Performance
509
-
510
- Built for tight `dom → click → dom` loops. Typical Electron app, ~200 AX nodes:
511
-
512
- | Scenario | agent-view | Playwright (estimate) |
513
- |--------------------------------|------------|-----------------------|
514
- | `dom` cold fetch | 2ms | ~30–80ms |
515
- | `dom` warm (cache hit) | 1ms | ~30–80ms |
516
- | Full cycle `dom click dom` | 17ms | ~75ms |
517
-
518
- What makes it fast: 300ms AX-tree cache (invalidated on `click`/`fill`/navigation; cached responses prefixed with
519
- `[cache]`), parallel CDP calls in `click`, `Accessibility.queryAXTree` for filter lookups, and a single persistent CDP
520
- WebSocket reused across commands (no relay).
521
-
522
- ## Troubleshooting
523
-
524
- ### CDP not responding
525
-
526
- 1. Check the port is listening: `curl -s http://localhost:9876/json/version`
527
- 2. For electron-vite: make sure you use `--` before the flag: `npx electron-vite dev -- --remote-debugging-port=9876`
528
- 3. Restart the app — HMR doesn't restart the main process
529
-
530
- ### Stale refs after HMR
531
-
532
- After hot reload, refs from previous `dom` calls become invalid. Run `agent-view dom` again to get fresh refs.
533
-
534
- ### Launch timeout
535
-
536
- Complex Electron apps may take >60s on cold start. If `agent-view launch` times out, start the app manually and use `agent-view discover` to verify.
537
-
538
- ## License
539
-
540
- MIT
1
+ <div align="center">
2
+ <img src="assets/logo.svg" alt="agent-view logo" width="160" height="160">
3
+ <h1>agent-view</h1>
4
+ <p><b>DevTools-level access for AI agents. Electron, Tauri, Chromium.</b></p>
5
+ </div>
6
+
7
+ <p align="center">
8
+ <a href="https://npmjs.com/package/@petukhovart/agent-view"><img src="https://img.shields.io/npm/v/@petukhovart/agent-view?color=yellow" alt="npm version" /></a>
9
+ <a href="https://npmjs.com/package/@petukhovart/agent-view"><img src="https://img.shields.io/npm/dt/@petukhovart/agent-view?color=blue" alt="npm downloads" /></a>
10
+ <a href="https://npmjs.com/package/@petukhovart/agent-view"><img src="https://img.shields.io/npm/unpacked-size/@petukhovart/agent-view?color=purple&label=size" alt="package size" /></a>
11
+ <a href="https://github.com/PetukhovArt/agent-view/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/@petukhovart/agent-view?color=green" alt="license" /></a>
12
+ <a href="https://nodejs.org"><img src="https://img.shields.io/node/v/@petukhovart/agent-view" alt="node" /></a>
13
+ <a href="https://github.com/PetukhovArt/agent-view/stargazers"><img src="https://img.shields.io/github/stars/PetukhovArt/agent-view?style=flat&color=orange" alt="github stars" /></a>
14
+ </p>
15
+
16
+ <p align="center">
17
+ <a href="#quickstart-claude-code">Quickstart</a> ·
18
+ <a href="#features">Features</a> ·
19
+ <a href="#commands">Commands</a> ·
20
+ <a href="#workflow-with-claude-code">Workflow</a> ·
21
+ <a href="CHANGELOG.md">Changelog</a>
22
+ </p>
23
+
24
+ > Agents can read your code and your tests. What they can't see: whether the button is actually disabled, whether the modal opened, whether the store mutated. **agent-view** is one CLI that talks to your Electron, Tauri, or Chromium app over Chrome DevTools Protocol so the agent can answer those questions itself.
25
+
26
+ Works with any agent that can run shell commands. There's a Claude Code plugin if you want the smoothest path.
27
+
28
+ ---
29
+
30
+ ## Why agent-view
31
+
32
+ - Reads state inside `SharedWorker`, `ServiceWorker`, and dedicated workers. Half of a modern app's state lives there, and most browser-automation tools don't follow it.
33
+ - Every command takes `--window <id>`. Settings, tray, and detached windows in Electron and Tauri apps work the same as the main window.
34
+ - Electron, Tauri (WebView2 and WebKit), and plain Chromium. One CLI, same commands.
35
+ - `click`, `fill`, and `drag` fire real CDP input events. Vue `v-model`, React controlled inputs, and native fields actually accept the value; synthetic DOM events fail silently there.
36
+ - `watch` emits RFC-6902 JSON-patches of any JS expression between two events. Answers "what mutated after the click?" without parsing screenshots.
37
+ - `dom` returns the accessibility tree with `[ref=N]` handles. `--compact` cuts deep trees by 40–60%; `--diff`, `--count`, and `--max-lines` keep output bounded. `screenshot --crop` and WebP scaling do the same for vision tokens.
38
+ - Lazy CDP daemon, one persistent socket, 300 ms AX-tree cache. `dom click dom` in about 17 ms.
39
+
40
+ ---
41
+
42
+ ## Quickstart (Claude Code)
43
+
44
+ > Using Cursor / Aider / Cline / CI? Jump to [Other agents](#using-agent-view-with-other-agents-cursor-aider-cline-copilot-ci).
45
+
46
+ **1. Install the CLI and create a config:**
47
+
48
+ ```bash
49
+ npm install -g @petukhovart/agent-view # one-time, global
50
+ cd your-project
51
+ agent-view init # writes agent-view.config.json (runtime, port, launch script)
52
+ ```
53
+
54
+ `init` auto-detects most projects. Review the generated `launch` field if your dev command is non-standard, and set `"allowEval": true` if you want recipes to use `eval`/`watch`. Prefer to write the config by hand? See [Config](#config) for the field list.
55
+
56
+ **2. Install the Claude Code plugin** (adds the `verify` and `verify-recipe` skills):
57
+
58
+ ```text
59
+ /plugin marketplace add PetukhovArt/agent-view
60
+ /plugin install agent-view@agent-view
61
+ ```
62
+
63
+ **3. Open a CDP debug port** in your app, matching the `port` in your config. Pick your runtime:
64
+
65
+ <details open>
66
+ <summary><b>Electron</b> — top of <code>main.ts</code>, before <code>app.whenReady()</code></summary>
67
+
68
+ ```js
69
+ import { app } from 'electron';
70
+ if (!app.isPackaged) {
71
+ app.commandLine.appendSwitch('remote-debugging-port', '9876');
72
+ }
73
+ ```
74
+ </details>
75
+
76
+ <details>
77
+ <summary><b>Tauri 2</b> (WebView2 / Windows) — env var passed to <code>tauri dev</code></summary>
78
+
79
+ In `package.json`, wrap the dev script with [`cross-env`](https://www.npmjs.com/package/cross-env) so it works on Windows, macOS and Linux shells:
80
+
81
+ ```json
82
+ {
83
+ "scripts": {
84
+ "dev": "cross-env WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS=--remote-debugging-port=9876 tauri dev"
85
+ }
86
+ }
87
+ ```
88
+
89
+ Then `npm run dev` as usual. Devtools must be enabled in `tauri.conf.json` (default in `tauri dev`; for release builds, enable the `devtools` Cargo feature). macOS/Linux WebKit use different env vars; see [Enabling CDP](#enabling-cdp).
90
+ </details>
91
+
92
+ <details>
93
+ <summary><b>Plain Chromium app</b> — launch flag</summary>
94
+
95
+ ```bash
96
+ chromium --remote-debugging-port=9876
97
+ ```
98
+ </details>
99
+
100
+ **4. In Claude Code, describe what you want verified:**
101
+
102
+ ```text
103
+ Verify: after clicking Save, the button must be disabled until network completes.
104
+ No console errors.
105
+ ```
106
+
107
+ The `verify` skill starts your app via `agent-view launch`, runs the cheapest checks first (`eval` before `dom` before `screenshot`), and reports pass/fail. For repeatable checks, ask it to author a recipe first; see [Workflow with Claude Code](#workflow-with-claude-code).
108
+
109
+ ---
110
+
111
+ ## Manual CLI usage
112
+
113
+ When you want to drive the CLI yourself (other agents, CI, or just to poke around):
114
+
115
+ ```bash
116
+ agent-view init # writes agent-view.config.json; auto-detects runtime/port/launch
117
+ agent-view launch # starts the app, waits for CDP, idempotent
118
+ agent-view dom --filter "Submit" # AX tree, with [ref=N] handles
119
+ agent-view click 12 # use a ref from the dom output
120
+ agent-view eval "store.state.user" # requires allowEval
121
+ ```
122
+
123
+ Full command surface in [Commands](#commands). For non-Claude-Code agents, see also [Other agents](#using-agent-view-with-other-agents-cursor-aider-cline-copilot-ci).
124
+
125
+ ---
126
+
127
+ ## How it works
128
+
129
+ ```
130
+ ┌──────────────┐ JSON over TCP ┌─────────────────┐ ┌──────────────┐
131
+ │ agent-view │ (token-auth, local) │ Lazy daemon │ CDP │ Your app │
132
+ │ CLI │ ──────────────────────▶ │ 127.0.0.1:47922│ ──────────────▶ │ (Electron / │
133
+ │ │ │ │ WebSocket │ Tauri /
134
+ │ one shot │ ◀────────────────────── │ cache + reuse │ ◀────────────── │ Chromium) │
135
+ └──────────────┘ compact text └─────────────────┘ └──────────────┘
136
+ ▲ spawned on first call
137
+ │ shuts down after 5 min idle
138
+ │ reuses one CDP socket across commands
139
+ ```
140
+
141
+ The daemon is why `dom → click → dom` runs in ~17ms total: one persistent CDP socket, a 300ms AX-tree cache, parallel CDP calls inside `click`. CLI commands themselves are stateless. Each one is a single shell call you can drop into a script or a recipe.
142
+
143
+ ---
144
+
145
+ ## Features
146
+
147
+ | Command | What it gives the agent |
148
+ |---------------|-----------------------------------------------------------------------------------------|
149
+ | `dom` | Accessibility tree with `[ref=N]` handles. Flags: `--filter`, `--compact`, `--count`, `--max-lines`, `--diff`. |
150
+ | `screenshot` | PNG, or scaled WebP, or `--crop <element>` for one element only. Cuts vision tokens. |
151
+ | `click` / `fill` / `drag` | Real CDP input events. Works with Vue/React/native and HTML5/pointer DnD. |
152
+ | `eval` | Run JS in the page's main world. Read store/state directly instead of scraping DOM. |
153
+ | `watch` | Stream JSON-patch diffs of any expression. Answers "what changed between click and final state?". |
154
+ | `console` | `console.log` + `Log.entryAdded` per page **and per worker**, with `--follow --until <pattern>`. |
155
+ | `wait` | Block until an element appears (default 10s). |
156
+ | `scene` | WebGL scene graph (PixiJS today, engine-pluggable). `--compact` and `--diff` mirror `dom`. |
157
+ | `snap` | DOM + scene + optional screenshot in one call. |
158
+ | `targets` | Enumerate pages, iframes, shared/service/dedicated workers. |
159
+ | `discover` / `launch` / `init` / `stop` | Lifecycle and setup. |
160
+
161
+ Full flag reference in [Commands](#commands).
162
+
163
+ ---
164
+
165
+ ## Workflow with Claude Code
166
+
167
+ The plugin adds two skills built around an author-once / re-run loop:
168
+
169
+ - `verify-recipe` interviews you about a feature or fix, then writes `.claude/verify-recipes/<slug>.md` with Repro Steps, Evidence Commands (cheapest first: `eval` before `dom` before `screenshot`), and an optional Design Conformance table mapping screenshots to local reference images.
170
+ - `verify` reads a recipe (or runs ad-hoc), executes the commands against the live app, and reports pass/fail.
171
+
172
+ ```mermaid
173
+ flowchart LR
174
+ subgraph Author["Phase 1 author once"]
175
+ direction TB
176
+ Dev1["Developer"] -->|prompt + plan/commits| Recipe["verify-recipe<br/>skill"]
177
+ Recipe -->|writes| File[".claude/verify-recipes/<br/>&lt;slug&gt;.md"]
178
+ end
179
+
180
+ subgraph Run["Phase 2 run after every iteration"]
181
+ direction TB
182
+ Dev2["Developer"] -->|"run the recipe"| Verify["verify skill"]
183
+ File -.->|read| Verify
184
+ Verify -->|"dom / eval / click /<br/>screenshot / watch"| CLI["agent-view CLI"]
185
+ CLI -->|CDP| App["Live app"]
186
+ App -->|results| Verify
187
+ Verify -->|pass/fail + design verdict| Dev2
188
+ end
189
+ ```
190
+
191
+ ### Phase 1: author
192
+
193
+ ```text
194
+ Generate a verify-recipe for commits <hash1>..<hash2>.
195
+ Source plan: .claude/plans/2026-04-27-login-redirect.md
196
+ Symptom: after login, redirect went to /home instead of /dashboard.
197
+
198
+ Design references (optional):
199
+ - /abs/path/figma-exports/post-login.png → "post-login dashboard"
200
+ ```
201
+
202
+ ### Phase 2: run
203
+
204
+ ```text
205
+ Run the verify-recipe at .claude/verify-recipes/login-redirect.md.
206
+ ```
207
+
208
+ When something fails:
209
+
210
+ ```text
211
+ Step 4 failed (zone filter not mutating store). Fix and re-run that step plus step 7.
212
+ ```
213
+
214
+ ### One-shot (no plan, no persistent recipe)
215
+
216
+ ```text
217
+ Verify: after clicking Save, the button must be disabled until network completes. No console errors.
218
+ ```
219
+
220
+ ### Anti-patterns
221
+
222
+ - "Just verify the feature" with no symptom. The recipe author can't pick the cheapest signal without knowing what "works" means.
223
+ - Pasting Figma URLs. agent-view doesn't fetch from Figma; export to PNG and pass the local path.
224
+ - 50 assertions in one recipe. Split per-feature; a recipe should run in under 2 minutes.
225
+
226
+ ---
227
+
228
+ ## Using agent-view with other agents (Cursor, Aider, Cline, Copilot, CI)
229
+
230
+ The CLI is the whole product. Any agent that can run shell commands can use it:
231
+
232
+ ```bash
233
+ agent-view discover # JSON: window IDs, titles, URLs
234
+ agent-view dom --filter "Submit" # AX tree, with refs
235
+ agent-view fill 3 "hello@example.com"
236
+ agent-view click 7
237
+ agent-view eval "store.state.user.role"
238
+ agent-view screenshot --crop "Sidebar" --scale 0.5
239
+ ```
240
+
241
+ For agents that benefit from a system-prompt shim, copy the gist of [`skills/verify/SKILL.md`](skills/verify/SKILL.md) into your agent's instructions. The DOM-first workflow and tool-selection table are framework-agnostic.
242
+
243
+ ---
244
+
245
+ ## Enabling CDP
246
+
247
+ agent-view talks to your app over Chrome DevTools Protocol. Your app must be launched with a debugging port open.
248
+
249
+ ### Recommended: in code (reliable, works with any build tool)
250
+
251
+ Add to your Electron main process, **before `app.whenReady()`** (top of `main.ts`/`main.js`, right after the `electron` import; switches set after the app is ready are ignored):
252
+
253
+ ```js
254
+ import { app } from 'electron';
255
+
256
+ app.commandLine.appendSwitch('remote-debugging-port', '9876');
257
+ ```
258
+
259
+ > Any free port works; `9876` is just an example. Avoid `9222` (Chrome's own default remote-debugging port) to prevent collisions when Chrome is open.
260
+
261
+ **Production safety:** an open CDP port in a signed/notarized build is a remote-code-execution surface. Gate it on `!app.isPackaged` so it only opens in dev:
262
+
263
+ ```js
264
+ if (!app.isPackaged) {
265
+ app.commandLine.appendSwitch('remote-debugging-port', '9876');
266
+ }
267
+ ```
268
+
269
+ ### Alternative: via CLI flag (no code changes)
270
+
271
+ ```bash
272
+ # Plain Electron
273
+ electron . --remote-debugging-port=9876
274
+
275
+ # electron-vite (note the -- to forward the flag past the build tool)
276
+ npx electron-vite dev -- --remote-debugging-port=9876
277
+ ```
278
+
279
+ ### Other runtimes
280
+
281
+ | Runtime | Setup |
282
+ |----------------------|--------------------------------------------|
283
+ | **Tauri** | CDP via devtools configuration |
284
+ | **Any Chromium app** | `--remote-debugging-port=9876` launch flag |
285
+
286
+ ### Verify CDP is working
287
+
288
+ ```bash
289
+ curl -s http://localhost:9876/json/version
290
+ ```
291
+
292
+ A JSON response with process info means CDP is reachable.
293
+
294
+ ---
295
+
296
+ ## Config
297
+
298
+ Running `agent-view init` in your project root generates `agent-view.config.json`. Minimal form:
299
+
300
+ ```json
301
+ {
302
+ "runtime": "electron",
303
+ "port": 9876,
304
+ "launch": "npm run dev"
305
+ }
306
+ ```
307
+
308
+ Full form with all optional fields:
309
+
310
+ ```json
311
+ {
312
+ "runtime": "electron",
313
+ "port": 9876,
314
+ "launch": "npm run dev",
315
+ "allowEval": true,
316
+ "webgl": {
317
+ "engine": "pixi"
318
+ },
319
+ "consoleBufferSize": 500,
320
+ "consoleTargets": ["page", "shared_worker", "service_worker"]
321
+ }
322
+ ```
323
+
324
+ | Field | Required | Description |
325
+ |---------------------|----------|-----------------------------------------------------------------------------------------------------------|
326
+ | `runtime` | yes | `"electron"`, `"tauri"`, or `"browser"` |
327
+ | `port` | yes | CDP debugging port |
328
+ | `launch` | no | Command to start the app |
329
+ | `webgl.engine` | no | `"pixi"` (scene extractor architecture supports adding more engines) |
330
+ | `allowEval` | no | `true` to enable `agent-view eval` and `watch`. Off by default; opt-in for arbitrary JS execution |
331
+ | `consoleBufferSize` | no | Per-target console ring capacity. Default `500` |
332
+ | `consoleTargets` | no | Target types `agent-view console` auto-attaches to. Default `["page", "shared_worker", "service_worker"]` |
333
+
334
+ ---
335
+
336
+ ## Commands
337
+
338
+ Every command targeting a window accepts `--window <id|title-substring>` (IDs come from `discover`). Examples below omit it for brevity.
339
+
340
+ ### `init`
341
+
342
+ Auto-generates config by reading `package.json`.
343
+
344
+ ### `discover`
345
+
346
+ Lists running app windows as JSON: window IDs, titles, URLs.
347
+
348
+ ```bash
349
+ agent-view discover
350
+ ```
351
+
352
+ ### `dom`
353
+
354
+ Dumps the accessibility tree in compact text format. Each element gets a session ref ID for interaction.
355
+
356
+ ```bash
357
+ agent-view dom
358
+ agent-view dom --filter "Submit" # Filter by text/role
359
+ agent-view dom --depth 3 # Limit tree depth
360
+ agent-view dom --max-lines 200 # Hard line budget (refs for hidden nodes still stored)
361
+ agent-view dom --text # Fall back to DOM textContent search when AX returns no match
362
+ agent-view dom --compact # Merge single-child chains onto one line (saves ~40-60% tokens)
363
+ agent-view dom --count # Return only the count of matching nodes (e.g. "5")
364
+ agent-view dom --filter "row" --count # Count how many rows match
365
+ agent-view dom --diff # Show only lines that changed since last call
366
+ ```
367
+
368
+ When `--filter` is set, depth defaults to unlimited so deep matches aren't truncated.
369
+
370
+ `--count` skips tree formatting and ref-store mutations entirely; useful for assertions like "does this section have N rows?" without the token cost of a full tree dump.
371
+
372
+ `--max-lines <n>` caps the number of output lines. When the tree exceeds the budget, output is truncated after `n-1` lines and a summary tail `… M more nodes` is appended. Refs for all nodes, including those past the cutoff, are still registered in the ref store, so a follow-up `dom --filter` or `click <ref>` works without re-running.
373
+
374
+ `--diff` computes a line-level diff against the previous `dom` call for the same target. The first call always returns the full tree (no prior snapshot). Subsequent calls emit only added (`+ `) and removed (`- `) lines. Returns `No changes` when the tree is identical.
375
+
376
+ ### `click`
377
+
378
+ Clicks a DOM element by ref ID or coordinates.
379
+
380
+ ```bash
381
+ agent-view click 5 # By ref from dom output
382
+ agent-view click --pos 100,200 # By coordinates (for canvas)
383
+ agent-view click 5 --double # Double-click (fires dblclick handlers)
384
+ ```
385
+
386
+ ### `fill`
387
+
388
+ Types text into an input. Uses native value setter + dispatches input/change events (works with Vue, React, and other frameworks).
389
+
390
+ ```bash
391
+ agent-view fill 3 "hello@example.com"
392
+ ```
393
+
394
+ ### `drag`
395
+
396
+ HTML5 / pointer-driven drag-and-drop via CDP `Input.dispatchMouseEvent` (`mousePressed` → N × `mouseMoved` → `mouseReleased`). Real mouse events, not synthesized JS events; works with `vue-draggable-resizable`, `react-grid-layout`, gridstack, kanban boards, file drop zones, map pin drags, resize handles.
397
+
398
+ ```bash
399
+ agent-view drag --from 42 --to 88 # ref → ref
400
+ agent-view drag --from-pos 86,792 --to-pos 640,200 # coord → coord (canvas, custom DnD)
401
+ agent-view drag --from 42 --to-pos 640,200 # mixed
402
+ agent-view drag --from 5 --to 9 --steps 20 --hold-ms 150
403
+ ```
404
+
405
+ `--steps` (default 10) controls intermediate `mouseMoved` events so libraries that throttle on movement deltas still see continuous motion. `--hold-ms` inserts a pause between press and the first move (some libs require >100ms for touch-style activation). `--button` accepts `left|right|middle`.
406
+
407
+ ### `screenshot`
408
+
409
+ Captures a screenshot, saves to temp dir, prints the file path. PNG by default; WebP (q=80) when `--scale` is set (JPEG fallback for older Chrome/Electron).
410
+
411
+ ```bash
412
+ agent-view screenshot
413
+ agent-view screenshot --scale 0.5 # Half-res WebP (~3× fewer vision tokens)
414
+ agent-view screenshot --scale 0.25 # Quarter-res WebP (~12× fewer, 1 tile)
415
+ agent-view screenshot --crop "Sidebar" # Crop to element bounding box (~12× fewer in best case)
416
+ agent-view screenshot --crop "Chart" --scale 0.5 # Crop + scale (stacks)
417
+ ```
418
+
419
+ `--scale` accepts a factor in `(0, 1]`. CDP-side clip + WebP encode; recommended for agent loops where vision tokens dominate cost.
420
+
421
+ `--crop <filter>` resolves a DOM element by the same filter syntax as `dom --filter`, then crops the screenshot to its bounding box before encoding. One tile (~1.6k vision tokens) instead of twelve (~19k) in the best case. If the filter matches nothing a warning is emitted to stderr and the full window is captured instead. Combines naturally with `--scale`.
422
+
423
+ ### `scene`
424
+
425
+ Reads the WebGL scene graph for canvas-based apps. Currently supports PixiJS via `window.__PIXI_DEVTOOLS__`.
426
+
427
+ ```bash
428
+ agent-view scene # Full scene graph
429
+ agent-view scene --diff # Changes since last call
430
+ agent-view scene --filter "player" # Filter by name/type
431
+ agent-view scene --verbose # Extended props (alpha, scale, bounds)
432
+ agent-view scene --compact # Merge single-child chains onto one line
433
+ ```
434
+
435
+ ### `snap`
436
+
437
+ Combined DOM + scene graph in one call. Shows DOM always; scene section appears when a WebGL engine is detected. Pass `--scale` to also capture a screenshot and append it as a third section.
438
+
439
+ ```bash
440
+ agent-view snap
441
+ agent-view snap --scale 0.5 # DOM + Scene + Screenshot (path written to tmp)
442
+ ```
443
+
444
+ ### `wait`
445
+
446
+ Waits for a DOM element matching the filter to appear. Useful after navigation or async operations.
447
+
448
+ ```bash
449
+ agent-view wait --filter "Dashboard" # Wait for element (default 10s)
450
+ agent-view wait --filter "Dashboard" --timeout 30 # Custom timeout in seconds
451
+ ```
452
+
453
+ ### `launch`
454
+
455
+ Starts the app using the `launch` command from config. Polls CDP until ready (60s timeout). Idempotent; skips if already running.
456
+
457
+ ### `targets`
458
+
459
+ Lists every CDP target: pages, iframes, shared/service/dedicated workers. Use this when you need access to non-page targets (e.g. an Electron app with a `SharedWorker`).
460
+
461
+ ```bash
462
+ agent-view targets # all supported types
463
+ agent-view targets --type shared_worker,service_worker # filter
464
+ agent-view targets --json # machine-readable
465
+ ```
466
+
467
+ ### `eval`
468
+
469
+ Runs `Runtime.evaluate` in any connectable target. **Requires `"allowEval": true` in `agent-view.config.json`**; the local socket is shared and this is the project-owner opt-in.
470
+
471
+ ```bash
472
+ agent-view eval "document.title"
473
+ agent-view eval --target IJ56KL "self.constructor.name" # by id (or title/url substring)
474
+ agent-view eval --window "Monitor 1" --await "fetch('/api/health').then(r => r.status)"
475
+ agent-view eval --json "({ buttons: document.querySelectorAll('button').length })"
476
+ ```
477
+
478
+ Output is capped at 64 KB. Thrown exceptions and syntax errors propagate as non-zero exit with the CDP error message.
479
+
480
+ > **Note on execution context.** `agent-view eval` runs in the page's **main world** via `Runtime.evaluate`. Only values reachable from the main-world `window` are visible. To expose your API for `eval` (and `watch`), attach it to `window`:
481
+ > - Vanilla / browser: `window.myApi = { ... }`
482
+ > - Electron preload with `contextIsolation: true`: `contextBridge.exposeInMainWorld('myApi', { ... })`
483
+ > - Tauri / WebView2: same; assign to `window` from your bootstrap script
484
+ >
485
+ > Anything kept inside an isolated-world preload without `contextBridge` will be invisible to `eval`; `eval "typeof window.myApi"` will return `"undefined"` even though the value exists in the preload context.
486
+
487
+ ### `console`
488
+
489
+ Streams or dumps console output (`Runtime.consoleAPICalled` + `Log.entryAdded`) from auto-attached targets. Lazy: first call attaches matching targets, subsequent calls reuse them.
490
+
491
+ ```bash
492
+ agent-view console # buffered messages since attach
493
+ agent-view console --follow --timeout 10 # stream for 10s
494
+ agent-view console --follow --until "ready" # exit as soon as a message contains "ready"
495
+ agent-view console --follow --until "/error/i" # exit on regex match (case-insensitive)
496
+ agent-view console --target IJ56KL # restrict to one target (exact id)
497
+ agent-view console --target sync-worker # restrict to one target (title/URL substring)
498
+ agent-view console --level error,warn # level filter
499
+ agent-view console --since "2026-04-26T10:00:00Z"
500
+ agent-view console --clear # drop in-memory ring
501
+ ```
502
+
503
+ `--until <pattern>` requires `--follow`. Exits as soon as a message matches the pattern (substring or `/regex/flags`). On timeout without match exits non-zero with `Timeout: pattern not seen in <N>s`.
504
+
505
+ `--target` resolves the same way as `eval --target`: exact id wins, then title substring, then URL substring. If no match is found, an error is returned.
506
+
507
+ Default attached target types: `page`, `shared_worker`, `service_worker`. Override with `consoleTargets` in config.
508
+
509
+ ### `watch`
510
+
511
+ Polls a JS expression and streams JSON-patch (RFC 6902) diffs as it changes. Closes the "what changed between click and final state?" gap that screenshots and DOM dumps can't cover. **Requires `"allowEval": true`** (same gate as `eval`).
512
+
513
+ ```bash
514
+ agent-view watch "store.cart.total" # 250ms poll, exits at 10 changes or 30s
515
+ agent-view watch "appState" --interval 100 --duration 60 # tighter cadence, longer window
516
+ agent-view watch "store.status" --until "store.status === 'ready'" # wait-for assertion
517
+ agent-view watch "appState" --max-changes 1 # snapshot first change after a click
518
+ agent-view watch "appState" --json # NDJSON, one frame per line
519
+ ```
520
+
521
+ Output frames: `init` (baseline value), `diff` (RFC 6902 ops since last frame), `error`, `stop`. SIGINT exits cleanly. Snapshot size cap 256 KB; narrow the expression (e.g. `store.cart.items.length`) when watching large objects.
522
+
523
+ ### `stop`
524
+
525
+ Stops the background lazy server.
526
+
527
+ ---
528
+
529
+ ## Performance
530
+
531
+ Built for tight `dom → click → dom` loops. Typical Electron app, ~200 AX nodes:
532
+
533
+ | Scenario | agent-view | Playwright (estimate) |
534
+ |--------------------------------|------------|-----------------------|
535
+ | `dom` cold fetch | 2ms | ~30–80ms |
536
+ | `dom` warm (cache hit) | 1ms | ~30–80ms |
537
+ | Full cycle `dom → click → dom` | 17ms | ~75ms |
538
+
539
+ What makes it fast: 300ms AX-tree cache (invalidated on `click`/`fill`/navigation; cached responses prefixed with `[cache]`), parallel CDP calls in `click`, `Accessibility.queryAXTree` for filter lookups, and a single persistent CDP WebSocket reused across commands (no relay).
540
+
541
+ ---
542
+
543
+ ## Troubleshooting
544
+
545
+ ### CDP not responding
546
+
547
+ 1. Check the port is listening: `curl -s http://localhost:9876/json/version`
548
+ 2. For electron-vite: make sure you use `--` before the flag: `npx electron-vite dev -- --remote-debugging-port=9876`
549
+ 3. Restart the app; HMR doesn't restart the main process
550
+
551
+ ### Stale refs after HMR
552
+
553
+ After hot reload, refs from previous `dom` calls become invalid. Run `agent-view dom` again to get fresh refs.
554
+
555
+ ### Launch timeout
556
+
557
+ Complex Electron apps may take >60s on cold start. If `agent-view launch` times out, start the app manually and use `agent-view discover` to verify.
558
+
559
+ ---
560
+
561
+ ## License
562
+
563
+ MIT. See [LICENSE](LICENSE).