pw-repl 0.11.5 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md CHANGED
@@ -1,4 +1,4 @@
1
- # Agent Instructions — playwright-repl
1
+ # Agent Instructions — pw-repl
2
2
 
3
3
  How to use the REPL is in the skill `bin/pw-repl.js skill` prints (from `skill/SKILL.md`, stamped with
4
4
  its version and hash). Read it first. In this clone, `pw-repl` there means `bin/pw-repl.js` (from the
@@ -102,7 +102,10 @@ Commits follow [Conventional Commits](https://www.conventionalcommits.org/): `fe
102
102
  1.0, a change that breaks how the REPL is used is a minor bump (0.2.0 to 0.3.0), anything else a patch.
103
103
 
104
104
  1. `npm test` passes and the working tree is clean.
105
- 2. `npm outdated` and `npm audit` show nothing that needs doing first.
105
+ 2. `npm outdated` and `npm audit` show nothing that needs doing first. The lockfile holds playwright-core
106
+ at 1.63: on 1.64, a click on a link to a 204 waits out its timeout instead of returning (the test
107
+ "waits for the page to load, counting a navigation that just began" fails). Update it once a version
108
+ passes `npm test`.
106
109
  3. `npm version <patch|minor|major> -m "chore: release %s"` sets the version in `package.json` and
107
110
  `package-lock.json`, commits it as `chore: release X.Y.Z`, and tags that commit `vX.Y.Z`.
108
111
  4. `git push --follow-tags` pushes the commits and the tag.
package/README.md CHANGED
@@ -1,152 +1,166 @@
1
- # playwright-repl
1
+ # pw-repl
2
2
 
3
- A command REPL for a Chromium you are already using, shared by you and your agents. It connects over CDP
4
- through Playwright; users click in the browser and type at the prompt, agents send the same commands,
5
- and every command shows in the REPL, so each sees what the other does.
3
+ A Playwright REPL for driving Chromium from the command line, made to be shared by you and your AI
4
+ agents.
6
5
 
7
- ## Why use it
6
+ pw-repl connects to a Chromium over CDP (the Chrome DevTools Protocol), in the browser you already use or
7
+ in one it starts itself. You type commands at a `pw>` prompt. Agents send the same commands from a shell
8
+ with `pw-repl send`. Every command shows in the REPL, whoever sent it, so you always see what an agent
9
+ is doing in your browser, and the agent can see what you did.
8
10
 
9
- For working on a web page together with an agent, in the browser you already use:
11
+ ```text
12
+ pw> tab new http://localhost:3000/cart
13
+ pw> snapshot # the page by role and name, with [ref=eN] labels
14
+ pw> click e7 # click by ref, or by any Playwright selector
15
+ pw> requests # what the page requested
16
+ pw> body 4 # what one request got back
17
+ pw> route **/api/cart 500 {"error":"boom"} # fake a failing backend
18
+ pw> reload
19
+ pw> console error # and see how the page copes
20
+ ```
21
+
22
+ ## Why use it
10
23
 
11
- - **Your browser, as it is.** It connects to a running Chromium, with your tabs, sign-ins and state, and
12
- leaves it running when it stops; nothing is reset to a fresh profile.
24
+ - **Your browser, as it is.** It connects to a running Chromium, with your tabs, logins and state, and
25
+ leaves it running when it stops. Nothing is reset to a fresh profile.
13
26
  - **One session, seen by everyone.** You and any number of agents drive the same browser, each with a
14
- selected tab of its own, and every command shows in the REPL, whoever sent it.
27
+ selected tab of its own, and every command shows in the REPL.
15
28
  - **What you did, for an agent to read.** `watch` records each step you take in a tab, with the requests
16
- it caused, so you can reproduce a bug by hand and the agent can see exactly what happened; `watch save`
17
- keeps the steps as a file of commands that runs them again.
29
+ it caused. Reproduce a bug by hand and the agent sees exactly what happened. `watch save` keeps the
30
+ steps as a file of commands that runs them again.
18
31
  - **Breaking things on purpose.** Fake, patch, delay or fail responses, cut or slow the network, emulate a
19
- phone, a locale or a timezone, all per tab, so your other tabs are left alone.
20
-
21
- Coming from Microsoft's playwright-cli? See [How it differs](#how-it-differs-from-playwright-cli).
32
+ phone, a locale or a timezone. All of it applies to one tab, so your other tabs are left alone.
33
+ - **Videos that explain themselves.** Record a tab with a pointer that glides to each click, captions on
34
+ screen, boxes around what matters, and pacing for a viewer.
35
+
36
+ ## What it can do
37
+
38
+ - **Read the page:** accessibility snapshots with clickable refs, text, HTML, attributes, links, form
39
+ controls, event listeners, screenshots (viewport, full page or one element).
40
+ - **Act on it:** click, fill, type, press keys, select, check, upload files, move the mouse, scroll the
41
+ wheel, answer dialogs.
42
+ - **Watch the network:** every request and response body, console messages and page errors, all recorded
43
+ as they happen.
44
+ - **Change the network:** fake a response (`route`), patch its JSON, delay it, fail it, or cut or slow the
45
+ whole tab's network.
46
+ - **Emulate:** a phone, dark mode, a locale, a timezone, a viewport size.
47
+ - **Run code:** `eval` any JavaScript in the page, or send a raw CDP command with `cdp`.
48
+ - **Wait:** for an element, some text, a response or a page load.
49
+ - **Record:** what someone does in a tab (`watch`), a timeline of requests and console (`capture`), or a
50
+ video of the tab (`record`), with a virtual pointer (`cursor`), captions (`toast`) and highlights
51
+ (`highlight`).
52
+ - **Share:** many clients on one REPL, each with its own tab; a command server on a Unix socket or a local
53
+ port, with an HTTP+JSON protocol.
22
54
 
23
55
  ## Quick start
24
56
 
25
- Needs Node.js 20 or newer and a Chromium-based browser (Chrome, Chromium, ...). With none installed,
26
- `npx playwright-core install chromium` downloads Playwright's.
57
+ You need Node.js 20 or newer. pw-repl can use a Chromium-based browser you already have (Chrome,
58
+ Chromium, ...), or Playwright's own: `npx playwright-core install chromium` downloads it.
27
59
 
28
60
  ```bash
29
61
  npx pw-repl@latest run --launch https://example.com
30
62
  ```
31
63
 
32
- `--launch` starts a private headless Chromium for the REPL, and stops it with the REPL; it prints the
33
- command it ran. `--headed` shows that browser, to click in it yourself. The page opens in a new tab,
34
- and a `pw>` prompt waits:
64
+ `--launch` starts a private headless Chromium for the REPL and stops it when the REPL quits. Add
65
+ `--headed` to see that browser and click in it yourself. The page opens in a new tab, and a `pw>`
66
+ prompt waits:
35
67
 
36
68
  ```text
37
69
  pw> help # common tasks and topics; help <topic>, help <command>, help --all
38
- pw> snapshot # the page by role and name, with [ref=eN] labels
39
- pw> click e3 # click by snapshot ref (or any Playwright selector)
40
- pw> requests # requests the tab made
70
+ pw> snapshot
71
+ pw> click e3
72
+ pw> screenshot
41
73
  pw> quit
42
74
  ```
43
75
 
44
- Commands act on the selected tab (`tab` lists the tabs, with `*` on the selected one).
76
+ Commands act on the selected tab. `tab` lists the tabs, with `*` on the selected one.
77
+
78
+ ### Install
79
+
80
+ | How | Setup | Then run |
81
+ | ------------ | -------------------------------------------- | ------------------------------ |
82
+ | Without | nothing | `npx pw-repl@latest <command>` |
83
+ | Global | `npm install -g pw-repl` | `pw-repl <command>` |
84
+ | From a clone | `npm install` (and `npm link` for `pw-repl`) | `bin/pw-repl.js <command>` |
45
85
 
46
- Without installing, use `npx pw-repl@latest <command>` in the same form every time, so each command runs
47
- the same version. Installed: `npm install -g pw-repl`, then `pw-repl <command>`. From a clone:
48
- `npm install`, then `bin/pw-repl.js <command>` (or `npm link` to get `pw-repl`).
86
+ With `npx`, use `npx pw-repl@latest` the same way every time, so every command runs the same version.
49
87
 
50
88
  ## Use your own browser
51
89
 
52
- Start it with remote debugging, then run the REPL without `--launch`:
90
+ Start Chrome with remote debugging, then run the REPL without `--launch`:
53
91
 
54
92
  ```bash
55
93
  chrome --remote-debugging-port=9222 --user-data-dir="$HOME/.config/chrome-debug"
56
- pw-repl run # connects to localhost:9222; pw-repl on its own shows the usage
94
+ pw-repl run # connects to localhost:9222
57
95
  ```
58
96
 
59
- Use a separate `--user-data-dir`: recent Chrome versions do not open the debugging port on the default
60
- profile. Check it is up with `curl http://localhost:9222/json/version`. `PW_CDP_URL=http://host:9222`
61
- reaches a browser elsewhere.
97
+ Use a separate `--user-data-dir`: recent versions of Chrome do not open the debugging port on the default
98
+ profile. To check that it is up: `curl http://localhost:9222/json/version`. To reach a browser on
99
+ another port or machine, set `PW_CDP_URL=http://host:9222`.
62
100
 
63
- Headless works the same way (`chrome --headless=new --remote-debugging-port=9222
64
- --user-data-dir=/tmp/chrome-headless`). Nobody answers a headless browser's dialogs: `dialog
65
- accept|dismiss` does. Pages start at about 800x600; `viewport 1280x800` changes it.
101
+ A headless Chrome works the same way (`chrome --headless=new --remote-debugging-port=9222
102
+ --user-data-dir=/tmp/chrome-headless`). Nobody can click a headless browser's dialogs, so answer them
103
+ with `dialog accept` or `dialog dismiss`. Its pages start at about 800x600; `viewport 1280x800` changes
104
+ that.
66
105
 
67
106
  **Browser on the host, REPL in a container:** with host networking, `localhost:9222` reaches the host's
68
- browser directly. Otherwise set `PW_CDP_URL` to the host's address as seen from the container (for example
69
- the Docker bridge gateway, `ip route | awk '/default/ {print $3}'`).
107
+ browser directly. Otherwise, set `PW_CDP_URL` to the host's address as the container sees it (for
108
+ example the Docker bridge gateway, `ip route | awk '/default/ {print $3}'`).
70
109
 
71
110
  ## Ways to run it
72
111
 
73
- | Command | What you get |
74
- | ---------------------------- | --------------------------------------------------------------------------------------------- |
75
- | `pw-repl run` | a prompt in this terminal; `send` reaches it only through a tmux session named `playwright-repl` |
76
- | `pw-repl serve` | a prompt (`pw[serve]>`), plus a command server on `/tmp/playwright-repl.sock`; `send` needs no tmux |
77
- | `pw-repl serve --background` | no terminal: `attach` to use it, `stop` to stop it, `where` to find it; output in `/tmp/playwright-repl.log` |
112
+ | Command | What you get |
113
+ | ---------------------------- | ---------------------------------------------------------------------------------- |
114
+ | `pw-repl run` | a prompt in this terminal; `send` reaches it only through a tmux session `pw-repl` |
115
+ | `pw-repl serve` | a prompt (`pw[serve]>`), plus a command server on `/tmp/pw-repl.sock` |
116
+ | `pw-repl serve --background` | no terminal; output in `/tmp/pw-repl.log` |
78
117
 
79
- - For `send` to reach `run`, start it in tmux: `tmux new -s playwright-repl`, then `pw-repl run` there.
80
- - A URL after the command opens in a new tab: `pw-repl run http://localhost:3000`.
81
- - `--launch` works with each of them; flags after `--` go to that Chromium.
82
- - A socket of its own: `-e /tmp/mine.sock` on every command, `serve` included (`pw-repl serve --background
83
- -e /tmp/mine.sock`), or `PW_SOCKET`; `serve <port>` listens on TCP on 127.0.0.1.
84
- - A background REPL cannot be brought back like a Ctrl-Z job; `attach` is how you get back to it, from
85
- any terminal.
118
+ - `pw-repl attach` shows a background REPL and takes commands, from any terminal. `pw-repl stop` stops
119
+ it. `pw-repl where` says what is running and how `send` will reach it.
120
+ - For `send` to reach `run`, start it in tmux: `tmux new -s pw-repl`, then `pw-repl run` there.
121
+ - A URL after the command opens in a new tab: `pw-repl serve http://localhost:3000`.
122
+ - `--launch` works with each of them. Flags after `--` go to that Chromium.
123
+ - A REPL of your own goes on a socket of its own: `-e /tmp/mine.sock` on every command, `serve`
124
+ included, or set `PW_SOCKET`. `serve <port>` listens on TCP, on 127.0.0.1 only.
86
125
 
87
126
  ## Common tasks
88
127
 
89
- | I want to… | Commands |
90
- | ------------------------------------ | ------------------------------------------------------------------------------------- |
91
- | see where I am | `tab` (it marks the tab you are looking at `(visible)`), `info` |
92
- | see what is on the page | `snapshot`, `screenshot` |
93
- | do something on it | `click`, `fill`, `press` |
94
- | wait for a page or element | `wait load`, `wait <selector>`, `wait <selector> --gone` |
95
- | choose a file in a file input | `upload <selector> <file>` |
96
- | see it as a phone, or in dark mode | `emulate mobile`, `emulate dark` (also `emulate locale`, `emulate timezone`) |
97
- | see what the page requested | `requests`, then `body <#>` for what one got back |
98
- | see console messages and errors | `console` |
99
- | show an agent what I do | `watch on`, click around in the browser, then `watch` |
100
- | see each step as I click | `watch on --live` |
101
- | replay what I clicked through | `watch on`, click around, `watch save flow.txt`, then `pw-repl send --file flow.txt` |
102
- | record requests and console together | `capture on`, then `capture off` |
103
- | record a video of the page | `record on`, then `record off` (`help video` for a take with a pointer) |
104
- | show a pointer where the agent acts | `cursor on`, then `cursor off` (in screenshots and videos) |
105
- | say what is happening on screen | `toast <text>`, then `toast off` (`--duration=3s` hides it by itself) |
106
- | point something out on the page | `highlight <ref>`: a box, unlabelled unless `--labels on`; `highlight off` hides it |
107
- | break the backend on purpose | `route <glob> <status> <json>` (fake a response), `route <glob> abort`, `network off` |
108
- | change or slow an API response | `route <glob> patch <json>`, `route <glob> delay <secs>` |
109
- | slow the whole network | `network slow` |
110
- | clean up | `modes off` |
111
-
112
- Everything else is in `help <topic>`; `help <command>` has usage and caveats.
128
+ | I want to… | Commands |
129
+ | ------------------------------------- | ------------------------------------------------------------------------------------ |
130
+ | see where I am | `tab` (it marks the tab you are looking at `(visible)`), `info` |
131
+ | see what is on the page | `snapshot`, `screenshot` |
132
+ | do something on it | `click`, `fill`, `type`, `press` |
133
+ | click what has no selector (a canvas) | `mouseclick <x> <y>` |
134
+ | run some JavaScript in the page | `eval document.title` |
135
+ | wait for a page or element | `wait load`, `wait <selector>`, `wait <selector> --gone`, `wait text <text>` |
136
+ | choose a file in a file input | `upload <selector> <file>` |
137
+ | see it as a phone, or in dark mode | `emulate mobile`, `emulate dark` (also `emulate locale`, `emulate timezone`) |
138
+ | see what the page requested | `requests`, then `body <#>` for what one got back |
139
+ | see console messages and errors | `console` |
140
+ | show an agent what I do | `watch on`, click around in the browser, then `watch` |
141
+ | see each step as I click | `watch on --live` |
142
+ | replay what I clicked through | `watch on`, click around, `watch save flow.txt`, then `pw-repl send --file flow.txt` |
143
+ | record requests and console together | `capture on`, then `capture off` |
144
+ | fake a backend response | `route <glob> <status> <json>`, `route <glob> abort` |
145
+ | change or slow an API response | `route <glob> patch <json>`, `route <glob> delay <secs>` |
146
+ | cut or slow the whole network | `network off`, `network slow`, then `network on` |
147
+ | record a video of the page | `record on`, then `record off` (`help video` for a take with a pointer) |
148
+ | show a pointer where the agent acts | `cursor on`, then `cursor off` (in screenshots and videos) |
149
+ | say what is happening on screen | `toast <text>`, then `toast off` (`--duration=3s` hides it by itself) |
150
+ | point something out on the page | `highlight <ref>` draws a box; `highlight off` hides it |
151
+ | clean up | `modes off` |
152
+
153
+ `help <topic>` lists the rest, and `help <command>` has usage and caveats.
113
154
 
114
155
  ### Modes
115
156
 
116
- `watch`, `capture`, `route`, `network off` or `slow`, `emulate`, `viewport`, `record`, `highlight`, `cursor`
117
- and `toast` stay on until you turn them off: `watch on|off`, `capture on|off`, `route ...|route off`,
118
- `network off|slow|on`, `emulate ...|emulate off`, `viewport <WxH>|viewport off`, `record on|off`,
119
- `highlight <selector>|highlight off` (and `highlight --labels on|off`), `cursor on|off`,
120
- `toast <text>|toast off`.
121
- While any are on in the selected tab, the prompt shows them: `(watch network:off routes:2) pw>`. `modes`
122
- lists them for every tab, and `modes off` turns them all off.
123
-
124
- `tab`, `watch`, `capture`, `route`, `network`, `emulate`, `viewport`, `record`, `highlight`, `cursor`, `toast`
125
- and `modes` on their own show their state and what you can run next.
126
-
127
- ## How it differs from playwright-cli
128
-
129
- [playwright-cli](https://github.com/microsoft/playwright-cli) is Microsoft's command line for agents. It
130
- gives each agent a browser session of its own; pw-repl shares one browser between users and agents.
131
- Its command names and most of their options work here too (`help playwright-cli` lists them), and where
132
- pw-repl differs, it is mostly because someone else may be using the browser:
157
+ Some commands turn on a mode that stays on until you turn it off: `watch`, `capture`, `route`, `network
158
+ off` or `slow`, `emulate`, `viewport`, `record`, `highlight`, `cursor` and `toast`. While any are on in
159
+ the selected tab, the prompt shows them: `(watch network:off routes:2) pw>`. `modes` lists them for every
160
+ tab, and `modes off` turns them all off. Each of these commands on its own shows its state and what you
161
+ can run next.
133
162
 
134
- - `open` and `close` open a tab and turn off your modes; they never start, close or wipe a browser.
135
- - Routes, network and emulation apply to one tab, not the whole browser.
136
- - File pickers are not caught, since they may be the user's: `upload` names the input instead.
137
- - There is no snapshot after every command, since the user reads the REPL too; `snapshot` shows one.
138
- - Instead of `-s=<session>`, an agent is a client of its own (`send -c <name>`).
139
- - `watch` records what the user does as steps with their requests, and `watch save` writes them as
140
- pw-repl commands to run again, not as Playwright code.
141
- - `highlight` draws its box without Playwright's locator label, which covers what is below it and puts
142
- selectors in screenshots and videos; `highlight --labels on` shows it.
143
-
144
- For a browser of its own per agent, isolated sessions, traces, video, PDFs or generated test code,
145
- playwright-cli is the better fit. `record on` records a tab's page, and `cursor on` draws a pointer where the
146
- agent acts; for the shared browser as you see it, use a screen recorder (`ffmpeg -f x11grab`, macOS
147
- `screencapture -v`, OBS).
148
-
149
- ## From scripts and agents
163
+ ## For agents and scripts
150
164
 
151
165
  ### A skill for agents
152
166
 
@@ -159,9 +173,9 @@ mkdir -p <skills folder>/pw-repl
159
173
  npx pw-repl@latest skill > <skills folder>/pw-repl/SKILL.md
160
174
  ```
161
175
 
162
- It is stamped with the version it came from and a hash of its text, and `pw-repl where` names the skill
163
- of the pw-repl being run, so an agent can tell when its saved copy is out of date and offer to update it
164
- (keeping its Custom rules section). Working on the REPL itself: see `AGENTS.md`.
176
+ It is stamped with the version it came from and a hash of its text. `pw-repl where` names the skill of
177
+ the pw-repl being run, so an agent can tell when its saved copy is out of date and offer to update it
178
+ (keeping its Custom rules section).
165
179
 
166
180
  ### send, clients and where
167
181
 
@@ -171,44 +185,74 @@ pw-repl send help # the REPL's commands; works without a running REPL
171
185
  pw-repl where # which REPL send would reach
172
186
  ```
173
187
 
174
- `pw-repl send` sends one command and prints its result, through the server when it is running and through the
175
- `playwright-repl` tmux session otherwise. Chain several in the shell: `&&` stops at the first that fails or
176
- is not confirmed (exit 1 or 2), `;` runs on.
188
+ `pw-repl send` sends one command and prints its result, through the server when one is running, and
189
+ through the `pw-repl` tmux session otherwise. Chain several in the shell: `&&` stops at the first that
190
+ fails or is not confirmed (exit 1 or 2), and `;` carries on.
191
+
192
+ Several agents can share one REPL. `pw-repl send -c <name>` (or `PW_CLIENT=<name>`) sends as a client
193
+ with a selected tab of its own, shown in the REPL as `[server:<name>]`. `modes` says which client turned
194
+ each mode on, and `modes off --mine` turns off only the sender's own.
177
195
 
178
- Several agents can share one REPL: `pw-repl send -c <name>` (or `PW_CLIENT=<name>`) sends as a client with a
179
- selected tab of its own, shown in the pane as `[server:<name>]`. `modes` says which client turned each mode on,
180
- and `modes off --mine` turns off only the sender's own.
196
+ `send --file take.txt` runs a file of commands, one per line, and stops at the first that fails: a
197
+ repro to keep, or a video take.
181
198
 
182
- A password can be typed as a variable: `PW_PASSWORD=... pw-repl send fill '#password' "{{ PW_PASSWORD }}"`,
183
- or the same line in a file run with `send --file`, as `watch save` writes it. `send` takes the value of
184
- `{{ PW_NAME }}` from its own environment and passes it along with the command; the REPL puts it in only as
185
- it runs the command, so the file, and the command as the pane, the log and the prompt's history show it,
186
- never hold it. Output that reads it back can: `snapshot`, `html` and `attrs` hide a password field's value,
187
- but `eval` reading the field, a field a Show password button made plain text (`help snapshot`), or page
188
- text that repeats it do not. Only `PW_` names are variables (`pw-repl --help` has the rest).
199
+ **Passwords:** type one as a variable: `PW_PASSWORD=... pw-repl send fill '#password' "{{ PW_PASSWORD
200
+ }}"`, or the same line in a file run with `send --file`, as `watch save` writes it. `send` passes the
201
+ value along with the command, and the REPL puts it in only as it runs the command, so the file, the
202
+ REPL's output, its log and its history never hold it. Output that reads it back can: `snapshot`, `html`
203
+ and `attrs` hide a password field's value, but `eval` on the field, a field that a Show password button
204
+ made plain text, or page text that repeats it do not. Only `PW_` names are variables.
189
205
 
190
206
  ### The HTTP protocol
191
207
 
192
208
  With `pw-repl serve`, the server speaks HTTP with JSON, for clients of your own:
193
209
 
194
210
  ```bash
195
- curl --unix-socket /tmp/playwright-repl.sock -H 'Content-Type: application/json' \
211
+ curl --unix-socket /tmp/pw-repl.sock -H 'Content-Type: application/json' \
196
212
  -d '{"command": "info"}' http://localhost/run
197
213
  ```
198
214
 
199
215
  The body may also have `"client": "<name>"`, and `"vars": {"PW_NAME": "<value>"}` with the values of the
200
- `{{ PW_NAME }}` variables in the command, one line each (else 400). It returns `{"status": "ok" | "error", "output": "..."}`, plus
201
- `"unconfirmed": true` when the command may or may not have done what it was sent to do (it timed out, or
202
- the REPL quit while it ran and it was not read-only). While the REPL starts, `/run` answers 503 with
203
- `"starting": true`: retry. `GET /health` says `"status": "starting"` until it serves, then `"ok"`.
204
- `pw-repl serve <port>` serves TCP on 127.0.0.1 instead; other addresses are refused.
216
+ `{{ PW_NAME }}` variables in the command (one line only, else 400). It returns `{"status": "ok" |
217
+ "error", "output": "..."}`, plus `"unconfirmed": true` when the command may or may not have done what it
218
+ was sent to do (it timed out, or the REPL quit while it ran and it was not read-only). While the REPL
219
+ starts, `/run` answers 503 with `"starting": true`: retry. `GET /health` says `"status": "starting"` until
220
+ it serves, then `"ok"`. `pw-repl serve <port>` serves TCP on 127.0.0.1; other addresses are refused.
221
+
222
+ ## How it differs from playwright-cli
205
223
 
206
- ## Tests
224
+ [playwright-cli](https://github.com/microsoft/playwright-cli) is Microsoft's command line for agents. It
225
+ gives each agent a browser session of its own, while pw-repl shares one browser between users and agents.
226
+ playwright-cli's command names and most of their options work here too (`help playwright-cli` lists
227
+ them). Where pw-repl differs, it is mostly because someone else may be using the browser:
228
+
229
+ - `open` and `close` open a tab and turn off your modes; they never start, close or wipe a browser.
230
+ - Routes, network and emulation apply to one tab, not the whole browser.
231
+ - File pickers are not caught, since they may be the user's: `upload` names the input instead.
232
+ - There is no snapshot after every command, since the user reads the REPL too; `snapshot` shows one.
233
+ - Instead of `-s=<session>`, an agent is a client of its own (`send -c <name>`).
234
+ - `watch` records what the user does as steps with their requests, and `watch save` writes them as
235
+ pw-repl commands to run again, not as Playwright code.
236
+ - `highlight` draws its box without Playwright's locator label, which would cover what is below it and
237
+ put selectors in screenshots and videos. `highlight --labels on` shows it.
238
+
239
+ For a browser of its own for each agent, isolated sessions, traces, PDFs or generated test code,
240
+ playwright-cli is the better fit. `record` records a tab's page; to record the shared browser as you see
241
+ it, with your real pointer, use a screen recorder (OBS, `ffmpeg -f x11grab`, macOS `screencapture -v`).
242
+
243
+ ## Contributing
244
+
245
+ `AGENTS.md` describes how the code is laid out, how to add a command, and how releases are cut.
207
246
 
208
247
  ```bash
248
+ npm install
209
249
  npm test
210
250
  ```
211
251
 
212
- Needs Node.js 21 or newer. Runs against a private headless Chromium it starts itself (`PW_TEST_CHROME`, or
213
- the one `--launch` would use: Playwright's, e.g. from `npx playwright-core install chromium`, then one on
214
- the `PATH`) and a local test site; the browser tests are skipped when no Chromium is found.
252
+ The tests need Node.js 21 or newer. They run against a private headless Chromium they start themselves
253
+ (`PW_TEST_CHROME`, or the one `--launch` would use: Playwright's, then one on the `PATH`) and a local test
254
+ site. The browser tests are skipped when no Chromium is found.
255
+
256
+ ## License
257
+
258
+ MIT. See `LICENSE.md`.
package/bin/pw-repl.js CHANGED
@@ -8,14 +8,15 @@ const USAGE = `Usage:
8
8
  connect to the browser and open the prompt
9
9
 
10
10
  pw-repl serve [--background] [--launch [--headed]] [[-e] endpoint] [start-url] [-- <chromium flags>]
11
- the same, plus a command server (socket, port, or 127.0.0.1:port; default /tmp/playwright-repl.sock);
11
+ the same, plus a command server (socket, port, or 127.0.0.1:port; default /tmp/pw-repl.sock);
12
12
  --background runs it detached, with its output in a log next to the socket
13
13
 
14
14
  pw-repl attach [-e endpoint]
15
15
  see everything a background REPL does, and type commands to it; Ctrl-C leaves it running
16
16
 
17
17
  pw-repl stop [-e endpoint]
18
- stop a background REPL, and say what became of each recording it ended
18
+ stop a background REPL, and say what became of each recording it ended; its socket is removed, its
19
+ log stays
19
20
 
20
21
  pw-repl send [-e endpoint | -s session] [-c client] [-t seconds] [--no-vars] <command...> | --file <file>
21
22
  run one command in a running REPL and print its output; --file runs a file of them, one per line
@@ -29,10 +30,10 @@ const USAGE = `Usage:
29
30
  pw-repl skill
30
31
  print an agent skill (SKILL.md) that teaches an agent to use the REPL
31
32
 
32
- send uses the server when -e, $PW_ENDPOINT, or the socket ($PW_SOCKET, default /tmp/playwright-repl.sock)
33
- is there, and the tmux session (-s, $PW_TMUX_SESSION, default playwright-repl) otherwise. If the socket
34
- exists but nothing answers, send fails rather than fall back. serve without an endpoint serves on that
35
- same one: $PW_ENDPOINT, then $PW_SOCKET, then the default.
33
+ send uses the server when -e, $PW_ENDPOINT, or the socket ($PW_SOCKET, default /tmp/pw-repl.sock) is
34
+ there, and the tmux session (-s, $PW_TMUX_SESSION, default pw-repl) otherwise. If the socket exists but
35
+ nothing answers, send fails rather than fall back. serve without an endpoint serves on that same one:
36
+ $PW_ENDPOINT, then $PW_SOCKET, then the default.
36
37
 
37
38
  send -c <client> (or $PW_CLIENT) sends as a client of the REPL's with a selected tab of its own, so
38
39
  several agents can share one REPL; pw-repl help session has the rest.
@@ -64,7 +65,7 @@ and stops it with the REPL (Ctrl-C while it starts too); stop returns once that
64
65
  Flags after -- go to it; a --user-data-dir=<dir> among them is used instead of the temporary profile, and
65
66
  kept. PW_CHROME picks which one. To set a browser up your own way, start it yourself and use PW_CDP_URL.
66
67
 
67
- In a tmux session named playwright-repl, pw-repl send reaches pw-repl run without the server.`;
68
+ In a tmux session named pw-repl, pw-repl send reaches pw-repl run without the server.`;
68
69
 
69
70
  const REPL_HELP = `The REPL's own commands: help at the pw> prompt, or pw-repl send help here (no REPL needed).
70
71
 
package/lib/background.js CHANGED
@@ -20,9 +20,9 @@ const FOLLOW_INTERVAL = 150;
20
20
  const ATTACH_BACKLOG = 20;
21
21
  const ATTACH_COMMAND_TIMEOUT = 3600000;
22
22
 
23
- // /tmp/playwright-repl.sock keeps /tmp/playwright-repl.pid and .log; a port, /tmp/playwright-repl-<port>.*.
23
+ // /tmp/pw-repl.sock keeps /tmp/pw-repl.pid and .log; a port, /tmp/pw-repl-<port>.*.
24
24
  function filesFor(endpoint) {
25
- const base = endpoint.socket ? endpoint.socket.replace(/\.sock$/, '') : path.join('/tmp', `playwright-repl-${endpoint.port}`);
25
+ const base = endpoint.socket ? endpoint.socket.replace(/\.sock$/, '') : path.join('/tmp', `pw-repl-${endpoint.port}`);
26
26
  return { pidFile: `${base}.pid`, logFile: `${base}.log` };
27
27
  }
28
28
 
package/lib/client.js CHANGED
@@ -2,7 +2,7 @@
2
2
  const http = require('http');
3
3
  const path = require('path');
4
4
 
5
- const DEFAULT_SOCKET = '/tmp/playwright-repl.sock';
5
+ const DEFAULT_SOCKET = '/tmp/pw-repl.sock';
6
6
  const LOOPBACK = new Set(['127.0.0.1', 'localhost', '::1']);
7
7
 
8
8
  // A port or loopback host:port is TCP; anything else is a unix socket path.
package/lib/elements.js CHANGED
@@ -465,6 +465,27 @@ const commands = {
465
465
  out.log(`Moved the mouse to ${x}, ${y}`);
466
466
  },
467
467
 
468
+ // A click at a point, as Playwright's mouse.click: for what has no selector, such as a marker drawn on a canvas.
469
+ async mouseclick(line) {
470
+ const usage = 'mouseclick <x> <y> [left|right|middle] [--delay=<ms>]';
471
+ const held = /(?:^|\s)--delay(?:=|\s+)(\S*)(?=\s|$)/.exec(line || '');
472
+ if (held && !/^\d+$/.test(held[1])) throw new Error(`Usage: ${usage}, the ms between press and release, e.g. mouseclick 400 300 --delay=500`);
473
+ const words = (held ? line.replace(held[0], ' ') : line || '').trim().split(/\s+/).filter(Boolean);
474
+ const button = /^[a-z]+$/.test(words[words.length - 1] || '') ? mouseButton(words.pop(), 'mouseclick <x> <y>') : 'left';
475
+ const [x, y, extra] = numbers(words.join(' '), usage);
476
+ if (y === undefined || extra !== undefined) throw new Error(`Usage: ${usage}, in CSS pixels from the top left of the viewport`);
477
+ stepTarget(state.page, null, { x, y });
478
+ await glideTo(state.page, x, y);
479
+ await state.page.mouse.move(x, y);
480
+ tabState(state.page).mouseAt = { x, y };
481
+ // The ring shows at the press, as mousedown's does, while a --delay holds the button.
482
+ await state.page.mouse.down({ button });
483
+ await showClick(state.page);
484
+ if (held) await new Promise(resolve => setTimeout(resolve, Number(held[1])));
485
+ await state.page.mouse.up({ button });
486
+ out.log(`Clicked the ${button} button at ${x}, ${y}`);
487
+ },
488
+
468
489
  async mousedown(args) {
469
490
  const button = mouseButton(args, 'mousedown');
470
491
  await glideToMouse();
package/lib/help.js CHANGED
@@ -22,7 +22,7 @@ function wrap(text, width = WIDTH) {
22
22
  }).join('\n\n');
23
23
  }
24
24
 
25
- const OVERVIEW = wrap(`playwright-repl drives Chromium over CDP. Commands act on the selected tab (\`tab\` shows which).
25
+ const OVERVIEW = wrap(`pw-repl drives Chromium over CDP. Commands act on the selected tab (\`tab\` shows which).
26
26
  The browser may be a shared session, with other users' tabs open in it.
27
27
 
28
28
  Common tasks:
@@ -70,7 +70,7 @@ tab on its own lists them all.`,
70
70
  intro: `Selectors are Playwright selectors (CSS, text=..., role=...) or snapshot refs such as e5.
71
71
  Commands use the first match (click, dblclick and hover the first they can use: help click); see help
72
72
  fill for selectors with spaces. mousemove and the other mouse commands act at a point instead.`,
73
- commands: ['click', 'dblclick', 'hover', 'fill', 'type', 'press', 'select', 'check', 'uncheck', 'upload', 'mousemove', 'mousedown', 'mouseup', 'mousewheel'],
73
+ commands: ['click', 'dblclick', 'hover', 'fill', 'type', 'press', 'select', 'check', 'uncheck', 'upload', 'mousemove', 'mouseclick', 'mousedown', 'mouseup', 'mousewheel'],
74
74
  },
75
75
  inspect: {
76
76
  intro: `Output is capped; --all right after the command, or at the end, shows everything (text --all body).`,
@@ -128,7 +128,7 @@ still show sensitive data (cdp Network.getCookies shows cookie values).`,
128
128
  Unknown outcome: a command that timed out after it began acting on the page may or may not have done
129
129
  it. It says so (pw-repl send exits 2), and the REPL carries on.
130
130
 
131
- Server: pw-repl serve also takes commands on /tmp/playwright-repl.sock; they show here as [server] lines.
131
+ Server: pw-repl serve also takes commands on /tmp/pw-repl.sock; they show here as [server] lines.
132
132
 
133
133
  Clients: pw-repl send -c <name> (or $PW_CLIENT) sends as a client of its own. It has a selected tab of
134
134
  its own, so clients do not move each other's; its commands show as [server:<name>] lines. modes and tab
@@ -219,8 +219,21 @@ events) and that the outcome is unknown; Playwright's full call log goes to the
219
219
  eval (r => [r.x + r.width / 2, r.y + r.height / 2])(document.querySelector("#map")
220
220
  .getBoundingClientRect())
221
221
 
222
- A click at a point: mousemove <x> <y>, mousedown, mouseup. A drag: mousedown, then mousemove to another
223
- point, then mouseup.`,
222
+ A click at a point: mouseclick <x> <y>. A drag: mousedown, then mousemove to another point, then mouseup.`,
223
+ },
224
+ mouseclick: {
225
+ usage: 'mouseclick <x> <y> [button]',
226
+ summary: 'click at a point in the viewport',
227
+ args: [
228
+ ['<x> <y>', 'CSS pixels from the top left of the tab\'s viewport, as for mousemove.'],
229
+ ['[button]', 'left, right or middle. Default: left.'],
230
+ ],
231
+ options: [
232
+ ['--delay=<ms>', 'holds the button down this long between press and release, as Playwright\'s mouse.click delay. Default: 0.'],
233
+ ],
234
+ detail: `For what has no selector, such as a marker drawn on a canvas; anything a selector finds is better
235
+ clicked with click, which waits for it. help mousemove shows how to find a point. The mouse stays at the point, for a mousewheel or mousedown after
236
+ it. The cursor (help cursor) moves there first and shows a ring at the press.`,
224
237
  },
225
238
  mousedown: { usage: 'mousedown [button]', summary: 'press a mouse button where the mouse is (left, right or middle)' },
226
239
  mouseup: { usage: 'mouseup [button]', summary: 'release a mouse button where the mouse is' },
@@ -460,7 +473,7 @@ circle). That changes the page, so put it back afterwards, as it was if it had a
460
473
  ['-d, --delay <secs>', 'counts down out loud first, up to 60, so someone can hold a hover or open a menu.'],
461
474
  ['--filename=<file>', 'saves it there instead (a JPEG if it ends in .jpg). Relative to the REPL\'s folder; through pw-repl send, the sender\'s. It never replaces a file.'],
462
475
  ],
463
- detail: `Where: $PW_SCREENSHOT_DIR; without it, next to the REPL's socket when it serves on one of its own, or
476
+ detail: `Where: $PW_SCREENSHOT_DIR (a folder that exists); without it, next to the REPL's socket when it serves on one of its own, or
464
477
  else in /tmp.
465
478
 
466
479
  It brings the tab to the front of its window first: Chrome draws only the tab in front. The image is
@@ -511,8 +524,8 @@ shows in screenshots and recordings. Selectors, snapshot and text don't see it,
511
524
  detail: `The REPL's clicks and typing don't move a pointer on screen, so a recording shows things happening
512
525
  with nothing pointing at them. With the cursor on, these commands move it smoothly to their element or
513
526
  point before they act: click, dblclick, hover, fill, type <selector>, press <selector>, select, check,
514
- uncheck, upload and mousemove. Each move takes 150 to 600ms by distance (300 to 1000ms while the tab
515
- records), and the command waits for it. Clicks (click, dblclick, check, uncheck, mousedown, and upload
527
+ uncheck, upload, mousemove and mouseclick. Each move takes 150 to 600ms by distance (300 to 1000ms while the tab
528
+ records), and the command waits for it. Clicks (click, dblclick, check, uncheck, mouseclick, mousedown, and upload
516
529
  when it clicks a button) show a ring where they land.
517
530
 
518
531
  Only the drawing moves: no mouse events are sent along the way, so the page gets the same input as with
@@ -905,6 +918,11 @@ Different on purpose, since the browser may be someone else's too:
905
918
  return Object.hasOwn(COMMANDS, topicOrCommand) ? `${text}\n\n${renderCommand(topicOrCommand)}` : text;
906
919
  }
907
920
  if (Object.hasOwn(COMMANDS, topicOrCommand)) return renderCommand(topicOrCommand);
921
+ // Not a topic: the mouse commands are in interact, with the others that act on the page.
922
+ if (topicOrCommand === 'mouse') {
923
+ const mice = TOPICS.interact.commands.filter(c => c.startsWith('mouse'));
924
+ return ['The mouse commands, which act at a point (part of help interact):', '', ...commandLines(mice)].join('\n');
925
+ }
908
926
  const full = /^(\S+)\s+--all$/.exec(topicOrCommand);
909
927
  if (full && Object.hasOwn(COMMANDS, full[1])) return renderCommand(full[1], true);
910
928
  // A playwright-cli name: what it runs here, with that command's help.
package/lib/record.js CHANGED
@@ -392,7 +392,7 @@ function videoTime(rec) {
392
392
  // What a step is, for its line: the command and what it acts on, never what it types or chooses, the
393
393
  // code it runs or the URL it goes to, which can hold a password or a token. A steps file goes where the
394
394
  // video goes, and the video shows a password as dots.
395
- const WHOLE = new Set(['click', 'dblclick', 'hover', 'check', 'uncheck', 'mousemove', 'mousedown', 'mouseup', 'mousewheel']);
395
+ const WHOLE = new Set(['click', 'dblclick', 'hover', 'check', 'uncheck', 'mousemove', 'mouseclick', 'mousedown', 'mouseup', 'mousewheel']);
396
396
  const TARGET_FIRST = new Set(['fill', 'type', 'select', 'press', 'upload']);
397
397
  function stepLabel(cmd, args) {
398
398
  if (WHOLE.has(cmd)) {
package/lib/send.js CHANGED
@@ -25,7 +25,7 @@ function hasSession(session) {
25
25
  function route(options) {
26
26
  const socket = process.env.PW_SOCKET || client.DEFAULT_SOCKET;
27
27
  const endpoint = options.endpoint || process.env.PW_ENDPOINT || '';
28
- const session = options.session || process.env.PW_TMUX_SESSION || 'playwright-repl';
28
+ const session = options.session || process.env.PW_TMUX_SESSION || 'pw-repl';
29
29
  if (options.session) return { kind: 'tmux', session };
30
30
  if (endpoint) return { kind: 'server', endpoint: client.parseEndpoint(endpoint), explicit: true };
31
31
  if (process.env.PW_SOCKET) return { kind: 'server', endpoint: client.parseEndpoint(socket), explicit: true };
@@ -235,7 +235,7 @@ async function where(options) {
235
235
  console.error(way.endpoint.socket && !fs.existsSync(way.endpoint.socket) ? `server: no REPL is serving on ${name} (there is no socket)` : `server: ${name} is not answering`);
236
236
  if (way.explicit) return 64;
237
237
  }
238
- const session = options.session || process.env.PW_TMUX_SESSION || 'playwright-repl';
238
+ const session = options.session || process.env.PW_TMUX_SESSION || 'pw-repl';
239
239
  if (!hasSession(session)) {
240
240
  console.error(`tmux: no session '${session}'`);
241
241
  console.error('A REPL on a socket of its own is found with -e <socket> or PW_SOCKET.');
package/lib/start.js CHANGED
@@ -27,6 +27,14 @@ curl ${CDP_URL}/json/version checks that it answers; PW_CDP_URL points at a brow
27
27
  Or let pw-repl start a private one for this REPL: pw-repl run --launch (or serve --launch).`;
28
28
  }
29
29
 
30
+ // The command this REPL was started with, to start it again: a background one runs as serve, with
31
+ // --background left out of its arguments.
32
+ function startedAs() {
33
+ const args = process.argv.slice(2).map(a => (/[\s"'$]/.test(a) ? JSON.stringify(a) : a));
34
+ if (process.env.PW_REPL_PID_FILE && args[0] === 'serve') args.splice(1, 0, '--background');
35
+ return ['pw-repl', ...args].join(' ');
36
+ }
37
+
30
38
  async function start(options) {
31
39
  const START_URL = options.startUrl || process.env.PW_START_URL || null;
32
40
  // First, so a terminal or a log says which pw-repl ran; where names the skill to compare a saved one with.
@@ -60,7 +68,7 @@ async function start(options) {
60
68
  state.connectionLost = true;
61
69
  state.stopping = true;
62
70
  process.exitCode = 1;
63
- out.error('Chromium connection lost; queued commands will not run.');
71
+ out.error(`Chromium connection lost; queued commands will not run. Start the REPL again to carry on: ${startedAs()}`);
64
72
  void shutdown().then(beforeExit).then(() => process.exit(1));
65
73
  });
66
74
  out.log('Connected to Chromium via CDP');
@@ -100,7 +108,7 @@ async function start(options) {
100
108
  return;
101
109
  }
102
110
  if (!options.serve && !process.env.TMUX) {
103
- out.log('Tip: run it in a tmux session named playwright-repl so pw-repl send can reach it, or use pw-repl serve.');
111
+ out.log('Tip: run it in a tmux session named pw-repl so pw-repl send can reach it, or use pw-repl serve.');
104
112
  }
105
113
  out.log("Run 'help' to see the commands. They act on the selected tab (*).");
106
114
  out.log('');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pw-repl",
3
- "version": "0.11.5",
3
+ "version": "0.12.1",
4
4
  "description": "Text REPL for driving an existing Chromium through Playwright over CDP",
5
5
  "keywords": [
6
6
  "playwright",
@@ -14,7 +14,7 @@
14
14
  "license": "MIT",
15
15
  "repository": {
16
16
  "type": "git",
17
- "url": "git+https://github.com/arcanemachine/playwright-repl.git"
17
+ "url": "git+https://github.com/arcanemachine/pw-repl.git"
18
18
  },
19
19
  "bin": {
20
20
  "pw-repl": "bin/pw-repl.js"
package/skill/SKILL.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: pw-repl
3
- description: Inspect and drive a Chromium browser, possibly one the user is using, through the pw-repl (playwright-repl) REPL - tabs, page snapshots, clicks and typing, the mouse at a point (moves, buttons, wheel), requests and their bodies, console messages, waiting for pages and elements, choosing files, faking, patching or delaying responses, cutting or slowing the network, emulating a phone, dark mode, a locale or a timezone, recording what the user does, and recording a video of a tab, with a pointer and on-screen captions. Use when asked to look at, debug or test something in a web page, in an existing Chromium with remote debugging or in one it starts itself.
3
+ description: Inspect and drive a Chromium browser, possibly one the user is using, through the pw-repl REPL - tabs, page snapshots, clicks and typing, the mouse at a point (moves, buttons, wheel), requests and their bodies, console messages, waiting for pages and elements, choosing files, faking, patching or delaying responses, cutting or slowing the network, emulating a phone, dark mode, a locale or a timezone, recording what the user does, and recording a video of a tab, with a pointer and on-screen captions. Use when asked to look at, debug or test something in a web page, in an existing Chromium with remote debugging or in one it starts itself.
4
4
  allowed-tools: Bash(pw-repl:*) Bash(npx pw-repl@latest:*)
5
5
  ---
6
6
 
@@ -8,8 +8,8 @@ allowed-tools: Bash(pw-repl:*) Bash(npx pw-repl@latest:*)
8
8
 
9
9
  <!-- pw-repl skill stamp -->
10
10
 
11
- pw-repl (playwright-repl) is a REPL that drives a running Chromium over CDP. The browser may be a
12
- shared session: the user can have their own tabs open in it and be using it while you work.
11
+ pw-repl is a REPL that drives a running Chromium over CDP. The browser may be a shared session: the
12
+ user can have their own tabs open in it and be using it while you work.
13
13
 
14
14
  `pw-repl` below is the command the `pw-repl` npm package installs. Without a global install, use
15
15
  `npx pw-repl@latest` in its place, in that same form for every command, so each one runs the same
@@ -45,10 +45,10 @@ when none is running). Right after you start one, for a moment before its proces
45
45
  say none is there: retry for a few seconds before taking that as a failed start. There are three ways to
46
46
  run one; each takes an optional start URL, which opens in a new tab.
47
47
 
48
- - `pw-repl serve --background` runs it detached, with a command server on `/tmp/playwright-repl.sock`
49
- (owner-only) and its output in `/tmp/playwright-repl.log`. `pw-repl attach` shows everything it does
50
- and takes commands; `pw-repl stop` stops it. It returns once the REPL serves; Ctrl-C before then gives
51
- up on the start, stops the REPL, exits 130, and says so in the log.
48
+ - `pw-repl serve --background` runs it detached, with a command server on `/tmp/pw-repl.sock`
49
+ (owner-only) and its output in `/tmp/pw-repl.log`. `pw-repl attach` shows everything it does and
50
+ takes commands; `pw-repl stop` stops it. It returns once the REPL serves; Ctrl-C before then gives up
51
+ on the start, stops the REPL, exits 130, and says so in the log.
52
52
  - `pw-repl serve` runs the same in a terminal, where the pane shows every command. Its prompt is
53
53
  `pw[serve]>`. It stops at that prompt (`quit`, or Ctrl-C); `pw-repl stop` is for a background one.
54
54
  - Add `--launch` to `run` or `serve` (with or without `--background`) to have it start a Chromium of its
@@ -61,11 +61,11 @@ run one; each takes an optional start URL, which opens in a new tab.
61
61
  attached, so `requests` and `console` have only what came after, often nothing: `reload` for a full
62
62
  record.
63
63
  - `pw-repl run` runs it in a terminal with no server; `send` then reaches it through tmux, if it runs in
64
- the tmux session `playwright-repl`:
64
+ the tmux session `pw-repl`:
65
65
 
66
66
  ```bash
67
- tmux send-keys -t playwright-repl -l 'pw-repl run'
68
- tmux send-keys -t playwright-repl Enter
67
+ tmux send-keys -t pw-repl -l 'pw-repl run'
68
+ tmux send-keys -t pw-repl Enter
69
69
  ```
70
70
 
71
71
  A REPL of your own goes on a socket of its own, named with `-e` on every command, `serve` included:
@@ -187,10 +187,9 @@ blindly retry a change), `64` usage or the REPL is not reachable. `pw-repl --hel
187
187
  ## Learn the commands
188
188
 
189
189
  Run `pw-repl send help`. It lists seven topics; `help <topic>` lists their commands, `help <command>`
190
- gives usage and caveats, and `help --all` prints everything at once. pw-repl answers it itself: it needs
191
- no running REPL, and never reaches one. The
192
- help is the command reference; this file does not repeat it. If you know playwright-cli, its command
193
- names work too (`help playwright-cli` lists them).
190
+ gives usage and caveats: read it before you use a command, since this file does not repeat them. `help
191
+ --all` prints everything at once. pw-repl answers help itself: it needs no running REPL, and never
192
+ reaches one. If you know playwright-cli, its command names work too (`help playwright-cli` lists them).
194
193
 
195
194
  ### Coming from playwright-cli
196
195
 
@@ -252,12 +251,12 @@ pw-repl send -c <name> close # your modes off; tab close
252
251
  - Playwright's own Chromium and ffmpeg are found where Playwright installs them:
253
252
  `PLAYWRIGHT_BROWSERS_PATH`, or `~/.cache/ms-playwright`.
254
253
  - `PW_CDP_URL` — CDP endpoint (default `http://localhost:9222`).
255
- - `PW_SCREENSHOT_DIR` — where the REPL saves screenshots, read when it starts, not by `send`. Without
256
- it, a REPL on a socket of its own saves them next to its socket, and any other in `/tmp`. `screenshot`
257
- prints each file's path; other REPLs may save theirs in the same place. Remove only your own, and keep
258
- those too if they are needed, e.g. as evidence or as something to hand over.
254
+ - `PW_SCREENSHOT_DIR` — where the REPL saves screenshots (a folder that exists), read when it starts,
255
+ not by `send`. Without it, a REPL on a socket of its own saves them next to its socket, and any other
256
+ in `/tmp`. `screenshot` prints each file's path; other REPLs may save theirs in the same place. Remove
257
+ only your own, and keep those too if they are needed, e.g. as evidence or as something to hand over.
259
258
  - `PW_ENDPOINT` / `PW_TMUX_SESSION` — defaults for `send -e` / `-s`. `PW_SOCKET` — the socket `serve`
260
- serves on and `send` looks for when neither is given (default `/tmp/playwright-repl.sock`).
259
+ serves on and `send` looks for when neither is given (default `/tmp/pw-repl.sock`).
261
260
 
262
261
  ## Custom rules
263
262