@verirun/cli 0.2.3 → 0.2.5
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 +118 -10
- package/dist/cli.js +28 -26
- package/dist/gate.mjs +1 -1
- package/dist/graph.mjs +39 -39
- package/man/verirun.1 +50 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -147,6 +147,20 @@ what you recorded is what runs.
|
|
|
147
147
|
into a field and close the browser without clicking or tabbing away, that last
|
|
148
148
|
value is not recorded. Tab out before closing.
|
|
149
149
|
|
|
150
|
+
**Dialogs.** Answer `alert` / `confirm` / `prompt` boxes in the recording
|
|
151
|
+
browser as you normally would. Codegen notes *that* a step opened one but not
|
|
152
|
+
which button you pressed, so after you close the browser `record` asks, per such
|
|
153
|
+
step, `[O]K / [c]ancel` (Enter = OK; without a terminal every answer is OK). The
|
|
154
|
+
answer is saved on the step and `run` replays it:
|
|
155
|
+
|
|
156
|
+
```json
|
|
157
|
+
{ "index": 4, "action": "click", "selector": "…", "dialog": { "action": "dismiss" } }
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
`action` is `accept` (OK) or `dismiss` (Cancel). For a `prompt()`, add
|
|
161
|
+
`"promptText": "…"` — without it, accepting submits the prompt's default value.
|
|
162
|
+
Every dialog the step opens gets the same answer.
|
|
163
|
+
|
|
150
164
|
**Nothing recorded.** If you close the browser without doing anything, nothing
|
|
151
165
|
is saved and the command says so.
|
|
152
166
|
|
|
@@ -217,6 +231,7 @@ and writes `.verirun/runs/<name>-<timestamp>/logs.json`.
|
|
|
217
231
|
| `--user-data-dir <dir>` | Replay in a persistent profile directory, so it runs already logged in. The profile must not be open in another browser. |
|
|
218
232
|
| `--cdp <url>` | Attach to a browser already running with remote debugging and drive it. See below. |
|
|
219
233
|
| `--user <id>` | Keep only log entries whose message or raw payload contains this string, case-insensitive — e.g. a user's email. Overrides `config.userFilter`. Recorded in `logs.json` as `"filter": { "user": … }`; `entries` and the per-source counts are post-filter. If everything is filtered out, `run` warns. |
|
|
234
|
+
| `--dialog <answer>` | How to answer a browser dialog opened by a step with no saved `dialog` answer: `accept` (OK, the default) or `dismiss` (Cancel). A step's own `dialog` always wins. |
|
|
220
235
|
|
|
221
236
|
**Where the user filter runs.** For **Supabase** it goes into the log query's
|
|
222
237
|
`WHERE` (matched against the rendered message and the JSON of `metadata`), so
|
|
@@ -263,6 +278,11 @@ frontmost.
|
|
|
263
278
|
whatever logs already landed are still written, and the exit code is non-zero.
|
|
264
279
|
- Popups and newly opened tabs become the active target as they open. A workflow
|
|
265
280
|
that drives several tabs at once is not supported yet.
|
|
281
|
+
- Browser dialogs (`alert`, `confirm`, `prompt`, `beforeunload`) are answered
|
|
282
|
+
automatically: with the step's saved `dialog` if it has one, otherwise with
|
|
283
|
+
`--dialog` (default `accept`). Each one is printed under its step and listed
|
|
284
|
+
in `logs.json` `dialogs`. With `--cdp`, only tabs the run itself drives or
|
|
285
|
+
opens are touched.
|
|
266
286
|
|
|
267
287
|
### Sequencing
|
|
268
288
|
|
|
@@ -282,6 +302,9 @@ warned about and contributes no entries.
|
|
|
282
302
|
"window": { "startedAt": "2026-08-31T13:01:50.998Z", "endedAt": "2026-08-31T13:01:51.499Z" },
|
|
283
303
|
"steps": { "total": 12, "replayed": 12 },
|
|
284
304
|
"filter": { "user": "ada@example.com" },
|
|
305
|
+
"dialogs": [
|
|
306
|
+
{ "step": 7, "type": "confirm", "message": "Delete this item?", "action": "accept", "at": "2026-08-31T13:01:51.102Z" }
|
|
307
|
+
],
|
|
285
308
|
"sources": [{ "id": "vercel", "name": "Vercel", "entries": 8 }],
|
|
286
309
|
"entries": [
|
|
287
310
|
{
|
|
@@ -300,6 +323,10 @@ warned about and contributes no entries.
|
|
|
300
323
|
(the step index) and the file carries a top-level `error` string.
|
|
301
324
|
- `filter` is present only when `--user` / `config.userFilter` was in effect;
|
|
302
325
|
`entries` and every `sources[].entries` count are then post-filter.
|
|
326
|
+
- `dialogs` lists every browser dialog the replay answered, in order: the
|
|
327
|
+
`step` running when it opened, its `type` and `message`, the prompt's
|
|
328
|
+
`defaultValue` (prompts only), the `action` taken, and the `promptText`
|
|
329
|
+
submitted to an accepted prompt. Empty when none opened.
|
|
303
330
|
- `entries` merges every source, sorted by `timestamp`. `stream` is the
|
|
304
331
|
sub-stream within a source (`lambda`, `edge`, `postgres_logs`, …). `raw` is
|
|
305
332
|
the provider's untouched payload (for Supabase that now includes the row's
|
|
@@ -422,11 +449,25 @@ element that gets you there:
|
|
|
422
449
|
$ verirun map --bfs /account --depth 2
|
|
423
450
|
page:/account
|
|
424
451
|
└─ nav "verirun" → page:/
|
|
425
|
-
└─ effect "revoke" [if
|
|
452
|
+
└─ effect "revoke" [if window.confirm("Revoke this terminal's access? …")] → effect:POST ?
|
|
453
|
+
opens confirm "Revoke this terminal's access? …" — the answer decides what the click does
|
|
426
454
|
└─ nav "Log in" → page:/login
|
|
427
455
|
# frontier at depth 2: page:/login, page:/signup
|
|
428
456
|
```
|
|
429
457
|
|
|
458
|
+
**Browser dialogs.** An element whose handler calls the native `alert()`,
|
|
459
|
+
`confirm()` or `prompt()` (bare, or on `window` / `globalThis`; a locally
|
|
460
|
+
imported `confirm` is a custom modal, not a dialog) carries
|
|
461
|
+
`dialogs: [{ type, message, messageStatic, gates, … }]` in `--json`. `gates` is
|
|
462
|
+
true when the handler reads the answer, so OK and Cancel lead to different
|
|
463
|
+
outcomes. An early `if (!window.confirm(…)) return;` also shows up as the
|
|
464
|
+
`guardSource` of every backend call after it, which is how you see that Cancel
|
|
465
|
+
skips the `POST`. The per-page summary counts the elements that open a dialog,
|
|
466
|
+
`--bfs` prints each one under its edge, and `coverage.md` lists them all. A
|
|
467
|
+
workflow step that clicks one answers it with its `dialog` field (see
|
|
468
|
+
[`verirun run`](#verirun-run-name)); `workflow check` warns when that field is
|
|
469
|
+
missing (see below).
|
|
470
|
+
|
|
430
471
|
**Limits, honestly.** It is static analysis: a target computed at runtime shows
|
|
431
472
|
as `unresolved`, an endpoint passed through a variable as `?`, and Supabase
|
|
432
473
|
`.auth.*` / `.storage.*` calls are not yet classified as effects. `--reach`
|
|
@@ -451,6 +492,15 @@ verirun workflow check login --json # machine-readable findings
|
|
|
451
492
|
verirun workflow check ./some/file.json
|
|
452
493
|
```
|
|
453
494
|
|
|
495
|
+
If `verirun map --report` has saved `.verirun/map/interaction-tree.json`,
|
|
496
|
+
`check` also warns about a step that clicks an element the graph says opens a
|
|
497
|
+
browser dialog but has no `dialog` answer. Replay would press OK, which is
|
|
498
|
+
usually what you want, but when the handler reads the answer, Cancel is a
|
|
499
|
+
different path and should be chosen on purpose. Matching is by exact selector, so it catches
|
|
500
|
+
workflows written from `map --json`. A selector that elements *without* a dialog
|
|
501
|
+
also match (a bare `role=button`) is skipped rather than guessed at. Re-run
|
|
502
|
+
`map --report` when the app changes; the saved graph goes stale.
|
|
503
|
+
|
|
454
504
|
Static only: it never opens a browser, so it cannot tell you whether a selector
|
|
455
505
|
matches the live page. Only `verirun run` can. Non-zero exit if anything is an
|
|
456
506
|
error.
|
|
@@ -477,7 +527,9 @@ an agent — to write `.verirun/workflows/<name>.json` directly:
|
|
|
477
527
|
Actions and required `params`: `navigate` (`url`, absolute), `click` /
|
|
478
528
|
`dblclick`, `fill` (`text`), `press` (`key`), `check` / `uncheck`, `select`
|
|
479
529
|
(`values`), `setInputFiles` (`files`). Everything but `navigate` needs a
|
|
480
|
-
`selector`, which is handed to `page.locator()` verbatim.
|
|
530
|
+
`selector`, which is handed to `page.locator()` verbatim. A step that opens a
|
|
531
|
+
browser dialog can carry `"dialog": { "action": "accept" | "dismiss",
|
|
532
|
+
"promptText"?: "…" }`; without it `run` accepts.
|
|
481
533
|
|
|
482
534
|
A recorded workflow is ground truth; a written one is a guess until `run`
|
|
483
535
|
confirms it. Don't overwrite a recording with a generated file — use a new name.
|
|
@@ -495,17 +547,25 @@ workflows, recent runs.
|
|
|
495
547
|
```bash
|
|
496
548
|
verirun agent > .verirun/AGENT.md # save it as context for your agent
|
|
497
549
|
verirun agent --json # machine-readable form
|
|
498
|
-
verirun agent --skill --install
|
|
550
|
+
verirun agent --skill --install # .claude/skills/verirun/SKILL.md
|
|
551
|
+
verirun agent --skill --install cursor # .cursor/rules/verirun.mdc
|
|
552
|
+
verirun agent --skill --install all # both
|
|
499
553
|
```
|
|
500
554
|
|
|
501
|
-
`--skill` emits the same knowledge as
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
555
|
+
`--skill` emits the same knowledge as an agent skill — frontmatter with a
|
|
556
|
+
`description` that tells the agent when to load it, then a shorter body aimed at
|
|
557
|
+
deciding *which* command to reach for. `--install` writes it where the agent
|
|
558
|
+
looks:
|
|
559
|
+
|
|
560
|
+
| Target | File | Loaded |
|
|
561
|
+
|---|---|---|
|
|
562
|
+
| `claude` (default) | `.claude/skills/verirun/SKILL.md` | automatically, when a task looks like app testing |
|
|
563
|
+
| `cursor` | `.cursor/rules/verirun.mdc` | when the task matches its description (an agent-requested rule, not always-on) |
|
|
564
|
+
| `all` | both | |
|
|
507
565
|
|
|
508
|
-
|
|
566
|
+
Re-run it after upgrading verirun; the file is generated, not hand-maintained.
|
|
567
|
+
|
|
568
|
+
For any other agent, paste the output into `CLAUDE.md`, an `AGENTS.md`, or pipe it
|
|
509
569
|
straight into a prompt. No account needed. The agent then knows to run
|
|
510
570
|
`verirun run <name>`, read exit code + `.verirun/runs/<name>-<newest>/logs.json`,
|
|
511
571
|
and act on `status` / `error` / `entries` without you explaining the tool.
|
|
@@ -655,6 +715,54 @@ run this often.
|
|
|
655
715
|
|
|
656
716
|
## Changelog
|
|
657
717
|
|
|
718
|
+
### 0.2.5
|
|
719
|
+
|
|
720
|
+
- **`verirun run` answers browser dialogs instead of cancelling them.** With no
|
|
721
|
+
handler, Playwright dismissed every `alert` / `confirm` / `prompt`, so each
|
|
722
|
+
`confirm()` in a workflow came back as Cancel and the action it guarded
|
|
723
|
+
quietly never happened. Replay now answers each one: with the step's saved
|
|
724
|
+
`dialog` (`accept` / `dismiss`, plus `promptText` for a prompt), otherwise
|
|
725
|
+
with the new `--dialog accept|dismiss` (default `accept`). Each dialog is
|
|
726
|
+
printed under its step and listed in `logs.json` under `dialogs`. With
|
|
727
|
+
`--cdp`, only the tabs the run drives are touched.
|
|
728
|
+
- **`verirun record` asks which button you pressed.** Playwright's recorder notes
|
|
729
|
+
that a step opened a dialog but not the answer, so after you close the
|
|
730
|
+
browser `record` asks `[O]K / [c]ancel` for each such step and saves it on the
|
|
731
|
+
step.
|
|
732
|
+
- **`verirun map` shows the dialogs an element opens.** `--json` carries a
|
|
733
|
+
`dialogs` list per element (`type`, `message`, and `gates` when the handler
|
|
734
|
+
reads the answer). An early `if (!window.confirm(…)) return;` now shows up as
|
|
735
|
+
the `guardSource` of the backend calls after it, so you can see that Cancel
|
|
736
|
+
skips them. The summary counts them, `--bfs` prints them under their edge,
|
|
737
|
+
and `coverage.md` lists them.
|
|
738
|
+
- **`verirun workflow check` validates the `dialog` field.** After `map
|
|
739
|
+
--report`, it also warns about a step that clicks a dialog-opening element
|
|
740
|
+
without saying OK or Cancel.
|
|
741
|
+
|
|
742
|
+
### 0.2.4
|
|
743
|
+
|
|
744
|
+
- **`verirun map` reads the import aliases your project actually declares.**
|
|
745
|
+
Only `"@/*": ["./src/*"]` was understood before; a `paths` entry resolved
|
|
746
|
+
against `baseUrl` (`"@/*": ["*"]`) or inherited through `extends` — the two
|
|
747
|
+
shapes `create-next-app` and most monorepos emit — silently produced no
|
|
748
|
+
aliases at all. Every `@/…` import then resolved to nothing, so the child
|
|
749
|
+
components a page renders were never analysed and each page was reported as
|
|
750
|
+
empty: pages listed, zero elements, zero effects, zero edges, no warning.
|
|
751
|
+
- **An unresolvable import alias now says so, and says what to do.** `map`
|
|
752
|
+
prints the exact `--alias` flag to re-run with, instead of quietly reporting
|
|
753
|
+
an app it could not read as an app with nothing in it. A scoped npm package
|
|
754
|
+
is not mistaken for a broken alias.
|
|
755
|
+
- **`verirun agent --skill --install` now installs for Cursor too.** `--install
|
|
756
|
+
cursor` writes `.cursor/rules/verirun.mdc` as an agent-requested rule, `--install
|
|
757
|
+
all` writes that and the Claude Code skill; a bare `--install` still means Claude
|
|
758
|
+
Code.
|
|
759
|
+
- **`verirun record --url` checks the URL is up before opening a browser.** A
|
|
760
|
+
dev server that is not running produced a raw Node stack trace from
|
|
761
|
+
Playwright's child process, followed by a message blaming the `jsonl` codegen
|
|
762
|
+
target — pointing at the wrong thing entirely. It now stops with
|
|
763
|
+
`Nothing is listening at http://localhost:3000`. The message for a codegen
|
|
764
|
+
exit that genuinely recorded nothing no longer leads with the `jsonl` theory.
|
|
765
|
+
|
|
658
766
|
### 0.2.3
|
|
659
767
|
|
|
660
768
|
- **`verirun whoami` shows this machine's fingerprint**, in the same 24-character
|