surf-cli 2.5.2 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -3
- package/dist/content/accessibility-tree.js +8 -8
- package/dist/content/accessibility-tree.js.map +1 -1
- package/dist/content/visual-indicator.js +17 -17
- package/dist/content/visual-indicator.js.map +1 -1
- package/dist/manifest.json +1 -1
- package/dist/service-worker/index.js +27 -27
- package/dist/service-worker/index.js.map +1 -1
- package/native/aistudio-build.cjs +562 -0
- package/native/aistudio-client.cjs +502 -0
- package/native/aistudio-model.cjs +225 -0
- package/native/aistudio-parser.cjs +424 -0
- package/native/aistudio-response.cjs +336 -0
- package/native/cli.cjs +95 -14
- package/native/do-executor.cjs +1 -1
- package/native/gemini-client.cjs +304 -63
- package/native/host-helpers.cjs +29 -0
- package/native/host.cjs +261 -14
- package/native/mcp-server.cjs +1 -1
- package/native/network-store.cjs +3 -1
- package/package.json +10 -9
- package/scripts/install-native-host.cjs +14 -2
- package/scripts/uninstall-native-host.cjs +7 -1
- package/skills/README.md +21 -0
- package/skills/surf/SKILL.md +575 -0
|
@@ -0,0 +1,575 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: surf
|
|
3
|
+
description: Control Chrome browser via CLI for testing, automation, and debugging. Use when the user needs browser automation, screenshots, form filling, page inspection, network/CPU emulation, DevTools streaming, or AI queries via ChatGPT/Gemini/Perplexity/Grok/AI Studio.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Surf Browser Automation
|
|
7
|
+
|
|
8
|
+
Control Chrome browser via CLI or Unix socket.
|
|
9
|
+
|
|
10
|
+
## CLI Quick Reference
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
surf --help # Full help
|
|
14
|
+
surf <group> # Group help (tab, scroll, page, wait, dialog, emulate, form, perf, ai)
|
|
15
|
+
surf --help-full # All commands
|
|
16
|
+
surf --find <term> # Search tools
|
|
17
|
+
surf --help-topic <topic> # Topic guide (refs, semantic, frames, devices, windows)
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Core Workflow
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# 1. Navigate to page
|
|
24
|
+
surf navigate "https://example.com"
|
|
25
|
+
|
|
26
|
+
# 2. Read page to get element refs
|
|
27
|
+
surf page.read
|
|
28
|
+
|
|
29
|
+
# 3. Click by ref or coordinates
|
|
30
|
+
surf click --ref "e1"
|
|
31
|
+
surf click --x 100 --y 200
|
|
32
|
+
|
|
33
|
+
# 4. Type text
|
|
34
|
+
surf type --text "hello"
|
|
35
|
+
|
|
36
|
+
# 5. Screenshot
|
|
37
|
+
surf screenshot --output /tmp/shot.png
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## AI Assistants (No API Keys)
|
|
41
|
+
|
|
42
|
+
Query AI models using your browser's logged-in session. Must be logged into the respective service in Chrome.
|
|
43
|
+
|
|
44
|
+
### ChatGPT
|
|
45
|
+
```bash
|
|
46
|
+
surf chatgpt "explain this code"
|
|
47
|
+
surf chatgpt "summarize" --with-page # Include current page context
|
|
48
|
+
surf chatgpt "review" --model gpt-4o # Specify model
|
|
49
|
+
surf chatgpt "analyze" --file document.pdf # With file attachment
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Gemini
|
|
53
|
+
```bash
|
|
54
|
+
surf gemini "explain quantum computing"
|
|
55
|
+
surf gemini "summarize" --with-page # Include page context
|
|
56
|
+
surf gemini "analyze" --file data.csv # Attach file
|
|
57
|
+
surf gemini "a robot surfing" --generate-image /tmp/robot.png
|
|
58
|
+
surf gemini "add sunglasses" --edit-image photo.jpg --output out.jpg
|
|
59
|
+
surf gemini "summarize" --youtube "https://youtube.com/..."
|
|
60
|
+
surf gemini "hello" --model gemini-2.5-flash # Models: gemini-3-pro (default), gemini-2.5-pro, gemini-2.5-flash
|
|
61
|
+
surf gemini "wide banner" --generate-image /tmp/banner.png --aspect-ratio 16:9
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Perplexity
|
|
65
|
+
```bash
|
|
66
|
+
surf perplexity "what is quantum computing"
|
|
67
|
+
surf perplexity "explain this page" --with-page # Include page context
|
|
68
|
+
surf perplexity "deep dive" --mode research # Research mode (Pro)
|
|
69
|
+
surf perplexity "latest news" --model sonar # Model selection (Pro)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Grok (via x.com - requires X.com login in Chrome)
|
|
73
|
+
```bash
|
|
74
|
+
surf grok "what are the latest AI trends on X" # Search X posts
|
|
75
|
+
surf grok "analyze @username recent activity" # Profile analysis
|
|
76
|
+
surf grok "summarize this page" --with-page # Include page context
|
|
77
|
+
surf grok "find viral AI posts" --deep-search # DeepSearch mode
|
|
78
|
+
surf grok "quick question" --model fast # Models: auto, fast, expert, thinking (default)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Grok Validation & Troubleshooting:**
|
|
82
|
+
```bash
|
|
83
|
+
# Validate Grok UI and check available models (no query sent)
|
|
84
|
+
surf grok --validate
|
|
85
|
+
|
|
86
|
+
# If models changed, save discovered models to surf.json config
|
|
87
|
+
surf grok --validate --save-models
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### AI Studio (via aistudio.google.com - requires Google login in Chrome)
|
|
91
|
+
```bash
|
|
92
|
+
surf aistudio "explain quantum computing"
|
|
93
|
+
surf aistudio "redteam this" --with-page # Include current page context
|
|
94
|
+
surf aistudio "quick answer" --model gemini-3-flash-preview # Model selection
|
|
95
|
+
surf aistudio "analyze" --timeout 600 # Custom timeout (default: 300s)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**Why AI Studio over Gemini?** AI Studio gives access to less restricted Gemini models. For Gemini 3 Pro the difference can be significant with certain prompts. Downside: aggressive per-day rate limits on Pro and Flash models.
|
|
99
|
+
|
|
100
|
+
**Model selection is best-effort:** Pass any AI Studio model id (e.g. `gemini-3.1-pro-preview`, `gemini-3-flash-preview`, `gemini-flash-lite-latest`). If the model isn't found, AI Studio uses whatever model was last selected in the UI.
|
|
101
|
+
|
|
102
|
+
### AI Studio App Builder
|
|
103
|
+
```bash
|
|
104
|
+
surf aistudio.build "build a portfolio site"
|
|
105
|
+
surf aistudio.build "todo app" --model gemini-3.1-pro-preview # Model override
|
|
106
|
+
surf aistudio.build "crm dashboard" --output ./out # Extract zip to directory
|
|
107
|
+
surf aistudio.build "game" --keep-open --timeout 600 # Keep tab open, 10min timeout
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Automates AI Studio's App Builder at `aistudio.google.com/apps`. Types your prompt, clicks Build, waits for completion, downloads the generated zip, and optionally extracts it.
|
|
111
|
+
|
|
112
|
+
- `--output <dir>` extracts the zip to a directory
|
|
113
|
+
- `--model <id>` overrides the model in Advanced Settings
|
|
114
|
+
- `--timeout <seconds>` build timeout (default: 600s)
|
|
115
|
+
- `--keep-open` leaves the AI Studio tab open after completion
|
|
116
|
+
|
|
117
|
+
Returns `zipPath`, `extractedPath`, `model`, `buildDuration`, and `tookMs`.
|
|
118
|
+
|
|
119
|
+
### AI Tool Troubleshooting
|
|
120
|
+
|
|
121
|
+
When AI queries fail, check these common issues:
|
|
122
|
+
|
|
123
|
+
1. **Not logged in**: The error "login required" means you need to log into the service in Chrome (chatgpt.com, gemini.google.com, perplexity.ai, x.com, or aistudio.google.com)
|
|
124
|
+
2. **Model selection failed**: The UI may have changed. Run `surf grok --validate` to check
|
|
125
|
+
3. **Response timeout**: Thinking models (ChatGPT o1, Grok thinking) can take 45+ seconds. AI Studio builds can take several minutes.
|
|
126
|
+
4. **Element not found**: The service's UI changed. Check for surf-cli updates
|
|
127
|
+
|
|
128
|
+
**Debugging workflow for agents:**
|
|
129
|
+
```bash
|
|
130
|
+
# 1. Check if the service is accessible and UI is valid
|
|
131
|
+
surf grok --validate
|
|
132
|
+
|
|
133
|
+
# 2. If models mismatch, update the local settings
|
|
134
|
+
surf grok --validate --save-models
|
|
135
|
+
|
|
136
|
+
# 3. Retry with explicit model name from validation output
|
|
137
|
+
surf grok "query" --model <model-from-validation>
|
|
138
|
+
|
|
139
|
+
# 4. If still failing, try with longer timeout
|
|
140
|
+
surf grok "query" --timeout 600
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Tab Management
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
surf tab.list
|
|
147
|
+
surf tab.new "https://google.com"
|
|
148
|
+
surf tab.switch 12345
|
|
149
|
+
surf tab.close 12345
|
|
150
|
+
surf tab.reload # Reload current tab
|
|
151
|
+
|
|
152
|
+
# Named tabs (aliases)
|
|
153
|
+
surf tab.name myapp # Name current tab
|
|
154
|
+
surf tab.switch myapp # Switch by name
|
|
155
|
+
surf tab.named # List named tabs
|
|
156
|
+
surf tab.unname myapp # Remove name
|
|
157
|
+
|
|
158
|
+
# Tab groups
|
|
159
|
+
surf tab.group # Create/add to tab group
|
|
160
|
+
surf tab.ungroup # Remove from group
|
|
161
|
+
surf tab.groups # List all tab groups
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Window Management
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
surf window.list # List all windows
|
|
168
|
+
surf window.list --tabs # Include tab details
|
|
169
|
+
surf window.new # New window
|
|
170
|
+
surf window.new --url "https://example.com" # New window with URL
|
|
171
|
+
surf window.new --incognito # New incognito window
|
|
172
|
+
surf window.new --unfocused # Don't focus new window
|
|
173
|
+
surf window.focus 12345 # Focus window by ID
|
|
174
|
+
surf window.close 12345 # Close window
|
|
175
|
+
surf window.resize --id 123 --width 1920 --height 1080
|
|
176
|
+
surf window.resize --id 123 --state maximized # States: normal, minimized, maximized, fullscreen
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**Window isolation for agents:**
|
|
180
|
+
```bash
|
|
181
|
+
# Create isolated window for agent work
|
|
182
|
+
surf window.new "https://example.com"
|
|
183
|
+
# Returns window ID, use with subsequent commands:
|
|
184
|
+
surf --window-id 123 tab.list
|
|
185
|
+
surf --window-id 123 go "https://other.com"
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Input Methods
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
# CDP method (real events) - default
|
|
192
|
+
surf type --text "hello"
|
|
193
|
+
surf click --x 100 --y 200
|
|
194
|
+
|
|
195
|
+
# JS method (DOM manipulation) - for contenteditable
|
|
196
|
+
surf type --text "hello" --selector "#input" --method js
|
|
197
|
+
|
|
198
|
+
# Keys
|
|
199
|
+
surf key Enter
|
|
200
|
+
surf key "cmd+a"
|
|
201
|
+
surf key.repeat --key Tab --count 5 # Repeat key presses
|
|
202
|
+
|
|
203
|
+
# Hover and drag
|
|
204
|
+
surf hover --ref e5
|
|
205
|
+
surf drag --from-x 100 --from-y 100 --to-x 200 --to-y 200
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Page Inspection
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
surf page.read # Accessibility tree with refs + page text
|
|
212
|
+
surf page.read --no-text # Interactive elements only (no text content)
|
|
213
|
+
surf page.read --ref e5 # Get specific element details
|
|
214
|
+
surf page.read --depth 3 # Limit tree depth
|
|
215
|
+
surf page.read --compact # Minimal output for LLM efficiency
|
|
216
|
+
surf page.text # Plain text content only
|
|
217
|
+
surf page.state # Modals, loading state, scroll info
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Semantic Element Location
|
|
221
|
+
|
|
222
|
+
Find and act on elements by role, text, or label instead of refs:
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
# Find by ARIA role
|
|
226
|
+
surf locate.role button --name "Submit" --action click
|
|
227
|
+
surf locate.role textbox --name "Email" --action fill --value "test@example.com"
|
|
228
|
+
surf locate.role link --all # Return all matches
|
|
229
|
+
|
|
230
|
+
# Find by text content
|
|
231
|
+
surf locate.text "Sign In" --action click
|
|
232
|
+
surf locate.text "Accept" --exact --action click
|
|
233
|
+
|
|
234
|
+
# Find form field by label
|
|
235
|
+
surf locate.label "Username" --action fill --value "john"
|
|
236
|
+
surf locate.label "Password" --action fill --value "secret"
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
**Actions:** `click`, `fill`, `hover`, `text` (get text content)
|
|
240
|
+
|
|
241
|
+
## Text Search
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
surf search "login" # Find text in page
|
|
245
|
+
surf search "Error" --case-sensitive # Case-sensitive
|
|
246
|
+
surf search "button" --limit 5 # Limit results
|
|
247
|
+
surf find "login" # Alias for search
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Element Inspection
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
surf element.styles e5 # Get computed styles by ref
|
|
254
|
+
surf element.styles ".card" # Or by CSS selector
|
|
255
|
+
# Returns: font, color, background, border, padding, bounding box
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Scrolling
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
surf scroll.bottom
|
|
262
|
+
surf scroll.top
|
|
263
|
+
surf scroll.to --y 500 # Scroll to Y position
|
|
264
|
+
surf scroll.to --ref e5 # Scroll element into view
|
|
265
|
+
surf scroll.by --y 200 # Scroll by amount
|
|
266
|
+
surf scroll.info # Get scroll position
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## Waiting
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
surf wait 2 # Wait 2 seconds
|
|
273
|
+
surf wait.element ".loaded" # Wait for element
|
|
274
|
+
surf wait.network # Wait for network idle
|
|
275
|
+
surf wait.url "/success" # Wait for URL pattern
|
|
276
|
+
surf wait.dom --stable 100 # Wait for DOM stability
|
|
277
|
+
surf wait.load # Wait for page load complete
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
## Dialog Handling
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
surf dialog.info # Get current dialog type/message
|
|
284
|
+
surf dialog.accept # Accept (OK)
|
|
285
|
+
surf dialog.accept --text "response" # Accept prompt with text
|
|
286
|
+
surf dialog.dismiss # Dismiss (Cancel)
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## Device/Network Emulation
|
|
290
|
+
|
|
291
|
+
```bash
|
|
292
|
+
# Network throttling
|
|
293
|
+
surf emulate.network slow-3g # Presets: slow-3g, fast-3g, 4g, offline
|
|
294
|
+
surf emulate.network reset # Disable throttling
|
|
295
|
+
|
|
296
|
+
# CPU throttling
|
|
297
|
+
surf emulate.cpu 4 # 4x slower
|
|
298
|
+
surf emulate.cpu 1 # Reset
|
|
299
|
+
|
|
300
|
+
# Device emulation (19 presets)
|
|
301
|
+
surf emulate.device "iPhone 14"
|
|
302
|
+
surf emulate.device "Pixel 7"
|
|
303
|
+
surf emulate.device --list # List available devices
|
|
304
|
+
|
|
305
|
+
# Custom viewport
|
|
306
|
+
surf emulate.viewport --width 1280 --height 720
|
|
307
|
+
surf emulate.touch --enable # Enable touch emulation
|
|
308
|
+
|
|
309
|
+
# Geolocation
|
|
310
|
+
surf emulate.geo --lat 37.7749 --lon -122.4194
|
|
311
|
+
surf emulate.geo --clear
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## Form Automation
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
surf page.read # Get element refs first
|
|
318
|
+
|
|
319
|
+
# Fill by ref
|
|
320
|
+
surf form.fill --data '[{"ref":"e1","value":"John"},{"ref":"e2","value":"john@example.com"}]'
|
|
321
|
+
|
|
322
|
+
# Checkboxes: true/false
|
|
323
|
+
surf form.fill --data '[{"ref":"e7","value":true}]'
|
|
324
|
+
|
|
325
|
+
# Dropdown selection
|
|
326
|
+
surf select e5 "Option A" # By value (default)
|
|
327
|
+
surf select e5 "Option A" "Option B" # Multi-select
|
|
328
|
+
surf select e5 --by label "Display Text" # By visible label
|
|
329
|
+
surf select e5 --by index 2 # By index (0-based)
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
## File Upload
|
|
333
|
+
|
|
334
|
+
```bash
|
|
335
|
+
surf upload --ref e5 --files "/path/to/file.txt"
|
|
336
|
+
surf upload --ref e5 --files "/path/file1.txt,/path/file2.txt"
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
## Iframe Handling
|
|
340
|
+
|
|
341
|
+
```bash
|
|
342
|
+
surf frame.list # List frames with IDs
|
|
343
|
+
surf frame.switch "FRAME_ID" # Switch to iframe context
|
|
344
|
+
surf frame.main # Return to main frame
|
|
345
|
+
surf frame.js --id "FRAME_ID" --code "return document.title"
|
|
346
|
+
|
|
347
|
+
# After frame.switch, subsequent commands target that frame:
|
|
348
|
+
surf frame.switch "iframe-1"
|
|
349
|
+
surf page.read # Reads iframe content
|
|
350
|
+
surf click e5 # Clicks in iframe
|
|
351
|
+
surf frame.main # Back to main page
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
## Network Inspection
|
|
355
|
+
|
|
356
|
+
```bash
|
|
357
|
+
surf network # List captured requests
|
|
358
|
+
surf network --stream # Real-time network events
|
|
359
|
+
surf network.get --id "req-123" # Full request details
|
|
360
|
+
surf network.body --id "req-123" # Get response body
|
|
361
|
+
surf network.curl --id "req-123" # Generate curl command
|
|
362
|
+
surf network.origins # List origins with stats
|
|
363
|
+
surf network.stats # Capture statistics
|
|
364
|
+
surf network.export # Export all requests
|
|
365
|
+
surf network.clear # Clear captured requests
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
## Console
|
|
369
|
+
|
|
370
|
+
```bash
|
|
371
|
+
surf console # Get console messages
|
|
372
|
+
surf console --stream # Real-time console
|
|
373
|
+
surf console --stream --level error # Errors only
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
## JavaScript Execution
|
|
377
|
+
|
|
378
|
+
```bash
|
|
379
|
+
surf js "return document.title"
|
|
380
|
+
surf js "document.querySelector('.btn').click()"
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
## Performance
|
|
384
|
+
|
|
385
|
+
```bash
|
|
386
|
+
surf perf.metrics # Current metrics snapshot
|
|
387
|
+
surf perf.start # Start trace
|
|
388
|
+
surf perf.stop # Stop and get results
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
## Screenshots
|
|
392
|
+
|
|
393
|
+
```bash
|
|
394
|
+
surf screenshot # Auto-saves to /tmp/surf-snap-*.png
|
|
395
|
+
surf screenshot --output /tmp/shot.png # Save to specific file
|
|
396
|
+
surf screenshot --selector ".card" # Element only
|
|
397
|
+
surf screenshot --full-page # Full page scroll capture
|
|
398
|
+
surf screenshot --no-save # Return base64 only, don't save file
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
## Zoom
|
|
402
|
+
|
|
403
|
+
```bash
|
|
404
|
+
surf zoom # Get current zoom level
|
|
405
|
+
surf zoom 1.5 # Set zoom to 150%
|
|
406
|
+
surf zoom 1 # Reset to 100%
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
## Cookies & Storage
|
|
410
|
+
|
|
411
|
+
```bash
|
|
412
|
+
surf cookie.list # List cookies for current page
|
|
413
|
+
surf cookie.list --domain .google.com
|
|
414
|
+
surf cookie.set --name "token" --value "abc123"
|
|
415
|
+
surf cookie.get --name "token"
|
|
416
|
+
surf cookie.clear # Clear all cookies
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
## History & Bookmarks
|
|
420
|
+
|
|
421
|
+
```bash
|
|
422
|
+
surf history --query "github" --max 20
|
|
423
|
+
surf bookmarks --query "docs"
|
|
424
|
+
surf bookmark.add --url "https://..." --title "My Bookmark"
|
|
425
|
+
surf bookmark.remove
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
## Health Checks & Smoke Tests
|
|
429
|
+
|
|
430
|
+
```bash
|
|
431
|
+
surf health --url "http://localhost:3000"
|
|
432
|
+
surf smoke --urls "http://localhost:3000" "http://localhost:3000/about"
|
|
433
|
+
surf smoke --urls "..." --screenshot /tmp/smoke
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
## Workflows
|
|
437
|
+
|
|
438
|
+
Execute multi-step browser automation as a single command with smart auto-waits.
|
|
439
|
+
|
|
440
|
+
### Inline Workflows
|
|
441
|
+
|
|
442
|
+
```bash
|
|
443
|
+
# Pipe-separated commands
|
|
444
|
+
surf do 'go "https://example.com" | click e5 | screenshot'
|
|
445
|
+
|
|
446
|
+
# Multi-step login flow
|
|
447
|
+
surf do 'go "https://example.com/login" | type "user@example.com" --selector "#email" | type "pass" --selector "#password" | click --selector "button[type=submit]"'
|
|
448
|
+
|
|
449
|
+
# Validate without executing
|
|
450
|
+
surf do 'go "url" | click e5' --dry-run
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
### Named Workflows
|
|
454
|
+
|
|
455
|
+
Save workflows as JSON files in `~/.surf/workflows/` (user) or `./.surf/workflows/` (project):
|
|
456
|
+
|
|
457
|
+
```bash
|
|
458
|
+
# List available workflows
|
|
459
|
+
surf workflow.list
|
|
460
|
+
|
|
461
|
+
# Show workflow details
|
|
462
|
+
surf workflow.info my-workflow
|
|
463
|
+
|
|
464
|
+
# Run by name with arguments
|
|
465
|
+
surf do my-workflow --email "user@example.com" --password "secret"
|
|
466
|
+
|
|
467
|
+
# Validate workflow file
|
|
468
|
+
surf workflow.validate workflow.json
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
### Workflow JSON Format
|
|
472
|
+
|
|
473
|
+
```json
|
|
474
|
+
{
|
|
475
|
+
"name": "Login Flow",
|
|
476
|
+
"description": "Automate login process",
|
|
477
|
+
"args": {
|
|
478
|
+
"email": { "required": true },
|
|
479
|
+
"password": { "required": true },
|
|
480
|
+
"url": { "default": "https://example.com/login" }
|
|
481
|
+
},
|
|
482
|
+
"steps": [
|
|
483
|
+
{ "tool": "navigate", "args": { "url": "%{url}" } },
|
|
484
|
+
{ "tool": "type", "args": { "text": "%{email}", "selector": "input[name=email]" } },
|
|
485
|
+
{ "tool": "type", "args": { "text": "%{password}", "selector": "input[name=password]" } },
|
|
486
|
+
{ "tool": "click", "args": { "selector": "button[type=submit]" } },
|
|
487
|
+
{ "tool": "screenshot", "args": {}, "as": "result" }
|
|
488
|
+
]
|
|
489
|
+
}
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
### Loops and Step Outputs
|
|
493
|
+
|
|
494
|
+
```json
|
|
495
|
+
{
|
|
496
|
+
"steps": [
|
|
497
|
+
// Capture step output for later use
|
|
498
|
+
{ "tool": "js", "args": { "code": "return [1,2,3]" }, "as": "items" },
|
|
499
|
+
|
|
500
|
+
// Fixed iterations
|
|
501
|
+
{ "repeat": 5, "steps": [
|
|
502
|
+
{ "tool": "click", "args": { "ref": "e5" } }
|
|
503
|
+
]},
|
|
504
|
+
|
|
505
|
+
// Iterate over array
|
|
506
|
+
{ "each": "%{items}", "as": "item", "steps": [
|
|
507
|
+
{ "tool": "js", "args": { "code": "console.log('%{item}')" } }
|
|
508
|
+
]},
|
|
509
|
+
|
|
510
|
+
// Repeat until condition
|
|
511
|
+
{ "repeat": 20, "until": { "tool": "js", "args": { "code": "return done" } }, "steps": [...] }
|
|
512
|
+
]
|
|
513
|
+
}
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
### Workflow Options
|
|
517
|
+
|
|
518
|
+
```bash
|
|
519
|
+
--file, -f <path> # Load from JSON file
|
|
520
|
+
--dry-run # Parse and validate without executing
|
|
521
|
+
--on-error stop|continue # Error handling (default: stop)
|
|
522
|
+
--step-delay <ms> # Delay between steps (default: 100, 0 to disable)
|
|
523
|
+
--no-auto-wait # Disable automatic waits
|
|
524
|
+
--json # Structured JSON output
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
**Auto-waits:** Commands automatically wait for completion:
|
|
528
|
+
- Navigation (`go`, `back`, `forward`) → waits for page load
|
|
529
|
+
- Clicks, key presses, form fills → waits for DOM stability
|
|
530
|
+
- Tab switches → waits for tab to load
|
|
531
|
+
|
|
532
|
+
**Why use `do`?** Instead of 6-8 separate CLI calls with LLM orchestration between each, a workflow executes deterministically. Faster, cheaper, and more reliable.
|
|
533
|
+
|
|
534
|
+
## Error Diagnostics
|
|
535
|
+
|
|
536
|
+
```bash
|
|
537
|
+
# Auto-capture screenshot + console on failure
|
|
538
|
+
surf wait.element ".missing" --auto-capture --timeout 2000
|
|
539
|
+
# Saves to /tmp/surf-error-*.png
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
## Common Options
|
|
543
|
+
|
|
544
|
+
```bash
|
|
545
|
+
--tab-id <id> # Target specific tab
|
|
546
|
+
--window-id <id> # Target specific window
|
|
547
|
+
--json # Raw JSON output
|
|
548
|
+
--auto-capture # Screenshot + console on error
|
|
549
|
+
--timeout <ms> # Override default timeout
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
## Tips
|
|
553
|
+
|
|
554
|
+
1. **First CDP operation is slow** (~5-8s) - debugger attachment overhead, subsequent calls fast
|
|
555
|
+
2. **Use refs from page.read** for reliable element targeting over CSS selectors
|
|
556
|
+
3. **JS method for contenteditable** - Modern editors (ChatGPT, Claude, Notion) need `--method js`
|
|
557
|
+
4. **Named tabs for workflows** - `tab.name app` then `tab.switch app`
|
|
558
|
+
5. **Auto-capture for debugging** - `--auto-capture` saves diagnostics on failure
|
|
559
|
+
6. **AI tools use browser session** - Must be logged into the service (ChatGPT, Gemini, Perplexity, Grok, AI Studio), no API keys needed
|
|
560
|
+
7. **Grok validation** - Run `surf grok --validate` if queries fail to check UI changes
|
|
561
|
+
8. **Long timeouts for thinking models** - ChatGPT o1, Grok thinking can take 60+ seconds. AI Studio builds default to 600s.
|
|
562
|
+
9. **AI Studio for unrestricted Gemini** - `surf aistudio` gives less filtered responses than `surf gemini` for the same models
|
|
563
|
+
10. **Use `surf do` for multi-step tasks** - Reduces token overhead and improves reliability
|
|
564
|
+
11. **Dry-run workflows first** - `surf do '...' --dry-run` validates without executing
|
|
565
|
+
12. **Window isolation** - Use `window.new` + `--window-id` to keep agent work separate from your browsing
|
|
566
|
+
13. **Semantic locators** - `locate.role`, `locate.text`, `locate.label` for more robust element finding
|
|
567
|
+
14. **Frame context** - Use `frame.switch` before interacting with iframe content
|
|
568
|
+
|
|
569
|
+
## Socket API
|
|
570
|
+
|
|
571
|
+
For programmatic access:
|
|
572
|
+
|
|
573
|
+
```bash
|
|
574
|
+
echo '{"type":"tool_request","method":"execute_tool","params":{"tool":"tab.list","args":{}},"id":"1"}' | nc -U /tmp/surf.sock
|
|
575
|
+
```
|