patchright-cli 0.10.0__py3-none-any.whl → 0.11.1__py3-none-any.whl

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.
@@ -1,3 +1,3 @@
1
1
  """patchright-cli — Undetected browser automation CLI using Patchright."""
2
2
 
3
- __version__ = "0.10.0"
3
+ __version__ = "0.11.1"
@@ -28,7 +28,7 @@ patchright-cli screenshot # capture the page
28
28
  patchright-cli close # done
29
29
  ```
30
30
 
31
- Every interaction follows: **open -> snapshot -> read refs -> interact -> snapshot again -> repeat**. Refs are ephemeral -- they change on every page update. If a ref fails, re-snapshot.
31
+ Every interaction follows: **open -> snapshot -> read refs -> interact -> snapshot again -> repeat**. A ref (`e5`, or `f3e5` inside an iframe and after a navigation) names one element until it leaves the page; a ref whose element is gone fails fast with `no longer matches an element` -- re-snapshot then. Refs are per tab: after `tab-select`, use the snapshot it prints. A click that opens a popup makes the popup current, and the popup's first-document refs (`e1`, `e2`, ...) can reuse numbers from the opener, so use the snapshot printed after the click.
32
32
 
33
33
  ## Command chaining
34
34
 
@@ -149,9 +149,9 @@ snapshot <ref> # Subtree of a specific element
149
149
  snapshot --selector="#main" # Subtree of a CSS selector -- must match exactly
150
150
  # one element. No ref needed, so
151
151
  # this works before the first snapshot
152
- snapshot --depth=N # Limit depth
153
- snapshot -i # Interactive elements only
154
- snapshot --boxes # Append [box=x,y,w,h] to each [ref=eN] line
152
+ snapshot --depth=N # Levels 0..N; a cut node ends in `# +N refs`
153
+ snapshot -i # Interactive elements (and named landmarks around them)
154
+ snapshot --boxes # Append [box=x,y,w,h] (page coordinates, iframes too)
155
155
  ```
156
156
 
157
157
  ### Searching instead of snapshotting
@@ -165,8 +165,14 @@ patchright-cli find --regex "sign (in|up)" # regex, case-insensitive
165
165
  patchright-cli find --regex "/Sign In/" # slash form carries flags (i, m, s)
166
166
  patchright-cli find "price" --all # include text/paragraph nodes
167
167
  patchright-cli find "hide" --limit=50 # default limit is 20
168
+ patchright-cli find --role=button --description="Deletes" # role + accessible description
168
169
  ```
169
170
 
171
+ The snapshot never shows accessible descriptions (`aria-describedby`,
172
+ `aria-description`, a `title` that is not the name). To target an element by
173
+ one, use `find --role=<role>` with `--name` and/or `--description`: substring
174
+ and case-insensitive, `/regex/i`, or whole with `--exact`. It returns refs.
175
+
170
176
  `find` searches links, buttons, inputs and headings by default — the things
171
177
  you can act on. Use `--all` when you are looking for page *content* rather
172
178
  than a control.
@@ -176,13 +182,13 @@ controls stay distinguishable:
176
182
 
177
183
  ```
178
184
  # table > rowgroup > cell "407 points by pluc 4 hours ago | hide | 321 ..."
179
- - link "hide": [ref=e49]
185
+ - link "hide" [ref=e49]:
180
186
  - /url: hide?id=49489982
181
187
  ```
182
188
 
183
- Refs from `find` are numbered across the whole page and are immediately
184
- usable with `click`, `fill`, and the rest. They stay valid until the next
185
- `snapshot` or `find`.
189
+ Refs from `find` are the same refs `snapshot` prints and are immediately
190
+ usable with `click`, `fill`, and the rest. A hit with no ref of its own (a
191
+ `text:` line or an `option`) names the element to act on as `[in=e12]`.
186
192
 
187
193
  When output says `Found 20 of 340 matches`, narrow the query rather than
188
194
  raising `--limit`.
@@ -200,6 +206,8 @@ drop <ref> --path=./file.png # Drop file onto element (HTML5 drop from outside)
200
206
  drop <ref> --data="text/plain=hello" # Drop arbitrary MIME data
201
207
  ```
202
208
 
209
+ `drop` fails (exit 1) when the target does not accept drops, meaning its `dragover` handler does not call `preventDefault()`. Before, it reported success without anything being dropped. Drop onto the element that handles the drop, not onto a wrapper around it.
210
+
203
211
  ### Form input
204
212
 
205
213
  ```bash
@@ -300,7 +308,7 @@ dialog-dismiss # Dismiss next dialog
300
308
  ### DevTools
301
309
 
302
310
  ```bash
303
- console # Show console messages
311
+ console # Start capture / show captured console messages
304
312
  console warning # Filter by level
305
313
  network # Show network requests (each line is `#<id> METHOD STATUS URL`)
306
314
  requests # Alias for `network`
@@ -312,6 +320,38 @@ highlight <ref> # Persistent overlay on element [--style=CSS]
312
320
  highlight <ref> --hide # Remove overlay; `highlight --hide` clears all
313
321
  ```
314
322
 
323
+ The first `console` call starts CDP Runtime capture across this session's existing
324
+ and future pages, including popups. Earlier messages are unavailable: call it
325
+ before reproducing an issue, then again to read messages. Capture makes CDP
326
+ detectable until the session closes; `console --clear` only clears the buffer.
327
+
328
+ A highlight is page-visible while shown (an `<x-pw-glass>` element under `<html>`);
329
+ `--hide` removes the element once no highlight is left. `pick-locator` refuses to
330
+ run without `--detectable`: Playwright's recorder then stays in every page of the
331
+ session (`window.playwright`, `__pw_*` globals, an `<x-pw-glass>` element it
332
+ re-adds) until the session closes, so use a throwaway session for it.
333
+
334
+ ### Debugger (step through a command's browser calls)
335
+
336
+ ```bash
337
+ debugger-pause # Arm: the next page action, navigation or eval pauses
338
+ click e3 # Replies at once: "Paused before: Evaluate (held: `click e3`)"
339
+ snapshot # Other commands still run while paused, actions included
340
+ debugger-step # Run that call, pause before the next ("Click ...")
341
+ debugger-resume # Let the held command finish, turn the debugger off
342
+ debugger-status # off | armed | paused + call title and held command
343
+ ```
344
+
345
+ This is Playwright's action debugger, not a JavaScript debugger: it holds
346
+ patchright-cli's own calls in the driver, sends nothing to Chrome, and page
347
+ scripts keep running, so pages cannot detect it. Only page actions, navigation,
348
+ `eval` and element getters pause; `snapshot`, `title`, cookies, `state-save`,
349
+ `tab-new` and `highlight` run straight through (the reply says so) and leave it
350
+ armed. While one call is held, other commands, actions included, run at once,
351
+ so their side effects can land before the held one's. After `debugger-step` the
352
+ debugger stays armed until `debugger-resume`, which also cancels an armed pause
353
+ nothing has hit. `close` while paused resumes and closes.
354
+
315
355
  ### Recording and capture
316
356
 
317
357
  ```bash
@@ -352,6 +392,15 @@ clear-media
352
392
  `--content-type`, `--header`); `route-list` and `unroute` manage them, and
353
393
  `network-state-set offline|online` simulates connectivity.
354
394
 
395
+ ### Passkeys (WebAuthn)
396
+
397
+ Run a `passkey-*` command, such as `passkey-list`, BEFORE the page calls
398
+ `navigator.credentials.create()` or `.get()`. The first one installs a virtual
399
+ authenticator in the session; until then the page gets Chrome's native OS
400
+ passkey dialog and the ceremony hangs. Then `passkey-list` shows what the page
401
+ registered, `passkey-add <rp-id>` seeds one, and `passkey-export` /
402
+ `passkey-import` keep passkeys across sessions (the export holds private keys).
403
+
355
404
  ## Command reference
356
405
 
357
406
  Every command, its flags and what it does. `patchright-cli <command> --help`
@@ -361,24 +410,25 @@ arguments shows whether the daemon is up and which sessions are open.
361
410
  <!-- BEGIN GENERATED: commands (scripts/gen_skill.py from COMMAND_SPECS; do not edit by hand) -->
362
411
  ```bash
363
412
  # Core
364
- open [url] [--block-networks] [--headed] # Open browser (starts daemon if needed)
413
+ open [url] [--block-networks] [--headed] [--webmcp] # Open browser (starts daemon if needed)
365
414
  attach --cdp=<url> [--cdp-headers] [--cdp-timeout] [--block-networks] # Attach to running Chrome via CDP
366
415
  goto <url> # Navigate to URL
367
- click <ref> [button] [--modifiers] # Click element
416
+ click <ref> [button] [--modifiers] [--scroll] # Click element
368
417
  dblclick <ref> [button] [--modifiers] # Double-click element
369
418
  fill <ref> <value> [--submit] # Fill text into element
370
419
  type <text> [--submit] # Type text via keyboard
371
- hover <ref> # Hover over element
420
+ hover <ref> [--scroll] # Hover over element
372
421
  select <ref> <value> # Select dropdown option
373
- check <ref> # Check checkbox/radio
422
+ check <ref> [--scroll] # Check checkbox/radio
374
423
  uncheck <ref> # Uncheck checkbox/radio
375
424
  snapshot [ref] [--selector] [--filename] [--depth] [--interactive] [--boxes] # Take accessibility snapshot
376
- find <text> [--regex] [--all] [--limit] # Search the snapshot for matching elements
425
+ find <text> [--regex] [--all] [--limit] [--role] [--name] [--description] [--exact] # Search the snapshot for matching elements
377
426
  eval <expr> [ref] [--file] # Evaluate JavaScript (expression, --file or stdin)
378
427
  text <ref|selector> # Get text content of element
428
+ html [ref] [--selector] [--include-shadow] [--filename] [--max-chars] # Print page HTML, or one element's outerHTML
379
429
  screenshot [ref] [--full-page] [--hires] [--filename] # Save screenshot
380
- drag <from> <to> # Drag element to target
381
- drop <ref> [--path] [--data] # Drop file/data onto element
430
+ drag <from> <to> [--scroll] # Drag element to target
431
+ drop <ref> [--path] [--data] # Drop file/data onto element (fails if it does not accept drops)
382
432
  close # Close browser session (or the --tab it is addressed to)
383
433
  detach # Detach attached session (keep external browser running)
384
434
 
@@ -455,6 +505,14 @@ sessionstorage-set <key> <value> # Set sessionStorage item
455
505
  sessionstorage-delete <key> # Delete sessionStorage item
456
506
  sessionstorage-clear # Clear sessionStorage
457
507
 
508
+ # Passkeys
509
+ passkey-list [--rp-id] [--id] # List virtual passkeys; run before the page uses WebAuthn
510
+ passkey-add <rp-id> [--id] [--user-handle] [--private-key] [--public-key] [--sign-count] # Seed a virtual passkey
511
+ passkey-delete <id> # Delete a virtual passkey by credential id
512
+ passkey-clear [--rp-id] # Delete all virtual passkeys
513
+ passkey-export [file] [--rp-id] # Export virtual passkeys with private keys to an owner-only JSON
514
+ passkey-import <file> # Seed virtual passkeys from a passkey-export file
515
+
458
516
  # Permissions
459
517
  grant-permissions <perms> [--origin] # Grant comma-separated permissions
460
518
 
@@ -472,7 +530,7 @@ tracing-start # Start Playwright tracing
472
530
  tracing-stop # Stop tracing and save
473
531
 
474
532
  # Video
475
- video-start # Start video recording
533
+ video-start [--fps] # Start video recording
476
534
  video-stop [--filename] # Stop recording and save
477
535
  video-chapter <title> # Add chapter marker to video
478
536
  video-show-actions [--duration] [--position] # Annotate actions in the recording
@@ -482,12 +540,23 @@ video-hide-actions # Stop annotating actions
482
540
  pdf [--filename] # Save page as PDF
483
541
 
484
542
  # DevTools
485
- console [level] [--clear] # Show console messages
543
+ console [level] [--clear] # Start session-wide CDP capture and show messages; earlier messages are unavailable (detectable)
486
544
  network [--static] [--clear] # Show network requests
487
545
  requests [--static] [--clear] # Alias for `network`
488
546
  request <id> [--body] # Show full detail for a network request
489
547
  generate-locator <ref> # Emit Playwright locator expression for a ref
490
- highlight <ref> [--style] [--hide] # Show overlay on element
548
+ pick-locator [--detectable] [--wait] [--cancel] # Wait for a person to click an element; print its locator (page-detectable: needs --detectable)
549
+ highlight <ref> [--style] [--hide] # Show overlay on element (page-detectable while shown; removed on --hide)
550
+
551
+ # Debugger
552
+ debugger-pause # Pause before the next page action, navigation or eval; that command replies at once, held
553
+ debugger-step # Run the paused call and pause before the next one; prints the held command's result
554
+ debugger-resume # Let the held command finish and print its result (or cancel an unhit pause)
555
+ debugger-status # Show the debugger state: off, armed, or the paused call and held command
556
+
557
+ # WebMCP
558
+ webmcp-list # List the WebMCP tools the page registers
559
+ webmcp-call <name> [json] [--params] # Call a WebMCP tool the page registers
491
560
 
492
561
  # Session
493
562
  list # List sessions
@@ -2,97 +2,108 @@
2
2
 
3
3
  ## How the snapshot system works
4
4
 
5
- patchright-cli uses Playwright's accessibility tree to build a YAML snapshot of all interactive elements on the page. Each element gets a short ref like `e1`, `e5`, `e12`. You use these refs to target elements in commands like `click`, `fill`, `hover`, etc.
5
+ patchright-cli takes Playwright's AI-mode accessibility snapshot of the whole
6
+ page, iframes included, and saves it as YAML. Elements carry Playwright's own
7
+ refs, like `e5` or `f3e5`. You use these refs to target elements in commands
8
+ like `click`, `fill`, `hover`, etc.
6
9
 
7
10
  ```
8
11
  open browser -> snapshot -> read refs -> interact -> snapshot again -> repeat
9
12
  ```
10
13
 
11
- Refs are **ephemeral** -- they change every time the page updates. After navigation, form submission, or any dynamic content change, you must re-snapshot to get fresh refs.
14
+ ## What a ref is
15
+
16
+ - A ref names **one element** for as long as that element stays on the page.
17
+ Taking another snapshot, or acting, does not renumber it; new elements get
18
+ new numbers.
19
+ - `e5` is an element of the tab's first page. After a navigation (`goto`, a
20
+ link, `reload`) the page's refs gain a frame prefix, `f3e5`, and refs inside
21
+ an iframe always have one. Copy refs exactly as printed.
22
+ - A ref whose element was removed or replaced fails at once:
23
+ `Ref e7 no longer matches an element (removed or changed since the snapshot). Run snapshot.`
24
+ A ref from a page the tab has left fails with `is from a page this tab has left`.
25
+ Nothing falls back to "an element with the same role and name", so a stale
26
+ ref never clicks the wrong element.
27
+ - Refs are **per tab**. A ref that is not in this tab's last snapshot is refused:
28
+ `e2 is not from a snapshot of this tab; run snapshot (...)`. An element whose role
29
+ or name changes (a button relabelled "Saved") gets a new ref, so the old one is refused too.
30
+ After `tab-select`, use the snapshot it prints. A click that opens a popup makes
31
+ the popup current, and the popup's first-document refs (`e1`, `e2`, ...) can reuse
32
+ numbers from the opener, so use the snapshot printed after the click.
33
+ - `e5`, `@e5`, `ref=e5` and `[ref=e5]` all work. Anything else is a usage error (exit 2).
12
34
 
13
35
  ## Snapshot commands
14
36
 
15
37
  ```bash
16
38
  patchright-cli snapshot # Full page snapshot
17
39
  patchright-cli snapshot e3 # Subtree rooted at ref e3
18
- patchright-cli snapshot --depth=2 # Limit tree depth (reduces noise)
40
+ patchright-cli snapshot --selector="#main" # Subtree under a CSS selector (exactly one match)
41
+ patchright-cli snapshot --depth=2 # Levels 0..2 only
42
+ patchright-cli snapshot -i # Interactive elements only
43
+ patchright-cli snapshot --boxes # [box=x,y,w,h] on each element
19
44
  patchright-cli snapshot --filename=snap.yml # Save to custom filename
20
- patchright-cli snapshot -i # Interactive-only elements
21
- patchright-cli snapshot --interactive # Same as -i
22
45
  ```
23
46
 
24
- ### Options
25
-
26
47
  | Flag | Effect |
27
48
  |------|--------|
28
49
  | `[ref]` | Show only the subtree rooted at the given ref |
29
- | `--selector=<css>` | Show only the subtree under a CSS selector. Must match exactly one element |
30
- | `--depth=N` | Limit depth of the tree (useful for complex pages) |
31
- | `-i` / `--interactive` | Show only interactive elements (buttons, links, inputs) |
50
+ | `--selector=<css>` | Show only the subtree under a CSS selector. Must match exactly one element that is in the accessibility tree |
51
+ | `--depth=N` | Show levels 0..N. A node whose children were cut ends in `# +N refs` (or `# +more`) |
52
+ | `-i` / `--interactive` | Interactive elements, clickable `generic [cursor=pointer]` nodes, a combobox's options, and the named landmarks and iframes around them. `text:` and `/url:` lines are dropped |
53
+ | `--boxes` | Append `[box=x,y,w,h]`: viewport coordinates in CSS pixels, converted to page coordinates inside iframes |
32
54
  | `--filename=F` | Save snapshot to a custom file path |
33
55
 
34
- ## When to re-snapshot
35
-
36
- Re-snapshot whenever the page state has changed and you need to interact with elements:
56
+ Every view is cut from one full-page snapshot, so the refs it shows are the
57
+ page's refs: a ref from `snapshot e3`, `--depth` or `-i` works with every
58
+ command, and refs outside the printed part keep working too.
37
59
 
38
- - After `goto`, `go-back`, `go-forward`, `reload`
39
- - After `click` that triggers navigation or DOM changes
40
- - After form submission
41
- - After `wait` / `wait-for` for dynamic content
42
- - After `eval` / `run-code` that modifies the DOM
60
+ ## When to re-snapshot
43
61
 
44
- Most state-changing commands (click, fill, goto, etc.) **auto-snapshot** and return the new snapshot. You only need to manually run `snapshot` when the page changes asynchronously or you need a subtree/filtered view.
62
+ Most state-changing commands (click, fill, goto, etc.) **auto-snapshot** and
63
+ return the new snapshot. Re-snapshot yourself when the page changes on its own
64
+ (timers, AJAX), after `eval` / `run-code` that changes the DOM, or when a ref
65
+ reports `no longer matches an element`.
45
66
 
46
67
  ## Reading the snapshot
47
68
 
48
- The snapshot is a YAML tree. Each element shows:
49
- - Its **ref** (e.g., `e5`)
50
- - Its **role** (button, link, textbox, heading, etc.)
51
- - Its **name** or text content
52
- - Child elements nested underneath
53
-
54
- Example output:
55
69
  ```yaml
56
- - heading "Welcome" [e1]
57
- - link "Sign in" [e2]
58
- - navigation [e3]
59
- - link "Home" [e4]
60
- - link "About" [e5]
61
- - main [e6]
62
- - textbox "Search" [e7]
63
- - button "Go" [e8]
70
+ - heading "Welcome" [level=1] [ref=e2]
71
+ - navigation "Main" [ref=e3]:
72
+ - link "Home" [ref=e4]:
73
+ - /url: /
74
+ - main [ref=e6]:
75
+ - textbox "Search" [ref=e7]
76
+ - button "Go" [ref=e8]
77
+ - generic [ref=e9] [cursor=pointer]: Open card
78
+ - combobox "Size" [ref=e10]:
79
+ - option "Small" [selected]
80
+ - option "Large"
81
+ - iframe [ref=e11]:
82
+ - button "Pay" [ref=f2e4]
64
83
  ```
65
84
 
66
- ## Troubleshooting
85
+ - `[active]` marks the focused element, `[cursor=pointer]` a node that looks
86
+ clickable though its role does not say so.
87
+ - Wrapper `generic` nodes with nothing of their own are not printed; their
88
+ children move up a level.
89
+ - `text:` lines and `option`s have no ref. Select an option by its label:
90
+ `select e10 Large`.
67
91
 
68
- ### "Could not locate element for ref"
69
- The page has changed since the last snapshot. Run `snapshot` to get fresh refs and retry.
92
+ ## Troubleshooting
70
93
 
71
94
  ### Element not visible or not interactive
72
- Some elements are hidden or overlapped. Try:
73
95
  - `scroll-to <ref>` to bring the element into view
74
- - `wait-for <ref>` to wait until the element appears
75
- - `snapshot -i` to see only interactive elements
76
- - `snapshot <ref>` to inspect a subtree for nested elements
77
- - `snapshot --selector="#main"` to scope by CSS when you have no ref yet
78
-
79
- ### Refs from a scoped snapshot
80
-
81
- A scoped snapshot -- `snapshot <ref>` or `snapshot --selector=<css>` -- numbers
82
- its refs from `e1` within that subtree, and those refs resolve inside the same
83
- subtree. They are not the numbers a full-page `snapshot` would give, so do not
84
- mix refs from a scoped snapshot with refs from a full one: take a fresh
85
- snapshot at the scope you intend to work in.
96
+ - `wait-for <ref>` to wait until it is visible (`--state=hidden` to wait until it goes)
97
+ - `snapshot <ref>` to inspect a subtree
86
98
 
87
99
  ### Too many elements in snapshot
88
- Use `--depth=N` to limit tree depth, or snapshot a specific subtree with `snapshot <ref>`. The `-i` flag also helps by filtering to interactive elements only.
100
+ Use `find`, `--depth=N`, `-i`, or `snapshot <ref>`.
89
101
 
90
- ### Stale refs after dynamic content
91
- SPAs and pages with AJAX calls update the DOM without navigation. After triggering dynamic content (e.g., clicking a "Load more" button), wait briefly and re-snapshot:
102
+ ### Elements that appear later
92
103
  ```bash
93
- patchright-cli click e5 # Triggers dynamic load
104
+ patchright-cli click e5 # Triggers a dynamic load
94
105
  patchright-cli wait 1000 # Wait for content
95
- patchright-cli snapshot # Get fresh refs
106
+ patchright-cli snapshot # Refs for the new elements
96
107
  ```
97
108
 
98
109
  ## `find` — searching the snapshot
@@ -103,14 +114,15 @@ find --regex <pattern> Regex match; bare patterns are case-insensitive
103
114
  find --regex "/p/ims" Slash form; supported flags are i, m, s
104
115
  find --all Search every node, not just interactive roles + heading
105
116
  find --limit=N Cap rendered hits (default 20)
117
+ find --role=<role> Elements get_by_role matches (--name, --description, --exact)
106
118
  ```
107
119
 
108
120
  ### What gets searched
109
121
 
110
- By default, roles in `SEARCHABLE_ROLES` — every interactive role plus
111
- `heading`. This is deliberate: role filtering is the single biggest lever on
112
- output size. Measured across 13 queries on four real pages it cut hits 4.3x
113
- (729 to 168); on one Wikipedia query, 442 hits became 53.
122
+ By default, every interactive role plus `heading`. This is deliberate: role
123
+ filtering is the single biggest lever on output size. Measured across 13
124
+ queries on four real pages it cut hits 4.3x (729 to 168); on one Wikipedia
125
+ query, 442 hits became 53.
114
126
 
115
127
  Matching runs against a node's accessible name. For unnamed nodes such as
116
128
  `- text: Star 95.3k`, the value after the colon is used instead. Property
@@ -120,7 +132,8 @@ lines like `- /url: ...` are not nodes and never match.
120
132
 
121
133
  Per hit: a ` # ancestor > ancestor > parent` breadcrumb (3 deep, names cut at
122
134
  45 characters, repeated names collapsed), then the matched node with its ref,
123
- then its subtree.
135
+ then its subtree. A hit without a ref of its own (an `option`, or a `text:`
136
+ line under `--all`) shows the nearest element you can act on as `[in=e12]`.
124
137
 
125
138
  `find` prints inline and writes no `.yml` file. `snapshot` still writes one.
126
139
 
@@ -80,7 +80,7 @@ patchright-cli state-save auth.json # Save cookies + localSt
80
80
  patchright-cli state-load auth.json # Restore state
81
81
  ```
82
82
 
83
- When loading state, navigate to the matching origin first so localStorage can be applied correctly.
83
+ `state-load` replaces the session's state: it first clears the existing cookies, localStorage, IndexedDB and OPFS data, then applies the file. localStorage is applied to every origin in the file; you do not need to visit an origin first.
84
84
 
85
85
  ## Cookie persistence login pattern
86
86