@petukhovart/agent-view 0.1.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 (131) hide show
  1. package/.claude-plugin/marketplace.json +14 -0
  2. package/.claude-plugin/plugin.json +13 -2
  3. package/README.md +211 -61
  4. package/dist/adapters/browser.d.ts.map +1 -1
  5. package/dist/adapters/browser.js +11 -11
  6. package/dist/adapters/browser.js.map +1 -1
  7. package/dist/adapters/electron.d.ts.map +1 -1
  8. package/dist/adapters/electron.js +11 -11
  9. package/dist/adapters/electron.js.map +1 -1
  10. package/dist/adapters/tauri.d.ts.map +1 -1
  11. package/dist/adapters/tauri.js +11 -11
  12. package/dist/adapters/tauri.js.map +1 -1
  13. package/dist/adapters/types.d.ts +5 -2
  14. package/dist/adapters/types.d.ts.map +1 -1
  15. package/dist/cdp/_tests/console-stream.d.ts +35 -0
  16. package/dist/cdp/_tests/console-stream.d.ts.map +1 -0
  17. package/dist/cdp/_tests/console-stream.js +103 -0
  18. package/dist/cdp/_tests/console-stream.js.map +1 -0
  19. package/dist/cdp/ax-cache.d.ts +16 -0
  20. package/dist/cdp/ax-cache.d.ts.map +1 -0
  21. package/dist/cdp/ax-cache.js +31 -0
  22. package/dist/cdp/ax-cache.js.map +1 -0
  23. package/dist/cdp/console-stream.d.ts +35 -0
  24. package/dist/cdp/console-stream.d.ts.map +1 -0
  25. package/dist/cdp/console-stream.js +103 -0
  26. package/dist/cdp/console-stream.js.map +1 -0
  27. package/dist/cdp/transport.d.ts +5 -2
  28. package/dist/cdp/transport.d.ts.map +1 -1
  29. package/dist/cdp/transport.js +309 -26
  30. package/dist/cdp/transport.js.map +1 -1
  31. package/dist/cdp/types.d.ts +109 -8
  32. package/dist/cdp/types.d.ts.map +1 -1
  33. package/dist/cdp/types.js +35 -1
  34. package/dist/cdp/types.js.map +1 -1
  35. package/dist/cli/commands/console.d.ts +12 -0
  36. package/dist/cli/commands/console.d.ts.map +1 -0
  37. package/dist/cli/commands/console.js +32 -0
  38. package/dist/cli/commands/console.js.map +1 -0
  39. package/dist/cli/commands/dom.d.ts +5 -0
  40. package/dist/cli/commands/dom.d.ts.map +1 -1
  41. package/dist/cli/commands/dom.js +5 -0
  42. package/dist/cli/commands/dom.js.map +1 -1
  43. package/dist/cli/commands/drag.d.ts +13 -0
  44. package/dist/cli/commands/drag.d.ts.map +1 -0
  45. package/dist/cli/commands/drag.js +72 -0
  46. package/dist/cli/commands/drag.js.map +1 -0
  47. package/dist/cli/commands/eval.d.ts +9 -0
  48. package/dist/cli/commands/eval.d.ts.map +1 -0
  49. package/dist/cli/commands/eval.js +30 -0
  50. package/dist/cli/commands/eval.js.map +1 -0
  51. package/dist/cli/commands/scene.d.ts +1 -0
  52. package/dist/cli/commands/scene.d.ts.map +1 -1
  53. package/dist/cli/commands/scene.js +2 -0
  54. package/dist/cli/commands/scene.js.map +1 -1
  55. package/dist/cli/commands/screenshot.d.ts +2 -0
  56. package/dist/cli/commands/screenshot.d.ts.map +1 -1
  57. package/dist/cli/commands/screenshot.js +6 -0
  58. package/dist/cli/commands/screenshot.js.map +1 -1
  59. package/dist/cli/commands/snap.d.ts +1 -0
  60. package/dist/cli/commands/snap.d.ts.map +1 -1
  61. package/dist/cli/commands/snap.js +2 -0
  62. package/dist/cli/commands/snap.js.map +1 -1
  63. package/dist/cli/commands/targets.d.ts +7 -0
  64. package/dist/cli/commands/targets.d.ts.map +1 -0
  65. package/dist/cli/commands/targets.js +30 -0
  66. package/dist/cli/commands/targets.js.map +1 -0
  67. package/dist/cli/commands/watch.d.ts +12 -0
  68. package/dist/cli/commands/watch.d.ts.map +1 -0
  69. package/dist/cli/commands/watch.js +233 -0
  70. package/dist/cli/commands/watch.js.map +1 -0
  71. package/dist/cli/index.js +86 -1
  72. package/dist/cli/index.js.map +1 -1
  73. package/dist/config/manager.d.ts.map +1 -1
  74. package/dist/config/manager.js +11 -1
  75. package/dist/config/manager.js.map +1 -1
  76. package/dist/config/types.d.ts +11 -3
  77. package/dist/config/types.d.ts.map +1 -1
  78. package/dist/inspectors/dom/index.d.ts +30 -0
  79. package/dist/inspectors/dom/index.d.ts.map +1 -0
  80. package/dist/inspectors/dom/index.js +283 -0
  81. package/dist/inspectors/dom/index.js.map +1 -0
  82. package/dist/inspectors/scene/adapters/pixi/adapter.d.ts +3 -0
  83. package/dist/inspectors/scene/adapters/pixi/adapter.d.ts.map +1 -0
  84. package/dist/inspectors/scene/adapters/pixi/adapter.js +51 -0
  85. package/dist/inspectors/scene/adapters/pixi/adapter.js.map +1 -0
  86. package/dist/inspectors/scene/adapters/pixi/index.d.ts +2 -0
  87. package/dist/inspectors/scene/adapters/pixi/index.d.ts.map +1 -0
  88. package/dist/inspectors/scene/adapters/pixi/index.js +2 -0
  89. package/dist/inspectors/scene/adapters/pixi/index.js.map +1 -0
  90. package/dist/inspectors/scene/adapters/pixi/injection.d.ts +39 -0
  91. package/dist/inspectors/scene/adapters/pixi/injection.d.ts.map +1 -0
  92. package/dist/inspectors/scene/adapters/pixi/injection.js +41 -0
  93. package/dist/inspectors/scene/adapters/pixi/injection.js.map +1 -0
  94. package/dist/inspectors/scene/formatter.d.ts +0 -1
  95. package/dist/inspectors/scene/formatter.d.ts.map +1 -1
  96. package/dist/inspectors/scene/formatter.js +100 -43
  97. package/dist/inspectors/scene/formatter.js.map +1 -1
  98. package/dist/inspectors/scene/index.d.ts +4 -4
  99. package/dist/inspectors/scene/index.d.ts.map +1 -1
  100. package/dist/inspectors/scene/index.js +8 -5
  101. package/dist/inspectors/scene/index.js.map +1 -1
  102. package/dist/inspectors/scene/pixi.js.map +1 -1
  103. package/dist/inspectors/scene/registry.d.ts +2 -2
  104. package/dist/inspectors/scene/registry.d.ts.map +1 -1
  105. package/dist/inspectors/scene/registry.js +8 -8
  106. package/dist/inspectors/scene/registry.js.map +1 -1
  107. package/dist/inspectors/scene/types.d.ts +6 -10
  108. package/dist/inspectors/scene/types.d.ts.map +1 -1
  109. package/dist/inspectors/watch/index.d.ts +18 -0
  110. package/dist/inspectors/watch/index.d.ts.map +1 -0
  111. package/dist/inspectors/watch/index.js +39 -0
  112. package/dist/inspectors/watch/index.js.map +1 -0
  113. package/dist/inspectors/watch/types.d.ts +70 -0
  114. package/dist/inspectors/watch/types.d.ts.map +1 -0
  115. package/dist/inspectors/watch/types.js +21 -0
  116. package/dist/inspectors/watch/types.js.map +1 -0
  117. package/dist/server/server.d.ts +31 -1
  118. package/dist/server/server.d.ts.map +1 -1
  119. package/dist/server/server.js +620 -67
  120. package/dist/server/server.js.map +1 -1
  121. package/dist/server/watch-session.d.ts +32 -0
  122. package/dist/server/watch-session.d.ts.map +1 -0
  123. package/dist/server/watch-session.js +165 -0
  124. package/dist/server/watch-session.js.map +1 -0
  125. package/dist/types.d.ts +4 -1
  126. package/dist/types.d.ts.map +1 -1
  127. package/dist/types.js +1 -0
  128. package/dist/types.js.map +1 -1
  129. package/package.json +61 -59
  130. package/skills/verify/SKILL.md +146 -11
  131. package/skills/verify-recipe/SKILL.md +185 -0
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: verify
3
- description: "Visual verification of desktop app UI after code changes. Use when modifying UI components, fixing visual bugs, testing user interactions, verifying layout, or when any workflow phase needs to inspect the running application. Triggers on: verify, check UI, test how it looks, visual regression, screenshot, inspect DOM."
3
+ description: "Visual + runtime verification of desktop apps via Chrome DevTools Protocol. Use when modifying UI components, fixing visual bugs, testing user interactions, verifying layout, or when any workflow phase needs to inspect the running application — DOM, screenshots, scene graph, runtime state in pages and SharedWorkers/ServiceWorkers, console errors, or reactive-state diffs over time. Triggers on: verify, check UI, test how it looks, visual regression, screenshot, inspect DOM, check store/state, watch state changes, what changed after click, wait until state, read worker, console errors, runtime check, eval in page."
4
4
  allowed-tools: Bash(agent-view *)
5
5
  ---
6
6
 
@@ -12,7 +12,7 @@ You have access to `agent-view` CLI for inspecting and interacting with desktop
12
12
 
13
13
  The target project must have:
14
14
  1. `agent-view.config.json` in project root (run `agent-view init` to generate)
15
- 2. CDP enabled in the app (e.g. `--remote-debugging-port=9222` for Electron)
15
+ 2. CDP enabled in the app (e.g. `--remote-debugging-port=9876` for Electron — avoid `9222`, it's Chrome's own default and collides when Chrome is open)
16
16
 
17
17
  If config is missing, run `agent-view init` first.
18
18
 
@@ -31,22 +31,119 @@ agent-view dom # DOM accessibility tree (default window
31
31
  agent-view dom --window <id|name> # Specific window
32
32
  agent-view dom --filter "button" # Filter by text/role
33
33
  agent-view dom --depth 3 # Limit tree depth
34
+ agent-view dom --compact # Merge single-child chains onto one line (~40-60% fewer tokens)
35
+ agent-view dom --count # Count of all visible nodes (single integer line)
36
+ agent-view dom --filter "row" --count # Count matching nodes — e.g. "does this table have 5 rows?"
37
+ agent-view dom --max-lines 200 # Hard line budget; refs for truncated nodes still stored
38
+ agent-view dom --diff # Lines changed since last dom call (+ added / - removed)
34
39
  ```
35
40
 
41
+ `--count` skips tree output and ref mutations — cheapest way to assert "element exists N times" without loading the full tree into context.
42
+
36
43
  ### Interaction
37
44
  ```bash
38
45
  agent-view click <ref> # Click element by ref from dom output
39
46
  agent-view click --pos 100,200 # Click by coordinates (for canvas)
40
47
  agent-view fill <ref> "text" # Type into input field
48
+ agent-view drag --from <ref> --to <ref> # Drag element to another element by ref
49
+ agent-view drag --from-pos 50,80 --to-pos 200,300 # Drag by coordinates (for canvas / Pixi)
50
+ agent-view drag --from <ref> --to <ref> --steps 25 --hold-ms 60 # Smoother movement, longer hold
41
51
  ```
42
52
 
53
+ `drag` dispatches `mousePressed` → N × `mouseMoved` → `mouseReleased` via CDP. Endpoints can mix
54
+ ref and coordinate (e.g. `--from <ref> --to-pos 400,300`). For canvas/Pixi targets always use
55
+ `--from-pos`/`--to-pos` — derive the centroid via `agent-view eval` from the scene graph.
56
+ Refs are resolved fresh on each call, so window resizes between snapshots are tolerated.
57
+ Increase `--steps` for handlers using `globalpointermove` so intermediate frames are not skipped.
58
+
43
59
  ### Screenshots
44
60
  ```bash
45
- agent-view screenshot # Save PNG to temp dir, print path
46
- agent-view screenshot --window <id> # Specific window
61
+ agent-view screenshot --scale 0.5 # Recommended: JPEG at half-res (~3× fewer vision tokens)
62
+ agent-view screenshot --scale 0.5 --window <id> # Specific window
63
+ agent-view screenshot --crop "Sidebar" # Crop to element bounding box (~1.6k tokens — 12× win)
64
+ agent-view screenshot --crop "Chart" --scale 0.5 # Crop + scale (stacks)
65
+ agent-view screenshot # Full-res PNG (expensive: ~19k tokens at 1920×1080)
66
+ ```
67
+
68
+ `--crop <filter>` resolves the element with the same filter syntax as `dom --filter`, then crops the screenshot to its bounding box. Prefer `--crop` over full-window screenshots whenever you only need to inspect a specific section. Falls back to full-window with a stderr warning if the filter matches nothing.
69
+
70
+ ### Runtime State (`eval`)
71
+
72
+ Reads runtime values DOM/screenshot can't reveal — store contents, computed flags, worker internals.
73
+ **Requires `"allowEval": true` in `agent-view.config.json`** — if the call returns "eval is disabled", tell the user to add the flag rather than working around it.
74
+
75
+ ```bash
76
+ agent-view eval "store.state.user.role" # default page target
77
+ agent-view eval --window "Settings" "router.currentRoute.path"
78
+ agent-view eval --target sync-worker "self.queue.length" # SharedWorker / ServiceWorker by id or substring
79
+ agent-view eval --await "fetch('/api/health').then(r => r.status)"
80
+ agent-view eval --json "({ buttons: document.querySelectorAll('button').length })"
81
+ ```
82
+
83
+ When to reach for `eval` instead of `dom`:
84
+ - The truth lives in JS state, not the DOM (Pinia/Vuex/Redux/Zustand store, Vue refs, computed values, app singletons).
85
+ - The target is a worker (`shared_worker`, `service_worker`, `worker`) — DOM doesn't exist there.
86
+ - You need a precise number/string answer, not a tree to scan.
87
+
88
+ ### Reactive State (`watch`)
89
+
90
+ Streams JSON-patch diffs of an expression over time. Use when you need to see *what changed* between an action and a final state — `eval` shows the snapshot, `watch` shows the trajectory. **Requires `"allowEval": true`.**
91
+
92
+ ```bash
93
+ agent-view watch "store.cart.total" # 250ms poll, default 10 changes or 30s
94
+ agent-view watch "appState" --until "appState.status === 'ready'" # wait-for-condition with diff log
95
+ agent-view watch "store.user" --max-changes 1 # capture exactly one change after a click
96
+ agent-view watch "appState" --json # NDJSON, machine-readable
97
+ ```
98
+
99
+ When to reach for `watch` instead of `eval`:
100
+ - Debugging "the click did X but state shows Y — what happened in between?"
101
+ - Time-based assertions ("wait until store.status === 'ready'") — `--until` exits cleanly when truthy.
102
+ - Confirming an action triggered the *expected* sequence of mutations, not just the final state.
103
+
104
+ Output: `init` line (baseline), one line per RFC 6902 op (`replace /path old → new`, `add /items/0 ...`), final `stop` line with reason. Snapshot size cap 256 KB — narrow the expression (`store.x.y`, not `store`) for large objects.
105
+
106
+ ### Console (`console`)
107
+
108
+ Streams `Runtime.consoleAPICalled` + `Log.entryAdded`. Use to confirm a flow finished without errors, or to surface a specific warning after an interaction.
109
+
110
+ ```bash
111
+ agent-view console # buffered messages from auto-attached targets
112
+ agent-view console --level error,warn # filter
113
+ agent-view console --target sync-worker # one target (title/URL substring, same fuzzy semantics as eval --target)
114
+ agent-view console --target IJ56KL # one target (exact id)
115
+ agent-view console --follow --timeout 10 # stream window (use sparingly — 10s of waiting)
116
+ agent-view console --follow --until "ready" # exit as soon as a message contains "ready"
117
+ agent-view console --follow --until "/error/i" # exit on regex match (case-insensitive)
118
+ agent-view console --clear # baseline before an interaction
119
+ agent-view console --since "2026-04-26T10:00:00Z"
120
+ ```
121
+
122
+ `--until` requires `--follow`. Exits immediately when a message matches (substring or `/regex/flags`). On timeout without match exits non-zero.
123
+
124
+ Standard pattern for "did this action error?":
125
+ ```bash
126
+ agent-view console --clear
127
+ agent-view click --filter "Save"
128
+ agent-view wait --filter "Saved"
129
+ agent-view console --level error # expect "(no console messages)"
130
+ ```
131
+
132
+ Default attached target types: `page`, `shared_worker`, `service_worker` (override via `consoleTargets` in config).
133
+
134
+ ### Targets (`targets`)
135
+
136
+ When `--window` doesn't show what you expected, or you need a worker target id for `eval`/`console`:
137
+
138
+ ```bash
139
+ agent-view targets # everything connectable
140
+ agent-view targets --type shared_worker,service_worker # filter
141
+ agent-view targets --json # machine-readable
47
142
  ```
48
143
 
49
- ### Canvas / WebGL (only when `webgl` is configured in agent-view.config.json)
144
+ You usually don't need this `eval --target <substring>` and `--window <name>` both do fuzzy matching. Reach for `targets` when the substring is ambiguous.
145
+
146
+ ### Scene / Canvas / WebGL (only when `webgl` is configured in agent-view.config.json)
50
147
 
51
148
  These commands read the scene graph from canvas-based rendering engines. Skip this section if the project has no `webgl` field in config.
52
149
 
@@ -55,9 +152,30 @@ agent-view scene # Scene graph from configured engine
55
152
  agent-view scene --filter "player" # Filter by object name/type
56
153
  agent-view scene --verbose # Extended props (scale, alpha, rotation)
57
154
  agent-view scene --diff # Changes since last call
155
+ agent-view scene --compact # Merge single-child chains onto one line (reduces output)
58
156
  agent-view snap # DOM + Scene combined
157
+ agent-view snap --scale 0.5 # DOM + Scene + Screenshot (path appended as === Screenshot === section)
59
158
  ```
60
159
 
160
+ ## Picking the right tool
161
+
162
+ Verifications cost very different amounts. Pick the cheapest tool that can actually answer the question:
163
+
164
+ | The question is about… | Use | Why |
165
+ |---|---|---|
166
+ | Element existence / text / role | `dom --filter` | Cheapest, structured, no vision tokens |
167
+ | Count of matching elements | `dom --filter X --count` | Single integer, no tree output, no ref mutations |
168
+ | App state, store contents, computed values | `eval "expr"` | DOM doesn't expose JS state; reading the tree to infer it is wasteful and unreliable |
169
+ | State *trajectory* — what changed during/after an action | `watch "expr" --until …` or `--max-changes 1` | `eval` shows the final snapshot only; `watch` shows the diffs in order |
170
+ | Worker logic (SharedWorker / ServiceWorker) | `eval --target <name>` | Workers have no DOM at all |
171
+ | Did the last action throw or warn? | `console --clear` before, `console --level error,warn` after | Catches errors that don't surface in the DOM |
172
+ | Layout/visual of a specific element | `screenshot --crop "<element>"` | ~1.6k tokens (1 tile) — crops to bounding box, massive token win |
173
+ | Layout, spacing, full-window visual regression | `screenshot --scale 0.5` | The only tool that sees pixels — but expensive (~6k tokens), use last |
174
+ | Canvas/WebGL scene contents | `scene --diff` | DOM is empty for canvas apps |
175
+ | What DOM nodes changed after an interaction | `dom --diff` | Returns only `+`/`-` lines; much cheaper than re-reading the full tree |
176
+
177
+ When two tools could answer the same question, prefer the one higher up the table. A common mistake is screenshotting to check "is the count = 5?" when `eval "store.counter"` returns the number directly for ~50 tokens.
178
+
61
179
  ## Verification Workflow
62
180
 
63
181
  ### Ad-hoc Mode (standalone)
@@ -66,10 +184,12 @@ After making code changes:
66
184
 
67
185
  1. **Determine affected areas** from git diff
68
186
  2. **Ensure app is running**: `agent-view launch` or `agent-view discover`
69
- 3. **Inspect DOM**: `agent-view dom --filter "<area>"` — check structure matches expectations
70
- 4. **Take screenshot**: `agent-view screenshot` capture visual state
71
- 5. **Interact if needed**: `agent-view click`/`fill` `agent-view dom` to verify state changed
72
- 6. **For canvas apps**: `agent-view scene --diff` to see what changed
187
+ 3. **Inspect DOM**: `agent-view dom --filter "<area>" --depth 2` — check structure matches expectations
188
+ 4. **Interact if needed**: `agent-view click`/`fill` `agent-view dom --filter` to verify state changed
189
+ 5. **For canvas apps**: `agent-view scene --diff` to see what changed
190
+ 6. **For non-DOM truth** (store, computed values, worker state): `agent-view eval` — much cheaper than reading the DOM tree to infer state
191
+ 7. **After any interaction that could fail silently**: `agent-view console --level error` — catches uncaught exceptions, network failures, framework warnings
192
+ 8. **Screenshot only for final visual confirm**: `agent-view screenshot --scale 0.5` — captures layout/styling that DOM can't reveal
73
193
 
74
194
  ### Scenario Execution Mode (from plan)
75
195
 
@@ -78,7 +198,7 @@ When UI scenarios are pre-generated (e.g., from a plan file with `## UI Scenario
78
198
  1. **Read scenario steps** with symbolic refs (`$var` notation)
79
199
  2. **Resolve each $var**: `agent-view dom --filter "<text>" --depth 3` → map to ref ID
80
200
  3. **Execute steps** sequentially: fill, click, dom --filter (verify expected outcome)
81
- 4. **Screenshot**: capture on FAIL and at E2E scenario end not every step
201
+ 4. **Screenshot**: `agent-view screenshot --scale 0.5` — only on FAIL and at E2E scenario end, not every step
82
202
  5. **Report per-scenario**: PASS / FAIL with reason and evidence
83
203
 
84
204
  This mode works with any workflow that generates plan files with UI scenarios.
@@ -97,4 +217,19 @@ This mode works with any workflow that generates plan files with UI scenarios.
97
217
  - **Multiwindow**: all commands support `--window` flag
98
218
  - **Output format**: plain text (DOM, scene), JSON (discover only), file path (screenshot)
99
219
  - **Lazy server**: auto-starts on first call, shuts down after 5min idle
100
- - **Token optimization**: always use `dom --filter` with specific text, limit `--depth` to 2-3
220
+
221
+ ## Token Optimization
222
+
223
+ Vision tokens dominate cost. One full-res screenshot ≈ 19k tokens (1920×1080, 12 tiles).
224
+
225
+ | Technique | Savings |
226
+ |---|---|
227
+ | `agent-view eval "expr"` for state checks | Returns one value (~50 tokens) instead of a DOM/screenshot |
228
+ | `agent-view dom --filter "row" --count` | Single integer answer — zero tree tokens |
229
+ | `agent-view dom --filter X --depth 2` | Narrow tree to relevant subtree, cap depth |
230
+ | `agent-view screenshot --scale 0.5` | ~3× fewer vision tokens (4 tiles) |
231
+ | `agent-view screenshot --scale 0.25` | ~12× fewer vision tokens (1 tile, ~1.6k tokens) |
232
+ | `agent-view screenshot --crop "<element>"` | ~12× fewer in best case (1 tile) — crops to element bounding box |
233
+ | DOM/eval-first: screenshot only for final visual confirm | Eliminates most screenshot calls |
234
+
235
+ **Default rule**: if the answer is a value → `eval`; if the answer is "is element X visible/correct?" → `agent-view dom --filter`; if you need pixels for a specific section → `screenshot --crop "<element>"` (one tile); only call `screenshot --scale 0.5` for full-window visual proof.
@@ -0,0 +1,185 @@
1
+ ---
2
+ name: verify-recipe
3
+ description: "Generates a concrete, command-by-command agent-view recipe for verifying a feature or bugfix. Use when the developer wants to write a verify-recipe.md, create a verification plan, build an agent-view recipe, or produce a verify checklist for a change they shipped. Triggers on: write a verify-recipe, write verification steps, generate verify steps for the feature/bug I just shipped/fixed, make a verify-recipe.md, what should I run to verify X, create a verification plan, agent-view recipe for this fix, verify checklist for this feature. Does NOT execute the checks — it authors the plan. For running checks against a live app, use the verify skill instead."
4
+ allowed-tools: Read, Write, Bash(agent-view *)
5
+ ---
6
+
7
+ # Verification Recipe Generator
8
+
9
+ You help the developer author a disciplined, cheapest-first verification recipe for a feature they shipped or a bug they fixed. You do not run the checks — you produce a `.claude/verify-recipes/<slug>.md` file that any AI coding agent can execute later.
10
+
11
+ ## What this produces
12
+
13
+ A file at `.claude/verify-recipes/<kebab-slug>.md` containing:
14
+
15
+ - **REPRO STEPS** — exact state the app must be in before checks run
16
+ - **NARROWED SIGNAL** — the measurable indicator that proves success or failure
17
+ - **EVIDENCE COMMANDS** — ordered `agent-view` calls, cheapest first, each annotated with what it proves
18
+ - **POSITIVE-CASE ASSERTIONS** — what "pass" looks like for each command
19
+ - **REGRESSION CHECKS** — adjacent paths that must not have broken
20
+
21
+ Create the directory if missing: `mkdir -p .claude/verify-recipes`
22
+
23
+ ## Methodology
24
+
25
+ Frame the recipe with **hard-debug** discipline. That skill defines the chain: REPRO → narrowed signal → minimize scope → root-cause check → fix verification. Apply the same logic here in authoring mode:
26
+
27
+ 1. Start from a reproducible starting state, not "open the app and poke around"
28
+ 2. Convert vague expectations ("looks right") into measurable signals ("store.user.role === 'admin'")
29
+ 3. Prefer the cheapest tool that can answer the question — a value check costs ~50 tokens, a screenshot costs ~6 000
30
+ 4. Include at least one negative-case check (the old symptom must no longer appear)
31
+ 5. Include at least one regression check (an adjacent flow must still work)
32
+
33
+ ## Tool-cost decision tree
34
+
35
+ Pick the first row that can answer the question. Only go lower when the row above can't:
36
+
37
+ | Question | Command | Why it's cheapest |
38
+ |---|---|---|
39
+ | Element exists / has specific text / role | `agent-view dom --filter "<text>" --depth 2` | Structured text, zero vision tokens |
40
+ | App state, store value, computed flag | `agent-view eval "<expr>"` | Returns the value directly; DOM inference is wasteful and fragile |
41
+ | What changed between action and final state | `agent-view watch "<expr>" --until "<condition>"` or `--max-changes 1` | `eval` shows the snapshot; `watch` shows the trajectory |
42
+ | SharedWorker / ServiceWorker internal state | `agent-view eval --target <name> "<expr>"` | Workers have no DOM; this is the only path |
43
+ | Did this action throw or warn silently? | `agent-view console --clear` before, `agent-view console --level error,warn` after | Catches uncaught exceptions and network failures invisible to DOM |
44
+ | Layout, spacing, visual regression | `agent-view screenshot --scale 0.5` | Last resort — the only tool that sees pixels, but costs ~6 000 tokens |
45
+ | Canvas / WebGL scene state | `agent-view scene --diff` | DOM is empty for canvas apps |
46
+
47
+ **Anti-patterns to reject:**
48
+ - Opening with a screenshot to "see the state" — use `dom --filter` or `eval` first
49
+ - Using `eval` when `dom --filter` answers the question
50
+ - Assertions that depend on transient state without `watch --until` to stabilize first
51
+ - "Check that it looks right" — every assertion must be a concrete pass/fail criterion
52
+
53
+ ## Workflow
54
+
55
+ ### Step 1 — gather context
56
+
57
+ When invoked, ask the developer in plain text (no tool calls yet):
58
+
59
+ 1. What was shipped or fixed? (feature name or bug description)
60
+ 2. What was the original symptom or expected behavior?
61
+ 3. Any known failure mode or edge case to cover?
62
+
63
+ Wait for the response before continuing.
64
+
65
+ ### Step 2 — draft the recipe
66
+
67
+ Use the answers to produce a recipe with these sections:
68
+
69
+ ```markdown
70
+ # Verify: <feature or fix name>
71
+
72
+ Generated: <date>
73
+ Scope: <one sentence describing what this covers>
74
+
75
+ ## Repro Steps
76
+ 1. <Exact starting state — window open, user logged in, specific route, etc.>
77
+ 2. <Action(s) that trigger the behavior under test>
78
+
79
+ ## Narrowed Signal
80
+ <!-- The one measurable thing that proves it works -->
81
+ `<agent-view command>` must return `<expected value>`.
82
+
83
+ ## Evidence Commands
84
+
85
+ ### 1. <What this proves>
86
+ ```bash
87
+ agent-view <command>
88
+ ```
89
+ Expected: <concrete criterion — value, text, absence of error>
90
+ Cost: ~<N> tokens
91
+
92
+ ### 2. ...
93
+
94
+ ## Positive-Case Assertions
95
+ - [ ] <criterion>
96
+ - [ ] <criterion>
97
+
98
+ ## Regression Checks
99
+ - [ ] <adjacent flow> — `agent-view <command>` → `<expected>`
100
+
101
+ ## Anti-patterns avoided
102
+ - <note any recipe-specific traps, e.g. "state resets on reload — watch needed before dom check">
103
+ ```
104
+
105
+ ### Step 3 — save the file
106
+
107
+ Determine a kebab-slug from the feature/fix name (e.g. `login-redirect-fix`, `cart-total-display`).
108
+
109
+ Save to `.claude/verify-recipes/<slug>.md`. Create the directory first if it doesn't exist.
110
+
111
+ Confirm the path to the developer.
112
+
113
+ ## Worked example: "fixed login redirect bug"
114
+
115
+ **Developer input:**
116
+ > Fixed a bug where after login, the redirect went to `/home` instead of `/dashboard`. Store mutation `SET_REDIRECT_PATH` was missing. No visual change — purely a routing issue.
117
+
118
+ **Recipe produced:**
119
+
120
+ ```markdown
121
+ # Verify: Login Redirect Fix
122
+
123
+ Generated: 2026-04-27
124
+ Scope: Confirms that a successful login routes to /dashboard, not /home, and that the store mutation fires correctly.
125
+
126
+ ## Repro Steps
127
+ 1. App running, user logged out, at `/login`
128
+ 2. Fill email + password, click "Sign in"
129
+
130
+ ## Narrowed Signal
131
+ `agent-view eval "router.currentRoute.path"` must return `"/dashboard"`.
132
+
133
+ ## Evidence Commands
134
+
135
+ ### 0. Setup — baseline console (before any action)
136
+ ```bash
137
+ agent-view console --clear
138
+ ```
139
+
140
+ ### 1. Confirm redirect target
141
+ ```bash
142
+ agent-view fill <email-ref> "admin@example.com"
143
+ agent-view fill <password-ref> "password"
144
+ agent-view click <signin-ref>
145
+ agent-view watch "router.currentRoute.path" --until "router.currentRoute.path === '/dashboard'"
146
+ ```
147
+ Expected: `replace / "/login" → "/dashboard"` in watch output
148
+ Cost: ~100 tokens
149
+
150
+ ### 2. Confirm mutation fired
151
+ ```bash
152
+ agent-view eval "store.state.auth.redirectPath"
153
+ ```
154
+ Expected: `"/dashboard"` (not `"/home"`, not `null`)
155
+ Cost: ~50 tokens
156
+
157
+ ### 3. No errors during login flow
158
+ ```bash
159
+ agent-view console --level error,warn
160
+ ```
161
+ Expected: `(no console messages)`
162
+ Cost: ~30 tokens
163
+
164
+ ### 4. Regression — logout returns to /login
165
+ ```bash
166
+ agent-view click <logout-ref>
167
+ agent-view eval "router.currentRoute.path"
168
+ ```
169
+ Expected: `"/login"`
170
+ Cost: ~60 tokens
171
+
172
+ ## Positive-Case Assertions
173
+ - [ ] `router.currentRoute.path` === `/dashboard` after login
174
+ - [ ] `store.state.auth.redirectPath` === `/dashboard`
175
+ - [ ] No console errors during the flow
176
+
177
+ ## Regression Checks
178
+ - [ ] Logout → `/login` still works
179
+
180
+ ## Anti-patterns avoided
181
+ - Not using screenshot to confirm route (route is a string — eval is 120× cheaper)
182
+ - watch used before eval so route change is confirmed to have settled, not just sampled mid-transition
183
+ ```
184
+
185
+ **Saved to:** `.claude/verify-recipes/login-redirect-fix.md`