@petukhovart/agent-view 0.3.0 → 0.5.0

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.
Files changed (77) hide show
  1. package/.claude-plugin/marketplace.json +14 -0
  2. package/.claude-plugin/plugin.json +2 -2
  3. package/README.md +164 -113
  4. package/dist/cdp/ax-cache.d.ts +7 -0
  5. package/dist/cdp/ax-cache.d.ts.map +1 -1
  6. package/dist/cdp/ax-cache.js +7 -0
  7. package/dist/cdp/ax-cache.js.map +1 -1
  8. package/dist/cdp/transport.d.ts.map +1 -1
  9. package/dist/cdp/transport.js +98 -27
  10. package/dist/cdp/transport.js.map +1 -1
  11. package/dist/cdp/types.d.ts +45 -2
  12. package/dist/cdp/types.d.ts.map +1 -1
  13. package/dist/cdp/types.js +6 -0
  14. package/dist/cdp/types.js.map +1 -1
  15. package/dist/cli/commands/console.d.ts +1 -0
  16. package/dist/cli/commands/console.d.ts.map +1 -1
  17. package/dist/cli/commands/console.js +1 -0
  18. package/dist/cli/commands/console.js.map +1 -1
  19. package/dist/cli/commands/dom.d.ts +4 -0
  20. package/dist/cli/commands/dom.d.ts.map +1 -1
  21. package/dist/cli/commands/dom.js +4 -0
  22. package/dist/cli/commands/dom.js.map +1 -1
  23. package/dist/cli/commands/drag.d.ts +13 -0
  24. package/dist/cli/commands/drag.d.ts.map +1 -0
  25. package/dist/cli/commands/drag.js +72 -0
  26. package/dist/cli/commands/drag.js.map +1 -0
  27. package/dist/cli/commands/scene.d.ts +1 -0
  28. package/dist/cli/commands/scene.d.ts.map +1 -1
  29. package/dist/cli/commands/scene.js +2 -0
  30. package/dist/cli/commands/scene.js.map +1 -1
  31. package/dist/cli/commands/screenshot.d.ts +1 -0
  32. package/dist/cli/commands/screenshot.d.ts.map +1 -1
  33. package/dist/cli/commands/screenshot.js +4 -0
  34. package/dist/cli/commands/screenshot.js.map +1 -1
  35. package/dist/cli/commands/snap.d.ts +1 -0
  36. package/dist/cli/commands/snap.d.ts.map +1 -1
  37. package/dist/cli/commands/snap.js +2 -0
  38. package/dist/cli/commands/snap.js.map +1 -1
  39. package/dist/cli/commands/watch.d.ts +12 -0
  40. package/dist/cli/commands/watch.d.ts.map +1 -0
  41. package/dist/cli/commands/watch.js +233 -0
  42. package/dist/cli/commands/watch.js.map +1 -0
  43. package/dist/cli/index.js +48 -1
  44. package/dist/cli/index.js.map +1 -1
  45. package/dist/config/manager.js +1 -1
  46. package/dist/config/types.d.ts +0 -3
  47. package/dist/config/types.d.ts.map +1 -1
  48. package/dist/inspectors/dom/index.d.ts +13 -0
  49. package/dist/inspectors/dom/index.d.ts.map +1 -1
  50. package/dist/inspectors/dom/index.js +255 -103
  51. package/dist/inspectors/dom/index.js.map +1 -1
  52. package/dist/inspectors/scene/formatter.d.ts.map +1 -1
  53. package/dist/inspectors/scene/formatter.js +56 -8
  54. package/dist/inspectors/scene/formatter.js.map +1 -1
  55. package/dist/inspectors/scene/types.d.ts +1 -0
  56. package/dist/inspectors/scene/types.d.ts.map +1 -1
  57. package/dist/inspectors/watch/index.d.ts +18 -0
  58. package/dist/inspectors/watch/index.d.ts.map +1 -0
  59. package/dist/inspectors/watch/index.js +39 -0
  60. package/dist/inspectors/watch/index.js.map +1 -0
  61. package/dist/inspectors/watch/types.d.ts +70 -0
  62. package/dist/inspectors/watch/types.d.ts.map +1 -0
  63. package/dist/inspectors/watch/types.js +21 -0
  64. package/dist/inspectors/watch/types.js.map +1 -0
  65. package/dist/server/server.d.ts +9 -1
  66. package/dist/server/server.d.ts.map +1 -1
  67. package/dist/server/server.js +279 -48
  68. package/dist/server/server.js.map +1 -1
  69. package/dist/server/watch-session.d.ts +32 -0
  70. package/dist/server/watch-session.d.ts.map +1 -0
  71. package/dist/server/watch-session.js +165 -0
  72. package/dist/server/watch-session.js.map +1 -0
  73. package/dist/types.d.ts +2 -0
  74. package/dist/types.d.ts.map +1 -1
  75. package/package.json +61 -60
  76. package/skills/verify/SKILL.md +64 -13
  77. package/skills/verify-recipe/SKILL.md +185 -0
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "agent-view",
3
+ "owner": {
4
+ "name": "PetukhovArt",
5
+ "url": "https://github.com/PetukhovArt"
6
+ },
7
+ "plugins": [
8
+ {
9
+ "name": "agent-view",
10
+ "source": "./",
11
+ "description": "Visual verification CLI for desktop apps (Electron/Tauri/Browser) via Chrome DevTools Protocol. Inspect DOM, interact with UI, capture screenshots, and read WebGL scene graphs."
12
+ }
13
+ ]
14
+ }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "agent-view",
3
- "description": "Visual verification CLI for desktop apps (Electron/Tauri/Browser) via Chrome DevTools Protocol. Inspect DOM, interact with UI, capture screenshots, and read WebGL scene graphs.",
4
- "version": "0.1.0",
3
+ "description": "Visual verification CLI for desktop apps (Electron/Tauri/Browser) via Chrome DevTools Protocol. Ships two skills: verify (run DOM, screenshot, eval, watch, console checks against a live app) and verify-recipe (author a disciplined verification plan as a .md file).",
4
+ "version": "0.5.0",
5
5
  "keywords": [
6
6
  "cdp",
7
7
  "electron",
package/README.md CHANGED
@@ -1,13 +1,24 @@
1
1
  # agent-view
2
2
 
3
- **Give your AI agent eyes and hands for desktop apps.**
3
+ **Give your AI agent eyes and hands for complex desktop apps verification**
4
4
 
5
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
6
 
7
- agent-view bridges that gap: it connects to any Chromium-based desktop app via Chrome DevTools Protocol and lets the agent inspect the UI, take screenshots, click buttons, and fill forms.
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
8
 
9
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
10
 
11
+ ## What it does
12
+
13
+ - **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
14
+ - **Screenshots** — full-res PNG, scaled WebP (~3–12× fewer vision tokens), or `--crop <filter>` to a single element bounding box
15
+ - **Interaction** — click, fill, and drag by ref or coordinates; works with Vue/React/native frameworks
16
+ - **JS state via `eval`** — read store contents, computed values, async results without scraping the DOM
17
+ - **Reactive state via `watch`** — stream JSON-patch diffs of any expression (store, ref, computed) until a condition is met
18
+ - **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
19
+ - **Worker access** — SharedWorker, ServiceWorker, dedicated Worker visible alongside pages; fuzzy `--target` resolution everywhere (id → title → URL)
20
+ - **Canvas / WebGL scene graph** — PixiJS today, engine-pluggable; `--compact` mirrors the DOM mode
21
+
11
22
  ## Why CLI, not MCP?
12
23
 
13
24
  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.
@@ -16,68 +27,70 @@ agent-view is a CLI. One Bash call, compact text output, zero schema overhead. T
16
27
 
17
28
  And CLI works everywhere — Claude Code, Copilot, Codex, custom pipelines, CI. No MCP client required.
18
29
 
19
- ## The feedback loop
20
-
21
- The real power isn't in individual commands — it's in the **loop**:
30
+ ## Install & Update
22
31
 
23
- ```
24
- Code → Launch → See → Verify → Fix → See again
25
- ```
32
+ ### Claude Code (recommended)
26
33
 
27
- The agent writes code, then immediately checks what the user would see. If something's wrong, it fixes and re-checks no human needed. This catches problems that builds and tests miss: CSS regressions, broken layouts, missing error messages, silent IPC failures.
34
+ Two stepsboth required:
28
35
 
29
- ## v0.3.0 — DevTools access (eval, console, workers)
30
-
31
- Beyond DOM and screenshots, v0.3.0 adds direct access to JS state and console — including SharedWorker / ServiceWorker. Useful when «what's rendered» isn't enough and you need to check what's actually in the store, in a worker, or in the console.
32
-
33
- - `eval <expr>` — read state directly (`store.user.role`, computed values, async getters). Gated by `"allowEval": true` in config.
34
- - `eval --target <worker>` — same, but inside a SharedWorker / ServiceWorker / dedicated Worker.
35
- - `console` — capture `console.log/warn/error` per page or per worker. `--clear` for baselines, `--level` to filter.
36
- - `targets` — list every connectable CDP target.
36
+ ```bash
37
+ # 1. Install the plugin — adds two skills: verify (run checks against a live app) and verify-recipe (author a verification plan)
38
+ /plugin marketplace add PetukhovArt/agent-view
39
+ /plugin install agent-view@agent-view
37
40
 
38
- See [Commands](#commands) for flags. Full notes in [CHANGELOG](CHANGELOG.md).
41
+ # 2. Install the CLI — the skill calls these binaries; the plugin doesn't bundle them
42
+ npm install -g @petukhovart/agent-view
43
+ ```
39
44
 
40
- ## Performance
45
+ 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".
41
46
 
42
- AI agents run dozens of `dom → click → dom` verification cycles per session. Every millisecond compounds. agent-view v0.2.0 is built specifically for this pattern.
47
+ Verify:
43
48
 
44
- ### Benchmark results (Electron app, ~200 AX nodes)
49
+ ```bash
50
+ agent-view --version # 0.5.0+
51
+ ```
45
52
 
46
- | Scenario | v0.1.0 | v0.2.0 | vs Playwright* |
47
- |---|---|---|---|
48
- | `dom` cold fetch | 10ms | 2ms | ~30–80ms |
49
- | `dom` warm (cache hit) | 10ms | 1ms | ~30–80ms |
50
- | Full cycle `dom → click → dom` | 27ms | 17ms | ~75ms |
51
- | `click --filter "Save"` | 12ms | 17ms† | ~15–30ms |
53
+ ### Standalone CLI (any other agent, CI, or scripting)
52
54
 
53
- \* *Playwright estimate based on architectural analysis — no published Electron-specific benchmarks exist*
54
- *queryAXTree has CDP overhead that exceeds the benefit on small DOMs; improves on large production DOMs (1000+ nodes)*
55
+ ```bash
56
+ npm install -g @petukhovart/agent-view
57
+ ```
55
58
 
56
- ### What makes it fast
59
+ Everything works from this alone — `agent-view dom`, `screenshot`, `eval`, etc. Skip the plugin step.
57
60
 
58
- **AX tree cache (300ms TTL).** The single biggest win. When an agent calls `dom`, then immediately `click --filter`, the second fetch hits the in-process cache instead of making a CDP round-trip. Cache is invalidated aggressively — busted on every `click`, `fill`, or page navigation.
61
+ ### Update
59
62
 
60
- **Parallel CDP calls in click.** Previously 5 serial round-trips; now 3 parallel batches. `DOM.resolveNode` and `DOM.getBoxModel` run concurrently, then mouse events fire back-to-back without waiting for each response (the same approach Playwright uses internally).
63
+ ```bash
64
+ # Update the CLI to the latest version
65
+ npm update -g @petukhovart/agent-view
61
66
 
62
- **`Accessibility.queryAXTree` for targeted lookups.** Plain string filters (`click --filter "Save"`) and `role:name` filters (`click --filter "button:Save"`) query the browser directly instead of fetching the full tree. Falls back gracefully on older Electron versions.
67
+ # Update the Claude Code plugin (refreshes skills from the marketplace)
68
+ /plugin marketplace update agent-view
69
+ /plugin install agent-view@agent-view # re-run to pick up new skill versions
70
+ ```
63
71
 
64
- **Raw CDP, no relay.** No Playwright client-server relay between your agent and the browser. The server process holds the CDP WebSocket connection and reuses it across commands.
72
+ The two are independent bump the CLI when a new release ships features (see `CHANGELOG.md`), bump the plugin when skill instructions change.
65
73
 
66
74
  ## Enabling CDP
67
75
 
76
+ agent-view talks to your app over Chrome DevTools Protocol. Your app must be launched with a debugging port open.
77
+
68
78
  ### Recommended: in code (reliable, works with any build tool)
69
79
 
70
80
  Add to your Electron main process:
71
81
 
72
82
  ```js
73
- app.commandLine.appendSwitch('remote-debugging-port', '9222');
83
+ app.commandLine.appendSwitch('remote-debugging-port', '9876');
74
84
  ```
75
85
 
86
+ > Any free port works — `9876` is just an example. Avoid `9222` (Chrome's own default remote-debugging port) to prevent
87
+ > collisions when Chrome is open.
88
+
76
89
  For dev-only:
77
90
 
78
91
  ```js
79
92
  if (!app.isPackaged) {
80
- app.commandLine.appendSwitch('remote-debugging-port', '9222');
93
+ app.commandLine.appendSwitch('remote-debugging-port', '9876');
81
94
  }
82
95
  ```
83
96
 
@@ -85,46 +98,26 @@ if (!app.isPackaged) {
85
98
 
86
99
  ```bash
87
100
  # Plain Electron
88
- electron . --remote-debugging-port=9222
101
+ electron . --remote-debugging-port=9876
89
102
 
90
103
  # electron-vite (note the -- to forward the flag past the build tool)
91
- npx electron-vite dev -- --remote-debugging-port=9222
104
+ npx electron-vite dev -- --remote-debugging-port=9876
92
105
  ```
93
106
 
94
107
  ### Other runtimes
95
108
 
96
- | Runtime | Setup |
97
- |---------|-------|
98
- | **Tauri** | CDP via devtools configuration |
99
- | **Any Chromium app** | `--remote-debugging-port=9222` launch flag |
109
+ | Runtime | Setup |
110
+ |----------------------|--------------------------------------------|
111
+ | **Tauri** | CDP via devtools configuration |
112
+ | **Any Chromium app** | `--remote-debugging-port=9876` launch flag |
100
113
 
101
114
  ### Verify CDP is working
102
115
 
103
116
  ```bash
104
- curl -s http://localhost:9222/json/version
117
+ curl -s http://localhost:9876/json/version
105
118
  ```
106
119
 
107
- If you see a JSON response with browser info — you're good.
108
-
109
- ## Install
110
-
111
- ### As CLI tool
112
-
113
- ```bash
114
- npm install -g @petukhovart/agent-view
115
- ```
116
-
117
- ### As Claude Code plugin
118
-
119
- ```bash
120
- # Add marketplace (once)
121
- /plugin marketplace add PetukhovArt/agent-view
122
-
123
- # Install plugin
124
- /plugin install agent-view@agent-view
125
- ```
126
-
127
- This gives Claude the `/agent-view:verify` skill — it knows when and how to use agent-view for visual verification during development workflows.
120
+ If you see a JSON response with process info — you're good.
128
121
 
129
122
  ## Quick start
130
123
 
@@ -144,7 +137,7 @@ agent-view screenshot # PNG screenshot
144
137
 
145
138
  # 4. Interact
146
139
  agent-view click 5 # Click element by ref
147
- agent-view fill 3 "hello" # Type into input
140
+ agent-view fill 3 "hello" # Type into input
148
141
 
149
142
  # 5. Verify the result
150
143
  agent-view dom --filter "success" # Check for expected element
@@ -161,28 +154,47 @@ A background server connects to your app's CDP port, caches sessions, and auto-s
161
154
 
162
155
  ## Config
163
156
 
164
- Running `agent-view init` in your project root generates `agent-view.config.json`:
157
+ Running `agent-view init` in your project root generates `agent-view.config.json`. Minimal form:
165
158
 
166
159
  ```json
167
160
  {
168
161
  "runtime": "electron",
169
- "port": 9222,
162
+ "port": 9876,
170
163
  "launch": "npm run dev"
171
164
  }
172
165
  ```
173
166
 
174
- | Field | Required | Description |
175
- |-------|----------|-------------|
176
- | `runtime` | yes | `"electron"`, `"tauri"`, or `"browser"` |
177
- | `port` | yes | CDP debugging port |
178
- | `launch` | no | Command to start the app |
179
- | `webgl.engine` | no | `"pixi"` (scene extractor architecture supports adding more engines) |
180
- | `allowEval` | no | `true` to enable `agent-view eval`. Off by default — opt-in for arbitrary JS execution |
181
- | `consoleBufferSize` | no | Per-target console ring capacity. Default `500` |
182
- | `consoleTargets` | no | Target types `agent-view console` auto-attaches to. Default `["page", "shared_worker", "service_worker"]` |
167
+ Full form with all optional fields:
168
+
169
+ ```json
170
+ {
171
+ "runtime": "electron",
172
+ "port": 9876,
173
+ "launch": "npm run dev",
174
+ "allowEval": true,
175
+ "webgl": {
176
+ "engine": "pixi"
177
+ },
178
+ "consoleBufferSize": 500,
179
+ "consoleTargets": ["page", "shared_worker", "service_worker"]
180
+ }
181
+ ```
182
+
183
+ | Field | Required | Description |
184
+ |---------------------|----------|-----------------------------------------------------------------------------------------------------------|
185
+ | `runtime` | yes | `"electron"`, `"tauri"`, or `"browser"` |
186
+ | `port` | yes | CDP debugging port |
187
+ | `launch` | no | Command to start the app |
188
+ | `webgl.engine` | no | `"pixi"` (scene extractor architecture supports adding more engines) |
189
+ | `allowEval` | no | `true` to enable `agent-view eval` and `watch`. Off by default — opt-in for arbitrary JS execution |
190
+ | `consoleBufferSize` | no | Per-target console ring capacity. Default `500` |
191
+ | `consoleTargets` | no | Target types `agent-view console` auto-attaches to. Default `["page", "shared_worker", "service_worker"]` |
183
192
 
184
193
  ## Commands
185
194
 
195
+ Every command targeting a window accepts `--window <id|title-substring>` (IDs come from `discover`). Examples below omit
196
+ it for brevity.
197
+
186
198
  ### `init`
187
199
 
188
200
  Auto-generates config by reading `package.json`.
@@ -203,12 +215,22 @@ Dumps the accessibility tree in compact text format. Each element gets a session
203
215
  agent-view dom
204
216
  agent-view dom --filter "Submit" # Filter by text/role
205
217
  agent-view dom --depth 3 # Limit tree depth
206
- agent-view dom --window "Settings" # Target specific window
218
+ agent-view dom --max-lines 200 # Hard line budget (refs for hidden nodes still stored)
207
219
  agent-view dom --text # Fall back to DOM textContent search when AX returns no match
220
+ agent-view dom --compact # Merge single-child chains onto one line (saves ~40-60% tokens)
221
+ agent-view dom --count # Return only the count of matching nodes (e.g. "5")
222
+ agent-view dom --filter "row" --count # Count how many rows match
223
+ agent-view dom --diff # Show only lines that changed since last call
208
224
  ```
209
225
 
210
226
  When `--filter` is set, depth defaults to unlimited so deep matches aren't truncated.
211
227
 
228
+ `--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.
229
+
230
+ `--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.
231
+
232
+ `--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.
233
+
212
234
  ### `click`
213
235
 
214
236
  Clicks a DOM element by ref ID or coordinates.
@@ -226,18 +248,40 @@ Types text into an input. Uses native value setter + dispatches input/change eve
226
248
  agent-view fill 3 "hello@example.com"
227
249
  ```
228
250
 
251
+ ### `drag`
252
+
253
+ HTML5 / pointer-driven drag-and-drop via CDP `Input.dispatchMouseEvent`
254
+ (`mousePressed` → N × `mouseMoved` → `mouseReleased`). Real mouse events, not
255
+ synthesized JS events — works with `vue-draggable-resizable`, `react-grid-layout`,
256
+ gridstack, kanban boards, file drop zones, map pin drags, resize handles.
257
+
258
+ ```bash
259
+ agent-view drag --from 42 --to 88 # ref → ref
260
+ agent-view drag --from-pos 86,792 --to-pos 640,200 # coord → coord (canvas, custom DnD)
261
+ agent-view drag --from 42 --to-pos 640,200 # mixed
262
+ agent-view drag --from 5 --to 9 --steps 20 --hold-ms 150
263
+ ```
264
+
265
+ `--steps` (default 10) controls intermediate `mouseMoved` events so libraries
266
+ that throttle on movement deltas still see continuous motion. `--hold-ms`
267
+ inserts a pause between press and the first move (some libs require >100ms
268
+ for touch-style activation). `--button` accepts `left|right|middle`.
269
+
229
270
  ### `screenshot`
230
271
 
231
- Captures a screenshot, saves to temp dir, prints the file path. PNG by default; JPEG when `--scale` is set.
272
+ 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).
232
273
 
233
274
  ```bash
234
275
  agent-view screenshot
235
- agent-view screenshot --window "Settings"
236
- agent-view screenshot --scale 0.5 # Half-res JPEG (~3× fewer vision tokens)
237
- agent-view screenshot --scale 0.25 # Quarter-res JPEG (~12× fewer, 1 tile)
276
+ agent-view screenshot --scale 0.5 # Half-res WebP (~3× fewer vision tokens)
277
+ agent-view screenshot --scale 0.25 # Quarter-res WebP (~12× fewer, 1 tile)
278
+ agent-view screenshot --crop "Sidebar" # Crop to element bounding box (~12× fewer in best case)
279
+ agent-view screenshot --crop "Chart" --scale 0.5 # Crop + scale (stacks)
238
280
  ```
239
281
 
240
- `--scale` accepts a factor in `(0, 1]`. CDP-side clip + JPEG encode — recommended for agent loops where vision tokens dominate cost.
282
+ `--scale` accepts a factor in `(0, 1]`. CDP-side clip + WebP encode — recommended for agent loops where vision tokens dominate cost.
283
+
284
+ `--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`.
241
285
 
242
286
  ### `scene`
243
287
 
@@ -248,14 +292,16 @@ agent-view scene # Full scene graph
248
292
  agent-view scene --diff # Changes since last call
249
293
  agent-view scene --filter "player" # Filter by name/type
250
294
  agent-view scene --verbose # Extended props (alpha, scale, bounds)
295
+ agent-view scene --compact # Merge single-child chains onto one line
251
296
  ```
252
297
 
253
298
  ### `snap`
254
299
 
255
- Combined DOM + scene graph in one call. Shows DOM always; scene section appears when a WebGL engine is detected.
300
+ 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.
256
301
 
257
302
  ```bash
258
303
  agent-view snap
304
+ agent-view snap --scale 0.5 # DOM + Scene + Screenshot (path written to tmp)
259
305
  ```
260
306
 
261
307
  ### `wait`
@@ -301,55 +347,60 @@ Streams or dumps console output (`Runtime.consoleAPICalled` + `Log.entryAdded`)
301
347
  ```bash
302
348
  agent-view console # buffered messages since attach
303
349
  agent-view console --follow --timeout 10 # stream for 10s
304
- agent-view console --target IJ56KL # restrict to one target
350
+ agent-view console --follow --until "ready" # exit as soon as a message contains "ready"
351
+ agent-view console --follow --until "/error/i" # exit on regex match (case-insensitive)
352
+ agent-view console --target IJ56KL # restrict to one target (exact id)
353
+ agent-view console --target sync-worker # restrict to one target (title/URL substring)
305
354
  agent-view console --level error,warn # level filter
306
355
  agent-view console --since "2026-04-26T10:00:00Z"
307
356
  agent-view console --clear # drop in-memory ring
308
357
  ```
309
358
 
310
- Default attached target types: `page`, `shared_worker`, `service_worker`. Override with `consoleTargets` in config.
359
+ `--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`.
311
360
 
312
- ### `stop`
361
+ `--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.
313
362
 
314
- Stops the background lazy server.
363
+ Default attached target types: `page`, `shared_worker`, `service_worker`. Override with `consoleTargets` in config.
315
364
 
316
- ## Multiwindow
365
+ ### `watch`
317
366
 
318
- All commands accept `--window` with either an ID (from `discover`) or a window title substring:
367
+ 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`).
319
368
 
320
369
  ```bash
321
- agent-view dom --window "Settings"
322
- agent-view screenshot --window "About"
370
+ agent-view watch "store.cart.total" # 250ms poll, exits at 10 changes or 30s
371
+ agent-view watch "appState" --interval 100 --duration 60 # tighter cadence, longer window
372
+ agent-view watch "store.status" --until "store.status === 'ready'" # wait-for assertion
373
+ agent-view watch "appState" --max-changes 1 # snapshot first change after a click
374
+ agent-view watch "appState" --json # NDJSON, one frame per line
323
375
  ```
324
376
 
325
- ## Output format
377
+ 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.
326
378
 
327
- | Command | Format | Why |
328
- |---------|--------|-----|
329
- | `dom`, `scene`, `snap` | Plain text | LLM-friendly, minimal tokens |
330
- | `discover` | JSON | Machine-parseable |
331
- | `screenshot` | File path | Agent reads the image |
379
+ ### `stop`
332
380
 
333
- ## Claude Code plugin
381
+ Stops the background lazy server.
334
382
 
335
- agent-view ships as a Claude Code plugin with a built-in `verify` skill. The skill teaches Claude how to use agent-view for UI verification after code changes.
383
+ ## Output format
336
384
 
337
- ### Local development
385
+ | Command | Format | Why |
386
+ |------------------------|------------|------------------------------|
387
+ | `dom`, `scene`, `snap` | Plain text | LLM-friendly, minimal tokens |
388
+ | `discover` | JSON | Machine-parseable |
389
+ | `screenshot` | File path | Agent reads the image |
338
390
 
339
- ```bash
340
- claude --plugin-dir /path/to/agent-view
341
- ```
391
+ ## Performance
342
392
 
343
- The skill becomes available as `/agent-view:verify`.
393
+ Built for tight `dom click → dom` loops. Typical Electron app, ~200 AX nodes:
344
394
 
345
- ### After npm install
395
+ | Scenario | agent-view | Playwright (estimate) |
396
+ |--------------------------------|------------|-----------------------|
397
+ | `dom` cold fetch | 2ms | ~30–80ms |
398
+ | `dom` warm (cache hit) | 1ms | ~30–80ms |
399
+ | Full cycle `dom → click → dom` | 17ms | ~75ms |
346
400
 
347
- ```bash
348
- # Find where the package is installed
349
- npm root -g
350
- # Use that path with --plugin-dir
351
- claude --plugin-dir "$(npm root -g)/agent-view"
352
- ```
401
+ What makes it fast: 300ms AX-tree cache (invalidated on `click`/`fill`/navigation; cached responses prefixed with
402
+ `[cache]`), parallel CDP calls in `click`, `Accessibility.queryAXTree` for filter lookups, and a single persistent CDP
403
+ WebSocket reused across commands (no relay).
353
404
 
354
405
  ## Example: testing a login flow
355
406
 
@@ -378,8 +429,8 @@ agent-view screenshot
378
429
 
379
430
  ### CDP not responding
380
431
 
381
- 1. Check the port is listening: `curl -s http://localhost:9222/json/version`
382
- 2. For electron-vite: make sure you use `--` before the flag: `npx electron-vite dev -- --remote-debugging-port=9222`
432
+ 1. Check the port is listening: `curl -s http://localhost:9876/json/version`
433
+ 2. For electron-vite: make sure you use `--` before the flag: `npx electron-vite dev -- --remote-debugging-port=9876`
383
434
  3. Restart the app — HMR doesn't restart the main process
384
435
 
385
436
  ### Stale refs after HMR
@@ -1,7 +1,14 @@
1
1
  import type { AXNode } from './types.js';
2
+ export type AxTreeResult = {
3
+ nodes: AXNode[];
4
+ fromCache: boolean;
5
+ };
2
6
  export declare class AxTreeCache {
3
7
  private entries;
4
8
  get(key: string): AXNode[] | null;
9
+ getWithMeta(key: string): AxTreeResult & {
10
+ found: boolean;
11
+ };
5
12
  set(key: string, nodes: AXNode[]): void;
6
13
  invalidate(key: string): void;
7
14
  invalidateAll(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"ax-cache.d.ts","sourceRoot":"","sources":["../../src/cdp/ax-cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AASxC,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAgC;IAE/C,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI;IAUjC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI;IAIvC,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAI7B,aAAa,IAAI,IAAI;CAGtB"}
1
+ {"version":3,"file":"ax-cache.d.ts","sourceRoot":"","sources":["../../src/cdp/ax-cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AASxC,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,SAAS,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAgC;IAE/C,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI;IAUjC,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG;QAAE,KAAK,EAAE,OAAO,CAAA;KAAE;IAQ3D,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI;IAIvC,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAI7B,aAAa,IAAI,IAAI;CAGtB"}
@@ -11,6 +11,13 @@ export class AxTreeCache {
11
11
  }
12
12
  return entry.nodes;
13
13
  }
14
+ getWithMeta(key) {
15
+ const cached = this.get(key);
16
+ if (cached) {
17
+ return { nodes: cached, fromCache: true, found: true };
18
+ }
19
+ return { nodes: [], fromCache: false, found: false };
20
+ }
14
21
  set(key, nodes) {
15
22
  this.entries.set(key, { nodes, timestamp: Date.now() });
16
23
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ax-cache.js","sourceRoot":"","sources":["../../src/cdp/ax-cache.ts"],"names":[],"mappings":"AAEA,MAAM,eAAe,GAAG,GAAG,CAAA;AAO3B,MAAM,OAAO,WAAW;IACd,OAAO,GAAG,IAAI,GAAG,EAAsB,CAAA;IAE/C,GAAG,CAAC,GAAW;QACb,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QACnC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAA;QACvB,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,GAAG,eAAe,EAAE,CAAC;YACnD,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YACxB,OAAO,IAAI,CAAA;QACb,CAAC;QACD,OAAO,KAAK,CAAC,KAAK,CAAA;IACpB,CAAC;IAED,GAAG,CAAC,GAAW,EAAE,KAAe;QAC9B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAA;IACzD,CAAC;IAED,UAAU,CAAC,GAAW;QACpB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;IAC1B,CAAC;IAED,aAAa;QACX,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAA;IACtB,CAAC;CACF"}
1
+ {"version":3,"file":"ax-cache.js","sourceRoot":"","sources":["../../src/cdp/ax-cache.ts"],"names":[],"mappings":"AAEA,MAAM,eAAe,GAAG,GAAG,CAAA;AAY3B,MAAM,OAAO,WAAW;IACd,OAAO,GAAG,IAAI,GAAG,EAAsB,CAAA;IAE/C,GAAG,CAAC,GAAW;QACb,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QACnC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAA;QACvB,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,GAAG,eAAe,EAAE,CAAC;YACnD,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YACxB,OAAO,IAAI,CAAA;QACb,CAAC;QACD,OAAO,KAAK,CAAC,KAAK,CAAA;IACpB,CAAC;IAED,WAAW,CAAC,GAAW;QACrB,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QAC5B,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAA;QACxD,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;IACtD,CAAC;IAED,GAAG,CAAC,GAAW,EAAE,KAAe;QAC9B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAA;IACzD,CAAC;IAED,UAAU,CAAC,GAAW;QACpB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;IAC1B,CAAC;IAED,aAAa;QACX,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAA;IACtB,CAAC;CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/cdp/transport.ts"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,SAAS,EAGd,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,WAAW,EAGjB,MAAM,YAAY,CAAA;AACnB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAoBhD,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAkBpE;AAED,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAQ9E;AAsKD,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,cAAc,CAAC,CAmBhG;AAED,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,WAAW,GACjB,OAAO,CAAC,WAAW,CAAC,CAmItB"}
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/cdp/transport.ts"],"names":[],"mappings":"AAEA,OAAO,EAML,KAAK,SAAS,EAId,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,WAAW,EAKjB,MAAM,YAAY,CAAA;AACnB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAoBhD,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAkBpE;AAED,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAQ9E;AAsKD,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,cAAc,CAAC,CAmBhG;AAED,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,WAAW,GACjB,OAAO,CAAC,WAAW,CAAC,CAoNtB"}