@flrande/browserctl 0.1.0 → 0.2.0-dev.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README-CN.md CHANGED
@@ -2,1154 +2,65 @@
2
2
 
3
3
  [English](README.md) | 简体中文
4
4
 
5
- 通用浏览器控制 CLI + daemon,采用 MCP 风格的工具路由。
5
+ 最快路径:通过 relay 扩展直接控制你已打开的 Edge/Chrome。
6
6
 
7
- ## 这个 CLI 做什么
7
+ ## 扩展模式最简上手(推荐)
8
8
 
9
- `browserctl` 是 `browserd` 的 TCP 客户端。
10
-
11
- 1. 解析命令行参数。
12
- 2. 向 `browserd` 发送工具调用。
13
- 3. 当 daemon 不可达时,自动拉起 `browserd` 并重试一次。
14
-
15
- 根包也发布了以下可执行入口:
16
-
17
- - `browserctl` -> `bin/browserctl.cjs`
18
- - `browserd` -> `bin/browserd.cjs`
19
-
20
- ## 快速开始
21
-
22
- 先决条件:
9
+ 前置条件:
23
10
 
24
11
  - Node.js 22+
25
- - pnpm
12
+ - npm 或 pnpm
26
13
  - PowerShell 7 (`pwsh`)
14
+ - Edge 或 Chrome
27
15
 
28
- 最小启动(首次体验,约 2 分钟):
29
-
30
- ```powershell
31
- pnpm install
32
- pnpm exec tsx .\apps\browserctl\src\main.ts status --json
33
- ```
34
-
35
- 仓库完整校验(贡献代码前建议执行):
36
-
37
- ```powershell
38
- pnpm lint
39
- pnpm typecheck
40
- pnpm run test:all
41
- pnpm build
42
- pwsh -NoLogo -NoProfile -File .\scripts\smoke.ps1
43
- ```
44
-
45
- 以持久 TCP 模式启动 daemon:
46
-
47
- ```powershell
48
- pnpm exec tsx .\apps\browserctl\src\main.ts daemon-start --json
49
- pnpm exec tsx .\apps\browserctl\src\main.ts daemon-status --json
50
- ```
51
-
52
- 在当前 shell 覆盖 daemon 端口:
53
-
54
- ```powershell
55
- $env:BROWSERCTL_DAEMON_PORT = "42491"
56
- ```
57
-
58
- ## 发布流程
59
-
60
- 发布前建议按以下顺序执行:
61
-
62
- ```powershell
63
- pnpm lint
64
- pnpm typecheck
65
- pnpm run test:all
66
- pnpm build
67
- pwsh -NoLogo -NoProfile -File .\scripts\smoke.ps1
68
- ```
69
-
70
- 打 tag 发布:
16
+ 1. 安装已发布包:
71
17
 
72
18
  ```powershell
73
- $version = node -p "require('./package.json').version"
74
- git tag "v$version"
75
- git push origin "v$version"
19
+ npm install --global @flrande/browserctl
20
+ # 或:pnpm add --global @flrande/browserctl
76
21
  ```
77
22
 
78
- 说明:
79
-
80
- - `publish.yml` 会先跑跨平台 verify 矩阵,再执行发布。
81
- - 发布作业会上传 dry-run 与 npm dist-tag 工件,便于追踪与回滚评估。
82
- - 手动触发(`workflow_dispatch`)支持 `dry_run` 与 `dist_tag`。
83
-
84
- ## 新手先看(推荐顺序)
85
-
86
- 如果你是第一次用,建议按下面顺序:
87
-
88
- 1. 先跑一次“最小启动”。
89
- 2. 先走路径 A(`managed-local`,推荐)。
90
- 3. 只有在你要控制“已打开的浏览器”时,再走路径 B(`chrome-relay`)。
91
-
92
- ### 路径 A:控制一个新启动的本地浏览器(推荐)
93
-
94
- ```powershell
95
- pnpm exec tsx .\apps\browserctl\src\main.ts daemon-start --json
96
- pnpm exec tsx .\apps\browserctl\src\main.ts status --json --session demo --profile managed-local
97
- pnpm exec tsx .\apps\browserctl\src\main.ts tab-open --json --session demo --profile managed-local https://example.com
98
- pnpm exec tsx .\apps\browserctl\src\main.ts tabs --json --session demo --profile managed-local
99
- ```
100
-
101
- 可选:在 PowerShell 里自动取 `targetId` 后抓快照:
102
-
103
- ```powershell
104
- $tabs = pnpm exec tsx .\apps\browserctl\src\main.ts tabs --json --session demo --profile managed-local | ConvertFrom-Json
105
- $targetId = $tabs.data.tabs[0]
106
- pnpm exec tsx .\apps\browserctl\src\main.ts snapshot --json --session demo --profile managed-local $targetId
107
- pnpm exec tsx .\apps\browserctl\src\main.ts screenshot --json --session demo --profile managed-local $targetId
108
- ```
109
-
110
- ### 路径 B:控制你当前正在使用的 Edge/Chrome(扩展 relay)
111
-
112
- 1. 先把 daemon 切到扩展 relay 模式:
23
+ 2. 用扩展 relay 模式启动 daemon:
113
24
 
114
25
  ```powershell
115
26
  $env:BROWSERD_DEFAULT_DRIVER = "chrome-relay"
116
27
  $env:BROWSERD_CHROME_RELAY_MODE = "extension"
117
28
  $env:BROWSERD_CHROME_RELAY_URL = "http://127.0.0.1:9223"
118
29
  $env:BROWSERD_CHROME_RELAY_EXTENSION_TOKEN = "relay-secret"
119
- pnpm exec tsx .\apps\browserctl\src\main.ts daemon-stop --json
120
- pnpm exec tsx .\apps\browserctl\src\main.ts daemon-start --json
121
- ```
122
-
123
- 2. 打开 `edge://extensions` 或 `chrome://extensions`,开启“开发人员模式”,加载已解压扩展目录 `extensions/chrome-relay`。
124
- 3. 打开扩展弹窗,把 `Bridge URL` 设为 `ws://127.0.0.1:9223/bridge`,并填写相同 token(`relay-secret`),点击 Save,再点 Reconnect。
125
- 4. 用下面命令确认连接:
126
-
127
- ```powershell
128
- pnpm exec tsx .\apps\browserctl\src\main.ts status --json --session relay --profile chrome-relay
129
- ```
130
-
131
- 期望信号:`status.data.status.connected = true`。
132
-
133
- ### 快速故障检查
134
-
135
- 命令失败时,先跑:
136
-
137
- ```powershell
138
- pnpm exec tsx .\apps\browserctl\src\main.ts daemon-status --json
139
- Invoke-WebRequest -UseBasicParsing -Uri "http://127.0.0.1:9223/browserctl/relay/status" -TimeoutSec 3
30
+ browserctl daemon-stop --json
31
+ browserctl daemon-start --json
140
32
  ```
141
33
 
142
- 如果 relay 状态仍是 `connected: false`,回到扩展弹窗再点一次 Reconnect。
143
-
144
- ## 扩展阅读/控制接口
34
+ 3. 加载扩展:
145
35
 
146
- CLI 已增加以下浏览器阅读/控制命令:
147
-
148
- ```text
149
- dom-query <targetId> <selector>
150
- dom-query-all <targetId> <selector>
151
- element-screenshot <targetId> <selector>
152
- a11y-snapshot <targetId> [selector]
153
- network-wait-for <targetId> <urlPattern> [--method <METHOD>] [--status <CODE>] [--timeout-ms <ms>] [--poll-ms <ms>]
154
- cookie-get <targetId> [name]
155
- cookie-set <targetId> <name> <value> [url]
156
- cookie-clear <targetId> [name]
157
- storage-get <targetId> <local|session> <key>
158
- storage-set <targetId> <local|session> <key> <value>
159
- frame-list <targetId>
160
- frame-snapshot <targetId> <frameId>
161
- ```
36
+ 1. 打开 `edge://extensions` 或 `chrome://extensions`。
37
+ 2. 开启开发者模式。
38
+ 3. 选择“加载已解压的扩展程序”,目录为 `extensions/chrome-relay`。
39
+ 4. 在扩展弹窗中设置:
40
+ - `Bridge URL`: `ws://127.0.0.1:9223/bridge`
41
+ - `Token`: `relay-secret`
42
+ 5. 点击 `Save`,再点击 `Reconnect`。
162
43
 
163
- 示例:
44
+ 4. 连接验证与首个命令:
164
45
 
165
46
  ```powershell
166
- pnpm exec tsx .\apps\browserctl\src\main.ts dom-query --json --session demo $targetId "article h1"
167
- pnpm exec tsx .\apps\browserctl\src\main.ts element-screenshot --json --session demo $targetId "#main"
168
- pnpm exec tsx .\apps\browserctl\src\main.ts network-wait-for --json --session demo $targetId "/api/items" --method GET --status 200 --timeout-ms 15000
169
- pnpm exec tsx .\apps\browserctl\src\main.ts cookie-get --json --session demo $targetId
170
- pnpm exec tsx .\apps\browserctl\src\main.ts storage-set --json --session demo $targetId local theme dark
171
- pnpm exec tsx .\apps\browserctl\src\main.ts frame-list --json --session demo $targetId
172
- ```
173
-
174
- ## 全局命令模型
175
-
176
- 语法:
177
-
178
- ```text
179
- browserctl [--json] <command> [command-options] [positionals]
180
- ```
181
-
182
- 由命令上下文处理的全局参数:
183
-
184
- - `--session <id>`:会话命名空间,默认 `cli:local`
185
- - `--profile <driverKey>`:驱动键覆盖(`managed`、`managed-local`、`chrome-relay`、`remote-cdp`)
186
- - `--token <authToken>`:认证 token 覆盖
187
- - `--browser <preset>`:启动浏览器预设(`chromium`、`chrome`、`edge`)
188
-
189
- 说明:
190
-
191
- - `--json` 会被全局消费并控制输出信封格式。
192
- - 未知 flag 不做严格选项 schema 校验,可能被当作位置参数。
193
- - `--browser` 仅影响 daemon 启动。若 daemon 已运行,不会热更新现有进程。
194
-
195
- ## 核心概念
196
-
197
- ## 会话命名空间(`--session`)
198
-
199
- 会话命名空间就是 daemon 会话存储中的 `sessionId`。
200
-
201
- 1. daemon 会按 session 维护状态,例如当前 `profile`(驱动键)和当前 `targetId`。
202
- 2. 默认值是 `cli:local`,可通过 `--session <id>` 覆盖。
203
- 3. 不同 session ID 会隔离控制上下文,互不覆盖。
204
- 4. 这是上下文隔离,不是安全隔离。
205
- 5. 会话状态在内存中,daemon 重启后会清空。
206
-
207
- ## 认证 token(`--token`、`BROWSERD_AUTH_TOKEN`)
208
-
209
- 认证 token 是用于请求鉴权的共享密钥字符串。
210
-
211
- 1. daemon 设置 `BROWSERD_AUTH_TOKEN` 后,每次工具调用都必须带匹配的 `authToken`。
212
- 2. CLI 会从 `--token` 或 `BROWSERCTL_AUTH_TOKEN` 转发 token。
213
- 3. 缺失或不匹配会返回 `E_PERMISSION: Invalid auth token.`。
214
- 4. token 负责“鉴权”;可执行范围由 `BROWSERD_AUTH_SCOPES` 单独限制。
215
-
216
- ## 浏览器预设(`--browser`)
217
-
218
- 浏览器预设用于控制 managed-local 启动时的 channel 选择。
219
-
220
- 1. `chromium`:`browserName=chromium`,不覆盖 channel。
221
- 2. `chrome`:`browserName=chromium`,`channel=chrome`。
222
- 3. `edge`:`browserName=chromium`,`channel=msedge`。
223
- 4. 预设不影响 `chrome-relay` 和 `remote-cdp`。
224
- 5. 预设只在 daemon 启动时生效;daemon 已运行时需重启 daemon 才会切换。
225
-
226
- ## 退出码与输出
227
-
228
- 退出码:
229
-
230
- - `0`:成功
231
- - `1`:命令执行错误
232
- - `2`:参数错误或未知命令
233
-
234
- 成功信封(`--json`):
235
-
236
- ```json
237
- {
238
- "ok": true,
239
- "command": "status",
240
- "data": {
241
- "kind": "browserd",
242
- "ready": true
243
- }
244
- }
47
+ browserctl status --json --session relay --profile chrome-relay
48
+ browserctl tab-open --json --session relay --profile chrome-relay https://example.com
245
49
  ```
246
50
 
247
- 失败信封(`--json`,写到 stderr):
248
-
249
- ```json
250
- {
251
- "ok": false,
252
- "error": {
253
- "message": "E_PERMISSION: Invalid auth token.",
254
- "exitCode": 1
255
- }
256
- }
257
- ```
258
-
259
- ## 环境变量
260
-
261
- ### CLI(`browserctl`)
262
-
263
- | 变量 | 默认值 | 说明 |
264
- | --- | --- | --- |
265
- | `BROWSERCTL_DAEMON_PORT` | `41337` | daemon 请求使用的 TCP 端口。 |
266
- | `BROWSERCTL_DAEMON_STARTUP_TIMEOUT_MS` | `10000` | daemon 就绪最长等待时间。 |
267
- | `BROWSERCTL_DAEMON_REQUEST_TIMEOUT_MS` | `5000` | 单次请求 socket 超时。 |
268
- | `BROWSERCTL_BROWSER` | 未设置 | daemon 启动时的默认浏览器预设(`chromium`、`chrome`、`edge`)。 |
269
- | `BROWSERCTL_AUTH_TOKEN` | 未设置 | 请求默认认证 token。 |
270
-
271
- 优先级:
272
-
273
- - token:`--token` > `BROWSERCTL_AUTH_TOKEN`
274
- - browser preset:`--browser` > `BROWSERCTL_BROWSER`
275
-
276
- ### Daemon(`browserd`)
277
-
278
- | 变量 | 默认值 | 说明 |
279
- | --- | --- | --- |
280
- | `BROWSERD_TRANSPORT` | `stdio` | CLI 拉起 daemon 时会使用 `tcp`。 |
281
- | `BROWSERD_STDIO_PROTOCOL` | `mcp` | `legacy` 表示 JSON-line 兼容模式。 |
282
- | `BROWSERD_HOST` | `127.0.0.1` | transport=tcp 时的监听 host。 |
283
- | `BROWSERD_PORT` | `41337` | transport=tcp 时的监听端口。 |
284
- | `BROWSERD_DEFAULT_DRIVER` | 启用 managed-local 时为 `managed-local`,否则为 `managed` | 若不可用会回退到 `managed`。 |
285
- | `BROWSERD_MANAGED_LOCAL_ENABLED` | `true` | 设为 false 可取消注册 `managed-local`。 |
286
- | `BROWSERD_MANAGED_LOCAL_BROWSER` | `chromium` | `chromium`、`firefox`、`webkit`。 |
287
- | `BROWSERD_MANAGED_LOCAL_HEADLESS` | `true` | 支持 `1/0`、`true/false`、`yes/no`、`on/off`。 |
288
- | `BROWSERD_MANAGED_LOCAL_CHANNEL` | 未设置 | 可选 channel 覆盖。 |
289
- | `BROWSERD_MANAGED_LOCAL_EXECUTABLE_PATH` | 未设置 | 可选可执行文件路径。 |
290
- | `BROWSERD_MANAGED_LOCAL_LAUNCH_TIMEOUT_MS` | 未设置 | 非负整数。 |
291
- | `BROWSERD_MANAGED_LOCAL_ARGS` | 未设置(`[]`) | 逗号分隔启动参数。 |
292
- | `BROWSERD_CHROME_RELAY_URL` | `http://127.0.0.1:9223` | `chrome-relay` 端点。 |
293
- | `BROWSERD_CHROME_RELAY_MODE` | `cdp` | `chrome-relay` 模式:`cdp` 或 `extension`。 |
294
- | `BROWSERD_CHROME_RELAY_EXTENSION_TOKEN` | 未设置 | 当 `BROWSERD_CHROME_RELAY_MODE=extension` 时必填。 |
295
- | `BROWSERD_CHROME_RELAY_EXTENSION_REQUEST_TIMEOUT_MS` | `5000` | 扩展 bridge RPC 超时(毫秒)。 |
296
- | `BROWSERD_REMOTE_CDP_URL` | `http://127.0.0.1:9222/devtools/browser/default` | `remote-cdp` 端点。 |
297
- | `BROWSERD_AUTH_TOKEN` | 未设置 | 当 `BROWSERD_TRANSPORT=tcp` 时必填;设置后每个工具调用都必须提供匹配的 `authToken`。 |
298
- | `BROWSERD_AUTH_SCOPES` | `read,act,upload,download` | 允许的作用域。 |
299
- | `BROWSERD_UPLOAD_ROOT` | 未设置 | 上传路径白名单根目录。 |
300
- | `BROWSERD_DOWNLOAD_ROOT` | 未设置 | 下载路径白名单根目录。 |
301
-
302
- ## 运行默认值与驱动说明
303
-
304
- 默认运行行为:
305
-
306
- - 默认启用并选择 `managed-local` 作为默认驱动。
307
- - `managed`、`chrome-relay`、`remote-cdp` 始终注册。
308
- - `BROWSERD_DEFAULT_DRIVER` 可强制默认驱动键。
309
- - 若配置的默认驱动不可用,会回退到 `managed`。
310
- - 默认远端端点:
311
- - `BROWSERD_CHROME_RELAY_URL=http://127.0.0.1:9223`
312
- - `BROWSERD_REMOTE_CDP_URL=http://127.0.0.1:9222/devtools/browser/default`
313
-
314
- `managed-local` 说明:
315
-
316
- - 浏览器懒启动(首次需要浏览器上下文时)。
317
- - 可选启动控制:
318
- - `BROWSERD_MANAGED_LOCAL_BROWSER`(`chromium|firefox|webkit`,默认 `chromium`)
319
- - `BROWSERD_MANAGED_LOCAL_HEADLESS`(默认 `true`)
320
- - `BROWSERD_MANAGED_LOCAL_CHANNEL`
321
- - `BROWSERD_MANAGED_LOCAL_EXECUTABLE_PATH`
322
- - `BROWSERD_MANAGED_LOCAL_LAUNCH_TIMEOUT_MS`
323
- - `BROWSERD_MANAGED_LOCAL_ARGS`(逗号分隔)
324
-
325
- `chrome-relay` 说明:
326
-
327
- - 使用 `BROWSERD_CHROME_RELAY_URL`(默认 `http://127.0.0.1:9223`)。
328
- - 默认模式是 `BROWSERD_CHROME_RELAY_MODE=cdp`,支持 `ws(s)` 或 `http(s)` URL。
329
- - 当为 `http(s)` 时,运行时会尝试 `/json/version` 并优先使用 `webSocketDebuggerUrl`。
330
- - `BROWSERD_CHROME_RELAY_MODE=extension` 会在 `BROWSERD_CHROME_RELAY_URL` 启动本地扩展 bridge。
331
- - 扩展模式下,请把 `extensions/chrome-relay` 以“加载已解压的扩展程序”方式安装,并在弹窗里设置 Bridge URL(默认 `ws://127.0.0.1:9223/bridge`)。
332
- - 扩展模式必须设置 `BROWSERD_CHROME_RELAY_EXTENSION_TOKEN`,并在扩展弹窗配置同一个 token。
333
- - 扩展模式已支持通过 bridge 回传 console 与 network 遥测(可用时包含 response body)。
334
- - 在 `--profile chrome-relay` 下发生连接错误时,CLI 会附加引导排查信息。
335
-
336
- 示例:
51
+ ## 30 秒排查
337
52
 
338
53
  ```powershell
339
- $env:BROWSERD_DEFAULT_DRIVER = "chrome-relay"
340
- $env:BROWSERD_CHROME_RELAY_URL = "http://127.0.0.1:9223"
341
- pnpm exec tsx .\apps\browserctl\src\main.ts status --json --session cli:relay --profile chrome-relay
342
- ```
343
-
344
- `remote-cdp` 说明:
345
-
346
- - 使用 `BROWSERD_REMOTE_CDP_URL`(默认 `http://127.0.0.1:9222/devtools/browser/default`)。
347
- - 直接通过 CDP 连接到配置 URL。
348
-
349
- 示例:
350
-
351
- ```powershell
352
- $env:BROWSERD_DEFAULT_DRIVER = "remote-cdp"
353
- $env:BROWSERD_REMOTE_CDP_URL = "http://127.0.0.1:9222/devtools/browser/default"
354
- pnpm exec tsx .\apps\browserctl\src\main.ts status --json --session cli:remote --profile remote-cdp
355
- ```
356
-
357
- ## 驱动模式与使用方式
358
-
359
- 驱动对比:
360
-
361
- | 驱动 | 本质 | 适用场景 | 前置要求 | 常见状态字段 |
362
- | --- | --- | --- | --- | --- |
363
- | `managed` | 内存中的托管 stub 驱动 | 合同测试、确定性本地校验 | 无 | `status.kind = managed` |
364
- | `managed-local` | Playwright 启动的本地真实浏览器 | 默认本地自动化 | 本地浏览器运行时;可选 channel/executable 配置 | `status.kind = managed-local` |
365
- | `chrome-relay` | 通过 relay 端点(`ws/http`)连接 CDP | attach 工作流、扩展 relay 工作流 | 可访问的 relay 端点(`BROWSERD_CHROME_RELAY_URL`) | `status.kind = chrome-relay` |
366
- | `remote-cdp` | 直接连接远端/本地浏览器 CDP 端点 | 已有浏览器/CDP 基础设施 | 可访问的 CDP 端点(`BROWSERD_REMOTE_CDP_URL`) | `status.kind = remote-cdp` |
367
-
368
- 如何选择驱动:
369
-
370
- 1. 单次命令:传 `--profile <driverKey>`。
371
- 2. 会话级别:`profile-use <driverKey> --session <id>`。
372
- 3. daemon 默认值:设置 `BROWSERD_DEFAULT_DRIVER`。
373
-
374
- ### 使用 `managed`(stub)
375
-
376
- ```powershell
377
- $env:BROWSERD_DEFAULT_DRIVER = "managed"
378
- pnpm exec tsx .\apps\browserctl\src\main.ts status --json --session demo --profile managed
379
- pnpm exec tsx .\apps\browserctl\src\main.ts tab-open --json --session demo --profile managed https://example.com
380
- ```
381
-
382
- ### 使用 `managed-local`(本地真实浏览器)
383
-
384
- ```powershell
385
- $env:BROWSERD_DEFAULT_DRIVER = "managed-local"
386
- $env:BROWSERD_MANAGED_LOCAL_HEADLESS = "false"
387
- pnpm exec tsx .\apps\browserctl\src\main.ts daemon-stop --json
388
- pnpm exec tsx .\apps\browserctl\src\main.ts daemon-start --json --browser edge
389
- pnpm exec tsx .\apps\browserctl\src\main.ts status --json --session demo --profile managed-local
390
- ```
391
-
392
- ### 使用 `chrome-relay`
393
-
394
- ```powershell
395
- $env:BROWSERD_DEFAULT_DRIVER = "chrome-relay"
396
- $env:BROWSERD_CHROME_RELAY_URL = "http://127.0.0.1:9223"
397
- pnpm exec tsx .\apps\browserctl\src\main.ts status --json --session relay --profile chrome-relay
398
- pnpm exec tsx .\apps\browserctl\src\main.ts tab-open --json --session relay --profile chrome-relay https://example.com
399
- ```
400
-
401
- 如果连接失败,CLI 会附加 relay 引导信息(扩展激活、端点检查、URL 检查)。
402
-
403
- 扩展模式示例:
404
-
405
- ```powershell
406
- $env:BROWSERD_DEFAULT_DRIVER = "chrome-relay"
407
- $env:BROWSERD_CHROME_RELAY_MODE = "extension"
408
- $env:BROWSERD_CHROME_RELAY_URL = "http://127.0.0.1:9223"
409
- $env:BROWSERD_CHROME_RELAY_EXTENSION_TOKEN = "relay-secret"
410
- pnpm exec tsx .\apps\browserctl\src\main.ts daemon-stop --json
411
- pnpm exec tsx .\apps\browserctl\src\main.ts daemon-start --json
412
- pnpm exec tsx .\apps\browserctl\src\main.ts status --json --session relay --profile chrome-relay
413
- ```
414
-
415
- 扩展安装(Chrome/Edge):
416
-
417
- 1. 打开 `chrome://extensions` 或 `edge://extensions`。
418
- 2. 打开开发者模式。
419
- 3. 点击“加载已解压的扩展程序”,选择 `extensions/chrome-relay`。
420
- 4. 打开扩展弹窗,填写 Bridge URL 与同一个 token,然后点击 Save/Reconnect。
421
-
422
- ### 使用 `remote-cdp`
423
-
424
- ```powershell
425
- $env:BROWSERD_DEFAULT_DRIVER = "remote-cdp"
426
- $env:BROWSERD_REMOTE_CDP_URL = "http://127.0.0.1:9222/devtools/browser/default"
427
- pnpm exec tsx .\apps\browserctl\src\main.ts status --json --session remote --profile remote-cdp
428
- pnpm exec tsx .\apps\browserctl\src\main.ts tab-open --json --session remote --profile remote-cdp https://example.com
429
- ```
430
-
431
- 推荐切换模式:
432
-
433
- 1. 每个驱动使用独立 session(如 `session:local`、`session:relay`、`session:remote`)。
434
- 2. 自动化脚本里优先显式传 `--profile`,避免 session 历史状态产生隐式切换。
435
-
436
- ## 认证与路径约束
437
-
438
- - `BROWSERD_TRANSPORT=tcp` 必须设置 `BROWSERD_AUTH_TOKEN`。
439
- - 若设置 `BROWSERD_AUTH_TOKEN`,每个工具调用都必须提供匹配的 `authToken`。
440
- - `BROWSERD_AUTH_SCOPES` 是 `read`、`act`、`upload`、`download` 的逗号分隔白名单。
441
- - 未设置 `BROWSERD_UPLOAD_ROOT` 时,`browser.upload.arm` 会被拒绝。
442
- - 未设置 `BROWSERD_DOWNLOAD_ROOT` 时,`browser.download.wait` 会被拒绝。
443
- - `BROWSERD_UPLOAD_ROOT` 将 `upload-arm` 文件路径限制在该根目录下。
444
- - `BROWSERD_DOWNLOAD_ROOT` 将 `download-wait` 输出路径限制在该根目录下。
445
- - `download-wait` 支持可选位置参数 `path`。
446
- - 若设置了 `BROWSERD_DOWNLOAD_ROOT`,且请求路径与驱动返回路径都不存在,`download-wait` 会返回内部错误。
447
-
448
- ## 驱动与会话行为
449
-
450
- 已注册驱动:
451
-
452
- - `managed`
453
- - `managed-local`(除非被禁用)
454
- - `chrome-relay`
455
- - `remote-cdp`
456
-
457
- 会话存储行为:
458
-
459
- 1. 传入 `--profile` 会覆盖本次调用驱动,并更新 session profile。
460
- 2. 不传 `--profile` 时,daemon 先看 session profile,再回退默认驱动。
461
- 3. `tab-open` 会把 session target 更新为新开目标。
462
-
463
- ## Edge 与浏览器预设
464
-
465
- `--browser` 或 `BROWSERCTL_BROWSER` 的映射:
466
-
467
- - `edge` -> `chromium + channel=msedge`
468
- - `chrome` -> `chromium + channel=chrome`
469
- - `chromium` -> `chromium`(不覆盖 channel)
470
-
471
- 示例:
472
-
473
- ```powershell
474
- pnpm exec tsx .\apps\browserctl\src\main.ts daemon-stop --json
475
- pnpm exec tsx .\apps\browserctl\src\main.ts daemon-start --json --browser edge
476
- pnpm exec tsx .\apps\browserctl\src\main.ts status --json
477
- ```
478
-
479
- ## 命令参考(含 JSON 示例)
480
-
481
- 下面所有示例都使用:
482
-
483
- ```powershell
484
- pnpm exec tsx .\apps\browserctl\src\main.ts
485
- ```
486
-
487
- ## `daemon-start`
488
-
489
- 用途:确保 daemon 运行;若未运行则启动。
490
-
491
- 语法:
492
-
493
- ```text
494
- daemon-start [--json] [--token <authToken>] [--browser <chromium|chrome|edge>]
495
- ```
496
-
497
- 示例命令:
498
-
499
- ```powershell
500
- pnpm exec tsx .\apps\browserctl\src\main.ts daemon-start --json --browser edge
501
- ```
502
-
503
- 示例 JSON 输出:
504
-
505
- ```json
506
- {
507
- "ok": true,
508
- "command": "daemon-start",
509
- "data": {
510
- "running": true,
511
- "port": 41337,
512
- "pid": 24680
513
- }
514
- }
515
- ```
516
-
517
- ## `daemon-status`
518
-
519
- 用途:检查 daemon 是否可达。
520
-
521
- 语法:
522
-
523
- ```text
524
- daemon-status [--json] [--token <authToken>]
525
- ```
526
-
527
- 示例命令:
528
-
529
- ```powershell
530
- pnpm exec tsx .\apps\browserctl\src\main.ts daemon-status --json
531
- ```
532
-
533
- 示例 JSON 输出:
534
-
535
- ```json
536
- {
537
- "ok": true,
538
- "command": "daemon-status",
539
- "data": {
540
- "running": true,
541
- "port": 41337,
542
- "pid": 24680
543
- }
544
- }
545
- ```
546
-
547
- ## `daemon-stop`
548
-
549
- 用途:基于 PID 文件停止 daemon。
550
-
551
- 语法:
552
-
553
- ```text
554
- daemon-stop [--json]
555
- ```
556
-
557
- 示例命令:
558
-
559
- ```powershell
560
- pnpm exec tsx .\apps\browserctl\src\main.ts daemon-stop --json
561
- ```
562
-
563
- 示例 JSON 输出:
564
-
565
- ```json
566
- {
567
- "ok": true,
568
- "command": "daemon-stop",
569
- "data": {
570
- "stopped": true,
571
- "port": 41337,
572
- "pid": 24680
573
- }
574
- }
575
- ```
576
-
577
- ## `status`
578
-
579
- 用途:获取 browserd 状态和当前驱动状态。
580
-
581
- 语法:
582
-
583
- ```text
584
- status [--json] [--session <id>] [--profile <driverKey>] [--token <authToken>]
585
- ```
586
-
587
- 示例命令:
588
-
589
- ```powershell
590
- pnpm exec tsx .\apps\browserctl\src\main.ts status --json --session demo --profile managed-local
591
- ```
592
-
593
- 示例 JSON 输出:
594
-
595
- ```json
596
- {
597
- "ok": true,
598
- "command": "status",
599
- "data": {
600
- "kind": "browserd",
601
- "ready": true,
602
- "driver": "managed-local",
603
- "drivers": [
604
- "chrome-relay",
605
- "managed",
606
- "managed-local",
607
- "remote-cdp"
608
- ],
609
- "status": {
610
- "kind": "managed-local",
611
- "connected": false,
612
- "launched": false,
613
- "browserName": "chromium",
614
- "headless": true
615
- }
616
- }
617
- }
618
- ```
619
-
620
- ## `tabs`
621
-
622
- 用途:列出当前驱动/上下文下的 target ID 列表。
623
-
624
- 语法:
625
-
626
- ```text
627
- tabs [--json] [--session <id>] [--profile <driverKey>] [--token <authToken>]
628
- ```
629
-
630
- 示例命令:
631
-
632
- ```powershell
633
- pnpm exec tsx .\apps\browserctl\src\main.ts tabs --json --session demo
634
- ```
635
-
636
- 示例 JSON 输出:
637
-
638
- ```json
639
- {
640
- "ok": true,
641
- "command": "tabs",
642
- "data": {
643
- "driver": "managed-local",
644
- "tabs": [
645
- "target:managed-local:profile:managed-local:default:1"
646
- ]
647
- }
648
- }
649
- ```
650
-
651
- ## `profile-list`
652
-
653
- 用途:列出当前驱动可见 profile 列表。
654
-
655
- 语法:
656
-
657
- ```text
658
- profile-list [--json] [--session <id>] [--profile <driverKey>] [--token <authToken>]
659
- ```
660
-
661
- 示例命令:
662
-
663
- ```powershell
664
- pnpm exec tsx .\apps\browserctl\src\main.ts profile-list --json --profile managed-local
665
- ```
666
-
667
- 示例 JSON 输出:
668
-
669
- ```json
670
- {
671
- "ok": true,
672
- "command": "profile-list",
673
- "data": {
674
- "driver": "managed-local",
675
- "profiles": [
676
- "profile:managed-local:default"
677
- ]
678
- }
679
- }
680
- ```
681
-
682
- ## `profile-use`
683
-
684
- 用途:把 session 绑定到某个驱动键。
685
-
686
- 语法:
687
-
688
- ```text
689
- profile-use <driverKey> [--json] [--session <id>] [--token <authToken>]
690
- ```
691
-
692
- 示例命令:
693
-
694
- ```powershell
695
- pnpm exec tsx .\apps\browserctl\src\main.ts profile-use --json --session demo chrome-relay
696
- ```
697
-
698
- 示例 JSON 输出:
699
-
700
- ```json
701
- {
702
- "ok": true,
703
- "command": "profile-use",
704
- "data": {
705
- "profile": "chrome-relay"
706
- }
707
- }
708
- ```
709
-
710
- ## `tab-open`
711
-
712
- 用途:新建标签页并导航到 URL。
713
-
714
- 语法:
715
-
716
- ```text
717
- tab-open <url> [--json] [--session <id>] [--profile <driverKey>] [--token <authToken>]
718
- ```
719
-
720
- 示例命令:
721
-
722
- ```powershell
723
- pnpm exec tsx .\apps\browserctl\src\main.ts tab-open --json --session demo https://example.com
724
- ```
725
-
726
- 示例 JSON 输出:
727
-
728
- ```json
729
- {
730
- "ok": true,
731
- "command": "tab-open",
732
- "data": {
733
- "driver": "managed-local",
734
- "targetId": "target:managed-local:profile:managed-local:default:2"
735
- }
736
- }
737
- ```
738
-
739
- ## `tab-focus`
740
-
741
- 用途:聚焦已有目标页。
742
-
743
- 语法:
744
-
745
- ```text
746
- tab-focus <targetId> [--json] [--session <id>] [--profile <driverKey>] [--token <authToken>]
747
- ```
748
-
749
- 示例命令:
750
-
751
- ```powershell
752
- pnpm exec tsx .\apps\browserctl\src\main.ts tab-focus --json --session demo target:managed-local:profile:managed-local:default:2
753
- ```
754
-
755
- 示例 JSON 输出:
756
-
757
- ```json
758
- {
759
- "ok": true,
760
- "command": "tab-focus",
761
- "data": {
762
- "driver": "managed-local",
763
- "targetId": "target:managed-local:profile:managed-local:default:2",
764
- "focused": true
765
- }
766
- }
767
- ```
768
-
769
- ## `tab-close`
770
-
771
- 用途:关闭已有目标页。
772
-
773
- 语法:
774
-
775
- ```text
776
- tab-close <targetId> [--json] [--session <id>] [--profile <driverKey>] [--token <authToken>]
777
- ```
778
-
779
- 示例命令:
780
-
781
- ```powershell
782
- pnpm exec tsx .\apps\browserctl\src\main.ts tab-close --json --session demo target:managed-local:profile:managed-local:default:2
783
- ```
784
-
785
- 示例 JSON 输出:
786
-
787
- ```json
788
- {
789
- "ok": true,
790
- "command": "tab-close",
791
- "data": {
792
- "driver": "managed-local",
793
- "targetId": "target:managed-local:profile:managed-local:default:2",
794
- "closed": true
795
- }
796
- }
797
- ```
798
-
799
- ## `snapshot`
800
-
801
- 用途:抓取目标页快照(可包含 URL/标题/HTML/请求摘要)。
802
-
803
- 语法:
804
-
805
- ```text
806
- snapshot <targetId> [--json] [--session <id>] [--profile <driverKey>] [--token <authToken>]
807
- ```
808
-
809
- 示例命令:
810
-
811
- ```powershell
812
- pnpm exec tsx .\apps\browserctl\src\main.ts snapshot --json --session demo target:managed-local:profile:managed-local:default:1
813
- ```
814
-
815
- 示例 JSON 输出:
816
-
817
- ```json
818
- {
819
- "ok": true,
820
- "command": "snapshot",
821
- "data": {
822
- "driver": "managed-local",
823
- "targetId": "target:managed-local:profile:managed-local:default:1",
824
- "snapshot": {
825
- "kind": "managed-local",
826
- "profile": "profile:managed-local:default",
827
- "targetId": "target:managed-local:profile:managed-local:default:1",
828
- "hasTarget": true,
829
- "url": "https://example.com/",
830
- "title": "Example Domain",
831
- "html": "<!doctype html>...",
832
- "requestSummaries": []
833
- }
834
- }
835
- }
836
- ```
837
-
838
- ## `screenshot`
839
-
840
- 用途:抓取目标页截图(PNG base64 载荷)。
841
-
842
- 语法:
843
-
844
- ```text
845
- screenshot <targetId> [--json] [--session <id>] [--profile <driverKey>] [--token <authToken>]
846
- ```
847
-
848
- 示例命令:
849
-
850
- ```powershell
851
- pnpm exec tsx .\apps\browserctl\src\main.ts screenshot --json --session demo target:managed-local:profile:managed-local:default:1
852
- ```
853
-
854
- 示例 JSON 输出:
855
-
856
- ```json
857
- {
858
- "ok": true,
859
- "command": "screenshot",
860
- "data": {
861
- "driver": "managed-local",
862
- "targetId": "target:managed-local:profile:managed-local:default:1",
863
- "screenshot": {
864
- "kind": "managed-local",
865
- "profile": "profile:managed-local:default",
866
- "targetId": "target:managed-local:profile:managed-local:default:1",
867
- "hasTarget": true,
868
- "mimeType": "image/png",
869
- "encoding": "base64",
870
- "imageBase64": "iVBORw0KGgoAAAANSUhEUgAA..."
871
- }
872
- }
873
- }
874
- ```
875
-
876
- ## `act`
877
-
878
- 用途:按动作类型对目标页执行操作。
879
-
880
- 语法:
881
-
882
- ```text
883
- act <actionType> <targetId> [--json] [--session <id>] [--profile <driverKey>] [--token <authToken>]
884
- ```
885
-
886
- 当前 CLI 的关键行为:
887
-
888
- - CLI 只发送 `action.type`。
889
- - 不发送 `action.payload`。
890
- - 需要 payload 的动作可能在 `data.result` 中返回 `ok: false`。
891
-
892
- 示例命令:
893
-
894
- ```powershell
895
- pnpm exec tsx .\apps\browserctl\src\main.ts act --json --session demo click target:managed-local:profile:managed-local:default:1
896
- ```
897
-
898
- 示例 JSON 输出:
899
-
900
- ```json
901
- {
902
- "ok": true,
903
- "command": "act",
904
- "data": {
905
- "driver": "managed-local",
906
- "targetId": "target:managed-local:profile:managed-local:default:1",
907
- "result": {
908
- "actionType": "click",
909
- "profile": "profile:managed-local:default",
910
- "targetId": "target:managed-local:profile:managed-local:default:1",
911
- "targetKnown": true,
912
- "ok": false,
913
- "executed": false,
914
- "error": "action.payload.selector is required for click action."
915
- }
916
- }
917
- }
918
- ```
919
-
920
- ## `upload-arm`
921
-
922
- 用途:为目标页预置上传文件。
923
-
924
- 语法:
925
-
926
- ```text
927
- upload-arm <targetId> <file1> [file2 ...] [--json] [--session <id>] [--profile <driverKey>] [--token <authToken>]
928
- ```
929
-
930
- 示例命令:
931
-
932
- ```powershell
933
- pnpm exec tsx .\apps\browserctl\src\main.ts upload-arm --json --session demo target:managed-local:profile:managed-local:default:1 .\fixtures\a.txt .\fixtures\b.txt
934
- ```
935
-
936
- 示例 JSON 输出:
937
-
938
- ```json
939
- {
940
- "ok": true,
941
- "command": "upload-arm",
942
- "data": {
943
- "driver": "managed-local",
944
- "targetId": "target:managed-local:profile:managed-local:default:1",
945
- "armed": true,
946
- "files": [
947
- "C:\\repo\\fixtures\\a.txt",
948
- "C:\\repo\\fixtures\\b.txt"
949
- ]
950
- }
951
- }
952
- ```
953
-
954
- ## `dialog-arm`
955
-
956
- 用途:为目标页预置对话框处理。
957
-
958
- 语法:
959
-
960
- ```text
961
- dialog-arm <targetId> [--json] [--session <id>] [--profile <driverKey>] [--token <authToken>]
962
- ```
963
-
964
- 示例命令:
965
-
966
- ```powershell
967
- pnpm exec tsx .\apps\browserctl\src\main.ts dialog-arm --json --session demo target:managed-local:profile:managed-local:default:1
968
- ```
969
-
970
- 示例 JSON 输出:
971
-
972
- ```json
973
- {
974
- "ok": true,
975
- "command": "dialog-arm",
976
- "data": {
977
- "driver": "managed-local",
978
- "targetId": "target:managed-local:profile:managed-local:default:1",
979
- "armed": true
980
- }
981
- }
982
- ```
983
-
984
- ## `download-trigger`
985
-
986
- 用途:触发目标页下载流程。
987
-
988
- 语法:
989
-
990
- ```text
991
- download-trigger <targetId> [--json] [--session <id>] [--profile <driverKey>] [--token <authToken>]
992
- ```
993
-
994
- 示例命令:
995
-
996
- ```powershell
997
- pnpm exec tsx .\apps\browserctl\src\main.ts download-trigger --json --session demo target:managed-local:profile:managed-local:default:1
998
- ```
999
-
1000
- 示例 JSON 输出:
1001
-
1002
- ```json
1003
- {
1004
- "ok": true,
1005
- "command": "download-trigger",
1006
- "data": {
1007
- "driver": "managed-local",
1008
- "targetId": "target:managed-local:profile:managed-local:default:1",
1009
- "triggered": true
1010
- }
1011
- }
1012
- ```
1013
-
1014
- ## `download-wait`
1015
-
1016
- 用途:等待并返回下载元数据。
1017
-
1018
- 语法:
1019
-
1020
- ```text
1021
- download-wait <targetId> [path] [--json] [--session <id>] [--profile <driverKey>] [--token <authToken>]
1022
- ```
1023
-
1024
- 示例命令:
1025
-
1026
- ```powershell
1027
- pnpm exec tsx .\apps\browserctl\src\main.ts download-wait --json --session demo target:managed-local:profile:managed-local:default:1 .\downloads\artifact.bin
1028
- ```
1029
-
1030
- 示例 JSON 输出:
1031
-
1032
- ```json
1033
- {
1034
- "ok": true,
1035
- "command": "download-wait",
1036
- "data": {
1037
- "driver": "managed-local",
1038
- "targetId": "target:managed-local:profile:managed-local:default:1",
1039
- "download": {
1040
- "path": "C:\\repo\\downloads\\artifact.bin",
1041
- "profile": "profile:managed-local:default",
1042
- "targetId": "target:managed-local:profile:managed-local:default:1",
1043
- "uploadFiles": [
1044
- "C:\\repo\\fixtures\\a.txt"
1045
- ],
1046
- "dialogArmedCount": 1,
1047
- "triggerCount": 1
1048
- }
1049
- }
1050
- }
1051
- ```
1052
-
1053
- ## `console-list`
1054
-
1055
- 用途:读取目标页控制台遥测条目。
1056
-
1057
- 语法:
1058
-
1059
- ```text
1060
- console-list <targetId> [--json] [--session <id>] [--profile <driverKey>] [--token <authToken>]
1061
- ```
1062
-
1063
- 示例命令:
1064
-
1065
- ```powershell
1066
- pnpm exec tsx .\apps\browserctl\src\main.ts console-list --json --session demo target:managed-local:profile:managed-local:default:1
1067
- ```
1068
-
1069
- 示例 JSON 输出:
1070
-
1071
- ```json
1072
- {
1073
- "ok": true,
1074
- "command": "console-list",
1075
- "data": {
1076
- "driver": "managed-local",
1077
- "targetId": "target:managed-local:profile:managed-local:default:1",
1078
- "entries": [
1079
- {
1080
- "type": "warning",
1081
- "text": "Example warning",
1082
- "timestamp": "2026-02-23T10:00:00.000Z",
1083
- "location": {
1084
- "url": "https://example.com",
1085
- "lineNumber": 12,
1086
- "columnNumber": 4
1087
- }
1088
- }
1089
- ]
1090
- }
1091
- }
1092
- ```
1093
-
1094
- ## `response-body`
1095
-
1096
- 用途:按 request ID 读取已捕获的网络响应体。
1097
-
1098
- 语法:
1099
-
1100
- ```text
1101
- response-body <targetId> <requestId> [--json] [--session <id>] [--profile <driverKey>] [--token <authToken>]
1102
- ```
1103
-
1104
- 示例命令:
1105
-
1106
- ```powershell
1107
- pnpm exec tsx .\apps\browserctl\src\main.ts response-body --json --session demo target:managed-local:profile:managed-local:default:1 request:managed-local:profile%3Amanaged-local%3Adefault:target%3Amanaged-local%3Aprofile%3Amanaged-local%3Adefault%3A1:1
1108
- ```
1109
-
1110
- 示例 JSON 输出:
1111
-
1112
- ```json
1113
- {
1114
- "ok": true,
1115
- "command": "response-body",
1116
- "data": {
1117
- "driver": "managed-local",
1118
- "targetId": "target:managed-local:profile:managed-local:default:1",
1119
- "requestId": "request:managed-local:profile%3Amanaged-local%3Adefault:target%3Amanaged-local%3Aprofile%3Amanaged-local%3Adefault%3A1:1",
1120
- "body": "{\"ok\":true}",
1121
- "encoding": "utf8"
1122
- }
1123
- }
54
+ browserctl daemon-status --json
55
+ Invoke-WebRequest -UseBasicParsing -Uri "http://127.0.0.1:9223/browserctl/relay/status" -TimeoutSec 3
1124
56
  ```
1125
57
 
1126
- ## Relay 故障排查
1127
-
1128
- 当 relay 配置下出现连接类错误(`ECONNREFUSED`、超时、`ENOTFOUND` 等)时,CLI 会附加引导:
1129
-
1130
- 1. 扩展 relay 方案请先设置 `BROWSERD_CHROME_RELAY_MODE=extension`。
1131
- 2. 从 `extensions/chrome-relay` 加载扩展并保持激活。
1132
- 3. 确认扩展弹窗 Bridge URL 与 `BROWSERD_CHROME_RELAY_URL` 一致(`ws://<host>:<port>/bridge`)。
1133
- 4. CDP relay 方案请确认浏览器远程调试端点已启动。
1134
- 5. 确认 `BROWSERD_CHROME_RELAY_URL` 配置正确。
58
+ `connected` 为 `false`,重新打开扩展弹窗并点击 `Reconnect`。
1135
59
 
1136
- ## 示例负载准确性说明
1137
-
1138
- - 以上 JSON 示例与当前命令/返回结构一致,用于代表典型返回。
1139
- - 实际运行值会受驱动、浏览器状态和环境策略影响。
1140
- - `snapshot.html`、`screenshot.imageBase64` 与遥测字段可能很大,示例中做了省略。
1141
-
1142
- ## Smoke 流程
1143
-
1144
- 运行 smoke 流程:
1145
-
1146
- ```powershell
1147
- pwsh -NoLogo -NoProfile -File .\scripts\smoke.ps1
1148
- ```
60
+ ## 完整文档
1149
61
 
1150
- Smoke 流程行为:
62
+ - [Full User Guide (English)](docs/user-guide.md)
63
+ - [完整使用文档(中文)](docs/user-guide-cn.md)
64
+ - [Chrome Relay Extension README (English)](extensions/chrome-relay/README.md)
65
+ - [Chrome Relay 扩展文档(中文)](extensions/chrome-relay/README-CN.md)
1151
66
 
1152
- 1. 启动 `browserd`。
1153
- 2. 执行 `browserctl status --json`。
1154
- 3. 等待 daemon 通过 TCP 可达。
1155
- 4. 若响应包含错误或 `ok` 为 `false` 则失败。