agent-browser 0.3.7 → 0.4.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/README.md +151 -32
- package/bin/agent-browser +13 -2
- package/bin/agent-browser-darwin-arm64 +0 -0
- package/bin/agent-browser-darwin-x64 +0 -0
- package/bin/agent-browser-linux-arm64 +0 -0
- package/bin/agent-browser-linux-x64 +0 -0
- package/bin/agent-browser-win32-x64.exe +0 -0
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +104 -19
- package/dist/actions.js.map +1 -1
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +9 -3
- package/dist/browser.js.map +1 -1
- package/dist/daemon.d.ts +16 -1
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +80 -9
- package/dist/daemon.js.map +1 -1
- package/dist/snapshot.d.ts +2 -0
- package/dist/snapshot.d.ts.map +1 -1
- package/dist/snapshot.js +67 -4
- package/dist/snapshot.js.map +1 -1
- package/package.json +28 -10
- package/scripts/sync-version.js +43 -0
- package/skills/browsing-web/SKILL.md +143 -0
- package/dist/cli-light.d.ts +0 -11
- package/dist/cli-light.d.ts.map +0 -1
- package/dist/cli-light.js +0 -409
- package/dist/cli-light.js.map +0 -1
- package/dist/client.d.ts +0 -17
- package/dist/client.d.ts.map +0 -1
- package/dist/client.js +0 -133
- package/dist/client.js.map +0 -1
- package/dist/index.d.ts +0 -3
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -1163
- package/dist/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,13 +1,33 @@
|
|
|
1
1
|
# agent-browser
|
|
2
2
|
|
|
3
|
-
Headless browser automation CLI for AI agents.
|
|
3
|
+
Headless browser automation CLI for AI agents. Fast Rust CLI with Node.js fallback.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
|
+
### npm (recommended)
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g agent-browser
|
|
11
|
+
agent-browser install # Download Chromium
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
### From Source
|
|
15
|
+
|
|
7
16
|
```bash
|
|
17
|
+
git clone https://github.com/vercel-labs/agent-browser
|
|
18
|
+
cd agent-browser
|
|
8
19
|
pnpm install
|
|
9
|
-
npx playwright install chromium
|
|
10
20
|
pnpm build
|
|
21
|
+
agent-browser install
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Linux Dependencies
|
|
25
|
+
|
|
26
|
+
On Linux, install system dependencies:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
agent-browser install --with-deps
|
|
30
|
+
# or manually: npx playwright install-deps chromium
|
|
11
31
|
```
|
|
12
32
|
|
|
13
33
|
## Quick Start
|
|
@@ -44,17 +64,14 @@ agent-browser fill <sel> <text> # Clear and fill
|
|
|
44
64
|
agent-browser press <key> # Press key (Enter, Tab, Control+a)
|
|
45
65
|
agent-browser keydown <key> # Hold key down
|
|
46
66
|
agent-browser keyup <key> # Release key
|
|
47
|
-
agent-browser insert <text> # Insert text (no key events)
|
|
48
67
|
agent-browser hover <sel> # Hover element
|
|
49
68
|
agent-browser select <sel> <val> # Select dropdown option
|
|
50
|
-
agent-browser multiselect <sel> <v1> <v2> # Multi-select
|
|
51
69
|
agent-browser check <sel> # Check checkbox
|
|
52
70
|
agent-browser uncheck <sel> # Uncheck checkbox
|
|
53
71
|
agent-browser scroll <dir> [px] # Scroll (up/down/left/right)
|
|
54
|
-
agent-browser
|
|
72
|
+
agent-browser scrollintoview <sel> # Scroll element into view
|
|
55
73
|
agent-browser drag <src> <tgt> # Drag and drop
|
|
56
74
|
agent-browser upload <sel> <files> # Upload files
|
|
57
|
-
agent-browser download [path] # Wait for download
|
|
58
75
|
agent-browser screenshot [path] # Take screenshot (--full for full page)
|
|
59
76
|
agent-browser pdf <path> # Save as PDF
|
|
60
77
|
agent-browser snapshot # Accessibility tree with refs (best for AI)
|
|
@@ -140,14 +157,14 @@ agent-browser set geo <lat> <lng> # Set geolocation
|
|
|
140
157
|
agent-browser set offline [on|off] # Toggle offline mode
|
|
141
158
|
agent-browser set headers <json> # Extra HTTP headers
|
|
142
159
|
agent-browser set credentials <u> <p> # HTTP basic auth
|
|
143
|
-
agent-browser set media [dark|light
|
|
160
|
+
agent-browser set media [dark|light] # Emulate color scheme
|
|
144
161
|
```
|
|
145
162
|
|
|
146
163
|
### Cookies & Storage
|
|
147
164
|
|
|
148
165
|
```bash
|
|
149
166
|
agent-browser cookies # Get all cookies
|
|
150
|
-
agent-browser cookies set <
|
|
167
|
+
agent-browser cookies set <name> <val> # Set cookie
|
|
151
168
|
agent-browser cookies clear # Clear cookies
|
|
152
169
|
|
|
153
170
|
agent-browser storage local # Get all localStorage
|
|
@@ -167,14 +184,13 @@ agent-browser network route <url> --body <json> # Mock response
|
|
|
167
184
|
agent-browser network unroute [url] # Remove routes
|
|
168
185
|
agent-browser network requests # View tracked requests
|
|
169
186
|
agent-browser network requests --filter api # Filter requests
|
|
170
|
-
agent-browser response <url> # Get response body (waits for matching request)
|
|
171
187
|
```
|
|
172
188
|
|
|
173
189
|
### Tabs & Windows
|
|
174
190
|
|
|
175
191
|
```bash
|
|
176
192
|
agent-browser tab # List tabs
|
|
177
|
-
agent-browser tab new
|
|
193
|
+
agent-browser tab new [url] # New tab (optionally with URL)
|
|
178
194
|
agent-browser tab <n> # Switch to tab n
|
|
179
195
|
agent-browser tab close [n] # Close tab
|
|
180
196
|
agent-browser window new # New window
|
|
@@ -197,15 +213,15 @@ agent-browser dialog dismiss # Dismiss
|
|
|
197
213
|
### Debug
|
|
198
214
|
|
|
199
215
|
```bash
|
|
200
|
-
agent-browser trace start
|
|
201
|
-
agent-browser trace stop
|
|
216
|
+
agent-browser trace start [path] # Start recording trace
|
|
217
|
+
agent-browser trace stop [path] # Stop and save trace
|
|
202
218
|
agent-browser console # View console messages
|
|
203
219
|
agent-browser console --clear # Clear console
|
|
204
220
|
agent-browser errors # View page errors
|
|
221
|
+
agent-browser errors --clear # Clear errors
|
|
205
222
|
agent-browser highlight <sel> # Highlight element
|
|
206
223
|
agent-browser state save <path> # Save auth state
|
|
207
224
|
agent-browser state load <path> # Load auth state
|
|
208
|
-
agent-browser initscript <js> # Run JS on every page load
|
|
209
225
|
```
|
|
210
226
|
|
|
211
227
|
### Navigation
|
|
@@ -216,25 +232,13 @@ agent-browser forward # Go forward
|
|
|
216
232
|
agent-browser reload # Reload page
|
|
217
233
|
```
|
|
218
234
|
|
|
219
|
-
###
|
|
235
|
+
### Setup
|
|
220
236
|
|
|
221
237
|
```bash
|
|
222
|
-
agent-browser
|
|
223
|
-
agent-browser
|
|
238
|
+
agent-browser install # Download Chromium browser
|
|
239
|
+
agent-browser install --with-deps # Also install system deps (Linux)
|
|
224
240
|
```
|
|
225
241
|
|
|
226
|
-
## Options
|
|
227
|
-
|
|
228
|
-
| Option | Description |
|
|
229
|
-
|--------|-------------|
|
|
230
|
-
| `--session <name>` | Use isolated session (or `AGENT_BROWSER_SESSION` env) |
|
|
231
|
-
| `--json` | JSON output (for agents) |
|
|
232
|
-
| `--full, -f` | Full page screenshot |
|
|
233
|
-
| `--name, -n` | Locator name filter |
|
|
234
|
-
| `--exact` | Exact text match |
|
|
235
|
-
| `--headed` | Show browser window (not headless) |
|
|
236
|
-
| `--debug` | Debug output |
|
|
237
|
-
|
|
238
242
|
## Sessions
|
|
239
243
|
|
|
240
244
|
Run multiple isolated browser instances:
|
|
@@ -244,13 +248,54 @@ Run multiple isolated browser instances:
|
|
|
244
248
|
agent-browser --session agent1 open site-a.com
|
|
245
249
|
agent-browser --session agent2 open site-b.com
|
|
246
250
|
|
|
247
|
-
# Or via environment
|
|
251
|
+
# Or via environment variable
|
|
248
252
|
AGENT_BROWSER_SESSION=agent1 agent-browser click "#btn"
|
|
249
253
|
|
|
250
|
-
# List
|
|
254
|
+
# List active sessions
|
|
251
255
|
agent-browser session list
|
|
256
|
+
|
|
257
|
+
# Show current session
|
|
258
|
+
agent-browser session
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Each session has its own:
|
|
262
|
+
- Browser instance
|
|
263
|
+
- Cookies and storage
|
|
264
|
+
- Navigation history
|
|
265
|
+
- Authentication state
|
|
266
|
+
|
|
267
|
+
## Snapshot Options
|
|
268
|
+
|
|
269
|
+
The `snapshot` command supports filtering to reduce output size:
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
agent-browser snapshot # Full accessibility tree
|
|
273
|
+
agent-browser snapshot -i # Interactive elements only (buttons, inputs, links)
|
|
274
|
+
agent-browser snapshot -c # Compact (remove empty structural elements)
|
|
275
|
+
agent-browser snapshot -d 3 # Limit depth to 3 levels
|
|
276
|
+
agent-browser snapshot -s "#main" # Scope to CSS selector
|
|
277
|
+
agent-browser snapshot -i -c -d 5 # Combine options
|
|
252
278
|
```
|
|
253
279
|
|
|
280
|
+
| Option | Description |
|
|
281
|
+
|--------|-------------|
|
|
282
|
+
| `-i, --interactive` | Only show interactive elements (buttons, links, inputs) |
|
|
283
|
+
| `-c, --compact` | Remove empty structural elements |
|
|
284
|
+
| `-d, --depth <n>` | Limit tree depth |
|
|
285
|
+
| `-s, --selector <sel>` | Scope to CSS selector |
|
|
286
|
+
|
|
287
|
+
## Options
|
|
288
|
+
|
|
289
|
+
| Option | Description |
|
|
290
|
+
|--------|-------------|
|
|
291
|
+
| `--session <name>` | Use isolated session (or `AGENT_BROWSER_SESSION` env) |
|
|
292
|
+
| `--json` | JSON output (for agents) |
|
|
293
|
+
| `--full, -f` | Full page screenshot |
|
|
294
|
+
| `--name, -n` | Locator name filter |
|
|
295
|
+
| `--exact` | Exact text match |
|
|
296
|
+
| `--headed` | Show browser window (not headless) |
|
|
297
|
+
| `--debug` | Debug output |
|
|
298
|
+
|
|
254
299
|
## Selectors
|
|
255
300
|
|
|
256
301
|
### Refs (Recommended for AI)
|
|
@@ -317,7 +362,7 @@ agent-browser is visible @e2 --json
|
|
|
317
362
|
```bash
|
|
318
363
|
# 1. Navigate and get snapshot
|
|
319
364
|
agent-browser open example.com
|
|
320
|
-
agent-browser snapshot --json
|
|
365
|
+
agent-browser snapshot -i --json # AI parses tree and refs
|
|
321
366
|
|
|
322
367
|
# 2. AI identifies target refs from snapshot
|
|
323
368
|
# 3. Execute actions using refs
|
|
@@ -325,7 +370,81 @@ agent-browser click @e2
|
|
|
325
370
|
agent-browser fill @e3 "input text"
|
|
326
371
|
|
|
327
372
|
# 4. Get new snapshot if page changed
|
|
328
|
-
agent-browser snapshot --json
|
|
373
|
+
agent-browser snapshot -i --json
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
## Headed Mode
|
|
377
|
+
|
|
378
|
+
Show the browser window for debugging:
|
|
379
|
+
|
|
380
|
+
```bash
|
|
381
|
+
agent-browser open example.com --headed
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
This opens a visible browser window instead of running headless.
|
|
385
|
+
|
|
386
|
+
## Architecture
|
|
387
|
+
|
|
388
|
+
agent-browser uses a client-daemon architecture:
|
|
389
|
+
|
|
390
|
+
1. **Rust CLI** (fast native binary) - Parses commands, communicates with daemon
|
|
391
|
+
2. **Node.js Daemon** - Manages Playwright browser instance
|
|
392
|
+
3. **Fallback** - If native binary unavailable, uses Node.js directly
|
|
393
|
+
|
|
394
|
+
The daemon starts automatically on first command and persists between commands for fast subsequent operations.
|
|
395
|
+
|
|
396
|
+
## Platforms
|
|
397
|
+
|
|
398
|
+
| Platform | Binary | Fallback |
|
|
399
|
+
|----------|--------|----------|
|
|
400
|
+
| macOS ARM64 | ✅ Native Rust | Node.js |
|
|
401
|
+
| macOS x64 | ✅ Native Rust | Node.js |
|
|
402
|
+
| Linux ARM64 | ✅ Native Rust | Node.js |
|
|
403
|
+
| Linux x64 | ✅ Native Rust | Node.js |
|
|
404
|
+
| Windows | - | Node.js |
|
|
405
|
+
|
|
406
|
+
## Usage with AI Agents
|
|
407
|
+
|
|
408
|
+
### Just ask the agent
|
|
409
|
+
|
|
410
|
+
The simplest approach - just tell your agent to use it:
|
|
411
|
+
|
|
412
|
+
```
|
|
413
|
+
Use agent-browser to test the login flow. Run agent-browser --help to see available commands.
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
The `--help` output is comprehensive and most agents can figure it out from there.
|
|
417
|
+
|
|
418
|
+
### AGENTS.md / CLAUDE.md
|
|
419
|
+
|
|
420
|
+
For more consistent results, add to your project or global instructions file:
|
|
421
|
+
|
|
422
|
+
```markdown
|
|
423
|
+
## Browser Automation
|
|
424
|
+
|
|
425
|
+
Use `agent-browser` for web automation. Run `agent-browser --help` for all commands.
|
|
426
|
+
|
|
427
|
+
Core workflow:
|
|
428
|
+
1. `agent-browser open <url>` - Navigate to page
|
|
429
|
+
2. `agent-browser snapshot -i` - Get interactive elements with refs (@e1, @e2)
|
|
430
|
+
3. `agent-browser click @e1` / `fill @e2 "text"` - Interact using refs
|
|
431
|
+
4. Re-snapshot after page changes
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
### Claude Code Skill
|
|
435
|
+
|
|
436
|
+
For Claude Code, a [skill](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices) provides richer context:
|
|
437
|
+
|
|
438
|
+
```bash
|
|
439
|
+
cp -r node_modules/agent-browser/skills/browsing-web .claude/skills/
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
Or download:
|
|
443
|
+
|
|
444
|
+
```bash
|
|
445
|
+
mkdir -p .claude/skills/browsing-web
|
|
446
|
+
curl -o .claude/skills/browsing-web/SKILL.md \
|
|
447
|
+
https://raw.githubusercontent.com/vercel-labs/agent-browser/main/skills/browsing-web/SKILL.md
|
|
329
448
|
```
|
|
330
449
|
|
|
331
450
|
## License
|
package/bin/agent-browser
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
|
+
# agent-browser CLI wrapper
|
|
3
|
+
# Detects OS/arch and runs the appropriate native binary
|
|
4
|
+
|
|
2
5
|
SCRIPT="$0"
|
|
3
6
|
while [ -L "$SCRIPT" ]; do
|
|
4
7
|
SCRIPT_DIR="$(cd "$(dirname "$SCRIPT")" && pwd)"
|
|
@@ -6,10 +9,18 @@ while [ -L "$SCRIPT" ]; do
|
|
|
6
9
|
case "$SCRIPT" in /*) ;; *) SCRIPT="$SCRIPT_DIR/$SCRIPT" ;; esac
|
|
7
10
|
done
|
|
8
11
|
SCRIPT_DIR="$(cd "$(dirname "$SCRIPT")" && pwd)"
|
|
12
|
+
|
|
9
13
|
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
|
|
10
14
|
ARCH=$(uname -m)
|
|
11
15
|
case "$OS" in darwin) OS="darwin" ;; linux) OS="linux" ;; mingw*|msys*|cygwin*) OS="win32" ;; esac
|
|
12
16
|
case "$ARCH" in x86_64|amd64) ARCH="x64" ;; aarch64|arm64) ARCH="arm64" ;; esac
|
|
17
|
+
|
|
13
18
|
BINARY="$SCRIPT_DIR/agent-browser-${OS}-${ARCH}"
|
|
14
|
-
|
|
15
|
-
|
|
19
|
+
|
|
20
|
+
if [ -f "$BINARY" ] && [ -x "$BINARY" ]; then
|
|
21
|
+
exec "$BINARY" "$@"
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
echo "Error: No binary found for ${OS}-${ARCH}" >&2
|
|
25
|
+
echo "Run 'npm run build:native' to build for your platform" >&2
|
|
26
|
+
exit 1
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/dist/actions.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EACV,OAAO,EACP,QAAQ,EAoGT,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EACV,OAAO,EACP,QAAQ,EAoGT,MAAM,YAAY,CAAC;AAkDpB;;GAEG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,QAAQ,CAAC,CAiPjG"}
|
package/dist/actions.js
CHANGED
|
@@ -1,4 +1,31 @@
|
|
|
1
1
|
import { successResponse, errorResponse } from './protocol.js';
|
|
2
|
+
/**
|
|
3
|
+
* Convert Playwright errors to AI-friendly messages
|
|
4
|
+
*/
|
|
5
|
+
function toAIFriendlyError(error, selector) {
|
|
6
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
7
|
+
// Handle strict mode violation (multiple elements match)
|
|
8
|
+
if (message.includes('strict mode violation')) {
|
|
9
|
+
// Extract count if available
|
|
10
|
+
const countMatch = message.match(/resolved to (\d+) elements/);
|
|
11
|
+
const count = countMatch ? countMatch[1] : 'multiple';
|
|
12
|
+
return new Error(`Selector "${selector}" matched ${count} elements. ` +
|
|
13
|
+
`Run 'snapshot' to get updated refs, or use a more specific CSS selector.`);
|
|
14
|
+
}
|
|
15
|
+
// Handle element not found
|
|
16
|
+
if (message.includes('waiting for') &&
|
|
17
|
+
(message.includes('to be visible') || message.includes('Timeout'))) {
|
|
18
|
+
return new Error(`Element "${selector}" not found or not visible. ` +
|
|
19
|
+
`Run 'snapshot' to see current page elements.`);
|
|
20
|
+
}
|
|
21
|
+
// Handle element not interactable
|
|
22
|
+
if (message.includes('intercepts pointer events') || message.includes('not visible')) {
|
|
23
|
+
return new Error(`Element "${selector}" is not interactable (may be hidden or covered). ` +
|
|
24
|
+
`Try scrolling it into view or check if a modal/overlay is blocking it.`);
|
|
25
|
+
}
|
|
26
|
+
// Return original error for unknown cases
|
|
27
|
+
return error instanceof Error ? error : new Error(message);
|
|
28
|
+
}
|
|
2
29
|
/**
|
|
3
30
|
* Execute a command and return a response
|
|
4
31
|
*/
|
|
@@ -262,21 +289,31 @@ async function handleNavigate(command, browser) {
|
|
|
262
289
|
async function handleClick(command, browser) {
|
|
263
290
|
// Support both refs (@e1) and regular selectors
|
|
264
291
|
const locator = browser.getLocator(command.selector);
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
292
|
+
try {
|
|
293
|
+
await locator.click({
|
|
294
|
+
button: command.button,
|
|
295
|
+
clickCount: command.clickCount,
|
|
296
|
+
delay: command.delay,
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
catch (error) {
|
|
300
|
+
throw toAIFriendlyError(error, command.selector);
|
|
301
|
+
}
|
|
270
302
|
return successResponse(command.id, { clicked: true });
|
|
271
303
|
}
|
|
272
304
|
async function handleType(command, browser) {
|
|
273
305
|
const locator = browser.getLocator(command.selector);
|
|
274
|
-
|
|
275
|
-
|
|
306
|
+
try {
|
|
307
|
+
if (command.clear) {
|
|
308
|
+
await locator.fill('');
|
|
309
|
+
}
|
|
310
|
+
await locator.pressSequentially(command.text, {
|
|
311
|
+
delay: command.delay,
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
catch (error) {
|
|
315
|
+
throw toAIFriendlyError(error, command.selector);
|
|
276
316
|
}
|
|
277
|
-
await locator.pressSequentially(command.text, {
|
|
278
|
-
delay: command.delay,
|
|
279
|
-
});
|
|
280
317
|
return successResponse(command.id, { typed: true });
|
|
281
318
|
}
|
|
282
319
|
async function handlePress(command, browser) {
|
|
@@ -391,12 +428,22 @@ async function handleScroll(command, browser) {
|
|
|
391
428
|
async function handleSelect(command, browser) {
|
|
392
429
|
const locator = browser.getLocator(command.selector);
|
|
393
430
|
const values = Array.isArray(command.values) ? command.values : [command.values];
|
|
394
|
-
|
|
431
|
+
try {
|
|
432
|
+
await locator.selectOption(values);
|
|
433
|
+
}
|
|
434
|
+
catch (error) {
|
|
435
|
+
throw toAIFriendlyError(error, command.selector);
|
|
436
|
+
}
|
|
395
437
|
return successResponse(command.id, { selected: values });
|
|
396
438
|
}
|
|
397
439
|
async function handleHover(command, browser) {
|
|
398
440
|
const locator = browser.getLocator(command.selector);
|
|
399
|
-
|
|
441
|
+
try {
|
|
442
|
+
await locator.hover();
|
|
443
|
+
}
|
|
444
|
+
catch (error) {
|
|
445
|
+
throw toAIFriendlyError(error, command.selector);
|
|
446
|
+
}
|
|
400
447
|
return successResponse(command.id, { hovered: true });
|
|
401
448
|
}
|
|
402
449
|
async function handleContent(command, browser) {
|
|
@@ -444,33 +491,63 @@ async function handleWindowNew(command, browser) {
|
|
|
444
491
|
// New handlers for enhanced Playwright parity
|
|
445
492
|
async function handleFill(command, browser) {
|
|
446
493
|
const locator = browser.getLocator(command.selector);
|
|
447
|
-
|
|
494
|
+
try {
|
|
495
|
+
await locator.fill(command.value);
|
|
496
|
+
}
|
|
497
|
+
catch (error) {
|
|
498
|
+
throw toAIFriendlyError(error, command.selector);
|
|
499
|
+
}
|
|
448
500
|
return successResponse(command.id, { filled: true });
|
|
449
501
|
}
|
|
450
502
|
async function handleCheck(command, browser) {
|
|
451
503
|
const locator = browser.getLocator(command.selector);
|
|
452
|
-
|
|
504
|
+
try {
|
|
505
|
+
await locator.check();
|
|
506
|
+
}
|
|
507
|
+
catch (error) {
|
|
508
|
+
throw toAIFriendlyError(error, command.selector);
|
|
509
|
+
}
|
|
453
510
|
return successResponse(command.id, { checked: true });
|
|
454
511
|
}
|
|
455
512
|
async function handleUncheck(command, browser) {
|
|
456
513
|
const locator = browser.getLocator(command.selector);
|
|
457
|
-
|
|
514
|
+
try {
|
|
515
|
+
await locator.uncheck();
|
|
516
|
+
}
|
|
517
|
+
catch (error) {
|
|
518
|
+
throw toAIFriendlyError(error, command.selector);
|
|
519
|
+
}
|
|
458
520
|
return successResponse(command.id, { unchecked: true });
|
|
459
521
|
}
|
|
460
522
|
async function handleUpload(command, browser) {
|
|
461
523
|
const locator = browser.getLocator(command.selector);
|
|
462
524
|
const files = Array.isArray(command.files) ? command.files : [command.files];
|
|
463
|
-
|
|
525
|
+
try {
|
|
526
|
+
await locator.setInputFiles(files);
|
|
527
|
+
}
|
|
528
|
+
catch (error) {
|
|
529
|
+
throw toAIFriendlyError(error, command.selector);
|
|
530
|
+
}
|
|
464
531
|
return successResponse(command.id, { uploaded: files });
|
|
465
532
|
}
|
|
466
533
|
async function handleDoubleClick(command, browser) {
|
|
467
534
|
const locator = browser.getLocator(command.selector);
|
|
468
|
-
|
|
535
|
+
try {
|
|
536
|
+
await locator.dblclick();
|
|
537
|
+
}
|
|
538
|
+
catch (error) {
|
|
539
|
+
throw toAIFriendlyError(error, command.selector);
|
|
540
|
+
}
|
|
469
541
|
return successResponse(command.id, { clicked: true });
|
|
470
542
|
}
|
|
471
543
|
async function handleFocus(command, browser) {
|
|
472
544
|
const locator = browser.getLocator(command.selector);
|
|
473
|
-
|
|
545
|
+
try {
|
|
546
|
+
await locator.focus();
|
|
547
|
+
}
|
|
548
|
+
catch (error) {
|
|
549
|
+
throw toAIFriendlyError(error, command.selector);
|
|
550
|
+
}
|
|
474
551
|
return successResponse(command.id, { focused: true });
|
|
475
552
|
}
|
|
476
553
|
async function handleDrag(command, browser) {
|
|
@@ -556,7 +633,15 @@ async function handleCookiesGet(command, browser) {
|
|
|
556
633
|
async function handleCookiesSet(command, browser) {
|
|
557
634
|
const page = browser.getPage();
|
|
558
635
|
const context = page.context();
|
|
559
|
-
|
|
636
|
+
// Auto-fill URL for cookies that don't have domain/path/url set
|
|
637
|
+
const pageUrl = page.url();
|
|
638
|
+
const cookies = command.cookies.map((cookie) => {
|
|
639
|
+
if (!cookie.url && !cookie.domain && !cookie.path) {
|
|
640
|
+
return { ...cookie, url: pageUrl };
|
|
641
|
+
}
|
|
642
|
+
return cookie;
|
|
643
|
+
});
|
|
644
|
+
await context.addCookies(cookies);
|
|
560
645
|
return successResponse(command.id, { set: true });
|
|
561
646
|
}
|
|
562
647
|
async function handleCookiesClear(command, browser) {
|