@web-auto/camo 0.1.26 → 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.
Files changed (117) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +586 -586
  3. package/bin/browser-service.mjs +11 -11
  4. package/bin/camo.mjs +22 -22
  5. package/package.json +48 -48
  6. package/scripts/build.mjs +19 -19
  7. package/scripts/bump-version.mjs +34 -34
  8. package/scripts/check-file-size.mjs +80 -80
  9. package/scripts/file-size-policy.json +12 -2
  10. package/scripts/install.mjs +76 -76
  11. package/scripts/release.sh +54 -54
  12. package/src/autoscript/action-providers/index.mjs +6 -6
  13. package/src/autoscript/impact-engine.mjs +78 -78
  14. package/src/autoscript/runtime.mjs +1017 -1017
  15. package/src/autoscript/schema.mjs +376 -376
  16. package/src/cli.mjs +405 -405
  17. package/src/commands/attach.mjs +141 -141
  18. package/src/commands/autoscript.mjs +1011 -1011
  19. package/src/commands/browser.mjs +1255 -1257
  20. package/src/commands/container.mjs +401 -401
  21. package/src/commands/cookies.mjs +69 -69
  22. package/src/commands/create.mjs +98 -98
  23. package/src/commands/devtools.mjs +349 -349
  24. package/src/commands/events.mjs +152 -152
  25. package/src/commands/highlight-mode.mjs +24 -24
  26. package/src/commands/init.mjs +68 -68
  27. package/src/commands/lifecycle.mjs +275 -275
  28. package/src/commands/mouse.mjs +45 -45
  29. package/src/commands/profile.mjs +46 -46
  30. package/src/commands/record.mjs +115 -115
  31. package/src/commands/system.mjs +14 -14
  32. package/src/commands/window.mjs +123 -123
  33. package/src/container/change-notifier.mjs +362 -362
  34. package/src/container/element-filter.mjs +143 -143
  35. package/src/container/index.mjs +3 -3
  36. package/src/container/runtime-core/checkpoint.mjs +209 -209
  37. package/src/container/runtime-core/index.mjs +21 -21
  38. package/src/container/runtime-core/operations/index.mjs +774 -774
  39. package/src/container/runtime-core/operations/selector-scripts.mjs +277 -277
  40. package/src/container/runtime-core/operations/tab-pool.mjs +746 -746
  41. package/src/container/runtime-core/operations/viewport.mjs +189 -189
  42. package/src/container/runtime-core/search.mjs +190 -190
  43. package/src/container/runtime-core/subscription.mjs +224 -224
  44. package/src/container/runtime-core/utils.mjs +94 -94
  45. package/src/container/runtime-core/validation.mjs +127 -184
  46. package/src/container/runtime-core.mjs +1 -1
  47. package/src/container/subscription-registry.mjs +459 -459
  48. package/src/core/actions.mjs +561 -561
  49. package/src/core/browser.mjs +266 -266
  50. package/src/core/index.mjs +52 -52
  51. package/src/core/utils.mjs +91 -91
  52. package/src/events/daemon-entry.mjs +33 -33
  53. package/src/events/daemon.mjs +80 -80
  54. package/src/events/progress-log.mjs +109 -109
  55. package/src/events/ws-server.mjs +239 -239
  56. package/src/lib/client.mjs +200 -200
  57. package/src/lifecycle/cleanup.mjs +83 -83
  58. package/src/lifecycle/lock.mjs +126 -126
  59. package/src/lifecycle/session-registry.mjs +279 -279
  60. package/src/lifecycle/session-view.mjs +76 -76
  61. package/src/lifecycle/session-watchdog.mjs +281 -281
  62. package/src/services/browser-service/index.js +671 -674
  63. package/src/services/browser-service/internal/BrowserSession.input.test.js +389 -389
  64. package/src/services/browser-service/internal/BrowserSession.js +325 -336
  65. package/src/services/browser-service/internal/ElementRegistry.js +60 -60
  66. package/src/services/browser-service/internal/ProfileLock.js +84 -84
  67. package/src/services/browser-service/internal/SessionManager.js +184 -184
  68. package/src/services/browser-service/internal/SessionManager.test.js +39 -39
  69. package/src/services/browser-service/internal/browser-session/cookies.js +144 -144
  70. package/src/services/browser-service/internal/browser-session/input-ops.js +222 -219
  71. package/src/services/browser-service/internal/browser-session/input-pipeline.js +144 -144
  72. package/src/services/browser-service/internal/browser-session/logging.js +46 -46
  73. package/src/services/browser-service/internal/browser-session/navigation.js +38 -38
  74. package/src/services/browser-service/internal/browser-session/page-hooks.js +442 -442
  75. package/src/services/browser-service/internal/browser-session/page-management.js +302 -336
  76. package/src/services/browser-service/internal/browser-session/page-management.test.js +148 -148
  77. package/src/services/browser-service/internal/browser-session/recording.js +198 -198
  78. package/src/services/browser-service/internal/browser-session/runtime-events.js +61 -61
  79. package/src/services/browser-service/internal/browser-session/session-core.js +84 -84
  80. package/src/services/browser-service/internal/browser-session/session-state.js +38 -38
  81. package/src/services/browser-service/internal/browser-session/types.js +14 -14
  82. package/src/services/browser-service/internal/browser-session/utils.js +95 -95
  83. package/src/services/browser-service/internal/browser-session/viewport-manager.js +46 -46
  84. package/src/services/browser-service/internal/browser-session/viewport.js +215 -215
  85. package/src/services/browser-service/internal/container-matcher.js +851 -851
  86. package/src/services/browser-service/internal/container-registry.js +182 -182
  87. package/src/services/browser-service/internal/engine-manager.js +259 -259
  88. package/src/services/browser-service/internal/fingerprint.js +203 -203
  89. package/src/services/browser-service/internal/heartbeat.js +137 -137
  90. package/src/services/browser-service/internal/logging.js +46 -46
  91. package/src/services/browser-service/internal/page-runtime/runtime.js +1317 -1317
  92. package/src/services/browser-service/internal/pageRuntime.js +28 -28
  93. package/src/services/browser-service/internal/runtimeInjector.js +31 -31
  94. package/src/services/browser-service/internal/service-process-logger.js +140 -140
  95. package/src/services/browser-service/internal/state-bus.js +45 -45
  96. package/src/services/browser-service/internal/storage-paths.js +42 -42
  97. package/src/services/browser-service/internal/ws-server.js +1194 -1194
  98. package/src/services/browser-service/internal/ws-server.test.js +58 -58
  99. package/src/services/browser-service/server.mjs +6 -6
  100. package/src/services/controller/cli-bridge.js +93 -93
  101. package/src/services/controller/container-index.js +50 -50
  102. package/src/services/controller/container-storage.js +36 -36
  103. package/src/services/controller/controller-actions.js +207 -207
  104. package/src/services/controller/controller.js +1138 -1138
  105. package/src/services/controller/selectors.js +54 -54
  106. package/src/services/controller/transport.js +125 -125
  107. package/src/utils/args.mjs +26 -26
  108. package/src/utils/browser-service.mjs +544 -544
  109. package/src/utils/command-log.mjs +64 -64
  110. package/src/utils/config.mjs +214 -214
  111. package/src/utils/fingerprint.mjs +181 -181
  112. package/src/utils/help.mjs +216 -216
  113. package/src/utils/js-policy.mjs +13 -13
  114. package/src/utils/ws-client.mjs +30 -30
  115. package/src/container/runtime-core/operations/tab-pool.mjs.bak +0 -762
  116. package/src/container/runtime-core/operations/tab-pool.mjs.syntax-error +0 -762
  117. package/src/services/browser-service/index.js.bak +0 -671
package/README.md CHANGED
@@ -1,586 +1,586 @@
1
- # Camo CLI
2
-
3
- [![CI](https://github.com/Jasonzhangf/camo/actions/workflows/ci.yml/badge.svg)](https://github.com/Jasonzhangf/camo/actions/workflows/ci.yml)
4
- [![npm version](https://badge.fury.io/js/@web-auto%2Fcamo.svg)](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
+ [![CI](https://github.com/Jasonzhangf/camo/actions/workflows/ci.yml/badge.svg)](https://github.com/Jasonzhangf/camo/actions/workflows/ci.yml)
4
+ [![npm version](https://badge.fury.io/js/@web-auto%2Fcamo.svg)](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