@web-auto/camo 0.2.0 → 0.2.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/LICENSE +21 -21
- package/README.md +586 -586
- package/bin/browser-service.mjs +11 -11
- package/bin/camo.mjs +22 -22
- package/package.json +48 -48
- package/scripts/build.mjs +19 -19
- package/scripts/bump-version.mjs +34 -34
- package/scripts/check-file-size.mjs +80 -80
- package/scripts/file-size-policy.json +12 -2
- package/scripts/install.mjs +76 -76
- package/scripts/release.sh +54 -54
- package/src/autoscript/action-providers/index.mjs +6 -6
- package/src/autoscript/impact-engine.mjs +78 -78
- package/src/autoscript/runtime.mjs +1017 -1017
- package/src/autoscript/schema.mjs +376 -376
- package/src/cli.mjs +405 -405
- package/src/commands/attach.mjs +141 -141
- package/src/commands/autoscript.mjs +1011 -1011
- package/src/commands/browser.mjs +1255 -1255
- package/src/commands/container.mjs +401 -401
- package/src/commands/cookies.mjs +69 -69
- package/src/commands/create.mjs +98 -98
- package/src/commands/devtools.mjs +349 -349
- package/src/commands/events.mjs +152 -152
- package/src/commands/highlight-mode.mjs +24 -24
- package/src/commands/init.mjs +68 -68
- package/src/commands/lifecycle.mjs +275 -275
- package/src/commands/mouse.mjs +45 -45
- package/src/commands/profile.mjs +46 -46
- package/src/commands/record.mjs +115 -115
- package/src/commands/system.mjs +14 -14
- package/src/commands/window.mjs +123 -123
- package/src/container/change-notifier.mjs +362 -362
- package/src/container/element-filter.mjs +143 -143
- package/src/container/index.mjs +3 -3
- package/src/container/runtime-core/checkpoint.mjs +209 -209
- package/src/container/runtime-core/index.mjs +21 -21
- package/src/container/runtime-core/operations/index.mjs +774 -774
- package/src/container/runtime-core/operations/selector-scripts.mjs +277 -277
- package/src/container/runtime-core/operations/tab-pool.mjs +746 -746
- package/src/container/runtime-core/operations/viewport.mjs +189 -189
- package/src/container/runtime-core/search.mjs +190 -190
- package/src/container/runtime-core/subscription.mjs +224 -224
- package/src/container/runtime-core/utils.mjs +94 -94
- package/src/container/runtime-core/validation.mjs +127 -127
- package/src/container/runtime-core.mjs +1 -1
- package/src/container/subscription-registry.mjs +459 -459
- package/src/core/actions.mjs +561 -561
- package/src/core/browser.mjs +266 -266
- package/src/core/index.mjs +52 -52
- package/src/core/utils.mjs +91 -91
- package/src/events/daemon-entry.mjs +33 -33
- package/src/events/daemon.mjs +80 -80
- package/src/events/progress-log.mjs +109 -109
- package/src/events/ws-server.mjs +239 -239
- package/src/lib/client.mjs +200 -200
- package/src/lifecycle/cleanup.mjs +83 -83
- package/src/lifecycle/lock.mjs +126 -126
- package/src/lifecycle/session-registry.mjs +279 -279
- package/src/lifecycle/session-view.mjs +76 -76
- package/src/lifecycle/session-watchdog.mjs +281 -281
- package/src/services/browser-service/index.js +671 -671
- package/src/services/browser-service/internal/BrowserSession.input.test.js +389 -389
- package/src/services/browser-service/internal/BrowserSession.js +325 -304
- package/src/services/browser-service/internal/ElementRegistry.js +60 -60
- package/src/services/browser-service/internal/ProfileLock.js +84 -84
- package/src/services/browser-service/internal/SessionManager.js +184 -184
- package/src/services/browser-service/internal/SessionManager.test.js +39 -39
- package/src/services/browser-service/internal/browser-session/cookies.js +144 -144
- package/src/services/browser-service/internal/browser-session/input-ops.js +222 -222
- package/src/services/browser-service/internal/browser-session/input-pipeline.js +144 -144
- package/src/services/browser-service/internal/browser-session/logging.js +46 -46
- package/src/services/browser-service/internal/browser-session/navigation.js +38 -38
- package/src/services/browser-service/internal/browser-session/page-hooks.js +442 -442
- package/src/services/browser-service/internal/browser-session/page-management.js +302 -302
- package/src/services/browser-service/internal/browser-session/page-management.test.js +148 -148
- package/src/services/browser-service/internal/browser-session/recording.js +198 -198
- package/src/services/browser-service/internal/browser-session/runtime-events.js +61 -61
- package/src/services/browser-service/internal/browser-session/session-core.js +84 -84
- package/src/services/browser-service/internal/browser-session/session-state.js +38 -38
- package/src/services/browser-service/internal/browser-session/types.js +14 -14
- package/src/services/browser-service/internal/browser-session/utils.js +95 -95
- package/src/services/browser-service/internal/browser-session/viewport-manager.js +46 -46
- package/src/services/browser-service/internal/browser-session/viewport.js +215 -215
- package/src/services/browser-service/internal/container-matcher.js +851 -851
- package/src/services/browser-service/internal/container-registry.js +182 -182
- package/src/services/browser-service/internal/engine-manager.js +259 -259
- package/src/services/browser-service/internal/fingerprint.js +203 -203
- package/src/services/browser-service/internal/heartbeat.js +137 -137
- package/src/services/browser-service/internal/logging.js +46 -46
- package/src/services/browser-service/internal/page-runtime/runtime.js +1317 -1317
- package/src/services/browser-service/internal/pageRuntime.js +28 -28
- package/src/services/browser-service/internal/runtimeInjector.js +31 -31
- package/src/services/browser-service/internal/service-process-logger.js +140 -140
- package/src/services/browser-service/internal/state-bus.js +45 -45
- package/src/services/browser-service/internal/storage-paths.js +42 -42
- package/src/services/browser-service/internal/ws-server.js +1194 -1194
- package/src/services/browser-service/internal/ws-server.test.js +58 -58
- package/src/services/browser-service/server.mjs +6 -6
- package/src/services/controller/cli-bridge.js +93 -93
- package/src/services/controller/container-index.js +50 -50
- package/src/services/controller/container-storage.js +36 -36
- package/src/services/controller/controller-actions.js +207 -207
- package/src/services/controller/controller.js +1138 -1138
- package/src/services/controller/selectors.js +54 -54
- package/src/services/controller/transport.js +125 -125
- package/src/utils/args.mjs +26 -26
- package/src/utils/browser-service.mjs +544 -544
- package/src/utils/command-log.mjs +64 -64
- package/src/utils/config.mjs +214 -214
- package/src/utils/fingerprint.mjs +181 -181
- package/src/utils/help.mjs +216 -216
- package/src/utils/js-policy.mjs +13 -13
- package/src/utils/ws-client.mjs +30 -30
package/README.md
CHANGED
|
@@ -1,586 +1,586 @@
|
|
|
1
|
-
# Camo CLI
|
|
2
|
-
|
|
3
|
-
[](https://github.com/Jasonzhangf/camo/actions/workflows/ci.yml)
|
|
4
|
-
[](https://www.npmjs.com/package/@web-auto/camo)
|
|
5
|
-
|
|
6
|
-
A cross-platform command-line interface for Camoufox browser automation.
|
|
7
|
-
|
|
8
|
-
## What Camo Provides
|
|
9
|
-
|
|
10
|
-
- Browser lifecycle management: start/stop/list sessions, idle cleanup, lock cleanup.
|
|
11
|
-
- Profile-first automation: persistent profile dirs, fingerprint support, remembered window size.
|
|
12
|
-
- Browser control primitives: navigation, tabs, viewport/window, mouse and keyboard actions.
|
|
13
|
-
- Devtools debugging helpers: open devtools, evaluate JS quickly, collect browser console logs.
|
|
14
|
-
- Session recorder: JSONL interaction capture (click/input/scroll/keyboard + page visits) with runtime toggle.
|
|
15
|
-
- Container subscription layer: selector registration, filter/list/watch in viewport.
|
|
16
|
-
- Autoscript runtime: validate/explain/run/resume/mock-run with snapshot and replay.
|
|
17
|
-
- Progress stream: local websocket daemon (`/events`) with tail/recent/emit commands.
|
|
18
|
-
|
|
19
|
-
## Installation
|
|
20
|
-
|
|
21
|
-
### npm (Recommended)
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
npm install -g @web-auto/camo
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
### From Source
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
git clone https://github.com/Jasonzhangf/camo.git
|
|
31
|
-
cd camo
|
|
32
|
-
npm run build:global
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## Quick Start
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
# Initialize environment
|
|
39
|
-
camo init
|
|
40
|
-
|
|
41
|
-
# Create a profile
|
|
42
|
-
camo profile create myprofile
|
|
43
|
-
|
|
44
|
-
# Set as default
|
|
45
|
-
camo profile default myprofile
|
|
46
|
-
|
|
47
|
-
# Start browser (with alias)
|
|
48
|
-
camo start --url https://example.com --alias main
|
|
49
|
-
|
|
50
|
-
# Start headless worker (auto-kill after idle timeout)
|
|
51
|
-
camo start worker-1 --headless --alias shard1 --idle-timeout 30m
|
|
52
|
-
|
|
53
|
-
# Start with devtools (headful only)
|
|
54
|
-
camo start worker-1 --devtools
|
|
55
|
-
|
|
56
|
-
# Evaluate JS (devtools-style input in page context)
|
|
57
|
-
camo devtools eval worker-1 "document.title"
|
|
58
|
-
|
|
59
|
-
# Read captured console entries
|
|
60
|
-
camo devtools logs worker-1 --levels error,warn --limit 50
|
|
61
|
-
|
|
62
|
-
# Start recording into JSONL (with in-page toggle)
|
|
63
|
-
camo record start worker-1 --name run-a --output ./logs/run-a.jsonl --overlay
|
|
64
|
-
|
|
65
|
-
# Navigate
|
|
66
|
-
camo goto https://www.xiaohongshu.com
|
|
67
|
-
|
|
68
|
-
# Interact
|
|
69
|
-
camo highlight-mode on
|
|
70
|
-
camo click "#search-input" --highlight
|
|
71
|
-
camo type "#search-input" "hello world" --highlight
|
|
72
|
-
camo scroll --down --amount 500 --selector ".feed-list"
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
## Codex Skill (`camoufox`)
|
|
76
|
-
|
|
77
|
-
This repository includes a Codex skill at `skills/camoufox`.
|
|
78
|
-
|
|
79
|
-
Install or refresh it locally:
|
|
80
|
-
|
|
81
|
-
```bash
|
|
82
|
-
mkdir -p ~/.codex/skills
|
|
83
|
-
rsync -a ./skills/camoufox/ ~/.codex/skills/camoufox/
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
Use it in Codex with `$camoufox` (or by asking for camo CLI workflows directly).
|
|
87
|
-
|
|
88
|
-
Layered capability model:
|
|
89
|
-
- Observe/Debug: visible DOM filtering, URL/context checks, devtools eval/logs.
|
|
90
|
-
- User Ops: click/type/scroll/keyboard/tab/window operations with optional highlight.
|
|
91
|
-
- Orchestration: container subscription + autoscript flows.
|
|
92
|
-
- Progress/Recovery: events/status/cleanup for runtime diagnostics.
|
|
93
|
-
|
|
94
|
-
## Core Workflows
|
|
95
|
-
|
|
96
|
-
### 1) Interactive browser session
|
|
97
|
-
|
|
98
|
-
```bash
|
|
99
|
-
camo init
|
|
100
|
-
camo profile create myprofile
|
|
101
|
-
camo profile default myprofile
|
|
102
|
-
camo start --url https://example.com --alias main
|
|
103
|
-
camo click "#search-input"
|
|
104
|
-
camo type "#search-input" "hello world"
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
### 2) Headless worker with idle auto-stop
|
|
108
|
-
|
|
109
|
-
```bash
|
|
110
|
-
camo start worker-1 --headless --alias shard1 --idle-timeout 30m
|
|
111
|
-
camo instances
|
|
112
|
-
camo stop idle
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
### 3) Devtools-style debugging
|
|
116
|
-
|
|
117
|
-
```bash
|
|
118
|
-
camo start myprofile --devtools
|
|
119
|
-
camo devtools eval myprofile "document.title"
|
|
120
|
-
camo devtools eval myprofile "(console.error('check-error'), location.href)"
|
|
121
|
-
camo devtools logs myprofile --levels error,warn --limit 50
|
|
122
|
-
camo devtools clear myprofile
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
### 4) Run autoscript with live progress
|
|
126
|
-
|
|
127
|
-
```bash
|
|
128
|
-
camo autoscript validate ./autoscripts/xhs.autoscript.json
|
|
129
|
-
camo autoscript run ./autoscripts/xhs.autoscript.json --profile myprofile \
|
|
130
|
-
--jsonl-file ./runs/xhs/run.jsonl \
|
|
131
|
-
--summary-file ./runs/xhs/summary.json
|
|
132
|
-
camo events tail --profile myprofile --mode autoscript
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
### 5) Record manual interactions as JSONL
|
|
136
|
-
|
|
137
|
-
```bash
|
|
138
|
-
camo start myprofile --record --record-name xhs-debug --record-output ./logs/xhs-debug.jsonl --record-overlay
|
|
139
|
-
camo record status myprofile
|
|
140
|
-
camo record stop myprofile
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
## Commands
|
|
144
|
-
|
|
145
|
-
### Profile Management
|
|
146
|
-
|
|
147
|
-
```bash
|
|
148
|
-
camo profiles # List profiles with default profile
|
|
149
|
-
camo profile create <profileId> # Create a profile
|
|
150
|
-
camo profile delete <profileId> # Delete a profile
|
|
151
|
-
camo profile default [profileId] # Get or set default profile
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
### Initialization
|
|
155
|
-
|
|
156
|
-
```bash
|
|
157
|
-
camo init # Ensure camoufox + browser-service
|
|
158
|
-
camo init geoip # Download GeoIP database
|
|
159
|
-
camo init list # List available OS and regions
|
|
160
|
-
camo create fingerprint --os <os> --region <region>
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
### Config
|
|
164
|
-
|
|
165
|
-
```bash
|
|
166
|
-
camo config repo-root [path] # Get/set persisted camo repo root
|
|
167
|
-
camo highlight-mode [status|on|off] # Global highlight mode for click/type/scroll
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
### Browser Control
|
|
171
|
-
|
|
172
|
-
```bash
|
|
173
|
-
camo start [profileId] [--url <url>] [--headless] [--devtools] [--record] [--record-name <name>] [--record-output <path>] [--record-overlay|--no-record-overlay] [--alias <name>] [--idle-timeout <duration>] [--width <w> --height <h>]
|
|
174
|
-
camo stop [profileId]
|
|
175
|
-
camo stop --id <instanceId>
|
|
176
|
-
camo stop --alias <alias>
|
|
177
|
-
camo stop idle
|
|
178
|
-
camo stop all
|
|
179
|
-
camo status [profileId] # Show resolved per-profile session view
|
|
180
|
-
camo shutdown # Shutdown browser-service (all sessions)
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
`camo start` in headful mode now persists window size per profile and reuses that size on next start.
|
|
184
|
-
If no saved size exists, it defaults to near-fullscreen (full width, slight vertical reserve).
|
|
185
|
-
Use `--width/--height` to override and update the saved profile size.
|
|
186
|
-
For headless sessions, default idle timeout is `30m` (auto-stop on inactivity). Use `--idle-timeout` (e.g. `45m`, `1800s`, `0`) to customize.
|
|
187
|
-
Use `--devtools` to open browser developer tools in headed mode (cannot be combined with `--headless`).
|
|
188
|
-
Use `--record` to auto-enable JSONL recording at startup; `--record-name`, `--record-output`, and `--record-overlay` customize file naming/output and floating toggle UI.
|
|
189
|
-
Set `CAMO_BRING_TO_FRONT_MODE=never` to keep protocol-level input and page lifecycle operations from forcing the browser window to front during headed runs.
|
|
190
|
-
`CAMO_SKIP_BRING_TO_FRONT=1` remains supported as a legacy alias.
|
|
191
|
-
|
|
192
|
-
### Lifecycle & Cleanup
|
|
193
|
-
|
|
194
|
-
```bash
|
|
195
|
-
camo instances # List resolved session view (live + registered + idle state)
|
|
196
|
-
camo sessions # List resolved session view for all profiles
|
|
197
|
-
camo cleanup [profileId] # Cleanup only one profile (remote stop + local registry/lock/watchdog)
|
|
198
|
-
camo cleanup all # Cleanup all active sessions
|
|
199
|
-
camo cleanup locks # Cleanup stale lock files
|
|
200
|
-
camo force-stop [profileId] # Force stop only one profile (no alias/id targeting)
|
|
201
|
-
camo lock list # List active session locks
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
Session isolation rules:
|
|
205
|
-
- `profileId` is the lifecycle primary key across browser-service session, local registry, watchdog, and lock.
|
|
206
|
-
- `camo start/stop/cleanup/force-stop <profileId>` only target that exact profile and must not affect other profiles.
|
|
207
|
-
- `camo stop --id` and `camo stop --alias` are stop-only convenience selectors; `cleanup` and `force-stop` intentionally reject indirect targeting.
|
|
208
|
-
- `camo status`, `camo sessions`, and `camo instances` share the same resolved session view fields:
|
|
209
|
-
- `live`: browser-service currently has this profile session
|
|
210
|
-
- `registered`: local registry has metadata for this profile
|
|
211
|
-
- `orphaned`: registry exists but the service session is gone
|
|
212
|
-
- `needsRecovery`: registry still says active but browser-service no longer has that profile
|
|
213
|
-
|
|
214
|
-
Isolation examples:
|
|
215
|
-
|
|
216
|
-
```bash
|
|
217
|
-
# Observe both profiles independently
|
|
218
|
-
camo sessions
|
|
219
|
-
camo status finger
|
|
220
|
-
camo status xhs-qa-1
|
|
221
|
-
|
|
222
|
-
# Stop only finger; xhs-qa-1 must remain live
|
|
223
|
-
camo stop finger
|
|
224
|
-
camo status finger
|
|
225
|
-
camo status xhs-qa-1
|
|
226
|
-
|
|
227
|
-
# cleanup / force-stop require direct profile targeting
|
|
228
|
-
camo cleanup finger
|
|
229
|
-
camo force-stop finger
|
|
230
|
-
|
|
231
|
-
# Invalid on purpose: indirect targeting is rejected
|
|
232
|
-
camo cleanup --alias shard1
|
|
233
|
-
camo force-stop --id inst_xxxxxxxx
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
### Navigation
|
|
237
|
-
|
|
238
|
-
```bash
|
|
239
|
-
camo goto [profileId] <url> # Navigate to URL
|
|
240
|
-
camo back [profileId] # Navigate back
|
|
241
|
-
camo screenshot [profileId] [--output <file>] [--full]
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
### Interaction
|
|
245
|
-
|
|
246
|
-
```bash
|
|
247
|
-
camo scroll [profileId] [--down|--up|--left|--right] [--amount <px>] [--selector <css>] [--highlight|--no-highlight]
|
|
248
|
-
camo click [profileId] <selector> [--highlight|--no-highlight] # Click visible element by CSS selector
|
|
249
|
-
camo type [profileId] <selector> <text> [--highlight|--no-highlight] # Type into visible input element
|
|
250
|
-
camo highlight [profileId] <selector> # Highlight element (red border, 2s)
|
|
251
|
-
camo clear-highlight [profileId] # Clear all highlights
|
|
252
|
-
camo viewport [profileId] --width <w> --height <h>
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
### Devtools
|
|
256
|
-
|
|
257
|
-
```bash
|
|
258
|
-
camo devtools logs [profileId] [--limit 120] [--since <unix_ms>] [--levels error,warn] [--clear]
|
|
259
|
-
camo devtools eval [profileId] <expression> [--profile <id>]
|
|
260
|
-
camo devtools clear [profileId]
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
`devtools logs` reads entries from an injected in-page console collector.
|
|
264
|
-
Supported levels: `log`, `info`, `warn`, `error`, `debug`.
|
|
265
|
-
|
|
266
|
-
### Recording
|
|
267
|
-
|
|
268
|
-
```bash
|
|
269
|
-
camo record start [profileId] [--name <name>] [--output <file>] [--overlay|--no-overlay]
|
|
270
|
-
camo record stop [profileId] [--reason <text>]
|
|
271
|
-
camo record status [profileId]
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
Recorder JSONL events include:
|
|
275
|
-
- `page.visit`
|
|
276
|
-
- `interaction.click`
|
|
277
|
-
- `interaction.keydown`
|
|
278
|
-
- `interaction.input`
|
|
279
|
-
- `interaction.wheel`
|
|
280
|
-
- `interaction.scroll`
|
|
281
|
-
- `recording.start|stop|toggled|runtime_ready`
|
|
282
|
-
|
|
283
|
-
### Pages
|
|
284
|
-
|
|
285
|
-
```bash
|
|
286
|
-
camo new-page [profileId] [--url <url>]
|
|
287
|
-
camo close-page [profileId] [index]
|
|
288
|
-
camo switch-page [profileId] <index>
|
|
289
|
-
camo list-pages [profileId] # Requires live=true for that profile
|
|
290
|
-
```
|
|
291
|
-
|
|
292
|
-
### Cookies
|
|
293
|
-
|
|
294
|
-
```bash
|
|
295
|
-
camo cookies get [profileId] Get all cookies for profile
|
|
296
|
-
camo cookies save [profileId] --path <file> Save cookies to file
|
|
297
|
-
camo cookies load [profileId] --path <file> Load cookies from file
|
|
298
|
-
camo cookies auto start [profileId] [--interval <ms>] Start auto-saving cookies
|
|
299
|
-
camo cookies auto stop [profileId] Stop auto-saving
|
|
300
|
-
camo cookies auto status [profileId] Check auto-save status
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
### Window Control
|
|
304
|
-
|
|
305
|
-
```bash
|
|
306
|
-
camo window move [profileId] --x <x> --y <y>
|
|
307
|
-
camo window resize [profileId] --width <w> --height <h>
|
|
308
|
-
```
|
|
309
|
-
|
|
310
|
-
### Mouse Control
|
|
311
|
-
|
|
312
|
-
```bash
|
|
313
|
-
camo mouse click [profileId] --x <x> --y <y> [--button left|right|middle] [--clicks <n>] [--delay <ms>]
|
|
314
|
-
camo mouse wheel [profileId] [--deltax <px>] [--deltay <px>]
|
|
315
|
-
```
|
|
316
|
-
|
|
317
|
-
### System
|
|
318
|
-
|
|
319
|
-
```bash
|
|
320
|
-
camo system display # Show display metrics
|
|
321
|
-
```
|
|
322
|
-
|
|
323
|
-
### Container Subscription
|
|
324
|
-
|
|
325
|
-
```bash
|
|
326
|
-
camo container init [--source <container-library-dir>] [--force]
|
|
327
|
-
camo container sets [--site <siteKey>]
|
|
328
|
-
camo container register [profileId] <setId...> [--append]
|
|
329
|
-
camo container targets [profileId]
|
|
330
|
-
camo container filter [profileId] <selector...>
|
|
331
|
-
camo container watch [profileId] [--selector <css>] [--throttle <ms>]
|
|
332
|
-
camo container list [profileId]
|
|
333
|
-
```
|
|
334
|
-
|
|
335
|
-
### Autoscript
|
|
336
|
-
|
|
337
|
-
```bash
|
|
338
|
-
camo autoscript validate <file>
|
|
339
|
-
camo autoscript explain <file>
|
|
340
|
-
camo autoscript snapshot <jsonl-file> [--out <snapshot-file>]
|
|
341
|
-
camo autoscript replay <jsonl-file> [--summary-file <path>]
|
|
342
|
-
camo autoscript run <file> [--profile <id>] [--jsonl-file <path>] [--summary-file <path>]
|
|
343
|
-
camo autoscript resume <file> --snapshot <snapshot-file> [--from-node <nodeId>] [--profile <id>] [--jsonl-file <path>] [--summary-file <path>]
|
|
344
|
-
camo autoscript mock-run <file> --fixture <fixture.json> [--profile <id>] [--jsonl-file <path>] [--summary-file <path>]
|
|
345
|
-
```
|
|
346
|
-
|
|
347
|
-
### Progress Events (WS)
|
|
348
|
-
|
|
349
|
-
```bash
|
|
350
|
-
camo events serve [--host 127.0.0.1] [--port 7788]
|
|
351
|
-
camo events tail [--profile <id>] [--run-id <id>] [--events e1,e2] [--replay 50]
|
|
352
|
-
camo events recent [--limit 50]
|
|
353
|
-
```
|
|
354
|
-
|
|
355
|
-
By default, non-`events` commands auto-start the progress daemon (`/events`) in background.
|
|
356
|
-
|
|
357
|
-
## Fingerprint Options
|
|
358
|
-
|
|
359
|
-
### OS Options
|
|
360
|
-
|
|
361
|
-
- `mac` (default) - macOS (auto architecture)
|
|
362
|
-
- `mac-m1` - macOS with Apple Silicon
|
|
363
|
-
- `mac-intel` - macOS with Intel
|
|
364
|
-
- `windows` - Windows 11
|
|
365
|
-
- `windows-10` - Windows 10
|
|
366
|
-
- `linux` - Ubuntu 22.04
|
|
367
|
-
|
|
368
|
-
### Region Options
|
|
369
|
-
|
|
370
|
-
- `us` (default) - United States (New York)
|
|
371
|
-
- `us-west` - United States (Los Angeles)
|
|
372
|
-
- `uk` - United Kingdom (London)
|
|
373
|
-
- `de` - Germany (Berlin)
|
|
374
|
-
- `fr` - France (Paris)
|
|
375
|
-
- `jp` - Japan (Tokyo)
|
|
376
|
-
- `sg` - Singapore
|
|
377
|
-
- `au` - Australia (Sydney)
|
|
378
|
-
- `hk` - Hong Kong
|
|
379
|
-
- `tw` - Taiwan (Taipei)
|
|
380
|
-
- `br` - Brazil (Sao Paulo)
|
|
381
|
-
- `in` - India (Mumbai)
|
|
382
|
-
|
|
383
|
-
## Configuration
|
|
384
|
-
|
|
385
|
-
- Config file: `~/.camo/camo-cli.json`
|
|
386
|
-
- Profiles directory: `~/.camo/profiles/`
|
|
387
|
-
- Fingerprints directory: `~/.camo/fingerprints/`
|
|
388
|
-
- Session registry: `~/.camo/sessions/`
|
|
389
|
-
- Lock files: `~/.camo/locks/`
|
|
390
|
-
- GeoIP database: `~/.camo/geoip/GeoLite2-City.mmdb`
|
|
391
|
-
- User container root: `~/.camo/container-lib/`
|
|
392
|
-
- Subscription root: `~/.camo/container-subscriptions/`
|
|
393
|
-
|
|
394
|
-
### Subscription-driven Watch
|
|
395
|
-
|
|
396
|
-
```bash
|
|
397
|
-
# 1) Migrate container-library into subscription sets
|
|
398
|
-
camo container init --source /Users/fanzhang/Documents/github/camo/container-library
|
|
399
|
-
|
|
400
|
-
# 2) Register sets to a profile
|
|
401
|
-
camo container register xiaohongshu-batch-1 xiaohongshu_home xiaohongshu_home.search_input
|
|
402
|
-
|
|
403
|
-
# 3) Start watch using registered selectors (no --selector needed)
|
|
404
|
-
camo container watch xiaohongshu-batch-1 --throttle 500
|
|
405
|
-
```
|
|
406
|
-
|
|
407
|
-
### Autoscript Mode (Subscription + Operations)
|
|
408
|
-
|
|
409
|
-
```bash
|
|
410
|
-
# Validate + explain + run
|
|
411
|
-
camo autoscript validate ./autoscripts/my-flow.autoscript.json
|
|
412
|
-
camo autoscript explain ./autoscripts/my-flow.autoscript.json
|
|
413
|
-
camo autoscript run ./autoscripts/my-flow.autoscript.json \
|
|
414
|
-
--profile my-profile \
|
|
415
|
-
--jsonl-file ./runs/my-flow/run.jsonl \
|
|
416
|
-
--summary-file ./runs/my-flow/run.summary.json
|
|
417
|
-
|
|
418
|
-
# Build snapshot + replay summary from existing JSONL
|
|
419
|
-
camo autoscript snapshot ./runs/my-flow/run.jsonl \
|
|
420
|
-
--out ./runs/my-flow/run.snapshot.json
|
|
421
|
-
camo autoscript replay ./runs/my-flow/run.jsonl \
|
|
422
|
-
--summary-file ./runs/my-flow/replay.summary.json
|
|
423
|
-
|
|
424
|
-
# Resume from a snapshot (optionally force rerun from a node)
|
|
425
|
-
camo autoscript resume ./autoscripts/my-flow.autoscript.json \
|
|
426
|
-
--snapshot ./runs/my-flow/run.snapshot.json \
|
|
427
|
-
--from-node some_operation \
|
|
428
|
-
--profile my-profile
|
|
429
|
-
|
|
430
|
-
# Mock replay mode for deterministic local debugging
|
|
431
|
-
camo autoscript mock-run ./autoscripts/my-flow.autoscript.json \
|
|
432
|
-
--fixture ./autoscripts/fixtures/mock-run.json \
|
|
433
|
-
--summary-file ./runs/my-flow/mock.summary.json
|
|
434
|
-
```
|
|
435
|
-
|
|
436
|
-
Example script:
|
|
437
|
-
|
|
438
|
-
```json
|
|
439
|
-
{
|
|
440
|
-
"name": "generic-login-flow",
|
|
441
|
-
"profileId": "my-profile",
|
|
442
|
-
"throttle": 500,
|
|
443
|
-
"subscriptions": [
|
|
444
|
-
{ "id": "login_input", "selector": "#login-input" },
|
|
445
|
-
{ "id": "submit_btn", "selector": "button.submit" }
|
|
446
|
-
],
|
|
447
|
-
"operations": [
|
|
448
|
-
{
|
|
449
|
-
"id": "fill_login",
|
|
450
|
-
"action": "type",
|
|
451
|
-
"selector": "#login-input",
|
|
452
|
-
"text": "demo@example.com",
|
|
453
|
-
"trigger": "login_input.appear"
|
|
454
|
-
},
|
|
455
|
-
{
|
|
456
|
-
"id": "click_submit",
|
|
457
|
-
"action": "click",
|
|
458
|
-
"selector": "button.submit",
|
|
459
|
-
"trigger": { "subscription": "submit_btn", "event": "exist" },
|
|
460
|
-
"conditions": [
|
|
461
|
-
{ "type": "operation_done", "operationId": "fill_login" },
|
|
462
|
-
{ "type": "subscription_exist", "subscriptionId": "submit_btn" }
|
|
463
|
-
]
|
|
464
|
-
}
|
|
465
|
-
]
|
|
466
|
-
}
|
|
467
|
-
```
|
|
468
|
-
|
|
469
|
-
Condition types:
|
|
470
|
-
- `operation_done`: previous operation completed
|
|
471
|
-
- `subscription_exist`: subscribed element currently exists
|
|
472
|
-
- `subscription_appear`: subscribed element has appeared at least once
|
|
473
|
-
|
|
474
|
-
### Environment Variables
|
|
475
|
-
|
|
476
|
-
- `CAMO_INPUT_MODE` - Input mode: `playwright` (default) or `cdp`. CDP mode uses `Input.dispatchMouseEvent` via Chrome DevTools Protocol, bypassing OS-level input system. Does not require window foreground. See [CDP Input Mode](#cdp-input-mode) below.
|
|
477
|
-
- `CAMO_BROWSER_URL` - Browser service URL (default: `http://127.0.0.1:7704`)
|
|
478
|
-
- `CAMO_INSTALL_DIR` - `@web-auto/camo` 安装目录(可选,首次安装兜底)
|
|
479
|
-
- `CAMO_REPO_ROOT` - Camo repository root (optional, dev mode)
|
|
480
|
-
- `CAMO_DATA_ROOT` / `CAMO_HOME` - 用户数据目录(Windows 默认 `D:/camo`,无 D 盘回退 `~/.camo`)
|
|
481
|
-
- `CAMO_PROFILE_ROOT` - Profile 目录覆盖(默认 `<data-root>/profiles`)
|
|
482
|
-
- `CAMO_ROOT` - 兼容旧变量(当值不是 `camo/.camo` 目录时会自动补 `.camo`)
|
|
483
|
-
- `CAMO_CONTAINER_ROOT` - User container root override (default: `~/.camo/container-lib`)
|
|
484
|
-
- `CAMO_PROGRESS_EVENTS_FILE` - Optional progress event JSONL path override
|
|
485
|
-
- `CAMO_PROGRESS_WS_HOST` / `CAMO_PROGRESS_WS_PORT` - Progress websocket daemon bind address (default: `127.0.0.1:7788`)
|
|
486
|
-
- `CAMO_DEFAULT_WINDOW_VERTICAL_RESERVE` - Reserved vertical pixels for default headful auto-size
|
|
487
|
-
|
|
488
|
-
### CDP Input Mode
|
|
489
|
-
|
|
490
|
-
By default, Camo uses Playwright's high-level input API (`page.mouse.click`), which goes through the OS input system and requires the browser window to be in the foreground. This can cause hangs (up to 30s timeout) on Windows when the window loses focus.
|
|
491
|
-
|
|
492
|
-
CDP mode sends mouse events directly via the Chrome DevTools Protocol (`Input.dispatchMouseEvent`), which:
|
|
493
|
-
|
|
494
|
-
- **Does not require window foreground** — works with minimized, background, or headless windows
|
|
495
|
-
- **Does not depend on OS input system** — no `bringToFront`, no `ensureInputReady`
|
|
496
|
-
- **Bypasses input pipeline checks** — no 30s timeout risk from `ensureInputReady` hanging
|
|
497
|
-
|
|
498
|
-
#### How to enable
|
|
499
|
-
|
|
500
|
-
```bash
|
|
501
|
-
# Environment variable (recommended)
|
|
502
|
-
CAMO_INPUT_MODE=cdp camo start xhs-qa-1 --url https://www.xiaohongshu.com
|
|
503
|
-
|
|
504
|
-
# Or set in shell profile
|
|
505
|
-
export CAMO_INPUT_MODE=cdp
|
|
506
|
-
```
|
|
507
|
-
|
|
508
|
-
#### Behavior differences
|
|
509
|
-
|
|
510
|
-
| Feature | Playwright (default) | CDP mode |
|
|
511
|
-
|---------|---------------------|----------|
|
|
512
|
-
| Window foreground required | Yes | No |
|
|
513
|
-
| OS input system | Yes | No |
|
|
514
|
-
| Auto-scroll to element | Yes (via Playwright) | No (caller must ensure element in viewport) |
|
|
515
|
-
| `ensureInputReady` check | Yes (can hang 30s) | Skipped |
|
|
516
|
-
| `bringToFront` | Yes (default) | Skipped |
|
|
517
|
-
| Nudge/recovery on timeout | Yes | No (fast fail) |
|
|
518
|
-
| Input coordinate system | Viewport-relative | Viewport-relative (same) |
|
|
519
|
-
|
|
520
|
-
#### Limitations
|
|
521
|
-
|
|
522
|
-
- **Element must be in viewport**: CDP clicks at coordinates only. If the target element is scrolled out of view, the click will miss. Callers (like webauto's `clickPoint`) already resolve viewport-relative coordinates via `getBoundingClientRect`.
|
|
523
|
-
- **No auto-scroll**: Unlike Playwright's `page.click(selector)`, CDP mode does not scroll to bring elements into view.
|
|
524
|
-
- **keyboard operations still use Playwright**: `keyboard:press` and `keyboard:type` are not affected by CDP mode (they already work reliably in background via Playwright's keyboard API).
|
|
525
|
-
|
|
526
|
-
#### Related environment variables
|
|
527
|
-
|
|
528
|
-
- `CAMO_INPUT_ACTION_TIMEOUT_MS` — Max wait for input action (default: 30000)
|
|
529
|
-
- `CAMO_INPUT_ACTION_MAX_ATTEMPTS` — Retry count on failure (default: 2)
|
|
530
|
-
- `CAMO_INPUT_READY_SETTLE_MS` — Settle time after input ready (default: 80)
|
|
531
|
-
- `CAMO_BRING_TO_FRONT_MODE` — `never` (skip) or `auto` (default, bring window to front)
|
|
532
|
-
|
|
533
|
-
## Session Persistence
|
|
534
|
-
|
|
535
|
-
Camo CLI persists session information locally:
|
|
536
|
-
|
|
537
|
-
- Sessions are registered in `~/.camo/sessions/`
|
|
538
|
-
- On restart, `camo sessions` / `camo instances` shows live + orphaned sessions
|
|
539
|
-
- Stale sessions (>7 days) are automatically cleaned up
|
|
540
|
-
|
|
541
|
-
## Requirements
|
|
542
|
-
|
|
543
|
-
- Node.js >= 20.0.0
|
|
544
|
-
- Python 3 with `camoufox` package
|
|
545
|
-
|
|
546
|
-
## Development
|
|
547
|
-
|
|
548
|
-
```bash
|
|
549
|
-
# Install dependencies
|
|
550
|
-
npm install
|
|
551
|
-
|
|
552
|
-
# Build
|
|
553
|
-
npm run build
|
|
554
|
-
|
|
555
|
-
# Test
|
|
556
|
-
npm test
|
|
557
|
-
|
|
558
|
-
# Global install (build + test + install)
|
|
559
|
-
npm run build:global
|
|
560
|
-
|
|
561
|
-
# Bump version
|
|
562
|
-
npm run version:bump
|
|
563
|
-
```
|
|
564
|
-
|
|
565
|
-
## Release
|
|
566
|
-
|
|
567
|
-
```bash
|
|
568
|
-
# Create a release (bumps version, runs tests, creates tag)
|
|
569
|
-
./scripts/release.sh
|
|
570
|
-
|
|
571
|
-
# Or manually:
|
|
572
|
-
npm run version:bump
|
|
573
|
-
npm test
|
|
574
|
-
git add package.json
|
|
575
|
-
git commit -m "chore: release v$(node -p "require('./package.json').version")"
|
|
576
|
-
git tag "v$(node -p "require('./package.json').version")"
|
|
577
|
-
git push --follow-tags
|
|
578
|
-
```
|
|
579
|
-
|
|
580
|
-
GitHub Actions will automatically:
|
|
581
|
-
1. Run tests on push to main
|
|
582
|
-
2. Publish to npm when a release is created
|
|
583
|
-
|
|
584
|
-
## License
|
|
585
|
-
|
|
586
|
-
MIT
|
|
1
|
+
# Camo CLI
|
|
2
|
+
|
|
3
|
+
[](https://github.com/Jasonzhangf/camo/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/@web-auto/camo)
|
|
5
|
+
|
|
6
|
+
A cross-platform command-line interface for Camoufox browser automation.
|
|
7
|
+
|
|
8
|
+
## What Camo Provides
|
|
9
|
+
|
|
10
|
+
- Browser lifecycle management: start/stop/list sessions, idle cleanup, lock cleanup.
|
|
11
|
+
- Profile-first automation: persistent profile dirs, fingerprint support, remembered window size.
|
|
12
|
+
- Browser control primitives: navigation, tabs, viewport/window, mouse and keyboard actions.
|
|
13
|
+
- Devtools debugging helpers: open devtools, evaluate JS quickly, collect browser console logs.
|
|
14
|
+
- Session recorder: JSONL interaction capture (click/input/scroll/keyboard + page visits) with runtime toggle.
|
|
15
|
+
- Container subscription layer: selector registration, filter/list/watch in viewport.
|
|
16
|
+
- Autoscript runtime: validate/explain/run/resume/mock-run with snapshot and replay.
|
|
17
|
+
- Progress stream: local websocket daemon (`/events`) with tail/recent/emit commands.
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
### npm (Recommended)
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install -g @web-auto/camo
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### From Source
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
git clone https://github.com/Jasonzhangf/camo.git
|
|
31
|
+
cd camo
|
|
32
|
+
npm run build:global
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Quick Start
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Initialize environment
|
|
39
|
+
camo init
|
|
40
|
+
|
|
41
|
+
# Create a profile
|
|
42
|
+
camo profile create myprofile
|
|
43
|
+
|
|
44
|
+
# Set as default
|
|
45
|
+
camo profile default myprofile
|
|
46
|
+
|
|
47
|
+
# Start browser (with alias)
|
|
48
|
+
camo start --url https://example.com --alias main
|
|
49
|
+
|
|
50
|
+
# Start headless worker (auto-kill after idle timeout)
|
|
51
|
+
camo start worker-1 --headless --alias shard1 --idle-timeout 30m
|
|
52
|
+
|
|
53
|
+
# Start with devtools (headful only)
|
|
54
|
+
camo start worker-1 --devtools
|
|
55
|
+
|
|
56
|
+
# Evaluate JS (devtools-style input in page context)
|
|
57
|
+
camo devtools eval worker-1 "document.title"
|
|
58
|
+
|
|
59
|
+
# Read captured console entries
|
|
60
|
+
camo devtools logs worker-1 --levels error,warn --limit 50
|
|
61
|
+
|
|
62
|
+
# Start recording into JSONL (with in-page toggle)
|
|
63
|
+
camo record start worker-1 --name run-a --output ./logs/run-a.jsonl --overlay
|
|
64
|
+
|
|
65
|
+
# Navigate
|
|
66
|
+
camo goto https://www.xiaohongshu.com
|
|
67
|
+
|
|
68
|
+
# Interact
|
|
69
|
+
camo highlight-mode on
|
|
70
|
+
camo click "#search-input" --highlight
|
|
71
|
+
camo type "#search-input" "hello world" --highlight
|
|
72
|
+
camo scroll --down --amount 500 --selector ".feed-list"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Codex Skill (`camoufox`)
|
|
76
|
+
|
|
77
|
+
This repository includes a Codex skill at `skills/camoufox`.
|
|
78
|
+
|
|
79
|
+
Install or refresh it locally:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
mkdir -p ~/.codex/skills
|
|
83
|
+
rsync -a ./skills/camoufox/ ~/.codex/skills/camoufox/
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Use it in Codex with `$camoufox` (or by asking for camo CLI workflows directly).
|
|
87
|
+
|
|
88
|
+
Layered capability model:
|
|
89
|
+
- Observe/Debug: visible DOM filtering, URL/context checks, devtools eval/logs.
|
|
90
|
+
- User Ops: click/type/scroll/keyboard/tab/window operations with optional highlight.
|
|
91
|
+
- Orchestration: container subscription + autoscript flows.
|
|
92
|
+
- Progress/Recovery: events/status/cleanup for runtime diagnostics.
|
|
93
|
+
|
|
94
|
+
## Core Workflows
|
|
95
|
+
|
|
96
|
+
### 1) Interactive browser session
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
camo init
|
|
100
|
+
camo profile create myprofile
|
|
101
|
+
camo profile default myprofile
|
|
102
|
+
camo start --url https://example.com --alias main
|
|
103
|
+
camo click "#search-input"
|
|
104
|
+
camo type "#search-input" "hello world"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### 2) Headless worker with idle auto-stop
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
camo start worker-1 --headless --alias shard1 --idle-timeout 30m
|
|
111
|
+
camo instances
|
|
112
|
+
camo stop idle
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### 3) Devtools-style debugging
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
camo start myprofile --devtools
|
|
119
|
+
camo devtools eval myprofile "document.title"
|
|
120
|
+
camo devtools eval myprofile "(console.error('check-error'), location.href)"
|
|
121
|
+
camo devtools logs myprofile --levels error,warn --limit 50
|
|
122
|
+
camo devtools clear myprofile
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 4) Run autoscript with live progress
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
camo autoscript validate ./autoscripts/xhs.autoscript.json
|
|
129
|
+
camo autoscript run ./autoscripts/xhs.autoscript.json --profile myprofile \
|
|
130
|
+
--jsonl-file ./runs/xhs/run.jsonl \
|
|
131
|
+
--summary-file ./runs/xhs/summary.json
|
|
132
|
+
camo events tail --profile myprofile --mode autoscript
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### 5) Record manual interactions as JSONL
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
camo start myprofile --record --record-name xhs-debug --record-output ./logs/xhs-debug.jsonl --record-overlay
|
|
139
|
+
camo record status myprofile
|
|
140
|
+
camo record stop myprofile
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Commands
|
|
144
|
+
|
|
145
|
+
### Profile Management
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
camo profiles # List profiles with default profile
|
|
149
|
+
camo profile create <profileId> # Create a profile
|
|
150
|
+
camo profile delete <profileId> # Delete a profile
|
|
151
|
+
camo profile default [profileId] # Get or set default profile
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Initialization
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
camo init # Ensure camoufox + browser-service
|
|
158
|
+
camo init geoip # Download GeoIP database
|
|
159
|
+
camo init list # List available OS and regions
|
|
160
|
+
camo create fingerprint --os <os> --region <region>
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Config
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
camo config repo-root [path] # Get/set persisted camo repo root
|
|
167
|
+
camo highlight-mode [status|on|off] # Global highlight mode for click/type/scroll
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Browser Control
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
camo start [profileId] [--url <url>] [--headless] [--devtools] [--record] [--record-name <name>] [--record-output <path>] [--record-overlay|--no-record-overlay] [--alias <name>] [--idle-timeout <duration>] [--width <w> --height <h>]
|
|
174
|
+
camo stop [profileId]
|
|
175
|
+
camo stop --id <instanceId>
|
|
176
|
+
camo stop --alias <alias>
|
|
177
|
+
camo stop idle
|
|
178
|
+
camo stop all
|
|
179
|
+
camo status [profileId] # Show resolved per-profile session view
|
|
180
|
+
camo shutdown # Shutdown browser-service (all sessions)
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
`camo start` in headful mode now persists window size per profile and reuses that size on next start.
|
|
184
|
+
If no saved size exists, it defaults to near-fullscreen (full width, slight vertical reserve).
|
|
185
|
+
Use `--width/--height` to override and update the saved profile size.
|
|
186
|
+
For headless sessions, default idle timeout is `30m` (auto-stop on inactivity). Use `--idle-timeout` (e.g. `45m`, `1800s`, `0`) to customize.
|
|
187
|
+
Use `--devtools` to open browser developer tools in headed mode (cannot be combined with `--headless`).
|
|
188
|
+
Use `--record` to auto-enable JSONL recording at startup; `--record-name`, `--record-output`, and `--record-overlay` customize file naming/output and floating toggle UI.
|
|
189
|
+
Set `CAMO_BRING_TO_FRONT_MODE=never` to keep protocol-level input and page lifecycle operations from forcing the browser window to front during headed runs.
|
|
190
|
+
`CAMO_SKIP_BRING_TO_FRONT=1` remains supported as a legacy alias.
|
|
191
|
+
|
|
192
|
+
### Lifecycle & Cleanup
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
camo instances # List resolved session view (live + registered + idle state)
|
|
196
|
+
camo sessions # List resolved session view for all profiles
|
|
197
|
+
camo cleanup [profileId] # Cleanup only one profile (remote stop + local registry/lock/watchdog)
|
|
198
|
+
camo cleanup all # Cleanup all active sessions
|
|
199
|
+
camo cleanup locks # Cleanup stale lock files
|
|
200
|
+
camo force-stop [profileId] # Force stop only one profile (no alias/id targeting)
|
|
201
|
+
camo lock list # List active session locks
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Session isolation rules:
|
|
205
|
+
- `profileId` is the lifecycle primary key across browser-service session, local registry, watchdog, and lock.
|
|
206
|
+
- `camo start/stop/cleanup/force-stop <profileId>` only target that exact profile and must not affect other profiles.
|
|
207
|
+
- `camo stop --id` and `camo stop --alias` are stop-only convenience selectors; `cleanup` and `force-stop` intentionally reject indirect targeting.
|
|
208
|
+
- `camo status`, `camo sessions`, and `camo instances` share the same resolved session view fields:
|
|
209
|
+
- `live`: browser-service currently has this profile session
|
|
210
|
+
- `registered`: local registry has metadata for this profile
|
|
211
|
+
- `orphaned`: registry exists but the service session is gone
|
|
212
|
+
- `needsRecovery`: registry still says active but browser-service no longer has that profile
|
|
213
|
+
|
|
214
|
+
Isolation examples:
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
# Observe both profiles independently
|
|
218
|
+
camo sessions
|
|
219
|
+
camo status finger
|
|
220
|
+
camo status xhs-qa-1
|
|
221
|
+
|
|
222
|
+
# Stop only finger; xhs-qa-1 must remain live
|
|
223
|
+
camo stop finger
|
|
224
|
+
camo status finger
|
|
225
|
+
camo status xhs-qa-1
|
|
226
|
+
|
|
227
|
+
# cleanup / force-stop require direct profile targeting
|
|
228
|
+
camo cleanup finger
|
|
229
|
+
camo force-stop finger
|
|
230
|
+
|
|
231
|
+
# Invalid on purpose: indirect targeting is rejected
|
|
232
|
+
camo cleanup --alias shard1
|
|
233
|
+
camo force-stop --id inst_xxxxxxxx
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Navigation
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
camo goto [profileId] <url> # Navigate to URL
|
|
240
|
+
camo back [profileId] # Navigate back
|
|
241
|
+
camo screenshot [profileId] [--output <file>] [--full]
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Interaction
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
camo scroll [profileId] [--down|--up|--left|--right] [--amount <px>] [--selector <css>] [--highlight|--no-highlight]
|
|
248
|
+
camo click [profileId] <selector> [--highlight|--no-highlight] # Click visible element by CSS selector
|
|
249
|
+
camo type [profileId] <selector> <text> [--highlight|--no-highlight] # Type into visible input element
|
|
250
|
+
camo highlight [profileId] <selector> # Highlight element (red border, 2s)
|
|
251
|
+
camo clear-highlight [profileId] # Clear all highlights
|
|
252
|
+
camo viewport [profileId] --width <w> --height <h>
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Devtools
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
camo devtools logs [profileId] [--limit 120] [--since <unix_ms>] [--levels error,warn] [--clear]
|
|
259
|
+
camo devtools eval [profileId] <expression> [--profile <id>]
|
|
260
|
+
camo devtools clear [profileId]
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
`devtools logs` reads entries from an injected in-page console collector.
|
|
264
|
+
Supported levels: `log`, `info`, `warn`, `error`, `debug`.
|
|
265
|
+
|
|
266
|
+
### Recording
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
camo record start [profileId] [--name <name>] [--output <file>] [--overlay|--no-overlay]
|
|
270
|
+
camo record stop [profileId] [--reason <text>]
|
|
271
|
+
camo record status [profileId]
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
Recorder JSONL events include:
|
|
275
|
+
- `page.visit`
|
|
276
|
+
- `interaction.click`
|
|
277
|
+
- `interaction.keydown`
|
|
278
|
+
- `interaction.input`
|
|
279
|
+
- `interaction.wheel`
|
|
280
|
+
- `interaction.scroll`
|
|
281
|
+
- `recording.start|stop|toggled|runtime_ready`
|
|
282
|
+
|
|
283
|
+
### Pages
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
camo new-page [profileId] [--url <url>]
|
|
287
|
+
camo close-page [profileId] [index]
|
|
288
|
+
camo switch-page [profileId] <index>
|
|
289
|
+
camo list-pages [profileId] # Requires live=true for that profile
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### Cookies
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
camo cookies get [profileId] Get all cookies for profile
|
|
296
|
+
camo cookies save [profileId] --path <file> Save cookies to file
|
|
297
|
+
camo cookies load [profileId] --path <file> Load cookies from file
|
|
298
|
+
camo cookies auto start [profileId] [--interval <ms>] Start auto-saving cookies
|
|
299
|
+
camo cookies auto stop [profileId] Stop auto-saving
|
|
300
|
+
camo cookies auto status [profileId] Check auto-save status
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Window Control
|
|
304
|
+
|
|
305
|
+
```bash
|
|
306
|
+
camo window move [profileId] --x <x> --y <y>
|
|
307
|
+
camo window resize [profileId] --width <w> --height <h>
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Mouse Control
|
|
311
|
+
|
|
312
|
+
```bash
|
|
313
|
+
camo mouse click [profileId] --x <x> --y <y> [--button left|right|middle] [--clicks <n>] [--delay <ms>]
|
|
314
|
+
camo mouse wheel [profileId] [--deltax <px>] [--deltay <px>]
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### System
|
|
318
|
+
|
|
319
|
+
```bash
|
|
320
|
+
camo system display # Show display metrics
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### Container Subscription
|
|
324
|
+
|
|
325
|
+
```bash
|
|
326
|
+
camo container init [--source <container-library-dir>] [--force]
|
|
327
|
+
camo container sets [--site <siteKey>]
|
|
328
|
+
camo container register [profileId] <setId...> [--append]
|
|
329
|
+
camo container targets [profileId]
|
|
330
|
+
camo container filter [profileId] <selector...>
|
|
331
|
+
camo container watch [profileId] [--selector <css>] [--throttle <ms>]
|
|
332
|
+
camo container list [profileId]
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Autoscript
|
|
336
|
+
|
|
337
|
+
```bash
|
|
338
|
+
camo autoscript validate <file>
|
|
339
|
+
camo autoscript explain <file>
|
|
340
|
+
camo autoscript snapshot <jsonl-file> [--out <snapshot-file>]
|
|
341
|
+
camo autoscript replay <jsonl-file> [--summary-file <path>]
|
|
342
|
+
camo autoscript run <file> [--profile <id>] [--jsonl-file <path>] [--summary-file <path>]
|
|
343
|
+
camo autoscript resume <file> --snapshot <snapshot-file> [--from-node <nodeId>] [--profile <id>] [--jsonl-file <path>] [--summary-file <path>]
|
|
344
|
+
camo autoscript mock-run <file> --fixture <fixture.json> [--profile <id>] [--jsonl-file <path>] [--summary-file <path>]
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### Progress Events (WS)
|
|
348
|
+
|
|
349
|
+
```bash
|
|
350
|
+
camo events serve [--host 127.0.0.1] [--port 7788]
|
|
351
|
+
camo events tail [--profile <id>] [--run-id <id>] [--events e1,e2] [--replay 50]
|
|
352
|
+
camo events recent [--limit 50]
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
By default, non-`events` commands auto-start the progress daemon (`/events`) in background.
|
|
356
|
+
|
|
357
|
+
## Fingerprint Options
|
|
358
|
+
|
|
359
|
+
### OS Options
|
|
360
|
+
|
|
361
|
+
- `mac` (default) - macOS (auto architecture)
|
|
362
|
+
- `mac-m1` - macOS with Apple Silicon
|
|
363
|
+
- `mac-intel` - macOS with Intel
|
|
364
|
+
- `windows` - Windows 11
|
|
365
|
+
- `windows-10` - Windows 10
|
|
366
|
+
- `linux` - Ubuntu 22.04
|
|
367
|
+
|
|
368
|
+
### Region Options
|
|
369
|
+
|
|
370
|
+
- `us` (default) - United States (New York)
|
|
371
|
+
- `us-west` - United States (Los Angeles)
|
|
372
|
+
- `uk` - United Kingdom (London)
|
|
373
|
+
- `de` - Germany (Berlin)
|
|
374
|
+
- `fr` - France (Paris)
|
|
375
|
+
- `jp` - Japan (Tokyo)
|
|
376
|
+
- `sg` - Singapore
|
|
377
|
+
- `au` - Australia (Sydney)
|
|
378
|
+
- `hk` - Hong Kong
|
|
379
|
+
- `tw` - Taiwan (Taipei)
|
|
380
|
+
- `br` - Brazil (Sao Paulo)
|
|
381
|
+
- `in` - India (Mumbai)
|
|
382
|
+
|
|
383
|
+
## Configuration
|
|
384
|
+
|
|
385
|
+
- Config file: `~/.camo/camo-cli.json`
|
|
386
|
+
- Profiles directory: `~/.camo/profiles/`
|
|
387
|
+
- Fingerprints directory: `~/.camo/fingerprints/`
|
|
388
|
+
- Session registry: `~/.camo/sessions/`
|
|
389
|
+
- Lock files: `~/.camo/locks/`
|
|
390
|
+
- GeoIP database: `~/.camo/geoip/GeoLite2-City.mmdb`
|
|
391
|
+
- User container root: `~/.camo/container-lib/`
|
|
392
|
+
- Subscription root: `~/.camo/container-subscriptions/`
|
|
393
|
+
|
|
394
|
+
### Subscription-driven Watch
|
|
395
|
+
|
|
396
|
+
```bash
|
|
397
|
+
# 1) Migrate container-library into subscription sets
|
|
398
|
+
camo container init --source /Users/fanzhang/Documents/github/camo/container-library
|
|
399
|
+
|
|
400
|
+
# 2) Register sets to a profile
|
|
401
|
+
camo container register xiaohongshu-batch-1 xiaohongshu_home xiaohongshu_home.search_input
|
|
402
|
+
|
|
403
|
+
# 3) Start watch using registered selectors (no --selector needed)
|
|
404
|
+
camo container watch xiaohongshu-batch-1 --throttle 500
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### Autoscript Mode (Subscription + Operations)
|
|
408
|
+
|
|
409
|
+
```bash
|
|
410
|
+
# Validate + explain + run
|
|
411
|
+
camo autoscript validate ./autoscripts/my-flow.autoscript.json
|
|
412
|
+
camo autoscript explain ./autoscripts/my-flow.autoscript.json
|
|
413
|
+
camo autoscript run ./autoscripts/my-flow.autoscript.json \
|
|
414
|
+
--profile my-profile \
|
|
415
|
+
--jsonl-file ./runs/my-flow/run.jsonl \
|
|
416
|
+
--summary-file ./runs/my-flow/run.summary.json
|
|
417
|
+
|
|
418
|
+
# Build snapshot + replay summary from existing JSONL
|
|
419
|
+
camo autoscript snapshot ./runs/my-flow/run.jsonl \
|
|
420
|
+
--out ./runs/my-flow/run.snapshot.json
|
|
421
|
+
camo autoscript replay ./runs/my-flow/run.jsonl \
|
|
422
|
+
--summary-file ./runs/my-flow/replay.summary.json
|
|
423
|
+
|
|
424
|
+
# Resume from a snapshot (optionally force rerun from a node)
|
|
425
|
+
camo autoscript resume ./autoscripts/my-flow.autoscript.json \
|
|
426
|
+
--snapshot ./runs/my-flow/run.snapshot.json \
|
|
427
|
+
--from-node some_operation \
|
|
428
|
+
--profile my-profile
|
|
429
|
+
|
|
430
|
+
# Mock replay mode for deterministic local debugging
|
|
431
|
+
camo autoscript mock-run ./autoscripts/my-flow.autoscript.json \
|
|
432
|
+
--fixture ./autoscripts/fixtures/mock-run.json \
|
|
433
|
+
--summary-file ./runs/my-flow/mock.summary.json
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
Example script:
|
|
437
|
+
|
|
438
|
+
```json
|
|
439
|
+
{
|
|
440
|
+
"name": "generic-login-flow",
|
|
441
|
+
"profileId": "my-profile",
|
|
442
|
+
"throttle": 500,
|
|
443
|
+
"subscriptions": [
|
|
444
|
+
{ "id": "login_input", "selector": "#login-input" },
|
|
445
|
+
{ "id": "submit_btn", "selector": "button.submit" }
|
|
446
|
+
],
|
|
447
|
+
"operations": [
|
|
448
|
+
{
|
|
449
|
+
"id": "fill_login",
|
|
450
|
+
"action": "type",
|
|
451
|
+
"selector": "#login-input",
|
|
452
|
+
"text": "demo@example.com",
|
|
453
|
+
"trigger": "login_input.appear"
|
|
454
|
+
},
|
|
455
|
+
{
|
|
456
|
+
"id": "click_submit",
|
|
457
|
+
"action": "click",
|
|
458
|
+
"selector": "button.submit",
|
|
459
|
+
"trigger": { "subscription": "submit_btn", "event": "exist" },
|
|
460
|
+
"conditions": [
|
|
461
|
+
{ "type": "operation_done", "operationId": "fill_login" },
|
|
462
|
+
{ "type": "subscription_exist", "subscriptionId": "submit_btn" }
|
|
463
|
+
]
|
|
464
|
+
}
|
|
465
|
+
]
|
|
466
|
+
}
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
Condition types:
|
|
470
|
+
- `operation_done`: previous operation completed
|
|
471
|
+
- `subscription_exist`: subscribed element currently exists
|
|
472
|
+
- `subscription_appear`: subscribed element has appeared at least once
|
|
473
|
+
|
|
474
|
+
### Environment Variables
|
|
475
|
+
|
|
476
|
+
- `CAMO_INPUT_MODE` - Input mode: `playwright` (default) or `cdp`. CDP mode uses `Input.dispatchMouseEvent` via Chrome DevTools Protocol, bypassing OS-level input system. Does not require window foreground. See [CDP Input Mode](#cdp-input-mode) below.
|
|
477
|
+
- `CAMO_BROWSER_URL` - Browser service URL (default: `http://127.0.0.1:7704`)
|
|
478
|
+
- `CAMO_INSTALL_DIR` - `@web-auto/camo` 安装目录(可选,首次安装兜底)
|
|
479
|
+
- `CAMO_REPO_ROOT` - Camo repository root (optional, dev mode)
|
|
480
|
+
- `CAMO_DATA_ROOT` / `CAMO_HOME` - 用户数据目录(Windows 默认 `D:/camo`,无 D 盘回退 `~/.camo`)
|
|
481
|
+
- `CAMO_PROFILE_ROOT` - Profile 目录覆盖(默认 `<data-root>/profiles`)
|
|
482
|
+
- `CAMO_ROOT` - 兼容旧变量(当值不是 `camo/.camo` 目录时会自动补 `.camo`)
|
|
483
|
+
- `CAMO_CONTAINER_ROOT` - User container root override (default: `~/.camo/container-lib`)
|
|
484
|
+
- `CAMO_PROGRESS_EVENTS_FILE` - Optional progress event JSONL path override
|
|
485
|
+
- `CAMO_PROGRESS_WS_HOST` / `CAMO_PROGRESS_WS_PORT` - Progress websocket daemon bind address (default: `127.0.0.1:7788`)
|
|
486
|
+
- `CAMO_DEFAULT_WINDOW_VERTICAL_RESERVE` - Reserved vertical pixels for default headful auto-size
|
|
487
|
+
|
|
488
|
+
### CDP Input Mode
|
|
489
|
+
|
|
490
|
+
By default, Camo uses Playwright's high-level input API (`page.mouse.click`), which goes through the OS input system and requires the browser window to be in the foreground. This can cause hangs (up to 30s timeout) on Windows when the window loses focus.
|
|
491
|
+
|
|
492
|
+
CDP mode sends mouse events directly via the Chrome DevTools Protocol (`Input.dispatchMouseEvent`), which:
|
|
493
|
+
|
|
494
|
+
- **Does not require window foreground** — works with minimized, background, or headless windows
|
|
495
|
+
- **Does not depend on OS input system** — no `bringToFront`, no `ensureInputReady`
|
|
496
|
+
- **Bypasses input pipeline checks** — no 30s timeout risk from `ensureInputReady` hanging
|
|
497
|
+
|
|
498
|
+
#### How to enable
|
|
499
|
+
|
|
500
|
+
```bash
|
|
501
|
+
# Environment variable (recommended)
|
|
502
|
+
CAMO_INPUT_MODE=cdp camo start xhs-qa-1 --url https://www.xiaohongshu.com
|
|
503
|
+
|
|
504
|
+
# Or set in shell profile
|
|
505
|
+
export CAMO_INPUT_MODE=cdp
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
#### Behavior differences
|
|
509
|
+
|
|
510
|
+
| Feature | Playwright (default) | CDP mode |
|
|
511
|
+
|---------|---------------------|----------|
|
|
512
|
+
| Window foreground required | Yes | No |
|
|
513
|
+
| OS input system | Yes | No |
|
|
514
|
+
| Auto-scroll to element | Yes (via Playwright) | No (caller must ensure element in viewport) |
|
|
515
|
+
| `ensureInputReady` check | Yes (can hang 30s) | Skipped |
|
|
516
|
+
| `bringToFront` | Yes (default) | Skipped |
|
|
517
|
+
| Nudge/recovery on timeout | Yes | No (fast fail) |
|
|
518
|
+
| Input coordinate system | Viewport-relative | Viewport-relative (same) |
|
|
519
|
+
|
|
520
|
+
#### Limitations
|
|
521
|
+
|
|
522
|
+
- **Element must be in viewport**: CDP clicks at coordinates only. If the target element is scrolled out of view, the click will miss. Callers (like webauto's `clickPoint`) already resolve viewport-relative coordinates via `getBoundingClientRect`.
|
|
523
|
+
- **No auto-scroll**: Unlike Playwright's `page.click(selector)`, CDP mode does not scroll to bring elements into view.
|
|
524
|
+
- **keyboard operations still use Playwright**: `keyboard:press` and `keyboard:type` are not affected by CDP mode (they already work reliably in background via Playwright's keyboard API).
|
|
525
|
+
|
|
526
|
+
#### Related environment variables
|
|
527
|
+
|
|
528
|
+
- `CAMO_INPUT_ACTION_TIMEOUT_MS` — Max wait for input action (default: 30000)
|
|
529
|
+
- `CAMO_INPUT_ACTION_MAX_ATTEMPTS` — Retry count on failure (default: 2)
|
|
530
|
+
- `CAMO_INPUT_READY_SETTLE_MS` — Settle time after input ready (default: 80)
|
|
531
|
+
- `CAMO_BRING_TO_FRONT_MODE` — `never` (skip) or `auto` (default, bring window to front)
|
|
532
|
+
|
|
533
|
+
## Session Persistence
|
|
534
|
+
|
|
535
|
+
Camo CLI persists session information locally:
|
|
536
|
+
|
|
537
|
+
- Sessions are registered in `~/.camo/sessions/`
|
|
538
|
+
- On restart, `camo sessions` / `camo instances` shows live + orphaned sessions
|
|
539
|
+
- Stale sessions (>7 days) are automatically cleaned up
|
|
540
|
+
|
|
541
|
+
## Requirements
|
|
542
|
+
|
|
543
|
+
- Node.js >= 20.0.0
|
|
544
|
+
- Python 3 with `camoufox` package
|
|
545
|
+
|
|
546
|
+
## Development
|
|
547
|
+
|
|
548
|
+
```bash
|
|
549
|
+
# Install dependencies
|
|
550
|
+
npm install
|
|
551
|
+
|
|
552
|
+
# Build
|
|
553
|
+
npm run build
|
|
554
|
+
|
|
555
|
+
# Test
|
|
556
|
+
npm test
|
|
557
|
+
|
|
558
|
+
# Global install (build + test + install)
|
|
559
|
+
npm run build:global
|
|
560
|
+
|
|
561
|
+
# Bump version
|
|
562
|
+
npm run version:bump
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
## Release
|
|
566
|
+
|
|
567
|
+
```bash
|
|
568
|
+
# Create a release (bumps version, runs tests, creates tag)
|
|
569
|
+
./scripts/release.sh
|
|
570
|
+
|
|
571
|
+
# Or manually:
|
|
572
|
+
npm run version:bump
|
|
573
|
+
npm test
|
|
574
|
+
git add package.json
|
|
575
|
+
git commit -m "chore: release v$(node -p "require('./package.json').version")"
|
|
576
|
+
git tag "v$(node -p "require('./package.json').version")"
|
|
577
|
+
git push --follow-tags
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
GitHub Actions will automatically:
|
|
581
|
+
1. Run tests on push to main
|
|
582
|
+
2. Publish to npm when a release is created
|
|
583
|
+
|
|
584
|
+
## License
|
|
585
|
+
|
|
586
|
+
MIT
|